aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaymaekers Luca <luca@spacehb.net>2025-03-29 14:24:07 +0100
committerRaymaekers Luca <luca@spacehb.net>2025-04-27 11:12:40 +0200
commit85af2d80c35d060cc003302115c7a8975b545afe (patch)
tree4becc19c5495e99930a994eca932bf9adceeec05
parent1cc92de9f83a87e474ff405176ee6681146be762 (diff)
Code compression; Added error stack
-rwxr-xr-xbuild.sh2
-rwxr-xr-xbuild/metacbin28496 -> 38856 bytes
-rw-r--r--examples/table.c2
-rwxr-xr-xexamples/table.metabin15488 -> 0 bytes
-rw-r--r--examples/table.meta.c9
-rw-r--r--examples/wrong.c13
-rw-r--r--source/build.bat7
-rwxr-xr-xsource/build.sh6
-rw-r--r--source/meta.c549
9 files changed, 386 insertions, 202 deletions
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
--- a/build/metac
+++ b/build/metac
Binary files 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
--- a/examples/table.meta
+++ /dev/null
Binary files 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 <stdio.h>
+
+@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 <fcntl.h>
#include <signal.h>
#include <stdint.h>
@@ -35,6 +19,7 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <stdlib.h>
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;
}