add <-iea operator
[soc.git] / src / soc / decoder / pseudo / parser.py
index 6c67265b9c51478bd7aaae7ceb17ffea32612e82..bd05b4e9e8c2f11d7014e5c1fa36f044b5f8a8df 100644 (file)
@@ -14,6 +14,7 @@ import astor
 
 from soc.decoder.power_decoder import create_pdecode
 from soc.decoder.pseudo.lexer import IndentLexer
+from soc.decoder.orderedset import OrderedSet
 
 # I use the Python AST
 #from compiler import ast
@@ -22,7 +23,7 @@ import ast
 # Helper function
 
 
-def Assign(left, right):
+def Assign(left, right, iea_mode):
     names = []
     print("Assign", left, right)
     if isinstance(left, ast.Name):
@@ -106,6 +107,7 @@ def make_eq_compare(arg):
 
 
 binary_ops = {
+    "^": ast.BitXor(),
     "&": ast.BitAnd(),
     "|": ast.BitOr(),
     "+": ast.Add(),
@@ -150,6 +152,27 @@ def identify_sint_mul_pattern(p):
     elt = l[0]
     return isinstance(elt, ast.Constant)
 
+def apply_trailer(atom, trailer):
+    if trailer[0] == "TLIST":
+        # assume depth of one
+        atom = apply_trailer(atom, trailer[1])
+        trailer = trailer[2]
+    if trailer[0] == "CALL":
+        #p[0] = ast.Expr(ast.Call(p[1], p[2][1], []))
+        return ast.Call(atom, trailer[1], [])
+        # if p[1].id == 'print':
+        #    p[0] = ast.Printnl(ast.Tuple(p[2][1]), None, None)
+        # else:
+        #    p[0] = ast.CallFunc(p[1], p[2][1], None, None)
+    else:
+        print("subscript atom", trailer[1])
+        #raise AssertionError("not implemented %s" % p[2][0])
+        subs = trailer[1]
+        if len(subs) == 1:
+            idx = subs[0]
+        else:
+            idx = ast.Slice(subs[0], subs[1], None)
+        return ast.Subscript(atom, idx, ast.Load())
 
 ##########   Parser (tokens -> AST) ######
 
@@ -187,6 +210,7 @@ class PowerParser:
     precedence = (
         ("left", "EQ", "GT", "LT", "LE", "GE", "LTU", "GTU"),
         ("left", "BITOR"),
+        ("left", "BITXOR"),
         ("left", "BITAND"),
         ("left", "PLUS", "MINUS"),
         ("left", "MULT", "DIV", "MOD"),
@@ -197,9 +221,9 @@ class PowerParser:
         self.gprs = {}
         for rname in ['RA', 'RB', 'RC', 'RT', 'RS']:
             self.gprs[rname] = None
-        self.read_regs = []
-        self.uninit_regs = []
-        self.write_regs = []
+        self.read_regs = OrderedSet()
+        self.uninit_regs = OrderedSet()
+        self.write_regs = OrderedSet()
 
     # The grammar comments come from Python's Grammar/Grammar file
 
@@ -296,7 +320,8 @@ class PowerParser:
     # augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' |
     #             '<<=' | '>>=' | '**=' | '//=')
     def p_expr_stmt(self, p):
-        """expr_stmt : testlist ASSIGN testlist
+        """expr_stmt : testlist ASSIGNEA testlist
+                     | testlist ASSIGN testlist
                      | testlist """
         print("expr_stmt", p)
         if len(p) == 2:
@@ -304,17 +329,36 @@ class PowerParser:
             #p[0] = ast.Discard(p[1])
             p[0] = p[1]
         else:
+            iea_mode = p[2] == '<-iea'
+            name = None
             if isinstance(p[1], ast.Name):
                 name = p[1].id
             elif isinstance(p[1], ast.Subscript):
                 name = p[1].value.id
                 if name in self.gprs:
                     # add to list of uninitialised
-                    self.uninit_regs.append(name)
+                    self.uninit_regs.add(name)
+            elif isinstance(p[1], ast.Call) and p[1].func.id == 'GPR':
+                print(astor.dump_tree(p[1]))
+                # replace GPR(x) with GPR[x]
+                idx = p[1].args[0]
+                p[1] = ast.Subscript(p[1].func, idx)
+            elif isinstance(p[1], ast.Call) and p[1].func.id == 'MEM':
+                print ("mem assign")
+                print(astor.dump_tree(p[1]))
+                p[1].func.id = "memassign" # change function name to set
+                p[1].args.append(p[3])
+                p[0] = p[1]
+                print ("mem rewrite")
+                print(astor.dump_tree(p[0]))
+                return
+            else:
+                print ("help, help")
+                print(astor.dump_tree(p[1]))
             print("expr assign", name, p[1])
-            if name in self.gprs:
-                self.write_regs.append(name)  # add to list of regs to write
-            p[0] = Assign(p[1], p[3])
+            if name and name in self.gprs:
+                self.write_regs.add(name)  # add to list of regs to write
+            p[0] = Assign(p[1], p[3], iea_mode)
 
     def p_flow_stmt(self, p):
         "flow_stmt : return_stmt"
@@ -339,9 +383,9 @@ class PowerParser:
         p[0] = ast.Break()
 
     def p_for_stmt(self, p):
-        """for_stmt : FOR test EQ test TO test COLON suite
+        """for_stmt : FOR atom EQ test TO test COLON suite
+                    | DO atom EQ test TO test COLON suite
         """
-        p[0] = ast.While(p[2], p[4], [])
         # auto-add-one (sigh) due to python range
         start = p[4]
         end = ast.BinOp(p[6], ast.Add(), ast.Constant(1))
@@ -399,6 +443,7 @@ class PowerParser:
                       | comparison LT comparison
                       | comparison GT comparison
                       | comparison BITOR comparison
+                      | comparison BITXOR comparison
                       | comparison BITAND comparison
                       | PLUS comparison
                       | comparison MINUS
@@ -432,30 +477,18 @@ class PowerParser:
 
     # power: atom trailer* ['**' factor]
     # trailers enables function calls (and subscripts).
-    # I only allow one level of calls
-    # so this is 'trailer'
+    # so this is 'trailerlist'
     def p_power(self, p):
         """power : atom
-                 | atom trailer"""
+                 | atom trailerlist"""
         if len(p) == 2:
             p[0] = p[1]
         else:
-            if p[2][0] == "CALL":
-                #p[0] = ast.Expr(ast.Call(p[1], p[2][1], []))
-                p[0] = ast.Call(p[1], p[2][1], [])
-                # if p[1].id == 'print':
-                #    p[0] = ast.Printnl(ast.Tuple(p[2][1]), None, None)
-                # else:
-                #    p[0] = ast.CallFunc(p[1], p[2][1], None, None)
-            else:
-                print("subscript atom", p[2][1])
-                #raise AssertionError("not implemented %s" % p[2][0])
-                subs = p[2][1]
-                if len(subs) == 1:
-                    idx = subs[0]
-                else:
-                    idx = ast.Slice(subs[0], subs[1], None)
-                p[0] = ast.Subscript(p[1], idx, ast.Load())
+            print("power dump atom")
+            print(astor.dump_tree(p[1]))
+            print("power dump trailerlist")
+            print(astor.dump_tree(p[2]))
+            p[0] = apply_trailer(p[1], p[2])
 
     def p_atom_name(self, p):
         """atom : NAME"""
@@ -485,13 +518,43 @@ class PowerParser:
     def p_atom_tuple(self, p):
         """atom : LPAR testlist RPAR"""
         print("tuple", p[2])
+        print("astor dump")
+        print(astor.dump_tree(p[2]))
+
         if isinstance(p[2], ast.Name):
             print("tuple name", p[2].id)
             if p[2].id in self.gprs:
-                self.read_regs.append(p[2].id)  # add to list of regs to read
+                self.read_regs.add(p[2].id)  # add to list of regs to read
                 #p[0] = ast.Subscript(ast.Name("GPR"), ast.Str(p[2].id))
                 # return
-        p[0] = p[2]
+            p[0] = p[2]
+        elif isinstance(p[2], ast.BinOp):
+            if isinstance(p[2].left, ast.Name) and \
+               isinstance(p[2].right, ast.Constant) and \
+                p[2].right.value == 0 and \
+                p[2].left.id in self.gprs:
+                    rid = p[2].left.id
+                    self.read_regs.add(rid)  # add to list of regs to read
+                    # create special call to GPR.getz
+                    gprz = ast.Name("GPR")
+                    gprz = ast.Attribute(gprz, "getz")   # get testzero function
+                    # *sigh* see class GPR.  we need index itself not reg value
+                    ridx = ast.Name("_%s" % rid)
+                    p[0] = ast.Call(gprz, [ridx], [])
+                    print("tree", astor.dump_tree(p[0]))
+            else:
+                p[0] = p[2]
+        else:
+            p[0] = p[2]
+
+    def p_trailerlist(self, p):
+        """trailerlist : trailer trailerlist
+                       | trailer
+        """
+        if len(p) == 2:
+            p[0] = p[1]
+        else:
+            p[0] = ("TLIST", p[1], p[2])
 
     # trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
     def p_trailer(self, p):
@@ -585,20 +648,21 @@ class PowerParser:
 
 
 class GardenSnakeParser(PowerParser):
-    def __init__(self, lexer=None):
+    def __init__(self, lexer=None, debug=False):
         PowerParser.__init__(self)
+        self.debug = debug
         if lexer is None:
             lexer = IndentLexer(debug=0)
         self.lexer = lexer
         self.tokens = lexer.tokens
         self.parser = yacc.yacc(module=self, start="file_input_end",
-                                debug=False, write_tables=False)
+                                debug=debug, write_tables=False)
 
         self.sd = create_pdecode()
 
     def parse(self, code):
         # self.lexer.input(code)
-        result = self.parser.parse(code, lexer=self.lexer, debug=False)
+        result = self.parser.parse(code, lexer=self.lexer, debug=self.debug)
         return ast.Module(result)
 
 
@@ -607,8 +671,8 @@ class GardenSnakeParser(PowerParser):
 #from compiler import misc, syntax, pycodegen
 
 class GardenSnakeCompiler(object):
-    def __init__(self):
-        self.parser = GardenSnakeParser()
+    def __init__(self, debug=False):
+        self.parser = GardenSnakeParser(debug=debug)
 
     def compile(self, code, mode="exec", filename="<string>"):
         tree = self.parser.parse(code)