MAD - Language features
In this post we’ll look at the MAD language (as implemented by GOM on MTS) in more detail. As MAD is quite a large language, compared to FORTRAN or BASIC, I will only go over some of its interesting or unusual features; for a good overview of the language you may want to read the Wikipedia article first.
Complete examples below (those ending with END OF PROGRAM
) have been tested using *GOM
on MTS D6.0; do note that initial blanks are needed for lines which do not contain statement labels.
Synonyms and abbreviations
There are a number of synonyms for MAD keywords, (eg TRANSFER TO
for GO TO
, and spaces are not generally needed. For example a goto label X could be expressed as:
GOTO X
GO TO X
TRANSFER TO X
TRANSFERTOX
GOTOX
would not work as this is ambiguous, as it could be a references to the variable GOTOX
. The TRANSFERTOX
works as this is longer than a variable name could be.
Keywords can be abbreviated by taking the first and last letter and inserting a '
: for example T'O
for TRANSFER TO
’. The compiler can optionally produce a listing of the input with these expanded by setting the sprint
parameter.
Constant qualification
Constants can be qualified to a particular type or format with a suffix: some examples
1B
- Boolean true100@X
- hex integer 100, ie decimal 256.12@L1
- one byte integer"HI"@L4
- character string of length 4, right padded with blanks
Statement label vectors
As well as simple labels as seen in FORTRAN, you can have vectors of statement labels. For example, the below will print “Two”:
INTEGER J
J = 2
GOTO L(J)
L(1) PRINT COMMENT "One"
GO TO DONE
L(2) PRINT COMMENT "Two"
GO TO DONE
L(3) PRINT COMMENT "Three"
DONE END OF PROGRAM
Conversions
MAD does implicit conversions by assigning to a variable of different type. You can cast to another type without conversion using .AS
.
INTEGER IM, C1, C2
FLOATING POINT F
F = 123.45
IM = F
C1 = F.AS.INTEGER
C2.AS.FLOATING POINT = F
PRINT RESULTS IM, C1, C2
END OF PROGRAM
This will print:
IM = 123 C1 = 1115386675 C2 = 1115386675
Character expressions and strings
Strings are expressed as character vectors; sub-elements of a vector can be addressed using block notation, with ...
standing for range, with optional first and last subscript, and |
for length. For example:
CHARACTER HELLO(5),H1(3),H2(2)
HELLO(...) = "Hello"
H1(...) = HELLO(2...4)
H2(...) = HELLO(1|2)
PRINT COMMENT H1
PRINT COMMENT H2
END OF PROGRAM
Will print “llo” and “el”.
Conditionals
The conditional statement allows else clauses and there is an implicit block structure for each clause:
INTEGER X
X = 3
IF X > 1 .AND. X <= 3
PRINT COMMENT "Yes"
PRINT RESULTS X
ELSE
PRINT COMMENT "No"
END IF
END OF PROGRAM
Loops
As we saw in the hello world example, the basic loop takes an initial variable, increment and condition which when true will mark the end of the loop. So the below will print “Hello, world!” five times
LOOP FOR I=1, 1, I > 5
PRINT COMMENT "Hello, world!"
END LOOP
END OF PROGRAM
There is also a THROUGH variant which is more like a FORTRAN loop: this will print “Hi” and “There” five times then “Done”.
THROUGH L, FOR I=1,1,I>5
PRINT COMMENT "Hi"
L PRINT COMMENT "There"
PRINT COMMENT "Done"
END OF PROGRAM
and a LOOP WHILE b
and LOOP UNTIL b
which implement while loops.
Dynamic memory and pointers
Addresses can be referenced with .LOC.
and indirection done with .IND.
followed by the type (which does not have to be the original type of what is being pointed to). It’s possible to do pointer arithmetic also. The below example will print the result “42”.
INTEGER Q
Q = 0
POINTER P
P = .LOC.Q
P.IND.INTEGER = 42
PRINT RESULTS Q
END OF PROGRAM
A dynamic record defines a simple structure made up of data fields
DYNAMIC RECORD (POINT) X,Y
INTEGER X, Y
To use this you need to point it at an existing memory location or allocate new space with ALLOCATE
and free memory with RELEASE
. You can then use :
to address fields:
DYNAMIC RECORD (POINT) X,Y
INTEGER X, Y
POINTER P
ALLOCATE (POINT)->P
P:X = 10
P:Y = 20
PRINT RESULTS P:Y / P:X
RELEASE P
END OF PROGRAM
The USING
keywords allows you to select a pointer, after which references to a record’s fields will be done through that pointer. As an example, the above could be rewritten as:
DYNAMIC RECORD (POINT) X,Y
INTEGER X, Y
POINTER P
ALLOCATE (POINT)->P
USING POINTER P, FOR POINT
X = 10
Y = 20
PRINT RESULTS Y / X
RELEASE P
END OF PROGRAM
The USING
will continue until another USING
replaces it, or you do STOP USING POINTER
.
Functions
MAD supports external (definition can provided at link time) or internal functions. Functions have a number of interesting features:
- Names must end with a
.
so they are recognised by the parser - Optional or variable number of arguments are supported
- It’s possible to have multiple entry points into a function
- As well as a return value it’s possible to set a return code to signal unusual conditions
A example showing how an internal function can be defined and called, using the return code feature:
INTERNAL FUNCTION NEGATE.(X)
NORMAL MODE IS INTEGER
IF X = 0
FUNCTION RETURN 0, RC=1
ELSE
FUNCTION RETURN - X
END IF
END OF FUNCTION
INTEGER X, X1, R
READ DATA FROM UNIT 5
X1 = NEGATE.(X)->R
IF R = 0
PRINT COMMENT "Zero is still zero"
ELSE
PRINT RESULTS X1
END IF
END OF PROGRAM
Input/output
In the previous example, the READ DATA FROM UNIT 5
requires that you set unit 5 to a FDname on the run command. But how does it know where to put the input? It expects the input format to be a set of name=value
pairs separated by commas and terminated by an asterisk, which it will use to set variables. So a sample run of the above program, taking input from the keyboard, would look like:
# $run -load 5=*source*
# Execution begins 10:47:49
X=42*
X1 = -42
# Execution terminated 10:47:55 T=0.001
You can also use READ AND PRINT DATA
to input as above and then echo the values entered.
For output, PRINT RESULTS
will print data in a similar way to the format used by READ DATA
’; PRINT COMMENT
can be used to output a string.
It’s also possible to do formatted input/output, similar but not identical to FORTRAN.
Further information
See the GOM Manual for a full specification of the language and how it differs from the original version of MAD.