summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <lekensteyn@gmail.com>2011-11-30 23:18:10 +0000
committerPeter Wu <lekensteyn@gmail.com>2011-11-30 23:18:10 +0000
commit9e797458dd8d144544564674a8767c077ed4bd39 (patch)
treed91b68e37c166b01c712a7b5ed9b2a87d29d68f4
parentf8c1ccfac7fc22ba7d316a5b25ee58cd4d26a031 (diff)
downloadpp2cc-9e797458dd8d144544564674a8767c077ed4bd39.tar.gz
Support for all assignment except shifting, fix rightshift bug
-rw-r--r--README2
-rw-r--r--TODO11
-rwxr-xr-xpp2cc.py56
3 files changed, 42 insertions, 27 deletions
diff --git a/README b/README
index 9521338..1e45505 100644
--- a/README
+++ b/README
@@ -63,7 +63,7 @@ Example in bits assuming 4-bit words: 1000 (-8) >> 2 becomes 0010 (2), 0110 (6)
<< 1 becomes 1100 (-4)
A7.14-A7.15 Logical AND && and OR || are supported. Result is indeed 0 or 1
A7.16 Conditional operator ? : - supported
-A7.17 Assignment - supported: = Unsupported: *= /= %= += -= <<= >>= &= ^= |=
+A7.17 Assignment - supported: = *= /= %= += -= &= ^= |= Unsupported: <<= >>=
Supported for variable names only, pointers and array references
A7.18 Comma - supported
A7.19 Constant expressions - not checked
diff --git a/TODO b/TODO
index 0e74c12..ba21e8c 100644
--- a/TODO
+++ b/TODO
@@ -1,16 +1,9 @@
Support for other assignment operators:
-/= *= += -= %= <<= >>= |= &= ^=
+<<= >>=
Post decrement/increment operators:
p-- p++
-Indirection, address and pointers in general
-*x &x x.y x->y
-
-Arrays (definition and use)
-int x;
-int a[2] = {1, 2};
-a[2] = 2;
-x = a[2]
+x.y x->y
Function calls with arguments
diff --git a/pp2cc.py b/pp2cc.py
index 6e6e614..6217f41 100755
--- a/pp2cc.py
+++ b/pp2cc.py
@@ -441,7 +441,7 @@ class Parse(object):
# word size in bits
self.WORDSIZE = 18
# preload operators and their instructions
- self.binary_ops = {
+ self.math_ops = {
"+": "ADD",
"-": "SUB",
"*": "MULS",
@@ -459,6 +459,7 @@ class Parse(object):
"==": "BEQ",
"!=": "BNE"
}
+ self.binary_ops = self.math_ops
self.binary_ops.update(self.comparison_ops)
# local and global variable names to be defined in @DATA
@@ -718,21 +719,27 @@ class Parse(object):
else:
# because DIV works with signed numbers, right shift is
# a bit harder because the sign bit does not vanish
- lbl_make_positive = self.uniqLbl("shiftPositive")
- lines.append(self.asm.binary_op("CMP", reg_first, 0))
- # if it's positive, skip handling for negative values
- lines.append(self.asm.branch_op("BPL", lbl_make_positive))
- # -1 / 2 = 0, so make sure that the last bit is zero
+ # Assume 4-bit numbers in the next example.
+ # binary | decimal
+ # 1111 | -1
+ # 0111 | 7
+ # The rightmost bit is insignificant in a right shift
+ # but causes issues with division by two for -1 because
+ # it gets rounded to 0. After removal of the rightmost
+ # bit and division by two, all bits are shifted left,
+ # but the result is still negative. Since we're doing a
+ # zero-padded shift (unsigned), clear the leftmost bit
+ # For positive numbers, this has no side effects
lines.append(self.asm.binary_op("AND", reg_first, "%10"))
- # shift it by one
- lines.append(self.asm.binary_op("DIV", reg_first, 1))
- # make it positive if not already
+ # shift it by one to the right
+ lines.append(self.asm.binary_op("DIV", reg_first, 2))
+ # clear the leftmost bit by masking it with 011..11
mask = "%0" + (self.WORDSIZE - 1) * "1"
- lines.append(self.asm.binary_op("AND", reg_first, mask,
- label=lbl_make_positive))
+ lines.append(self.asm.binary_op("AND", reg_first, mask))
# decrease shift count and finish if nothing to shift
operand /= 2
if operand > 1:
+ # process the remaining shift
lines.append(self.asm.binary_op("DIV", reg_first, operand))
else:
lbl_gen = self.uniqLbl("gen2_loop")
@@ -747,14 +754,12 @@ class Parse(object):
if op == "<<":
lines.append(self.asm.binary_op("MULS", reg_first, 2, label=lbl_gen))
else:
- # now first check if the first number is negative...
- lines.append(self.asm.binary_op("CMP", reg_first, 0))
- lines.append(self.asm.branch_op("BPL", lbl_gen))
- # shift it by one
- lines.append(self.asm.binary_op("DIV", reg_first, 1))
- # make negative values positive
+ # see above big block of comments for explanation
+ lines.append(self.asm.binary_op("AND", reg_first, "%10"))
+ lines.append(self.asm.binary_op("DIV", reg_first, 2))
mask = "%0" + (self.WORDSIZE - 1) * "1"
lines.append(self.asm.binary_op("AND", reg_first, mask))
+
# decrease shift count and finish if shift count is zero
lines.append(self.asm.binary_op("SUB", reg_second, 1))
lines.append(self.asm.branch_op("BEQ", lbl_gen_end))
@@ -1162,6 +1167,23 @@ class Parse(object):
if node.op == "=":
lines.append(self.asm.binary_op("STOR", result_reg,
"[" + lvalue_reg + "]"))
+ elif (len(node.op) == 2 and node.op[1] == "=" and
+ node.op[0] in self.math_ops):
+ binop = self.math_ops[node.op[0]]
+ # abuse lvalue_reg to save a register by storing the value of the
+ # lvalue. This should allow for doing x / y first before assigning
+ # (writing) to y
+ lines.append(self.asm.push(lvalue_reg))
+ # get the value of lvalue, e.g. the value of x
+ lines.append(self.asm.binary_op("LOAD", lvalue_reg, "["+lvalue_reg+"]"))
+ # perform the operation on the value
+ lines.append(self.asm.binary_op(binop, lvalue_reg, result_reg))
+ # since lvalue_reg is now the integer result, use result_reg as the
+ # register for holding the address of y
+ lines.append(self.asm.pull(result_reg))
+ # finally store the result from lvalue_reg into result_reg
+ lines.append(self.asm.binary_op("STOR", lvalue_reg,
+ "[" + result_reg + "]"))
else:
raise RuntimeError("Unsupported assignment operator: " + node.op)
return lines