113540Sandrea.mondelli@ucf.edu#!/usr/bin/env python2.7 24479Sbinkertn@umich.edu 34479Sbinkertn@umich.edu# ----------------------------------------------------------------------------- 44479Sbinkertn@umich.edu# calc.py 54479Sbinkertn@umich.edu# 64479Sbinkertn@umich.edu# A simple calculator with variables. This is from O'Reilly's 74479Sbinkertn@umich.edu# "Lex and Yacc", p. 63. 84479Sbinkertn@umich.edu# 94479Sbinkertn@umich.edu# Class-based example contributed to PLY by David McNab. 104479Sbinkertn@umich.edu# 114479Sbinkertn@umich.edu# Modified to use new-style classes. Test case. 124479Sbinkertn@umich.edu# ----------------------------------------------------------------------------- 134479Sbinkertn@umich.edu 144479Sbinkertn@umich.eduimport sys 154479Sbinkertn@umich.edusys.path.insert(0,"../..") 164479Sbinkertn@umich.edu 176498Snate@binkert.orgif sys.version_info[0] >= 3: 186498Snate@binkert.org raw_input = input 196498Snate@binkert.org 204479Sbinkertn@umich.eduimport ply.lex as lex 214479Sbinkertn@umich.eduimport ply.yacc as yacc 224479Sbinkertn@umich.eduimport os 234479Sbinkertn@umich.edu 244479Sbinkertn@umich.educlass Parser(object): 254479Sbinkertn@umich.edu """ 264479Sbinkertn@umich.edu Base class for a lexer/parser that has the rules defined as methods 274479Sbinkertn@umich.edu """ 284479Sbinkertn@umich.edu tokens = () 294479Sbinkertn@umich.edu precedence = () 304479Sbinkertn@umich.edu 314479Sbinkertn@umich.edu 324479Sbinkertn@umich.edu def __init__(self, **kw): 334479Sbinkertn@umich.edu self.debug = kw.get('debug', 0) 344479Sbinkertn@umich.edu self.names = { } 354479Sbinkertn@umich.edu try: 364479Sbinkertn@umich.edu modname = os.path.split(os.path.splitext(__file__)[0])[1] + "_" + self.__class__.__name__ 374479Sbinkertn@umich.edu except: 384479Sbinkertn@umich.edu modname = "parser"+"_"+self.__class__.__name__ 394479Sbinkertn@umich.edu self.debugfile = modname + ".dbg" 404479Sbinkertn@umich.edu self.tabmodule = modname + "_" + "parsetab" 414479Sbinkertn@umich.edu #print self.debugfile, self.tabmodule 424479Sbinkertn@umich.edu 434479Sbinkertn@umich.edu # Build the lexer and parser 444479Sbinkertn@umich.edu lex.lex(module=self, debug=self.debug) 454479Sbinkertn@umich.edu yacc.yacc(module=self, 464479Sbinkertn@umich.edu debug=self.debug, 474479Sbinkertn@umich.edu debugfile=self.debugfile, 484479Sbinkertn@umich.edu tabmodule=self.tabmodule) 494479Sbinkertn@umich.edu 504479Sbinkertn@umich.edu def run(self): 514479Sbinkertn@umich.edu while 1: 524479Sbinkertn@umich.edu try: 534479Sbinkertn@umich.edu s = raw_input('calc > ') 544479Sbinkertn@umich.edu except EOFError: 554479Sbinkertn@umich.edu break 566498Snate@binkert.org if not s: continue 574479Sbinkertn@umich.edu yacc.parse(s) 584479Sbinkertn@umich.edu 596498Snate@binkert.org 604479Sbinkertn@umich.educlass Calc(Parser): 614479Sbinkertn@umich.edu 624479Sbinkertn@umich.edu tokens = ( 634479Sbinkertn@umich.edu 'NAME','NUMBER', 644479Sbinkertn@umich.edu 'PLUS','MINUS','EXP', 'TIMES','DIVIDE','EQUALS', 654479Sbinkertn@umich.edu 'LPAREN','RPAREN', 664479Sbinkertn@umich.edu ) 674479Sbinkertn@umich.edu 684479Sbinkertn@umich.edu # Tokens 694479Sbinkertn@umich.edu 704479Sbinkertn@umich.edu t_PLUS = r'\+' 714479Sbinkertn@umich.edu t_MINUS = r'-' 724479Sbinkertn@umich.edu t_EXP = r'\*\*' 734479Sbinkertn@umich.edu t_TIMES = r'\*' 744479Sbinkertn@umich.edu t_DIVIDE = r'/' 754479Sbinkertn@umich.edu t_EQUALS = r'=' 764479Sbinkertn@umich.edu t_LPAREN = r'\(' 774479Sbinkertn@umich.edu t_RPAREN = r'\)' 784479Sbinkertn@umich.edu t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' 794479Sbinkertn@umich.edu 804479Sbinkertn@umich.edu def t_NUMBER(self, t): 814479Sbinkertn@umich.edu r'\d+' 824479Sbinkertn@umich.edu try: 834479Sbinkertn@umich.edu t.value = int(t.value) 844479Sbinkertn@umich.edu except ValueError: 856498Snate@binkert.org print("Integer value too large %s" % t.value) 864479Sbinkertn@umich.edu t.value = 0 874479Sbinkertn@umich.edu #print "parsed number %s" % repr(t.value) 884479Sbinkertn@umich.edu return t 894479Sbinkertn@umich.edu 904479Sbinkertn@umich.edu t_ignore = " \t" 914479Sbinkertn@umich.edu 924479Sbinkertn@umich.edu def t_newline(self, t): 934479Sbinkertn@umich.edu r'\n+' 944479Sbinkertn@umich.edu t.lexer.lineno += t.value.count("\n") 956498Snate@binkert.org 964479Sbinkertn@umich.edu def t_error(self, t): 976498Snate@binkert.org print("Illegal character '%s'" % t.value[0]) 984479Sbinkertn@umich.edu t.lexer.skip(1) 994479Sbinkertn@umich.edu 1004479Sbinkertn@umich.edu # Parsing rules 1014479Sbinkertn@umich.edu 1024479Sbinkertn@umich.edu precedence = ( 1034479Sbinkertn@umich.edu ('left','PLUS','MINUS'), 1044479Sbinkertn@umich.edu ('left','TIMES','DIVIDE'), 1054479Sbinkertn@umich.edu ('left', 'EXP'), 1064479Sbinkertn@umich.edu ('right','UMINUS'), 1074479Sbinkertn@umich.edu ) 1084479Sbinkertn@umich.edu 1094479Sbinkertn@umich.edu def p_statement_assign(self, p): 1104479Sbinkertn@umich.edu 'statement : NAME EQUALS expression' 1114479Sbinkertn@umich.edu self.names[p[1]] = p[3] 1124479Sbinkertn@umich.edu 1134479Sbinkertn@umich.edu def p_statement_expr(self, p): 1144479Sbinkertn@umich.edu 'statement : expression' 1156498Snate@binkert.org print(p[1]) 1164479Sbinkertn@umich.edu 1174479Sbinkertn@umich.edu def p_expression_binop(self, p): 1184479Sbinkertn@umich.edu """ 1194479Sbinkertn@umich.edu expression : expression PLUS expression 1204479Sbinkertn@umich.edu | expression MINUS expression 1214479Sbinkertn@umich.edu | expression TIMES expression 1224479Sbinkertn@umich.edu | expression DIVIDE expression 1234479Sbinkertn@umich.edu | expression EXP expression 1244479Sbinkertn@umich.edu """ 1254479Sbinkertn@umich.edu #print [repr(p[i]) for i in range(0,4)] 1264479Sbinkertn@umich.edu if p[2] == '+' : p[0] = p[1] + p[3] 1274479Sbinkertn@umich.edu elif p[2] == '-': p[0] = p[1] - p[3] 1284479Sbinkertn@umich.edu elif p[2] == '*': p[0] = p[1] * p[3] 1294479Sbinkertn@umich.edu elif p[2] == '/': p[0] = p[1] / p[3] 1304479Sbinkertn@umich.edu elif p[2] == '**': p[0] = p[1] ** p[3] 1314479Sbinkertn@umich.edu 1324479Sbinkertn@umich.edu def p_expression_uminus(self, p): 1334479Sbinkertn@umich.edu 'expression : MINUS expression %prec UMINUS' 1344479Sbinkertn@umich.edu p[0] = -p[2] 1354479Sbinkertn@umich.edu 1364479Sbinkertn@umich.edu def p_expression_group(self, p): 1374479Sbinkertn@umich.edu 'expression : LPAREN expression RPAREN' 1384479Sbinkertn@umich.edu p[0] = p[2] 1394479Sbinkertn@umich.edu 1404479Sbinkertn@umich.edu def p_expression_number(self, p): 1414479Sbinkertn@umich.edu 'expression : NUMBER' 1424479Sbinkertn@umich.edu p[0] = p[1] 1434479Sbinkertn@umich.edu 1444479Sbinkertn@umich.edu def p_expression_name(self, p): 1454479Sbinkertn@umich.edu 'expression : NAME' 1464479Sbinkertn@umich.edu try: 1474479Sbinkertn@umich.edu p[0] = self.names[p[1]] 1484479Sbinkertn@umich.edu except LookupError: 1496498Snate@binkert.org print("Undefined name '%s'" % p[1]) 1504479Sbinkertn@umich.edu p[0] = 0 1514479Sbinkertn@umich.edu 1524479Sbinkertn@umich.edu def p_error(self, p): 1536498Snate@binkert.org if p: 1546498Snate@binkert.org print("Syntax error at '%s'" % p.value) 1556498Snate@binkert.org else: 1566498Snate@binkert.org print("Syntax error at EOF") 1574479Sbinkertn@umich.edu 1584479Sbinkertn@umich.eduif __name__ == '__main__': 1594479Sbinkertn@umich.edu calc = Calc() 1604479Sbinkertn@umich.edu calc.run() 161