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 84479Sbinkertn@umich.eduimport sys 94479Sbinkertn@umich.edusys.path.insert(0,"../..") 104479Sbinkertn@umich.edu 116498Snate@binkert.orgif sys.version_info[0] >= 3: 126498Snate@binkert.org raw_input = input 136498Snate@binkert.org 142632Sstever@eecs.umich.edutokens = ( 152632Sstever@eecs.umich.edu 'NAME','NUMBER', 162632Sstever@eecs.umich.edu 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', 172632Sstever@eecs.umich.edu 'LPAREN','RPAREN', 182632Sstever@eecs.umich.edu ) 192632Sstever@eecs.umich.edu 202632Sstever@eecs.umich.edu# Tokens 212632Sstever@eecs.umich.edu 222632Sstever@eecs.umich.edut_PLUS = r'\+' 232632Sstever@eecs.umich.edut_MINUS = r'-' 242632Sstever@eecs.umich.edut_TIMES = r'\*' 252632Sstever@eecs.umich.edut_DIVIDE = r'/' 262632Sstever@eecs.umich.edut_EQUALS = r'=' 272632Sstever@eecs.umich.edut_LPAREN = r'\(' 282632Sstever@eecs.umich.edut_RPAREN = r'\)' 292632Sstever@eecs.umich.edut_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' 302632Sstever@eecs.umich.edu 312632Sstever@eecs.umich.edudef t_NUMBER(t): 322632Sstever@eecs.umich.edu r'\d+' 332632Sstever@eecs.umich.edu try: 342632Sstever@eecs.umich.edu t.value = int(t.value) 352632Sstever@eecs.umich.edu except ValueError: 366498Snate@binkert.org print("Integer value too large %s" % t.value) 372632Sstever@eecs.umich.edu t.value = 0 382632Sstever@eecs.umich.edu return t 392632Sstever@eecs.umich.edu 402632Sstever@eecs.umich.edut_ignore = " \t" 412632Sstever@eecs.umich.edu 422632Sstever@eecs.umich.edudef t_newline(t): 432632Sstever@eecs.umich.edu r'\n+' 444479Sbinkertn@umich.edu t.lexer.lineno += t.value.count("\n") 456498Snate@binkert.org 462632Sstever@eecs.umich.edudef t_error(t): 476498Snate@binkert.org print("Illegal character '%s'" % t.value[0]) 484479Sbinkertn@umich.edu t.lexer.skip(1) 496498Snate@binkert.org 502632Sstever@eecs.umich.edu# Build the lexer 514479Sbinkertn@umich.eduimport ply.lex as lex 522632Sstever@eecs.umich.edulex.lex(optimize=1) 532632Sstever@eecs.umich.edu 542632Sstever@eecs.umich.edu# Parsing rules 552632Sstever@eecs.umich.edu 562632Sstever@eecs.umich.eduprecedence = ( 572632Sstever@eecs.umich.edu ('left','PLUS','MINUS'), 582632Sstever@eecs.umich.edu ('left','TIMES','DIVIDE'), 592632Sstever@eecs.umich.edu ('right','UMINUS'), 602632Sstever@eecs.umich.edu ) 612632Sstever@eecs.umich.edu 622632Sstever@eecs.umich.edu# dictionary of names 632632Sstever@eecs.umich.edunames = { } 642632Sstever@eecs.umich.edu 652632Sstever@eecs.umich.edudef p_statement_assign(t): 662632Sstever@eecs.umich.edu 'statement : NAME EQUALS expression' 672632Sstever@eecs.umich.edu names[t[1]] = t[3] 682632Sstever@eecs.umich.edu 692632Sstever@eecs.umich.edudef p_statement_expr(t): 702632Sstever@eecs.umich.edu 'statement : expression' 716498Snate@binkert.org print(t[1]) 722632Sstever@eecs.umich.edu 732632Sstever@eecs.umich.edudef p_expression_binop(t): 742632Sstever@eecs.umich.edu '''expression : expression PLUS expression 752632Sstever@eecs.umich.edu | expression MINUS expression 762632Sstever@eecs.umich.edu | expression TIMES expression 772632Sstever@eecs.umich.edu | expression DIVIDE expression''' 782632Sstever@eecs.umich.edu if t[2] == '+' : t[0] = t[1] + t[3] 792632Sstever@eecs.umich.edu elif t[2] == '-': t[0] = t[1] - t[3] 802632Sstever@eecs.umich.edu elif t[2] == '*': t[0] = t[1] * t[3] 812632Sstever@eecs.umich.edu elif t[2] == '/': t[0] = t[1] / t[3] 822632Sstever@eecs.umich.edu elif t[2] == '<': t[0] = t[1] < t[3] 832632Sstever@eecs.umich.edu 842632Sstever@eecs.umich.edudef p_expression_uminus(t): 852632Sstever@eecs.umich.edu 'expression : MINUS expression %prec UMINUS' 862632Sstever@eecs.umich.edu t[0] = -t[2] 872632Sstever@eecs.umich.edu 882632Sstever@eecs.umich.edudef p_expression_group(t): 892632Sstever@eecs.umich.edu 'expression : LPAREN expression RPAREN' 902632Sstever@eecs.umich.edu t[0] = t[2] 912632Sstever@eecs.umich.edu 922632Sstever@eecs.umich.edudef p_expression_number(t): 932632Sstever@eecs.umich.edu 'expression : NUMBER' 942632Sstever@eecs.umich.edu t[0] = t[1] 952632Sstever@eecs.umich.edu 962632Sstever@eecs.umich.edudef p_expression_name(t): 972632Sstever@eecs.umich.edu 'expression : NAME' 982632Sstever@eecs.umich.edu try: 992632Sstever@eecs.umich.edu t[0] = names[t[1]] 1002632Sstever@eecs.umich.edu except LookupError: 1016498Snate@binkert.org print("Undefined name '%s'" % t[1]) 1022632Sstever@eecs.umich.edu t[0] = 0 1032632Sstever@eecs.umich.edu 1042632Sstever@eecs.umich.edudef p_error(t): 1056498Snate@binkert.org if t: 1066498Snate@binkert.org print("Syntax error at '%s'" % t.value) 1076498Snate@binkert.org else: 1086498Snate@binkert.org print("Syntax error at EOF") 1092632Sstever@eecs.umich.edu 1104479Sbinkertn@umich.eduimport ply.yacc as yacc 1112632Sstever@eecs.umich.eduyacc.yacc(optimize=1) 1122632Sstever@eecs.umich.edu 1132632Sstever@eecs.umich.eduwhile 1: 1142632Sstever@eecs.umich.edu try: 1152632Sstever@eecs.umich.edu s = raw_input('calc > ') 1162632Sstever@eecs.umich.edu except EOFError: 1172632Sstever@eecs.umich.edu break 1182632Sstever@eecs.umich.edu yacc.parse(s) 1192632Sstever@eecs.umich.edu 120