Пример #1
0
def _return(f):
    scanner._skip_white(f)
    if scanner._nchar == '(':
        scanner._match(f, '(')
        _expression(f)
        # Copy value over to return value register
        codegen._load_address(codegen.RETURN_VAL, codegen.PRIMARY, 0)
        scanner._match(f, ')')
    # Pop the return address into the BRANCH_TARGET register and return to it
    codegen._pop(codegen.BRANCH_TARGET)
    codegen._br_def()
Пример #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()
Пример #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'])
Пример #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()
Пример #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)
Пример #6
0
def _if(f):
    scanner._match(f, '(')
    _expression(f)
    scanner._match(f, ')')
    scanner._match(f, '{')
    label = LABEL_PREFIX + str(_next_label())
    codegen._load_branch_address_relative(label)
    codegen._brzr_def()
    _block(f)
    codegen._post_label(label)
    scanner._match(f, '}')
    scanner._skip_white(f)
Пример #7
0
def _function_call(f, entry):
    num_param = entry['num_param']
    codegen._alloc_stack(num_param * codegen.WORD // codegen.BYTE)
    offset = codegen.WORD // codegen.BYTE
    scanner._match(f, '(')
    for i in range(num_param):
        _expression(f)
        codegen._store_primary(offset, codegen.STACK)
        offset += codegen.WORD // codegen.BYTE
        scanner._skip_white(f)
        if scanner._nchar == ',':
            scanner._match(f, ',')
        else:
            break
    scanner._match(f, ')')
    codegen._push(codegen.BASE)
    # Base pointer points to the thing that was just pushed (address of old
    # bp) and we need to offset b/c STACK points off end of stack
    codegen._load_address(codegen.BASE, codegen.STACK, codegen.WORD //
                          codegen.BYTE)
    codegen._load_branch_address_relative(entry['offset'])
    codegen._brl_def()
    # Clean up the stack: restore rb and remove the args we pushed
    codegen._pop(codegen.BASE)
    codegen._dealloc_stack(num_param * codegen.WORD // codegen.BYTE)
Пример #8
0
def _while(f):
    label_loop, label_exit = LABEL_PREFIX + str(_next_label()), \
                             LABEL_PREFIX + str(_next_label())
    codegen._post_label(label_loop)
    scanner._match(f, '(')
    _expression(f)
    scanner._match(f, ')')
    scanner._match(f, '{')
    codegen._load_branch_address_relative(label_exit)
    codegen._brzr_def()
    _block(f)
    codegen._load_branch_address_relative(label_loop)
    codegen._br_def()
    scanner._match(f, '}')
Пример #9
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")
Пример #10
0
def _p_assignment(f):
    scanner._match(f, '(')
    _expression(f)
    scanner._match(f, ')')
    codegen._push_primary()
    scanner._match(f, '=')
    _expression(f)
    codegen._pop_secondary()
    codegen._store_primary(0, codegen.SECONDARY)
Пример #11
0
def _assignment(f, entry):
    scanner._match(f, '=')
    _expression(f)
    codegen._store_primary(entry['offset'], entry['base'])