Here are some model solutions for Section B. Full model solutions for the whole paper may happen later. Attribute free version ====================== COMPILER Mixed CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" . digit = "0123456789" . IGNORE CHR(9) .. CHR(13) IGNORE CASE COMMENTS FROM "(*" TO "*)" NESTED TOKENS ident = letter { letter | digit } . integer = digit { digit } . label = letter { letter | digit } ":" . PRODUCTIONS Mixed = "PROGRAM" Declarations CompoundStatement "." . Declarations = { Type OneVar { "," OneVar } ";" } . Type = "INT" | "BOOL" . OneVar = Identifier . CompoundStatement = "BEGIN" Statement { ";" Statement } "END" . Statement = [ Assignment | IfStatement | AsmSequence | CompoundStatement ] . Assignment = Variable ":=" Expression . Variable = Identifier . Expression = Variable | Integer . IfStatement = "IF" Condition "THEN" Statement "ELSE" Statement . Condition = Expression "=" Expression . AsmSequence = "ASM" { AsmStatement } "END" . AsmStatement = label | Identifier Operand [ "," Operand ] ";" . Operand = Identifier | Integer | "[" Integer "]" . Identifier = ident . Integer = integer . END Mixed. C++ version ============ COMPILER Mixed $CXN /* Pat Terry Mon 09-14-98 */ #include "misc.h" CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" . digit = "0123456789" . IGNORE CHR(9) .. CHR(13) IGNORE CASE COMMENTS FROM "(*" TO "*)" NESTED TOKENS ident = letter { letter | digit } . integer = digit { digit } . label = letter { letter | digit } ":" . PRODUCTIONS Mixed = "PROGRAM" (. Initialize(); .) Declarations CompoundStatement "." . Declarations = (. int NextAdr = 255; .) { Type OneVar<NextAdr> { "," OneVar<NextAdr> } ";" } . Type = "INT" | "BOOL" . OneVar <int &NextAdr> = (. char Name[100]; .) Identifier<Name> (. Insert(Name, NextAdr--); .) . CompoundStatement = "BEGIN" Statement { ";" Statement } "END" . Statement = [ Assignment | IfStatement | AsmSequence | CompoundStatement ] . Assignment = (. int Pos; .) Variable<Pos> (. printf(" MOV "); WriteOperand(Pos); printf(", ") .) ":=" Expression (. printf("\n"); .) . Variable <int &Pos> = (. char Name[100]; bool found.) Identifier<Name> (. Position(Name, Pos, found); if (!found) SemError(104); .) . Expression = (. int Pos, Value; .) Variable<Pos> (. WriteOperand(Pos); .) | Integer<Value> (. printf("%d", Value); .) . IfStatement = "IF" Condition (. int Lab = NextLabel; NextLabel += 2; printf(" BNZ L%d\n", Lab); .) "THEN" Statement (. printf(" BRN L%d\n", Lab+1); printf("L%d:\n", Lab); .) "ELSE" Statement (. printf("L%d:\n", Lab+1); .) . Condition = (. printf(" CMP "); .) Expression (. printf(", "); .) "=" Expression (. printf("\n"); .) . AsmSequence = "ASM" { AsmStatement } "END" . AsmStatement = (. char OpCode[100]; TIPES Tipe; bool Valid; char LabelField[100]; .) ( label (. LexName(LabelField, 99); puts(LabelField) .) | Identifier<OpCode> (. CheckOpCode(OpCode, Tipe, Valid); if (!Valid) SemError(101); else printf(" %s ", OpCode); .) Operand<Tipe, TRUE> ( (. if (Tipe == Branch) SemError(102); .) "," (. printf(", "); .) Operand<Tipe, FALSE> | (. if (Tipe != Branch) SemError(103); .) ) (. printf("\n"); .) SYNC ";" ) . Operand<TIPES Tipe, bool First> = (. char Name[100]; int Value, Pos; bool found; .) Identifier<Name> (. if (Tipe == Branch || ValidReg(Name)) printf("%s", Name); else { Position(Name, Pos, found); if (!found) SemError(104); else WriteOperand(Pos); } .) | Integer<Value> (. if (Tipe == Move && First) SemError(105); printf("%d", Value); .) | "[" Integer<Value> "]" (. printf("[%d]", Value); .) . Identifier <char * Id> = ident (. LexName(Id, 99); .) . Integer <int &N> = (. char S[100]; .) integer (. LexName(S, 99); N = atoi(S); .) . END Mixed. MISC.H ====== // Various common items #ifndef MISC_H #define MISC_H #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <ctype.h> #include <limits.h> #define boolean int #define bool int #define true 1 #define false 0 #define TRUE 1 #define FALSE 0 #define maxint INT_MAX #if __MSDOS__ || MSDOS || WIN32 # define pathsep '\\' #else # define pathsep '/' #endif static void appendextension (char *oldstr, char *ext, char *newstr) // Changes filename in oldstr from PRIMARY.xxx to PRIMARY.ext in newstr { int i; char old[256]; strcpy(old, oldstr); i = strlen(old); while ((i > 0) && (old[i-1] != '.') && (old[i-1] != pathsep)) i--; if ((i > 0) && (old[i-1] == '.')) old[i-1] = 0; if (ext[0] == '.') sprintf(newstr,"%s%s", old, ext); else sprintf(newstr, "%s.%s", old, ext); } const int LastValidReg = 5; const int LastValidOpcode = 5; typedef enum { Bad, Move, Branch, Compare } TIPES; static int NextLabel; /* for branch statements */ static int LastVar; /* in symbol table */ typedef struct { char Name[100]; int Address; /* allocated memory address */ } ENTRIES; typedef struct { char Name[100]; TIPES Tipe; } OPCODES; static ENTRIES Table[200]; static OPCODES OpCodes[LastValidOpcode+1]; static char ValidRegs [100] [LastValidReg+1]; static void Initialize(void) { /* Initialize symbol tables etc */ NextLabel = 0; LastVar = 0; Table[0].Address = 0; strcpy(ValidRegs[1], "R1"); strcpy(ValidRegs[2], "R2"); strcpy(ValidRegs[3], "R3"); strcpy(ValidRegs[4], "R4"); strcpy(ValidRegs[5], "R5"); strcpy(OpCodes[0].Name, "BAD"); OpCodes[0].Tipe = Bad; strcpy(OpCodes[1].Name, "MOV"); OpCodes[1].Tipe = Move; strcpy(OpCodes[2].Name, "CMP"); OpCodes[2].Tipe = Compare; strcpy(OpCodes[3].Name, "BNZ"); OpCodes[3].Tipe = Branch; strcpy(OpCodes[4].Name, "BZE"); OpCodes[4].Tipe = Branch; strcpy(OpCodes[5].Name, "BRN"); OpCodes[5].Tipe = Branch; } static void Insert (char *Name, int Address) { /* Make new entry into user defined table */ LastVar++; strcpy(Table[LastVar].Name, Name); Table[LastVar].Address = Address; } static void Position (char *ID, int &I, bool &found) { // Locate ID in user defined table; return position and whether found strcpy(Table[0].Name, ID); I = LastVar; while (strcmp(ID, Table[I].Name) != 0) I--; found = I != 0; } static void WriteOperand (int I) { printf("[%d]", Table[I].Address); } static bool ValidReg (char *R) { /* Check that R is one of the reserved m/c register names */ strcpy(ValidRegs[0], R); int I = LastValidReg; while (strcmp(R, ValidRegs[I]) != 0) I--; return I != 0; } static void CheckOpCode (char *O, TIPES &Tipe, bool &Valid) { /* Check that O is one of the reserved m/c opcode mnemonics */ strcpy(OpCodes[0].Name, O); int I = LastValidOpcode; while (strcmp(O, OpCodes[I].Name) != 0) I--; Valid = I != 0; Tipe = OpCodes[I].Tipe; } #endif /* MISC_H */ Pascal version ============== COMPILER Mixed $CN (* Pat Terry Mon 09-14-98 *) CONST LastValidReg = 5; LastValidOpCode = 5; TYPE IDNAMES = STRING[20]; TIPES = (Bad, Move, Branch, Compare); VAR NextLabel : INTEGER; (* for branch statements *) LastVar : INTEGER; (* in symbol table *) Table : ARRAY [0 .. 200] OF (* user defined symbol table *) RECORD Name : IDNAMES; Address : INTEGER; (* allocated memory address *) END; ValidRegs : ARRAY [0 .. LastValidReg] OF IDNAMES; (* m/c dependent *) OpCodes : ARRAY [0 .. LastValidOpCode] OF (* m/c dependent *) RECORD Name : IDNAMES; Tipe : TIPES END; PROCEDURE Initialize; (* Initialize symbol tables etc *) BEGIN NextLabel := 0; LastVar := 0; Table[0].Address := 0; ValidRegs[1] := 'R1'; ValidRegs[2] := 'R2'; ValidRegs[3] := 'R3'; ValidRegs[4] := 'R4'; ValidRegs[5] := 'R5'; OpCodes[0].Name := 'BAD'; OpCodes[0].Tipe := Bad; OpCodes[1].Name := 'MOV'; OpCodes[1].Tipe := Move; OpCodes[2].Name := 'CMP'; OpCodes[2].Tipe := Compare; OpCodes[3].Name := 'BNZ'; OpCodes[3].Tipe := Branch; OpCodes[4].Name := 'BZE'; OpCodes[4].Tipe := Branch; OpCodes[5].Name := 'BRN'; OpCodes[5].Tipe := Branch; END; PROCEDURE Insert (Name : IDNAMES; Address : INTEGER); (* Make new entry into user defined table *) BEGIN INC(LastVar); Table[LastVar].Name := Name; Table[LastVar].Address := Address; END; FUNCTION Position (ID : IDNAMES) : INTEGER; (* Locate ID in user defined table; complain if not there *) VAR I : INTEGER; BEGIN Table[0].Name := ID; I := LastVar; WHILE ID <> Table[I].Name DO DEC(I); IF I = 0 THEN SemError(104); Position := I END; PROCEDURE WriteOperand (I : INTEGER); BEGIN Write('[', Table[I].Address:1, ']'); END; FUNCTION GetNumber (VAR Str : STRING) : INTEGER; (* Convert latest token to integer value Int *) VAR Int, Error : INTEGER; BEGIN Int := 0; Val(Str, Int, Error); GetNumber := Int; END; FUNCTION ValidReg (R : IDNAMES) : BOOLEAN; (* Check that R is one of the reserved m/c register names *) VAR I : INTEGER; BEGIN ValidRegs[0] := R; I := LastValidReg; WHILE R <> ValidRegs[I] DO DEC(I); ValidReg := I <> 0 END; PROCEDURE CheckOpCode (O : IDNAMES; VAR Tipe : Tipes; VAR Valid : BOOLEAN); (* Check that O is one of the reserved m/c opcode mnemonics *) VAR I : INTEGER; BEGIN OpCodes[0].Name := O; I := LastValidOpCode; WHILE O <> OpCodes[I].Name DO DEC(I); Valid := I <> 0; Tipe := OpCodes[I].Tipe; END; CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" . digit = "0123456789" . IGNORE CHR(9) .. CHR(13) IGNORE CASE COMMENTS FROM "(*" TO "*)" NESTED TOKENS ident = letter { letter | digit } . integer = digit { digit } . label = letter { letter | digit } ":" . PRODUCTIONS Mixed = "PROGRAM" (. Initialize .) Declarations CompoundStatement "." . Declarations (. VAR NextAdr : INTEGER; .) = (. NextAdr := 255 .) { Type OneVar<NextAdr> { "," OneVar<NextAdr> } ";" } . Type = "INT" | "BOOL" . OneVar <VAR NextAdr : INTEGER> (. VAR Name : IDNAMES; .) = Identifier<Name> (. Insert(Name, NextAdr); DEC(NextAdr) .) . CompoundStatement = "BEGIN" Statement { ";" Statement } "END" . Statement = [ Assignment | IfStatement | AsmSequence | CompoundStatement ] . Assignment (. VAR Pos : INTEGER; .) = Variable<Pos> (. Write(' MOV '); WriteOperand(Pos); Write(', ') .) ":=" Expression (. WriteLn .) . Variable <VAR Pos : INTEGER> (. VAR Name : IDNAMES; .) = Identifier<Name> (. Pos := Position(Name) .) . Expression (. VAR Pos, Value : INTEGER; .) = Variable<Pos> (. WriteOperand(Pos) .) | Integer<Value> (. Write(Value:1) .) . IfStatement (. VAR Lab : INTEGER; .) = "IF" Condition (. Lab := NextLabel; INC(NextLabel, 2); WriteLn(' BNZ L', Lab:1); .) "THEN" Statement (. WriteLn(' BRN L', Lab+1); WriteLn('L', Lab:1, ':') .) "ELSE" Statement (. WriteLn('L', Lab+1:1, ':') .) . Condition = (. Write(' CMP ') .) Expression (. Write(', ') .) '=' Expression (. WriteLn .) . AsmSequence = "ASM" { AsmStatement } "END" . AsmStatement (. VAR OpCode : IDNAMES; Tipe : TIPES; Valid : BOOLEAN; LabelField : STRING; .) = ( label (. LexName(LabelField); WriteLn(LabelField) .) | Identifier<OpCode> (. CheckOpCode(OpCode, Tipe, Valid); IF NOT Valid THEN SemError(101) ELSE Write(' ', OpCode, ' ') .) Operand<Tipe, TRUE> ( (. IF Tipe = Branch THEN SemError(102) .) "," (. Write(', ') .) Operand<Tipe, FALSE> | (. IF Tipe <> Branch THEN SemError(103) .) ) (. WriteLn .) SYNC ";" ) . Operand<Tipe : TIPES; First : BOOLEAN> (. VAR Name : IDNAMES; Value : INTEGER; .) = Identifier<Name> (. IF (Tipe = Branch) OR ValidReg(Name) THEN Write(Name) ELSE WriteOperand(Position(Name)) .) | Integer<Value> (. IF (Tipe = Move) AND First THEN SemError(105); Write(Value:1) .) | "[" Integer<Value> "]" (. Write('[', Value:1, ']') .) . Identifier <VAR Id : IDNAMES> (. VAR S : STRING; .) = ident (. LexName(S); Id := S .) . Integer <VAR N : INTEGER> (. VAR S : STRING; .) = integer (. LexName(S); N := GetNumber(S) .) . END Mixed.