コード例 #1
0
ファイル: asmgrammar.py プロジェクト: tapichu/asm2d
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
コード例 #2
0
ファイル: asmsemantic.py プロジェクト: tapichu/asm2d
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()
コード例 #3
0
ファイル: asmgrammar.py プロジェクト: tapichu/asm2d
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
コード例 #4
0
ファイル: asmsemantic.py プロジェクト: tapichu/asm2d
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)
コード例 #5
0
ファイル: asmgrammar.py プロジェクト: tapichu/asm2d
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)
コード例 #6
0
ファイル: asmgrammar.py プロジェクト: tapichu/asm2d
def p_error(t):
    value = t.value if t.value != '\n' else 'NEWLINE'
    error("Syntax error near token {0}", value, lineno=t.lineno)
コード例 #7
0
ファイル: asmgrammar.py プロジェクト: tapichu/asm2d
def p_element_instruction_error(p):
    'element : error'
    error("Syntax error in instruction", lineno=p.lineno(1), errors=p.parser.errors)
コード例 #8
0
ファイル: asmgrammar.py プロジェクト: tapichu/asm2d
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)
コード例 #9
0
ファイル: asmgrammar.py プロジェクト: tapichu/asm2d
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)
コード例 #10
0
ファイル: asmtokens.py プロジェクト: tapichu/asm2d
def t_error(t):
    error("Illegal character '{0}'", t.value[0], errors=t.lexer.errors, lineno=t.lexer.lineno)
    t.lexer.skip(1)
コード例 #11
0
ファイル: asmsemantic.py プロジェクト: tapichu/asm2d
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)