326 buffer()->WriteDWord (onenter ? dhOnEnter : dhOnExit); |
320 buffer()->WriteDWord (onenter ? dhOnEnter : dhOnExit); |
327 } |
321 } |
328 |
322 |
329 // ============================================================================ |
323 // ============================================================================ |
330 // |
324 // |
331 void BotscriptParser::ParseVariableDeclaration() |
325 void BotscriptParser::ParseVar() |
332 { |
326 { |
333 // For now, only globals are supported |
327 const bool isconst = mLexer->GetNext (tkConst); |
|
328 mLexer->MustGetAnyOf ({tkInt, tkStr, tkVoid}); |
|
329 |
|
330 // TODO |
334 if (mCurrentMode != ETopLevelMode || mCurrentState.IsEmpty() == false) |
331 if (mCurrentMode != ETopLevelMode || mCurrentState.IsEmpty() == false) |
335 Error ("variables must only be global for now"); |
332 Error ("variables must only be global for now"); |
336 |
333 |
337 EType type = (TokenIs (tkInt)) ? EIntType : |
334 EType type = (TokenIs (tkInt)) ? EIntType : |
338 (TokenIs (tkStr)) ? EStringType : |
335 (TokenIs (tkStr)) ? EStringType : |
339 EBoolType; |
336 EBoolType; |
340 |
337 |
341 mLexer->MustGetNext(); |
338 mLexer->MustGetNext(); |
342 String varname = GetTokenString(); |
339 String varname = GetTokenString(); |
343 |
340 |
344 // Var name must not be a number |
341 if (varname[0] >= '0' && varname[0] <= '9') |
345 if (varname.IsNumeric()) |
342 Error ("variable name must not start with a number"); |
346 Error ("variable name must not be a number"); |
|
347 |
343 |
348 ScriptVariable* var = DeclareGlobalVariable (type, varname); |
344 ScriptVariable* var = DeclareGlobalVariable (type, varname); |
349 (void) var; |
345 |
|
346 if (isconst == false) |
|
347 { |
|
348 var->writelevel = ScriptVariable::WRITE_Mutable; |
|
349 } |
|
350 else |
|
351 { |
|
352 mLexer->MustGetNext (tkAssign); |
|
353 Expression expr (this, mLexer, type); |
|
354 |
|
355 if (expr.GetResult()->IsConstexpr()) |
|
356 { |
|
357 var->writelevel = ScriptVariable::WRITE_Constexpr; |
|
358 var->value = expr.GetResult()->GetValue(); |
|
359 } |
|
360 else |
|
361 { |
|
362 // TODO: might need a VM-wise oninit for this... |
|
363 Error ("const variables must be constexpr for now"); |
|
364 } |
|
365 } |
|
366 |
350 mLexer->MustGetNext (tkSemicolon); |
367 mLexer->MustGetNext (tkSemicolon); |
351 } |
368 } |
352 |
369 |
353 // ============================================================================ |
370 // ============================================================================ |
354 // |
371 // |
797 mLexer->GetNext (tkSemicolon); |
814 mLexer->GetNext (tkSemicolon); |
798 } |
815 } |
799 |
816 |
800 // ============================================================================ |
817 // ============================================================================ |
801 // |
818 // |
802 void BotscriptParser::ParseConst() |
|
803 { |
|
804 ConstantInfo info; |
|
805 |
|
806 // Get the type |
|
807 mLexer->MustGetNext(); |
|
808 String typestring = GetTokenString(); |
|
809 info.type = GetTypeByName (typestring); |
|
810 |
|
811 if (info.type == EUnknownType || info.type == EVoidType) |
|
812 Error ("unknown type `%1` for constant", typestring); |
|
813 |
|
814 mLexer->MustGetNext(); |
|
815 info.name = GetTokenString(); |
|
816 |
|
817 mLexer->MustGetNext (tkAssign); |
|
818 |
|
819 switch (info.type) |
|
820 { |
|
821 case EBoolType: |
|
822 case EIntType: |
|
823 { |
|
824 mLexer->MustGetNext (tkNumber); |
|
825 } break; |
|
826 |
|
827 case EStringType: |
|
828 { |
|
829 mLexer->MustGetNext (tkString); |
|
830 } break; |
|
831 |
|
832 case EUnknownType: |
|
833 case EVoidType: |
|
834 break; |
|
835 } |
|
836 |
|
837 info.val = mLexer->GetToken()->text; |
|
838 mConstants << info; |
|
839 |
|
840 mLexer->MustGetNext (tkSemicolon); |
|
841 } |
|
842 |
|
843 // ============================================================================ |
|
844 // |
|
845 void BotscriptParser::ParseLabel() |
819 void BotscriptParser::ParseLabel() |
846 { |
820 { |
847 CheckNotToplevel(); |
821 CheckNotToplevel(); |
848 String labelName = GetTokenString(); |
822 String labelName = GetTokenString(); |
849 ByteMark* mark = null; |
823 ByteMark* mark = null; |
968 // Parses a command call |
942 // Parses a command call |
969 DataBuffer* BotscriptParser::ParseCommand (CommandInfo* comm) |
943 DataBuffer* BotscriptParser::ParseCommand (CommandInfo* comm) |
970 { |
944 { |
971 DataBuffer* r = new DataBuffer (64); |
945 DataBuffer* r = new DataBuffer (64); |
972 |
946 |
973 if (mCurrentMode == ETopLevelMode) |
947 if (mCurrentMode == ETopLevelMode && comm->returnvalue == EVoidType) |
974 Error ("command call at top level"); |
948 Error ("command call at top level"); |
975 |
949 |
976 mLexer->MustGetNext (tkParenStart); |
950 mLexer->MustGetNext (tkParenStart); |
977 mLexer->MustGetNext(); |
951 mLexer->MustGetNext(); |
978 |
952 |
1133 // by an assignment operator, followed by an expression value. Expects current |
1107 // by an assignment operator, followed by an expression value. Expects current |
1134 // token to be the name of the variable, and expects the variable to be given. |
1108 // token to be the name of the variable, and expects the variable to be given. |
1135 // |
1109 // |
1136 DataBuffer* BotscriptParser::ParseAssignment (ScriptVariable* var) |
1110 DataBuffer* BotscriptParser::ParseAssignment (ScriptVariable* var) |
1137 { |
1111 { |
|
1112 if (var->writelevel != ScriptVariable::WRITE_Mutable) |
|
1113 { |
|
1114 Error ("cannot alter read-only variable $%1", var->name); |
|
1115 } |
|
1116 |
1138 // Get an operator |
1117 // Get an operator |
1139 EAssignmentOperator oper = ParseAssignmentOperator(); |
1118 EAssignmentOperator oper = ParseAssignmentOperator(); |
1140 DataBuffer* retbuf = new DataBuffer; |
1119 DataBuffer* retbuf = new DataBuffer; |
1141 |
1120 |
1142 if (mCurrentMode == ETopLevelMode) |
1121 if (mCurrentMode == ETopLevelMode) |
1210 |
1189 |
1211 // ============================================================================ |
1190 // ============================================================================ |
1212 // |
1191 // |
1213 DataBuffer* BotscriptParser::ParseStatement() |
1192 DataBuffer* BotscriptParser::ParseStatement() |
1214 { |
1193 { |
1215 if (FindConstant (GetTokenString())) // There should not be constants here. |
|
1216 Error ("invalid use for constant\n"); |
|
1217 |
|
1218 // If it's a variable, expect assignment. |
1194 // If it's a variable, expect assignment. |
1219 if (ScriptVariable* var = FindGlobalVariable (GetTokenString())) |
1195 if (TokenIs (tkDollarSign)) |
|
1196 { |
|
1197 mLexer->MustGetNext (tkSymbol); |
|
1198 ScriptVariable* var = FindGlobalVariable (GetTokenString()); |
|
1199 |
|
1200 if (var == null) |
|
1201 Error ("unknown variable $%1", var->name); |
|
1202 |
1220 return ParseAssignment (var); |
1203 return ParseAssignment (var); |
|
1204 } |
1221 |
1205 |
1222 return null; |
1206 return null; |
1223 } |
1207 } |
1224 |
1208 |
1225 // ============================================================================ |
1209 // ============================================================================ |
1247 info->casecursor++; |
1231 info->casecursor++; |
1248 } |
1232 } |
1249 |
1233 |
1250 // ============================================================================ |
1234 // ============================================================================ |
1251 // |
1235 // |
1252 ConstantInfo* BotscriptParser::FindConstant (const String& tok) |
|
1253 { |
|
1254 for (int i = 0; i < mConstants.Size(); i++) |
|
1255 if (mConstants[i].name == tok) |
|
1256 return &mConstants[i]; |
|
1257 |
|
1258 return null; |
|
1259 } |
|
1260 |
|
1261 // ============================================================================ |
|
1262 // |
|
1263 bool BotscriptParser::TokenIs (EToken a) |
1236 bool BotscriptParser::TokenIs (EToken a) |
1264 { |
1237 { |
1265 return (mLexer->GetTokenType() == a); |
1238 return (mLexer->GetTokenType() == a); |
1266 } |
1239 } |
1267 |
1240 |