예제 #1
0
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(';');
}
예제 #2
0
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++;
	}
}
예제 #3
0
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++;
	}
}
예제 #4
0
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++;
	}
}