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.

MAD IDE Interface

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.

Note: Labels are historically restricted to 6 characters and padded to column 11. MAD IDE automatically pads line labels to column 11 for you.
           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:

AbbreviationExpansion
W'RWHENEVER
O'EOTHERWISE
E'LEND OF CONDITIONAL
T'HTHROUGH
T'OTRANSFER TO
F'NFUNCTION RETURN
E'NEND OF FUNCTION

How to Run MAD Code

To run any MAD code inside the MAD IDE, follow these steps:

  1. Open your .mad file using File -> Open, or create a new file and paste your code.
  2. Make sure you have built the underlying compiler first by clicking Tools -> Build MAD Compiler.
  3. Click the ▶ Run button in the top toolbar or press F5.
  4. 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)