diff --git a/DbcParserLib.Tests/NodeLineParserTests.cs b/DbcParserLib.Tests/NodeLineParserTests.cs index 4fb39fc..67f8879 100644 --- a/DbcParserLib.Tests/NodeLineParserTests.cs +++ b/DbcParserLib.Tests/NodeLineParserTests.cs @@ -28,6 +28,16 @@ private static ILineParser CreateParser() return new NodeLineParser(new SilentFailureObserver()); } + [Test] + public void EmptyNodeListIsAccepted() + { + var dbcBuilderMock = m_repository.Create(); + var nodeLineParser = CreateParser(); + var nextLineProviderMock = m_repository.Create(); + + Assert.That(nodeLineParser.TryParse(" BU_: ", dbcBuilderMock.Object, nextLineProviderMock.Object), Is.True); + } + [Test] public void EmptyCommentLineIsIgnored() { @@ -95,7 +105,6 @@ public void FullLineIsParsed() [TestCase("BU_: 0nodeName")] [TestCase("BU_:nodeName")] - [TestCase("BU_:")] public void NodeSyntaxErrorIsObserved(string line) { var observerMock = m_repository.Create(); diff --git a/DbcParserLib/Parsers/CommentLineParser.cs b/DbcParserLib/Parsers/CommentLineParser.cs index ba1c2cb..2ec0bf9 100644 --- a/DbcParserLib/Parsers/CommentLineParser.cs +++ b/DbcParserLib/Parsers/CommentLineParser.cs @@ -6,12 +6,18 @@ namespace DbcParserLib.Parsers { internal class CommentLineParser : ILineParser { + private const string CharGroup = "CharString"; + private const string NodeNameGroup = "NodeName"; + private const string MessageIdGroup = "MessageId"; + private const string SignalNameGroup = "SignalName"; + private const string EnvVarNameGroup = "EnvVarName"; private const string CommentLineStarter = "CM_ "; - private const string GenericCommentParsingRegex = @"CM_\s+""*([^""]*)""*\s*;"; - private const string NodeParsingRegex = @"CM_ BU_\s+([a-zA-Z_][\w]*)\s+""*([^""]*)""*\s*;"; - private const string MessageParsingRegex = @"CM_ BO_\s+(\d+)\s+""*([^""]*)""*\s*;"; - private const string SignalParsingRegex = @"CM_ SG_\s+(\d+)\s+([a-zA-Z_][\w]*)\s+""*([^""]*)""*\s*;"; - private const string EnvironmentVariableParsingRegex = @"CM_ EV_\s+([a-zA-Z_][\w]*)\s+""*([^""]*)""*\s*;"; + + private readonly string m_genericCommentParsingRegex = $@"CM_\s+""*(?<{CharGroup}>[^""]*)""*\s*;"; + private readonly string m_nodeParsingRegex = $@"CM_ BU_\s+(?<{NodeNameGroup}>[a-zA-Z_][\w]*)\s+""*(?<{CharGroup}>[^""]*)""*\s*;"; + private readonly string m_messageParsingRegex = $@"CM_ BO_\s+(?<{MessageIdGroup}>\d+)\s+""*(?<{CharGroup}>[^""]*)""*\s*;"; + private readonly string m_signalParsingRegex = $@"CM_ SG_\s+(?<{MessageIdGroup}>\d+)\s+(?<{SignalNameGroup}>[a-zA-Z_][\w]*)\s+""*(?<{CharGroup}>[^""]*)""*\s*;"; + private readonly string m_environmentVariableParsingRegex = $@"CM_ EV_\s+(?<{EnvVarNameGroup}>[a-zA-Z_][\w]*)\s+""*(?<{CharGroup}>[^""]*)""*\s*;"; private readonly IParseFailureObserver m_observer; @@ -54,7 +60,7 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin return true; } - var match = Regex.Match(cleanLine, GenericCommentParsingRegex); + var match = Regex.Match(cleanLine, m_genericCommentParsingRegex); if (match.Success) return true; @@ -62,42 +68,42 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin return true; } - private static void SetSignalComment(string sigCommentStr, IParseFailureObserver observer, IDbcBuilder builder, INextLineProvider nextLineProvider) + private void SetSignalComment(string sigCommentStr, IParseFailureObserver observer, IDbcBuilder builder, INextLineProvider nextLineProvider) { - var match = Regex.Match(sigCommentStr, SignalParsingRegex); + var match = Regex.Match(sigCommentStr, m_signalParsingRegex); if (match.Success) - builder.AddSignalComment(uint.Parse(match.Groups[1].Value), match.Groups[2].Value, match.Groups[3].Value); + builder.AddSignalComment(uint.Parse(match.Groups[MessageIdGroup].Value), match.Groups[SignalNameGroup].Value, match.Groups[CharGroup].Value); else observer.CommentSyntaxError(); } - private static void SetNodeComment(string sigCommentStr, IParseFailureObserver observer, IDbcBuilder builder, INextLineProvider nextLineProvider) + private void SetNodeComment(string sigCommentStr, IParseFailureObserver observer, IDbcBuilder builder, INextLineProvider nextLineProvider) { - var match = Regex.Match(sigCommentStr, NodeParsingRegex); + var match = Regex.Match(sigCommentStr, m_nodeParsingRegex); if (match.Success) - builder.AddNodeComment(match.Groups[1].Value, match.Groups[2].Value); + builder.AddNodeComment(match.Groups[NodeNameGroup].Value, match.Groups[CharGroup].Value); else observer.CommentSyntaxError(); } - private static void SetMessageComment(string sigCommentStr, IParseFailureObserver observer, IDbcBuilder builder, INextLineProvider nextLineProvider) + private void SetMessageComment(string sigCommentStr, IParseFailureObserver observer, IDbcBuilder builder, INextLineProvider nextLineProvider) { - var match = Regex.Match(sigCommentStr, MessageParsingRegex); + var match = Regex.Match(sigCommentStr, m_messageParsingRegex); if (match.Success) - builder.AddMessageComment(uint.Parse(match.Groups[1].Value), match.Groups[2].Value); + builder.AddMessageComment(uint.Parse(match.Groups[MessageIdGroup].Value), match.Groups[CharGroup].Value); else observer.CommentSyntaxError(); } - private static void SetEnvironmentVariableComment(string envCommentStr, IParseFailureObserver observer, IDbcBuilder builder) + private void SetEnvironmentVariableComment(string envCommentStr, IParseFailureObserver observer, IDbcBuilder builder) { - var match = Regex.Match(envCommentStr, EnvironmentVariableParsingRegex); + var match = Regex.Match(envCommentStr, m_environmentVariableParsingRegex); if (match.Success) - builder.AddEnvironmentVariableComment(match.Groups[1].Value, match.Groups[2].Value); + builder.AddEnvironmentVariableComment(match.Groups[EnvVarNameGroup].Value, match.Groups[CharGroup].Value); else observer.CommentSyntaxError(); } diff --git a/DbcParserLib/Parsers/EnvironmentDataVariableLineParser.cs b/DbcParserLib/Parsers/EnvironmentDataVariableLineParser.cs index 7acd8b9..642cb90 100644 --- a/DbcParserLib/Parsers/EnvironmentDataVariableLineParser.cs +++ b/DbcParserLib/Parsers/EnvironmentDataVariableLineParser.cs @@ -5,8 +5,11 @@ namespace DbcParserLib.Parsers { internal class EnvironmentDataVariableLineParser : ILineParser { + private const string NameGroup = "Name"; + private const string DataSizeGroup = "DataSize"; private const string EnvironmentDataVariableLineStarter = "ENVVAR_DATA_ "; - private const string EnvironmentDataVariableParsingRegex = @"ENVVAR_DATA_\s+([a-zA-Z_][\w]*)\s*:\s+(\d+)\s*;"; + + private readonly string m_environmentDataVariableParsingRegex = $@"ENVVAR_DATA_\s+(?<{NameGroup}>[a-zA-Z_][\w]*)\s*:\s+(?<{DataSizeGroup}>\d+)\s*;"; private readonly IParseFailureObserver m_observer; @@ -22,12 +25,12 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin if (cleanLine.StartsWith(EnvironmentDataVariableLineStarter) == false) return false; - var match = Regex.Match(cleanLine, EnvironmentDataVariableParsingRegex); + var match = Regex.Match(cleanLine, m_environmentDataVariableParsingRegex); if (match.Success) - builder.AddEnvironmentDataVariable(match.Groups[1].Value, uint.Parse(match.Groups[2].Value)); + builder.AddEnvironmentDataVariable(match.Groups[NameGroup].Value, uint.Parse(match.Groups[DataSizeGroup].Value)); else m_observer.EnvironmentDataVariableSyntaxError(); - + return true; } } diff --git a/DbcParserLib/Parsers/EnvironmentVariableLineParser.cs b/DbcParserLib/Parsers/EnvironmentVariableLineParser.cs index 825e612..69848d4 100644 --- a/DbcParserLib/Parsers/EnvironmentVariableLineParser.cs +++ b/DbcParserLib/Parsers/EnvironmentVariableLineParser.cs @@ -6,8 +6,21 @@ namespace DbcParserLib.Parsers { internal class EnvironmentVariableLineParser : ILineParser { + private const string NameGroup = "Name"; + private const string VarTypeGroup = "VarType"; + private const string MinGroup = "Min"; + private const string MaxGroup = "Max"; + private const string UnitGroup = "Unit"; + private const string InitialValueGroup = "InitialValue"; + private const string VarId = "VarId"; + private const string StringDataTypeGroup = "StringDataType"; + private const string AccessibilityGroup = "Accessibility2"; + private const string NodeGroup = "Node"; private const string EnvironmentVariableLineStarter = "EV_ "; - private const string EnvironmentVariableParsingRegex = @"EV_\s+([a-zA-Z_][\w]*)\s*:\s+([012])\s+\[([\d\+\-eE.]+)\|([\d\+\-eE.]+)\]\s+""([^""]*)""\s+([\d\+\-eE.]+)\s+(\d+)\s+DUMMY_NODE_VECTOR(800){0,1}([0123])\s+((?:[a-zA-Z_][\w]*)(?:,[a-zA-Z_][\w]*)*)\s*;"; + + private readonly string m_environmentVariableParsingRegex = $@"EV_\s+(?<{NameGroup}>[a-zA-Z_][\w]*)\s*:\s+(?<{VarTypeGroup}>[012])\s+\[(?<{MinGroup}>[\d\+\-eE.]+)\|(?<{MaxGroup}>[\d\+\-eE.]+)\]" + + $@"\s+""(?<{UnitGroup}>[^""]*)""\s+(?<{InitialValueGroup}>[\d\+\-eE.]+)\s+(?<{VarId}>\d+)\s+DUMMY_NODE_VECTOR(?<{StringDataTypeGroup}>800){{0,1}}" + + $@"(?<{AccessibilityGroup}>[0123])\s+(?<{NodeGroup}>(?:[a-zA-Z_][\w]*)(?:,[a-zA-Z_][\w]*)*)\s*;"; private readonly IParseFailureObserver m_observer; @@ -23,16 +36,16 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin if (cleanLine.StartsWith(EnvironmentVariableLineStarter) == false) return false; - var match = Regex.Match(cleanLine, EnvironmentVariableParsingRegex); + var match = Regex.Match(cleanLine, m_environmentVariableParsingRegex); if (match.Success) { var environmentVariable = new EnvironmentVariable() { - Name = match.Groups[1].Value, - Unit = match.Groups[5].Value, + Name = match.Groups[NameGroup].Value, + Unit = match.Groups[UnitGroup].Value, }; - switch (uint.Parse(match.Groups[9].Value)) + switch (uint.Parse(match.Groups[AccessibilityGroup].Value)) { case 0: environmentVariable.Access = EnvAccessibility.Unrestricted; @@ -48,30 +61,30 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin break; } - if (match.Groups[8].Value == "800") + if (match.Groups[StringDataTypeGroup].Value == "800") { environmentVariable.Type = EnvDataType.String; } else { - switch (uint.Parse(match.Groups[2].Value)) + switch (uint.Parse(match.Groups[VarTypeGroup].Value)) { case 0: environmentVariable.Type = EnvDataType.Integer; environmentVariable.IntegerEnvironmentVariable = new NumericEnvironmentVariable() { - Minimum = int.Parse(match.Groups[3].Value), - Maximum = int.Parse(match.Groups[4].Value), - Default = int.Parse(match.Groups[6].Value) + Minimum = int.Parse(match.Groups[MinGroup].Value), + Maximum = int.Parse(match.Groups[MaxGroup].Value), + Default = int.Parse(match.Groups[InitialValueGroup].Value) }; break; case 1: environmentVariable.Type = EnvDataType.Float; environmentVariable.FloatEnvironmentVariable = new NumericEnvironmentVariable() { - Minimum = double.Parse(match.Groups[3].Value), - Maximum = double.Parse(match.Groups[4].Value), - Default = double.Parse(match.Groups[6].Value) + Minimum = double.Parse(match.Groups[MinGroup].Value), + Maximum = double.Parse(match.Groups[MaxGroup].Value), + Default = double.Parse(match.Groups[InitialValueGroup].Value) }; break; case 2: @@ -80,17 +93,17 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin } } - builder.AddEnvironmentVariable(match.Groups[1].Value, environmentVariable); + builder.AddEnvironmentVariable(match.Groups[NameGroup].Value, environmentVariable); - var nodes = match.Groups[10].Value.Split(','); + var nodes = match.Groups[NodeGroup].Value.Split(','); foreach (var node in nodes) { - builder.AddNodeEnvironmentVariable(node, match.Groups[1].Value); + builder.AddNodeEnvironmentVariable(node, match.Groups[NameGroup].Value); } } else m_observer.EnvironmentVariableSyntaxError(); - + return true; } } diff --git a/DbcParserLib/Parsers/MessageLineParser.cs b/DbcParserLib/Parsers/MessageLineParser.cs index 48712f4..b4342a0 100644 --- a/DbcParserLib/Parsers/MessageLineParser.cs +++ b/DbcParserLib/Parsers/MessageLineParser.cs @@ -7,8 +7,13 @@ namespace DbcParserLib.Parsers { internal class MessageLineParser : ILineParser { + private const string IdGroup = "Id"; + private const string NameGroup = "Name"; + private const string SizeGroup = "Size"; + private const string TransmitterGroup = "Transmitter"; private const string MessageLineStarter = "BO_ "; - private const string MessageRegex = @"BO_ (\d+)\s+([a-zA-Z_][\w]*)\s*:\s*(\d+)\s+([a-zA-Z_][\w]*)"; + + private readonly string m_messageRegex = $@"BO_ (?<{IdGroup}>\d+)\s+(?<{NameGroup}>[a-zA-Z_][\w]*)\s*:\s*(?<{SizeGroup}>\d+)\s+(?<{TransmitterGroup}>[a-zA-Z_][\w]*)"; private readonly IParseFailureObserver m_observer; @@ -19,25 +24,25 @@ public MessageLineParser(IParseFailureObserver observer) public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { - if(line.Trim().StartsWith(MessageLineStarter) == false) + if (line.Trim().StartsWith(MessageLineStarter) == false) return false; - - var match = Regex.Match(line, MessageRegex); - if(match.Success) + + var match = Regex.Match(line, m_messageRegex); + if (match.Success) { var msg = new Message() { - Name = match.Groups[2].Value, - DLC = ushort.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture), - Transmitter = match.Groups[4].Value, - ID = uint.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture) + Name = match.Groups[NameGroup].Value, + DLC = ushort.Parse(match.Groups[SizeGroup].Value, CultureInfo.InvariantCulture), + Transmitter = match.Groups[TransmitterGroup].Value, + ID = uint.Parse(match.Groups[IdGroup].Value, CultureInfo.InvariantCulture) }; - + builder.AddMessage(msg); } else m_observer.MessageSyntaxError(); - + return true; } } diff --git a/DbcParserLib/Parsers/NodeLineParser.cs b/DbcParserLib/Parsers/NodeLineParser.cs index 6cceca2..a0ea2ec 100644 --- a/DbcParserLib/Parsers/NodeLineParser.cs +++ b/DbcParserLib/Parsers/NodeLineParser.cs @@ -6,14 +6,18 @@ namespace DbcParserLib.Parsers { internal class NodeLineParser : ILineParser { + private const string NameGroup = "Name"; private const string NodeLineStarter = "BU_:"; - private const string NodeLineParsingRegex = @"BU_:((?:\s+(?:[a-zA-Z_][\w]*))+)"; + + private readonly string m_nodeLineParsingRegex = $@"BU_:(?<{NameGroup}>(?:\s+(?:[a-zA-Z_][\w]*))+)"; private readonly IParseFailureObserver m_observer; + private readonly Regex m_regex; public NodeLineParser(IParseFailureObserver observer) { m_observer = observer; + m_regex = new Regex(m_nodeLineParsingRegex); } public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) @@ -21,10 +25,14 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin if (line.TrimStart().StartsWith(NodeLineStarter) == false) return false; - var match = Regex.Match(line, NodeLineParsingRegex); + // Empty node list + if (line.Trim().Equals(NodeLineStarter)) + return true; + + var match = m_regex.Match(line); if (match.Success) { - foreach (var nodeName in match.Groups[1].Value.TrimStart().SplitBySpace()) + foreach (var nodeName in match.Groups[NameGroup].Value.TrimStart().SplitBySpace()) { var node = new Node() { diff --git a/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs b/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs index 14380ef..a36a989 100644 --- a/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs +++ b/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs @@ -1,18 +1,34 @@ using DbcParserLib.Model; using DbcParserLib.Observers; using System.Globalization; -using System.Linq; using System.Text.RegularExpressions; namespace DbcParserLib.Parsers { internal class PropertiesDefinitionLineParser : ILineParser { + private const string ObjectTypeGroup = "ObjectType"; + private const string AttributeNameGroup = "AttributeName"; + private const string AttributeValueGroup = "AttributeValue"; + private const string IsIntegerValueGroup = "IsIntegerValue"; + private const string MinIntGroup = "MinInt"; + private const string MaxIntGroup = "MaxInt"; + private const string MinFloatGroup = "MinFloat"; + private const string MaxFloatGroup = "MaxFloat"; + private const string IsFloatValueGroup = "IsFloatValue"; + private const string IsStringValueGroup = "IsStringValue"; + private const string IsEnumValueGroup = "IsEnumValue"; + private const string EnumValueGroup = "EnumValue"; private const string PropertiesDefinitionLineStarter = "BA_DEF_ "; private const string PropertiesDefinitionDefaultLineStarter = "BA_DEF_DEF_ "; - private const string PropertyDefinitionParsingRegex = @"BA_DEF_(?:\s+(BU_|BO_|SG_|EV_))?\s+""([a-zA-Z_][\w]*)""\s+(?:(?:(INT|HEX)\s+(-?\d+)\s+(-?\d+))|(?:(FLOAT)\s+([\d\+\-eE.]+)\s+([\d\+\-eE.]+))|(STRING)|(?:(ENUM)\s+((?:""[^""]*"",\s*)*(?:""[^""]*""))))\s*;"; - private const string PropertyDefinitionDefaultParsingRegex = @"BA_DEF_DEF_\s+""([a-zA-Z_][\w]*)""\s+(-?\d+|[\d\+\-eE.]+|""[^""]*"")\s*;"; + private readonly string m_propertyDefinitionParsingRegex = $@"BA_DEF_(?:\s+(?<{ObjectTypeGroup}>BU_|BO_|SG_|EV_))?\s+""(?<{AttributeNameGroup}>[a-zA-Z_][\w]*)""\s+" + + $@"(?:(?:(?<{IsIntegerValueGroup}>INT|HEX)\s+(?<{MinIntGroup}>-?\d+)\s+(?<{MaxIntGroup}>-?\d+))|" + + $@"(?:(?<{IsFloatValueGroup}>FLOAT)\s+(?<{MinFloatGroup}>[\d\+\-eE.]+)\s+(?<{MaxFloatGroup}>[\d\+\-eE.]+))" + + $@"|(?<{IsStringValueGroup}>STRING)|(?:(?<{IsEnumValueGroup}>ENUM)\s+(?<{EnumValueGroup}>(?:""[^""]*"",\s*)*(?:""[^""]*""))))\s*;"; + + private readonly string m_propertyDefinitionDefaultParsingRegex = $@"BA_DEF_DEF_\s+""(?<{AttributeNameGroup}>[a-zA-Z_][\w]*)""\s+(?<{AttributeValueGroup}>-?\d+|[\d\+\-eE.]+|""[^""]*"")\s*;"; + private readonly IParseFailureObserver m_observer; public PropertiesDefinitionLineParser(IParseFailureObserver observer) @@ -30,9 +46,9 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin if (cleanLine.StartsWith(PropertiesDefinitionDefaultLineStarter)) { - var match = Regex.Match(cleanLine, PropertyDefinitionDefaultParsingRegex); + var match = Regex.Match(cleanLine, m_propertyDefinitionDefaultParsingRegex); if (match.Success) - builder.AddCustomPropertyDefaultValue(match.Groups[1].Value, match.Groups[2].Value.Replace(Helpers.DoubleQuotes, ""), !match.Groups[2].Value.StartsWith(Helpers.DoubleQuotes)); + builder.AddCustomPropertyDefaultValue(match.Groups[AttributeNameGroup].Value, match.Groups[AttributeValueGroup].Value.Replace(Helpers.DoubleQuotes, ""), !match.Groups[AttributeValueGroup].Value.StartsWith(Helpers.DoubleQuotes)); else m_observer.PropertyDefaultSyntaxError(); return true; @@ -40,16 +56,16 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin if (cleanLine.StartsWith(PropertiesDefinitionLineStarter)) { - var match = Regex.Match(cleanLine, PropertyDefinitionParsingRegex); + var match = Regex.Match(cleanLine, m_propertyDefinitionParsingRegex); if (match.Success) { var customProperty = new CustomPropertyDefinition(m_observer) { - Name = match.Groups[2].Value, + Name = match.Groups[AttributeNameGroup].Value, }; CustomPropertyObjectType objectType = CustomPropertyObjectType.Global; - switch (match.Groups[1].Value) + switch (match.Groups[ObjectTypeGroup].Value) { case "BU_": objectType = CustomPropertyObjectType.Node; break; @@ -62,43 +78,43 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin } CustomPropertyDataType dataType = CustomPropertyDataType.Integer; - if (match.Groups[3].Value == "INT") + if (match.Groups[IsIntegerValueGroup].Value.Equals("INT")) { customProperty.IntegerCustomProperty = new NumericCustomPropertyDefinition { - Minimum = int.Parse(match.Groups[4].Value, CultureInfo.InvariantCulture), - Maximum = int.Parse(match.Groups[5].Value, CultureInfo.InvariantCulture), + Minimum = int.Parse(match.Groups[MinIntGroup].Value, CultureInfo.InvariantCulture), + Maximum = int.Parse(match.Groups[MaxIntGroup].Value, CultureInfo.InvariantCulture), }; } - else if (match.Groups[3].Value == "HEX") + else if (match.Groups[IsIntegerValueGroup].Value.Equals("HEX")) { dataType = CustomPropertyDataType.Hex; customProperty.HexCustomProperty = new NumericCustomPropertyDefinition { - Minimum = int.Parse(match.Groups[4].Value, CultureInfo.InvariantCulture), - Maximum = int.Parse(match.Groups[5].Value, CultureInfo.InvariantCulture), + Minimum = int.Parse(match.Groups[MinIntGroup].Value, CultureInfo.InvariantCulture), + Maximum = int.Parse(match.Groups[MaxIntGroup].Value, CultureInfo.InvariantCulture), }; } - else if (match.Groups[6].Value == "FLOAT") + else if (match.Groups[IsFloatValueGroup].Value.Equals("FLOAT")) { dataType = CustomPropertyDataType.Float; customProperty.FloatCustomProperty = new NumericCustomPropertyDefinition { - Minimum = double.Parse(match.Groups[7].Value, CultureInfo.InvariantCulture), - Maximum = double.Parse(match.Groups[8].Value, CultureInfo.InvariantCulture), + Minimum = double.Parse(match.Groups[MinFloatGroup].Value, CultureInfo.InvariantCulture), + Maximum = double.Parse(match.Groups[MaxFloatGroup].Value, CultureInfo.InvariantCulture), }; } - else if (match.Groups[9].Value == "STRING") + else if (match.Groups[IsStringValueGroup].Value.Equals("STRING")) { dataType = CustomPropertyDataType.String; customProperty.StringCustomProperty = new StringCustomPropertyDefinition(); } - else if (match.Groups[10].Value.StartsWith("ENUM")) + else if (match.Groups[IsEnumValueGroup].Value.StartsWith("ENUM")) { dataType = CustomPropertyDataType.Enum; customProperty.EnumCustomProperty = new EnumCustomPropertyDefinition { - Values = match.Groups[11] + Values = match.Groups[EnumValueGroup] .Value .Replace(Helpers.DoubleQuotes, string.Empty) .Replace(Helpers.Space, string.Empty) diff --git a/DbcParserLib/Parsers/PropertiesLineParser.cs b/DbcParserLib/Parsers/PropertiesLineParser.cs index b0df540..031f0b9 100644 --- a/DbcParserLib/Parsers/PropertiesLineParser.cs +++ b/DbcParserLib/Parsers/PropertiesLineParser.cs @@ -6,9 +6,20 @@ namespace DbcParserLib.Parsers { internal class PropertiesLineParser : ILineParser { + private const string AttributeNameGroup = "AttributeName"; + private const string AttributeValueGroup = "AttributeValue"; + private const string IsNodeEnvGroup = "NodeEnv"; + private const string NodeEnvNameGroup = "NodeName"; + private const string IsMessageGroup = "Message"; + private const string MessageIdGroup = "MessageId"; + private const string IsSignalGroup = "Signal"; + private const string MessageSignalIdGroup = "MessageId"; + private const string SignalNameGroup = "SignalName"; private const string PropertiesLineStarter = "BA_ "; - private const string PropertyParsingRegex = @"BA_\s+""([a-zA-Z_][\w]*)""(?:\s+(?:(BU_|EV_)\s+([a-zA-Z_][\w]*))|\s+(?:(BO_)\s+(\d+))|\s+(?:(SG_)\s+(\d+)\s+([a-zA-Z_][\w]*)))?\s+(-?\d+|[\d\+\-eE.]+|""[^""]*"");"; + private readonly string m_propertyParsingRegex = $@"BA_\s+""(?<{AttributeNameGroup}>[a-zA-Z_][\w]*)""(?:\s+(?:(?<{IsNodeEnvGroup}>BU_|EV_)\s+(?<{NodeEnvNameGroup}>[a-zA-Z_][\w]*))|\s+" + + $@"(?:(?<{IsMessageGroup}>BO_)\s+(?<{MessageIdGroup}>\d+))|\s+(?:(?<{IsSignalGroup}>SG_)\s+(?<{MessageSignalIdGroup}>\d+)\s+" + + $@"(?<{SignalNameGroup}>[a-zA-Z_][\w]*)))?\s+(?<{AttributeValueGroup}>-?\d+|[\d\+\-eE.]+|""[^""]*"");"; private readonly IParseFailureObserver m_observer; public PropertiesLineParser(IParseFailureObserver observer) @@ -23,23 +34,23 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin if (cleanLine.StartsWith(PropertiesLineStarter) == false) return false; - var match = Regex.Match(cleanLine, PropertyParsingRegex); + var match = Regex.Match(cleanLine, m_propertyParsingRegex); if (match.Success) { - var isNumeric = !match.Groups[9].Value.StartsWith(Helpers.DoubleQuotes); - var stringValue = match.Groups[9].Value.Replace(Helpers.DoubleQuotes, string.Empty); - - if (match.Groups[2].Value == "BU_") - builder.AddNodeCustomProperty(match.Groups[1].Value, match.Groups[3].Value, stringValue, isNumeric); - else if (match.Groups[2].Value == "EV_") - builder.AddEnvironmentVariableCustomProperty(match.Groups[1].Value, match.Groups[3].Value, stringValue, isNumeric); - else if (match.Groups[4].Value == "BO_") - builder.AddMessageCustomProperty(match.Groups[1].Value, uint.Parse(match.Groups[5].Value, CultureInfo.InvariantCulture), stringValue, isNumeric); - else if (match.Groups[6].Value == "SG_") - builder.AddSignalCustomProperty(match.Groups[1].Value, uint.Parse(match.Groups[7].Value, CultureInfo.InvariantCulture), match.Groups[8].Value, stringValue, isNumeric); + var isNumeric = !match.Groups[AttributeValueGroup].Value.StartsWith(Helpers.DoubleQuotes); + var stringValue = match.Groups[AttributeValueGroup].Value.Replace(Helpers.DoubleQuotes, string.Empty); + + if (match.Groups[IsNodeEnvGroup].Value.Equals(string.Empty) == false) + builder.AddNodeCustomProperty(match.Groups[AttributeNameGroup].Value, match.Groups[NodeEnvNameGroup].Value, stringValue, isNumeric); + else if (match.Groups[IsNodeEnvGroup].Value.Equals(string.Empty) == false) + builder.AddEnvironmentVariableCustomProperty(match.Groups[AttributeNameGroup].Value, match.Groups[NodeEnvNameGroup].Value, stringValue, isNumeric); + else if (match.Groups[IsMessageGroup].Value.Equals(string.Empty) == false) + builder.AddMessageCustomProperty(match.Groups[AttributeNameGroup].Value, uint.Parse(match.Groups[MessageIdGroup].Value, CultureInfo.InvariantCulture), stringValue, isNumeric); + else if (match.Groups[IsSignalGroup].Value.Equals(string.Empty) == false) + builder.AddSignalCustomProperty(match.Groups[AttributeNameGroup].Value, uint.Parse(match.Groups[MessageSignalIdGroup].Value, CultureInfo.InvariantCulture), match.Groups[SignalNameGroup].Value, stringValue, isNumeric); else { - builder.AddGlobalCustomProperty(match.Groups[1].Value, stringValue, isNumeric); + builder.AddGlobalCustomProperty(match.Groups[AttributeNameGroup].Value, stringValue, isNumeric); } } else diff --git a/DbcParserLib/Parsers/SignalLineParser.cs b/DbcParserLib/Parsers/SignalLineParser.cs index a9b3d32..c0be5e4 100644 --- a/DbcParserLib/Parsers/SignalLineParser.cs +++ b/DbcParserLib/Parsers/SignalLineParser.cs @@ -8,10 +8,25 @@ namespace DbcParserLib.Parsers { internal class SignalLineParser : ILineParser { + private const string NameGroup = "Name"; + private const string MultiplexerGroup = "Multiplexer"; + private const string StartBirGroup = "StartBit"; + private const string SizeGroup = "Size"; + private const string ByteOrderGroup = "ByteOrder"; + private const string ValueTypeGroup = "ValueType"; + private const string FactorGroup = "Factor"; + private const string OffsetGroup = "Offset"; + private const string MinGroup = "Min"; + private const string MaxGroup = "Max"; + private const string UnitGroup = "Unit"; + private const string ReceiverGroup = "Receiver"; private const string SignalLineStarter = "SG_ "; private const string SignedSymbol = "-"; - private static readonly string[] m_commaSpaceSeparator = new string[] { Helpers.Space, Helpers.Comma }; - private const string SignalRegex = @"\s*SG_\s+([\w]+)\s*([Mm\d]*)\s*:\s*(\d+)\|(\d+)@([01])([+-])\s+\(([\d\+\-eE.]+),([\d\+\-eE.]+)\)\s+\[([\d\+\-eE.]+)\|([\d\+\-eE.]+)\]\s+""(.*)""\s+([\w\s,]+)"; + private static readonly string[] CommaSpaceSeparator = { Helpers.Space, Helpers.Comma }; + + private readonly string m_signalRegex = $@"\s*SG_\s+(?<{NameGroup}>[\w]+)\s*(?<{MultiplexerGroup}>[Mm\d]*)\s*:\s*(?<{StartBirGroup}>\d+)\|(?<{SizeGroup}>\d+)@(?<{ByteOrderGroup}>[01])" + + $@"(?<{ValueTypeGroup}>[+-])\s+\((?<{FactorGroup}>[\d\+\-eE.]+),(?<{OffsetGroup}>[\d\+\-eE.]+)\)\s+\[(?<{MinGroup}>[\d\+\-eE.]+)\|(?<{MaxGroup}>[\d\+\-eE.]+)\]" + + $@"\s+""(?<{UnitGroup}>.*)""\s+(?<{ReceiverGroup}>[\w\s,]+)"; private readonly IParseFailureObserver m_observer; @@ -25,25 +40,25 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin if (line.TrimStart().StartsWith(SignalLineStarter) == false) return false; - var match = Regex.Match(line, SignalRegex); + var match = Regex.Match(line, m_signalRegex); if (match.Success) { - var factorStr = match.Groups[7].Value; + var factorStr = match.Groups[FactorGroup].Value; var sig = new Signal { - Multiplexing = match.Groups[2].Value, - Name = match.Groups[1].Value, - StartBit = ushort.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture), - Length = ushort.Parse(match.Groups[4].Value, CultureInfo.InvariantCulture), - ByteOrder = byte.Parse(match.Groups[5].Value, CultureInfo.InvariantCulture), // 0 = MSB (Motorola), 1 = LSB (Intel) - ValueType = (match.Groups[6].Value == SignedSymbol ? DbcValueType.Signed : DbcValueType.Unsigned), + Multiplexing = match.Groups[MultiplexerGroup].Value, + Name = match.Groups[NameGroup].Value, + StartBit = ushort.Parse(match.Groups[StartBirGroup].Value, CultureInfo.InvariantCulture), + Length = ushort.Parse(match.Groups[SizeGroup].Value, CultureInfo.InvariantCulture), + ByteOrder = byte.Parse(match.Groups[ByteOrderGroup].Value, CultureInfo.InvariantCulture), // 0 = MSB (Motorola), 1 = LSB (Intel) + ValueType = (match.Groups[ValueTypeGroup].Value == SignedSymbol ? DbcValueType.Signed : DbcValueType.Unsigned), IsInteger = IsInteger(factorStr), - Factor = double.Parse(match.Groups[7].Value, CultureInfo.InvariantCulture), - Offset = double.Parse(match.Groups[8].Value, CultureInfo.InvariantCulture), - Minimum = double.Parse(match.Groups[9].Value, CultureInfo.InvariantCulture), - Maximum = double.Parse(match.Groups[10].Value, CultureInfo.InvariantCulture), - Unit = match.Groups[11].Value, - Receiver = match.Groups[12].Value.Split(m_commaSpaceSeparator, StringSplitOptions.RemoveEmptyEntries) // can be multiple receivers splitted by "," + Factor = double.Parse(match.Groups[FactorGroup].Value, CultureInfo.InvariantCulture), + Offset = double.Parse(match.Groups[OffsetGroup].Value, CultureInfo.InvariantCulture), + Minimum = double.Parse(match.Groups[MinGroup].Value, CultureInfo.InvariantCulture), + Maximum = double.Parse(match.Groups[MaxGroup].Value, CultureInfo.InvariantCulture), + Unit = match.Groups[UnitGroup].Value, + Receiver = match.Groups[ReceiverGroup].Value.Split(CommaSpaceSeparator, StringSplitOptions.RemoveEmptyEntries) // can be multiple receivers splitted by "," }; builder.AddSignal(sig); diff --git a/DbcParserLib/Parsers/SignalValueTypeLineParser.cs b/DbcParserLib/Parsers/SignalValueTypeLineParser.cs index bdac460..f86c7d0 100644 --- a/DbcParserLib/Parsers/SignalValueTypeLineParser.cs +++ b/DbcParserLib/Parsers/SignalValueTypeLineParser.cs @@ -6,8 +6,12 @@ namespace DbcParserLib.Parsers { internal class SignalValueTypeLineParser : ILineParser { + private const string MessageIdGroup = "MessageId"; + private const string SignalNameGroup = "SignalName"; + private const string SignalTypeGroup = "SignalType"; private const string SignalValueTypeStarter = "SIG_VALTYPE_ "; - private const string SignalValueTypeParsingRegex = @"SIG_VALTYPE_\s+(\d+)\s+([a-zA-Z_][\w]*)\s+[:]*\s*([0123])\s*;"; + + private readonly string m_signalValueTypeParsingRegex = $@"SIG_VALTYPE_\s+(?<{MessageIdGroup}>\d+)\s+(?<{SignalNameGroup}>[a-zA-Z_][\w]*)\s+[:]*\s*(?<{SignalTypeGroup}>[0123])\s*;"; private readonly IParseFailureObserver m_observer; @@ -23,19 +27,19 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin if (cleanLine.StartsWith(SignalValueTypeStarter) == false) return false; - var match = Regex.Match(cleanLine, SignalValueTypeParsingRegex); + var match = Regex.Match(cleanLine, m_signalValueTypeParsingRegex); if (match.Success) { - var valueType = uint.Parse(match.Groups[3].Value); + var valueType = uint.Parse(match.Groups[SignalTypeGroup].Value); if (valueType == 1 || valueType == 2) { - builder.AddSignalValueType(uint.Parse(match.Groups[1].Value), match.Groups[2].Value, + builder.AddSignalValueType(uint.Parse(match.Groups[MessageIdGroup].Value), match.Groups[SignalNameGroup].Value, valueType == 1 ? DbcValueType.IEEEFloat : DbcValueType.IEEEDouble); } } else m_observer.SignalValueTypeSyntaxError(); - + return true; } } diff --git a/DbcParserLib/Parsers/ValueTableDefinitionLineParser.cs b/DbcParserLib/Parsers/ValueTableDefinitionLineParser.cs index c55a89e..1e823bf 100644 --- a/DbcParserLib/Parsers/ValueTableDefinitionLineParser.cs +++ b/DbcParserLib/Parsers/ValueTableDefinitionLineParser.cs @@ -5,8 +5,11 @@ namespace DbcParserLib.Parsers { internal class ValueTableDefinitionLineParser : ILineParser { + private const string ValTableGroup = "ValTableName"; + private const string ValueDescriptionGroup = "ValueDescription"; private const string ValueTableDefinitionLineStarter = "VAL_TABLE_ "; - private const string ValueTableDefinitionParsingRegex = @"VAL_TABLE_\s+([a-zA-Z_][\w]*)\s+((?:\d+\s+(?:""[^""]*"")\s+)*)\s*;"; + + private readonly string m_valueTableDefinitionParsingRegex = $@"VAL_TABLE_\s+(?<{ValTableGroup}>[a-zA-Z_][\w]*)\s+(?<{ValueDescriptionGroup}>(?:\d+\s+(?:""[^""]*"")\s+)*)\s*;"; private readonly IParseFailureObserver m_observer; @@ -22,11 +25,11 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin if (cleanLine.StartsWith(ValueTableDefinitionLineStarter) == false) return false; - var match = Regex.Match(cleanLine, ValueTableDefinitionParsingRegex); + var match = Regex.Match(cleanLine, m_valueTableDefinitionParsingRegex); if (match.Success) { - if(match.Groups[2].Value.TryParseToDict(out var valueTableDictionary)) - builder.AddNamedValueTable(match.Groups[1].Value, valueTableDictionary); + if (match.Groups[ValueDescriptionGroup].Value.TryParseToDict(out var valueTableDictionary)) + builder.AddNamedValueTable(match.Groups[ValTableGroup].Value, valueTableDictionary); else m_observer.ValueTableDefinitionSyntaxError(); } diff --git a/DbcParserLib/Parsers/ValueTableLineParser.cs b/DbcParserLib/Parsers/ValueTableLineParser.cs index a3f10d1..2f5a124 100644 --- a/DbcParserLib/Parsers/ValueTableLineParser.cs +++ b/DbcParserLib/Parsers/ValueTableLineParser.cs @@ -5,9 +5,17 @@ namespace DbcParserLib.Parsers { internal class ValueTableLineParser : ILineParser { + private const string MessageIdGroup = "MessageId"; + private const string SignalNameGroup = "SignalName"; + private const string ValueTableGroup = "ValueTable"; + private const string EnvVarGroup = "EnvVarName"; + private const string ValueDescriptionGroup = "ValueDescription"; + private const string EndValeDescriptionGroup = "ValueDescriptionEnd"; private const string ValueTableLineStarter = "VAL_ "; - private const string ValueTableLinkParsingRegex = @"VAL_\s+(\d+)\s+([a-zA-Z_][\w]*)\s+([a-zA-Z_][\w]*)\s*;"; - private const string ValueTableParsingRegex = @"VAL_\s+(?:(?:(\d+)\s+([a-zA-Z_][\w]*))|([a-zA-Z_][\w]*))\s+((?:(?:-?\d+)\s+(?:""[^""]*"")\s+)*)((?:(?:-?\d+)\s+(?:""[^""]*"")\s*));"; + + private readonly string m_valueTableLinkParsingRegex = $@"VAL_\s+(?<{MessageIdGroup}>\d+)\s+(?<{SignalNameGroup}>[a-zA-Z_][\w]*)\s+(?<{ValueTableGroup}>[a-zA-Z_][\w]*)\s*;"; + private readonly string m_valueTableParsingRegex = $@"VAL_\s+(?:(?:(?<{MessageIdGroup}>\d+)\s+(?<{SignalNameGroup}>[a-zA-Z_][\w]*))|(?<{EnvVarGroup}>[a-zA-Z_][\w]*))\s+" + + $@"(?<{ValueDescriptionGroup}>(?:(?:-?\d+)\s+(?:""[^""]*"")\s+)*)(?<{EndValeDescriptionGroup}>(?:(?:-?\d+)\s+(?:""[^""]*"")\s*));"; private readonly IParseFailureObserver m_observer; @@ -23,24 +31,26 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin if (cleanLine.StartsWith(ValueTableLineStarter) == false) return false; - var match = Regex.Match(cleanLine, ValueTableLinkParsingRegex); + var match = Regex.Match(cleanLine, m_valueTableLinkParsingRegex); if (match.Success) { - builder.LinkNamedTableToSignal(uint.Parse(match.Groups[1].Value), match.Groups[2].Value, match.Groups[3].Value); + builder.LinkNamedTableToSignal(uint.Parse(match.Groups[MessageIdGroup].Value), match.Groups[SignalNameGroup].Value, match.Groups[ValueTableGroup].Value); return true; } - match = Regex.Match(cleanLine, ValueTableParsingRegex); + match = Regex.Match(cleanLine, m_valueTableParsingRegex); if (match.Success) { - var dictionary = string.IsNullOrEmpty(match.Groups[4].Value) ? match.Groups[5].Value : string.Concat(match.Groups[4].Value, match.Groups[5].Value); + var dictionary = string.IsNullOrEmpty(match.Groups[ValueDescriptionGroup].Value) + ? match.Groups[EndValeDescriptionGroup].Value + : string.Concat(match.Groups[ValueDescriptionGroup].Value, match.Groups[EndValeDescriptionGroup].Value); if (!string.IsNullOrEmpty(dictionary) && dictionary.TryParseToDict(out var valueTableDictionary)) { - if (match.Groups[3].Value != string.Empty) - builder.LinkTableValuesToEnvironmentVariable(match.Groups[3].Value, valueTableDictionary); + if (match.Groups[EnvVarGroup].Value.Equals(string.Empty) == false) + builder.LinkTableValuesToEnvironmentVariable(match.Groups[EnvVarGroup].Value, valueTableDictionary); else - builder.LinkTableValuesToSignal(uint.Parse(match.Groups[1].Value), match.Groups[2].Value, + builder.LinkTableValuesToSignal(uint.Parse(match.Groups[MessageIdGroup].Value), match.Groups[SignalNameGroup].Value, valueTableDictionary); return true; }