1 /**
2 This module contains a simple example of a arithmetic expression grammar and
3 how use the ParseTree to calculate a expression.
4 */
5 module pegged.examples.simple_arithmetic;
6 
7 import std.conv: to;
8 
9 import pegged.grammar;
10 
11 mixin(grammar(`
12 Arithmetic:
13     Term     < Factor (Add / Sub)*
14     Add      < "+" Factor
15     Sub      < "-" Factor
16     Factor   < Primary (Mul / Div)*
17     Mul      < "*" Primary
18     Div      < "/" Primary
19     Primary  < Parens / Neg / Number / Variable
20     Parens   < :"(" Term :")"
21     Neg      < "-" Primary
22     Number   < ~([0-9]+)
23     Variable <- identifier
24 `));
25 
26 /// Example interpreter
27 float interpreter(string expr)
28 {
29     auto p = Arithmetic(expr);
30 
31     // Travels the ParseTree, calculting the expresion value
32     float value(ParseTree p)
33     {
34         switch (p.name)
35         {
36             case "Arithmetic":
37                 return value(p.children[0]);
38             case "Arithmetic.Term":
39                 float v = 0.0;
40                 foreach(child; p.children) v += value(child);
41                 return v;
42             case "Arithmetic.Add":
43                 return value(p.children[0]);
44             case "Arithmetic.Sub":
45                 return -value(p.children[0]);
46             case "Arithmetic.Factor":
47                 float v = 1.0;
48                 foreach(child; p.children) v *= value(child);
49                 return v;
50             case "Arithmetic.Mul":
51                 return value(p.children[0]);
52             case "Arithmetic.Div":
53                 return 1.0/value(p.children[0]);
54             case "Arithmetic.Primary":
55                 return value(p.children[0]);
56             case "Arithmetic.Parens":
57                 return value(p.children[0]);
58             case "Arithmetic.Neg":
59                 return -value(p.children[0]);
60             case "Arithmetic.Number":
61                 return to!float(p.matches[0]);
62             default:
63                 return float.nan;
64         }
65     }
66 
67     return value(p);
68 }
69 
70 unittest
71 {
72     assert(interpreter("1") == 1.0);
73     assert(interpreter("-1") == -1.0);
74     assert(interpreter("1+1") == 2.0);
75     assert(interpreter("1-1") == 0.0);
76 
77     assert(interpreter("1+1+1") == 3.0);
78     assert(interpreter("1-1-1") == -1.0);
79     assert(interpreter("1+1-1") == 1.0);
80     assert(interpreter("1-1+1") == 1.0);
81     assert(interpreter("-1+1+1") == 1.0);
82 
83     assert(interpreter("(-1+1)+1") == 1.0);
84     assert(interpreter("-1+(1+1)") == 1.0);
85     assert(interpreter("(-1+1+1)") == 1.0);
86     assert(interpreter("1-(1-1)") == 1.0);
87 
88     assert(interpreter("1*1") == 1.0);
89     assert(interpreter("1/1") == 1.0);
90     assert(interpreter("-1*1") == -1.0);
91     assert(interpreter("-1/1") == -1.0);
92 
93     assert(interpreter("1+2*3") == 7.0);
94     assert(interpreter("1-2*3") == -5.0);
95     assert(interpreter("-1-2*-3") == 5.0);
96     assert(interpreter("-1+2*-3") == -7.0);
97 
98     assert(interpreter("1/2/(1/2)") == 1.0);
99     assert(interpreter("1/2/1/2") == .25);
100     assert(interpreter("1 - 2*3 - 2*3") == -11.0);
101 
102     assert(interpreter("2*3*3 - 3*3+3*4") == 21.0);
103     assert(interpreter("2 * 3 * 3 - 3 * (3 + 3 * 4)") == -27.0);
104 }