mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-12 07:34:50 +00:00
Add non-action function parsing to the DECORATE parser
This commit is contained in:
parent
10a2c0f58a
commit
9e3ed70021
1 changed files with 205 additions and 151 deletions
|
@ -277,22 +277,184 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls)
|
||||||
sc.MustGetToken(';');
|
sc.MustGetToken(';');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// ParseArgListDef
|
||||||
|
//
|
||||||
|
// Parses the argument list from a function declaration.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static void ParseArgListDef(FScanner &sc, PClassActor *cls,
|
||||||
|
TArray<PType *> &args, TArray<DWORD> &argflags)
|
||||||
|
{
|
||||||
|
if (!sc.CheckToken(')'))
|
||||||
|
{
|
||||||
|
while (sc.TokenType != ')')
|
||||||
|
{
|
||||||
|
int flags = 0;
|
||||||
|
PType *type = NULL;
|
||||||
|
PClass *restrict = NULL;
|
||||||
|
|
||||||
|
// Retrieve flags before type name
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (sc.CheckToken(TK_Coerce) || sc.CheckToken(TK_Native))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Read the variable type
|
||||||
|
sc.MustGetAnyToken();
|
||||||
|
switch (sc.TokenType)
|
||||||
|
{
|
||||||
|
case TK_Bool:
|
||||||
|
case TK_Int:
|
||||||
|
type = TypeSInt32;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TK_Float:
|
||||||
|
type = TypeFloat64;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TK_Sound: type = TypeSound; break;
|
||||||
|
case TK_String: type = TypeString; break;
|
||||||
|
case TK_Name: type = TypeName; break;
|
||||||
|
case TK_State: type = TypeState; break;
|
||||||
|
case TK_Color: type = TypeColor; break;
|
||||||
|
case TK_Class:
|
||||||
|
sc.MustGetToken('<');
|
||||||
|
sc.MustGetToken(TK_Identifier); // Get class name
|
||||||
|
restrict = PClass::FindClass(sc.String);
|
||||||
|
if (restrict == NULL)
|
||||||
|
{
|
||||||
|
sc.ScriptMessage("Unknown class type %s", sc.String);
|
||||||
|
FScriptPosition::ErrorCounter++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = NewClassPointer(restrict);
|
||||||
|
}
|
||||||
|
sc.MustGetToken('>');
|
||||||
|
break;
|
||||||
|
case TK_Ellipsis:
|
||||||
|
// Making the final type NULL signals a varargs function.
|
||||||
|
type = NULL;
|
||||||
|
sc.MustGetToken(')');
|
||||||
|
sc.UnGet();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sc.ScriptMessage ("Unknown variable type %s", sc.TokenName(sc.TokenType, sc.String).GetChars());
|
||||||
|
type = TypeSInt32;
|
||||||
|
FScriptPosition::ErrorCounter++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Read the optional variable name
|
||||||
|
if (!sc.CheckToken(',') && !sc.CheckToken(')'))
|
||||||
|
{
|
||||||
|
sc.MustGetToken(TK_Identifier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sc.UnGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc.CheckToken('='))
|
||||||
|
{
|
||||||
|
flags |= VARF_Optional;
|
||||||
|
FxExpression *def = ParseParameter(sc, cls, type, true);
|
||||||
|
delete def;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.Push(type);
|
||||||
|
argflags.Push(flags);
|
||||||
|
sc.MustGetAnyToken();
|
||||||
|
if (sc.TokenType != ',' && sc.TokenType != ')')
|
||||||
|
{
|
||||||
|
sc.ScriptError ("Expected ',' or ')' but got %s instead", sc.TokenName(sc.TokenType, sc.String).GetChars());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sc.MustGetToken(';');
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// ParseFunctionDef
|
||||||
|
//
|
||||||
|
// Parses a native function's parameters and adds it to the class,
|
||||||
|
// if possible.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void ParseFunctionDef(FScanner &sc, PClassActor *cls, FName funcname,
|
||||||
|
TArray<PType *> &rets, DWORD funcflags, unsigned int error)
|
||||||
|
{
|
||||||
|
assert(cls != NULL);
|
||||||
|
|
||||||
|
const AFuncDesc *afd;
|
||||||
|
TArray<PType *> args;
|
||||||
|
TArray<DWORD> argflags;
|
||||||
|
|
||||||
|
afd = FindFunction(funcname);
|
||||||
|
if (afd == NULL)
|
||||||
|
{
|
||||||
|
sc.ScriptMessage ("The function '%s' has not been exported from the executable.", funcname.GetChars());
|
||||||
|
++error;
|
||||||
|
}
|
||||||
|
sc.MustGetToken('(');
|
||||||
|
|
||||||
|
if (funcflags & VARF_Method)
|
||||||
|
{
|
||||||
|
args.Push(NewClassPointer(cls)), argflags.Push(0); // implied self pointer
|
||||||
|
}
|
||||||
|
if (funcflags & VARF_Action)
|
||||||
|
{
|
||||||
|
args.Push(NewClassPointer(RUNTIME_CLASS(AActor))), argflags.Push(0); // implied stateowner pointer
|
||||||
|
args.Push(TypeState), argflags.Push(0); // implied callingstate pointer
|
||||||
|
}
|
||||||
|
ParseArgListDef(sc, cls, args, argflags);
|
||||||
|
|
||||||
|
if (afd != NULL)
|
||||||
|
{
|
||||||
|
PFunction *sym = new PFunction(funcname);
|
||||||
|
sym->AddVariant(NewPrototype(rets, args), argflags, *(afd->VMPointer));
|
||||||
|
sym->Flags = funcflags;
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
FScriptPosition::ErrorCounter += error;
|
||||||
|
}
|
||||||
|
else if (cls->Symbols.AddSymbol(sym) == NULL)
|
||||||
|
{
|
||||||
|
delete sym;
|
||||||
|
sc.ScriptMessage ("'%s' is already defined in class '%s'.",
|
||||||
|
funcname.GetChars(), cls->TypeName.GetChars());
|
||||||
|
FScriptPosition::ErrorCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// ParseNativeVariable
|
// ParseNativeVariable
|
||||||
//
|
//
|
||||||
// Parses a native variable declaration.
|
// Parses a native variable or non-action function declaration.
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cls)
|
static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cls)
|
||||||
{
|
{
|
||||||
PType *valuetype;
|
PType *valuetype;
|
||||||
|
unsigned int error = 0;
|
||||||
|
|
||||||
if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0)
|
if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0)
|
||||||
{
|
{
|
||||||
sc.ScriptMessage ("variables can only be imported by internal class and actor definitions!");
|
sc.ScriptMessage ("variables can only be imported by internal class and actor definitions!");
|
||||||
FScriptPosition::ErrorCounter++;
|
FScriptPosition::ErrorCounter++;
|
||||||
|
error++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the type and make sure it's int or float.
|
// Read the type and make sure it's int or float.
|
||||||
|
@ -300,6 +462,7 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor *
|
||||||
switch (sc.TokenType)
|
switch (sc.TokenType)
|
||||||
{
|
{
|
||||||
case TK_Int:
|
case TK_Int:
|
||||||
|
case TK_Bool:
|
||||||
valuetype = TypeSInt32;
|
valuetype = TypeSInt32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -328,6 +491,17 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor *
|
||||||
|
|
||||||
sc.MustGetToken(TK_Identifier);
|
sc.MustGetToken(TK_Identifier);
|
||||||
FName symname = sc.String;
|
FName symname = sc.String;
|
||||||
|
if (sc.CheckToken('('))
|
||||||
|
{
|
||||||
|
TArray<PType *> rets;
|
||||||
|
|
||||||
|
rets.Push(valuetype);
|
||||||
|
sc.UnGet();
|
||||||
|
ParseFunctionDef(sc, cls, symname, rets, VARF_Method, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (sc.CheckToken('['))
|
if (sc.CheckToken('['))
|
||||||
{
|
{
|
||||||
FxExpression *expr = ParseExpression (sc, cls);
|
FxExpression *expr = ParseExpression (sc, cls);
|
||||||
|
@ -363,6 +537,7 @@ static void ParseNativeVariable (FScanner &sc, PSymbolTable *symt, PClassActor *
|
||||||
cls->Fields.Push(sym);
|
cls->Fields.Push(sym);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
@ -908,11 +1083,8 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag)
|
||||||
static void ParseActionDef (FScanner &sc, PClassActor *cls)
|
static void ParseActionDef (FScanner &sc, PClassActor *cls)
|
||||||
{
|
{
|
||||||
unsigned int error = 0;
|
unsigned int error = 0;
|
||||||
const AFuncDesc *afd;
|
|
||||||
FName funcname;
|
FName funcname;
|
||||||
TArray<PType *> rets;
|
TArray<PType *> rets;
|
||||||
TArray<PType *> args;
|
|
||||||
TArray<DWORD> argflags;
|
|
||||||
|
|
||||||
if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0)
|
if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0)
|
||||||
{
|
{
|
||||||
|
@ -928,125 +1100,7 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls)
|
||||||
}
|
}
|
||||||
sc.MustGetToken(TK_Identifier);
|
sc.MustGetToken(TK_Identifier);
|
||||||
funcname = sc.String;
|
funcname = sc.String;
|
||||||
afd = FindFunction(sc.String);
|
ParseFunctionDef(sc, cls, funcname, rets, VARF_Method | VARF_Action, error);
|
||||||
if (afd == NULL)
|
|
||||||
{
|
|
||||||
sc.ScriptMessage ("The function '%s' has not been exported from the executable.", sc.String);
|
|
||||||
++error;
|
|
||||||
}
|
|
||||||
args.Push(NewClassPointer(cls)), argflags.Push(0); // implied self pointer
|
|
||||||
args.Push(NewClassPointer(RUNTIME_CLASS(AActor))), argflags.Push(0); // implied stateowner pointer
|
|
||||||
args.Push(TypeState), argflags.Push(0); // implied callingstate pointer
|
|
||||||
|
|
||||||
sc.MustGetToken('(');
|
|
||||||
if (!sc.CheckToken(')'))
|
|
||||||
{
|
|
||||||
while (sc.TokenType != ')')
|
|
||||||
{
|
|
||||||
int flags = 0;
|
|
||||||
PType *type = NULL;
|
|
||||||
PClass *restrict = NULL;
|
|
||||||
|
|
||||||
// Retrieve flags before type name
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
if (sc.CheckToken(TK_Coerce) || sc.CheckToken(TK_Native))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Read the variable type
|
|
||||||
sc.MustGetAnyToken();
|
|
||||||
switch (sc.TokenType)
|
|
||||||
{
|
|
||||||
case TK_Bool:
|
|
||||||
case TK_Int:
|
|
||||||
type = TypeSInt32;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TK_Float:
|
|
||||||
type = TypeFloat64;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TK_Sound: type = TypeSound; break;
|
|
||||||
case TK_String: type = TypeString; break;
|
|
||||||
case TK_Name: type = TypeName; break;
|
|
||||||
case TK_State: type = TypeState; break;
|
|
||||||
case TK_Color: type = TypeColor; break;
|
|
||||||
case TK_Class:
|
|
||||||
sc.MustGetToken('<');
|
|
||||||
sc.MustGetToken(TK_Identifier); // Get class name
|
|
||||||
restrict = PClass::FindClass(sc.String);
|
|
||||||
if (restrict == NULL)
|
|
||||||
{
|
|
||||||
sc.ScriptMessage("Unknown class type %s", sc.String);
|
|
||||||
FScriptPosition::ErrorCounter++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
type = NewClassPointer(restrict);
|
|
||||||
}
|
|
||||||
sc.MustGetToken('>');
|
|
||||||
break;
|
|
||||||
case TK_Ellipsis:
|
|
||||||
// Making the final type NULL signals a varargs function.
|
|
||||||
type = NULL;
|
|
||||||
sc.MustGetToken(')');
|
|
||||||
sc.UnGet();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sc.ScriptMessage ("Unknown variable type %s", sc.TokenName(sc.TokenType, sc.String).GetChars());
|
|
||||||
type = TypeSInt32;
|
|
||||||
FScriptPosition::ErrorCounter++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Read the optional variable name
|
|
||||||
if (!sc.CheckToken(',') && !sc.CheckToken(')'))
|
|
||||||
{
|
|
||||||
sc.MustGetToken(TK_Identifier);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sc.UnGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sc.CheckToken('='))
|
|
||||||
{
|
|
||||||
flags |= VARF_Optional;
|
|
||||||
FxExpression *def = ParseParameter(sc, cls, type, true);
|
|
||||||
delete def;
|
|
||||||
}
|
|
||||||
|
|
||||||
args.Push(type);
|
|
||||||
argflags.Push(flags);
|
|
||||||
sc.MustGetAnyToken();
|
|
||||||
if (sc.TokenType != ',' && sc.TokenType != ')')
|
|
||||||
{
|
|
||||||
sc.ScriptError ("Expected ',' or ')' but got %s instead", sc.TokenName(sc.TokenType, sc.String).GetChars());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sc.MustGetToken(';');
|
|
||||||
if (afd != NULL)
|
|
||||||
{
|
|
||||||
PFunction *sym = new PFunction(funcname);
|
|
||||||
sym->AddVariant(NewPrototype(rets, args), argflags, *(afd->VMPointer));
|
|
||||||
sym->Flags = VARF_Method | VARF_Action;
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
FScriptPosition::ErrorCounter += error;
|
|
||||||
}
|
|
||||||
else if (cls->Symbols.AddSymbol(sym) == NULL)
|
|
||||||
{
|
|
||||||
delete sym;
|
|
||||||
sc.ScriptMessage ("'%s' is already defined in class '%s'.",
|
|
||||||
funcname.GetChars(), cls->TypeName.GetChars());
|
|
||||||
FScriptPosition::ErrorCounter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
Loading…
Reference in a new issue