Browse Source

added functions

rlbr-dev
Larry Xue 5 years ago
parent
commit
4351d39489
  1. 98
      c2logic/compiler.py
  2. 2
      c2logic/consts.py
  3. 34
      c2logic/instructions.py

98
c2logic/compiler.py

@ -1,13 +1,20 @@
from pycparser.c_ast import Compound, Constant, DeclList, Enum, FileAST, FuncDecl, Struct, TypeDecl
from .instructions import BinaryOp, Enable, End, JumpCondition, Print, PrintFlush, Radar, RawAsm, RelativeJump, Sensor, Shoot, UnaryOp, Instruction, Set, Noop
from pycparser import c_ast, parse_file
from dataclasses import dataclass
from .operations import func_unary_ops, func_binary_ops
from pycparser import c_ast, parse_file
from pycparser.c_ast import (
Compound, Constant, DeclList, Enum, FileAST, FuncDecl, Struct, TypeDecl
)
from .consts import builtins, func_binary_ops, func_unary_ops
from .instructions import (
BinaryOp, Enable, End, FunctionCall, Instruction, JumpCondition, Print, PrintFlush, Radar,
RawAsm, RelativeJump, Return, Sensor, Set, Shoot, UnaryOp
)
@dataclass
class Function():
name: str
args: list
params: list
instructions: list
start: int
@ -40,20 +47,29 @@ class Compiler(c_ast.NodeVisitor):
ast = parse_file(filename, use_cpp=True, cpp_args=["-I", "include/"])
self.visit(ast)
#TODO actually handle functions properly
out = []
offset = 0
init_call = FunctionCall("main")
preamble = [Set("__retaddr", "2"), init_call, End()]
offset = len(preamble)
#set function starts
for function in self.functions.values():
function.start = offset
offset += len(function.instructions)
#rewrite relative jumps and func calls
init_call.func_start = self.functions["main"].start
for function in self.functions.values():
instructions = function.instructions
out2 = []
for instruction in instructions:
if isinstance(instruction, RelativeJump):
instruction.func_start = function.start
out2.append(str(instruction))
out.append("\n".join(out2))
return "\n\n".join(out)
if isinstance(instruction, FunctionCall):
instruction.func_start = self.functions[instruction.func_name].start
out = ["\n".join(map(str, preamble))]
out.extend(
"\n".join(map(str, function.instructions)) for function in self.functions.values()
)
return "\n".join(out)
#utilities
def push(self, instruction: Instruction):
@ -65,6 +81,9 @@ class Compiler(c_ast.NodeVisitor):
def peek(self):
return self.curr_function.instructions[-1]
def curr_offset(self):
return len(self.curr_function.instructions) - 1
def can_avoid_indirection(self, var="__rax"):
top = self.peek()
return self.opt_level >= 1 and isinstance(top, Set) and top.dest == var
@ -90,18 +109,24 @@ class Compiler(c_ast.NodeVisitor):
self.push(RelativeJump(None, JumpCondition("==", "__rax", "0")))
def start_loop(self, cond):
self.loop_start = len(self.curr_function.instructions)
self.loop_start = self.curr_offset() + 1
self.visit(cond)
self.push_body_jump()
self.loop_end_jumps = [len(self.curr_function.instructions) - 1] # also used for breaks
self.loop_end_jumps = [self.curr_offset()] # also used for breaks
def end_loop(self):
self.push(RelativeJump(self.loop_start, JumpCondition.always))
for offset in self.loop_end_jumps:
self.curr_function.instructions[offset].offset = len(self.curr_function.instructions)
self.curr_function.instructions[offset].offset = self.curr_offset() + 1
self.loop_start = None
self.loop_end_jumps = None
def push_ret(self):
if self.curr_function.name == "main":
self.push(End())
else:
self.push(Return())
def optimize_psuedofunc_args(self, args):
if self.opt_level >= 1:
for i, arg in reversed(list(enumerate(args))):
@ -115,23 +140,28 @@ class Compiler(c_ast.NodeVisitor):
def visit_FuncDef(self, node): # function definitions
func_name = node.decl.name
func_decl = node.decl.type
args = [arg_decl.name for arg_decl in func_decl.args.params]
params = [param_decl.name for param_decl in func_decl.args.params]
self.curr_function = Function(func_name, args, [], None)
self.curr_function = Function(func_name, params, [], None)
self.visit(node.body)
#in case for loop is the last thing in a function to ensure the jump target is valid
if self.loop_start is not None:
self.push(Noop())
#implicit return
#needed unconditionally in case loop/if body is at end of function
self.push(Set("__rax", "null"))
self.push(Return())
self.functions[func_name] = self.curr_function
def visit_Decl(self, node):
if isinstance(node.type, TypeDecl): # variable declaration
#TODO fix local/global split
if node.init is not None:
self.visit(node.init)
self.set_to_rax(node.name)
elif isinstance(node.type, FuncDecl):
#TODO actually process func declarations
pass
if node.name not in builtins + func_unary_ops + func_binary_ops:
#create placeholder function for forward declarations
self.functions[node.name] = Function(
node.name, [param_decl.name for param_decl in node.type.args.params], [], None
)
elif isinstance(node.type, Struct):
if node.type.name != "MindustryObject":
#TODO structs
@ -209,7 +239,7 @@ class Compiler(c_ast.NodeVisitor):
def visit_DoWhile(self, node):
#jump over the condition on the first iterattion
self.push(RelativeJump(None, JumpCondition.always))
init_jump_offset = len(self.curr_function.instructions) - 1
init_jump_offset = self.curr_offset()
self.start_loop(node.cond)
self.curr_function.instructions[init_jump_offset].offset = len(
self.curr_function.instructions
@ -220,12 +250,12 @@ class Compiler(c_ast.NodeVisitor):
def visit_If(self, node):
self.visit(node.cond)
self.push_body_jump()
cond_jump_offset = len(self.curr_function.instructions) - 1
cond_jump_offset = self.curr_offset()
self.visit(node.iftrue)
#jump over else body from end of if body
if node.iffalse is not None:
self.push(RelativeJump(None, JumpCondition.always))
cond_jump_offset2 = len(self.curr_function.instructions) - 1
cond_jump_offset2 = self.curr_offset()
self.curr_function.instructions[cond_jump_offset].offset = len(
self.curr_function.instructions
)
@ -237,11 +267,15 @@ class Compiler(c_ast.NodeVisitor):
def visit_Break(self, node):
self.push(RelativeJump(None, JumpCondition.always))
self.loop_end_jumps.append(len(self.curr_function.instructions) - 1)
self.loop_end_jumps.append(self.curr_offset())
def visit_Continue(self, node):
self.push(RelativeJump(self.loop_start, JumpCondition.always))
def visit_Return(self, node):
self.visit(node.expr)
self.push(Return())
def visit_FuncCall(self, node):
name = node.name.name
args = node.args.exprs
@ -249,7 +283,7 @@ class Compiler(c_ast.NodeVisitor):
if name == "asm":
arg = args[0]
if not isinstance(arg, Constant) or arg.type != "string":
raise TypeError("Non-string argument to _asm", node)
raise TypeError("Non-string argument to asm", node)
self.push(RawAsm(arg.value[1:-1]))
elif name in ("print", "printd"):
self.visit(args[0])
@ -329,7 +363,15 @@ class Compiler(c_ast.NodeVisitor):
else:
self.push(UnaryOp("__rax", "__rax", name))
else:
raise NotImplementedError(node)
try:
func = self.functions[name]
except KeyError:
raise ValueError(f"{name} is not a function")
for param, arg in zip(func.params, args):
self.visit(arg)
self.set_to_rax(param)
self.push(Set("__retaddr", self.curr_offset() + 2))
self.push(FunctionCall(name))
def generic_visit(self, node):
if isinstance(node, (FileAST, Compound, DeclList)):
@ -347,4 +389,4 @@ def main():
print(Compiler(args.optimization_level).compile(args.file), file=args.output)
if __name__ == "__main__":
main()
main()

c2logic/operations.py → c2logic/consts.py

34
c2logic/instructions.py

@ -1,5 +1,5 @@
from dataclasses import dataclass
from .operations import binary_op_inverses, binary_ops, condition_ops, unary_ops
from .consts import binary_op_inverses, binary_ops, condition_ops, unary_ops
class Instruction:
pass
@ -9,7 +9,7 @@ class Noop(Instruction):
return "noop"
class Set(Instruction):
def __init__(self, dest, src):
def __init__(self, dest: str, src: str):
self.src = src
self.dest = dest
@ -17,7 +17,7 @@ class Set(Instruction):
return f"set {self.dest} {self.src}"
class BinaryOp(Instruction):
def __init__(self, dest, left, right, op):
def __init__(self, dest: str, left: str, right: str, op: str):
self.left = left
self.right = right
self.op = op
@ -30,7 +30,7 @@ class BinaryOp(Instruction):
return f"op {binary_ops[self.op]} {self.dest} {self.left} {self.right}"
class UnaryOp(Instruction):
def __init__(self, dest, src, op):
def __init__(self, dest: str, src: str, op: str):
self.src = src
self.dest = dest
self.op = op
@ -62,22 +62,36 @@ class RelativeJump(Instruction):
def __str__(self):
return f"jump {self.func_start+self.offset} {self.cond}"
class FunctionCall(Instruction):
def __init__(self, func_name: str):
self.func_name = func_name
self.func_start: int = None
def __str__(self):
return f"jump {self.func_start} {JumpCondition.always}"
class Return(Instruction):
def __str__(self):
return "set @counter __retaddr"
class Print(Instruction):
def __init__(self, val):
def __init__(self, val: str):
self.val = val
def __str__(self):
return f"print {self.val}"
class PrintFlush(Instruction):
def __init__(self, val):
def __init__(self, val: str):
self.val = val
def __str__(self):
return f"printflush {self.val}"
class Radar(Instruction):
def __init__(self, dest, src, target1, target2, target3, sort, index):
def __init__(
self, dest: str, src: str, target1: str, target2: str, target3: str, sort: str, index: str
):
self.src = src
self.dest = dest
self.target1 = target1
@ -90,7 +104,7 @@ class Radar(Instruction):
return f"radar {self.target1} {self.target2} {self.target3} {self.sort} {self.src} {self.index} {self.dest}"
class Sensor(Instruction):
def __init__(self, dest, src, prop):
def __init__(self, dest: str, src: str, prop: str):
self.dest = dest
self.src = src
self.prop = prop
@ -99,7 +113,7 @@ class Sensor(Instruction):
return f"sensor {self.dest} {self.src} @{self.prop}"
class Enable(Instruction):
def __init__(self, obj, enabled):
def __init__(self, obj: str, enabled: str):
self.obj = obj
self.enabled = enabled
@ -107,7 +121,7 @@ class Enable(Instruction):
return f"control enabled {self.obj} {self.enabled} 0 0 0"
class Shoot(Instruction):
def __init__(self, obj, x, y, shoot):
def __init__(self, obj: str, x: str, y: str, shoot: str):
self.obj = obj
self.x = x
self.y = y

Loading…
Cancel
Save