diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index f876fa49..918e82c6 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -53,6 +53,8 @@ #include "Modules/Vote.hpp" #include "Modules/Weapon.hpp" +#include "Modules/BotLib/lPrecomp.hpp" + namespace Components { bool Loader::Pregame = true; @@ -168,6 +170,8 @@ namespace Components Register(new GSC()); + Register(new lPrecomp()); + Pregame = false; // Make sure preDestroy is called when the game shuts down diff --git a/src/Components/Modules/AssetInterfaces/IFont_s.cpp b/src/Components/Modules/AssetInterfaces/IFont_s.cpp index 75619cd1..ed23d835 100644 --- a/src/Components/Modules/AssetInterfaces/IFont_s.cpp +++ b/src/Components/Modules/AssetInterfaces/IFont_s.cpp @@ -264,9 +264,9 @@ namespace Assets AssertSize(Game::Font_s, 24); AssertSize(Game::Glyph, 24); - Utils::Stream* buffer = builder->getBuffer(); - Game::Font_s* asset = header.font; - Game::Font_s* dest = buffer->dest(); + auto* buffer = builder->getBuffer(); + auto* asset = header.font; + auto* dest = buffer->dest(); buffer->save(asset); diff --git a/src/Components/Modules/BotLib/lPrecomp.cpp b/src/Components/Modules/BotLib/lPrecomp.cpp new file mode 100644 index 00000000..bb42b2d8 --- /dev/null +++ b/src/Components/Modules/BotLib/lPrecomp.cpp @@ -0,0 +1,155 @@ +#include +#include "lPrecomp.hpp" + +namespace Components +{ + // Two new directives! Refer to (https://en.cppreference.com/w/cpp/preprocessor/conditional) + Game::directive_s lPrecomp::directives[] = + { + {"if", Game::PC_Directive_if}, + {"ifdef", Game::PC_Directive_ifdef}, + {"ifndef", Game::PC_Directive_ifndef}, + {"elifdef", lPrecomp::PC_Directive_elifdef}, + {"elifndef", lPrecomp::PC_Directive_elifndef}, + {"elif", Game::PC_Directive_elif}, + {"else", Game::PC_Directive_else}, + {"endif", Game::PC_Directive_endif}, + {"include", Game::PC_Directive_include}, + {"define", Game::PC_Directive_define}, + {"undef", Game::PC_Directive_undef}, + {"line", Game::PC_Directive_line}, + {"error", Game::PC_Directive_error}, + {"pragma", Game::PC_Directive_pragma}, + {"eval", Game::PC_Directive_eval}, + {"evalfloat", Game::PC_Directive_evalfloat}, + {nullptr, nullptr} + }; + + int lPrecomp::PC_Directive_elif_def(Game::source_s* source, int* value, int type) + { + Game::token_s token; + int skip; + + if (!Game::PC_ReadLine(source, &token, false)) + { + Game::SourceError(source, "#elifdef without name"); + return false; + } + + if (token.type != TT_NAME) + { + Game::PC_UnreadSourceToken(source, &token); + Game::SourceError(source, "expected name after #elifdef, found %s", token.string); + return false; + } + + auto* d = Game::PC_FindHashedDefine(source->definehash, token.string); + *value = skip = (type == INDENT_IFDEF) == (d == nullptr); + return true; + } + + // #elifdef identifier is essentially equivalent to #elif defined identifier + int lPrecomp::PC_Directive_elifdef(Game::source_s* source) + { + int type; + int skip; + + Game::PC_PopIndent(source, &type, &skip); + if (!type || type == INDENT_ELSE) + { + Game::SourceError(source, "misplaced #elifdef"); + return false; + } + + int value; + if (PC_Directive_elif_def(source, &value, INDENT_IFDEF)) + { + if (skip == Game::SKIP_YES) + { + skip = value; + } + else + { + skip = Game::SKIP_ALL_ELIFS; + } + + Game::PC_PushIndent(source, INDENT_ELIF, skip); + return true; + } + + return false; + } + + // #elifndef identifier is essentially equivalent to #elif !defined identifier + int lPrecomp::PC_Directive_elifndef(Game::source_s* source) + { + int type; + int skip; + + Game::PC_PopIndent(source, &type, &skip); + if (!type || type == INDENT_ELSE) + { + Game::SourceError(source, "misplaced #elifndef"); + return false; + } + + int value; + if (PC_Directive_elif_def(source, &value, INDENT_IFNDEF)) + { + if (skip == Game::SKIP_YES) + { + skip = value; + } + else + { + skip = Game::SKIP_ALL_ELIFS; + } + + Game::PC_PushIndent(source, INDENT_ELIF, skip); + return true; + } + + return false; + } + + int lPrecomp::PC_ReadDirective(Game::source_s* source) + { + Game::token_s token; + + // Read the directive name + if (!Game::PC_ReadSourceToken(source, &token)) + { + Game::SourceError(source, "found # without name"); + return false; + } + + // Directive name must be on the same line + if (token.linescrossed > 0) + { + Game::PC_UnreadSourceToken(source, &token); + Game::SourceError(source, "found # at end of line"); + return false; + } + + // If it is a name + if (token.type == TT_NAME) + { + // Find the precompiler directive + for (auto i = 0; directives[i].name; ++i) + { + if (!std::strcmp(directives[i].name, token.string)) + { + return directives[i].func(source); + } + } + } + + Game::SourceError(source, "unknown precompiler directive %s", token.string); + return false; + } + + lPrecomp::lPrecomp() + { + Utils::Hook(0x4ACD19, PC_ReadDirective, HOOK_CALL).install()->quick(); + } +} diff --git a/src/Components/Modules/BotLib/lPrecomp.hpp b/src/Components/Modules/BotLib/lPrecomp.hpp new file mode 100644 index 00000000..a0939293 --- /dev/null +++ b/src/Components/Modules/BotLib/lPrecomp.hpp @@ -0,0 +1,46 @@ +#pragma once + +namespace Components +{ + class lPrecomp : public Component + { + public: + lPrecomp(); + + private: + enum + { + INDENT_IF = 1, + INDENT_ELSE = 2, + INDENT_ELIF = 4, + INDENT_IFDEF = 8, + INDENT_IFNDEF = 10, + }; + + enum + { + TT_STRING = 1, + TT_LITERAL = 2, + TT_NUMBER = 3, + TT_NAME = 4, + TT_PUNCTUATION = 5, + TT_DECIMAL = 8, + TT_HEX = 0x100, + TT_OCTAL = 0x200, + TT_BINARY = 0x400, + TT_FLOAT = 0x800, + TT_INTEGER = 0x1000, + TT_LONG = 0x2000, + TT_UNSIGNED = 0x4000, + }; + + static Game::directive_s directives[]; + + static int PC_Directive_elif_def(Game::source_s* source, int* value, int type); + + static int PC_Directive_elifdef(Game::source_s* source); + static int PC_Directive_elifndef(Game::source_s* source); + + static int PC_ReadDirective(Game::source_s* source); + }; +} diff --git a/src/Components/Modules/Menus.cpp b/src/Components/Modules/Menus.cpp index 7119a712..0328a1bd 100644 --- a/src/Components/Modules/Menus.cpp +++ b/src/Components/Modules/Menus.cpp @@ -55,14 +55,14 @@ namespace Components } // Reserve it, if yes - Game::sourceFiles[i] = reinterpret_cast(1); + Game::sourceFiles[i] = reinterpret_cast(1); return i; } - Game::script_t* Menus::LoadMenuScript(const std::string& name, const std::string& buffer) + Game::script_s* Menus::LoadMenuScript(const std::string& name, const std::string& buffer) { - auto* script = static_cast(Game::GetClearedMemory(sizeof(Game::script_t) + 1 + buffer.length())); + auto* script = static_cast(Game::GetClearedMemory(sizeof(Game::script_s) + 1 + buffer.length())); if (!script) return nullptr; strcpy_s(script->filename, sizeof(script->filename), name.data()); @@ -136,7 +136,7 @@ namespace Components return nullptr; } - Game::pc_token_t token; + Game::pc_token_s token; if (!Game::PC_ReadTokenHandle(handle, &token) || token.string[0] != '{') { allocator->free(menu->items); @@ -195,8 +195,8 @@ namespace Components if (!menuFile.exists()) return nullptr; - Game::pc_token_t token; - int handle = LoadMenuSource(menu, menuFile.getBuffer()); + Game::pc_token_s token; + const auto handle = LoadMenuSource(menu, menuFile.getBuffer()); if (IsValidSourceHandle(handle)) { @@ -259,7 +259,7 @@ namespace Components if (menuFile.exists()) { - Game::pc_token_t token; + Game::pc_token_s token; const auto handle = LoadMenuSource(menu, menuFile.getBuffer()); if (IsValidSourceHandle(handle)) @@ -744,11 +744,11 @@ namespace Components { if (menu->window.name == "connect"s) // Check if we're supposed to draw the loadscreen { - Game::menuDef_t* originalConnect = AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_MENU, "connect").menu; + const auto* originalConnect = AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_MENU, "connect").menu; if (originalConnect == menu) // Check if we draw the original loadscreen { - if (MenuList.find("connect") != Menus::MenuList.end()) // Check if we have a custom loadscreen, to prevent drawing the original one on top + if (MenuList.contains("connect")) // Check if we have a custom load screen, to prevent drawing the original one on top { return false; } @@ -801,8 +801,8 @@ namespace Components if (Dedicated::IsEnabled()) return; // Intercept asset finding - AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_MENU, MenuFindHook); - AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_MENULIST, MenuListFindHook); + AssetHandler::OnFind(Game::ASSET_TYPE_MENU, MenuFindHook); + AssetHandler::OnFind(Game::ASSET_TYPE_MENULIST, MenuListFindHook); // Don't open connect menu // Utils::Hook::Nop(0x428E48, 5); diff --git a/src/Components/Modules/Menus.hpp b/src/Components/Modules/Menus.hpp index ecf7afdd..793cc817 100644 --- a/src/Components/Modules/Menus.hpp +++ b/src/Components/Modules/Menus.hpp @@ -31,7 +31,7 @@ namespace Components static void SafeMergeMenus(std::vector>* menus, std::vector> newMenus); - static Game::script_t* LoadMenuScript(const std::string& name, const std::string& buffer); + static Game::script_s* LoadMenuScript(const std::string& name, const std::string& buffer); static int LoadMenuSource(const std::string& name, const std::string& buffer); static int ReserveSourceHandle(); diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index c8a1d56f..68de56bf 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -669,7 +669,7 @@ namespace Components } }); -#ifdef DEBUG +#ifdef DEBUG_MAT_LOG AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, const std::string& /*name*/, bool* /*restrict*/) { if (type == Game::XAssetType::ASSET_TYPE_GFXWORLD) diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index bd97f394..f30761a1 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -130,11 +130,6 @@ namespace Game Scr_AddSourceBuffer_t Scr_AddSourceBuffer = Scr_AddSourceBuffer_t(0x61ABC0); - PC_FreeDefine_t PC_FreeDefine = PC_FreeDefine_t(0x4E0D60); - PC_ReadToken_t PC_ReadToken = PC_ReadToken_t(0x4ACCD0); - PC_ReadTokenHandle_t PC_ReadTokenHandle = PC_ReadTokenHandle_t(0x4D2060); - PC_SourceError_t PC_SourceError = PC_SourceError_t(0x467A00); - Party_GetMaxPlayers_t Party_GetMaxPlayers = Party_GetMaxPlayers_t(0x4F5D60); PartyHost_CountMembers_t PartyHost_CountMembers = PartyHost_CountMembers_t(0x497330); PartyHost_GetMemberAddressBySlot_t PartyHost_GetMemberAddressBySlot = PartyHost_GetMemberAddressBySlot_t(0x44E100); @@ -267,7 +262,7 @@ namespace Game cmd_function_s** cmd_functions = reinterpret_cast(0x1AAC658); - source_t** sourceFiles = reinterpret_cast(0x7C4A98); + source_s** sourceFiles = reinterpret_cast(0x7C4A98); float* cgameFOVSensitivityScale = reinterpret_cast(0xB2F884); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 4081eafe..84c69d90 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -320,18 +320,6 @@ namespace Game typedef char*(*Scr_AddSourceBuffer_t)(const char* filename, const char* extFilename, const char* codePos, bool archive); extern Scr_AddSourceBuffer_t Scr_AddSourceBuffer; - typedef void(*PC_FreeDefine_t)(define_s* define); - extern PC_FreeDefine_t PC_FreeDefine; - - typedef int(*PC_ReadToken_t)(source_t*, token_t*); - extern PC_ReadToken_t PC_ReadToken; - - typedef int(*PC_ReadTokenHandle_t)(int handle, pc_token_s *pc_token); - extern PC_ReadTokenHandle_t PC_ReadTokenHandle; - - typedef void(*PC_SourceError_t)(int, const char*, ...); - extern PC_SourceError_t PC_SourceError; - typedef int(*Party_GetMaxPlayers_t)(PartyData* party); extern Party_GetMaxPlayers_t Party_GetMaxPlayers; @@ -611,7 +599,7 @@ namespace Game extern float* cgameFOVSensitivityScale; - extern source_t** sourceFiles; + extern source_s** sourceFiles; extern UiContext* uiContext; diff --git a/src/Game/Game.hpp b/src/Game/Game.hpp index fc7262f6..8ac32235 100644 --- a/src/Game/Game.hpp +++ b/src/Game/Game.hpp @@ -7,6 +7,7 @@ #include "FileSystem.hpp" #include "Functions.hpp" #include "Dvars.hpp" +#include "PreProcessor.hpp" #include "Script.hpp" #include "Server.hpp" #include "System.hpp" diff --git a/src/Game/PreProcessor.cpp b/src/Game/PreProcessor.cpp new file mode 100644 index 00000000..2f3c9e86 --- /dev/null +++ b/src/Game/PreProcessor.cpp @@ -0,0 +1,86 @@ +#include + +namespace Game +{ + PC_FreeDefine_t PC_FreeDefine = PC_FreeDefine_t(0x4E0D60); + PC_FindHashedDefine_t PC_FindHashedDefine = PC_FindHashedDefine_t(0x421E00); + PC_ReadToken_t PC_ReadToken = PC_ReadToken_t(0x4ACCD0); + PC_ReadTokenHandle_t PC_ReadTokenHandle = PC_ReadTokenHandle_t(0x4D2060); + PC_ReadSourceToken_t PC_ReadSourceToken = PC_ReadSourceToken_t(0x4B16F0); + PC_UnreadSourceToken_t PC_UnreadSourceToken = PC_UnreadSourceToken_t(0x47CD00); + PC_SourceError_t PC_SourceError = PC_SourceError_t(0x467A00); + + SourceError_t SourceError = SourceError_t(0x44C6C0); + + PC_Directive_if_def_t PC_Directive_if_def = PC_Directive_if_def_t(0x490A70); + + PC_Directive_if_t PC_Directive_if = PC_Directive_if_t(0x486220); + PC_Directive_ifdef_t PC_Directive_ifdef = PC_Directive_ifdef_t(0x4F4ED0); + PC_Directive_ifndef_t PC_Directive_ifndef = PC_Directive_ifndef_t(0x42EF10); + PC_Directive_elif_t PC_Directive_elif = PC_Directive_elif_t(0x41AAB0); + PC_Directive_else_t PC_Directive_else = PC_Directive_else_t(0x4B55B0); + PC_Directive_endif_t PC_Directive_endif = PC_Directive_endif_t(0x491920); + PC_Directive_include_t PC_Directive_include = PC_Directive_include_t(0x495310); + PC_Directive_define_t PC_Directive_define = PC_Directive_define_t(0x42E460); + PC_Directive_undef_t PC_Directive_undef = PC_Directive_undef_t(0x4E1820); + PC_Directive_line_t PC_Directive_line = PC_Directive_line_t(0x4FD8A0); + PC_Directive_error_t PC_Directive_error = PC_Directive_error_t(0x494AA0); + PC_Directive_pragma_t PC_Directive_pragma = PC_Directive_pragma_t(0x42C160); + PC_Directive_eval_t PC_Directive_eval = PC_Directive_eval_t(0x57DB20); + PC_Directive_evalfloat_t PC_Directive_evalfloat = PC_Directive_evalfloat_t(0x4BC2A0); + + __declspec(naked) int PC_ReadLine([[maybe_unused]] source_s* source, [[maybe_unused]] token_s* token, [[maybe_unused]] bool expandDefines) + { + static const DWORD PC_ReadLine_t = 0x57D830; + + __asm + { + push eax + pushad + + mov ebx, [esp + 0x24 + 0x4] // source + + push [esp + 0x24 + 0xC] // expandDefines + push [esp + 0x24 + 0xC] // token + call PC_ReadLine_t + add esp, 0x8 + + mov [esp + 0x20], eax + popad + pop eax + + ret + } + } + + void PC_PushIndent(source_s* source, int type_, int skip) + { + static const DWORD PC_PushIndent_t = 0x57D740; + + __asm + { + pushad + mov edi, skip + mov esi, source + push type_ + call PC_PushIndent_t + add esp, 0x4 + popad + } + } + + void PC_PopIndent(source_s* source, int* type_, int* skip) + { + static const DWORD PC_PopIndent_t = 0x57D780; + + __asm + { + pushad + mov edx, skip + mov eax, type_ + mov ecx, source + call PC_PopIndent_t + popad + } + } +} diff --git a/src/Game/PreProcessor.hpp b/src/Game/PreProcessor.hpp new file mode 100644 index 00000000..54f803bf --- /dev/null +++ b/src/Game/PreProcessor.hpp @@ -0,0 +1,77 @@ +#pragma once + +namespace Game +{ + typedef void(*PC_FreeDefine_t)(define_s* define); + extern PC_FreeDefine_t PC_FreeDefine; + + typedef define_s*(*PC_FindHashedDefine_t)(define_s** definehash, const char* name); + extern PC_FindHashedDefine_t PC_FindHashedDefine; + + typedef int(*PC_ReadToken_t)(source_s*, token_s*); + extern PC_ReadToken_t PC_ReadToken; + + typedef int(*PC_ReadTokenHandle_t)(int handle, pc_token_s* pc_token); + extern PC_ReadTokenHandle_t PC_ReadTokenHandle; + + typedef int(*PC_ReadSourceToken_t)(source_s* source, token_s* token); + extern PC_ReadSourceToken_t PC_ReadSourceToken; + + typedef int(*PC_UnreadSourceToken_t)(source_s* source, token_s* token); + extern PC_UnreadSourceToken_t PC_UnreadSourceToken; + + typedef void(*PC_SourceError_t)(int, const char*, ...); + extern PC_SourceError_t PC_SourceError; + + typedef void(*SourceError_t)(source_s* source, const char* str, ...); + extern SourceError_t SourceError; + + typedef int(*PC_Directive_if_def_t)(source_s* source, int type); + extern PC_Directive_if_def_t PC_Directive_if_def; + + typedef int(*PC_Directive_if_t)(source_s* source); + extern PC_Directive_if_t PC_Directive_if; + + typedef int(*PC_Directive_ifdef_t)(source_s* source); + extern PC_Directive_ifdef_t PC_Directive_ifdef; + + typedef int(*PC_Directive_ifndef_t)(source_s* source); + extern PC_Directive_ifndef_t PC_Directive_ifndef; + + typedef int(*PC_Directive_elif_t)(source_s* source); + extern PC_Directive_elif_t PC_Directive_elif; + + typedef int(*PC_Directive_else_t)(source_s* source); + extern PC_Directive_else_t PC_Directive_else; + + typedef int(*PC_Directive_endif_t)(source_s* source); + extern PC_Directive_endif_t PC_Directive_endif; + + typedef int(*PC_Directive_include_t)(source_s* source); + extern PC_Directive_include_t PC_Directive_include; + + typedef int(*PC_Directive_define_t)(source_s* source); + extern PC_Directive_define_t PC_Directive_define; + + typedef int(*PC_Directive_undef_t)(source_s* source); + extern PC_Directive_undef_t PC_Directive_undef; + + typedef int(*PC_Directive_line_t)(source_s* source); + extern PC_Directive_line_t PC_Directive_line; + + typedef int(*PC_Directive_error_t)(source_s* source); + extern PC_Directive_error_t PC_Directive_error; + + typedef int(*PC_Directive_pragma_t)(source_s* source); + extern PC_Directive_pragma_t PC_Directive_pragma; + + typedef int(*PC_Directive_eval_t)(source_s* source); + extern PC_Directive_eval_t PC_Directive_eval; + + typedef int(*PC_Directive_evalfloat_t)(source_s* source); + extern PC_Directive_evalfloat_t PC_Directive_evalfloat; + + extern int PC_ReadLine(source_s* source, token_s* token, bool expandDefines); + extern void PC_PushIndent(source_s* source, int type, int skip); + extern void PC_PopIndent(source_s* source, int* type, int* skip); +} diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 6a78bcb9..5297d176 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -7367,31 +7367,38 @@ namespace Game CModelSectionHeader sectionHeader[4]; }; - typedef struct punctuation_s + struct punctuation_s { char* p; //punctuation character(s) int n; //punctuation indication punctuation_s* next; //next punctuation - } punctuation_t; + }; #define MAX_TOKEN 1024 #define MAX_TOKENLENGTH 1024 - typedef struct token_s + enum parseSkip_t { - char string[MAX_TOKEN]; //available token - int type; //last read token type - int subtype; //last read token sub type - unsigned long int intvalue; //integer value - long double floatvalue; //floating point value - char* whitespace_p; //start of white space before token - char* endwhitespace_p; //start of white space before token - int line; //line the token was on - int linescrossed; //lines crossed in white space - token_s* next; //next token in chain - } token_t; + SKIP_NO = 0x0, + SKIP_YES = 0x1, + SKIP_ALL_ELIFS = 0x2, + }; - typedef struct script_s + struct token_s + { + char string[MAX_TOKEN]; // available token + int type; // last read token type + int subtype; // last read token sub type + unsigned long int intvalue; // integer value + long double floatvalue; // floating point value + char* whitespace_p; // start of white space before token + char* endwhitespace_p; // start of white space before token + int line; // line the token was on + int linescrossed; // lines crossed in white space + token_s* next; // next token in chain + }; + + struct script_s { char filename[64]; //file name of the script char* buffer; //buffer containing the script @@ -7405,54 +7412,60 @@ namespace Game int lastline; //line before reading token int tokenavailable; //set by UnreadLastToken int flags; //several script flags - punctuation_t* punctuations; //the punctuations used in the script - punctuation_t** punctuationtable; - token_t token; //available token + punctuation_s* punctuations; //the punctuations used in the script + punctuation_s** punctuationtable; + token_s token; //available token script_s* next; //next script in a chain - } script_t; + }; - typedef struct define_s + struct define_s { char* name; //define name int flags; //define flags int builtin; // > 0 if builtin define int numparms; //number of define parameters - token_t* parms; //define parameters - token_t* tokens; //macro tokens (possibly containing parm tokens) + token_s* parms; //define parameters + token_s* tokens; //macro tokens (possibly containing parm tokens) define_s* next; //next defined macro in a list define_s* hashnext; //next define in the hash chain - } define_t; + }; - typedef struct indent_s + struct indent_s { int type; //indent type int skip; //true if skipping current indent - script_t* script; //script the indent was in + script_s* script; //script the indent was in indent_s* next; //next indent on the indent stack - } indent_t; + }; - typedef struct source_s + struct source_s { char filename[MAX_QPATH]; //file name of the script char includepath[MAX_QPATH]; //path to include files - punctuation_t* punctuations; //punctuations to use - script_t* scriptstack; //stack with scripts of the source - token_t* tokens; //tokens to read first - define_t* defines; //list with macro definitions - define_t** definehash; //hash chain with defines - indent_t* indentstack; //stack with indents + punctuation_s* punctuations; //punctuations to use + script_s* scriptstack; //stack with scripts of the source + token_s* tokens; //tokens to read first + define_s* defines; //list with macro definitions + define_s** definehash; //hash chain with defines + indent_s* indentstack; //stack with indents int skip; // > 0 if skipping conditional code - token_t token; //last read token - } source_t; + token_s token; //last read token + }; - typedef struct pc_token_s + struct directive_s + { + const char* name; + int (*func)(source_s* source); + }; + + struct pc_token_s { int type; int subtype; int intvalue; float floatvalue; char string[MAX_TOKENLENGTH]; - } pc_token_t; + }; template struct KeywordHashEntry