* Factored out the DSNLEXER class so it can be re-used more generally. The

constructor takes a keyword table, so it can be used for arbitrary DSN
    syntax files of your own chosing.  Simply create an enum {} with all your
    unique tokens in it.  Then create a KEYWORD table.  See SPECCTRA_DB::keywords[].
    The reason you want an enum is to give the C++ debugger better type information
    so it can show symbolic integer symbols.
  * Factored out common richio.cpp and richio.h
    which is what DSNLEXER uses.
  * Fixed some minor issues with reading circuit descriptor from a *.dsn file.
This commit is contained in:
dickelbeck 2009-12-11 04:55:24 +00:00
parent 0fc7d7c127
commit ceb6ad1a72
14 changed files with 2264 additions and 2053 deletions

View File

@ -4,6 +4,21 @@ KiCad ChangeLog 2009
Please add newer entries at the top, list the date and your name with Please add newer entries at the top, list the date and your name with
email address. email address.
2009-Dec-10 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================
++all
* Factored out the DSNLEXER class so it can be re-used more generally. The
constructor takes a keyword table, so it can be used for arbitrary DSN
syntax files of your own chosing. Simply create an enum {} with all your
unique tokens in it. Then create a KEYWORD table. See SPECCTRA_DB::keywords[].
The reason you want an enum is to give the C++ debugger better type information
so it can show symbolic integer symbols.
* Factored out common richio.cpp and richio.h
which is what DSNLEXER uses.
* Fixed some minor issues with reading circuit descriptor from a *.dsn file.
2009-Dec-6 UPDATE Dick Hollenbeck <dick@softplc.com> 2009-Dec-6 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================ ================================================================================
++pcbnew & gerbview ++pcbnew & gerbview

View File

@ -13,7 +13,7 @@ set(COMMON_SRCS
bezier_curves.cpp bezier_curves.cpp
block_commande.cpp block_commande.cpp
class_marker_base.cpp class_marker_base.cpp
class_plotter.cpp class_plotter.cpp
class_undoredo_container.cpp class_undoredo_container.cpp
common.cpp common.cpp
common_plot_functions.cpp common_plot_functions.cpp
@ -24,13 +24,14 @@ set(COMMON_SRCS
confirm.cpp confirm.cpp
copy_to_clipboard.cpp copy_to_clipboard.cpp
dialog_display_info_HTML_base.cpp dialog_display_info_HTML_base.cpp
dialog_load_error.cpp dialog_load_error.cpp
dcsvg.cpp dcsvg.cpp
displlst.cpp displlst.cpp
dlist.cpp dlist.cpp
drawframe.cpp drawframe.cpp
drawpanel.cpp drawpanel.cpp
drawtxt.cpp drawtxt.cpp
dsnlexer.cpp
edaappl.cpp edaappl.cpp
eda_dde.cpp eda_dde.cpp
eda_doc.cpp eda_doc.cpp
@ -41,6 +42,7 @@ set(COMMON_SRCS
msgpanel.cpp msgpanel.cpp
projet_config.cpp projet_config.cpp
# pyhandler.cpp # pyhandler.cpp
richio.cpp
selcolor.cpp selcolor.cpp
string.cpp string.cpp
toolbars.cpp toolbars.cpp

View File

@ -11,14 +11,6 @@
#define BUILD_VERSION "(2009-12-05-unstable)" #define BUILD_VERSION "(2009-12-05-unstable)"
#ifdef HAVE_SVN_VERSION
#include "version.h"
wxString g_BuildVersion( wxT( KICAD_SVN_VERSION ) );
#else
wxString g_BuildVersion( wxT( BUILD_VERSION ) );
#endif
#if defined(HAVE_SVN_VERSION) || defined(HAVE_SVN_REVISION) #if defined(HAVE_SVN_VERSION) || defined(HAVE_SVN_REVISION)
# include "version.h" # include "version.h"
#ifndef KICAD_ABOUT_VERSION #ifndef KICAD_ABOUT_VERSION
@ -30,6 +22,15 @@ wxString g_BuildAboutVersion( wxT( BUILD_VERSION ) );
#endif #endif
/** Function GetAboutBuildVersion()
* Return custom build date for about dialog
*/
wxString GetAboutBuildVersion()
{
return g_BuildAboutVersion;
}
/**********************************/ /**********************************/
wxString SetMsg( const wxString& msg ) wxString SetMsg( const wxString& msg )
/**********************************/ /**********************************/
@ -40,13 +41,13 @@ wxString SetMsg( const wxString& msg )
* Perhaps depending on wxWidgets versions * Perhaps depending on wxWidgets versions
*/ */
{ {
wxString message; wxString message;
#if 1 /* Windows */ #if 1 /* Windows */
message = wxT( "\n" ); message = wxT( "\n" );
#endif #endif
message << msg; message << msg;
return message; return message;
} }
@ -54,116 +55,116 @@ wxString SetMsg( const wxString& msg )
void InitKiCadAbout( wxAboutDialogInfo& info ) void InitKiCadAbout( wxAboutDialogInfo& info )
/**************************************************/ /**************************************************/
{ {
/* Set name and title */ /* Set name and title */
info.SetName( wxGetApp().GetTitle() ); info.SetName( wxGetApp().GetTitle() );
/* Set description */ /* Set description */
wxString description; wxString description;
/* KiCad build version */ /* KiCad build version */
description << ( _T( "Build: " ) ) << GetAboutBuildVersion(); description << ( _T( "Build: " ) ) << GetAboutBuildVersion();
/* Print for wxversion */ /* Print for wxversion */
description << ( wxT( "\n\nwxWidgets " ) ) description << ( wxT( "\n\nwxWidgets " ) )
<< wxMAJOR_VERSION << wxMAJOR_VERSION
<< wxT( "." ) << wxT( "." )
<< wxMINOR_VERSION << wxT( "." ) << wxMINOR_VERSION << wxT( "." )
<< wxRELEASE_NUMBER << wxRELEASE_NUMBER
/* Show Unicode or Ansi version */ /* Show Unicode or Ansi version */
#if wxUSE_UNICODE #if wxUSE_UNICODE
<< ( wxT( " Unicode " ) ); << ( wxT( " Unicode " ) );
# else # else
<< ( wxT( " Ansi " ) ); << ( wxT( " Ansi " ) );
#endif #endif
/************************** /**************************
* Check Operating System * * Check Operating System *
**************************/ **************************/
#if defined __WINDOWS__ #if defined __WINDOWS__
description << ( wxT( "on Windows" ) ); description << ( wxT( "on Windows" ) );
/* Check for wxMAC */ /* Check for wxMAC */
# elif defined __WXMAC__ # elif defined __WXMAC__
description << ( wxT( "on Macintosh" ) ); description << ( wxT( "on Macintosh" ) );
/* Linux 64 bits */ /* Linux 64 bits */
# elif defined _LP64 && __LINUX__ # elif defined _LP64 && __LINUX__
description << ( wxT( "on 64 Bits GNU/Linux" ) ); description << ( wxT( "on 64 Bits GNU/Linux" ) );
/* Linux 32 bits */ /* Linux 32 bits */
# elif defined __LINUX__ # elif defined __LINUX__
description << ( wxT( "on 32 Bits GNU/Linux" ) ); description << ( wxT( "on 32 Bits GNU/Linux" ) );
/* OpenBSD */ /* OpenBSD */
# elif defined __OpenBSD__ # elif defined __OpenBSD__
description << ( wxT ("on OpenBSD") ); description << ( wxT ("on OpenBSD") );
/* FreeBSD */ /* FreeBSD */
# elif defined __FreeBSD__ # elif defined __FreeBSD__
description << ( wxT ("on FreeBSD") ); description << ( wxT ("on FreeBSD") );
#endif #endif
/* Websites */ /* Websites */
description << wxT( "\n\nKiCad on the web\n\n" ); description << wxT( "\n\nKiCad on the web\n\n" );
description << wxT( "http://iut-tice.ujf-grenoble.fr/kicad \n" ); description << wxT( "http://iut-tice.ujf-grenoble.fr/kicad \n" );
description << wxT( "http://kicad.sourceforge.net \n" ); description << wxT( "http://kicad.sourceforge.net \n" );
description << wxT( "http://www.kicadlib.org" ); description << wxT( "http://www.kicadlib.org" );
/* Set the complete about description */ /* Set the complete about description */
info.SetDescription( description ); info.SetDescription( description );
/* Set copyright dialog */ /* Set copyright dialog */
info.SetCopyright( _T( "(C) 1992-2009 KiCad Developers Team" ) ); info.SetCopyright( _T( "(C) 1992-2009 KiCad Developers Team" ) );
/* Set license dialog */ /* Set license dialog */
info.SetLicence( wxString::FromAscii info.SetLicence( wxString::FromAscii
( "The complete KiCad EDA Suite is released under the\n" ( "The complete KiCad EDA Suite is released under the\n"
"GNU General Public License version 2.\n" "GNU General Public License version 2.\n"
"See <http://www.gnu.org/licenses/> for more information." "See <http://www.gnu.org/licenses/> for more information."
)); ));
/* Add developers */ /* Add developers */
info.AddDeveloper( wxT( "Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>" ) ); info.AddDeveloper( wxT( "Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>" ) );
info.AddDeveloper( SetMsg( wxT( "Dick Hollenbeck <dick@softplc.com>" ) ) ); info.AddDeveloper( SetMsg( wxT( "Dick Hollenbeck <dick@softplc.com>" ) ) );
info.AddDeveloper( SetMsg( wxT( "Hauptmech <hauptmech@gmail.com>") ) ); info.AddDeveloper( SetMsg( wxT( "Hauptmech <hauptmech@gmail.com>") ) );
info.AddDeveloper( SetMsg( wxT( "Jerry Jacobs <jerkejacobs@gmail.com>" ) ) ); info.AddDeveloper( SetMsg( wxT( "Jerry Jacobs <jerkejacobs@gmail.com>" ) ) );
info.AddDeveloper( SetMsg( wxT( "Jonas Diemer <diemer@gmx.de>" ) ) ); info.AddDeveloper( SetMsg( wxT( "Jonas Diemer <diemer@gmx.de>" ) ) );
info.AddDeveloper( SetMsg( wxT( "KBool Library <http://boolean.klaasholwerda.nl/bool.html>" ) ) ); info.AddDeveloper( SetMsg( wxT( "KBool Library <http://boolean.klaasholwerda.nl/bool.html>" ) ) );
info.AddDeveloper( SetMsg( wxT( "Lorenzo <lomarcan@tin.it>" ) ) ); info.AddDeveloper( SetMsg( wxT( "Lorenzo <lomarcan@tin.it>" ) ) );
info.AddDeveloper( SetMsg( wxT( "Marco Serantoni <marco.serantoni@gmail.com>" ) ) ); info.AddDeveloper( SetMsg( wxT( "Marco Serantoni <marco.serantoni@gmail.com>" ) ) );
info.AddDeveloper( SetMsg( wxT( "Rok Markovic <rok@kanardia.eu>" ) ) ); info.AddDeveloper( SetMsg( wxT( "Rok Markovic <rok@kanardia.eu>" ) ) );
info.AddDeveloper( SetMsg( wxT( "Tim Hanson <sideskate@gmail.com>" ) ) ); info.AddDeveloper( SetMsg( wxT( "Tim Hanson <sideskate@gmail.com>" ) ) );
info.AddDeveloper( SetMsg( wxT( "Vesa Solonen <vesa.solonen@hut.fi>" ) ) ); info.AddDeveloper( SetMsg( wxT( "Vesa Solonen <vesa.solonen@hut.fi>" ) ) );
info.AddDeveloper( SetMsg( wxT( "Wayne Stambaugh <stambaughw@verizon.net>" ) ) ); info.AddDeveloper( SetMsg( wxT( "Wayne Stambaugh <stambaughw@verizon.net>" ) ) );
/* Add document writers*/ /* Add document writers*/
info.AddDocWriter( wxT( "Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>" ) ); info.AddDocWriter( wxT( "Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>" ) );
info.AddDocWriter( SetMsg( wxT( "Igor Plyatov <plyatov@gmail.com>" ) ) ); info.AddDocWriter( SetMsg( wxT( "Igor Plyatov <plyatov@gmail.com>" ) ) );
/* Add translators */ /* Add translators */
info.AddTranslator( wxT( "Czech (CZ) Martin Kratoška <martin@ok1rr.com>" ) ); info.AddTranslator( wxT( "Czech (CZ) Martin Kratoška <martin@ok1rr.com>" ) );
info.AddTranslator( SetMsg( wxT( "Dutch (NL) Jerry Jacobs <jerkejacobs@gmail.com>" ) ) ); info.AddTranslator( SetMsg( wxT( "Dutch (NL) Jerry Jacobs <jerkejacobs@gmail.com>" ) ) );
info.AddTranslator( SetMsg( wxT( "French (FR) Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>" ) ) ); info.AddTranslator( SetMsg( wxT( "French (FR) Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>" ) ) );
info.AddTranslator( SetMsg( wxT( "Polish (PL) Mateusz Skowroński <skowri@gmail.com>" ) ) ); info.AddTranslator( SetMsg( wxT( "Polish (PL) Mateusz Skowroński <skowri@gmail.com>" ) ) );
info.AddTranslator( SetMsg( wxT( "Portuguese (PT) Renie Marquet <reniemarquet@uol.com.br>" ) ) ); info.AddTranslator( SetMsg( wxT( "Portuguese (PT) Renie Marquet <reniemarquet@uol.com.br>" ) ) );
info.AddTranslator( SetMsg( wxT( "Russian (RU) Igor Plyatov <plyatov@gmail.com>" ) ) ); info.AddTranslator( SetMsg( wxT( "Russian (RU) Igor Plyatov <plyatov@gmail.com>" ) ) );
info.AddTranslator( SetMsg( wxT( "Spanish (ES) Pedro Martin del Valle <pkicad@yahoo.es>" ) ) ); info.AddTranslator( SetMsg( wxT( "Spanish (ES) Pedro Martin del Valle <pkicad@yahoo.es>" ) ) );
info.AddTranslator( SetMsg( wxT( "Spanish (ES) Iñigo Zuluaga <inigo_zuluaga@yahoo.es>" ) ) ); info.AddTranslator( SetMsg( wxT( "Spanish (ES) Iñigo Zuluaga <inigo_zuluaga@yahoo.es>" ) ) );
info.AddTranslator( SetMsg( wxT( "German (DE) Rafael Sokolowski <rafael.sokolowski@web.de>" ) ) ); info.AddTranslator( SetMsg( wxT( "German (DE) Rafael Sokolowski <rafael.sokolowski@web.de>" ) ) );
/* TODO are these all russian translators, placed them here now TODO /* TODO are these all russian translators, placed them here now TODO
TODO or else align them below other language maintainer with mail adres TODO*/ TODO or else align them below other language maintainer with mail adres TODO*/
info.AddTranslator( SetMsg( wxT( "\nRemy Halvick" ) ) ); info.AddTranslator( SetMsg( wxT( "\nRemy Halvick" ) ) );
info.AddTranslator( SetMsg( wxT( "David Briscoe" ) ) ); info.AddTranslator( SetMsg( wxT( "David Briscoe" ) ) );
info.AddTranslator( SetMsg( wxT( "Dominique Laigle" ) ) ); info.AddTranslator( SetMsg( wxT( "Dominique Laigle" ) ) );
info.AddTranslator( SetMsg( wxT( "Paul Burke" ) ) ); info.AddTranslator( SetMsg( wxT( "Paul Burke" ) ) );
/* Add programm credits for icons */ /* Add programm credits for icons */
info.AddArtist( wxT( "Icons by Iñigo Zuluagaz <inigo_zuluaga@yahoo.es>" ) ); info.AddArtist( wxT( "Icons by Iñigo Zuluagaz <inigo_zuluaga@yahoo.es>" ) );
info.AddArtist( SetMsg( wxT( "3D modules by Renie Marquet <reniemarquet@uol.com.br>" ) ) ); info.AddArtist( SetMsg( wxT( "3D modules by Renie Marquet <reniemarquet@uol.com.br>" ) ) );
info.AddArtist( SetMsg( wxT( "3D modules by Christophe Boschat <nox454@hotmail.fr>" ) ) ); info.AddArtist( SetMsg( wxT( "3D modules by Christophe Boschat <nox454@hotmail.fr>" ) ) );
} }

View File

@ -118,6 +118,17 @@ StructColors ColorRefs[NBCOLOR] =
}; };
#define BUILD_VERSION "(2009-12-05-unstable)"
#ifdef HAVE_SVN_VERSION
#include "version.h"
wxString g_BuildVersion( wxT( KICAD_SVN_VERSION ) );
#else
wxString g_BuildVersion( wxT( BUILD_VERSION ) );
#endif
/** Function GetBuildVersion() /** Function GetBuildVersion()
* Return the build date * Return the build date
*/ */
@ -127,15 +138,6 @@ wxString GetBuildVersion()
} }
/** Function GetAboutBuildVersion()
* Return custom build date for about dialog
*/
wxString GetAboutBuildVersion()
{
return g_BuildAboutVersion;
}
/** function SetLocaleTo_C_standard /** function SetLocaleTo_C_standard
* because kicad is internationalized, switch internalization to "C" standard * because kicad is internationalized, switch internalization to "C" standard
* i.e. uses the . (dot) as separator in print/read float numbers * i.e. uses the . (dot) as separator in print/read float numbers

404
common/dsnlexer.cpp Normal file
View File

@ -0,0 +1,404 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2007-2008 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2007 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 <cstdarg>
#include <cstdio>
#include <cstdlib> // bsearch()
#include <cctype>
#include "dsnlexer.h"
#include "fctsys.h"
#include "pcbnew.h"
static int compare( const void* a1, const void* a2 )
{
const KEYWORD* k1 = (const KEYWORD*) a1;
const KEYWORD* k2 = (const KEYWORD*) a2;
int ret = strcmp( k1->name, k2->name );
return ret;
}
//-----<DSNLEXER>-------------------------------------------------------------
DSNLEXER::DSNLEXER( FILE* aFile, const wxString& aFilename,
const KEYWORD* aKeywordTable, unsigned aKeywordCount ) :
reader( aFile, 4096 )
{
keywords = aKeywordTable;
keywordCount = aKeywordCount;
curTok = DSN_NONE;
stringDelimiter = '"';
filename = aFilename;
space_in_quoted_tokens = true;
// "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 DSNLEXER::findToken( const std::string& tok )
{
// convert to lower case once, this should be faster than using strcasecmp()
// for each test in compare().
lowercase.clear();
for( std::string::const_iterator iter = tok.begin(); iter!=tok.end(); ++iter )
lowercase += (char) tolower( *iter );
KEYWORD search;
search.name = lowercase.c_str();
// a boost hashtable might be a few percent faster, depending on
// hashtable size and quality of the hash function.
const KEYWORD* findings = (const KEYWORD*) bsearch( &search,
keywords, keywordCount,
sizeof(KEYWORD), compare );
if( findings )
return findings->token;
else
return -1;
}
const char* DSNLEXER::Syntax( int aTok )
{
const char* ret;
switch( aTok )
{
case DSN_NONE:
ret = "NONE";
break;
case DSN_QUOTE_DEF:
ret = "quoted text delimiter";
break;
case DSN_DASH:
ret = "-";
break;
case DSN_SYMBOL:
ret = "symbol";
break;
case DSN_NUMBER:
ret = "number";
break;
case DSN_RIGHT:
ret = ")";
break;
case DSN_LEFT:
ret = "(";
break;
case DSN_STRING:
ret = "quoted string";
break;
case DSN_EOF:
ret = "end of file";
break;
default:
ret = "???";
}
return ret;
}
const char* DSNLEXER::GetTokenText( int aTok )
{
const char* ret;
if( aTok < 0 )
{
return Syntax( aTok );
}
else if( (unsigned) aTok < keywordCount )
{
ret = keywords[aTok].name;
}
else
ret = "token too big";
return ret;
}
void DSNLEXER::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 );
}
/**
* Function isspace
* strips the upper bits of the int to ensure the value passed to ::isspace() is
* in the range of 0-255
*/
static inline bool isSpace( int cc )
{
// make sure int passed to ::isspace() is 0-255
return ::isspace( cc & 0xff );
}
int DSNLEXER::NextTok() throw (IOError)
{
char* cur = next;
char* head = cur;
prevTok = curTok;
if( curTok != DSN_EOF )
{
if( cur >= limit )
{
L_read:
int len = readLine();
if( len == 0 )
{
curTok = DSN_EOF;
goto exit;
}
cur = start;
// skip leading whitespace
while( cur<limit && isSpace(*cur) )
++cur;
// if the first non-blank character is #, this line is a comment.
if( cur<limit && *cur=='#' )
goto L_read;
}
else
{
// skip leading whitespace
while( cur<limit && isSpace(*cur) )
++cur;
}
if( cur >= limit )
goto L_read;
// switching the string_quote character
if( prevTok == DSN_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 += cc;
head = cur+1;
if( head<limit && *head!=')' && *head!='(' && !isSpace(*head) )
{
ThrowIOError( errtxt, CurOffset() );
}
curTok = DSN_QUOTE_DEF;
goto exit;
}
if( *cur == '(' )
{
curText.clear();
curText += *cur;
curTok = DSN_LEFT;
head = cur+1;
goto exit;
}
if( *cur == ')' )
{
curText.clear();
curText += *cur;
curTok = DSN_RIGHT;
head = cur+1;
goto exit;
}
/* get the dash out of a <pin_reference> which is embedded for example
like: U2-14 or "U2"-"14"
This is detectable by a non-space immediately preceeding the dash.
*/
if( *cur == '-' && cur>start && !isSpace( cur[-1] ) )
{
head = cur+1;
curText.clear();
curText += '-';
curTok = DSN_DASH;
goto exit;
}
// handle DSN_NUMBER
if( strchr( "+-.0123456789", *cur ) )
{
head = cur+1;
while( head<limit && strchr( ".0123456789", *head ) )
++head;
if( (head<limit && isSpace(*head)) || *head==')' || *head=='(' || head==limit )
{
curText.clear();
curText.append( cur, head );
curTok = DSN_NUMBER;
goto exit;
}
// else it was something like +5V, fall through below
}
// a quoted string
if( *cur == stringDelimiter )
{
++cur; // skip over the leading delimiter: ",', or $
head = cur;
while( head<limit && !isStringTerminator( *head ) )
++head;
if( head >= limit )
{
wxString errtxt(_("Un-terminated delimited string") );
ThrowIOError( errtxt, CurOffset() );
}
curText.clear();
curText.append( cur, head );
++head; // skip over the trailing delimiter
curTok = DSN_STRING;
goto exit;
}
// Maybe it is a token we will find in the token table.
// If not, then call it a DSN_SYMBOL.
{
head = cur+1;
while( head<limit && !isSpace( *head ) && *head!=')' && *head!='(' )
++head;
curText.clear();
curText.append( cur, head );
int found = findToken( curText );
if( found != -1 )
curTok = found;
else if( 0 == curText.compare( "string_quote" ) )
curTok = DSN_STRING_QUOTE;
else // unrecogized token, call it a symbol
curTok = DSN_SYMBOL;
}
}
exit: // single point of exit, no returns elsewhere please.
curOffset = cur - start;
next = head;
// printf("tok:\"%s\"\n", curText.c_str() );
return curTok;
}
#if 0 && defined(STANDALONE)
// stand alone testing
int main( int argc, char** argv )
{
// wxString filename( wxT("/tmp/fpcroute/Sample_1sided/demo_1sided.dsn") );
wxString filename( wxT("/tmp/testdesigns/test.dsn") );
FILE* fp = wxFopen( filename, wxT("r") );
if( !fp )
{
fprintf( stderr, "unable to open file \"%s\"\n",
(const char*) filename.mb_str() );
exit(1);
}
// this won't compile without a token table.
DSNLEXER lexer( fp, filename );
try
{
int tok;
while( (tok = lexer.NextTok()) != DSN_EOF )
{
printf( "%-3d %s\n", tok, lexer.CurText() );
}
}
catch( IOError ioe )
{
printf( "%s\n", (const char*) ioe.errorText.mb_str() );
}
fclose( fp );
return 0;
}
#endif

201
common/richio.cpp Normal file
View File

@ -0,0 +1,201 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2007-2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2007 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 <cstdarg>
#include "richio.h"
// This file defines 3 classes useful for working with DSN text files and is named
// "richio" after its author, Richard Hollenbeck, aka Dick Hollenbeck.
//-----<LINE_READER>------------------------------------------------------
LINE_READER::LINE_READER( FILE* aFile, unsigned aMaxLineLength )
{
fp = aFile;
lineNum = 0;
maxLineLength = aMaxLineLength;
// the real capacity is 10 bytes larger than requested.
capacity = aMaxLineLength + 10;
line = new char[capacity];
line[0] = '\0';
length = 0;
}
int LINE_READER::ReadLine() throw (IOError)
{
const char* p = fgets( line, capacity, fp );
if( !p )
{
line[0] = 0;
length = 0;
}
else
{
length = strlen( line );
if( length > maxLineLength )
throw IOError( _("Line length exceeded") );
++lineNum;
}
return length;
}
//-----<OUTPUTFORMATTER>----------------------------------------------------
// factor out a common GetQuoteChar
const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, const char* quote_char )
{
// Include '#' so a symbol is not confused with a comment. We intend
// to wrap any symbol starting with a '#'.
// Our LEXER class handles comments, and comments appear to be an extension
// to the SPECCTRA DSN specification.
if( *wrapee == '#' )
return quote_char;
if( strlen(wrapee)==0 )
return quote_char;
bool isFirst = true;
for( ; *wrapee; ++wrapee, isFirst=false )
{
static const char quoteThese[] = "\t ()"
"%" // per Alfons of freerouting.net, he does not like this unquoted as of 1-Feb-2008
"{}" // guessing that these are problems too
;
// if the string to be wrapped (wrapee) has a delimiter in it,
// return the quote_char so caller wraps the wrapee.
if( strchr( quoteThese, *wrapee ) )
return quote_char;
if( !isFirst && '-' == *wrapee )
return quote_char;
}
return ""; // caller does not need to wrap, can use an unwrapped string.
}
//-----<STRINGFORMATTER>----------------------------------------------------
const char* STRINGFORMATTER::GetQuoteChar( const char* wrapee )
{
// for what we are using STRINGFORMATTER for at this time, we can return
// the nul string always.
return "";
// return OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, "\"" );
}
int STRINGFORMATTER::vprint( const char* fmt, va_list ap )
{
int ret = vsnprintf( &buffer[0], buffer.size(), fmt, ap );
if( ret >= (int) buffer.size() )
{
buffer.reserve( ret+200 );
ret = vsnprintf( &buffer[0], buffer.size(), fmt, ap );
}
if( ret > 0 )
mystring.append( (const char*) &buffer[0] );
return ret;
}
int STRINGFORMATTER::sprint( const char* fmt, ... )
{
va_list args;
va_start( args, fmt );
int ret = vprint( fmt, args);
va_end( args );
return ret;
}
int STRINGFORMATTER::Print( int nestLevel, const char* fmt, ... ) throw( IOError )
{
#define NESTWIDTH 2 ///< how many spaces per nestLevel
va_list args;
va_start( args, fmt );
int result = 0;
int total = 0;
for( int i=0; i<nestLevel; ++i )
{
result = sprint( "%*c", NESTWIDTH, ' ' );
if( result < 0 )
break;
total += result;
}
if( result<0 || (result=vprint( fmt, args ))<0 )
{
throw IOError( _("Error writing to STRINGFORMATTER") );
}
va_end( args );
total += result;
return total;
}
void STRINGFORMATTER::StripUseless()
{
std::string copy = mystring;
mystring.clear();
for( std::string::iterator i=copy.begin(); i!=copy.end(); ++i )
{
if( !isspace( *i ) && *i!=')' && *i!='(' && *i!='"' )
{
mystring += *i;
}
}
}

259
include/dsnlexer.h Normal file
View File

@ -0,0 +1,259 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2007-2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2007 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 _DSNLEXER_H
#define _DSNLEXER_H
#include <cstdio>
#include <string>
#include "fctsys.h"
#include "pcbnew.h"
#include "richio.h"
/**
* Struct KEYWORD
* holds a keyword string and its unique integer token.
*/
struct KEYWORD
{
const char* name; ///< unique keyword.
int token; ///< a zero based index into an array of KEYWORDs
};
// something like this macro can be used to help initialize a KEYWORD table.
// see SPECCTRA_DB::keywords[] as an example.
//#define TOKDEF(x) { #x, T_##x }
/**
* Enum DSN_SYNTAX_T
* lists all the DSN lexer's tokens that are supported in lexing. It is up
* to the parser if it wants also to support them.
*/
enum DSN_SYNTAX_T {
DSN_NONE = -10,
DSN_STRING_QUOTE = -9,
DSN_QUOTE_DEF = -8,
DSN_DASH = -7,
DSN_SYMBOL = -6,
DSN_NUMBER = -5,
DSN_RIGHT = -4, // right bracket, ')'
DSN_LEFT = -3, // left bracket, '('
DSN_STRING = -2, // a quoted string, stripped of the quotes
DSN_EOF = -1, // special case for end of file
};
/**
* Class DLEXER
* implements a lexical analyzer for the SPECCTRA DSN file format. It
* reads lexical tokens from the current LINE_READER through the NextTok()
* function. The NextTok() function returns one of the DSN_T values.
*/
class DSNLEXER
{
char* next;
char* start;
char* limit;
LINE_READER reader;
int stringDelimiter;
bool space_in_quoted_tokens; ///< blank spaces within quoted strings
wxString filename;
int prevTok; ///< curTok from previous NextTok() call.
int curOffset; ///< offset within current line of the current token
int curTok; ///< the current token obtained on last NextTok()
std::string curText; ///< the text of the current token
std::string lowercase; ///< a scratch buf holding token in lowercase
const KEYWORD* keywords;
unsigned keywordCount;
int readLine() throw (IOError)
{
int len = reader.ReadLine();
next = start;
limit = start + len;
return len;
}
/**
* Function findToken
* takes a string and looks up the string in the list of expected
* tokens.
*
* @param tok A string holding the token text to lookup, in an
* unpredictable case: uppercase or lowercase
* @return int - DSN_T or -1 if argument string is not a recognized token.
*/
int findToken( const std::string& tok );
bool isStringTerminator( char cc )
{
if( !space_in_quoted_tokens && cc==' ' )
return true;
if( cc == stringDelimiter )
return true;
return false;
}
public:
/**
* Constructor DSNLEXER
* intializes a DSN lexer and prepares to read from aFile which
* is already open and has aFilename.
*
* @param aKeywordTable is an array of KEYWORDS holding \a aKeywordCount. This
* token table need not contain the lexer separators such as '(' ')', etc.
* @param aKeywordTable is the count of tokens in aKeywordTable.
*/
DSNLEXER( FILE* aFile, const wxString& aFilename,
const KEYWORD* aKeywordTable, unsigned aKeywordCount );
/**
* Function SetStringDelimiter
* changes the string delimiter from the default " to some other character
* and returns the old value.
* @param aStringDelimiter The character in lowest 8 bits.
* @return int - The old delimiter in the lowest 8 bits.
*/
int SetStringDelimiter( int aStringDelimiter )
{
int old = stringDelimiter;
stringDelimiter = aStringDelimiter;
return old;
}
/**
* Function SetSpaceInQuotedTokens
* changes the setting controlling whether a space in a quoted string is
* a terminator.
* @param val If true, means
*/
bool SetSpaceInQuotedTokens( bool val )
{
bool old = space_in_quoted_tokens;
space_in_quoted_tokens = val;
return old;
}
/**
* Function NextTok
* returns the next token found in the input file or T_EOF when reaching
* the end of file.
* @return int - the type of token found next.
* @throw IOError - only if the LINE_READER throws it.
*/
int NextTok() throw (IOError);
/**
* Function ThrowIOError
* encapsulates the formatting of an error message which contains the exact
* location within the input file of something the caller is rejecting.
*/
void ThrowIOError( wxString aText, int charOffset ) throw (IOError);
/**
* Function GetTokenString
* returns the C string representation of a DSN_T value.
*/
const char* GetTokenText( int aTok );
static const char* Syntax( int aTok );
/**
* Function CurText
* returns a pointer to the current token's text.
*/
const char* CurText()
{
return curText.c_str();
}
/**
* Function CurTok
* returns whatever NextTok() returned the last time it was called.
*/
int CurTok()
{
return curTok;
}
/**
* Function CurLineNumber
* returns the current line number within my LINE_READER
*/
int CurLineNumber()
{
return reader.LineNumber();
}
/**
* Function CurFilename
* returns the current input filename.
* @return const wxString& - the filename.
*/
const wxString& CurFilename()
{
return filename;
}
/**
* Function PrevTok
* returns whatever NextTok() returned the 2nd to last time it was called.
*/
int PrevTok()
{
return prevTok;
}
/**
* 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;
}
};
#endif // _DSNLEXER_H

265
include/richio.h Normal file
View File

@ -0,0 +1,265 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2007-2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2007 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 RICHIO_H_
#define RICHIO_H_
// This file defines 3 classes useful for working with DSN text files and is named
// "richio" after its author, Richard Hollenbeck, aka Dick Hollenbeck.
#include <string>
#include <vector>
// I really did not want to be dependent on wxWidgets in richio
// but the errorText needs to be wide char so wxString rules.
#include <wx/wx.h>
#include <cstdio> // FILE
/**
* Struct IOError
* is a class used to hold an error message and may be used to throw exceptions
* containing meaningful error messages.
*/
struct IOError
{
wxString errorText;
IOError( const wxChar* aMsg ) :
errorText( aMsg )
{
}
IOError( const wxString& aMsg ) :
errorText( aMsg )
{
}
};
/**
* Class LINE_READER
* reads single lines of text into its buffer and increments a line number counter.
* It throws an exception if a line is too long.
*/
class LINE_READER
{
protected:
FILE* fp;
int lineNum;
unsigned maxLineLength;
unsigned length;
char* line;
unsigned capacity;
public:
/**
* Constructor LINE_READER
* takes an open FILE and the size of the desired line buffer.
* @param aFile An open file in "ascii" mode, not binary mode.
* @param aMaxLineLength The number of bytes to use in the line buffer.
*/
LINE_READER( FILE* aFile, unsigned aMaxLineLength );
~LINE_READER()
{
delete[] line;
}
/*
int CharAt( int aNdx )
{
if( (unsigned) aNdx < capacity )
return (char) (unsigned char) line[aNdx];
return -1;
}
*/
/**
* Function ReadLine
* reads a line of text into the buffer and increments the line number
* counter. If the line is larger than the buffer size, then an exception
* is thrown.
* @return int - The number of bytes read, 0 at end of file.
* @throw IOError only when a line is too long.
*/
int ReadLine() throw (IOError);
operator char* ()
{
return line;
}
int LineNumber()
{
return lineNum;
}
unsigned Length()
{
return length;
}
};
/**
* Class OUTPUTFORMATTER
* is an interface (abstract class) used to output ASCII text in a convenient
* way. The primary interface is printf() like but with support for indentation
* control. The destination of the 8 bit wide text is up to the implementer.
* If you want to output a wxString, then use CONV_TO_UTF8() on it before passing
* it as an argument to Print().
* <p>
* Since this is an abstract interface, only classes derived from this one
* will be the implementations.
*/
class OUTPUTFORMATTER
{
#if defined(__GNUG__) // The GNU C++ compiler defines this
// When used on a C++ function, we must account for the "this" pointer,
// so increase the STRING-INDEX and FIRST-TO_CHECK by one.
// See http://docs.freebsd.org/info/gcc/gcc.info.Function_Attributes.html
// Then to get format checking during the compile, compile with -Wall or -Wformat
#define PRINTF_FUNC __attribute__ ((format (printf, 3, 4)))
#else
#define PRINTF_FUNC // nothing
#endif
public:
/**
* Function Print
* formats and writes text to the output stream.
*
* @param nestLevel The multiple of spaces to preceed the output with.
* @param fmt A printf() style format string.
* @param ... a variable list of parameters that will get blended into
* the output under control of the format string.
* @return int - the number of characters output.
* @throw IOError, if there is a problem outputting, such as a full disk.
*/
virtual int PRINTF_FUNC Print( int nestLevel, const char* fmt, ... ) throw( IOError ) = 0;
/**
* Function GetQuoteChar
* performs quote character need determination.
* It returns the quote character as a single character string for a given
* input wrapee string. If the wrappee does not need to be quoted,
* the return value is "" (the null string), such as when there are no
* delimiters in the input wrapee string. If you want the quote_char
* to be assuredly not "", then pass in "(" as the wrappee.
* <p>
* Implementations are free to override the default behavior, which is to
* call the static function of the same name.
* @param wrapee A string that might need wrapping on each end.
* @return const char* - the quote_char as a single character string, or ""
* if the wrapee does not need to be wrapped.
*/
virtual const char* GetQuoteChar( const char* wrapee ) = 0;
virtual ~OUTPUTFORMATTER() {}
/**
* Function GetQuoteChar
* performs quote character need determination according to the Specctra DSN
* specification.
* @param wrapee A string that might need wrapping on each end.
* @param quote_char A single character C string which provides the current
* quote character, should it be needed by the wrapee.
*
* @return const char* - the quote_char as a single character string, or ""
* if the wrapee does not need to be wrapped.
*/
static const char* GetQuoteChar( const char* wrapee, const char* quote_char );
};
/**
* Class STRINGFORMATTER
* implements OUTPUTFORMATTER to a memory buffer. After Print()ing the
* string is available through GetString()
*/
class STRINGFORMATTER : public OUTPUTFORMATTER
{
std::vector<char> buffer;
std::string mystring;
int sprint( const char* fmt, ... );
int vprint( const char* fmt, va_list ap );
public:
/**
* Constructor STRINGFORMATTER
* reserves space in the buffer
*/
STRINGFORMATTER( int aReserve = 300 ) :
buffer( aReserve, '\0' )
{
}
/**
* Function Clear
* clears the buffer and empties the internal string.
*/
void Clear()
{
mystring.clear();
}
/**
* Function StripUseless
* removes whitespace, '(', and ')' from the mystring.
*/
void StripUseless();
std::string GetString()
{
return mystring;
}
//-----<OUTPUTFORMATTER>------------------------------------------------
int PRINTF_FUNC Print( int nestLevel, const char* fmt, ... ) throw( IOError );
const char* GetQuoteChar( const char* wrapee );
//-----</OUTPUTFORMATTER>-----------------------------------------------
};
#endif // RICHIO_H_

View File

@ -78,7 +78,6 @@ set(PCBNEW_SRCS
dist.cpp dist.cpp
dragsegm.cpp dragsegm.cpp
drc.cpp drc.cpp
dsn.cpp
edgemod.cpp edgemod.cpp
edit.cpp edit.cpp
editedge.cpp editedge.cpp
@ -222,9 +221,9 @@ install(TARGETS pcbnew
# This one gets made only when testing. # This one gets made only when testing.
add_executable(dsntest EXCLUDE_FROM_ALL dsn.cpp) #add_executable(dsntest EXCLUDE_FROM_ALL dsn.cpp)
target_link_libraries(dsntest common ${wxWidgets_LIBRARIES}) #target_link_libraries(dsntest common ${wxWidgets_LIBRARIES})
# This one gets made only when testing. # This one gets made only when testing.
add_executable(specctra_test EXCLUDE_FROM_ALL specctra.cpp dsn.cpp) add_executable(specctra_test EXCLUDE_FROM_ALL specctra.cpp)
target_link_libraries(specctra_test common ${wxWidgets_LIBRARIES}) target_link_libraries(specctra_test common ${wxWidgets_LIBRARIES})

View File

@ -1,856 +0,0 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2007-2008 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2007 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 <cstdarg>
#include <cstdio>
#include <cstdlib> // bsearch()
#include <cctype>
#include "dsn.h"
#include "fctsys.h"
#include "pcbnew.h"
/**
* Class LEXER
* implements a lexical analyzer for the SPECCTRA DSN file format. It
* reads lexical tokens from the current LINE_READER through the NextTok()
* function. The NextTok() function returns one of the DSN_T values.
*/
namespace DSN {
/**
* Struct KEYWORD
* holds a string and a DSN_T
*/
struct KEYWORD
{
const char* name;
// int token;
};
//#define TOKDEF(x) { #x, T_##x }
#define TOKDEF(x) { #x }
// This MUST be sorted alphabetically, and also so MUST enum DSN_T {} be alphabetized.
// These MUST all be lower case because of the conversion to lowercase in findToken().
const static KEYWORD tokens[] = {
TOKDEF(absolute),
TOKDEF(added),
TOKDEF(add_group),
TOKDEF(add_pins),
TOKDEF(allow_antenna),
TOKDEF(allow_redundant_wiring),
TOKDEF(amp),
TOKDEF(ancestor),
TOKDEF(antipad),
TOKDEF(aperture_type),
TOKDEF(array),
TOKDEF(attach),
TOKDEF(attr),
TOKDEF(average_pair_length),
TOKDEF(back),
TOKDEF(base_design),
TOKDEF(bbv_ctr2ctr),
TOKDEF(bend_keepout),
TOKDEF(bond),
TOKDEF(both),
TOKDEF(bottom),
TOKDEF(bottom_layer_sel),
TOKDEF(boundary),
TOKDEF(brickpat),
TOKDEF(bundle),
TOKDEF(bus),
TOKDEF(bypass),
TOKDEF(capacitance_resolution),
TOKDEF(capacitor),
TOKDEF(case_sensitive),
TOKDEF(cct1),
TOKDEF(cct1a),
TOKDEF(center_center),
TOKDEF(checking_trim_by_pin),
TOKDEF(circ),
TOKDEF(circle),
TOKDEF(circuit),
TOKDEF(class),
TOKDEF(class_class),
TOKDEF(classes),
TOKDEF(clear),
TOKDEF(clearance),
TOKDEF(cluster),
TOKDEF(cm),
TOKDEF(color),
TOKDEF(colors),
TOKDEF(comment),
TOKDEF(comp),
TOKDEF(comp_edge_center),
TOKDEF(comp_order),
TOKDEF(component),
TOKDEF(composite),
TOKDEF(conductance_resolution),
TOKDEF(conductor),
TOKDEF(conflict),
TOKDEF(connect),
TOKDEF(constant),
TOKDEF(contact),
TOKDEF(control),
TOKDEF(corner),
TOKDEF(corners),
TOKDEF(cost),
TOKDEF(created_time),
TOKDEF(cross),
TOKDEF(crosstalk_model),
TOKDEF(current_resolution),
TOKDEF(delete_pins),
TOKDEF(deleted),
TOKDEF(deleted_keepout),
TOKDEF(delta),
TOKDEF(diagonal),
TOKDEF(direction),
TOKDEF(directory),
TOKDEF(discrete),
TOKDEF(effective_via_length),
TOKDEF(elongate_keepout),
TOKDEF(exclude),
TOKDEF(expose),
TOKDEF(extra_image_directory),
TOKDEF(family),
TOKDEF(family_family),
TOKDEF(family_family_spacing),
TOKDEF(fanout),
TOKDEF(farad),
TOKDEF(file),
TOKDEF(fit),
TOKDEF(fix),
TOKDEF(flip_style),
TOKDEF(floor_plan),
TOKDEF(footprint),
TOKDEF(forbidden),
TOKDEF(force_to_terminal_point),
TOKDEF(forgotten),
TOKDEF(free),
TOKDEF(fromto),
TOKDEF(front),
TOKDEF(front_only),
TOKDEF(gap),
TOKDEF(gate),
TOKDEF(gates),
TOKDEF(generated_by_freeroute),
TOKDEF(global),
TOKDEF(grid),
TOKDEF(group),
TOKDEF(group_set),
TOKDEF(guide),
TOKDEF(hard),
TOKDEF(height),
TOKDEF(high),
TOKDEF(history),
TOKDEF(horizontal),
TOKDEF(host_cad),
TOKDEF(host_version),
TOKDEF(image),
TOKDEF(image_conductor),
TOKDEF(image_image),
TOKDEF(image_image_spacing),
TOKDEF(image_outline_clearance),
TOKDEF(image_set),
TOKDEF(image_type),
TOKDEF(inch),
TOKDEF(include),
TOKDEF(include_pins_in_crosstalk),
TOKDEF(inductance_resolution),
TOKDEF(insert),
TOKDEF(instcnfg),
TOKDEF(inter_layer_clearance),
TOKDEF(jumper),
TOKDEF(junction_type),
TOKDEF(keepout),
TOKDEF(kg),
TOKDEF(kohm),
TOKDEF(large),
TOKDEF(large_large),
TOKDEF(layer),
TOKDEF(layer_depth),
TOKDEF(layer_noise_weight),
TOKDEF(layer_pair),
TOKDEF(layer_rule),
TOKDEF(length),
TOKDEF(length_amplitude),
TOKDEF(length_factor),
TOKDEF(length_gap),
TOKDEF(library),
TOKDEF(library_out),
TOKDEF(limit),
TOKDEF(limit_bends),
TOKDEF(limit_crossing),
TOKDEF(limit_vias),
TOKDEF(limit_way),
TOKDEF(linear),
TOKDEF(linear_interpolation),
TOKDEF(load),
TOKDEF(lock_type),
TOKDEF(logical_part),
TOKDEF(logical_part_mapping),
TOKDEF(low),
TOKDEF(match_fromto_delay),
TOKDEF(match_fromto_length),
TOKDEF(match_group_delay),
TOKDEF(match_group_length),
TOKDEF(match_net_delay),
TOKDEF(match_net_length),
TOKDEF(max_delay),
TOKDEF(max_len),
TOKDEF(max_length),
TOKDEF(max_noise),
TOKDEF(max_restricted_layer_length),
TOKDEF(max_stagger),
TOKDEF(max_stub),
TOKDEF(max_total_delay),
TOKDEF(max_total_length),
TOKDEF(max_total_vias),
TOKDEF(medium),
TOKDEF(mhenry),
TOKDEF(mho),
TOKDEF(microvia),
TOKDEF(mid_driven),
TOKDEF(mil),
TOKDEF(min_gap),
TOKDEF(mirror),
TOKDEF(mirror_first),
TOKDEF(mixed),
TOKDEF(mm),
TOKDEF(negative_diagonal),
TOKDEF(net),
TOKDEF(net_number),
TOKDEF(net_out),
TOKDEF(net_pin_changes),
TOKDEF(nets),
TOKDEF(network),
TOKDEF(network_out),
TOKDEF(no),
TOKDEF(noexpose),
TOKDEF(noise_accumulation),
TOKDEF(noise_calculation),
TOKDEF(normal),
TOKDEF(object_type),
TOKDEF(off),
TOKDEF(off_grid),
TOKDEF(offset),
TOKDEF(on),
TOKDEF(open),
TOKDEF(opposite_side),
TOKDEF(order),
TOKDEF(orthogonal),
TOKDEF(outline),
TOKDEF(overlap),
TOKDEF(pad),
TOKDEF(pad_pad),
TOKDEF(padstack),
TOKDEF(pair),
TOKDEF(parallel),
TOKDEF(parallel_noise),
TOKDEF(parallel_segment),
TOKDEF(parser),
TOKDEF(part_library),
TOKDEF(path),
TOKDEF(pcb),
TOKDEF(permit_orient),
TOKDEF(permit_side),
TOKDEF(physical),
TOKDEF(physical_part_mapping),
TOKDEF(piggyback),
TOKDEF(pin),
TOKDEF(pin_allow),
TOKDEF(pin_cap_via),
TOKDEF(pin_via_cap),
TOKDEF(pin_width_taper),
TOKDEF(pins),
TOKDEF(pintype),
TOKDEF(place),
TOKDEF(place_boundary),
TOKDEF(place_control),
TOKDEF(place_keepout),
TOKDEF(place_rule),
TOKDEF(placement),
TOKDEF(plan),
TOKDEF(plane),
TOKDEF(pn),
TOKDEF(point),
TOKDEF(polyline_path), // used by freerouting.com
TOKDEF(polygon),
TOKDEF(position),
TOKDEF(positive_diagonal),
TOKDEF(power),
TOKDEF(power_dissipation),
TOKDEF(power_fanout),
TOKDEF(prefix),
TOKDEF(primary),
TOKDEF(priority),
TOKDEF(property),
TOKDEF(protect),
TOKDEF(qarc),
TOKDEF(quarter),
TOKDEF(radius),
TOKDEF(ratio),
TOKDEF(ratio_tolerance),
TOKDEF(rect),
TOKDEF(reduced),
TOKDEF(region),
TOKDEF(region_class),
TOKDEF(region_class_class),
TOKDEF(region_net),
TOKDEF(relative_delay),
TOKDEF(relative_group_delay),
TOKDEF(relative_group_length),
TOKDEF(relative_length),
TOKDEF(reorder),
TOKDEF(reroute_order_viols),
TOKDEF(resistance_resolution),
TOKDEF(resistor),
TOKDEF(resolution),
TOKDEF(restricted_layer_length_factor),
TOKDEF(room),
TOKDEF(rotate),
TOKDEF(rotate_first),
TOKDEF(round),
TOKDEF(roundoff_rotation),
TOKDEF(route),
TOKDEF(route_to_fanout_only),
TOKDEF(routes),
TOKDEF(routes_include),
TOKDEF(rule),
TOKDEF(same_net_checking),
TOKDEF(sample_window),
TOKDEF(saturation_length),
TOKDEF(sec),
TOKDEF(secondary),
TOKDEF(self),
TOKDEF(sequence_number),
TOKDEF(session),
TOKDEF(set_color),
TOKDEF(set_pattern),
TOKDEF(shape),
TOKDEF(shield),
TOKDEF(shield_gap),
TOKDEF(shield_loop),
TOKDEF(shield_tie_down_interval),
TOKDEF(shield_width),
TOKDEF(side),
TOKDEF(signal),
TOKDEF(site),
TOKDEF(small),
TOKDEF(smd),
TOKDEF(snap),
TOKDEF(snap_angle),
TOKDEF(soft),
TOKDEF(source),
TOKDEF(space_in_quoted_tokens),
TOKDEF(spacing),
TOKDEF(spare),
TOKDEF(spiral_via),
TOKDEF(square),
TOKDEF(stack_via),
TOKDEF(stack_via_depth),
TOKDEF(standard),
TOKDEF(starburst),
TOKDEF(status),
TOKDEF(string_quote),
TOKDEF(structure),
TOKDEF(structure_out),
TOKDEF(subgate),
TOKDEF(subgates),
TOKDEF(substituted),
TOKDEF(such),
TOKDEF(suffix),
TOKDEF(super_placement),
TOKDEF(supply),
TOKDEF(supply_pin),
TOKDEF(swapping),
TOKDEF(switch_window),
TOKDEF(system),
TOKDEF(tandem_noise),
TOKDEF(tandem_segment),
TOKDEF(tandem_shield_overhang),
TOKDEF(terminal),
TOKDEF(terminator),
TOKDEF(term_only),
TOKDEF(test),
TOKDEF(test_points),
TOKDEF(testpoint),
TOKDEF(threshold),
TOKDEF(time_length_factor),
TOKDEF(time_resolution),
TOKDEF(tjunction),
TOKDEF(tolerance),
TOKDEF(top),
TOKDEF(topology),
TOKDEF(total),
TOKDEF(track_id),
TOKDEF(turret),
TOKDEF(type),
TOKDEF(um),
TOKDEF(unassigned),
TOKDEF(unconnects),
TOKDEF(unit),
TOKDEF(up),
TOKDEF(use_array),
TOKDEF(use_layer),
TOKDEF(use_net),
TOKDEF(use_via),
TOKDEF(value),
TOKDEF(vertical),
TOKDEF(via),
TOKDEF(via_array_template),
TOKDEF(via_at_smd),
TOKDEF(via_keepout),
TOKDEF(via_number),
TOKDEF(via_rotate_first),
TOKDEF(via_site),
TOKDEF(via_size),
TOKDEF(virtual_pin),
TOKDEF(volt),
TOKDEF(voltage_resolution),
TOKDEF(was_is),
TOKDEF(way),
TOKDEF(weight),
TOKDEF(width),
TOKDEF(window),
TOKDEF(wire),
TOKDEF(wire_keepout),
TOKDEF(wires),
TOKDEF(wires_include),
TOKDEF(wiring),
TOKDEF(write_resolution),
TOKDEF(x),
TOKDEF(xy),
TOKDEF(y),
};
static int compare( const void* a1, const void* a2 )
{
const KEYWORD* k1 = (const KEYWORD*) a1;
const KEYWORD* k2 = (const KEYWORD*) a2;
int ret = strcmp( k1->name, k2->name );
return ret;
}
//-----<LINE_READER>------------------------------------------------------
LINE_READER::LINE_READER( FILE* aFile, unsigned aMaxLineLength )
{
fp = aFile;
lineNum = 0;
maxLineLength = aMaxLineLength;
// the real capacity is 10 bytes larger than requested.
capacity = aMaxLineLength + 10;
line = new char[capacity];
line[0] = '\0';
length = 0;
}
int LINE_READER::ReadLine() throw (IOError)
{
const char* p = fgets( line, capacity, fp );
if( !p )
{
line[0] = 0;
length = 0;
}
else
{
length = strlen( line );
if( length > maxLineLength )
throw IOError( _("Line length exceeded") );
++lineNum;
}
return length;
}
//-----<LEXER>-------------------------------------------------------------
LEXER::LEXER( FILE* aFile, const wxString& aFilename ) :
reader( aFile, 4096 )
{
curTok = T_END;
stringDelimiter = '"';
filename = aFilename;
space_in_quoted_tokens = true;
// "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 )
{
// convert to lower case once, this should be faster than using strcasecmp()
// for each test in compare().
lowercase.clear();
for( std::string::const_iterator iter = tok.begin(); iter!=tok.end(); ++iter )
lowercase += (char) tolower( *iter );
KEYWORD search;
search.name = lowercase.c_str();
const KEYWORD* findings = (const KEYWORD*) bsearch( &search,
tokens, sizeof(tokens)/sizeof(tokens[0]),
sizeof(KEYWORD), compare );
if( findings )
// return findings->token;
return findings - tokens;
else
return -1;
}
const char* LEXER::GetTokenText( DSN_T aTok )
{
const char* ret;
if( aTok < 0 )
{
switch( aTok )
{
case T_NONE:
ret = "NONE";
break;
case T_QUOTE_DEF:
ret = "quoted text delimiter";
break;
case T_DASH:
ret = "-";
break;
case T_SYMBOL:
ret = "symbol";
break;
case T_NUMBER:
ret = "number";
break;
case T_RIGHT:
ret = ")";
break;
case T_LEFT:
ret = "(";
break;
case T_STRING:
ret = "quoted string";
break;
case T_EOF:
ret = "end of file";
break;
default:
ret = "???";
}
}
else
{
ret = tokens[aTok].name;
}
return ret;
}
wxString LEXER::GetTokenString( DSN_T aTok )
{
wxString ret;
ret << wxT("'") << CONV_FROM_UTF8( GetTokenText(aTok) ) << 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 );
}
/**
* Function isspace
* strips the upper bits of the int to ensure the value passed to ::isspace() is
* in the range of 0-255
*/
static inline bool isSpace( int cc )
{
// make sure int passed to ::isspace() is 0-255
return ::isspace( cc & 0xff );
}
DSN_T LEXER::NextTok() throw (IOError)
{
char* cur = next;
char* head = cur;
prevTok = curTok;
if( curTok != T_EOF )
{
if( cur >= limit )
{
L_read:
int len = readLine();
if( len == 0 )
{
curTok = T_EOF;
goto exit;
}
cur = start;
// skip leading whitespace
while( cur<limit && isSpace(*cur) )
++cur;
// if the first non-blank character is #, this line is a comment.
if( cur<limit && *cur=='#' )
goto L_read;
}
else
{
// skip leading whitespace
while( cur<limit && isSpace(*cur) )
++cur;
}
if( cur >= limit )
goto L_read;
// switching the string_quote character
if( prevTok == 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 += cc;
head = cur+1;
if( head<limit && *head!=')' && *head!='(' && !isSpace(*head) )
{
ThrowIOError( errtxt, CurOffset() );
}
curTok = T_QUOTE_DEF;
goto exit;
}
if( *cur == '(' )
{
curText.clear();
curText += *cur;
curTok = T_LEFT;
head = cur+1;
goto exit;
}
if( *cur == ')' )
{
curText.clear();
curText += *cur;
curTok = T_RIGHT;
head = cur+1;
goto exit;
}
/* get the dash out of a <pin_reference> which is embedded for example
like: U2-14 or "U2"-"14"
This is detectable by a non-space immediately preceeding the dash.
*/
if( *cur == '-' && cur>start && !isSpace( cur[-1] ) )
{
head = cur+1;
curText.clear();
curText += '-';
curTok = T_DASH;
goto exit;
}
// handle T_NUMBER
if( strchr( "+-.0123456789", *cur ) )
{
head = cur+1;
while( head<limit && strchr( ".0123456789", *head ) )
++head;
if( (head<limit && isSpace(*head)) || *head==')' || *head=='(' || head==limit )
{
curText.clear();
curText.append( cur, head );
curTok = T_NUMBER;
goto exit;
}
// else it was something like +5V, fall through below
}
// a quoted string
if( *cur == stringDelimiter )
{
++cur; // skip over the leading delimiter: ",', or $
head = cur;
while( head<limit && !isStringTerminator( *head ) )
++head;
if( head >= limit )
{
wxString errtxt(_("Un-terminated delimited string") );
ThrowIOError( errtxt, CurOffset() );
}
curText.clear();
curText.append( cur, head );
++head; // skip over the trailing delimiter
curTok = T_STRING;
goto exit;
}
// a token we hope to find in the tokens[] array. If not, then
// call it a T_SYMBOL.
{
head = cur+1;
while( head<limit && !isSpace( *head ) && *head!=')' && *head!='(' )
++head;
curText.clear();
curText.append( cur, head );
int found = findToken( curText );
if( found != -1 )
curTok = (DSN_T) found;
else // unrecogized token, call it a symbol
curTok = T_SYMBOL;
}
}
exit: // single point of exit
curOffset = cur - start;
next = head;
// printf("tok:\"%s\"\n", curText.c_str() );
return curTok;
}
} // namespace DSN
#if 0 && defined(STANDALONE)
// stand alone testing
int main( int argc, char** argv )
{
// wxString filename( wxT("/tmp/fpcroute/Sample_1sided/demo_1sided.dsn") );
wxString filename( wxT("/tmp/testdesigns/test.dsn") );
FILE* fp = wxFopen( filename, wxT("r") );
if( !fp )
{
fprintf( stderr, "unable to open file \"%s\"\n",
(const char*) filename.mb_str() );
exit(1);
}
DSN::LEXER lexer( fp, filename );
try
{
int tok;
while( (tok = lexer.NextTok()) != DSN::T_EOF )
{
printf( "%-3d %s\n", tok, lexer.CurText() );
}
}
catch( DSN::IOError ioe )
{
printf( "%s\n", (const char*) ioe.errorText.mb_str() );
}
fclose( fp );
return 0;
}
#endif

View File

@ -1,725 +0,0 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2007-2008 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2007 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 _DSN_H
#define _DSN_H
#include <cstdio>
#include <string>
#include "fctsys.h"
#include "pcbnew.h"
namespace DSN {
/**
* Enum DSN_T
* lists all the DSN lexer's tokens that are supported in lexing. It is up
* to the parser if it wants also to support them.
*/
enum DSN_T {
// the first few are special (the uppercase ones)
T_NONE = -9,
T_QUOTE_DEF = -8,
T_DASH = -7,
T_SYMBOL = -6,
T_NUMBER = -5,
T_RIGHT = -4, // right bracket, ')'
T_LEFT = -3, // left bracket, '('
T_STRING = -2, // a quoted string, stripped of the quotes
T_EOF = -1, // special case for end of file
// from here down, this list segment should be coordinated with the
// const static KEYWORD tokens[] array in dsn.cpp, and must be sorted
// alphabetically. Remember that '_' is less than any alpha character
// according to ASCII.
T_absolute, // this one should be == zero
T_added,
T_add_group,
T_add_pins,
T_allow_antenna,
T_allow_redundant_wiring,
T_amp,
T_ancestor,
T_antipad,
T_aperture_type,
T_array,
T_attach,
T_attr,
T_average_pair_length,
T_back,
T_base_design,
T_bbv_ctr2ctr,
T_bend_keepout,
T_bond,
T_both,
T_bottom,
T_bottom_layer_sel,
T_boundary,
T_brickpat,
T_bundle,
T_bus,
T_bypass,
T_capacitance_resolution,
T_capacitor,
T_case_sensitive,
T_cct1,
T_cct1a,
T_center_center,
T_checking_trim_by_pin,
T_circ,
T_circle,
T_circuit,
T_class,
T_class_class,
T_classes,
T_clear,
T_clearance,
T_cluster,
T_cm,
T_color,
T_colors,
T_comment,
T_comp,
T_comp_edge_center,
T_comp_order,
T_component,
T_composite,
T_conductance_resolution,
T_conductor,
T_conflict,
T_connect,
T_constant,
T_contact,
T_control,
T_corner,
T_corners,
T_cost,
T_created_time,
T_cross,
T_crosstalk_model,
T_current_resolution,
T_delete_pins,
T_deleted,
T_deleted_keepout,
T_delta,
T_diagonal,
T_direction,
T_directory,
T_discrete,
T_effective_via_length,
T_elongate_keepout,
T_exclude,
T_expose,
T_extra_image_directory,
T_family,
T_family_family,
T_family_family_spacing,
T_fanout,
T_farad,
T_file,
T_fit,
T_fix,
T_flip_style,
T_floor_plan,
T_footprint,
T_forbidden,
T_force_to_terminal_point,
T_free,
T_forgotten,
T_fromto,
T_front,
T_front_only,
T_gap,
T_gate,
T_gates,
T_generated_by_freeroute,
T_global,
T_grid,
T_group,
T_group_set,
T_guide,
T_hard,
T_height,
T_high,
T_history,
T_horizontal,
T_host_cad,
T_host_version,
T_image,
T_image_conductor,
T_image_image,
T_image_image_spacing,
T_image_outline_clearance,
T_image_set,
T_image_type,
T_inch,
T_include,
T_include_pins_in_crosstalk,
T_inductance_resolution,
T_insert,
T_instcnfg,
T_inter_layer_clearance,
T_jumper,
T_junction_type,
T_keepout,
T_kg,
T_kohm,
T_large,
T_large_large,
T_layer,
T_layer_depth,
T_layer_noise_weight,
T_layer_pair,
T_layer_rule,
T_length,
T_length_amplitude,
T_length_factor,
T_length_gap,
T_library,
T_library_out,
T_limit,
T_limit_bends,
T_limit_crossing,
T_limit_vias,
T_limit_way,
T_linear,
T_linear_interpolation,
T_load,
T_lock_type,
T_logical_part,
T_logical_part_mapping,
T_low,
T_match_fromto_delay,
T_match_fromto_length,
T_match_group_delay,
T_match_group_length,
T_match_net_delay,
T_match_net_length,
T_max_delay,
T_max_len,
T_max_length,
T_max_noise,
T_max_restricted_layer_length,
T_max_stagger,
T_max_stub,
T_max_total_delay,
T_max_total_length,
T_max_total_vias,
T_medium,
T_mhenry,
T_mho,
T_microvia,
T_mid_driven,
T_mil,
T_min_gap,
T_mirror,
T_mirror_first,
T_mixed,
T_mm,
T_negative_diagonal,
T_net,
T_net_number,
T_net_out,
T_net_pin_changes,
T_nets,
T_network,
T_network_out,
T_no,
T_noexpose,
T_noise_accumulation,
T_noise_calculation,
T_normal,
T_object_type,
T_off,
T_off_grid,
T_offset,
T_on,
T_open,
T_opposite_side,
T_order,
T_orthogonal,
T_outline,
T_overlap,
T_pad,
T_pad_pad,
T_padstack,
T_pair,
T_parallel,
T_parallel_noise,
T_parallel_segment,
T_parser,
T_part_library,
T_path,
T_pcb,
T_permit_orient,
T_permit_side,
T_physical,
T_physical_part_mapping,
T_piggyback,
T_pin,
T_pin_allow,
T_pin_cap_via,
T_pin_via_cap,
T_pin_width_taper,
T_pins,
T_pintype,
T_place,
T_place_boundary,
T_place_control,
T_place_keepout,
T_place_rule,
T_placement,
T_plan,
T_plane,
T_pn,
T_point,
T_polyline_path,
T_polygon,
T_position,
T_positive_diagonal,
T_power,
T_power_dissipation,
T_power_fanout,
T_prefix,
T_primary,
T_priority,
T_property,
T_protect,
T_qarc,
T_quarter,
T_radius,
T_ratio,
T_ratio_tolerance,
T_rect,
T_reduced,
T_region,
T_region_class,
T_region_class_class,
T_region_net,
T_relative_delay,
T_relative_group_delay,
T_relative_group_length,
T_relative_length,
T_reorder,
T_reroute_order_viols,
T_resistance_resolution,
T_resistor,
T_resolution,
T_restricted_layer_length_factor,
T_room,
T_rotate,
T_rotate_first,
T_round,
T_roundoff_rotation,
T_route,
T_route_to_fanout_only,
T_routes,
T_routes_include,
T_rule,
T_same_net_checking,
T_sample_window,
T_saturation_length,
T_sec,
T_secondary,
T_self,
T_sequence_number,
T_session,
T_set_color,
T_set_pattern,
T_shape,
T_shield,
T_shield_gap,
T_shield_loop,
T_shield_tie_down_interval,
T_shield_width,
T_side,
T_signal,
T_site,
T_small,
T_smd,
T_snap,
T_snap_angle,
T_soft,
T_source,
T_space_in_quoted_tokens,
T_spacing,
T_spare,
T_spiral_via,
T_square,
T_stack_via,
T_stack_via_depth,
T_standard,
T_starburst,
T_status,
T_string_quote,
T_structure,
T_structure_out,
T_subgate,
T_subgates,
T_substituted,
T_such,
T_suffix,
T_super_placement,
T_supply,
T_supply_pin,
T_swapping,
T_switch_window,
T_system,
T_tandem_noise,
T_tandem_segment,
T_tandem_shield_overhang,
T_terminal,
T_terminator,
T_term_only,
T_test,
T_test_points,
T_testpoint,
T_threshold,
T_time_length_factor,
T_time_resolution,
T_tjunction,
T_tolerance,
T_top,
T_topology,
T_total,
T_track_id,
T_turret,
T_type,
T_um,
T_unassigned,
T_unconnects,
T_unit,
T_up,
T_use_array,
T_use_layer,
T_use_net,
T_use_via,
T_value,
T_vertical,
T_via,
T_via_array_template,
T_via_at_smd,
T_via_keepout,
T_via_number,
T_via_rotate_first,
T_via_site,
T_via_size,
T_virtual_pin,
T_volt,
T_voltage_resolution,
T_was_is,
T_way,
T_weight,
T_width,
T_window,
T_wire,
T_wire_keepout,
T_wires,
T_wires_include,
T_wiring,
T_write_resolution,
T_x,
T_xy,
T_y,
T_END // just a sentinel, not a token
};
/**
* Struct IOError
* is a class used to hold an error message and may be thrown from the LEXER.
*/
struct IOError
{
wxString errorText;
IOError( const wxChar* aMsg ) :
errorText( aMsg )
{
}
IOError( const wxString& aMsg ) :
errorText( aMsg )
{
}
};
/**
* Class LINE_READER
* reads single lines of text into its buffer and increments a line number counter.
* It throws an exception if a line is too long.
*/
class LINE_READER
{
protected:
FILE* fp;
int lineNum;
unsigned maxLineLength;
unsigned length;
char* line;
unsigned capacity;
public:
/**
* Constructor LINE_READER
* takes an open FILE and the size of the desired line buffer.
* @param aFile An open file in "ascii" mode, not binary mode.
* @param aMaxLineLength The number of bytes to use in the line buffer.
*/
LINE_READER( FILE* aFile, unsigned aMaxLineLength );
~LINE_READER()
{
delete[] line;
}
/*
int CharAt( int aNdx )
{
if( (unsigned) aNdx < capacity )
return (char) (unsigned char) line[aNdx];
return -1;
}
*/
/**
* Function ReadLine
* reads a line of text into the buffer and increments the line number
* counter. If the line is larger than the buffer size, then an exception
* is thrown.
* @return int - The number of bytes read, 0 at end of file.
* @throw IOError only when a line is too long.
*/
int ReadLine() throw (IOError);
operator char* ()
{
return line;
}
int LineNumber()
{
return lineNum;
}
unsigned Length()
{
return length;
}
};
/**
* Class LEXER
* implements a lexical analyzer for the SPECCTRA DSN file format. It
* reads lexical tokens from the current LINE_READER through the NextTok()
* function. The NextTok() function returns one of the DSN_T values.
*/
class LEXER
{
char* next;
char* start;
char* limit;
LINE_READER reader;
int stringDelimiter;
bool space_in_quoted_tokens; ///< blank spaces within quoted strings
wxString filename;
DSN_T prevTok; ///< 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()
std::string curText; ///< the text of the current token
std::string lowercase; ///< a scratch buf holding token in lowercase
int readLine() throw (IOError)
{
int len = reader.ReadLine();
next = start;
limit = start + len;
return len;
}
/**
* Function findToken
* takes a string and looks up the string in the list of expected
* tokens.
*
* @param tok A string holding the token text to lookup, in an
* unpredictable case: uppercase or lowercase
* @return int - DSN_T or -1 if argument string is not a recognized token.
*/
int findToken( const std::string& tok );
bool isStringTerminator( char cc )
{
if( !space_in_quoted_tokens && cc==' ' )
return true;
if( cc == stringDelimiter )
return true;
return false;
}
public:
LEXER( FILE* aFile, const wxString& aFilename );
/**
* Function SetStringDelimiter
* changes the string delimiter from the default " to some other character
* and returns the old value.
* @param aStringDelimiter The character in lowest 8 bits.
* @return int - The old delimiter in the lowest 8 bits.
*/
int SetStringDelimiter( int aStringDelimiter )
{
int old = stringDelimiter;
stringDelimiter = aStringDelimiter;
return old;
}
/**
* Function SetSpaceInQuotedTokens
* changes the setting controlling whether a space in a quoted string is
* a terminator.
* @param val If true, means
*/
bool SetSpaceInQuotedTokens( bool val )
{
bool old = space_in_quoted_tokens;
space_in_quoted_tokens = val;
return old;
}
/**
* Function NextTok
* returns the next token found in the input file or T_EOF when reaching
* the end of file.
* @return DSN_T - the type of token found next.
* @throw IOError - only if the LINE_READER throws it.
*/
DSN_T NextTok() throw (IOError);
/**
* Function ThrowIOError
* encapsulates the formatting of an error message which contains the exact
* location within the input file of something the caller is rejecting.
*/
void ThrowIOError( wxString aText, int charOffset ) throw (IOError);
/**
* Function GetTokenString
* returns the wxString representation of a DSN_T value.
*/
static wxString GetTokenString( DSN_T aTok );
/**
* Function GetTokenString
* returns the C string representation of a DSN_T value.
*/
static const char* GetTokenText( DSN_T aTok );
/**
* Function CurText
* returns a pointer to the current token's text.
*/
const char* CurText()
{
return curText.c_str();
}
/**
* Function CurTok
* returns whatever NextTok() returned the last time it was called.
*/
DSN_T CurTok()
{
return curTok;
}
/**
* Function CurLineNumber
* returns the current line number within my LINE_READER
*/
int CurLineNumber()
{
return reader.LineNumber();
}
/**
* Function CurFilename
* returns the current input filename.
* @return const wxString& - the filename.
*/
const wxString& CurFilename()
{
return filename;
}
/**
* Function PrevTok
* returns whatever NextTok() returned the 2nd to last time it was called.
*/
DSN_T PrevTok()
{
return prevTok;
}
/**
* 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;
}
};
} // namespace DSN
#endif // _DSN_H

View File

@ -47,20 +47,21 @@
*/ */
#include <cstdarg> #include <cstdarg>
#include <cstdio> #include <cstdio>
#include "specctra.h" #include "specctra.h"
#include "common.h" // IsOK() & EDA_FileSelector()
#include <wx/ffile.h> #include <wx/ffile.h>
// To build the DSN beautifier and unit tester, simply uncomment this and then // To build the DSN beautifier and unit tester, simply uncomment this and then
// use CMake's makefile to build target "specctra_test". // use CMake's makefile to build target "specctra_test".
#define STANDALONE // define "stand alone, i.e. unit testing" //#define SPECCTRA_TEST // define for "stand alone, i.e. unit testing"
#if defined(STANDALONE) #if defined(SPECCTRA_TEST)
#define EDA_BASE // build_version.h behavior #define EDA_BASE // build_version.h behavior
#undef COMMON_GLOBL #undef COMMON_GLOBL
#define COMMON_GLOBL // build_version.h behavior #define COMMON_GLOBL // build_version.h behavior
@ -72,11 +73,445 @@ namespace DSN {
#define NESTWIDTH 2 ///< how many spaces per nestLevel #define NESTWIDTH 2 ///< how many spaces per nestLevel
#define TOKDEF(x) { #x, T_##x }
// This MUST be sorted alphabetically, and the order of enum DSN_T {} be
// identially alphabetized. These MUST all be lower case because of the
// conversion to lowercase in findToken().
const KEYWORD SPECCTRA_DB::keywords[] = {
// Note that TOKDEF(string_quote) has been moved to the
// DSNLEXER, and DSN_SYNTAX_T enum, and the string for it is "string_quote".
TOKDEF(absolute),
TOKDEF(added),
TOKDEF(add_group),
TOKDEF(add_pins),
TOKDEF(allow_antenna),
TOKDEF(allow_redundant_wiring),
TOKDEF(amp),
TOKDEF(ancestor),
TOKDEF(antipad),
TOKDEF(aperture_type),
TOKDEF(array),
TOKDEF(attach),
TOKDEF(attr),
TOKDEF(average_pair_length),
TOKDEF(back),
TOKDEF(base_design),
TOKDEF(bbv_ctr2ctr),
TOKDEF(bend_keepout),
TOKDEF(bond),
TOKDEF(both),
TOKDEF(bottom),
TOKDEF(bottom_layer_sel),
TOKDEF(boundary),
TOKDEF(brickpat),
TOKDEF(bundle),
TOKDEF(bus),
TOKDEF(bypass),
TOKDEF(capacitance_resolution),
TOKDEF(capacitor),
TOKDEF(case_sensitive),
TOKDEF(cct1),
TOKDEF(cct1a),
TOKDEF(center_center),
TOKDEF(checking_trim_by_pin),
TOKDEF(circ),
TOKDEF(circle),
TOKDEF(circuit),
TOKDEF(class),
TOKDEF(class_class),
TOKDEF(classes),
TOKDEF(clear),
TOKDEF(clearance),
TOKDEF(cluster),
TOKDEF(cm),
TOKDEF(color),
TOKDEF(colors),
TOKDEF(comment),
TOKDEF(comp),
TOKDEF(comp_edge_center),
TOKDEF(comp_order),
TOKDEF(component),
TOKDEF(composite),
TOKDEF(conductance_resolution),
TOKDEF(conductor),
TOKDEF(conflict),
TOKDEF(connect),
TOKDEF(constant),
TOKDEF(contact),
TOKDEF(control),
TOKDEF(corner),
TOKDEF(corners),
TOKDEF(cost),
TOKDEF(created_time),
TOKDEF(cross),
TOKDEF(crosstalk_model),
TOKDEF(current_resolution),
TOKDEF(delete_pins),
TOKDEF(deleted),
TOKDEF(deleted_keepout),
TOKDEF(delta),
TOKDEF(diagonal),
TOKDEF(direction),
TOKDEF(directory),
TOKDEF(discrete),
TOKDEF(effective_via_length),
TOKDEF(elongate_keepout),
TOKDEF(exclude),
TOKDEF(expose),
TOKDEF(extra_image_directory),
TOKDEF(family),
TOKDEF(family_family),
TOKDEF(family_family_spacing),
TOKDEF(fanout),
TOKDEF(farad),
TOKDEF(file),
TOKDEF(fit),
TOKDEF(fix),
TOKDEF(flip_style),
TOKDEF(floor_plan),
TOKDEF(footprint),
TOKDEF(forbidden),
TOKDEF(force_to_terminal_point),
TOKDEF(forgotten),
TOKDEF(free),
TOKDEF(fromto),
TOKDEF(front),
TOKDEF(front_only),
TOKDEF(gap),
TOKDEF(gate),
TOKDEF(gates),
TOKDEF(generated_by_freeroute),
TOKDEF(global),
TOKDEF(grid),
TOKDEF(group),
TOKDEF(group_set),
TOKDEF(guide),
TOKDEF(hard),
TOKDEF(height),
TOKDEF(high),
TOKDEF(history),
TOKDEF(horizontal),
TOKDEF(host_cad),
TOKDEF(host_version),
TOKDEF(image),
TOKDEF(image_conductor),
TOKDEF(image_image),
TOKDEF(image_image_spacing),
TOKDEF(image_outline_clearance),
TOKDEF(image_set),
TOKDEF(image_type),
TOKDEF(inch),
TOKDEF(include),
TOKDEF(include_pins_in_crosstalk),
TOKDEF(inductance_resolution),
TOKDEF(insert),
TOKDEF(instcnfg),
TOKDEF(inter_layer_clearance),
TOKDEF(jumper),
TOKDEF(junction_type),
TOKDEF(keepout),
TOKDEF(kg),
TOKDEF(kohm),
TOKDEF(large),
TOKDEF(large_large),
TOKDEF(layer),
TOKDEF(layer_depth),
TOKDEF(layer_noise_weight),
TOKDEF(layer_pair),
TOKDEF(layer_rule),
TOKDEF(length),
TOKDEF(length_amplitude),
TOKDEF(length_factor),
TOKDEF(length_gap),
TOKDEF(library),
TOKDEF(library_out),
TOKDEF(limit),
TOKDEF(limit_bends),
TOKDEF(limit_crossing),
TOKDEF(limit_vias),
TOKDEF(limit_way),
TOKDEF(linear),
TOKDEF(linear_interpolation),
TOKDEF(load),
TOKDEF(lock_type),
TOKDEF(logical_part),
TOKDEF(logical_part_mapping),
TOKDEF(low),
TOKDEF(match_fromto_delay),
TOKDEF(match_fromto_length),
TOKDEF(match_group_delay),
TOKDEF(match_group_length),
TOKDEF(match_net_delay),
TOKDEF(match_net_length),
TOKDEF(max_delay),
TOKDEF(max_len),
TOKDEF(max_length),
TOKDEF(max_noise),
TOKDEF(max_restricted_layer_length),
TOKDEF(max_stagger),
TOKDEF(max_stub),
TOKDEF(max_total_delay),
TOKDEF(max_total_length),
TOKDEF(max_total_vias),
TOKDEF(medium),
TOKDEF(mhenry),
TOKDEF(mho),
TOKDEF(microvia),
TOKDEF(mid_driven),
TOKDEF(mil),
TOKDEF(min_gap),
TOKDEF(mirror),
TOKDEF(mirror_first),
TOKDEF(mixed),
TOKDEF(mm),
TOKDEF(negative_diagonal),
TOKDEF(net),
TOKDEF(net_number),
TOKDEF(net_out),
TOKDEF(net_pin_changes),
TOKDEF(nets),
TOKDEF(network),
TOKDEF(network_out),
TOKDEF(no),
TOKDEF(noexpose),
TOKDEF(noise_accumulation),
TOKDEF(noise_calculation),
TOKDEF(normal),
TOKDEF(object_type),
TOKDEF(off),
TOKDEF(off_grid),
TOKDEF(offset),
TOKDEF(on),
TOKDEF(open),
TOKDEF(opposite_side),
TOKDEF(order),
TOKDEF(orthogonal),
TOKDEF(outline),
TOKDEF(overlap),
TOKDEF(pad),
TOKDEF(pad_pad),
TOKDEF(padstack),
TOKDEF(pair),
TOKDEF(parallel),
TOKDEF(parallel_noise),
TOKDEF(parallel_segment),
TOKDEF(parser),
TOKDEF(part_library),
TOKDEF(path),
TOKDEF(pcb),
TOKDEF(permit_orient),
TOKDEF(permit_side),
TOKDEF(physical),
TOKDEF(physical_part_mapping),
TOKDEF(piggyback),
TOKDEF(pin),
TOKDEF(pin_allow),
TOKDEF(pin_cap_via),
TOKDEF(pin_via_cap),
TOKDEF(pin_width_taper),
TOKDEF(pins),
TOKDEF(pintype),
TOKDEF(place),
TOKDEF(place_boundary),
TOKDEF(place_control),
TOKDEF(place_keepout),
TOKDEF(place_rule),
TOKDEF(placement),
TOKDEF(plan),
TOKDEF(plane),
TOKDEF(pn),
TOKDEF(point),
TOKDEF(polyline_path), // used by freerouting.com
TOKDEF(polygon),
TOKDEF(position),
TOKDEF(positive_diagonal),
TOKDEF(power),
TOKDEF(power_dissipation),
TOKDEF(power_fanout),
TOKDEF(prefix),
TOKDEF(primary),
TOKDEF(priority),
TOKDEF(property),
TOKDEF(protect),
TOKDEF(qarc),
TOKDEF(quarter),
TOKDEF(radius),
TOKDEF(ratio),
TOKDEF(ratio_tolerance),
TOKDEF(rect),
TOKDEF(reduced),
TOKDEF(region),
TOKDEF(region_class),
TOKDEF(region_class_class),
TOKDEF(region_net),
TOKDEF(relative_delay),
TOKDEF(relative_group_delay),
TOKDEF(relative_group_length),
TOKDEF(relative_length),
TOKDEF(reorder),
TOKDEF(reroute_order_viols),
TOKDEF(resistance_resolution),
TOKDEF(resistor),
TOKDEF(resolution),
TOKDEF(restricted_layer_length_factor),
TOKDEF(room),
TOKDEF(rotate),
TOKDEF(rotate_first),
TOKDEF(round),
TOKDEF(roundoff_rotation),
TOKDEF(route),
TOKDEF(route_to_fanout_only),
TOKDEF(routes),
TOKDEF(routes_include),
TOKDEF(rule),
TOKDEF(same_net_checking),
TOKDEF(sample_window),
TOKDEF(saturation_length),
TOKDEF(sec),
TOKDEF(secondary),
TOKDEF(self),
TOKDEF(sequence_number),
TOKDEF(session),
TOKDEF(set_color),
TOKDEF(set_pattern),
TOKDEF(shape),
TOKDEF(shield),
TOKDEF(shield_gap),
TOKDEF(shield_loop),
TOKDEF(shield_tie_down_interval),
TOKDEF(shield_width),
TOKDEF(side),
TOKDEF(signal),
TOKDEF(site),
TOKDEF(small),
TOKDEF(smd),
TOKDEF(snap),
TOKDEF(snap_angle),
TOKDEF(soft),
TOKDEF(source),
TOKDEF(space_in_quoted_tokens),
TOKDEF(spacing),
TOKDEF(spare),
TOKDEF(spiral_via),
TOKDEF(square),
TOKDEF(stack_via),
TOKDEF(stack_via_depth),
TOKDEF(standard),
TOKDEF(starburst),
TOKDEF(status),
TOKDEF(structure),
TOKDEF(structure_out),
TOKDEF(subgate),
TOKDEF(subgates),
TOKDEF(substituted),
TOKDEF(such),
TOKDEF(suffix),
TOKDEF(super_placement),
TOKDEF(supply),
TOKDEF(supply_pin),
TOKDEF(swapping),
TOKDEF(switch_window),
TOKDEF(system),
TOKDEF(tandem_noise),
TOKDEF(tandem_segment),
TOKDEF(tandem_shield_overhang),
TOKDEF(terminal),
TOKDEF(terminator),
TOKDEF(term_only),
TOKDEF(test),
TOKDEF(test_points),
TOKDEF(testpoint),
TOKDEF(threshold),
TOKDEF(time_length_factor),
TOKDEF(time_resolution),
TOKDEF(tjunction),
TOKDEF(tolerance),
TOKDEF(top),
TOKDEF(topology),
TOKDEF(total),
TOKDEF(track_id),
TOKDEF(turret),
TOKDEF(type),
TOKDEF(um),
TOKDEF(unassigned),
TOKDEF(unconnects),
TOKDEF(unit),
TOKDEF(up),
TOKDEF(use_array),
TOKDEF(use_layer),
TOKDEF(use_net),
TOKDEF(use_via),
TOKDEF(value),
TOKDEF(vertical),
TOKDEF(via),
TOKDEF(via_array_template),
TOKDEF(via_at_smd),
TOKDEF(via_keepout),
TOKDEF(via_number),
TOKDEF(via_rotate_first),
TOKDEF(via_site),
TOKDEF(via_size),
TOKDEF(virtual_pin),
TOKDEF(volt),
TOKDEF(voltage_resolution),
TOKDEF(was_is),
TOKDEF(way),
TOKDEF(weight),
TOKDEF(width),
TOKDEF(window),
TOKDEF(wire),
TOKDEF(wire_keepout),
TOKDEF(wires),
TOKDEF(wires_include),
TOKDEF(wiring),
TOKDEF(write_resolution),
TOKDEF(x),
TOKDEF(xy),
TOKDEF(y),
};
const unsigned SPECCTRA_DB::keywordCount = DIM(SPECCTRA_DB::keywords);
//-----<SPECCTRA_DB>------------------------------------------------- //-----<SPECCTRA_DB>-------------------------------------------------
#if !defined(STANDALONE) const char* SPECCTRA_DB::TokenName( int aTok )
{
const char* ret;
if( (unsigned) aTok < keywordCount )
{
ret = keywords[aTok].name;
}
else if( aTok < 0 )
{
return DSNLEXER::Syntax( aTok );
}
else
ret = "token too big";
return ret;
}
const char* GetTokenText( int aTok )
{
return SPECCTRA_DB::TokenName( aTok );
}
wxString SPECCTRA_DB::GetTokenString( int aTok )
{
wxString ret;
ret << wxT("'") << CONV_FROM_UTF8( GetTokenText(aTok) ) << wxT("'");
return ret;
}
#if !defined(SPECCTRA_TEST)
void SPECCTRA_DB::buildLayerMaps( BOARD* aBoard ) void SPECCTRA_DB::buildLayerMaps( BOARD* aBoard )
{ {
@ -131,7 +566,7 @@ void SPECCTRA_DB::ThrowIOError( const wxChar* fmt, ... ) throw( IOError )
void SPECCTRA_DB::expecting( DSN_T aTok ) throw( IOError ) void SPECCTRA_DB::expecting( DSN_T aTok ) throw( IOError )
{ {
wxString errText( _("Expecting") ); wxString errText( _("Expecting") );
errText << wxT(" ") << LEXER::GetTokenString( aTok ); errText << wxT(" ") << GetTokenString( aTok );
lexer->ThrowIOError( errText, lexer->CurOffset() ); lexer->ThrowIOError( errText, lexer->CurOffset() );
} }
@ -145,7 +580,7 @@ void SPECCTRA_DB::expecting( const char* text ) throw( IOError )
void SPECCTRA_DB::unexpected( DSN_T aTok ) throw( IOError ) void SPECCTRA_DB::unexpected( DSN_T aTok ) throw( IOError )
{ {
wxString errText( _("Unexpected") ); wxString errText( _("Unexpected") );
errText << wxT(" ") << LEXER::GetTokenString( aTok ); errText << wxT(" ") << GetTokenString( aTok );
lexer->ThrowIOError( errText, lexer->CurOffset() ); lexer->ThrowIOError( errText, lexer->CurOffset() );
} }
@ -159,7 +594,7 @@ void SPECCTRA_DB::unexpected( const char* text ) throw( IOError )
DSN_T SPECCTRA_DB::nextTok() DSN_T SPECCTRA_DB::nextTok()
{ {
DSN_T ret = lexer->NextTok(); DSN_T ret = (DSN_T) lexer->NextTok();
return ret; return ret;
} }
@ -198,7 +633,7 @@ DSN_T SPECCTRA_DB::needSYMBOL() throw( IOError )
DSN_T SPECCTRA_DB::needSYMBOLorNUMBER() throw( IOError ) DSN_T SPECCTRA_DB::needSYMBOLorNUMBER() throw( IOError )
{ {
DSN_T tok = nextTok(); DSN_T tok = nextTok();
if( !isSymbol( tok ) && tok!=T_NUMBER ) if( !isSymbol( tok ) && tok!=T_NUMBER )
expecting( "symbol|number" ); expecting( "symbol|number" );
return tok; return tok;
@ -206,11 +641,11 @@ DSN_T SPECCTRA_DB::needSYMBOLorNUMBER() throw( IOError )
void SPECCTRA_DB::readCOMPnPIN( std::string* component_id, std::string* pin_id ) throw( IOError ) void SPECCTRA_DB::readCOMPnPIN( std::string* component_id, std::string* pin_id ) throw( IOError )
{ {
DSN_T tok; DSN_T tok;
static const char pin_def[] = "<pin_reference>::=<component_id>-<pin_id>"; static const char pin_def[] = "<pin_reference>::=<component_id>-<pin_id>";
if( !isSymbol( lexer->CurTok() ) ) if( !isSymbol( (DSN_T) lexer->CurTok() ) )
expecting( pin_def ); expecting( pin_def );
// case for: A12-14, i.e. no wrapping quotes. This should be a single // case for: A12-14, i.e. no wrapping quotes. This should be a single
@ -329,7 +764,7 @@ void SPECCTRA_DB::LoadPCB( const wxString& filename ) throw( IOError )
delete lexer; delete lexer;
lexer = 0; lexer = 0;
lexer = new LEXER( file.fp(), filename ); lexer = new DSNLEXER( file.fp(), filename, SPECCTRA_DB::keywords, SPECCTRA_DB::keywordCount );
if( nextTok() != T_LEFT ) if( nextTok() != T_LEFT )
expecting( T_LEFT ); expecting( T_LEFT );
@ -359,7 +794,7 @@ void SPECCTRA_DB::LoadSESSION( const wxString& filename ) throw( IOError )
delete lexer; delete lexer;
lexer = 0; lexer = 0;
lexer = new LEXER( file.fp(), filename ); lexer = new DSNLEXER( file.fp(), filename, SPECCTRA_DB::keywords, SPECCTRA_DB::keywordCount );
if( nextTok() != T_LEFT ) if( nextTok() != T_LEFT )
expecting( T_LEFT ); expecting( T_LEFT );
@ -508,7 +943,7 @@ void SPECCTRA_DB::doPARSER( PARSER* growth ) throw( IOError )
tok = nextTok(); tok = nextTok();
switch( tok ) switch( tok )
{ {
case T_string_quote: case T_STRING_QUOTE:
tok = nextTok(); tok = nextTok();
if( tok != T_QUOTE_DEF ) if( tok != T_QUOTE_DEF )
expecting( T_QUOTE_DEF ); expecting( T_QUOTE_DEF );
@ -1200,7 +1635,7 @@ void SPECCTRA_DB::doSTRINGPROP( STRINGPROP* growth ) throw( IOError )
void SPECCTRA_DB::doTOKPROP( TOKPROP* growth ) throw( IOError ) void SPECCTRA_DB::doTOKPROP( TOKPROP* growth ) throw( IOError )
{ {
DSN_T tok = nextTok(); DSN_T tok = nextTok();
if( tok<0 ) if( tok<0 )
unexpected( lexer->CurText() ); unexpected( lexer->CurText() );
@ -2613,9 +3048,6 @@ void SPECCTRA_DB::doCLASS( CLASS* growth ) throw( IOError )
int bracketNesting = 1; // we already saw the opening T_LEFT int bracketNesting = 1; // we already saw the opening T_LEFT
DSN_T tok = T_NONE; DSN_T tok = T_NONE;
builder += '(';
builder += lexer->CurText();
while( bracketNesting!=0 && tok!=T_EOF ) while( bracketNesting!=0 && tok!=T_EOF )
{ {
tok = nextTok(); tok = nextTok();
@ -2628,7 +3060,9 @@ void SPECCTRA_DB::doCLASS( CLASS* growth ) throw( IOError )
if( bracketNesting >= 1 ) if( bracketNesting >= 1 )
{ {
if( lexer->PrevTok() != T_LEFT && tok!=T_RIGHT ) DSN_T prevTok = (DSN_T) lexer->PrevTok();
if( prevTok!=T_LEFT && prevTok!=T_circuit && tok!=T_RIGHT )
builder += ' '; builder += ' ';
if( tok==T_STRING ) if( tok==T_STRING )
@ -2644,9 +3078,8 @@ void SPECCTRA_DB::doCLASS( CLASS* growth ) throw( IOError )
// to bracketNesting == 0, then save the builder and break; // to bracketNesting == 0, then save the builder and break;
if( bracketNesting == 0 ) if( bracketNesting == 0 )
{ {
builder += ')'; growth->circuit.push_back( builder );
growth->circuit.push_back( builder ); break;
break;
} }
} }
@ -2656,7 +3089,7 @@ void SPECCTRA_DB::doCLASS( CLASS* growth ) throw( IOError )
break; break;
default: default:
unexpected( lexer->CurText() ); unexpected( lexer->CurText() );
} // switch } // switch
tok = nextTok(); tok = nextTok();
@ -3518,41 +3951,6 @@ int SPECCTRA_DB::Print( int nestLevel, const char* fmt, ... ) throw( IOError )
return total; return total;
} }
// factor out a common GetQuoteChar
const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, const char* quote_char )
{
// Include '#' so a symbol is not confused with a comment. We intend
// to wrap any symbol starting with a '#'.
// Our LEXER class handles comments, and comments appear to be an extension
// to the SPECCTRA DSN specification.
if( *wrapee == '#' )
return quote_char;
if( strlen(wrapee)==0 )
return quote_char;
bool isFirst = true;
for( ; *wrapee; ++wrapee, isFirst=false )
{
static const char quoteThese[] = "\t ()"
"%" // per Alfons of freerouting.net, he does not like this unquoted as of 1-Feb-2008
"{}" // guessing that these are problems too
;
// if the string to be wrapped (wrapee) has a delimiter in it,
// return the quote_char so caller wraps the wrapee.
if( strchr( quoteThese, *wrapee ) )
return quote_char;
if( !isFirst && '-' == *wrapee )
return quote_char;
}
return ""; // caller does not need to wrap, can use an unwrapped string.
}
const char* SPECCTRA_DB::GetQuoteChar( const char* wrapee ) const char* SPECCTRA_DB::GetQuoteChar( const char* wrapee )
{ {
@ -3627,91 +4025,6 @@ PCB* SPECCTRA_DB::MakePCB()
} }
//-----<STRINGFORMATTER>----------------------------------------------------
const char* STRINGFORMATTER::GetQuoteChar( const char* wrapee )
{
// for what we are using STRINGFORMATTER for at this time, we can return the nul string
// always.
return "";
// return OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, "\"" );
}
int STRINGFORMATTER::vprint( const char* fmt, va_list ap )
{
int ret = vsnprintf( &buffer[0], buffer.size(), fmt, ap );
if( ret >= (int) buffer.size() )
{
buffer.reserve( ret+200 );
ret = vsnprintf( &buffer[0], buffer.size(), fmt, ap );
}
if( ret > 0 )
mystring.append( (const char*) &buffer[0] );
return ret;
}
int STRINGFORMATTER::sprint( const char* fmt, ... )
{
va_list args;
va_start( args, fmt );
int ret = vprint( fmt, args);
va_end( args );
return ret;
}
int STRINGFORMATTER::Print( int nestLevel, const char* fmt, ... ) throw( IOError )
{
va_list args;
va_start( args, fmt );
int result = 0;
int total = 0;
for( int i=0; i<nestLevel; ++i )
{
result = sprint( "%*c", NESTWIDTH, ' ' );
if( result < 0 )
break;
total += result;
}
if( result<0 || (result=vprint( fmt, args ))<0 )
{
throw IOError( _("Error writing to STRINGFORMATTER") );
}
va_end( args );
total += result;
return total;
}
void STRINGFORMATTER::StripUseless()
{
std::string copy = mystring;
mystring.clear();
for( std::string::iterator i=copy.begin(); i!=copy.end(); ++i )
{
if( !isspace( *i ) && *i!=')' && *i!='(' && *i!='"' )
{
mystring += *i;
}
}
}
//-----<ELEM>--------------------------------------------------------------- //-----<ELEM>---------------------------------------------------------------
ELEM::ELEM( DSN_T aType, ELEM* aParent ) : ELEM::ELEM( DSN_T aType, ELEM* aParent ) :
@ -3725,6 +4038,10 @@ ELEM::~ELEM()
{ {
} }
const char* ELEM::Name() const
{
return SPECCTRA_DB::TokenName( type );
}
UNIT_RES* ELEM::GetUnits() const UNIT_RES* ELEM::GetUnits() const
{ {
@ -3737,7 +4054,7 @@ UNIT_RES* ELEM::GetUnits() const
void ELEM::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError ) void ELEM::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{ {
out->Print( nestLevel, "(%s\n", LEXER::GetTokenText( Type() ) ); out->Print( nestLevel, "(%s\n", Name() );
FormatContents( out, nestLevel+1 ); FormatContents( out, nestLevel+1 );
@ -3903,7 +4220,7 @@ void PLACE::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{ {
useMultiLine = true; useMultiLine = true;
out->Print( nestLevel, "(%s %s%s%s\n", LEXER::GetTokenText( Type() ), out->Print( nestLevel, "(%s %s%s%s\n", Name(),
quote, component_id.c_str(), quote ); quote, component_id.c_str(), quote );
out->Print( nestLevel+1, "%s", "" ); out->Print( nestLevel+1, "%s", "" );
@ -3912,7 +4229,7 @@ void PLACE::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{ {
useMultiLine = false; useMultiLine = false;
out->Print( nestLevel, "(%s %s%s%s", LEXER::GetTokenText( Type() ), out->Print( nestLevel, "(%s %s%s%s", Name(),
quote, component_id.c_str(), quote ); quote, component_id.c_str(), quote );
} }
@ -3920,7 +4237,7 @@ void PLACE::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{ {
out->Print( 0, " %.6g %.6g", vertex.x, vertex.y ); out->Print( 0, " %.6g %.6g", vertex.x, vertex.y );
out->Print( 0, " %s", LEXER::GetTokenText( side ) ); out->Print( 0, " %s", GetTokenText( side ) );
out->Print( 0, " %.6g", rotation ); out->Print( 0, " %.6g", rotation );
} }
@ -3929,13 +4246,13 @@ void PLACE::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
if( mirror != T_NONE ) if( mirror != T_NONE )
{ {
out->Print( 0, "%s(mirror %s)", space, LEXER::GetTokenText( mirror ) ); out->Print( 0, "%s(mirror %s)", space, GetTokenText( mirror ) );
space = ""; space = "";
} }
if( status != T_NONE ) if( status != T_NONE )
{ {
out->Print( 0, "%s(status %s)", space, LEXER::GetTokenText( status ) ); out->Print( 0, "%s(status %s)", space, GetTokenText( status ) );
space = ""; space = "";
} }
@ -3967,8 +4284,7 @@ void PLACE::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
out->Print( nestLevel+1, ")\n" ); out->Print( nestLevel+1, ")\n" );
} }
if( lock_type != T_NONE ) if( lock_type != T_NONE )
out->Print( nestLevel+1, "(lock_type %s)\n", out->Print( nestLevel+1, "(lock_type %s)\n", GetTokenText(lock_type) );
LEXER::GetTokenText(lock_type) );
if( rules ) if( rules )
rules->Format( out, nestLevel+1 ); rules->Format( out, nestLevel+1 );
@ -3986,8 +4302,7 @@ void PLACE::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{ {
if( lock_type != T_NONE ) if( lock_type != T_NONE )
{ {
out->Print( 0, "%s(lock_type %s)", space, out->Print( 0, "%s(lock_type %s)", space, GetTokenText(lock_type) );
LEXER::GetTokenText(lock_type) );
space = ""; space = "";
} }
@ -4002,16 +4317,17 @@ void PLACE::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
out->Print( 0, ")\n" ); out->Print( 0, ")\n" );
} }
} // namespace DSN } // namespace DSN
// unit test this source file // unit test this source file. You can use the beautifiers below to output
// exactly what you read in but beautified and without #comments. This can
#if defined(STANDALONE) // then be used along with program 'diff' to test the parsing and formatting
// of every element. You may have to run the first output back through to
// get two files that should match, the 2nd and 3rd outputs.
#include "common.h" // IsOK() & EDA_FileSelector() #if defined(SPECCTRA_TEST)
using namespace DSN; using namespace DSN;
@ -4035,8 +4351,8 @@ int main( int argc, char** argv )
try try
{ {
db.LoadPCB( filename ); // db.LoadPCB( filename );
// db.LoadSESSION( filename ); db.LoadSESSION( filename );
} }
catch( IOError ioe ) catch( IOError ioe )
{ {
@ -4048,18 +4364,25 @@ int main( int argc, char** argv )
fprintf( stderr, "loaded OK\n" ); fprintf( stderr, "loaded OK\n" );
// export what we read in, making this test program basically a beautifier // export what we read in, making this test program basically a beautifier
// db.ExportSESSION( wxT("/tmp/export.ses") ); // hose the beautified DSN file to stdout. If an exception occurred,
// db.ExportPCB( wxT("/tmp/export.dsn") ); // we will be outputting only a portion of what we wanted to read in.
DSN::PCB* pcb = db.GetPCB();
// hose the beautified DSN file to stdout.
db.SetFILE( stdout ); db.SetFILE( stdout );
#if 0
// export a PCB
DSN::PCB* pcb = db.GetPCB();
pcb->Format( &db, 0 ); pcb->Format( &db, 0 );
#else
// export a SESSION file.
DSN::SESSION* ses = db.GetSESSION();
ses->Format( &db, 0 );
#endif
SetLocaleTo_Default( ); // revert to the current locale SetLocaleTo_Default( ); // revert to the current locale
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* /*
* This program source code file is part of KICAD, a free EDA CAD application. * This program source code file is part of KICAD, a free EDA CAD application.
* *
* Copyright (C) 2007-2008 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2007-2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2007 Kicad Developers, see change_log.txt for contributors. * Copyright (C) 2007 Kicad Developers, see change_log.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -257,8 +257,8 @@ SEGVIA* SPECCTRA_DB::makeVIA( PADSTACK* aPadstack, const POINT& aPoint, int aNet
shape = (SHAPE*) (*aPadstack)[0]; shape = (SHAPE*) (*aPadstack)[0];
DSN_T type = shape->shape->Type(); DSN_T type = shape->shape->Type();
if( type != T_circle ) if( type != T_circle )
ThrowIOError( _( "Unsupported via shape: \"%s\""), ThrowIOError( _( "Unsupported via shape: %s"),
GetChars( LEXER::GetTokenString( type ) ) ); GetChars( GetTokenString( type ) ) );
CIRCLE* circle = (CIRCLE*) shape->shape; CIRCLE* circle = (CIRCLE*) shape->shape;
int viaDiam = scale( circle->diameter, routeResolution ); int viaDiam = scale( circle->diameter, routeResolution );
@ -275,8 +275,8 @@ SEGVIA* SPECCTRA_DB::makeVIA( PADSTACK* aPadstack, const POINT& aPoint, int aNet
shape = (SHAPE*) (*aPadstack)[0]; shape = (SHAPE*) (*aPadstack)[0];
DSN_T type = shape->shape->Type(); DSN_T type = shape->shape->Type();
if( type != T_circle ) if( type != T_circle )
ThrowIOError( _( "Unsupported via shape: \"%s\""), ThrowIOError( _( "Unsupported via shape: %s"),
GetChars( LEXER::GetTokenString( type ) ) ); GetChars( GetTokenString( type ) ) );
CIRCLE* circle = (CIRCLE*) shape->shape; CIRCLE* circle = (CIRCLE*) shape->shape;
int viaDiam = scale( circle->diameter, routeResolution ); int viaDiam = scale( circle->diameter, routeResolution );
@ -299,8 +299,8 @@ SEGVIA* SPECCTRA_DB::makeVIA( PADSTACK* aPadstack, const POINT& aPoint, int aNet
shape = (SHAPE*) (*aPadstack)[i]; shape = (SHAPE*) (*aPadstack)[i];
DSN_T type = shape->shape->Type(); DSN_T type = shape->shape->Type();
if( type != T_circle ) if( type != T_circle )
ThrowIOError( _( "Unsupported via shape: \"%s\""), ThrowIOError( _( "Unsupported via shape: %s"),
GetChars( LEXER::GetTokenString( type ) ) ); GetChars( GetTokenString( type ) ) );
CIRCLE* circle = (CIRCLE*) shape->shape; CIRCLE* circle = (CIRCLE*) shape->shape;
@ -473,7 +473,7 @@ void SPECCTRA_DB::FromSESSION( BOARD* aBoard ) throw( IOError )
wxString netId = CONV_FROM_UTF8( wire->net_id.c_str() ); wxString netId = CONV_FROM_UTF8( wire->net_id.c_str() );
ThrowIOError( ThrowIOError(
_("Unsupported wire shape: \"%s\" for net: \"%s\""), _("Unsupported wire shape: \"%s\" for net: \"%s\""),
LEXER::GetTokenString(shape).GetData(), DLEX::GetTokenString(shape).GetData(),
netId.GetData() netId.GetData()
); );
*/ */