{ > PasMain }

{ Tutu 19 feb 86 - bce repacked, with re-align after declaration end }
{ Tutu 17 feb 86 - brought into line with 1.06/7 bug fixes with packing }
{ Tutu 11 feb 86 - totaldescsize made manifest constant, array acc. changed.
                    also A4 type (&FF) identification byte added on code }
{ Tutu 30 jan 86 - fcbsize made manifest constant }
{ Tutu 16 dec 85 - altered version for ARMulation ! }

{ Sam altered version number 15 Nov 85 to 1.04 }

{ Tutu 08 nov 85 - got a CMOS front end : D1.03 etc. }

{ Tutu XX oct 85 - Changed pshK_ptr 0000 to pshK_nil : D1.02 }
{ And flush the keyboard buffer if we had any errors }


procedure align (var thing : si); { Tutu - align stack frame / vbl offsets }
var dif : integer;
begin
  dif := thing MOD 4;
  if dif <> 0 then thing := thing - dif + 4
end; { align }


FUNCTION BADSCOPE : BOOLEAN;
BEGIN
   BADSCOPE := (X.USED_AT_LEV = X.LEVEL) AND (X.USED_IN_PROC = X.THISPROCNO)
END;


PROCEDURE GETTYP (VAR TP          : TYPES;
                  VAR RF          : STP;
                  VAR SZ, ARECSIZ : SI;
                  VAR ELEMPAC     : BOOLEAN;
                      PAC, ARAYEL : BOOLEAN); FORWARD;


PROCEDURE VARLIST (VAR NoINLIST         : UB;
                       VARPARM, ISPARAM : BOOLEAN;
                       IDTIPE           : SYMBOLS;
                   VAR OFFSET, ARECSIZ  : SI;
                       PAC              : BOOLEAN;
                   VAR HASFILE          : BOOLEAN);
VAR TP : TYPES;
    RF : STP;
    SZ : SI;
    ID1, ID2 : SYMP;
    IDCOUNT : UW;
    HASFYLE, ELEMPAC : BOOLEAN;


PROCEDURE FUJENT;
{ IF THE VARIABLE NAME IS A PROGRAM PARAMETER THEN IT MUST BE MOVED FROM IT'S
  CURRENT POSITION IN THE LINKED LIST SYMBOL TABLE, TO A POSITION INSIDE THE
  SEQUENTIAL LINKED LIST OF THE ID LIST
}
BEGIN
   IF (SYM = VARID) AND (X.LEVEL <> 1)
   THEN ERROR (143) {PROGPARAMS ARE GLOBAL}

   ELSE IF (THISSYMP^.IDTYP = FYLE) AND (THISSYMP^.ADR = -3)
   THEN
   BEGIN
      IF THISSYMP <> LASTSYMP THEN
      BEGIN
         THISSYMP^.ADR := -4;
         NEXTSYMP^.LINK := THISSYMP^.LINK;
         IF THISSYMP = ID1 THEN ID1 := THISSYMP^.LINK;
         THISSYMP^.LINK := LASTSYMP;
         LASTSYMP := THISSYMP;
         DISPLAY[1]^.LASTSYM := LASTSYMP
      END
   END

   ELSE
   BEGIN
      IF (SYM <> NEWID) OR (THISSYMP^.OBJ = VARID) THEN ERROR (62);
     { Check that an id with the same spelling as the new id has not
       been used at the current level }
      IF BADSCOPE AND (SYM = NEWID) THEN ERROR (104)
   END;

   LASTSYMP^.OBJ := IDTIPE;
   LASTSYMP^.NRM := NOT VARPARM;
   NEXTSYM
END; { fujent }


BEGIN { varlist }
   ID1 := NIL;
   FUJENT;
   ID1 := LASTSYMP^.LINK;

   IDCOUNT := 1; { Loop over identically typed variables }
   WHILE ISCOMA DO
   BEGIN  { GET ANY MORE IDS IN ID LIST }
      NXTSYMOK;
      IDCOUNT := SUCC (IDCOUNT);
      FUJENT
   END;

   ISDEC := FALSE;
   ID2 := LASTSYMP; {SAVE LAST ID IN ID LIST}

   CHKNEXT (COLON);
   IF ISPARAM AND (SYM <> TIPE) THEN ERROR (115);

   GETTYP (TP, RF, SZ, ARECSIZ, ELEMPAC, PAC, FALSE); {Type not array element}

   HASFYLE := CONTAINSFILE (TP, RF^, TRUE);
   IF HASFYLE THEN HASFILE := TRUE;

   IF VARPARM THEN SZ := ptrsize { Tutu - was 2 }
   ELSE
      IF ISPARAM AND HASFYLE THEN ERROR (158);

   NoINLIST := IDCOUNT;
   OFFSET := OFFSET + IDCOUNT * SZ;
   IDCOUNT := OFFSET;
  { Assign ids in list to correct type }
   REPEAT
      ID2^.IDTYP := TP;
      ID2^.REF   := RF;
      IDCOUNT    := IDCOUNT - SZ;
      ID2^.ADR   := IDCOUNT;
      ID2^.PAK   := ELEMPAC;
      ID2        := ID2^.LINK
   UNTIL (ID2 = ID1) OR FUCKUP
END; { varlist }


FUNCTION CHKTYP (VAR RF : STP; VAR SZ : SI; PAC : BOOLEAN) : TYPES;
VAR LEVELCOPY : SI;

BEGIN { chktyp }
   LEVELCOPY := X.LEVEL;

   WHILE THISSYMP^.IDTYP = NOTYP DO
   BEGIN
      LEVELCOPY := PRED (LEVELCOPY);
      X.DEPTH := LEVELCOPY;
      LOOKUPID;
      IF THISSYMP = NIL THEN ERROR (115)
      ELSE IF THISSYMP^.OBJ <> TIPE THEN ERROR (115)
   END;

   RF := THISSYMP^.REF;
   SZ := THISSYMP^.ADR;
   IF PAC AND (THISSYMP^.IDTYP = SUBR) THEN SZ := BYTES (RF^.LOW, RF^.HIGH);
   CHKTYP := THISSYMP^.IDTYP;
END; { chktyp }


PROCEDURE CHKSZ (VAR SIZE : SI);
BEGIN
   IF SIZE >= MAXUW THEN { Tutu - to be maxmadr eventually }
   BEGIN
      SIZE := 1;
      ERROR (26) { Type too big for memory }
   END
END; { chksz }


PROCEDURE ORDTYP (VAR RF  : STP; VAR SZE : SI; PAC : BOOLEAN);
LABEL 13;

VAR COUNT : UW;
    THISLEV : UB;
    TP1 : TYPES;
    RF1 : STP;

BEGIN { ordtyp }
   IF SYM = TIPE THEN
   BEGIN
      IF CHKTYP (RF, SZE, PAC) <> SUBR THEN ERROR (120); {ORD TYPE EXPECTED}
      NXTSYMOK
   END

   ELSE {NUORDTYP}
   BEGIN
      NEW (RF1, SUBR);
      RF1^.SUBRSIZ := 1;
      SUBRP := RF1;
      IF SYM <> LPAREN THEN ORDCON;
      IF SYM = KONST THEN
      BEGIN
         RF1^.LOW := THISSYMP^.VAL;
         SUBRP^.SUBRREF := THISSYMP^.REF^.SUBRREF;
         TP1 := THISSYMP^.REF^.TYP;
         RF1^.TYP := TP1;
         NEXTSYM;
         CHKNEXT (DDOT);
         ORDCON;
         IF (TP1 <> THISSYMP^.REF^.TYP) OR
            (THISSYMP^.REF^.SUBRREF <> SUBRP^.SUBRREF) THEN ERROR (118);
         SUBRP^.HIGH := THISSYMP^.VAL;
         IF THISSYMP^.VAL < SUBRP^.LOW THEN ERROR (119);
         NEXTSYM;
         IF TP1 = INT THEN RF1^.SUBRSIZ := 4
      END

      ELSE
      BEGIN
         THISLEV := X.LEVEL;
         X.LEVEL := X.PROCLEV;
         ISDEC := TRUE;
         IF SYM <> LPAREN THEN ERROR (120); {ORDINAL TYPE EXPECTED}
         NEXTSYM;
         COUNT := 0;

         13:CHK (NEWID);
           { Check that an id with the same spelling as the new id has not
             been used at the current level }
            IF BADSCOPE THEN ERROR (104);
            SETSUBRTYP (THISSYMP^, SUBRP);
            THISSYMP^.VAL := COUNT;
            COUNT := SUCC (COUNT);
            NEXTSYM;
            IF ISCOMA THEN
            BEGIN
               NEXTSYM;
               GOTO 13
            END;

         X.LEVEL := THISLEV;
         ISDEC := FALSE;
         CHKNEXT (RPAREN);
         RF1^.LOW := 0;
         RF1^.TYP := ENUM;
         RF1^.SUBRREF := RF1;
         RF1^.HIGH := PRED (COUNT)
      END;
      SZE := RF1^.SUBRSIZ;
      IF PAC THEN SZE := BYTES (RF1^.LOW, RF1^.HIGH);
      RF := RF1
   END;  {OF NUORDTYP}

   CHKSZ (SZE)
END; { ordtyp }


PROCEDURE GETTYP; {ALREADY DECLARED BEFORE IDLIST}
VAR THISLEV : SI;
    TP1 : TYPES;
    RF1 : STP;
    SZ1 : SI;
    COULDBESTR,
    LOCALELEMPAC : BOOLEAN;
    THISCOPY : SYMP;


PROCEDURE ARAYTYP (VAR RF : STP; VAR SZE, ARECSIZ : SI; PAC, ARAYEL : BOOLEAN);
VAR TP : TYPES;
    RF1, ELRF, AP : STP;
    TEMP, ELSIZ : SI;
    DESCSIZ : UW;
    ELEMPAC : BOOLEAN;

BEGIN { araytyp }
   ORDTYP (RF1, SZE, TRUE);
   NEW (AP, ARAY, ARAY, ARAY); { CREATE NEW ARRAY RECORD }
   AP^.IREF := RF1;

   IF ISCOMA THEN
   BEGIN
      NXTSYMOK;
      ELEMPAC := PAC;
      ARAYTYP (ELRF, ELSIZ, ARECSIZ, PAC, TRUE);
      TP := ARAY;
      IF COULDBESTR THEN TP := STRNG
   END
   ELSE
   BEGIN
      CHKNEXT (RBRAK);
      CHKNEXT (OFSY);
      GETTYP (TP, ELRF, ELSIZ, ARECSIZ, ELEMPAC, PAC, TRUE)
   END;                                             {Type is element of array}

   TEMP := SUCC (RF1^.HIGH - RF1^.LOW);

   COULDBESTR := PAC AND (RF1^.LOW = 1) AND (ELRF = CHARDESC)
                 AND (RF1^.TYP = INT) AND (TEMP > 1);
{ Tutu - Strings are packed array [1..n] of char only }

   AP^.ELSIZE := ELSIZ;
   AP^.ELREF  := ELRF;
   AP^.TYP    := TP;
   CHKSZ (TEMP);
   SZE := TEMP * ELSIZ;
   CHKSZ (SZE);
   AP^.VARSIZ := SZE;
   RF1 := AP;

   IF NOT ARAYEL THEN
   BEGIN
{ Create array descriptor + plant code to load it onto the stack at run time }
      GENLORS (LOCATE, ARECSIZ);   { Locate current lev array descriptor adr }
      GENOPWTB (LOCILD+42{long version}, 0);
      DESCSIZ := 0;

      TP := ARAY;
      WHILE (TP = ARAY) OR (TP = STRNG) DO
      BEGIN
         GENUW (AP^.ELSIZE); genuw (0); { Tutu - need to pad out on beeb }
{ Tutu - was : (index type byte not needed for ARM)
         IF AP^.IREF^.SUBRSIZ = 1 THEN GENUB (1) ELSE GENUB (4);
}
         GENSI (AP^.IREF^.LOW);
         GENSI (AP^.IREF^.HIGH);
         DESCSIZ := DESCSIZ + totaldescsize; { Tutu - was 11 }
         TP := AP^.TYP;
         AP := AP^.ELREF
      END;

      STORPATCH (X.LASTADR, DESCSIZ);
      GENLORS (40{popI_blk}, DESCSIZ);
      RF1^.ADESCOFF := ARECSIZ;
      ARECSIZ := ARECSIZ + DESCSIZ { Descsize must be multiple of 4 }
   END;
   RF := RF1;
   RF1^.ALEV := (ORD (ELEMPAC) * 128) + X.PROCLEV
END; { araytyp }


PROCEDURE FIELDLIST (VAR OFFSET, ARECSIZ : SI;
                     VAR VARIENTS1       : VARIANTP;
                         PAC             : BOOLEAN);
LABEL 13;

VAR TP : TYPES;
    RF1 : STP;
    SAVELASTNAME, No_CONSTS : UW;
    SZ : SI;
    DINGO, SEMI : BOOLEAN;
    ID1 : SYMP;
    MAXVARIANT : SI;
    VARIENTS2, LASTVARIANT, NESTEDV : VARIANTP;
    CLIST, CLIST2, NEXTCONST : CONSTSP;
    PIGS_WILL_FLY : UB;

BEGIN { fieldlist }
   SEMI := TRUE;
   ISDEC := TRUE;

   align (offset); align (arecsiz); { Tutu paranoia }

   WHILE (SYM = NEWID) OR (SYM = VARID) DO
   BEGIN
      IF NOT SEMI THEN ERROR (19);
      VARLIST (PIGS_WILL_FLY, FALSE{not var param}, FALSE{not param},
                                         FIELD, OFFSET, ARECSIZ, PAC, DINGO);
      ISDEC := TRUE;
      SEMI := ISSEMI;
      IF SEMI THEN NXTSYMOK;

      align (offset); align (arecsiz); { Tutu paranoia }
   END;

   IF SYM = CASEY THEN
   BEGIN  {VARIANT PART}
      IF NOT SEMI THEN ERROR (19);
      SEMI := FALSE;
      ISDEC := FALSE;
     { START OF VARIANT SELECTOR }
      NXTSYMOK;
      SAVESYM := SYM;
      ID1 := THISSYMP;
      NEXTSYM;
      IF SYM = COLON THEN
      BEGIN  {TAG-FIELD PRESENT}
         IF SAVESYM > NEWID THEN
         BEGIN  {MUST INSERT ID INTO SYMBOL TABLE AS NEW ID}
            NAMES.TADR := Y.LASTNAME;
            ENTERID (TAG, NOTYP);
            THISSYMP^.NAMLINK := ID1^.NAMLINK;
            ID1 := THISSYMP
         END
         ELSE
           IF SAVESYM = NEWID THEN ID1^.OBJ := TAG ELSE ERROR (62); {ID EXPECT}

         NEXTSYM;
         IF SYM <> TIPE THEN ERROR (120); {ORD TYPE EXPECTED}
         ORDTYP (RF1, SZ, PAC);
         ID1^.IDTYP := SUBR;
         ID1^.REF := RF1;
         ID1^.ADR := OFFSET;
         ID1^.PAK := PAC;
         OFFSET := OFFSET + SZ
      END

      ELSE
      BEGIN  {NO TAG-FIELD PRESENT, SHOULD BE TAG-TYPE}
         IF SAVESYM <> TIPE THEN ERROR (135);
         THISSYMP := ID1;
         SAVELASTNAME := Y.LASTNAME;
         Y.LASTNAME := THISSYMP^.NAMLINK;
         IF CHKTYP (RF1, SZ, PAC) <> SUBR THEN ERROR (120); {ORDINAL TYPE EXP}
         ID1 := THISSYMP;
         Y.LASTNAME := SAVELASTNAME
      END;

     { END OF VARIANT SELECTOR }

      CHK (OFSY); { START OF VARIANT }

      MAXVARIANT := OFFSET;
      LASTVARIANT := NIL;
      No_CONSTS := 0;
      REPEAT
         NEW (VARIENTS2);
         VARIENTS2^.LASTV := LASTVARIANT;
        { Create pointer to new list of constants }
         NEW (CLIST);
         VARIENTS2^.CONSTLIST := CLIST;
         CLIST^.NEXTC := NIL;

         13:IF NOT SEMI THEN NEXTSYM;
            SEMI := FALSE;
            ORDCON;
            No_CONSTS := SUCC (No_CONSTS);
            IF NOT EQTYPS (ID1^, THISSYMP^, FALSE) OR
               (LIMITS (ID1^) < THISSYMP^.VAL) OR (LLIM > THISSYMP^.VAL) THEN
               ERROR (141);
{
            IF (RF1^.TYP <> THISSYMP^.REF^.TYP) OR
               (RF1^.SUBRREF <> THISSYMP^.REF^.SUBRREF) OR
               (THISSYMP^.VAL > RF1^.HIGH) OR
               (THISSYMP^.VAL < RF1^.LOW) THEN ERROR (141);
}
            IF THISSYMP = BASESYMP THEN
            BEGIN { Case constant is only a temporary constant ie has not been
                   previously declared, so create a symbol table entry for it}
               NEW (LASTSYMP);
               LASTSYMP^ := THISSYMP^;
               THISSYMP := LASTSYMP
            END;

            NESTEDV := VARIENTS2;
            WHILE NESTEDV <> NIL DO
            BEGIN
               CLIST2 := NESTEDV^.CONSTLIST;
               WHILE CLIST2^.NEXTC <> NIL DO
               BEGIN
                  IF CLIST2^.CONS^.VAL = THISSYMP^.VAL THEN ERROR (71);
                  CLIST2 := CLIST2^.NEXTC
               END;
               NESTEDV := NESTEDV^.LASTV
            END;

            CLIST^.CONS := THISSYMP;
            NEXTSYM;
            IF ISCOMA THEN
            BEGIN
               NEW (NEXTCONST);
               CLIST^.NEXTC := NEXTCONST;
               CLIST := NEXTCONST;
               CLIST^.NEXTC := NIL;
               GOTO 13;
            END;

         CHKNEXT (COLON);
         ISDEC := TRUE;
         CHKNEXT (LPAREN);
         SZ := OFFSET;
         FIELDLIST (SZ, ARECSIZ, NESTEDV, PAC);

         VARIENTS2^.NESTEDV := NESTEDV;
         VARIENTS2^.MAXSIZE := SZ;
         LASTVARIANT := VARIENTS2;

         CHKNEXT (RPAREN);
         IF SZ > MAXVARIANT THEN MAXVARIANT := SZ;

         ISDEC := FALSE;
         SEMI := ISSEMI;
         IF SEMI THEN NXTSYMOK
      UNTIL NOT (SEMI AND ((SYM = KONST) OR (SYM IN [PLUS, MINUS])));

      OFFSET := MAXVARIANT;
      IF SUCC (RF1^.HIGH - RF1^.LOW) <> No_CONSTS THEN ERROR (100)

   END  { OF VARIANT-PART }
   ELSE VARIENTS2 := NIL;
   VARIENTS1 := VARIENTS2;

   IF ISSEMI THEN IF SEMI THEN ERROR (35) ELSE NXTSYMOK {END EXPECTED}
END; { fieldlist }


{PROCEDURE GETTYP (VAR TP          : TYPES;
                   VAR RF          : STP;
                   VAR SZ, ARECSIZ : SI;
                   VAR ELEMPAC     : BOOLEAN;
                       PAC, ARAYEL : BOOLEAN); FORWARD;}
BEGIN { gettyp }
   ELEMPAC := PAC;

   IF SYM IN [ARRAYSY, FILESY, RECORDSY, SETSY, PACKSY] THEN
   BEGIN { Type is structured, possibly packed }
      PAC := (SYM = PACKSY);

      elempac := pac; { Tutu - fixes 6.4.3.1 bug == D1.06 }
                      { Tutu - was ELEMPAC := PAC OR ELEMPAC; }

      IF PAC THEN NXTSYMOK; { skip 'packed' }

      IF SYM = SETSY THEN
      BEGIN
         TP1 := SETT;
         NXTSYMOK;
         CHKNEXT (OFSY);
         ORDTYP (RF1, SZ1, FALSE);
         SZ1 := MAXSET;
         if (rf1^.low < 0) or (rf1^.high > 255) then error (28) { Tutu }
{ Tutu - was
         IF BYTES (RF1^.LOW, RF1^.HIGH) > 1 THEN ERROR (28)
  Isolates against packing changing definition of BYTES
}
      END

      ELSE IF SYM = FILESY THEN
      BEGIN
         NXTSYMOK;
         CHKNEXT (OFSY);
         NEW (RF1, FYLE);
         align (sz1); { Tutu }
         GETTYP (RF1^.TYP, RF1^.FILEREF, SZ1, ARECSIZ, RF1^.FILEPAC, PAC,
                                                      FALSE{not aray element});
         RF1^.FILESIZ := SZ1;
         SZ1 := SZ1 + fcbsize; { Tutu - was 5 : POINTER AND FLAGS FOR FCB }
         align (sz1); { Tutu }
         IF CONTAINSFILE (FYLE, RF1^, FALSE) THEN ERROR (123);
                                               {NO FILES OF FILES}
         TP1 := FYLE
      END

      ELSE IF SYM = ARRAYSY THEN
      BEGIN
         NXTSYMOK;
         CHKNEXT (LBRAK);
         ARAYTYP (RF1, SZ1, ARECSIZ, PAC, ARAYEL);
         TP1 := ARAY;
         IF COULDBESTR THEN TP1 := STRNG
      END

      ELSE IF SYM = RECORDSY THEN
      BEGIN
         IF X.LEVEL = MAXLEV THEN ERROR (166);
         X.LEVEL := SUCC (X.LEVEL);
         NEW (RF1, REKORD, REKORD, REKORD);
         DISPLAY[X.LEVEL] := RF1;
         RF1^.TYP := REKORD;
         RF1^.LASTSYM := NIL;
         SZ1 := 0; {SET OFFSET ADDRESS IN RECORD TO 0}
         ISDEC := TRUE;
         NXTSYMOK;
         FIELDLIST (SZ1, ARECSIZ, RF1^.VARIANTS, PAC);
         RF1^.VARSIZ := SZ1;
         X.LEVEL := PRED (X.LEVEL);
         LASTSYMP := DISPLAY[X.LEVEL]^.LASTSYM;
         CHKNEXT (ENDSY);
         TP1 := REKORD
      END

      ELSE ERROR (134) { Can't pack an unstructured type }
   END { of checking for structured types }

   ELSE
      IF SYM = TIPE THEN { already known type }
      BEGIN
         TP1 := CHKTYP (RF1, SZ1, PAC);
         if thissymp^.idtyp > pntr then elempac := thissymp^.pak; { Tutu }
{ Tutu - 6.4.3.1 bug again : thissymp^ only packed if structured }
{ Tutu - was ELEMPAC := ELEMPAC OR THISSYMP^.PAK; }

         NXTSYMOK
      END

      ELSE IF SYM = AT THEN { new pointer type }
      BEGIN
         ISDEC := ISTYPDECS;
         THISLEV := X.LEVEL;
         X.LEVEL := X.PROCLEV;
         NXTSYMOK;
         X.LEVEL := THISLEV;
         NEW (RF1, PNTR);
         THISCOPY := THISSYMP;

         IF SYM = TIPE THEN
         BEGIN
            IF THISCOPY^.IDTYP = NOTYP THEN
            BEGIN { Id used before as domain & has not been resolved, so add
                    it to list of uses of this unresolved type }
               RF1^.NEXTREF := THISCOPY^.REF^.NEXTREF;
               THISCOPY^.REF^.NEXTREF := RF1
            END
            ELSE
            BEGIN {ALL INFO AT HAND SO CREATE POINTER RECORD}
               RF1^.PNTRREF := THISCOPY^.REF;
               RF1^.TYP := THISCOPY^.IDTYP;
               RF1^.PSZ := THISCOPY^.ADR
            END
         END

         ELSE IF ISTYPDECS THEN
            IF SYM = NEWID THEN
            BEGIN
             { Check that an id with the same spelling as the new id
               has not been used at the current level }
               THISCOPY^.USED_LEV := THISLEV;
               THISCOPY^.USED_PROC:= X.THISPROCNO;
               THISCOPY^.OBJ := TIPE;
               THISCOPY^.REF := RF1;
               RF1^.NEXTREF := NIL
            END
            ELSE
               IF (SYM = BADUN) AND (THISSYMP = TYPID) THEN
               BEGIN  {LHS OF TYPE DEC IS REFERENCED ON RHS}
                  RF1^.NEXTREF := LHSPTR;
                  LHSPTR := RF1
               END
               ELSE ERROR (115) {TYPE ID EXPECTED}

         ELSE ERROR (115); {TYPE ID EXPECTED}

         TP1 := PNTR;
         SZ1 := ptrsize; { Tutu - was 2 }
         ISDEC := FALSE;
         NEXTSYM
      END  {OF NUPNTRTYP}

      ELSE
      BEGIN
         IF SYM IN [KONST, LPAREN, MINUS, PLUS]
         THEN ORDTYP (RF1, SZ1, PAC) {ENUMERATED OR SUBR}
         ELSE ERROR (115); {TYPE EXPECTED}
         TP1 := SUBR
      END;

   CHKSZ (SZ1);
   RF := RF1;
   SZ := SZ1;
   TP := TP1
END; { gettyp }


PROCEDURE TYPEDECS (VAR ARECSIZ : SI);
VAR RF, RF1, RF2 : STP;
    THISDISP : TYPREC;
    LAST, NEXT : SYMP;
    TP : TYPES;
    LASTNAME, TEMP, SZ : SI;
    DOMAIN : BOOLEAN;


PROCEDURE RESOLVEPTR;
BEGIN
   WHILE RF2 <> NIL DO
   BEGIN
      RF2^.PNTRREF := RF;
      RF2^.TYP     := TP;
      RF2^.PSZ     := SZ;
      RF2          := RF2^.NEXTREF
   END
END; { resolveptr }


BEGIN { typedecs }
   ISTYPDECS := TRUE;
   NXTSYMOK;

   REPEAT
      align (arecsiz); { Tutu - each time round the loop }

      DOMAIN := (SYM = TIPE);
      IF NOT ((SYM = NEWID) OR (DOMAIN AND (THISSYMP^.IDTYP = NOTYP)))
      THEN ERROR (62); { Newid expected }
      TYPID := THISSYMP;
     { Check that an id with the same spelling as the new id
       has not been used at the current level }
      IF BADSCOPE AND (SYM = NEWID) THEN ERROR (104);
      TYPID^.OBJ := BADUN;
      NEXTSYM;
      ISDEC := FALSE;
      LHSPTR := NIL;
      LAST := TYPID;
      CHKNEXT (EQUALS);
      GETTYP (TP, RF, SZ, ARECSIZ, LAST^.PAK, FALSE, FALSE{not array element});
      ISDEC := TRUE;
      RF1 := LHSPTR;
      LAST^.OBJ := TIPE;
      LAST^.IDTYP := TP;
      LAST^.ADR := SZ;

      IF DOMAIN THEN
      BEGIN
         RF2 := LAST^.REF;
         RESOLVEPTR;
      END;

      RF2 := RF1;
      RESOLVEPTR;

      LAST^.REF := RF;
      CHKNEXT (SEMICOLON)
   UNTIL SYM <= EOFILE;

{ LOOK FOR ANY UNRESOLVED POINTER TYPES }

   THISDISP := DISPLAY[X.LEVEL]^;
   LAST := THISDISP.LASTSYM;
   NEXT := LAST;
   LASTNAME := Y.LASTNAME;
   REPEAT
      IF (NEXT^.OBJ = TIPE) AND (NEXT^.IDTYP = NOTYP) THEN
      BEGIN
         X.DEPTH := PRED (X.LEVEL);
         REPEAT
            THISSYMP := DISPLAY[X.DEPTH]^.LASTSYM;
            Y.LASTNAME := NEXT^.NAMLINK;
            TEMP := CODE1 (EQID, X.DEPTH, X.DEPTH);
            X.DEPTH := PRED (X.DEPTH)
         UNTIL (X.DEPTH > 100) OR (THISSYMP <> NIL);

         IF THISSYMP = NIL THEN ERROR (132)
         ELSE IF THISSYMP^.OBJ = TIPE THEN
         BEGIN
            RF2 := NEXT^.REF;
            WITH THISSYMP^ DO
            BEGIN
               RF := REF;
               TP := IDTYP;
               SZ := ADR
            END;
            RESOLVEPTR;

           { REMOVE NEXT FROM SYMBOL TABLE LIST }
            IF NEXT = THISDISP.LASTSYM THEN
            BEGIN
               THISDISP.LASTSYM := NEXT^.LINK;
               LASTSYMP := THISDISP.LASTSYM
            END
            ELSE
            BEGIN
               LAST^.LINK := NEXT^.LINK;
               NEXT := LAST
            END
         END
         ELSE ERROR (133)
      END;
      LAST := NEXT;
      NEXT := NEXT^.LINK
   UNTIL NEXT = NIL;

   DISPLAY[X.LEVEL]^ := THISDISP;
   Y.LASTNAME := LASTNAME
END; { typedecs }


PROCEDURE PFDEC (NOTPARAM : BOOLEAN; PROCADR  : UW); FORWARD;


PROCEDURE FPARAMLIST (VAR PSIZE : SI; VAR PLIST : PARAMP);
VAR VALPARM, PACVAR : BOOLEAN;
    RF1, RF2 : STP;
    SZ1, IDCOUNT : SI;
    NEXTOFFSET, No_PACKED, CDESCADR : UW;
    TP, SAVETYP : TYPES;
    PLIST2 : PARAMP;
    ID1, ID2 : SYMP;


PROCEDURE FPARAMTYP (VAR TP      : TYPES;
                     VAR RF      : STP;
                     VAR SZ      : SI;
                     VAR ELEMPAC : BOOLEAN);


PROCEDURE CARAYTYP (VAR RF : STP;  PAC : BOOLEAN);
VAR AP : STP;
    LOWB,
    HIGHB : SYMP;
    TP1 : TYPES;
    RF1 : STP;
    SZ1 : SI;
    LOCALELEMPAC : BOOLEAN;


PROCEDURE BOUNDS (BOUND : SYMP);
BEGIN
   BOUND^.IDTYP := SUBR;
   BOUND^.OBJ   := BOUNDID;
   BOUND^.REF   := RF1;
   BOUND^.OFSET := NEXTOFFSET;
   NEXTOFFSET   := NEXTOFFSET + twiceptrsize { Tutu - was 4 }
END; { bounds }


BEGIN { caraytyp }
   CHKNEXT (NEWID);
  { Check that an id with the same spelling as the new id
    has not been used at the current level }
   IF BADSCOPE THEN ERROR (104);
   LOWB := THISSYMP;

   CHKNEXT (DDOT);

   CHKNEXT (NEWID);
  { Check that an id with the same spelling as the new id
    has not been used at the current level }
   IF BADSCOPE THEN ERROR (104);

   HIGHB := THISSYMP;
   ISDEC := FALSE;

   CHKNEXT (COLON);

   NEW (AP, CARAY, CARAY, CARAY);
   AP^.LOWB := LOWB;
   AP^.HIGHB := HIGHB;

   ORDTYP (RF1, SZ1, FALSE);
   AP^.IREF := RF1;
   BOUNDS (LOWB);
   BOUNDS (HIGHB);
   NEXTOFFSET := NEXTOFFSET + 3; { Tutu - watch for this one ! }

   LOCALELEMPAC := PAC;
   IF ISSEMI THEN
   BEGIN
      IF PAC THEN ERROR (144);
      ISDEC := TRUE;
      NXTSYMOK;
      CARAYTYP (RF, PAC)
   END
   ELSE
   BEGIN
      CHKNEXT (RBRAK);
      CHKNEXT (OFSY);
      FPARAMTYP (TP, RF, SZ, LOCALELEMPAC)
   END;

   AP^.ELREF := RF;
   AP^.TYP   := TP;

   TP := CARAY;
   RF := AP;
   RF^.ALEV := X.LEVEL + ORD (LOCALELEMPAC OR PAC) * 128
END; { caraytyp }


BEGIN { fparamtyp }
   IF SYM = PACKSY THEN
   BEGIN
      ELEMPAC := TRUE;
      No_PACKED := SUCC (No_PACKED);
      IF No_PACKED > 1 THEN ERROR (144); { Packed carays must be single dim }
      NXTSYMOK
   END
   ELSE ELEMPAC := FALSE;

   IF SYM = ARRAYSY THEN
   BEGIN
      NXTSYMOK;
      CHKNEXT (LBRAK);
      CARAYTYP (RF, ELEMPAC);
      SZ := twiceptrsize { Tutu - was 4 }
   END

   ELSE IF SYM = TIPE THEN
   BEGIN
      IF ELEMPAC THEN ERROR (106);
      WITH THISSYMP^ DO
      BEGIN
         TP := IDTYP;  SZ := ADR;  RF := REF;  ELEMPAC := PAK
      END;
      NXTSYMOK
   END

   ELSE ERROR (115) { Type id expected }
END; { fparamtyp }


BEGIN { fparamlist }
   REPEAT
      No_PACKED := 0;
      NEXTOFFSET := 3;
      ISDEC := TRUE;
      NEXTSYM; { Skip '(' }

      IF (SYM = PROCSY) OR (SYM = FUNCSY) THEN { Got a routine as a parameter }
      BEGIN
         PFDEC (FALSE, PSIZE);
         PSIZE := PSIZE + dspNprocsize; { Tutu - was 18 }
         X.LEVEL := PRED (X.LEVEL)
      END

      ELSE
      BEGIN {PARAMETER (S) SHOULD BE IDS}
         VALPARM := SYM <> VARSY;
         IF SYM = VARSY THEN NXTSYMOK;
        { GET ID LIST IN }
         CHKNEXT (NEWID);
         ID1 := LASTSYMP^.LINK;
         LASTSYMP^.NRM := VALPARM;
        { Check that an id with the same spelling as the new id
          has not been used at the current level }
         IF BADSCOPE THEN ERROR (104);

         IDCOUNT := 1; { Loop over identically typed parameters }
         WHILE ISCOMA DO
         BEGIN
            NXTSYMOK;
            CHKNEXT (NEWID);
           { Check that an id with the same spelling as the new id
             has not been used at the current level }
            IF BADSCOPE THEN ERROR (104);
            IDCOUNT := SUCC (IDCOUNT);
            LASTSYMP^.NRM := VALPARM
         END;
         ID2 := LASTSYMP;

        { GOT ID LIST }
         ISDEC := FALSE;
         CHKNEXT (COLON);

        { GET TYPE }
         FPARAMTYP (TP, RF1, SZ1, PACVAR);

         IF NOT VALPARM THEN SZ1 := ptrsize { Tutu - was 2 }
         ELSE
            IF CONTAINSFILE (TP, RF1^, TRUE) THEN ERROR (158);

         IF TP = CARAY THEN
         BEGIN
            CDESCADR := psize + ptrsize; { Tutu - was SUCC (SUCC (PSIZE))}
            SZ1 := sz1 + ptrsize;        { Tutu - was SUCC (SUCC (SZ1))}
            RF2 := RF1;
            REPEAT
               RF2^.ADESCOFF     := CDESCADR;
               RF2^.LOWB^.ADESC  := CDESCADR;
               RF2^.HIGHB^.ADESC := CDESCADR;
               SAVETYP           := RF2^.TYP;
               RF2               := RF2^.ELREF
            UNTIL SAVETYP <> CARAY
         END;

         NEW (PLIST2);
         PLIST2^.No     := IDCOUNT;
         PLIST2^.NEXTNo := PLIST;
         PLIST          := PLIST2;

         PSIZE := PSIZE + IDCOUNT * SZ1;
         align (psize); { Tutu }
         IDCOUNT := PSIZE - SZ1;
        { ASSIGN IDS IN LIST TO CORRECT TYPE }
         REPEAT
            ID2^.OBJ := VARID;
            ID2^.IDTYP := TP;
            ID2^.REF := RF1;
            ID2^.ADR := IDCOUNT;
            IDCOUNT  := IDCOUNT - SZ1;
            ID2^.PAK := PACVAR;
            ID2      := ID2^.LINK
         UNTIL (ID2 = ID1) OR FUCKUP
      END
   UNTIL (NOT ISSEMI) OR FUCKUP;

   CHKNEXT (RPAREN)
END; { fparamlist }


PROCEDURE BLOCK (VAR ARECSIZ : SI); FORWARD;


PROCEDURE PFDEC;
VAR NMRK : UW;
    BLKNAME : SYMP;
    TP : TYPES;
    LOCSIZ : SI;
    SAVESYM : SYMBOLS;
    FROGGY, VARPARM : BOOLEAN;
    PLIST2 : PARAMP;
    PNO : UB;
    PFNAM : PFNAMP;


PROCEDURE PFBLK;
VAR FUNCRES : SYMREC;
    ENTADR : UW; { Address of start of ENTER patches }


PROCEDURE REMOVE (VAR LP, LS : SYMP);
VAR ID, LS2 : SYMP;

BEGIN { remove }
   LS2 := LS;
   WHILE LS2 <> LP DO
   BEGIN
      IF (LS2^.OBJ = PROC) OR (LS2^.OBJ = FUNC) THEN
      BEGIN
         REMOVE (LS2^.REF^.LASTSYM, LS2^.REF^.LASTPARAM);
         DISPOSE (LS2^.REF)
      END;
      ID := LS2^.LINK;
      DISPOSE (LS2);
      LS2 := ID
   END;
   LS := NIL
END; { remove }


BEGIN { pfblk }
   DBUGNAME (BLKNAME^); { Tutu - This must now be generated at all times ! }

   FLUSHNGEN (221); { S_enter : proc/func }
   GENUB (PRED (X.LEVEL));
   ENTADR := X.CADR;
   GENSI (0); { arec size & SP offset - to be patched later on }

   BLOCK (LOCSIZ);

   WITH BLKNAME^.REF^ DO
   BEGIN
{ Check if this procedure has any value parameter conformant arrays; if it
  does then code must be generated to remove the copy array from the heap.
}
      X.LEVEL := SUCC (X.LEVEL);
      VAL_CONF_DISPOSE (LASTPARAM);

      X.LEVEL := X.PROCLEV;
      STORPATCH (ENTADR,   X.MAXSTK);
      STORPATCH (ENTADR+2, LOCSIZ-PARAMSIZ);
      VARSIZ := LOCSIZ;

      IF BLKNAME^.OBJ = FUNC THEN
      BEGIN
         FLUSHNGEN (181); { S_func_ret : from function }
         GENUW (FUNCVAR);
         GENUB (RESSIZ);
         IF NOT BLKNAME^.FUNCASS THEN ERROR (96)
      END
      ELSE FLUSHNGEN (125); { S_return : from procedure }

     { Release unwanted symbol table }
      Y.LASTNAME := NMRK;
      REMOVE (LASTPARAM, LASTSYM)
   END
END; { pfblk }


BEGIN { pfdec }
   SAVESYM := PROC;
   IF SYM = FUNCSY THEN SAVESYM := FUNC;
   ISDEC := TRUE;
   NXTSYMOK;
   BLKNAME := THISSYMP;
   BLKNAME^.NRM := NOTPARAM;
   NMRK := Y.LASTNAME;

   IF SYM = NEWID THEN {New PROC or FUNC declaration}
   BEGIN
     { Check that procedure id has not been used before defining occurence }
      IF X.USED_AT_LEV >= X.LEVEL THEN ERROR (164);
      IF NOTPARAM THEN PFLIST;
      X.THISPROCNO := X.PROCNO;
      BLKNAME^.ADR := PROCADR;
      LOCSIZ := hkfsize; { Tutu - was 9 }
      BLKNAME^.OBJ := SAVESYM;
      ENTBLK;
      NXTSYMOK;

      BLKNAME^.REF := DISPLAY[X.LEVEL];
      WITH BLKNAME^.REF^ DO
      BEGIN
         PLIST := NIL;
         IF SYM = LPAREN THEN
         BEGIN
            ISTYPDECS := FALSE;
            PHEAD := TRUE;
            FPARAMLIST (LOCSIZ, PLIST);
            LASTPARAM := LASTSYM;
            PHEAD := FALSE
         END;
         PARAMSIZ := LOCSIZ;

         X.PROCLEV := X.LEVEL;
         ISDEC := FALSE;
         IF SAVESYM = FUNC THEN
         BEGIN
            CHKNEXT (COLON);
            IF SYM = TIPE THEN
            BEGIN
               RESSIZ := THISSYMP^.ADR;
               TP := THISSYMP^.IDTYP;
               IF TP > PNTR THEN ERROR (128); {FUNC TYPE MUST BE ORD/REAL/PTR}
               FUNCVAR := LOCSIZ;
               LOCSIZ := LOCSIZ + RESSIZ;
               align (locsiz); { Tutu }
               BLKNAME^.IDTYP := TP;
               FUNCREF := THISSYMP^.REF;
            END
            ELSE ERROR (126);  {FUNCTION TYPE EXPECTED}
            NEXTSYM
         END;

         IF NOTPARAM THEN
         BEGIN
            CHKNEXT (SEMICOLON);
            BLKNAME^.ADR := X.PROCNO;
            IF SYM = FORWAD THEN
            BEGIN
               VARSIZ := LOCSIZ;
               BLKNAME^.PERM := TRUE;  {IE. UNDEFINED}
               X.LEVEL := PRED (X.LEVEL);
               NXTSYMOK
            END
            ELSE PFBLK
         END
         ELSE Y.LASTNAME := NMRK
      END {with}
   END

   ELSE
      IF (SYM = SAVESYM) AND (NOTPARAM) THEN { Definition of FORWARD procedure}
      BEGIN
         X.LEVEL := SUCC (X.LEVEL);
         DISPLAY[X.LEVEL] := BLKNAME^.REF;
         X.THISPROCNO := BLKNAME^.ADR;
         NXTSYMOK;
         CHKNEXT (SEMICOLON);
         LOCSIZ := BLKNAME^.REF^.VARSIZ;
         IF NOT BLKNAME^.PERM THEN ERROR (140);
         BLKNAME^.PERM := FALSE;
         PFNAM := PROCTAB;
         FOR PNO := 0 TO BLKNAME^.ADR DO PFNAM := PFNAM^.NEXT;
         PFNAM^.ADR := X.CADR;
         PFBLK
      END  {OF FORWARDEF}
      ELSE ERROR (138)
END;


PROCEDURE BLOCK;
LABEL 13;

VAR TEMPFS, SEMI : BOOLEAN;
    PIGS_WILL_FLY : UB;
    PJMP : UW;
    P1, P2 : LABP;
    ID1 : SYMP;
    LABVAL : SI;

BEGIN { block }
   X.PROCLEV := X.LEVEL;
   ISDEC := TRUE;

   ACCEPT := [LABELSY,CONSTSY,VARSY,TYPESY,BEGINSY,PROCSY,FUNCSY,SEMICOLON];

   LABS[X.LEVEL] := NIL;
   IF SYM = LABELSY THEN
   BEGIN
      REPEAT
         NEXTSYM;
         UC;
         LABVAL := THISSYMP^.VAL;
         IF (NOT ISLAB) OR (LABVAL < 0) OR (LABVAL > 9999)
         THEN ERROR (40) { Label must be a sequence of digits 0 - 9999}
         ELSE
         BEGIN
            P1 := LABS[X.LEVEL];
            P2 := P1;
            WHILE P1 <> NIL DO
            BEGIN
               IF P1^.VAL = LABVAL THEN
               BEGIN
                  ERROR (39); { Label already declared }
                  GOTO 13
               END;
               P2 := P1;
               P1 := P1^.NEXT
            END;

            NEW (P1);
            P1^.CA     := 0;
            P1^.VAL    := LABVAL;
            P1^.USED   := FALSE;
            P1^.NEXT   := NIL;
            P1^.USER   := NIL;
            P1^.PREFIX := FALSE;
            IF P2 = NIL THEN LABS[X.LEVEL] := P1 ELSE P2^.NEXT := P1
         END;
      13 : NEXTSYM
      UNTIL NOT ISCOMA;
      CHKNEXT (SEMICOLON)
   END; { of label declaration part }

   IF SYM = CONSTSY THEN
   BEGIN
      NXTSYMOK;
      REPEAT
         CHKNEXT (NEWID);
        { Check that an id with the same spelling as the new id has not
          been used at the current level }
         IF BADSCOPE THEN ERROR (104);
         ISDEC := FALSE;
         CHKNEXT (EQUALS);
         KONSTANT;
         LASTSYMP^.OBJ     := KONST;
         LASTSYMP^.IDTYP   := THISSYMP^.IDTYP;
         LASTSYMP^.REELVAL := THISSYMP^.REELVAL;
         LASTSYMP^.REF     := THISSYMP^.REF;
         IF THISSYMP^.IDTYP = STRNG THEN
         BEGIN
            IF THISSYMP = BASESYMP {SAVE STRING IN NAMES TABLE}
            THEN Y.LASTNAME := SUCC (NAMES.TADR);
            LASTSYMP^.PAK := TRUE
         END;
         ISDEC := TRUE;
         NEXTSYM;
         CHKNEXT (SEMICOLON)
      UNTIL SYM <= EOFILE
   END; { of constant declaration part }

   X.ACTIVLEV := X.LEVEL;
   IF SYM = TYPESY THEN TYPEDECS (ARECSIZ); { Try type declaration part }

   align (arecsiz); { Tutu paranoia }

   TEMPFS := FALSE;
   IF SYM = VARSY THEN
   BEGIN
      ISTYPDECS := FALSE;
      NXTSYMOK;
      ISDEC := TRUE;
      REPEAT
         align (arecsiz); { Tutu paranoia }
         VARLIST (PIGS_WILL_FLY, FALSE {not var param},
                  FALSE {not param}, VARID, ARECSIZ, ARECSIZ, FALSE, TEMPFS);
         ISDEC := TRUE;
         CHKNEXT (SEMICOLON)
      UNTIL SYM <= EOFILE
   END; { of variable declaration part }

   align (arecsiz); { Tutu paranoia }

   IF (SYM = PROCSY) OR (SYM = FUNCSY) THEN { Any embedded local routines ? }
   BEGIN
      GENJMP (68, 0); { jmp_now : Branch around any procedures }
      PJMP := X.LASTADR;

      REPEAT
         PFDEC (TRUE, 0); { Parse over procedure/ function declarations }
         CHKNEXT (SEMICOLON)
      UNTIL (SYM <> PROCSY) AND (SYM <> FUNCSY);

      STORPATCH (PJMP, X.CADR)
   END;                   

   ISDEC := FALSE;

   ID1 := DISPLAY[X.LEVEL]^.LASTSYM;
   WHILE ID1 <> NIL DO
   BEGIN
      IF (ID1^.OBJ >= PROC) AND (ID1^.PERM) THEN ERROR (31); {Und FORWARD dec}
      IF (ID1^.OBJ = VARID) AND (ID1^.ADR < -2)
      THEN ERROR (102); { File appeared in program header but was not defined }
      ID1 := ID1^.LINK
   END;

   CHK (BEGINSY); { Start to parse block body }
   X.STKINC  := ARECSIZ;
   X.MAXSTK  := X.STKINC;
   X.STMTLEV := 0;
   X.ACTIVLEV := X.LEVEL;
   X.SEQNO := 0;
   OKGOTOS := [];

   BLKSTMT (ENDSY);

   IF TEMPFS THEN FLUSHNGEN (219); { close_files }

   P1 := LABS[X.LEVEL];
   WHILE P1 <> NIL DO
   BEGIN
      IF NOT P1^.USED THEN ERROR (24); { Label declared but not defined }
      P2 := P1;
      P1 := P1^.NEXT;
      DISPOSE (P2)
   END;

   X.MAXSTK := X.MAXSTK + 32; { Tutu - arbitrary guess for hasp use, was 10 }
   DISPLAY[X.LEVEL] := NIL;
   X.LEVEL := PRED (X.LEVEL);

   THISSYMP := DISPLAY[X.LEVEL]^.LASTSYM;
   WHILE (THISSYMP <> NIL) AND (THISSYMP^.OBJ >= EPROC) DO
   BEGIN
      THISSYMP^.USED_LEV := 0;
      THISSYMP := THISSYMP^.LINK
   END;

   X.PROCLEV := X.LEVEL
END; { block }


BEGIN { main }
   writeln ('ARM Pascal Compiler 0.12 (01-Apr-86)');

   signed := FALSE; { RCM - avoids unassigned error }
   stack_size := 0; { Tutu - Use default stack unless told otherwise }

   X.MAXNAME     := 2000;
   X.ACTIVLEV    := 1;
   X.LEVEL       := PRED (0);
   X.LINENO      := 0;
   X.CADR        := 0;
   X.ERRORS      := 0;
   X.CHRNO       := 0;
   X.ERRNO       := 0;
   X.PROCNO      := PRED (0);
   X.THISPROCNO  := 0;
   PHEAD         := FALSE;
   ERRSET        := [];
   SINGLEOPS     := '@~,.:;^()[]*+-/====<> ';
   CBUFF.BASICOP := 0; { Sets code buffer to empty }
   ACTIVELIST    := NIL;

   NEW (PROCTAB);
   PFNAMES       := PROCTAB;

  {OPTYPVAL = OFFSETS TO ADD TO BL-OPERATOR-CODES DEPENDING ON OPERAND TYPES}

  {MOVTYPVAL = OFFSETS TO ADD TO BL-MOVEDATA-CODES DEPENDING ON OPERAND TYPES
   Also used in reads and writes }

   NEW (PATCH1); { Set up the list of patches to be made after compilation }
   NEW (PATCH1^.NEXT);
   PATCH1^.NEXT^.NEXT  := NIL;
   PATCH1^.NEXT^.ADDR  := 0;
   PATCH1^.NEXT^.VALUE := 0;

   NEW (BASESYMP);
   SETSUBRTYP (BASESYMP^, NIL);

{ COMPILER OPTIONS SET UP BY MACHINE CODE INIT }
{ Initialise display for standard ids and BOOLDESC, CHARDESC & INTDESC }
   ENTBLK;
   X.INDEX := CODE1 (PNTRINIT, 0, FUCKUP);
   DISPLAY[0]^.LASTSYM := LASTSYMP;

{ Reset sourcefile to the console }
   CLRSTR (SOURCEFILE);
   OPEN;

{ Get source file name from the command tail }
   GETNAME (SOURCEFILE);
   X.NAMESZ := PRED (X.INDEX);

   IF X.INDEX = 1 THEN
   BEGIN
      SOURCEFILE[1] := CHR (13);
      X.SRCLINE := 0;
      X.NAMESZ := 1;
      ERROR (167)
   END;

   SKIPSPACES;

{ Get code file name from the command tail }
   GETNAME (CODEFILE);
   IF X.INDEX = 1 THEN ERROR (167)
   ELSE
   BEGIN
      IF CODEFILE = SOURCEFILE THEN ERROR (168);
      X.INDEX := CODE1 (DELFILE, 0, CODEFILE)
   END;

   SKIPSPACES;

   genub (&FF); { Tutu - identification byte for A4 type code }

{ Get command line compiler options if any }
   CLO := (SOURCE^ = '{');
   IF NOT CLO THEN OPEN;

   NEXTSYM;
   CHANGE := FALSE;

   GENUB (175); { S_init }
   GENUB (ORD (TAIL));
   X.DBUGTAB := X.CADR;
   GENUW (0);
   genuw (stack_size); { Tutu - extra two bytes to say how much stack to use }

   ACCEPT := [EOFILE, DOT, SEMICOLON, VARID, BEGINSY, PROCSY,
              FUNCSY, CONSTSY, VARSY, TYPESY, LABELSY];

   CHKNEXT (PROGSY);
   PFLIST;
   DBUGNAME (THISSYMP^);
   LASTSYMP := LASTSYMP^.LINK;
   DISPLAY[X.LEVEL]^.LASTSYM := LASTSYMP;
   IF SYM < FORWAD THEN ERROR (1);

   ENTBLK;
   NAMES.TADR := X.GARECADR;
   GLOBSIZ := CODE1 (TABINIT, 0, NAMES.TPTR^);

{INPUT = FILE No 1, NEGATIVE = TEMPORARY FILE}
   ENTERID (VARID, TXT);
   LASTSYMP^.REF := CHARDESC;
   LASTSYMP^.ADR := PRED (0);
   LASTSYMP^.NAMLINK := X.GARECADR;
   INPTSYMP := LASTSYMP;

{OUTPUT = FILE No 2, NEGATIVE = TEMPORARY FILE}
   ENTERID (VARID, TXT);
   LASTSYMP^.REF := CHARDESC;
   LASTSYMP^.ADR := -2;
   LASTSYMP^.NAMLINK := X.GARECADR + 6; { :len: "input " }
   OTPTSYMP := LASTSYMP;

   Y.LASTNAME := X.GARECADR + 13; { :len: "input output " }

   GENUW (221); { S_enter, level zero - main program }
   X.GARECADR := X.CADR;
   GENSI (0); { arec size & SP offset to be patched later}

   GLOBSIZ := hkfsize; { Tutu - was 9 }
   NEXTSYM;

   IF SYM = LPAREN THEN { We have program parameters }
   BEGIN
      REPEAT
         NEXTSYM;
         THISSYMP^.PERM := TRUE;
         IF SYM = NEWID THEN
         BEGIN
            THISSYMP^.OBJ   := VARID;
            THISSYMP^.IDTYP := FYLE;
            THISSYMP^.ADR   := -3
         END

         ELSE IF (SYM = VARID) THEN
         BEGIN
            IF THISSYMP^.ADR = PRED (0) {FILE NOT BEEN MADE PERMANENT }
            THEN X.INDEX := &A7 {SET INPUT TO PERMANENT}
            ELSE
               IF THISSYMP^.ADR = -2
               THEN X.INDEX := &AB { SET OUTPUT TO PERMANENT }
               ELSE ERROR (131); {FILE ALREADY DECLARED PERMANENT}

            THISSYMP^.ADR := GLOBSIZ; {SET INPUT/OUTPUT TO PERMANENT}

            GENMOV (LOCATE, THISSYMP^);
            flushngen (&F2); { pshK_nil - GENUB would ignore above loc. ! }
{ Tutu - was GENOPWTB (1, 0); PshK_ptr 0000 replaced with above line D1.02 }
            GENUB (X.INDEX);  { RESET INPUT / REWRITE OUTPUT }
            GENSI (0);
            GLOBSIZ := GLOBSIZ + fcbsize + 4 { Tutu - was 6 : FCB + BV }
         END

         ELSE ERROR (110); {VARIABLE EXPECTED}

         NEXTSYM
      UNTIL NOT ISCOMA;

      CHKNEXT (RPAREN)
   END; { of program parms }

   CHKNEXT (SEMICOLON); { Need semicolon anyway }

   BLOCK (GLOBSIZ);

   STORPATCH (X.GARECADR,   X.MAXSTK); { Patch the enter code }
   STORPATCH (X.GARECADR+2, GLOBSIZ-hkfsize); { Tutu - was 9 }

   FLUSHNGEN (176); { S_exit }

   STORPATCH (X.DBUGTAB, X.CADR);

{ Output the procedure address table }

   REPEAT
      PROCTAB := PROCTAB^.NEXT;
      GENUW (PROCTAB^.ADR)
   UNTIL PROCTAB^.NEXT = NIL;
   GENUW (&FFFF);

   CHKNEXT (DOT);

999:
   WRITELN;
   ERRLINE;
   write (X.ERRORS:1, ' Compilation error');
   if x.errors <> 1 then write ('s'); { Tutu pedantry strikes again }
   writeln;

   if x.errors <> 0 then oscli ('fx21') ; { Tutu - flush kbd buffer D1.03 }


{ Patch the code file }

   IF GENCODE THEN
   BEGIN
      X.LASTADR := 0;
      RESET (PFILE);
      REWRITE (CODEF, CODEFILE);
      PATCH1 := PATCH1^.NEXT^.NEXT;

      REPEAT
         READ (PFILE, X.INDEX);
         IF PATCH1^.ADDR = X.LASTADR THEN
         BEGIN
            X.LASTADR := SUCC (X.LASTADR);
            READ (PFILE, X.INDEX);
            WRITE (CODEF, PATCH1^.VALUE MOD 256);
            X.INDEX := PATCH1^.VALUE DIV 256;
            IF PATCH1^.NEXT <> NIL THEN PATCH1 := PATCH1^.NEXT
         END;

         X.LASTADR := SUCC (X.LASTADR);
         WRITE (CODEF, X.INDEX)
      UNTIL X.CADR <= X.LASTADR
   END;

   WRITELN ('Code size = ', X.CADR:1, ' bytes')
END. { main }
