COMPILER M2c (* Modula-2 program modules without procedures, with an MC64 backend (see MGen for details). - program module only, no DEFINITION / IMPLEMENTATION split - no local modules, no EXPORT, no PRIORITY - no ProcedureDeclaration, FormalParameters, ProcedureType, ProcedureCall, ActualParameters, FORWARD, RETURN - statements: assignment, IF, CASE, WHILE, REPEAT, LOOP/EXIT, FOR, WITH - symbol table (SymTab) with static type checking: error codes 200/201/202 and 210-224, same lenient rules as the reference implementation (single pass, declare-before-use; INTEGER, CARDINAL and subranges form one integer family; no mixed INTEGER/REAL arithmetic; INTEGER assigns to REAL; 1-character literal is CHAR; InvalidType suppresses follow-on errors) - backend (MGen): emits a single-module MC64 image .MCD (current directory), runnable with mcint. Lowered: scalar globals, CONST literals (startup stores), SET OF ordinals (bit masks) with literals, IN, = and #; full scalar expressions on the stack machine; control flow via E0/E1 jumps. Everything else parses and type-checks but gets error 230 (not supported in this phase): ARRAY/RECORD/POINTER variables, string variables, WITH, non-literal CONST expressions and BY steps, EXIT outside LOOP, imported names used as values. - test convention (the language has no I/O): a global VAR ExitCode : INTEGER; is printed as decimal + CRLF through an embedded helper; without it the program just ends. - known semantic edges: INTEGER DIV/MOD truncate toward zero (not Modula-2 floor); CARDINAL values past MAXINT compare as signed; AND/OR are eager (no short-circuit); REAL widens to binary64; assignment targets cost one dead load. *) IMPORT SymTab, MGen; CHARACTERS eol = CHR(13) . letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" . digit = "0123456789" . hexDigit = digit + "ABCDEF" . noQuote1 = ANY - "'" - eol . noQuote2 = ANY - '"' - eol . IGNORE CHR(9) .. CHR(13) COMMENTS FROM "(*" TO "*)" NESTED TOKENS ident = letter { letter | digit } . integer = digit { digit } | digit { digit } CONTEXT("..") | digit { hexDigit } "H" . real = digit { digit } "." { digit } [ "E" [ "+" | "-" ] digit { digit } ] . string = "'" { noQuote1 } "'" | '"' { noQuote2 } '"' . PRODUCTIONS M2c (. VAR m1, m2: SymTab.Name; .) = "MODULE" GetIdent (. SymTab.Init; MGen.OpenModule(m1); IF ~SymTab.Enter(m1, SymTab.KindModule) THEN SemError(200) END .) ";" { Import } Block GetIdent (. IF ~SymTab.Equal(m1, m2) THEN SemError(202) END .) "." (. MGen.EndModule; SymTab.PrintTable; .) . Import (. VAR n: SymTab.Name; .) = "FROM" GetIdent (. IF ~SymTab.Enter(n, SymTab.KindImport) THEN SemError(200) END .) "IMPORT" ImportList ";" | "IMPORT" ImportList ";" . ImportList (. VAR n: SymTab.Name; .) = GetIdent (. IF ~SymTab.Enter(n, SymTab.KindImport) THEN SemError(200) END .) { "," GetIdent (. IF ~SymTab.Enter(n, SymTab.KindImport) THEN SemError(200) END .) } . Block = { Declaration } [ "BEGIN" (. MGen.BeginBody; .) StatSeq ] "END" . Declaration = "CONST" { ConstDecl ";" } | "TYPE" { TypeDecl ";" } | "VAR" { VarDecl ";" } . ConstDecl (. VAR n: SymTab.Name; t: SymTab.TypeIndex; lx: MGen.LitStr; cls: INTEGER; .) = GetIdent (. IF ~SymTab.Enter(n, SymTab.KindConst) THEN SemError(200) END .) "=" (. MGen.NoEmitEnter; .) ConstExpr (. SymTab.SetSymType(n, t); cls := SymTab.ClassOf(t); IF cls = SymTab.ClStr THEN SemError(230) ELSIF ~MGen.IsLit(lx) THEN SemError(230) END; MGen.DeclConst(n, lx, t); MGen.NoEmitExit; .) . ConstExpr = Expr . TypeDecl (. VAR n: SymTab.Name; t0, t1: SymTab.TypeIndex; .) = GetIdent (. IF ~SymTab.Enter(n, SymTab.KindType) THEN SemError(200) END; t0 := SymTab.NewAlias(); SymTab.SetSymType(n, t0); .) "=" Type (. IF t1 = t0 THEN SemError(223); SymTab.SetTarget(t0, SymTab.InvalidType) ELSE SymTab.SetTarget(t0, t1) END; .) . VarDecl (. VAR t: SymTab.TypeIndex; i: CARDINAL; nm: SymTab.Name; cls: INTEGER; .) = VarIdents ":" Type (. cls := SymTab.ClassOf(t); IF (cls # SymTab.ClInt) & (cls # SymTab.ClReal) & (cls # SymTab.ClBool) & (cls # SymTab.ClChar) & (cls # SymTab.ClEnum) & (cls # SymTab.ClSet) THEN SemError(230) END; i := 0; WHILE i < SymTab.PendCount() DO SymTab.PendName(i, nm); MGen.DeclVar(nm); INC(i) END; SymTab.FixPending(t); .) . VarIdents (. VAR n: SymTab.Name; .) = GetIdent (. IF ~SymTab.EnterPending(n, SymTab.KindVar) THEN SemError(200) END .) { "," GetIdent (. IF ~SymTab.EnterPending(n, SymTab.KindVar) THEN SemError(200) END .) } . QualIdent (. VAR n, m: SymTab.Name; .) = GetIdent (. IF ~SymTab.Lookup(n) THEN SemError(201); t := SymTab.InvalidType ELSIF (SymTab.SymKind(n) # SymTab.KindType) & (SymTab.SymKind(n) # SymTab.KindPredef) & (SymTab.SymKind(n) # SymTab.KindImport) THEN SemError(221); t := SymTab.InvalidType ELSE t := SymTab.SymType(n) END; .) { "." GetIdent (. t := SymTab.InvalidType; .) } . (* Types: ProcedureType removed; subrange factored for LL(1) *) Type = SimpleType | ArrayType | RecordType | SetType | PointerType . SimpleType (. VAR t1, t2: SymTab.TypeIndex; lx1, lx2: MGen.LitStr; .) = QualIdent [ "[" (. MGen.NoEmitEnter; .) ConstExpr (. IF (t1 # SymTab.InvalidType) & (SymTab.ClassOf(t1) # SymTab.ClInt) & (SymTab.ClassOf(t1) # SymTab.ClChar) & (SymTab.ClassOf(t1) # SymTab.ClEnum) THEN SemError(224) END; .) ".." ConstExpr (. IF (t2 # SymTab.InvalidType) & (SymTab.ClassOf(t2) # SymTab.ClInt) & (SymTab.ClassOf(t2) # SymTab.ClChar) & (SymTab.ClassOf(t2) # SymTab.ClEnum) THEN SemError(224) END; .) "]" (. t := SymTab.NewSub(t1); MGen.NoEmitExit; .) ] | "[" (. MGen.NoEmitEnter; .) ConstExpr (. IF (t1 # SymTab.InvalidType) & (SymTab.ClassOf(t1) # SymTab.ClInt) & (SymTab.ClassOf(t1) # SymTab.ClChar) & (SymTab.ClassOf(t1) # SymTab.ClEnum) THEN SemError(224) END; .) ".." ConstExpr (. IF (t2 # SymTab.InvalidType) & (SymTab.ClassOf(t2) # SymTab.ClInt) & (SymTab.ClassOf(t2) # SymTab.ClChar) & (SymTab.ClassOf(t2) # SymTab.ClEnum) THEN SemError(224) END; .) "]" (. t := SymTab.NewSub(t1); MGen.NoEmitExit; .) | Enum . Enum (. VAR n: SymTab.Name; ord: INTEGER; .) = "(" (. t := SymTab.NewEnum(); ord := 0; .) GetIdent (. IF ~SymTab.Enter(n, SymTab.KindConst) THEN SemError(200) END; SymTab.SetSymType(n, t); MGen.DeclConstInt(n, ord); INC(ord); .) { "," GetIdent (. IF ~SymTab.Enter(n, SymTab.KindConst) THEN SemError(200) END; SymTab.SetSymType(n, t); MGen.DeclConstInt(n, ord); INC(ord); .) } ")" . ArrayType (. VAR s, s2, e: SymTab.TypeIndex; .) = "ARRAY" SimpleType (. IF (s # SymTab.InvalidType) & (SymTab.ClassOf(s) # SymTab.ClInt) & (SymTab.ClassOf(s) # SymTab.ClChar) & (SymTab.ClassOf(s) # SymTab.ClEnum) THEN SemError(224) END; .) { "," SimpleType (. IF (s2 # SymTab.InvalidType) & (SymTab.ClassOf(s2) # SymTab.ClInt) & (SymTab.ClassOf(s2) # SymTab.ClChar) & (SymTab.ClassOf(s2) # SymTab.ClEnum) THEN SemError(224) END; .) } "OF" Type (. t := SymTab.NewArray(e); .) . RecordType = "RECORD" (. t := SymTab.NewRecord(); .) FieldSeq "END" . FieldSeq = Field { ";" Field } . Field (. VAR et: SymTab.TypeIndex; .) = [ FieldIdents ":" Type (. SymTab.FixPendingF(rt, et); .) ] . FieldIdents (. VAR n: SymTab.Name; .) = GetIdent (. IF ~SymTab.FieldPending(rt, n) THEN SemError(200) END .) { "," GetIdent (. IF ~SymTab.FieldPending(rt, n) THEN SemError(200) END .) } . SetType (. VAR s: SymTab.TypeIndex; .) = "SET" "OF" SimpleType (. IF (s # SymTab.InvalidType) & (SymTab.ClassOf(s) # SymTab.ClInt) & (SymTab.ClassOf(s) # SymTab.ClChar) & (SymTab.ClassOf(s) # SymTab.ClEnum) THEN SemError(224) END; t := SymTab.NewSet(s); .) . PointerType (. VAR b: SymTab.TypeIndex; .) = "POINTER" "TO" Type (. t := SymTab.NewPtr(b); .) . (* Statements: ProcedureCall and RETURN removed *) StatSeq = Stat { ";" Stat } . Stat (. VAR lx: INTEGER; .) = [ Assign | IfStat | CaseStat | WhileStat | RepeatStat | LoopStat | ForStat | WithStat | "EXIT" (. IF MGen.TopLoop(lx) THEN MGen.Jmp(lx) ELSE SemError(230) END; .) ] . Assign (. VAR dt, et: SymTab.TypeIndex; dk: INTEGER; bn: SymTab.Name; lxe, lxD: MGen.LitStr; isR, conv: BOOLEAN; .) = Design ":=" Expr (. IF (dt # SymTab.InvalidType) & (dk # SymTab.KindVar) & (dk # SymTab.KindField) & (dk # SymTab.KindImport) THEN SemError(210) ELSIF ~SymTab.Assignable(et, dt) THEN SemError(210) END; IF dk = SymTab.KindImport THEN SemError(230) END; isR := (dt # SymTab.InvalidType) & (SymTab.ClassOf(dt) = SymTab.ClReal); conv := isR & SymTab.IsIntFamily(et); IF dk = SymTab.KindVar THEN IF conv THEN MGen.IntToReal; END; MGen.StoreVar(bn) ELSE MGen.Drop END; .) . IfStat (. VAR t: SymTab.TypeIndex; lxC: MGen.LitStr; elseL, endL: INTEGER; hasElse: BOOLEAN; .) = "IF" Expr (. IF ~SymTab.BoolCheck(t) THEN SemError(214) END; elseL := MGen.NewLabel(); endL := MGen.NewLabel(); MGen.Jz(elseL); hasElse := FALSE; .) "THEN" StatSeq { "ELSIF" (. MGen.Jmp(endL); MGen.DefLabel(elseL); .) Expr (. IF ~SymTab.BoolCheck(t) THEN SemError(214) END; elseL := MGen.NewLabel(); MGen.Jz(elseL); .) "THEN" StatSeq } [ "ELSE" (. MGen.Jmp(endL); MGen.DefLabel(elseL); hasElse := TRUE; .) StatSeq ] "END" (. IF ~hasElse THEN MGen.DefLabel(elseL) END; MGen.DefLabel(endL); .) . CaseStat (. VAR st: SymTab.TypeIndex; lxS: MGen.LitStr; tmp, endL: INTEGER; .) = "CASE" Expr (. tmp := MGen.TempGlobal(); MGen.StoreTemp(tmp); endL := MGen.NewLabel(); .) "OF" Case { "|" Case } [ "ELSE" StatSeq ] "END" (. MGen.DefLabel(endL); .) . Case (. VAR lB, lN: INTEGER; .) = [ LabelList ":" (. MGen.DefLabel(lB); .) StatSeq (. MGen.Jmp(endL); MGen.DefLabel(lN); .) ] . LabelList = (. lB := MGen.NewLabel(); lN := MGen.NewLabel(); .) Labels { "," Labels } (. MGen.Jmp(lN); .) . Labels (. VAR t, t2: SymTab.TypeIndex; lx1, lx2: MGen.LitStr; ta, tb, chunk: INTEGER; r, hasRange: BOOLEAN; .) = ConstExpr (. IF ~SymTab.EqCheck(t, sel) THEN SemError(213) END; r := (SymTab.ClassOf(sel) = SymTab.ClReal) & (SymTab.ClassOf(t) = SymTab.ClReal); ta := MGen.TempGlobal(); MGen.StoreTemp(ta); hasRange := FALSE; .) [ ".." ConstExpr (. IF ~SymTab.EqCheck(t2, sel) THEN SemError(213) END; tb := MGen.TempGlobal(); MGen.StoreTemp(tb); hasRange := TRUE; .) ] (. IF hasRange THEN MGen.LoadTemp(tmp); MGen.LoadTemp(ta); IF r THEN MGen.RealGe ELSE MGen.IGe END; MGen.LoadTemp(tmp); MGen.LoadTemp(tb); IF r THEN MGen.RealLe ELSE MGen.ILe END; MGen.And ELSE MGen.LoadTemp(tmp); MGen.LoadTemp(ta); IF r THEN MGen.RealEq ELSE MGen.Eq END END; chunk := MGen.NewLabel(); MGen.Jz(chunk); MGen.Jmp(bodyL); MGen.DefLabel(chunk); .) . WhileStat (. VAR t: SymTab.TypeIndex; lxC: MGen.LitStr; topL, endL: INTEGER; .) = "WHILE" (. topL := MGen.NewLabel(); endL := MGen.NewLabel(); MGen.DefLabel(topL); .) Expr (. IF ~SymTab.BoolCheck(t) THEN SemError(214) END; MGen.Jz(endL); .) "DO" StatSeq "END" (. MGen.Jmp(topL); MGen.DefLabel(endL); .) . RepeatStat (. VAR t: SymTab.TypeIndex; lxC: MGen.LitStr; topL: INTEGER; .) = "REPEAT" (. topL := MGen.NewLabel(); MGen.DefLabel(topL); .) StatSeq "UNTIL" Expr (. IF ~SymTab.BoolCheck(t) THEN SemError(214) END; MGen.Jz(topL); .) . LoopStat (. VAR topL, exitL: INTEGER; .) = "LOOP" (. topL := MGen.NewLabel(); exitL := MGen.NewLabel(); MGen.DefLabel(topL); MGen.PushLoop(exitL); .) StatSeq "END" (. MGen.Jmp(topL); MGen.DefLabel(exitL); MGen.PopLoop; .) . ForStat (. VAR n, lv: SymTab.Name; lo, hi: SymTab.TypeIndex; lxLo, lxHi: MGen.LitStr; byV, ht: INTEGER; lTop, lChk, lEnd: INTEGER; neg: BOOLEAN; .) = "FOR" GetIdent (. IF ~SymTab.Lookup(n) THEN SemError(201) ELSIF (SymTab.SymKind(n) # SymTab.KindVar) & (SymTab.SymKind(n) # SymTab.KindField) THEN SemError(220) ELSIF (SymTab.SymType(n) # SymTab.InvalidType) & ~SymTab.IsIntFamily( SymTab.SymType(n)) THEN SemError(220) END; MGen.CopyName(n, lv); .) ":=" Expr (. IF (lo # SymTab.InvalidType) & ~SymTab.IsIntFamily(lo) THEN SemError(220) END; MGen.StoreVar(lv); .) "TO" Expr (. IF (hi # SymTab.InvalidType) & ~SymTab.IsIntFamily(hi) THEN SemError(220) END; ht := MGen.TempGlobal(); MGen.StoreTemp(ht); byV := 1; neg := FALSE; .) [ "BY" ByLit (. neg := byV < 0; .) ] "DO" (. lTop := MGen.NewLabel(); lChk := MGen.NewLabel(); lEnd := MGen.NewLabel(); MGen.Jmp(lChk); MGen.DefLabel(lTop); .) StatSeq "END" (. MGen.LoadVar(lv); MGen.PushInt(byV); MGen.Add; MGen.StoreVar(lv); MGen.DefLabel(lChk); MGen.LoadVar(lv); MGen.LoadTemp(ht); IF neg THEN MGen.IGe ELSE MGen.ILe END; MGen.Jz(lEnd); MGen.Jmp(lTop); MGen.DefLabel(lEnd); .) . ByLit (. VAR s: ARRAY [0 .. 255] OF CHAR; .) = integer (. LexString(s); IF ~MGen.ParseInt(s, v) THEN v := 1 END; .) | "-" integer (. LexString(s); IF MGen.ParseInt(s, v) THEN v := -v ELSE v := -1 END; .) . WithStat (. VAR dt: SymTab.TypeIndex; dk: INTEGER; bnW: SymTab.Name; lxW: MGen.LitStr; pushed: BOOLEAN; .) = "WITH" Design (. pushed := FALSE; IF dt # SymTab.InvalidType THEN pushed := SymTab.PushRecord(dt); IF ~pushed THEN SemError(215) END END; IF pushed THEN MGen.NoSupEnter; SemError(230) END; .) "DO" StatSeq "END" (. IF pushed THEN SymTab.PopScope; MGen.NoSupExit END; .) . (* Expressions: Designator without ActualParameters. Only record fields resolve qualified access; WITH pushes an inner scope so field names also work unqualified in its body. Each expression synthesizes its SymTab type in t and, for single literals, the source text in lx ("" otherwise, used for CONST validation). Values travel on the MC64 stack. *) Design (. VAR n, m: SymTab.Name; it: SymTab.TypeIndex; lxI: MGen.LitStr; cls: INTEGER; .) = GetIdent (. MGen.CopyName(n, bn); lx[0] := 0C; IF ~SymTab.Lookup(n) THEN SemError(201); t := SymTab.InvalidType; k := -1; IF doLoad THEN MGen.PushInt(0) END ELSE t := SymTab.SymType(n); k := SymTab.SymKind(n); IF k = SymTab.KindConst THEN IF SymTab.Equal(n, "TRUE") THEN t := SymTab.BoolType(); MGen.CopyName("TRUE", lx); IF doLoad THEN MGen.PushInt(1) END ELSIF SymTab.Equal(n, "FALSE") THEN t := SymTab.BoolType(); MGen.CopyName("FALSE", lx); IF doLoad THEN MGen.PushInt(0) END ELSE cls := SymTab.ClassOf(t); IF (t # SymTab.InvalidType) & (cls # SymTab.ClStr) & ((cls = SymTab.ClInt) OR (cls = SymTab.ClReal) OR (cls = SymTab.ClBool) OR (cls = SymTab.ClChar) OR (cls = SymTab.ClEnum)) THEN IF doLoad THEN MGen.LoadVar(n) END ELSIF doLoad THEN MGen.PushInt(0) END END ELSIF k = SymTab.KindVar THEN cls := SymTab.ClassOf(t); IF (cls = SymTab.ClInt) OR (cls = SymTab.ClReal) OR (cls = SymTab.ClBool) OR (cls = SymTab.ClChar) OR (cls = SymTab.ClEnum) OR (cls = SymTab.ClSet) THEN IF doLoad THEN MGen.LoadVar(n) END ELSE SemError(230); IF doLoad THEN MGen.PushInt(0) END END ELSE IF doLoad THEN MGen.PushInt(0) END; IF k = SymTab.KindField THEN IF ~MGen.NoSup() THEN SemError(230) END ELSIF k = SymTab.KindImport THEN SemError(230) END END END; .) { "." (. lx[0] := 0C; .) GetIdent (. IF t = SymTab.InvalidType THEN ELSIF SymTab.ClassOf(t) # SymTab.ClRecord THEN SemError(215); t := SymTab.InvalidType ELSIF ~SymTab.FieldExists(t, m) THEN SemError(216); t := SymTab.InvalidType ELSE t := SymTab.FieldType(t, m); SemError(230) END; IF doLoad THEN MGen.Drop; MGen.PushInt(0) END; .) | "[" Expr (. MGen.Drop; IF t = SymTab.InvalidType THEN ELSIF SymTab.ClassOf(t) # SymTab.ClArray THEN SemError(217); t := SymTab.InvalidType ELSIF (it # SymTab.InvalidType) & ~SymTab.IsIntFamily(it) THEN SemError(218); t := SymTab.InvalidType ELSE t := SymTab.ArrayElem(t); SemError(230) END; IF doLoad THEN MGen.Drop; MGen.PushInt(0) END; .) { "," Expr (. MGen.Drop; IF (it # SymTab.InvalidType) & ~SymTab.IsIntFamily(it) THEN SemError(218) END; .) } "]" | "^" (. lx[0] := 0C; IF t = SymTab.InvalidType THEN ELSIF SymTab.ClassOf(t) # SymTab.ClPtr THEN SemError(219); t := SymTab.InvalidType ELSE t := SymTab.PtrBase(t); SemError(230) END; IF doLoad THEN MGen.Drop; MGen.PushInt(0) END; .) } . Expr (. VAR t2: SymTab.TypeIndex; tc, op: INTEGER; lx2: MGen.LitStr; r: BOOLEAN; .) = SimExpr [ Rel SimExpr (. lx[0] := 0C; IF op = SymTab.OpIn THEN IF SymTab.InCheck(t, t2) THEN t := SymTab.BoolType(); MGen.BitIn ELSE SemError(222); t := SymTab.InvalidType; MGen.Drop; MGen.Drop; MGen.PushInt(0) END ELSE tc := SymTab.ClassOf(t); IF SymTab.RelCheck(t, t2, op) THEN t := SymTab.BoolType() ELSE SemError(213); t := SymTab.InvalidType END; IF t # SymTab.InvalidType THEN r := tc = SymTab.ClReal; IF r THEN IF op = SymTab.OpEq THEN MGen.RealEq ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN MGen.RealNe ELSIF op = SymTab.OpLt THEN MGen.RealLt ELSIF op = SymTab.OpLe THEN MGen.RealLe ELSIF op = SymTab.OpGt THEN MGen.RealGt ELSE MGen.RealGe END ELSE IF op = SymTab.OpEq THEN MGen.Eq ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN MGen.Neq ELSIF op = SymTab.OpLt THEN MGen.ILt ELSIF op = SymTab.OpLe THEN MGen.ILe ELSIF op = SymTab.OpGt THEN MGen.IGt ELSE MGen.IGe END END ELSE MGen.Drop; MGen.Drop; MGen.PushInt(0) END END; .) ] . Rel = "=" (. op := SymTab.OpEq; .) | "#" (. op := SymTab.OpNeq1; .) | "<>" (. op := SymTab.OpNeq2; .) | "<" (. op := SymTab.OpLt; .) | "<=" (. op := SymTab.OpLe; .) | ">" (. op := SymTab.OpGt; .) | ">=" (. op := SymTab.OpGe; .) | "IN" (. op := SymTab.OpIn; .) . SimExpr (. VAR t2, res2: SymTab.TypeIndex; op: INTEGER; lx2: MGen.LitStr; neg, isR: BOOLEAN; .) = (. neg := FALSE; .) [ "+" | "-" (. neg := TRUE; .) ] Term (. IF neg THEN IF MGen.IsLit(lx) THEN MGen.NegFold(lx, lx) ELSE lx[0] := 0C END; IF SymTab.ClassOf(t) = SymTab.ClReal THEN MGen.NegReal ELSE MGen.NegInt END END; .) { AddOp Term (. lx[0] := 0C; IF op = SymTab.OpOr THEN IF SymTab.BoolCheck(t) & SymTab.BoolCheck(t2) THEN t := SymTab.BoolType() ELSE SemError(212); t := SymTab.InvalidType END; MGen.Or ELSE IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN t := res2 ELSE SemError(211); t := SymTab.InvalidType END; isR := (t # SymTab.InvalidType) & (SymTab.ClassOf(t) = SymTab.ClReal); IF op = SymTab.OpAdd THEN IF isR THEN MGen.RealAdd ELSE MGen.Add END ELSE IF isR THEN MGen.RealSub ELSE MGen.Sub END END END; .) } . AddOp = "+" (. op := SymTab.OpAdd; .) | "-" (. op := SymTab.OpSub; .) | "OR" (. op := SymTab.OpOr; .) . Term (. VAR t2, res2: SymTab.TypeIndex; op: INTEGER; lx2: MGen.LitStr; isR: BOOLEAN; mt: INTEGER; .) = Fact { MulOp Fact (. lx[0] := 0C; IF op = SymTab.OpAnd THEN IF SymTab.BoolCheck(t) & SymTab.BoolCheck(t2) THEN t := SymTab.BoolType() ELSE SemError(212); t := SymTab.InvalidType END; MGen.And ELSE IF SymTab.ArithCheck(t, t2, (op = SymTab.OpDiv) OR (op = SymTab.OpMod), res2) THEN t := res2 ELSE SemError(211); t := SymTab.InvalidType END; isR := (t # SymTab.InvalidType) & (SymTab.ClassOf(t) = SymTab.ClReal); IF op = SymTab.OpTimes THEN IF isR THEN MGen.RealMul ELSE MGen.MulU END ELSIF op = SymTab.OpSlash THEN IF isR THEN MGen.RealDiv ELSE MGen.DivI END ELSIF op = SymTab.OpDiv THEN MGen.DivI ELSE mt := MGen.TempGlobal(); MGen.ModI(mt) END END; .) } . MulOp = "*" (. op := SymTab.OpTimes; .) | "/" (. op := SymTab.OpSlash; .) | "DIV" (. op := SymTab.OpDiv; .) | "MOD" (. op := SymTab.OpMod; .) | "AND" (. op := SymTab.OpAnd; .) | "&" (. op := SymTab.OpAnd; .) . Fact (. VAR s: ARRAY [0 .. 255] OF CHAR; t2, et, dt, st: SymTab.TypeIndex; dk: INTEGER; bnF: SymTab.Name; lxD, lx2: MGen.LitStr; v: INTEGER; c: CARDINAL; b: LONGCARD; .) = integer (. LexString(s); MGen.CopyName(s, lx); IF MGen.ParseInt(s, v) THEN MGen.PushInt(v) ELSIF MGen.ParseCard(s, c) THEN MGen.PushBits( VAL(LONGCARD, c)) ELSE MGen.PushInt(0) END; t := SymTab.IntType(); .) | real (. LexString(s); MGen.CopyName(s, lx); IF MGen.ParseReal(s, b) THEN MGen.PushBits(b) ELSE MGen.PushBits(0H) END; t := SymTab.RealType(); .) | string (. LexString(s); IF SymTab.StrLen(s) <= 3 THEN t := SymTab.CharType(); MGen.CopyName(s, lx); MGen.PushInt( MGen.CharOrd(s)) ELSE t := SymTab.NewStr(); SemError(230); lx[0] := 0C; MGen.PushInt(0) END; .) | Design (. t := dt; MGen.CopyName(lxD, lx); .) | "(" Expr ")" (. t := et; .) | ( "NOT" | "~" ) Fact (. lx[0] := 0C; IF SymTab.BoolCheck(t2) THEN t := SymTab.BoolType() ELSE SemError(212); t := SymTab.InvalidType END; MGen.Not; .) | SetLit (. lx[0] := 0C; t := st; .) . SetLit (. VAR first, et: SymTab.TypeIndex; lxE, lxE2: MGen.LitStr; hasR: BOOLEAN; .) = "{" (. MGen.PushInt(0); t := SymTab.SetFor(SymTab.IntType()); .) [ Elem (. first := et; t := SymTab.SetFor(et); IF hasR THEN MGen.FieldMask ELSE MGen.Power2 END; MGen.Or; .) { "," Elem (. IF ~SymTab.SetElemCheck(first, et) THEN SemError(222) END; IF hasR THEN MGen.FieldMask ELSE MGen.Power2 END; MGen.Or; .) } ] "}" . Elem (. VAR t2: SymTab.TypeIndex; .) = Expr (. hasR := FALSE; lx2[0] := 0C; .) [ ".." Expr (. IF ~SymTab.SetElemCheck(t, t2) THEN SemError(222) END; hasR := TRUE; .) ] . GetIdent = ident (. LexName(n); .) . END M2c.