mirror of
https://github.com/irmen/prog8.git
synced 2024-09-10 09:54:32 +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):
|
if isinstance(node.op, ast.UAdd):
|
||||||
node = self.generic_visit(node)
|
node = self.generic_visit(node)
|
||||||
return ast.copy_location(ast.Num(node.operand.n), 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:
|
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):
|
def visit_BinOp(self, node):
|
||||||
node = self.generic_visit(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)
|
raise TypeError("invalid arg ast node type", node)
|
||||||
if isinstance(node, ast.Attribute):
|
if isinstance(node, ast.Attribute):
|
||||||
return astnode_to_repr(node.value) + "." + node.attr
|
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))
|
print("error", ast.dump(node))
|
||||||
raise TypeError("invalid arg ast node type", 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)
|
return ParseResult.IntegerValue(expression.address, datatype=DataType.WORD, name=expression.name)
|
||||||
else:
|
else:
|
||||||
raise self.PError("cannot take the address of this type")
|
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)
|
number = parse_expr_as_number(text, self.cur_block.symbols, self.ppsymbols, self.sourceref)
|
||||||
try:
|
try:
|
||||||
if type(number) is int:
|
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
|
# the comparison operator and rvalue (0) will be removed and the if-status changed accordingly
|
||||||
for stmt in block.statements:
|
for stmt in block.statements:
|
||||||
if isinstance(stmt, ParseResult.CallStmt):
|
if isinstance(stmt, ParseResult.CallStmt):
|
||||||
if stmt.condition and isinstance(stmt.condition.rvalue, (ParseResult.IntegerValue, ParseResult.FloatValue)):
|
cond = stmt.condition
|
||||||
if stmt.condition.rvalue.value == 0:
|
if cond and isinstance(cond.rvalue, (ParseResult.IntegerValue, ParseResult.FloatValue)) and cond.rvalue.value == 0:
|
||||||
print("ZOMG COMPARE WITH ZERO", stmt.lineno) # XXX
|
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:
|
def combine_assignments_into_multi(self, block: ParseResult.Block) -> None:
|
||||||
# fold multiple consecutive assignments with the same rvalue into one multi-assignment
|
# 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)
|
@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
|
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.
|
so if your program runs and it hits a breakpoint, Vice will halt execution and drop into the monitor.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TODOS
|
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:
|
||||||
|
|
||||||
if[_XX] [<expression>] {
|
if[_XX] [<expression>] {
|
||||||
|
@ -8,16 +8,28 @@ output raw
|
|||||||
|
|
||||||
|
|
||||||
start
|
start
|
||||||
|
A = 44
|
||||||
|
X = ~22+44
|
||||||
|
A= ~-1
|
||||||
|
Y = ~-2
|
||||||
return
|
return
|
||||||
label1
|
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 22<=Y goto label1
|
||||||
if_true A<=22 goto label1
|
if_true A<=22 goto label1
|
||||||
if_true A<X goto label1
|
if_true A<X goto label1
|
||||||
if_true X>Y goto label1
|
if_true X>Y goto label1
|
||||||
if_true X>A 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 A<=22 goto label1
|
||||||
if_cc A goto label1
|
if_cc A goto label1
|
||||||
if_vc X goto label1
|
if_vc X goto label1
|
||||||
|
Loading…
Reference in New Issue
Block a user