IUCompilerCourse / python-student-support-code

Support for for students (Python)
MIT License
57 stars 38 forks source link

How to eval raw x86 code? #18

Open waynee95 opened 1 year ago

waynee95 commented 1 year ago

Using x86_parser.parseon the following assembly program (equivalent to print(40 + 2))

  .globl main
main:
  pushq %rbp
  movq %rsp, %rbp
  subq $16, %rsp
  movq $40, -8(%rbp)
  addq $2, -8(%rbp)
  movq -8(%rbp), %rdi
  callq print_int
  addq $16, %rsp
  popq %rbp
  retq

yields something of the form (I truncated the output)

Tree(Token('RULE', 'prog'), [Tree(Token('RULE', 'block'), [Token('CNAME', 'main')]), Tree(Token('RULE', 'block'), [Token('CNAME', 'main'), Tree('pushq', [Tree('reg_a', [Token('RBP', 'rbp')])]), Tree('movq', [Tree('reg_a', [Token('RSP', 'rsp')]), Tree('reg_a', [Token('RBP', 'rbp')])]), Tree('subq', [Tree('int_a', [Tree('int_a', [Token('NUMBER', '16')])]), Tree('reg_a', [Token('RSP', 'rsp')])]), Tree('movq', [Tree('int_a', [Tree('int_a', [Token('NUMBER', '40')])]), ...

which is not in the correct shape for eval_x86.eval_program to accept it.

However, evaluating assembly generated by the compiler works.

Using a finished compiler from chapter 2 to compile print(40 + 2) to x86 ast and then using convert_x86.convert_program yields something of the form (I truncated the output again)

Tree('prog', [Tree('block', ['main', Tree('pushq', [Tree('reg_a', ['rbp'])]), Tree('movq', [Tree('reg_a', ['rsp']), Tree('reg_a', ['rbp'])]), Tree('subq', [Tree('int_a', [16]), Tree('reg_a', ['rsp'])]), Tree('movq', [Tree('int_a', [40]), Tree('mem_a', [Tree('int_a', [-8]), 'rbp'])]),  ...

which is of the correct form for eval_x86.eval_program to accept and produce a result.

I feel like I am missing something since eval_x86.eval_program is written to operate on the result that lark produces no?

waynee95 commented 1 year ago

For now I fixed it with a dirty fix:

def eval_imm(self, e) -> int:
        if e.data == 'int_a':
           ### fix ###
           from lark import Tree
           if type(e.children[0]) == Tree:
              v = int(e.children[0].children[0])
           else:
           ### fix ###

              v = int(e.children[0])
           if is_int64(v):
               return v
           else:
               raise Exception('eval_imm: invalid immediate:', v)

        #if e.data == 'int_a':
        #    return int(e.children[0])
        #elif e.data == 'neg_a':
        if e.data == 'neg_a':
            return -self.eval_imm(e.children[0])
        else:
            raise Exception('eval_imm: unknown immediate:', e)

Another thing that was missing is the actual "eval" part in the function parse_and_eval_program:

def parse_and_eval_program(self, s):
        p = x86_parser.parse(s)
        return self.eval_program(p)