Ejemplo n.º 1
0
def _program(f):
    name = scanner._get_name(f)
    while name == 'var':
        _global_var(f)
        name = scanner._get_name(f)
    # After parsing all the global variable declarations we want to jump to
    # main
    codegen._load_primary_address_relative(MAIN_LABEL)
    codegen._br(codegen.PRIMARY)
    while name == 'function':
        _function(f)
        name = scanner._get_name(f)
Ejemplo n.º 2
0
def _function(f):
    global _local_offset
    identifier = scanner._get_name(f)
    scanner._skip_white(f)
    if identifier in _symtab[0]:
        # Eventually calls sys.exit()
        error._error("Duplicate symbol function: " + str(identifier))
    _symtab[0][identifier] = {'type': 'function'}
    scanner._match(f, '(')
    # Offset from base pointer for the local variables, leave one space for
    # pointer to the parent's bp
    offset = (codegen.WORD // codegen.BYTE)
    # Set local offset to track location of local variables.
    _local_offset = _init_local_offset
    local_symbols = {}
    while scanner._is_valid_identifier_start(scanner._nchar):
        id = scanner._get_name(f)
        if id in local_symbols:
            error._error("Duplicate parameter: " + str(id))
        local_symbols[id] = {'type': 'local_var', 'offset': offset, 'base':
                             codegen.BASE}
        scanner._skip_white(f)
        if scanner._nchar == ',':
            scanner._match(f, ',')
            scanner._skip_white(f)
        else:
            # No more parameters to read
            break
        offset += codegen.WORD // codegen.BYTE
    _symtab[0][identifier]['num_param'] = len(local_symbols)
    # Add our local symbols so that descendant blocks can see them
    _symtab.append(local_symbols)
    scanner._match(f, ')')
    scanner._match(f, '{')
    if identifier == MAIN:
        label = MAIN_LABEL
    else:
        label = "{}_{}{}".format(FUNCTION_PREFIX, identifier, _next_label())
    _symtab[0][identifier]['offset'] = label
    _symtab[0][identifier]['base'] = codegen.ZERO
    codegen._post_label(label)
    # Function assembly body starts here
    # Save return address
    codegen._push_ret()
    _block(f)
    scanner._match(f, '}')
    # Remove our local symbol table
    _symtab.pop()
Ejemplo n.º 3
0
def _local_var(f):
    global _local_offset
    _local_offset -= (codegen.WORD // codegen.BYTE)
    identifier = scanner._get_name(f)
    if identifier in _symtab[-1]:
        error._error("Repeat local identifier: " + str(identifier))
    _symtab[-1][identifier] = {'type': 'local_var', 'offset': _local_offset,
                               'base': codegen.BASE}
    # Allocate space for var on stack
    codegen._alloc_stack(codegen.WORD // codegen.BYTE)
    scanner._skip_white(f)
    if scanner._nchar == '=':
        scanner._match(f, '=')
        _expression(f)
        entry = _symtab[-1][identifier]
        codegen._store_primary(entry['offset'], entry['base'])
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
def _global_var(f):
    global _symtab, _keywords
    identifier = scanner._get_name(f)
    scanner._skip_white(f)
    if identifier in _symtab[0]:
        # Eventually calls sys.exit()
        error._error("Duplicate symbol variable: " + str(identifier))
    if identifier in _keywords:
        error._error("Variable shadows keyword: " + str(identifier))
    label = GLOBAL_PREFIX + str(_next_label())
    codegen._alloc_global(label)
    _symtab[0][identifier] = {'type': 'global_var', 'offset': label, 'base':
                              codegen.ZERO}
    if scanner._nchar == '=':
        # This variable is initialized
        scanner._match(f, '=')
        scanner._skip_white(f)
        _expression(f)
        codegen._store_primary_abs(label)
Ejemplo n.º 6
0
def _a_factor(f):
    op = scanner._get_operator(f)
    if op in scanner._add_ops:
        _a_factor(f)
        if op == '-':
            # Negate the primary reg, if + we don't have to do anything
            codegen._neg(codegen.PRIMARY, codegen.PRIMARY)
    elif op == '':
        if scanner._nchar == '(':
            scanner._match(f, '(')
            _expression(f)
            scanner._match(f, ')')
        elif scanner._is_valid_identifier_start(scanner._nchar):
            id = scanner._get_name(f)
            entry = _lookup(id)
            if entry is None:
                error._error("Undeclared identifier: " + str(id))
            if entry['type'] == 'global_var' or entry['type'] == 'local_var':
                codegen._load_primary(entry['offset'], entry['base'])
            elif entry['type'] == 'function':
                _function_call(f, entry)
                # Move return value to primary
                codegen._load_primary_address(codegen.RETURN_VAL, 0)
            else:
                error._error("Unknown type of entry: {}".format(str(entry)))
        elif scanner._is_num(scanner._nchar):
            n = scanner._get_num(f)
            codegen._load_primary_address_relative(n)
        elif scanner._nchar == '@':
            scanner._match(f, '@')
            scanner._match(f, '(')
            _expression(f)
            scanner._match(f, ')')
            codegen._load_primary(0, codegen.PRIMARY)
    else:
        # Unget the op chars and reset scanner._nchar
        f.seek(-len(op), 1)
        scanner._nchar = f.read(1).decode("utf-8")