static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls) { int currvalue = 0; sc.MustGetToken('{'); while (!sc.CheckToken('}')) { sc.MustGetToken(TK_Identifier); FName symname = sc.String; if (sc.CheckToken('=')) { FxExpression *expr = ParseExpression (sc, cls); currvalue = expr->EvalExpression(NULL).GetInt(); delete expr; } PSymbolConst *sym = new PSymbolConst(symname); sym->ValueType = VAL_Int; sym->Value = currvalue; if (symt->AddSymbol (sym) == NULL) { delete sym; sc.ScriptMessage ("'%s' is already defined in '%s'.", symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); FScriptPosition::ErrorCounter++; } // This allows a comma after the last value but doesn't enforce it. if (sc.CheckToken('}')) break; sc.MustGetToken(','); currvalue++; } sc.MustGetToken(';'); }
static void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls) { // Read the type and make sure it's int or float. if (sc.CheckToken(TK_Int) || sc.CheckToken(TK_Float)) { int type = sc.TokenType; sc.MustGetToken(TK_Identifier); FName symname = sc.String; sc.MustGetToken('='); FxExpression *expr = ParseExpression (sc, cls); sc.MustGetToken(';'); ExpVal val = expr->EvalExpression(NULL); delete expr; PSymbolConst *sym = new PSymbolConst(symname); if (type == TK_Int) { sym->ValueType = VAL_Int; sym->Value = val.GetInt(); } else { sym->ValueType = VAL_Float; sym->Float = val.GetFloat(); } if (symt->AddSymbol (sym) == NULL) { delete sym; sc.ScriptMessage ("'%s' is already defined in '%s'.", symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); FScriptPosition::ErrorCounter++; } } else { sc.ScriptMessage("Numeric type required for constant"); FScriptPosition::ErrorCounter++; } }
static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClass *cls) { FExpressionType valuetype; // Only non-native classes may have user variables. if (!cls->bRuntimeClass) { sc.ScriptError("Native classes may not have user variables"); } // Read the type and make sure it's int. sc.MustGetAnyToken(); if (sc.TokenType != TK_Int) { sc.ScriptMessage("User variables must be of type int"); FScriptPosition::ErrorCounter++; } valuetype = VAL_Int; sc.MustGetToken(TK_Identifier); // For now, restrict user variables to those that begin with "user_" to guarantee // no clashes with internal member variable names. if (sc.StringLen < 6 || strnicmp("user_", sc.String, 5) != 0) { sc.ScriptMessage("User variable names must begin with \"user_\""); FScriptPosition::ErrorCounter++; } FName symname = sc.String; if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression(sc, cls); int maxelems = expr->EvalExpression(NULL).GetInt(); delete expr; sc.MustGetToken(']'); if (maxelems <= 0) { sc.ScriptMessage("Array size must be positive"); FScriptPosition::ErrorCounter++; maxelems = 1; } valuetype.MakeArray(maxelems); } sc.MustGetToken(';'); // We must ensure that we do not define duplicates, even when they come from a parent table. if (symt->FindSymbol(symname, true) != NULL) { sc.ScriptMessage ("'%s' is already defined in '%s' or one of its ancestors.", symname.GetChars(), cls ? cls->TypeName.GetChars() : "Global"); FScriptPosition::ErrorCounter++; return; } PSymbolVariable *sym = new PSymbolVariable(symname); sym->offset = cls->Extend(sizeof(int) * (valuetype.Type == VAL_Array ? valuetype.size : 1)); sym->ValueType = valuetype; sym->bUserVar = true; if (symt->AddSymbol(sym) == NULL) { delete sym; sc.ScriptMessage ("'%s' is already defined in '%s'.", symname.GetChars(), cls ? cls->TypeName.GetChars() : "Global"); FScriptPosition::ErrorCounter++; } }
static void ParseNativeVariable (FScanner &sc, PSymbolTable * symt, PClass *cls) { FExpressionType valuetype; if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) { sc.ScriptMessage ("variables can only be imported by internal class and actor definitions!"); FScriptPosition::ErrorCounter++; } // Read the type and make sure it's int or float. sc.MustGetAnyToken(); switch (sc.TokenType) { case TK_Int: valuetype = VAL_Int; break; case TK_Float: valuetype = VAL_Float; break; case TK_Angle_t: valuetype = VAL_Angle; break; case TK_Fixed_t: valuetype = VAL_Fixed; break; case TK_Bool: valuetype = VAL_Bool; break; case TK_Identifier: valuetype = VAL_Object; // Todo: Object type sc.ScriptError("Object type variables not implemented yet!"); break; default: sc.ScriptError("Invalid variable type %s", sc.String); return; } sc.MustGetToken(TK_Identifier); FName symname = sc.String; if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression (sc, cls); int maxelems = expr->EvalExpression(NULL).GetInt(); delete expr; sc.MustGetToken(']'); valuetype.MakeArray(maxelems); } sc.MustGetToken(';'); const FVariableInfo *vi = FindVariable(symname, cls); if (vi == NULL) { sc.ScriptError("Unknown native variable '%s'", symname.GetChars()); } PSymbolVariable *sym = new PSymbolVariable(symname); sym->offset = vi->address; // todo sym->ValueType = valuetype; sym->bUserVar = false; if (symt->AddSymbol (sym) == NULL) { delete sym; sc.ScriptMessage ("'%s' is already defined in '%s'.", symname.GetChars(), cls? cls->TypeName.GetChars() : "Global"); FScriptPosition::ErrorCounter++; } }