changeset 11:b89582ed94be draft

Make arithmetic parser really succinct.
author Lewin Bormann <lbo@spheniscida.de>
date Sun, 19 May 2019 18:03:56 +0200
parents d29f53479f83
children 03803eda236a
files arith_test.py
diffstat 1 files changed, 25 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/arith_test.py	Sun May 19 18:03:46 2019 +0200
+++ b/arith_test.py	Sun May 19 18:03:56 2019 +0200
@@ -10,10 +10,12 @@
 
 
 def Parens():
+    """Parentheses contain a term."""
     return (Operator('(') + Term() + Operator(')')) >> (lambda l: l[1])
 
 def Variable():
-    return Last(Whitespace() + Regex('\w+'))
+    """A variable consists of several letters."""
+    return Last(Whitespace() + Regex('[a-zA-Z]+[0-9]*'))
 
 def Atom():
     """An atom is a variable or a float or a parentheses term."""
@@ -23,52 +25,35 @@
     """An operator or parenthesis."""
     return Last(Skip(Whitespace()) + OneOf(set))
 
+def Power():
+    return (
+            OptimisticSequence(Last(Atom()), Operator('^'), Last(Atom())) >>
+            (lambda l: (l[0], l[1], l[2]) if len(l) == 3 else l[0])
+            )
+
+class Psower(Parser):
+
+    def parse(self, st):
+        p = OptimisticSequence(Last(Atom()), Operator('^'), Last(Atom()))
+        to_tuple = p >> (lambda l: (l[0], l[1], l[2]) if len(l) == 3 else l[0])
+        return to_tuple.parse(st)
+
 class Product(Parser):
 
     def parse(self, st):
-        initial = st.index()
-
-        left, st = Atom().parse(st)
-        print('p', left, st)
-        if left is None:
-            st.reset(initial)
-            return None, st
-
-        op, st = Operator('*/').parse(st)
-        print('p', op, st)
-        if op is None:
-            return left, st
-
-        right, st = Product().parse(st)
-        print('p', right, st)
-        if right is None:
-            st.reset(initial)
-            return None, st
-        return ((left, op, right), st)
+        # Try to parse an atom, a product operator, and another product.
+        p = OptimisticSequence(Power(), Operator('*/'), Product())
+        to_tuple = p >> (lambda l: (l[0], l[1], l[2]) if len(l) == 3 else l[0])
+        return to_tuple.parse(st)
 
 class Term(Parser):
 
     def parse(self, st):
-        initial = st.index()
-
-        left, st = Product().parse(st)
-        print('t', left, st)
-        if left is None:
-            st.reset(initial)
-            return None, st
-
-        op, st = Operator('+-').parse(st)
-        print('t', op, st)
-        if op is None:
-            return left, st
-
-        right, st = Term().parse(st)
-        print(right, st)
-        if right is None:
-            st.reset(initial)
-            return None, st
-
-        return (left, op, right), st
+        # Try to parse a product, then a sum operator, then another term.
+        # OptimisticSequence will just return a product if there is no sum operator.
+        p = OptimisticSequence(Product(), Operator('+-'), Term())
+        to_tuple = p >> (lambda l: (l[0], l[1], l[2]) if len(l) == 3 else l[0])
+        return to_tuple.parse(st)
 
 def pretty_print(tpl):
     # tpl is a (left, op, right) tuple or a scalar.