Loading pcbnew/dsn.cpp +100 −12 Original line number Original line Diff line number Diff line Loading @@ -156,6 +156,7 @@ const static KEYWORD tokens[] = { TOKDEF(host_cad), TOKDEF(host_cad), TOKDEF(host_version), TOKDEF(host_version), TOKDEF(image), TOKDEF(image), TOKDEF(image_conductor), TOKDEF(image_image), TOKDEF(image_image), TOKDEF(image_image_spacing), TOKDEF(image_image_spacing), TOKDEF(image_outline_clearance), TOKDEF(image_outline_clearance), Loading Loading @@ -464,6 +465,25 @@ int LINE_READER::ReadLine() throw (IOError) //-----<LEXER>------------------------------------------------------------- //-----<LEXER>------------------------------------------------------------- LEXER::LEXER( FILE* aFile, const wxString& aFilename ) : reader( aFile, 4096 ) { curTok = T_END; stringDelimiter = '"'; filename = aFilename; space_in_quoted_tokens = false; // "start" should never change until we change the reader. The DSN // format spec supports an include file mechanism but we can add that later // using a std::stack to hold a stack of LINE_READERs to track nesting. start = (char*) reader; limit = start; next = start; } int LEXER::findToken( const std::string& tok ) int LEXER::findToken( const std::string& tok ) { { // convert to lower case once, this should be faster than using strcasecmp() // convert to lower case once, this should be faster than using strcasecmp() Loading @@ -486,15 +506,69 @@ int LEXER::findToken( const std::string& tok ) } } wxString LEXER::GetTokenText( DSN_T aTok ) { wxString ret; if( aTok < 0 ) { switch( aTok ) { case T_QUOTE_DEF: ret << _("'quoted text delimiter'"); break; case T_DASH: ret << wxT( "'-'" ); break; case T_SYMBOL: ret << _("'symbol'"); break; case T_NUMBER: ret << _("'number'"); break; case T_RIGHT: ret << wxT( "')'" ); break; case T_LEFT: ret << wxT( "'('" ); break; case T_STRING: ret << _("\"quoted string\""); break; case T_EOF: ret << _("'end of file'"); break; default: ; } } else { ret << wxT("'") << CONV_FROM_UTF8( tokens[aTok].name ) << wxT("'"); } return ret; } void LEXER::ThrowIOError( wxString aText, int charOffset ) throw (IOError) { aText << wxT(" ") << _("in file") << wxT(" \"") << filename << wxT("\" ") << _("on line") << wxT(" ") << reader.LineNumber() << wxT(" ") << _("at offset") << wxT(" ") << charOffset; throw IOError( aText ); } DSN_T LEXER::NextTok() throw (IOError) DSN_T LEXER::NextTok() throw (IOError) { { char* head; char* cur = next; char* cur; char* head = cur; lastTok = curTok; lastTok = curTok; cur = next; if( curTok != T_EOF ) if( curTok != T_EOF ) { { if( cur >= limit ) if( cur >= limit ) Loading @@ -520,15 +594,27 @@ L_read: // switching the string_quote character // switching the string_quote character if( lastTok == T_string_quote ) if( lastTok == T_string_quote ) { { static const wxString errtxt( _("String delimiter must be a single character of ', \", or $")); char cc = *cur; switch( cc ) { case '\'': case '$': case '"': break; default: ThrowIOError( errtxt, CurOffset() ); } curText.clear(); curText.clear(); curText += *cur; curText += cc; head = cur+1; head = cur+1; if( head<limit && *head!=')' && *head!='(' && !isspace(*head) ) if( head<limit && *head!=')' && *head!='(' && !isspace(*head) ) { { wxString errtxt(_("String delimiter char must be a single char") ); ThrowIOError( errtxt, CurOffset() ); ThrowIOError( errtxt, cur-start+1 ); } } curTok = T_QUOTE_DEF; curTok = T_QUOTE_DEF; Loading Loading @@ -578,17 +664,17 @@ L_read: // a quoted string // a quoted string else if( *cur == stringDelimiter ) else if( *cur == stringDelimiter ) { { ++cur; // skip over the leading " ++cur; // skip over the leading delimiter: ",', or $ head = cur; head = cur; while( head<limit && *head!=stringDelimiter ) while( head<limit && !isStringTerminator( *head ) ) ++head; ++head; if( head >= limit ) if( head >= limit ) { { wxString errtxt(_("Un-terminated delimited string") ); wxString errtxt(_("Un-terminated delimited string") ); ThrowIOError( errtxt, cur-start+1 ); ThrowIOError( errtxt, CurOffset() ); } } curText.clear(); curText.clear(); Loading Loading @@ -630,6 +716,8 @@ L_read: exit: // single point of exit exit: // single point of exit curOffset = cur - start; next = head; next = head; return curTok; return curTok; Loading @@ -640,7 +728,7 @@ exit: // single point of exit #if defined(STANDALONE) #if 0 && defined(STANDALONE) // stand alone testing // stand alone testing Loading pcbnew/dsn.h +46 −26 Original line number Original line Diff line number Diff line Loading @@ -42,11 +42,10 @@ namespace DSN { enum DSN_T { enum DSN_T { // the first few are special (the uppercase ones) // the first few are special (the uppercase ones) T_QUOTE_DEF = -9, T_QUOTE_DEF = -8, T_DASH = -8, T_DASH = -7, T_SYMBOL = -7, T_SYMBOL = -6, T_NUMBER = -6, T_NUMBER = -5, T_NONE = -5, // not a token T_RIGHT = -4, // right bracket, ')' T_RIGHT = -4, // right bracket, ')' T_LEFT = -3, // left bracket, '(' T_LEFT = -3, // left bracket, '(' T_STRING = -2, // a quoted string, stripped of the quotes T_STRING = -2, // a quoted string, stripped of the quotes Loading Loading @@ -157,6 +156,7 @@ enum DSN_T { T_host_cad, T_host_cad, T_host_version, T_host_version, T_image, T_image, T_image_conductor, T_image_image, T_image_image, T_image_image_spacing, T_image_image_spacing, T_image_outline_clearance, T_image_outline_clearance, Loading Loading @@ -513,8 +513,11 @@ class LEXER LINE_READER reader; LINE_READER reader; int stringDelimiter; int stringDelimiter; bool space_in_quoted_tokens; ///< blank spaces within quoted strings wxString filename; wxString filename; int lastTok; ///< curTok from previous NextTok() call. int lastTok; ///< curTok from previous NextTok() call. int curOffset; ///< offset within current line of the current token DSN_T curTok; ///< the current token obtained on last NextTok() DSN_T curTok; ///< the current token obtained on last NextTok() std::string curText; ///< the text of the current token std::string curText; ///< the text of the current token Loading Loading @@ -543,24 +546,22 @@ class LEXER */ */ int findToken( const std::string& tok ); int findToken( const std::string& tok ); bool isStringTerminator( char cc ) public: LEXER( FILE* aFile, const wxString& aFilename ) : reader( aFile, 4096 ) { { curTok = T_NONE; if( !space_in_quoted_tokens && cc==' ' ) stringDelimiter = '"'; return true; filename = aFilename; // "start" should never change until we change the reader. The DSN if( cc == stringDelimiter ) // format spec supports an include file mechanism but we can add that later return true; // using a std::stack to hold a stack of LINE_READERs to track nesting. start = (char*) reader; limit = start; return false; next = start; } } public: LEXER( FILE* aFile, const wxString& aFilename ); /** /** * Function SetStringDelimiter * Function SetStringDelimiter * changes the string delimiter from the default " to some other character * changes the string delimiter from the default " to some other character Loading @@ -575,6 +576,19 @@ public: return old; return old; } } /** * Function SetSpaceInQuotedTokens * changes the setting controlling whether a space in a quoted string is * a terminator */ bool SetSpaceInQuotedTokens( bool val ) { bool old = space_in_quoted_tokens; space_in_quoted_tokens = val; return old; } /** /** * Function NextTok * Function NextTok * returns the next token found in the input file or T_EOF when reaching * returns the next token found in the input file or T_EOF when reaching Loading @@ -590,14 +604,10 @@ public: * encapsulates the formatting of an error message which contains the exact * encapsulates the formatting of an error message which contains the exact * location within the input file of a lexical error. * location within the input file of a lexical error. */ */ void ThrowIOError( wxString aText, int charOffset ) throw (IOError) void ThrowIOError( wxString aText, int charOffset ) throw (IOError); { aText << wxT(" ") << _("in file") << wxT(" \"") << filename << wxT("\" ") << _("on line") << wxT(" ") << reader.LineNumber() << wxT(" ") << _("at offset") << wxT(" ") << charOffset; throw IOError( aText ); } wxString GetTokenText( DSN_T aTok ); /** /** Loading @@ -619,6 +629,16 @@ public: return curTok; return curTok; } } /** * Function CurOffset * returns the char offset within the current line, using a 1 based index. * @return int - a one based index into the current line. */ int CurOffset() { return curOffset + 1; } }; }; Loading pcbnew/specctra.cpp +370 −28 Original line number Original line Diff line number Diff line Loading @@ -29,7 +29,7 @@ #include <boost/ptr_container/ptr_vector.hpp> #include <boost/ptr_container/ptr_vector.hpp> #include <wx/ffile.h> #include "fctsys.h" #include "fctsys.h" #include "pcbstruct.h" #include "pcbstruct.h" Loading @@ -43,7 +43,6 @@ namespace DSN { * is a base class for any DSN element. It is not a parent node so it * is a base class for any DSN element. It is not a parent node so it * cannot contain other elements but it can be extended to hold fields * cannot contain other elements but it can be extended to hold fields * for any DSN element which contains no other elements, only fields. * for any DSN element which contains no other elements, only fields. */ class ELEM class ELEM { { protected: protected: Loading @@ -58,26 +57,24 @@ public: virtual ~ELEM() virtual ~ELEM() { { printf("~ELEM(%p %d)\n", this, Type() ); // printf("~ELEM(%p %d)\n", this, Type() ); } } DSN_T Type() { return type; } virtual void Test() { printf("virtual Test()\n" ); } }; }; */ /** /** * Class PARENT * Class ELEM * is a base class holder for any DSN element. It can contain other * is a holder for any DSN element. It can contain other * elements, including elements derived from this class. * elements, including elements derived from this class. */ */ class PARENT : public ELEM class ELEM { { protected: DSN_T type; // see http://www.boost.org/libs/ptr_container/doc/ptr_sequence_adapter.html // see http://www.boost.org/libs/ptr_container/doc/ptr_sequence_adapter.html typedef boost::ptr_vector<ELEM> ELEM_ARRAY; typedef boost::ptr_vector<ELEM> ELEM_ARRAY; Loading @@ -86,18 +83,53 @@ public: public: public: PARENT( DSN_T aType ) : ELEM( DSN_T aType ) : ELEM( aType ) type( aType ) { { } } virtual ~PARENT() virtual ~ELEM() { { printf("~PARENT(%p %d)\n", this, Type() ); // printf("~ELEM(%p %d)\n", this, Type() ); } } DSN_T Type() { return type; } //-----< list operations >-------------------------------------------- //-----< list operations >-------------------------------------------- /** * Function FindElem * finds a particular instance number of a given type of ELEM. * @param aType The type of ELEM to find * @param instanceNum The instance number of to find: 0 for first, 1 for second, etc. * @return int - The index into the kids array or -1 if not found. */ int FindElem( DSN_T aType, int instanceNum ) { int repeats=0; for( unsigned i=0; i<kids.size(); ++i ) { if( kids[i].Type() == aType ) { if( repeats == instanceNum ) return i; ++repeats; } } return -1; } /** * Function Length * returns the number ELEMs in this ELEM. * @return int - the count of children */ int Length() const { return kids.size(); } void Append( ELEM* aElem ) void Append( ELEM* aElem ) { { kids.push_back( aElem ); kids.push_back( aElem ); Loading @@ -115,6 +147,7 @@ public: return ret.release(); return ret.release(); } } /* ELEM& operator[]( int aIndex ) ELEM& operator[]( int aIndex ) { { return kids[aIndex]; return kids[aIndex]; Loading @@ -124,14 +157,17 @@ public: { { return kids[aIndex]; return kids[aIndex]; } } */ void Insert( int aIndex, ELEM* aElem ) void Insert( int aIndex, ELEM* aElem ) { { kids.insert( kids.begin()+aIndex, aElem ); kids.insert( kids.begin()+aIndex, aElem ); } } ELEM* At( int aIndex ) ELEM* operator[]( int aIndex ) { { // we have varying sized object and are using polymorphism, so we // must return a pointer not a reference. return &kids[aIndex]; return &kids[aIndex]; } } Loading @@ -139,20 +175,20 @@ public: { { kids.erase( kids.begin()+aIndex ); kids.erase( kids.begin()+aIndex ); } } }; }; /** /** * Class SPECCTRA_DB * Class SPECCTRA_DB * holds a DSN data tree, usually coming from a DSN file. * holds a DSN data tree, usually coming from a DSN file. */ */ class SPECCTRA_DB class SPECCTRA_DB { { FILE* fp; LEXER* lexer; ELEM* tree; FILE* fp; /** /** Loading @@ -164,15 +200,49 @@ class SPECCTRA_DB */ */ void print( const char* fmt, ... ); void print( const char* fmt, ... ); /** * Function nextTok * returns the next token from the lexer. */ DSN_T nextTok(); void expecting( DSN_T ) throw( IOError ); void expecting( const wxChar* text ) throw( IOError ); void doPCB( ELEM* growth ) throw(IOError); void doPARSER( ELEM* growth ) throw(IOError); void doRESOLUTION( ELEM* growth ) throw(IOError); public: public: SPECCTRA_DB( FILE* aFile ) : SPECCTRA_DB() fp( aFile ) { { lexer = 0; tree = 0; fp = 0; } } ~SPECCTRA_DB() { delete lexer; delete tree; if( fp ) fclose( fp ); } /** * Function Load * is a recursive descent parser for a DSN file. * @param filename The name of the dsn file to load. * @throw IOError if there is a lexer or parser error. */ void Load( const wxString& filename ) throw( IOError ); void ThrowIOError( const wxChar* fmt, ... ) throw( IOError ); /** /** * Function Export * Function Export Loading @@ -180,10 +250,261 @@ public: * @param aBoard The BOARD to save. * @param aBoard The BOARD to save. */ */ void Export( BOARD* aBoard ); void Export( BOARD* aBoard ); }; }; void SPECCTRA_DB::ThrowIOError( const wxChar* fmt, ... ) throw( IOError ) { wxString errText; va_list args; va_start( args, fmt ); errText.PrintfV( fmt, args ); va_end( args ); throw IOError( errText ); } void SPECCTRA_DB::expecting( DSN_T aTok ) throw( IOError ) { wxString errText( _("Expecting") ); errText << wxT(" ") << lexer->GetTokenText( aTok ); lexer->ThrowIOError( errText, lexer->CurOffset() ); } void SPECCTRA_DB::expecting( const wxChar* text ) throw( IOError ) { wxString errText( _("Expecting") ); errText << wxT(" '") << text << wxT("'"); lexer->ThrowIOError( errText, lexer->CurOffset() ); } DSN_T SPECCTRA_DB::nextTok() { return lexer->NextTok(); } void SPECCTRA_DB::Load( const wxString& filename ) throw( IOError ) { wxFFile file( filename.c_str() ); if( !file.IsOpened() ) { ThrowIOError( _("Unable to open file \"%s\""), filename.GetData() ); } delete lexer; lexer = 0; lexer = new LEXER( file.fp(), filename ); if( nextTok() != T_LEFT ) expecting( T_LEFT ); if( nextTok() != T_pcb ) expecting( T_pcb ); tree = new ELEM( T_pcb ); doPCB( tree ); } void SPECCTRA_DB::doPCB( ELEM* growth ) throw( IOError ) { ELEM* child; DSN_T tok = nextTok(); switch( tok ) { case T_SYMBOL: case T_STRING: break; default: expecting( T_STRING ); } while( (tok = nextTok()) != T_EOF ) { if( tok != T_LEFT ) expecting( T_LEFT ); tok = nextTok(); switch( tok ) { case T_parser: child = new ELEM( T_parser ); growth->Append( child ); doPARSER( child ); break; case T_unit: child = new ELEM( T_unit ); growth->Append( child ); break; case T_resolution: child = new ELEM( T_resolution ); growth->Append( child ); doRESOLUTION( child ); break; case T_structure: case T_placement: case T_library: break; default: expecting( wxT("parser, unit, resolution, or structure") ); } } } void SPECCTRA_DB::doPARSER( ELEM* growth ) throw( IOError ) { DSN_T tok; while( (tok = nextTok()) != T_RIGHT ) { if( tok != T_LEFT ) expecting( T_LEFT ); tok = nextTok(); switch( tok ) { case T_string_quote: tok = nextTok(); if( tok != T_QUOTE_DEF ) expecting( T_QUOTE_DEF ); lexer->SetStringDelimiter( (unsigned char) *lexer->CurText() ); break; case T_space_in_quoted_tokens: tok = nextTok(); if( tok!=T_on && tok!=T_off ) expecting( _("on or off") ); lexer->SetSpaceInQuotedTokens( tok==T_on ); break; case T_host_cad: tok = nextTok(); if( tok!=T_STRING && tok!=T_SYMBOL ) expecting( T_SYMBOL ); // @todo break; case T_host_version: tok = nextTok(); if( tok!=T_STRING && tok!=T_SYMBOL ) expecting( T_SYMBOL ); // @todo break; case T_constant: tok = nextTok(); if( tok!=T_STRING && tok!=T_SYMBOL ) expecting( T_SYMBOL ); tok = nextTok(); if( tok!=T_STRING && tok!=T_SYMBOL ) expecting( T_SYMBOL ); // @todo break; case T_write_resolution: // [(writee_resolution {<character> <positive_integer >})] while( (tok = nextTok()) != T_RIGHT ) { if( tok!=T_SYMBOL ) expecting( T_SYMBOL ); tok = nextTok(); if( tok!=T_NUMBER ) expecting( T_NUMBER ); // @todo } continue; // we ate the T_RIGHT case T_routes_include: // [(routes_include {[testpoint | guides | image_conductor]})] while( (tok = nextTok()) != T_RIGHT ) { switch( tok ) { case T_testpoint: case T_guide: case T_image_conductor: // @todo break; default: expecting( _("testpoint, guides, or image_conductor") ); } } continue; // we ate the T_RIGHT case T_wires_include: // [(wires_include testpoint)] tok = nextTok(); if( tok != T_testpoint ) expecting( T_testpoint ); // @todo break; case T_case_sensitive: tok = nextTok(); if( tok!=T_on && tok!=T_off ) expecting( _("on or off") ); // @todo break; case T_via_rotate_first: // [(via_rotate_first [on | off])] tok = nextTok(); if( tok!=T_on && tok!=T_off ) expecting( _("on or off") ); // @todo break; default: expecting( wxT("parser_descriptor contents") ); } tok = nextTok(); if( tok != T_RIGHT ) expecting( T_RIGHT ); } } void SPECCTRA_DB::doRESOLUTION( ELEM* growth ) throw(IOError) { DSN_T tok = nextTok(); switch( tok ) { case T_inch: case T_mil: case T_cm: case T_mm: case T_um: // @todo break; default: expecting( wxT("inch, mil, cm, mm, or um") ); } tok = nextTok(); if( tok != T_NUMBER ) expecting( T_NUMBER ); tok = nextTok(); if( tok != T_RIGHT ) expecting( T_RIGHT ); } void SPECCTRA_DB::print( const char* fmt, ... ) void SPECCTRA_DB::print( const char* fmt, ... ) { { Loading @@ -210,15 +531,36 @@ using namespace DSN; int main( int argc, char** argv ) int main( int argc, char** argv ) { { PARENT parent( T_pcb ); #if 0 ELEM parent( T_pcb ); PARENT* child = new PARENT( T_absolute ); ELEM* child = new ELEM( T_absolute ); parent.Append( child ); parent.Append( child ); parent.At(0)->Test(); parent[0]->Test(); child->Append( new ELEM( T_absolute ) ); child->Append( new ELEM( T_absolute ) ); #else wxString filename( wxT("/tmp/fpcroute/Sample_1sided/demo_1sided.dsn") ); // wxString filename( wxT("/tmp/testdesigns/test.dsn") ); SPECCTRA_DB db; try { db.Load( filename ); } catch( IOError ioe ) { printf( "%s\n", CONV_TO_UTF8(ioe.errorText) ); exit(1); } printf("loaded OK\n"); #endif } } Loading Loading
pcbnew/dsn.cpp +100 −12 Original line number Original line Diff line number Diff line Loading @@ -156,6 +156,7 @@ const static KEYWORD tokens[] = { TOKDEF(host_cad), TOKDEF(host_cad), TOKDEF(host_version), TOKDEF(host_version), TOKDEF(image), TOKDEF(image), TOKDEF(image_conductor), TOKDEF(image_image), TOKDEF(image_image), TOKDEF(image_image_spacing), TOKDEF(image_image_spacing), TOKDEF(image_outline_clearance), TOKDEF(image_outline_clearance), Loading Loading @@ -464,6 +465,25 @@ int LINE_READER::ReadLine() throw (IOError) //-----<LEXER>------------------------------------------------------------- //-----<LEXER>------------------------------------------------------------- LEXER::LEXER( FILE* aFile, const wxString& aFilename ) : reader( aFile, 4096 ) { curTok = T_END; stringDelimiter = '"'; filename = aFilename; space_in_quoted_tokens = false; // "start" should never change until we change the reader. The DSN // format spec supports an include file mechanism but we can add that later // using a std::stack to hold a stack of LINE_READERs to track nesting. start = (char*) reader; limit = start; next = start; } int LEXER::findToken( const std::string& tok ) int LEXER::findToken( const std::string& tok ) { { // convert to lower case once, this should be faster than using strcasecmp() // convert to lower case once, this should be faster than using strcasecmp() Loading @@ -486,15 +506,69 @@ int LEXER::findToken( const std::string& tok ) } } wxString LEXER::GetTokenText( DSN_T aTok ) { wxString ret; if( aTok < 0 ) { switch( aTok ) { case T_QUOTE_DEF: ret << _("'quoted text delimiter'"); break; case T_DASH: ret << wxT( "'-'" ); break; case T_SYMBOL: ret << _("'symbol'"); break; case T_NUMBER: ret << _("'number'"); break; case T_RIGHT: ret << wxT( "')'" ); break; case T_LEFT: ret << wxT( "'('" ); break; case T_STRING: ret << _("\"quoted string\""); break; case T_EOF: ret << _("'end of file'"); break; default: ; } } else { ret << wxT("'") << CONV_FROM_UTF8( tokens[aTok].name ) << wxT("'"); } return ret; } void LEXER::ThrowIOError( wxString aText, int charOffset ) throw (IOError) { aText << wxT(" ") << _("in file") << wxT(" \"") << filename << wxT("\" ") << _("on line") << wxT(" ") << reader.LineNumber() << wxT(" ") << _("at offset") << wxT(" ") << charOffset; throw IOError( aText ); } DSN_T LEXER::NextTok() throw (IOError) DSN_T LEXER::NextTok() throw (IOError) { { char* head; char* cur = next; char* cur; char* head = cur; lastTok = curTok; lastTok = curTok; cur = next; if( curTok != T_EOF ) if( curTok != T_EOF ) { { if( cur >= limit ) if( cur >= limit ) Loading @@ -520,15 +594,27 @@ L_read: // switching the string_quote character // switching the string_quote character if( lastTok == T_string_quote ) if( lastTok == T_string_quote ) { { static const wxString errtxt( _("String delimiter must be a single character of ', \", or $")); char cc = *cur; switch( cc ) { case '\'': case '$': case '"': break; default: ThrowIOError( errtxt, CurOffset() ); } curText.clear(); curText.clear(); curText += *cur; curText += cc; head = cur+1; head = cur+1; if( head<limit && *head!=')' && *head!='(' && !isspace(*head) ) if( head<limit && *head!=')' && *head!='(' && !isspace(*head) ) { { wxString errtxt(_("String delimiter char must be a single char") ); ThrowIOError( errtxt, CurOffset() ); ThrowIOError( errtxt, cur-start+1 ); } } curTok = T_QUOTE_DEF; curTok = T_QUOTE_DEF; Loading Loading @@ -578,17 +664,17 @@ L_read: // a quoted string // a quoted string else if( *cur == stringDelimiter ) else if( *cur == stringDelimiter ) { { ++cur; // skip over the leading " ++cur; // skip over the leading delimiter: ",', or $ head = cur; head = cur; while( head<limit && *head!=stringDelimiter ) while( head<limit && !isStringTerminator( *head ) ) ++head; ++head; if( head >= limit ) if( head >= limit ) { { wxString errtxt(_("Un-terminated delimited string") ); wxString errtxt(_("Un-terminated delimited string") ); ThrowIOError( errtxt, cur-start+1 ); ThrowIOError( errtxt, CurOffset() ); } } curText.clear(); curText.clear(); Loading Loading @@ -630,6 +716,8 @@ L_read: exit: // single point of exit exit: // single point of exit curOffset = cur - start; next = head; next = head; return curTok; return curTok; Loading @@ -640,7 +728,7 @@ exit: // single point of exit #if defined(STANDALONE) #if 0 && defined(STANDALONE) // stand alone testing // stand alone testing Loading
pcbnew/dsn.h +46 −26 Original line number Original line Diff line number Diff line Loading @@ -42,11 +42,10 @@ namespace DSN { enum DSN_T { enum DSN_T { // the first few are special (the uppercase ones) // the first few are special (the uppercase ones) T_QUOTE_DEF = -9, T_QUOTE_DEF = -8, T_DASH = -8, T_DASH = -7, T_SYMBOL = -7, T_SYMBOL = -6, T_NUMBER = -6, T_NUMBER = -5, T_NONE = -5, // not a token T_RIGHT = -4, // right bracket, ')' T_RIGHT = -4, // right bracket, ')' T_LEFT = -3, // left bracket, '(' T_LEFT = -3, // left bracket, '(' T_STRING = -2, // a quoted string, stripped of the quotes T_STRING = -2, // a quoted string, stripped of the quotes Loading Loading @@ -157,6 +156,7 @@ enum DSN_T { T_host_cad, T_host_cad, T_host_version, T_host_version, T_image, T_image, T_image_conductor, T_image_image, T_image_image, T_image_image_spacing, T_image_image_spacing, T_image_outline_clearance, T_image_outline_clearance, Loading Loading @@ -513,8 +513,11 @@ class LEXER LINE_READER reader; LINE_READER reader; int stringDelimiter; int stringDelimiter; bool space_in_quoted_tokens; ///< blank spaces within quoted strings wxString filename; wxString filename; int lastTok; ///< curTok from previous NextTok() call. int lastTok; ///< curTok from previous NextTok() call. int curOffset; ///< offset within current line of the current token DSN_T curTok; ///< the current token obtained on last NextTok() DSN_T curTok; ///< the current token obtained on last NextTok() std::string curText; ///< the text of the current token std::string curText; ///< the text of the current token Loading Loading @@ -543,24 +546,22 @@ class LEXER */ */ int findToken( const std::string& tok ); int findToken( const std::string& tok ); bool isStringTerminator( char cc ) public: LEXER( FILE* aFile, const wxString& aFilename ) : reader( aFile, 4096 ) { { curTok = T_NONE; if( !space_in_quoted_tokens && cc==' ' ) stringDelimiter = '"'; return true; filename = aFilename; // "start" should never change until we change the reader. The DSN if( cc == stringDelimiter ) // format spec supports an include file mechanism but we can add that later return true; // using a std::stack to hold a stack of LINE_READERs to track nesting. start = (char*) reader; limit = start; return false; next = start; } } public: LEXER( FILE* aFile, const wxString& aFilename ); /** /** * Function SetStringDelimiter * Function SetStringDelimiter * changes the string delimiter from the default " to some other character * changes the string delimiter from the default " to some other character Loading @@ -575,6 +576,19 @@ public: return old; return old; } } /** * Function SetSpaceInQuotedTokens * changes the setting controlling whether a space in a quoted string is * a terminator */ bool SetSpaceInQuotedTokens( bool val ) { bool old = space_in_quoted_tokens; space_in_quoted_tokens = val; return old; } /** /** * Function NextTok * Function NextTok * returns the next token found in the input file or T_EOF when reaching * returns the next token found in the input file or T_EOF when reaching Loading @@ -590,14 +604,10 @@ public: * encapsulates the formatting of an error message which contains the exact * encapsulates the formatting of an error message which contains the exact * location within the input file of a lexical error. * location within the input file of a lexical error. */ */ void ThrowIOError( wxString aText, int charOffset ) throw (IOError) void ThrowIOError( wxString aText, int charOffset ) throw (IOError); { aText << wxT(" ") << _("in file") << wxT(" \"") << filename << wxT("\" ") << _("on line") << wxT(" ") << reader.LineNumber() << wxT(" ") << _("at offset") << wxT(" ") << charOffset; throw IOError( aText ); } wxString GetTokenText( DSN_T aTok ); /** /** Loading @@ -619,6 +629,16 @@ public: return curTok; return curTok; } } /** * Function CurOffset * returns the char offset within the current line, using a 1 based index. * @return int - a one based index into the current line. */ int CurOffset() { return curOffset + 1; } }; }; Loading
pcbnew/specctra.cpp +370 −28 Original line number Original line Diff line number Diff line Loading @@ -29,7 +29,7 @@ #include <boost/ptr_container/ptr_vector.hpp> #include <boost/ptr_container/ptr_vector.hpp> #include <wx/ffile.h> #include "fctsys.h" #include "fctsys.h" #include "pcbstruct.h" #include "pcbstruct.h" Loading @@ -43,7 +43,6 @@ namespace DSN { * is a base class for any DSN element. It is not a parent node so it * is a base class for any DSN element. It is not a parent node so it * cannot contain other elements but it can be extended to hold fields * cannot contain other elements but it can be extended to hold fields * for any DSN element which contains no other elements, only fields. * for any DSN element which contains no other elements, only fields. */ class ELEM class ELEM { { protected: protected: Loading @@ -58,26 +57,24 @@ public: virtual ~ELEM() virtual ~ELEM() { { printf("~ELEM(%p %d)\n", this, Type() ); // printf("~ELEM(%p %d)\n", this, Type() ); } } DSN_T Type() { return type; } virtual void Test() { printf("virtual Test()\n" ); } }; }; */ /** /** * Class PARENT * Class ELEM * is a base class holder for any DSN element. It can contain other * is a holder for any DSN element. It can contain other * elements, including elements derived from this class. * elements, including elements derived from this class. */ */ class PARENT : public ELEM class ELEM { { protected: DSN_T type; // see http://www.boost.org/libs/ptr_container/doc/ptr_sequence_adapter.html // see http://www.boost.org/libs/ptr_container/doc/ptr_sequence_adapter.html typedef boost::ptr_vector<ELEM> ELEM_ARRAY; typedef boost::ptr_vector<ELEM> ELEM_ARRAY; Loading @@ -86,18 +83,53 @@ public: public: public: PARENT( DSN_T aType ) : ELEM( DSN_T aType ) : ELEM( aType ) type( aType ) { { } } virtual ~PARENT() virtual ~ELEM() { { printf("~PARENT(%p %d)\n", this, Type() ); // printf("~ELEM(%p %d)\n", this, Type() ); } } DSN_T Type() { return type; } //-----< list operations >-------------------------------------------- //-----< list operations >-------------------------------------------- /** * Function FindElem * finds a particular instance number of a given type of ELEM. * @param aType The type of ELEM to find * @param instanceNum The instance number of to find: 0 for first, 1 for second, etc. * @return int - The index into the kids array or -1 if not found. */ int FindElem( DSN_T aType, int instanceNum ) { int repeats=0; for( unsigned i=0; i<kids.size(); ++i ) { if( kids[i].Type() == aType ) { if( repeats == instanceNum ) return i; ++repeats; } } return -1; } /** * Function Length * returns the number ELEMs in this ELEM. * @return int - the count of children */ int Length() const { return kids.size(); } void Append( ELEM* aElem ) void Append( ELEM* aElem ) { { kids.push_back( aElem ); kids.push_back( aElem ); Loading @@ -115,6 +147,7 @@ public: return ret.release(); return ret.release(); } } /* ELEM& operator[]( int aIndex ) ELEM& operator[]( int aIndex ) { { return kids[aIndex]; return kids[aIndex]; Loading @@ -124,14 +157,17 @@ public: { { return kids[aIndex]; return kids[aIndex]; } } */ void Insert( int aIndex, ELEM* aElem ) void Insert( int aIndex, ELEM* aElem ) { { kids.insert( kids.begin()+aIndex, aElem ); kids.insert( kids.begin()+aIndex, aElem ); } } ELEM* At( int aIndex ) ELEM* operator[]( int aIndex ) { { // we have varying sized object and are using polymorphism, so we // must return a pointer not a reference. return &kids[aIndex]; return &kids[aIndex]; } } Loading @@ -139,20 +175,20 @@ public: { { kids.erase( kids.begin()+aIndex ); kids.erase( kids.begin()+aIndex ); } } }; }; /** /** * Class SPECCTRA_DB * Class SPECCTRA_DB * holds a DSN data tree, usually coming from a DSN file. * holds a DSN data tree, usually coming from a DSN file. */ */ class SPECCTRA_DB class SPECCTRA_DB { { FILE* fp; LEXER* lexer; ELEM* tree; FILE* fp; /** /** Loading @@ -164,15 +200,49 @@ class SPECCTRA_DB */ */ void print( const char* fmt, ... ); void print( const char* fmt, ... ); /** * Function nextTok * returns the next token from the lexer. */ DSN_T nextTok(); void expecting( DSN_T ) throw( IOError ); void expecting( const wxChar* text ) throw( IOError ); void doPCB( ELEM* growth ) throw(IOError); void doPARSER( ELEM* growth ) throw(IOError); void doRESOLUTION( ELEM* growth ) throw(IOError); public: public: SPECCTRA_DB( FILE* aFile ) : SPECCTRA_DB() fp( aFile ) { { lexer = 0; tree = 0; fp = 0; } } ~SPECCTRA_DB() { delete lexer; delete tree; if( fp ) fclose( fp ); } /** * Function Load * is a recursive descent parser for a DSN file. * @param filename The name of the dsn file to load. * @throw IOError if there is a lexer or parser error. */ void Load( const wxString& filename ) throw( IOError ); void ThrowIOError( const wxChar* fmt, ... ) throw( IOError ); /** /** * Function Export * Function Export Loading @@ -180,10 +250,261 @@ public: * @param aBoard The BOARD to save. * @param aBoard The BOARD to save. */ */ void Export( BOARD* aBoard ); void Export( BOARD* aBoard ); }; }; void SPECCTRA_DB::ThrowIOError( const wxChar* fmt, ... ) throw( IOError ) { wxString errText; va_list args; va_start( args, fmt ); errText.PrintfV( fmt, args ); va_end( args ); throw IOError( errText ); } void SPECCTRA_DB::expecting( DSN_T aTok ) throw( IOError ) { wxString errText( _("Expecting") ); errText << wxT(" ") << lexer->GetTokenText( aTok ); lexer->ThrowIOError( errText, lexer->CurOffset() ); } void SPECCTRA_DB::expecting( const wxChar* text ) throw( IOError ) { wxString errText( _("Expecting") ); errText << wxT(" '") << text << wxT("'"); lexer->ThrowIOError( errText, lexer->CurOffset() ); } DSN_T SPECCTRA_DB::nextTok() { return lexer->NextTok(); } void SPECCTRA_DB::Load( const wxString& filename ) throw( IOError ) { wxFFile file( filename.c_str() ); if( !file.IsOpened() ) { ThrowIOError( _("Unable to open file \"%s\""), filename.GetData() ); } delete lexer; lexer = 0; lexer = new LEXER( file.fp(), filename ); if( nextTok() != T_LEFT ) expecting( T_LEFT ); if( nextTok() != T_pcb ) expecting( T_pcb ); tree = new ELEM( T_pcb ); doPCB( tree ); } void SPECCTRA_DB::doPCB( ELEM* growth ) throw( IOError ) { ELEM* child; DSN_T tok = nextTok(); switch( tok ) { case T_SYMBOL: case T_STRING: break; default: expecting( T_STRING ); } while( (tok = nextTok()) != T_EOF ) { if( tok != T_LEFT ) expecting( T_LEFT ); tok = nextTok(); switch( tok ) { case T_parser: child = new ELEM( T_parser ); growth->Append( child ); doPARSER( child ); break; case T_unit: child = new ELEM( T_unit ); growth->Append( child ); break; case T_resolution: child = new ELEM( T_resolution ); growth->Append( child ); doRESOLUTION( child ); break; case T_structure: case T_placement: case T_library: break; default: expecting( wxT("parser, unit, resolution, or structure") ); } } } void SPECCTRA_DB::doPARSER( ELEM* growth ) throw( IOError ) { DSN_T tok; while( (tok = nextTok()) != T_RIGHT ) { if( tok != T_LEFT ) expecting( T_LEFT ); tok = nextTok(); switch( tok ) { case T_string_quote: tok = nextTok(); if( tok != T_QUOTE_DEF ) expecting( T_QUOTE_DEF ); lexer->SetStringDelimiter( (unsigned char) *lexer->CurText() ); break; case T_space_in_quoted_tokens: tok = nextTok(); if( tok!=T_on && tok!=T_off ) expecting( _("on or off") ); lexer->SetSpaceInQuotedTokens( tok==T_on ); break; case T_host_cad: tok = nextTok(); if( tok!=T_STRING && tok!=T_SYMBOL ) expecting( T_SYMBOL ); // @todo break; case T_host_version: tok = nextTok(); if( tok!=T_STRING && tok!=T_SYMBOL ) expecting( T_SYMBOL ); // @todo break; case T_constant: tok = nextTok(); if( tok!=T_STRING && tok!=T_SYMBOL ) expecting( T_SYMBOL ); tok = nextTok(); if( tok!=T_STRING && tok!=T_SYMBOL ) expecting( T_SYMBOL ); // @todo break; case T_write_resolution: // [(writee_resolution {<character> <positive_integer >})] while( (tok = nextTok()) != T_RIGHT ) { if( tok!=T_SYMBOL ) expecting( T_SYMBOL ); tok = nextTok(); if( tok!=T_NUMBER ) expecting( T_NUMBER ); // @todo } continue; // we ate the T_RIGHT case T_routes_include: // [(routes_include {[testpoint | guides | image_conductor]})] while( (tok = nextTok()) != T_RIGHT ) { switch( tok ) { case T_testpoint: case T_guide: case T_image_conductor: // @todo break; default: expecting( _("testpoint, guides, or image_conductor") ); } } continue; // we ate the T_RIGHT case T_wires_include: // [(wires_include testpoint)] tok = nextTok(); if( tok != T_testpoint ) expecting( T_testpoint ); // @todo break; case T_case_sensitive: tok = nextTok(); if( tok!=T_on && tok!=T_off ) expecting( _("on or off") ); // @todo break; case T_via_rotate_first: // [(via_rotate_first [on | off])] tok = nextTok(); if( tok!=T_on && tok!=T_off ) expecting( _("on or off") ); // @todo break; default: expecting( wxT("parser_descriptor contents") ); } tok = nextTok(); if( tok != T_RIGHT ) expecting( T_RIGHT ); } } void SPECCTRA_DB::doRESOLUTION( ELEM* growth ) throw(IOError) { DSN_T tok = nextTok(); switch( tok ) { case T_inch: case T_mil: case T_cm: case T_mm: case T_um: // @todo break; default: expecting( wxT("inch, mil, cm, mm, or um") ); } tok = nextTok(); if( tok != T_NUMBER ) expecting( T_NUMBER ); tok = nextTok(); if( tok != T_RIGHT ) expecting( T_RIGHT ); } void SPECCTRA_DB::print( const char* fmt, ... ) void SPECCTRA_DB::print( const char* fmt, ... ) { { Loading @@ -210,15 +531,36 @@ using namespace DSN; int main( int argc, char** argv ) int main( int argc, char** argv ) { { PARENT parent( T_pcb ); #if 0 ELEM parent( T_pcb ); PARENT* child = new PARENT( T_absolute ); ELEM* child = new ELEM( T_absolute ); parent.Append( child ); parent.Append( child ); parent.At(0)->Test(); parent[0]->Test(); child->Append( new ELEM( T_absolute ) ); child->Append( new ELEM( T_absolute ) ); #else wxString filename( wxT("/tmp/fpcroute/Sample_1sided/demo_1sided.dsn") ); // wxString filename( wxT("/tmp/testdesigns/test.dsn") ); SPECCTRA_DB db; try { db.Load( filename ); } catch( IOError ioe ) { printf( "%s\n", CONV_TO_UTF8(ioe.errorText) ); exit(1); } printf("loaded OK\n"); #endif } } Loading