Add compile-expr/
This commit is contained in:
parent
a77da74da5
commit
689034a522
3
compile-expr/.gitignore
vendored
Normal file
3
compile-expr/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
expr
|
||||||
|
expr.o
|
||||||
|
expr.s
|
8
compile-expr/Makefile
Normal file
8
compile-expr/Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
expr: expr.o
|
||||||
|
ld expr.o -o expr -l System -syslibroot `xcrun -sdk macosx --show-sdk-path` -e main -arch arm64
|
||||||
|
|
||||||
|
expr.o: expr.s
|
||||||
|
as expr.s -o expr.o
|
||||||
|
|
||||||
|
expr.s: expr.ppp
|
||||||
|
./expr.py expr.ppp > expr.s
|
1
compile-expr/expr.ppp
Normal file
1
compile-expr/expr.ppp
Normal file
@ -0,0 +1 @@
|
|||||||
|
(((a*b)+(c*d))*((e*f)+(g*h)))+(((i*j)+(k*l))*((m*n)+(o*p)))
|
61
compile-expr/expr.py
Executable file
61
compile-expr/expr.py
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
Generates the ARM64 Assembly for an executable that performs the given
|
||||||
|
calculation and exits with that number as the exit code. It currently
|
||||||
|
only allows for multiplication and addition. You can check the output
|
||||||
|
modulo 256 using `echo $?`. The only defined variables are the letters
|
||||||
|
a-z, where they represent their 1-based index into the alphabet.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import string
|
||||||
|
import sys, os; sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) # just becuase this is in a subdirectory
|
||||||
|
from ppp_lexer import *
|
||||||
|
from ppp_parser import *
|
||||||
|
|
||||||
|
_program, file_path = sys.argv
|
||||||
|
|
||||||
|
lexer = Lexer.from_file(file_path)
|
||||||
|
expr = parse_expression(lexer)
|
||||||
|
lexer.assert_token(EofToken())
|
||||||
|
|
||||||
|
def get_index(char: str) -> int:
|
||||||
|
"""
|
||||||
|
Assuming char is [a-z]
|
||||||
|
"""
|
||||||
|
return ord(char)-96
|
||||||
|
|
||||||
|
def get_stack_address(index: int) -> int:
|
||||||
|
return 112-index*4
|
||||||
|
|
||||||
|
def to_asm(expr: Expression, *, taken: int=0):
|
||||||
|
"""
|
||||||
|
Generates the assembly using registers w0, w1, w2, ... as a stack.
|
||||||
|
|
||||||
|
`taken` is how many registers are already taken by previous elements 'on the stack'
|
||||||
|
"""
|
||||||
|
if isinstance(expr, Variable):
|
||||||
|
assert expr.name in string.ascii_lowercase
|
||||||
|
address = get_stack_address(get_index(expr.name))
|
||||||
|
print(f"\tldr w{taken}, [sp, {address}] // {expr.name}")
|
||||||
|
else:
|
||||||
|
match expr:
|
||||||
|
case Addition(): word = 'add'
|
||||||
|
case Multiplication(): word = 'mul'
|
||||||
|
case _: assert False, f"Unimplemented: {expr}"
|
||||||
|
to_asm(expr.lhs, taken=taken)
|
||||||
|
to_asm(expr.rhs, taken=taken+1)
|
||||||
|
|
||||||
|
print(f"\t{word} w{taken}, w{taken}, w{taken+1} // {expr.represent()}")
|
||||||
|
|
||||||
|
print(".global main")
|
||||||
|
print(".align 2")
|
||||||
|
print()
|
||||||
|
print("main:")
|
||||||
|
print("\tsub sp, sp, #112") # to fit 26*4=104 bytes. It seems that the sp should only be offset by 16 bytes at a time.
|
||||||
|
for i in range(1,27):
|
||||||
|
print(f"\tmov w0, {i}")
|
||||||
|
print(f"\tstr w0, [sp, {get_stack_address(i)}]")
|
||||||
|
to_asm(expr)
|
||||||
|
print("\tadd sp, sp, 112")
|
||||||
|
print("\tret")
|
Loading…
Reference in New Issue
Block a user