// Line -> Comment | Declaration private void Line() { MessageToken peeked = Peek(); if (PeekType(MessageTokenType.Comment)) { Comment(); } else if (PeekType(MessageTokenType.BuiltInType) || PeekType(MessageTokenType.DefinedType) || PeekType(MessageTokenType.Header)) { Declaration(); } else { // Mumble mumble if (peeked == null) { throw new MessageParserException( "Unexpected end of input " + "' at " + inFilePath + ":" + lineNum); } else { throw new MessageParserException( "Unexpected token '" + peeked.content + "' at " + inFilePath + ":" + lineNum + ". Expecting a comment or field declaration."); } } }
private string MatchByType(MessageTokenType type) { MessageToken token = tokens[0]; if (token.type.Equals(type)) { tokens.RemoveAt(0); // Update line num if (!IsEmpty()) { lineNum = tokens[0].lineNum; } return(token.content); } else { throw new MessageParserException( "Unexpected token '" + token.content + "' at " + inFilePath + ":" + token.lineNum + ". Expecting a token of type " + Enum.GetName(typeof(MessageTokenType), token.type)); } }
// Declaration -> BuiltInType Identifier | BuiltInType Identifier ConstantDeclaration | BuiltInType ArrayDeclaration Identifier // Declaration -> DefinedType Identifier | DefinedType ArrayDeclaration Identifier // Declaration -> Header Identifier private void Declaration() { string declaration = ""; // Type MessageToken peeked = Peek(); string type = ""; bool canHaveConstDecl = false; declaration += MsgAutoGenUtilities.TWO_TABS + "public "; if (PeekType(MessageTokenType.BuiltInType)) { type = builtInTypeMapping[MatchByType(MessageTokenType.BuiltInType)]; if (!type.Equals("Time") && !type.Equals("Duration")) { // Time and Duration can't have constant declaration // See <wiki.ros.org/msg> canHaveConstDecl = true; } else { // Need to import Standard imports.Add("Std"); } } else if (PeekType(MessageTokenType.DefinedType)) { type = MatchByType(MessageTokenType.DefinedType); string[] hierarchy = type.Split(new char[] { '/', '\\' }); // Assume type can only be either: // Type // package/Type switch (hierarchy.Length) { case 1: break; case 2: if (hierarchy[0].Equals("") || hierarchy[1].Equals("")) { throw new MessageParserException( "Invalid field type '" + type + "'. + " + "(" + inFilePath + ":" + lineNum + ")"); } string package = MsgAutoGenUtilities.ResolvePackageName(hierarchy[0]); // Do not add package name if exists in current namespace type = package.Equals(rosPackageNamespace) ? hierarchy[1] : package + "." + hierarchy[1]; break; default: throw new MessageParserException( "Invalid field type '" + type + "'. + " + "(" + inFilePath + ":" + lineNum + ")"); } } else { type = MatchByType(MessageTokenType.Header); if (PeekType(MessageTokenType.FixedSizeArray) || PeekType(MessageTokenType.VariableSizeArray)) { Warn( "By convention, there is only one header for each message." + "(" + inFilePath + ":" + lineNum + ")"); } if (PeekType(MessageTokenType.Identifier) && !Peek().content.Equals("header")) { Warn( "By convention, a ros message Header will be named 'header'. '" + Peek().content + "'. (" + inFilePath + ":" + lineNum + ")"); } imports.Add("Std"); } // Array Declaration int arraySize = -1; if (PeekType(MessageTokenType.FixedSizeArray)) { type += "[]"; canHaveConstDecl = false; arraySize = int.Parse(MatchByType(MessageTokenType.FixedSizeArray)); } if (PeekType(MessageTokenType.VariableSizeArray)) { type += "[]"; canHaveConstDecl = false; MatchByType(MessageTokenType.VariableSizeArray); arraySize = 0; } // Identifier string identifier = MatchByType(MessageTokenType.Identifier); // Check for duplicate declaration if (symbolTable.ContainsKey(identifier)) { throw new MessageParserException( "Field '" + identifier + "' at " + inFilePath + ":" + lineNum + " already declared!"); } // Check if identifier is a ROS message built-in type if (builtInTypeMapping.ContainsKey(identifier) && identifier.Equals("time") && identifier.Equals("duration")) { throw new MessageParserException( "Invalid field identifier '" + identifier + "' at " + inFilePath + ":" + lineNum + ". '" + identifier + "' is a ROS message built-in type."); } // Check if identifier is a C# keyword if (MsgAutoGenUtilities.CSharpKeywords.Contains(identifier)) { Warn( "'" + identifier + "' is a C# keyword. It can be accessed under the name @" + identifier + "." + "(" + inFilePath + ":" + lineNum + ")"); identifier = "@" + identifier; } symbolTable.Add(identifier, type); // Array declaration table if (arraySize > -1) { arraySizes.Add(identifier, arraySize); } // Constant Declaration if (PeekType(MessageTokenType.ConstantDeclaration)) { if (canHaveConstDecl) { declaration += "const " + type + " " + identifier + " = "; declaration += ConstantDeclaration(type); constants.Add(identifier); } else { throw new MessageParserException( "Type " + type + "' at " + inFilePath + ":" + lineNum + " cannot have constant declaration"); } } else { declaration += type + " " + identifier + ";\n"; } body += declaration; }