Beispiel #1
0
 def test_nested_block(self):
     body = """
 long x;
 if (0 == 0) {
     long x = 1;
 }
 """
     stms = parse_stm(body)
     local_vars = get_local_vars(stms)
     self.assertEqual(local_vars, ['x', 'x'])
Beispiel #2
0
 def test_function(self):
     body = """
 long x;
 long y = 1;
 int m = 0;
 if (x == 0) {
     long z;
 } else {
     long t;
 }
 while (x == x) {
     long a = 1;
 }
 """
     stms = parse_stm(body)
     local_vars = get_local_vars(stms)
     self.assertEqual(local_vars, ['x', 'y', 'm', 'z', 't', 'a'])
Beispiel #3
0
    def visit_FunDecl(self, _type, name, params, body):
        funname = mangle_fun(name)
        # prepare the prologue
        #
        # at this moment [rsp] contains the return address
        # [rsp] +  8 contains arg #1
        # [rsp] + 16 contains arg #2
        # etc
        #
        # We store rsp in rbp at the very start of the prologue
        # so we can reference the vars using offsets of rbp.
        #
        # THIS ALSO MEANS THAT WE MUST ADD ANOTHER OFFSET OF 8!
        # The stack looks like this:
        # [rbp]      == value of rsp
        # [rbp +  8] == stored value of rbp
        # [rbp + 16] == arg #1
        # [rbp + 24] == arg #2
        # etc!
        #
        # Note that the value of rsp changes as we change the stack.
        # rbp is a callee-save register, so we don't have to worry
        # about it being changed when calling other functions.
        #
        # Local variables are stored on the other side of rbp, ie:
        # [rbp -  8] == first local variable
        # [rbp - 16] == second local variable
        # etc!

        # Bind the parameters
        word_len = 8
        for i, param in enumerate(params):
            var = param.var
            index = i + 2
            # offset = word_len * index
            addr = VarAddr("rbp", MemOffset(Sign.Plus, word_len, index))
            self.add_parameter_of_local(var, addr)

        # Allocate local variables
        local_vars = get_local_vars(body)
        for i, var in enumerate(local_vars):
            index = i + 1
            addr = VarAddr("rbp", MemOffset(Sign.Minus, word_len, index))
            self.add_parameter_of_local(var, addr)

        # update the rsp to make space for local variables
        locals_size = word_len * len(local_vars)
        local_vars_add_space = f"sub rsp, {locals_size}"
        local_vars_dec_space = f"add rsp, {locals_size}"

        prologue = f"""
    push rbp
    mov rbp, rsp
    {local_vars_add_space}
"""

        # the epilogue label must be known here, because we need to jump here
        # if we find any return
        epilogue_lbl = f"{funname}_epilogue"

        self.push_epilogue(epilogue_lbl)

        # The main body of the function
        # the result of the function call is the content of the rax register
        body_code = self.visit_many(body)

        # we pass the label as a correctness check
        self.pop_epilogue(epilogue_lbl)

        # prepare the epilogue
        # NOTE: the parameters on the stack will be removed by the caller
        epilogue = f"""
    {local_vars_dec_space}
    pop rbp
"""

        # remove the bindings for the local vars:
        for var in local_vars:
            self.remove_parameter_or_local(var)

        # remove the bindings for the params
        for param in params:
            self.remove_parameter_or_local(param.var)

        return f"""