diff --git a/il65/astparse.py b/il65/astparse.py index 169c53103..c56e3c488 100644 --- a/il65/astparse.py +++ b/il65/astparse.py @@ -222,9 +222,20 @@ class ExpressionTransformer(EvaluatingTransformer): if isinstance(node.op, ast.UAdd): node = self.generic_visit(node) return ast.copy_location(ast.Num(node.operand.n), node) - raise self.error("expected unary + or -") + if isinstance(node.op, ast.Invert): + if isinstance(node.operand, ast.Num): + node = self.generic_visit(node) + return ast.copy_location(ast.Num(~node.operand.n), node) + else: + raise self.error("can only bitwise invert a number") + raise self.error("expected unary + or - or ~") + elif isinstance(node.operand, ast.UnaryOp): + # nested unary ops, for instance: "~-2" = invert(minus(2)) + node = self.generic_visit(node) + return self.visit_UnaryOp(node) else: - raise self.error("expected numeric operand for unary operator") + print(node.operand) + raise self.error("expected constant numeric operand for unary operator") def visit_BinOp(self, node): node = self.generic_visit(node) @@ -262,5 +273,14 @@ def astnode_to_repr(node: ast.AST) -> str: raise TypeError("invalid arg ast node type", node) if isinstance(node, ast.Attribute): return astnode_to_repr(node.value) + "." + node.attr + if isinstance(node, ast.UnaryOp): + if isinstance(node.op, ast.USub): + return "-" + astnode_to_repr(node.operand) + if isinstance(node.op, ast.UAdd): + return "+" + astnode_to_repr(node.operand) + if isinstance(node.op, ast.Invert): + return "~" + astnode_to_repr(node.operand) + if isinstance(node.op, ast.Not): + return "not " + astnode_to_repr(node.operand) print("error", ast.dump(node)) raise TypeError("invalid arg ast node type", node) diff --git a/il65/parse.py b/il65/parse.py index ce38c23e7..0808fc897 100644 --- a/il65/parse.py +++ b/il65/parse.py @@ -1363,7 +1363,7 @@ class Parser: return ParseResult.IntegerValue(expression.address, datatype=DataType.WORD, name=expression.name) else: raise self.PError("cannot take the address of this type") - elif text[0] in "-.0123456789$%": + elif text[0] in "-.0123456789$%~": number = parse_expr_as_number(text, self.cur_block.symbols, self.ppsymbols, self.sourceref) try: if type(number) is int: @@ -1592,9 +1592,32 @@ class Optimizer: # the comparison operator and rvalue (0) will be removed and the if-status changed accordingly for stmt in block.statements: if isinstance(stmt, ParseResult.CallStmt): - if stmt.condition and isinstance(stmt.condition.rvalue, (ParseResult.IntegerValue, ParseResult.FloatValue)): - if stmt.condition.rvalue.value == 0: - print("ZOMG COMPARE WITH ZERO", stmt.lineno) # XXX + cond = stmt.condition + if cond and isinstance(cond.rvalue, (ParseResult.IntegerValue, ParseResult.FloatValue)) and cond.rvalue.value == 0: + simplified = False + if cond.ifstatus in ("true", "ne"): + if cond.comparison_op == "==": + # if_true something == 0 -> if_not something + cond.ifstatus = "not" + cond.comparison_op, cond.rvalue = "", None + simplified = True + elif cond.comparison_op == "!=": + # if_true something != 0 -> if_true something + cond.comparison_op, cond.rvalue = "", None + simplified = True + elif cond.ifstatus in ("not", "eq"): + if cond.comparison_op == "==": + # if_not something == 0 -> if_true something + cond.ifstatus = "true" + cond.comparison_op, cond.rvalue = "", None + simplified = True + elif cond.comparison_op == "!=": + # if_not something != 0 -> if_not something + cond.comparison_op, cond.rvalue = "", None + simplified = True + if simplified: + print("{:s}:{:d}: simplified comparison with zero".format(block.sourceref.file, stmt.lineno)) + def combine_assignments_into_multi(self, block: ParseResult.Block) -> None: # fold multiple consecutive assignments with the same rvalue into one multi-assignment diff --git a/reference.md b/reference.md index 12e38c928..d39e57d61 100644 --- a/reference.md +++ b/reference.md @@ -311,7 +311,27 @@ essentially is the same as calling a subroutine and only doing something differe @todo support call non-register args (variable parameter passing) -DEBUGGING (with Vice) +### Conditional Execution Flow + +Conditional execution flow means that the flow of execution changes based on certiain conditions, +rather than having fixed gotos or subroutine calls. IL65 has a *conditional goto* statement for this, +that is translated into a comparison (if needed) and then a conditional branch instruction: + + if[_XX] [] goto