|
| 1 | +from syntree import * |
| 2 | +from symtable import * |
| 3 | + |
| 4 | +def build_symtable(ast): |
| 5 | + if not isinstance(ast, Function) or ast.name != 'main' or ast.deco['type'] != Type.VOID or len(ast.args)>0: |
| 6 | + raise Exception('Cannot find a valid entry point') |
| 7 | + symtable = SymbolTable() |
| 8 | + process_scope(ast, symtable) |
| 9 | + |
| 10 | +def process_scope(fun, symtable): |
| 11 | + fun.deco['nonlocal'] = set() # set of nonlocal variable names in the function body, used in "readable" python transpilation only |
| 12 | + symtable.push_scope(fun.deco) |
| 13 | + for v in fun.args: # process function arguments |
| 14 | + symtable.add_var(*v) |
| 15 | + for v in fun.var: # process local variables |
| 16 | + symtable.add_var(*v) |
| 17 | + for f in fun.fun: # then process nested function bodies |
| 18 | + process_scope(f, symtable) |
| 19 | + for s in fun.body: # process the list of statements |
| 20 | + process_stat(s, symtable) |
| 21 | + symtable.pop_scope() |
| 22 | + |
| 23 | +def process_stat(n, symtable): # process "statement" syntax tree nodes |
| 24 | + if isinstance(n, Print): |
| 25 | + process_expr(n.expr, symtable) |
| 26 | + elif isinstance(n, Return): |
| 27 | + if n.expr is None: return |
| 28 | + process_expr(n.expr, symtable) |
| 29 | + elif isinstance(n, Assign): |
| 30 | + process_expr(n.expr, symtable) |
| 31 | + deco = symtable.find_var(n.name) |
| 32 | + update_nonlocals(n.name, symtable) # used in "readable" python transpilation only |
| 33 | + elif isinstance(n, FunCall): # no type checking is necessary |
| 34 | + process_expr(n, symtable) |
| 35 | + elif isinstance(n, While): |
| 36 | + process_expr(n.expr, symtable) |
| 37 | + for s in n.body: |
| 38 | + process_stat(s, symtable) |
| 39 | + elif isinstance(n, IfThenElse): |
| 40 | + process_expr(n.expr, symtable) |
| 41 | + for s in n.ibody + n.ebody: |
| 42 | + process_stat(s, symtable) |
| 43 | + else: |
| 44 | + raise Exception('Unknown statement type') |
| 45 | + |
| 46 | +def process_expr(n, symtable): # process "expression" syntax tree nodes |
| 47 | + if isinstance(n, ArithOp): |
| 48 | + process_expr(n.left, symtable) |
| 49 | + process_expr(n.right, symtable) |
| 50 | + elif isinstance(n, LogicOp): |
| 51 | + process_expr(n.left, symtable) |
| 52 | + process_expr(n.right, symtable) |
| 53 | + elif isinstance(n, Integer): |
| 54 | + n.deco['type'] = Type.INT |
| 55 | + elif isinstance(n, Boolean): |
| 56 | + n.deco['type'] = Type.BOOL |
| 57 | + elif isinstance(n, Var): |
| 58 | + deco = symtable.find_var(n.name) |
| 59 | + update_nonlocals(n.name, symtable) # used in "readable" python transpilation only |
| 60 | + elif isinstance(n, FunCall): |
| 61 | + for s in n.args: |
| 62 | + process_expr(s, symtable) |
| 63 | + elif isinstance(n, String): |
| 64 | + pass |
| 65 | + else: |
| 66 | + raise Exception('Unknown expression type', n) |
| 67 | + |
| 68 | +def update_nonlocals(var, symtable): # add the variable name to the set of nonlocals |
| 69 | + for i in reversed(range(len(symtable.variables))): # for all the enclosing scopes until we find the instance |
| 70 | + if var in symtable.variables[i]: break # used in "readable" python transpilation only |
| 71 | + symtable.ret_stack[i]['nonlocal'].add(var) |
0 commit comments