749 lines
24 KiB
C++
749 lines
24 KiB
C++
|
#include "..\src\gs_language.h"
|
||
|
#include "..\src\foldhaus_memory.h"
|
||
|
#include "..\src\gs_string.h"
|
||
|
|
||
|
#include "gs_meta_error.h"
|
||
|
#include "gs_meta_lexer.h"
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
error_list GlobalErrorList = {};
|
||
|
|
||
|
PLATFORM_ALLOC(StdAlloc)
|
||
|
{
|
||
|
platform_memory_result Result = {};
|
||
|
Result.Base = (u8*)malloc(Size);
|
||
|
Result.Size = Size;
|
||
|
Result.Error = 0;
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
struct source_code_file
|
||
|
{
|
||
|
string Path;
|
||
|
s32 FileSize;
|
||
|
string Contents;
|
||
|
};
|
||
|
|
||
|
struct code_block_builder
|
||
|
{
|
||
|
memory_arena Data;
|
||
|
string String;
|
||
|
};
|
||
|
|
||
|
#define TYPE_TABLE_IDENTIFIER_MAX_LENGTH 128
|
||
|
#define TYPE_TABLE_BUFFER_MAX 64
|
||
|
struct type_table_buffer
|
||
|
{
|
||
|
u8* IdentifiersBackbuffer;
|
||
|
string* Identifiers;
|
||
|
s32* Sizes;
|
||
|
s32 Used;
|
||
|
s32 Max;
|
||
|
type_table_buffer* Next;
|
||
|
};
|
||
|
|
||
|
struct type_table
|
||
|
{
|
||
|
type_table_buffer* Head;
|
||
|
s32 TotalUsed;
|
||
|
s32 TotalMax;
|
||
|
};
|
||
|
|
||
|
internal void
|
||
|
AddTypeToTable (string Identifier, s32 Size, type_table* Table)
|
||
|
{
|
||
|
if (!Table->Head || Table->TotalUsed >= Table->TotalMax)
|
||
|
{
|
||
|
s32 NewHeadSize = sizeof(type_table_buffer) + ((sizeof(string) + TYPE_TABLE_IDENTIFIER_MAX_LENGTH + sizeof(s32)) * TYPE_TABLE_BUFFER_MAX);
|
||
|
u8* NewHeadBuffer = (u8*)malloc(NewHeadSize);
|
||
|
static_memory_arena Memory = CreateMemoryArena(NewHeadBuffer, NewHeadSize);
|
||
|
|
||
|
type_table_buffer* NewHead = PushStruct(&Memory, type_table_buffer);
|
||
|
NewHead->IdentifiersBackbuffer = PushArray(&Memory, u8, TYPE_TABLE_IDENTIFIER_MAX_LENGTH * TYPE_TABLE_BUFFER_MAX);
|
||
|
NewHead->Identifiers = PushArray(&Memory, string, TYPE_TABLE_BUFFER_MAX);
|
||
|
NewHead->Sizes = PushArray(&Memory, s32, TYPE_TABLE_BUFFER_MAX);
|
||
|
NewHead->Used = 0;
|
||
|
NewHead->Max = TYPE_TABLE_BUFFER_MAX;
|
||
|
NewHead->Next = 0;
|
||
|
|
||
|
// Init Strings
|
||
|
for (s32 i = 0; i < NewHead->Max; i++)
|
||
|
{
|
||
|
string* String = NewHead->Identifiers + i;
|
||
|
u8* Backbuffer = NewHead->IdentifiersBackbuffer + (TYPE_TABLE_IDENTIFIER_MAX_LENGTH * i);
|
||
|
InitializeString(String, (char*)Backbuffer, 0, TYPE_TABLE_IDENTIFIER_MAX_LENGTH);
|
||
|
}
|
||
|
|
||
|
if (Table->Head) { NewHead->Next = Table->Head; }
|
||
|
Table->Head = NewHead;
|
||
|
Table->TotalMax += NewHead->Max;
|
||
|
}
|
||
|
|
||
|
s32 TypeIndex = Table->Head->Used++;
|
||
|
string* DestIdentifier = Table->Head->Identifiers + TypeIndex;
|
||
|
|
||
|
CopyStringTo(Identifier, DestIdentifier);
|
||
|
Table->Head->Sizes[TypeIndex] = Size;
|
||
|
}
|
||
|
|
||
|
internal s32
|
||
|
GetSizeOfType (string Identifier, type_table* TypeTable)
|
||
|
{
|
||
|
s32 Result = -1;
|
||
|
|
||
|
type_table_buffer* Buffer = TypeTable->Head;
|
||
|
while (Buffer)
|
||
|
{
|
||
|
for (s32 i = 0; i < Buffer->Used; i++)
|
||
|
{
|
||
|
string StoredIdentifier = Buffer->Identifiers[i];
|
||
|
if (StringsEqual(StoredIdentifier, Identifier))
|
||
|
{
|
||
|
Result = Buffer->Sizes[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Result > 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Buffer = Buffer->Next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
internal code_block_builder
|
||
|
InitCodeBlockBuilder()
|
||
|
{
|
||
|
code_block_builder Result = {};
|
||
|
InitMemoryArena(&Result.Data, 0, 0, StdAlloc);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
CodeBlockPrint (code_block_builder* Block, string Source)
|
||
|
{
|
||
|
char* NewCode = PushArray(&Block->Data, char, Source.Length);
|
||
|
GSMemCopy(Source.Memory, NewCode, Source.Length);
|
||
|
if (Block->String.Memory == 0)
|
||
|
{
|
||
|
Block->String.Memory = NewCode;
|
||
|
}
|
||
|
Block->String.Max += Source.Length;
|
||
|
Block->String.Length += Source.Length;
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
WriteMemoryRegionToFile (memory_region* Region, FILE* WriteFile)
|
||
|
{
|
||
|
if (Region->PreviousRegion)
|
||
|
{
|
||
|
WriteMemoryRegionToFile(Region->PreviousRegion, WriteFile);
|
||
|
}
|
||
|
fwrite(Region->Base, 1, Region->Used, WriteFile);
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
WriteCodeBlockToFile(code_block_builder CodeBlock, FILE* WriteFile)
|
||
|
{
|
||
|
memory_region* Region = CodeBlock.Data.CurrentRegion;
|
||
|
WriteMemoryRegionToFile (Region, WriteFile);
|
||
|
}
|
||
|
|
||
|
internal s32
|
||
|
GetFileSize (char* FileName)
|
||
|
{
|
||
|
s32 Result = 0;
|
||
|
|
||
|
FILE* ReadFile = fopen(FileName, "r");
|
||
|
if (ReadFile)
|
||
|
{
|
||
|
fseek(ReadFile, 0, SEEK_END);
|
||
|
size_t FileSize = ftell(ReadFile);
|
||
|
fseek(ReadFile, 0, SEEK_SET);
|
||
|
|
||
|
Result = (s32)FileSize;
|
||
|
fclose(ReadFile);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
internal s32
|
||
|
ReadEntireFileAndNullTerminate (char* Filename, char* Memory, s32 MemorySize)
|
||
|
{
|
||
|
s32 LengthRead = 0;
|
||
|
|
||
|
FILE* ReadFile = fopen(Filename, "r");
|
||
|
if (ReadFile)
|
||
|
{
|
||
|
fseek(ReadFile, 0, SEEK_END);
|
||
|
size_t FileSize = ftell(ReadFile);
|
||
|
fseek(ReadFile, 0, SEEK_SET);
|
||
|
if (FileSize <= MemorySize)
|
||
|
{
|
||
|
size_t ReadSize = fread(Memory, 1, FileSize, ReadFile);
|
||
|
Memory[FileSize] = 0;
|
||
|
LengthRead = (s32)ReadSize + 1;
|
||
|
}
|
||
|
fclose(ReadFile);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LogError(&GlobalErrorList, "Could Not Read File: %s", Filename);
|
||
|
}
|
||
|
|
||
|
return LengthRead;
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
EatToNextLine (tokenizer* Tokenizer)
|
||
|
{
|
||
|
while (AtValidPosition(*Tokenizer) && !IsNewline(*Tokenizer->At))
|
||
|
{
|
||
|
Tokenizer->At++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct seen_node_struct
|
||
|
{
|
||
|
string Name;
|
||
|
s32 MembersSize;
|
||
|
s32 MembersCount;
|
||
|
seen_node_struct* Next;
|
||
|
};
|
||
|
|
||
|
internal seen_node_struct*
|
||
|
FindSeenStructInList (seen_node_struct* SeenStructList, string Name)
|
||
|
{
|
||
|
seen_node_struct* Result = 0;
|
||
|
|
||
|
seen_node_struct* Iter = SeenStructList;
|
||
|
while(Iter)
|
||
|
{
|
||
|
if (StringsEqual(Name, Iter->Name))
|
||
|
{
|
||
|
Result = Iter;
|
||
|
break;
|
||
|
}
|
||
|
Iter = Iter->Next;
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
ParseNodeStruct (token* NodeStruct, code_block_builder* NodeMembersBlock, seen_node_struct* SeenStruct, type_table* TypeTable)
|
||
|
{
|
||
|
token* OpenParen = NodeStruct->Next;
|
||
|
token* StructName = OpenParen->Next;
|
||
|
|
||
|
SeenStruct->Name = StructName->Text;
|
||
|
|
||
|
MakeStringBuffer(Buffer, 256);
|
||
|
|
||
|
PrintF(&Buffer, "node_struct_member MemberList_%.*s[] = {\n",
|
||
|
StructName->Text.Length, StructName->Text.Memory);
|
||
|
CodeBlockPrint(NodeMembersBlock, Buffer);
|
||
|
|
||
|
token* Token = StructName->Next;
|
||
|
while (Token->Type != Token_RightCurlyBracket)
|
||
|
{
|
||
|
if (Token->Type != Token_Identifier)
|
||
|
{
|
||
|
Token = Token->Next;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
b32 IsInput = false;
|
||
|
b32 IsOutput = false;
|
||
|
|
||
|
if (StringsEqual(MakeStringLiteral("NODE_IN"), Token->Text) ||
|
||
|
StringsEqual(MakeStringLiteral("NODE_COLOR_BUFFER_IN"), Token->Text))
|
||
|
{
|
||
|
IsInput = true;
|
||
|
}
|
||
|
else if (StringsEqual(MakeStringLiteral("NODE_OUT"), Token->Text) ||
|
||
|
StringsEqual(MakeStringLiteral("NODE_COLOR_BUFFER_OUT"), Token->Text))
|
||
|
{
|
||
|
IsOutput = true;
|
||
|
}
|
||
|
else if (StringsEqual(MakeStringLiteral("NODE_COLOR_BUFFER_INOUT"), Token->Text))
|
||
|
{
|
||
|
IsInput = true;
|
||
|
IsOutput = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SeenStruct->MembersSize += GetSizeOfType(Token->Text, TypeTable);
|
||
|
Token = GetNextTokenOfType(Token, Token_Semicolon)->Next;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
token* TypeToken = GetNextTokenOfType(Token, Token_Identifier);
|
||
|
token* NameToken = GetNextTokenOfType(TypeToken, Token_Identifier);
|
||
|
|
||
|
MakeStringBuffer(TypeBuffer, 64);
|
||
|
MakeStringBuffer(NameBuffer, 64);
|
||
|
|
||
|
CopyStringTo(TypeToken->Text, &TypeBuffer);
|
||
|
CopyStringTo(NameToken->Text, &NameBuffer);
|
||
|
|
||
|
if (StringsEqual(MakeStringLiteral("s32"), TypeToken->Text))
|
||
|
{
|
||
|
SeenStruct->MembersSize += sizeof(s32);
|
||
|
}
|
||
|
else if (StringsEqual(MakeStringLiteral("r32"), TypeToken->Text))
|
||
|
{
|
||
|
SeenStruct->MembersSize += sizeof(r32);
|
||
|
}
|
||
|
else if (StringsEqual(MakeStringLiteral("v4"), TypeToken->Text))
|
||
|
{
|
||
|
SeenStruct->MembersSize += sizeof(r32) * 4;
|
||
|
}
|
||
|
else if (StringsEqual(MakeStringLiteral("NODE_COLOR_BUFFER_INOUT"), Token->Text))
|
||
|
{
|
||
|
SeenStruct->MembersSize += sizeof(u32*) + sizeof(u32*) + sizeof(s32);
|
||
|
|
||
|
CopyStringTo(MakeStringLiteral("NODE_COLOR_BUFFER"), &TypeBuffer);
|
||
|
CopyStringTo(MakeStringLiteral("LEDs"), &NameBuffer);
|
||
|
}
|
||
|
else if (StringsEqual(MakeStringLiteral("NODE_COLOR_BUFFER_IN"), Token->Text) ||
|
||
|
StringsEqual(MakeStringLiteral("NODE_COLOR_BUFFER_OUT"), Token->Text))
|
||
|
{
|
||
|
SeenStruct->MembersSize += sizeof(u32*) + sizeof(u32*) + sizeof(s32);
|
||
|
|
||
|
CopyStringTo(MakeStringLiteral("NODE_COLOR_BUFFER"), &TypeBuffer);
|
||
|
|
||
|
CopyStringTo(TypeToken->Text, &NameBuffer);
|
||
|
ConcatString(MakeStringLiteral("LEDs"), &NameBuffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PrintF(&Buffer, "Invalid Type Specified for %.*s %.*s\n",
|
||
|
TypeToken->Text.Length, TypeToken->Text.Memory,
|
||
|
NameToken->Text.Length, NameToken->Text.Memory);
|
||
|
NullTerminate(&Buffer);
|
||
|
printf(Buffer.Memory);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
PrintF(&Buffer, "{ MemberType_%.*s, \"%.*s\", (u64)&((%.*s*)0)->%.*s, %s %s %s},\n",
|
||
|
TypeBuffer.Length, TypeBuffer.Memory,
|
||
|
NameBuffer.Length, NameBuffer.Memory,
|
||
|
StructName->Text.Length, StructName->Text.Memory,
|
||
|
NameBuffer.Length, NameBuffer.Memory,
|
||
|
(IsInput ? "IsInputMember" : ""),
|
||
|
(IsInput && IsOutput ? "|" : ""),
|
||
|
(IsOutput ? "IsOutputMember" : ""));
|
||
|
CodeBlockPrint(NodeMembersBlock, Buffer);
|
||
|
|
||
|
SeenStruct->MembersCount++;
|
||
|
Token = GetNextTokenOfType(Token, Token_Semicolon)->Next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CodeBlockPrint(NodeMembersBlock, MakeStringLiteral("};\n\n"));
|
||
|
}
|
||
|
|
||
|
internal s32
|
||
|
GetTypedefSize (token* Token)
|
||
|
{
|
||
|
s32 Size = 0;
|
||
|
|
||
|
token* LookingAt = Token->Next;
|
||
|
|
||
|
if (StringsEqual(LookingAt->Text, MakeStringLiteral("unsigned")) ||
|
||
|
StringsEqual(LookingAt->Text, MakeStringLiteral("signed")))
|
||
|
{
|
||
|
LookingAt = LookingAt->Next;
|
||
|
}
|
||
|
|
||
|
s32 Level = 1;
|
||
|
if (StringsEqual(LookingAt->Text, MakeStringLiteral("short")))
|
||
|
{
|
||
|
Level = -1;
|
||
|
LookingAt = LookingAt->Next;
|
||
|
}
|
||
|
while (StringsEqual(LookingAt->Text, MakeStringLiteral("long")))
|
||
|
{
|
||
|
Level= 2.f;
|
||
|
LookingAt = LookingAt->Next;
|
||
|
}
|
||
|
|
||
|
if (StringsEqual(LookingAt->Text, MakeStringLiteral("char")))
|
||
|
{
|
||
|
Size = 1;
|
||
|
}
|
||
|
else if (StringsEqual(LookingAt->Text, MakeStringLiteral("int")))
|
||
|
{
|
||
|
switch (Level)
|
||
|
{
|
||
|
case -1: { Size = 2; } break;
|
||
|
case 1: { Size = 4; } break;
|
||
|
case 2: { Size = 8; } break;
|
||
|
InvalidDefaultCase;
|
||
|
}
|
||
|
}
|
||
|
else if (StringsEqual(LookingAt->Text, MakeStringLiteral("float")))
|
||
|
{
|
||
|
Size = 4;
|
||
|
}
|
||
|
else if (StringsEqual(LookingAt->Text, MakeStringLiteral("double")))
|
||
|
{
|
||
|
Size = 8;
|
||
|
}
|
||
|
else if (StringsEqual(LookingAt->Text, MakeStringLiteral("bool")))
|
||
|
{
|
||
|
Size = 1;
|
||
|
}
|
||
|
else if (StringsEqual(LookingAt->Text, MakeStringLiteral("void")))
|
||
|
{
|
||
|
LogError(&GlobalErrorList, "void type Not Handled");
|
||
|
}
|
||
|
|
||
|
return Size;
|
||
|
}
|
||
|
|
||
|
internal string
|
||
|
GetTypedefIdentifier (token* Token)
|
||
|
{
|
||
|
string Identifier = {};
|
||
|
|
||
|
token* PreviousToken = Token;
|
||
|
token* LookingAt = Token->Next;
|
||
|
while (LookingAt->Type != Token_Semicolon)
|
||
|
{
|
||
|
PreviousToken = LookingAt;
|
||
|
LookingAt = LookingAt->Next;
|
||
|
}
|
||
|
|
||
|
if (PreviousToken->Type == Token_Identifier)
|
||
|
{
|
||
|
Identifier = PreviousToken->Text;
|
||
|
}
|
||
|
|
||
|
return Identifier;
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
ParseTypedefs (token* Tokens, type_table* TypeTable)
|
||
|
{
|
||
|
string TypedefIdentifier = MakeStringLiteral("typedef");
|
||
|
string StructIdentifier = MakeStringLiteral("struct");
|
||
|
|
||
|
token* Token = Tokens;
|
||
|
while (Token)
|
||
|
{
|
||
|
if (StringsEqual(Token->Text, TypedefIdentifier))
|
||
|
{
|
||
|
if (!StringsEqual(Token->Next->Text, StructIdentifier))
|
||
|
{
|
||
|
s32 Size = GetTypedefSize(Token);
|
||
|
string Identifier = GetTypedefIdentifier(Token);
|
||
|
if (Size > 0) // NOTE(Peter): This is just to skip over typedefs of structs and function pointers
|
||
|
{
|
||
|
AddTypeToTable(Identifier, Size, TypeTable);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
Token = Token->Next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void
|
||
|
ParseNodeProc (token* NodeProc,
|
||
|
code_block_builder* NodeTypeBlock,
|
||
|
code_block_builder* NodeSpecificationsBlock,
|
||
|
code_block_builder* CallNodeProcBlock,
|
||
|
seen_node_struct* SeenStructs,
|
||
|
b32 IsPatternProc)
|
||
|
{
|
||
|
token* ProcName = GetNextTokenOfType(NodeProc, Token_Identifier);
|
||
|
token* ProcArg = GetNextTokenOfType(ProcName, Token_Identifier);
|
||
|
|
||
|
MakeStringBuffer(Buffer, 256);
|
||
|
|
||
|
// Types Enum
|
||
|
PrintF(&Buffer, "NodeType_%.*s,\n", ProcName->Text.Length, ProcName->Text.Memory);
|
||
|
CodeBlockPrint(NodeTypeBlock, Buffer);
|
||
|
|
||
|
// Node Specification
|
||
|
string ArgName = ProcArg->Text;
|
||
|
seen_node_struct* ArgStruct = FindSeenStructInList(SeenStructs, ArgName);
|
||
|
|
||
|
PrintF(&Buffer, "{ NodeType_%.*s, \"%.*s\", %d, MemberList_%.*s, %d, %d, %.*s},\n",
|
||
|
ProcName->Text.Length, ProcName->Text.Memory,
|
||
|
ProcName->Text.Length, ProcName->Text.Memory,
|
||
|
ProcName->Text.Length,
|
||
|
ProcArg->Text.Length, ProcArg->Text.Memory,
|
||
|
ArgStruct->MembersSize,
|
||
|
ArgStruct->MembersCount,
|
||
|
(IsPatternProc ? 4 : 5), (IsPatternProc ? "true" : "false"));
|
||
|
CodeBlockPrint(NodeSpecificationsBlock, Buffer);
|
||
|
|
||
|
// Call Node Proc
|
||
|
if (IsPatternProc)
|
||
|
{
|
||
|
LogError(&GlobalErrorList, "Node Proc is no longer supported");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PrintF(&Buffer, "case NodeType_%.*s: { %.*s((%.*s*)Data, DeltaTime); } break; \n",
|
||
|
ProcName->Text.Length, ProcName->Text.Memory,
|
||
|
ProcName->Text.Length, ProcName->Text.Memory,
|
||
|
ProcArg->Text.Length, ProcArg->Text.Memory);
|
||
|
CodeBlockPrint(CallNodeProcBlock, Buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal s32
|
||
|
PreprocessStructsAndProcs (string StructSearchString, string ProcSearchString, b32 FindingPatterns,
|
||
|
token* Tokens,
|
||
|
code_block_builder* NodeMembersBlock,
|
||
|
code_block_builder* NodeTypeBlock,
|
||
|
code_block_builder* NodeSpecificationsBlock,
|
||
|
code_block_builder* CallNodeProcBlock,
|
||
|
type_table* TypeTable)
|
||
|
{
|
||
|
// Node Structs
|
||
|
seen_node_struct* Structs = 0;
|
||
|
|
||
|
token_selection_spec NodeStructSpec = {};
|
||
|
NodeStructSpec.MatchText = true;
|
||
|
NodeStructSpec.Text = StructSearchString;
|
||
|
|
||
|
token* NodeStructToken = FindNextMatchingToken(Tokens, NodeStructSpec);
|
||
|
while (NodeStructToken)
|
||
|
{
|
||
|
seen_node_struct* SeenStruct = (seen_node_struct*)malloc(sizeof(seen_node_struct));
|
||
|
*SeenStruct = {};
|
||
|
|
||
|
if (Structs != 0)
|
||
|
{
|
||
|
SeenStruct->Next = Structs;
|
||
|
}
|
||
|
Structs = SeenStruct;
|
||
|
|
||
|
ParseNodeStruct(NodeStructToken, NodeMembersBlock, SeenStruct, TypeTable);
|
||
|
NodeStructToken = FindNextMatchingToken(NodeStructToken->Next, NodeStructSpec);
|
||
|
}
|
||
|
|
||
|
// Node Procs
|
||
|
token_selection_spec NodeProcSpec = {};
|
||
|
NodeProcSpec.MatchText = true;
|
||
|
NodeProcSpec.Text = ProcSearchString;
|
||
|
|
||
|
token* NodeProcToken = FindNextMatchingToken(Tokens, NodeProcSpec);
|
||
|
s32 NodeProcCount = 0;
|
||
|
while (NodeProcToken)
|
||
|
{
|
||
|
NodeProcCount++;
|
||
|
ParseNodeProc(NodeProcToken, NodeTypeBlock, NodeSpecificationsBlock, CallNodeProcBlock, Structs, FindingPatterns);
|
||
|
NodeProcToken = FindNextMatchingToken(NodeProcToken->Next, NodeProcSpec);
|
||
|
}
|
||
|
return NodeProcCount;
|
||
|
}
|
||
|
|
||
|
// Step 1: Get All Tokens, for every file
|
||
|
// Step 2: Identify all preprocessor directives
|
||
|
// Step 3: Apply Preprocessor Directives && Generate Code
|
||
|
// Step 4: Write out new files
|
||
|
// Step 5: Compile
|
||
|
int main(int ArgCount, char** ArgV)
|
||
|
{
|
||
|
if (ArgCount <= 1)
|
||
|
{
|
||
|
printf("Please supply at least one source directory to analyze.\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
type_table TypeTable = {};
|
||
|
|
||
|
memory_arena SourceFileArena = {};
|
||
|
InitMemoryArena(&SourceFileArena, 0, 0, StdAlloc);
|
||
|
|
||
|
code_block_builder NodeTypeBlock = InitCodeBlockBuilder();
|
||
|
CodeBlockPrint(&NodeTypeBlock, MakeStringLiteral("enum node_type\n{\nNodeType_OutputNode,\n"));
|
||
|
|
||
|
code_block_builder NodeMembersBlock = InitCodeBlockBuilder();
|
||
|
|
||
|
code_block_builder NodeSpecificationsBlock = InitCodeBlockBuilder();
|
||
|
CodeBlockPrint(&NodeSpecificationsBlock, MakeStringLiteral("node_specification NodeSpecifications[] = {\n"));
|
||
|
|
||
|
code_block_builder CallNodeProcBlock = InitCodeBlockBuilder();
|
||
|
CodeBlockPrint(&CallNodeProcBlock, MakeStringLiteral("internal void CallNodeProc(interface_node* Node, u8* Data, led* LEDs, s32 LEDsCount, r32 DeltaTime)\n{\n"));
|
||
|
CodeBlockPrint(&CallNodeProcBlock, MakeStringLiteral("switch (Node->Type)\n{\n"));
|
||
|
|
||
|
// Build Search Paths Array
|
||
|
s32 SearchPathsCount = 1; //ArgCount - 1;
|
||
|
string* SearchPaths = PushArray(&SourceFileArena, string, SearchPathsCount);
|
||
|
for (s32 InputPath = 0; InputPath < SearchPathsCount; InputPath++)
|
||
|
{
|
||
|
string* SearchPathString = SearchPaths + InputPath;
|
||
|
InitializeEmptyString(SearchPathString, PushArray(&SourceFileArena, char, MAX_PATH), MAX_PATH);
|
||
|
|
||
|
// NOTE(Peter): Adding one to skip the default argument which is the name of the application currently running
|
||
|
CopyCharArrayToString(ArgV[InputPath + 1], SearchPathString);
|
||
|
ConcatCharArrayToString("*", SearchPathString);
|
||
|
NullTerminate(SearchPathString);
|
||
|
}
|
||
|
|
||
|
// Total Source Files Count
|
||
|
s32 SourceFileCount = 0;
|
||
|
for (s32 SearchPath = 0; SearchPath < SearchPathsCount; SearchPath++)
|
||
|
{
|
||
|
string* SearchPathString = SearchPaths + SearchPath;
|
||
|
|
||
|
WIN32_FIND_DATA FindFileData;
|
||
|
HANDLE CurrentFile = FindFirstFile(SearchPathString->Memory, &FindFileData);
|
||
|
|
||
|
if (CurrentFile == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
printf("Invalid File Handle\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
do {
|
||
|
if (FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
|
||
|
{
|
||
|
continue; // TODO(Peter): Recurse?
|
||
|
}
|
||
|
SourceFileCount++;
|
||
|
} while (FindNextFile(CurrentFile, &FindFileData));
|
||
|
}
|
||
|
|
||
|
// Allocate Source File Array
|
||
|
source_code_file* SourceFiles = PushArray(&SourceFileArena, source_code_file, SourceFileCount);
|
||
|
|
||
|
// Populate Source File Array
|
||
|
s32 SourceFilesUsed = 0;
|
||
|
for (s32 SearchPath = 0; SearchPath < SearchPathsCount; SearchPath++)
|
||
|
{
|
||
|
string* SearchPathString = SearchPaths + SearchPath;
|
||
|
|
||
|
WIN32_FIND_DATA FindFileData;
|
||
|
HANDLE CurrentFile = FindFirstFile(SearchPathString->Memory, &FindFileData);
|
||
|
|
||
|
do {
|
||
|
if (FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
|
||
|
{
|
||
|
continue; // TODO(Peter): Recurse?
|
||
|
}
|
||
|
|
||
|
string FileName = MakeString(FindFileData.cFileName);
|
||
|
string FileExtension = Substring(FileName, LastIndexOfChar(FileName, '.'));
|
||
|
|
||
|
if (StringsEqual(FileExtension, MakeStringLiteral("cpp")) ||
|
||
|
StringsEqual(FileExtension, MakeStringLiteral("h")))
|
||
|
{
|
||
|
source_code_file* File = SourceFiles + SourceFilesUsed++;
|
||
|
|
||
|
PushString(&File->Path, &SourceFileArena, SearchPathString->Length + CharArrayLength(FindFileData.cFileName));
|
||
|
CopyStringTo(Substring(*SearchPathString, 0, SearchPathString->Length - 2), &File->Path);
|
||
|
ConcatCharArrayToString(FindFileData.cFileName, &File->Path);
|
||
|
NullTerminate(&File->Path);
|
||
|
|
||
|
File->FileSize = FindFileData.nFileSizeLow;
|
||
|
ErrorAssert(FindFileData.nFileSizeHigh == 0, &GlobalErrorList, "File Too Big. Peter needs to handle this. File: %.*s", FileName.Length, FileName.Memory);
|
||
|
|
||
|
PushString(&File->Contents, &SourceFileArena, File->FileSize + 1);
|
||
|
File->Contents.Length = ReadEntireFileAndNullTerminate(File->Path.Memory, File->Contents.Memory, File->Contents.Max);
|
||
|
}
|
||
|
|
||
|
} while (FindNextFile(CurrentFile, &FindFileData));
|
||
|
}
|
||
|
|
||
|
// Tokenize All The Files
|
||
|
s32 TokensCount = 0;
|
||
|
token* Tokens = 0;
|
||
|
token** FileStartTokens = PushArray(&SourceFileArena, token*, SourceFilesUsed);
|
||
|
for (s32 SourceFileIdx = 0; SourceFileIdx < SourceFilesUsed; SourceFileIdx++)
|
||
|
{
|
||
|
source_code_file* File = SourceFiles + SourceFileIdx;
|
||
|
|
||
|
tokenizer Tokenizer = {};
|
||
|
Tokenizer.At = File->Contents.Memory;
|
||
|
Tokenizer.Memory = File->Contents.Memory;
|
||
|
Tokenizer.MemoryLength = File->Contents.Max;
|
||
|
|
||
|
token* LastToken = 0;
|
||
|
while(AtValidPosition(Tokenizer))
|
||
|
{
|
||
|
token* Token = PushStruct(&SourceFileArena, token);
|
||
|
if (Tokens == 0)
|
||
|
{
|
||
|
Tokens = Token;
|
||
|
}
|
||
|
|
||
|
TokensCount++;
|
||
|
*Token = GetNextToken(&Tokenizer);
|
||
|
|
||
|
Token->Next = 0;
|
||
|
if (LastToken) {
|
||
|
LastToken->Next = Token;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FileStartTokens[SourceFileIdx] = Token;
|
||
|
}
|
||
|
LastToken = Token;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (s32 SourceFile = 0; SourceFile < SourceFilesUsed; SourceFile++)
|
||
|
{
|
||
|
ParseTypedefs (FileStartTokens[SourceFile], &TypeTable);
|
||
|
}
|
||
|
|
||
|
s32 NodeProcCount = 0;
|
||
|
|
||
|
|
||
|
for (s32 SourceFileIdx = 0; SourceFileIdx < SourceFilesUsed; SourceFileIdx++)
|
||
|
{
|
||
|
token* FileStartToken = FileStartTokens[SourceFileIdx];
|
||
|
NodeProcCount += PreprocessStructsAndProcs (MakeStringLiteral("NODE_STRUCT"),
|
||
|
MakeStringLiteral("NODE_PROC"),
|
||
|
false,
|
||
|
FileStartToken, &NodeMembersBlock, &NodeTypeBlock, &NodeSpecificationsBlock, &CallNodeProcBlock,
|
||
|
&TypeTable);
|
||
|
NodeProcCount += PreprocessStructsAndProcs (MakeStringLiteral("NODE_PATTERN_STRUCT"),
|
||
|
MakeStringLiteral("NODE_PATTERN_PROC"),
|
||
|
true,
|
||
|
FileStartToken, &NodeMembersBlock, &NodeTypeBlock, &NodeSpecificationsBlock, &CallNodeProcBlock,
|
||
|
&TypeTable);
|
||
|
}
|
||
|
|
||
|
MakeStringBuffer(Buffer, 256);
|
||
|
|
||
|
// Close Types Block - overwrite the last comma and '\' newline character with newlines.
|
||
|
CodeBlockPrint(&NodeTypeBlock, MakeStringLiteral("NodeType_Count,\n};\n\n"));
|
||
|
|
||
|
// Close Specifications Block
|
||
|
CodeBlockPrint(&NodeSpecificationsBlock, MakeStringLiteral("};\n"));
|
||
|
PrintF(&Buffer, "s32 NodeSpecificationsCount = %d;\n\n", NodeProcCount);
|
||
|
CodeBlockPrint(&NodeSpecificationsBlock, Buffer);
|
||
|
|
||
|
// Close Call Node Proc Block
|
||
|
CodeBlockPrint(&CallNodeProcBlock, MakeStringLiteral("}\n}\n"));
|
||
|
|
||
|
FILE* NodeGeneratedCPP = fopen("C:\\projects\\foldhaus\\src\\generated\\foldhaus_nodes_generated.cpp", "w");
|
||
|
if (NodeGeneratedCPP)
|
||
|
{
|
||
|
WriteCodeBlockToFile(NodeTypeBlock, NodeGeneratedCPP);
|
||
|
WriteCodeBlockToFile(NodeMembersBlock, NodeGeneratedCPP);
|
||
|
WriteCodeBlockToFile(NodeSpecificationsBlock, NodeGeneratedCPP);
|
||
|
WriteCodeBlockToFile(CallNodeProcBlock, NodeGeneratedCPP);
|
||
|
fclose(NodeGeneratedCPP);
|
||
|
}
|
||
|
|
||
|
PrintErrorList(GlobalErrorList);
|
||
|
return 0;
|
||
|
}
|