def _match(f, c): global _nchar _skip_white(f) if _nchar == c: _nchar = f.read(1).decode("utf-8") else: error._expected(c)
def _a_expression(f): _a_term(f) op = scanner._get_operator(f) while op != "": if op not in scanner._add_ops: # Unget the op chars and reset scanner._nchar f.seek(-len(op) - 1, 1) scanner._nchar = f.read(1).decode("utf-8") # Break out of the loop - not our operator break # TODO Handle unary ++ and -- codegen._push_primary() _a_term(f) codegen._pop_secondary() # Flip order of primary and secondary for - b/c second argument is # the one in primary. + is commutative so it doesn't matter for that # case regs = (codegen.PRIMARY, codegen.SECONDARY, codegen.PRIMARY) if op == '+': codegen._add(*regs) elif op == '-': codegen._sub(*regs) else: error._expected('+ or -') op = scanner._get_operator(f)
def _get_name(f): global _nchar _skip_white(f) if _nchar == '': return '' if not _is_valid_identifier_start(_nchar): # Eventually calls sys.exit() error._expected(("Identifier beginning [alpha or _], got {} on " + "line {}").format(_nchar, _line)) id = "" while _is_valid_identifier(_nchar): id += _nchar _nchar = f.read(1).decode("utf-8") return id
def _get_num(f): """Returns the next number as a str """ global _nchar _skip_white(f) if _nchar == '': return '' if not _is_num(_nchar): # Eventually calls sys.exit() error._expected("Number") n = "" while _is_num(_nchar): n += _nchar _nchar = f.read(1).decode("utf-8") return n
def _block(f): _symtab.append({}) scanner._skip_white(f) local_allocations = 0 dealloc = True while scanner._nchar != '}': if scanner._is_valid_identifier_start(scanner._nchar): identifier = scanner._get_name(f) if identifier == 'if': _if(f) elif identifier == 'while': _while(f) elif identifier == 'var': local_allocations += 1 _local_var(f) elif identifier == 'break': pass elif identifier == 'return': dealloc = False # Dealloc local vars - special case because the code will exit # the block before the "end" codegen._dealloc_stack(local_allocations * codegen.WORD // codegen.BYTE) _return(f) else: # Either an assignment or a function call # Look in symbol table to tell which is which entry = _lookup(identifier) if entry is not None: if entry['type'] == 'local_var' or entry['type'] == \ 'global_var': _assignment(f, entry) elif entry['type'] == 'function': _function_call(f, entry) else: error._error("Undeclared identifier: " + str(identifier)) elif scanner._nchar == '@': scanner._match(f, '@') _p_assignment(f) else: error._expected("Identifier or '@', got {}".format(scanner._nchar)) scanner._skip_white(f) if dealloc: # Dealloc local vars to get back to return address codegen._dealloc_stack(local_allocations * codegen.WORD // codegen.BYTE) _symtab.pop()
def _term(f): _factor(f) op = scanner._get_operator(f) while op != "": if op not in scanner._and_ops: # Unget the op chars and reset scanner._nchar f.seek(-len(op) - 1, 1) scanner._nchar = f.read(1).decode("utf-8") # Break out of the loop - not our operator break codegen._push_primary() _factor(f) codegen._pop_secondary() regs = (codegen.PRIMARY, codegen.PRIMARY, codegen.SECONDARY) if op == '&': codegen._bitwise_and(*regs) elif op == '&&': codegen._logical_and(*regs) else: error._expected('& or &&') op = scanner._get_operator(f)
def _a_term(f): _a_factor(f) op = scanner._get_operator(f) while op != "": if op not in scanner._mul_ops: # Unget the op chars and reset scanner._nchar f.seek(-len(op) - 1, 1) scanner._nchar = f.read(1).decode("utf-8") # Break out of the loop - not our operator break codegen._push_primary() _a_factor(f) codegen._pop_secondary() # Flip order for / for same reason as -. * is comm so doesn't matter regs = (codegen.PRIMARY, codegen.SECONDARY, codegen.PRIMARY) if op == '*': codegen._mul(*regs) elif op == '/': codegen._div(*regs) else: error._expected('* or /') op = scanner._get_operator(f)
def _expression(f): _term(f) op = scanner._get_operator(f) while op != "": if op not in scanner._or_ops: # Unget the op chars and reset scanner._nchar f.seek(-len(op) - 1, 1) scanner._nchar = f.read(1).decode("utf-8") # Break out of the loop - not our operator break codegen._push_primary() _term(f) codegen._pop_secondary() # Both branches use the same arguments regs = (codegen.PRIMARY, codegen.PRIMARY, codegen.SECONDARY) if op == '|': # Unpack the regs tuple as args codegen._bitwise_or(*regs) elif op == '||': codegen._logical_or(*regs) else: error._expected('| or ||') op = scanner._get_operator(f)