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 # attribute symbols_of = {TIMES: ' * ', DIV: ' div ', MOD: ' mod ', AND: ' and '} write(symbols_of[op]) writeHtml(symbols_of[op]) # getSym() if op == AND and type(x) != Const: x = CG.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 = CG.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 = CG.genBinaryOp(AND, x, y) else: mark('bad type') return x
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 # attribute symbols_of = { EQ: ' = ', NE: '<>', LT: ' < ', LE: ' <= ', GT: ' > ', GE: ' >= ' } write(symbols_of[op]) writeHtml(symbols_of[op]) # 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 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 term(): """ Parses term = factor {("*" «write(' * ')» | "div" «write(' div ')» | "mod" «write(' mod ')» | "and" «write(' 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: write(' and ') x = CG.genUnaryOp(AND, x) if op == TIMES: write(' * ') elif op == DIV: write(' div ') elif op == MOD: write(' mod ') 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 = CG.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 = CG.genBinaryOp(AND, x, y) else: mark('bad type') return x
def statementSuite(): if SC.sym in FIRSTSTATEMENT: x = statementList() elif SC.sym == INDENT: getSym(); x = statementBlock() if SC.sym == DEDENT: getSym(); else: mark('dedent or new line expected') else: mark("indented statement expected") return x
def expression(): 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 = CG.genRelation(op, x, y) else: mark('bad type') return x
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 typedIds(kind, l): """ Parses typedIds(l) = ident «write(ident)» {"," «write(', ')» ident «write(ident)»} ":" «write(': ')» type(l). 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: write(SC.val) tid = [SC.val] getSym() else: mark("identifier expected") tid = [] while SC.sym == COMMA: write(', ') getSym() if SC.sym == IDENT: write(SC.val) tid.append(SC.val) getSym() else: mark('identifier expected') if SC.sym == COLON: write(': ') getSym() tp = typ(l).tp if tp != None: for i in tid: newObj(i, kind(tp)) else: mark("':' expected")
def simpleExpression(): if SC.sym == PLUS: getSym() x = term() elif SC.sym == BAR: 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 = CG.genUnaryOp(MINUS, x) else: x = term() while SC.sym in {PLUS, MINUS, OR, BAR}: op = SC.sym getSym() if op == OR and type(x) != Const: x = CG.genUnaryOp(OR, x) y = term() # x op y if x.tp == Int == y.tp and op in {PLUS, MINUS, BAR}: 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 elif op == BAR: 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 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 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 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 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', 16) 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([], [Var(Int)])) newDecl('write', StdProc([Var(Int)], [])) newDecl('writeln', StdProc([], [])) CG.genProgStart() declarations(CG.genGlobalVars) if SC.sym == PROGRAM: getSym() else: mark("'program' expected") ident = SC.val if SC.sym == IDENT: getSym() else: mark('program name expected') openScope(); CG.genProgEntry(ident); x = body(ident, 0) closeScope(); x = CG.genProgExit(x) 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: if type(x) == Const and op == TIMES: # fold 1 * y if x.val == 1: x = y else: # swap x and y for immediate addressing # e.g., 3 * x becomes x * 3 x = genBinaryOp(op, y, x) # fold x*1, x/1 elif type(y) == Const and op in {TIMES, DIV} and y.val == 1: pass 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', 13) return x
def term(): x = factor() while SC.sym in {TIMES, DIV, MOD, INTERSECTION, AND}: op = SC.sym; getSym(); if op == AND and type(x) != Const: x = CG.genUnaryOp(AND, x) y = factor() # x op y if op in {TIMES, DIV, MOD} and x.tp == Int == y.tp: 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 = CG.genBinaryOp(op, x, y) elif op == INTERSECTION and type(x.tp) == Set == type(y.tp): x = CG.genBinaryOp(op, x, y) elif op == AND and x.tp == Bool == y.tp: if type(x) == Const: # constant folding if x.val: x = y # if x is true, take y, else x else: x = CG.genBinaryOp(AND, x, y) else: mark('bad type') return x
def term(): x = factor() while SC.sym in {TIMES, DIV, MOD, AND, AMP}: op = SC.sym getSym() if op == AND and type(x) != Const: x = CG.genUnaryOp(AND, x) y = factor() # x op y if x.tp == Int == y.tp and op in {TIMES, DIV, MOD, AMP}: 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 elif op == AMP: x.val = x.val & y.val else: x = CG.genBinaryOp(op, x, y) if x.tp != Int or y.tp != Int and op == AMP: mark('not integer') 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 = CG.genBinaryOp(AND, x, y) else: mark('bad type') 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') getSym() else: mark("'begin' expected") x = statement(l + 1) while SC.sym == SEMICOLON or SC.sym in FIRSTSTATEMENT: if SC.sym == SEMICOLON: write(';') getSym() else: mark("; missing") y = statement(l + 1) x = CG.genSeq(x, y) if SC.sym == END: writeln() write(l * indent + 'end') getSym() else: mark("'end' 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: 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 program(): """ Parses program = "program" ident ";" declarations compoundStatement. Generates code if no error is reported """ newObj('boolean', Type(Bool)) Bool.size = 8 # 64 bit sizes newObj('integer', Type(Int)) Int.size = 8 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", 64) ident = SC.val if SC.sym == IDENT: getSym() else: mark('program name expected', 65) if SC.sym == SEMICOLON: getSym() else: mark('; expected', 66) declarations(genGlobalVars) progEntry(ident) x = compoundStatement() return progExit(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 simpleExpression(): 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 = CG.genUnaryOp(MINUS, x) else: x = term() while SC.sym in {PLUS, MINUS, UNION, OR}: op = SC.sym; getSym() if op == OR and type(x) != Const: x = CG.genUnaryOp(OR, x) y = term() # x op y if op in {PLUS, MINUS} and x.tp == Int == y.tp: 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 op == UNION and type(x.tp) == Set == type(y.tp): x = CG.genBinaryOp(UNION, x, y) elif op == OR and x.tp == Bool == y.tp: 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: print(x, y); mark('bad type') return x
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 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 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 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 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 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') if SC.sym == COLON: getSym(); tp = typ().tp for i in tid: newObj(i, kind(tp)) else: mark("':' expected")
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 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', 14) 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: if type(x) == Const: #fold 0 + y, 0 - y if x.val == 0: x = y # change const + y to x + const elif op == PLUS: x = genBinaryOp(op, y, x) elif type(y) == Const and y.val == 0: #fold x + 0, x - 0 pass 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', 15) 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 """ 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 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: #isinstance(x.tp, Record):# for f in x.tp.fields: if f.name == SC.val: x = genSelect(x, f) break else: mark("not a field", 1) getSym() else: mark("not a record", 2) else: mark("identifier expected", 3) else: # x[y] getSym() y = expression() if type(x.tp) == Array: #isinstance(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', 4) else: x = genIndex(x, y) else: mark('index not integer', 5) else: mark('not an array', 6) if SC.sym == RBRAK: getSym() else: mark("] expected", 7) return x
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 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 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(): """ 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 simpleExpression(): """ Parses simpleExpression = ["+" | "-"] term {("+" | "-" | "or") term}. Generates code for the simpleExpression if no error is reported """ if SC.sym == PLUS: # attribute write(' + ') writeHtml(' + ') # getSym() x = term() elif SC.sym == MINUS: # attribute write(' - ') writeHtml(' - ') # 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() symbols_of = {5: ' + ', 6: ' - ', 7: ' or '} write(symbols_of[op]) writeHtml(symbols_of[op]) if op == OR and type(x) != Const: x = CG.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 = 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 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 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
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: mark('invalid statement'); x = None
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 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
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