5 struct OperatorInfo |
5 struct OperatorInfo |
6 { |
6 { |
7 EToken token; |
7 EToken token; |
8 int priority; |
8 int priority; |
9 int numoperands; |
9 int numoperands; |
10 EDataHeader header; |
10 DataHeader header; |
11 }; |
11 }; |
12 |
12 |
13 static const OperatorInfo gOperators[] = |
13 static const OperatorInfo gOperators[] = |
14 { |
14 { |
15 { tkExclamationMark, 0, 1, dhNegateLogical, }, |
15 { tkExclamationMark, 0, 1, DH_NegateLogical, }, |
16 { tkMinus, 0, 1, dhUnaryMinus, }, |
16 { tkMinus, 0, 1, DH_UnaryMinus, }, |
17 { tkMultiply, 10, 2, dhMultiply, }, |
17 { tkMultiply, 10, 2, DH_Multiply, }, |
18 { tkDivide, 10, 2, dhDivide, }, |
18 { tkDivide, 10, 2, DH_Divide, }, |
19 { tkModulus, 10, 2, dhModulus, }, |
19 { tkModulus, 10, 2, DH_Modulus, }, |
20 { tkPlus, 20, 2, dhAdd, }, |
20 { tkPlus, 20, 2, DH_Add, }, |
21 { tkMinus, 20, 2, dhSubtract, }, |
21 { tkMinus, 20, 2, DH_Subtract, }, |
22 { tkLeftShift, 30, 2, dhLeftShift, }, |
22 { tkLeftShift, 30, 2, DH_LeftShift, }, |
23 { tkRightShift, 30, 2, dhRightShift, }, |
23 { tkRightShift, 30, 2, DH_RightShift, }, |
24 { tkLesser, 40, 2, dhLessThan, }, |
24 { tkLesser, 40, 2, DH_LessThan, }, |
25 { tkGreater, 40, 2, dhGreaterThan, }, |
25 { tkGreater, 40, 2, DH_GreaterThan, }, |
26 { tkAtLeast, 40, 2, dhAtLeast, }, |
26 { tkAtLeast, 40, 2, DH_AtLeast, }, |
27 { tkAtMost, 40, 2, dhAtMost, }, |
27 { tkAtMost, 40, 2, DH_AtMost, }, |
28 { tkEquals, 50, 2, dhEquals }, |
28 { tkEquals, 50, 2, DH_Equals }, |
29 { tkNotEquals, 50, 2, dhNotEquals }, |
29 { tkNotEquals, 50, 2, DH_NotEquals }, |
30 { tkAmperstand, 60, 2, dhAndBitwise }, |
30 { tkAmperstand, 60, 2, DH_AndBitwise }, |
31 { tkCaret, 70, 2, dhEorBitwise }, |
31 { tkCaret, 70, 2, DH_EorBitwise }, |
32 { tkBar, 80, 2, dhOrBitwise }, |
32 { tkBar, 80, 2, DH_OrBitwise }, |
33 { tkDoubleAmperstand, 90, 2, dhAndLogical }, |
33 { tkDoubleAmperstand, 90, 2, DH_AndLogical }, |
34 { tkDoubleBar, 100, 2, dhOrLogical }, |
34 { tkDoubleBar, 100, 2, DH_OrLogical }, |
35 { tkQuestionMark, 110, 3, (EDataHeader) 0 }, |
35 { tkQuMARK_stion, 110, 3, (DataHeader) 0 }, |
36 }; |
36 }; |
37 |
37 |
38 // ============================================================================= |
38 // ============================================================================= |
39 // |
39 // |
40 Expression::Expression (BotscriptParser* parser, Lexer* lx, EType reqtype) : |
40 Expression::Expression (BotscriptParser* parser, Lexer* lx, DataType reqtype) : |
41 mParser (parser), |
41 mParser (parser), |
42 mLexer (lx), |
42 mLexer (lx), |
43 mType (reqtype) |
43 mType (reqtype) |
44 { |
44 { |
45 ExpressionSymbol* sym; |
45 ExpressionSymbol* sym; |
66 delete sym; |
66 delete sym; |
67 } |
67 } |
68 |
68 |
69 // ============================================================================= |
69 // ============================================================================= |
70 // |
70 // |
71 // Try to parse an expression symbol (i.e. an operator or operand or a colon) |
71 // Try to parse an expression symbol (i.e. an OPER_erator or OPER_erand or a colon) |
72 // from the lexer. |
72 // from the lexer. |
73 // |
73 // |
74 ExpressionSymbol* Expression::ParseSymbol() |
74 ExpressionSymbol* Expression::ParseSymbol() |
75 { |
75 { |
76 int pos = mLexer->GetPosition(); |
76 int pos = mLexer->GetPosition(); |
77 ExpressionValue* op = null; |
77 ExpressionValue* op = null; |
78 |
78 |
79 if (mLexer->GetNext (tkColon)) |
79 if (mLexer->GetNext (tkColon)) |
80 return new ExpressionColon; |
80 return new ExpressionColon; |
81 |
81 |
82 // Check for operator |
82 // Check for OPER_erator |
83 for (const OperatorInfo& op : gOperators) |
83 for (const OperatorInfo& op : gOperators) |
84 if (mLexer->GetNext (op.token)) |
84 if (mLexer->GetNext (op.token)) |
85 return new ExpressionOperator ((EOperator) (&op - &gOperators[0])); |
85 return new ExpressionOperator ((ExpressionOperatorType) (&op - &gOperators[0])); |
86 |
86 |
87 // Check sub-expression |
87 // Check sub-expression |
88 if (mLexer->GetNext (tkParenStart)) |
88 if (mLexer->GetNext (tkParenStart)) |
89 { |
89 { |
90 Expression expr (mParser, mLexer, mType); |
90 Expression expr (mParser, mLexer, mType); |
120 GetTypeName (mType), var->name, GetTypeName (var->type)); |
120 GetTypeName (mType), var->name, GetTypeName (var->type)); |
121 |
121 |
122 if (var->isarray) |
122 if (var->isarray) |
123 { |
123 { |
124 mLexer->MustGetNext (tkBracketStart); |
124 mLexer->MustGetNext (tkBracketStart); |
125 Expression expr (mParser, mLexer, EIntType); |
125 Expression expr (mParser, mLexer, TYPE_Int); |
126 expr.GetResult()->ConvertToBuffer(); |
126 expr.GetResult()->ConvertToBuffer(); |
127 DataBuffer* buf = expr.GetResult()->GetBuffer()->Clone(); |
127 DataBuffer* buf = expr.GetResult()->GetBuffer()->Clone(); |
128 buf->WriteDWord (dhPushGlobalArray); |
128 buf->WriteDWord (DH_PushGlobalArray); |
129 buf->WriteDWord (var->index); |
129 buf->WriteDWord (var->index); |
130 op->SetBuffer (buf); |
130 op->SetBuffer (buf); |
131 mLexer->MustGetNext (tkBracketEnd); |
131 mLexer->MustGetNext (tkBracketEnd); |
132 } |
132 } |
133 elif (var->writelevel == Variable::WRITE_Constexpr) |
133 elif (var->writelevel == WRITE_Constexpr) |
134 op->SetValue (var->value); |
134 op->SetValue (var->value); |
135 else |
135 else |
136 { |
136 { |
137 DataBuffer* buf = new DataBuffer (8); |
137 DataBuffer* buf = new DataBuffer (8); |
138 |
138 |
139 if (var->IsGlobal()) |
139 if (var->IsGlobal()) |
140 buf->WriteDWord (dhPushGlobalVar); |
140 buf->WriteDWord (DH_PushGlobalVar); |
141 else |
141 else |
142 buf->WriteDWord (dhPushLocalVar); |
142 buf->WriteDWord (DH_PushLocalVar); |
143 |
143 |
144 buf->WriteDWord (var->index); |
144 buf->WriteDWord (var->index); |
145 op->SetBuffer (buf); |
145 op->SetBuffer (buf); |
146 } |
146 } |
147 |
147 |
193 return null; |
193 return null; |
194 } |
194 } |
195 |
195 |
196 // ============================================================================= |
196 // ============================================================================= |
197 // |
197 // |
198 // The symbol parsing process only does token-based checking for operators. Thus |
198 // The symbol parsing process only does token-based checking for OPER_erators. Thus |
199 // ALL minus operators are actually unary minuses simply because both have |
199 // ALL minus OPER_erators are actually unary minuses simply because both have |
200 // tkMinus as their token and the unary minus is prior to the binary minus in |
200 // tkMinus as their token and the unary minus is prior to the binary minus in |
201 // the operator table. Now that we have all symbols present, we can correct |
201 // the OPER_erator table. Now that we have all symbols present, we can correct |
202 // cases like this. |
202 // cases like this. |
203 // |
203 // |
204 void Expression::AdjustOperators() |
204 void Expression::AdjustOperators() |
205 { |
205 { |
206 for (auto it = mSymbols.begin() + 1; it != mSymbols.end(); ++it) |
206 for (auto it = mSymbols.begin() + 1; it != mSymbols.end(); ++it) |
207 { |
207 { |
208 if ((*it)->GetType() != eOperatorSymbol) |
208 if ((*it)->GetType() != EXPRSYM_Operator) |
209 continue; |
209 continue; |
210 |
210 |
211 ExpressionOperator* op = static_cast<ExpressionOperator*> (*it); |
211 ExpressionOperator* op = static_cast<ExpressionOperator*> (*it); |
212 |
212 |
213 // Unary minus with a value as the previous symbol cannot really be |
213 // Unary minus with a value as the previous symbol cannot really be |
214 // unary; replace with binary minus. |
214 // unary; replace with binary minus. |
215 if (op->GetID() == opUnaryMinus && (*(it - 1))->GetType() == eValueSymbol) |
215 if (op->GetID() == OPER_UnaryMinus && (*(it - 1))->GetType() == EXPRSYM_Value) |
216 op->SetID (opSubtraction); |
216 op->SetID (OPER_Subtraction); |
217 } |
217 } |
218 } |
218 } |
219 |
219 |
220 // ============================================================================= |
220 // ============================================================================= |
221 // |
221 // |
222 // Verifies a single value. Helper function for Expression::Verify. |
222 // Verifies a single value. Helper function for Expression::Verify. |
223 // |
223 // |
224 void Expression::TryVerifyValue (bool* verified, SymbolList::Iterator it) |
224 void Expression::TryVerifyValue (bool* verified, SymbolList::Iterator it) |
225 { |
225 { |
226 // If it's an unary operator we skip to its value. The actual operator will |
226 // If it's an unary OPER_erator we skip to its value. The actual OPER_erator will |
227 // be verified separately. |
227 // be verified separately. |
228 if ((*it)->GetType() == eOperatorSymbol && |
228 if ((*it)->GetType() == EXPRSYM_Operator && |
229 gOperators[static_cast<ExpressionOperator*> (*it)->GetID()].numoperands == 1) |
229 gOperators[static_cast<ExpressionOperator*> (*it)->GetID()].numoperands == 1) |
230 { |
230 { |
231 ++it; |
231 ++it; |
232 } |
232 } |
233 |
233 |
234 int i = it - mSymbols.begin(); |
234 int i = it - mSymbols.begin(); |
235 |
235 |
236 // Ensure it's an actual value |
236 // Ensure it's an actual value |
237 if ((*it)->GetType() != eValueSymbol) |
237 if ((*it)->GetType() != EXPRSYM_Value) |
238 Error ("malformed expression (symbol #%1 is not a value)", i); |
238 Error ("malformed expression (symbol #%1 is not a value)", i); |
239 |
239 |
240 verified[i] = true; |
240 verified[i] = true; |
241 } |
241 } |
242 |
242 |
247 // |
247 // |
248 void Expression::Verify() |
248 void Expression::Verify() |
249 { |
249 { |
250 if (mSymbols.Size() == 1) |
250 if (mSymbols.Size() == 1) |
251 { |
251 { |
252 if (mSymbols[0]->GetType() != eValueSymbol) |
252 if (mSymbols[0]->GetType() != EXPRSYM_Value) |
253 Error ("bad expression"); |
253 Error ("bad expression"); |
254 |
254 |
255 return; |
255 return; |
256 } |
256 } |
257 |
257 |
258 if (mType == EStringType) |
258 if (mType == TYPE_String) |
259 Error ("Cannot perform operations on strings"); |
259 Error ("Cannot perform OPER_erations on strings"); |
260 |
260 |
261 bool* verified = new bool[mSymbols.Size()]; |
261 bool* verified = new bool[mSymbols.Size()]; |
262 memset (verified, 0, mSymbols.Size() * sizeof (decltype (*verified))); |
262 memset (verified, 0, mSymbols.Size() * sizeof (decltype (*verified))); |
263 const auto last = mSymbols.end() - 1; |
263 const auto last = mSymbols.end() - 1; |
264 const auto first = mSymbols.begin(); |
264 const auto first = mSymbols.begin(); |
265 |
265 |
266 for (auto it = mSymbols.begin(); it != mSymbols.end(); ++it) |
266 for (auto it = mSymbols.begin(); it != mSymbols.end(); ++it) |
267 { |
267 { |
268 int i = (it - first); |
268 int i = (it - first); |
269 |
269 |
270 if ((*it)->GetType() != eOperatorSymbol) |
270 if ((*it)->GetType() != EXPRSYM_Operator) |
271 continue; |
271 continue; |
272 |
272 |
273 ExpressionOperator* op = static_cast<ExpressionOperator*> (*it); |
273 ExpressionOperator* op = static_cast<ExpressionOperator*> (*it); |
274 int numoperands = gOperators[op->GetID()].numoperands; |
274 int numoperands = gOperators[op->GetID()].numoperands; |
275 |
275 |
276 switch (numoperands) |
276 switch (numoperands) |
277 { |
277 { |
278 case 1: |
278 case 1: |
279 { |
279 { |
280 // Ensure that: |
280 // Ensure that: |
281 // - unary operator is not the last symbol |
281 // - unary OPER_erator is not the last symbol |
282 // - unary operator is succeeded by a value symbol |
282 // - unary OPER_erator is succeeded by a value symbol |
283 // - neither symbol overlaps with something already verified |
283 // - neither symbol overlaps with something already verified |
284 TryVerifyValue (verified, it + 1); |
284 TryVerifyValue (verified, it + 1); |
285 |
285 |
286 if (it == last || verified[i] == true) |
286 if (it == last || verified[i] == true) |
287 Error ("malformed expression"); |
287 Error ("malformed expression"); |
413 // This is not a constant expression so we'll have to use databuffers |
413 // This is not a constant expression so we'll have to use databuffers |
414 // to convey the expression to bytecode. Actual value cannot be evaluated |
414 // to convey the expression to bytecode. Actual value cannot be evaluated |
415 // until Zandronum processes it at run-time. |
415 // until Zandronum processes it at run-time. |
416 newval->SetBuffer (new DataBuffer); |
416 newval->SetBuffer (new DataBuffer); |
417 |
417 |
418 if (op->GetID() == opTernary) |
418 if (op->GetID() == OPER_Ternary) |
419 { |
419 { |
420 // There isn't a dataheader for ternary operator. Instead, we use dhIfNotGoto |
420 // There isn't a dataheader for ternary OPER_erator. Instead, we use DH_IfNotGoto |
421 // to create an "if-block" inside an expression. |
421 // to create an "if-block" inside an expression. |
422 // Behold, big block of writing madness! :P |
422 // Behold, big block of writing madness! :P |
423 // |
423 // |
424 DataBuffer* buf = newval->GetBuffer(); |
424 DataBuffer* buf = newval->GetBuffer(); |
425 DataBuffer* b0 = values[0]->GetBuffer(); |
425 DataBuffer* b0 = values[0]->GetBuffer(); |
426 DataBuffer* b1 = values[1]->GetBuffer(); |
426 DataBuffer* b1 = values[1]->GetBuffer(); |
427 DataBuffer* b2 = values[2]->GetBuffer(); |
427 DataBuffer* b2 = values[2]->GetBuffer(); |
428 ByteMark* mark1 = buf->AddMark (""); // start of "else" case |
428 ByteMark* mark1 = buf->AddMark (""); // start of "else" case |
429 ByteMark* mark2 = buf->AddMark (""); // end of expression |
429 ByteMark* mark2 = buf->AddMark (""); // end of expression |
430 buf->MergeAndDestroy (b0); |
430 buf->MergeAndDestroy (b0); |
431 buf->WriteDWord (dhIfNotGoto); // if the first operand (condition) |
431 buf->WriteDWord (DH_IfNotGoto); // if the first OPER_erand (condition) |
432 buf->AddReference (mark1); // didn't eval true, jump into mark1 |
432 buf->AddReference (mark1); // didn't eval true, jump into mark1 |
433 buf->MergeAndDestroy (b1); // otherwise, perform second operand (true case) |
433 buf->MergeAndDestroy (b1); // otherwise, perform second OPER_erand (true case) |
434 buf->WriteDWord (dhGoto); // afterwards, jump to the end, which is |
434 buf->WriteDWord (DH_Goto); // afterwards, jump to the end, which is |
435 buf->AddReference (mark2); // marked by mark2. |
435 buf->AddReference (mark2); // marked by mark2. |
436 buf->AdjustMark (mark1); // move mark1 at the end of the true case |
436 buf->AdjustMark (mark1); // move mark1 at the end of the true case |
437 buf->MergeAndDestroy (b2); // perform third operand (false case) |
437 buf->MergeAndDestroy (b2); // perform third OPER_erand (false case) |
438 buf->AdjustMark (mark2); // move the ending mark2 here |
438 buf->AdjustMark (mark2); // move the ending mark2 here |
439 |
439 |
440 for (int i = 0; i < 3; ++i) |
440 for (int i = 0; i < 3; ++i) |
441 values[i]->SetBuffer (null); |
441 values[i]->SetBuffer (null); |
442 } |
442 } |
443 else |
443 else |
444 { |
444 { |
445 // Generic case: write all arguments and apply the operator's |
445 // Generic case: write all arguments and apply the OPER_erator's |
446 // data header. |
446 // data header. |
447 for (ExpressionValue* val : values) |
447 for (ExpressionValue* val : values) |
448 { |
448 { |
449 newval->GetBuffer()->MergeAndDestroy (val->GetBuffer()); |
449 newval->GetBuffer()->MergeAndDestroy (val->GetBuffer()); |
450 |
450 |
466 for (ExpressionValue* val : values) |
466 for (ExpressionValue* val : values) |
467 nums << val->GetValue(); |
467 nums << val->GetValue(); |
468 |
468 |
469 switch (op->GetID()) |
469 switch (op->GetID()) |
470 { |
470 { |
471 case opAddition: a = nums[0] + nums[1]; break; |
471 case OPER_Addition: a = nums[0] + nums[1]; break; |
472 case opSubtraction: a = nums[0] - nums[1]; break; |
472 case OPER_Subtraction: a = nums[0] - nums[1]; break; |
473 case opMultiplication: a = nums[0] * nums[1]; break; |
473 case OPER_Multiplication: a = nums[0] * nums[1]; break; |
474 case opUnaryMinus: a = -nums[0]; break; |
474 case OPER_UnaryMinus: a = -nums[0]; break; |
475 case opNegateLogical: a = !nums[0]; break; |
475 case OPER_NegateLogical: a = !nums[0]; break; |
476 case opLeftShift: a = nums[0] << nums[1]; break; |
476 case OPER_LeftShift: a = nums[0] << nums[1]; break; |
477 case opRightShift: a = nums[0] >> nums[1]; break; |
477 case OPER_RightShift: a = nums[0] >> nums[1]; break; |
478 case opCompareLesser: a = (nums[0] < nums[1]) ? 1 : 0; break; |
478 case OPER_CompareLesser: a = (nums[0] < nums[1]) ? 1 : 0; break; |
479 case opCompareGreater: a = (nums[0] > nums[1]) ? 1 : 0; break; |
479 case OPER_CompareGreater: a = (nums[0] > nums[1]) ? 1 : 0; break; |
480 case opCompareAtLeast: a = (nums[0] <= nums[1]) ? 1 : 0; break; |
480 case OPER_CompareAtLeast: a = (nums[0] <= nums[1]) ? 1 : 0; break; |
481 case opCompareAtMost: a = (nums[0] >= nums[1]) ? 1 : 0; break; |
481 case OPER_CompareAtMost: a = (nums[0] >= nums[1]) ? 1 : 0; break; |
482 case opCompareEquals: a = (nums[0] == nums[1]) ? 1 : 0; break; |
482 case OPER_CompareEquals: a = (nums[0] == nums[1]) ? 1 : 0; break; |
483 case opCompareNotEquals: a = (nums[0] != nums[1]) ? 1 : 0; break; |
483 case OPER_CompareNotEquals: a = (nums[0] != nums[1]) ? 1 : 0; break; |
484 case opBitwiseAnd: a = nums[0] & nums[1]; break; |
484 case OPER_BitwiseAnd: a = nums[0] & nums[1]; break; |
485 case opBitwiseOr: a = nums[0] | nums[1]; break; |
485 case OPER_BitwiseOr: a = nums[0] | nums[1]; break; |
486 case opBitwiseXOr: a = nums[0] ^ nums[1]; break; |
486 case OPER_BitwiseXOr: a = nums[0] ^ nums[1]; break; |
487 case opLogicalAnd: a = (nums[0] && nums[1]) ? 1 : 0; break; |
487 case OPER_LogicalAnd: a = (nums[0] && nums[1]) ? 1 : 0; break; |
488 case opLogicalOr: a = (nums[0] || nums[1]) ? 1 : 0; break; |
488 case OPER_LogicalOr: a = (nums[0] || nums[1]) ? 1 : 0; break; |
489 case opTernary: a = (nums[0] != 0) ? nums[1] : nums[2]; break; |
489 case OPER_Ternary: a = (nums[0] != 0) ? nums[1] : nums[2]; break; |
490 |
490 |
491 case opDivision: |
491 case OPER_Division: |
492 { |
492 { |
493 if (nums[1] == 0) |
493 if (nums[1] == 0) |
494 Error ("division by zero in constant expression"); |
494 Error ("division by zero in constant expression"); |
495 |
495 |
496 a = nums[0] / nums[1]; |
496 a = nums[0] / nums[1]; |
497 break; |
497 break; |
498 } |
498 } |
499 |
499 |
500 case opModulus: |
500 case OPER_Modulus: |
501 { |
501 { |
502 if (nums[1] == 0) |
502 if (nums[1] == 0) |
503 Error ("modulus by zero in constant expression"); |
503 Error ("modulus by zero in constant expression"); |
504 |
504 |
505 a = nums[0] % nums[1]; |
505 a = nums[0] % nums[1]; |