← Back to team overview

kicad-developers team mailing list archive

Re: Proposed Recursive Descent s-expression Parser Design Pattern

 

On 01/18/2011 02:07 PM, Wayne Stambaugh wrote:
> On 1/18/2011 10:11 AM, Dick Hollenbeck wrote:
>> 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.
> Dick,
>
> Sounds good to me.  Anything that simplifies the design and improves
> readability is a good thing.
>
> Wayne
>
>>
>>
>>
>> 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.

This one item is a "no go".  It gets too hard to mentions an enum value,
have to supply the class
and some of the containing class names are long enough to make the very
inconvenient.  There is
no way to provide a typedef to shorten the value name either, whereas with a
namespace containing
the enum, there is.  I spent too much time on this, actually began to
dislike C++ while doing so,
and I think the issue is very settled in my mind.


>> *) 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.

SPECCTRA_DB is done but it was more than 40 changed lines of code.  :)

I think all the changes were however, nothing but simplifications, and a
move in the right direction.
This seems now like a firm foundation to build LOTS more on top of.

Dick




References