mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-28 06:42:09 +00:00
- added 'null' token to the ZScript parser which is needed for null pointers.
- removed function declaration parser from DECORATE because it is not needed anymore. - fixed: comparison operators could not handle names.
This commit is contained in:
parent
f6b3cdc23d
commit
665d752686
7 changed files with 23 additions and 272 deletions
|
@ -171,6 +171,7 @@ std2:
|
||||||
'global' { RET(TK_Global); }
|
'global' { RET(TK_Global); }
|
||||||
'self' { RET(TK_Self); }
|
'self' { RET(TK_Self); }
|
||||||
'stop' { RET(TK_Stop); }
|
'stop' { RET(TK_Stop); }
|
||||||
|
'null' { RET(TK_Null); }
|
||||||
|
|
||||||
'is' { RET(TK_Is); }
|
'is' { RET(TK_Is); }
|
||||||
'replaces' { RET(TK_Replaces); }
|
'replaces' { RET(TK_Replaces); }
|
||||||
|
|
|
@ -106,6 +106,7 @@ xx(TK_Optional, "'optional'")
|
||||||
xx(TK_Export, "'expert'")
|
xx(TK_Export, "'expert'")
|
||||||
xx(TK_Virtual, "'virtual'")
|
xx(TK_Virtual, "'virtual'")
|
||||||
xx(TK_Super, "'super'")
|
xx(TK_Super, "'super'")
|
||||||
|
xx(TK_Null, "'null'")
|
||||||
xx(TK_Global, "'global'")
|
xx(TK_Global, "'global'")
|
||||||
xx(TK_Self, "'self'")
|
xx(TK_Self, "'self'")
|
||||||
xx(TK_Stop, "'stop'")
|
xx(TK_Stop, "'stop'")
|
||||||
|
|
|
@ -1888,6 +1888,10 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric)
|
||||||
{
|
{
|
||||||
ValueType = TypeBool;
|
ValueType = TypeBool;
|
||||||
}
|
}
|
||||||
|
else if (left->ValueType == TypeName && right->ValueType == TypeName)
|
||||||
|
{
|
||||||
|
ValueType = TypeName;
|
||||||
|
}
|
||||||
else if (left->IsNumeric() && right->IsNumeric())
|
else if (left->IsNumeric() && right->IsNumeric())
|
||||||
{
|
{
|
||||||
if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT)
|
if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT)
|
||||||
|
@ -2395,7 +2399,7 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsNumeric() && !IsPointer())
|
if (!IsNumeric() && !IsPointer() && ValueType != TypeName)
|
||||||
{
|
{
|
||||||
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
||||||
delete this;
|
delete this;
|
||||||
|
|
|
@ -334,213 +334,6 @@ 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:
|
|
||||||
type = TypeBool;
|
|
||||||
break;
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
assert(cls != NULL);
|
|
||||||
|
|
||||||
const AFuncDesc *afd;
|
|
||||||
TArray<PType *> args;
|
|
||||||
TArray<DWORD> argflags;
|
|
||||||
TArray<FName> argnames;
|
|
||||||
|
|
||||||
afd = FindFunction(funcname);
|
|
||||||
if (afd == NULL)
|
|
||||||
{
|
|
||||||
sc.ScriptMessage ("The function '%s' has not been exported from the executable.", funcname.GetChars());
|
|
||||||
FScriptPosition::ErrorCounter++;
|
|
||||||
}
|
|
||||||
sc.MustGetToken('(');
|
|
||||||
|
|
||||||
SetImplicitArgs(&args, &argflags, &argnames, cls, funcflags);
|
|
||||||
// This function will be removed once all internal classes have been ported so don't bother filling in the function's argument names, because for anything going through here they'll never be used.
|
|
||||||
ParseArgListDef(sc, cls, args, argflags);
|
|
||||||
|
|
||||||
if (afd != NULL)
|
|
||||||
{
|
|
||||||
PFunction *sym = new PFunction(cls, funcname);
|
|
||||||
sym->AddVariant(NewPrototype(rets, args), argflags, argnames, *(afd->VMPointer), funcflags);
|
|
||||||
if (cls->Symbols.AddSymbol(sym) == NULL)
|
|
||||||
{
|
|
||||||
delete sym;
|
|
||||||
sc.ScriptMessage ("'%s' is already defined in class '%s'.",
|
|
||||||
funcname.GetChars(), cls->TypeName.GetChars());
|
|
||||||
FScriptPosition::ErrorCounter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// ParseNativeFunction
|
|
||||||
//
|
|
||||||
// Parses a non-action function declaration.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
static void ParseNativeFunction(FScanner &sc, PClassActor *cls)
|
|
||||||
{
|
|
||||||
TArray<PType *> rets(1);
|
|
||||||
|
|
||||||
if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0)
|
|
||||||
{
|
|
||||||
sc.ScriptMessage ("functions can only be declared by native actors!");
|
|
||||||
FScriptPosition::ErrorCounter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the type and make sure it's acceptable.
|
|
||||||
sc.MustGetAnyToken();
|
|
||||||
switch (sc.TokenType)
|
|
||||||
{
|
|
||||||
case TK_Bool:
|
|
||||||
rets.Push(TypeBool);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TK_Int:
|
|
||||||
rets.Push(TypeSInt32);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TK_Float:
|
|
||||||
rets.Push(TypeFloat64);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TK_State:
|
|
||||||
rets.Push(TypeState);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TK_Void:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TK_Identifier:
|
|
||||||
rets.Push(NewPointer(RUNTIME_CLASS(DObject)));
|
|
||||||
// Todo: Object type
|
|
||||||
sc.ScriptError("Object type variables not implemented yet!");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
sc.ScriptError("Invalid return type %s", sc.String);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sc.MustGetToken(TK_Identifier);
|
|
||||||
ParseFunctionDef(sc, cls, sc.String, rets, VARF_Method);
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// ParseUserVariable
|
// ParseUserVariable
|
||||||
|
@ -1081,55 +874,6 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// ActorActionDef
|
|
||||||
//
|
|
||||||
// Parses an action function definition. A lot of this is essentially
|
|
||||||
// documentation in the declaration for when I have a proper language
|
|
||||||
// ready.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
static void ParseActionDef (FScanner &sc, PClassActor *cls)
|
|
||||||
{
|
|
||||||
unsigned int error = 0;
|
|
||||||
FName funcname;
|
|
||||||
TArray<PType *> rets;
|
|
||||||
|
|
||||||
if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0)
|
|
||||||
{
|
|
||||||
sc.ScriptMessage ("Action functions can only be imported by internal class and actor definitions!");
|
|
||||||
FScriptPosition::ErrorCounter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
sc.MustGetToken(TK_Native);
|
|
||||||
// check for a return value
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (sc.CheckToken(TK_Bool))
|
|
||||||
{
|
|
||||||
rets.Push(TypeBool);
|
|
||||||
}
|
|
||||||
else if (sc.CheckToken(TK_Int))
|
|
||||||
{
|
|
||||||
rets.Push(TypeSInt32);
|
|
||||||
}
|
|
||||||
else if (sc.CheckToken(TK_State))
|
|
||||||
{
|
|
||||||
rets.Push(TypeState);
|
|
||||||
}
|
|
||||||
else if (sc.CheckToken(TK_Float))
|
|
||||||
{
|
|
||||||
rets.Push(TypeFloat64);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (sc.CheckToken(','));
|
|
||||||
sc.MustGetToken(TK_Identifier);
|
|
||||||
funcname = sc.String;
|
|
||||||
ParseFunctionDef(sc, cls, funcname, rets, VARF_Method | VARF_Action);
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// Starts a new actor definition
|
// Starts a new actor definition
|
||||||
|
@ -1330,10 +1074,6 @@ static void ParseActor(FScanner &sc)
|
||||||
{
|
{
|
||||||
switch (sc.TokenType)
|
switch (sc.TokenType)
|
||||||
{
|
{
|
||||||
case TK_Action:
|
|
||||||
ParseActionDef (sc, info);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TK_Const:
|
case TK_Const:
|
||||||
ParseConstant (sc, &info->Symbols, info);
|
ParseConstant (sc, &info->Symbols, info);
|
||||||
break;
|
break;
|
||||||
|
@ -1342,10 +1082,6 @@ static void ParseActor(FScanner &sc)
|
||||||
ParseEnum (sc, &info->Symbols, info);
|
ParseEnum (sc, &info->Symbols, info);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TK_Native:
|
|
||||||
ParseNativeFunction (sc, info);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TK_Var:
|
case TK_Var:
|
||||||
ParseUserVariable (sc, &info->Symbols, info);
|
ParseUserVariable (sc, &info->Symbols, info);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -956,6 +956,13 @@ primary(X) ::= IDENTIFIER(A).
|
||||||
expr->Type = NULL;
|
expr->Type = NULL;
|
||||||
X = expr;
|
X = expr;
|
||||||
}
|
}
|
||||||
|
primary(X) ::= NULL(T).
|
||||||
|
{
|
||||||
|
NEW_AST_NODE(Expression, expr, T);
|
||||||
|
expr->Operation = PEX_Null;
|
||||||
|
expr->Type = NULL;
|
||||||
|
X = expr;
|
||||||
|
}
|
||||||
primary(X) ::= SUPER(T).
|
primary(X) ::= SUPER(T).
|
||||||
{
|
{
|
||||||
NEW_AST_NODE(Expression, expr, T);
|
NEW_AST_NODE(Expression, expr, T);
|
||||||
|
|
|
@ -3,6 +3,7 @@ xx(Nil, )
|
||||||
|
|
||||||
xx(ID, )
|
xx(ID, )
|
||||||
xx(Super, )
|
xx(Super, )
|
||||||
|
xx(Null, )
|
||||||
xx(Self, )
|
xx(Self, )
|
||||||
xx(ConstValue, )
|
xx(ConstValue, )
|
||||||
xx(FuncCall, )
|
xx(FuncCall, )
|
||||||
|
|
|
@ -153,6 +153,7 @@ static void InitTokenMap()
|
||||||
TOKENDEF (TK_Out, ZCC_OUT);
|
TOKENDEF (TK_Out, ZCC_OUT);
|
||||||
TOKENDEF (TK_Optional, ZCC_OPTIONAL);
|
TOKENDEF (TK_Optional, ZCC_OPTIONAL);
|
||||||
TOKENDEF (TK_Super, ZCC_SUPER);
|
TOKENDEF (TK_Super, ZCC_SUPER);
|
||||||
|
TOKENDEF (TK_Null, ZCC_NULL);
|
||||||
TOKENDEF (TK_Self, ZCC_SELF);
|
TOKENDEF (TK_Self, ZCC_SELF);
|
||||||
TOKENDEF ('~', ZCC_TILDE);
|
TOKENDEF ('~', ZCC_TILDE);
|
||||||
TOKENDEF ('!', ZCC_BANG);
|
TOKENDEF ('!', ZCC_BANG);
|
||||||
|
|
Loading…
Reference in a new issue