Skip to content

Commit

Permalink
Compiling to files!
Browse files Browse the repository at this point in the history
  • Loading branch information
JVKran committed May 13, 2021
1 parent 6176dd1 commit adc8efc
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 145 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ Litteraly everybody working in IT has *at least touched* code once and is able t
> **Course requirements**: Check the [course](COURSE.md) markdown file for description of meeting course requirements.
## Features
### Shell and File
SRPL can interpret a file, but can also be used as a shell.
To start shell, execute ```python srpl.py``` in the commandline.
### Shell, Interpreter and Compiler
SRPL can interpret a file, can be used as a shell and is able to compile files to assembly.
To start the shell, execute ```python srpl.py``` in the commandline.
To run 'main.srpl' execute ```python srpl.py main.srpl``` in the commandline. Please note that the newlines can be replaced by semicolons and that every line in the file needs to end with a space.
To compile an SRPL sourcefile, execute ```python srpl.py example/source/even.srpl example/source/even.asm```. The SRPL sourcecode in even.srpl will then be compiled to assembly in even.asm.
### Float and Int
The heart of this language is the number. Numbers can be an integer or a float. Furthermore, a ```true``` is seen as a Number larger than 0.
``` SRPL
Expand Down
43 changes: 21 additions & 22 deletions compile/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ def __init__(self, sourceFile : str, destinationFile : str, function : FunctionN
print("This function requires", requiredRegisters, "registers!")

self.file = open(destinationFile, "w")
print("\t.cpu cortex-m0")
print("\t.text")
print("\t.align 2")
print(f"\t.global {function.name}\n")
print(f'{function.name}:')
print("\tpush \t{r4, r5, r6, lr}")
self.file.write("\t.cpu cortex-m0\n")
self.file.write("\t.text\n")
self.file.write("\t.align 2\n")
self.file.write(f"\t.global {function.name}\n\n")
self.file.write(f'{function.name}:\n')
self.file.write("\tpush \t{r4, r5, r6, lr}\n")

def __del__(self):
print("\tpop \t{r4, r5, r6, pc}")
self.file.write("\tpop \t{r4, r5, r6, pc}\n")
self.file.close()

def compile(self, node : Node, context : Context):
Expand All @@ -40,15 +40,15 @@ def compileOperatorNode(node : OperatorNode, context : Context) -> Number:
right = self.compile(node.right_node, context)
methodName = f'{type(node.operator).__name__}'.replace("Token", '') # AddToken becomes Add, MultiplyToken becomes Multiply, etc.
method = getattr(left, methodName)
res = method(right, context)
res = method(right, context, self.file)
return res

# compileNumbernode :: NumberNode -> Context -> Number
def compileNumberNode(node : NumberNode, context : Context) -> Number:
""" Create number from number node. """
availableRegister = context.getRegister()
number = Number(node.token.stringToParse, node.token.lineNumber, availableRegister)
print(f"\tmovs\t{availableRegister}, #{number.value}")
self.file.write(f"\tmovs\t{availableRegister}, #{number.value}\n")
return number

# compileVariableNode :: VariableNode -> Context -> Number
Expand All @@ -61,36 +61,35 @@ def compileVariableNode(node : VariableNode, context : Context) -> Number:
variableName = node.var_name
value = self.compile(node.value, context)
context.symbols[variableName] = value
# print(f"\tmovs\tr0, {value.register}")
return value

def compileIfNode(node : IfNode, context : Context) -> Optional[Number]:
""" Execute expression of if statement when condition is met or exepression of else statement when provided. """
conditionIsMet: Number = self.compile(node.condition, context)
availableRegisters = copy(context.registers) # Save registers since the condition is either true, or false.
print(f"\tcmp\t{conditionIsMet.register}, #1")
self.file.write(f"\tcmp \t{conditionIsMet.register}, #1\n")
segment = context.getSegment()
print(f"\tbne\t{segment}") # If condition isn't met; go to L2.
self.file.write(f"\tbne \t{segment}\n") # If condition isn't met; go to L2.
resReg = context.registers[0]
res = self.compile(node.expression, context)
print("\tb\tend")
print(f"{segment}:")
self.file.write("\tb\tend \n")
self.file.write(f"{segment}:\n")
context.registers = availableRegisters
if node.elseExpression:
self.compile(node.elseExpression, context)
if(type(node.elseExpression) == CallNode):
print(f"\tmovs\t{resReg}, r0") # Inherent to the way SRPL deals with variables and return values.
self.file.write(f"\tmovs\t{resReg}, r0\n") # Inherent to the way SRPL deals with variables and return values.
return res

# compileWhileNode :: WhileNode -> Context -> Nothing
def compileWhileNode(node : WhileNode, context : Context) -> None:
""" Execute while loop until condition is no longer met. """
print("loop:")
self.file.write("loop:\n")
conditionIsMet: Number = self.compile(node.condition, context)
print(f"\tcmp\t{conditionIsMet.register}, #1")
print(f"\tbne\tend") # If condition isn't met; go to L2.
self.file.write(f"\tcmp \t{conditionIsMet.register}, #1\n")
self.file.write(f"\tbne \tend\n") # If condition isn't met; go to L2.
self.compile(node.codeSequence, context)
print("\tb\tloop")
self.file.write("\tb \tloop\n")

# compileFunctionNode :: FunctionNode -> Context -> Function
def compileFunctionNode(node : FunctionNode, context : Context) -> Function:
Expand All @@ -105,7 +104,7 @@ def compileCallNode(node : FunctionNode, context : Context):
arguments: List[Number] = []
if node.argumentNodes != None:
arguments = list(chain(*map(lambda node: [*arguments, self.compile(node, context)], node.argumentNodes)))
print(f"\tbl\t{node.nodeToCall.var_name.stringToParse}")
self.file.write(f"\tbl \t{node.nodeToCall.var_name.stringToParse}\n")

# compileListNode :: ListNode -> Context -> Number | [Number]
def compileListNode(node : ListNode, context : Context) -> Union[Number, List[Number]]:
Expand Down Expand Up @@ -141,8 +140,8 @@ def compileReturnNode(node : ReturnNode, context : Context) -> Optional[Number]:
""" Execute return statement. """
if node.nodeToReturn:
res = self.compile(node.nodeToReturn, context)
print("end:")
print(f"\tmovs\tr0, {res.register}")
self.file.write("end:\n")
self.file.write(f"\tmovs\tr0, {res.register}\n")
return res

functionName: str = f'compile{type(node).__name__}' # Determine name of function to call.
Expand Down
106 changes: 53 additions & 53 deletions compile/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,103 +11,103 @@ def __init__(self, value : Union[int, float], lineNumber : int, register : str):
self.register = register

# Add :: Number -> Number
def Add(self, other : 'Number', context: Context) -> 'Number':
print(f'\tadd\t{self.register}, {other.register}')
def Add(self, other : 'Number', context: Context, file) -> 'Number':
file.write(f'\tadd \t{self.register}, {other.register}\n')
return Number(self.value + other.value, self.lineNumber, self.register)

# Substract :: Number -> Number
def Substract(self, other : 'Number', context: Context) -> 'Number':
print(f'\tsub\t{self.register}, {other.register}')
def Substract(self, other : 'Number', context: Context, file) -> 'Number':
file.write(f'\tsub \t{self.register}, {other.register}\n')
return Number(self.value - other.value, self.lineNumber, self.register)

# Multiply :: Number -> Number
def Multiply(self, other : 'Number', context: Context) -> 'Number':
print(f'\tmuls\t{self.register}, {self.register}, {other.register}') # Multiply self with other and store in self.
def Multiply(self, other : 'Number', context: Context, file) -> 'Number':
file.write(f'\tmuls\t{self.register}, {self.register}, {other.register}\n') # Multiply self with other and store in self.
return Number(self.value * other.value, self.lineNumber, self.register)

# Divide :: Number -> Number
def Divide(self, other : 'Number', context: Context) -> 'Number':
def Divide(self, other : 'Number', context: Context, file) -> 'Number':
# TODO: Make sure numbers to divide are in r0 and r1.
print("\tbl\t__aeabi_idiv")
file.write("\tbl \t__aeabi_idiv\n")
return Number(self.value / other.value, self.lineNumber, self.register)

# Equality :: Number -> Number
def Equality(self, other : 'Number', context: Context) -> 'Number':
def Equality(self, other : 'Number', context: Context, file) -> 'Number':
scratchRegister = context.getRegister()
tempRegister = context.getRegister() # Used since we don't want the original register to change.
print(f"\tsub\t{tempRegister}, {other.register}, {self.register}")
print(f"\tneg\t{scratchRegister}, {tempRegister}") # TODO: Request register from context.
print(f"\tadc\t{scratchRegister}, {scratchRegister}, {tempRegister}")
file.write(f"\tsub \t{tempRegister}, {other.register}, {self.register}\n")
file.write(f"\tneg \t{scratchRegister}, {tempRegister}\n") # TODO: Request register from context.
file.write(f"\tadc \t{scratchRegister}, {scratchRegister}, {tempRegister}\n")
return Number(int(self.value == other.value), self.lineNumber, scratchRegister) # Scratchregister contains result.

# NonEquality :: Number -> Number
def NonEquality(self, other : 'Number', context: Context) -> 'Number':
def NonEquality(self, other : 'Number', context: Context, file) -> 'Number':
scratchRegister = context.getRegister()
tempRegister = context.getRegister() # TODO: Free temp register.
print(f"\tsub\t{tempRegister}, {other.register}, {self.register}")
print(f"\tsub\t{scratchRegister}, {tempRegister}, #1")
print(f"\tsbc\t{scratchRegister}, {scratchRegister}, {scratchRegister}")
file.write(f"\tsub \t{tempRegister}, {other.register}, {self.register}\n")
file.write(f"\tsub \t{scratchRegister}, {tempRegister}, #1\n")
file.write(f"\tsbc \t{scratchRegister}, {scratchRegister}, {scratchRegister}\n")
return Number(int(self.value != other.value), self.lineNumber, scratchRegister)

# Less :: Number -> Number
def Less(self, other : 'Number', context: Context) -> 'Number':
def Less(self, other : 'Number', context: Context, file) -> 'Number':
scratchRegister = context.getRegister()
print(f"\tmov\t{scratchRegister}, #1")
print(f"\tcmp\t{self.register}, {other.register}")
print("\tblt\t.L2")
print(f"\tmovs\t{scratchRegister}, #0")
print(".L2:")
print(f"\tmovs\t{self.register}, {scratchRegister}")
file.write(f"\tmov \t{scratchRegister}, #1\n")
file.write(f"\tcmp \t{self.register}, {other.register}\n")
file.write("\tblt \t.L2\n")
file.write(f"\tmovs\t{scratchRegister}, #0\n")
file.write(".L2:\n")
file.write(f"\tmovs\t{self.register}, {scratchRegister}\n")
return Number(int(self.value < other.value), self.lineNumber, self.register)

# Greater :: Number -> Number
def Greater(self, other : 'Number', context: Context) -> 'Number':
def Greater(self, other : 'Number', context: Context, file) -> 'Number':
scratchRegister = context.getRegister()
print(f"\tmovs\t{scratchRegister}, #1")
print(f"\tcmp\t{self.register}, {other.register}")
print("\tbgt\t.L2")
print(f"\tmovs\t{scratchRegister}, #0")
print(".L2:")
print(f"\tmovs\t{self.register}, {scratchRegister}")
file.write(f"\tmovs\t{scratchRegister}, #1\n")
file.write(f"\tcmp \t{self.register}, {other.register}\n")
file.write("\tbgt \t.L2\n")
file.write(f"\tmovs\t{scratchRegister}, #0\n")
file.write(".L2:\n")
file.write(f"\tmovs\t{self.register}, {scratchRegister}\n")
return Number(int(self.value > other.value), self.lineNumber, self.register)

# LessEqual :: Number -> Number
def LessEqual(self, other : 'Number', context: Context) -> 'Number':
def LessEqual(self, other : 'Number', context: Context, file) -> 'Number':
scratchRegister = context.getRegister()
tempRegister = context.getRegister()
print(f"\tlsr\t{scratchRegister}, {self.register}, #31")
print(f"\tasr\t{tempRegister}, {other.register}, #31")
print(f"\tcmp\t{self.register}, {other.register}")
print(f"\tadc\t{scratchRegister}, {scratchRegister}, {tempRegister}")
file.write(f"\tlsr \t{scratchRegister}, {self.register}, #31\n")
file.write(f"\tasr \t{tempRegister}, {other.register}, #31\n")
file.write(f"\tcmp \t{self.register}, {other.register}\n")
file.write(f"\tadc \t{scratchRegister}, {scratchRegister}, {tempRegister}\n")
return Number(int(self.value <= other.value), self.lineNumber, scratchRegister)

# GreaterEqual :: Number -> Number
def GreaterEqual(self, other : 'Number', context: Context) -> 'Number':
def GreaterEqual(self, other : 'Number', context: Context, file) -> 'Number':
scratchRegister = context.getRegister()
otherRegister = context.getRegister()
print(f"\tasr\t{scratchRegister}, {self.register}, #31")
print(f"\tlsr\t{otherRegister}, {other.register}, #31")
print(f"\tcmp\t{self.register}, {other.register}")
print(f"\tadc\t{scratchRegister}, {scratchRegister}, {otherRegister}")
file.write(f"\tasr \t{scratchRegister}, {self.register}, #31\n")
file.write(f"\tlsr \t{otherRegister}, {other.register}, #31\n")
file.write(f"\tcmp \t{self.register}, {other.register}\n")
file.write(f"\tadc \t{scratchRegister}, {scratchRegister}, {otherRegister}\n")
return Number(int(self.value >= other.value), self.lineNumber, scratchRegister)

# And :: Number -> Number
def And(self, other : 'Number', context: Context) -> 'Number':
print(f"\tmovs r3, r0")
print(f"\tmovs r0, #0")
print(f"\tcmp r3, #0")
print(f"\tbeq .L2")
print(f"\tsub r0, r1, #1")
print(f"\tsbcs r1, r1, r0")
print(f"\tuxtb r0, r1")
print(f".L2:")
def And(self, other : 'Number', context: Context, file) -> 'Number':
file.write(f"\tmovs r3, r0\n")
file.write(f"\tmovs r0, #0\n")
file.write(f"\tcmp r3, #0\n")
file.write(f"\tbeq .L2\n")
file.write(f"\tsub r0, r1, #1\n")
file.write(f"\tsbcs r1, r1, r0\n")
file.write(f"\tuxtb r0, r1\n")
file.write(f".L2:\n")
return Number(int(self.value and other.value), self.lineNumber, self.register)

# Or :: Number -> Number
def Or(self, other : 'Number', context: Context) -> 'Number':
print(f"\torrs\t{self.register}, {other.register}")
print(f"\tsub\t{other.register}, {self.register}, #1")
print(f"\tsbcs\t{self.register}, {self.register}, {other.register}")
def Or(self, other : 'Number', context: Context, file) -> 'Number':
file.write(f"\torrs\t{self.register}, {other.register}\n")
file.write(f"\tsub\t{other.register}, {self.register}, #1\n")
file.write(f"\tsbcs\t{self.register}, {self.register}, {other.register}\n")
return Number(int(self.value or other.value), self.lineNumber, self.register)

# __bool__ -> Boolean
Expand Down
20 changes: 10 additions & 10 deletions example/source/equals.asm
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
.cpu cortex-m0
.text
.align 2
.global equals
.cpu cortex-m0
.text
.align 2
.global equals

equals:
push {r4, r5, r6, lr}
sub r3, r1, r0
neg r2, r3
adc r2, r2, r3
push {r4, r5, r6, lr}
sub r3, r1, r0
neg r2, r3
adc r2, r2, r3
end:
movs r0, r2
pop {r4, r5, r6, pc}
movs r0, r2
pop {r4, r5, r6, pc}
38 changes: 19 additions & 19 deletions example/source/even.asm
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
.cpu cortex-m0
.text
.align 2
.global even
.cpu cortex-m0
.text
.align 2
.global even

even:
push {r4, r5, r6, lr}
movs r1, #0
sub r3, r1, r0
neg r2, r3
adc r2, r2, r3
cmp r2, #1
bne .L2
movs r4, #1
b end
push {r4, r5, r6, lr}
movs r1, #0
sub r3, r1, r0
neg r2, r3
adc r2, r2, r3
cmp r2, #1
bne .L2
movs r4, #1
b end
.L2:
movs r4, #1
sub r0, r4
bl odd
movs r4, r0
movs r4, #1
sub r0, r4
bl odd
movs r4, r0
end:
movs r0, r4
pop {r4, r5, r6, pc}
movs r0, r4
pop {r4, r5, r6, pc}
38 changes: 19 additions & 19 deletions example/source/odd.asm
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
.cpu cortex-m0
.text
.align 2
.global odd
.cpu cortex-m0
.text
.align 2
.global odd

odd:
push {r4, r5, r6, lr}
movs r1, #0
sub r3, r1, r0
neg r2, r3
adc r2, r2, r3
cmp r2, #1
bne .L2
movs r4, #0
b end
push {r4, r5, r6, lr}
movs r1, #0
sub r3, r1, r0
neg r2, r3
adc r2, r2, r3
cmp r2, #1
bne .L2
movs r4, #0
b end
.L2:
movs r4, #1
sub r0, r4
bl even
movs r4, r0
movs r4, #1
sub r0, r4
bl even
movs r4, r0
end:
movs r0, r4
pop {r4, r5, r6, pc}
movs r0, r4
pop {r4, r5, r6, pc}
Loading

0 comments on commit adc8efc

Please sign in to comment.