aboutsummaryrefslogtreecommitdiff
path: root/examples/calc.g
blob: 54328554f017b789d42eee63fba57058694c446b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
globalvars = {}       # We will store the calculator's variables here

def lookup(map, name):
    for x,v in map:  
        if x == name: return v
    if not globalvars.has_key(name): print 'Undefined (defaulting to 0):', name
    return globalvars.get(name, 0)

def stack_input(scanner,ign):
    """Grab more input"""
    scanner.stack_input(raw_input(">?> "))

%%
parser Calculator:
    ignore:    "[ \r\t\n]+"
    ignore:    "[?]"         {{ stack_input }}

    token END: "$"
    token NUM: "[0-9]+"
    token VAR: "[a-zA-Z_]+"

    # Each line can either be an expression or an assignment statement
    rule goal:   expr<<[]>> END            {{ print '=', expr }}
                                           {{ return expr }}
               | "set" VAR expr<<[]>> END  {{ globalvars[VAR] = expr }}
                                           {{ print VAR, '=', expr }}
                                           {{ return expr }}

    # An expression is the sum and difference of factors
    rule expr<<V>>:   factor<<V>>         {{ n = factor }}
                     ( "[+]" factor<<V>>  {{ n = n+factor }}
                     |  "-"  factor<<V>>  {{ n = n-factor }}
                     )*                   {{ return n }}

    # A factor is the product and division of terms
    rule factor<<V>>: term<<V>>           {{ v = term }}
                     ( "[*]" term<<V>>    {{ v = v*term }}
                     |  "/"  term<<V>>    {{ v = v/term }}
                     )*                   {{ return v }}

    # A term is a number, variable, or an expression surrounded by parentheses
    rule term<<V>>:   
                 NUM                      {{ return int(NUM) }}
               | VAR                      {{ return lookup(V, VAR) }}
               | "\\(" expr "\\)"         {{ return expr }}
               | "let" VAR "=" expr<<V>>  {{ V = [(VAR, expr)] + V }}
                 "in" expr<<V>>           {{ return expr }}
%%
if __name__=='__main__':
    print 'Welcome to the calculator sample for Yapps 2.'
    print '  Enter either "<expression>" or "set <var> <expression>",'
    print '  or just press return to exit.  An expression can have'
    print '  local variables:  let x = expr in expr'
    # We could have put this loop into the parser, by making the
    # `goal' rule use (expr | set var expr)*, but by putting the
    # loop into Python code, we can make it interactive (i.e., enter
    # one expression, get the result, enter another expression, etc.)
    while 1:
        try: s = raw_input('>>> ')
        except EOFError: break
        if not s.strip(): break
        parse('goal', s)
    print 'Bye.'