src/Parser.cc

changeset 91
427eb377d53e
parent 89
029a330a9bef
child 92
3a00d396bce2
equal deleted inserted replaced
90:90ab2f2b3dc0 91:427eb377d53e
32 #include "StringTable.h" 32 #include "StringTable.h"
33 #include "Variables.h" 33 #include "Variables.h"
34 #include "Containers.h" 34 #include "Containers.h"
35 #include "Lexer.h" 35 #include "Lexer.h"
36 #include "DataBuffer.h" 36 #include "DataBuffer.h"
37 #include "Expression.h"
37 38
38 #define SCOPE(n) (mScopeStack[mScopeCursor - n]) 39 #define SCOPE(n) (mScopeStack[mScopeCursor - n])
39 40
40 // ============================================================================ 41 // ============================================================================
41 // 42 //
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
1477 } 1223 }
1478 } 1224 }
1479 1225
1480 // ============================================================================ 1226 // ============================================================================
1481 // 1227 //
1228 void BotscriptParser::ParseExpression (EType reqtype)
1229 {
1230 Expression expr (this, reqtype, mLexer);
1231 expr.GetResult()->ConvertToBuffer();
1232 buffer()->MergeAndDestroy (expr.GetResult()->GetBuffer());
1233 }
1234
1235 // ============================================================================
1236 //
1482 DataBuffer* BotscriptParser::ParseStatement() 1237 DataBuffer* BotscriptParser::ParseStatement()
1483 { 1238 {
1484 if (FindConstant (GetTokenString())) // There should not be constants here. 1239 if (FindConstant (GetTokenString())) // There should not be constants here.
1485 Error ("invalid use for constant\n"); 1240 Error ("invalid use for constant\n");
1486 1241

mercurial