From 06c28826132c64c4d7353fa9a12a85e422742e4a Mon Sep 17 00:00:00 2001 From: Larry Xue Date: Sun, 23 Aug 2020 16:02:22 -0400 Subject: [PATCH] added do while, logical not, preincrement --- c2logic/compiler.py | 72 +++++++++++++++++++++++++++-------------- c2logic/operations.py | 1 - examples/control_flow.c | 12 ++++--- include/mindustry.h | 2 +- 4 files changed, 57 insertions(+), 30 deletions(-) diff --git a/c2logic/compiler.py b/c2logic/compiler.py index 8c7333d..4cf5954 100644 --- a/c2logic/compiler.py +++ b/c2logic/compiler.py @@ -28,7 +28,7 @@ class Compiler(c_ast.NodeVisitor): self.functions = [] self.curr_function: Function = None self.loop_start: int = None - self.loop_end_jumps:list = None + self.loop_end_jumps: list = None #self.cond_jump_offset: int = None def compile(self, filename: str): @@ -79,7 +79,7 @@ class Compiler(c_ast.NodeVisitor): self.push(Set(varname, "__rax")) def push_body_jump(self): - # jump over loop/if body when cond is false + """ jump over loop/if body when cond is false """ if self.opt_level >= 1 and isinstance(self.peek(), BinaryOp): try: self.push(RelativeJump(None, JumpCondition.from_binaryop(self.pop().inverse()))) @@ -88,6 +88,19 @@ class Compiler(c_ast.NodeVisitor): else: self.push(RelativeJump(None, JumpCondition("==", "__rax", "0"))) + def start_loop(self, cond): + self.loop_start = len(self.curr_function.instructions) + self.visit(cond) + self.push_body_jump() + self.loop_end_jumps = [len(self.curr_function.instructions) - 1] # 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.loop_start = None + self.loop_end_jumps = None + def optimize_psuedofunc_args(self, args): if self.opt_level >= 1: for i, arg in reversed(list(enumerate(args))): @@ -105,8 +118,8 @@ class Compiler(c_ast.NodeVisitor): self.curr_function = Function(node.decl.name, args, [], None) self.visit(node.body) #in case for loop is the last thing in a function to ensure the jump target is valid - #TODO avoid this when for loop isn't last thing - self.push(Noop()) + if self.loop_start is not None: + self.push(Noop()) self.functions.append(self.curr_function) def visit_Decl(self, node): @@ -136,9 +149,9 @@ class Compiler(c_ast.NodeVisitor): else: #augmented assignment(+=,-=,etc) if self.can_avoid_indirection(): #avoid indirection through __rax - self.push(BinaryOp(varname, varname, self.pop().src, node.op[0])) + self.push(BinaryOp(varname, varname, self.pop().src, node.op[:-1])) else: - self.push(BinaryOp(varname, varname, "__rax", node.op[0])) + self.push(BinaryOp(varname, varname, "__rax", node.op[:-1])) def visit_Constant(self, node): # literals self.push(Set("__rax", node.value)) @@ -163,34 +176,45 @@ class Compiler(c_ast.NodeVisitor): varname = node.expr.name self.push(Set("__rax", varname)) self.push(BinaryOp(varname, varname, "1", node.op[1])) - #TODO preincrement/predecrement + elif node.op == "++" or node.op == "--": + varname = node.expr.name + self.push(BinaryOp(varname, varname, "1", node.op[0])) + self.push(Set("__rax", varname)) + elif node.op == "!": + self.visit(node.expr) + if self.opt_level >= 1 and isinstance(self.peek(), BinaryOp): + try: + self.push(self.pop().inverse()) + except KeyError: + self.push(BinaryOp("__rax", "__rax", "0", "==")) + else: + self.push(BinaryOp("__rax", "__rax", "0", "==")) else: self.visit(node.expr) self.push(UnaryOp("__rax", "__rax", node.op)) def visit_For(self, node): self.visit(node.init) - self.loop_start = len(self.curr_function.instructions) - self.visit(node.cond) - self.push_body_jump() - self.loop_end_jumps = [len(self.curr_function.instructions) - 1] # also used for breaks + self.start_loop(node.cond) self.visit(node.stmt) # loop body self.visit(node.next) - #jump to start of loop - 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.end_loop() def visit_While(self, node): - self.loop_start = len(self.curr_function.instructions) - self.visit(node.cond) - self.push_body_jump() - self.loop_end_jumps = [len(self.curr_function.instructions) - 1] # also used for breaks + self.start_loop(node.cond) self.visit(node.stmt) - #jump to start of loop - 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.end_loop() + + 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 + self.start_loop(node.cond) + self.curr_function.instructions[init_jump_offset].offset = len( + self.curr_function.instructions + ) + self.visit(node.stmt) + self.end_loop() def visit_If(self, node): self.visit(node.cond) @@ -220,7 +244,7 @@ class Compiler(c_ast.NodeVisitor): def visit_FuncCall(self, node): name = node.name.name #TODO avoid duplication in psuedo-function calls - if name == "_asm": + if name == "asm": arg = node.args.exprs[0] if not isinstance(arg, Constant) or arg.type != "string": raise TypeError("Non-string argument to _asm", node) diff --git a/c2logic/operations.py b/c2logic/operations.py index 45514cf..bf45148 100644 --- a/c2logic/operations.py +++ b/c2logic/operations.py @@ -10,7 +10,6 @@ binary_ops = { "<=": "lessThanEq", ">": "greaterThan", ">=": "greaterThanEq", - "^": "pow", ">>": "shl", "<<": "shr", "|": "or", diff --git a/examples/control_flow.c b/examples/control_flow.c index 0e2eec2..3c9396f 100644 --- a/examples/control_flow.c +++ b/examples/control_flow.c @@ -2,16 +2,19 @@ extern struct MindustryObject message1; void main(void) { int i = 0; - while (i < 10) { + for (i = 5; i < 9; i++) { + printd(i); + } + do { if (i % 2 == 1) { continue; } printd(i); - i++; - if (i == 4) { + ++i; + if (i == 8) { break; } - } + } while (!(i >= 10)); print("\n"); i = 0; printd(i); @@ -22,4 +25,5 @@ void main(void) { } print("\n"); printflush(message1); + asm("noop"); } \ No newline at end of file diff --git a/include/mindustry.h b/include/mindustry.h index c980e48..f11db0f 100644 --- a/include/mindustry.h +++ b/include/mindustry.h @@ -1,7 +1,7 @@ #ifndef MINDUSTRY_H #define MINDUSTRY_H struct MindustryObject {}; -void _asm(char* code); +// void _asm(char* code); void print(char* s); void printd(double s); void printflush(struct MindustryObject msg_block);