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