1583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata#!/usr/bin/env python 2583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 3583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata# ----------------------------------------------------------------------------- 4583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata# calc.py 5583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata# 6583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata# A simple calculator with variables. This is from O'Reilly's 7583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata# "Lex and Yacc", p. 63. 8583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata# 9583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata# Class-based example contributed to PLY by David McNab. 10583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata# 11583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata# Modified to use new-style classes. Test case. 12583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata# ----------------------------------------------------------------------------- 13583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 14583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granataimport sys 15583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granatasys.path.insert(0, "../..") 16583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 17583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granataif sys.version_info[0] >= 3: 18583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata raw_input = input 19583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 20583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granataimport ply.lex as lex 21583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granataimport ply.yacc as yacc 22583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granataimport os 23583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 24583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 25583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granataclass Parser(object): 26583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata """ 27583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata Base class for a lexer/parser that has the rules defined as methods 28583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata """ 29583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata tokens = () 30583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata precedence = () 31583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 32583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata def __init__(self, **kw): 33583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata self.debug = kw.get('debug', 0) 34583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata self.names = {} 35583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata try: 36583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata modname = os.path.split(os.path.splitext(__file__)[0])[ 37583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 1] + "_" + self.__class__.__name__ 38583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata except: 39583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata modname = "parser" + "_" + self.__class__.__name__ 40583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata self.debugfile = modname + ".dbg" 41583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata self.tabmodule = modname + "_" + "parsetab" 42583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata # print self.debugfile, self.tabmodule 43583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 44583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata # Build the lexer and parser 45583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata lex.lex(module=self, debug=self.debug) 46583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata yacc.yacc(module=self, 47583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata debug=self.debug, 48583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata debugfile=self.debugfile, 49583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata tabmodule=self.tabmodule) 50583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 51583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata def run(self): 52583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata while 1: 53583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata try: 54583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata s = raw_input('calc > ') 55583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata except EOFError: 56583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata break 57583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata if not s: 58583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata continue 59583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata yacc.parse(s) 60583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 61583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 62583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granataclass Calc(Parser): 63583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 64583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata tokens = ( 65583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 'NAME', 'NUMBER', 66583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 'PLUS', 'MINUS', 'EXP', 'TIMES', 'DIVIDE', 'EQUALS', 67583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 'LPAREN', 'RPAREN', 68583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata ) 69583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 70583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata # Tokens 71583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 72583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t_PLUS = r'\+' 73583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t_MINUS = r'-' 74583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t_EXP = r'\*\*' 75583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t_TIMES = r'\*' 76583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t_DIVIDE = r'/' 77583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t_EQUALS = r'=' 78583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t_LPAREN = r'\(' 79583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t_RPAREN = r'\)' 80583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' 81583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 82583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata def t_NUMBER(self, t): 83583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata r'\d+' 84583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata try: 85583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t.value = int(t.value) 86583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata except ValueError: 87583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata print("Integer value too large %s" % t.value) 88583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t.value = 0 89583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata # print "parsed number %s" % repr(t.value) 90583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata return t 91583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 92583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t_ignore = " \t" 93583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 94583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata def t_newline(self, t): 95583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata r'\n+' 96583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t.lexer.lineno += t.value.count("\n") 97583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 98583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata def t_error(self, t): 99583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata print("Illegal character '%s'" % t.value[0]) 100583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata t.lexer.skip(1) 101583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 102583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata # Parsing rules 103583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 104583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata precedence = ( 105583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata ('left', 'PLUS', 'MINUS'), 106583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata ('left', 'TIMES', 'DIVIDE'), 107583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata ('left', 'EXP'), 108583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata ('right', 'UMINUS'), 109583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata ) 110583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 111583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata def p_statement_assign(self, p): 112583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 'statement : NAME EQUALS expression' 113583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata self.names[p[1]] = p[3] 114583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 115583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata def p_statement_expr(self, p): 116583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 'statement : expression' 117583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata print(p[1]) 118583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 119583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata def p_expression_binop(self, p): 120583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata """ 121583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata expression : expression PLUS expression 122583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata | expression MINUS expression 123583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata | expression TIMES expression 124583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata | expression DIVIDE expression 125583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata | expression EXP expression 126583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata """ 127583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata # print [repr(p[i]) for i in range(0,4)] 128583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata if p[2] == '+': 129583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata p[0] = p[1] + p[3] 130583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata elif p[2] == '-': 131583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata p[0] = p[1] - p[3] 132583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata elif p[2] == '*': 133583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata p[0] = p[1] * p[3] 134583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata elif p[2] == '/': 135583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata p[0] = p[1] / p[3] 136583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata elif p[2] == '**': 137583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata p[0] = p[1] ** p[3] 138583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 139583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata def p_expression_uminus(self, p): 140583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 'expression : MINUS expression %prec UMINUS' 141583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata p[0] = -p[2] 142583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 143583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata def p_expression_group(self, p): 144583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 'expression : LPAREN expression RPAREN' 145583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata p[0] = p[2] 146583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 147583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata def p_expression_number(self, p): 148583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 'expression : NUMBER' 149583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata p[0] = p[1] 150583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 151583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata def p_expression_name(self, p): 152583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 'expression : NAME' 153583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata try: 154583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata p[0] = self.names[p[1]] 155583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata except LookupError: 156583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata print("Undefined name '%s'" % p[1]) 157583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata p[0] = 0 158583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 159583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata def p_error(self, p): 160583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata if p: 161583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata print("Syntax error at '%s'" % p.value) 162583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata else: 163583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata print("Syntax error at EOF") 164583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata 165583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granataif __name__ == '__main__': 166583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata calc = Calc() 167583d33c593896afeb8486a25fabfcf6e9dc9ca75Enrico Granata calc.run() 168