mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-12-15 15:01:42 +00:00
332 lines
7.7 KiB
C++
332 lines
7.7 KiB
C++
|
#include "dobject.h"
|
||
|
#include "sc_man.h"
|
||
|
#include "c_console.h"
|
||
|
#include "c_dispatch.h"
|
||
|
#include "w_wad.h"
|
||
|
#include "cmdlib.h"
|
||
|
#include "m_alloc.h"
|
||
|
|
||
|
class ZCCParser
|
||
|
{
|
||
|
public:
|
||
|
void PrintError(const char *fmt, ...)
|
||
|
{
|
||
|
va_list argptr;
|
||
|
va_start(argptr, fmt);
|
||
|
VPrintf(PRINT_HIGH, fmt, argptr);
|
||
|
va_end(argptr);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
union ZCCToken
|
||
|
{
|
||
|
int Int;
|
||
|
double Float;
|
||
|
const char *String;
|
||
|
};
|
||
|
|
||
|
class StringTable
|
||
|
{
|
||
|
public:
|
||
|
StringTable()
|
||
|
{
|
||
|
memset(Buckets, 0, sizeof(Buckets));
|
||
|
}
|
||
|
~StringTable()
|
||
|
{
|
||
|
for (size_t i = 0; i < countof(Buckets); ++i)
|
||
|
{
|
||
|
Node *node, *next;
|
||
|
for (node = Buckets[i]; node != NULL; node = next)
|
||
|
{
|
||
|
if (node->String != NULL)
|
||
|
{
|
||
|
delete[] node->String;
|
||
|
}
|
||
|
next = node->Next;
|
||
|
delete node;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
const char *Get(const char *str, int len)
|
||
|
{
|
||
|
unsigned int hash = SuperFastHash(str, len);
|
||
|
Node *node, **nodep;
|
||
|
|
||
|
nodep = &Buckets[hash % countof(Buckets)];
|
||
|
node = *nodep;
|
||
|
// Search for string in the hash table.
|
||
|
while (node != NULL)
|
||
|
{
|
||
|
if (node->Hash == hash && strcmp(str, node->String))
|
||
|
{
|
||
|
return node->String;
|
||
|
}
|
||
|
nodep = &node->Next;
|
||
|
node = *nodep;
|
||
|
}
|
||
|
// String is not in the hash table; add it.
|
||
|
node = new Node;
|
||
|
*nodep = node;
|
||
|
node->Hash = hash;
|
||
|
node->String = copystring(str);
|
||
|
node->Next = NULL;
|
||
|
return node->String;
|
||
|
}
|
||
|
private:
|
||
|
struct Node
|
||
|
{
|
||
|
Node *Next;
|
||
|
const char *String;
|
||
|
unsigned int Hash;
|
||
|
};
|
||
|
Node *Buckets[256];
|
||
|
};
|
||
|
|
||
|
static FString ZCCTokenName(int terminal);
|
||
|
|
||
|
#include "zcc-parse.h"
|
||
|
#include "zcc-parse.c"
|
||
|
|
||
|
static TMap<SWORD, SWORD> TokenMap;
|
||
|
static SWORD BackTokenMap[YYERRORSYMBOL]; // YYERRORSYMBOL immediately follows the terminals described by the grammar
|
||
|
|
||
|
static void InitTokenMap()
|
||
|
{
|
||
|
#define TOKENDEF(sc, zcc) TokenMap.Insert(sc, zcc); BackTokenMap[zcc] = sc
|
||
|
TOKENDEF('=', ZCC_EQ);
|
||
|
TOKENDEF(TK_MulEq, ZCC_MULEQ);
|
||
|
TOKENDEF(TK_DivEq, ZCC_DIVEQ);
|
||
|
TOKENDEF(TK_ModEq, ZCC_MODEQ);
|
||
|
TOKENDEF(TK_AddEq, ZCC_ADDEQ);
|
||
|
TOKENDEF(TK_SubEq, ZCC_SUBEQ);
|
||
|
TOKENDEF(TK_LShiftEq, ZCC_LSHEQ);
|
||
|
TOKENDEF(TK_RShiftEq, ZCC_RSHEQ);
|
||
|
TOKENDEF(TK_AndEq, ZCC_ANDEQ);
|
||
|
TOKENDEF(TK_OrEq, ZCC_OREQ);
|
||
|
TOKENDEF(TK_XorEq, ZCC_XOREQ);
|
||
|
TOKENDEF('?', ZCC_QUESTION);
|
||
|
TOKENDEF(':', ZCC_COLON);
|
||
|
TOKENDEF(TK_OrOr, ZCC_OROR);
|
||
|
TOKENDEF(TK_AndAnd, ZCC_ANDAND);
|
||
|
TOKENDEF(TK_Eq, ZCC_EQEQ);
|
||
|
TOKENDEF(TK_Neq, ZCC_NEQ);
|
||
|
TOKENDEF(TK_ApproxEq, ZCC_APPROXEQ);
|
||
|
TOKENDEF('<', ZCC_LT);
|
||
|
TOKENDEF('>', ZCC_GT);
|
||
|
TOKENDEF(TK_Leq, ZCC_LTEQ);
|
||
|
TOKENDEF(TK_Geq, ZCC_GTEQ);
|
||
|
TOKENDEF(TK_LtGtEq, ZCC_LTGTEQ);
|
||
|
TOKENDEF(TK_Is, ZCC_IS);
|
||
|
TOKENDEF(TK_DotDot, ZCC_DOTDOT);
|
||
|
TOKENDEF('|', ZCC_OR);
|
||
|
TOKENDEF('^', ZCC_XOR);
|
||
|
TOKENDEF('&', ZCC_AND);
|
||
|
TOKENDEF(TK_LShift, ZCC_LSH);
|
||
|
TOKENDEF(TK_RShift, ZCC_RSH);
|
||
|
TOKENDEF('-', ZCC_SUB);
|
||
|
TOKENDEF('+', ZCC_ADD);
|
||
|
TOKENDEF('*', ZCC_MUL);
|
||
|
TOKENDEF('/', ZCC_DIV);
|
||
|
TOKENDEF('%', ZCC_MOD);
|
||
|
TOKENDEF(TK_Cross, ZCC_CROSSPROD);
|
||
|
TOKENDEF(TK_Dot, ZCC_DOTPROD);
|
||
|
TOKENDEF(TK_MulMul, ZCC_POW);
|
||
|
TOKENDEF(TK_Incr, ZCC_ADDADD);
|
||
|
TOKENDEF(TK_Decr, ZCC_SUBSUB);
|
||
|
TOKENDEF('.', ZCC_DOT);
|
||
|
TOKENDEF('(', ZCC_LPAREN);
|
||
|
TOKENDEF(')', ZCC_RPAREN);
|
||
|
TOKENDEF(TK_ColonColon, ZCC_SCOPE);
|
||
|
TOKENDEF(';', ZCC_SEMICOLON);
|
||
|
TOKENDEF(',', ZCC_COMMA);
|
||
|
TOKENDEF(TK_Class, ZCC_CLASS);
|
||
|
TOKENDEF(TK_Abstract, ZCC_ABSTRACT);
|
||
|
TOKENDEF(TK_Native, ZCC_NATIVE);
|
||
|
TOKENDEF(TK_Replaces, ZCC_REPLACES);
|
||
|
TOKENDEF(TK_Static, ZCC_STATIC);
|
||
|
TOKENDEF(TK_Private, ZCC_PRIVATE);
|
||
|
TOKENDEF(TK_Protected, ZCC_PROTECTED);
|
||
|
TOKENDEF(TK_Latent, ZCC_LATENT);
|
||
|
TOKENDEF(TK_Final, ZCC_FINAL);
|
||
|
TOKENDEF(TK_Meta, ZCC_META);
|
||
|
TOKENDEF(TK_Deprecated, ZCC_DEPRECATED);
|
||
|
TOKENDEF('{', ZCC_LBRACE);
|
||
|
TOKENDEF('}', ZCC_RBRACE);
|
||
|
TOKENDEF(TK_Struct, ZCC_STRUCT);
|
||
|
TOKENDEF(TK_Enum, ZCC_ENUM);
|
||
|
TOKENDEF(TK_SByte, ZCC_SBYTE);
|
||
|
TOKENDEF(TK_Byte, ZCC_BYTE);
|
||
|
TOKENDEF(TK_Short, ZCC_SHORT);
|
||
|
TOKENDEF(TK_UShort, ZCC_USHORT);
|
||
|
TOKENDEF(TK_Int, ZCC_INT);
|
||
|
TOKENDEF(TK_UInt, ZCC_UINT);
|
||
|
TOKENDEF(TK_Bool, ZCC_BOOL);
|
||
|
TOKENDEF(TK_Float, ZCC_FLOAT);
|
||
|
TOKENDEF(TK_Double, ZCC_DOUBLE);
|
||
|
TOKENDEF(TK_String, ZCC_STRING);
|
||
|
TOKENDEF(TK_Vector, ZCC_VECTOR);
|
||
|
TOKENDEF(TK_Name, ZCC_NAME);
|
||
|
TOKENDEF(TK_Map, ZCC_MAP);
|
||
|
TOKENDEF(TK_Array, ZCC_ARRAY);
|
||
|
TOKENDEF(TK_Void, ZCC_VOID);
|
||
|
TOKENDEF('[', ZCC_LBRACKET);
|
||
|
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_Self, ZCC_SELF);
|
||
|
TOKENDEF('~', ZCC_TILDE);
|
||
|
TOKENDEF('!', ZCC_BANG);
|
||
|
TOKENDEF(TK_SizeOf, ZCC_SIZEOF);
|
||
|
TOKENDEF(TK_AlignOf, ZCC_ALIGNOF);
|
||
|
TOKENDEF(TK_Continue, ZCC_CONTINUE);
|
||
|
TOKENDEF(TK_Break, ZCC_BREAK);
|
||
|
TOKENDEF(TK_Return, ZCC_RETURN);
|
||
|
TOKENDEF(TK_Do, ZCC_DO);
|
||
|
TOKENDEF(TK_For, ZCC_FOR);
|
||
|
TOKENDEF(TK_While, ZCC_WHILE);
|
||
|
TOKENDEF(TK_Until, ZCC_UNTIL);
|
||
|
TOKENDEF(TK_If, ZCC_IF);
|
||
|
TOKENDEF(TK_Else, ZCC_ELSE);
|
||
|
TOKENDEF(TK_Switch, ZCC_SWITCH);
|
||
|
TOKENDEF(TK_Case, ZCC_CASE);
|
||
|
TOKENDEF(TK_Default, ZCC_DEFAULT);
|
||
|
TOKENDEF(TK_Const, ZCC_CONST);
|
||
|
TOKENDEF(TK_Stop, ZCC_STOP);
|
||
|
TOKENDEF(TK_Wait, ZCC_WAIT);
|
||
|
TOKENDEF(TK_Fail, ZCC_FAIL);
|
||
|
TOKENDEF(TK_Loop, ZCC_LOOP);
|
||
|
TOKENDEF(TK_Goto, ZCC_GOTO);
|
||
|
TOKENDEF(TK_States, ZCC_STATES);
|
||
|
|
||
|
TOKENDEF(TK_Identifier, ZCC_IDENTIFIER);
|
||
|
TOKENDEF(TK_StringConst, ZCC_STRCONST);
|
||
|
TOKENDEF(TK_IntConst, ZCC_INTCONST);
|
||
|
TOKENDEF(TK_FloatConst, ZCC_FLOATCONST);
|
||
|
TOKENDEF(TK_NonWhitespace, ZCC_NWS);
|
||
|
#undef TOKENDEF
|
||
|
}
|
||
|
|
||
|
static void DoParse(const char *filename)
|
||
|
{
|
||
|
if (TokenMap.CountUsed() == 0)
|
||
|
{
|
||
|
InitTokenMap();
|
||
|
}
|
||
|
|
||
|
FScanner sc;
|
||
|
StringTable strings;
|
||
|
void *parser;
|
||
|
int tokentype;
|
||
|
int lump;
|
||
|
bool failed;
|
||
|
ZCCToken value;
|
||
|
|
||
|
lump = Wads.CheckNumForFullName(filename, true);
|
||
|
if (lump >= 0)
|
||
|
{
|
||
|
sc.OpenLumpNum(lump);
|
||
|
}
|
||
|
else if (FileExists(filename))
|
||
|
{
|
||
|
sc.OpenFile(filename);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Printf("Could not find script lump '%s'\n", filename);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
parser = ZCCParseAlloc(malloc);
|
||
|
failed = false;
|
||
|
FILE *f = fopen("trace.txt", "w");
|
||
|
ZCCParseTrace(f, "");
|
||
|
while (sc.GetToken())
|
||
|
{
|
||
|
if (sc.TokenType == TK_StringConst)
|
||
|
{
|
||
|
value.String = strings.Get(sc.String, sc.StringLen);
|
||
|
tokentype = ZCC_STRCONST;
|
||
|
}
|
||
|
else if (sc.TokenType == TK_IntConst)
|
||
|
{
|
||
|
value.Int = sc.Number;
|
||
|
tokentype = ZCC_INTCONST;
|
||
|
}
|
||
|
else if (sc.TokenType == TK_FloatConst)
|
||
|
{
|
||
|
value.Float = sc.Float;
|
||
|
tokentype = ZCC_FLOATCONST;
|
||
|
}
|
||
|
else if (sc.TokenType == TK_Identifier)
|
||
|
{
|
||
|
value.Int = FName(sc.String);
|
||
|
tokentype = ZCC_IDENTIFIER;
|
||
|
}
|
||
|
else if (sc.TokenType == TK_NonWhitespace)
|
||
|
{
|
||
|
value.Int = FName(sc.String);
|
||
|
tokentype = ZCC_NWS;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SWORD *zcctoken = TokenMap.CheckKey(sc.TokenType);
|
||
|
if (zcctoken != NULL)
|
||
|
{
|
||
|
tokentype = *zcctoken;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sc.ScriptMessage("Unexpected token %s.\n", sc.TokenName(sc.TokenType).GetChars());
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
ZCCParse(parser, tokentype, value, &sc);
|
||
|
if (failed)
|
||
|
{
|
||
|
sc.ScriptMessage("Parse failed\n");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
value.Int = -1;
|
||
|
ZCCParse(parser, ZCC_EOF, value, &sc);
|
||
|
ZCCParse(parser, 0, value, &sc);
|
||
|
ZCCParseFree(parser, free);
|
||
|
if (f != NULL)
|
||
|
{
|
||
|
fclose(f);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CCMD(parse)
|
||
|
{
|
||
|
if (argv.argc() == 2)
|
||
|
{
|
||
|
DoParse(argv[1]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static FString ZCCTokenName(int terminal)
|
||
|
{
|
||
|
if (terminal == ZCC_EOF)
|
||
|
{
|
||
|
return "end of file";
|
||
|
}
|
||
|
int sc_token;
|
||
|
if (terminal > 0 && terminal < countof(BackTokenMap))
|
||
|
{
|
||
|
sc_token = BackTokenMap[terminal];
|
||
|
if (sc_token == 0)
|
||
|
{ // This token was not initialized. Whoops!
|
||
|
sc_token = -terminal;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ // This should never happen.
|
||
|
sc_token = -terminal;
|
||
|
}
|
||
|
return FScanner::TokenName(sc_token);
|
||
|
}
|