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