16498Snate@binkert.org# ----------------------------------------------------------------------------- 26498Snate@binkert.org# calc.py 36498Snate@binkert.org# 46498Snate@binkert.org# A calculator parser that makes use of closures. The function make_calculator() 56498Snate@binkert.org# returns a function that accepts an input string and returns a result. All 66498Snate@binkert.org# lexing rules, parsing rules, and internal state are held inside the function. 76498Snate@binkert.org# ----------------------------------------------------------------------------- 86498Snate@binkert.org 96498Snate@binkert.orgimport sys 106498Snate@binkert.orgsys.path.insert(0,"../..") 116498Snate@binkert.org 126498Snate@binkert.orgif sys.version_info[0] >= 3: 136498Snate@binkert.org raw_input = input 146498Snate@binkert.org 156498Snate@binkert.org# Make a calculator function 166498Snate@binkert.org 176498Snate@binkert.orgdef make_calculator(): 186498Snate@binkert.org import ply.lex as lex 196498Snate@binkert.org import ply.yacc as yacc 206498Snate@binkert.org 216498Snate@binkert.org # ------- Internal calculator state 226498Snate@binkert.org 236498Snate@binkert.org variables = { } # Dictionary of stored variables 246498Snate@binkert.org 256498Snate@binkert.org # ------- Calculator tokenizing rules 266498Snate@binkert.org 276498Snate@binkert.org tokens = ( 286498Snate@binkert.org 'NAME','NUMBER', 296498Snate@binkert.org ) 306498Snate@binkert.org 316498Snate@binkert.org literals = ['=','+','-','*','/', '(',')'] 326498Snate@binkert.org 336498Snate@binkert.org t_ignore = " \t" 346498Snate@binkert.org 356498Snate@binkert.org t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' 366498Snate@binkert.org 376498Snate@binkert.org def t_NUMBER(t): 386498Snate@binkert.org r'\d+' 396498Snate@binkert.org t.value = int(t.value) 406498Snate@binkert.org return t 416498Snate@binkert.org 426498Snate@binkert.org def t_newline(t): 436498Snate@binkert.org r'\n+' 446498Snate@binkert.org t.lexer.lineno += t.value.count("\n") 456498Snate@binkert.org 466498Snate@binkert.org def t_error(t): 476498Snate@binkert.org print("Illegal character '%s'" % t.value[0]) 486498Snate@binkert.org t.lexer.skip(1) 496498Snate@binkert.org 506498Snate@binkert.org # Build the lexer 516498Snate@binkert.org lexer = lex.lex() 526498Snate@binkert.org 536498Snate@binkert.org # ------- Calculator parsing rules 546498Snate@binkert.org 556498Snate@binkert.org precedence = ( 566498Snate@binkert.org ('left','+','-'), 576498Snate@binkert.org ('left','*','/'), 586498Snate@binkert.org ('right','UMINUS'), 596498Snate@binkert.org ) 606498Snate@binkert.org 616498Snate@binkert.org def p_statement_assign(p): 626498Snate@binkert.org 'statement : NAME "=" expression' 636498Snate@binkert.org variables[p[1]] = p[3] 646498Snate@binkert.org p[0] = None 656498Snate@binkert.org 666498Snate@binkert.org def p_statement_expr(p): 676498Snate@binkert.org 'statement : expression' 686498Snate@binkert.org p[0] = p[1] 696498Snate@binkert.org 706498Snate@binkert.org def p_expression_binop(p): 716498Snate@binkert.org '''expression : expression '+' expression 726498Snate@binkert.org | expression '-' expression 736498Snate@binkert.org | expression '*' expression 746498Snate@binkert.org | expression '/' expression''' 756498Snate@binkert.org if p[2] == '+' : p[0] = p[1] + p[3] 766498Snate@binkert.org elif p[2] == '-': p[0] = p[1] - p[3] 776498Snate@binkert.org elif p[2] == '*': p[0] = p[1] * p[3] 786498Snate@binkert.org elif p[2] == '/': p[0] = p[1] / p[3] 796498Snate@binkert.org 806498Snate@binkert.org def p_expression_uminus(p): 816498Snate@binkert.org "expression : '-' expression %prec UMINUS" 826498Snate@binkert.org p[0] = -p[2] 836498Snate@binkert.org 846498Snate@binkert.org def p_expression_group(p): 856498Snate@binkert.org "expression : '(' expression ')'" 866498Snate@binkert.org p[0] = p[2] 876498Snate@binkert.org 886498Snate@binkert.org def p_expression_number(p): 896498Snate@binkert.org "expression : NUMBER" 906498Snate@binkert.org p[0] = p[1] 916498Snate@binkert.org 926498Snate@binkert.org def p_expression_name(p): 936498Snate@binkert.org "expression : NAME" 946498Snate@binkert.org try: 956498Snate@binkert.org p[0] = variables[p[1]] 966498Snate@binkert.org except LookupError: 976498Snate@binkert.org print("Undefined name '%s'" % p[1]) 986498Snate@binkert.org p[0] = 0 996498Snate@binkert.org 1006498Snate@binkert.org def p_error(p): 1016498Snate@binkert.org if p: 1026498Snate@binkert.org print("Syntax error at '%s'" % p.value) 1036498Snate@binkert.org else: 1046498Snate@binkert.org print("Syntax error at EOF") 1056498Snate@binkert.org 1066498Snate@binkert.org 1076498Snate@binkert.org # Build the parser 1086498Snate@binkert.org parser = yacc.yacc() 1096498Snate@binkert.org 1106498Snate@binkert.org # ------- Input function 1116498Snate@binkert.org 1126498Snate@binkert.org def input(text): 1136498Snate@binkert.org result = parser.parse(text,lexer=lexer) 1146498Snate@binkert.org return result 1156498Snate@binkert.org 1166498Snate@binkert.org return input 1176498Snate@binkert.org 1186498Snate@binkert.org# Make a calculator object and use it 1196498Snate@binkert.orgcalc = make_calculator() 1206498Snate@binkert.org 1216498Snate@binkert.orgwhile True: 1226498Snate@binkert.org try: 1236498Snate@binkert.org s = raw_input("calc > ") 1246498Snate@binkert.org except EOFError: 1256498Snate@binkert.org break 1266498Snate@binkert.org r = calc(s) 1276498Snate@binkert.org if r: 1286498Snate@binkert.org print(r) 1296498Snate@binkert.org 1306498Snate@binkert.org 131