home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / misc / bcpl.ark / BCPL.B next >
Encoding:
Text File  |  1988-11-27  |  74.6 KB  |  2,721 lines

  1. // BCPL for Zilog Z80.
  2. // S. Kelley,     Autumn 1987.
  3.  
  4. SECTION "LEX"
  5. GET "COMPHDR"
  6.  
  7. STATIC $( 
  8. CH=?; CHBUF=?; CHCOUNT=?; LINECOUNT=?
  9. GETP=?; SKIPTAG=?; NAMETABLE=?
  10. $)
  11.  
  12. LET START() BE
  13. $( LET MAXMEM, TOTALERRS = 0, 0
  14.    LET TREESIZE, TREEBASE, A = ?, ?, ?
  15.  
  16.    SOURCESTREAM := INPUT()
  17.    OCODE := (OUTPUT() = CON) -> FINDOUTPUT("BCPL.OUT"), OUTPUT()
  18.   
  19.    TREESIZE := MAXVEC()-250 // Save space for 3 get files to be opened
  20.    TREEBASE := GETVEC(TREESIZE)
  21.  
  22.    SELECTOUTPUT(CON)
  23.    WRITEF("*NZ80 BCPL Compiler starting....*N*
  24.             *Workspace available is %N words.*N*N", TREESIZE)
  25.  
  26.    UNLESS SOURCESTREAM DO ABORT("Can't open input file")
  27.    UNLESS OCODE        DO ABORT("Can't open output file")
  28.  
  29.    SELECTOUTPUT(OCODE)
  30.    BINARYOUTPUT(TRUE)
  31.    WRITE1(S.STARTFILE)
  32.    SELECTOUTPUT(CON)
  33.  
  34.    TREETOP := TREEBASE+TREESIZE
  35.    LINECOUNT := 1
  36.  
  37.    $( TREEP := TREEBASE
  38.       A := FORMTREE()
  39.       TOTALERRS := TOTALERRS+REPORTCOUNT
  40.       TREEPMAX := TREEP
  41.  
  42.       IF REPORTCOUNT=0 THEN
  43.            $( SELECTOUTPUT(OCODE)
  44.               COMPILEAE(A)
  45.               TOTALERRS := TOTALERRS + REPORTCOUNT
  46.               SELECTOUTPUT(CON)  
  47.            $)
  48.  
  49.       IF TREEPMAX>MAXMEM THEN MAXMEM := TREEPMAX
  50.      
  51.    $) REPEATUNTIL A=0
  52.  
  53.    WRITEF("Workspace used was %n words.*N", MAXMEM-TREEBASE)
  54.    WRITEF(TOTALERRS->"%N errors.*N","No errors.*N", TOTALERRS)
  55.  
  56.  
  57.    ENDREAD()
  58.    SELECTOUTPUT(OCODE)
  59.    WRITE1(S.ENDFILE)
  60.    TEST TOTALERRS=0 THEN ENDWRITE()
  61.                     ELSE REMOVEOUTPUT() // delete a faulty output file
  62. $)
  63.  
  64. AND NEXTSYMB() BE
  65. $(1 NLPENDING := FALSE
  66.  
  67.     IF INTKEY() THEN ABORT("Interrupted") // Abort on ctrl-C
  68.  
  69. $(2 IF '0'<=CH<='9' THEN
  70.         $( SYMB := S.NUMBER
  71.            READNUMBER(10)
  72.            RETURN
  73.         $)
  74.  
  75.     IF 'A'<=CH<='Z' THEN
  76.         $( RDTAG(CH)
  77.            SYMB := LOOKUPWORD()
  78.            UNLESS SYMB=S.GET RETURN
  79.            // go to the include file....
  80.            NEXTSYMB()
  81.            UNLESS SYMB=S.STRING THEN SYNREPORT("Bad GET")
  82.  
  83.            $( LET NEWSTREAM = FINDINPUT(@(H2!WORDNODE))
  84.               UNLESS NEWSTREAM DO SYNREPORT("Cannot open %S", @(H2!WORDNODE))
  85.               GETP := LIST5(GETP, SOURCESTREAM, LINECOUNT, CH, WORDNODE)
  86.               LINECOUNT := 1
  87.               SOURCESTREAM := NEWSTREAM
  88.               SELECTINPUT(SOURCESTREAM)
  89.               RCH()
  90.               LOOP
  91.            $)
  92.         $)
  93.  
  94.     SWITCHON CH INTO
  95.  
  96. $(S CASE '*N': LINECOUNT := LINECOUNT + 1
  97.                NLPENDING := TRUE  // IGNORABLE CHARACTERS
  98.     CASE '*T':
  99.     CASE '*S': RCH() REPEATWHILE CH='*S'
  100.                LOOP
  101.  
  102.     CASE '$': RCH()
  103.               IF CH='$' | CH='<' | CH='>' DO
  104.               $( LET K = CH
  105.                  RDTAG('<')
  106.                  SYMB := LOOKUPWORD()
  107.  
  108.                  IF K='>' DO
  109.                  $( IF SKIPTAG=WORDNODE DO SKIPTAG := 0
  110.                     LOOP
  111.                  $)
  112.  
  113.                  UNLESS SKIPTAG=0 LOOP
  114.  
  115.                  IF K='$' DO
  116.                  $( H1!WORDNODE := SYMB=S.TRUE -> S.FALSE, S.TRUE
  117.                     LOOP
  118.                  $)
  119.  
  120.                  // K must be '<'
  121.                  IF SYMB=S.TRUE LOOP
  122.                  SKIPTAG := WORDNODE
  123.                  UNTIL SKIPTAG=0 DO NEXTSYMB()
  124.                  RETURN
  125.               $)
  126.  
  127.               UNLESS CH='(' | CH=')' DO SYNREPORT("'$' out of context")
  128.               SYMB := CH='(' -> S.LSECT, S.RSECT
  129.               RDTAG('$')
  130.               LOOKUPWORD()
  131.               RETURN
  132.  
  133.     CASE '[':
  134.     CASE '(': SYMB := S.LPAREN; BREAK
  135.  
  136.     CASE ']':
  137.     CASE ')': SYMB := S.RPAREN; BREAK
  138.  
  139.     CASE '#':
  140.          SYMB := S.NUMBER
  141.          RCH()
  142.          IF '0'<=CH<='7' DO $(        READNUMBER(8);  RETURN  $)
  143.          IF CH='B'       DO $( RCH(); READNUMBER(2);  RETURN  $)
  144.          IF CH='O'       DO $( RCH(); READNUMBER(8);  RETURN  $)
  145.          IF CH='X'       DO $( RCH(); READNUMBER(16); RETURN  $)
  146.          SYNREPORT("Bad number")
  147.  
  148.     CASE '?': SYMB := S.QUERY;     BREAK
  149.     CASE '+': SYMB := S.PLUS;      BREAK
  150.     CASE ',': SYMB := S.COMMA;     BREAK
  151.     CASE ';': SYMB := S.SEMICOLON; BREAK
  152.     CASE '@': SYMB := S.LV;        BREAK
  153.     CASE '&': SYMB := S.LOGAND;    BREAK
  154.     CASE '|': SYMB := S.LOGOR;     BREAK
  155.     CASE '=': SYMB := S.EQ;        BREAK
  156.     CASE '!': SYMB := S.VECAP;     BREAK
  157.     CASE '%': SYMB := S.BYTEAP;    BREAK
  158.     CASE '**':SYMB := S.MULT;      BREAK
  159.  
  160.     CASE '/':
  161.          RCH()
  162.          IF CH='\' DO $( SYMB := S.LOGAND; BREAK $)
  163.          IF CH='/' DO
  164.             $( RCH() REPEATUNTIL CH='*N' | CH=ENDSTREAMCH
  165.                LOOP  $)
  166.  
  167.          UNLESS CH='**' DO $( SYMB := S.DIV; RETURN  $)
  168.  
  169.          $( RCH()
  170.             IF CH='**' DO
  171.                $( RCH() REPEATWHILE CH='**'
  172.                   IF CH='/' BREAK  $)
  173.             IF CH='*N' DO LINECOUNT := LINECOUNT+1
  174.             IF CH=ENDSTREAMCH DO SYNREPORT("'**/' missing")
  175.          $) REPEAT
  176.  
  177.          RCH()
  178.          LOOP
  179.  
  180.     CASE '\': RCH()
  181.               IF CH='/' DO $( SYMB := S.LOGOR;  BREAK $)
  182.               IF CH='=' DO $( SYMB := S.NE;     BREAK $)
  183.               SYMB := S.NOT
  184.               RETURN
  185.  
  186.     CASE '~': RCH()
  187.               IF CH='=' DO $( SYMB := S.NE;     BREAK $)
  188.               SYMB := S.NOT
  189.               RETURN
  190.  
  191.     CASE '<': RCH()
  192.               IF CH='=' DO $( SYMB := S.LE;     BREAK $)
  193.               IF CH='<' DO $( SYMB := S.LSHIFT; BREAK $)
  194.               SYMB := S.LS
  195.               RETURN
  196.  
  197.     CASE '>': RCH()
  198.               IF CH='=' DO $( SYMB := S.GE;     BREAK $)
  199.               IF CH='>' DO $( SYMB := S.RSHIFT; BREAK $)
  200.               SYMB := S.GR
  201.               RETURN
  202.  
  203.     CASE '-': RCH()
  204.               IF CH='>' DO $( SYMB := S.COND; BREAK  $)
  205.               SYMB := S.MINUS
  206.               RETURN
  207.  
  208.     CASE ':': RCH()
  209.               IF CH='=' DO $( SYMB := S.ASS; BREAK  $)
  210.               IF CH=':' DO $( SYMB := S.OF;  BREAK  $)
  211.               SYMB := S.COLON
  212.               RETURN
  213.  
  214.  
  215.     CASE '"':
  216.            $( LET CHARV = TREEP+H2
  217.               LET CHARP = 0
  218.               RCH()
  219.               UNTIL CH = '"' DO
  220.               $( IF CHARP=255 DO SYNREPORT("String too long")
  221.                  CHARP := CHARP + 1
  222.                  IF (CHARV+(CHARP/BYTESPERWORD))>TREETOP BREAK
  223.                  CHARV%CHARP := STRCH()
  224.                  RCH()
  225.               $)
  226.               RCH()
  227.               CHARV%0 := CHARP
  228.               H1!TREEP := S.STRING
  229.               SYMB:=S.STRING
  230.               WORDNODE := NEWVEC((CHARP/BYTESPERWORD)+1)
  231.               RETURN
  232.            $)
  233.  
  234.     CASE '*'':RCH()
  235.               DECVAL := STRCH()
  236.               RCH()
  237.               SYMB := S.NUMBER
  238.               UNLESS CH='*'' DO SYNREPORT("Bad char")
  239.               BREAK
  240.  
  241.     CASE ENDSTREAMCH:
  242.     CASE '.': IF GETP=0 DO $( SYMB := S.END
  243.                               RETURN   $)
  244.               ENDREAD()
  245.               SOURCESTREAM := H2!GETP
  246.               SELECTINPUT(SOURCESTREAM)
  247.               LINECOUNT := H3!GETP
  248.               CH := H4!GETP
  249.               GETP := H1!GETP
  250.               LOOP
  251.  
  252.     DEFAULT: CH := '*S'
  253.              SYNREPORT("Illegal character")
  254. $)S
  255.  
  256. $)2 REPEAT
  257.  
  258.     RCH()
  259. $)1
  260.  
  261.  
  262. AND LOOKUPWORD() = VALOF
  263. $(1 LET CHARV = TREEP+H3
  264.     LET LENGTH = CHARV%0
  265.     LET HASHVAL = (CHARV%1+CHARV%LENGTH) & (NAMETABLESIZE-1)
  266.                   // Nametablesize must be a power of two.
  267.     LET I = 0
  268.  
  269.     WORDNODE := NAMETABLE!HASHVAL
  270.  
  271.     UNTIL WORDNODE=0 | I>LENGTH DO
  272.           TEST (WORDNODE+2)%I=CHARV%I
  273.             THEN I := I+1
  274.             ELSE WORDNODE, I := H2!WORDNODE, 0
  275.  
  276.     IF WORDNODE=0 DO // string is already in the correct place
  277.       $( WORDNODE := NEWVEC((LENGTH/BYTESPERWORD)+2)
  278.          WORDNODE!0, WORDNODE!1 := S.NAME, NAMETABLE!HASHVAL
  279.          NAMETABLE!HASHVAL := WORDNODE  $)
  280.  
  281.     RESULTIS H1!WORDNODE  $)1
  282.  
  283.  
  284. AND DECLSYSWORDS() BE
  285. $( LET D(WORDS, CODEP) BE
  286.    $( LET I = 1
  287.       LET LENGTH = 0
  288.       $( LET CH = WORDS%I
  289.          LET CHARV = TREEP+H3
  290.          TEST CH='/'
  291.              THEN $( IF LENGTH=0 RETURN
  292.                      CHARV%0 := LENGTH
  293.                      LOOKUPWORD()
  294.                      H1!WORDNODE := !CODEP
  295.                      CODEP := CODEP + 1
  296.                      LENGTH := 0  $)
  297.              ELSE $( LENGTH := LENGTH + 1
  298.                      CHARV%LENGTH := CH  $)
  299.          I := I + 1
  300.       $) REPEAT
  301.   $)
  302.  
  303.     D("AND/ABS/*
  304.       *BE/BREAK/BY/*
  305.       *CASE/*
  306.       *DO/DEFAULT/*
  307.       *EQ/EQV/ELSE/ENDCASE/*
  308.       *FALSE/FOR/FINISH/*
  309.       *GOTO/GE/GR/GLOBAL/GET/*
  310.       *IF/INTO/*
  311.       *LET/LV/LE/LS/LOGOR/LOGAND/LOOP/LSHIFT//",
  312.  
  313.       TABLE
  314.  
  315.       S.AND,S.ABS,
  316.       S.BE,S.BREAK,S.BY,
  317.       S.CASE,
  318.       S.DO,S.DEFAULT,
  319.       S.EQ,S.EQV,S.OR,S.ENDCASE,
  320.       S.FALSE,S.FOR,S.FINISH,
  321.       S.GOTO,S.GE,S.GR,S.GLOBAL,S.GET,
  322.       S.IF,S.INTO,
  323.       S.LET,S.LV,S.LE,S.LS,S.LOGOR,S.LOGAND,S.LOOP,S.LSHIFT)
  324.  
  325.     D("MANIFEST/*
  326.       *NE/NOT/NEQV/NEEDS/*
  327.       *OR/OF/*
  328.       *RESULTIS/RETURN/REM/RSHIFT/RV/*
  329.       *REPEAT/REPEATWHILE/REPEATUNTIL/*
  330.       *SWITCHON/STATIC/SECTION/SLCT/*
  331.       *TO/TEST/TRUE/THEN/TABLE/*
  332.       *UNTIL/UNLESS/*
  333.       *VEC/VALOF/*
  334.       *WHILE/*
  335.       *$//",
  336.  
  337.       TABLE
  338.  
  339.       S.MANIFEST,
  340.       S.NE,S.NOT,S.NEQV,S.NEEDS,
  341.       S.OR,S.OF,
  342.       S.RESULTIS,S.RETURN,S.REM,S.RSHIFT,S.RV,
  343.       S.REPEAT,S.REPEATWHILE,S.REPEATUNTIL,
  344.       S.SWITCHON,S.STATIC,S.SECTION,S.SLCT,
  345.       S.TO,S.TEST,S.TRUE,S.DO,S.TABLE,
  346.       S.UNTIL,S.UNLESS,
  347.       S.VEC,S.VALOF,
  348.       S.WHILE,
  349.       0)
  350.  
  351.      NULLTAG := WORDNODE  
  352. $)
  353.  
  354. AND RCH() BE
  355. $( CH := RDCH()
  356.    IF CH = ENDSTREAMCH RETURN
  357.    CHCOUNT := CHCOUNT + 1
  358.    CHBUF%(CHCOUNT&63) := CH  
  359.    IF 'a'<=CH<='z' THEN CH := CH + ('A'-'a') // Convert whole prog to UC
  360. $)
  361.  
  362.  
  363. AND RDTAG(CHAR1) BE
  364.     $( LET CHARP = 1
  365.        LET CHARV = TREEP+H3
  366.        CHARV%1 := CHAR1 // build the string on the top
  367.                         // of the tree, so it's
  368.                         // in the right place
  369.        $( RCH()
  370.           UNLESS 'A'<=CH<='Z' | '0'<=CH<='9' | CH='.' BREAK
  371.           CHARP := CHARP+1
  372.           IF (CHARV+(CHARP/BYTESPERWORD))>TREETOP BREAK
  373.           CHARV%CHARP := CH
  374.        $)
  375.           REPEAT
  376.  
  377.        CHARV%0 := CHARP
  378.     $)
  379.  
  380.  
  381.  
  382. AND READNUMBER(RADIX) BE
  383.     $( LET D = VALUE(CH)
  384.        DECVAL := D
  385.        IF D>=RADIX DO SYNREPORT("Bad number")
  386.  
  387.        $( RCH()
  388.  
  389.           D := VALUE(CH)
  390.           IF D>=RADIX RETURN
  391.           DECVAL := RADIX*DECVAL + D  $) REPEAT
  392.     $)
  393.  
  394.  
  395. AND VALUE(CH) = '0'<=CH<='9' -> CH-'0',
  396.                 'A'<=CH<='F' -> CH+(10-'A'),
  397.                 100
  398.  
  399. AND STRCH() = VALOF
  400. $( // Read in a char from a string or char constant 
  401.    IF CH < '*S' DO // Rather ASCII specific 
  402.              SYNREPORT("Unescaped control char in string or char")
  403.   
  404.    UNLESS CH ='**' RESULTIS CHBUF%(CHCOUNT&63) // Char without LC->UC
  405.  
  406.    RCH()
  407.    TEST CH='*N' | CH='*S' | CH='*T' THEN // Continuation
  408.        $( WHILE CH='*N' | CH='*S' | CH='*T' DO
  409.                $( IF CH='*N' DO LINECOUNT := LINECOUNT + 1
  410.                   RCH()
  411.                $) 
  412.           UNLESS CH='**' DO SYNREPORT("Bad string continuation")
  413.           RCH()
  414.           RESULTIS STRCH()
  415.        $)
  416.    ELSE
  417.        $( // Escape
  418.           IF '0'<=CH<='9' RESULTIS (VALUE(CH)*8) + READOCTALORHEX(8)
  419.           SWITCHON CH INTO
  420.               $( CASE 'T': RESULTIS '*T'
  421.                  CASE 'S': RESULTIS '*S'
  422.                  CASE 'N': RESULTIS '*N'
  423.                  CASE 'E': RESULTIS '*E'
  424.                  CASE 'B': RESULTIS '*B'
  425.                  CASE 'P': RESULTIS '*P'
  426.                  CASE 'C': RESULTIS '*C'
  427.                  CASE 'X': RESULTIS READOCTALORHEX(16)
  428.                  DEFAULT:  RESULTIS CHBUF%(CHCOUNT&63)
  429.               $)
  430.        $)
  431. $)             
  432.  
  433. AND READOCTALORHEX(RADIX) = VALOF
  434.     $( LET ANSWER = 0
  435.        FOR J = 1 TO 2 DO
  436.           $( LET VALCH = VALUE(VALOF $( RCH(); RESULTIS CH $) )
  437.              IF VALCH > RADIX DO SYNREPORT("Bad char constant")
  438.              ANSWER:=ANSWER*RADIX + VALCH
  439.           $)
  440.        RESULTIS ANSWER
  441.     $)
  442.  
  443. AND FORMTREE() =  VALOF
  444. $(  LET CB = VEC 63/BYTESPERWORD
  445.     LET NT = VEC NAMETABLESIZE
  446.     LET R = ?
  447.   
  448.     CHBUF := CB // Empty chbuf
  449.     FOR I = 0 TO 63 DO CHBUF%I := 0
  450.  
  451.     NAMETABLE := NT // clear hash table
  452.     FOR I = 0 TO NAMETABLESIZE DO NAMETABLE!I := 0
  453.  
  454.     CHCOUNT, SKIPTAG, GETP, REPORTCOUNT := 0,0,0,0
  455.  
  456.     RCH(); IF CH=ENDSTREAMCH RESULTIS 0
  457.  
  458.     DECLSYSWORDS() // put in reserved words
  459.  
  460.     REC.P1, REC.P2, REC.L := LEVEL1(), LEVEL2(), L
  461.  
  462.  L: NEXTSYMB()
  463.     TEST SYMB=S.SECTION THEN
  464.        $( LET A = ?
  465.           NEXTSYMB(); A:=RBEXP()
  466.           UNLESS H1!A=S.STRING SYNREPORT("Bad section name")
  467.           R := LIST3(S.SECTION, A, RDBLOCKBODY())
  468.        $)
  469.     ELSE  R := RDBLOCKBODY()
  470.  
  471.     UNLESS SYMB=S.END DO SYNREPORT("Incorrect termination")
  472.  
  473.     FOR I = 0 TO NAMETABLESIZE DO // clear hash chains for TRANS
  474.        $( LET P = NAMETABLE!I
  475.           UNTIL P=0 DO
  476.             $( LET T = H2!P
  477.                H2!P := 0
  478.                P := T
  479.             $)
  480.        $)
  481.  
  482.     RESULTIS R        
  483. $)
  484.  
  485. AND ABORT(S) BE 
  486. $( SELECTOUTPUT(OCODE) // delete a partial output file
  487.    REMOVEOUTPUT()
  488.    SELECTOUTPUT(CON)
  489.    WRITEF("Aborting. %s.*n*n", S)
  490.    FINISH
  491. $)
  492.  
  493. AND SYNREPORT(S, A) BE
  494. $( REPORTCOUNT := REPORTCOUNT + 1
  495.    IF REPORTCOUNT = REPORTMAX THEN
  496.                      WRITES("*NFurther errors suppressed.*N*N")
  497.    IF REPORTCOUNT < REPORTMAX THEN
  498.        $( WRITEF("*NSyntax error:    %F", S, A)
  499.           WRITEF(".*NNear line %N ", LINECOUNT)
  500.           IF GETP THEN WRITEF("of %s", @(H2!(H5!GETP)))
  501.           WRITES("*N...")
  502.           $( LET P = CHCOUNT-63
  503.              $( LET K = CHBUF%(P&63)
  504.                 UNLESS K=0 DO WRCH(K)
  505.                 P := P+1
  506.              $) REPEATUNTIL P=CHCOUNT
  507.           $)
  508.           NEWLINE() 
  509.        $)
  510.    NLPENDING := FALSE
  511.  
  512.    UNTIL SYMB=S.LSECT | SYMB=S.RSECT |
  513.          SYMB=S.LET | SYMB=S.AND |
  514.          SYMB=S.END | NLPENDING DO NEXTSYMB()
  515.    LONGJUMP(REC.P1, REC.P2, REC.L)   
  516. $)
  517.  
  518.  
  519. .
  520.  
  521. //   SYN
  522. SECTION "SYN"
  523.  
  524. GET "COMPHDR"
  525.  
  526. LET NEWVEC(N) = VALOF
  527.     $( LET A = TREEP
  528.        TREEP := TREEP + N + 1;
  529.        IF TREEP>TREETOP DO ABORT("Out of workspace")
  530.        RESULTIS A  $)
  531.  
  532. AND LIST2(X, Y) = VALOF
  533.     $( LET P = NEWVEC(1)
  534.        P!0, P!1 := X, Y
  535.        RESULTIS P   $)
  536.  
  537. AND LIST3(X, Y, Z) = VALOF
  538.     $( LET P = NEWVEC(2)
  539.        MEMCPY(@X, P, 3)
  540.        RESULTIS P     $)
  541.  
  542. AND LIST4(X, Y, Z, T) = VALOF
  543.     $( LET P = NEWVEC(3)
  544.        MEMCPY(@X, P, 4)
  545.        RESULTIS P   $)
  546.  
  547. AND LIST5(X, Y, Z, T, U) = VALOF
  548.     $( LET P = NEWVEC(4)
  549.        MEMCPY(@X, P, 5)
  550.        RESULTIS P   $)
  551.  
  552. AND LIST6(X, Y, Z, T, U, V) = VALOF
  553.     $( LET P = NEWVEC(5)
  554.        MEMCPY(@X, P, 6)
  555.        RESULTIS P  $)
  556.  
  557. AND RDBLOCKBODY() = VALOF
  558. $(1 LET P1, P2, L = REC.P1, REC.P2, REC.L
  559.     LET A = 0
  560.  
  561.     REC.P1, REC.P2, REC.L := LEVEL1(), LEVEL2(), RECOVER
  562.  
  563.     IGNORE(S.SEMICOLON)
  564.  
  565.     SWITCHON SYMB INTO
  566.     $(S CASE S.MANIFEST:
  567.         CASE S.STATIC:
  568.         CASE S.GLOBAL:
  569.             $(  LET OP = SYMB
  570.                 NEXTSYMB()
  571.                 A := RDSECT(RDCDEFS)
  572.                 A := LIST3(OP, A, RDBLOCKBODY())
  573.                 ENDCASE  $)
  574.  
  575.  
  576.         CASE S.LET: NEXTSYMB()
  577.                     A := RDEF()
  578.            RECOVER: WHILE SYMB=S.AND DO
  579.                        $( NEXTSYMB()
  580.                           A := LIST3(S.AND, A, RDEF())  $)
  581.                     A := LIST3(S.LET, A, RDBLOCKBODY())
  582.                     ENDCASE
  583.  
  584.         CASE S.NEEDS: NEXTSYMB()
  585.                       A := RBEXP()
  586.                       UNLESS H1!A = S.STRING THEN
  587.                                           SYNREPORT("Bad NEEDS")
  588.                       A := LIST3(S.NEEDS, A, RDBLOCKBODY())
  589.                       ENDCASE
  590.  
  591.         DEFAULT: A := RDSEQ()
  592.  
  593.                  UNLESS SYMB=S.RSECT | SYMB=S.END DO
  594.                           SYNREPORT("Error in command")
  595.  
  596.         CASE S.RSECT: CASE S.END:
  597.     $)S
  598.  
  599.     REC.P1, REC.P2, REC.L := P1, P2, L
  600.     RESULTIS A   $)1
  601.  
  602. AND RDSEQ() = VALOF
  603. $( LET A = ?
  604.    IGNORE(S.SEMICOLON)
  605.    A := RCOM()
  606.    IF SYMB=S.RSECT | SYMB=S.END RESULTIS A
  607.    RESULTIS LIST3(S.SEQ, A, RDSEQ())   
  608. $)
  609.  
  610. AND RDCDEFS() = VALOF
  611. $( LET A, B = ?, ?
  612.    LET PTR = @A
  613.    LET P1, P2, L = REC.P1, REC.P2, REC.L
  614.    REC.P1, REC.P2, REC.L := LEVEL1(), LEVEL2(), RECOVER
  615.  
  616.    $( B := RNAME()
  617.       TEST SYMB=S.EQ | SYMB=S.COLON THEN NEXTSYMB()
  618.                                     ELSE SYNREPORT("Bad declaration")
  619.       !PTR := LIST3(0, B, REXP(0))
  620.       PTR := @H1!(!PTR)
  621. RECOVER: 
  622.       IGNORE(S.SEMICOLON) 
  623.    $) REPEATWHILE SYMB=S.NAME
  624.  
  625.       REC.P1, REC.P2, REC.L  :=  P1, P2,L
  626.       RESULTIS A  
  627. $)
  628.  
  629. AND RDSECT(R) = VALOF
  630. $(  LET TAG, A = WORDNODE, ?
  631.     CHECKFOR(S.LSECT, "'$(' expected")
  632.     A := R()
  633.     UNLESS SYMB=S.RSECT DO SYNREPORT("'$)' expected")
  634.     TEST TAG=WORDNODE
  635.          THEN NEXTSYMB()
  636.          ELSE IF WORDNODE=NULLTAG DO
  637.                    $( SYMB := 0
  638.                       SYNREPORT("Untagged '$)' mismatch")  $)
  639.     RESULTIS A   
  640. $)
  641.  
  642.  
  643. AND RNAMELIST() = VALOF
  644. $(  LET A = RNAME()
  645.     UNLESS SYMB=S.COMMA RESULTIS A
  646.     NEXTSYMB()
  647.     RESULTIS LIST3(S.COMMA, A, RNAMELIST())   
  648. $)
  649.  
  650.  
  651. AND RNAME() = VALOF
  652. $( LET A = WORDNODE
  653.    CHECKFOR(S.NAME, "Name expected")
  654.    RESULTIS A
  655. $)
  656.  
  657. AND IGNORE(ITEM) BE IF SYMB=ITEM DO NEXTSYMB()
  658.  
  659. AND CHECKFOR(ITEM, N) BE
  660. $( UNLESS SYMB=ITEM DO SYNREPORT(N)
  661.    NEXTSYMB()
  662. $)
  663.  
  664. AND RBEXP() = VALOF
  665. $(1 LET A, OP = ?, SYMB
  666.  
  667.     SWITCHON SYMB INTO
  668.  
  669. $(  DEFAULT: SYNREPORT("Error in expr")
  670.  
  671.     CASE S.QUERY:
  672.         NEXTSYMB()
  673.         RESULTIS TABLE S.QUERY
  674. // Use one static node for QUERY, (No parameters).
  675.  
  676.     CASE S.TRUE:
  677.     CASE S.FALSE:
  678.     CASE S.NAME:
  679.     CASE S.STRING:
  680.         A := WORDNODE
  681.         NEXTSYMB()
  682.         RESULTIS A
  683.  
  684.     CASE S.NUMBER:
  685. // There are enough constant zeros in the average program to justify
  686. // having a static node for number 0.
  687.         A := DECVAL=0 -> (TABLE S.NUMBER, 0),
  688.                          LIST2(S.NUMBER, DECVAL)
  689.         NEXTSYMB()
  690.         RESULTIS A
  691.  
  692.     CASE S.LPAREN:
  693.         NEXTSYMB()
  694.         A := REXP(0)
  695.         CHECKFOR(S.RPAREN, "')' missing")
  696.         RESULTIS A
  697.  
  698.     CASE S.VALOF:
  699.         NEXTSYMB()
  700.         RESULTIS LIST2(S.VALOF, RCOM())
  701.  
  702.     CASE S.VECAP: OP := S.RV
  703.     CASE S.LV:
  704.     CASE S.RV: NEXTSYMB(); RESULTIS LIST2(OP, REXP(37))
  705.  
  706.     CASE S.PLUS: NEXTSYMB(); RESULTIS REXP(34)
  707.  
  708.     CASE S.MINUS: NEXTSYMB()
  709.                   A := REXP(34)
  710.                   TEST H1!A=S.NUMBER
  711.                       THEN H2!A := - H2!A
  712.                       ELSE A := LIST2(S.NEG, A)
  713.                   RESULTIS A
  714.  
  715.     CASE S.NOT: NEXTSYMB(); RESULTIS LIST2(S.NOT, REXP(24))
  716.  
  717.     CASE S.ABS: NEXTSYMB(); RESULTIS LIST2(S.ABS, REXP(35))
  718.  
  719.     CASE S.TABLE: $( LET PTR = @A // Build a LISP list for table
  720.                      $( NEXTSYMB()   // so TRN can calculate consts easily
  721.                         !PTR := LIST2(REXP(0), 0)
  722.                         PTR := @H2!(!PTR)
  723.                      $) REPEATWHILE SYMB =S.COMMA
  724.                   $)
  725.  
  726.                   RESULTIS LIST2(S.TABLE, A)   
  727.  
  728.     CASE S.SLCT:  $( NEXTSYMB()
  729.                      A := LIST4(S.SLCT, REXP(0), 0, 0)
  730.                      IF SYMB = S.COLON THEN
  731.                          $( NEXTSYMB()
  732.                             H3!A := REXP(0)
  733.                             IF SYMB = S.COLON THEN 
  734.                                 $( NEXTSYMB()
  735.                                    H4!A := REXP(0)
  736.                                 $)
  737.                          $)
  738.                      RESULTIS A
  739.                   $)
  740. $)1
  741.  
  742.  
  743.  
  744. AND REXP(N) = VALOF
  745. $(1 LET A = RBEXP()
  746.  
  747.     LET B, C, P, Q = 0, 0, ?, ?
  748.  
  749. $(2 LET OP = SYMB
  750.  
  751.     IF NLPENDING RESULTIS A
  752.  
  753.     SWITCHON OP INTO
  754.  
  755. $(S DEFAULT: RESULTIS A
  756.  
  757.     CASE S.LPAREN: NEXTSYMB()
  758.                    B := 0
  759.                    UNLESS SYMB=S.RPAREN DO B := REXPLIST()
  760.                    CHECKFOR(S.RPAREN, "')' missing")
  761.                    A := LIST3(S.FNAP, A, B)
  762.                    LOOP
  763.  
  764.     CASE S.BYTEAP: P := 36; GOTO LASSOC
  765.     CASE S.OF:
  766.     CASE S.VECAP:  P := 40; GOTO LASSOC
  767.  
  768.     CASE S.REM:CASE S.MULT:CASE S.DIV: P := 35; GOTO LASSOC
  769.  
  770.     CASE S.PLUS:CASE S.MINUS: P := 34; GOTO LASSOC
  771.  
  772.     CASE S.EQ:CASE S.NE:
  773.     CASE S.LE:CASE S.GE:
  774.     CASE S.LS:CASE S.GR:
  775.         IF N>=30 RESULTIS A
  776.  
  777.         $(R NEXTSYMB()
  778.             B := REXP(30)
  779.             A := LIST3(OP, A, B)
  780.             TEST C=0 THEN C :=  A
  781.                      ELSE C := LIST3(S.LOGAND, C, A)
  782.             A, OP := B, SYMB
  783.         $)R REPEATWHILE S.LS<=OP<=S.NE
  784.  
  785.         A := C
  786.         LOOP
  787.  
  788.     CASE S.LSHIFT:CASE S.RSHIFT: P, Q := 25, 30; GOTO DYADIC
  789.  
  790.     CASE S.LOGAND: P := 23; GOTO LASSOC
  791.  
  792.     CASE S.LOGOR:  P := 22; GOTO LASSOC
  793.  
  794.     CASE S.EQV:CASE S.NEQV: P := 21; GOTO LASSOC
  795.  
  796.     CASE S.COND:
  797.             IF N>=13 RESULTIS A
  798.             NEXTSYMB()
  799.             B := REXP(0)
  800.             CHECKFOR(S.COMMA, "Bad conditional expr")
  801.             A := LIST4(S.COND, A, B, REXP(0))
  802.             LOOP
  803.  
  804.     LASSOC: Q := P
  805.  
  806.     DYADIC: IF N>=P RESULTIS A
  807.             NEXTSYMB()
  808.             A := LIST3(OP, A, REXP(Q))
  809.             LOOP
  810. $)S
  811. $)2 REPEAT
  812. $)1
  813.  
  814. AND REXPLIST() = VALOF
  815.     $(1 LET A = ?
  816.         LET PTR = @A
  817.  
  818.         $( LET B = REXP(0)
  819.            UNLESS SYMB=S.COMMA DO $( !PTR := B
  820.                                      RESULTIS A  $)
  821.            NEXTSYMB()
  822.            !PTR := LIST3(S.COMMA, B, 0)
  823.            PTR := @H3!(!PTR)  $) REPEAT
  824.     $)1
  825.  
  826. AND RDEF() = VALOF
  827. $(1 LET N = RNAMELIST()
  828.  
  829.     SWITCHON SYMB INTO
  830.  
  831.  $( CASE S.LPAREN:
  832.       $( LET A = 0
  833.          NEXTSYMB()
  834.          UNLESS H1!N=S.NAME DO SYNREPORT("Name expected")
  835.          IF SYMB=S.NAME DO A := RNAMELIST()
  836.          CHECKFOR(S.RPAREN, "')' missing")
  837.  
  838.          IF SYMB=S.BE DO
  839.             $( NEXTSYMB()
  840.                RESULTIS LIST5(S.RTDEF, N, A, RCOM(), ?)  $)
  841.  
  842.          IF SYMB=S.EQ DO
  843.             $( NEXTSYMB()
  844.                RESULTIS LIST5(S.FNDEF, N, A, REXP(0), ?)  $)
  845.  
  846.          SYNREPORT("Bad proc heading")  
  847.       $)
  848.  
  849.     DEFAULT: SYNREPORT("Bad declaration")
  850.  
  851.     CASE S.EQ:
  852.          NEXTSYMB()
  853.          IF SYMB=S.VEC DO
  854.               $( NEXTSYMB()
  855.                  UNLESS H1!N=S.NAME DO SYNREPORT("Name expected")
  856.                  RESULTIS LIST3(S.VECDEF, N, REXP(0))  $)
  857.          RESULTIS LIST3(S.VALDEF, N, REXPLIST())  $)1
  858.  
  859.  
  860. AND RBCOM() = VALOF
  861. $(1 LET A, B, OP = ?, ?, SYMB
  862.  
  863.     SWITCHON SYMB INTO
  864.  $( DEFAULT: RESULTIS 0
  865.  
  866.     CASE S.NAME:CASE S.NUMBER:CASE S.STRING:
  867.     CASE S.TRUE:CASE S.FALSE:
  868.     CASE S.LV:CASE S.RV:CASE S.VECAP:
  869.     CASE S.LPAREN:
  870.             A := REXPLIST()
  871.  
  872.             IF SYMB=S.ASS  THEN
  873.                $( OP := SYMB
  874.                   NEXTSYMB()
  875.                   RESULTIS LIST3(OP, A, REXPLIST())  $)
  876.  
  877.             IF SYMB=S.COLON DO
  878.                $( UNLESS H1!A=S.NAME DO SYNREPORT("Unexpected ':'")
  879.                   NEXTSYMB()
  880.                   RESULTIS LIST4(S.COLON, A, RBCOM(), ?)  $)
  881.  
  882.             IF H1!A=S.FNAP DO
  883.                  $( H1!A := S.RTAP
  884.                     RESULTIS A  $)
  885.  
  886.             SYNREPORT("Error in command")
  887.             RESULTIS A
  888.  
  889.     CASE S.GOTO:CASE S.RESULTIS:
  890.             NEXTSYMB()
  891.             RESULTIS LIST2(OP, REXP(0))
  892.  
  893.     CASE S.IF:CASE S.UNLESS:
  894.     CASE S.WHILE:CASE S.UNTIL:
  895.             NEXTSYMB()
  896.             A := REXP(0)
  897.             IGNORE(S.DO)
  898.             RESULTIS LIST3(OP, A, RCOM())
  899.  
  900.     CASE S.TEST:
  901.             NEXTSYMB()
  902.             A := REXP(0)
  903.             IGNORE(S.DO)
  904.             B := RCOM()
  905.             CHECKFOR(S.OR, "ELSE expected")
  906.             RESULTIS LIST4(S.TEST, A, B, RCOM())
  907.  
  908.     CASE S.FOR:
  909.         $(  LET I, J, K = 0, 0, 0
  910.             NEXTSYMB()
  911.             A := RNAME()
  912.             CHECKFOR(S.EQ, "Bad FOR loop")
  913.             I := REXP(0)
  914.             CHECKFOR(S.TO, "TO expected")
  915.             J := REXP(0)
  916.             IF SYMB=S.BY DO $( NEXTSYMB()
  917.                                K := REXP(0)  $)
  918.             IGNORE(S.DO)
  919.             RESULTIS LIST6(S.FOR, A, I, J, K, RCOM())  $)
  920.  
  921.     CASE S.LOOP:
  922.     CASE S.BREAK:CASE S.RETURN:CASE S.FINISH:CASE S.ENDCASE:
  923.             A := WORDNODE
  924.             NEXTSYMB()
  925.             RESULTIS A
  926.  
  927.     CASE S.SWITCHON:
  928.             NEXTSYMB()
  929.             A := REXP(0)
  930.             CHECKFOR(S.INTO, "INTO expected")
  931.             RESULTIS LIST3(S.SWITCHON, A, RDSECT(RDSEQ))
  932.  
  933.     CASE S.CASE:
  934.             NEXTSYMB()
  935.             A := REXP(0)
  936.             CHECKFOR(S.COLON, "':' expected")
  937.             RESULTIS LIST3(S.CASE, A, RBCOM())
  938.  
  939.     CASE S.DEFAULT:
  940.             NEXTSYMB()
  941.             CHECKFOR(S.COLON, "':' needed after DEFAULT")
  942.             RESULTIS LIST2(S.DEFAULT, RBCOM())
  943.  
  944.     CASE S.LSECT:
  945.             RESULTIS RDSECT(RDBLOCKBODY)   $)1
  946.  
  947.  
  948. AND RCOM() = VALOF
  949. $(1 LET A = RBCOM()
  950.  
  951.     IF A=0 DO SYNREPORT("Error in command")
  952.  
  953.     WHILE SYMB=S.REPEAT | SYMB=S.REPEATWHILE |
  954.                           SYMB=S.REPEATUNTIL DO
  955.           $( LET OP = SYMB
  956.              NEXTSYMB()
  957.              TEST OP=S.REPEAT
  958.                  THEN A := LIST2(OP, A)
  959.                  ELSE A := LIST3(OP, A, REXP(0))   $)
  960.  
  961.     RESULTIS A  $)1
  962.  
  963.  
  964. .
  965. //  TRN0
  966. SECTION "TRN0"
  967. GET "COMPHDR"
  968.  
  969. STATIC $( LOCALCOUNT=?; LEAFPROC=? $)
  970.  
  971. LET TRANS(X) BE
  972. $( LET SW = ?
  973.  
  974. NEXT: 
  975.    IF INTKEY() THEN ABORT("Interrupted")
  976.  
  977.    SW := FALSE
  978.    IF X=0 RETURN
  979.  
  980.    SWITCHON H1!X INTO
  981.   $( CASE S.LET:
  982.       $( LET B = TREEP
  983.          LET S = SSP
  984.          LET SD = STKDEPTH
  985.          LET CB = CASEB
  986.  
  987.          $( LET B1, S1, S2 = TREEP, ?, SSP
  988.             DECLNAMES(H2!X)
  989.             CHECKDISTINCT(B1)
  990.             S1 := SSP
  991.             SSP := S2
  992.             TRANSDEF(H2!X)
  993.             UNLESS SSP=S1 DO TRANSREPORT("Unbalanced declaration")
  994.             X:=H3!X // Repeat for chains of LETs
  995.          $)
  996.             REPEATWHILE X & (H1!X=S.LET) // so that we deallocate
  997.                                          // all vectors at once
  998.          CASEB := -1    // switch not allowed now
  999.          DECLLABELS(X)
  1000.          TRANS(X)    // then translate the rest
  1001.          STACKTO(SD)    // lose the vector space
  1002.          STKDEPTH, SSP := SD, S
  1003.          TREEP := B
  1004.          CASEB := CB
  1005.          RETURN   
  1006.       $)
  1007.  
  1008.  
  1009.     CASE S.STATIC:
  1010.     CASE S.GLOBAL:
  1011.     CASE S.MANIFEST:
  1012.       $( LET B = TREEP
  1013.          LET Y = H2!X
  1014.  
  1015.          UNTIL Y=0 DO SWITCHON H1!X INTO
  1016.             $( CASE S.STATIC:
  1017.                   $( LET M = NEXTPARAM()
  1018.                      LET T = H1!Y
  1019.                      ADDNAME(H2!Y, S.LABEL, M)
  1020.                      H1!Y := S.STATIC // So dumplits isn't confused
  1021.                      H3!Y := EVALCONST(H3!Y) // evaluate init in correct environment
  1022.                      ADDLIT(M, Y)
  1023.                      Y := T
  1024.                      ENDCASE
  1025.                   $)
  1026.  
  1027.                CASE S.GLOBAL:
  1028.                   $( LET GN = EVALCONST(H3!Y)
  1029.                      ADDNAME(H2!Y, S.GLOBAL, GN)
  1030.                      WRITE2(S.GLOBSYM, GN)
  1031.                      WRITESTRING(@H3!(H2!Y))
  1032.                      Y := H1!Y
  1033.                      ENDCASE
  1034.                   $)
  1035.           
  1036.                CASE S.MANIFEST:
  1037.                   $( ADDNAME(H2!Y, S.NUMBER, EVALCONST(H3!Y))
  1038.                      Y := H1!Y
  1039.                      ENDCASE
  1040.                   $)
  1041.  
  1042.             $)
  1043.  
  1044.          CHECKDISTINCT(B)
  1045.          DECLLABELS(H3!X)
  1046.          TRANS(H3!X)
  1047.          TREEP := B
  1048.          RETURN
  1049.       $)
  1050.  
  1051.     CASE S.NEEDS:
  1052.        $( LET N = VEC 5 // Buffer for filename
  1053.           PARSE(@H2!(H2!X), N) // Parse into CPM FCB format
  1054.           WRITE1(S.NEEDS) // Send the parsed filename out.
  1055.           FOR K = 0 TO 11 DO WRITE1(N%K)
  1056.           X := H3!X
  1057.           GOTO NEXT
  1058.        $)
  1059.  
  1060.     CASE S.ASS:
  1061.        ASSIGN(H2!X, H3!X)
  1062.        RETURN
  1063.  
  1064.     CASE S.RTAP:
  1065.         TRANSCALL(X)
  1066.         RETURN
  1067.  
  1068.  
  1069.     CASE S.GOTO:
  1070.         LOAD(H2!X)
  1071.         OUT2(S.LIMIY,STKDEPTH*2) // For stack fixup
  1072.     OUT1(S.GOTO)
  1073.         STOPFLOW()
  1074.         RETURN
  1075.  
  1076.     CASE S.COLON:
  1077.      $( COMPLAB(H4!X)
  1078.         OUT2(S.LIMHL, -STKDEPTH*2) // Used to fixup stack by GOTO code.
  1079.         X := H3!X
  1080.         GOTO NEXT
  1081.      $)
  1082.  
  1083.     CASE S.UNLESS: SW := TRUE
  1084.     CASE S.IF:
  1085.      $( LET L = COMISJUMP(H3!X)
  1086.         TEST L & (RESULT2 = STKDEPTH) THEN 
  1087.               JUMPCOND(H2!X, NOT SW, L, FALSE)
  1088.         ELSE
  1089.            $( L := NEXTPARAM()
  1090.               JUMPCOND(H2!X, SW, L, FALSE)
  1091.               TRANS(H3!X)
  1092.               COMPLAB(L)
  1093.            $)
  1094.         RETURN   
  1095.      $)
  1096.  
  1097.     CASE S.TEST:
  1098.      $( LET L, M, N = ?, ?, ?
  1099.         L := COMISJUMP(H3!X)
  1100.         IF L & (RESULT2 = STKDEPTH) THEN
  1101.            $( JUMPCOND(H2!X, TRUE, L, FALSE)
  1102.               TRANS(H4!X)
  1103.               RETURN
  1104.            $)
  1105.  
  1106.         L := COMISJUMP(H4!X)
  1107.         IF L & (RESULT2=STKDEPTH) THEN
  1108.            $( JUMPCOND(H2!X, FALSE, L, FALSE)
  1109.               TRANS(H3!X)
  1110.               RETURN
  1111.            $)
  1112.  
  1113.         L, M, N  := NEXTPARAM(), NEXTPARAM(), ?
  1114.         JUMPCOND(H2!X, FALSE, L, FALSE)
  1115.         TRANS(H3!X)
  1116.         N := COMPJUMP(M)
  1117.         COMPLAB(L)
  1118.         TRANS(H4!X)
  1119.         IF N THEN COMPLAB(M)
  1120.         RETURN   
  1121.      $)
  1122.  
  1123.     CASE S.LOOP:
  1124.     CASE S.BREAK:
  1125.     CASE S.ENDCASE:
  1126.      $( LET L = COMISJUMP(X)
  1127.         TEST L THEN
  1128.              $( STACKTO(RESULT2)
  1129.                 COMPJUMP(L)
  1130.              $)
  1131.         ELSE TRANSREPORT(RESULT2)
  1132.         RETURN
  1133.      $)
  1134.  
  1135.     CASE S.RESULTIS:
  1136.         IF RESULTLABEL<0 DO $( TRANSREPORT("Illegal RESULTIS")
  1137.                                RETURN $)
  1138.         LOAD(H2!X) // Get the expr
  1139.         IF RESULTLABEL ~=0 THEN // Normal Result, jump round
  1140.            $( STACKTO(RESULTSTACK)
  1141.               COMPJUMP(RESULTLABEL)
  1142.               RETURN
  1143.            $)
  1144.         // Drop through for function return special case (RESULTLABEL=0)
  1145.  
  1146.     CASE S.RETURN:
  1147.         STACKTO(0)
  1148.         COMPRETURN()
  1149.         RETURN
  1150.  
  1151.     CASE S.FINISH:
  1152.         OUT1(S.FINISH)
  1153.         STOPFLOW()
  1154.         RETURN
  1155.  
  1156.     CASE S.WHILE: SW := TRUE
  1157.     CASE S.UNTIL:
  1158.      $( LET L, M = NEXTPARAM(), NEXTPARAM()
  1159.         LET BL, LL = BREAKLABEL, LOOPLABEL
  1160.         LET LPS = LOOPSTACK
  1161.  
  1162.         BREAKLABEL, LOOPLABEL := 0, M
  1163.         LOOPSTACK := STKDEPTH
  1164.  
  1165.         COMPJUMP(M)
  1166.         COMPLAB(L)
  1167.         TRANS(H3!X)
  1168.         COMPLAB(M)
  1169.         JUMPCOND(H2!X, SW, L, FALSE)
  1170.         UNLESS BREAKLABEL=0 DO COMPLAB(BREAKLABEL)
  1171.  
  1172.         LOOPSTACK:= LPS
  1173.         BREAKLABEL, LOOPLABEL := BL, LL
  1174.         RETURN   $)
  1175.  
  1176.     CASE S.REPEATWHILE: SW := TRUE
  1177.     CASE S.REPEATUNTIL:
  1178.     CASE S.REPEAT:
  1179.      $( LET L, BL, LL = NEXTPARAM(), BREAKLABEL, LOOPLABEL
  1180.         LET LPS = LOOPSTACK
  1181.  
  1182.         LOOPSTACK := STKDEPTH
  1183.         BREAKLABEL, LOOPLABEL := 0, 0
  1184.         COMPLAB(L)
  1185.         TEST H1!X=S.REPEAT
  1186.             THEN $( LOOPLABEL := L
  1187.                     TRANS(H2!X)
  1188.                     COMPJUMP(L)  $)
  1189.               OR $( TRANS(H2!X)
  1190.                     UNLESS LOOPLABEL=0 DO COMPLAB(LOOPLABEL)
  1191.                     JUMPCOND(H3!X, SW, L, FALSE)  $)
  1192.         UNLESS BREAKLABEL=0 DO COMPLAB(BREAKLABEL)
  1193.  
  1194.         LOOPSTACK := LPS
  1195.         BREAKLABEL, LOOPLABEL := BL, LL
  1196.         RETURN   $)
  1197.  
  1198.     CASE S.CASE:
  1199.      $( LET L = NEXTPARAM()
  1200.         COMPLAB(L)
  1201.         TEST CASEB<0 THEN
  1202.                      $( TRANSREPORT("Illegal CASE")
  1203.                         X := H3!X $)
  1204.         ELSE
  1205.           $( LET P = CASEB // Pointer to chain of cases
  1206.              LET K = EVALCONST(H2!X) // get case constant
  1207.              UNTIL P = 0 DO // Chain down the list
  1208.              $( IF K = H2!P THEN $( TRANSREPORT("Two cases with same constant")
  1209.                                     BREAK
  1210.                                  $)
  1211.                 P := H1!P // Next one
  1212.              $)
  1213.              H1!X := CASEB
  1214.              CASEB := X // put this one on the list
  1215.              H2!X := K  // replace expr by constant
  1216.              P := H3!X // See if the next instruction is another CASE
  1217.              H3!X := L // label kept here
  1218.              X := P
  1219.           $)
  1220.              REPEATWHILE (X & (H1!X=S.CASE)) // Re-use the same label if so.
  1221.  
  1222.         GOTO NEXT
  1223.      $)
  1224.  
  1225.     CASE S.DEFAULT:
  1226.         TEST CASEB<0 DO TRANSREPORT("Illegal DEFAULT")
  1227.         ELSE
  1228.         $( UNLESS DEFAULTLABEL=0 DO TRANSREPORT("Duplicate DEFAULT")
  1229.            DEFAULTLABEL := NEXTPARAM()
  1230.            COMPLAB(DEFAULTLABEL)
  1231.         $)
  1232.         X := H2!X
  1233.         GOTO NEXT
  1234.  
  1235.     CASE S.SWITCHON:
  1236.       $( LET B, DL = CASEB, DEFAULTLABEL
  1237.          LET ECL, CSK = ENDCASELABEL, CASESTACK
  1238.          LET L, L1 = NEXTPARAM(), NEXTPARAM()
  1239.  
  1240.          COMPJUMP(L)
  1241.  
  1242.          CASESTACK := STKDEPTH
  1243.          ENDCASELABEL, DEFAULTLABEL, CASEB := 0, 0, 0
  1244.  
  1245.          TRANS(H3!X)
  1246.  
  1247.          UNLESS COMPJUMP(L1) | (DEFAULTLABEL=0) DO L1 := 0
  1248.          IF DEFAULTLABEL=0 DO DEFAULTLABEL := L1
  1249.  
  1250.          COMPLAB(L)
  1251.          LOAD(H2!X)
  1252.  
  1253.          $( LET P, COUNT = CASEB, 0
  1254.             UNTIL P = 0 DO
  1255.                $( P := H1!P // Count no of cases
  1256.                   COUNT := COUNT + 1
  1257.                $)
  1258.  
  1259.             IF COUNT > 255 THEN TRANSREPORT("Too many cases")
  1260.             OUTB(S.LIMB, COUNT)
  1261.  
  1262.             TEST COUNT THEN OUT1(S.SWITCHON)
  1263.                        ELSE COMPJUMP(DEFAULTLABEL)
  1264.                  // zero cases is pathalogical
  1265.          $)
  1266.  
  1267.          UNTIL CASEB = 0 DO // Produce the switch table
  1268.            $( OUT2(S.DW, H2!CASEB)
  1269.               OUT2(S.DWLAB, H3!CASEB)
  1270.               CASEB := H1!CASEB
  1271.            $)
  1272.          OUT2(S.DWLAB, DEFAULTLABEL)
  1273.  
  1274.          STOPFLOW()
  1275.  
  1276.          IF ENDCASELABEL THEN COMPLAB(ENDCASELABEL)
  1277.          IF L1 THEN COMPLAB(L1)
  1278.          ENDCASELABEL, CASESTACK := ECL, CSK
  1279.          CASEB, DEFAULTLABEL := B, DL         
  1280.          RETURN
  1281.       $)
  1282.  
  1283.     CASE S.FOR:
  1284.       $( LET B = TREEP
  1285.          LET L, M, M1 = NEXTPARAM(), NEXTPARAM(), NEXTPARAM()
  1286.          LET BL, LL = BREAKLABEL, LOOPLABEL
  1287.          LET LPS = LOOPSTACK
  1288.          LET STEP = 1
  1289.          LET CONST = CONSTANT(H4!X)
  1290.          LET LIMIT = RESULT2
  1291.          LET S = SSP
  1292.          BREAKLABEL, LOOPLABEL := NEXTPARAM(), 0
  1293.  
  1294.          UNLESS H5!X=0 DO STEP := EVALCONST(H5!X)
  1295.          ADDNAME(H2!X, S.LOCAL, S)
  1296.          SSP := SSP + 1
  1297.  
  1298.          UNLESS CONST DO
  1299.             $( LOAD(H4!X) // loop limit onto the stack
  1300.                OUT1(S.PUSHHL)
  1301.                STKDEPTH := STKDEPTH + 1
  1302.             $)
  1303.  
  1304.          LOOPSTACK := STKDEPTH
  1305.   
  1306.          LOAD(H3!X) // initial counter
  1307.          COMPJUMP(L)
  1308.  
  1309.          DECLLABELS(H6!X)
  1310.          COMPLAB(M)
  1311.          OUT2(S.JPM,BREAKLABEL)
  1312.          COMPLAB(M1)
  1313.          TRANS(H6!X)
  1314.          UNLESS LOOPLABEL=0 DO COMPLAB(LOOPLABEL)
  1315.          LOAD(H2!X) // Count var
  1316.          ADDCONST(STEP)
  1317.  
  1318.          COMPLAB(L)
  1319.          OUTB(S.STLIX, S*2)
  1320.          OUTB(S.STHIX, (S*2)+1)
  1321.          TEST CONST THEN    OUT2(S.LIMDE, LIMIT)
  1322.                     ELSE $( OUT1(S.POPDE)
  1323.                             OUT1(S.PUSHDE) 
  1324.                          $) // now have limit in DE, count in HL
  1325.          OUT1(S.ORA)    // clear carry
  1326.          OUT1(S.MINUS)  // condition flags
  1327.          TEST STEP > 0 THEN
  1328.              $( OUT2(S.JPZ,M1)  // This lot and the test at M
  1329.                 OUT2(S.JPPE,M)  // does signed hl < de
  1330.              $)                      // or hl > de depending on step
  1331.          ELSE   OUT2(S.JPPO,M)
  1332.  
  1333.          OUT2(S.JPM,M1)
  1334.          COMPLAB(BREAKLABEL)
  1335.          BREAKLABEL, LOOPLABEL, SSP := BL, LL, S
  1336.          LOOPSTACK := LPS
  1337.          UNLESS CONST DO
  1338.              $( STKDEPTH := STKDEPTH - 1
  1339.                 OUT1(S.POPHL) // Lose the limit from the stack
  1340.              $)
  1341.          TREEP := B  
  1342.          RETURN
  1343.       $)
  1344.  
  1345.     CASE S.SEQ:
  1346.         TRANS(H2!X)
  1347.         X := H3!X
  1348.         GOTO NEXT 
  1349.    $)
  1350. $)
  1351.  
  1352. AND DECLNAMES(X) BE UNLESS X=0 SWITCHON H1!X INTO
  1353.      $(  CASE S.VECDEF: CASE S.VALDEF:
  1354.                DECLDYN(H2!X)
  1355.                RETURN
  1356.  
  1357.          CASE S.RTDEF: CASE S.FNDEF:
  1358.                H5!X := NEXTPARAM()
  1359.                DECLSTAT(X, H2!X, H5!X)
  1360.                RETURN
  1361.  
  1362.          CASE S.AND:
  1363.                DECLNAMES(H2!X)
  1364.                DECLNAMES(H3!X)
  1365.                RETURN    
  1366.      $)
  1367.  
  1368.  
  1369. AND DECLDYN(X) BE UNLESS X=0 DO
  1370. $( WHILE H1!X=S.COMMA DO
  1371.       $( ADDNAME(H2!X, S.LOCAL, SSP)
  1372.          SSP := SSP + 1
  1373.          X := H3!X   
  1374.       $)
  1375.    ADDNAME(X, S.LOCAL, SSP)
  1376.    SSP := SSP+1
  1377. $)
  1378.  
  1379. AND DECLSTAT(P, X, L) BE
  1380. $( TEST CELLWITHNAME(X) = S.GLOBAL DO
  1381.        $( LET N = RESULT2
  1382.           ADDNAME(X, S.GLOBAL, N)
  1383.           WRITE2(S.GORG, N)
  1384.           WRITE2(S.DWLAB, L)
  1385.        $)
  1386.    ELSE
  1387.        $( LET M = NEXTPARAM()
  1388.           ADDNAME(X, S.LABEL, M)
  1389.           ADDLIT(M, P)
  1390.        $)
  1391.  $)
  1392.  
  1393.  
  1394. AND DECLLABELS(X) BE
  1395. $( LET B = TREEP
  1396.    SCANLABELS(X)
  1397.    CHECKDISTINCT(B)
  1398. $)
  1399.  
  1400.  
  1401.  
  1402. AND SCANLABELS(X) BE UNLESS X=0 SWITCHON H1!X INTO
  1403. $( DEFAULT: RETURN
  1404.  
  1405.    CASE S.COLON:
  1406.         H4!X := NEXTPARAM()
  1407.         DECLSTAT(X, H2!X, H4!X)
  1408.  
  1409.    CASE S.IF: CASE S.UNLESS: CASE S.WHILE: CASE S.UNTIL:
  1410.    CASE S.SWITCHON: CASE S.CASE: CASE S.NEEDS:
  1411.         SCANLABELS(H3!X)
  1412.         RETURN
  1413.  
  1414.    CASE S.SEQ:
  1415.         SCANLABELS(H3!X)
  1416.  
  1417.    CASE S.REPEAT:
  1418.    CASE S.REPEATWHILE: CASE S.REPEATUNTIL: CASE S.DEFAULT:
  1419.         SCANLABELS(H2!X)
  1420.         RETURN
  1421.  
  1422.    CASE S.TEST:
  1423.         SCANLABELS(H3!X)
  1424.         SCANLABELS(H4!X)
  1425.         RETURN    
  1426. $)
  1427.  
  1428.  
  1429. AND TRANSDEF(X) BE
  1430. $( TRANSDYNDEFS(X)
  1431.    IF STATDEFS(X) DO
  1432.       $( LET L, CP, N = NEXTPARAM(), CURPROC, ?
  1433.          LET BL, LL = BREAKLABEL, LOOPLABEL
  1434.          LET RL, CB = RESULTLABEL, CASEB
  1435.          LET ECL = ENDCASELABEL
  1436.          LET S, SD, DP = SSP, STKDEPTH, DVECP
  1437.          LET SFS, ASSP = SFSIZE, ARGSSP
  1438.          N := COMPJUMP(L)
  1439.          TRANSSTATDEFS(X)
  1440.          BREAKLABEL, LOOPLABEL := BL, LL
  1441.          RESULTLABEL, CASEB := RL, CB
  1442.          ENDCASELABEL := ECL
  1443.          CURPROC := CP
  1444.          SSP, STKDEPTH, DVECP := S, SD, DP
  1445.          SFSIZE, ARGSSP := SFS, ASSP
  1446.          IF N THEN COMPLAB(L)  
  1447.       $)
  1448. $)
  1449.  
  1450. AND TRANSDYNDEFS(X) BE SWITCHON H1!X INTO
  1451. $( CASE S.AND:
  1452.         TRANSDYNDEFS(H2!X)
  1453.         TRANSDYNDEFS(H3!X)
  1454.         RETURN
  1455.  
  1456.    CASE S.VECDEF:
  1457.         $( LET SIZE = 1 + EVALCONST(H3!X)
  1458.            STKDEPTH := STKDEPTH + SIZE
  1459.            OUT2(S.LIMHL, -SIZE*2)
  1460.            OUT1(S.VEC)
  1461.            OUTB(S.STLIX, SSP*2)
  1462.            OUTB(S.STHIX, (SSP*2)+1)
  1463.            CACHE.MODE, CACHE.VAL := S.LOCAL, SSP 
  1464.            SSP := SSP + 1
  1465.            RETURN
  1466.         $)
  1467.  
  1468.    CASE S.VALDEF: 
  1469.             LOADLIST(H3!X, @SSP)
  1470.    DEFAULT: RETURN
  1471. $)
  1472.  
  1473. AND TRANSSTATDEFS(X) BE SWITCHON H1!X INTO
  1474. $( CASE S.AND:
  1475.         TRANSSTATDEFS(H2!X)
  1476.         TRANSSTATDEFS(H3!X)
  1477.         RETURN
  1478.  
  1479.    CASE S.FNDEF: CASE S.RTDEF:
  1480.          LOOPLABEL, RESULTLABEL := -1, -1
  1481.          CASEB, ENDCASELABEL := -1, -1
  1482.  
  1483.          CURPROC := (H2!X)+H3
  1484.            
  1485.          LOCALCOUNT := LENLIST(H3!X)
  1486.          SFSIZE := LOCALCOUNT
  1487.          LEAFPROC := TRUE
  1488.          COUNTLOCALS(H4!X)
  1489.          IF SFSIZE>64 THEN TRANSREPORT("Too many locals")
  1490.          IF LEAFPROC THEN SFSIZE := 0 // don't need stack frame 
  1491.                                       // for leaf procedure  
  1492.  
  1493.          ARGSSP, STKDEPTH := 0, 0
  1494.          SSP := -SFSIZE // Start the stack frame at most neg offset
  1495.  
  1496.          DVECP := TREEP
  1497.          DECLDYN(H3!X) // Declare the argument list
  1498.          CHECKDISTINCT(DVECP)
  1499.  
  1500.          COMPLAB(H5!X)
  1501.          BUMPP(SFSIZE)
  1502.  
  1503.          TEST H1!X=S.RTDEF
  1504.             THEN $( DECLLABELS(H4!X) // Routine Defn
  1505.                     TRANS(H4!X)
  1506.                  $)
  1507.             ELSE $( LET E=H4!X // Function Defn
  1508.                     TEST H1!E = S.VALOF THEN // special case for 
  1509.                        $( RESULTLABEL := 0   // Fn = VALOF.....
  1510.                           DECLLABELS(H2!E)
  1511.                           TRANS(H2!E)
  1512.                        $)
  1513.                     ELSE LOAD(E) // Ordinary case.
  1514.                  $)
  1515.  
  1516.          COMPRETURN()
  1517.  
  1518.          TREEP := DVECP
  1519.  
  1520.       DEFAULT: RETURN   
  1521. $)
  1522.  
  1523. AND STATDEFS(X) = H1!X=S.FNDEF | H1!X=S.RTDEF -> TRUE,
  1524.                   H1!X NE S.AND -> FALSE,
  1525.                   STATDEFS(H2!X) -> TRUE,
  1526.                   STATDEFS(H3!X)
  1527.  
  1528. AND LENLIST(X) = VALOF
  1529. $( LET ANS = 1
  1530.    IF X=0 RESULTIS 0
  1531.    WHILE H1!X=S.COMMA DO
  1532.    $( X := H3!X
  1533.       ANS := ANS+1
  1534.    $)
  1535.    RESULTIS ANS
  1536. $)
  1537.  
  1538. AND COUNTDECLS(X) BE
  1539. $( SWITCHON H1!X INTO
  1540.    $( CASE S.VALDEF: CASE S.VECDEF:
  1541.       LOCALCOUNT := LOCALCOUNT + LENLIST(H2!X)
  1542.       RETURN
  1543.  
  1544.       CASE S.AND:
  1545.       COUNTDECLS(H2!X)
  1546.       COUNTDECLS(H3!X)
  1547.       RETURN
  1548.  
  1549.    $)
  1550. $)
  1551.  
  1552. AND COUNTLOCALS(X) BE
  1553. $( IF X=0 RETURN
  1554.    SWITCHON H1!X INTO
  1555.       $( CASE S.LET:
  1556.  
  1557.          $( LET OCOUNT = LOCALCOUNT
  1558.             COUNTDECLS(H2!X)
  1559.             COUNTLOCALS(H2!X)
  1560.             COUNTLOCALS(H3!X)
  1561.             IF SFSIZE<LOCALCOUNT THEN SFSIZE := LOCALCOUNT 
  1562.             LOCALCOUNT := OCOUNT
  1563.             RETURN
  1564.          $)
  1565.  
  1566.          CASE S.RTAP: CASE S.FNAP:
  1567.  
  1568.          LEAFPROC := FALSE
  1569.          COUNTLOCALS(H2!X)
  1570.  
  1571.          CASE S.STATIC: CASE S.GLOBAL: CASE S.MANIFEST: CASE S.NEEDS:
  1572.          CASE S.COLON: CASE S.VALDEF:
  1573.  
  1574.          COUNTLOCALS(H3!X)
  1575.          RETURN
  1576.  
  1577.          CASE S.TEST: CASE S.COND:
  1578.  
  1579.          COUNTLOCALS(H4!X)
  1580.  
  1581.          CASE S.ASS: CASE S.IF: CASE S.UNLESS:
  1582.          CASE S.WHILE:  CASE S.UNTIL: CASE S.REPEATWHILE:
  1583.          CASE S.REPEATUNTIL: CASE S.CASE: CASE S.SWITCHON: CASE S.SEQ:
  1584.          CASE S.REM: CASE S.LS: CASE S.GR: CASE S.LE: CASE S.GE: CASE S.EQ:
  1585.          CASE S.NE: CASE S.RSHIFT: CASE S.LOGAND: CASE S.LOGOR: CASE S.EQV:
  1586.          CASE S.NEQV: CASE S.PLUS: CASE S.MINUS: CASE S.MULT: CASE S.DIV:
  1587.          CASE S.LSHIFT: CASE S.VECAP: CASE S.BYTEAP:  CASE S.OF:
  1588.          CASE S.COMMA: CASE S.AND:
  1589.  
  1590.          COUNTLOCALS(H3!X) 
  1591.  
  1592.          CASE S.GOTO: CASE S.RESULTIS: CASE S.REPEAT: CASE S.DEFAULT:
  1593.          CASE S.NEG:  CASE S.ABS: CASE S.NOT: CASE S.RV: CASE S.LV:
  1594.          CASE S.VALOF:
  1595.  
  1596.          COUNTLOCALS(H2!X)
  1597.  
  1598.          RETURN      
  1599.  
  1600.          CASE S.FOR:
  1601.  
  1602.          LOCALCOUNT := LOCALCOUNT+1
  1603.          IF SFSIZE<LOCALCOUNT THEN SFSIZE := LOCALCOUNT
  1604.          COUNTLOCALS(H3!X)
  1605.          COUNTLOCALS(H4!X)
  1606.          COUNTLOCALS(H5!X)
  1607.          COUNTLOCALS(H6!X)
  1608.          LOCALCOUNT := LOCALCOUNT-1
  1609.          RETURN
  1610.  
  1611.       $)
  1612. $)
  1613.  .
  1614.  
  1615.  
  1616. //TRN1
  1617.  
  1618. SECTION "TRN1"
  1619. GET "COMPHDR"
  1620.  
  1621. // expressions.....
  1622.  
  1623. // Load the expression in X in HL, don't save DE
  1624. // Check for a constant expr here , but not sub-exprs (in general)
  1625. LET LOAD(X) BE TEST CONSTANT(X) THEN LOADCONST(RESULT2)
  1626.                                 ELSE LOADHL(X,FALSE)
  1627.  
  1628. AND SIMPLEOP(O) = O=S.STRING | O=S.FALSE | O=S.QUERY |
  1629.                   O=S.TRUE | O=S.NAME | O=S.NUMBER | O=S.TABLE -> TRUE,FALSE
  1630.  
  1631. AND LOADLR(X) BE
  1632. $( TEST SIMPLEOP(H1!(H3!X)) THEN // Get HL first to avoid saving DE
  1633.         $( LOADHL(H2!X, FALSE)
  1634.            LOADDE(H3!X, TRUE)
  1635.         $)
  1636.    ELSE
  1637.         $( LOADDE(H3!X, FALSE)
  1638.            LOADHL(H2!X, TRUE)
  1639.         $)
  1640. $)
  1641.  
  1642. AND LOADHL(X,SAVE) BE
  1643. $( LET OP = H1!X
  1644.  
  1645.    SWITCHON OP INTO
  1646.      $( CASE S.REM:
  1647.         CASE S.LS:
  1648.         CASE S.GR:
  1649.         CASE S.LE:
  1650.         CASE S.GE:
  1651.         CASE S.EQ:
  1652.         CASE S.NE:
  1653.         CASE S.RSHIFT:
  1654.         CASE S.LOGAND:
  1655.         CASE S.LOGOR:
  1656.         CASE S.EQV:
  1657.         CASE S.NEQV:
  1658.         DYAD:          PUSHDE(SAVE)
  1659.                        LOADLR(X) // get Left and Right into HL and DE
  1660.                        IF OP=S.MINUS THEN OUT1(S.ORA)
  1661.                        OUT1(OP)
  1662.                        POPDE(SAVE)
  1663.                        IF OP=S.GE | OP=S.LS |
  1664.                           OP=S.LE | OP=S.GR THEN OUT1(S.SUBHH)
  1665.                                 // Convert carry to hl=0000,FFFF
  1666.                        RETURN
  1667.  
  1668.         CASE S.PLUS:   SWAPROUND(X)
  1669.         CASE S.MINUS:  IF CONSTANT(H3!X) THEN
  1670.                              $( LET C = OP=S.PLUS -> RESULT2, -RESULT2
  1671.                                 LOADHL(H2!X, SAVE)
  1672.                                 ADDCONST(C)
  1673.                                 RETURN
  1674.                              $)
  1675.                        GOTO DYAD
  1676.  
  1677.  
  1678.         CASE S.MULT:   SWAPROUND(X)
  1679.         CASE S.DIV:    IF CONSTANT(H3!X) THEN
  1680.                          $( LET L = VALOF
  1681.                             $( LET P = 0         // Return log2 N or zero 
  1682.                                                  // if N is not integer power
  1683.                                IF RESULT2 <= 0 RESULTIS 0
  1684.                                UNTIL (RESULT2&1) = 1 DO 
  1685.                                      $( P := P + 1
  1686.                                         RESULT2 := RESULT2 >> 1 
  1687.                                      $)      
  1688.                                RESULTIS RESULT2=1 -> P, 0
  1689.                             $)
  1690.  
  1691.                             IF 0<L<=(OP=S.MULT -> 10,4) THEN
  1692.                               $( LOADHL(H2!X, SAVE)
  1693.                                  FOR I = 1 TO L DO 
  1694.                                       OUT1(OP=S.MULT -> S.ADDHH, S.TWODIV)
  1695.                                  RETURN
  1696.                               $)
  1697.                          $)
  1698.                        GOTO DYAD
  1699.  
  1700.         CASE S.LSHIFT: IF CONSTANT(H3!X) THEN
  1701.                          $( LET S = RESULT2 & #X1F // Short out big shifts
  1702.                             LOADHL(H2!X, SAVE)
  1703.                             FOR I = 1 TO S DO OUT1(S.ADDHH)
  1704.                             RETURN
  1705.                          $)
  1706.                         GOTO DYAD
  1707.  
  1708.         CASE S.VECAP:
  1709.         CASE S.RV:     PUSHDE(SAVE) // RV corrupts DE as well
  1710.                        LOADLV(X, FALSE)
  1711.                        OUT1(S.RV)
  1712.                        POPDE(SAVE)
  1713.                        RETURN
  1714.  
  1715.         CASE S.BYTEAP: IF BYTEADDR(X,SAVE) THEN
  1716.                          $( OUT1(S.LDBYTE)
  1717.                             OUTB(S.LDHIM,0)
  1718.                             RETURN
  1719.                          $)
  1720.                        GOTO DYAD
  1721.  
  1722.         CASE S.NEG:
  1723.     CASE S.ABS:
  1724.         CASE S.NOT:    LOADHL(H2!X,SAVE)
  1725.                        OUT1(OP)
  1726.                        RETURN
  1727.  
  1728.  
  1729.         CASE S.LV:     LOADLV(H2!X,SAVE)
  1730.                        RETURN
  1731.         CASE S.TRUE:   LOADCONST(TRUE)
  1732.                        RETURN
  1733.         CASE S.FALSE:  LOADCONST(FALSE)
  1734.         CASE S.QUERY:  RETURN
  1735.  
  1736.  
  1737.         CASE S.NUMBER: LOADCONST(H2!X)
  1738.                        RETURN
  1739.  
  1740.         CASE S.TABLE:
  1741.         CASE S.STRING:
  1742.          $( LET L = NEXTPARAM()
  1743.             OUT2(S.LABADDR,L)
  1744.             ADDLIT(L, X)
  1745.             RETURN
  1746.          $)
  1747.  
  1748.         CASE S.SLCT:  LOADCONST(EVALCONST(X))
  1749.                       RETURN
  1750.  
  1751.         CASE S.OF:    IF TRANSOF(X, SAVE) THEN
  1752.                         $( LOADCONST(0)
  1753.                            OUT1(S.SKIPZ)
  1754.                            OUT1(S.INCHL)
  1755.                         $)
  1756.                       RETURN
  1757.  
  1758.         CASE S.NAME:
  1759.          $( LET M = TRANSNAME(X)
  1760.             // May already be in HL
  1761.             IF CACHE.MODE = M & CACHE.VAL = RESULT2 RETURN 
  1762.  
  1763.             SWITCHON M INTO
  1764.             $( CASE S.LOCAL:  OUTB(S.LDLIX, RESULT2*2)
  1765.                               OUTB(S.LDHIX, (RESULT2*2)+1)
  1766.                               ENDCASE
  1767.  
  1768.                CASE S.GLOBAL: OUT2(S.LDHLGLB, RESULT2)
  1769.                               ENDCASE
  1770.  
  1771.                CASE S.LABEL:  OUT2(S.LDHLLAB, RESULT2)
  1772.                               ENDCASE
  1773.  
  1774.                CASE S.NUMBER: LOADCONST(RESULT2)
  1775.                DEFAULT:       RETURN
  1776.             $)
  1777.             CACHE.MODE, CACHE.VAL := M, RESULT2
  1778.             RETURN
  1779.          $)
  1780.  
  1781.         CASE S.VALOF:
  1782.          $( LET RL, RS = RESULTLABEL, RESULTSTACK
  1783.             LET B = TREEP
  1784.             DECLLABELS(H2!X)
  1785.             RESULTLABEL := NEXTPARAM()
  1786.             PUSHDE(SAVE)
  1787.             RESULTSTACK := STKDEPTH
  1788.             TRANS(H2!X)
  1789.             COMPLAB(RESULTLABEL)
  1790.             POPDE(SAVE)
  1791.             TREEP := B
  1792.             RESULTLABEL, RESULTSTACK := RL, RS
  1793.             RETURN  $)
  1794.  
  1795.  
  1796.         CASE S.FNAP:
  1797.          $( PUSHDE(SAVE)
  1798.             TRANSCALL(X)
  1799.             POPDE(SAVE)
  1800.             RETURN   $)
  1801.  
  1802.         CASE S.COND:
  1803.          $( LET L, M = NEXTPARAM(), NEXTPARAM()
  1804.             JUMPCOND(H2!X, FALSE, M, SAVE)
  1805.             LOADHL(H3!X,SAVE)
  1806.             COMPJUMP(L)
  1807.             COMPLAB(M)
  1808.             LOADHL(H4!X,SAVE)
  1809.             COMPLAB(L)
  1810.             RETURN   $)
  1811.  
  1812.      $)
  1813. $)
  1814.  
  1815. AND LOADCONST(N) BE
  1816. $( IF CACHE.MODE = S.NUMBER & CACHE.VAL = N RETURN
  1817.    OUT2(S.LIMHL, N)
  1818.    CACHE.MODE := S.NUMBER
  1819.    CACHE.VAL  := N
  1820. $)
  1821.  
  1822. AND SWAPROUND(X) BE
  1823. $( LET T = ?
  1824.    IF CONSTANT(H2!X) THEN
  1825.        $( T := H2!X
  1826.           H2!X := H3!X
  1827.           H3!X := T
  1828.        $)
  1829. $)
  1830.  
  1831. AND LOADLV(X, SAVE) BE 
  1832. $( SWITCHON H1!X INTO
  1833.    $( DEFAULT: TRANSREPORT("Cannot take address of expr")
  1834.                RETURN
  1835.  
  1836.         CASE S.NAME:
  1837.             $( SWITCHON TRANSNAME(X) INTO
  1838.                $( CASE S.LOCAL:  OUT2(S.LIMBC, RESULT2*2)
  1839.                                  OUT1(S.LOCADDR)
  1840.                                  RETURN
  1841.  
  1842.                   CASE S.GLOBAL: OUT2(S.GLBADDR, RESULT2)
  1843.                                  RETURN
  1844.  
  1845.                   CASE S.LABEL:  OUT2(S.LABADDR, RESULT2)
  1846.                                  RETURN
  1847.  
  1848.                   CASE S.NUMBER: TRANSREPORT("Cannot take addr of %s", X)
  1849.                   DEFAULT:       RETURN
  1850.                $)
  1851.             $)
  1852.  
  1853.         CASE S.RV:
  1854.             LOADHL(H2!X,SAVE)
  1855.             RETURN
  1856.  
  1857.         CASE S.VECAP:
  1858.          $( H1!X := S.PLUS
  1859.             LOADHL(X,SAVE)
  1860.             H1!X := S.VECAP
  1861.             RETURN   $)  
  1862.    $)
  1863. $)
  1864.  
  1865. AND LOADDE(X, SAVE) BE
  1866. // Load DE with expression
  1867. $( SWITCHON H1!X INTO
  1868.    $(   CASE S.TRUE:   OUT2(S.LIMDE,TRUE)
  1869.                        RETURN
  1870.         CASE S.FALSE:  OUT2(S.LIMDE,FALSE)
  1871.                        RETURN
  1872.  
  1873.         CASE S.NUMBER: OUT2(S.LIMDE,H2!X)
  1874.         CASE S.QUERY:  RETURN
  1875.  
  1876.         CASE S.RV:     // Need to load RV into DE a lot
  1877.         CASE S.VECAP:  // hence this hack
  1878.              IF SAVE THEN 
  1879.                  $( OUT1(S.PUSHHL)
  1880.                     STKDEPTH := STKDEPTH+1
  1881.                  $)
  1882.              LOADLV(X, FALSE)
  1883.              OUT1(S.RV)
  1884.              IF SAVE THEN
  1885.                  $( OUT1(S.POPHL)
  1886.                     STKDEPTH := STKDEPTH-1
  1887.                  $)
  1888.              RETURN
  1889.  
  1890.         CASE S.TABLE:
  1891.         CASE S.STRING:
  1892.          $( LET L = NEXTPARAM()
  1893.             OUT2(S.LABDEADR,L)
  1894.             ADDLIT(L,X)
  1895.             RETURN
  1896.          $)
  1897.  
  1898.  
  1899.         CASE S.NAME:
  1900.          $( LET M = TRANSNAME(X)
  1901.             IF M=CACHE.MODE & RESULT2=CACHE.VAL & ~SAVE THEN
  1902.                 $( OUT1(S.EXCHG)
  1903.                    RETURN
  1904.                 $)
  1905.             SWITCHON M INTO
  1906.             $( CASE S.LOCAL:  OUTB(S.LDEIX, RESULT2*2)
  1907.                               OUTB(S.LDDIX, (RESULT2*2)+1)
  1908.                               RETURN
  1909.  
  1910.                CASE S.GLOBAL: OUT2(S.LDDEGLB, RESULT2)
  1911.                               RETURN
  1912.  
  1913.                CASE S.LABEL:  OUT2(S.LDDELAB, RESULT2)
  1914.                               RETURN
  1915.  
  1916.                CASE S.NUMBER: OUT2(S.LIMDE, RESULT2)
  1917.                DEFAULT:       RETURN
  1918.             $)
  1919.          $)
  1920.  
  1921.         CASE S.PLUS:     SWAPROUND(X)
  1922.         CASE S.MINUS:    IF CONSTANT(H3!X) & RESULT2<8 THEN
  1923.                           $( LET C = RESULT2
  1924.                              LOADDE(H2!X, SAVE)
  1925.                                 FOR I = 1 TO C DO
  1926.                                       OUT1(H1!X=S.PLUS -> S.INCDE, S.DECDE)
  1927.                                 RETURN
  1928.                              $)
  1929. // Fall through
  1930.  
  1931.         DEFAULT:
  1932.             IF SAVE THEN OUT1(S.EXCHG)
  1933.             LOADHL(X, SAVE)
  1934.             OUT1(S.EXCHG)
  1935.             RETURN
  1936.     $)
  1937. $)
  1938.  
  1939.  
  1940. AND PUSHDE(B) BE IF B THEN $( OUT1(S.PUSHDE)
  1941.                               STKDEPTH := STKDEPTH + 1  $)
  1942.  
  1943.  
  1944. AND POPDE(B) BE  IF B THEN $( OUT1(S.POPDE)
  1945.                               STKDEPTH := STKDEPTH - 1  $)
  1946.  
  1947.  
  1948.  
  1949.  
  1950.  
  1951. AND ASSIGN(X, Y) BE
  1952. $(1 SWITCHON H1!X INTO
  1953.      $( CASE S.COMMA:
  1954.             UNLESS H1!Y=S.COMMA DO
  1955.                 $( TRANSREPORT("Unbalanced assignment")
  1956.                    RETURN   $)
  1957.             ASSIGN(H2!X, H2!Y)
  1958.             ASSIGN(H3!X, H3!Y)
  1959.             RETURN
  1960.  
  1961.         CASE S.NAME:
  1962.          $( LET M = TRANSNAME(X)
  1963.             LET A = RESULT2
  1964.  
  1965.             SWITCHON  M INTO
  1966.             $( CASE S.LOCAL:  IF H1!Y = S.PLUS THEN // check for X := X+1
  1967.                                      $( SWAPROUND(Y)
  1968.                                         IF H2!Y = X & 
  1969.                                            CONSTANT(H3!Y) &
  1970.                                            RESULT2=1 THEN
  1971.                                                $( OUTB(S.INCLOC, A*2)
  1972.                                                   OUT1(S.SKIP)
  1973.                                               OUTB(S.INCLOC, (A*2)+1)
  1974.                                                   RETURN
  1975.                                                $)
  1976.                                      $)
  1977.  
  1978.                               STORELOCAL(A, Y)
  1979.                               RETURN
  1980.  
  1981.                CASE S.GLOBAL: 
  1982.                CASE S.LABEL:  LOAD(Y)
  1983.                               $( LET CM, CV = CACHE.MODE, CACHE.VAL
  1984.                                  OUT2((M=S.LABEL->S.STHLLAB, S.STHLGLB) ,A)
  1985.                                  TEST CM = S.NUMBER THEN CACHE.MODE, CACHE.VAL := CM, CV
  1986.                                                     ELSE CACHE.MODE, CACHE.VAL := M, A
  1987.                                  RETURN
  1988.                               $)
  1989.  
  1990.                CASE S.NUMBER: TRANSREPORT("Cannot assign to %s", X)
  1991.                DEFAULT:       RETURN
  1992.             $)
  1993.          $)
  1994.  
  1995.         CASE S.BYTEAP:
  1996.             UNLESS BYTEADDR(X, FALSE) DO
  1997.                $( LOADLR(X)
  1998.                   OUT1(S.ADDHH)
  1999.                   OUT1(S.PLUS)
  2000.                $)
  2001.             // Now have byte address in HL, for easy cases, get byte
  2002.             // in A, and store, else get value in DE and store E            
  2003.             IF CONSTANT(Y) THEN
  2004.                $( OUTB(S.STBYTIM, RESULT2)
  2005.                   RETURN
  2006.                $)
  2007.  
  2008.             IF H1!Y = S.NAME THEN
  2009.                $( SWITCHON TRANSNAME(Y) INTO
  2010.                      $( CASE S.LOCAL:   OUTB(S.LDAIX, RESULT2*2)
  2011.                                         ENDCASE
  2012.  
  2013.                         CASE S.GLOBAL:  OUT2(S.LDAGLB, RESULT2)
  2014.                                         ENDCASE
  2015.  
  2016.                         CASE S.LABEL:   OUT2(S.LDALAB, RESULT2)
  2017.                         DEFAULT:        ENDCASE
  2018.   
  2019.                         // Manifest are dealt with by the constant code
  2020.                      $)
  2021.  
  2022.                   OUT1(S.STBYTEA)
  2023.                   RETURN
  2024.                $)
  2025.  
  2026.             LOADDE(Y,TRUE)
  2027.             OUT1(S.STBYTE)
  2028.             RETURN
  2029.  
  2030.         CASE S.RV: CASE S.VECAP:
  2031.              TEST SIMPLEOP(H1!Y) THEN // Get HL first to avoid saving DE
  2032.                 $( LOADLV(X, FALSE)
  2033.                    LOADDE(Y, TRUE)
  2034.                 $)
  2035.              ELSE
  2036.                 $( LOADDE(Y, FALSE)
  2037.                    LOADLV(X, TRUE)
  2038.                 $)
  2039.              OUT1(S.STIND)
  2040.              RETURN
  2041.  
  2042.         CASE S.OF:
  2043.             $( LET SEL = EVALCONST(H2!X)
  2044.                LET SIZE   = (SLCT 4:12) OF @SEL
  2045.                LET SHIFT  = (SLCT 4:8)  OF @SEL
  2046.  
  2047.                LOAD(H3!X)  
  2048.                ADDCONST((SLCT 8) OF @SEL)
  2049.                // Now have address in HL
  2050.  
  2051.                TEST CONSTANT(Y) & SIZE=1 THEN // Can use the 'set', 'res' etc
  2052.                    $( OUT1(S.ADDHH)
  2053.                       IF SHIFT>=8 THEN // High byte is second
  2054.                         $( OUT1(S.INCHL)
  2055.                            SHIFT := SHIFT-8
  2056.                         $)
  2057.                       OUTB(S.BIT, (SHIFT<<3) | (((RESULT2&1)=0) -> #B10000110,
  2058.                                                                    #B11000110))
  2059.                                                       // This rather breaks the
  2060.                    $)                                 // abstraction, sorry.
  2061.                ELSE   
  2062.                    $( LOADDE(Y, TRUE)
  2063.                       TEST SIZE=0 THEN // Size is whole word
  2064.                             OUT1(S.STIND)
  2065.                       ELSE TEST (SIZE=8) & ((SHIFT=0) | (SHIFT=8)) THEN
  2066.                          $( // Can use byte instrs
  2067.                             OUT1(S.ADDHH)
  2068.                             IF SHIFT=8 THEN OUT1(S.INCHL)
  2069.                             OUT1(S.STBYTE)
  2070.                          $)
  2071.                       ELSE            
  2072.                          $( OUT2(S.LIMBC, (-1>>(16-SIZE)) << SHIFT) // The mask
  2073.                             OUTB(S.LIMA, SHIFT)
  2074.                             OUT1(S.OFLV)
  2075.                          $)
  2076.                    $)
  2077.                RETURN
  2078.             $)
  2079.  
  2080.  
  2081.         DEFAULT: TRANSREPORT("Assignment to RTYPE expr")   
  2082. $)1
  2083.  
  2084. AND TRANSOF(X, SAVE) = VALOF
  2085. $( LET SEL = EVALCONST(H2!X)
  2086.    LET SIZE   = (SLCT 4:12) OF @SEL
  2087.    LET SHIFT  = (SLCT 4:8)  OF @SEL
  2088.  
  2089.    LOADHL(H3!X, SAVE) // Need to keep DE if this is assignment
  2090.    ADDCONST((SLCT 8) OF @SEL)
  2091.    // Now have address in HL
  2092.  
  2093.    TEST SIZE=1 THEN // Can use the 'bit'
  2094.       $(  OUT1(S.ADDHH)
  2095.           IF SHIFT>=8 THEN // High byte is second
  2096.             $( OUT1(S.INCHL)
  2097.                SHIFT := SHIFT-8
  2098.             $)
  2099.          OUTB(S.BIT, (SHIFT<<3) | #B01000110) // This rather breaks the
  2100.          RESULTIS TRUE                         // abstraction, sorry.
  2101.       $)
  2102.    ELSE   
  2103.       $( TEST SIZE=0 THEN // Size is whole word
  2104.                 OUT1(S.RV)
  2105.          ELSE TEST (SIZE=8) & ((SHIFT=0) | (SHIFT=8)) THEN
  2106.              $( // Can use byte instrs
  2107.                 OUT1(S.ADDHH)
  2108.                 IF SHIFT=8 THEN OUT1(S.INCHL)
  2109.                 OUT1(S.LDBYTE)
  2110.                 OUTB(S.LDHIM, 0)
  2111.              $)
  2112.          ELSE
  2113.              $( OUT2(S.LIMBC, (-1>>(16-SIZE)) << SHIFT) // The mask
  2114.                 OUTB(S.LIMA, SHIFT)
  2115.                 OUT1(S.OFRV)
  2116.              $)
  2117.          RESULTIS FALSE
  2118.       $)
  2119. $)
  2120.  
  2121. AND ADDCONST(C) BE 
  2122. $( TEST -4<=C<=4 THEN
  2123.          FOR K = 1 TO ABS C DO OUT1(C<0 -> S.DECHL, S.INCHL)
  2124.    ELSE
  2125.        $( OUT2(S.LIMBC, C)
  2126.           OUT1(S.ADDHB)
  2127.        $)
  2128. $)
  2129.  
  2130.  
  2131. AND TRANSCALL(X) BE
  2132. $( LET ARGBASE = ARGSSP
  2133.    LET ARGLIST = H3!X
  2134.    UNLESS ARGLIST = 0 DO
  2135.       $( LET FIRSTARG = ?
  2136.          TEST H1!ARGLIST = S.COMMA THEN // More than one arg
  2137.             $( LET SECONDARG = H3!ARGLIST
  2138. // This is to allow ARGSSP to be zero during the evaluation of the second
  2139. // arg, thus eliminating redundant BUMPP's if it is a function call
  2140.                TEST H1!SECONDARG = S.COMMA THEN 
  2141.                     $( STORELOCAL(ARGSSP+1, H2!SECONDARG)
  2142.                        ARGSSP := ARGSSP+2
  2143.                        LOADLIST(H3!SECONDARG, @ARGSSP)
  2144.                     $)
  2145.                ELSE 
  2146.                     $( STORELOCAL(ARGSSP+1, SECONDARG)
  2147.                        ARGSSP :=  ARGSSP+2
  2148.                     $)
  2149.                FIRSTARG := H2!ARGLIST // and then first
  2150.             $)
  2151.          ELSE 
  2152.                FIRSTARG := ARGLIST   // this case when one arg only
  2153.  
  2154.          TEST CONSTANT(FIRSTARG) THEN OUT2(S.LIMDE, RESULT2)
  2155.                                  ELSE LOADDE(FIRSTARG, FALSE)
  2156.       $)
  2157.     LOADHL(H2!X, ARGLIST ~= 0) // Get proc value
  2158.     BUMPP(ARGBASE) // for nested calls
  2159.     OUT1(ARGLIST=0 -> S.SRTAP, S.RTAP) // srtap for zero args
  2160.     BUMPP(-ARGBASE)
  2161.     ARGSSP := ARGBASE
  2162.  $)
  2163.  
  2164. AND LOADLIST(X, COUNTVAR) BE
  2165. $( WHILE H1!X = S.COMMA DO
  2166.      $( STORELOCAL(!COUNTVAR, H2!X)
  2167.         !COUNTVAR := (!COUNTVAR)+1
  2168.         X := H3!X
  2169.      $)
  2170.    STORELOCAL(!COUNTVAR, X)
  2171.    !COUNTVAR := (!COUNTVAR)+1
  2172. $)
  2173.  
  2174. AND BYTEADDR(X, SAVE) = VALOF
  2175. // Compile code to get byte addr of X%Y if simple, return TRUE if done.
  2176.   $( IF CONSTANT(H3!X) & 0<=RESULT2<=4 THEN
  2177.          $( LET C=RESULT2
  2178.             LOADHL(H2!X,SAVE)
  2179.             FOR K = 1 TO C/2 DO OUT1(S.INCHL) // These are worth 2
  2180.             OUT1(S.ADDHH)                     // because of this.
  2181.             IF C REM 2 DO OUT1(S.INCHL)       // if c is odd.
  2182.             RESULTIS TRUE
  2183.          $)
  2184.      RESULTIS FALSE
  2185. $)
  2186.  
  2187. AND STORELOCAL(S, X) BE
  2188. $( IF H1!X=S.QUERY RETURN
  2189.    TEST CONSTANT(X) THEN
  2190.      $( LET M = CACHE.MODE
  2191.         LET A = (S*2) /\ #XFF
  2192.         OUT2(S.STIXIM,A+(RESULT2<<8)) // Pack the address and data bytes
  2193.         OUT2(S.STIXIM,A+1+(RESULT2＀)) // into the word arg.
  2194.         UNLESS M=S.LOCAL & CACHE.VAL=S DO CACHE.MODE := M
  2195.      $)
  2196.    ELSE
  2197.      $( LOADHL(X, FALSE)
  2198.         OUTB(S.STLIX, S*2)
  2199.         OUTB(S.STHIX, (S*2)+1)
  2200.         CACHE.MODE, CACHE.VAL := S.LOCAL, S
  2201.      $)
  2202. $)
  2203.  
  2204. AND EVALCONST(X) = VALOF
  2205. $( IF CONSTANT(X) THEN RESULTIS RESULT2
  2206.    
  2207.    IF H1!RESULT2 = S.QUERY RESULTIS 0 // Query is legal in const exprs
  2208.                            // But we don't want to treat it as having a value
  2209.    
  2210.    TEST H1!RESULT2 = S.NAME THEN 
  2211.                $( LET N = RESULT2
  2212.                   IF TRANSNAME(N) THEN 
  2213.                           TRANSREPORT("Variable %s used in constant expr", N)
  2214.                $)
  2215.           ELSE TRANSREPORT("Error in constant expr")
  2216. $)
  2217.  
  2218. AND CONSTANT(X) = VALOF
  2219. // if X is a constant expr, return TRUE, and it's value in RESULT2
  2220. // else return duff node in RESULT2
  2221. $( LET A, B, C = ?, ?, ?
  2222.  
  2223.    IF X=0  THEN 
  2224.         $( RESULT2 := 0
  2225.            RESULTIS TRUE  // For optional parts of SLCT
  2226.         $)
  2227.  
  2228.    SWITCHON H1!X INTO
  2229.      $( DEFAULT: RESULT2 := X
  2230.                  RESULTIS FALSE
  2231.  
  2232.         CASE S.NAME:
  2233.           TEST CELLWITHNAME(X) = S.NUMBER THEN    RESULTIS TRUE
  2234.                                           ELSE $( RESULT2 := X
  2235.                                                   RESULTIS FALSE
  2236.                                                $)
  2237.         CASE S.SLCT:
  2238.  
  2239.           TEST CONSTANT(H4!X) THEN C := RESULT2
  2240.                               ELSE RESULTIS FALSE
  2241.  
  2242.         CASE S.PLUS:   CASE S.MINUS:  CASE S.DIV: CASE S.REM: CASE S.MULT:
  2243.         CASE S.LOGOR:  CASE S.LOGAND: CASE S.EQV: CASE S.NEQV:
  2244.         CASE S.LSHIFT: CASE S.RSHIFT:
  2245.  
  2246.           TEST CONSTANT(H3!X) THEN B := RESULT2
  2247.                               ELSE RESULTIS FALSE
  2248.  
  2249.         CASE S.ABS: CASE S.NEG: CASE S.NOT:
  2250.  
  2251.           TEST CONSTANT(H2!X) THEN A := RESULT2
  2252.                               ELSE RESULTIS FALSE
  2253.          
  2254.         CASE S.NUMBER: CASE S.TRUE: CASE S.FALSE:
  2255.  
  2256.           RESULT2 := VALOF SWITCHON H1!X INTO
  2257.            $( CASE S.NUMBER: RESULTIS H2!X
  2258.               CASE S.TRUE:   RESULTIS TRUE
  2259.               CASE S.FALSE:  RESULTIS FALSE
  2260.  
  2261.               CASE S.NEG:    RESULTIS  -  A
  2262.               CASE S.ABS:    RESULTIS ABS A
  2263.               CASE S.NOT:    RESULTIS NOT A
  2264.  
  2265.               CASE S.MULT:   RESULTIS A   *    B
  2266.               CASE S.PLUS:   RESULTIS A   +    B
  2267.               CASE S.MINUS:  RESULTIS A   -    B
  2268.               CASE S.LSHIFT: RESULTIS A   <<   B
  2269.               CASE S.RSHIFT: RESULTIS A   >>   B
  2270.               CASE S.LOGOR:  RESULTIS A LOGOR  B
  2271.               CASE S.LOGAND: RESULTIS A LOGAND B
  2272.               CASE S.EQV:    RESULTIS A  EQV   B
  2273.               CASE S.NEQV:   RESULTIS A  NEQV  B
  2274.  
  2275.               CASE S.DIV: CASE S.REM:
  2276.                   IF B=0 THEN $( TRANSREPORT("Division by zero")
  2277.                                  B := 1
  2278.                               $)
  2279.                   RESULTIS H1!X=S.DIV -> A / B, A REM B
  2280.  
  2281.               CASE S.SLCT:
  2282.                   IF A=0 THEN A := 16-B // use rest of word if size is zero
  2283.                   IF A>16 | B>15 | C>255 | (A+B)>16 
  2284.                           THEN TRANSREPORT("Illegal value(s) in SLCT")
  2285.                   RESULTIS ((A) << 12)  + (B<<8) + C
  2286.            $)
  2287.          RESULTIS TRUE
  2288.         
  2289.      $)
  2290.  
  2291. $)
  2292.  
  2293. .
  2294.  
  2295. //TRN2
  2296. SECTION "TRN2"
  2297. GET "COMPHDR"
  2298.  
  2299. // Odds and ends for TRN
  2300.  
  2301. STATIC $(
  2302. PARAMNUMBER=?; LIT=?; LITS=?; 
  2303. DVECBASE=?; REACHABLE=?
  2304. $)
  2305.  
  2306. LET NEXTPARAM() = VALOF
  2307.     $( PARAMNUMBER := PARAMNUMBER + 1
  2308.        RESULTIS PARAMNUMBER  $)
  2309.  
  2310. AND TRANSREPORT(S, N) BE
  2311. $( SELECTOUTPUT(CON)                                                  
  2312.    REPORTCOUNT := REPORTCOUNT + 1                                          
  2313.    IF REPORTCOUNT = REPORTMAX THEN                                         
  2314.                           WRITES("*NFurther errors suppressed.*N*N")       
  2315.    IF REPORTCOUNT < REPORTMAX THEN                                         
  2316.       $( WRITEF("Report:   %F", S, @(H3!N))                               
  2317.          WRITEF(" in procedure %S.*N",CURPROC)                            
  2318.       $)                                                                   
  2319.    SELECTOUTPUT(OCODE)                                                     
  2320. $)                                                                         
  2321.  
  2322.  
  2323. AND COMPILEAE(X) BE
  2324. $( LET B = VEC LITMAX
  2325.    LET R = VEC 63
  2326.  
  2327.    RETTABLE := R
  2328.    FOR K = 0 TO 63 DO RETTABLE!K := 0
  2329.  
  2330.    LIT, LITS := B, 0
  2331.  
  2332.    DVECBASE, DVECP :=  TREEP, TREEP
  2333.  
  2334.    CASEB, RESULTLABEL, BREAKLABEL := -1, -1, -1
  2335.    LOOPLABEL, ENDCASELABEL := -1, -1
  2336.  
  2337.    SSP, ARGSSP := 0, 0
  2338.    REACHABLE := FALSE
  2339.    CACHE.MODE := 0
  2340.    PARAMNUMBER := 0
  2341.    CURPROC := "Main program"
  2342.  
  2343.    IF X=0 RETURN
  2344.  
  2345.    WRITE1(S.STARTSECT)
  2346.    IF H1!X=S.SECTION THEN
  2347.       $(  WRITE1(S.SECTION)
  2348.           WRITESTRING(@H2!(H2!X))
  2349.           X:=H3!X $)
  2350.  
  2351.    DECLLABELS(X)
  2352.    TRANS(X)
  2353.  
  2354.    IF LITS \=0 THEN DUMPLITS() // Dump any remaining literals
  2355. $)
  2356.  
  2357. AND BUMPP(VAL) BE
  2358. $( IF VAL=0 RETURN
  2359.    IF VAL=1 THEN
  2360.       $( OUT1(S.INCIX)
  2361.          OUT1(S.INCIX)
  2362.          RETURN
  2363.       $)
  2364.    IF VAL=-1 THEN
  2365.       $( OUT1(S.DECIX)
  2366.          OUT1(S.DECIX)
  2367.          RETURN
  2368.       $)
  2369.    OUT2(S.LIMBC, VAL*2)
  2370.    OUT1(S.ADDIXBC)
  2371. $)
  2372.  
  2373. AND COMISJUMP(X) = VALOF
  2374. // If X is a command which can be compiled to a jump, return the
  2375. // Label and the new stack level in RESULT2. If it should be a jump
  2376. // But there is an error, return zero and message in RESULT2
  2377. // Else just return zero
  2378. $( SWITCHON H1!X INTO
  2379.    $( CASE S.LOOP:
  2380.          IF LOOPLABEL<0 THEN
  2381.             $( RESULT2 := "Illegal LOOP"
  2382.                RESULTIS 0
  2383.             $)
  2384.          IF LOOPLABEL=0 DO LOOPLABEL := NEXTPARAM()
  2385.          RESULT2 := LOOPSTACK
  2386.          RESULTIS LOOPLABEL
  2387.  
  2388.       CASE S.BREAK:
  2389.          IF LOOPLABEL<0 THEN
  2390.             $( RESULT2 :=  "Illegal BREAK"
  2391.                RESULTIS 0
  2392.             $)
  2393.          IF BREAKLABEL=0 DO BREAKLABEL := NEXTPARAM()
  2394.          RESULT2 := LOOPSTACK
  2395.          RESULTIS BREAKLABEL
  2396.  
  2397.       CASE S.ENDCASE:
  2398.          IF ENDCASELABEL<0 THEN
  2399.             $( RESULT2 := "Illegal ENDCASE"
  2400.                RESULTIS 0
  2401.             $)
  2402.          IF ENDCASELABEL=0 DO ENDCASELABEL := NEXTPARAM()
  2403.          RESULT2 := CASESTACK
  2404.          RESULTIS ENDCASELABEL
  2405.  
  2406.       CASE S.RETURN:
  2407.          RESULT2 := 0
  2408.          RESULTIS RETTABLE!SFSIZE
  2409.      
  2410.       DEFAULT:
  2411.          RESULTIS 0
  2412.    $)
  2413. $)
  2414.    
  2415. AND STACKTO(S) BE
  2416. TEST S+8 < STKDEPTH THEN
  2417.     $( OUT2(S.LIMIY, 2*(STKDEPTH-S))
  2418.        OUT1(S.ADDIYSP)
  2419.        OUT1(S.LDSPIY)
  2420.     $)
  2421. ELSE
  2422.     $( LET C = STKDEPTH
  2423.        UNTIL C = S DO
  2424.          $( OUT1(S.POPDE)
  2425.             C := C - 1
  2426.          $)
  2427.     $)
  2428.  
  2429. AND JUMPCOND(X, B, L ,SAVE) BE
  2430. $(   LET SW = B
  2431.      LET CACHE.SAVE = ?
  2432.  
  2433.      SWITCHON H1!X INTO
  2434.      $( CASE S.NOT: JUMPCOND(H2!X, NOT B, L, SAVE)
  2435.                     RETURN
  2436.      
  2437.         CASE S.FALSE: SW :=  NOT SW
  2438.         CASE S.TRUE:  IF SW THEN COMPJUMP(L)
  2439.                       RETURN
  2440.  
  2441.  
  2442.         CASE S.LOGAND: SW := NOT SW
  2443.         CASE S.LOGOR:
  2444.             TEST SW THEN $( JUMPCOND(H2!X, B, L, SAVE)
  2445.                             JUMPCOND(H3!X, B, L, SAVE)  $)
  2446.  
  2447.                       OR $( LET M = NEXTPARAM()
  2448.                             JUMPCOND(H2!X, NOT B, M, SAVE)
  2449.                             JUMPCOND(H3!X, B, L, SAVE)
  2450.                             COMPLAB(M)  $)
  2451.  
  2452.             RETURN
  2453.  
  2454.         CASE S.OF:
  2455.             TEST TRANSOF(X, SAVE) THEN GOTO JP     // Result in HL
  2456.                                   ELSE GOTO CHECKZ // Result in Z
  2457.  
  2458.         CASE S.LS: CASE S.GE:
  2459.             IF CONSTANT(H3!X) & RESULT2=0 THEN
  2460.                  $( IF H1!X = S.GE THEN B := NOT B
  2461.                     LOADHL(H2!X, SAVE)
  2462.                     OUT1(S.ADDHH)
  2463.                     GOTO JPC
  2464.                  $) 
  2465. // Fall through
  2466.         CASE S.LE: CASE S.GR:
  2467.             PUSHDE(SAVE)
  2468.             LOADLR(X)
  2469.             OUT1(H1!X)
  2470.             POPDE(SAVE)
  2471. JPC:
  2472.             TEST B THEN OUT2(S.JPC, L)
  2473.                    ELSE OUT2(S.JPNC, L)
  2474.             RETURN
  2475.  
  2476.         CASE S.EQ: B := NOT B
  2477.         CASE S.NE:
  2478.             SWAPROUND(X)
  2479.             IF CONSTANT(H3!X) THEN
  2480.                 $( LET C=RESULT2
  2481.                    IF (H1!(H2!X)=S.NAME) & (CELLWITHNAME(H2!X)=S.LOCAL) THEN
  2482.                      $( // Possible special case for locals
  2483.                         IF 0<=C<=255 THEN
  2484.                         UNLESS (CACHE.MODE = S.LOCAL) & (CACHE.VAL = RESULT2) THEN
  2485.                           $( CACHE.SAVE := CACHE.MODE
  2486.                              OUTB(S.LDAIX, RESULT2*2)
  2487.                              IF C=1 THEN OUT1(S.DECA)
  2488.                              IF C>=2 THEN OUTB(S.SUBA, C)
  2489.                              OUTB(S.ORIX, (RESULT2*2)+1)
  2490.                              CACHE.MODE := CACHE.SAVE
  2491.                              GOTO JP
  2492.                           $)
  2493.                      $)
  2494.                // else fall through
  2495.                    LOADHL(H2!X, SAVE)
  2496.                    IF -3<=C<=1 THEN // best way for these
  2497.                      $( ADDCONST(-C)
  2498.                         GOTO CHECKZ
  2499.                      $)
  2500.                    TEST 2<=C<=255 THEN // and for these
  2501.                      $( CACHE.SAVE := CACHE.MODE
  2502.                         OUT1(S.LDAL)
  2503.                         OUTB(S.SUBA, C)
  2504.                         OUT1(S.ORH)
  2505.                         CACHE.MODE := CACHE.SAVE
  2506.                      $)
  2507.                    ELSE
  2508.                      $( OUT2(S.LIMBC, C) // Whats left gets awful code
  2509.                         OUT1(S.ORA)
  2510.                         OUT1(S.SUBHB)
  2511.                      $)
  2512.                    GOTO JP
  2513.                 $)
  2514.  
  2515.             // Here is non-constant equals
  2516.             PUSHDE(SAVE)
  2517.             LOADLR(X)
  2518.             OUT1(S.ORA)
  2519.         OUT1(S.MINUS)
  2520.             POPDE(SAVE)
  2521.             GOTO JP
  2522.  
  2523.         CASE S.NAME:
  2524.             IF CELLWITHNAME(X) = S.LOCAL THEN
  2525.             UNLESS (CACHE.MODE = S.LOCAL) & (CACHE.VAL = RESULT2) DO
  2526.               $( CACHE.SAVE := CACHE.MODE
  2527.                  OUTB(S.LDAIX, RESULT2*2)
  2528.                  OUTB(S.ORIX, (RESULT2*2)+1)
  2529.                  CACHE.MODE := CACHE.SAVE
  2530.                  GOTO JP
  2531.               $)
  2532.             // else fall through
  2533.  
  2534.         DEFAULT: LOADHL(X,SAVE)
  2535.         CHECKZ:  CACHE.SAVE := CACHE.MODE
  2536.                  OUT1(S.LDAL)
  2537.              OUT1(S.ORH)
  2538.                  CACHE.MODE := CACHE.SAVE
  2539.         JP:      CACHE.SAVE := CACHE.MODE
  2540.                  TEST B THEN OUT2(S.JPNZ, L)
  2541.                         ELSE OUT2(S.JPZ, L)
  2542.                  CACHE.MODE := CACHE.SAVE
  2543.                  RETURN     
  2544.      $)
  2545. $)
  2546.  
  2547.  
  2548. AND CHECKDISTINCT(E) BE
  2549.        UNTIL E=TREEP DO
  2550.           $( IF E ~= H2!(H1!E) DO TRANSREPORT("%s declared twice", H1!E)
  2551.              E := E + 3  $)
  2552.  
  2553.  
  2554. AND ADDNAME(N, P, V) BE
  2555. $( LET A = TREEP+3
  2556.    IF A >= TREETOP DO ABORT("Out of workspace")
  2557.    H1!TREEP, H2!TREEP, H3!TREEP := N, P, V
  2558.    H2!N := TREEP // The hint
  2559.    TREEP := A
  2560.    IF TREEP>TREEPMAX THEN TREEPMAX := TREEP
  2561. $)  
  2562.  
  2563.  
  2564. AND CELLWITHNAME(N) = VALOF
  2565. $( LET X = H2!N // The hint
  2566.    IF X THEN // else not ever declared
  2567.       $( IF X>=TREEP THEN X := TREEP-3 // declaration superceded
  2568.          UNTIL X=(DVECBASE-3) DO
  2569.               $( IF H1!X=N THEN // Found it
  2570.                    $( LET M = H2!X
  2571.                       H2!N := X // update the hint
  2572.                       TEST M = S.LOCAL & X<DVECP THEN 
  2573.                           $( RESULT2 := FALSE // DFV error
  2574.                              RESULTIS 0 
  2575.                           $)
  2576.                       ELSE $( RESULT2 := H3!X
  2577.                               RESULTIS M // Found
  2578.                            $)
  2579.                    $)    
  2580.                  X := X-3
  2581.              $)
  2582.       $)
  2583.    
  2584.    RESULT2 := TRUE
  2585.    RESULTIS 0 // Not found
  2586. $)
  2587.  
  2588.  
  2589. AND ADDLIT(L, X) BE
  2590. $( IF LITS>=LITMAX DO
  2591.         $( LET M = NEXTPARAM() // dump overflowing literal pool
  2592.            COMPJUMP(M)         // by compiling a branch round it
  2593.            COMPLAB(M)  $)
  2594.  
  2595.    LIT!LITS, LIT!(LITS+1) := L, X
  2596.    LITS := LITS + 2
  2597.  
  2598.    IF H1!X = S.TABLE THEN
  2599.       $( LET Y = H2!X
  2600.          WHILE Y DO
  2601.             $( H1!Y := EVALCONST(H1!Y)
  2602.                Y := H2!Y
  2603.             $)
  2604.       $)
  2605. $)
  2606.  
  2607.  
  2608. AND TRANSNAME(X)=VALOF
  2609. $( LET M = CELLWITHNAME(X)
  2610.    IF M=0 THEN TRANSREPORT(RESULT2 -> "%s not declared",
  2611.                                       "Dynamic free variable %s used", X)
  2612.    RESULTIS M
  2613. $)
  2614.  
  2615. AND COMPRETURN() BE
  2616. $( UNLESS REACHABLE RETURN
  2617.    TEST (RETTABLE!SFSIZE)=0 THEN 
  2618.       $( UNLESS SFSIZE=0 DO
  2619.             $( RETTABLE!SFSIZE := NEXTPARAM()
  2620.                COMPLAB(RETTABLE!SFSIZE)
  2621.                BUMPP(-SFSIZE)
  2622.             $)
  2623.          OUT1(S.RET)
  2624.          STOPFLOW()
  2625.       $)
  2626.    ELSE  COMPJUMP(RETTABLE!SFSIZE)
  2627. $)
  2628.  
  2629. AND COMPJUMP(L) = VALOF
  2630. $( LET OLD = REACHABLE
  2631.    OUT2(S.JPLAB, L)
  2632.    STOPFLOW()
  2633.    RESULTIS OLD
  2634. $)
  2635.  
  2636. AND COMPLAB(L) BE
  2637. // If control can't fall into the label from above, use NEWLAB.
  2638. // this is used by the loaders jump short-circuiting
  2639. $( LET OLDR = REACHABLE
  2640.    REACHABLE := TRUE
  2641.    OUT2((OLDR -> S.LABDEF, S.NEWLAB), L)
  2642. $)
  2643.  
  2644. AND OUT2(I, A) BE IF REACHABLE THEN $( CACHE.MODE := 0
  2645.                                        WRITE2(I, A)
  2646.                                     $)
  2647.  
  2648. AND OUTB(I, A) BE IF REACHABLE THEN $( CACHE.MODE := 0
  2649.                                        WRITEB(I, A)
  2650.                                     $)
  2651.  
  2652. AND OUT1(I) BE    IF REACHABLE THEN $( CACHE.MODE := 0
  2653.                                        WRITE1(I)
  2654.                                     $)
  2655.  
  2656. AND STOPFLOW() BE
  2657. $( REACHABLE := FALSE
  2658.    IF LITS > (LITMAX/2) DUMPLITS() // Quit if reasonable room left
  2659.                               // so as not to waste bytes aligning
  2660. $)
  2661.  
  2662. AND DUMPLITS() BE
  2663. $( WRITE1(S.WALIGN) // This stuff must be aligned
  2664.    FOR K= 0 TO LITS-1 BY 2 DO // Dump the literal pool
  2665.      $( LET X = LIT!(K+1)
  2666.         LET LABEL = LIT!K
  2667.         SWITCHON H1!X INTO
  2668.           $( CASE S.TABLE:
  2669.              $( LET Y = H2!X
  2670.                 WRITE2(S.LABDEF, LABEL)
  2671.                 WHILE Y DO
  2672.                 $( WRITE2(S.DW, H1!Y)
  2673.                    Y := H2!Y
  2674.                 $)
  2675.                 ENDCASE
  2676.              $)
  2677.  
  2678.              CASE S.STRING:
  2679.              $( LET S = @(H2!X)
  2680.                 WRITE2(S.LABDEF, LABEL)
  2681.                 FOR K = 0 TO S%0 DO WRITEB(S.DB, S%K)
  2682.                 WRITE1(S.WALIGN) // realign
  2683.                 ENDCASE
  2684.              $)
  2685.  
  2686.              CASE S.FNDEF:
  2687.              CASE S.RTDEF:
  2688.              CASE S.COLON:
  2689.              CASE S.STATIC:
  2690.                 WRITE2(S.LABSYM, LABEL)
  2691.                 WRITESTRING(@H3!(H2!X)) 
  2692.                 TEST H1!X = S.STATIC 
  2693.                      THEN WRITE2(S.DW, H3!X)
  2694.                      ELSE WRITE2(S.DWLAB, (H1!X=S.COLON -> H4!X, H5!X))
  2695.                 ENDCASE
  2696.       
  2697.          $)
  2698.     $)
  2699.     LITS := 0 // Empty the literal pool
  2700. $)
  2701.  
  2702. AND WRITE1(I) BE WRCH(I)
  2703.  
  2704. AND WRITEB(I, A) BE
  2705. $( WRCH(I)
  2706.    WRCH(A)
  2707. $)
  2708.  
  2709. AND WRITE2(I, A) BE
  2710. $( WRCH(I)
  2711.    WRCH(A)
  2712.    WRCH(A>>8)
  2713. $)
  2714.  
  2715. AND WRITESTRING(S) BE
  2716. $( WRITES(S)
  2717.    WRCH(0)
  2718. $)
  2719.  
  2720. .
  2721.