1 #include "MathParser.hpp"
2 
3 namespace pdal
4 {
5 namespace expr
6 {
7 
expression(Expression & expr)8 bool MathParser::expression(Expression& expr)
9 {
10     return addexpr(expr);
11 }
12 
addexpr(Expression & expr)13 bool MathParser::addexpr(Expression& expr)
14 {
15     if (!multexpr(expr))
16         return false;
17 
18     while (true)
19     {
20         NodeType type;
21 
22         if (match(TokenType::Plus))
23             type = NodeType::Add;
24         else if (match(TokenType::Dash))
25             type = NodeType::Subtract;
26         else
27             return true;
28 
29         if (!multexpr(expr))
30         {
31             setError("Expected expression following '" +
32                 curToken().sval() + "'.");
33             return false;
34         }
35 
36         NodePtr right = expr.popNode();
37         NodePtr left = expr.popNode();
38 
39         ConstValueNode *leftVal = dynamic_cast<ConstValueNode *>(left.get());
40         ConstValueNode *rightVal = dynamic_cast<ConstValueNode *>(right.get());
41         if (leftVal && rightVal)
42         {
43             double v = (type == NodeType::Add) ?
44                 leftVal->value() + rightVal->value() :
45                 leftVal->value() - rightVal->value();
46             expr.pushNode(NodePtr(new ConstValueNode(v)));
47         }
48         else
49         {
50             if (left->isBool() || right->isBool())
51             {
52                 setError("Can't apply '" + curToken().sval() + "' to "
53                     "logical expression.");
54                 return false;
55             }
56             expr.pushNode(NodePtr(new BinMathNode(type, std::move(left), std::move(right))));
57         }
58     }
59     return true;
60 }
61 
multexpr(Expression & expr)62 bool MathParser::multexpr(Expression& expr)
63 {
64     if (!uminus(expr))
65         return false;
66 
67     while (true)
68     {
69         NodeType type;
70         if (match(TokenType::Asterisk))
71             type = NodeType::Multiply;
72         else if (match(TokenType::Slash))
73             type = NodeType::Divide;
74         else
75             return true;
76 
77         if (!uminus(expr))
78         {
79             setError("Expected expression following '" +
80                 curToken().sval() + "'.");
81             return false;
82         }
83 
84         NodePtr right = expr.popNode();
85         NodePtr left = expr.popNode();
86 
87         ConstValueNode *leftVal = dynamic_cast<ConstValueNode *>(left.get());
88         ConstValueNode *rightVal = dynamic_cast<ConstValueNode *>(right.get());
89 
90         if (leftVal && rightVal)
91         {
92             double v;
93             if (type == NodeType::Multiply)
94                 v = leftVal->value() * rightVal->value();
95             else
96             {
97                 if (rightVal->value() == 0.0)
98                 {
99                     setError("Divide by 0.");
100                     return false;
101                 }
102                 v = leftVal->value() / rightVal->value();
103             }
104             expr.pushNode(NodePtr(new ConstValueNode(v)));
105         }
106         else
107         {
108             if (left->isBool() || right->isBool())
109             {
110                 setError("Can't apply '" + curToken().sval() + "' to "
111                     "logical expression.");
112                 return false;
113             }
114             expr.pushNode(NodePtr(new BinMathNode(type, std::move(left), std::move(right))));
115         }
116     }
117     return true;
118 }
119 
uminus(Expression & expr)120 bool MathParser::uminus(Expression& expr)
121 {
122     if (!match(TokenType::Dash))
123         return primary(expr);
124 
125     if (!primary(expr))
126     {
127         setError("Expecting expression following '-'.");
128         return false;
129     }
130 
131     NodePtr sub = expr.popNode();
132     ConstValueNode *node = dynamic_cast<ConstValueNode *>(sub.get());
133     if (node)
134     {
135         double v = -(node->value());
136         expr.pushNode(NodePtr(new ConstValueNode(v)));
137     }
138     else
139     {
140         if (node->isBool())
141         {
142             setError("Can't apply '-' to logical expression '" +
143                 sub->print() + "'.");
144             return false;
145         }
146         expr.pushNode(NodePtr(new UnMathNode(NodeType::Negative, std::move(sub))));
147     }
148     return true;
149 }
150 
primary(Expression & expr)151 bool MathParser::primary(Expression& expr)
152 {
153     if (match(TokenType::Number))
154     {
155         expr.pushNode(NodePtr(new ConstValueNode(curToken().dval())));
156         return true;
157     }
158     else if (match(TokenType::Identifier))
159     {
160         expr.pushNode(NodePtr(new VarNode(curToken().sval())));
161         return true;
162     }
163 
164     return parexpr(expr);
165 }
166 
parexpr(Expression & expr)167 bool MathParser::parexpr(Expression& expr)
168 {
169     if (!match(TokenType::Lparen))
170         return false;
171 
172     if (!expression(expr))
173     {
174         setError("Expected expression following '('.");
175         return false;
176     }
177 
178     if (!match(TokenType::Rparen))
179     {
180         setError("Expected ')' following expression at '" +
181             curToken().sval() + "'.");
182         return false;
183     }
184     return true;
185 }
186 
187 } // namespace expr
188 } // namespace pdal
189