From f8263c0e62a535e8bd3f2904afacdaa1a4cdaf0b Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Mon, 14 Feb 2011 00:39:51 -0600 Subject: [PATCH] sweet parser work --- common/dsnlexer.cpp | 14 ++ include/dsnlexer.h | 9 + new/CMakeLists.txt | 1 + new/eeschema_part_sexpr_format_EN.odt | Bin 0 -> 27293 bytes new/sch_lib.cpp | 6 +- new/sch_part.cpp | 286 ++-------------------- new/sch_part.h | 138 ++++++----- new/sch_sweet_parser.cpp | 336 ++++++++++++++++++++++++++ new/sch_sweet_parser.h | 95 ++++++++ 9 files changed, 554 insertions(+), 331 deletions(-) create mode 100644 new/eeschema_part_sexpr_format_EN.odt create mode 100644 new/sch_sweet_parser.cpp create mode 100644 new/sch_sweet_parser.h diff --git a/common/dsnlexer.cpp b/common/dsnlexer.cpp index 0173ad2797..f775a3cc20 100644 --- a/common/dsnlexer.cpp +++ b/common/dsnlexer.cpp @@ -351,6 +351,20 @@ int DSNLEXER::NeedSYMBOLorNUMBER() throw( IO_ERROR ) } +int DSNLEXER::NeedNUMBER( const char* aExpectation ) throw( IO_ERROR ) +{ + int tok = NextTok(); + if( tok != DSN_NUMBER ) + { + wxString errText; + + errText.Printf( _("need a NUMBER for '%s'"), wxString::FromUTF8( aExpectation ).GetData() ); + THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); + } + return tok; +} + + /** * Function isspace * strips the upper bits of the int to ensure the value passed to ::isspace() is diff --git a/include/dsnlexer.h b/include/dsnlexer.h index 268debd554..e34f7dd762 100644 --- a/include/dsnlexer.h +++ b/include/dsnlexer.h @@ -292,6 +292,15 @@ public: */ int NeedSYMBOLorNUMBER() throw( IO_ERROR ); + /** + * Function NeedNUMBER + * calls NextTok() and then verifies that the token read is type DSN_NUMBER. + * If not, and IO_ERROR is thrown using text from aExpectation. + * @return int - the actual token read in. + * @throw IO_ERROR, if the next token does not satisfy the above test + */ + int NeedNUMBER( const char* aExpectation ) throw( IO_ERROR ); + /** * Function CurTok * returns whatever NextTok() returned the last time it was called. diff --git a/new/CMakeLists.txt b/new/CMakeLists.txt index 0ef8632ef4..06c4019e34 100644 --- a/new/CMakeLists.txt +++ b/new/CMakeLists.txt @@ -108,6 +108,7 @@ add_library( sweet SHARED sch_lpid.cpp sch_dir_lib_source.cpp sch_part.cpp + sch_sweet_parser.cpp sweet_keywords.cpp ${PROJECT_SOURCE_DIR}/common/richio.cpp ${PROJECT_SOURCE_DIR}/common/dsnlexer.cpp diff --git a/new/eeschema_part_sexpr_format_EN.odt b/new/eeschema_part_sexpr_format_EN.odt new file mode 100644 index 0000000000000000000000000000000000000000..af163a13e3e3df46dd1fb9eaae43daf2300889b4 GIT binary patch literal 27293 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 #include #include -#include +#include #include @@ -253,9 +253,9 @@ PART* LIB::LookupPart( const LPID& aLPID, LIB_TABLE* aLibTable ) throw( IO_ERROR #endif // @todo consider changing ReadPart to return a "source" - SWEET_LEXER sw( part->body, wxString::FromUTF8( aLPID.Format().c_str() ) ); + SWEET_PARSER sp( part->body, wxString::FromUTF8( aLPID.Format().c_str() ) ); - part->Parse( &sw, aLibTable ); + part->Parse( &sp, aLibTable ); } return part; diff --git a/new/sch_part.cpp b/new/sch_part.cpp index 0cb263754c..b50be607ff 100644 --- a/new/sch_part.cpp +++ b/new/sch_part.cpp @@ -24,269 +24,12 @@ #include // _() #include -#include +#include #include #include + using namespace SCH; -using namespace PR; // tokens, enum T for SWEET_LEXER - - -#define MAX_INHERITANCE_NESTING 6 // no problem going larger - - -//----------------------- -struct XY {}; -struct AT {}; - -class POLY_LINE -{ - -}; - - -//---------------------- - - -/** - * Class PART_PARSER - * is a localized/hidden PART Parser. You get here through the public interface - * PART::Parse(). Advantages of private class declaration in this situation: - * 1) keeps all the recursive parsing helper functions out of the main public PART -* header file and so should speed up compilation. - * 2) Allows use of cost-less Java like inline functions, since nobody knows about - * them but this source file. Most are only used once and called from one place. - *

- * All the functions in this class throw PARSE_ERROR. If SWEET_LEXER throws, it - * may be an IO_ERROR, propogated from here also. The throws() statements are left off - * to keep the noise level down. - */ -class PART_PARSER -{ - SWEET_LEXER* in; - LIB_TABLE* libs; - int contains; // separate from PART::contains until done - // so we can see what we inherited from base PART - -public: - PART_PARSER( PART* aPart, SWEET_LEXER* aLexer, LIB_TABLE* aTable ) : - in( aLexer ), - libs( aTable ), - contains( 0 ) - { - parsePart( aPart ); - } - - - void parseXY( XY* me ) - { - } - - void parseAt( AT* me ) - { - } - - - void parseExtends( PART* me ) - { - PART* base; - int offset; - - if( contains & PB(EXTENDS) ) - in->Duplicate( T_extends ); - - in->NeedSYMBOLorNUMBER(); - me->setExtends( new LPID() ); - - offset = me->extends->Parse( in->CurText() ); - if( offset > -1 ) // -1 is success - THROW_PARSE_ERROR( _("invalid extends LPID"), - in->CurSource(), - in->CurLine(), - in->CurLineNumber(), - in->CurOffset() + offset ); - - base = libs->LookupPart( *me->extends, me->Owner() ); - - // we could be going in circles here, recursively, or too deep, set limits - // and disallow extending from self (even indirectly) - int extendsDepth = 0; - for( PART* ancestor = base; ancestor && extendsDepthbase ) - { - if( ancestor == me ) - { - THROW_PARSE_ERROR( _("'extends' may not have self as any ancestor"), - in->CurSource(), - in->CurLine(), - in->CurLineNumber(), - in->CurOffset() ); - } - } - - if( extendsDepth == MAX_INHERITANCE_NESTING ) - { - THROW_PARSE_ERROR( _("max allowed extends depth exceeded"), - in->CurSource(), - in->CurLine(), - in->CurLineNumber(), - in->CurOffset() ); - } - - me->inherit( *base ); - me->base = base; - contains |= PB(EXTENDS); - } - - /// @param me = ja mir, the object getting stuffed, from its perspective - void parsePart( PART* me ) - { - T tok; - -#if 0 - // Be flexible regarding the starting point of the stream. - // Caller may not have read the first two tokens out of the - // stream: T_LEFT and T_part, so ignore them if seen here. - // The 1st two tokens T_LEFT and T_part are then optional in the grammar. - - if( (tok = in->NextTok() ) == T_LEFT ) - { - if( ( tok = in->NextTok() ) != T_part ) - in->Expecting( T_part ); - } - -#else - // "( part" are not optional - in->NeedLEFT(); - - if( ( tok = in->NextTok() ) != T_part ) - in->Expecting( T_part ); -#endif - - in->NeedSYMBOLorNUMBER(); // read in part NAME_HINT, and toss - tok = in->NextTok(); - - // extends must be _first_ thing, if it is present at all, after NAME_HINT - if( tok == T_extends ) - { - parseExtends( me ); - tok = in->NextTok(); - } - - for( ; tok!=T_RIGHT; tok = in->NextTok() ) - { - if( tok==T_EOF ) - in->Unexpected( T_EOF ); - - if( tok == T_LEFT ) - tok = in->NextTok(); - - switch( tok ) - { - default: - // describe what we expect at this level - in->Expecting( - "anchor|value|footprint|model|keywords|alternates\n" - "|property\n" - " |property_del\n" - "|pin\n" - " |pin_merge|pin_swap|pin_renum|pin_rename|route_pin_swap\n" - "|polyline|line|rectangle|circle|arc|bezier|text" - ); - break; - - case T_anchor: - if( contains & PB(ANCHOR) ) - in->Duplicate( tok ); - contains |= PB(ANCHOR); - break; - - case T_line: - - break; - - - /* - case T_value: - if( contains & PB(VALUE) ) - in->Duplicate( tok ); - contains |= PB(VALUE); - in->NeedSYMBOLorNUMBER(); - // me->value = in->CurText(); - in->NeedRIGHT(); - break; - - case T_footprint: - break; - - case T_model: - break; - - case T_keywords: - break; - - case T_alternates: - break; - - case T_property: - break; - - case T_property_del: - break; - - case T_pin: - break; - - case T_pin_merge: - break; - - case T_pin_swap: - break; - - case T_pin_renum: - break; - - case T_pin_rename: - break; - - case T_route_pin_swap: - break; - - case T_polyline: - break; - - case T_rectangle: - break; - - case T_circle: - break; - - case T_arc: - break; - - case T_bezier: - break; - - case T_text: - break; - */ - - // Not sure about reference in a PART, comes in at COMPONENT object. - // It is maybe just a hint here or a prefix. - case T_reference: - if( contains & PB(REFERENCE) ) - in->Duplicate( tok ); - contains |= PB(REFERENCE); - break; - } - } - - contains |= PB(PARSED); - - me->contains |= contains; - } - -}; PART::PART( LIB* aOwner, const STRING& aPartNameAndRev ) : @@ -302,9 +45,26 @@ PART::PART( LIB* aOwner, const STRING& aPartNameAndRev ) : } +void PART::clear() +{ + if( extends ) + { + delete extends; + extends = 0; + } + + for( GRAPHICS::iterator it = graphics.begin(); it != graphics.end(); ++it ) + delete *it; + graphics.clear(); + + + // @todo delete all properties, pins, and graphics +} + + PART::~PART() { - delete extends; + clear(); } @@ -339,14 +99,12 @@ PART& PART::operator=( const PART& other ) } -void PART::Parse( SWEET_LEXER* aLexer, LIB_TABLE* aTable ) throw( IO_ERROR ) +void PART::Parse( SWEET_PARSER* aParser, LIB_TABLE* aTable ) throw( IO_ERROR, PARSE_ERROR ) { - PART_PARSER( this, aLexer, aTable ); + aParser->Parse( this, aTable ); } - - #if 0 && defined(DEBUG) int main( int argc, char** argv ) diff --git a/new/sch_part.h b/new/sch_part.h index a3d6441d23..03ecf2531f 100644 --- a/new/sch_part.h +++ b/new/sch_part.h @@ -1,66 +1,68 @@ -/* - * This program source code file is part of KICAD, a free EDA CAD application. - * - * Copyright (C) 2010 Kicad Developers, see change_log.txt for contributors. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - #ifndef SCH_PART_H_ #define SCH_PART_H_ #include -class SWEET_LEXER; -class PART_PARSER; + +//----------------------- + +typedef wxPoint POINT; + +#include +#include + +namespace SCH { + +class PART; +class SWEET_PARSER; + + +class BASE_GRAPHIC +{ + friend class PART; + friend class SWEET_PARSER; + +protected: + PART* owner; + +public: + BASE_GRAPHIC( PART* aOwner ) : + owner( aOwner ) + {} + + virtual ~BASE_GRAPHIC() {} +}; + + +class POLY_LINE : BASE_GRAPHIC +{ + friend class PART; + friend class SWEET_PARSER; + +protected: + double width; + std::vector pts; + +public: + POLY_LINE( PART* aOwner ) : + BASE_GRAPHIC( aOwner ) + {} +}; + + +}; + + +//---------------------- namespace SCH { +typedef std::vector< BASE_GRAPHIC* > GRAPHICS; + class LPID; - -/** - * Enum PartBit - * is a set of bit positions that can be used to create flag bits within - * PART::contains to indicate what state the PART is in and what it contains, i.e. - * whether the PART has been parsed, and what the PART contains, categorically. - */ -enum PartBit -{ - PARSED, ///< have parsed this part already, otherwise 'body' text must be parsed - EXTENDS, ///< saw "extends" keyword, inheriting from another PART - VALUE, - ANCHOR, - REFERENCE, - FOOTPRINT, - DATASHEET, - MODEL, - KEYWORDS, -}; - - -/// Function PB -/// is a PartBit shifter for PART::contains field. -static inline const int PB( PartBit oneBitOnly ) -{ - return ( 1 << oneBitOnly ); -} +class SWEET_PARSER; /** @@ -75,13 +77,20 @@ static inline const int PB( PartBit oneBitOnly ) class PART { friend class LIB; // is the owner of all PARTS, afterall - friend class ::PART_PARSER; + friend class SWEET_PARSER; protected: // not likely to have C++ descendants, but protected none-the-less. /// a protected constructor, only a LIB can instantiate a PART. PART( LIB* aOwner, const STRING& aPartNameAndRev ); + /** + * Function destroy + * clears out this object, deleting all graphics, all fields, all properties, + * etc. + */ + void clear(); + /** * Function inherit * is a specialized assignment function that copies a specific subset, enough @@ -89,33 +98,34 @@ protected: // not likely to have C++ descendants, but protected none-the-le */ void inherit( const PART& aBasePart ); + POINT anchor; //PART( LIB* aOwner ); - LIB* owner; ///< which LIB am I a part of (pun if you want) - int contains; ///< has bits from Enum PartParts + LIB* owner; ///< which LIB am I a part of (pun if you want) + int contains; ///< has bits from Enum PartParts - STRING partNameAndRev; ///< example "passives/R[/revN..]", immutable. + STRING partNameAndRev; ///< example "passives/R[/revN..]", immutable. - LPID* extends; ///< of base part, NULL if none, otherwise I own it. - PART* base; ///< which PART am I extending, if any. no ownership. + LPID* extends; ///< of base part, NULL if none, otherwise I own it. + PART* base; ///< which PART am I extending, if any. no ownership. /// encapsulate the old version deletion, take ownership of @a aLPID void setExtends( LPID* aLPID ); /// s-expression text for the part, initially empty, and read in as this part /// actually becomes cached in RAM. - STRING body; + STRING body; // bool cachedRevisions; ///< allows lazy loading of revision of this same part name // 3 separate lists for speed: /// A property list. - //PROPERTIES properties; + //PROPERTIES properties; /// A drawing list for graphics - //DRAWINGS drawings; + GRAPHICS graphics; /// A pin list //PINS pins; @@ -127,7 +137,7 @@ protected: // not likely to have C++ descendants, but protected none-the-le public: - ~PART(); + virtual ~PART(); PART& operator=( const PART& other ); @@ -143,12 +153,12 @@ public: * by the normal fields of this class. Parse is expected to call Inherit() * if this part extends any other. * - * @param aLexer is an instance of SWEET_LEXER, rewound at the first line. + * @param aParser is an instance of SWEET_PARSER, rewound at the first line. * * @param aLibTable is the LIB_TABLE "view" that is in effect for inheritance, * and comes from the big containing SCHEMATIC object. */ - void Parse( SWEET_LEXER* aLexer, LIB_TABLE* aLibTable ) throw( IO_ERROR ); + void Parse( SWEET_PARSER* aParser, LIB_TABLE* aLibTable ) throw( IO_ERROR, PARSE_ERROR ); /* void SetBody( const STR_UTF& aSExpression ) diff --git a/new/sch_sweet_parser.cpp b/new/sch_sweet_parser.cpp new file mode 100644 index 0000000000..a3b994b00b --- /dev/null +++ b/new/sch_sweet_parser.cpp @@ -0,0 +1,336 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2011 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2010 Kicad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +using namespace SCH; +using namespace PR; + + +#define MAX_INHERITANCE_NESTING 6 // no problem going larger + +/** + * Function log2int + * converts a logical coordinate to an internal coordinate. Logical coordinates + * are defined as the standard distance between pins being equal to one. + * Internal coordinates are 1000 times that. + */ +static inline int log2int( double aCoord ) +{ + return int( aCoord * 1000 ); +} + +static inline int internal( const STRING& aCoord ) +{ + return log2int( strtod( aCoord.c_str(), NULL ) ); +} + + +/** + * Enum PartBit + * is a set of bit positions that can be used to create flag bits within + * PART::contains to indicate what state the PART is in and what it contains, i.e. + * whether the PART has been parsed, and what the PART contains, categorically. + */ +enum PartBit +{ + PARSED, ///< have parsed this part already, otherwise 'body' text must be parsed + EXTENDS, ///< saw "extends" keyword, inheriting from another PART + VALUE, + ANCHOR, + REFERENCE, + FOOTPRINT, + DATASHEET, + MODEL, + KEYWORDS, +}; + + +/// Function PB +/// is a PartBit shifter for PART::contains field. +static inline const int PB( PartBit oneBitOnly ) +{ + return ( 1 << oneBitOnly ); +} + + + +void SWEET_PARSER::parseExtends( PART* me ) +{ + PART* base; + int offset; + + if( contains & PB(EXTENDS) ) + Duplicate( T_extends ); + + NeedSYMBOLorNUMBER(); + me->setExtends( new LPID() ); + + offset = me->extends->Parse( CurText() ); + if( offset > -1 ) // -1 is success + THROW_PARSE_ERROR( _("invalid extends LPID"), + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() + offset ); + + base = libs->LookupPart( *me->extends, me->Owner() ); + + // we could be going in circles here, recursively, or too deep, set limits + // and disallow extending from self (even indirectly) + int extendsDepth = 0; + for( PART* ancestor = base; ancestor && extendsDepthbase ) + { + if( ancestor == me ) + { + THROW_PARSE_ERROR( _("'extends' may not have self as any ancestor"), + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + } + + if( extendsDepth == MAX_INHERITANCE_NESTING ) + { + THROW_PARSE_ERROR( _("max allowed extends depth exceeded"), + CurSource(), + CurLine(), + CurLineNumber(), + CurOffset() ); + } + + me->inherit( *base ); + me->base = base; + contains |= PB(EXTENDS); +} + + +void SWEET_PARSER::Parse( PART* me, LIB_TABLE* aTable ) throw( IO_ERROR, PARSE_ERROR ) +{ + T tok; + + libs = aTable; + + // empty everything out, could be re-parsing this object and it may not be empty. + me->clear(); + +#if 0 + // Be flexible regarding the starting point of the stream. + // Caller may not have read the first two tokens out of the + // stream: T_LEFT and T_part, so ignore them if seen here. + // The 1st two tokens T_LEFT and T_part are then optional in the grammar. + + if( (tok = NextTok() ) == T_LEFT ) + { + if( ( tok = NextTok() ) != T_part ) + Expecting( T_part ); + } + +#else + // "( part" are not optional + NeedLEFT(); + + if( ( tok = NextTok() ) != T_part ) + Expecting( T_part ); +#endif + + NeedSYMBOLorNUMBER(); // read in part NAME_HINT, and toss + tok = NextTok(); + + // extends must be _first_ thing, if it is present at all, after NAME_HINT + if( tok == T_extends ) + { + parseExtends( me ); + tok = NextTok(); + } + + for( ; tok!=T_RIGHT; tok = NextTok() ) + { + if( tok==T_EOF ) + Unexpected( T_EOF ); + + if( tok == T_LEFT ) + tok = NextTok(); + + switch( tok ) + { + default: + // describe what we expect at this level + Expecting( + "anchor|value|footprint|model|keywords|alternates\n" + "|property\n" + " |property_del\n" + "|pin\n" + " |pin_merge|pin_swap|pin_renum|pin_rename|route_pin_swap\n" + "|polyline|line|rectangle|circle|arc|bezier|text" + ); + break; + + case T_anchor: + if( contains & PB(ANCHOR) ) + Duplicate( tok ); + NeedNUMBER( "anchor x" ); + me->anchor.x = internal( CurText() ); + NeedNUMBER( "anchor y" ); + me->anchor.y = internal( CurText() ); + contains |= PB(ANCHOR); + break; + + case T_line: + POLY_LINE* pl; + pl = new POLY_LINE( me ); + me->graphics.push_back( pl ); + parsePolyLine( pl ); + break; + + + /* + case T_value: + if( contains & PB(VALUE) ) + Duplicate( tok ); + contains |= PB(VALUE); + NeedSYMBOLorNUMBER(); + // me->value = CurText(); + NeedRIGHT(); + break; + + case T_footprint: + break; + + case T_model: + break; + + case T_keywords: + break; + + case T_alternates: + break; + + case T_property: + break; + + case T_property_del: + break; + + case T_pin: + break; + + case T_pin_merge: + break; + + case T_pin_swap: + break; + + case T_pin_renum: + break; + + case T_pin_rename: + break; + + case T_route_pin_swap: + break; + + case T_polyline: + break; + + case T_rectangle: + break; + + case T_circle: + break; + + case T_arc: + break; + + case T_bezier: + break; + + case T_text: + break; + */ + + // Not sure about reference in a PART, comes in at COMPONENT object. + // It is maybe just a hint here or a prefix. + case T_reference: + if( contains & PB(REFERENCE) ) + Duplicate( tok ); + contains |= PB(REFERENCE); + break; + } + } + + contains |= PB(PARSED); + + me->contains |= contains; +} + + +void SWEET_PARSER::parsePolyLine( POLY_LINE* me ) +{ + T tok; + int count; + + NeedLEFT(); + while( ( tok = NextTok() ) != T_RIGHT ) + { + NeedLEFT(); + + tok = NextTok(); + switch( tok ) + { + case T_line_width: + NeedNUMBER( "line_width" ); + me->width = strtod( CurText(), NULL ); + break; + + case T_pts: + for( count=0; ( tok = NextTok() ) != T_RIGHT; ++count ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NeedSYMBOL(); + if( tok != T_xy ) + Expecting( T_xy ); + + /* @todo resume here, its late + NeedNUMBER(); + */ + } + break; + + case T_fill: + break; + + default: + Expecting( "pts|line_width|fill" ); + } + } +} + diff --git a/new/sch_sweet_parser.h b/new/sch_sweet_parser.h new file mode 100644 index 0000000000..518b1710a3 --- /dev/null +++ b/new/sch_sweet_parser.h @@ -0,0 +1,95 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2011 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2010 Kicad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef SCH_SWEET_PARSER_H_ +#define SCH_SWEET_PARSER_H_ + +#include +#include + + +namespace SCH { + +class LIB_TABLE; +class PART; +class POLY_LINE; + + +/** + * Class SWEET_PARSER + * scans a Sweet string as input and stuffs a PART. + *

+ * Most functions in this class throw IO_ERROR and PARSE_ERROR. The IO_ERROR can + * happen if there is difficulty reading the input stream. + */ +class SWEET_PARSER : public SWEET_LEXER +{ + LIB_TABLE* libs; + int contains; // separate from PART::contains until done + // so we can see what we inherited from base PART + + // all these private functions rely on libs having been set via the public API, Parse( PART*) + + void parseExtends( PART* me ); + + void parsePolyLine( POLY_LINE* me ); + + +public: + + /** + * Constructor SWEET_PARSER + * takes aSweet string and gets ready to parse it. + * @param aSweet is the full description of a PART. + * @param aSource is used in error reporting and describes where the Sweet + * string came from in any appropriate way. + */ + SWEET_PARSER( const STRING& aSweet, const wxString& aSource = wxEmptyString ) : + SWEET_LEXER( aSweet, aSource ), + libs( 0 ), + contains( 0 ) + { + } + + SWEET_PARSER( LINE_READER* aLineReader ) : + SWEET_LEXER( aLineReader ), + libs( 0 ), + contains( 0 ) + { + } + + /** + * Function Parse + * stuffs @a aPart with data from this SWEET_LEXER, which has its own + * sweet string source. + * @param aPart is what is to be stuffed. + * @param aTable is the view of the LIBs in play. + */ + void Parse( PART* aPart, LIB_TABLE* aTable ) throw( IO_ERROR, PARSE_ERROR ); +}; + +} // namespace SCH + +#endif // SCH_SWEET_PARSER_H_ +