/* * 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 */ #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 ) : owner( aOwner ), contains( 0 ), partNameAndRev( aPartNameAndRev ), extends( 0 ), base( 0 ) { // Our goal is to have class LIB only instantiate what is needed, so print here // what it is doing. It is the only class where PART can be instantiated. D(printf("PART::PART(%s)\n", aPartNameAndRev.c_str() );) } PART::~PART() { delete extends; } void PART::setExtends( LPID* aLPID ) { delete extends; extends = aLPID; } void PART::inherit( const PART& other ) { contains = other.contains; // @todo copy the inherited drawables, properties, and pins here } PART& PART::operator=( const PART& other ) { owner = other.owner; partNameAndRev = other.partNameAndRev; body = other.body; base = other.base; setExtends( other.extends ? new LPID( *other.extends ) : 0 ); // maintain in concert with inherit(), which is a partial assignment operator. inherit( other ); return *this; } void PART::Parse( SWEET_LEXER* aLexer, LIB_TABLE* aTable ) throw( IO_ERROR ) { PART_PARSER( this, aLexer, aTable ); } #if 0 && defined(DEBUG) int main( int argc, char** argv ) { return 0; } #endif