def expression(): """ Parses expression = simpleExpression {("=" | "<>" | "<" | "<=" | ">" | ">=") simpleExpression}. Generates code for the expression if no error is reported """ x = simpleExpression() while SC.sym in {EQ, NE, LT, LE, GT, GE}: op = SC.sym; getSym(); y = simpleExpression() # x op y if x.tp == Int == y.tp: #============== ADDED CONSTANT FOLDING ============= if type(x) == Const == type(y): # if op == EQ and x.val != y.val: # x = genSkip() # elif op == NE and x.val == y.val: # x = genSkip() # elif op == LT and x.val >= y.val: # x = genSkip() # elif op == LE and x.val > y.val: # x = genSkip() # elif op == GT and x.val <= y.val: # x = genSkip() # elif op == GE and x.val < y.val: # x = genSkip() # else: x = genRelation(op, x, y) else: mark('bad type')
def find(name): for l in symTab: for e in l: if name == e.name: return e mark('undefined identifier ' + name) undef = Var(Int); undef.lev, undef.adr = 0, 0 return undef
def genVar(x): # assuming x is ST.Var, ST.Ref, ST.Const # for ST.Const: no code, x.val is constant # for ST.Var: x.reg is FP for local, 0 for global vars, # x.adr is relative or absolute address # for ST.Ref: address is loaded into register # returns ST.Var, ST.Const if type(x) == Const: y = x else: if x.lev == 0: s = R0 elif x.lev == curlev: s = FP else: mark("level!") s = R0 y = Var(x.tp) y.lev = x.lev if type(x) == Ref: # reference is loaded into register r = obtainReg() putM("lw", r, s, x.adr) y.reg, y.adr = r, 0 elif type(x) == Var: y.reg, y.adr = s, x.adr else: y = x # error, pass dummy item return y
def factor(): """ Parses factor = ident selector | integer | "(" expression ")" | "not" factor. Generates code for the factor if no error is reported """ if SC.sym not in FIRSTFACTOR: mark("factor expected"); getSym() while SC.sym not in FIRSTFACTOR | STRONGSYMS | FOLLOWFACTOR: getSym() if SC.sym == IDENT: x = find(SC.val) if type(x) in {Var, Ref}: x = genVar(x) elif type(x) == Const: x = Const(x.tp, x.val); x = genConst(x) else: mark('variable or constant expected') getSym(); x = selector(x) elif SC.sym == NUMBER: x = Const(Int, SC.val); x = genConst(x); getSym() elif SC.sym == LPAREN: getSym(); x = expression() if SC.sym == RPAREN: getSym() else: mark(") expected") elif SC.sym == NOT: getSym(); x = factor() if x.tp != Bool: mark('not boolean') elif type(x) == Const: x.val = 1 - x.val # constant folding else: x = genUnaryOp(NOT, x) else: mark("factor expected"); x = None return x
def simpleExpression(): """ Parses simpleExpression = ["+" | "-"] term {("+" | "-" | "or") term}. Generates code for the simpleExpression if no error is reported """ if SC.sym == PLUS: getSym(); x = term() elif SC.sym == MINUS: getSym(); x = term() if x.tp != Int: mark('bad type') elif type(x) == Const: x.val = - x.val # constant folding else: x = genUnaryOp(MINUS, x) else: x = term() while SC.sym in {PLUS, MINUS, OR}: op = SC.sym; getSym() if op == OR and type(x) != Const: x = genUnaryOp(OR, x) y = term() # x op y if x.tp == Int == y.tp and op in {PLUS, MINUS}: if type(x) == Const == type(y): # constant folding if op == PLUS: x.val = x.val + y.val elif op == MINUS: x.val = x.val - y.val else: x = genBinaryOp(op, x, y) elif x.tp == Bool == y.tp and op == OR: if type(x) == Const: # constant folding if not x.val: x = y # if x is false, take y, else x else: x = genBinaryOp(OR, x, y) else: mark('bad type') return x
def compileFile(srcfn): if srcfn.endswith(".p"): with open(srcfn, "r") as f: src = f.read() dstfn = srcfn[:-2] + ".s" compileString(src, dstfn) else: mark("'.p' file extension expected")
def simpleExpression(): """ Parses simpleExpression = ["+" | "-"] term {("+" | "-" | "or") term}. Generates code for the simpleExpression if no error is reported """ if SC.sym == PLUS: getSym() x = term() elif SC.sym == MINUS: getSym() x = term() if x.tp != Int: mark("bad type") elif type(x) == Const: x.val = -x.val # constant folding else: x = genUnaryOp(MINUS, x) else: x = term() while SC.sym in {PLUS, MINUS, OR}: op = SC.sym getSym() if op == OR and type(x) != Const: x = genUnaryOp(OR, x) # ----- y = term() # x op y if x.tp == Int == y.tp and op in {PLUS, MINUS}: # if (type(x)=int and type(y)=int) and (operator is + or -) if type(x) == Const == type(y): # constant folding ## does x + y if they are not zero if op == PLUS: x.val = x.val + y.val elif op == MINUS: x.val = x.val - y.val else: print("op", op) print("1. simpleExpression") if type(x).__name__ == "Const" and x.val == 0: x = y print("x = y") continue elif type(y).__name__ == "Const" and y.val == 0: print("x = x") x = x continue x = genBinaryOp(op, x, y) # does the arithmetic + and minus elif x.tp == Bool == y.tp and op == OR: # no changes past here if type(x) == Const: # constant folding if not x.val: x = y # if x is false, take y, else x else: x = genBinaryOp(OR, x, y) else: mark("bad type") writeln("TEST: ", "SimpleExpression: ", "5. ", "ended") # print("--- x: ", dir(x)); print("function ending x: ", vars(x)) return x
def genFormalParams(sc): """For list sc with formal procedure parameters, determine the $fp-relative address of each parameters; each parameter must be type integer, boolean or must be a reference parameter""" s = 0 # parameter block size for p in reversed(sc): if p.tp == Int or p.tp == Bool or type(p) == Ref: p.adr, s = s, s + 4 else: mark('no structured value parameters') return s
def genActualPara(ap, fp, n): """Pass parameter, ap is actual parameter, fp is the formal parameter, either Ref or Var, n is the parameter number""" if type(fp) == Ref: # reference parameter, assume p is Var if ap.adr != 0: # load address in register r = obtainReg(); putM('la', r, ap.reg, ap.adr) else: r = ap.reg # address already in register putM('sw', r, SP, - 4 * (n + 1)); releaseReg(r) else: # value parameter if type(ap) != Cond: if type(ap) != Reg: ap = loadItem(ap) putM('sw', ap.reg, SP, - 4 * (n + 1)); releaseReg(ap.reg) else: mark('unsupported parameter type')
def expression(): """ Parses expression = simpleExpression {("=" | "<>" | "<" | "<=" | ">" | ">=") simpleExpression}. Generates code for the expression if no error is reported """ x = simpleExpression() while SC.sym in {EQ, NE, LT, LE, GT, GE}: op = SC.sym getSym() y = simpleExpression() # x op y if x.tp == Int == y.tp: x = genRelation(op, x, y) else: mark("bad type") return x
def typedIds(kind): """ Parses typedIds = ident {"," ident} ":" type. Updates current scope of symbol table Assumes kind is Var or Ref and applies it to all identifiers Reports an error if an identifier is already defined in the current scope """ tid = [SC.val]; getSym() while SC.sym == COMMA: getSym() if SC.sym == IDENT: tid.append(SC.val); getSym() else: mark('identifier expected') if SC.sym == COLON: getSym(); tp = typ().tp for i in tid: newObj(i, kind(tp)) else: mark("':' expected")
def program(): """ Parses program = "program" ident ";" declarations compoundStatement. Generates code if no error is reported """ newObj("boolean", Type(Bool)) Bool.size = 4 newObj("integer", Type(Int)) Int.size = 4 newObj("true", Const(Bool, 1)) newObj("false", Const(Bool, 0)) newObj("read", StdProc([Ref(Int)])) newObj("write", StdProc([Var(Int)])) newObj("writeln", StdProc([])) progStart() if SC.sym == PROGRAM: getSym() else: mark("'program' expected") ident = SC.val if SC.sym == IDENT: getSym() else: mark("program name expected") if SC.sym == SEMICOLON: getSym() else: mark("; expected") declarations(genGlobalVars) progEntry(ident) x = compoundStatement() return progExit(x)
def term(): """ Parses term = factor {("*" | "div" | "mod" | "and") factor}. Generates code for the term if no error is reported """ x = factor() while SC.sym in {TIMES, DIV, MOD, AND}: op = SC.sym getSym() if op == AND and type(x) != Const: x = genUnaryOp(AND, x) y = factor() # x op y if x.tp == Int == y.tp and op in {TIMES, DIV, MOD}: if type(x) == Const == type(y): # constant folding if op == TIMES: x.val = x.val * y.val elif op == DIV: x.val = x.val // y.val elif op == MOD: x.val = x.val % y.val else: print("term 2: start optimization op", op) if type(x).__name__ == "Const" and x.val == 1: # check if x=1 for multiplications print("x == 1, do not multiply by 1") x = y elif type(y).__name__ == "Const" and y.val == 1: # check for imediate for multiplications print("y == 1, do not multiply by 1") x = x else: x = genBinaryOp(op, x, y) elif x.tp == Bool == y.tp and op == AND: if type(x) == Const: # constant folding if x.val: x = y # if x is true, take y, else x else: x = genBinaryOp(AND, x, y) else: mark("bad type") return x
def factor(): """ Parses factor = ident «write(ident)» selector | integer «write(integer)» | "(" «write('(')» expression ")" «write(')')» | "not" «write('not ') factor. Generates code for the factor if no error is reported """ if SC.sym not in FIRSTFACTOR: mark("expression expected") getSym() while SC.sym not in FIRSTFACTOR | STRONGSYMS | FOLLOWFACTOR: getSym() if SC.sym == IDENT: x = find(SC.val) if type(x) in {Var, Ref}: x = CG.genVar(x) elif type(x) == Const: x = Const(x.tp, x.val) x = CG.genConst(x) else: mark('expression expected') write(SC.val) getSym() x = selector(x) elif SC.sym == NUMBER: x = Const(Int, SC.val) x = CG.genConst(x) write(str(SC.val)) getSym() elif SC.sym == LPAREN: write('(') getSym() x = expression() if SC.sym == RPAREN: write(')') getSym() else: mark(") expected") elif SC.sym == NOT: write('not ') getSym() x = factor() if x.tp != Bool: mark('not boolean') elif type(x) == Const: x.val = 1 - x.val # constant folding else: x = CG.genUnaryOp(NOT, x) else: x = Const(None, 0) return x
def simpleExpression(): """ Parses simpleExpression = ["+" «write(' + ')» | "-" «write(' - ')»] term {("+" «write(' + ')» | "-" «write(' - ')» | "or" «write(' or ')») term}. Generates code for the simpleExpression if no error is reported """ if SC.sym == PLUS: write(' + ') getSym() x = term() elif SC.sym == MINUS: write(' - ') getSym() x = term() if x.tp != Int: mark('bad type') elif type(x) == Const: x.val = -x.val # constant folding else: x = CG.genUnaryOp(MINUS, x) else: x = term() while SC.sym in {PLUS, MINUS, OR}: op = SC.sym getSym() if op == OR and type(x) != Const: write(' or ') x = CG.genUnaryOp(OR, x) if op == PLUS: write(' + ') if op == MINUS: write(' - ') y = term() # x op y if x.tp == Int == y.tp and op in {PLUS, MINUS}: if type(x) == Const == type(y): # constant folding if op == PLUS: x.val = x.val + y.val elif op == MINUS: x.val = x.val - y.val else: x = CG.genBinaryOp(op, x, y) elif x.tp == Bool == y.tp and op == OR: if type(x) == Const: # constant folding if not x.val: x = y # if x is false, take y, else x else: x = CG.genBinaryOp(OR, x, y) else: mark('bad type') return x
def expression(): """ Parses expression = simpleExpression {("=" «write(' = ')» | "<>" «write(' <> ')» | "<" «write(' < ')» | "<=" «write(' <= ')» | ">" «write(' > ')» | ">=" «write(' >= ')») simpleExpression}. Generates code for the expression if no error is reported """ x = simpleExpression() while SC.sym in {EQ, NE, LT, LE, GT, GE}: op = SC.sym if op == EQ: write(' = ') elif op == NE: write(' <> ') elif op == LT: write(' < ') elif op == LE: write(' <= ') elif op == GT: write(' > ') elif op == GE: write(' >= ') getSym() y = simpleExpression() # x op y if x.tp == Int == y.tp: x = CG.genRelation(op, x, y) else: mark('bad type') return x
def body(ident, para): if SC.sym == INDENT: getSym() else: mark('indent expected') start = len(topScope()) local = declarations(CG.genLocalVars) CG.genProcEntry(ident, para, local) if SC.sym in FIRSTSTATEMENT: x = statementBlock() elif SC.sym == INDENT: getSym(); x = statementBlock() if SC.sym == DEDENT: getSym() else: mark('dedent or new line expected') else: mark('statement expected') CG.genProcExit(x, para, local) if SC.sym == DEDENT: getSym() else: mark('dedent or new line expected') return x
def term(): """ Parses term = factor {("*" | "div" | "mod" | "and") factor}. Generates code for the term if no error is reported """ x = factor() while SC.sym in {TIMES, DIV, MOD, AND}: op = SC.sym; getSym(); if op == AND and type(x) != Const: x = genUnaryOp(AND, x) y = factor() # x op y if x.tp == Int == y.tp and op in {TIMES, DIV, MOD}: if type(x) == Const == type(y): # constant folding if op == TIMES: x.val = x.val * y.val elif op == DIV: x.val = x.val // y.val elif op == MOD: x.val = x.val % y.val else: x = genBinaryOp(op, x, y) elif x.tp == Bool == y.tp and op == AND: if type(x) == Const: # constant folding if x.val: x = y # if x is true, take y, else x else: x = genBinaryOp(AND, x, y) else: mark('bad type') return x
def typedIds(kind): """ Parses typedIds = ident {"," ident} ":" type. Updates current scope of symbol table Assumes kind is Var or Ref and applies it to all identifiers Reports an error if an identifier is already defined in the current scope """ tid = [SC.val] getSym() while SC.sym == COMMA: getSym() if SC.sym == IDENT: tid.append(SC.val) getSym() else: mark('identifier expected', 48) if SC.sym == COLON: getSym() tp = typ().tp for i in tid: newObj(i, kind(tp)) else: mark("':' expected", 49)
def compoundStatement(): if SC.sym == BEGIN: getSym() else: mark("'begin' expected") x = statement() while SC.sym == SEMICOLON or SC.sym in FIRSTSTATEMENT: if SC.sym == SEMICOLON: getSym() else: mark("; missing") y = statement() x = CG.genSeq(x, y) if SC.sym == END: getSym() else: mark("'end' expected") return x
def program(): """ Parses program = "program" «write('program ')» ident «write(ident)» ";" «write(';')» declarations compoundStatement(1). Generates code if no error is reported """ newObj('boolean', Type(Bool)) Bool.size = 4 newObj('integer', Type(Int)) Int.size = 4 newObj('true', Const(Bool, 1)) newObj('false', Const(Bool, 0)) newObj('read', StdProc([Ref(Int)])) newObj('write', StdProc([Var(Int)])) newObj('writeln', StdProc([])) CG.progStart() if SC.sym == PROGRAM: # write('program ') writeHtml('program ') # getSym() else: mark("'program' expected") ident = SC.val if SC.sym == IDENT: # write(ident) writeHtml(ident, _class='ident') # getSym() else: mark('program name expected') if SC.sym == SEMICOLON: getSym() # write(';') writeln() writeHtml(';') writeHtmlLn() # else: mark('; expected') declarations(CG.genGlobalVars) CG.progEntry(ident) x = compoundStatement(1) return CG.progExit(x)
def compoundStatement(): """ Parses compoundStatement = "begin" statement {";" statement} "end" Generates code for the compoundStatement if no error is reported """ if SC.sym == BEGIN: getSym() else: mark("'begin' expected") x = statement() while SC.sym == SEMICOLON or SC.sym in FIRSTSTATEMENT: if SC.sym == SEMICOLON: getSym() else: mark("; missing") y = statement(); x = genSeq(x, y) if SC.sym == END: getSym() else: mark("'end' expected") return x
def compoundStatement(): """ Parses compoundStatement = "begin" statement {";" statement} "end" Generates code for the compoundStatement if no error is reported """ if SC.sym == BEGIN: getSym() else: mark("'begin' expected", 17) x = statement() while SC.sym == SEMICOLON or SC.sym in FIRSTSTATEMENT: if SC.sym == SEMICOLON: getSym() else: mark("; missing", 18) y = statement() x = genSeq(x, y) if SC.sym == END: getSym() else: mark("'end' expected", 19) return x
def compoundStatement(l): """ Parses compoundStatement(l) = "begin" «writeln; write(l * indent + 'begin')» statement(l + 1) {";" «write(';')» statement(l + 1)} "end" «writeln; write(l * ident + 'end')» Generates code for the compoundStatement if no error is reported """ if SC.sym == BEGIN: writeln() write(l * indent + 'begin') writeHtmlLn() writeHtml(l * htmlIndent + 'begin') getSym() else: mark("'begin' expected") x = statement(l + 1) while SC.sym == SEMICOLON or SC.sym in FIRSTSTATEMENT: if SC.sym == SEMICOLON: write(';') getSym() writeHtml(';') else: mark("; missing") y = statement(l + 1) x = CG.genSeq(x, y) if SC.sym == END: writeln() write(l * indent) write('end') writeln() writeHtmlLn() writeHtml(l * htmlIndent) writeHtml('end') writeHtmlLn() getSym() else: mark("'end' expected") return x
def program(): newDecl('boolean', Type(CG.genBool(Bool))) newDecl('integer', Type(CG.genInt(Int))) newDecl('true', Const(Bool, 1)) newDecl('false', Const(Bool, 0)) newDecl('read', StdProc([Ref(Int)])) newDecl('write', StdProc([Var(Int)])) newDecl('writeln', StdProc([])) CG.genProgStart() if SC.sym == PROGRAM: getSym() else: mark("'program' expected") ident = SC.val if SC.sym == IDENT: getSym() else: mark('program name expected') if SC.sym == SEMICOLON: getSym() else: mark('; expected') declarations(CG.genGlobalVars) CG.genProgEntry(ident) x = compoundStatement() return CG.genProgExit(x)
def typedIds(kind): """ Parses typedIds = ident {"," ident} ":" type. Updates current scope of symbol table Assumes kind is Var or Ref and applies it to all identifiers Reports an error if an identifier is already defined in the current scope """ if SC.sym == IDENT: tid = [SC.val] getSym() else: mark("identifier expected") tid = [] while SC.sym == COMMA: # attribute write(', ') writeHtml(', ') # getSym() if SC.sym == IDENT: # attribute write(SC.val) writeHtml(SC.val) # tid.append(SC.val) getSym() else: mark('identifier expected') if SC.sym == COLON: # attribute write(': ') writeHtml(': ') # getSym() tp = typ().tp if tp != None: for i in tid: newObj(i, kind(tp)) else: mark("':' expected")
def typedIds(kind): if SC.sym == IDENT: tid = [SC.val] getSym() else: mark("identifier expected") tid = [] while SC.sym == COMMA: getSym() if SC.sym == IDENT: tid.append(SC.val) getSym() else: mark('identifier expected') if SC.sym == COLON: getSym() tp = typ().val if tp != None: for i in tid: newDecl(i, kind(tp)) else: mark("':' expected")
def expression(): x = simpleExpression() while SC.sym in {EQ, NE, LT, LE, GT, GE, ELEMENT, SUBSET, SUPERSET}: op = SC.sym; getSym() if op in (EQ, NE, LT, LE, GT, GE): y = simpleExpression() # x op y if x.tp == y.tp in (Int, Bool): if type(x) == Const == type(y): # constant folding if op == EQ: x.val = int(x.val == y.val) elif op == NE: x.val = int(x.val != y.val) elif op == LT: x.val = int(x.val < y.val) elif op == LE: x.val = int(x.val <= y.val) elif op == GT: x.val = int(x.val > y.val) elif op == GE: x.val = int(x.val >= y.val) x.tp = Bool else: x = CG.genRelation(op, x, y) else: mark('bad type') elif (op == ELEMENT and x.tp == Int) or (op in (SUBSET, SUPERSET) and type(x.tp) == Set): x = CG.genUnaryOp(op, x); y = simpleExpression() if type(y.tp) == Set: x = CG.genRelation(op, x, y) else: mark('set expected') else: mark('bad type') return x
def declarations(allocVar): if SC.sym not in FIRSTDECL | FOLLOWDECL: getSym() mark("'begin' or declaration expected") while SC.sym not in FIRSTDECL | STRONGSYMS | FOLLOWDECL: getSym() while SC.sym == CONST: getSym() if SC.sym == IDENT: ident = SC.val getSym() if SC.sym == EQ: getSym() else: mark("= expected") x = expression() if type(x) == Const: newDecl(ident, x) else: mark('expression not constant') else: mark("constant name expected") if SC.sym == SEMICOLON: getSym() else: mark("; expected") while SC.sym == TYPE: getSym() if SC.sym == IDENT: ident = SC.val getSym() if SC.sym == EQ: getSym() else: mark("= expected") x = typ() newDecl(ident, x) # x is of type ST.Type if SC.sym == SEMICOLON: getSym() else: mark("; expected") else: mark("type name expected") start = len(topScope()) while SC.sym == VAR: getSym() typedIds(Var) if SC.sym == SEMICOLON: getSym() else: mark("; expected") varsize = allocVar(topScope(), start) while SC.sym == PROCEDURE: getSym() if SC.sym == IDENT: getSym() else: mark("procedure name expected") ident = SC.val newDecl(ident, Proc([])) # entered without parameters sc = topScope() CG.genProcStart() openScope() # new scope for parameters and body if SC.sym == LPAREN: getSym() if SC.sym in {VAR, IDENT}: if SC.sym == VAR: getSym() typedIds(Ref) else: typedIds(Var) while SC.sym == SEMICOLON: getSym() if SC.sym == VAR: getSym() typedIds(Ref) else: typedIds(Var) else: mark("formal parameters expected") fp = topScope() sc[-1].par = fp[:] # procedure parameters updated if SC.sym == RPAREN: getSym() else: mark(") expected") else: fp = [] parsize = CG.genFormalParams(fp) if SC.sym == SEMICOLON: getSym() else: mark("; expected") localsize = declarations(CG.genLocalVars) CG.genProcEntry(ident, parsize, localsize) x = compoundStatement() CG.genProcExit(x, parsize, localsize) closeScope() # scope for parameters and body closed if SC.sym == SEMICOLON: getSym() else: mark("; expected") return varsize
def declarations(allocVar): """ Parses declarations = {"const" ident "=" expression ";"} {"type" ident "=" type ";"} {"var" typedIds ";"} {"procedure" ident ["(" [["var"] typedIds {";" ["var"] typedIds}] ")"] ";" declarations compoundStatement ";"}. Updates current scope of symbol table. Reports an error if an identifier is already defined in the current scope. For each procedure, code is generated """ global depth if SC.sym not in FIRSTDECL | FOLLOWDECL: getSym() mark("'begin' or declaration expected") while SC.sym not in FIRSTDECL | STRONGSYMS | FOLLOWDECL: getSym() while SC.sym == CONST: # attributes depth += 1 write(indent * depth) write('const') writeln() writeHtml(htmlIndent * depth) writeHtml('const') writeHtmlLn() # getSym() if SC.sym == IDENT: # attributes depth += 1 ident = SC.val write(indent * depth) write(ident) writeHtml(htmlIndent * depth) # integer constant is upright writeHtml(ident) # getSym() if SC.sym == EQ: # attribute write(' = ') writeHtml(' = ') # getSym() else: mark("= expected") x = expression() if type(x) == Const: newObj(ident, x) else: mark('expression not constant') depth -= 1 else: mark("constant name expected") if SC.sym == SEMICOLON: # attributes write(';') writeln() writeHtml(';') writeHtmlLn() # getSym() else: mark("; expected") depth -= 1 while SC.sym == TYPE: # attributes depth += 1 write(indent * depth) write('type') writeln() writeHtml(htmlIndent * depth) writeHtml('type') writeHtmlLn() # getSym() if SC.sym == IDENT: # attributes depth += 1 ident = SC.val write(indent * depth) write(ident) writeHtml(htmlIndent * depth) writeHtml(ident, _class='ident') # getSym() if SC.sym == EQ: # attributes write(' = ') writeHtml(' = ') # getSym() else: mark("= expected") # attributes (emulate stack) old_depth = depth depth += 1 x = typ() depth = old_depth # newObj(ident, x) # x is of type ST.Type if SC.sym == SEMICOLON: # attribute write(';') writeln() writeHtml(';') writeHtmlLn() getSym() # else: mark("; expected") depth -= 1 else: mark("type name expected") depth -= 1 start = len(topScope()) while SC.sym == VAR: # attributes depth += 1 write(indent * depth) write('var') writeln() writeHtml(htmlIndent * depth) writeHtml('var') writeHtmlLn() depth += 1 getSym() write(indent * depth) write(SC.val) writeHtml(htmlIndent * depth) writeHtml(SC.val) # typedIds(Var) if SC.sym == SEMICOLON: # write(';') writeln() writeHtml(';') writeHtmlLn() getSym() # else: mark("; expected") depth -= 2 varsize = allocVar(topScope(), start) while SC.sym == PROCEDURE: # depth += 1 write(indent * depth) write('procedure ') writeHtml(htmlIndent * depth) writeHtml('procedure ') # getSym() if SC.sym == IDENT: # write(SC.val) writeHtml(SC.val) # getSym() else: mark("procedure name expected") ident = SC.val newObj(ident, Proc([])) # entered without parameters sc = topScope() CG.procStart() openScope() # new scope for parameters and body if SC.sym == LPAREN: # write('(') writeHtml('(') # getSym() if SC.sym in {VAR, IDENT}: if SC.sym == VAR: # write('var ') writeHtml('var ') getSym() write(SC.val) writeHtml(SC.val) # typedIds(Ref) else: typedIds(Var) while SC.sym == SEMICOLON: # write('; ') writeHtml('; ') # getSym() if SC.sym == VAR: # write('var ') writeHtml('var ') getSym() write(SC.val) writeHtml(SC.val) # typedIds(Ref) else: # write(SC.val) writeHtml(SC.val) # typedIds(Var) else: mark("formal parameters expected") fp = topScope() sc[-1].par = fp[:] # procedure parameters updated if SC.sym == RPAREN: # write(')') writeHtml(')') # getSym() else: mark(") expected") else: fp = [] parsize = CG.genFormalParams(fp) if SC.sym == SEMICOLON: # write(';') writeln() writeHtml(';') writeHtmlLn() # getSym() else: mark("; expected") depth += 1 localsize = declarations(CG.genLocalVars) CG.genProcEntry(ident, parsize, localsize) x = compoundStatement(depth + 1) CG.genProcExit(x, parsize, localsize) closeScope() # scope for parameters and body closed if SC.sym == SEMICOLON: getSym() else: mark("; expected") depth -= 1 return varsize
def typ(): if SC.sym not in FIRSTTYPE: getSym() mark("type expected") while SC.sym not in FIRSTTYPE | STRONGSYMS | FOLLOWTYPE: getSym() if SC.sym == IDENT: ident = SC.val x = find(ident) getSym() if type(x) == Type: x = Type(x.val) else: mark('not a type') x = Type(None) elif SC.sym == ARRAY: getSym() if SC.sym == LBRAK: getSym() else: mark("'[' expected") x = expression() if SC.sym == PERIOD: getSym() else: mark("'.' expected") if SC.sym == PERIOD: getSym() else: mark("'.' expected") y = expression() if SC.sym == RBRAK: getSym() else: mark("']' expected") if SC.sym == OF: getSym() else: mark("'of' expected") z = typ().val if type(x) != Const or x.val < 0: mark('bad lower bound') x = Type(None) elif type(y) != Const or y.val < x.val: mark('bad upper bound') x = Type(None) else: x = Type(CG.genArray(Array(z, x.val, y.val - x.val + 1))) elif SC.sym == RECORD: getSym() openScope() typedIds(Var) while SC.sym == SEMICOLON: getSym() typedIds(Var) if SC.sym == END: getSym() else: mark("'end' expected") r = topScope() closeScope() x = Type(CG.genRec(Record(r))) else: x = Type(None) return x
def statement(): """ Parses statement = ident selector ":=" expression | ident "(" [expression {"," expression}] ")" | compoundStatement | "if" expression "then" Statement ["else" Statement] | "while" expression "do" Statement. Generates code for the statement if no error is reported """ if SC.sym not in FIRSTSTATEMENT: mark("statement expected"); getSym() while SC.sym not in FIRSTSTATEMENT | STRONGSYMS | FOLLOWSTATEMENT: getSym() if SC.sym == IDENT: x = find(SC.val); getSym(); x = genVar(x) if type(x) in {Var, Ref}: x = selector(x) if SC.sym == BECOMES: getSym(); y = expression() if x.tp == y.tp in {Bool, Int}: if type(x) == Var: x = genAssign(x, y) else: mark('illegal assignment') else: mark('incompatible assignment') elif SC.sym == EQ: mark(':= expected'); getSym(); y = expression() else: mark(':= expected') elif type(x) in {Proc, StdProc} and SC.sym == LPAREN: getSym() fp, i = x.par, 0 # list of formal parameters if SC.sym in FIRSTEXPRESSION: y = expression() if i < len(fp): if type(fp[i]) == Var or type(y) == Var: # fp[i] == Ref and ty if type(x) == Proc: genActualPara(y, fp[i], i) i = i + 1 else: mark('illegal parameter mode') else: mark('extra parameter') while SC.sym == COMMA: getSym() y = expression() if i < len(fp): if type(fp[i]) == Var or type(y) == Var: if type(x) == Proc: genActualPara(y, fp[i], i) i = i + 1 else: mark('illegal parameter mode') else: mark('extra parameter') if i < len(fp): mark('too few parameters') if SC.sym == RPAREN: getSym() else: mark("')' expected") if type(x) == StdProc: if x.name == 'read': x = genRead(y) elif x.name == 'write': x = genWrite(y) elif x.name == 'writeln': x = genWriteln() else: x = genCall(x) else: mark("variable or procedure expected") elif SC.sym == BEGIN: x = compoundStatement() elif SC.sym == IF: getSym(); x = expression(); q=1; if x.tp == Bool: x = genCond(x) elif x.tp == Int: q = 0 # if we skipped genrelation, prepare to skip following statement
def factor(): if SC.sym == IDENT: x = find(SC.val) if type(x) == Var: x = CG.genVar(x); getSym() elif type(x) == Const: x = Const(x.tp, x.val); x = CG.genConst(x); getSym() else: mark('variable or constant identifier expected') x = selector(x) elif SC.sym == NUMBER: x = Const(Int, SC.val); x = CG.genConst(x); getSym() elif SC.sym == LPAREN: getSym(); x = expression() if SC.sym == RPAREN: getSym() else: mark(') expected') elif SC.sym == LBRACE: getSym() if SC.sym in FIRSTEXPRESSION: y = expression() if y.tp == Int: x = CG.genUnaryOp(SET, y) else: mark('not integer') while SC.sym == COMMA: getSym(); y = expression() if y.tp == Int: y = CG.genUnaryOp(SET, y) else: mark("not integer") x = CG.genBinaryOp(UNION, x, y) else: x = Const(Set(0, 32), 0); x = CG.genConst(x) if SC.sym == RBRACE: getSym() else: mark('} expected') elif SC.sym == NOT: getSym(); x = factor() if x.tp != Bool: mark('not boolean') elif type(x) == Const: x.val = 1 - x.val # constant folding else: x = CG.genUnaryOp(NOT, x) elif SC.sym in {CARD, COMPLEMENT}: op = SC.sym; getSym(); x = factor() if type(x.tp) == Set: x = CG.genUnaryOp(op, x) else: mark('set expected') else: mark('expression expected') return x
def declarations(allocVar): """ Parses declarations = {"const" ident "=" expression ";"} {"type" ident "=" type ";"} {"var" typedIds ";"} {"procedure" ident ["(" [["var"] typedIds {";" ["var"] typedIds}] ")"] ";" declarations compoundStatement ";"}. Updates current scope of symbol table. Reports an error if an identifier is already defined in the current scope. For each procedure, code is generated """ if SC.sym not in FIRSTDECL | FOLLOWDECL: getSym() mark("declaration expected") while SC.sym not in FIRSTDECL | FOLLOWDECL: getSym() while SC.sym == CONST: getSym() if SC.sym == IDENT: ident = SC.val getSym() if SC.sym == EQ: getSym() else: mark("= expected") x = expression() if type(x) == Const: newObj(ident, x) else: mark("expression not constant") else: mark("constant name expected") if SC.sym == SEMICOLON: getSym() else: mark("; expected") while SC.sym == TYPE: getSym() if SC.sym == IDENT: ident = SC.val getSym() if SC.sym == EQ: getSym() else: mark("= expected") x = typ() newObj(ident, x) # x is of type ST.Type if SC.sym == SEMICOLON: getSym() else: mark("; expected") else: print(SC.sym) mark("type name expected") start = len(topScope()) while SC.sym == VAR: getSym() typedIds(Var) if SC.sym == SEMICOLON: getSym() else: mark("; expected") varsize = allocVar(topScope(), start) while SC.sym == PROCEDURE: getSym() if SC.sym == IDENT: getSym() else: mark("procedure name expected") ident = SC.val newObj(ident, Proc([])) # entered without parameters sc = topScope() procStart() openScope() # new scope for parameters and body if SC.sym == LPAREN: getSym() if SC.sym in {VAR, IDENT}: if SC.sym == VAR: getSym() typedIds(Ref) # , procParams) else: typedIds(Var) # , procParams) while SC.sym == SEMICOLON: getSym() if SC.sym == VAR: getSym() typedIds(Ref) # , procParams) else: typedIds(Var) # , procParams) else: mark("formal parameters expected") fp = topScope() sc[-1].par = fp[:] # procedure parameters updated if SC.sym == RPAREN: getSym() else: mark(") expected") else: fp = [] parsize = genFormalParams(fp) if SC.sym == SEMICOLON: getSym() else: mark("; expected") localsize = declarations(genLocalVars) genProcEntry(ident, parsize, localsize) x = compoundStatement() genProcExit(x, parsize, localsize) closeScope() # scope for parameters and body closed if SC.sym == SEMICOLON: getSym() else: mark("; expected") return varsize
def selector(x): while SC.sym in {LBRAK, PERIOD}: if SC.sym == LBRAK: # x[y] getSym(); y = expression() if type(x.tp) == Array: if y.tp == Int: if type(y) == Const and (y.val < x.tp.lower or y.val >= x.tp.lower + x.tp.length): mark('index out of bounds') else: x = CG.genIndex(x, y) else: mark('index not integer') else: mark('not an array') if SC.sym == RBRAK: getSym() else: mark("] expected") else: # x.f getSym() if SC.sym == IDENT: if type(x.tp) == Record: for f in x.tp.fields: if f.name == SC.val: x = CG.genSelect(x, f); break else: mark("not a field") getSym() else: mark("not a record") else: mark("identifier expected") return x
def typedIds(): if SC.sym == IDENT: tid = [SC.val]; getSym() else: mark("identifier expected") while SC.sym == COMMA: getSym() if SC.sym == IDENT: tid.append(SC.val); getSym() else: mark('identifier expected') if SC.sym == COLON: getSym() else: mark("':' expected") tp = typ().val for i in tid: newDecl(i, Var(tp)) while SC.sym == COMMA: getSym() if SC.sym == IDENT: tid = [SC.val]; getSym() else: mark("identifier expected") while SC.sym == COMMA: getSym() if SC.sym == IDENT: tid.append(SC.val); getSym() else: mark('identifier expected') if SC.sym == COLON: getSym() else: mark("':' expected") tp = typ().val for i in tid: newDecl(i, Var(tp))
def statementBlock(): x = statementList() while SC.sym in FIRSTSTATEMENT: if not SC.newline: mark('new line expected') y = statementList(); x = CG.genSeq(x, y) return x
def typ(): """ Parses type = ident | "array" "[" expression ".." expression "]" "of" type | "record" typedIds {";" typedIds} "end". Returns a type descriptor """ global depth if SC.sym not in FIRSTTYPE: getSym() mark("type expected") while SC.sym not in FIRSTTYPE | STRONGSYMS | FOLLOWTYPE: getSym() if SC.sym == IDENT: # attribute ident = SC.val write(ident) writeHtml(ident, _class='ident') # x = find(ident) getSym() if type(x) == Type: x = Type(x.tp) else: mark('not a type') x = Type(None) elif SC.sym == ARRAY: depth += 1 # attribute writeln() write(indent * depth) write('array ') writeHtmlLn() writeHtml(htmlIndent * depth) writeHtml('array ') # getSym() if SC.sym == LBRAK: # attribute write('[') writeHtml('[') # getSym() else: mark("'[' expected") x = expression() if SC.sym == PERIOD: # attribute write(' .') writeHtml(' .') # getSym() else: mark("'.' expected") if SC.sym == PERIOD: # attribute write('. ') writeHtml('. ') # getSym() else: mark("'.' expected") y = expression() if SC.sym == RBRAK: # attribute write('] ') writeHtml('] ') # getSym() else: mark("']' expected") if SC.sym == OF: # attribute write('of') writeHtml('of') # getSym() else: mark("'of' expected") z = typ().tp if type(x) != Const or x.val < 0: mark('bad lower bound') x = Type(None) elif type(y) != Const or y.val < x.val: mark('bad upper bound') y = Type(None) else: x = Type(CG.genArray(Array(z, x.val, y.val - x.val + 1))) depth -= 1 elif SC.sym == RECORD: # attributes depth += 1 writeln() write(indent * depth) write('record') writeln() writeHtmlLn() writeHtml(htmlIndent * depth) writeHtml('record') writeHtmlLn() depth += 1 # getSym() # attributes write(indent * depth) write(SC.val) writeHtml(htmlIndent * depth) writeHtml(SC.val) # openScope() typedIds(Var) while SC.sym == SEMICOLON: # attributes write(';') writeln() writeHtml(';') writeHtmlLn() # getSym() # attributes write(indent * depth) write(SC.val) writeHtml(htmlIndent * depth) writeHtml(SC.val) # typedIds(Var) # attributes writeln() writeHtmlLn() depth -= 1 write(indent * depth) writeHtml(htmlIndent * depth) # if SC.sym == END: # attributes write('end') writeHtml('end') # getSym() else: mark("'end' expected") r = topScope() closeScope() x = Type(CG.genRec(Record(r))) depth -= 1 else: x = Type(None) return x
def statement(l): """ Parses statement = EDIT LINE ident selector ":=" expression | ident «write(l * indent + ident)» "(" «write('(')» [expression {"," «write(', ')» expression}] ")" «write(')')» | compoundStatement(l) | "if" «writeln; write(l * indent + 'if ')» expression "then" «write(' then')» statement(l + 1) ["else" «writeln; write(l * indent + 'else')» statement(l + 1)] | EDIT LINE "while" expression "do" statement. Generates code for the statement if no error is reported """ if SC.sym not in FIRSTSTATEMENT: mark("statement expected") getSym() while SC.sym not in FIRSTSTATEMENT | STRONGSYMS | FOLLOWSTATEMENT: getSym() if SC.sym == IDENT: x = find(SC.val) writeln() write(l * indent + SC.val) getSym() writeHtmlLn() writeHtml(l * htmlIndent + SC.val) x = CG.genVar(x) if type(x) in {Var, Ref}: x = selector(x) if SC.sym == BECOMES: write(' := ') writeHtml(' := ') getSym() y = expression() if x.tp == y.tp in { Bool, Int }: # and not SC.error: type(y) could be Type #if type(x) == Var: ### and type(y) in {Var, Const}: incomplete, y may be Reg x = CG.genAssign(x, y) #else: mark('illegal assignment') else: mark('incompatible assignment') elif SC.sym == EQ: mark(':= expected') getSym() y = expression() else: mark(':= expected') elif type(x) in {Proc, StdProc}: fp, i = x.par, 0 # list of formals, count of actuals if SC.sym == LPAREN: write('(') getSym() writeHtml('(') if SC.sym in FIRSTEXPRESSION: y = expression() if i < len(fp): if (type(fp[i]) == Var or type(y) == Var) and \ fp[i].tp == y.tp: if type(x) == Proc: CG.genActualPara(y, fp[i], i) i = i + 1 else: mark('illegal parameter mode') else: mark('extra parameter') while SC.sym == COMMA: write(', ') getSym() writeHtml(', ') y = expression() if i < len(fp): if (type(fp[i]) == Var or type(y) == Var) and \ fp[i].tp == y.tp: if type(x) == Proc: CG.genActualPara(y, fp[i], i) i = i + 1 else: mark('illegal parameter mode') else: mark('extra parameter') if SC.sym == RPAREN: write(')') getSym() writeHtml(')') else: mark("')' expected") if i < len(fp): mark('too few parameters') if type(x) == StdProc: if x.name == 'read': x = CG.genRead(y) elif x.name == 'write': x = CG.genWrite(y) elif x.name == 'writeln': x = CG.genWriteln() else: x = CG.genCall(x) else: mark("variable or procedure expected") elif SC.sym == BEGIN: x = compoundStatement(l + 1) elif SC.sym == IF: writeln() write(l * indent + 'if ') writeHtmlLn() writeHtml(l * htmlIndent + 'if ') getSym() x = expression() if x.tp == Bool: x = CG.genCond(x) else: mark('boolean expected') if SC.sym == THEN: write(' then') writeHtml(' then') getSym() else: mark("'then' expected") y = statement(l + 1) if SC.sym == ELSE: if x.tp == Bool: y = CG.genThen(x, y) writeln() write(l * indent + 'else') writeHtmlLn() writeHtml(l * htmlIndent + ' else') getSym() z = statement(l + 1) if x.tp == Bool: x = CG.genIfElse(x, y, z) else: if x.tp == Bool: x = CG.genIfThen(x, y) elif SC.sym == WHILE: writeln() write(indent * (l + 1)) write('while ') writeHtmlLn() writeHtml(htmlIndent * (l + 1)) writeHtml('while ') getSym() t = CG.genTarget() x = expression() if x.tp == Bool: x = CG.genCond(x) else: mark('boolean expected') if SC.sym == DO: write(' do') writeHtml(' do') getSym() else: mark("'do' expected") y = statement(l + 2) if x.tp == Bool: x = CG.genWhile(t, x, y) else: x = None return x
def statement(): """ Parses statement = ident selector ":=" expression | ident "(" [expression {"," expression}] ")" | compoundStatement | "if" expression "then" Statement ["else" Statement] | "while" expression "do" Statement. Generates code for the statement if no error is reported """ if SC.sym not in FIRSTSTATEMENT: mark("statement expected") getSym() while SC.sym not in FIRSTSTATEMENT | STRONGSYMS | FOLLOWSTATEMENT: getSym() if SC.sym == IDENT: x = find(SC.val) getSym() x = genVar(x) if type(x) in {Var, Ref}: x = selector(x) if SC.sym == BECOMES: getSym() y = expression() if x.tp == y.tp in {Bool, Int}: # if type(x) == Var: x = genAssign(x, y) if type(x) == Var: print("x: ", x, "y: ", y) x = genAssign2(x, y) else: mark("illegal assignment") else: mark("incompatible assignment") elif SC.sym == EQ: mark(":= expected") getSym() y = expression() else: mark(":= expected") elif type(x) in {Proc, StdProc} and SC.sym == LPAREN: getSym() fp, i = x.par, 0 # list of formal parameters if SC.sym in FIRSTEXPRESSION: y = expression() if i < len(fp): if type(fp[i]) == Var or type(y) == Var: # fp[i] == Ref and ty if type(x) == Proc: genActualPara(y, fp[i], i) i = i + 1 else: mark("illegal parameter mode") else: mark("extra parameter") while SC.sym == COMMA: getSym() y = expression() if i < len(fp): if type(fp[i]) == Var or type(y) == Var: if type(x) == Proc: genActualPara(y, fp[i], i) i = i + 1 else: mark("illegal parameter mode") else: mark("extra parameter") if i < len(fp): mark("too few parameters") if SC.sym == RPAREN: getSym() else: mark("')' expected") if type(x) == StdProc: if x.name == "read": x = genRead(y) elif x.name == "write": x = genWrite(y) elif x.name == "writeln": x = genWriteln() else: x = genCall(x) else: mark("variable or procedure expected") elif SC.sym == BEGIN: x = compoundStatement() elif SC.sym == IF: getSym() x = expression() if x.tp == Bool: x = genCond(x) else: mark("boolean expected") if SC.sym == THEN: getSym() else: mark("'then' expected") y = statement() if SC.sym == ELSE: y = genThen(x, y) getSym() z = statement() x = genIfElse(x, y, z) else: x = genIfThen(x, y) elif SC.sym == WHILE: getSym() t = genTarget() x = expression() if x.tp == Bool: x = genCond(x) else: mark("boolean expected") if SC.sym == DO: getSym() else: mark("'do' expected") y = statement() x = genWhile(t, x, y) else: mark("invalid statement") x = None return x
else: mark('extra parameter') if i < len(fp): mark('too few parameters') if SC.sym == RPAREN: getSym() else: mark("')' expected") if type(x) == StdProc: if x.name == 'read': x = genRead(y) elif x.name == 'write': x = genWrite(y) elif x.name == 'writeln': x = genWriteln() else: x = genCall(x) else: mark("variable or procedure expected") elif SC.sym == BEGIN: x = compoundStatement() elif SC.sym == IF: getSym(); x = expression(); q=1; if x.tp == Bool: x = genCond(x) elif x.tp == Int: q = 0 # if we skipped genrelation, prepare to skip following statement else: mark('boolean expected') if SC.sym == THEN: getSym() else: mark("'then' expected") if q=1: y = statement() # if (FALSE (q=0)) skip if SC.sym == ELSE and q=1: # if (TRUE (q=1)) then perform THEN y = genThen(x, y); getSym(); z = statement(); x = genIfElse(x, y, z) else: x = genIfThen(x, y) elif SC.sym == WHILE: getSym(); t = genTarget(); x = expression() if x.tp == Bool: x = genCond(x) else: mark('boolean expected') if SC.sym == DO: getSym() else: mark("'do' expected") y = statement(); x = genWhile(t, x, y) else:
def statement(): if SC.sym == IDENT: # x := y, y(...), x ← y(...) # type(x) == Proc, StdProc: check no result parameters needed; call, y := true, x # type(x) ≠ Proc, StdProc: x := selector(): # sym == BECOMES: assignment; call := false # sym == LARROW: check result paramter match, type(y) is Proc, StdProc, x = find(SC.val) if type(x) in {Proc, StdProc}: # procedure call without result if x.res != []: mark('variable for result expected') getSym(); call, xs, y = True, [], x elif type(x) == Var: # assignment or procedure call with result x = find(SC.val); x = CG.genVar(x); getSym() if SC.sym in FIRSTSELECTOR: xs = [CG.genLeftAssign(selector(x))] # array or field update else: # multiple assignment or procedure call with result xs = [CG.genLeftAssign(x)] while SC.sym == COMMA: getSym(); if SC.sym == IDENT: x = find(SC.val) if x.name not in {x.name for x in xs}: if type(x) == Var: xs += [CG.genLeftAssign(CG.genVar(x))]; getSym() else: mark('variable identifier expected') else: mark('duplicate variable identifier') else: mark('identifier expected') if SC.sym == BECOMES: getSym(); call = False; ys = [CG.genRightAssign(expression())] # xs := ys while SC.sym == COMMA: getSym(); ys += [CG.genRightAssign(expression())] if len(xs) == len(ys): for x, y in zip(reversed(xs), reversed(ys)): if compatible(x.tp, y.tp): x = CG.genAssign(x, y) else: mark('incompatible assignment') else: mark('unbalanced assignment') elif SC.sym == LARROW: getSym() if SC.sym == IDENT: y = find(SC.val); getSym(); call = True else: mark('procedure identifier expected') if type(y) in {Proc, StdProc}: if len(xs) == len(y.res): for x, r in zip(xs, y.res): if not compatible(x.tp, r.tp): mark('incompatible call') else: mark('unbalanced call') else: mark('procedure expected') else: mark(':= or ← expected') else: mark("variable or procedure expected") if call: # call y(ap) or xs ← y(ap) fp, ap, i = y.par, [], 0 # list of formals, list of actuals if SC.sym == LPAREN: getSym() else: mark("'(' expected") if SC.sym in FIRSTEXPRESSION: a = expression() if i < len(fp): if compatible(fp[i].tp, a.tp): ap.append(CG.genActualPara(a, fp[i], i)) else: mark('incompatible parameter') else: mark('extra parameter') i = i + 1 while SC.sym == COMMA: getSym() a = expression() if i < len(fp): if compatible(fp[i].tp, a.tp): ap.append(CG.genActualPara(a, fp[i], i)) else: mark('incompatible parameter') else: mark('extra parameter') i = i + 1 if SC.sym == RPAREN: getSym() else: mark("')' expected") if i < len(fp): mark('too few parameters') elif type(y) == StdProc: if y.name == 'read': x = CG.genRead(x) elif y.name == 'write': x = CG.genWrite(a) elif y.name == 'writeln': x = CG.genWriteln() else: x = CG.genCall(xs, y, ap) elif SC.sym == IF: getSym(); x = expression(); if x.tp == Bool: x = CG.genThen(x) else: mark('boolean expected') if SC.sym == THEN: getSym() else: mark("'then' expected") y = statementSuite() if SC.sym == ELSE: getSym() y = CG.genElse(x, y) z = statementSuite() x = CG.genIfElse(x, y, z) else: x = CG.genIfThen(x, y) elif SC.sym == WHILE: getSym(); t = CG.genWhile(); x = expression() if x.tp == Bool: x = CG.genDo(x) else: mark('boolean expected') if SC.sym == DO: getSym() else: mark("'do' expected") y = statementSuite() x = CG.genWhileDo(t, x, y) else: mark('statement expected') return x
def testRange(x): if x.val >= 0x8000 or x.val < -0x8000: mark('value too large')
def typ(): if SC.sym == IDENT: ident = SC.val; x = find(ident) if type(x) == Type: x = Type(x.val); getSym() else: mark('type identifier expected') elif SC.sym == LBRAK: getSym(); x = expression() if SC.sym == DOTDOT: getSym() else: mark("'..' expected") y = expression() if SC.sym == RBRAK: getSym() else: mark("']' expected") if SC.sym == RARROW: getSym() else: mark("'→' expected") z = typ().val; if type(x) != Const or x.val < 0: mark('bad lower bound') elif type(y) != Const or y.val < x.val: mark('bad upper bound') else: x = Type(CG.genArray(Array(z, x.val, y.val - x.val + 1))) elif SC.sym == LPAREN: getSym(); openScope(); typedIds() if SC.sym == RPAREN: getSym() else: mark("')' expected") r = topScope(); closeScope() x = Type(CG.genRec(Record(r))) elif SC.sym == FULLPAREN: pass elif SC.sym == SET: getSym(); if SC.sym == LBRAK: getSym() else: mark ("'[' expected") x = expression() if SC.sym == DOTDOT: getSym() else: mark("'..' expected") y = expression() if SC.sym == RBRAK: getSym() else: mark("']' expected") if type(x) != Const: mark('bad lower bound') elif type(y) != Const or y.val < x.val: mark('bad upper bound') else: x = Type(CG.genSet(Set(x.val, y.val - x.val + 1))) else: mark('type expected') return x
def find(name): for l in symTab: for e in l: if name == e.name: return e mark('undefined identifier ' + name) return Const(None, 0)
def declarations(allocVar): while SC.sym == CONST: getSym() if SC.sym == IDENT: ident = SC.val; getSym() else: mark("constant name expected") if SC.sym == EQ: getSym() else: mark("= expected") x = expression() if type(x) == Const: newDecl(ident, x) else: mark('expression not constant') while SC.sym == TYPE: getSym() if SC.sym == IDENT: ident = SC.val; getSym() else: mark("type name expected") if SC.sym == EQ: getSym() else: mark("= expected") x = typ(); newDecl(ident, x) # x is of type ST.Type start = len(topScope()) while SC.sym == VAR: getSym(); typedIds() var = allocVar(topScope(), start) while SC.sym == PROCEDURE: getSym() if SC.sym == LPAREN: getSym() if SC.sym == IDENT: r = SC.val; getSym() else: mark("identifier expected") if SC.sym == COLON: getSym() else: mark("':' expected") tp = typ().val if SC.sym == RPAREN: getSym() else: mark(") expected") else: r = None if SC.sym == IDENT: ident = SC.val; getSym() else: mark("procedure name expected") newDecl(ident, Proc([], [])) # entered without parameters sc = topScope(); openScope() # new scope for parameters and body if r: newDecl(r, Var(tp)) if SC.sym == LPAREN: getSym() else: mark("( expected") if SC.sym == IDENT: typedIds() fp = topScope() if SC.sym == RPAREN: getSym() else: mark(") expected") d = len(fp) if SC.sym == RARROW: getSym() if SC.sym == LPAREN: getSym() else: mark('( expected') typedIds() if SC.sym == RPAREN: getSym() else: mark(') expected') sc[-1].par, sc[-1].res = fp[:d], fp[d:] # procedure parameters updated para = CG.genProcStart(ident, fp[:d], fp[d:]) body(ident, para); closeScope() # scope for parameters and body closed return var
def compileFile(srcfn): if srcfn.endswith('.p'): with open(srcfn, 'r') as f: src = f.read() dstfn = srcfn[:-2] + '.s' compileString(src, dstfn) else: mark("'.p' file extension expected")
def selector(x): """ Parses selector = {"." ident | "[" expression "]"}. Assumes x is the entry for the identifier in front of the selector; generates code for the selector if no error is reported """ while SC.sym in {PERIOD, LBRAK}: if SC.sym == PERIOD: # x.f # attribute write('.') writeHtml('.') # getSym() if SC.sym == IDENT: # attribute write(SC.val) writeHtml(SC.val) # if type(x.tp) == Record: for f in x.tp.fields: if f.name == SC.val: x = CG.genSelect(x, f) break else: mark("not a field") getSym() else: mark("not a record") else: mark("identifier expected") else: # x[y] getSym() # attribute write('[') writeHtml('[') # y = expression() if type(x.tp) == Array: if y.tp == Int: if type(y) == Const and \ (y.val < x.tp.lower or y.val >= x.tp.lower + x.tp.length): mark('index out of bounds') else: x = CG.genIndex(x, y) else: mark('index not integer') else: mark('not an array') if SC.sym == RBRAK: getSym() # attribute write(']') writeHtml(']') else: mark("] expected") return x
def typ(): """ Parses type = ident | "array" "[" expression ".." expression "]" "of" type | "record" typedIds {";" typedIds} "end". Returns a type descriptor """ if SC.sym not in FIRSTTYPE: getSym() mark("type expected") while SC.sym not in FIRSTTYPE | FOLLOWTYPE | STRONGSYMS: getSym() if SC.sym == IDENT: ident = SC.val x = find(ident) getSym() if type(x) == Type: x = Type(x.tp) else: mark("not a type") elif SC.sym == ARRAY: getSym() if SC.sym == LBRAK: getSym() else: mark("'[' expected") x = expression() if type(x) != Const or x.val < 0: mark("bad lower bound") if SC.sym == PERIOD: getSym() else: mark("'.' expected") if SC.sym == PERIOD: getSym() else: mark("'.' expected") y = expression() if type(y) != Const or y.val < x.val: mark("bad upper bound") if SC.sym == RBRAK: getSym() else: mark("']' expected") if SC.sym == OF: getSym() else: mark("'of' expected") z = typ().tp l = y.val - x.val + 1 x = Type(genArray(Array(z, x.val, l))) elif SC.sym == RECORD: getSym() openScope() typedIds(Var) while SC.sym == SEMICOLON: getSym() typedIds(Var) if SC.sym == END: getSym() else: mark("'end' expected") r = topScope() closeScope() x = Type(genRec(Record(r))) else: mark("type expected") x = Type(None) return x
def obtainReg(): if len(regs) == 0: mark('out of registers') return R0 else: return regs.pop()
def statement(): if SC.sym not in FIRSTSTATEMENT: mark("statement expected") getSym() while SC.sym not in FIRSTSTATEMENT | STRONGSYMS | FOLLOWSTATEMENT: getSym() if SC.sym == IDENT: x = find(SC.val) getSym() if type(x) in {Var, Ref}: x = CG.genVar(x) x = selector(x) if SC.sym == BECOMES: getSym() y = expression() if x.tp == y.tp in {Bool, Int}: x = CG.genAssign(x, y) else: mark('incompatible assignment') elif SC.sym == EQ: mark(':= expected') getSym() y = expression() else: mark(':= expected') elif type(x) in {Proc, StdProc}: fp, ap, i = x.par, [], 0 # list of formals, list of actuals if SC.sym == LPAREN: getSym() if SC.sym in FIRSTEXPRESSION: y = expression() if i < len(fp): if (type(fp[i]) == Var or type(y) == Var) and \ fp[i].tp == y.tp: if type(x) == Proc: ap.append(CG.genActualPara(y, fp[i], i)) else: mark('illegal parameter mode') else: mark('extra parameter') i = i + 1 while SC.sym == COMMA: getSym() y = expression() if i < len(fp): if (type(fp[i]) == Var or type(y) == Var) and \ fp[i].tp == y.tp: if type(x) == Proc: ap.append(CG.genActualPara(y, fp[i], i)) else: mark('illegal parameter mode') else: mark('extra parameter') i = i + 1 if SC.sym == RPAREN: getSym() else: mark("')' expected") if i < len(fp): mark('too few parameters') elif type(x) == StdProc: if x.name == 'read': x = CG.genRead(y) elif x.name == 'write': x = CG.genWrite(y) elif x.name == 'writeln': x = CG.genWriteln() else: x = CG.genCall(x, ap) else: mark("variable or procedure expected") elif SC.sym == BEGIN: x = compoundStatement() elif SC.sym == IF: getSym() x = expression() if x.tp == Bool: x = CG.genCond(x) else: mark('boolean expected') if SC.sym == THEN: getSym() else: mark("'then' expected") y = statement() if SC.sym == ELSE: if x.tp == Bool: y = CG.genThen(x, y) getSym() z = statement() if x.tp == Bool: x = CG.genIfElse(x, y, z) else: if x.tp == Bool: x = CG.genIfThen(x, y) elif SC.sym == WHILE: getSym() t = CG.genTarget() x = expression() if x.tp == Bool: x = CG.genCond(x) else: mark('boolean expected') if SC.sym == DO: getSym() else: mark("'do' expected") y = statement() if x.tp == Bool: x = CG.genWhile(t, x, y) else: x = None return x
def testRange(x): """Check if x is suitable for immediate addressing""" if x.val >= 0x8000 or x.val < -0x8000: mark("value too large")
def selector(x): """ Parses selector = {"." ident | "[" expression "]"}. Assumes x is the entry for the identifier in front of the selector; generates code for the selector if no error is reported """ while SC.sym in {PERIOD, LBRAK}: if SC.sym == PERIOD: # x.f getSym() if SC.sym == IDENT: if type(x.tp) == Record: for f in x.tp.fields: if f.name == SC.val: x = genSelect(x, f) break else: mark("not a field") getSym() else: mark("not a record") else: mark("identifier expected") else: # x[y] getSym() y = expression() if type(x.tp) == Array: if y.tp == Int: if type(y) == Const and (y.val < x.tp.lower or y.val >= x.tp.lower + x.tp.length): mark("index out of bounds") else: x = genIndex(x, y) else: mark("index not integer") else: mark("not an array") if SC.sym == RBRAK: getSym() else: mark("] expected") return x
def obtainReg(): if len(regs) == 0: mark("out of registers") return R0 else: return regs.pop()
def newObj(name, entry): top, entry.lev, entry.name = symTab[0], len(symTab) - 1, name for e in top: if e.name == name: mark("multiple definition"); return top.append(entry)