xref: /aosp_15_r20/external/ply/ply/example/closurecalc/calc.py (revision 09948d41d6b3b06d4f51351d12c4c470db0bfb8f)
1*09948d41SKrzysztof Kosiński# -----------------------------------------------------------------------------
2*09948d41SKrzysztof Kosiński# calc.py
3*09948d41SKrzysztof Kosiński#
4*09948d41SKrzysztof Kosiński# A calculator parser that makes use of closures. The function make_calculator()
5*09948d41SKrzysztof Kosiński# returns a function that accepts an input string and returns a result.  All
6*09948d41SKrzysztof Kosiński# lexing rules, parsing rules, and internal state are held inside the function.
7*09948d41SKrzysztof Kosiński# -----------------------------------------------------------------------------
8*09948d41SKrzysztof Kosiński
9*09948d41SKrzysztof Kosińskiimport sys
10*09948d41SKrzysztof Kosińskisys.path.insert(0, "../..")
11*09948d41SKrzysztof Kosiński
12*09948d41SKrzysztof Kosińskiif sys.version_info[0] >= 3:
13*09948d41SKrzysztof Kosiński    raw_input = input
14*09948d41SKrzysztof Kosiński
15*09948d41SKrzysztof Kosiński# Make a calculator function
16*09948d41SKrzysztof Kosiński
17*09948d41SKrzysztof Kosiński
18*09948d41SKrzysztof Kosińskidef make_calculator():
19*09948d41SKrzysztof Kosiński    import ply.lex as lex
20*09948d41SKrzysztof Kosiński    import ply.yacc as yacc
21*09948d41SKrzysztof Kosiński
22*09948d41SKrzysztof Kosiński    # ------- Internal calculator state
23*09948d41SKrzysztof Kosiński
24*09948d41SKrzysztof Kosiński    variables = {}       # Dictionary of stored variables
25*09948d41SKrzysztof Kosiński
26*09948d41SKrzysztof Kosiński    # ------- Calculator tokenizing rules
27*09948d41SKrzysztof Kosiński
28*09948d41SKrzysztof Kosiński    tokens = (
29*09948d41SKrzysztof Kosiński        'NAME', 'NUMBER',
30*09948d41SKrzysztof Kosiński    )
31*09948d41SKrzysztof Kosiński
32*09948d41SKrzysztof Kosiński    literals = ['=', '+', '-', '*', '/', '(', ')']
33*09948d41SKrzysztof Kosiński
34*09948d41SKrzysztof Kosiński    t_ignore = " \t"
35*09948d41SKrzysztof Kosiński
36*09948d41SKrzysztof Kosiński    t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'
37*09948d41SKrzysztof Kosiński
38*09948d41SKrzysztof Kosiński    def t_NUMBER(t):
39*09948d41SKrzysztof Kosiński        r'\d+'
40*09948d41SKrzysztof Kosiński        t.value = int(t.value)
41*09948d41SKrzysztof Kosiński        return t
42*09948d41SKrzysztof Kosiński
43*09948d41SKrzysztof Kosiński    def t_newline(t):
44*09948d41SKrzysztof Kosiński        r'\n+'
45*09948d41SKrzysztof Kosiński        t.lexer.lineno += t.value.count("\n")
46*09948d41SKrzysztof Kosiński
47*09948d41SKrzysztof Kosiński    def t_error(t):
48*09948d41SKrzysztof Kosiński        print("Illegal character '%s'" % t.value[0])
49*09948d41SKrzysztof Kosiński        t.lexer.skip(1)
50*09948d41SKrzysztof Kosiński
51*09948d41SKrzysztof Kosiński    # Build the lexer
52*09948d41SKrzysztof Kosiński    lexer = lex.lex()
53*09948d41SKrzysztof Kosiński
54*09948d41SKrzysztof Kosiński    # ------- Calculator parsing rules
55*09948d41SKrzysztof Kosiński
56*09948d41SKrzysztof Kosiński    precedence = (
57*09948d41SKrzysztof Kosiński        ('left', '+', '-'),
58*09948d41SKrzysztof Kosiński        ('left', '*', '/'),
59*09948d41SKrzysztof Kosiński        ('right', 'UMINUS'),
60*09948d41SKrzysztof Kosiński    )
61*09948d41SKrzysztof Kosiński
62*09948d41SKrzysztof Kosiński    def p_statement_assign(p):
63*09948d41SKrzysztof Kosiński        'statement : NAME "=" expression'
64*09948d41SKrzysztof Kosiński        variables[p[1]] = p[3]
65*09948d41SKrzysztof Kosiński        p[0] = None
66*09948d41SKrzysztof Kosiński
67*09948d41SKrzysztof Kosiński    def p_statement_expr(p):
68*09948d41SKrzysztof Kosiński        'statement : expression'
69*09948d41SKrzysztof Kosiński        p[0] = p[1]
70*09948d41SKrzysztof Kosiński
71*09948d41SKrzysztof Kosiński    def p_expression_binop(p):
72*09948d41SKrzysztof Kosiński        '''expression : expression '+' expression
73*09948d41SKrzysztof Kosiński                      | expression '-' expression
74*09948d41SKrzysztof Kosiński                      | expression '*' expression
75*09948d41SKrzysztof Kosiński                      | expression '/' expression'''
76*09948d41SKrzysztof Kosiński        if p[2] == '+':
77*09948d41SKrzysztof Kosiński            p[0] = p[1] + p[3]
78*09948d41SKrzysztof Kosiński        elif p[2] == '-':
79*09948d41SKrzysztof Kosiński            p[0] = p[1] - p[3]
80*09948d41SKrzysztof Kosiński        elif p[2] == '*':
81*09948d41SKrzysztof Kosiński            p[0] = p[1] * p[3]
82*09948d41SKrzysztof Kosiński        elif p[2] == '/':
83*09948d41SKrzysztof Kosiński            p[0] = p[1] / p[3]
84*09948d41SKrzysztof Kosiński
85*09948d41SKrzysztof Kosiński    def p_expression_uminus(p):
86*09948d41SKrzysztof Kosiński        "expression : '-' expression %prec UMINUS"
87*09948d41SKrzysztof Kosiński        p[0] = -p[2]
88*09948d41SKrzysztof Kosiński
89*09948d41SKrzysztof Kosiński    def p_expression_group(p):
90*09948d41SKrzysztof Kosiński        "expression : '(' expression ')'"
91*09948d41SKrzysztof Kosiński        p[0] = p[2]
92*09948d41SKrzysztof Kosiński
93*09948d41SKrzysztof Kosiński    def p_expression_number(p):
94*09948d41SKrzysztof Kosiński        "expression : NUMBER"
95*09948d41SKrzysztof Kosiński        p[0] = p[1]
96*09948d41SKrzysztof Kosiński
97*09948d41SKrzysztof Kosiński    def p_expression_name(p):
98*09948d41SKrzysztof Kosiński        "expression : NAME"
99*09948d41SKrzysztof Kosiński        try:
100*09948d41SKrzysztof Kosiński            p[0] = variables[p[1]]
101*09948d41SKrzysztof Kosiński        except LookupError:
102*09948d41SKrzysztof Kosiński            print("Undefined name '%s'" % p[1])
103*09948d41SKrzysztof Kosiński            p[0] = 0
104*09948d41SKrzysztof Kosiński
105*09948d41SKrzysztof Kosiński    def p_error(p):
106*09948d41SKrzysztof Kosiński        if p:
107*09948d41SKrzysztof Kosiński            print("Syntax error at '%s'" % p.value)
108*09948d41SKrzysztof Kosiński        else:
109*09948d41SKrzysztof Kosiński            print("Syntax error at EOF")
110*09948d41SKrzysztof Kosiński
111*09948d41SKrzysztof Kosiński    # Build the parser
112*09948d41SKrzysztof Kosiński    parser = yacc.yacc()
113*09948d41SKrzysztof Kosiński
114*09948d41SKrzysztof Kosiński    # ------- Input function
115*09948d41SKrzysztof Kosiński
116*09948d41SKrzysztof Kosiński    def input(text):
117*09948d41SKrzysztof Kosiński        result = parser.parse(text, lexer=lexer)
118*09948d41SKrzysztof Kosiński        return result
119*09948d41SKrzysztof Kosiński
120*09948d41SKrzysztof Kosiński    return input
121*09948d41SKrzysztof Kosiński
122*09948d41SKrzysztof Kosiński# Make a calculator object and use it
123*09948d41SKrzysztof Kosińskicalc = make_calculator()
124*09948d41SKrzysztof Kosiński
125*09948d41SKrzysztof Kosińskiwhile True:
126*09948d41SKrzysztof Kosiński    try:
127*09948d41SKrzysztof Kosiński        s = raw_input("calc > ")
128*09948d41SKrzysztof Kosiński    except EOFError:
129*09948d41SKrzysztof Kosiński        break
130*09948d41SKrzysztof Kosiński    r = calc(s)
131*09948d41SKrzysztof Kosiński    if r:
132*09948d41SKrzysztof Kosiński        print(r)
133