1132 Error ("DataHeaderByOperator: couldn't find dataheader for operator %d!\n", oper); |
1133 Error ("DataHeaderByOperator: couldn't find dataheader for operator %d!\n", oper); |
1133 return 0; |
1134 return 0; |
1134 } |
1135 } |
1135 |
1136 |
1136 // ============================================================================ |
1137 // ============================================================================ |
1137 // Parses an expression, potentially recursively |
|
1138 // |
|
1139 DataBuffer* BotscriptParser::ParseExpression (EType reqtype) |
|
1140 { |
|
1141 DataBuffer* retbuf = new DataBuffer (64); |
|
1142 |
|
1143 // Parse first operand |
|
1144 retbuf->MergeAndDestroy (ParseExprValue (reqtype)); |
|
1145 |
|
1146 // Parse any and all operators we get |
|
1147 int oper; |
|
1148 |
|
1149 while ( (oper = ParseOperator (true)) != -1) |
|
1150 { |
|
1151 // We peeked the operator, move forward now |
|
1152 mLexer->Skip(); |
|
1153 |
|
1154 // Can't be an assignement operator, those belong in assignments. |
|
1155 if (IsAssignmentOperator (oper)) |
|
1156 Error ("assignment operator inside expression"); |
|
1157 |
|
1158 // Parse the right operand. |
|
1159 mLexer->MustGetNext(); |
|
1160 DataBuffer* rb = ParseExprValue (reqtype); |
|
1161 |
|
1162 if (oper == OPER_TERNARY) |
|
1163 { |
|
1164 // Ternary operator requires - naturally - a third operand. |
|
1165 mLexer->MustGetNext (tkColon); |
|
1166 mLexer->MustGetNext(); |
|
1167 DataBuffer* tb = ParseExprValue (reqtype); |
|
1168 |
|
1169 // It also is handled differently: there isn't a dataheader for ternary |
|
1170 // operator. Instead, we abuse PUSHNUMBER and IFNOTGOTO for this. |
|
1171 // Behold, big block of writing madness! :P |
|
1172 ByteMark* mark1 = retbuf->AddMark (""); // start of "else" case |
|
1173 ByteMark* mark2 = retbuf->AddMark (""); // end of expression |
|
1174 retbuf->WriteDWord (dhIfNotGoto); // if the first operand (condition) |
|
1175 retbuf->AddReference (mark1); // didn't eval true, jump into mark1 |
|
1176 retbuf->MergeAndDestroy (rb); // otherwise, perform second operand (true case) |
|
1177 retbuf->WriteDWord (dhGoto); // afterwards, jump to the end, which is |
|
1178 retbuf->AddReference (mark2); // marked by mark2. |
|
1179 retbuf->AdjustMark (mark1); // move mark1 at the end of the true case |
|
1180 retbuf->MergeAndDestroy (tb); // perform third operand (false case) |
|
1181 retbuf->AdjustMark (mark2); // move the ending mark2 here |
|
1182 } |
|
1183 else |
|
1184 { |
|
1185 // write to buffer |
|
1186 retbuf->MergeAndDestroy (rb); |
|
1187 retbuf->WriteDWord (GetDataHeaderByOperator (null, oper)); |
|
1188 } |
|
1189 } |
|
1190 |
|
1191 return retbuf; |
|
1192 } |
|
1193 |
|
1194 // ============================================================================ |
|
1195 // Parses an operator string. Returns the operator number code. |
|
1196 // |
|
1197 #define ISNEXT(C) (mLexer->PeekNextString (peek ? 1 : 0) == C) |
|
1198 |
|
1199 int BotscriptParser::ParseOperator (bool peek) |
|
1200 { |
|
1201 String oper; |
|
1202 |
|
1203 if (peek) |
|
1204 oper += mLexer->PeekNextString(); |
|
1205 else |
|
1206 oper += GetTokenString(); |
|
1207 |
|
1208 if (-oper == "strlen") |
|
1209 return OPER_STRLEN; |
|
1210 |
|
1211 // Check one-char operators |
|
1212 bool equalsnext = ISNEXT ("="); |
|
1213 |
|
1214 int o = (oper == "=" && !equalsnext) ? OPER_ASSIGN : |
|
1215 (oper == ">" && !equalsnext && !ISNEXT (">")) ? OPER_GREATERTHAN : |
|
1216 (oper == "<" && !equalsnext && !ISNEXT ("<")) ? OPER_LESSTHAN : |
|
1217 (oper == "&" && !ISNEXT ("&")) ? OPER_BITWISEAND : |
|
1218 (oper == "|" && !ISNEXT ("|")) ? OPER_BITWISEOR : |
|
1219 (oper == "+" && !equalsnext) ? OPER_ADD : |
|
1220 (oper == "-" && !equalsnext) ? OPER_SUBTRACT : |
|
1221 (oper == "*" && !equalsnext) ? OPER_MULTIPLY : |
|
1222 (oper == "/" && !equalsnext) ? OPER_DIVIDE : |
|
1223 (oper == "%" && !equalsnext) ? OPER_MODULUS : |
|
1224 (oper == "^") ? OPER_BITWISEEOR : |
|
1225 (oper == "?") ? OPER_TERNARY : |
|
1226 -1; |
|
1227 |
|
1228 if (o != -1) |
|
1229 { |
|
1230 return o; |
|
1231 } |
|
1232 |
|
1233 // Two-char operators |
|
1234 oper += mLexer->PeekNextString (peek ? 1 : 0); |
|
1235 equalsnext = mLexer->PeekNextString (peek ? 2 : 1) == ("="); |
|
1236 |
|
1237 o = (oper == "+=") ? OPER_ASSIGNADD : |
|
1238 (oper == "-=") ? OPER_ASSIGNSUB : |
|
1239 (oper == "*=") ? OPER_ASSIGNMUL : |
|
1240 (oper == "/=") ? OPER_ASSIGNDIV : |
|
1241 (oper == "%=") ? OPER_ASSIGNMOD : |
|
1242 (oper == "==") ? OPER_EQUALS : |
|
1243 (oper == "!=") ? OPER_NOTEQUALS : |
|
1244 (oper == ">=") ? OPER_GREATERTHANEQUALS : |
|
1245 (oper == "<=") ? OPER_LESSTHANEQUALS : |
|
1246 (oper == "&&") ? OPER_AND : |
|
1247 (oper == "||") ? OPER_OR : |
|
1248 (oper == "<<" && !equalsnext) ? OPER_LEFTSHIFT : |
|
1249 (oper == ">>" && !equalsnext) ? OPER_RIGHTSHIFT : |
|
1250 -1; |
|
1251 |
|
1252 if (o != -1) |
|
1253 { |
|
1254 mLexer->MustGetNext(); |
|
1255 return o; |
|
1256 } |
|
1257 |
|
1258 // Three-char opers |
|
1259 oper += mLexer->PeekNextString (peek ? 2 : 1); |
|
1260 o = oper == "<<=" ? OPER_ASSIGNLEFTSHIFT : |
|
1261 oper == ">>=" ? OPER_ASSIGNRIGHTSHIFT : |
|
1262 -1; |
|
1263 |
|
1264 if (o != -1) |
|
1265 { |
|
1266 mLexer->MustGetNext(); |
|
1267 mLexer->MustGetNext(); |
|
1268 } |
|
1269 |
|
1270 return o; |
|
1271 } |
|
1272 |
|
1273 // ============================================================================ |
|
1274 // |
1138 // |
1275 String BotscriptParser::ParseFloat() |
1139 String BotscriptParser::ParseFloat() |
1276 { |
1140 { |
1277 mLexer->TokenMustBe (tkNumber); |
1141 mLexer->TokenMustBe (tkNumber); |
1278 String floatstring = GetTokenString(); |
1142 String floatstring = GetTokenString(); |
1286 floatstring += "."; |
1150 floatstring += "."; |
1287 floatstring += GetTokenString(); |
1151 floatstring += GetTokenString(); |
1288 } |
1152 } |
1289 |
1153 |
1290 return floatstring; |
1154 return floatstring; |
1291 } |
|
1292 |
|
1293 // ============================================================================ |
|
1294 // Parses a value in the expression and returns the data needed to push |
|
1295 // it, contained in a data buffer. A value can be either a variable, a command, |
|
1296 // a literal or an expression. |
|
1297 // |
|
1298 DataBuffer* BotscriptParser::ParseExprValue (EType reqtype) |
|
1299 { |
|
1300 DataBuffer* b = new DataBuffer (16); |
|
1301 ScriptVariable* g; |
|
1302 |
|
1303 // Prefixing "!" means negation. |
|
1304 bool negate = TokenIs (tkExclamationMark); |
|
1305 |
|
1306 if (negate) // Jump past the "!" |
|
1307 mLexer->Skip(); |
|
1308 |
|
1309 if (TokenIs (tkParenStart)) |
|
1310 { |
|
1311 // Expression |
|
1312 mLexer->MustGetNext(); |
|
1313 DataBuffer* c = ParseExpression (reqtype); |
|
1314 b->MergeAndDestroy (c); |
|
1315 mLexer->MustGetNext (tkParenEnd); |
|
1316 } |
|
1317 else if (CommandInfo* comm = FindCommandByName (GetTokenString())) |
|
1318 { |
|
1319 delete b; |
|
1320 |
|
1321 // Command |
|
1322 if (reqtype && comm->returnvalue != reqtype) |
|
1323 Error ("%1 returns an incompatible data type", comm->name); |
|
1324 |
|
1325 b = ParseCommand (comm); |
|
1326 } |
|
1327 else if (ConstantInfo* constant = FindConstant (GetTokenString())) |
|
1328 { |
|
1329 // Type check |
|
1330 if (reqtype != constant->type) |
|
1331 Error ("constant `%1` is %2, expression requires %3\n", |
|
1332 constant->name, GetTypeName (constant->type), |
|
1333 GetTypeName (reqtype)); |
|
1334 |
|
1335 switch (constant->type) |
|
1336 { |
|
1337 case EBoolType: |
|
1338 case EIntType: |
|
1339 { |
|
1340 b->WriteDWord (dhPushNumber); |
|
1341 b->WriteDWord (constant->val.ToLong()); |
|
1342 break; |
|
1343 } |
|
1344 |
|
1345 case EStringType: |
|
1346 { |
|
1347 b->WriteStringIndex (constant->val); |
|
1348 break; |
|
1349 } |
|
1350 |
|
1351 case EVoidType: |
|
1352 case EUnknownType: |
|
1353 break; |
|
1354 } |
|
1355 } |
|
1356 else if ((g = FindGlobalVariable (GetTokenString()))) |
|
1357 { |
|
1358 // Global variable |
|
1359 b->WriteDWord (dhPushGlobalVar); |
|
1360 b->WriteDWord (g->index); |
|
1361 } |
|
1362 else |
|
1363 { |
|
1364 // If nothing else, check for literal |
|
1365 switch (reqtype) |
|
1366 { |
|
1367 case EVoidType: |
|
1368 case EUnknownType: |
|
1369 { |
|
1370 Error ("unknown identifier `%1` (expected keyword, function or variable)", GetTokenString()); |
|
1371 break; |
|
1372 } |
|
1373 |
|
1374 case EBoolType: |
|
1375 case EIntType: |
|
1376 { |
|
1377 mLexer->TokenMustBe (tkNumber); |
|
1378 |
|
1379 // All values are written unsigned - thus we need to write the value's |
|
1380 // absolute value, followed by an unary minus for negatives. |
|
1381 b->WriteDWord (dhPushNumber); |
|
1382 |
|
1383 long v = GetTokenString().ToLong(); |
|
1384 b->WriteDWord (static_cast<word> (abs (v))); |
|
1385 |
|
1386 if (v < 0) |
|
1387 b->WriteDWord (dhUnaryMinus); |
|
1388 |
|
1389 break; |
|
1390 } |
|
1391 |
|
1392 case EStringType: |
|
1393 { |
|
1394 // PushToStringTable either returns the string index of the |
|
1395 // string if it finds it in the table, or writes it to the |
|
1396 // table and returns it index if it doesn't find it there. |
|
1397 mLexer->TokenMustBe (tkString); |
|
1398 b->WriteStringIndex (GetTokenString()); |
|
1399 break; |
|
1400 } |
|
1401 } |
|
1402 } |
|
1403 |
|
1404 // Negate it now if desired |
|
1405 if (negate) |
|
1406 b->WriteDWord (dhNegateLogical); |
|
1407 |
|
1408 return b; |
|
1409 } |
1155 } |
1410 |
1156 |
1411 // ============================================================================ |
1157 // ============================================================================ |
1412 // Parses an assignment. An assignment starts with a variable name, followed |
1158 // Parses an assignment. An assignment starts with a variable name, followed |
1413 // by an assignment operator, followed by an expression value. Expects current |
1159 // by an assignment operator, followed by an expression value. Expects current |