• 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
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
31
32def t_NUMBER(t):
33    r'\d+'
34    try:
35        t.value = int(t.value)
36    except ValueError:
37        print("Integer value too large %s" % t.value)
38        t.value = 0
39    return t
40
41t_ignore = " \t"
42
43
44def t_newline(t):
45    r'\n+'
46    t.lexer.lineno += t.value.count("\n")
47
48
49def t_error(t):
50    print("Illegal character '%s'" % t.value[0])
51    t.lexer.skip(1)
52
53# Build the lexer
54import ply.lex as lex
55lex.lex(optimize=1)
56
57# Parsing rules
58
59precedence = (
60    ('left', 'PLUS', 'MINUS'),
61    ('left', 'TIMES', 'DIVIDE'),
62    ('right', 'UMINUS'),
63)
64
65# dictionary of names
66names = {}
67
68
69def p_statement_assign(t):
70    'statement : NAME EQUALS expression'
71    names[t[1]] = t[3]
72
73
74def p_statement_expr(t):
75    'statement : expression'
76    print(t[1])
77
78
79def p_expression_binop(t):
80    '''expression : expression PLUS expression
81                  | expression MINUS expression
82                  | expression TIMES expression
83                  | expression DIVIDE expression'''
84    if t[2] == '+':
85        t[0] = t[1] + t[3]
86    elif t[2] == '-':
87        t[0] = t[1] - t[3]
88    elif t[2] == '*':
89        t[0] = t[1] * t[3]
90    elif t[2] == '/':
91        t[0] = t[1] / t[3]
92    elif t[2] == '<':
93        t[0] = t[1] < t[3]
94
95
96def p_expression_uminus(t):
97    'expression : MINUS expression %prec UMINUS'
98    t[0] = -t[2]
99
100
101def p_expression_group(t):
102    'expression : LPAREN expression RPAREN'
103    t[0] = t[2]
104
105
106def p_expression_number(t):
107    'expression : NUMBER'
108    t[0] = t[1]
109
110
111def p_expression_name(t):
112    'expression : NAME'
113    try:
114        t[0] = names[t[1]]
115    except LookupError:
116        print("Undefined name '%s'" % t[1])
117        t[0] = 0
118
119
120def p_error(t):
121    if t:
122        print("Syntax error at '%s'" % t.value)
123    else:
124        print("Syntax error at EOF")
125
126import ply.yacc as yacc
127yacc.yacc(optimize=1)
128
129while 1:
130    try:
131        s = raw_input('calc > ')
132    except EOFError:
133        break
134    yacc.parse(s)
135