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