calc.py revision 6498
14479Sbinkertn@umich.edu#!/usr/bin/env python 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 124479Sbinkertn@umich.eduimport sys 134479Sbinkertn@umich.edusys.path.insert(0,"../..") 144479Sbinkertn@umich.edu 156498Snate@binkert.orgif sys.version_info[0] >= 3: 166498Snate@binkert.org raw_input = input 176498Snate@binkert.org 184479Sbinkertn@umich.eduimport ply.lex as lex 194479Sbinkertn@umich.eduimport ply.yacc as yacc 204479Sbinkertn@umich.eduimport os 214479Sbinkertn@umich.edu 224479Sbinkertn@umich.educlass Parser: 234479Sbinkertn@umich.edu """ 244479Sbinkertn@umich.edu Base class for a lexer/parser that has the rules defined as methods 254479Sbinkertn@umich.edu """ 264479Sbinkertn@umich.edu tokens = () 274479Sbinkertn@umich.edu precedence = () 284479Sbinkertn@umich.edu 294479Sbinkertn@umich.edu def __init__(self, **kw): 304479Sbinkertn@umich.edu self.debug = kw.get('debug', 0) 314479Sbinkertn@umich.edu self.names = { } 324479Sbinkertn@umich.edu try: 334479Sbinkertn@umich.edu modname = os.path.split(os.path.splitext(__file__)[0])[1] + "_" + self.__class__.__name__ 344479Sbinkertn@umich.edu except: 354479Sbinkertn@umich.edu modname = "parser"+"_"+self.__class__.__name__ 364479Sbinkertn@umich.edu self.debugfile = modname + ".dbg" 374479Sbinkertn@umich.edu self.tabmodule = modname + "_" + "parsetab" 384479Sbinkertn@umich.edu #print self.debugfile, self.tabmodule 394479Sbinkertn@umich.edu 404479Sbinkertn@umich.edu # Build the lexer and parser 414479Sbinkertn@umich.edu lex.lex(module=self, debug=self.debug) 424479Sbinkertn@umich.edu yacc.yacc(module=self, 434479Sbinkertn@umich.edu debug=self.debug, 444479Sbinkertn@umich.edu debugfile=self.debugfile, 454479Sbinkertn@umich.edu tabmodule=self.tabmodule) 464479Sbinkertn@umich.edu 474479Sbinkertn@umich.edu def run(self): 484479Sbinkertn@umich.edu while 1: 494479Sbinkertn@umich.edu try: 504479Sbinkertn@umich.edu s = raw_input('calc > ') 514479Sbinkertn@umich.edu except EOFError: 524479Sbinkertn@umich.edu break 534479Sbinkertn@umich.edu if not s: continue 544479Sbinkertn@umich.edu yacc.parse(s) 554479Sbinkertn@umich.edu 566498Snate@binkert.org 574479Sbinkertn@umich.educlass Calc(Parser): 584479Sbinkertn@umich.edu 594479Sbinkertn@umich.edu tokens = ( 604479Sbinkertn@umich.edu 'NAME','NUMBER', 614479Sbinkertn@umich.edu 'PLUS','MINUS','EXP', 'TIMES','DIVIDE','EQUALS', 624479Sbinkertn@umich.edu 'LPAREN','RPAREN', 634479Sbinkertn@umich.edu ) 644479Sbinkertn@umich.edu 654479Sbinkertn@umich.edu # Tokens 664479Sbinkertn@umich.edu 674479Sbinkertn@umich.edu t_PLUS = r'\+' 684479Sbinkertn@umich.edu t_MINUS = r'-' 694479Sbinkertn@umich.edu t_EXP = r'\*\*' 704479Sbinkertn@umich.edu t_TIMES = r'\*' 714479Sbinkertn@umich.edu t_DIVIDE = r'/' 724479Sbinkertn@umich.edu t_EQUALS = r'=' 734479Sbinkertn@umich.edu t_LPAREN = r'\(' 744479Sbinkertn@umich.edu t_RPAREN = r'\)' 754479Sbinkertn@umich.edu t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' 764479Sbinkertn@umich.edu 774479Sbinkertn@umich.edu def t_NUMBER(self, t): 784479Sbinkertn@umich.edu r'\d+' 794479Sbinkertn@umich.edu try: 804479Sbinkertn@umich.edu t.value = int(t.value) 814479Sbinkertn@umich.edu except ValueError: 826498Snate@binkert.org print("Integer value too large %s" % t.value) 834479Sbinkertn@umich.edu t.value = 0 844479Sbinkertn@umich.edu #print "parsed number %s" % repr(t.value) 854479Sbinkertn@umich.edu return t 864479Sbinkertn@umich.edu 874479Sbinkertn@umich.edu t_ignore = " \t" 884479Sbinkertn@umich.edu 894479Sbinkertn@umich.edu def t_newline(self, t): 904479Sbinkertn@umich.edu r'\n+' 914479Sbinkertn@umich.edu t.lexer.lineno += t.value.count("\n") 926498Snate@binkert.org 934479Sbinkertn@umich.edu def t_error(self, t): 946498Snate@binkert.org print("Illegal character '%s'" % t.value[0]) 954479Sbinkertn@umich.edu t.lexer.skip(1) 964479Sbinkertn@umich.edu 974479Sbinkertn@umich.edu # Parsing rules 984479Sbinkertn@umich.edu 994479Sbinkertn@umich.edu precedence = ( 1004479Sbinkertn@umich.edu ('left','PLUS','MINUS'), 1014479Sbinkertn@umich.edu ('left','TIMES','DIVIDE'), 1024479Sbinkertn@umich.edu ('left', 'EXP'), 1034479Sbinkertn@umich.edu ('right','UMINUS'), 1044479Sbinkertn@umich.edu ) 1054479Sbinkertn@umich.edu 1064479Sbinkertn@umich.edu def p_statement_assign(self, p): 1074479Sbinkertn@umich.edu 'statement : NAME EQUALS expression' 1084479Sbinkertn@umich.edu self.names[p[1]] = p[3] 1094479Sbinkertn@umich.edu 1104479Sbinkertn@umich.edu def p_statement_expr(self, p): 1114479Sbinkertn@umich.edu 'statement : expression' 1126498Snate@binkert.org print(p[1]) 1134479Sbinkertn@umich.edu 1144479Sbinkertn@umich.edu def p_expression_binop(self, p): 1154479Sbinkertn@umich.edu """ 1164479Sbinkertn@umich.edu expression : expression PLUS expression 1174479Sbinkertn@umich.edu | expression MINUS expression 1184479Sbinkertn@umich.edu | expression TIMES expression 1194479Sbinkertn@umich.edu | expression DIVIDE expression 1204479Sbinkertn@umich.edu | expression EXP expression 1214479Sbinkertn@umich.edu """ 1224479Sbinkertn@umich.edu #print [repr(p[i]) for i in range(0,4)] 1234479Sbinkertn@umich.edu if p[2] == '+' : p[0] = p[1] + p[3] 1244479Sbinkertn@umich.edu elif p[2] == '-': p[0] = p[1] - p[3] 1254479Sbinkertn@umich.edu elif p[2] == '*': p[0] = p[1] * p[3] 1264479Sbinkertn@umich.edu elif p[2] == '/': p[0] = p[1] / p[3] 1274479Sbinkertn@umich.edu elif p[2] == '**': p[0] = p[1] ** p[3] 1284479Sbinkertn@umich.edu 1294479Sbinkertn@umich.edu def p_expression_uminus(self, p): 1304479Sbinkertn@umich.edu 'expression : MINUS expression %prec UMINUS' 1314479Sbinkertn@umich.edu p[0] = -p[2] 1324479Sbinkertn@umich.edu 1334479Sbinkertn@umich.edu def p_expression_group(self, p): 1344479Sbinkertn@umich.edu 'expression : LPAREN expression RPAREN' 1354479Sbinkertn@umich.edu p[0] = p[2] 1364479Sbinkertn@umich.edu 1374479Sbinkertn@umich.edu def p_expression_number(self, p): 1384479Sbinkertn@umich.edu 'expression : NUMBER' 1394479Sbinkertn@umich.edu p[0] = p[1] 1404479Sbinkertn@umich.edu 1414479Sbinkertn@umich.edu def p_expression_name(self, p): 1424479Sbinkertn@umich.edu 'expression : NAME' 1434479Sbinkertn@umich.edu try: 1444479Sbinkertn@umich.edu p[0] = self.names[p[1]] 1454479Sbinkertn@umich.edu except LookupError: 1466498Snate@binkert.org print("Undefined name '%s'" % p[1]) 1474479Sbinkertn@umich.edu p[0] = 0 1484479Sbinkertn@umich.edu 1494479Sbinkertn@umich.edu def p_error(self, p): 1506498Snate@binkert.org if p: 1516498Snate@binkert.org print("Syntax error at '%s'" % p.value) 1526498Snate@binkert.org else: 1536498Snate@binkert.org print("Syntax error at EOF") 1544479Sbinkertn@umich.edu 1554479Sbinkertn@umich.eduif __name__ == '__main__': 1564479Sbinkertn@umich.edu calc = Calc() 1574479Sbinkertn@umich.edu calc.run() 158