MAD Language Documentation
Michigan Algorithm Decoder (MAD) is an early, highly influential algebraic programming language developed in 1959. This documentation covers the modern MAD IDE pipeline, syntax rules, and original historical code examples.
Basic Syntax & Formatting
Original MAD programs required strict columnar formatting for IBM 7090 execution. The MAD IDE intelligently processes statements so you can write freely, but the underlying transpiler relies on standard conventions.
NORMAL MODE IS INTEGER
DIMENSION KEY(32), MYTRAN(4)
INITAS.(0)
PRINT COMMENT $WHICH SCRIPT DO YOU WISH TO PLAY$
CTSS Abbreviations
The Compatible Time-Sharing System (CTSS) introduced abbreviations to speed up coding on teletypes. Our IDE automatically expands these at compile time:
| Abbreviation | Expansion |
|---|---|
W'R | WHENEVER |
O'E | OTHERWISE |
E'L | END OF CONDITIONAL |
T'H | THROUGH |
T'O | TRANSFER TO |
F'N | FUNCTION RETURN |
E'N | END OF FUNCTION |
How to Run MAD Code
To run any MAD code inside the MAD IDE, follow these steps:
- Open your
.madfile using File -> Open, or create a new file and paste your code. - Make sure you have built the underlying compiler first by clicking Tools -> Build MAD Compiler.
- Click the ▶ Run button in the top toolbar or press F5.
- The IDE will automatically apply CTSS pre-processing, compile the code natively to C, and execute the binary!
Original MAD Code: ELIZA Chatbot
Below is the full original ELIZA chatbot implemented in the MAD programming language. Scroll to see the complete implementation of this historical AI program.
EXTERNAL FUNCTION (KEY, MYTRAN)
NORMAL MODE IS INTEGER
ENTRY TO CHANGE.
LIST.(INPUT)
V'S G(1) = $TYPE$, $SUBST$, $APPEND$, $ADDS$, $START$, $RANKS$, $DISPLAS$
V'S SNUMB$ = $13 $
FIT=0
PRINT COMMENT $ PLEASE INSTRUCT ME$
LISTRD.(MTLIST.(INPUT),0)
JOB = POPTOP.(INPUT)
T'H IDENT, FOR J = 1,1, J .G. 7
IDENT W'R G(J) .E. JOB, T'O THEMA
PRINT COMMENT $CHANGE NOT RECOGNIZED$
T'O CHANGE
THEMA W'R J .E. 5
F'N IRALST.(INPUT)
W'R J .E. 7
T'H DISPLA, FOR I=0,1, I .G. 32
W'R LISTMT.(KEY(I)) .E. 0, T'O DISPLA
S = SEQRDR.(KEY(I))
READ(7) NEXT = SEQLR.(S,F)
W'R F .G. 0, T'O DISPLA
PRINT COMMENT $#$
TPRINT.(NEXT,0)
PRINT FORMAT SNUMB, I
PRINT COMMENT $ $
DISPLA T'O READ(7)
CONTINUE
PRINT COMMENT $ $
PRINT COMMENT $MEMORY LIST FOLLOWS$
MEMLST PRINT COMMENT $ $
T'H MEMLST, FOR I=1, 1, I .G. 4
TXTPRT.(MYTRAN(I),0)
T'O CHANGE
E'L
THEME = POPTOP.(INPUT)
SUBJCT = KEY(HASH.(THEME, 5))
S = SEQRDR.(SUBJCT)
LOOK TERM = SEQLR.(S,F)
W'R F .G. 0, T'O FAIL
W'R TOP.(TERM) .E. THEME, T'O FOUND
T'O LOOK
FOUND T'O DELTA(J)
DELTA(1) TPRINT.(TERM,0)
T'O CHANGE
FAIL PRINT COMMENT $LIST NOT FOUND$
DELTA(2) T'O CHANGE
S = SEQRDR.(TERM)
READ(1) CLD = POPTOP.(INPUT)
OBJCT = SEQLR.(S,F)
READ(2) W'R F .G. 0, T'O FAIL
W'R F .NE. 0, T'O READ(1)
INSIDE = SEQRDR.(OBJCT)
IT = SEQLR.(INSIDE,F)
W'R F .G. 0, T'O READ(1)
SIT = SEQRDR.(IT)
ITOLD SOLD = SEQRDR.(OLD)
TOLD = SEQLR.(SOLD, FOLD)
DIT = SEQLR.(SIT, FIT)
W'R TOLD .E. DIT .AND. FOLD .E. 0, T'O ITOLD
W'R FOLD .G. 0, T'O OK(J)
T'O READ(2)
SUBST.(POPTOP.(INPUT), LSPNTR.(INSIDE))
OK(2) T'O CHANGE
NEWBOT.(POPTOP.(INPUT), OBJCT)
OK(3) T'O CHANGE
DELTA(3) T'O DELTA(2)
W'R NAMTST.(BOT.(TERM)) .E. 0
BOTTOM=POPBOT.(TERM)
NEWBOT.(POPTOP.(INPUT), TERM)
DELTA(4) NEWBOT.(BOTTOM, TERM)
O'E
NEWBOT.(POPTOP.(INPUT), TERM)
E'L
T'O CHANGE
S = SEQRDR.(TERM)
DELTA(6) OBJCT = SEQLR.(S,F)
READ(6) W'R F .G. 0, T'O FAIL
W'R F .NE. 0, T'O READ(6)
OBJCT = SEQLL.(S,F)
W'R LNKL.(OBJCT) .E. 0
SUBST.(POPTOP.(INPUT), LSPNTR.(S))
O'E
NEWTOP.(POPTOP.(INPUT), LSPNTR.(S))
E'L
T'O CHANGE
E'N
EXTERNAL FUNCTION (LST)
NORMAL MODE IS INTEGER
ENTRY TO TPRINT.
SA = SEQRDR.(LST)
LIST.(OUT)
NEXT = SEQLR.(SA,FA)
READ W'R FA .G. 0, T'O P
W'R FA .E. 0, T'O B
POINT = NEWBOT.(NEXT, OUT)
W'R SA .L. 0, MRKNEG.(POINT)
T'O READ
TXTPRT.(OUT,0)
B SEQLL.(SA,FA)
NEXT = SEQLR.(SA,FA)
MORE W'R TOP.(NEXT) .E. $=$
TXTPRT.(NEXT,0)
T'O MORE
E'L
W'R FA .G. 0, T'O DONE
PRINT COMMENT $ $
SB = SEQRDR.(NEXT)
TERM = SEQLR.(SB,FB)
MEHR W'R FB .L. 0
PRINT ON LINE FORMAT NUMBER, TERM
V'S NUMBER = $13 $
T'O MEHR
E'L
W'R FB .G. 0, T'O MORE
TXTPRT.(TERM,0)
T'O MEHR
DONE E'N
EXTERNAL FUNCTION (LST,TAPE)
NORMAL MODE IS INTEGER
ENTRY TO LPRINT.
BLANK = $ 5 $
BEGIN EXECUTE PLACE.(TAPE,0)
LEFTP = 606074606060K
RIGHTP = 606034606060K
BOTH = 607460603460K
EXECUTE NEWTOP.(SEQRDR.(LST), LIST.(STACK))
S=POPTOP.(STACK)
EXECUTE PLACE.(LEFTP,1)
NEXT WORD = SEQLR.(S,FLAG)
W'R FLAG .L. 0
EXECUTE PLACE.(WORD,1)
W'R S .G. 0, PLACE.(BLANK,1)
T'O NEXT
O'R W'R FLAG .G. 0
EXECUTE PLACE.(RIGHTP,1)
W'R LISTMT.(STACK) .E. 0, T'O DONE
S = POPTOP.(STACK)
T'O NEXT
OTHERWISE
W'R LISTMT.(WORD) .E. 0
EXECUTE PLACE.(BOTH, 1)
T'O NEXT
OTHERWISE
EXECUTE NEWTOP.(S,STACK)
S = SEQRDR.(WORD)
T'O BEGIN
E'L
DONE E'L
EXECUTE PLACE.(0,-1)
EXECUTE IRALST.(STACK)
FUNCTION RETURN LST
END OF FUNCTION
EXTERNAL FUNCTION (CAND,S)
NORMAL MODE IS INTEGER
DIMENSION FIRST(5), SECOND(5)
ENTRY TO TESTS.
STORE = S
READER = SEQRDR.(CAND)
T'H ONE, FOR I = 0,1, I .G. 100
FIRST(I) = SEQLR.(READER, FR)
ONE W'R READER .G. 0, T'O ENDONE
SEQLL.(S,F)
ENDONE T'H TWO, FOR J = 0,1, J .G. 100
SECOND(J) = SEQLR.(S,F)
TWO W'R S .G. 0, T'O ENDTWO
ENDTWO W'R I .NE. J, F'N 0
T'H LOOK, FOR K=0,1, K .G. J
LOOK W'R FIRST(K) .NE. SECOND(K), F'N 0
EQL = SEQLR.(READER,FR)
W'R EQL .NE. $=$
SEQLL.(READER, FR)
F'N READER
O'E
POINT = LNKL.(STORE)
T'H DELETE, FOR K=0,1, K .G. J
REMOVE.(LSPNTR.(STORE))
DELETE SEQLR.(STORE, F)
INSRT NEW = SEQLR.(READER,FR)
POINT = NEWTOP.(NEW,POINT)
MRKNEG.(POINT)
W'R READER .L. 0
T'O INSRT
MRKPOS.(POINT)
F'N READER
E'L
E'N
EXTERNAL FUNCTION (A,B)
NORMAL MODE IS INTEGER
ENTRY TO FRBCD.
NUMBER W'R LNKL.(A) .E. 0, T'O NUMBER
B=A
F'N 0
K = A / 262144
B = BCDIT.(K)
F'N 0
E'N
ELIZA MAD
NORMAL MODE IS INTEGER
DIMENSION KEY(32), MYTRAN(4)
INITAS.(0)
PRINT COMMENT $WHICH SCRIPT DO YOU WISH TO PLAY$
READ FORMAT SNUMB, SCRIPT
LIST.(TEST)
LIST.(INPUT)
LIST.(OUTPUT)
LIST.(JUNK)
LIMIT=1
MLST LSSCPY.(TREAD.(INPUT, SCRIPT), JUNK)
MTLIST.(INPUT)
T'H MLST, FOR I=1,1, I .G. 4
LIST.(MYTRAN(I))
MINE=0
LIST.(MYLIST)
KEYLST T'H KEYLST, FOR I=0,1, I .G. 32
LIST.(KEY(I))
BEGIN MTLIST.(INPUT)
NODLST.(INPUT)
LISTRD.(INPUT, SCRIPT)
W'R LISTMT.(INPUT) .E. 0
TXTPRT.(JUNK,0)
MTLIST.(JUNK)
T'O START
E'L
W'R TOP.(INPUT) .E. $NONE$
NEWTOP.(LSSCPY.(INPUT,LIST.(9)), KEY(32))
T'O BEGIN
O'R W'R TOP.(INPUT) .E. $MEMORY$
POPTOP.(INPUT)
MEMORY = POPTOP.(INPUT)
T'H MEM, FOR I = 1,1, I .G. 4
LSSCPY.(POPTOP.(INPUT), MYTRAN(I))
T'O BEGIN
O'E
NEWBOT.(LSSCPY.(INPUT,LIST.(9)), KEY(HASH.(TOP.(INPUT),5)))
T'O BEGIN
E'L
START TREAD.(MTLIST.(INPUT),0)
KEYWRD=0
PREDNC=0
LIMIT = LIMIT+1
W'R LIMIT .E. 5, LIMIT=1
W'R LISTMT.(INPUT) .E. 0, T'O ENDPLA
IT=0
W'R TOP.(INPUT) .E. $+$
CHANGE.(KEY, MYTRAN)
T'O START
E'L
W'R TOP.(INPUT) .E. $S$, T'O NEWLST
S=SEQRDR.(INPUT)
NOTYET W'R S .L. 0
SEQLR.(S,F)
T'O NOTYET
O'E
WORD = SEQLR.(S,F)
W'R WORD .E. $.$ .OR. WORD .E. $,$ .OR. WORD .E. $BUT$
W'R IT .E. 0
NULSTL.(INPUT, LSPNTR.(S),JUNK)
MTLIST.(JUNK)
T'O NOTYET
O'E
NULSTR.(INPUT, LSPNTR.(S),JUNK)
MTLIST.(JUNK)
T'O ENDTXT
E'L
E'L
W'R F .G. 0, T'O ENDTXT
I = HASH.(WORD,5)
SCANER = SEQRDR.(KEY(I))
SF=0
T'H SEARCH, FOR J=0,0, SF .G. 0
SEARCH CAND = SEQLR.(SCANER, SF)
W'R SF .G. 0, T'O NOTYET
W'R TOP.(CAND) .E. WORD, T'O KEYFND
KEYFND READER = TESTS.(CAND,S)
W'R READER .E. 0, T'O NOTYET
W'R LSTNAM.(CAND) .NE. 0
DL = LSTNAM.(CAND)
SEQ W'R S .L. 0
SEQLR.(S,F)
T'O SEQ
O'E
NEWTOP.(DL,LSPNTR.(S))
E'L
O'E
E'L
NEXT SEQLR.(READER, FR)
W'R FR .G. 0, T'O NOTYET
PLCKEY W'R IT .E. 0 .AND. FR .E. 0
IT = READER
KEYWRD = WORD
O'R W'R FR .L. 0 .AND. NEXT .G. PREDNC
PREDNC = NEXT
NEXT = SEQLR.(READER,FR)
T'O PLCKEY
O'E
T'O NOTYET
E'L
T'O NOTYET
ENDTXT W'R IT .E. 0
W'R LIMIT .E. 4 .AND. LISTMT.(MYLIST) .NE. 0
OUT = POPTOP.(MYLIST)
TXTPRT.(OUT,0)
IRALST.(OUT)
T'O START
O'E
ES=BOT.(TOP.(KEY(32)))
T'O TRY
E'L
O'R W'R KEYWRD .E. MEMORY
I = HASH.(BOT.(INPUT),2)+1
NEWBOT.(REGEL.(MYTRAN(I), INPUT, LIST.(MINE)), MYLIST)
SEQLL.(IT,FR)
T'O MATCH
O'E
SEQLL.(IT,FR)
MATCH ES = SEQLR.(IT,FR)
W'R TOP.(ES) .E. $=$
S = SEQRDR.(ES)
SEQLR.(S,F)
WORD = SEQLR.(S,F)
I = HASH.(WORD,5)
SCANER = SEQRDR.(KEY(I))
SCAN ITS = SEQLR.(SCANER,F)
W'R F .G. 0, T'O NOMACH(LIMIT)
W'R WORD .E. TOP.(ITS)
S=SEQRDR.(ITS)
SCANI ES = SEQLR.(S,F)
W'R F .NE. 0, T'O SCANI
IT=S
T'O TRY
O'E
T'O SCAN
E'L
E'L
W'R FR .G. 0, T'O NOMACH(LIMIT)
TRY W'R YMATCH.(TOP.(ES),INPUT, MTLIST.(TEST)) .E. 0, T'O MATCH
ESRDR = SEQRDR.(ES)
SEQLR.(ESRDR, ESF)
POINT = SEQLR.(ESRDR,ESF)
POINTR = LSPNTR.(ESRDR)
W'R ESF .E. 0
NEWBOT.(1,POINTR)
TRANS = POINT
T'O HIT
O'E
T'H FNDHIT, FOR I=0,1, I .G. POINT
FNDHIT TRANS = SEQLR.(ESRDR,ESF)
W'R ESF .G. 0
SEQLR.(ESRDR, ESF)
TRANS = SEQLR.(ESRDR, ESF)
SUBST.(1,POINTR)
T'O HIT
O'E
SUBST.(POINT+1,POINTR)
T'O HIT
E'L
E'L
HIT TXTPRT.(ASSMBL.(TRANS, TEST, MTLIST.(OUTPUT)),0)
T'O START
E'L
NEWLST POPTOP.(INPUT)
NEWBOT.(LSSCPY.(INPUT,LIST.(9)), KEY(HASH.(TOP.(INPUT),5)))
T'O START
ENDPLA PRINT COMMENT $WHAT IS TO BE THE NUMBER OF THE NEW SCRIPT$
READ FORMAT SNUMB, SCRIPT
LPRINT.(INPUT, SCRIPT)
NEWTOP.(MEMORY, MTLIST.(OUTPUT))
NEWTOP.($MEMORY$, OUTPUT)
DUMP T'H DUMP, FOR I=1,1, I .G. 4
NEWBOT.(MYTRAN(I), OUTPUT)
LPRINT.(OUTPUT, SCRIPT)
MTLIST.(OUTPUT)
POPMOR T'H WRITE, FOR I=0,1, I .G. 32
W'R LISTMT.(KEY(I)) .E. 0, T'O WRITE
LPRINT.(POPTOP.(KEY(I)),SCRIPT)
T'O POPMOR
WRITE CONTINUE
LPRINT.(MTLIST.(INPUT), SCRIPT)
EXIT.
NOMACH(1) PRINT COMMENT $PLEASE CONTINUE $
T'O START
NOMACH(2) PRINT COMMENT $HMMM $
T'O START
NOMACH(3) PRINT COMMENT $GO ON, PLEASE $
T'O START
NOMACH(4) PRINT COMMENT $I SEE $
T'O START
VECTOR VALUES SNUMB = $13 $
E'M
ELIZA Chatbot Output Example
When you compile and run the ELIZA script in the MAD IDE, it interacts through the console.
PLEASE INSTRUCT ME
> HELLO, I AM FEELING SAD TODAY
HMMM
> WHY DO YOU SAY THAT?
PLEASE CONTINUE
> I NEED HELP
I SEE
Original MAD Code: External Functions
MAD supports modularity via external functions. Variables are typically passed by reference, and arrays are dimensioned using the DIMENSION keyword.
EXTERNAL FUNCTION (KEY, MYTRAN)
NORMAL MODE IS INTEGER
ENTRY TO CHANGE.
LIST.(INPUT)
VECTOR VALUES G(1) = $TYPE$, $SUBST$, $APPEND$, $ADDS,
$START$, $RANKS, $DISPLAS
VECTOR VALUES SNUMB$ = $13 $
FIT=0
CHANGE PRINT COMMENT $ PLEASE INSTRUCT ME$
LISTRD.(MTLIST.(INPUT),0)
JOB = POPTOP.(INPUT)
THROUGH IDENT, FOR J = 1,1, J .G. 7
IDENT WHENEVER G(J) .E. JOB, TRANSFER TO THEMA
PRINT COMMENT $CHANGE NOT RECOGNIZED$
TRANSFER TO CHANGE
THEMA WHENEVER J .E. 5
FUNCTION RETURN IRALST.(INPUT)