calc.py revision 6498
12SN/A#!/usr/bin/env python 21762SN/A 32SN/A# ----------------------------------------------------------------------------- 42SN/A# calc.py 52SN/A# 62SN/A# A simple calculator with variables. This is from O'Reilly's 72SN/A# "Lex and Yacc", p. 63. 82SN/A# 92SN/A# Class-based example contributed to PLY by David McNab. 102SN/A# 112SN/A# Modified to use new-style classes. Test case. 122SN/A# ----------------------------------------------------------------------------- 132SN/A 142SN/Aimport sys 152SN/Asys.path.insert(0,"../..") 162SN/A 172SN/Aif sys.version_info[0] >= 3: 182SN/A raw_input = input 192SN/A 202SN/Aimport ply.lex as lex 212SN/Aimport ply.yacc as yacc 222SN/Aimport os 232SN/A 242SN/Aclass Parser(object): 252SN/A """ 262SN/A Base class for a lexer/parser that has the rules defined as methods 272665SN/A """ 282665SN/A tokens = () 292SN/A precedence = () 302SN/A 312SN/A 322SN/A def __init__(self, **kw): 332SN/A self.debug = kw.get('debug', 0) 342SN/A self.names = { } 352SN/A try: 3611263Sandreas.sandberg@arm.com modname = os.path.split(os.path.splitext(__file__)[0])[1] + "_" + self.__class__.__name__ 3711263Sandreas.sandberg@arm.com except: 382SN/A modname = "parser"+"_"+self.__class__.__name__ 392SN/A self.debugfile = modname + ".dbg" 402SN/A self.tabmodule = modname + "_" + "parsetab" 4111263Sandreas.sandberg@arm.com #print self.debugfile, self.tabmodule 422SN/A 432SN/A # Build the lexer and parser 442SN/A lex.lex(module=self, debug=self.debug) 452SN/A yacc.yacc(module=self, 462SN/A debug=self.debug, 472SN/A debugfile=self.debugfile, 484981SN/A tabmodule=self.tabmodule) 492SN/A 502SN/A def run(self): 514981SN/A while 1: 522SN/A try: 532SN/A s = raw_input('calc > ') 542SN/A except EOFError: 554981SN/A break 564981SN/A if not s: continue 572SN/A yacc.parse(s) 582SN/A 594981SN/A 604981SN/Aclass Calc(Parser): 614981SN/A 622SN/A tokens = ( 634981SN/A 'NAME','NUMBER', 641152SN/A 'PLUS','MINUS','EXP', 'TIMES','DIVIDE','EQUALS', 652SN/A 'LPAREN','RPAREN', 662SN/A ) 671152SN/A 682566SN/A # Tokens 691152SN/A 702566SN/A t_PLUS = r'\+' 714419SN/A t_MINUS = r'-' 724419SN/A t_EXP = r'\*\*' 734419SN/A t_TIMES = r'\*' 742SN/A t_DIVIDE = r'/' 752SN/A t_EQUALS = r'=' 7611263Sandreas.sandberg@arm.com t_LPAREN = r'\(' 77 t_RPAREN = r'\)' 78 t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' 79 80 def t_NUMBER(self, t): 81 r'\d+' 82 try: 83 t.value = int(t.value) 84 except ValueError: 85 print("Integer value too large %s" % t.value) 86 t.value = 0 87 #print "parsed number %s" % repr(t.value) 88 return t 89 90 t_ignore = " \t" 91 92 def t_newline(self, t): 93 r'\n+' 94 t.lexer.lineno += t.value.count("\n") 95 96 def t_error(self, t): 97 print("Illegal character '%s'" % t.value[0]) 98 t.lexer.skip(1) 99 100 # Parsing rules 101 102 precedence = ( 103 ('left','PLUS','MINUS'), 104 ('left','TIMES','DIVIDE'), 105 ('left', 'EXP'), 106 ('right','UMINUS'), 107 ) 108 109 def p_statement_assign(self, p): 110 'statement : NAME EQUALS expression' 111 self.names[p[1]] = p[3] 112 113 def p_statement_expr(self, p): 114 'statement : expression' 115 print(p[1]) 116 117 def p_expression_binop(self, p): 118 """ 119 expression : expression PLUS expression 120 | expression MINUS expression 121 | expression TIMES expression 122 | expression DIVIDE expression 123 | expression EXP expression 124 """ 125 #print [repr(p[i]) for i in range(0,4)] 126 if p[2] == '+' : p[0] = p[1] + p[3] 127 elif p[2] == '-': p[0] = p[1] - p[3] 128 elif p[2] == '*': p[0] = p[1] * p[3] 129 elif p[2] == '/': p[0] = p[1] / p[3] 130 elif p[2] == '**': p[0] = p[1] ** p[3] 131 132 def p_expression_uminus(self, p): 133 'expression : MINUS expression %prec UMINUS' 134 p[0] = -p[2] 135 136 def p_expression_group(self, p): 137 'expression : LPAREN expression RPAREN' 138 p[0] = p[2] 139 140 def p_expression_number(self, p): 141 'expression : NUMBER' 142 p[0] = p[1] 143 144 def p_expression_name(self, p): 145 'expression : NAME' 146 try: 147 p[0] = self.names[p[1]] 148 except LookupError: 149 print("Undefined name '%s'" % p[1]) 150 p[0] = 0 151 152 def p_error(self, p): 153 if p: 154 print("Syntax error at '%s'" % p.value) 155 else: 156 print("Syntax error at EOF") 157 158if __name__ == '__main__': 159 calc = Calc() 160 calc.run() 161