src/Parser.cc

changeset 105
6dbac3305614
parent 104
62da929f7814
child 106
9174be9ac686
equal deleted inserted replaced
104:62da929f7814 105:6dbac3305614
28 28
29 #include "Parser.h" 29 #include "Parser.h"
30 #include "Events.h" 30 #include "Events.h"
31 #include "Commands.h" 31 #include "Commands.h"
32 #include "StringTable.h" 32 #include "StringTable.h"
33 #include "Variables.h"
34 #include "Containers.h" 33 #include "Containers.h"
35 #include "Lexer.h" 34 #include "Lexer.h"
36 #include "DataBuffer.h" 35 #include "DataBuffer.h"
37 #include "Expression.h" 36 #include "Expression.h"
38 37
40 39
41 // ============================================================================ 40 // ============================================================================
42 // 41 //
43 BotscriptParser::BotscriptParser() : 42 BotscriptParser::BotscriptParser() :
44 mReadOnly (false), 43 mReadOnly (false),
45 mLexer (new Lexer) {} 44 mMainBuffer (new DataBuffer),
45 mOnEnterBuffer (new DataBuffer),
46 mMainLoopBuffer (new DataBuffer),
47 mLexer (new Lexer),
48 mNumStates (0),
49 mNumEvents (0),
50 mCurrentMode (ETopLevelMode),
51 mStateSpawnDefined (false),
52 mGotMainLoop (false),
53 mScopeCursor (-1),
54 mCanElse (false) {}
46 55
47 // ============================================================================ 56 // ============================================================================
48 // 57 //
49 BotscriptParser::~BotscriptParser() 58 BotscriptParser::~BotscriptParser()
50 { 59 {
73 // of necessary buffering so stuff is written in the correct order. 82 // of necessary buffering so stuff is written in the correct order.
74 void BotscriptParser::ParseBotscript (String fileName) 83 void BotscriptParser::ParseBotscript (String fileName)
75 { 84 {
76 // Lex and preprocess the file 85 // Lex and preprocess the file
77 mLexer->ProcessFile (fileName); 86 mLexer->ProcessFile (fileName);
78
79 mMainBuffer = new DataBuffer;
80 mOnEnterBuffer = new DataBuffer;
81 mMainLoopBuffer = new DataBuffer;
82 mCurrentMode = ETopLevelMode;
83 mNumStates = 0;
84 mNumEvents = 0;
85 mScopeCursor = -1;
86 mStateSpawnDefined = false;
87 mGotMainLoop = false;
88 mIfExpression = null;
89 mCanElse = false;
90 PushScope(); 87 PushScope();
91 88
92 while (mLexer->GetNext()) 89 while (mLexer->GetNext())
93 { 90 {
94 // Check if else is potentically valid 91 // Check if else is potentically valid
323 320
324 // ============================================================================ 321 // ============================================================================
325 // 322 //
326 void BotscriptParser::ParseVar() 323 void BotscriptParser::ParseVar()
327 { 324 {
325 Variable* var = new Variable;
326 var->origin = mLexer->DescribeCurrentPosition();
328 const bool isconst = mLexer->GetNext (tkConst); 327 const bool isconst = mLexer->GetNext (tkConst);
328 const bool isglobal = true;
329 mLexer->MustGetAnyOf ({tkInt, tkStr, tkVoid}); 329 mLexer->MustGetAnyOf ({tkInt, tkStr, tkVoid});
330 330
331 // TODO 331 EType vartype = (TokenIs (tkInt)) ? EIntType :
332 if (mCurrentMode != ETopLevelMode || mCurrentState.IsEmpty() == false)
333 Error ("variables must only be global for now");
334
335 EType type = (TokenIs (tkInt)) ? EIntType :
336 (TokenIs (tkStr)) ? EStringType : 332 (TokenIs (tkStr)) ? EStringType :
337 EBoolType; 333 EBoolType;
338 334
339 mLexer->MustGetNext (tkSymbol); 335 mLexer->MustGetNext (tkSymbol);
340 String varname = GetTokenString(); 336 String name = GetTokenString();
341 337
342 if (varname[0] >= '0' && varname[0] <= '9') 338 /*
343 Error ("variable name must not start with a number"); 339 * TODO
344 340 if (isglobal && mScopeStack[0].globalVariables.Size() >= gMaxGlobalVars)
345 ScriptVariable* var = DeclareGlobalVariable (type, varname); 341 Error ("too many global variables!");
342 */
343
344 for (Variable* var : SCOPE(0).globalVariables + SCOPE(0).localVariables)
345 {
346 if (var->name == name)
347 Error ("Variable $%1 is already declared on this scope; declared at %2",
348 var->name, var->origin);
349 }
350
351 var->name = name;
352 var->statename = "";
353 var->type = vartype;
346 354
347 if (isconst == false) 355 if (isconst == false)
348 { 356 {
349 var->writelevel = ScriptVariable::WRITE_Mutable; 357 var->writelevel = Variable::WRITE_Mutable;
350 } 358 }
351 else 359 else
352 { 360 {
353 mLexer->MustGetNext (tkAssign); 361 mLexer->MustGetNext (tkAssign);
354 Expression expr (this, mLexer, type); 362 Expression expr (this, mLexer, vartype);
355 363
364 // If the expression was constexpr, we know its value and thus
365 // can store it in the variable.
356 if (expr.GetResult()->IsConstexpr()) 366 if (expr.GetResult()->IsConstexpr())
357 { 367 {
358 var->writelevel = ScriptVariable::WRITE_Constexpr; 368 var->writelevel = Variable::WRITE_Constexpr;
359 var->value = expr.GetResult()->GetValue(); 369 var->value = expr.GetResult()->GetValue();
360 } 370 }
361 else 371 else
362 { 372 {
363 // TODO: might need a VM-wise oninit for this... 373 // TODO: might need a VM-wise oninit for this...
364 Error ("const variables must be constexpr for now"); 374 Error ("const variables must be constexpr for now");
365 } 375 }
366 } 376 }
367 377
378 // Assign an index for the variable if it is not constexpr. Constexpr
379 // variables can simply be substituted out for their value when used
380 // so they need no index.
381 if (var->writelevel != Variable::WRITE_Constexpr)
382 {
383 bool isglobal = IsInGlobalState();
384 var->index = isglobal ? SCOPE(0).globalVarIndexBase++ : SCOPE(0).localVarIndexBase++;
385
386 if ((isglobal == true && var->index >= gMaxGlobalVars) ||
387 (isglobal == false && var->index >= gMaxStateVars))
388 {
389 Error ("too many %1 variables", isglobal ? "global" : "state-local");
390 }
391 }
392
393 if (IsInGlobalState())
394 SCOPE(0).globalVariables << var;
395 else
396 SCOPE(0).localVariables << var;
397
368 mLexer->MustGetNext (tkSemicolon); 398 mLexer->MustGetNext (tkSemicolon);
399 Print ("Declared %3 variable #%1 $%2\n", var->index, var->name, IsInGlobalState() ? "global" : "state-local");
369 } 400 }
370 401
371 // ============================================================================ 402 // ============================================================================
372 // 403 //
373 void BotscriptParser::ParseGoto() 404 void BotscriptParser::ParseGoto()
712 if (mScopeCursor > 0) 743 if (mScopeCursor > 0)
713 { 744 {
714 switch (SCOPE (0).type) 745 switch (SCOPE (0).type)
715 { 746 {
716 case eIfScope: 747 case eIfScope:
748 {
717 // Adjust the closing mark. 749 // Adjust the closing mark.
718 buffer()->AdjustMark (SCOPE (0).mark1); 750 buffer()->AdjustMark (SCOPE (0).mark1);
719 751
720 // We're returning from if, thus else can be next 752 // We're returning from `if`, thus `else` follow
721 mCanElse = true; 753 mCanElse = true;
722 break; 754 break;
755 }
723 756
724 case eElseScope: 757 case eElseScope:
758 {
725 // else instead uses mark1 for itself (so if expression 759 // else instead uses mark1 for itself (so if expression
726 // fails, jump to else), mark2 means end of else 760 // fails, jump to else), mark2 means end of else
727 buffer()->AdjustMark (SCOPE (0).mark2); 761 buffer()->AdjustMark (SCOPE (0).mark2);
728 break; 762 break;
763 }
729 764
730 case eForScope: 765 case eForScope:
731 // write the incrementor at the end of the loop block 766 { // write the incrementor at the end of the loop block
732 buffer()->MergeAndDestroy (SCOPE (0).buffer1); 767 buffer()->MergeAndDestroy (SCOPE (0).buffer1);
768 }
733 case eWhileScope: 769 case eWhileScope:
734 // write down the instruction to go back to the start of the loop 770 { // write down the instruction to go back to the start of the loop
735 buffer()->WriteDWord (dhGoto); 771 buffer()->WriteDWord (dhGoto);
736 buffer()->AddReference (SCOPE (0).mark1); 772 buffer()->AddReference (SCOPE (0).mark1);
737 773
738 // Move the closing mark here since we're at the end of the while loop 774 // Move the closing mark here since we're at the end of the while loop
739 buffer()->AdjustMark (SCOPE (0).mark2); 775 buffer()->AdjustMark (SCOPE (0).mark2);
740 break; 776 break;
777 }
741 778
742 case eDoScope: 779 case eDoScope:
743 { 780 {
744 mLexer->MustGetNext (tkWhile); 781 mLexer->MustGetNext (tkWhile);
745 mLexer->MustGetNext (tkParenStart); 782 mLexer->MustGetNext (tkParenStart);
819 { 856 {
820 CheckNotToplevel(); 857 CheckNotToplevel();
821 String labelName = GetTokenString(); 858 String labelName = GetTokenString();
822 ByteMark* mark = null; 859 ByteMark* mark = null;
823 860
824 // want no conflicts..
825 if (FindCommandByName (labelName))
826 Error ("label name `%1` conflicts with command name\n", labelName);
827
828 if (FindGlobalVariable (labelName))
829 Error ("label name `%1` conflicts with variable\n", labelName);
830
831 // See if a mark already exists for this label 861 // See if a mark already exists for this label
832 for (UndefinedLabel& label : mUndefinedLabels) 862 for (UndefinedLabel& label : mUndefinedLabels)
833 { 863 {
834 if (label.name != labelName) 864 if (label.name != labelName)
835 continue; 865 continue;
869 // ============================================================================= 899 // =============================================================================
870 // 900 //
871 void BotscriptParser::ParseFuncdef() 901 void BotscriptParser::ParseFuncdef()
872 { 902 {
873 CommandInfo* comm = new CommandInfo; 903 CommandInfo* comm = new CommandInfo;
904 comm->origin = mLexer->DescribeCurrentPosition();
874 905
875 // Return value 906 // Return value
876 mLexer->MustGetAnyOf ({tkInt, tkVoid, tkBool, tkStr}); 907 mLexer->MustGetAnyOf ({tkInt, tkVoid, tkBool, tkStr});
877 comm->returnvalue = GetTypeByName (mLexer->GetToken()->text); // TODO 908 comm->returnvalue = GetTypeByName (mLexer->GetToken()->text); // TODO
878 assert (comm->returnvalue != -1); 909 assert (comm->returnvalue != -1);
1065 return (EAssignmentOperator) 0; 1096 return (EAssignmentOperator) 0;
1066 } 1097 }
1067 1098
1068 // ============================================================================ 1099 // ============================================================================
1069 // 1100 //
1070 EDataHeader BotscriptParser::GetAssigmentDataHeader (EAssignmentOperator op, ScriptVariable* var) 1101 EDataHeader BotscriptParser::GetAssigmentDataHeader (EAssignmentOperator op, Variable* var)
1071 { 1102 {
1072 if (var->IsGlobal()) 1103 if (var->IsGlobal())
1073 { 1104 {
1074 switch (op) 1105 switch (op)
1075 { 1106 {
1104 // 1135 //
1105 // Parses an assignment. An assignment starts with a variable name, followed 1136 // Parses an assignment. An assignment starts with a variable name, followed
1106 // by an assignment operator, followed by an expression value. Expects current 1137 // by an assignment operator, followed by an expression value. Expects current
1107 // token to be the name of the variable, and expects the variable to be given. 1138 // token to be the name of the variable, and expects the variable to be given.
1108 // 1139 //
1109 DataBuffer* BotscriptParser::ParseAssignment (ScriptVariable* var) 1140 DataBuffer* BotscriptParser::ParseAssignment (Variable* var)
1110 { 1141 {
1111 if (var->writelevel != ScriptVariable::WRITE_Mutable) 1142 if (var->writelevel != Variable::WRITE_Mutable)
1112 { 1143 {
1113 Error ("cannot alter read-only variable $%1", var->name); 1144 Error ("cannot alter read-only variable $%1", var->name);
1114 } 1145 }
1115 1146
1116 // Get an operator 1147 // Get an operator
1166 info->mark2 = null; 1197 info->mark2 = null;
1167 info->buffer1 = null; 1198 info->buffer1 = null;
1168 info->cases.Clear(); 1199 info->cases.Clear();
1169 info->casecursor = info->cases.begin() - 1; 1200 info->casecursor = info->cases.begin() - 1;
1170 } 1201 }
1202
1203 // Reset variable stuff in any case
1204 SCOPE(0).globalVarIndexBase = (mScopeCursor == 0) ? 0 : SCOPE(1).globalVarIndexBase;
1205 SCOPE(0).localVarIndexBase = (mScopeCursor == 0) ? 0 : SCOPE(1).localVarIndexBase;
1206
1207 for (Variable* var : SCOPE(0).globalVariables + SCOPE(0).localVariables)
1208 delete var;
1209
1210 SCOPE(0).localVariables.Clear();
1211 SCOPE(0).globalVariables.Clear();
1171 } 1212 }
1172 1213
1173 // ============================================================================ 1214 // ============================================================================
1174 // 1215 //
1175 DataBuffer* BotscriptParser::ParseExpression (EType reqtype, bool fromhere) 1216 DataBuffer* BotscriptParser::ParseExpression (EType reqtype, bool fromhere)
1192 { 1233 {
1193 // If it's a variable, expect assignment. 1234 // If it's a variable, expect assignment.
1194 if (mLexer->GetNext (tkDollarSign)) 1235 if (mLexer->GetNext (tkDollarSign))
1195 { 1236 {
1196 mLexer->MustGetNext (tkSymbol); 1237 mLexer->MustGetNext (tkSymbol);
1197 ScriptVariable* var = FindGlobalVariable (GetTokenString()); 1238 Variable* var = FindVariable (GetTokenString());
1198 1239
1199 if (var == null) 1240 if (var == null)
1200 Error ("unknown variable $%1", var->name); 1241 Error ("unknown variable $%1", var->name);
1201 1242
1202 return ParseAssignment (var); 1243 return ParseAssignment (var);
1323 if (fp == null) 1364 if (fp == null)
1324 Error ("couldn't open %1 for writing: %2", outfile, strerror (errno)); 1365 Error ("couldn't open %1 for writing: %2", outfile, strerror (errno));
1325 1366
1326 // First, resolve references 1367 // First, resolve references
1327 for (MarkReference* ref : mMainBuffer->GetReferences()) 1368 for (MarkReference* ref : mMainBuffer->GetReferences())
1328 {
1329 // Substitute the placeholder with the mark position
1330 for (int i = 0; i < 4; ++i) 1369 for (int i = 0; i < 4; ++i)
1331 mMainBuffer->GetBuffer()[ref->pos + i] = (ref->target->pos >> (8 * i)) & 0xFF; 1370 mMainBuffer->GetBuffer()[ref->pos + i] = (ref->target->pos >> (8 * i)) & 0xFF;
1332
1333 // Print ("reference at %1 resolved to mark at %2\n", ref->pos, ref->target->pos);
1334 }
1335 1371
1336 // Then, dump the main buffer to the file 1372 // Then, dump the main buffer to the file
1337 fwrite (mMainBuffer->GetBuffer(), 1, mMainBuffer->GetWrittenSize(), fp); 1373 fwrite (mMainBuffer->GetBuffer(), 1, mMainBuffer->GetWrittenSize(), fp);
1338 Print ("-- %1 byte%s1 written to %2\n", mMainBuffer->GetWrittenSize(), outfile); 1374 Print ("-- %1 byte%s1 written to %2\n", mMainBuffer->GetWrittenSize(), outfile);
1339 fclose (fp); 1375 fclose (fp);
1340 } 1376 }
1377
1378 // ============================================================================
1379 //
1380 // Attempt to find the variable by the given name. Looks from current scope
1381 // downwards.
1382 //
1383 Variable* BotscriptParser::FindVariable (const String& name)
1384 {
1385 for (int i = mScopeCursor; i >= 0; --i)
1386 {
1387 for (Variable* var : mScopeStack[i].globalVariables + mScopeStack[i].localVariables)
1388 {
1389 if (var->name == name)
1390 return var;
1391 }
1392 }
1393
1394 return null;
1395 }
1396
1397 // ============================================================================
1398 //
1399 // Is the parser currently in global state (i.e. not in any specific state)?
1400 //
1401 bool BotscriptParser::IsInGlobalState() const
1402 {
1403 return mCurrentState.IsEmpty();
1404 }

mercurial