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