Exemple #1
0
def _token_from_name(token_string:str, table:SymbolTable, line_number:int=None) -> Token:
    """Returns the correct token from the name
    """
    if table.is_keyword(token_string):
        token_id = "keyword"
    elif table.is_operator(token_string):
        token_id = "operator"
    elif table.is_constant(token_string):
        token_id = "constant"
    elif token_string[0].lower() == "r":
        token_id = "identifier"
    else:
        token_id = "label"
    return Token(token_id, token_string, line_number=line_number)
Exemple #2
0
    def __init__(self, tokenizer):
        """
        Creates a new compilation engine with the given tokenizer.
        """
        if not tokenizer or not tokenizer.filename:
            raise TypeError('Tokenizer not valid.')

        filename = re.sub('.jack$', '.vm', tokenizer.filename)

        self.tokenizer = tokenizer
        self.vm_writer = VMWriter(filename)
        self.symbol_table = SymbolTable(filename)
        self.classname = self.get_classname(filename)

        self.tokenizer.seperate_all()

        # Different keywords and operators partition to digest
        # the structure of program.
        self.class_var_dec = ['static', 'field']
        self.subroutines = ['constructor', 'function', 'method']
        self.statements = ['let', 'do', 'if', 'while', 'return']
        self.ops = ['+', '-', '*', '/', '&', '|', '<', '>', '=']
        self.unary_ops = ['~', '-']

        # Determines the current subroutine in use.
        self.current_fn_type = None
        self.current_fn_name = None

        self.if_idx = 0
        self.while_idx = 0

        self.verbal_arithemtic = {
            '>': 'GT',
            '<': 'LT',
            '=': 'EQ',
            '|': 'OR',
            '-': 'SUB',
            '+': 'ADD',
            '&': 'AND'
        }

        self.verbal_unary = {'~': 'NOT', '-': 'NEG'}
Exemple #3
0
    def __init__(self):
        il.Symbol.IDC = 0
        il.Type.IDC = 0
        self.fcount = 0
        self.tcount = 0
        self.bcount = 0

        self.blocks = dict()

        self.functions = dict()
        self.fstack = list()

        self.objs = SymbolTable()
Exemple #4
0
def test_pushpop():
    table = SymbolTable()
    t1 = Symbol("t1", Int(0, 1))
    t2_1 = Symbol("t2", Int(0, 2))
    t3 = Symbol("t3", Int(0, 3))
    t2_2 = Symbol("t2", Int(0, 4))
    t4_1 = Symbol("t4", FuncPointer(0, 5))
    t4_2 = Symbol("t4", FuncPointer(0, 6))
    t5 = Symbol("t5", FuncPointer(0, 7))
    table.add(t1)
    table.add(t2_1)
    assert table == {"t1": t1, "t2": t2_1}
    table = table.push()
    assert table == {"t1": t1, "t2": t2_1}
    table.update({"t3": t3, "t2": t2_2})
    assert table == {"t1": t1, "t3": t3, "t2": t2_2}
    table = table.push()
    assert table == {"t1": t1, "t3": t3, "t2": t2_2}
    table.update({"t4": t4_1})
    assert table == {"t1": t1, "t3": t3, "t2": t2_2, "t4": t4_1}
    table = table.push()
    assert table == {"t1": t1, "t3": t3, "t2": t2_2, "t4": t4_1}
    table.update({"t4": t4_2, "t5": t5})
    assert table == {"t1": t1, "t3": t3, "t2": t2_2, "t4": t4_2, "t5": t5}
    table = table.pop()
    assert table == {"t1": t1, "t3": t3, "t2": t2_2, "t4": t4_1}
    table = table.pop()
    assert table == {"t1": t1, "t3": t3, "t2": t2_2}
    table = table.pop()
    assert table == {"t1": t1, "t2": t2_1}
    assert_raises(Exception, table.pop)
Exemple #5
0
class CompilationEngine:
    """
    Recursive top-down compilation engine for the Jack langauge.
    Using a Tokenizer object, this module will process different
    Jack tokens and compile it to VM code using the VMWriter.
    While at it, invalid Jack syntax will raise SyntaxError.
    """
    def __init__(self, tokenizer):
        """
        Creates a new compilation engine with the given tokenizer.
        """
        if not tokenizer or not tokenizer.filename:
            raise TypeError('Tokenizer not valid.')

        filename = re.sub('.jack$', '.vm', tokenizer.filename)

        self.tokenizer = tokenizer
        self.vm_writer = VMWriter(filename)
        self.symbol_table = SymbolTable(filename)
        self.classname = self.get_classname(filename)

        self.tokenizer.seperate_all()

        # Different keywords and operators partition to digest
        # the structure of program.
        self.class_var_dec = ['static', 'field']
        self.subroutines = ['constructor', 'function', 'method']
        self.statements = ['let', 'do', 'if', 'while', 'return']
        self.ops = ['+', '-', '*', '/', '&', '|', '<', '>', '=']
        self.unary_ops = ['~', '-']

        # Determines the current subroutine in use.
        self.current_fn_type = None
        self.current_fn_name = None

        self.if_idx = 0
        self.while_idx = 0

        self.verbal_arithemtic = {
            '>': 'GT',
            '<': 'LT',
            '=': 'EQ',
            '|': 'OR',
            '-': 'SUB',
            '+': 'ADD',
            '&': 'AND'
        }

        self.verbal_unary = {'~': 'NOT', '-': 'NEG'}

    def compile_class(self):
        """
        Compiles a complete class.
        """
        if not self.tokenizer.has_more_tokens():
            raise SyntaxError('No tokens available to compile.')

        # Advance to the first token.
        self.tokenizer.advance()

        self.process('class')
        self.get_token()  # class name
        self.process('{')

        # Reached a variable declaration or a subroutine,
        # there might be more than one.
        while self.tokenizer.current_token in self.class_var_dec:
            self.compile_class_var_dec()

        # Keep on writing subroutines until end of class.
        while self.tokenizer.current_token in self.subroutines:
            self.compile_subroutine_dec()

        # Validates the closing bracket of a class.
        self.process('}')
        self.vm_writer.close()

    def compile_class_var_dec(self):
        """
        Compiles a static variable declaration, or a field declaration.
        """
        kind = self.get_token()
        type = self.get_token()

        # Iterate tokens until reaching a command break (';').
        while self.tokenizer.current_token != ';':
            name = self.get_token()
            self.symbol_table.define(name, type, kind)

            if self.tokenizer.current_token == ',':
                self.process()

        self.process(';')

    def compile_subroutine_dec(self):
        """
        Compiles a complete method, function, or constructor.
        """
        self.current_fn_type = self.get_token(
        )  # static function, method or constructor.
        self.current_fn_return = self.get_token()  # void or type.
        self.current_fn_name = self.get_token()  # name of the subroutine.

        # Reset symbol table for current scope.
        self.symbol_table.start_subroutine()

        if self.current_fn_type == 'method':
            # The type of 'this' is the class name (for exmaple, 'Point').
            self.symbol_table.define('this', self.classname, 'arg')

        # Parameters list, e.g, (int Ax, int Ay, int Asize)
        self.process('(')
        self.compile_parameter_list()
        self.process(')')

        # Subroutine body
        self.compile_subroutine_body()

    def compile_parameter_list(self):
        """
        Compiles a (possibly empty) parameter list.
        """
        while self.tokenizer.current_token != ')':
            type = self.get_token()
            name = self.get_token()
            self.symbol_table.define(name, type, 'arg')

            if self.tokenizer.current_token == ',':
                self.process()

    def compile_subroutine_body(self):
        """
        Compiles a subroutine's body.
        """
        self.process('{')

        # Before proceeding to the routine's statements,
        # check if there are any variable declarations.
        while self.tokenizer.current_token not in self.statements:
            self.compile_var_dec()

        # Ouput the subroutine's declaration VM code.
        subroutine_name = '{}.{}'.format(self.classname, self.current_fn_name)
        nlocals = self.symbol_table.var_count('var')
        self.vm_writer.write_function(subroutine_name, nlocals)

        # Constructors require allocating memory to object fields.
        if self.current_fn_type == 'constructor':
            nargs = self.symbol_table.var_count('field')
            self.vm_writer.write_push('constant', nargs)
            self.vm_writer.write_call('Memory.alloc', 1)
            self.vm_writer.write_pop('pointer', 0)

        # THIS = argument 0 for class methods.
        if self.current_fn_type == 'method':
            self.vm_writer.write_push('argument', 0)
            self.vm_writer.write_pop('pointer', 0)

        # The subroutine body contains statements. For example,
        # let x = Ax;   let statement
        # do draw();    do statement
        # return x;     return statement
        self.compile_statements()

        self.process('}')

    def compile_var_dec(self):
        """
        Compiles a var declaration.
        """
        kind = self.get_token()
        type = self.get_token()

        while self.tokenizer.current_token != ';':
            name = self.get_token()
            self.symbol_table.define(name, type, kind)
            if self.tokenizer.current_token == ',':
                self.process(',')

        self.process(';')

    def compile_statements(self):
        """
        Compiles a sequence of statements.
        """
        # Write statements until ending closing bracket of parent subroutine.
        while self.tokenizer.current_token != '}':
            # Explicitly validate statement
            statement = self.get_token()
            if statement not in self.statements:
                s = ', '.join(self.statements)
                raise SyntaxError('Statement should start with one of ' + s)

            # Compile full statement.
            method = getattr(self, 'compile_' + statement)
            method()

    def compile_let(self):
        """
        Compiles a let statement.
        """
        if self.tokenizer.current_type != 'IDENTIFIER':
            raise SyntaxError('Let statement must proceed with an identifier.')

        identifier = self.get_token()
        index = self.get_index(identifier)
        segment = self.get_kind(identifier)

        # Placement might be an array entring.
        if self.tokenizer.current_token == '[':
            self.compile_array_entry()

            self.vm_writer.write_push(segment, index)
            self.vm_writer.write_arithmetic('ADD')
            self.vm_writer.write_pop('TEMP', 0)

            self.process('=')
            self.compile_expression()

            self.vm_writer.write_push('TEMP', 0)
            self.vm_writer.write_pop('POINTER', 1)
            self.vm_writer.write_pop('THAT', 0)
        else:
            # Regular assignment.
            self.process('=')
            self.compile_expression()
            self.vm_writer.write_pop(segment, index)

        self.process(';')

    def compile_do(self):
        """
        Compiles a do statement.
        """
        self.compile_subroutine_invoke()
        self.vm_writer.write_pop('TEMP', 0)
        self.process(';')  # end of do statement.

    def compile_subroutine_invoke(self):
        """
        Compiles a subroutine invokation.
        """
        identifier = self.get_token()
        args_count = 0

        # Either a static (outer) class funciton or an instance function call.
        if self.tokenizer.current_token == '.':
            self.process('.')
            subroutine_name = self.get_token()

            inst_type = self.symbol_table.type_of(identifier)
            if inst_type:
                # It's an instance.
                inst_kind = self.get_kind(identifier)
                inst_indx = self.get_index(identifier)

                self.vm_writer.write_push(inst_kind, inst_indx)
                fn_name = '{}.{}'.format(inst_type, subroutine_name)

                args_count += 1  # Pass 'this' as an argument.
            else:  # Static function of a class.
                fn_name = '{}.{}'.format(identifier, subroutine_name)

        else:  # Local method call.
            fn_name = '{}.{}'.format(self.classname, identifier)
            args_count += 1  # Pass 'this' as an argument.
            self.vm_writer.write_push('POINTER', 0)

        self.process('(')
        args_count += self.compile_expression_list()
        self.process(')')
        self.vm_writer.write_call(fn_name, args_count)

    def compile_if(self):
        """
        Compiles an if statement, possibly with a trailing else clause.
        """
        self.process('(')
        self.compile_expression()  # E.g., x > 2
        self.vm_writer.write_arithmetic('NOT')
        self.process(')')  # End of if condition statement.

        # if statement body
        self.process('{')

        idx = self.if_idx
        self.if_idx += 1
        label_false = '{}.if_false.{}'.format(self.current_fn_name, idx)
        label_proceed = '{}.{}'.format(self.current_fn_name, idx)

        self.vm_writer.write_if(label_false)

        self.compile_statements()

        self.vm_writer.write_goto(label_proceed)
        self.process('}')

        # Lables statements.
        self.vm_writer.write_label(label_false)
        if self.tokenizer.current_token == 'else':
            # We have a proceeding else.
            self.process('else')
            self.process('{')
            self.compile_statements()
            self.process('}')

        self.vm_writer.write_label(label_proceed)

    def compile_while(self):
        """
        Compiles a while statement.
        """
        self.process('(')

        fn_name = self.current_fn_name
        idx = self.while_idx
        self.while_idx += 1

        while_start_label = '{}.while_start.{}'.format(fn_name, idx)
        while_end_label = '{}.while_end.{}'.format(fn_name, idx)

        self.vm_writer.write_label(while_start_label)
        self.compile_expression()
        self.vm_writer.write_arithmetic('NOT')
        self.process(')')

        # while's body.
        self.process('{')
        self.vm_writer.write_if(while_end_label)
        self.compile_statements()
        self.vm_writer.write_goto(while_start_label)
        self.vm_writer.write_label(while_end_label)
        self.process('}')  # We're done

    def compile_return(self):
        """
        Compiles a return statement.
        """
        if self.tokenizer.current_token != ';':
            self.compile_expression()
        else:  # Return VOID.
            self.vm_writer.write_push('CONSTANT', 0)

        self.vm_writer.write_return()
        self.process(';')

    def compile_expression(self):
        """
        Compiles an expression.
        """
        self.compile_term()

        while self.tokenizer.current_token in self.ops:
            op = self.get_token()
            self.compile_term()  # Push is done by compile_term

            # Explicitly use Math.multiply or Math.divide.
            if op == '*':
                self.vm_writer.write_call('Math.multiply', 2)
            elif op == '/':
                self.vm_writer.write_call('Math.divide', 2)
            else:
                name = self.verbal_arithemtic.get(op)
                self.vm_writer.write_arithmetic(name)

    def compile_term(self):
        """
        Compiles a term. If the current token is an identifier, the routine
        must resolve it into a variable, an array entry, or a subroutine
        call. A single lookahead token, which may be [, (, or ., suffices
        to distinguish between the possibilities. Any other token is not
        part of this term and should not be advanced over.
        """

        current_token = self.tokenizer.current_token
        token_type = self.get_current_type()

        if current_token == '(':
            self.process('(')
            self.compile_expression()
            self.process(')')
        elif self.tokenizer.peek() == '[':
            arr_identifier = self.get_token()
            self.compile_array_entry()

            index = self.get_index(arr_identifier)
            segment = self.get_kind(arr_identifier)
            self.vm_writer.write_push(segment, index)
            self.vm_writer.write_arithmetic('ADD')
            self.vm_writer.write_pop('POINTER', 1)
            self.vm_writer.write_push('THAT', 0)

        elif current_token in self.unary_ops:
            unary_op = self.get_token()
            self.compile_term()
            name = self.verbal_unary.get(unary_op)
            self.vm_writer.write_arithmetic(name)

        elif self.peek() in ['.', '(']:
            self.compile_subroutine_invoke()

        elif token_type == 'INT_CONST':
            self._compile_integer()
        elif token_type == 'STRING_CONST':
            self._compile_string()
        elif token_type == 'KEYWORD':
            self._compile_keyword()
        else:
            self._compile_identifier()

    def _compile_integer(self):
        """Compiles the current token as an integer."""
        token = self.get_token()
        self.vm_writer.write_push('CONSTANT', abs(token))
        if token < 0:
            self.vm_writer.write_arithmetic('NEG')

    def _compile_string(self):
        """Compiles the current token as a string."""
        current_token = self.tokenizer.current_token
        self.vm_writer.write_push('CONSTANT', len(current_token))
        self.vm_writer.write_call('String.new', 1)

        # String assignments are handled using a series of calls
        # to String.appendChar(c), when c is the integer representing
        # unicode code point.
        for c in current_token:
            self.vm_writer.write_push('CONSTANT', ord(c))
            self.vm_writer.write_call('String.appendChar', 2)

        self.process()  # Finished compiling string.

    def _compile_keyword(self):
        """Compiles the current token as a keyword."""
        current_token = self.get_token()
        if current_token == 'this':
            self.vm_writer.write_push('POINTER', 0)
            return

        if current_token == 'true':
            self.vm_writer.write_push('CONSTANT', 1)
            self.vm_writer.write_arithmetic('NEG')
            return

        # null or false.
        self.vm_writer.write_push('CONSTANT', 0)

    def _compile_identifier(self):
        """Compiles the current token as an identifier."""
        current_token = self.get_token()
        index = self.get_index(current_token)
        segment = self.get_kind(current_token)
        self.vm_writer.write_push(segment, index)

    def get_current_type(self):
        """Returns the type of the current token."""
        return self.tokenizer.current_type

    def compile_expression_list(self):
        """
        Compiles a (possibly empty) comma- separated list of expressions
        and returns the number of arguments in this expression list.
        """
        args_count = 0
        while self.tokenizer.current_token != ')':
            args_count += 1
            self.compile_expression()

            if self.tokenizer.current_token == ',':
                self.process(',')

        return args_count

    def process(self, string=None):
        """
        A helper routine that validates the current token,
        and advances to get the next token.
        """

        t = self.tokenizer.current_token
        if string and t != string:
            caller = inspect.stack()[1][3]
            msg = 'Invalid token rasied from {}. Got {} when expected: {}'.format(
                caller, string, t)
            raise SyntaxError(msg)

        if self.tokenizer.has_more_tokens():
            self.tokenizer.advance()

    def get_token(self):
        """
        Helper method to get the current token and advance
        to the next one.
        """
        token = self.tokenizer.current_token

        if self.tokenizer.has_more_tokens():
            self.tokenizer.advance()

        return token

    def peek(self):
        """Peeks into the toknes deque."""
        return self.tokenizer.peek()

    def compile_array_entry(self):
        """
        A helper routine to compile an array entry.
        """
        self.process('[')
        self.compile_expression()
        self.process(']')

    def is_int(self, input):
        try:
            input = int(input)
            return True
        except ValueError:
            return None

    def get_kind(self, name):
        """Returns the kind value of a symbol table value."""
        segment = self.symbol_table.kind_of(name)
        segment = segment.lower()
        if segment == 'field':
            return 'this'
        if segment == 'var':
            return 'local'
        if segment == 'arg':
            return 'argument'

        return segment

    def get_index(self, name):
        """Returns the index value of a symbol table value."""
        return self.symbol_table.index_of(name)

    def get_classname(self, filename):
        """Returns the clean class name."""
        return filename.split('/')[-1].split('.')[0]

    def close(self):
        """
        Closes the vm stream.
        """
        self.vm_writer.close()
Exemple #6
0
class generate(object):
    def __new__(cls, root, debug=False):
        self = super(generate, cls).__new__(cls)
        self.__init__()
        self.debug = debug

        self.push_func("main")
        self.cfunc.scope_depth = 1
        entry = self.block()
        blk = self.Stmts(root, entry)
        main = self.pop_func()
        main.entry = entry
        main.exit = blk

        if debug:
            print_blks(self.blocks.values())

            print "Functions:"

            for name, f in sorted(self.functions.iteritems(), key=lambda x: x[0]):
                print f
            print
            print

        return self.objs, self.blocks, self.functions

    def __init__(self):
        il.Symbol.IDC = 0
        il.Type.IDC = 0
        self.fcount = 0
        self.tcount = 0
        self.bcount = 0

        self.blocks = dict()

        self.functions = dict()
        self.fstack = list()

        self.objs = SymbolTable()

    def tmp(self):
        self.tcount += 1
        return "t%i" % self.tcount

    def block(self):
        self.bcount += 1
        name = "b%i" % self.bcount
        blk = il.Block(name)
        self.blocks[name] = blk
        self.cfunc.blks.append(blk)
        return blk

    def push_func(self, name=None):
        self.fcount += 1
        if name is None:
            name = "f%i" % self.fcount
        self.functions[name] = il.Function(name)
        self.fstack.append(self.functions[name])
        self.cfunc.scope_depth = self.objs.depth + 1

    def pop_func(self):
        return self.fstack.pop()

    @property
    def cfunc(self):
        return self.fstack[-1]

    def Stmts(self, node, blk):
        assert node.label == "Stmts"
        for c in node.children:
            if c.label == "Assign":
                self.PreAssign(c)
            elif c.label == "Var":
                self.PreVar(c)
        for c in node.children:
            # print c.label
            if c.label == "Assign":
                blk = self.Assign(c, blk)
            elif c.label == "Var":
                blk = self.Var(c, blk)
            elif c.label == "Call":
                blk = self.Call(c, None, blk)
            elif c.label == "Print":
                blk = self.Print(c, blk)
            elif c.label == "If":
                blk = self.If(c, blk)
            else:
                raise Exception, c.label
        return blk

    def If(self, node, blk):
        assert node.label == "If"

        thenblk = self.block()
        finalblk = self.block()
        elseblk = None

        if len(node.children) == 3:
            elseblk = self.block()
            blk = self.BooleanExpr(node.children[0], blk, thenblk, elseblk)
        else:
            blk = self.BooleanExpr(node.children[0], blk, thenblk, finalblk)

        thenblk = self.Stmts(node.children[1], thenblk)
        thenblk.link(finalblk, il.UNCONDITIONAL)
        thenblk.insts += [il.Inst(il.J, finalblk, 0, 0)]

        if len(node.children) == 3:
            # blk.insts += [ il.Inst(il.J, elseblk, 0, 0) ] ## This line must go here. subtle bug
            elseblk = self.Stmts(node.children[2], elseblk)
            elseblk.link(finalblk, il.UNCONDITIONAL)
            elseblk.insts += [il.Inst(il.J, finalblk, 0, 0)]

        return finalblk

    def Print(self, node, blk):
        assert node.label == "Print"

        c = node.children[0]
        if c.label == "Expr":
            result = il.Symbol("r" + self.tmp(), il.Int())
            blk = self.Expr(c, result, blk)
        else:
            raise Exception, c.label
        blk.insts += [il.Inst(il.PRNT, result, 0, 0)]
        return blk

    def PreAssign(self, node):
        assert node.label == "Assign"
        name = node.children[0]
        c = node.children[1]
        if c.label == "Func":
            s = il.Symbol(name, il.Func(None))
            if name in self.objs.myscope:
                self.objs.add(s)
            elif name in self.objs:
                raise TypeError, "Cannot assign a function to a non local var."
            else:
                raise TypeError, "Variable name %s not declared." % (name)

    def PreVar(self, node):
        assert node.label == "Var"
        name = node.children[0]

        if len(node.children) == 2:
            c = node.children[1]
            if c.label == "Func":
                s = il.Symbol(name, il.Func(None))
                if name in self.objs.myscope:
                    raise TypeError, "Name '%s' redeclared in same scope." % name
                self.objs.add(s)

    def Assign(self, node, blk):
        assert node.label == "Assign"
        name = node.children[0]
        c = node.children[1]

        if name in self.objs:
            result = self.objs[name]
        else:
            raise TypeError, "Use of name %s without prior declaration" % name

        if c.label == "Expr":
            if isinstance(result.type, il.Null):
                result.type = il.Int()
            blk = self.Expr(c, result, blk, toplevel=True)
        elif c.label == "Func":
            if isinstance(result.type, il.Null):
                result.type = il.Func(None)
            blk = self.Func(c, name, blk)
        else:
            raise Exception, c.label

        return blk

    def Var(self, node, blk):
        assert node.label == "Var"
        name = node.children[0]

        if len(node.children) == 1:
            if name in self.objs.myscope:
                raise TypeError, "Name '%s' redeclared in same scope." % name
            self.objs.add(il.Symbol(name, il.Null()))
        else:
            c = node.children[1]

            if c.label == "Expr":
                if name in self.objs.myscope:
                    raise TypeError, "Name '%s' redeclared in same scope." % name
                result = il.Symbol(name, il.Int())
                self.objs.add(result)
                blk = self.Expr(c, result, blk, toplevel=True)
            elif c.label == "Func":
                blk = self.Func(c, name, blk)
            else:
                raise Exception, c.label

        return blk

    def Func(self, node, name, blk):
        assert node.label == "Func"
        parent_blk = blk

        self.push_func()
        blk = self.block()
        self.cfunc.entry = blk
        self.objs[name].type.entry = self.cfunc.name

        self.objs = self.objs.push()
        for c in node.children:
            if c.label == "DParams":
                blk = self.DParams(node.children[0], blk)
            elif c.label == "Stmts":
                blk = self.Stmts(c, blk)
            elif c.label == "Return":
                blk = self.Return(c, blk)
            else:
                raise Exception, c.label
        self.cfunc.exit = blk
        self.objs = self.objs.pop()
        self.pop_func()

        return parent_blk

    def Return(self, node, blk):
        assert node.label == "Return"
        if node.children:
            if node.children[0].label == "Expr":
                result = il.Symbol("r" + self.tmp(), il.Int())
                blk = self.Expr(node.children[0], result, blk)
                blk.insts += [il.Inst(il.OPRM, 0, result, 0)]
                self.cfunc.oparam_count += 1
            else:
                raise Exception, "Expected Expr got %s" % node.children[0].label
        blk.insts += [il.Inst(il.RTRN, 0, 0, 0)]
        return blk

    def DParams(self, node, blk):
        assert node.label == "DParams"
        for i, c in enumerate(node.children):
            t = il.Symbol(c, il.Int())
            self.objs.add(t)
            self.cfunc.params.append(c)
            blk.insts += [il.Inst(il.GPRM, i, 0, t)]
        return blk

    def Expr(self, node, result, blk, toplevel=False):
        if node.label == "Expr":
            c = node.children[0]
        else:
            c = node

        if c.label == "INT":
            blk = self.Int(c.children[0], result, blk)
        elif c.label == "/" or c.label == "*" or c.label == "-" or c.label == "+":
            blk = self.Op(c, result, blk)
        elif c.label == "NAME":
            ## If it this is a top level expression (eg. c = a) then
            ## this is a copy instruction. Otherwise, this is a reference
            ## instruction, (eg. c = a + 2)
            ## c = a
            ##   MV A, 0, C
            ## c = a + 2
            ##   IMM 2, 0, tmp
            ##   ADD a, tmp, c
            if toplevel:
                blk.insts += [il.Inst(il.MV, self.objs[c.children[0]], 0, result)]
            else:
                result.clone(self.objs[c.children[0]])
        elif c.label == "Call":
            blk = self.Call(c, result, blk)
        else:
            raise Exception, "Unexpected Node %s" % str(c)

        return blk

    def BooleanExpr(self, node, blk, thenblk, elseblk):
        assert node.label == "BooleanExpr"
        c = node.children[0]
        return self.BooleanOp(c, blk, thenblk, elseblk)

    def BooleanOp(self, c, blk, thenblk, elseblk, negate=False):
        if c.label == "BooleanExpr":
            return self.BooleanOp(c.children[0], blk, thenblk, elseblk, negate)
        elif c.label in ["==", "!=", "<", "<=", ">", ">="]:
            Ar = il.Symbol("r" + self.tmp(), il.Int())
            Br = il.Symbol("r" + self.tmp(), il.Int())
            blk = self.Expr(c.children[0], Ar, blk)
            blk = self.Expr(c.children[1], Br, blk)
            inst = self.CmpOp(c, negate)
            blk.insts += [il.Inst(inst, Ar, Br, thenblk), il.Inst(il.J, elseblk, 0, 0)]
            blk.link(thenblk, il.TRUE)
            blk.link(elseblk, il.FALSE)
        elif c.label in ("Or", "And"):
            ## the blk become the A expressions block
            ## we allocate a new blk for B, the previous block is blk
            a = c.children[0]
            b = c.children[1]
            ablk = blk
            bblk = self.block()
            op = c.label
            bresult = self.BooleanOp(b, bblk, thenblk, elseblk, negate)
            if negate:
                if op == "Or":
                    op = "And"
                elif op == "And":
                    op = "Or"
            if op == "Or":
                aresult = self.BooleanOp(a, ablk, thenblk, bresult, negate)
            elif op == "And":
                aresult = self.BooleanOp(a, ablk, bresult, elseblk, negate)
            blk = aresult
        elif c.label == "Not":
            blk = self.BooleanOp(c.children[0], blk, thenblk, elseblk, not negate)
        else:
            raise Exception, "Unexpected Node %s" % c.label

        return blk

    def CmpOp(self, node, negate=False):
        ops = {"==": il.IFEQ, "!=": il.IFNE, "<": il.IFLT, "<=": il.IFLE, ">": il.IFGT, ">=": il.IFGE}
        ops_ = {"==": il.IFNE, "!=": il.IFEQ, "<": il.IFGE, "<=": il.IFGT, ">": il.IFLE, ">=": il.IFLT}
        if negate:
            return ops_[node.label]
        else:
            return ops[node.label]

    def Op(self, node, result, blk):
        ops = {"/": "DIV", "*": "MUL", "-": "SUB", "+": "ADD"}
        Ar = il.Symbol("r" + self.tmp(), il.Int())
        Br = il.Symbol("r" + self.tmp(), il.Int())
        blk = self.Expr(node.children[0], Ar, blk)
        blk = self.Expr(node.children[1], Br, blk)
        blk.insts += [il.Inst(il.ops[ops[node.label]], Ar, Br, result)]
        return blk

    def Call(self, node, result, blk):
        assert node.label == "Call"
        fun = self.objs[node.children[0]]
        # print self.objs, fun, node.children[0], self.objs['f']
        if isinstance(fun.type, il.Int):
            fun.type = fun.type.cast(il.FuncPointer)
        # print fun
        # print repr(fun)
        if len(node.children) != 1:
            blk = self.Params(node.children[1], blk)
        blk.insts += [il.Inst(il.CALL, fun, 0, 0)]
        if result is not None:
            blk.insts += [il.Inst(il.RPRM, 0, 0, result)]
        return blk

    def Params(self, node, blk):
        assert node.label == "Params"
        params = list()
        for c in node.children:
            result = il.Symbol("r" + self.tmp(), il.Int())
            blk = self.Expr(c, result, blk)
            params.append(result)
        params.reverse()
        for i, p in enumerate(params):
            blk.insts += [il.Inst(il.IPRM, len(params) - 1 - i, p, 0)]
        return blk

    def Int(self, node, result, blk):
        blk.insts += [il.Inst(il.IMM, node, 0, result)]
        return blk