kicad-developers team mailing list archive
-
kicad-developers team
-
Mailing list archive
-
Message #06078
Proposed Recursive Descent s-expression Parser Design Pattern
I am proposing the following design pattern for the PARSER and LEXER used
with the TokenList2DsnLexerl.cmake technology. This is a change I am
volunteering to make, but wanted to see if anyone had any objections or
improvements first.
New Design Pattern:
==================
Let:
class <object> = is a non-trivial container class
class <object>_PARSER = the parser class for class <object>.
1) Parsing is done in a separate class for each major <object>, derived from
the corresponding lexer class. <object>_PARSER is to be derived from
<object>_LEXER. The <object>_PARSER class may be a friend of the <object>
being stuffed. <object>_PARSER can also handle the parsing for any
*trivial* object contained within <object> which does not have its own PARSER.
3) class <object>_PARSER be given a function :
public:
void <object>_PARSER::Parse( <object> * aObjectToBeStuffed ) throws(
IO_ERROR, PARSE_ERROR )
2) class <object> be given a function :
public:
void <object>::Parse( <object>_PARSER* aParser ) throws( IO_ERROR, PARSE_ERROR )
which is always implemented as just this:
{
aParser->Parse( this );
}
3) Every <object>_PARSER class is to have at least this one constructor:
<object>_PARSER( LINE_READER* aReader )
// allows sharing of aReader.
4) Every <object>_PARSER be given the method:
LINE_READER* <object>_PARSER::GetReader();
There are only minor changes needed to transition to this design pattern, we
are almost there already.
The Benefits:
==============
*) The token enums for the keywords can then be moved into the base
<object>_LEXER classes and we don't need enum namespaces. What makes this
possible is that the PARSER can access the enum from its *base* class, the
<object>_LEXER, without having to use any special enum prefix, although it
may need to use a "using" directive.
*) Simplifies the construction of the LEXER and PARSER combination, can be
done in fewer inline lines of code. (The new PARSER<->LEXER constructor
linkages take care of this simplification in a standard way.)
*) Keeps involved parsing code out of the <object> class, and out of its
header file. <object>_PARSER will have many functions/methods, probably one
for each trivial nested object. So keeping these out of public view is
valuable for reduced compile time, etc.
*) Allows falling down easy chaining of <object>_PARSERs when a major object
contains another major object which also has its own PARSER class, because
the LINE_READER* can be lent to the nested object's PARSER.
I would probably start by putting the big specctra parsing code under this
model as a "does it hold water" test. This change can be done in less than
40 changed lines of code I think.
Feedback welcomed,
Dick
Follow ups