Esempio n. 1
0
def p_element_instruction_label(p):
    'element : IDENTIFIER instruction'
    name, size, lineno = p[1], p[2][1], p.lineno(1)
    if name in p.parser.inst_table:
        error("Duplicate label definition: {0}", name, lineno=lineno, errors=p.parser.errors)
    p[0] = Inst(p[1], p[2], p[2][1], p.lineno(1))
    p.parser.inst_table[name] = p[0]
    p.parser.inst_table[SIZE] += size
Esempio n. 2
0
def analyse(ast, const_table, data_table, inst_table, errors):
    "Semantic analysis for the AST."

    if MAIN not in inst_table:
        error("Main entry point not defined", errors=errors)

    first_pass(ast, const_table, data_table, inst_table, errors)
    second_pass(ast, data_table, inst_table, errors)

    errors.report_errors()
Esempio n. 3
0
def p_element_declaration_variable(p):
    'element : IDENTIFIER RMB NUM'
    name, size, lineno = p[1], p[3], p.lineno(1)
    if name in p.parser.data_table:
        error("Duplicate name definition {0}", name, lineno=lineno, errors=p.parser.errors)
    if size <= 0:
        error("Error in variable declaration {0}: the number of bytes must be greater than zero",
                name, lineno=lineno, errors=p.parser.errors)
    p[0] = Var(p[1], p[3], lineno)
    p.parser.data_table[name] = p[0]
    p.parser.data_table[SIZE] += size
Esempio n. 4
0
def second_pass(ast, data_table, inst_table, errors):
    """The second pass handles unsigned values (color registers, fps) and checks
    that immediate values are of the correct size (one or two bytes).
    """
    for elem in ast:
        if isinstance(elem, Inst):
            if len(elem.inst) == 4:
                name, size, inst_type, value = elem.inst
                if name in INST_UNSIGNED:
                    if value < 0 or value > 255:
                        error("Value out of range {0} (instruction {1})",
                                value, name, lineno=elem.lineno, errors=errors)
                    else:
                        elem.inst = (name, size, inst_type, value)
                elif inst_type == 'imm' and name != 'DRSYM':
                    if size == 2:
                        if value < -128 or value > 127:
                            error("Value out of range {0} (instruction {1})",
                                    value, name, lineno=elem.lineno, errors=errors)
                    elif size == 3:
                        if value < -32768 or value > 32767:
                            error("Value out of range {0} (instruction {1})",
                                    value, name, lineno=elem.lineno, errors=errors)
            elif len(elem.inst) == 5:
                name, _, inst_type, offset, _ = elem.inst
                if inst_type == 'ind':
                    if offset < -128 or offset > 127:
                        error("Value out of range {0} (instruction {1})",
                                offset, name, lineno=elem.lineno, errors=errors)
Esempio n. 5
0
def eval_expr(ast, p, lineno):
    "Returns the value obtained by evaluating an expression."
    expr_type = ast[0]
    if expr_type == 'num':
        return ast[1]
    elif expr_type == 'const':
        name = ast[1]
        if name not in p.parser.const_table:
            error("Undefined constant {0}", name, lineno=lineno, errors=p.parser.errors)
            raise SyntaxError
        p.parser.const_table[name].used = True
        return p.parser.const_table[name].value
    elif expr_type == '+':
        return eval_expr(ast[1], p, lineno) + eval_expr(ast[2], p, lineno)
    elif expr_type == '-':
        return eval_expr(ast[1], p, lineno) - eval_expr(ast[2], p, lineno)
    elif expr_type == '*':
        return eval_expr(ast[1], p, lineno) * eval_expr(ast[2], p, lineno)
    elif expr_type == '/':
        return eval_expr(ast[1], p, lineno) / eval_expr(ast[2], p, lineno)
Esempio n. 6
0
def p_error(t):
    value = t.value if t.value != '\n' else 'NEWLINE'
    error("Syntax error near token {0}", value, lineno=t.lineno)
Esempio n. 7
0
def p_element_instruction_error(p):
    'element : error'
    error("Syntax error in instruction", lineno=p.lineno(1), errors=p.parser.errors)
Esempio n. 8
0
def p_element_instruction_label_error(p):
    'element : IDENTIFIER error'
    error("Syntax error in instruction at label {0}", p[1], lineno=p.lineno(1), errors=p.parser.errors)
Esempio n. 9
0
def p_element_declaration_error(p):
    'element : IDENTIFIER error expr'
    error("Syntax error in declaration {0}", p[1], lineno=p.lineno(1), errors=p.parser.errors)
Esempio n. 10
0
def t_error(t):
    error("Illegal character '{0}'", t.value[0], errors=t.lexer.errors, lineno=t.lexer.lineno)
    t.lexer.skip(1)
Esempio n. 11
0
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)