diff ply-3.8/example/closurecalc/calc.py @ 7267:343ff337a19b

<ais523> ` tar -xf ply-3.8.tar.gz
author HackBot
date Wed, 23 Mar 2016 02:40:16 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ply-3.8/example/closurecalc/calc.py	Wed Mar 23 02:40:16 2016 +0000
@@ -0,0 +1,130 @@
+# -----------------------------------------------------------------------------
+# calc.py
+#
+# A calculator parser that makes use of closures. The function make_calculator()
+# returns a function that accepts an input string and returns a result.  All 
+# lexing rules, parsing rules, and internal state are held inside the function.
+# -----------------------------------------------------------------------------
+
+import sys
+sys.path.insert(0,"../..")
+
+if sys.version_info[0] >= 3:
+    raw_input = input
+
+# Make a calculator function
+
+def make_calculator():
+    import ply.lex as lex
+    import ply.yacc as yacc
+
+    # ------- Internal calculator state
+
+    variables = { }       # Dictionary of stored variables
+
+    # ------- Calculator tokenizing rules
+
+    tokens = (
+        'NAME','NUMBER',
+    )
+
+    literals = ['=','+','-','*','/', '(',')']
+
+    t_ignore = " \t"
+
+    t_NAME    = r'[a-zA-Z_][a-zA-Z0-9_]*'
+
+    def t_NUMBER(t):
+        r'\d+'
+        t.value = int(t.value)
+        return t
+
+    def t_newline(t):
+        r'\n+'
+        t.lexer.lineno += t.value.count("\n")
+    
+    def t_error(t):
+        print("Illegal character '%s'" % t.value[0])
+        t.lexer.skip(1)
+    
+    # Build the lexer
+    lexer = lex.lex()
+
+    # ------- Calculator parsing rules
+
+    precedence = (
+        ('left','+','-'),
+        ('left','*','/'),
+        ('right','UMINUS'),
+    )
+
+    def p_statement_assign(p):
+        'statement : NAME "=" expression'
+        variables[p[1]] = p[3]
+        p[0] = None
+
+    def p_statement_expr(p):
+        'statement : expression'
+        p[0] = p[1]
+
+    def p_expression_binop(p):
+        '''expression : expression '+' expression
+                      | expression '-' expression
+                      | expression '*' expression
+                      | expression '/' expression'''
+        if p[2] == '+'  : p[0] = p[1] + p[3]
+        elif p[2] == '-': p[0] = p[1] - p[3]
+        elif p[2] == '*': p[0] = p[1] * p[3]
+        elif p[2] == '/': p[0] = p[1] / p[3]
+
+    def p_expression_uminus(p):
+        "expression : '-' expression %prec UMINUS"
+        p[0] = -p[2]
+
+    def p_expression_group(p):
+        "expression : '(' expression ')'"
+        p[0] = p[2]
+
+    def p_expression_number(p):
+        "expression : NUMBER"
+        p[0] = p[1]
+
+    def p_expression_name(p):
+        "expression : NAME"
+        try:
+            p[0] = variables[p[1]]
+        except LookupError:
+            print("Undefined name '%s'" % p[1])
+            p[0] = 0
+
+    def p_error(p):
+        if p:
+            print("Syntax error at '%s'" % p.value)
+        else:
+            print("Syntax error at EOF")
+
+
+    # Build the parser
+    parser = yacc.yacc()
+
+    # ------- Input function 
+    
+    def input(text):
+        result = parser.parse(text,lexer=lexer)
+        return result
+
+    return input
+
+# Make a calculator object and use it
+calc = make_calculator()
+
+while True:
+    try:
+        s = raw_input("calc > ")
+    except EOFError:
+        break
+    r = calc(s)
+    if r:
+        print(r)
+
+