Update to ply 2.3
[gem5.git] / ext / ply / example / classcalc / calc.py
1 #!/usr/bin/env python
2
3 # -----------------------------------------------------------------------------
4 # calc.py
5 #
6 # A simple calculator with variables. This is from O'Reilly's
7 # "Lex and Yacc", p. 63.
8 #
9 # Class-based example contributed to PLY by David McNab
10 # -----------------------------------------------------------------------------
11
12 import sys
13 sys.path.insert(0,"../..")
14
15 import readline
16 import ply.lex as lex
17 import ply.yacc as yacc
18 import os
19
20 class Parser:
21 """
22 Base class for a lexer/parser that has the rules defined as methods
23 """
24 tokens = ()
25 precedence = ()
26
27 def __init__(self, **kw):
28 self.debug = kw.get('debug', 0)
29 self.names = { }
30 try:
31 modname = os.path.split(os.path.splitext(__file__)[0])[1] + "_" + self.__class__.__name__
32 except:
33 modname = "parser"+"_"+self.__class__.__name__
34 self.debugfile = modname + ".dbg"
35 self.tabmodule = modname + "_" + "parsetab"
36 #print self.debugfile, self.tabmodule
37
38 # Build the lexer and parser
39 lex.lex(module=self, debug=self.debug)
40 yacc.yacc(module=self,
41 debug=self.debug,
42 debugfile=self.debugfile,
43 tabmodule=self.tabmodule)
44
45 def run(self):
46 while 1:
47 try:
48 s = raw_input('calc > ')
49 except EOFError:
50 break
51 if not s: continue
52 yacc.parse(s)
53
54
55 class Calc(Parser):
56
57 tokens = (
58 'NAME','NUMBER',
59 'PLUS','MINUS','EXP', 'TIMES','DIVIDE','EQUALS',
60 'LPAREN','RPAREN',
61 )
62
63 # Tokens
64
65 t_PLUS = r'\+'
66 t_MINUS = r'-'
67 t_EXP = r'\*\*'
68 t_TIMES = r'\*'
69 t_DIVIDE = r'/'
70 t_EQUALS = r'='
71 t_LPAREN = r'\('
72 t_RPAREN = r'\)'
73 t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'
74
75 def t_NUMBER(self, t):
76 r'\d+'
77 try:
78 t.value = int(t.value)
79 except ValueError:
80 print "Integer value too large", t.value
81 t.value = 0
82 #print "parsed number %s" % repr(t.value)
83 return t
84
85 t_ignore = " \t"
86
87 def t_newline(self, t):
88 r'\n+'
89 t.lexer.lineno += t.value.count("\n")
90
91 def t_error(self, t):
92 print "Illegal character '%s'" % t.value[0]
93 t.lexer.skip(1)
94
95 # Parsing rules
96
97 precedence = (
98 ('left','PLUS','MINUS'),
99 ('left','TIMES','DIVIDE'),
100 ('left', 'EXP'),
101 ('right','UMINUS'),
102 )
103
104 def p_statement_assign(self, p):
105 'statement : NAME EQUALS expression'
106 self.names[p[1]] = p[3]
107
108 def p_statement_expr(self, p):
109 'statement : expression'
110 print p[1]
111
112 def p_expression_binop(self, p):
113 """
114 expression : expression PLUS expression
115 | expression MINUS expression
116 | expression TIMES expression
117 | expression DIVIDE expression
118 | expression EXP expression
119 """
120 #print [repr(p[i]) for i in range(0,4)]
121 if p[2] == '+' : p[0] = p[1] + p[3]
122 elif p[2] == '-': p[0] = p[1] - p[3]
123 elif p[2] == '*': p[0] = p[1] * p[3]
124 elif p[2] == '/': p[0] = p[1] / p[3]
125 elif p[2] == '**': p[0] = p[1] ** p[3]
126
127 def p_expression_uminus(self, p):
128 'expression : MINUS expression %prec UMINUS'
129 p[0] = -p[2]
130
131 def p_expression_group(self, p):
132 'expression : LPAREN expression RPAREN'
133 p[0] = p[2]
134
135 def p_expression_number(self, p):
136 'expression : NUMBER'
137 p[0] = p[1]
138
139 def p_expression_name(self, p):
140 'expression : NAME'
141 try:
142 p[0] = self.names[p[1]]
143 except LookupError:
144 print "Undefined name '%s'" % p[1]
145 p[0] = 0
146
147 def p_error(self, p):
148 print "Syntax error at '%s'" % p.value
149
150 if __name__ == '__main__':
151 calc = Calc()
152 calc.run()