|
1 #include "Expression.h" |
|
2 #include "DataBuffer.h" |
|
3 #include "Lexer.h" |
|
4 #include "Variables.h" |
|
5 |
|
6 struct OperatorInfo |
|
7 { |
|
8 EToken token; |
|
9 int numoperands; |
|
10 int priority; |
|
11 EDataHeader header; |
|
12 }; |
|
13 |
|
14 static const OperatorInfo gOperators[] = |
|
15 { |
|
16 { tkExclamationMark, 0, 1, dhNegateLogical, }, |
|
17 { tkMinus, 0, 1, dhUnaryMinus, }, |
|
18 { tkMultiply, 10, 2, dhMultiply, }, |
|
19 { tkDivide, 10, 2, dhDivide, }, |
|
20 { tkModulus, 10, 2, dhModulus, }, |
|
21 { tkPlus, 20, 2, dhAdd, }, |
|
22 { tkMinus, 20, 2, dhSubtract, }, |
|
23 { tkLeftShift, 30, 2, dhLeftShift, }, |
|
24 { tkRightShift, 30, 2, dhRightShift, }, |
|
25 { tkLesser, 40, 2, dhLessThan, }, |
|
26 { tkGreater, 40, 2, dhGreaterThan, }, |
|
27 { tkAtLeast, 40, 2, dhAtLeast, }, |
|
28 { tkAtMost, 40, 2, dhAtMost, }, |
|
29 { tkEquals, 50, 2, dhEquals }, |
|
30 { tkNotEquals, 50, 2, dhNotEquals }, |
|
31 { tkAmperstand, 60, 2, dhAndBitwise }, |
|
32 { tkCaret, 70, 2, dhEorBitwise }, |
|
33 { tkBar, 80, 2, dhOrBitwise }, |
|
34 { tkDoubleAmperstand, 90, 2, dhAndLogical }, |
|
35 { tkDoubleBar, 100, 2, dhOrLogical }, |
|
36 { tkQuestionMark, 110, 3, (EDataHeader) 0 }, |
|
37 }; |
|
38 |
|
39 /* |
|
40 // There isn't a dataheader for ternary operator. Instead, we use dhIfNotGoto |
|
41 // to create an "if-block" inside an expression. |
|
42 // Behold, big block of writing madness! :P |
|
43 ByteMark* mark1 = retbuf->AddMark (""); // start of "else" case |
|
44 ByteMark* mark2 = retbuf->AddMark (""); // end of expression |
|
45 retbuf->WriteDWord (dhIfNotGoto); // if the first operand (condition) |
|
46 retbuf->AddReference (mark1); // didn't eval true, jump into mark1 |
|
47 retbuf->MergeAndDestroy (rb); // otherwise, perform second operand (true case) |
|
48 retbuf->WriteDWord (dhGoto); // afterwards, jump to the end, which is |
|
49 retbuf->AddReference (mark2); // marked by mark2. |
|
50 retbuf->AdjustMark (mark1); // move mark1 at the end of the true case |
|
51 retbuf->MergeAndDestroy (tb); // perform third operand (false case) |
|
52 retbuf->AdjustMark (mark2); // move the ending mark2 here |
|
53 */ |
|
54 |
|
55 // ============================================================================= |
|
56 // |
|
57 Expression::Expression (BotscriptParser* parser, EType reqtype, Lexer* lx) : |
|
58 mParser (parser), |
|
59 mLexer (lx), |
|
60 mType (reqtype), |
|
61 mResult (null) |
|
62 { |
|
63 ExpressionSymbol* sym; |
|
64 |
|
65 while ((sym = ParseSymbol()) != null) |
|
66 mSymbols << sym; |
|
67 |
|
68 if (mSymbols.IsEmpty()) |
|
69 Error ("Expected expression"); |
|
70 |
|
71 Verify(); |
|
72 mResult = Evaluate(); |
|
73 } |
|
74 |
|
75 // ============================================================================= |
|
76 // |
|
77 Expression::~Expression() |
|
78 { |
|
79 for (ExpressionSymbol* sym : mSymbols) |
|
80 delete sym; |
|
81 |
|
82 delete mResult; |
|
83 } |
|
84 |
|
85 // ============================================================================= |
|
86 // |
|
87 // Try to parse an expression symbol (i.e. an operator or operand or a colon) |
|
88 // from the lexer. |
|
89 // |
|
90 ExpressionSymbol* Expression::ParseSymbol() |
|
91 { |
|
92 int pos = mLexer->GetPosition(); |
|
93 ExpressionValue* op = null; |
|
94 enum ELocalException { failed }; |
|
95 |
|
96 try |
|
97 { |
|
98 ScriptVariable* globalvar; |
|
99 mLexer->MustGetNext(); |
|
100 |
|
101 if (mLexer->GetTokenType() == tkColon) |
|
102 return new ExpressionColon; |
|
103 |
|
104 // Check for operator |
|
105 for (const OperatorInfo* op : gOperators) |
|
106 if (mLexer->GetTokenType() == op->token) |
|
107 return new ExpressionOperator (op - gOperators); |
|
108 |
|
109 // Check sub-expression |
|
110 if (mLexer->GetTokenType() == tkParenStart) |
|
111 { |
|
112 mLexer->MustGetNext(); |
|
113 Expression expr (mParser, mLexer, mType); |
|
114 mLexer->MustGetNext (tkParenEnd); |
|
115 return expr.GetResult(); |
|
116 } |
|
117 |
|
118 op = new ExpressionValue; |
|
119 |
|
120 // Check function |
|
121 if (CommandInfo* comm = FindCommandByName (GetTokenString())) |
|
122 { |
|
123 if (mType != EUnknownType && comm->returnvalue != mType) |
|
124 Error ("%1 returns an incompatible data type", comm->name); |
|
125 |
|
126 op->SetBuffer (mParser->ParseCommand (comm)); |
|
127 return op; |
|
128 } |
|
129 |
|
130 // Check constant |
|
131 if (ConstantInfo* constant = mParser->FindConstant (GetTokenString())) |
|
132 { |
|
133 if (mType != constant->type) |
|
134 Error ("constant `%1` is %2, expression requires %3\n", |
|
135 constant->name, GetTypeName (constant->type), |
|
136 GetTypeName (mType)); |
|
137 |
|
138 switch (constant->type) |
|
139 { |
|
140 case EBoolType: |
|
141 case EIntType: |
|
142 op->SetValue (constant->val.ToLong()); |
|
143 break; |
|
144 |
|
145 case EStringType: |
|
146 op->SetValue (GetStringTableIndex (constant->val)); |
|
147 break; |
|
148 |
|
149 case EVoidType: |
|
150 case EUnknownType: |
|
151 break; |
|
152 } |
|
153 |
|
154 return op; |
|
155 } |
|
156 |
|
157 // Check global variable |
|
158 if ((globalvar = FindGlobalVariable (GetTokenString()))) |
|
159 { |
|
160 DataBuffer* buf = new DataBuffer (8); |
|
161 buf->WriteDWord (dhPushGlobalVar); |
|
162 buf->WriteDWord (globalvar->index); |
|
163 op->SetBuffer (buf); |
|
164 return op; |
|
165 } |
|
166 |
|
167 EToken tt; |
|
168 |
|
169 // Check for literal |
|
170 switch (mType) |
|
171 { |
|
172 case EVoidType: |
|
173 case EUnknownType: |
|
174 Error ("unknown identifier `%1` (expected keyword, function or variable)", GetTokenString()); |
|
175 break; |
|
176 |
|
177 case EBoolType: |
|
178 if ((tt = mLexer->GetTokenType()) == tkTrue || tt == tkFalse) |
|
179 { |
|
180 op->SetValue (tt == tkTrue ? 1 : 0); |
|
181 return op; |
|
182 } |
|
183 case EIntType: |
|
184 if (!mLexer->GetTokenType() != tkNumber) |
|
185 throw failed; |
|
186 |
|
187 op->SetValue (GetTokenString().ToLong()); |
|
188 return op; |
|
189 |
|
190 case EStringType: |
|
191 if (!mLexer->GetTokenType() != tkString) |
|
192 throw failed; |
|
193 |
|
194 op->SetValue (GetStringTableIndex (GetTokenString())); |
|
195 return op; |
|
196 } |
|
197 |
|
198 assert (false); |
|
199 throw failed; |
|
200 } |
|
201 catch (ELocalException&) |
|
202 { |
|
203 // We use a local enum here since catch(...) would catch Error() calls. |
|
204 mLexer->SetPosition (pos); |
|
205 delete op; |
|
206 return false; |
|
207 } |
|
208 |
|
209 assert (false); |
|
210 return false; |
|
211 } |
|
212 |
|
213 // ============================================================================= |
|
214 // |
|
215 ExpressionValue* Expression::Evaluate() |
|
216 { |
|
217 |
|
218 } |
|
219 |
|
220 // ============================================================================= |
|
221 // |
|
222 ExpressionValue* Expression::GetResult() |
|
223 { |
|
224 return mResult; |
|
225 } |
|
226 |
|
227 // ============================================================================= |
|
228 // |
|
229 String Expression::GetTokenString() |
|
230 { |
|
231 return mLexer->GetToken()->text; |
|
232 } |
|
233 |
|
234 // ============================================================================= |
|
235 // |
|
236 ExpressionOperator::ExpressionOperator (int id) : |
|
237 mID (id), |
|
238 mType (eOperator) {} |
|
239 |
|
240 // ============================================================================= |
|
241 // |
|
242 ExpressionValue::ExpressionValue(EType valuetype) : |
|
243 mBuffer (null), |
|
244 mType (eOperand), |
|
245 mValueType (valuetype) {} |
|
246 |
|
247 // ============================================================================= |
|
248 // |
|
249 void ExpressionValue::ConvertToBuffer() |
|
250 { |
|
251 if (IsConstexpr() == false) |
|
252 return; |
|
253 |
|
254 SetBuffer (new DataBuffer); |
|
255 |
|
256 switch (mValueType) |
|
257 { |
|
258 case EBoolType: |
|
259 case EIntType: |
|
260 GetBuffer()->WriteDWord (dhPushNumber); |
|
261 GetBuffer()->WriteDWord (abs (mValue)); |
|
262 |
|
263 if (mValue < 0) |
|
264 GetBuffer()->WriteDWord (dhUnaryMinus); |
|
265 break; |
|
266 |
|
267 case EStringType: |
|
268 GetBuffer()->WriteDWord (dhPushStringIndex); |
|
269 GetBuffer()->WriteDWord (mValue); |
|
270 break; |
|
271 |
|
272 case EVoidType: |
|
273 case EUnknownType: |
|
274 assert (false); |
|
275 break; |
|
276 } |
|
277 } |