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