I have a piece of code parsing a text file line by line. I have to goals: Testing the syntax of the text and extracting information of it. It is quite likely that syntax errors occur so I want to provice helpful information about where and what.
To give an idea of the problem, I have a text file like the following (simplified example):
1=\tSTRING\tDevice name
15=\tFLOAT\tSpeed
17=\tINTEGER\tMax Speed
18=INTEGER\tMax Speed
As you can guess, the syntax of each line is: <Parameter ID>=\t<Data Type>\t<Description>
My goal is to
- Return a vector of structs for every parameter.
- If there is an error, give an error message
- for example: "Error in Line 2: data type of INTEGER is not allowed"
- for example: "Error in Line 3: missing tab"
My general structure is:
- A "function":
std::vector<ParameterDAO> ParseText (std::string text)
- A "sub function"
ParameterDAO ParseTextLine (std::string text)
- As you can guess,
ParseTextLine
is called byParseText
for each line. - Some "subsub functions" used by ParseTextLine (checking spaces in the text, checking elements for validity/range/...
FYI: The strings/substrings itself I parse with regular expressions and some standard string operations (compare, ...). But this is not the main point in my question.
OK, now some more details of my implementation:
- Any of my functions (ParseText, ParseTextLine, ...) can throw an exception.
- I always throw the standard exception
std::invalid_argument("my error message")
- The function "ParseText" always checks for exceptions thrown in one of the sub functions to add the "Error in Line x" message. This is done by getting the what-message of the exception thrown, creating a new string with this message and the line info an rethrow the message:
- The code calling "ParseText" also checks for exceptions. If an exceptions has occured it will show the error message (for example "Error in Line 3: missing tab" to the user
Code snippet for 3:
try
{
Parse_HPA_CATEGORY_SingleLine_THROWS;
}
catch ( std::exception e )
{
std::string l_ErrorMessage = "Error in Line x: ";
l_ErrorMessage.append ( e.what () );
throw std::invalid_argument ( l_ErrorMessage.c_str() );
}
This structure works and has the following benefit:
- The error message is close to the location where the error occurs (for example close to a string compare or the regular expression).
But there may be some drawbacks / things I am not sure about, too:
- In the unit test, I have to repeat the string literally ( I don't know if this is actually bad).
- I read (unfortunately I can't remember where) that the "what message" is usually not used to directly create error messages. Do I misuse the "what message"? Should I maybe deviate an special exception error class from std::exception for every exception case?
- The ParseText function makes a kind of rethrow. Is there a way to avoid this?