assembly_parser now uses the standard parser

This commit is contained in:
PS 2020-10-10 17:22:31 -07:00
parent 55284cde25
commit e4266ba1ef
2 changed files with 125 additions and 398 deletions

View File

@ -45,362 +45,36 @@ enum assembly_field
AssemblyField_Count,
};
global char* AssemblyFieldIdentifiers[] = {
"assembly_name", // AssemblyField_AssemblyName
"assembly_scale", // AssemblyField_AssemblyScale
"assembly_center", // AssemblyField_AssemblyCenter
"led_strip_count", // AssemblyField_LedStripCount
"output_mode", // AssemblyField_OutputMode
global gs_const_string AssemblyFieldIdentifiers[] = {
ConstString("assembly_name"), // AssemblyField_AssemblyName
ConstString("assembly_scale"), // AssemblyField_AssemblyScale
ConstString("assembly_center"), // AssemblyField_AssemblyCenter
ConstString("led_strip_count"), // AssemblyField_LedStripCount
ConstString("output_mode"), // AssemblyField_OutputMode
"led_strip", // AssemblyField_LedStrip
ConstString("led_strip"), // AssemblyField_LedStrip
"output_sacn", // AssemblyField_OutputSACN
"start_universe", // AssemblyField_SACN_StartUniverse
"start_channel", // AssemblyField_SACN_StartChannel
ConstString("output_sacn"), // AssemblyField_OutputSACN
ConstString("start_universe"), // AssemblyField_SACN_StartUniverse
ConstString("start_channel"), // AssemblyField_SACN_StartChannel
"output_uart", // AssemblyField_OutputUART
"channel", // AssemblyField_UART_Channel
"com_port", // AssemblyField_UART_ComPort
ConstString("output_uart"), // AssemblyField_OutputUART
ConstString("channel"), // AssemblyField_UART_Channel
ConstString("com_port"), // AssemblyField_UART_ComPort
"point_placement_type", // AssemblyField_PointPlacementType
"interpolate_points", // AssemblyField_InterpolatePoints
"start", // AssemblyField_Start
"end", // AssemblyField_End
ConstString("point_placement_type"), // AssemblyField_PointPlacementType
ConstString("interpolate_points"), // AssemblyField_InterpolatePoints
ConstString("start"), // AssemblyField_Start
ConstString("end"), // AssemblyField_End
"led_count", // AssemblyField_LedCount
ConstString("led_count"), // AssemblyField_LedCount
"tags_count", // AssemblyField_TagCount
"tag", // AssemblyField_Tag
"name", // AssemblyField_Name
"value", // AssemblyField_Value
ConstString("tags_count"), // AssemblyField_TagCount
ConstString("tag"), // AssemblyField_Tag
ConstString("name"), // AssemblyField_Name
ConstString("value"), // AssemblyField_Value
};
struct assembly_error_list
{
gs_string String;
assembly_error_list* Next;
};
struct assembly_tokenizer
{
gs_string Text;
char* At;
gs_const_string FileName;
u32 LineNumber;
bool ParsingIsValid;
gs_memory_arena* ErrorArena;
assembly_error_list* ErrorsRoot;
assembly_error_list* ErrorsTail;
};
internal bool
AtValidPosition(assembly_tokenizer* T)
{
u64 Offset = T->At - T->Text.Str;
bool Result = (Offset < T->Text.Length);
return Result;
}
internal void
AdvanceChar(assembly_tokenizer* T)
{
if (IsNewline(T->At[0]))
{
T->LineNumber += 1;
}
T->At++;
}
internal void
EatWhitespace(assembly_tokenizer* T)
{
while(AtValidPosition(T) && IsNewlineOrWhitespace(T->At[0]))
{
AdvanceChar(T);
}
}
internal void
EatToNewLine(assembly_tokenizer* T)
{
while(AtValidPosition(T) && !IsNewline(T->At[0]))
{
AdvanceChar(T);
}
EatWhitespace(T);
}
internal bool
AdvanceIfTokenEquals(assembly_tokenizer* T, char* Value)
{
bool Result = true;
char* TAt = T->At;
char* VAt = Value;
while (*VAt != 0)
{
if (*TAt != *VAt)
{
Result = false;
break;
}
TAt += 1;
VAt += 1;
}
// TODO(Peter): What if the token is a subset of Value? ie. this would return true for
// T->At = hello_world and Value = hello_
// But the next token we read would fail
if (Result)
{
T->At = TAt;
EatWhitespace(T);
}
return Result;
}
internal void
TokenizerPushError(assembly_tokenizer* T, char* ErrorString)
{
// NOTE(Peter): We can make this more expressive if we need to
assembly_error_list* Error = PushStruct(T->ErrorArena, assembly_error_list);
Error->String = PushString(T->ErrorArena, 512);
PrintF(&Error->String, "%S(%d): %s", T->FileName, T->LineNumber, ErrorString);
SLLPushOrInit(T->ErrorsRoot, T->ErrorsTail, Error);
T->ParsingIsValid = false;
// NOTE(Peter): I'm not sure this is the best idea, but at least this way,
// if there's multiple errors, you'll get a number of them, rather than
// a bunch of erroneous errors happening on the same line
EatToNewLine(T);
}
#define PARSER_FIELD_REQUIRED true
#define PARSER_FIELD_OPTIONAL false
internal bool
ReadFieldIdentifier(assembly_field Field, assembly_tokenizer* T, bool Required = true)
{
bool Result = false;
if (AdvanceIfTokenEquals(T, AssemblyFieldIdentifiers[Field]))
{
if (AdvanceIfTokenEquals(T, ":"))
{
Result = true;
}
else
{
// We always throw an error if we get this far because we know you were trying to
// open the identifier
TokenizerPushError(T, "Field identifier is missing a colon");
}
}
else if (Required)
{
TokenizerPushError(T, "Field Identifier Invalid");
}
return Result;
}
internal bool
ReadFieldEnd(assembly_tokenizer* T)
{
bool Result = AdvanceIfTokenEquals(T, ";");
if (Result)
{
EatWhitespace(T);
}
else
{
TokenizerPushError(T, "Missing a semicolon");
}
return Result;
}
internal gs_string
ReadString(assembly_tokenizer* T)
{
gs_string Result = {};
if (AdvanceIfTokenEquals(T, "\""))
{
char* StringStart = T->At;
while(AtValidPosition(T) && T->At[0] != '\"')
{
T->At++;
}
Result.Str = StringStart;
Result.Size = T->At - StringStart;
Result.Length = Result.Size;
if (AdvanceIfTokenEquals(T, "\""))
{
// Success
}
else
{
TokenizerPushError(T, "String not closed with a \"");
}
}
else
{
TokenizerPushError(T, "Expecting a string, but none was found");
}
return Result;
}
internal gs_string
GetNumberString(assembly_tokenizer* T)
{
gs_string Result = {};
Result.Str = T->At;
while(AtValidPosition(T) && IsNumericExtended(T->At[0]))
{
AdvanceChar(T);
}
Result.Length = T->At - Result.Str;
Result.Size = Result.Length;
return Result;
}
internal r32
ReadFloat(assembly_tokenizer* T)
{
r32 Result = 0;
gs_string NumberString = GetNumberString(T);
Result = (r32)ParseFloat(NumberString.ConstString);
return Result;
}
internal s32
ReadInt(assembly_tokenizer* T)
{
s32 Result = 0;
gs_string NumberString = GetNumberString(T);
Result = (r32)ParseInt(NumberString.ConstString);
return Result;
}
internal gs_string
ReadStringField(assembly_field Field, assembly_tokenizer* T, gs_memory_arena* Arena, bool ShouldNullTerminate = false)
{
gs_string Result = {};
if (ReadFieldIdentifier(Field, T))
{
gs_string ExistingString = ReadString(T);
if (ReadFieldEnd(T))
{
// Success
u64 Length = ExistingString.Length + (ShouldNullTerminate ? 1 : 0);
Result = PushString(Arena, Length);
PrintF(&Result, "%S", ExistingString);
if (ShouldNullTerminate)
{
NullTerminate(&Result);
}
}
}
return Result;
}
internal r32
ReadFloatField(assembly_field Field, assembly_tokenizer* T)
{
r32 Result = 0.0f;
if (ReadFieldIdentifier(Field, T))
{
Result = ReadFloat(T);
if (!ReadFieldEnd(T))
{
T->ParsingIsValid = false;
}
}
return Result;
}
internal s32
ReadIntField(assembly_field Field, assembly_tokenizer* T)
{
r32 Result = 0.0f;
if (ReadFieldIdentifier(Field, T))
{
Result = ReadInt(T);
if (!ReadFieldEnd(T))
{
T->ParsingIsValid = false;
}
}
return Result;
}
internal v3
ReadV3Field(assembly_field Field, assembly_tokenizer* T)
{
v3 Result = {};
if (ReadFieldIdentifier(Field, T))
{
if (AdvanceIfTokenEquals(T, "("))
{
Result.x = ReadFloat(T);
if (AdvanceIfTokenEquals(T, ","))
{
Result.y = ReadFloat(T);
if (AdvanceIfTokenEquals(T, ","))
{
Result.z = ReadFloat(T);
if (AdvanceIfTokenEquals(T, ")"))
{
if (!ReadFieldEnd(T))
{
T->ParsingIsValid = false;
}
}
else
{
TokenizerPushError(T, "Vector 3 doesn't end with a ')'");
}
}
else
{
TokenizerPushError(T, "Vector 3: unable to read a field");
}
}
else
{
TokenizerPushError(T, "Vector 3: unable to read a field");
}
}
else
{
TokenizerPushError(T, "Vector 3: unable to read a field");
}
}
return Result;
}
internal bool
ReadStructOpening(assembly_field Field, assembly_tokenizer* T, bool Required = true)
{
bool Result = false;
if (ReadFieldIdentifier(Field, T, Required))
{
if (AdvanceIfTokenEquals(T, "{"))
{
Result = true;
}
}
return Result;
}
internal bool
ReadStructClosing(assembly_tokenizer* T)
{
bool Result = AdvanceIfTokenEquals(T, "};");
return Result;
}
internal void
StripSetTag(v2_strip* Strip, u32 TagIndex, gs_const_string TagName, gs_const_string TagValue)
{
@ -415,27 +89,26 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe
{
Assembly->LedCountTotal = 0;
r32 Value = ParseFloat(ConstString("-2.355"));
parser Parser = {0};
Parser.String = FileText;
Parser.Identifiers = &AssemblyFieldIdentifiers[0];
Parser.IdentifiersCount = AssemblyField_Count;
Parser.At = Parser.String.Str;
Parser.LineStart = Parser.At;
Parser.Arena = &Assembly->Arena;
assembly_tokenizer Tokenizer = {};
Tokenizer.Text = FileText;
Tokenizer.At = Tokenizer.Text.Str;
Tokenizer.ParsingIsValid = true;
Tokenizer.ErrorArena = Transient;
Tokenizer.FileName = FileName;
Assembly->Name = Parser_ReadStringValue(&Parser, AssemblyField_AssemblyName);
Assembly->Scale = Parser_ReadR32Value(&Parser, AssemblyField_AssemblyScale);
Assembly->Center = Parser_ReadV3Value(&Parser, AssemblyField_AssemblyCenter);
Assembly->StripCount = Parser_ReadU32Value(&Parser, AssemblyField_LedStripCount);
Assembly->Name = ReadStringField(AssemblyField_AssemblyName, &Tokenizer, &Assembly->Arena);
Assembly->Scale = ReadFloatField(AssemblyField_AssemblyScale, &Tokenizer);
Assembly->Center = ReadV3Field(AssemblyField_AssemblyCenter, &Tokenizer);
Assembly->StripCount = ReadIntField(AssemblyField_LedStripCount, &Tokenizer);
Assembly->Strips = PushArray(&Assembly->Arena, v2_strip, Assembly->StripCount);
gs_string OutputModeString = ReadStringField(AssemblyField_OutputMode, &Tokenizer, Transient);
gs_string OutputModeString = Parser_ReadStringValue(&Parser, AssemblyField_OutputMode);
if (StringsEqual(OutputModeString.ConstString, ConstString("UART")))
{
Assembly->OutputMode = NetworkProtocol_UART;
Assembly->UARTComPort = ReadStringField(AssemblyField_UART_ComPort, &Tokenizer, &Assembly->Arena, true).ConstString;
Assembly->UARTComPort = Parser_ReadStringValue(&Parser, AssemblyField_UART_ComPort, true).ConstString;
}
else if (StringsEqual(OutputModeString.ConstString, ConstString("SACN")))
{
@ -443,45 +116,44 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe
}
else
{
TokenizerPushError(&Tokenizer, "Invalid output mode specified.");
//TokenizerPushError(&Tokenizer, "Invalid output mode specified.");
}
for (u32 i = 0; i < Assembly->StripCount; i++)
{
v2_strip* StripAt = Assembly->Strips + i;
if (ReadStructOpening(AssemblyField_LedStrip, &Tokenizer))
if (Parser_ReadOpenStruct(&Parser, AssemblyField_LedStrip))
{
if (ReadStructOpening(AssemblyField_OutputSACN, &Tokenizer, PARSER_FIELD_OPTIONAL))
if (Parser_ReadOpenStruct(&Parser, AssemblyField_OutputSACN))
{
StripAt->SACNAddr.StartUniverse = ReadIntField(AssemblyField_SACN_StartUniverse, &Tokenizer);
StripAt->SACNAddr.StartChannel = ReadIntField(AssemblyField_SACN_StartChannel, &Tokenizer);
StripAt->SACNAddr.StartUniverse = Parser_ReadU32Value(&Parser, AssemblyField_SACN_StartUniverse);
StripAt->SACNAddr.StartChannel = Parser_ReadU32Value(&Parser, AssemblyField_SACN_StartChannel);
if (!ReadStructClosing(&Tokenizer))
if (!Parser_ReadCloseStruct(&Parser))
{
TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
//TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
}
}
if (ReadStructOpening(AssemblyField_OutputUART, &Tokenizer, PARSER_FIELD_OPTIONAL))
if (Parser_ReadOpenStruct(&Parser, AssemblyField_OutputUART))
{
StripAt->UARTAddr.Channel = (u8)ReadIntField(AssemblyField_UART_Channel, &Tokenizer);
StripAt->UARTAddr.Channel = (u8)Parser_ReadU32Value(&Parser, AssemblyField_UART_Channel);
if (!ReadStructClosing(&Tokenizer))
if (!Parser_ReadCloseStruct(&Parser))
{
TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
//TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
}
}
// TODO(Peter): Need to store this
gs_string PointPlacementType = ReadStringField(AssemblyField_PointPlacementType, &Tokenizer, &Assembly->Arena);
gs_string PointPlacementType = Parser_ReadStringValue(&Parser, AssemblyField_PointPlacementType);
// TODO(Peter): Switch on value of PointPlacementType
if (ReadStructOpening(AssemblyField_InterpolatePoints, &Tokenizer))
if (Parser_ReadOpenStruct(&Parser, AssemblyField_InterpolatePoints))
{
StripAt->StartPosition = ReadV3Field(AssemblyField_Start, &Tokenizer);
StripAt->EndPosition = ReadV3Field(AssemblyField_End, &Tokenizer);
if (!ReadStructClosing(&Tokenizer))
StripAt->StartPosition = Parser_ReadV3Value(&Parser, AssemblyField_Start);
StripAt->EndPosition = Parser_ReadV3Value(&Parser, AssemblyField_End);
if (!Parser_ReadCloseStruct(&Parser))
{
Tokenizer.ParsingIsValid = false;
// TODO(Peter): @ErrorHandling
// Have this function prepend the filename and line number.
// Create an error display popup window, or an error log window that takes over a panel automatically
@ -489,48 +161,47 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe
}
}
StripAt->LedCount = ReadIntField(AssemblyField_LedCount, &Tokenizer);
StripAt->LedCount = Parser_ReadU32Value(&Parser, AssemblyField_LedCount);
Assembly->LedCountTotal += StripAt->LedCount;
StripAt->TagsCount = ReadIntField(AssemblyField_TagsCount, &Tokenizer);
StripAt->TagsCount = Parser_ReadU32Value(&Parser, AssemblyField_TagsCount);
// NOTE(pjs): Always add one tag to the input to leave room for the assembly name
StripAt->TagsCount += 1;
StripAt->Tags = PushArray(&Assembly->Arena, v2_tag, StripAt->TagsCount);
StripSetTag(StripAt, 0, ConstString("assembly"), Assembly->Name.ConstString);
for (u32 Tag = 1; Tag < StripAt->TagsCount; Tag++)
{
if (ReadStructOpening(AssemblyField_Tag, &Tokenizer))
if (Parser_ReadOpenStruct(&Parser, AssemblyField_Tag))
{
// TODO(Peter): Need to store the gs_string somewhere we can look it up for display in the interface
// right now they are stored in temp memory and won't persist
gs_string TagName = ReadStringField(AssemblyField_Name, &Tokenizer, Transient);
gs_string TagValue = ReadStringField(AssemblyField_Value, &Tokenizer, Transient);
gs_string TagName = Parser_ReadStringValue(&Parser, AssemblyField_Name);
gs_string TagValue = Parser_ReadStringValue(&Parser, AssemblyField_Value);
StripSetTag(StripAt, Tag, TagName.ConstString, TagValue.ConstString);
if (!ReadStructClosing(&Tokenizer))
if (!Parser_ReadCloseStruct(&Parser))
{
TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
//TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
}
}
else
{
TokenizerPushError(&Tokenizer, "Expected a struct opening, but none was found");
//TokenizerPushError(&Tokenizer, "Expected a struct opening, but none was found");
}
}
if (!ReadStructClosing(&Tokenizer))
if (!Parser_ReadCloseStruct(&Parser))
{
TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
//TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
}
}
else
{
TokenizerPushError(&Tokenizer, "Expected a struct opening, but none was found");
//TokenizerPushError(&Tokenizer, "Expected a struct opening, but none was found");
}
}
return Tokenizer.ParsingIsValid;
return true; //Tokenizer.ParsingIsValid;
}
#define ASSEMBLY_PARSER_CPP

View File

@ -245,7 +245,7 @@ Parser_ReadString(parser* P, u32 IdentIndex)
}
internal gs_string
Parser_ReadStringValue(parser* P, gs_const_string Ident)
Parser_ReadStringValue(parser* P, gs_const_string Ident, bool ShouldNullTerminate = false)
{
// ident: "value";
gs_string Result = {};
@ -265,7 +265,16 @@ Parser_ReadStringValue(parser* P, gs_const_string Ident)
if (Parser_AdvanceIfTokenEquals(P, ConstString("\"")) &&
Parser_AdvanceIfLineEnd(P))
{
Result = PushStringF(P->Arena, FileString.Length, "%S", FileString);
u32 StringLength = FileString.Length;
if (ShouldNullTerminate)
{
StringLength += 1;
}
Result = PushStringF(P->Arena, StringLength, "%S", FileString);
if (ShouldNullTerminate)
{
NullTerminate(&Result);
}
}
else
{
@ -277,10 +286,10 @@ Parser_ReadStringValue(parser* P, gs_const_string Ident)
}
internal gs_string
Parser_ReadStringValue(parser* P, u32 IdentIndex)
Parser_ReadStringValue(parser* P, u32 IdentIndex, bool ShouldNullTerminate = false)
{
gs_const_string Ident = Parser_GetIdent(*P, IdentIndex);
return Parser_ReadStringValue(P, Ident);
return Parser_ReadStringValue(P, Ident, ShouldNullTerminate);
}
internal bool
@ -351,6 +360,15 @@ Parser_ReadU32Value(parser* P, u32 IdentIndex)
return Parser_ReadU32Value(P, Ident);
}
internal r32
Parser_ReadR32(parser* P)
{
r32 Result = 0;
gs_const_string NumStr = Parser_ReadNumberString(P);
Result = (r32)ParseFloat(NumStr);
return Result;
}
internal r32
Parser_ReadR32Value(parser* P, gs_const_string Ident)
{
@ -359,15 +377,16 @@ Parser_ReadR32Value(parser* P, gs_const_string Ident)
if (Parser_AdvanceIfTokenEquals(P, Ident) &&
Parser_AdvanceIfTokenEquals(P, ConstString(":")))
{
gs_const_string NumStr = Parser_ReadNumberString(P);
r32 Value = Parser_ReadR32(P);
if (Parser_AdvanceIfLineEnd(P))
{
Result = (r32)ParseFloat(NumStr);
Result = Value;
}
else
{
// TODO(pjs): Error
}
}
return Result;
}
@ -379,6 +398,43 @@ Parser_ReadR32Value(parser* P, u32 IdentIndex)
return Parser_ReadR32Value(P, Ident);
}
internal v3
Parser_ReadV3Value(parser* P, gs_const_string Ident)
{
v3 Result = {0};
if (Parser_AdvanceIfTokenEquals(P, Ident) &&
Parser_AdvanceIfTokenEquals(P, ConstString(":")) &&
Parser_AdvanceIfTokenEquals(P, ConstString("(")))
{
r32 X = Parser_ReadR32(P);
Parser_AdvanceIfTokenEquals(P, ConstString(","));
r32 Y = Parser_ReadR32(P);
Parser_AdvanceIfTokenEquals(P, ConstString(","));
r32 Z = Parser_ReadR32(P);
if (Parser_AdvanceIfTokenEquals(P, ConstString(")")) &&
Parser_AdvanceIfLineEnd(P))
{
Result.x = X;
Result.y = Y;
Result.z = Z;
}
else
{
// TODO(pjs): error
}
}
return Result;
}
internal v3
Parser_ReadV3Value(parser* P, u32 IdentIndex)
{
gs_const_string Ident = Parser_GetIdent(*P, IdentIndex);
return Parser_ReadV3Value(P, Ident);
}
#define FOLDHAUS_SERIALIZER_H
#endif // FOLDHAUS_SERIALIZER_H