def p_element_declaration_constant(p): 'element : IDENTIFIER EQU expr' name, lineno = p[1], p.lineno(1) if name in p.parser.const_table: warn("Overriding already defined constant {0}", name, lineno=lineno) try: p.parser.const_table[name] = Const(name, eval_expr(p[3], p, lineno), lineno) except SyntaxError: pass pass
def first_pass(ast, const_table, data_table, inst_table, errors): """The first pass assigns an address to variables (data segment) and labels, and checks for undefined references. It also warns about constants, variables and labels that are not used, and about mismatches between variable size and instruction size. """ data_offset = inst_table[SIZE] code_offset = 0 main_lineno = 0 for elem in ast: if isinstance(elem, Var): data_table[elem.id].addr = data_offset data_offset += elem.size if isinstance(elem, Inst): if elem.label != '': if elem.label == MAIN: main_lineno = elem.lineno inst_table[elem.label].addr = code_offset code_offset += elem.size if len(elem.inst) == 3: _, _, label = elem.inst if label not in inst_table: error("Undefined label {}", label, lineno=elem.lineno, errors=errors) else: inst_table[label].used = True elif len(elem.inst) == 4: name, size, inst_type, value = elem.inst if inst_type == 'var': if value not in data_table: error("Undefined variable {}", value, lineno=elem.lineno, errors=errors) else: data_table[value].used = True elem.inst = (name, size, 'ext', data_table[value].addr) var_size = data_table[value].size inst_size = 1 if name in INST_ONE_BYTE else 2 if inst_size != var_size: warn("Size mismatch: instruction {0} expects {1:d} byte{2}, variable {3} has {4:d} byte{5}", name, inst_size, 's' if inst_size > 1 else '', value, var_size, 's' if var_size > 1 else '', lineno=elem.lineno) elif len(elem.inst) == 5: _, _, inst_type, _, label = elem.inst if inst_type == 'imm-rel': if label not in inst_table: error("Undefined label {}", label, lineno=elem.lineno, errors=errors) else: inst_table[label].used = True # Warnings for unused constants, variables and labels for const in [k for k in const_table if const_table[k].used == False]: warn("Unused constant {}", const, lineno=const_table[const].lineno) for var in [k for k in data_table if k != SIZE and data_table[k].used == False]: warn("Unused variable {}", var, lineno=data_table[var].lineno) for label in [k for k in inst_table if k != SIZE and inst_table[k].used == False]: warn("Unused label {}", label, lineno=inst_table[label].lineno) if MAIN in inst_table and inst_table[MAIN].addr != MAIN_ADDR: error("Main label should be the first instruction",lineno=main_lineno, errors=errors)