calc.py revision 4479
14479Sbinkertn@umich.edu# ----------------------------------------------------------------------------- 24479Sbinkertn@umich.edu# calc.py 34479Sbinkertn@umich.edu# 44479Sbinkertn@umich.edu# A simple calculator with variables. This is from O'Reilly's 54479Sbinkertn@umich.edu# "Lex and Yacc", p. 63. 64479Sbinkertn@umich.edu# 74479Sbinkertn@umich.edu# This example uses unicode strings for tokens, docstrings, and input. 84479Sbinkertn@umich.edu# ----------------------------------------------------------------------------- 94479Sbinkertn@umich.edu 104479Sbinkertn@umich.eduimport sys 114479Sbinkertn@umich.edusys.path.insert(0,"../..") 124479Sbinkertn@umich.edu 134479Sbinkertn@umich.edutokens = ( 144479Sbinkertn@umich.edu 'NAME','NUMBER', 154479Sbinkertn@umich.edu 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', 164479Sbinkertn@umich.edu 'LPAREN','RPAREN', 174479Sbinkertn@umich.edu ) 184479Sbinkertn@umich.edu 194479Sbinkertn@umich.edu# Tokens 204479Sbinkertn@umich.edu 214479Sbinkertn@umich.edut_PLUS = ur'\+' 224479Sbinkertn@umich.edut_MINUS = ur'-' 234479Sbinkertn@umich.edut_TIMES = ur'\*' 244479Sbinkertn@umich.edut_DIVIDE = ur'/' 254479Sbinkertn@umich.edut_EQUALS = ur'=' 264479Sbinkertn@umich.edut_LPAREN = ur'\(' 274479Sbinkertn@umich.edut_RPAREN = ur'\)' 284479Sbinkertn@umich.edut_NAME = ur'[a-zA-Z_][a-zA-Z0-9_]*' 294479Sbinkertn@umich.edu 304479Sbinkertn@umich.edudef t_NUMBER(t): 314479Sbinkertn@umich.edu ur'\d+' 324479Sbinkertn@umich.edu try: 334479Sbinkertn@umich.edu t.value = int(t.value) 344479Sbinkertn@umich.edu except ValueError: 354479Sbinkertn@umich.edu print "Integer value too large", t.value 364479Sbinkertn@umich.edu t.value = 0 374479Sbinkertn@umich.edu return t 384479Sbinkertn@umich.edu 394479Sbinkertn@umich.edut_ignore = u" \t" 404479Sbinkertn@umich.edu 414479Sbinkertn@umich.edudef t_newline(t): 424479Sbinkertn@umich.edu ur'\n+' 434479Sbinkertn@umich.edu t.lexer.lineno += t.value.count("\n") 444479Sbinkertn@umich.edu 454479Sbinkertn@umich.edudef t_error(t): 464479Sbinkertn@umich.edu print "Illegal character '%s'" % t.value[0] 474479Sbinkertn@umich.edu t.lexer.skip(1) 484479Sbinkertn@umich.edu 494479Sbinkertn@umich.edu# Build the lexer 504479Sbinkertn@umich.eduimport ply.lex as lex 514479Sbinkertn@umich.edulex.lex() 524479Sbinkertn@umich.edu 534479Sbinkertn@umich.edu# Parsing rules 544479Sbinkertn@umich.edu 554479Sbinkertn@umich.eduprecedence = ( 564479Sbinkertn@umich.edu ('left','PLUS','MINUS'), 574479Sbinkertn@umich.edu ('left','TIMES','DIVIDE'), 584479Sbinkertn@umich.edu ('right','UMINUS'), 594479Sbinkertn@umich.edu ) 604479Sbinkertn@umich.edu 614479Sbinkertn@umich.edu# dictionary of names 624479Sbinkertn@umich.edunames = { } 634479Sbinkertn@umich.edu 644479Sbinkertn@umich.edudef p_statement_assign(p): 654479Sbinkertn@umich.edu 'statement : NAME EQUALS expression' 664479Sbinkertn@umich.edu names[p[1]] = p[3] 674479Sbinkertn@umich.edu 684479Sbinkertn@umich.edudef p_statement_expr(p): 694479Sbinkertn@umich.edu 'statement : expression' 704479Sbinkertn@umich.edu print p[1] 714479Sbinkertn@umich.edu 724479Sbinkertn@umich.edudef p_expression_binop(p): 734479Sbinkertn@umich.edu '''expression : expression PLUS expression 744479Sbinkertn@umich.edu | expression MINUS expression 754479Sbinkertn@umich.edu | expression TIMES expression 764479Sbinkertn@umich.edu | expression DIVIDE expression''' 774479Sbinkertn@umich.edu if p[2] == u'+' : p[0] = p[1] + p[3] 784479Sbinkertn@umich.edu elif p[2] == u'-': p[0] = p[1] - p[3] 794479Sbinkertn@umich.edu elif p[2] == u'*': p[0] = p[1] * p[3] 804479Sbinkertn@umich.edu elif p[2] == u'/': p[0] = p[1] / p[3] 814479Sbinkertn@umich.edu 824479Sbinkertn@umich.edudef p_expression_uminus(p): 834479Sbinkertn@umich.edu 'expression : MINUS expression %prec UMINUS' 844479Sbinkertn@umich.edu p[0] = -p[2] 854479Sbinkertn@umich.edu 864479Sbinkertn@umich.edudef p_expression_group(p): 874479Sbinkertn@umich.edu 'expression : LPAREN expression RPAREN' 884479Sbinkertn@umich.edu p[0] = p[2] 894479Sbinkertn@umich.edu 904479Sbinkertn@umich.edudef p_expression_number(p): 914479Sbinkertn@umich.edu 'expression : NUMBER' 924479Sbinkertn@umich.edu p[0] = p[1] 934479Sbinkertn@umich.edu 944479Sbinkertn@umich.edudef p_expression_name(p): 954479Sbinkertn@umich.edu 'expression : NAME' 964479Sbinkertn@umich.edu try: 974479Sbinkertn@umich.edu p[0] = names[p[1]] 984479Sbinkertn@umich.edu except LookupError: 994479Sbinkertn@umich.edu print "Undefined name '%s'" % p[1] 1004479Sbinkertn@umich.edu p[0] = 0 1014479Sbinkertn@umich.edu 1024479Sbinkertn@umich.edudef p_error(p): 1034479Sbinkertn@umich.edu print "Syntax error at '%s'" % p.value 1044479Sbinkertn@umich.edu 1054479Sbinkertn@umich.eduimport ply.yacc as yacc 1064479Sbinkertn@umich.eduyacc.yacc() 1074479Sbinkertn@umich.edu 1084479Sbinkertn@umich.eduwhile 1: 1094479Sbinkertn@umich.edu try: 1104479Sbinkertn@umich.edu s = raw_input('calc > ') 1114479Sbinkertn@umich.edu except EOFError: 1124479Sbinkertn@umich.edu break 1134479Sbinkertn@umich.edu if not s: continue 1144479Sbinkertn@umich.edu yacc.parse(unicode(s)) 115