calc.py revision 6498
111723Sar4jc@virginia.edu# ----------------------------------------------------------------------------- 211723Sar4jc@virginia.edu# calc.py 311723Sar4jc@virginia.edu# 411723Sar4jc@virginia.edu# A simple calculator with variables. This is from O'Reilly's 511723Sar4jc@virginia.edu# "Lex and Yacc", p. 63. 611723Sar4jc@virginia.edu# 711723Sar4jc@virginia.edu# This example uses unicode strings for tokens, docstrings, and input. 811723Sar4jc@virginia.edu# ----------------------------------------------------------------------------- 911723Sar4jc@virginia.edu 1011723Sar4jc@virginia.eduimport sys 1111723Sar4jc@virginia.edusys.path.insert(0,"../..") 1211723Sar4jc@virginia.edu 1311723Sar4jc@virginia.edutokens = ( 1411723Sar4jc@virginia.edu 'NAME','NUMBER', 1511723Sar4jc@virginia.edu 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', 1611723Sar4jc@virginia.edu 'LPAREN','RPAREN', 1711723Sar4jc@virginia.edu ) 1811723Sar4jc@virginia.edu 1911723Sar4jc@virginia.edu# Tokens 2011723Sar4jc@virginia.edu 2111723Sar4jc@virginia.edut_PLUS = ur'\+' 2211723Sar4jc@virginia.edut_MINUS = ur'-' 2311723Sar4jc@virginia.edut_TIMES = ur'\*' 2411723Sar4jc@virginia.edut_DIVIDE = ur'/' 2511723Sar4jc@virginia.edut_EQUALS = ur'=' 2611723Sar4jc@virginia.edut_LPAREN = ur'\(' 2711723Sar4jc@virginia.edut_RPAREN = ur'\)' 2811723Sar4jc@virginia.edut_NAME = ur'[a-zA-Z_][a-zA-Z0-9_]*' 2911723Sar4jc@virginia.edu 3011723Sar4jc@virginia.edudef t_NUMBER(t): 3111723Sar4jc@virginia.edu ur'\d+' 3211723Sar4jc@virginia.edu try: 3311723Sar4jc@virginia.edu t.value = int(t.value) 3411723Sar4jc@virginia.edu except ValueError: 3511723Sar4jc@virginia.edu print "Integer value too large", t.value 3611723Sar4jc@virginia.edu t.value = 0 3711723Sar4jc@virginia.edu return t 3811723Sar4jc@virginia.edu 3911723Sar4jc@virginia.edut_ignore = u" \t" 4011723Sar4jc@virginia.edu 4111723Sar4jc@virginia.edudef t_newline(t): 4211723Sar4jc@virginia.edu ur'\n+' 4311723Sar4jc@virginia.edu t.lexer.lineno += t.value.count("\n") 4411723Sar4jc@virginia.edu 4511723Sar4jc@virginia.edudef t_error(t): 4611723Sar4jc@virginia.edu print "Illegal character '%s'" % t.value[0] 4711723Sar4jc@virginia.edu t.lexer.skip(1) 4811723Sar4jc@virginia.edu 4911723Sar4jc@virginia.edu# Build the lexer 5011723Sar4jc@virginia.eduimport ply.lex as lex 5111723Sar4jc@virginia.edulex.lex() 5211723Sar4jc@virginia.edu 5311723Sar4jc@virginia.edu# Parsing rules 5411723Sar4jc@virginia.edu 5511723Sar4jc@virginia.eduprecedence = ( 5611723Sar4jc@virginia.edu ('left','PLUS','MINUS'), 5711723Sar4jc@virginia.edu ('left','TIMES','DIVIDE'), 5811723Sar4jc@virginia.edu ('right','UMINUS'), 5911723Sar4jc@virginia.edu ) 6011723Sar4jc@virginia.edu 6111723Sar4jc@virginia.edu# dictionary of names 6211723Sar4jc@virginia.edunames = { } 6311723Sar4jc@virginia.edu 6411723Sar4jc@virginia.edudef p_statement_assign(p): 6511723Sar4jc@virginia.edu 'statement : NAME EQUALS expression' 6611723Sar4jc@virginia.edu names[p[1]] = p[3] 6711723Sar4jc@virginia.edu 6811723Sar4jc@virginia.edudef p_statement_expr(p): 6911723Sar4jc@virginia.edu 'statement : expression' 7011723Sar4jc@virginia.edu print p[1] 7111723Sar4jc@virginia.edu 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