← Back to team overview

kicad-developers team mailing list archive

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:


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 :

void <object>_PARSER::Parse( <object> * aObjectToBeStuffed ) throws(

2) class <object> be given a function :

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,


Follow ups