From f8adc5919b3988555cfec96de857c35822e5834b Mon Sep 17 00:00:00 2001 From: Larry Xue Date: Sun, 23 Aug 2020 00:16:14 -0400 Subject: [PATCH] fixed bug with loop cond jump --- README.md | 20 +++++++++++++++ c2logic/compiler.py | 54 +++++++++++++++++++---------------------- examples/control_flow.c | 14 +++++++---- setup.py | 2 +- 4 files changed, 55 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 880684d..3c0788b 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,23 @@ Compiles C code to Mindustry logic. where `filename` is a string and `optimization_level` is an int See [examples](./examples) for API sample usage. + +# Documentation + +TODO + +See `include/mindustry.h`. + +# Unsupported Features + +- drawing +- getlink +- memory cell read/write +- do-while +- continue +- goto +- actual functions +- structs +- enums + +Some of these features may be worked around using `_asm()`. diff --git a/c2logic/compiler.py b/c2logic/compiler.py index 360c302..deb4669 100644 --- a/c2logic/compiler.py +++ b/c2logic/compiler.py @@ -1,14 +1,7 @@ from pycparser.c_ast import Compound, Constant, DeclList, Enum, FileAST, FuncDecl, Struct, TypeDecl from .instructions import BinaryOp, Enable, JumpCondition, Print, PrintFlush, Radar, RawAsm, RelativeJump, Sensor, Shoot, UnaryOp, Instruction, Set, Noop -from pycparser import c_parser, c_ast, parse_file +from pycparser import c_ast, parse_file from dataclasses import dataclass -""" -@dataclass -class LoopState(): - start: int - end: int - cond_jump_offset: int -""" @dataclass class Function(): @@ -29,8 +22,6 @@ class Compiler(c_ast.NodeVisitor): __rax: similar to x86 rax __rbx: stores left hand side of binary ops to avoid clobbering by the right side __retaddr: stores return address of func call - optimization levels: - 1: assignments set directly to the variable instead of indirectly through __rax """ def __init__(self, opt_level=0): self.opt_level = opt_level @@ -148,6 +139,7 @@ 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 else: self.visit(node.expr) self.push(UnaryOp("__rax", "__rax", node.op)) @@ -157,8 +149,10 @@ class Compiler(c_ast.NodeVisitor): self.loop_start = len(self.curr_function.instructions) self.visit(node.cond) # jump over loop body when cond is false - if isinstance(self.peek(), BinaryOp): - self.push(RelativeJump(None, JumpCondition.from_binaryop(self.pop()))) + if self.opt_level >= 1 and isinstance(self.peek(), BinaryOp): + #TODO fix this + self.push(RelativeJump(None, JumpCondition("==", "__rax", "0"))) + #self.push(RelativeJump(None, JumpCondition.from_binaryop(self.pop()))) else: self.push(RelativeJump(None, JumpCondition("==", "__rax", "0"))) self.cond_jump_offset = len(self.curr_function.instructions) - 1 @@ -174,8 +168,10 @@ class Compiler(c_ast.NodeVisitor): self.loop_start = len(self.curr_function.instructions) self.visit(node.cond) # jump over loop body when cond is false - if isinstance(self.peek(), BinaryOp): - self.push(RelativeJump(None, JumpCondition.from_binaryop(self.pop()))) + if self.opt_level >= 1 and isinstance(self.peek(), BinaryOp): + #TODO fix this + self.push(RelativeJump(None, JumpCondition("==", "__rax", "0"))) + #self.push(RelativeJump(None, JumpCondition.from_binaryop(self.pop()))) else: self.push(RelativeJump(None, JumpCondition("==", "__rax", "0"))) self.loop_end_jumps = [len(self.curr_function.instructions) - 1] # also used for breaks @@ -189,10 +185,10 @@ class Compiler(c_ast.NodeVisitor): self.visit(node.cond) # jump over if body when cond is false #TODO optimize for when cond is a binary operation - if isinstance(self.peek(), BinaryOp): - self.push(RelativeJump(None, JumpCondition("!=", "__rax", "0"))) + if self.opt_level >= 1 and isinstance(self.peek(), BinaryOp): + self.push(RelativeJump(None, JumpCondition("==", "__rax", "0"))) else: - self.push(RelativeJump(None, JumpCondition("!=", "__rax", "0"))) + self.push(RelativeJump(None, JumpCondition("==", "__rax", "0"))) cond_jump_offset = len(self.curr_function.instructions) - 1 self.visit(node.iftrue) #jump over else body from end of if body @@ -242,12 +238,12 @@ class Compiler(c_ast.NodeVisitor): self.visit(arg) self.set_to_rax(f"__radar_arg{i}") args.append(f"__radar_arg{i}") - - for i, arg in reversed(list(enumerate(args))): - if self.can_avoid_indirection(arg): - args[i] = self.pop().src - else: - break + if self.opt_level >= 1: + for i, arg in reversed(list(enumerate(args))): + if self.can_avoid_indirection(arg): + args[i] = self.pop().src + else: + break self.push(Radar("__rax", *args)) #pylint: disable=no-value-for-parameter elif name == "sensor": self.visit(node.args.exprs[0]) @@ -280,12 +276,12 @@ class Compiler(c_ast.NodeVisitor): self.visit(arg) self.set_to_rax(f"__shoot_arg{i}") args.append(f"__shoot_arg{i}") - - for i, arg in reversed(list(enumerate(args))): - if self.can_avoid_indirection(arg): - args[i] = self.pop().src - else: - break + if self.opt_level >= 1: + for i, arg in reversed(list(enumerate(args))): + if self.can_avoid_indirection(arg): + args[i] = self.pop().src + else: + break self.push(Shoot(*args)) #pylint: disable=no-value-for-parameter else: diff --git a/examples/control_flow.c b/examples/control_flow.c index 9a04f90..e039739 100644 --- a/examples/control_flow.c +++ b/examples/control_flow.c @@ -3,13 +3,17 @@ extern struct MindustryObject message1; void main(void) { double i = 0; while (i < 10) { - if (i == 3) { - print("is 3"); - } else { - print("not 3"); - } + printd(i); + i++; } + print("\n"); + i = 0; printd(i); + if (i == 3) { + print(" is 3"); + } else { + print(" is not 3"); + } print("\n"); printflush(message1); } \ No newline at end of file diff --git a/setup.py b/setup.py index 8bd3318..107b8c6 100755 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ with open("README.md", "r") as f: setuptools.setup( name="c2logic", version="0.1", - descripton="Compiles C code to mindustry logic.", + descripton="Compiles C code to Mindustry logic.", long_description=long_description, long_description_content_type="text/markdown", packages=["c2logic"],