From e4266ba1efc83d5600613fffc495fa50f1481385 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 10 Oct 2020 17:22:31 -0700 Subject: [PATCH] assembly_parser now uses the standard parser --- src/app/engine/assembly_parser.cpp | 455 ++++----------------------- src/app/engine/foldhaus_serializer.h | 68 +++- 2 files changed, 125 insertions(+), 398 deletions(-) diff --git a/src/app/engine/assembly_parser.cpp b/src/app/engine/assembly_parser.cpp index 006ae62..e6b1a02 100644 --- a/src/app/engine/assembly_parser.cpp +++ b/src/app/engine/assembly_parser.cpp @@ -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 diff --git a/src/app/engine/foldhaus_serializer.h b/src/app/engine/foldhaus_serializer.h index b82ee62..3a1849e 100644 --- a/src/app/engine/foldhaus_serializer.h +++ b/src/app/engine/foldhaus_serializer.h @@ -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 \ No newline at end of file