1# ----------------------------------------------------------------------------- 2# calc.py 3# 4# A simple calculator with variables. This is from O'Reilly's 5# "Lex and Yacc", p. 63. 6# ----------------------------------------------------------------------------- 7 8import sys 9sys.path.insert(0,"../..") 10 11if sys.version_info[0] >= 3: 12 raw_input = input 13 14tokens = ( 15 'NAME','NUMBER', 16 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', 17 'LPAREN','RPAREN', 18 ) 19 20# Tokens 21 22t_PLUS = r'\+' 23t_MINUS = r'-' 24t_TIMES = r'\*' 25t_DIVIDE = r'/' 26t_EQUALS = r'=' 27t_LPAREN = r'\(' 28t_RPAREN = r'\)' 29t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' 30 31def t_NUMBER(t): 32 r'\d+' 33 try: 34 t.value = int(t.value) 35 except ValueError: 36 print("Integer value too large %s" % t.value) 37 t.value = 0 38 return t 39 40t_ignore = " \t" 41 42def t_newline(t): 43 r'\n+' 44 t.lexer.lineno += t.value.count("\n") 45 46def t_error(t): 47 print("Illegal character '%s'" % t.value[0]) 48 t.lexer.skip(1) 49 50# Build the lexer 51import ply.lex as lex 52lex.lex(optimize=1) 53 54# Parsing rules 55 56precedence = ( 57 ('left','PLUS','MINUS'), 58 ('left','TIMES','DIVIDE'), 59 ('right','UMINUS'), 60 ) 61 62# dictionary of names 63names = { } 64 65def p_statement_assign(t): 66 'statement : NAME EQUALS expression' 67 names[t[1]] = t[3] 68 69def p_statement_expr(t): 70 'statement : expression' 71 print(t[1]) 72 73def p_expression_binop(t): 74 '''expression : expression PLUS expression 75 | expression MINUS expression 76 | expression TIMES expression 77 | expression DIVIDE expression''' 78 if t[2] == '+' : t[0] = t[1] + t[3] 79 elif t[2] == '-': t[0] = t[1] - t[3] 80 elif t[2] == '*': t[0] = t[1] * t[3] 81 elif t[2] == '/': t[0] = t[1] / t[3] 82 elif t[2] == '<': t[0] = t[1] < t[3] 83 84def p_expression_uminus(t): 85 'expression : MINUS expression %prec UMINUS' 86 t[0] = -t[2] 87 88def p_expression_group(t): 89 'expression : LPAREN expression RPAREN' 90 t[0] = t[2] 91 92def p_expression_number(t): 93 'expression : NUMBER' 94 t[0] = t[1] 95 96def p_expression_name(t): 97 'expression : NAME' 98 try: 99 t[0] = names[t[1]] 100 except LookupError: 101 print("Undefined name '%s'" % t[1]) 102 t[0] = 0 103 104def p_error(t): 105 if t: 106 print("Syntax error at '%s'" % t.value) 107 else: 108 print("Syntax error at EOF") 109 110import ply.yacc as yacc 111yacc.yacc(optimize=1) 112 113while 1: 114 try: 115 s = raw_input('calc > ') 116 except EOFError: 117 break 118 yacc.parse(s) 119 120