mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +00:00
unary operator ~ (bitwise invert)
This commit is contained in:
parent
f5c7573fb3
commit
e1ef9ff611
@ -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("expected numeric operand for unary operator")
|
||||
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:
|
||||
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)
|
||||
|
@ -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
|
||||
|
43
reference.md
43
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] [<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>] {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user