unary operator ~ (bitwise invert)

This commit is contained in:
Irmen de Jong 2017-12-28 00:44:17 +01:00
parent f5c7573fb3
commit e1ef9ff611
4 changed files with 86 additions and 30 deletions

View File

@ -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)

View File

@ -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

View File

@ -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] [<expression>] goto <label>
The if-status XX is one of: [cc, cs, vc, vs, eq, ne, pos, neg, true==ne, not==eq, zero==eq, lt==cc, gt==eq+cs, le==cc+eq, ge==cs]
It defaults to 'true' (=='ne', not-zero) if omitted. @todo signed: lts==neg?, gts==eq+pos?, les==neg+eq?, ges==pos?
The <expression> is optional. If it is provided, it will be evaluated first. Only the [true] and [not] if-statuses
can be used when such a *comparison expression* is used. An example is:
``if_not A > 55 goto more_iterations``
NOTE: some combination branches such as cc+eq an be peephole optimized see http://www.6502.org/tutorials/compare_beyond.html#2.2
Debugging (with Vice)
---------------------
The ``breakpoint`` statement is a special statement that instructs the compiler to put
@ -328,29 +348,10 @@ Vice will use the label names in memory disassembly, and will activate the break
so if your program runs and it hits a breakpoint, Vice will halt execution and drop into the monitor.
TODOS
-----
### Flow Control
Required building blocks: additional forms of 'goto' statement: including an if clause, comparison statement.
- a conditional goto instruction: directly translates to a branch instruction:
if[_XX] [<expression>] goto <label>
The if-status XX is one of: [cc, cs, vc, vs, eq, ne, pos, neg, true==ne, not==eq, zero==eq,
lt==cc, gt==eq+cs, le==cc+eq, ge==cs]
(@todo signed: lts==neg?, gts==eq+pos?, les==neg+eq?, ges==pos?)
and defaults to true (ne, not-zero) if omitted.
The <expression> is optional. If it is provided, it will be evaluated first. Only the [true] and [not] if-statuses
can be used when a *comparison expression* (such as "A < 10") is used.
NOTE: some combination branches such as cc+eq an be peephole optimized see http://www.6502.org/tutorials/compare_beyond.html#2.2
- comparison statement: compares left with right: compare <first_value>, <second_value>
(and keeps the comparison result in the status register.)
this translates into a lda first_value, cmp second_value sequence after which a conditional branch is possible.
### IF_XX:
if[_XX] [<expression>] {

View File

@ -8,16 +8,28 @@ output raw
start
A = 44
X = ~22+44
A= ~-1
Y = ~-2
return
label1
if_true A==0 goto label1
if_true A!=0 goto label1
if_not X!=0 goto label1
if_true A<=1 goto label1
if_true A==1 goto label1
if_true A!=1 goto label1
if_not X<1 goto label1
if_not Y>1 goto label1
if_not X!=1 goto label1
if_true 22<=Y goto label1
if_true A<=22 goto label1
if_true A<X goto label1
if_true X>Y goto label1
if_true X>A goto label1
if_true A<=0 goto label1
if_true A==0 goto label1
if_true A!=0 goto label1
if A<=22 goto label1
if_cc A goto label1
if_vc X goto label1