"PER BRINCH HANSEN
 INFORMATION SCIENCE
 CALIFORNIA INSTITUTE OF TECHNOLOGY
 PASADENA, CALIFORNIA 91125

 PDP 11/45 CONCURRENT/SEQUENTIAL PASCAL
 COMPILER PASS 6: CODE SELECTION

 9 SEPTEMBER 1974"
(NUMBER)

"###########
#  PREFIX  #
###########"

CONST              EOL = '(:10:)';     FF = '(:12:)';      EOM = '(:25:)';
PRINTLIMIT = 18;   MAXDIGIT = 6;
WORDLENGTH = 2 "BYTES";
REALLENGTH = 8 "BYTES";
SETLENGTH = 16 "BYTES";
LISTOPTION = 0;    SUMMARYOPTION = 1;  TESTOPTION = 2;     CHECKOPTION = 3;
CODEOPTION = 4;    NUMBEROPTION = 5;
MAXWORD = 100;

TYPE FILE = 1..2;

CONST IDLENGTH = 16;
TYPE IDENTIFIER = ARRAY (.1..IDLENGTH.) OF CHAR;

TYPE   POINTER = @ INTEGER;
TABLEPTR = @TABLE;
TABLE = RECORD
          NEXTPORTION: TABLEPTR;
          CONTENTS: ARRAY (.1..MAXWORD.) OF INTEGER
        END;
TABLEPART = RECORD
              PROGLENGTH, CODELENGTH, STACKLENGTH,
                VARLENGTH: INTEGER;
              JUMPTABLE, BLOCKTABLE, STACKTABLE,
                CONSTTABLE: TABLEPTR
            END;
TABLESPTR = @TABLEPART;
OPTION = LISTOPTION..NUMBEROPTION;
PASSPTR = @PASSLINK;
PASSLINK =
  RECORD
    OPTIONS: SET OF OPTION;
    LABELS, BLOCKS, CONSTANTS, RESETPOINT: INTEGER;
    TABLES: TABLESPTR
  END;

TYPE ARGTAG =
  (NILTYPE, BOOLTYPE, INTTYPE, IDTYPE, PTRTYPE);

TYPE ARGTYPE = RECORD
                 CASE TAG: ARGTAG OF
                   NILTYPE, BOOLTYPE: (BOOL: BOOLEAN);
                   INTTYPE: (INT: INTEGER);
                   IDTYPE: (ID: IDENTIFIER);
                   PTRTYPE: (PTR: PASSPTR)
               END;

CONST MAXARG = 10;
TEXT_LENGTH = 18;
TYPE ARGLIST = ARRAY (.1..MAXARG.) OF ARGTYPE;
  TEXT_TYPE = ARRAY (.1..TEXT_LENGTH.) OF CHAR;

CONST PAGELENGTH = 256;
TYPE PAGE = ARRAY (.1..PAGELENGTH.) OF INTEGER;

PROCEDURE READ(VAR C: CHAR);
PROCEDURE WRITE(C: CHAR);
PROCEDURE NOTUSED1;
PROCEDURE NOTUSED2;
PROCEDURE GET(F: FILE; P: INTEGER; VAR BLOCK: UNIV PAGE);
PROCEDURE PUT(F: FILE; P: INTEGER; BLOCK: UNIV PAGE);
FUNCTION FILE_LENGTH(F:FILE): INTEGER;
PROCEDURE MARK(VAR TOP: INTEGER);
PROCEDURE RELEASE(TOP: INTEGER);

PROGRAM MAIN(VAR PARAM: ARGLIST);

"#############################################
#  PASS(VAR OK: BOOLEAN; VAR LINK: POINTER)  #
#############################################"

CONST

"INPUT OPERATORS"

PUSHCONST1 = 0;    PUSHVAR1 = 1;       PUSHIND1 = 2;       PUSHADDR1 = 3;
FIELD1 = 4;        INDEX1 = 5;         POINTER1 = 6;       VARIANT1 = 7;
RANGE1 = 8;        ASSIGN1 = 9;        ASSIGNTAG1 = 10;    COPY1 = 11;
NEW1 = 12;         NOT1 = 13;          AND1 = 14;          OR1 = 15;
NEG1 = 16;         ADD1 = 17;          SUB1 = 18;          MUL1 = 19;
DIV1 = 20;         MOD1 = 21;          "NOT USED"          "NOT USED"
FUNCTION1 = 24;    BUILDSET1 = 25;     COMPARE1 = 26;      COMPSTRUC1 = 27;
FUNCVALUE1 = 28;   DEFLABEL1 = 29;     JUMP1 = 30;         FALSEJUMP1 = 31;
CASEJUMP1 = 32;    INITVAR1 = 33;      CALL1 = 34;         ENTER1 = 35;
RETURN1 = 36;      POP1 = 37;          NEWLINE1 = 38;      ERROR1 = 39;
CONSTANT1 = 40;    MESSAGE1 = 41;      INCREMENT1 = 42;    DECREMENT1 = 43;
PROCEDURE1 = 44;   INIT1 = 45;         PUSHLABEL1 = 46;    CALLPROG1 = 47;
EOM1=48;

"VIRTUAL DATA TYPES"

BYTETYPE = 0;      WORDTYPE = 1;       REALTYPE = 2;       SETTYPE = 3;

"VIRTUAL ADDRESSING MODES"

MODE0 = 0 "CONSTANT";
MODE1 = 1 "PROCEDURE";
MODE2 = 2 "PROGRAM";
MODE3 = 3 "PROCESS ENTRY";
MODE4 = 4 "CLASS ENTRY";
MODE5 = 5 "MONITOR ENTRY";
MODE6 = 6 "PROCESS";
MODE7 = 7 "CLASS";
MODE8 = 8 "MONITOR";
MODE9 = 9 "STANDARD";
MODE10=10 "UNDEFINED";

"COMPARISON OPERATORS"

LESS = 0;          EQUAL = 1;          GREATER = 2;        NOTLESS = 3;
NOTEQUAL = 4;      NOTGREATER = 5;     INSET = 6;

"STANDARD FUNCTIONS"

TRUNC1 = 0;        ABS1 = 1;           SUCC1 = 2;          PRED1 = 3;
CONV1 = 4;         EMPTY1 = 5;         ATTRIBUTE1 = 6;     REALTIME1 = 7;
MIN_FUNC = 0;      MAX_FUNC = 7;

"STANDARD PROCEDURES"

DELAY1 = 0;        CONTINUE1 = 1;      IO1 = 2;            START1 = 3;
STOP1 = 4;         SETHEAP1 = 5;       WAIT1 = 6;
MIN_PROC = 0;      MAX_PROC = 6;

"OUTPUT OPERATORS"

CONSTADDR2 = 0;    LOCALADDR2 = 1;     GLOBADDR2 = 2;      PUSHCONST2 = 3;
PUSHLOCAL2 = 4;    PUSHGLOB2 = 5;      PUSHIND2 = 6;       PUSHBYTE2 = 7;
PUSHREAL2 = 8;     PUSHSET2 = 9;       FIELD2 = 10;        INDEX2 = 11;
POINTER2 = 12;     VARIANT2 = 13;      RANGE2 = 14;        COPYBYTE2 = 15;
COPYWORD2 = 16;    COPYREAL2 = 17;     COPYSET2 = 18;      COPYTAG2 = 19;
COPYSTRUC2 = 20;   NEW2 = 21;          NEWINIT2 = 22;      NOT2 = 23;
ANDWORD2 = 24;     ANDSET2 = 25;       ORWORD2 = 26;       ORSET2 = 27;
NEGWORD2 = 28;     NEGREAL2 = 29;      ADDWORD2 = 30;      ADDREAL2 = 31;
SUBWORD2 = 32;     SUBREAL2 = 33;      SUBSET2 = 34;       MULWORD2 = 35;
MULREAL2 = 36;     DIVWORD2 = 37;      DIVREAL2 = 38;      MODWORD2 = 39;
BUILDSET2 = 40;    INSET2 = 41;        LSWORD2 = 42;       EQWORD2 = 43;
GRWORD2 = 44;      NLWORD2 = 45;       NEWORD2 = 46;       NGWORD2 = 47;
LSREAL2 = 48;      EQREAL2 = 49;       GRREAL2 = 50;       NLREAL2 = 51;
NEREAL2 = 52;      NGREAL2 = 53;       EQSET2 = 54;        NLSET2 = 55;
NESET2 = 56;       NGSET2 = 57;        LSSTRUCT2 = 58;     EQSTRUCT2 = 59;
GRSTRUCT2 = 60;    NLSTRUCT2 = 61;     NESTRUCT2 = 62;     NGSTRUCT2 = 63;
FUNCVALUE2 = 64;   JUMP2 = 65;         FALSEJUMP2 = 66;    CASEJUMP2 = 67;
INITVAR2 = 68;     CALL2 = 69;         CALLSYS2 = 70;      ENTER2 = 71;
EXIT2 = 72;        ENTERPROG2 = 73;    EXITPROG2 = 74;     BEGINCLAS2 = 75;
ENDCLASS2 = 76;    ENTERCLAS2 = 77;    EXITCLASS2 = 78;    BEGINMON2 = 79;
ENDMON2 = 80;      ENTERMON2 = 81;     EXITMON2 = 82;      BEGINPROC2 = 83;
ENDPROC2 = 84;     ENTERPROC2 = 85;    EXITPROC2 = 86;     POP2 = 87;
NEWLINE2 = 88;     INCRWORD2 = 89;     DECRWORD2 = 90;     INITCLASS2 = 91;
INITMON2 = 92;     INITPROC2 = 93;     PUSHLABEL2 = 94;    CALLPROG2 = 95;
TRUNCREAL2 = 96;   ABSWORD2 = 97;      ABSREAL2 = 98;      SUCCWORD2 = 99;
PREDWORD2 = 100;   CONVWORD2 = 101;    EMPTY2 = 102;       ATTRIBUTE2 = 103;
REALTIME2 = 104;   DELAY2 = 105;       CONTINUE2 = 106;    IO2 = 107;
START2 = 108;      STOP2 = 109;        SETHEAP2 = 110;     WAIT2 = 111;
MESSAGE2 = 112;    EOM2=113;

"OTHER CONSTANTS"

PDP11 = TRUE;
CONCURRENT=FALSE;
INITIALBLOCK = 1;
SPLITLENGTH = 4 "WORDS PER REAL";
TWOWORDS = 4;      THREEWORDS = 6;     FOURWORDS = 8;      FIVEWORDS = 10;
STACK_LIMIT = 32667 "GREATEST INTEGER - 100";              CODE_LIMIT = 32667;
THIS_PASS = 6;
INFILE = 2;        OUTFILE = 1;
STACK_ERROR = 1;   CODE_ERROR = 2;

VAR

LINK: PASSPTR;

SUMMARY, TEST, CHECK, GENERATE, NUMBER, AFTERBEGIN, AFTERERROR, DONE: BOOLEAN;

JUMPTABLE, BLOCKTABLE, STACKTABLE, CONSTTABLE: TABLEPTR;

CONSTANTS, STACKLENGTH, VARLENGTH, PARAMLENGTH, POPLENGTH, TEMP,
MAXTEMP, BLOCK, LOCATION, LINE, OP, ARG1, ARG2, ARG3, ARG4, ARG5: INTEGER;

"############################"
"COMMON TEST OUTPUT MECHANISM"
"############################"

PRINTED: INTEGER;

OK: BOOLEAN;
  "PASS1 TO 6:  OK = NOT DISK OVERFLOW
   PASS7:       OK = NOT DISK OVERFLOW & PROGRAM CORRECT"

PAGE_IN: PAGE;  PAGES_IN, WORDS_IN: INTEGER;
PAGE_OUT: PAGE;  PAGES_OUT, WORDS_OUT: INTEGER;

PROCEDURE PRINT_TEXT (TEXT: TEXT_TYPE);
VAR I: INTEGER;
BEGIN
  WRITE(EOL);
  FOR I:= 1 TO TEXT_LENGTH DO WRITE(TEXT(.I.));
  WRITE(EOL)
END;

PROCEDURE FILE_LIMIT;
BEGIN
  PRINT_TEXT('PASS 6: FILE_LIMIT');
  OK:= FALSE
END;

PROCEDURE INIT_PASS (VAR LINK: PASSPTR);
BEGIN
  LINK:= PARAM(.2.).PTR;
  OK:= TRUE;
  PAGES_IN:= 1; WORDS_IN:= PAGELENGTH;
  PAGES_OUT:= 1; WORDS_OUT:= 0
END;

PROCEDURE NEXT_PASS (LINK: PASSPTR);
BEGIN
  IF WORDS_OUT > 0 THEN
    IF PAGES_OUT > FILE_LENGTH(OUTFILE) THEN FILE_LIMIT
      ELSE PUT(OUTFILE, PAGES_OUT, PAGE_OUT);
  WITH PARAM(.1.) DO BEGIN
    TAG:= BOOLTYPE; BOOL:=OK END;
  WITH PARAM(.2.) DO BEGIN
    TAG:= PTRTYPE; PTR:= LINK END;
  WITH PARAM(.4.) DO BEGIN
    TAG:= INTTYPE;  INT:= PAGES_OUT  END;
END;

PROCEDURE READ_IFL (VAR I: INTEGER);
BEGIN
  IF WORDS_IN = PAGELENGTH THEN BEGIN
    IF PAGES_IN > FILE_LENGTH(INFILE) THEN FILE_LIMIT
    ELSE BEGIN
      GET(INFILE, PAGES_IN, PAGE_IN);
      PAGES_IN:= SUCC(PAGES_IN)
    END;
    WORDS_IN:= 0
  END;
  WORDS_IN:= SUCC(WORDS_IN);
  I:= PAGE_IN(.WORDS_IN.)
END;

PROCEDURE WRITE_IFL (I: INTEGER);
BEGIN
  WORDS_OUT:= SUCC(WORDS_OUT);
  PAGE_OUT(.WORDS_OUT.):= I;
  IF WORDS_OUT = PAGELENGTH THEN BEGIN
    IF PAGES_OUT > FILE_LENGTH(OUTFILE) THEN FILE_LIMIT
    ELSE BEGIN
      PUT(OUTFILE, PAGES_OUT, PAGE_OUT);
      PAGES_OUT:= SUCC(PAGES_OUT)
    END;
    WORDS_OUT:= 0
  END
END;

PROCEDURE PRINTABS(ARG: INTEGER);
VAR T: ARRAY (.1..MAXDIGIT.) OF CHAR; REM, DIGIT, I: INTEGER;
BEGIN
  REM:= ARG; DIGIT:= 0;
  REPEAT
    DIGIT:= DIGIT + 1;
    T(.DIGIT.):= CHR(ABS(REM MOD 10) + ORD('0'));
    REM:= REM DIV 10;
  UNTIL REM = 0;
  FOR I:= DIGIT DOWNTO 1 DO WRITE(T(.I.));
  FOR I:= DIGIT + 1 TO MAXDIGIT DO WRITE(' ');
END;

PROCEDURE PRINTEOL;
BEGIN WRITE(EOL); PRINTED:= 0 END;

PROCEDURE PRINTFF;
VAR I:INTEGER;
BEGIN
  PRINTEOL; FOR I:=1 TO 130 DO WRITE('6'); PRINTEOL
END;

PROCEDURE PRINTOP(OP: INTEGER);
BEGIN
  IF PRINTED = PRINTLIMIT THEN PRINTEOL;
  WRITE('C'); PRINTABS(OP);
  PRINTED:= PRINTED + 1;
END;

PROCEDURE PRINTARG(ARG: INTEGER);
BEGIN
  IF PRINTED = PRINTLIMIT THEN PRINTEOL;
  IF ARG < 0 THEN WRITE('-') ELSE WRITE(' ');
  PRINTABS(ARG);
  PRINTED:= PRINTED + 1;
END;

"################"
"INPUT PROCEDURES"
"################"

PROCEDURE READ1ARG;
BEGIN READ_IFL(ARG1) END;

PROCEDURE READ2ARG;
BEGIN READ_IFL(ARG1); READ_IFL(ARG2) END;

PROCEDURE READ3ARG;
BEGIN READ_IFL(ARG1); READ_IFL(ARG2); READ_IFL(ARG3) END;

PROCEDURE READ4ARG;
BEGIN
  READ_IFL(ARG1); READ_IFL(ARG2);
  READ_IFL(ARG3); READ_IFL(ARG4);
END;

PROCEDURE READ5ARG;
BEGIN
  READ_IFL(ARG1); READ_IFL(ARG2); READ_IFL(ARG3);
  READ_IFL(ARG4); READ_IFL(ARG5)
END;

"#################"
"OUTPUT PROCEDURES"
"#################"

PROCEDURE ERROR (PASS, NUMBER: INTEGER); FORWARD;

PROCEDURE WRITE1(OP: INTEGER);
BEGIN
  IF TEST THEN PRINTOP(OP);
  WRITE_IFL(OP);
  IF LOCATION < CODE_LIMIT THEN LOCATION:= LOCATION + WORDLENGTH
    ELSE BEGIN ERROR(THIS_PASS, CODE_ERROR); LOCATION:= 0 END;
END;

PROCEDURE WRITE2(OP, ARG: INTEGER);
BEGIN
  IF TEST THEN
  BEGIN PRINTOP(OP); PRINTARG(ARG) END;
  WRITE_IFL(OP); WRITE_IFL(ARG);
  IF LOCATION < CODE_LIMIT THEN LOCATION:= LOCATION + TWOWORDS
    ELSE BEGIN ERROR(THIS_PASS, CODE_ERROR); LOCATION:= 0 END;
END;

PROCEDURE WRITE3(OP, ARG1, ARG2: INTEGER);
BEGIN
  IF TEST THEN
  BEGIN PRINTOP(OP);
    PRINTARG(ARG1); PRINTARG(ARG2);
  END;
  WRITE_IFL(OP); WRITE_IFL(ARG1); WRITE_IFL(ARG2);
  IF LOCATION < CODE_LIMIT THEN LOCATION:= LOCATION + THREEWORDS
    ELSE BEGIN ERROR(THIS_PASS, CODE_ERROR); LOCATION:= 0 END;
END;

PROCEDURE WRITE4(OP, ARG1, ARG2, ARG3: INTEGER);
BEGIN
  IF TEST THEN
  BEGIN
    PRINTOP(OP); PRINTARG(ARG1);
    PRINTARG(ARG2); PRINTARG(ARG3);
  END;
  WRITE_IFL(OP); WRITE_IFL(ARG1);
  WRITE_IFL(ARG2); WRITE_IFL(ARG3);
  IF LOCATION < CODE_LIMIT THEN LOCATION:= LOCATION + FOURWORDS
    ELSE BEGIN ERROR(THIS_PASS, CODE_ERROR); LOCATION:= 0 END;
END;

PROCEDURE WRITE5(OP, ARG1, ARG2, ARG3, ARG4: INTEGER);
BEGIN
  IF TEST THEN
  BEGIN PRINTOP(OP);
    PRINTARG(ARG1); PRINTARG(ARG2);
    PRINTARG(ARG3); PRINTARG(ARG4);
  END;
  WRITE_IFL(OP);
  WRITE_IFL(ARG1); WRITE_IFL(ARG2);
  WRITE_IFL(ARG3); WRITE_IFL(ARG4);
  IF LOCATION < CODE_LIMIT THEN LOCATION:= LOCATION + FIVEWORDS
    ELSE BEGIN ERROR(THIS_PASS, CODE_ERROR); LOCATION:= 0 END;
END;

PROCEDURE WRITEARG(ARG: INTEGER);
BEGIN
  IF TEST THEN PRINTARG(ARG);
  WRITE_IFL(ARG);
  IF LOCATION < CODE_LIMIT THEN LOCATION:= LOCATION + WORDLENGTH
    ELSE BEGIN ERROR(THIS_PASS, CODE_ERROR); LOCATION:= 0 END;
END;

PROCEDURE WRITELOCATION;
BEGIN
  IF TEST THEN PRINTARG(LOCATION);
  WRITE_IFL(LOCATION);
END;

PROCEDURE COMMENT(LENGTH: INTEGER);
BEGIN LOCATION:= LOCATION - LENGTH END;
  
PROCEDURE ERROR;
BEGIN
  IF NOT AFTERERROR THEN BEGIN
    AFTERERROR:= TRUE;
    COMMENT(FOURWORDS);
    WRITE4(MESSAGE2, PASS, NUMBER, LINE);
    GENERATE:= FALSE
  END
END;
  
"################"
"STACK PROCEDURES"
"################"


PROCEDURE PUSHWORD;
BEGIN
  IF TEMP < STACK_LIMIT THEN TEMP:= TEMP + WORDLENGTH
    ELSE ERROR(THIS_PASS, STACK_ERROR);
  IF TEMP > MAXTEMP THEN MAXTEMP:= TEMP;
END;

PROCEDURE POPWORD;
BEGIN TEMP:= TEMP - WORDLENGTH END;

PROCEDURE PUSHREAL;
BEGIN
  IF TEMP < STACK_LIMIT THEN TEMP:= TEMP + REALLENGTH
    ELSE ERROR(THIS_PASS, STACK_ERROR);
  IF TEMP > MAXTEMP THEN MAXTEMP:= TEMP;
END;

PROCEDURE POPREAL;
BEGIN TEMP:= TEMP - REALLENGTH END;

PROCEDURE PUSHSET;
BEGIN
  IF TEMP < STACK_LIMIT THEN TEMP:= TEMP + SETLENGTH
    ELSE ERROR(THIS_PASS, STACK_ERROR);
  IF TEMP > MAXTEMP THEN MAXTEMP:= TEMP;
END;

PROCEDURE POPSET;
BEGIN TEMP:= TEMP - SETLENGTH END;

PROCEDURE PUSH(LENGTH: INTEGER);
BEGIN
  IF TEMP < STACK_LIMIT - LENGTH THEN TEMP:= TEMP + LENGTH
    ELSE ERROR(THIS_PASS, STACK_ERROR);
  IF TEMP > MAXTEMP THEN MAXTEMP:= TEMP;
END;

PROCEDURE POP(LENGTH: INTEGER);
BEGIN TEMP:= TEMP - LENGTH END;

"###################"
"VARIABLE PROCEDURES"
"###################"

FUNCTION DISPL(ARG: INTEGER): INTEGER;
BEGIN
  IF ARG < 0 THEN DISPL:= ARG
             ELSE DISPL:= ARG + FOURWORDS;
END;

PROCEDURE PUSHVALUE(MODE, ARG: INTEGER);
VAR ADDR: INTEGER;
BEGIN
  CASE MODE OF
    MODE1, MODE3, MODE4, MODE5:
      WRITE2(PUSHLOCAL2, DISPL(ARG));
    MODE2:
      BEGIN
        ADDR:= DISPL(ARG);
        IF ADDR > 0 THEN ADDR:= ADDR + WORDLENGTH;
        WRITE2(PUSHGLOB2, ADDR)
      END;
    MODE6, MODE7, MODE8:
      WRITE2(PUSHGLOB2, ARG);
    MODE10:
  END;
  PUSHWORD;
END;

PROCEDURE PUSHADDRESS(MODE, ARG: INTEGER);
VAR ADDR: INTEGER;
BEGIN
  CASE MODE OF
    MODE0:
      WRITE2(CONSTADDR2, ARG);
    MODE1, MODE3, MODE4, MODE5:
      WRITE2(LOCALADDR2, DISPL(ARG));
    MODE2:
      BEGIN
        ADDR:= DISPL(ARG);
        IF ADDR > 0 THEN ADDR:= ADDR + WORDLENGTH;
        WRITE2(GLOBADDR2, ADDR)
      END;
    MODE6, MODE7, MODE8:
      WRITE2(GLOBADDR2, ARG);
    MODE10:
  END;
  PUSHWORD;
END;

PROCEDURE PUSHINDIRECT(VARTYPE: INTEGER);
BEGIN
  CASE VARTYPE OF
    BYTETYPE:
      WRITE1(PUSHBYTE2);
    WORDTYPE:
      WRITE1(PUSHIND2);
    REALTYPE:
      BEGIN WRITE1(PUSHREAL2);
        POPWORD; PUSHREAL;
      END;
    SETTYPE:
      BEGIN WRITE1(PUSHSET2);
        POPWORD; PUSHSET;
      END
  END;
END;


"#####################"
"COMPARISON PROCEDURES"
"#####################"

PROCEDURE COMPAREWORD(ARG: INTEGER);
BEGIN
  CASE ARG OF
    LESS:        WRITE1(LSWORD2);
    EQUAL:       WRITE1(EQWORD2);
    GREATER:     WRITE1(GRWORD2);
    NOTLESS:     WRITE1(NLWORD2);
    NOTEQUAL:    WRITE1(NEWORD2);
    NOTGREATER:  WRITE1(NGWORD2)
  END;
  POPWORD;
END;

PROCEDURE COMPAREREAL(ARG: INTEGER);
BEGIN
  CASE ARG OF
    LESS:        WRITE1(LSREAL2);
    EQUAL:       WRITE1(EQREAL2);
    GREATER:     WRITE1(GRREAL2);
    NOTLESS:     WRITE1(NLREAL2);
    NOTEQUAL:    WRITE1(NEREAL2);
    NOTGREATER:  WRITE1(NGREAL2)
  END;
  POPREAL; POPREAL; PUSHWORD;
END;

PROCEDURE COMPARESET(ARG: INTEGER);
BEGIN
  CASE ARG OF
    EQUAL:       WRITE1(EQSET2);
    NOTLESS:     WRITE1(NLSET2);
    NOTEQUAL:    WRITE1(NESET2);
    NOTGREATER:  WRITE1(NGSET2);
    INSET:       WRITE1(INSET2)
  END;
  POPSET;
  IF ARG <> INSET THEN
  BEGIN POPSET; PUSHWORD END;
END;

PROCEDURE COMPARESTRUCT(ARG1, ARG2: INTEGER);
BEGIN
  CASE ARG1 OF
    LESS:        WRITE1(LSSTRUCT2);
    EQUAL:       WRITE1(EQSTRUCT2);
    GREATER:     WRITE1(GRSTRUCT2);
    NOTLESS:     WRITE1(NLSTRUCT2);
    NOTEQUAL:    WRITE1(NESTRUCT2);
    NOTGREATER:  WRITE1(NGSTRUCT2)
  END;
  WRITEARG(ARG2 DIV WORDLENGTH);
  POPWORD;
END;

"################"
"TABLE PROCEDURES"
"################"

PROCEDURE ALLOCATE(VAR T: TABLEPTR; ENTRIES: INTEGER);
VAR PORTION: TABLEPTR; I: INTEGER;
BEGIN
  NEW(T); PORTION:= T;
  I:= ENTRIES - MAXWORD;
  WHILE I > 0 DO
  WITH PORTION@ DO
  BEGIN
    NEW(NEXTPORTION); PORTION:= NEXTPORTION;
    I:= I - MAXWORD;
  END;
END;

PROCEDURE ENTER(T: TABLEPTR; I, J: INTEGER);
VAR PORTION: TABLEPTR; K: INTEGER;
BEGIN
  PORTION:= T; K:= I;
  WHILE K > MAXWORD DO
  BEGIN
    PORTION:= PORTION@.NEXTPORTION;
    K:= K - MAXWORD;
  END;
  PORTION@.CONTENTS(.K.):= J;
END;

FUNCTION ENTRY(T: TABLEPTR; I: INTEGER): INTEGER;
VAR PORTION: TABLEPTR; J: INTEGER;
BEGIN
  PORTION:= T; J:= I;
  WHILE J > MAXWORD DO
  BEGIN
    PORTION:= PORTION@.NEXTPORTION;
    J:= J - MAXWORD;
  END;
  ENTRY:= PORTION@.CONTENTS(.J.);
END;

"###############"
"LINE PROCEDURES"
"###############"

PROCEDURE NEWLINE(ARG: INTEGER);
BEGIN
  LINE:= ARG;
  AFTERERROR:=FALSE;
  IF NUMBER AND AFTERBEGIN THEN WRITE2(NEWLINE2,LINE)
END;

PROCEDURE INITLINE;
BEGIN
  LINE:=0; AFTERBEGIN:=FALSE
END;

"################"
"BLOCK PROCEDURES"
"################"

PROCEDURE ENTERBLOCK(I, J, K, L: INTEGER);
BEGIN
  BLOCK:= I; PARAMLENGTH:= J; VARLENGTH:= K; STACKLENGTH:=L;
  POPLENGTH:= PARAMLENGTH + FOURWORDS;
  TEMP:= 0; MAXTEMP:= 0;
  IF BLOCK=INITIALBLOCK THEN ENTER(JUMPTABLE,BLOCK,LOCATION)
    ELSE ENTER(BLOCKTABLE,BLOCK,LOCATION);
  "THE INITIAL BLOCK IS ONLY REFERENCED BY THE FIRST JUMP INSTRUCTION
  IN A PROGRAM, BUT NOT BY ANY CALL OR INIT INSTRUCTION"
  AFTERBEGIN:=TRUE
END;

PROCEDURE EXITBLOCK;
BEGIN
  IF STACKLENGTH < STACK_LIMIT - MAXTEMP - VARLENGTH THEN
    STACKLENGTH:= STACKLENGTH + MAXTEMP + VARLENGTH + FIVEWORDS
  ELSE ERROR(THIS_PASS, STACK_ERROR);
  ENTER(STACKTABLE, BLOCK, STACKLENGTH);
  AFTERBEGIN:=FALSE
END;

"#########################################"
"INITIALIZATION AND TERMINATION PROCEDURES"
"#########################################"

PROCEDURE BEGINPASS;
BEGIN
  WITH LINK@ DO
  BEGIN
    SUMMARY:= SUMMARYOPTION IN OPTIONS;
    TEST:= TESTOPTION IN OPTIONS;
    CHECK:= CHECKOPTION IN OPTIONS;
    NUMBER:= NUMBEROPTION IN OPTIONS;
    GENERATE:= TRUE;
    MARK(RESETPOINT);
    ALLOCATE(JUMPTABLE, LABELS);
    ALLOCATE(BLOCKTABLE, BLOCKS);
    ALLOCATE(STACKTABLE, BLOCKS);
    ALLOCATE(CONSTTABLE, CONSTANTS DIV WORDLENGTH);
  END;
  LOCATION:= 0; CONSTANTS:= 0;
  INITLINE;
  IF TEST THEN PRINTFF;
END;

PROCEDURE ENDPASS;
BEGIN
  WITH LINK@ DO
  BEGIN
    IF GENERATE THEN OPTIONS:= OPTIONS OR (.CODEOPTION.);
    NEW(TABLES);
    TABLES@.PROGLENGTH:= FOURWORDS + LOCATION + CONSTANTS;
    TABLES@.CODELENGTH:= LOCATION;
    TABLES@.STACKLENGTH:= STACKLENGTH;
    TABLES@.VARLENGTH:= VARLENGTH;
    TABLES@.JUMPTABLE:=JUMPTABLE;
    TABLES@.BLOCKTABLE:=BLOCKTABLE;
    TABLES@.STACKTABLE:=STACKTABLE;
    TABLES@.CONSTTABLE:=CONSTTABLE;
  END;
END;

"#########"
"OPERATORS"
"#########"

PROCEDURE SCAN;
BEGIN
  DONE:=FALSE;
  REPEAT
    READ_IFL(OP);
    CASE OP OF

PUSHCONST1"(VALUE)":
  BEGIN READ1ARG;
    WRITE2(PUSHCONST2, ARG1); PUSHWORD;
  END;

PUSHVAR1"(TYPE, MODE, DISPL)":
  BEGIN READ3ARG;
    IF ARG1 = WORDTYPE
      THEN PUSHVALUE(ARG2, ARG3)
      ELSE BEGIN
             PUSHADDRESS(ARG2, ARG3);
             PUSHINDIRECT(ARG1);
           END;
  END;

PUSHIND1"(TYPE)":
  BEGIN READ1ARG; PUSHINDIRECT(ARG1) END;

PUSHADDR1"(MODE, DISPL)":
  BEGIN READ2ARG; PUSHADDRESS(ARG1, ARG2) END;

FIELD1"(DISPL)":
  BEGIN READ1ARG; IF ARG1<>0 THEN WRITE2(FIELD2,ARG1) END;

INDEX1"(MIN, MAX, LENGTH)":
  BEGIN READ3ARG;
    WRITE4(INDEX2, ARG1, ARG2 - ARG1, ARG3);
    POPWORD;
  END;

POINTER1:
  IF CHECK THEN WRITE1(POINTER2);

VARIANT1"(TAGSET, DISPL)":
  BEGIN READ2ARG;
    IF CHECK THEN WRITE3(VARIANT2, ARG2, ARG1);
  END;

RANGE1"(MIN, MAX)":
  BEGIN READ2ARG;
    IF CHECK THEN WRITE3(RANGE2, ARG1, ARG2);
  END;

ASSIGN1"(TYPE)":
  BEGIN READ1ARG;
    CASE ARG1 OF
      BYTETYPE:
        BEGIN WRITE1(COPYBYTE2); POPWORD END;
      WORDTYPE:
        BEGIN WRITE1(COPYWORD2); POPWORD END;
      REALTYPE:
        BEGIN WRITE1(COPYREAL2); POPREAL END;
      SETTYPE:
        BEGIN WRITE1(COPYSET2); POPSET END
    END;
    POPWORD;
  END;

ASSIGNTAG1"(LENGTH)":
  BEGIN  READ1ARG;
    IF ARG1 = 0 THEN WRITE1(COPYWORD2)
    ELSE WRITE2(COPYTAG2, ARG1 DIV WORDLENGTH);
    POPWORD; POPWORD;
  END;

COPY1"(LENGTH)":
  BEGIN READ1ARG; WRITE2(COPYSTRUC2, ARG1 DIV WORDLENGTH);
    POPWORD; POPWORD;
  END;

NEW1"(LENGTH, INITIALIZE)":
  BEGIN READ2ARG;
    IF (ARG2 = 1) & CHECK
      THEN WRITE3(NEWINIT2, BLOCK, ARG1)
      ELSE WRITE3(NEW2, BLOCK, ARG1);
    POPWORD;
  END;

NOT1:
  WRITE1(NOT2);

AND1"(TYPE)":
  BEGIN READ1ARG;
    IF ARG1 = WORDTYPE
      THEN BEGIN WRITE1(ANDWORD2); POPWORD END
      ELSE BEGIN WRITE1(ANDSET2); POPSET END;
  END;

OR1"(TYPE)":
  BEGIN READ1ARG;
    IF ARG1 = WORDTYPE
      THEN BEGIN WRITE1(ORWORD2); POPWORD END
      ELSE BEGIN WRITE1(ORSET2); POPSET END;
  END;

NEG1"(TYPE)":
  BEGIN READ1ARG;
    IF ARG1 = WORDTYPE THEN WRITE1(NEGWORD2)
                       ELSE WRITE1(NEGREAL2);
  END;

ADD1"(TYPE)":
  BEGIN READ1ARG;
    IF ARG1 = WORDTYPE
      THEN BEGIN WRITE1(ADDWORD2); POPWORD END
      ELSE BEGIN WRITE1(ADDREAL2); POPREAL END;
  END;

SUB1"(TYPE)":
  BEGIN READ1ARG;
    CASE ARG1 OF
      WORDTYPE:
        BEGIN WRITE1(SUBWORD2); POPWORD END;
      REALTYPE:
        BEGIN WRITE1(SUBREAL2); POPREAL END;
      SETTYPE:
        BEGIN WRITE1(SUBSET2); POPSET END
    END;
  END;

MUL1"(TYPE)":
  BEGIN READ1ARG;
    IF ARG1 = WORDTYPE
      THEN BEGIN WRITE1(MULWORD2); POPWORD END
      ELSE BEGIN WRITE1(MULREAL2); POPREAL END;
  END;

DIV1"(TYPE)":
  BEGIN READ1ARG;
    IF ARG1 = WORDTYPE
      THEN BEGIN WRITE1(DIVWORD2); POPWORD END
      ELSE BEGIN WRITE1(DIVREAL2); POPREAL END;
  END;

MOD1"(TYPE)":
  BEGIN READ1ARG; WRITE1(MODWORD2); POPWORD END;

"(NOT USED)"

"(NOT USED)"

FUNCTION1"(STANDARDFUNC, TYPE)":
  BEGIN READ2ARG;
    IF (ARG1 >= MIN_FUNC) AND (ARG1 <= MAX_FUNC) THEN
    CASE ARG1 OF
      TRUNC1:
        BEGIN WRITE1(TRUNCREAL2); POPREAL; PUSHWORD END;
      ABS1:
        IF ARG2 = WORDTYPE THEN WRITE1(ABSWORD2)
                           ELSE WRITE1(ABSREAL2);
      SUCC1:
        WRITE1(SUCCWORD2);
      PRED1:
        WRITE1(PREDWORD2);
      CONV1:
        BEGIN WRITE1(CONVWORD2); POPWORD; PUSHREAL END;
      EMPTY1:
        WRITE1(EMPTY2);
      ATTRIBUTE1:
        WRITE1(ATTRIBUTE2);
      REALTIME1:
        BEGIN WRITE1(REALTIME2); PUSHWORD END
    END;
  END;

BUILDSET1:
  BEGIN WRITE1(BUILDSET2); POPWORD END;

COMPARE1"(COMPARISON, TYPE)":
  BEGIN READ2ARG;
    CASE ARG2 OF
      WORDTYPE:
        COMPAREWORD(ARG1);
      REALTYPE:
        COMPAREREAL(ARG1);
      SETTYPE:
        COMPARESET(ARG1)
    END;
  END;

COMPSTRUC1"(COMPARISON, LENGTH)":
  BEGIN READ2ARG; COMPARESTRUCT(ARG1, ARG2) END;

FUNCVALUE1"(MODE)":
  BEGIN READ2ARG;
    CASE ARG1 OF
      MODE1, MODE3:
      IF ARG2 = WORDTYPE THEN BEGIN
        WRITE2(FUNCVALUE2, 0); PUSHWORD
      END ELSE BEGIN
        WRITE2(FUNCVALUE2, 8); PUSHREAL
      END;
      MODE4, MODE5:
      IF ARG2 = WORDTYPE THEN BEGIN
        WRITE2(FUNCVALUE2, 16); PUSHWORD
      END ELSE BEGIN
        WRITE2(FUNCVALUE2, 24); PUSHREAL
      END;
        MODE9, MODE10:
    END;
  END;

DEFLABEL1"(LABEL)":
  BEGIN READ1ARG;
    ENTER(JUMPTABLE, ARG1, LOCATION);
    IF NUMBER THEN WRITE2(NEWLINE2,LINE)
  END;

JUMP1"(LABEL)":
  BEGIN READ1ARG;
    WRITE1(JUMP2); WRITELOCATION; WRITEARG(ARG1);
  END;

FALSEJUMP1"(LABEL)":
  BEGIN READ1ARG;
    WRITE1(FALSEJUMP2); WRITELOCATION; WRITEARG(ARG1);
    POPWORD;
  END;

CASEJUMP1"(MIN, MAX, LABELS)":
  BEGIN READ2ARG; ARG2:=  ARG2 - ARG1;
    WRITE3(CASEJUMP2, ARG1, ARG2); WRITELOCATION;
    FOR ARG3:= 0 TO ARG2 DO
    BEGIN READ1ARG; WRITEARG(ARG1) END;
    POPWORD;
  END;

INITVAR1"(LENGTH)":
  BEGIN READ1ARG;
    IF CHECK THEN WRITE2(INITVAR2, ARG1 DIV WORDLENGTH);
  END;

CALL1"(MODE, LABEL, PARAMLENGTH)":
  BEGIN READ3ARG;
    IF ARG1 = MODE3 THEN
    BEGIN WRITE2(CALLSYS2, (ARG2 - 2) * WORDLENGTH);
      ARG1:= WORDLENGTH;
    END ELSE
    BEGIN
      WRITE1(CALL2); WRITELOCATION; WRITEARG(ARG2);
      IF ARG1<>MODE1 THEN ARG3:=ARG3+WORDLENGTH;
      "INCLUDES COMPONENT ADDRESS IN PARAMLENGTH"
      IF CONCURRENT
        THEN ARG1:= ENTRY(STACKTABLE, ARG2)
        ELSE ARG1:= WORDLENGTH;
    END;
    PUSH(ARG1); POP(ARG1 + ARG3);
  END;

ENTER1"(MODE, LABEL, PARAMLENGTH, VARLENGTH, TEMPLENGTH)":
  BEGIN READ5ARG;
    ENTERBLOCK(ARG2, ARG3, ARG4, ARG5);
    CASE ARG1 OF
      MODE1:
        WRITE5(ENTER2, BLOCK, POPLENGTH, LINE, VARLENGTH);
      MODE2:
        WRITE5(ENTERPROG2, POPLENGTH + WORDLENGTH, LINE, BLOCK, VARLENGTH);
      MODE3:
        WRITE5(ENTERPROC2, BLOCK, POPLENGTH, LINE, VARLENGTH);
      MODE4:
        WRITE5(ENTERCLAS2, BLOCK, POPLENGTH + WORDLENGTH, LINE, VARLENGTH);
      MODE5:
        WRITE5(ENTERMON2, BLOCK, POPLENGTH + WORDLENGTH, LINE, VARLENGTH);
      MODE6:
        WRITE2(BEGINPROC2, LINE);
      MODE7:
        WRITE5(BEGINCLAS2, BLOCK, FIVEWORDS, LINE, 0);
      MODE8:
        WRITE5(BEGINMON2, BLOCK, FIVEWORDS, LINE, 0);
      MODE10:
    END;
  END;

RETURN1"(MODE)":
  BEGIN READ1ARG;
    CASE ARG1 OF
      MODE1:  WRITE1(EXIT2);
      MODE2:  WRITE1(EXITPROG2);
      MODE3:  WRITE1(EXITPROC2);
      MODE4:  WRITE1(EXITCLASS2);
      MODE5:  WRITE1(EXITMON2);
      MODE6:  WRITE1(ENDPROC2);
      MODE7:  WRITE1(ENDCLASS2);
      MODE8:  WRITE1(ENDMON2);
      MODE10:
    END;
    EXITBLOCK;
  END;

POP1"(LENGTH)":
  BEGIN READ1ARG;
    WRITE2(POP2, ARG1); POP(ARG1);
  END;

NEWLINE1"(NUMBER)":
  BEGIN READ1ARG; NEWLINE(ARG1) END;

ERROR1:
  GENERATE:= FALSE;

CONSTANT1 "(LENGTH, VALUE)":
  BEGIN READ1ARG;
    FOR ARG3:= 1 TO ARG1 DIV WORDLENGTH DO
    BEGIN CONSTANTS:= CONSTANTS + 1;
      READ1ARG; ENTER(CONSTTABLE, CONSTANTS, ARG1);
    END;
  END;

MESSAGE1"(PASS, ERROR)":
  BEGIN READ2ARG;
    ERROR(ARG1, ARG2)
  END;

INCREMENT1:
  BEGIN WRITE1(INCRWORD2); POPWORD END;

DECREMENT1:
  BEGIN WRITE1(DECRWORD2); POPWORD END;

PROCEDURE1"(STANDARDPROCEDURE)":
  BEGIN READ1ARG;
    IF (ARG1 >= MIN_PROC) AND (ARG1 <= MAX_PROC) THEN
    CASE ARG1 OF
      DELAY1:
        BEGIN WRITE1(DELAY2); POPWORD END;
      CONTINUE1:
        BEGIN WRITE1(CONTINUE2); POPWORD END;
      IO1:
        BEGIN WRITE1(IO2); POP(THREEWORDS) END;
      START1:
        WRITE1(START2);
      STOP1:
        BEGIN WRITE1(STOP2); POP(TWOWORDS) END;
      SETHEAP1:
        BEGIN WRITE1(SETHEAP2); POPWORD END;
      WAIT1:
        WRITE1(WAIT2)
    END;
  END;

INIT1"(MODE, LABEL, PARAMLENGTH, VARLENGTH)":
  BEGIN READ4ARG;
    IF ARG1 = MODE6 THEN
    BEGIN WRITE4(INITPROC2, ARG3, ARG4, ARG2);
      PUSH(FOURWORDS); POP(ARG3 + FIVEWORDS);
    END ELSE
    BEGIN
      IF ARG1 = MODE7
        THEN WRITE2(INITCLASS2, ARG3)
        ELSE WRITE2(INITMON2, ARG3);
      ARG1:= ENTRY(STACKTABLE, ARG2);
      POP(ARG3); PUSH(ARG1); POP(ARG1 + WORDLENGTH);
    END;
    WRITELOCATION; WRITEARG(ARG2);
  END;

PUSHLABEL1"(LABEL)":
  BEGIN READ1ARG;
    WRITE1(PUSHLABEL2); WRITELOCATION; WRITEARG(ARG1);
    PUSHWORD;
  END;

CALLPROG1:
  BEGIN WRITE1(CALLPROG2); PUSHWORD END;

EOM1"(VARLENGTH)":
  BEGIN
    DONE:=TRUE;
    READ1ARG; VARLENGTH:=ARG1;
    COMMENT(WORDLENGTH); WRITE1(EOM2)
  END

    END
  UNTIL DONE
END;

BEGIN
  INIT_PASS(LINK);
  BEGINPASS;
  SCAN;
  ENDPASS;
  NEXT_PASS(LINK);
END.
