calc.py revision 2632
12632Sstever@eecs.umich.edu# ----------------------------------------------------------------------------- 22632Sstever@eecs.umich.edu# calc.py 32632Sstever@eecs.umich.edu# 42632Sstever@eecs.umich.edu# A simple calculator with variables. This is from O'Reilly's 52632Sstever@eecs.umich.edu# "Lex and Yacc", p. 63. 62632Sstever@eecs.umich.edu# ----------------------------------------------------------------------------- 72632Sstever@eecs.umich.edu 82632Sstever@eecs.umich.edutokens = ( 92632Sstever@eecs.umich.edu 'NAME','NUMBER', 102632Sstever@eecs.umich.edu 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', 112632Sstever@eecs.umich.edu 'LPAREN','RPAREN', 122632Sstever@eecs.umich.edu ) 132632Sstever@eecs.umich.edu 142632Sstever@eecs.umich.edu# Tokens 152632Sstever@eecs.umich.edu 162632Sstever@eecs.umich.edut_PLUS = r'\+' 172632Sstever@eecs.umich.edut_MINUS = r'-' 182632Sstever@eecs.umich.edut_TIMES = r'\*' 192632Sstever@eecs.umich.edut_DIVIDE = r'/' 202632Sstever@eecs.umich.edut_EQUALS = r'=' 212632Sstever@eecs.umich.edut_LPAREN = r'\(' 222632Sstever@eecs.umich.edut_RPAREN = r'\)' 232632Sstever@eecs.umich.edut_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' 242632Sstever@eecs.umich.edu 252632Sstever@eecs.umich.edudef t_NUMBER(t): 262632Sstever@eecs.umich.edu r'\d+' 272632Sstever@eecs.umich.edu try: 282632Sstever@eecs.umich.edu t.value = int(t.value) 292632Sstever@eecs.umich.edu except ValueError: 302632Sstever@eecs.umich.edu print "Integer value too large", t.value 312632Sstever@eecs.umich.edu t.value = 0 322632Sstever@eecs.umich.edu return t 332632Sstever@eecs.umich.edu 342632Sstever@eecs.umich.edut_ignore = " \t" 352632Sstever@eecs.umich.edu 362632Sstever@eecs.umich.edudef t_newline(t): 372632Sstever@eecs.umich.edu r'\n+' 382632Sstever@eecs.umich.edu t.lineno += t.value.count("\n") 392632Sstever@eecs.umich.edu 402632Sstever@eecs.umich.edudef t_error(t): 412632Sstever@eecs.umich.edu print "Illegal character '%s'" % t.value[0] 422632Sstever@eecs.umich.edu t.skip(1) 432632Sstever@eecs.umich.edu 442632Sstever@eecs.umich.edu# Build the lexer 452632Sstever@eecs.umich.eduimport lex 462632Sstever@eecs.umich.edulex.lex(optimize=1) 472632Sstever@eecs.umich.edu 482632Sstever@eecs.umich.edu# Parsing rules 492632Sstever@eecs.umich.edu 502632Sstever@eecs.umich.eduprecedence = ( 512632Sstever@eecs.umich.edu ('left','PLUS','MINUS'), 522632Sstever@eecs.umich.edu ('left','TIMES','DIVIDE'), 532632Sstever@eecs.umich.edu ('right','UMINUS'), 542632Sstever@eecs.umich.edu ) 552632Sstever@eecs.umich.edu 562632Sstever@eecs.umich.edu# dictionary of names 572632Sstever@eecs.umich.edunames = { } 582632Sstever@eecs.umich.edu 592632Sstever@eecs.umich.edudef p_statement_assign(t): 602632Sstever@eecs.umich.edu 'statement : NAME EQUALS expression' 612632Sstever@eecs.umich.edu names[t[1]] = t[3] 622632Sstever@eecs.umich.edu 632632Sstever@eecs.umich.edudef p_statement_expr(t): 642632Sstever@eecs.umich.edu 'statement : expression' 652632Sstever@eecs.umich.edu print t[1] 662632Sstever@eecs.umich.edu 672632Sstever@eecs.umich.edudef p_expression_binop(t): 682632Sstever@eecs.umich.edu '''expression : expression PLUS expression 692632Sstever@eecs.umich.edu | expression MINUS expression 702632Sstever@eecs.umich.edu | expression TIMES expression 712632Sstever@eecs.umich.edu | expression DIVIDE expression''' 722632Sstever@eecs.umich.edu if t[2] == '+' : t[0] = t[1] + t[3] 732632Sstever@eecs.umich.edu elif t[2] == '-': t[0] = t[1] - t[3] 742632Sstever@eecs.umich.edu elif t[2] == '*': t[0] = t[1] * t[3] 752632Sstever@eecs.umich.edu elif t[2] == '/': t[0] = t[1] / t[3] 762632Sstever@eecs.umich.edu elif t[2] == '<': t[0] = t[1] < t[3] 772632Sstever@eecs.umich.edu 782632Sstever@eecs.umich.edudef p_expression_uminus(t): 792632Sstever@eecs.umich.edu 'expression : MINUS expression %prec UMINUS' 802632Sstever@eecs.umich.edu t[0] = -t[2] 812632Sstever@eecs.umich.edu 822632Sstever@eecs.umich.edudef p_expression_group(t): 832632Sstever@eecs.umich.edu 'expression : LPAREN expression RPAREN' 842632Sstever@eecs.umich.edu t[0] = t[2] 852632Sstever@eecs.umich.edu 862632Sstever@eecs.umich.edudef p_expression_number(t): 872632Sstever@eecs.umich.edu 'expression : NUMBER' 882632Sstever@eecs.umich.edu t[0] = t[1] 892632Sstever@eecs.umich.edu 902632Sstever@eecs.umich.edudef p_expression_name(t): 912632Sstever@eecs.umich.edu 'expression : NAME' 922632Sstever@eecs.umich.edu try: 932632Sstever@eecs.umich.edu t[0] = names[t[1]] 942632Sstever@eecs.umich.edu except LookupError: 952632Sstever@eecs.umich.edu print "Undefined name '%s'" % t[1] 962632Sstever@eecs.umich.edu t[0] = 0 972632Sstever@eecs.umich.edu 982632Sstever@eecs.umich.edudef p_error(t): 992632Sstever@eecs.umich.edu print "Syntax error at '%s'" % t.value 1002632Sstever@eecs.umich.edu 1012632Sstever@eecs.umich.eduimport yacc 1022632Sstever@eecs.umich.eduyacc.yacc(optimize=1) 1032632Sstever@eecs.umich.edu 1042632Sstever@eecs.umich.eduwhile 1: 1052632Sstever@eecs.umich.edu try: 1062632Sstever@eecs.umich.edu s = raw_input('calc > ') 1072632Sstever@eecs.umich.edu except EOFError: 1082632Sstever@eecs.umich.edu break 1092632Sstever@eecs.umich.edu yacc.parse(s) 1102632Sstever@eecs.umich.edu 111