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