src/Expression.cc

changeset 91
427eb377d53e
child 92
3a00d396bce2
equal deleted inserted replaced
90:90ab2f2b3dc0 91:427eb377d53e
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 }

mercurial