From 85af2d80c35d060cc003302115c7a8975b545afe Mon Sep 17 00:00:00 2001 From: Raymaekers Luca Date: Sat, 29 Mar 2025 14:24:07 +0100 Subject: Code compression; Added error stack --- build.sh | 2 + build/metac | Bin 28496 -> 38856 bytes examples/table.c | 2 +- examples/table.meta | Bin 15488 -> 0 bytes examples/table.meta.c | 9 +- examples/wrong.c | 13 ++ source/build.bat | 7 + source/build.sh | 6 + source/meta.c | 549 ++++++++++++++++++++++++++++++++------------------ 9 files changed, 386 insertions(+), 202 deletions(-) create mode 100755 build.sh delete mode 100755 examples/table.meta create mode 100644 examples/wrong.c create mode 100644 source/build.bat create mode 100755 source/build.sh diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..7502034 --- /dev/null +++ b/build.sh @@ -0,0 +1,2 @@ +#!/bin/sh +gcc -ggdb -o errors errors.c diff --git a/build/metac b/build/metac index d57a130..368dbf9 100755 Binary files a/build/metac and b/build/metac differ diff --git a/examples/table.c b/examples/table.c index 63edb16..715d68c 100644 --- a/examples/table.c +++ b/examples/table.c @@ -3,7 +3,7 @@ @table(name, str) MyEnumTable { { A "A" } - { B "Beau Gosse" } + { B "Beau gosse" } { C "C" } } diff --git a/examples/table.meta b/examples/table.meta deleted file mode 100755 index 2976f54..0000000 Binary files a/examples/table.meta and /dev/null differ diff --git a/examples/table.meta.c b/examples/table.meta.c index 5534457..2ab9fd6 100644 --- a/examples/table.meta.c +++ b/examples/table.meta.c @@ -3,19 +3,22 @@ typedef enum { - MyEnum_A, // "A" MyEnum_B, // "Beau Gosse" MyEnum_C, // "C" MyEnum_Count + MyEnum_A, + MyEnum_B, + MyEnum_C, + MyEnum_Count } MyEnum; char *StringTable[MyEnum_Count] = { "A", - "Beau Gosse", + "Beau gosse", "C", }; int main(int Argc, char *Args[]) { - printf("%s\n", StringTable[MyEnum_B]); + printf("@: %s\n", StringTable[MyEnum_B]); return 0; } diff --git a/examples/wrong.c b/examples/wrong.c new file mode 100644 index 0000000..7da07f4 --- /dev/null +++ b/examples/wrong.c @@ -0,0 +1,13 @@ +#include + +@table(name, str) MyEnumTable +{ + { A "A" } + { B "Beau gosse" } + { C "C" } +} + +char *StringTable[MyEnum_Count] = { + @expand(MyEnumTabl a + ` $(b.lolol),` +}; \ No newline at end of file diff --git a/source/build.bat b/source/build.bat new file mode 100644 index 0000000..d17d1be --- /dev/null +++ b/source/build.bat @@ -0,0 +1,7 @@ +@echo off + +set opts=-FC -GR- -EHa- -nologo -Zi +set code=%cd% +pushd build +cl %opts% %code%\build\mteac -Febuild\metac +popd diff --git a/source/build.sh b/source/build.sh new file mode 100755 index 0000000..e21a173 --- /dev/null +++ b/source/build.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -e + +ScriptDir="$(dirname "$(readlink -f "$0")")" + +gcc -ggdb -o "$ScriptDir"/../build/metac "$ScriptDir"/meta.c diff --git a/source/meta.c b/source/meta.c index b69cfca..438c9bf 100644 --- a/source/meta.c +++ b/source/meta.c @@ -1,32 +1,16 @@ -/* +/* C preprocessor that provides meta functionality. To-Do's - - [ ] Error messages instead of asserts - - Show byte offset to show where the errors happens in the file and highlight that. - Idea - - Print error - - exit - Problem what if inside function - - global variable error - When pushing new error do not overwrite - Since we have only fatal errors we could say there is only one global variable with the error contents. - - Idea - - Error stack - - Push new errors on the stack along with a message - - Error location (byte offset in file) - -> Maybe pretty print this - - Error kinds (optional, first only fatal errors) - - After parse check if there are any (fatal) errors - - - [ ] Expanding over multiple tables + - [x] Error messages instead of asserts +- [ ] Compress the code + - [ ] Use the real metadesk +- [ ] Expanding over multiple tables - [ ] Syntactic sugar to specify array of single values ? - [ ] Preserve indent when expansion is on a new line - - [ ] Compress the code + - [ ] Get rid of standard library, create an OS layer instead */ - #include #include #include @@ -35,6 +19,7 @@ #include #include #include +#include typedef uint8_t u8; typedef uint16_t u16; @@ -44,14 +29,16 @@ typedef int8_t i8; typedef int16_t i16; typedef int32_t i32; typedef int64_t i64; +typedef u32 b32; #define true 1 #define false 0 ///~ Misc macro's ////////////////////////////////////// -#define Assert(expr) if (!(expr)) { raise(SIGTRAP); } -#define Kilobyte(byte) byte * 1024L -#define Megabyte(byte) Kilobyte(byte) * 1024L -#define Gigabyte(byte) Megabyte(byte) * 1024L +#define Assert(Expression) if (!(Expression)) { raise(SIGTRAP); } +#define Kilobyte(Bytes) Bytes * 1024LL +#define Megabyte(Bytes) Kilobyte(Bytes) * 1024 +#define Gigabyte(Bytes) Megabyte(Bytes) * 1024 +#define Terabyte(Bytes) Gigabyte(Bytes) * 1024 #define internal static #define global_variable static #define local_persist static @@ -59,38 +46,38 @@ typedef int64_t i64; ///~ String //////////////////////////////////////////// typedef struct { - char *Memory; + char *Data; u64 Size; } s8; -#define S8_LIT(str) str, sizeof(str) - 1 -#define S8_ARG(str) str.Memory, str.Size -#define S8(str) { S8_LIT(str) } -#define S8_FMT "Memory: %.5s Size: %lu" +#define S8_LIT(String) { (String), sizeof((String)) - 1 } +#define S8_ARG(String) (String.Data), (String.Size) +#define S8_FMT "Data: %.5s Size: %lu" +#define S8_SIZE_DATA(String) (sizeof((String)) - 1), (String) //////////////////////////////////////////////////////// ///~ Arena ///////////////////////////////////////////// typedef struct { - char *Memory; + void *Memory; u64 Pos; u64 Size; } arena; -///~ Global variables ///////////////////////////////////////////// -// TODO: use meta program to generate Keywords table -global_variable s8 TableKeyword = S8("table"); -global_variable s8 TableGenEnumKeyword = S8("table_gen_enum"); -global_variable s8 ExpandKeyword = S8("expand"); -//////////////////////////////////////////////////////// - -char * -ArenaPush(arena* Arena, i64 Size) +void * +ArenaPush(arena* Arena, u64 Size) { - char *Result; - Result = (char*)Arena->Memory + Arena->Pos; + void *Result = Arena->Memory + Arena->Pos; Arena->Pos += Size; Assert(Arena->Pos <= Arena->Size); return Result; } + +void * +ArenaPop(arena *Arena, u64 Size) +{ + Assert(Size <= Arena->Pos); + Arena->Pos -= Size; + return Arena->Memory + Arena->Pos; +} //////////////////////////////////////////////////////// ///~ MetaC data structures ///////////////////////////// @@ -103,39 +90,57 @@ typedef struct { } table; typedef struct { - i32 Start; - i32 End; -} range; + u64 End; + u64 Size; + char *Data; +} parse_result; -global_variable char *ErrorMessage = 0; -global_variable i32 ErrorLocation = 0; -global_variable i32 ErrorAt; +typedef struct { + u64 At; + u64 Size; + char Message[]; +} error; +//////////////////////////////////////////////////////// + +///~ Global variables ///////////////////////////////////////////// +// TODO: use meta program to generate Keywords table +global_variable s8 TableKeyword = S8_LIT("table"); +global_variable s8 TableGenEnumKeyword = S8_LIT("table_gen_enum"); +global_variable s8 ExpandKeyword = S8_LIT("expand"); +//////////////////////////////////////////////////////// + +///~ MetaC functions /////////////////////////////////// +void +ErrorPush(arena *ErrorsArena, u64 MessageAt, u64 MessageSize, char *MessageData) +{ + error *Error = (error *)(ErrorsArena->Memory + ErrorsArena->Pos); + Error->At = MessageAt; + Error->Size = MessageSize; + memcpy(Error->Message, MessageData, MessageSize); + ErrorsArena->Pos += sizeof(MessageAt) + sizeof(MessageSize) + MessageSize; +} void -Error(i32 Expr, char *Message, i32 Offset) +ErrorPushAssert(b32 Condition, arena *ErrorsArena, u64 MessageAt, u64 MessageSize, char *MessageData) { - if (!Expr && !ErrorMessage) + if (!Condition) { - printf("%i: %s\n", Offset, Message); - ErrorMessage = Message; - ErrorLocation = Offset; + ErrorPush(ErrorsArena, MessageAt, MessageSize, MessageData); } } -//////////////////////////////////////////////////////// - s8 ReadEntireFileIntoMemory(char *Filepath) { i32 FD = 0; s8 Result = {0}; struct stat StatBuffer = {0}; - + FD = open(Filepath, O_RDONLY); fstat(FD, &StatBuffer); - + Result.Size = StatBuffer.st_size; - Result.Memory = mmap(0, Result.Size, PROT_READ | PROT_WRITE, MAP_PRIVATE, FD, 0); - + Result.Data = mmap(0, Result.Size, PROT_READ | PROT_WRITE, MAP_PRIVATE, FD, 0); + return Result; } @@ -147,52 +152,147 @@ IsWhitespace(char Ch) Ch == '\t'); } +parse_result +ParseUntilChar(u8 *In, u64 InSize, u64 At, char Ch, arena *ErrorsArena) +{ + parse_result Result = {0}; + u64 ExpressionAt = At; + + while (In[At] != Ch && At < InSize) At++; + if (At < InSize) + { + Result.Data = In + ExpressionAt; + Result.Size = At - ExpressionAt; + Result.End = At + 1; + } + else + { + s8 ErrorMessage = S8_LIT("Expected C"); + ErrorMessage.Data[ErrorMessage.Size - 1] = Ch; + ErrorPush(ErrorsArena, ExpressionAt, ErrorMessage.Size, ErrorMessage.Data); + } + + return Result; +} + +u64 +DecimalArenaPush(arena *Arena, u64 Value) +{ + u64 TempValue = Value; + + u32 DigitsCount = 1; + while (TempValue /= 10) DigitsCount++; + char *Number = (char *)ArenaPush(Arena, DigitsCount); + + u32 TempDigitsCount = DigitsCount; + for (TempValue = Value; + TempValue; + TempValue /= 10) + { + u32 Digit = TempValue % 10; + Number[--TempDigitsCount] = (char)(Digit + '0'); + } + + return DigitsCount; +} + +void +Memcpy(char *Destination, char *Source, u64 Size) +{ + while (Size--) *Destination++ = *Source++; +} + +char * +StringArenaPush(arena *Arena, char *Source, u64 Size) +{ + char *Pos = (char *)ArenaPush(Arena, Size); + Memcpy((char *)Pos, Source, Size); + return Pos; +} +//////////////////////////////////////////////////////// + int main(int ArgC, char *Args[]) { char *Filename = 0; - + char *OutputFilename = 0; + char *Storage = mmap(0, Megabyte(4), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); Assert(Storage); - arena ScratchArena = { - .Memory = Storage, - .Pos = 0, - .Size = Megabyte(1) - }; - arena TablesArena = { - .Memory = ScratchArena.Memory + ScratchArena.Size, - .Pos = 0, - .Size = Megabyte(1) - }; + + arena ScratchArena = {0}; + ScratchArena.Size = Megabyte(1); + ScratchArena.Memory = Storage; + + arena TablesArena = {0}; + TablesArena.Memory = ScratchArena.Memory + ScratchArena.Size; + TablesArena.Size = Megabyte(1); table *Tables = (table*)TablesArena.Memory; - i32 TablesCount = 0; - char *Out = TablesArena.Memory + TablesArena.Size; + u32 TablesCount = 0; + + arena ErrorsArena = {0}; + ErrorsArena.Memory = TablesArena.Memory + TablesArena.Size; + ErrorsArena.Size = Megabyte(1); + + char *Out = ErrorsArena.Memory + ErrorsArena.Size; char *OutBase = Out; - + if (ArgC > 1) { Filename = Args[1]; + if (ArgC > 2) + { + if (Args[2][0] == '-' && Args[2][1] == '\0') + { + OutputFilename = 0; + } + else + { + OutputFilename = Args[2]; + } + } + else + { + u32 Len = strlen(Filename); + if (!strncmp(Filename + Len - 2, ".c", 2)) + { + u32 SufLen = sizeof(".meta") - 1; + OutputFilename = malloc(Len + SufLen + 1); + memcpy(OutputFilename, Filename, Len - 2); + memcpy(OutputFilename + Len - 2, ".meta.c", SufLen + 2); + OutputFilename[Len + SufLen] = 0; + } + else + { + u32 SuffixLength = sizeof(".meta.c") - 1; + OutputFilename = malloc(Len + SuffixLength + 1); + memcpy(OutputFilename, Filename, Len); + memcpy(OutputFilename + Len, ".meta.c", SuffixLength); + OutputFilename[Len + SuffixLength] = 0; + } + + } } else { - fprintf(stderr, "Usage: %s [filename]\n", Args[0]); + fprintf(stderr, "Usage: %s filename [output_filename]\n", Args[0]); return 1; } - + // NOTE(luca): The memory is assumed to stay mapped until program exits, because we will use // pointers into that memory. s8 FileContents = ReadEntireFileIntoMemory(Filename); - - if (!FileContents.Memory || (void*)FileContents.Memory == (void*)-1) + + if (!FileContents.Data || (void*)FileContents.Data == (void*)-1) { fprintf(stderr, "File '%s' could not be loaded into memory.\n", Filename); return 1; } - - char *In = FileContents.Memory; - i64 InSize = FileContents.Size; - - for (i64 At = 0; + + char *In = FileContents.Data; + u64 InSize = FileContents.Size; + + for (u64 At = 0; At < InSize; At++) { @@ -202,55 +302,68 @@ main(int ArgC, char *Args[]) if (!strncmp(In + At, S8_ARG(ExpandKeyword))) { - Error(TablesCount > 0, "no tables defined", At); - + if (TablesCount == 0) + { + ErrorPush(&ErrorsArena, At, S8_SIZE_DATA("no tables defined")); + } + table *ExpressionTable = 0; s8 ExpressionTableName = {0}; i32 ExpressionTableNameAt = 0; s8 ExpressionTableArgument = {0}; i32 ExpressionTableArgumentAt = 0; - + At += ExpandKeyword.Size; - Error(At < InSize, "expected '('", At); - Error(In[At] == '(', "expected '('", At); + ErrorPushAssert(At < InSize, &ErrorsArena, At, S8_SIZE_DATA("expected '('")); + ErrorPushAssert(In[At] == '(', &ErrorsArena, At, S8_SIZE_DATA("expected '('")); At++; - + while (IsWhitespace(In[At]) && At < InSize) At++; + + // @compress_parse ExpressionTableNameAt = At; while (!IsWhitespace(In[At]) && In[At] != ')' && At < InSize) At++; - Error(At - ExpressionTableNameAt > 0, "table name required", ExpressionTableNameAt); - Error(At < InSize, "cannot parse table name", ExpressionTableNameAt); - ExpressionTableName.Memory = In + ExpressionTableNameAt; + ErrorPushAssert(At - ExpressionTableNameAt > 0, &ErrorsArena, At, S8_SIZE_DATA("table name required")); + ErrorPushAssert(At < InSize, &ErrorsArena, ExpressionTableNameAt, S8_SIZE_DATA("cannot parse table name")); + ExpressionTableName.Data = In + ExpressionTableNameAt; ExpressionTableName.Size = At - ExpressionTableNameAt; for (i32 TableAt = 0; TableAt < TablesCount; TableAt++) { - if (!strncmp(Tables[TableAt].Name.Memory, ExpressionTableName.Memory, ExpressionTableName.Size)) + if (ExpressionTableName.Size == Tables[TableAt].Name.Size && !strncmp(Tables[TableAt].Name.Data, ExpressionTableName.Data, ExpressionTableName.Size)) { ExpressionTable = Tables + TableAt; break; } } - Error(ExpressionTable != 0, "undefined table name", ExpressionTableNameAt); - + ErrorPushAssert(ExpressionTable != 0, &ErrorsArena, ExpressionTableNameAt, S8_SIZE_DATA("undefined table name")); + while (IsWhitespace(In[At]) && At < InSize) At++; - Error(At < InSize, "expected argument name", At); - ExpressionTableArgumentAt = At; - ErrorAt = At; - while (In[At] != ')' && At < InSize) At++; - Error(At > ExpressionTableArgumentAt, "argument name required", ExpressionTableArgumentAt); - Error(At < InSize, "expected ')'", ErrorAt); - ExpressionTableArgument.Memory = In + ExpressionTableArgumentAt; - ExpressionTableArgument.Size = At - ExpressionTableArgumentAt; - At++; - + ErrorPushAssert(At < InSize, &ErrorsArena, At, S8_SIZE_DATA("expected argument name")); + int ErrorAt = At; + + parse_result ParseResult = ParseUntilChar(In, InSize, At, ')', &ErrorsArena); + if (ParseResult.Size) + { + ExpressionTableArgument.Size = ParseResult.Size; + ExpressionTableArgument.Data = ParseResult.Data; + At = ParseResult.End; + } + else + { + // TODO: Logging + } + + // Error(At > ExpressionTableArgumentAt, "argument name required", ExpressionTableArgumentAt); + + // @compress_parse while (IsWhitespace(In[At]) && At < InSize) At++; - Error(At < InSize, "expected opening '`", At); - Error(In[At] == '`', "expected closing '`'", At); + ErrorPushAssert(At < InSize, &ErrorsArena, At, S8_SIZE_DATA("expected opening '`")); + ErrorPushAssert(In[At] == '`', &ErrorsArena, At, S8_SIZE_DATA("expected closing '`'")); At++; - + if (ExpressionTable) { i32 ExpressionAt = At; @@ -259,7 +372,7 @@ main(int ArgC, char *Args[]) ElementAt++) { At = ExpressionAt; - + while (In[At] != '`' && At < InSize) { while ((In[At] != '$' && In[At] != '`') && At < InSize) @@ -267,208 +380,219 @@ main(int ArgC, char *Args[]) if (In[At] == '\\') At++; *Out++ = In[At++]; } - + if (In[At] == '$' && In[At + 1] == '(') { At += 2; - + s8 ExpandArgument = {0}; - i32 ExpandArgumentAt = At; - while (In[At] != '.' && At < InSize) At++; // NOTE(luca): to make errors even smarter we should stop searching at the // closing characters up one level. ')' in this case. - Error(At < InSize, "expected '.'", ExpandArgumentAt); - ExpandArgument.Memory = In + ExpandArgumentAt; - ExpandArgument.Size = At - ExpandArgumentAt; - Error(!strncmp(ExpandArgument.Memory, - ExpressionTableArgument.Memory, - ExpandArgument.Size), - "argument name does not match defined one", - ExpandArgumentAt); - At++; - + ParseResult = ParseUntilChar(In, InSize, At, '.', &ErrorsArena); + if (ParseResult.Size) + { + if (ParseResult.Size != ExpressionTableArgument.Size || + strncmp(ExpandArgument.Data, + ExpressionTableArgument.Data, + ExpandArgument.Size)) + { + ErrorPush(&ErrorsArena, At, S8_SIZE_DATA("argument name does not match defined one")); + } + else + { + ExpandArgument.Data = ParseResult.Data; + ExpandArgument.Size = ParseResult.Size; + At = ParseResult.End; + } + } + s8 ExpansionLabel = {0}; - i32 ExpansionLabelAt = At; - while (In[At] != ')' && At < InSize) At++; - Error(At < InSize, "expected ')'", ExpandArgumentAt - 1); - ExpansionLabel.Memory = In + ExpansionLabelAt; - ExpansionLabel.Size = At - ExpansionLabelAt; - At++; - + parse_result ParseResult = ParseUntilChar(In, InSize, At, ')', &ErrorsArena); + if (ParseResult.Size) + { + ExpansionLabel.Data = ParseResult.Data; + ExpansionLabel.Size = ParseResult.Size; + At = ParseResult.End; + } + i32 LabelIndex = -1; for (i32 LabelAt = 0; LabelAt < ExpressionTable->LabelsCount; LabelAt++) { - if (!strncmp(ExpansionLabel.Memory, - ExpressionTable->Labels[LabelAt].Memory, + if (!strncmp(ExpansionLabel.Data, + ExpressionTable->Labels[LabelAt].Data, ExpansionLabel.Size)) { LabelIndex = LabelAt; break; } } - Error(LabelIndex != -1, "undefined label", ExpansionLabelAt); - + ErrorPushAssert(LabelIndex != -1, &ErrorsArena, At, S8_SIZE_DATA("undefined label")); + s8 Expansion = ExpressionTable->Elements[ElementAt * ExpressionTable->LabelsCount + LabelIndex]; - memcpy(Out, Expansion.Memory, Expansion.Size); + memcpy(Out, Expansion.Data, Expansion.Size); Out += Expansion.Size; } else if (In[At] != '`') { *Out++ = In[At++]; } - + } *Out++ = '\n'; - + } - Error(At < InSize, "expected closing '`'", ExpressionAt - 1); - + ErrorPushAssert(At < InSize, &ErrorsArena, ExpressionAt - 1, S8_SIZE_DATA("expected closing '`'") - 1); + At++; } } - else if (!strncmp(In + At, TableGenEnumKeyword.Memory, TableGenEnumKeyword.Size)) + else if (!strncmp(In + At, TableGenEnumKeyword.Data, TableGenEnumKeyword.Size)) { // TODO: not implemented yet while (In[At] != '}' && At < InSize) At++; - Error(At < InSize, "expected '}'", At); + ErrorPushAssert(At < InSize, &ErrorsArena, At, S8_SIZE_DATA("expected '}'")); } - else if (!strncmp(In + At, TableKeyword.Memory, TableKeyword.Size)) + else if (!strncmp(In + At, TableKeyword.Data, TableKeyword.Size)) { s8 TableName = {0}; i32 LabelsCount = 0; s8* Labels = 0; i32 ElementsCount = 0; s8* Elements = 0; - + Labels = (s8*)(ScratchArena.Memory + ScratchArena.Pos); - + // Parse the labels At += TableKeyword.Size; - Error(In[At] == '(', "expected '('", At); + ErrorPushAssert(In[At] == '(', &ErrorsArena, At, S8_SIZE_DATA("expected '('")); i32 BeginParenAt = At; At++; i32 CurrentLabelAt = At; s8* CurrentLabel = 0; - + while (In[At] != ')' && At < InSize) { if (In[At] == ',') { CurrentLabel = (s8*)ArenaPush(&ScratchArena, sizeof(*CurrentLabel)); - CurrentLabel->Memory = In + CurrentLabelAt; + CurrentLabel->Data = In + CurrentLabelAt; CurrentLabel->Size = At - CurrentLabelAt; LabelsCount++; - + At++; while (IsWhitespace(In[At]) && At < InSize) At++; - Error(At < InSize, "expected next label", At); + ErrorPushAssert(At < InSize, &ErrorsArena, At, S8_SIZE_DATA("expected next label")); CurrentLabelAt = At; } - + At++; } - Error(At < InSize, "expected ')'", At); - + ErrorPushAssert(At < InSize, &ErrorsArena, At, S8_SIZE_DATA("expected ')'")); + if (BeginParenAt + 1 != At) { CurrentLabel = (s8*)ArenaPush(&ScratchArena, sizeof(*CurrentLabel)); - CurrentLabel->Memory = In + CurrentLabelAt; + CurrentLabel->Data = In + CurrentLabelAt; CurrentLabel->Size = At - CurrentLabelAt; LabelsCount++; } - Error(LabelsCount, "no labels defined", At); - + ErrorPushAssert(LabelsCount, &ErrorsArena, At, S8_SIZE_DATA("no labels defined")); + // Parse table name At++; while (IsWhitespace(In[At]) && At < InSize) At++; - Error(At < InSize, "expected table name", At); + ErrorPushAssert(At < InSize, &ErrorsArena, At, S8_SIZE_DATA("expected table name")); + + // @compress_parse i32 TableNameAt = At; while (!IsWhitespace(In[At]) && At < InSize) At++; - Error(At < InSize, "EOF while parsing table name", At); - TableName.Memory = In + TableNameAt; + ErrorPushAssert(At < InSize, &ErrorsArena, At, S8_SIZE_DATA("EOF while parsing table name")); + TableName.Data = In + TableNameAt; TableName.Size = At - TableNameAt; - - ErrorAt = At; - while (In[At] != '{' && At < InSize) At++; - Error(At < InSize, "expected '{'", ErrorAt); - At++; + + parse_result ParseResult = ParseUntilChar(In, InSize, At, '{', &ErrorsArena); + if (ParseResult.Size) + { + At = ParseResult.End; + } Elements = (s8*)(ScratchArena.Memory + ScratchArena.Pos); - + i32 CurrentElementAt = 0; i32 ShouldStop = false; i32 IsPair = false; u8 PairChar = 0; s8* CurrentElement = 0; - + while (!ShouldStop) { while (IsWhitespace(In[At]) && At < InSize) At++; - Error(At < InSize, "expected '}' or '{'", At); + ErrorPushAssert(At < InSize, &ErrorsArena, At, S8_SIZE_DATA("expected '}' or '{'")); if (In[At] == '}') { ShouldStop = true; } else { - Error(In[At] == '{', "expected '{'", At); + ErrorPushAssert(In[At] == '{', &ErrorsArena, At, S8_SIZE_DATA("expected '{'")); At++; - + CurrentElement = (s8*)ArenaPush(&ScratchArena, sizeof(*CurrentElement) * LabelsCount); - + // Parse elements for (i32 LabelAt = 0; LabelAt < LabelsCount; LabelAt++) { while (IsWhitespace(In[At]) && At < InSize) At++; - Error(At < InSize, "expected element label", At); + ErrorPushAssert(At < InSize, &ErrorsArena, At, S8_SIZE_DATA("expected element label")); + + // @compress_parse CurrentElementAt = At; - + IsPair = true; switch (In[At]) { - case '\'': PairChar = '\''; break; - case '"': PairChar = '"'; break; - case '(': PairChar = ')'; break; - case '{': PairChar = '}'; break; - case '[': PairChar = ']'; break; - default: IsPair = false; break; + case '\'': PairChar = '\''; break; + case '"': PairChar = '"'; break; + case '(': PairChar = ')'; break; + case '{': PairChar = '}'; break; + case '[': PairChar = ']'; break; + default: IsPair = false; break; } - - ErrorAt = At; + // TODO: escape characters with '\' if (IsPair) { At++; // NOTE(luca): We need to skip quotes because they are the - // same character to open and to close. We can also assume - // that a label within an element must be a minimum of 1 - // character so skipping should be fine. + // same character to open and to close. We can also assume + // that a label within an element must be a minimum of 1 + // character so skipping should be fine. while (In[At] != PairChar && At < InSize) At++; At++; } else { - ErrorAt = At; while (!IsWhitespace(In[At]) && At < InSize) At++; } - Error(At < InSize, "EOF while parsing element label", ErrorAt); - - CurrentElement[LabelAt].Memory = In + CurrentElementAt; + ErrorPushAssert(At < InSize, &ErrorsArena, At, S8_SIZE_DATA("EOF while parsing element label")); + + CurrentElement[LabelAt].Data = In + CurrentElementAt; CurrentElement[LabelAt].Size = At - CurrentElementAt; } ElementsCount++; - - // Find end of element '}' - ErrorAt = At; - while (In[At] != '}' && At < InSize) At++; - Error(At < InSize, "expected '}'", ErrorAt); - At++; + + // NOTE(luca): Find end of element '}' + parse_result ParseResult = ParseUntilChar(In, InSize, At, '}', &ErrorsArena); + if (ParseResult.Size) + { + At = ParseResult.End; + } } } - + table *CurrentTable = (table*)ArenaPush(&TablesArena, sizeof(*CurrentTable)); CurrentTable->Name = TableName; CurrentTable->LabelsCount = LabelsCount; @@ -482,7 +606,7 @@ main(int ArgC, char *Args[]) *Out++ = '@'; *Out++ = In[At]; } - + } else { @@ -490,14 +614,43 @@ main(int ArgC, char *Args[]) } } - if (ErrorMessage) + if (ErrorsArena.Pos) { - // printf("%i: %s\n", ErrorLocation, ErrorMessage); + for (error *ErrorAt = (error *)ErrorsArena.Memory; + ErrorAt->Size; + ErrorAt = (error *)((void *)ErrorAt + sizeof(ErrorAt->At) + sizeof(ErrorAt->Size) + ErrorAt->Size)) + { + void *PosBase = ScratchArena.Memory + ScratchArena.Pos; + StringArenaPush(&ScratchArena, "Error(", 6); + DecimalArenaPush(&ScratchArena, ErrorAt->At); + StringArenaPush(&ScratchArena, "): ", 3); + StringArenaPush(&ScratchArena, ErrorAt->Message, ErrorAt->Size); + StringArenaPush(&ScratchArena, "\n", 1); + void *Pos = ScratchArena.Memory + ScratchArena.Pos; + + write(STDERR_FILENO, PosBase, Pos - PosBase); + } + } else { - write(STDOUT_FILENO, OutBase, Out - OutBase); + u32 FD = STDOUT_FILENO; + if (OutputFilename) + { + FD = open(OutputFilename, O_WRONLY | O_CREAT, 0644); + if (FD == -1) + { + fprintf(stderr, "Could not open %s\n", OutputFilename); + return 1; + } + else + { + fprintf(stderr, "Output: %s\n", OutputFilename); + } + } + + write(FD, OutBase, Out - OutBase); } - + return 0; } -- cgit v1.2.3