• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# -----------------------------------------------------------------------------
2# calc.py
3#
4# A simple calculator with variables.   This is from O'Reilly's
5# "Lex and Yacc", p. 63.
6#
7# This example uses unicode strings for tokens, docstrings, and input.
8# -----------------------------------------------------------------------------
9
10import sys
11sys.path.insert(0, "../..")
12
13tokens = (
14    'NAME', 'NUMBER',
15    'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'EQUALS',
16    'LPAREN', 'RPAREN',
17)
18
19# Tokens
20
21t_PLUS = ur'\+'
22t_MINUS = ur'-'
23t_TIMES = ur'\*'
24t_DIVIDE = ur'/'
25t_EQUALS = ur'='
26t_LPAREN = ur'\('
27t_RPAREN = ur'\)'
28t_NAME = ur'[a-zA-Z_][a-zA-Z0-9_]*'
29
30
31def t_NUMBER(t):
32    ur'\d+'
33    try:
34        t.value = int(t.value)
35    except ValueError:
36        print "Integer value too large", t.value
37        t.value = 0
38    return t
39
40t_ignore = u" \t"
41
42
43def t_newline(t):
44    ur'\n+'
45    t.lexer.lineno += t.value.count("\n")
46
47
48def t_error(t):
49    print "Illegal character '%s'" % t.value[0]
50    t.lexer.skip(1)
51
52# Build the lexer
53import ply.lex as lex
54lex.lex()
55
56# Parsing rules
57
58precedence = (
59    ('left', 'PLUS', 'MINUS'),
60    ('left', 'TIMES', 'DIVIDE'),
61    ('right', 'UMINUS'),
62)
63
64# dictionary of names
65names = {}
66
67
68def p_statement_assign(p):
69    'statement : NAME EQUALS expression'
70    names[p[1]] = p[3]
71
72
73def p_statement_expr(p):
74    'statement : expression'
75    print p[1]
76
77
78def p_expression_binop(p):
79    '''expression : expression PLUS expression
80                  | expression MINUS expression
81                  | expression TIMES expression
82                  | expression DIVIDE expression'''
83    if p[2] == u'+':
84        p[0] = p[1] + p[3]
85    elif p[2] == u'-':
86        p[0] = p[1] - p[3]
87    elif p[2] == u'*':
88        p[0] = p[1] * p[3]
89    elif p[2] == u'/':
90        p[0] = p[1] / p[3]
91
92
93def p_expression_uminus(p):
94    'expression : MINUS expression %prec UMINUS'
95    p[0] = -p[2]
96
97
98def p_expression_group(p):
99    'expression : LPAREN expression RPAREN'
100    p[0] = p[2]
101
102
103def p_expression_number(p):
104    'expression : NUMBER'
105    p[0] = p[1]
106
107
108def p_expression_name(p):
109    'expression : NAME'
110    try:
111        p[0] = names[p[1]]
112    except LookupError:
113        print "Undefined name '%s'" % p[1]
114        p[0] = 0
115
116
117def p_error(p):
118    if p:
119        print "Syntax error at '%s'" % p.value
120    else:
121        print "Syntax error at EOF"
122
123import ply.yacc as yacc
124yacc.yacc()
125
126while 1:
127    try:
128        s = raw_input('calc > ')
129    except EOFError:
130        break
131    if not s:
132        continue
133    yacc.parse(unicode(s))
134