- implemented the parser basics of a ZScript versioning system.
Note that this completely disables the newly added keywords 'play' and 'ui' for unversioned code to allow using them as identifiers as I have found at least one mod that uses a variable named 'play' that would have been rendered broken otherwise. This also disables many ZScript only keywords for other parsing jobs.
This commit is contained in:
parent
5d3244c3a7
commit
7df698dad8
20 changed files with 268 additions and 144 deletions
|
|
@ -40,6 +40,7 @@ static void SetNodeLine(ZCC_TreeNode *name, int line)
|
|||
struct ClassFlagsBlock {
|
||||
VM_UWORD Flags;
|
||||
ZCC_Identifier *Replaces;
|
||||
VersionInfo Version;
|
||||
};
|
||||
|
||||
struct StateOpts {
|
||||
|
|
@ -188,6 +189,7 @@ class_head(X) ::= EXTEND CLASS(T) IDENTIFIER(A).
|
|||
head->ParentName = nullptr;
|
||||
head->Flags = ZCC_Extension;
|
||||
head->Replaces = nullptr;
|
||||
head->Version = {0, 0};
|
||||
head->Type = nullptr;
|
||||
head->Symbol = nullptr;
|
||||
X = head;
|
||||
|
|
@ -200,6 +202,7 @@ class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C).
|
|||
head->ParentName = B;
|
||||
head->Flags = C.Flags;
|
||||
head->Replaces = C.Replaces;
|
||||
head->Version = C.Version;
|
||||
head->Type = nullptr;
|
||||
head->Symbol = nullptr;
|
||||
X = head;
|
||||
|
|
@ -210,12 +213,13 @@ class_ancestry(X) ::= . { X = NULL; }
|
|||
class_ancestry(X) ::= COLON dottable_id(A). { X = A; /*X-overwrites-A*/ }
|
||||
|
||||
%type class_flags{ClassFlagsBlock}
|
||||
class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; }
|
||||
class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; X.Version = {0,0}; }
|
||||
class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | ZCC_Abstract; X.Replaces = A.Replaces; }
|
||||
class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; X.Replaces = A.Replaces; }
|
||||
class_flags(X) ::= class_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; X.Replaces = A.Replaces; }
|
||||
class_flags(X) ::= class_flags(A) PLAY. { X.Flags = A.Flags | ZCC_Play; X.Replaces = A.Replaces; }
|
||||
class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; }
|
||||
class_flags(X) ::= class_flags(A) VERSION LPAREN STRCONST(C) RPAREN. { X.Flags = A.Flags | ZCC_Version; X.Replaces = A.Replaces; X.Version = C.String->GetChars(); }
|
||||
|
||||
/*----- Dottable Identifier -----*/
|
||||
// This can be either a single identifier or two identifiers connected by a .
|
||||
|
|
@ -322,16 +326,18 @@ struct_def(X) ::= STRUCT(T) IDENTIFIER(A) struct_flags(S) LBRACE opt_struct_body
|
|||
def->Body = B;
|
||||
def->Type = nullptr;
|
||||
def->Symbol = nullptr;
|
||||
def->Version = S.Version;
|
||||
def->Flags = S.Flags;
|
||||
X = def;
|
||||
}
|
||||
|
||||
%type struct_flags{ClassFlagsBlock}
|
||||
struct_flags(X) ::= . { X.Flags = 0; }
|
||||
struct_flags(X) ::= . { X.Flags = 0; X.Version = {0, 0}; }
|
||||
struct_flags(X) ::= struct_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; }
|
||||
struct_flags(X) ::= struct_flags(A) PLAY. { X.Flags = A.Flags | ZCC_Play; }
|
||||
struct_flags(X) ::= struct_flags(A) CLEARSCOPE. { X.Flags = A.Flags | ZCC_ClearScope; }
|
||||
struct_flags(X) ::= struct_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; }
|
||||
struct_flags(X) ::= struct_flags(A) VERSION LPAREN STRCONST(C) RPAREN. { X.Flags = A.Flags | ZCC_Version; X.Version = C.String->GetChars(); }
|
||||
|
||||
opt_struct_body(X) ::= . { X = NULL; }
|
||||
opt_struct_body(X) ::= struct_body(X).
|
||||
|
|
@ -966,6 +972,7 @@ decl_flags(X) ::= decl_flags(F) decl_flag(A).
|
|||
X = nil_f;
|
||||
X->Id = nullptr;
|
||||
X->Flags = A.Int;
|
||||
X->Version = { 0, 0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -982,6 +989,8 @@ decl_flags(X) ::= decl_flags(F) ACTION(B) states_opts(A).
|
|||
NEW_AST_NODE(DeclFlags,nil_f,B.SourceLoc);
|
||||
X = nil_f;
|
||||
X->Flags = ZCC_Action;
|
||||
X->Id = nullptr;
|
||||
X->Version = { 0, 0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -991,6 +1000,42 @@ decl_flags(X) ::= decl_flags(F) ACTION(B) states_opts(A).
|
|||
X->Id = A;
|
||||
}
|
||||
|
||||
decl_flags(X) ::= decl_flags(F) DEPRECATED(B) LPAREN STRCONST(A) RPAREN.
|
||||
{
|
||||
if (F == nullptr)
|
||||
{
|
||||
NEW_AST_NODE(DeclFlags,nil_f,B.SourceLoc);
|
||||
X = nil_f;
|
||||
X->Flags = ZCC_Deprecated;
|
||||
X->Id = nullptr;
|
||||
X->Version = { 0, 0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
X = F;
|
||||
X->Flags |= ZCC_Deprecated;
|
||||
}
|
||||
X->Version = A.String->GetChars();
|
||||
}
|
||||
|
||||
decl_flags(X) ::= decl_flags(F) VERSION(B) LPAREN STRINGCONST(A) RPAREN.
|
||||
{
|
||||
if (F == nullptr)
|
||||
{
|
||||
NEW_AST_NODE(DeclFlags,nil_f,B.SourceLoc);
|
||||
X = nil_f;
|
||||
X->Flags = ZCC_Version;
|
||||
X->Id = nullptr;
|
||||
X->Version = { 0, 0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
X = F;
|
||||
X->Flags |= ZCC_Version;
|
||||
}
|
||||
X->Version = A.String->GetChars();
|
||||
}
|
||||
|
||||
decl_flag(X) ::= NATIVE(T). { X.Int = ZCC_Native; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= STATIC(T). { X.Int = ZCC_Static; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= PRIVATE(T). { X.Int = ZCC_Private; X.SourceLoc = T.SourceLoc; }
|
||||
|
|
@ -1000,7 +1045,6 @@ decl_flag(X) ::= FINAL(T). { X.Int = ZCC_Final; X.SourceLoc = T.SourceLoc; }
|
|||
decl_flag(X) ::= META(T). { X.Int = ZCC_Meta; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= TRANSIENT(T). { X.Int = ZCC_Transient; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= READONLY(T). { X.Int = ZCC_ReadOnly; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= DEPRECATED(T). { X.Int = ZCC_Deprecated; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= VIRTUAL(T). { X.Int = ZCC_Virtual; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= OVERRIDE(T). { X.Int = ZCC_Override; X.SourceLoc = T.SourceLoc; }
|
||||
decl_flag(X) ::= VARARG(T). { X.Int = ZCC_VarArg; X.SourceLoc = T.SourceLoc; }
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include "i_system.h"
|
||||
#include "m_argv.h"
|
||||
#include "v_text.h"
|
||||
#include "version.h"
|
||||
#include "zcc_parser.h"
|
||||
#include "zcc_compile.h"
|
||||
|
||||
|
|
@ -145,6 +146,7 @@ static void InitTokenMap()
|
|||
TOKENDEF (TK_Final, ZCC_FINAL);
|
||||
TOKENDEF (TK_Meta, ZCC_META);
|
||||
TOKENDEF (TK_Deprecated, ZCC_DEPRECATED);
|
||||
TOKENDEF (TK_Version, ZCC_VERSION);
|
||||
TOKENDEF (TK_ReadOnly, ZCC_READONLY);
|
||||
TOKENDEF ('{', ZCC_LBRACE);
|
||||
TOKENDEF ('}', ZCC_RBRACE);
|
||||
|
|
@ -179,7 +181,6 @@ static void InitTokenMap()
|
|||
TOKENDEF (']', ZCC_RBRACKET);
|
||||
TOKENDEF (TK_In, ZCC_IN);
|
||||
TOKENDEF (TK_Out, ZCC_OUT);
|
||||
TOKENDEF (TK_Optional, ZCC_OPTIONAL);
|
||||
TOKENDEF (TK_Super, ZCC_SUPER);
|
||||
TOKENDEF (TK_Null, ZCC_NULLPTR);
|
||||
TOKENDEF ('~', ZCC_TILDE);
|
||||
|
|
@ -232,29 +233,36 @@ static void InitTokenMap()
|
|||
|
||||
//**--------------------------------------------------------------------------
|
||||
|
||||
static void ParseSingleFile(const char *filename, int lump, void *parser, ZCCParseState &state)
|
||||
static void ParseSingleFile(FScanner *pSC, const char *filename, int lump, void *parser, ZCCParseState &state)
|
||||
{
|
||||
int tokentype;
|
||||
//bool failed;
|
||||
ZCCToken value;
|
||||
FScanner sc;
|
||||
FScanner lsc;
|
||||
|
||||
if (filename != nullptr)
|
||||
if (pSC == nullptr)
|
||||
{
|
||||
lump = Wads.CheckNumForFullName(filename, true);
|
||||
if (lump >= 0)
|
||||
if (filename != nullptr)
|
||||
{
|
||||
sc.OpenLumpNum(lump);
|
||||
lump = Wads.CheckNumForFullName(filename, true);
|
||||
if (lump >= 0)
|
||||
{
|
||||
lsc.OpenLumpNum(lump);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Could not find script lump '%s'\n", filename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Could not find script lump '%s'\n", filename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else sc.OpenLumpNum(lump);
|
||||
else lsc.OpenLumpNum(lump);
|
||||
|
||||
pSC = &lsc;
|
||||
}
|
||||
FScanner &sc = *pSC;
|
||||
sc.SetParseVersion(state.ParseVersion);
|
||||
state.sc = ≻
|
||||
|
||||
while (sc.GetToken())
|
||||
{
|
||||
value.SourceLoc = sc.GetMessageLine();
|
||||
|
|
@ -343,9 +351,48 @@ static void DoParse(int lumpnum)
|
|||
#endif
|
||||
|
||||
sc.OpenLumpNum(lumpnum);
|
||||
sc.SetParseVersion({ 2, 4 }); // To get 'version' we need parse version 2.4 for the initial test
|
||||
auto saved = sc.SavePos();
|
||||
|
||||
ParseSingleFile(nullptr, lumpnum, parser, state);
|
||||
if (sc.GetToken())
|
||||
{
|
||||
if (sc.TokenType == TK_Version)
|
||||
{
|
||||
char *endp;
|
||||
sc.MustGetString();
|
||||
state.ParseVersion.major = (int16_t)clamp<long long>(strtoll(sc.String, &endp, 10), -1, USHRT_MAX);
|
||||
if (*endp != '.')
|
||||
{
|
||||
sc.ScriptError("Bad version directive");
|
||||
}
|
||||
state.ParseVersion.minor = (int16_t)clamp<long long>(strtoll(endp + 1, &endp, 10), -1, USHRT_MAX);
|
||||
if (*endp == '.')
|
||||
{
|
||||
state.ParseVersion.revision = (int16_t)clamp<long long>(strtoll(endp + 1, &endp, 10), -1, USHRT_MAX);
|
||||
}
|
||||
else state.ParseVersion.revision = 0;
|
||||
if (*endp != 0)
|
||||
{
|
||||
sc.ScriptError("Bad version directive");
|
||||
}
|
||||
if (state.ParseVersion.major < 0 || state.ParseVersion.minor < 0 || state.ParseVersion.revision < 0)
|
||||
{
|
||||
sc.ScriptError("Bad version directive");
|
||||
}
|
||||
if (!state.ParseVersion.Check(VER_MAJOR, VER_MINOR, VER_REVISION))
|
||||
{
|
||||
sc.ScriptError("Version mismatch. %d.%d expected but only %d.%d supported", state.ParseVersion.major, state.ParseVersion.minor, VER_MAJOR, VER_MINOR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state.ParseVersion.major = 1; // 0 excludes all ZSCRIPT keywords from the parser.
|
||||
state.ParseVersion.minor = 0;
|
||||
sc.RestorePos(saved);
|
||||
}
|
||||
}
|
||||
|
||||
ParseSingleFile(&sc, nullptr, lumpnum, parser, state);
|
||||
for (unsigned i = 0; i < Includes.Size(); i++)
|
||||
{
|
||||
lumpnum = Wads.CheckNumForFullName(Includes[i], true);
|
||||
|
|
@ -362,7 +409,7 @@ static void DoParse(int lumpnum)
|
|||
Wads.GetWadFullName(Wads.GetLumpFile(baselump)), Includes[i].GetChars());
|
||||
}
|
||||
|
||||
ParseSingleFile(nullptr, lumpnum, parser, state);
|
||||
ParseSingleFile(nullptr, nullptr, lumpnum, parser, state);
|
||||
}
|
||||
}
|
||||
Includes.Clear();
|
||||
|
|
@ -436,16 +483,6 @@ void ParseScripts()
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
CCMD(parse)
|
||||
{
|
||||
if (argv.argc() == 2)
|
||||
{
|
||||
DoParse(argv[1]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static FString ZCCTokenName(int terminal)
|
||||
{
|
||||
if (terminal == ZCC_EOF)
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ enum
|
|||
ZCC_Play = 1 << 18,
|
||||
ZCC_ClearScope = 1 << 19,
|
||||
ZCC_VirtualScope = 1 << 20,
|
||||
ZCC_Version = 1 << 21,
|
||||
};
|
||||
|
||||
// Function parameter modifiers
|
||||
|
|
@ -194,6 +195,7 @@ struct ZCC_Struct : ZCC_NamedNode
|
|||
VM_UWORD Flags;
|
||||
ZCC_TreeNode *Body;
|
||||
PStruct *Type;
|
||||
VersionInfo Version;
|
||||
};
|
||||
|
||||
struct ZCC_Property : ZCC_NamedNode
|
||||
|
|
@ -483,6 +485,7 @@ struct ZCC_FuncParamDecl : ZCC_TreeNode
|
|||
struct ZCC_DeclFlags : ZCC_TreeNode
|
||||
{
|
||||
ZCC_Identifier *Id;
|
||||
VersionInfo Version;
|
||||
int Flags;
|
||||
};
|
||||
|
||||
|
|
@ -542,6 +545,7 @@ struct ZCC_AST
|
|||
FSharedStringArena Strings;
|
||||
FMemArena SyntaxArena;
|
||||
struct ZCC_TreeNode *TopNode;
|
||||
VersionInfo ParseVersion;
|
||||
};
|
||||
|
||||
struct ZCCParseState : public ZCC_AST
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue