From 9e797458dd8d144544564674a8767c077ed4bd39 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Wed, 30 Nov 2011 23:18:10 +0000 Subject: Support for all assignment except shifting, fix rightshift bug --- README | 2 +- TODO | 11 ++--------- pp2cc.py | 56 +++++++++++++++++++++++++++++++++++++++----------------- 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 -- cgit v1.2.1