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 0000000000..af163a13e3 Binary files /dev/null and b/new/eeschema_part_sexpr_format_EN.odt differ diff --git a/new/sch_lib.cpp b/new/sch_lib.cpp index bad2ec3f1d..e76e09543d 100644 --- a/new/sch_lib.cpp +++ b/new/sch_lib.cpp @@ -29,7 +29,7 @@ #include #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_ +