Skip to content

Instantly share code, notes, and snippets.

@Pebaz
Last active September 29, 2020 19:29
Show Gist options
  • Save Pebaz/8cb385411fc788d61af36051d7484f7f to your computer and use it in GitHub Desktop.
Save Pebaz/8cb385411fc788d61af36051d7484f7f to your computer and use it in GitHub Desktop.
"""
Followed tutorial from:
https://keleshev.com/one-pass-compiler-primer
python .\calc_compiler.py 1 + 2; bat calc.s; zig cc -Wno-everything calc.s -o calc.exe; ./calc.exe; Write-Host $LASTEXITCODE
The Program:
1 + 2 + 3 * 4
Will Be Compiled To:
.global main
main:
push $1
push $2
pop %rax
pop %rbx
add %rbx, %rax
push %rax
push $3
pop %rax
pop %rbx
add %rbx, %rax
push %rax
push $4
pop %rax
pop %rbx
mul %rbx
push %rax
pop %rax
ret
"""
import sys
def gen(tokens, out=sys.stdout):
emit = out.write
emit('.global main\n')
emit('main:\n')
for token in tokens:
if isinstance(token, int):
emit(f'\tpush ${token}\n')
elif 'ADD' in token:
emit('\tpop %rax\n')
emit('\tpop %rbx\n')
emit('\tadd %rbx, %rax\n')
emit('\tpush %rax\n')
elif 'MUL' in token:
emit('\tpop %rax\n')
emit('\tpop %rbx\n')
emit('\tmul %rbx\n')
emit('\tpush %rax\n')
emit('\tpop %rax\n')
emit('\tret\n')
def lex(text):
for t in text.split():
if t.isnumeric():
yield int(t)
else:
yield 'OP_' + {'+' : 'ADD', '*' : 'MUL'}[t]
def parse(tokens):
yield next(tokens)
for b in tokens:
op = next(tokens)
yield op
yield b
def compile(text, out=sys.stdout):
gen(parse(lex(text)), out)
if __name__ == '__main__':
with open('calc.s', 'w') as outfile:
compile(' '.join(sys.argv[1:]), outfile)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment