diff options
author | saurabhb17 | 2020-02-26 15:57:49 +0530 |
---|---|---|
committer | saurabhb17 | 2020-02-26 15:57:49 +0530 |
commit | aa35045840b78d3f48212db45da59a2e5c69b223 (patch) | |
tree | 6acee185a4dc19113fcbf0f9a3d6941085dedaf7 /pcbnew/specctra.cpp | |
parent | 0db48f6533517ecebfd9f0693f89deca28408b76 (diff) | |
download | KiCad-eSim-aa35045840b78d3f48212db45da59a2e5c69b223.tar.gz KiCad-eSim-aa35045840b78d3f48212db45da59a2e5c69b223.tar.bz2 KiCad-eSim-aa35045840b78d3f48212db45da59a2e5c69b223.zip |
Added main execs
Diffstat (limited to 'pcbnew/specctra.cpp')
-rw-r--r-- | pcbnew/specctra.cpp | 3793 |
1 files changed, 3793 insertions, 0 deletions
diff --git a/pcbnew/specctra.cpp b/pcbnew/specctra.cpp new file mode 100644 index 0000000..2358d3b --- /dev/null +++ b/pcbnew/specctra.cpp @@ -0,0 +1,3793 @@ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2007-2011 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> + * Copyright (C) 2007-2015 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 + */ + + +/* This source file implements export and import capabilities to the + specctra dsn file format. The grammar for that file format is documented + fairly well. There are classes for each major type of descriptor in the + spec. + + Since there are so many classes in here, it may be helpful to generate + the Doxygen directory: + + $ cd <kicadSourceRoot> + $ doxygen + + Then you can view the html documentation in the <kicadSourceRoot>/doxygen + directory. The main class in this file is SPECCTRA_DB and its main + functions are LoadPCB(), LoadSESSION(), and ExportPCB(). + + Wide use is made of boost::ptr_vector<> and std::vector<> template classes. + If the contained object is small, then std::vector tends to be used. + If the contained object is large, variable size, or would require writing + an assignment operator() or copy constructor, then boost::ptr_vector + cannot be beat. +*/ + + +#include <cstdarg> +#include <cstdio> + +#include <build_version.h> + +#include <class_board.h> +#include <class_track.h> + +#include <specctra.h> +#include <macros.h> + + +namespace DSN { + +#define NESTWIDTH 2 ///< how many spaces per nestLevel + +//-----<SPECCTRA_DB>------------------------------------------------- + + +const char* GetTokenText( T aTok ) +{ + return SPECCTRA_LEXER::TokenName( aTok ); +} + +void SPECCTRA_DB::buildLayerMaps( BOARD* aBoard ) +{ + // specctra wants top physical layer first, then going down to the + // bottom most physical layer in physical sequence. + // Same as KiCad now except for B_Cu + unsigned layerCount = aBoard->GetCopperLayerCount(); + + layerIds.clear(); + pcbLayer2kicad.resize( layerCount ); + kicadLayer2pcb.resize( B_Cu + 1 ); + +#if 0 // was: + for( LAYER_NUM kiNdx = layerCount - 1, pcbNdx=FIRST_LAYER; + kiNdx >= 0; --kiNdx, ++pcbNdx ) + { + LAYER_NUM kilayer = (kiNdx>0 && kiNdx==layerCount-1) ? F_Cu : kiNdx; + + // establish bi-directional mapping between KiCad's BOARD layer and PCB layer + pcbLayer2kicad[pcbNdx] = kilayer; + kicadLayer2pcb[kilayer] = pcbNdx; + + // save the specctra layer name in SPECCTRA_DB::layerIds for later. + layerIds.push_back( TO_UTF8( aBoard->GetLayerName( ToLAYER_ID( kilayer ) ) ) ); + } +#else + + // establish bi-directional mapping between KiCad's BOARD layer and PCB layer + + for( unsigned i = 0; i < kicadLayer2pcb.size(); ++i ) + { + if( i < layerCount-1 ) + kicadLayer2pcb[i] = i; + else + kicadLayer2pcb[i] = layerCount - 1; + } + + for( unsigned i = 0; i < pcbLayer2kicad.size(); ++i ) + { + LAYER_ID id = ( i < layerCount-1 ) ? ToLAYER_ID( i ) : B_Cu; + + pcbLayer2kicad[i] = id; + + // save the specctra layer name in SPECCTRA_DB::layerIds for later. + layerIds.push_back( TO_UTF8( aBoard->GetLayerName( id ) ) ); + } + +#endif +} + + +int SPECCTRA_DB::findLayerName( const std::string& aLayerName ) const +{ + for( int i=0; i < int(layerIds.size()); ++i ) + { + if( 0 == aLayerName.compare( layerIds[i] ) ) + return i; + } + return -1; +} + + +void SPECCTRA_DB::ThrowIOError( const wxString& fmt, ... ) throw( IO_ERROR ) +{ + wxString errText; + va_list args; + + va_start( args, fmt ); + errText.PrintfV( fmt, args ); + va_end( args ); + + THROW_IO_ERROR( errText ); +} + + +void SPECCTRA_DB::readCOMPnPIN( std::string* component_id, std::string* pin_id ) throw( IO_ERROR ) +{ + T tok; + + static const char pin_def[] = "<pin_reference>::=<component_id>-<pin_id>"; + + if( !IsSymbol( (T) CurTok() ) ) + Expecting( pin_def ); + + // case for: A12-14, i.e. no wrapping quotes. This should be a single + // token, so split it. + if( CurTok() != T_STRING ) + { + const char* toktext = CurText(); + const char* dash = strchr( toktext, '-' ); + + if( !dash ) + Expecting( pin_def ); + + while( toktext != dash ) + *component_id += *toktext++; + + ++toktext; // skip the dash + + while( *toktext ) + *pin_id += *toktext++; + } + + // quoted string: "U12"-"14" or "U12"-14, 3 tokens in either case + else + { + *component_id = CurText(); + + tok = NextTok(); + if( tok!=T_DASH ) + Expecting( pin_def ); + + NextTok(); // accept anything after the dash. + *pin_id = CurText(); + } +} + + +void SPECCTRA_DB::readTIME( time_t* time_stamp ) throw( IO_ERROR ) +{ + T tok; + + struct tm mytime; + + static const char time_toks[] = "<month> <day> <hour> : <minute> : <second> <year>"; + + static const char* months[] = { // index 0 = Jan + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL + }; + + NeedSYMBOL(); // month + + const char* ptok = CurText(); + + mytime.tm_mon = 0; // remains if we don't find a month match. + for( int m=0; months[m]; ++m ) + { + if( !stricmp( months[m], ptok ) ) + { + mytime.tm_mon = m; + break; + } + } + + tok = NextTok(); // day + if( tok != T_NUMBER ) + Expecting( time_toks ); + mytime.tm_mday = atoi( CurText() ); + + tok = NextTok(); // hour + if( tok != T_NUMBER ) + Expecting( time_toks ); + mytime.tm_hour = atoi( CurText() ); + + // : colon + NeedSYMBOL(); + if( *CurText() != ':' || strlen( CurText() )!=1 ) + Expecting( time_toks ); + + tok = NextTok(); // minute + if( tok != T_NUMBER ) + Expecting( time_toks ); + mytime.tm_min = atoi( CurText() ); + + // : colon + NeedSYMBOL(); + if( *CurText() != ':' || strlen( CurText() )!=1 ) + Expecting( time_toks ); + + tok = NextTok(); // second + if( tok != T_NUMBER ) + Expecting( time_toks ); + mytime.tm_sec = atoi( CurText() ); + + tok = NextTok(); // year + if( tok != T_NUMBER ) + Expecting( time_toks ); + mytime.tm_year = atoi( CurText() ) - 1900; + + *time_stamp = mktime( &mytime ); +} + + +void SPECCTRA_DB::LoadPCB( const wxString& filename ) throw( IO_ERROR, boost::bad_pointer ) +{ + FILE_LINE_READER reader( filename ); + + PushReader( &reader ); + + if( NextTok() != T_LEFT ) + Expecting( T_LEFT ); + + if( NextTok() != T_pcb ) + Expecting( T_pcb ); + + SetPCB( new PCB() ); + + doPCB( pcb ); + PopReader(); +} + + +void SPECCTRA_DB::LoadSESSION( const wxString& filename ) throw( IO_ERROR, boost::bad_pointer ) +{ + FILE_LINE_READER reader( filename ); + + PushReader( &reader ); + + if( NextTok() != T_LEFT ) + Expecting( T_LEFT ); + + if( NextTok() != T_session ) + Expecting( T_session ); + + SetSESSION( new SESSION() ); + + doSESSION( session ); + + PopReader(); +} + + +void SPECCTRA_DB::doPCB( PCB* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + /* <design_descriptor >::= + (pcb <pcb_id > + [<parser_descriptor> ] + [<capacitance_resolution_descriptor> ] + [<conductance_resolution_descriptor> ] + [<current_resolution_descriptor> ] + [<inductance_resolution_descriptor> ] + [<resistance_resolution_descriptor> ] + [<resolution_descriptor> ] + [<time_resolution_descriptor> ] + [<voltage_resolution_descriptor> ] + [<unit_descriptor> ] + [<structure_descriptor> | <file_descriptor> ] + [<placement_descriptor> | <file_descriptor> ] + [<library_descriptor> | <file_descriptor> ] + [<floor_plan_descriptor> | <file_descriptor> ] + [<part_library_descriptor> | <file_descriptor> ] + [<network_descriptor> | <file_descriptor> ] + [<wiring_descriptor> ] + [<color_descriptor> ] + ) + */ + + NeedSYMBOL(); + growth->pcbname = CurText(); + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_parser: + if( growth->parser ) + Unexpected( tok ); + growth->parser = new PARSER( growth ); + doPARSER( growth->parser ); + break; + + case T_unit: + if( growth->unit ) + Unexpected( tok ); + growth->unit = new UNIT_RES( growth, tok ); + doUNIT( growth->unit ); + break; + + case T_resolution: + if( growth->resolution ) + Unexpected( tok ); + growth->resolution = new UNIT_RES( growth, tok ); + doRESOLUTION( growth->resolution ); + break; + + case T_structure: + if( growth->structure ) + Unexpected( tok ); + growth->structure = new STRUCTURE( growth ); + doSTRUCTURE( growth->structure ); + break; + + case T_placement: + if( growth->placement ) + Unexpected( tok ); + growth->placement = new PLACEMENT( growth ); + doPLACEMENT( growth->placement ); + break; + + case T_library: + if( growth->library ) + Unexpected( tok ); + growth->library = new LIBRARY( growth ); + doLIBRARY( growth->library ); + break; + + case T_network: + if( growth->network ) + Unexpected( tok ); + growth->network = new NETWORK( growth ); + doNETWORK( growth->network ); + break; + + case T_wiring: + if( growth->wiring ) + Unexpected( tok ); + growth->wiring = new WIRING( growth ); + doWIRING( growth->wiring ); + break; + + default: + Unexpected( CurText() ); + } + } + + tok = NextTok(); + if( tok != T_EOF ) + Expecting( T_EOF ); +} + + +void SPECCTRA_DB::doPARSER( PARSER* growth ) throw( IO_ERROR ) +{ + T tok; + std::string const1; + std::string const2; + + /* <parser_descriptor >::= + (parser + [(string_quote <quote_char >)] + (space_in_quoted_tokens [on | off]) + [(host_cad <id >)] + [(host_version <id >)] + [{(constant <id > <id >)}] + [(write_resolution] {<character> <positive_integer >})] + [(routes_include {[testpoint | guides | + image_conductor]})] + [(wires_include testpoint)] + [(case_sensitive [on | off])] + [(via_rotate_first [on | off])] + ) + */ + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_STRING_QUOTE: + tok = NextTok(); + if( tok != T_QUOTE_DEF ) + Expecting( T_QUOTE_DEF ); + SetStringDelimiter( (unsigned char) *CurText() ); + growth->string_quote = *CurText(); + quote_char = CurText(); + NeedRIGHT(); + break; + + case T_space_in_quoted_tokens: + tok = NextTok(); + if( tok!=T_on && tok!=T_off ) + Expecting( "on|off" ); + SetSpaceInQuotedTokens( tok==T_on ); + growth->space_in_quoted_tokens = (tok==T_on); + NeedRIGHT(); + break; + + case T_host_cad: + NeedSYMBOL(); + growth->host_cad = CurText(); + NeedRIGHT(); + break; + + case T_host_version: + NeedSYMBOLorNUMBER(); + growth->host_version = CurText(); + NeedRIGHT(); + break; + + case T_constant: + NeedSYMBOLorNUMBER(); + const1 = CurText(); + NeedSYMBOLorNUMBER(); + const2 = CurText(); + NeedRIGHT(); + growth->constants.push_back( const1 ); + growth->constants.push_back( const2 ); + break; + + case T_write_resolution: // [(writee_resolution {<character> <positive_integer >})] + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok!=T_SYMBOL ) + Expecting( T_SYMBOL ); + tok = NextTok(); + if( tok!=T_NUMBER ) + Expecting( T_NUMBER ); + // @todo + } + break; + + case T_routes_include: // [(routes_include {[testpoint | guides | image_conductor]})] + while( (tok = NextTok()) != T_RIGHT ) + { + switch( tok ) + { + case T_testpoint: + growth->routes_include_testpoint = true; + break; + case T_guide: + growth->routes_include_guides = true; + break; + case T_image_conductor: + growth->routes_include_image_conductor = true; + break; + default: + Expecting( "testpoint|guides|image_conductor" ); + } + } + break; + + case T_wires_include: // [(wires_include testpoint)] + tok = NextTok(); + if( tok != T_testpoint ) + Expecting( T_testpoint ); + growth->routes_include_testpoint = true; + NeedRIGHT(); + break; + + case T_case_sensitive: + tok = NextTok(); + if( tok!=T_on && tok!=T_off ) + Expecting( "on|off" ); + growth->case_sensitive = (tok==T_on); + NeedRIGHT(); + break; + + case T_via_rotate_first: // [(via_rotate_first [on | off])] + tok = NextTok(); + if( tok!=T_on && tok!=T_off ) + Expecting( "on|off" ); + growth->via_rotate_first = (tok==T_on); + NeedRIGHT(); + break; + + case T_generated_by_freeroute: + growth->generated_by_freeroute = true; + NeedRIGHT(); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doRESOLUTION( UNIT_RES* growth ) throw( IO_ERROR ) +{ + T tok = NextTok(); + + switch( tok ) + { + case T_inch: + case T_mil: + case T_cm: + case T_mm: + case T_um: + growth->units = tok; + break; + default: + Expecting( "inch|mil|cm|mm|um" ); + } + + tok = NextTok(); + if( tok != T_NUMBER ) + Expecting( T_NUMBER ); + + growth->value = atoi( CurText() ); + + NeedRIGHT(); +} + + +void SPECCTRA_DB::doUNIT( UNIT_RES* growth ) throw( IO_ERROR ) +{ + T tok = NextTok(); + + switch( tok ) + { + case T_inch: + case T_mil: + case T_cm: + case T_mm: + case T_um: + growth->units = tok; + break; + default: + Expecting( "inch|mil|cm|mm|um" ); + } + + NeedRIGHT(); +} + + +void SPECCTRA_DB::doLAYER_PAIR( LAYER_PAIR* growth ) throw( IO_ERROR ) +{ + NeedSYMBOL(); + growth->layer_id0 = CurText(); + + NeedSYMBOL(); + growth->layer_id1 = CurText(); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->layer_weight = strtod( CurText(), 0 ); + + NeedRIGHT(); +} + + +void SPECCTRA_DB::doLAYER_NOISE_WEIGHT( LAYER_NOISE_WEIGHT* growth ) + throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + if( NextTok() != T_layer_pair ) + Expecting( T_layer_pair ); + + LAYER_PAIR* layer_pair = new LAYER_PAIR( growth ); + growth->layer_pairs.push_back( layer_pair ); + doLAYER_PAIR( layer_pair ); + } +} + + +void SPECCTRA_DB::doSTRUCTURE( STRUCTURE* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_unit: + if( growth->unit ) + Unexpected( tok ); + growth->unit = new UNIT_RES( growth, tok ); + doUNIT( growth->unit ); + break; + + case T_resolution: + if( growth->unit ) + Unexpected( tok ); + growth->unit = new UNIT_RES( growth, tok ); + doRESOLUTION( growth->unit ); + break; + + case T_layer_noise_weight: + if( growth->layer_noise_weight ) + Unexpected( tok ); + growth->layer_noise_weight = new LAYER_NOISE_WEIGHT( growth ); + doLAYER_NOISE_WEIGHT( growth->layer_noise_weight ); + break; + + case T_place_boundary: +L_place: + if( growth->place_boundary ) + Unexpected( tok ); + growth->place_boundary = new BOUNDARY( growth, T_place_boundary ); + doBOUNDARY( growth->place_boundary ); + break; + + case T_boundary: + if( growth->boundary ) + { + if( growth->place_boundary ) + Unexpected( tok ); + goto L_place; + } + growth->boundary = new BOUNDARY( growth ); + doBOUNDARY( growth->boundary ); + break; + + case T_plane: + COPPER_PLANE* plane; + plane = new COPPER_PLANE( growth ); + growth->planes.push_back( plane ); + doKEEPOUT( plane ); + break; + + case T_region: + REGION* region; + region = new REGION( growth ); + growth->regions.push_back( region ); + doREGION( region ); + break; + + case T_snap_angle: + STRINGPROP* stringprop; + stringprop = new STRINGPROP( growth, T_snap_angle ); + growth->Append( stringprop ); + doSTRINGPROP( stringprop ); + break; + + case T_via: + if( growth->via ) + Unexpected( tok ); + growth->via = new VIA( growth ); + doVIA( growth->via ); + break; + + case T_control: + if( growth->control ) + Unexpected( tok ); + growth->control = new CONTROL( growth ); + doCONTROL( growth->control ); + break; + + case T_layer: + LAYER* layer; + layer = new LAYER( growth ); + growth->layers.push_back( layer ); + doLAYER( layer ); + break; + + case T_rule: + if( growth->rules ) + Unexpected( tok ); + growth->rules = new RULE( growth, T_rule ); + doRULE( growth->rules ); + break; + + case T_place_rule: + if( growth->place_rules ) + Unexpected( tok ); + growth->place_rules = new RULE( growth, T_place_rule ); + doRULE( growth->place_rules ); + break; + + case T_keepout: + case T_place_keepout: + case T_via_keepout: + case T_wire_keepout: + case T_bend_keepout: + case T_elongate_keepout: + KEEPOUT* keepout; + keepout = new KEEPOUT( growth, tok ); + growth->keepouts.push_back( keepout ); + doKEEPOUT( keepout ); + break; + + case T_grid: + GRID* grid; + grid = new GRID( growth ); + growth->grids.push_back( grid ); + doGRID( grid ); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doSTRUCTURE_OUT( STRUCTURE_OUT* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + /* + <structure_out_descriptor >::= + (structure_out + {<layer_descriptor> } + [<rule_descriptor> ] + ) + */ + + T tok = NextTok(); + + while( tok != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_layer: + LAYER* layer; + layer = new LAYER( growth ); + growth->layers.push_back( layer ); + doLAYER( layer ); + break; + + case T_rule: + if( growth->rules ) + Unexpected( tok ); + growth->rules = new RULE( growth, T_rule ); + doRULE( growth->rules ); + break; + + default: + Unexpected( CurText() ); + } + + tok = NextTok(); + } +} + + +void SPECCTRA_DB::doKEEPOUT( KEEPOUT* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok = NextTok(); + + if( IsSymbol(tok) ) + { + growth->name = CurText(); + tok = NextTok(); + } + + if( tok!=T_LEFT ) + Expecting( T_LEFT ); + + while( tok != T_RIGHT ) + { + if( tok!=T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_sequence_number: + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->sequence_number = atoi( CurText() ); + NeedRIGHT(); + break; + + case T_rule: + if( growth->rules ) + Unexpected( tok ); + growth->rules = new RULE( growth, T_rule ); + doRULE( growth->rules ); + break; + + case T_place_rule: + if( growth->place_rules ) + Unexpected( tok ); + growth->place_rules = new RULE( growth, T_place_rule ); + doRULE( growth->place_rules ); + break; + + case T_rect: + if( growth->shape ) + Unexpected( tok ); + growth->shape = new RECTANGLE( growth ); + doRECTANGLE( (RECTANGLE*) growth->shape ); + break; + + case T_circle: + if( growth->shape ) + Unexpected( tok ); + growth->shape = new CIRCLE( growth ); + doCIRCLE( (CIRCLE*) growth->shape ); + break; + + case T_polyline_path: + tok = T_path; + case T_path: + case T_polygon: + if( growth->shape ) + Unexpected( tok ); + growth->shape = new PATH( growth, tok ); + doPATH( (PATH*) growth->shape ); + break; + + case T_qarc: + if( growth->shape ) + Unexpected( tok ); + growth->shape = new QARC( growth ); + doQARC( (QARC*) growth->shape ); + break; + + case T_window: + WINDOW* window; + window = new WINDOW( growth ); + growth->windows.push_back( window ); + doWINDOW( window ); + break; + + default: + Unexpected( CurText() ); + } + + tok = NextTok(); + } +} + + +void SPECCTRA_DB::doCONNECT( CONNECT* growth ) throw( IO_ERROR ) +{ + /* from page 143 of specctra spec: + + (connect + {(terminal <object_type> [<pin_reference> ])} + ) + */ + + T tok = NextTok(); + + while( tok != T_RIGHT ) + { + if( tok!=T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + + switch( tok ) + { + case T_terminal: + // since we do not use the terminal information, simlpy toss it. + while( ( tok = NextTok() ) != T_RIGHT && tok != T_EOF ) + ; + break; + + default: + Unexpected( CurText() ); + } + + tok = NextTok(); + } +} + + +void SPECCTRA_DB::doWINDOW( WINDOW* growth ) throw( IO_ERROR ) +{ + T tok = NextTok(); + + while( tok != T_RIGHT ) + { + if( tok!=T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_rect: + if( growth->shape ) + Unexpected( tok ); + growth->shape = new RECTANGLE( growth ); + doRECTANGLE( (RECTANGLE*) growth->shape ); + break; + + case T_circle: + if( growth->shape ) + Unexpected( tok ); + growth->shape = new CIRCLE( growth ); + doCIRCLE( (CIRCLE*) growth->shape ); + break; + + case T_polyline_path: + tok = T_path; + case T_path: + case T_polygon: + if( growth->shape ) + Unexpected( tok ); + growth->shape = new PATH( growth, tok ); + doPATH( (PATH*) growth->shape ); + break; + + case T_qarc: + if( growth->shape ) + Unexpected( tok ); + growth->shape = new QARC( growth ); + doQARC( (QARC*) growth->shape ); + break; + + default: + Unexpected( CurText() ); + } + + tok = NextTok(); + } +} + + +void SPECCTRA_DB::doBOUNDARY( BOUNDARY* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok = NextTok(); + + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + if( tok == T_rect ) + { + if( growth->paths.size() ) + Unexpected( "rect when path already encountered" ); + + growth->rectangle = new RECTANGLE( growth ); + doRECTANGLE( growth->rectangle ); + NeedRIGHT(); + } + else if( tok == T_path ) + { + if( growth->rectangle ) + Unexpected( "path when rect already encountered" ); + + for(;;) + { + if( tok != T_path ) + Expecting( T_path ); + + PATH* path = new PATH( growth, T_path ) ; + growth->paths.push_back( path ); + + doPATH( path ); + + tok = NextTok(); + if( tok == T_RIGHT ) + break; + + if( tok != T_LEFT ) + Expecting(T_LEFT); + + tok = NextTok(); + } + } + else + Expecting( "rect|path" ); +} + + +void SPECCTRA_DB::doPATH( PATH* growth ) throw( IO_ERROR ) +{ + T tok = NextTok(); + + if( !IsSymbol( tok ) ) + Expecting( "layer_id" ); + + growth->layer_id = CurText(); + + if( NextTok() != T_NUMBER ) + Expecting( "aperture_width" ); + + growth->aperture_width = strtod( CurText(), NULL ); + + POINT ptTemp; + + tok = NextTok(); + + do + { + if( tok != T_NUMBER ) + Expecting( T_NUMBER ); + ptTemp.x = strtod( CurText(), NULL ); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + ptTemp.y = strtod( CurText(), NULL ); + + growth->points.push_back( ptTemp ); + + } while( (tok = NextTok())!=T_RIGHT && tok!=T_LEFT ); + + if( tok == T_LEFT ) + { + if( NextTok() != T_aperture_type ) + Expecting( T_aperture_type ); + + tok = NextTok(); + if( tok!=T_round && tok!=T_square ) + Expecting( "round|square" ); + + growth->aperture_type = tok; + + NeedRIGHT(); + } +} + + +void SPECCTRA_DB::doRECTANGLE( RECTANGLE* growth ) throw( IO_ERROR ) +{ + NeedSYMBOL(); + growth->layer_id = CurText(); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->point0.x = strtod( CurText(), NULL ); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->point0.y = strtod( CurText(), NULL ); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->point1.x = strtod( CurText(), NULL ); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->point1.y = strtod( CurText(), NULL ); + + NeedRIGHT(); +} + + +void SPECCTRA_DB::doCIRCLE( CIRCLE* growth ) throw( IO_ERROR ) +{ + T tok; + + NeedSYMBOL(); + growth->layer_id = CurText(); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->diameter = strtod( CurText(), 0 ); + + tok = NextTok(); + if( tok == T_NUMBER ) + { + growth->vertex.x = strtod( CurText(), 0 ); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->vertex.y = strtod( CurText(), 0 ); + + tok = NextTok(); + } + + if( tok != T_RIGHT ) + Expecting( T_RIGHT ); +} + + +void SPECCTRA_DB::doQARC( QARC* growth ) throw( IO_ERROR ) +{ + NeedSYMBOL(); + growth->layer_id = CurText(); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->aperture_width = strtod( CurText(), 0 ); + + for( int i=0; i<3; ++i ) + { + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->vertex[i].x = strtod( CurText(), 0 ); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->vertex[i].y = strtod( CurText(), 0 ); + } + + NeedRIGHT(); +} + + +void SPECCTRA_DB::doSTRINGPROP( STRINGPROP* growth ) throw( IO_ERROR ) +{ + NeedSYMBOL(); + growth->value = CurText(); + NeedRIGHT(); +} + + +void SPECCTRA_DB::doTOKPROP( TOKPROP* growth ) throw( IO_ERROR ) +{ + T tok = NextTok(); + + if( tok<0 ) + Unexpected( CurText() ); + + growth->value = tok; + + NeedRIGHT(); +} + + +void SPECCTRA_DB::doVIA( VIA* growth ) throw( IO_ERROR ) +{ + T tok; + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok == T_LEFT ) + { + if( NextTok() != T_spare ) + Expecting( T_spare ); + + while( (tok = NextTok()) != T_RIGHT ) + { + if( !IsSymbol( tok ) ) + Expecting( T_SYMBOL ); + + growth->spares.push_back( CurText() ); + } + } + else if( IsSymbol( tok ) ) + { + growth->padstacks.push_back( CurText() ); + } + else + Unexpected( CurText() ); + } +} + + +void SPECCTRA_DB::doCONTROL( CONTROL* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_via_at_smd: + tok = NextTok(); + if( tok!=T_on && tok!=T_off ) + Expecting( "on|off" ); + growth->via_at_smd = (tok==T_on); + NeedRIGHT(); + break; + + case T_off_grid: + case T_route_to_fanout_only: + case T_force_to_terminal_point: + case T_same_net_checking: + case T_checking_trim_by_pin: + case T_noise_calculation: + case T_noise_accumulation: + case T_include_pins_in_crosstalk: + case T_bbv_ctr2ctr: + case T_average_pair_length: + case T_crosstalk_model: + case T_roundoff_rotation: + case T_microvia: + case T_reroute_order_viols: + TOKPROP* tokprop; + tokprop = new TOKPROP( growth, tok ) ; + growth->Append( tokprop ); + doTOKPROP( tokprop ); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doPROPERTIES( PROPERTIES* growth ) throw( IO_ERROR ) +{ + T tok; + PROPERTY property; // construct it once here, append multiple times. + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + NeedSYMBOLorNUMBER(); + property.name = CurText(); + + NeedSYMBOLorNUMBER(); + property.value = CurText(); + + growth->push_back( property ); + + NeedRIGHT(); + } +} + + +void SPECCTRA_DB::doLAYER( LAYER* growth ) throw( IO_ERROR ) +{ + T tok = NextTok(); + + if( !IsSymbol(tok) ) + Expecting(T_SYMBOL); + + growth->name = CurText(); + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_type: + tok = NextTok(); + if( tok!=T_signal && tok!=T_power && tok!=T_mixed && tok!=T_jumper ) + Expecting( "signal|power|mixed|jumper" ); + growth->layer_type = tok; + if( NextTok()!=T_RIGHT ) + Expecting(T_RIGHT); + break; + + case T_rule: + growth->rules = new RULE( growth, T_rule ); + doRULE( growth->rules ); + break; + + case T_property: + doPROPERTIES( &growth->properties ); + break; + + case T_direction: + tok = NextTok(); + switch( tok ) + { + case T_horizontal: + case T_vertical: + case T_orthogonal: + case T_positive_diagonal: + case T_negative_diagonal: + case T_diagonal: + case T_off: + growth->direction = tok; + break; + default: + // the spec has an example show an abbreviation of the "horizontal" keyword. Ouch. + if( !strcmp( "hori", CurText() ) ) + { + growth->direction = T_horizontal; + break; + } + else if( !strcmp( "vert", CurText() ) ) + { + growth->direction = T_vertical; + break; + } + Expecting( "horizontal|vertical|orthogonal|positive_diagonal|negative_diagonal|diagonal|off" ); + } + if( NextTok()!=T_RIGHT ) + Expecting(T_RIGHT); + break; + + case T_cost: + tok = NextTok(); + switch( tok ) + { + case T_forbidden: + case T_high: + case T_medium: + case T_low: + case T_free: + growth->cost = tok; + break; + case T_NUMBER: + // store as negative so we can differentiate between + // T (positive) and T_NUMBER (negative) + growth->cost = -atoi( CurText() ); + break; + default: + Expecting( "forbidden|high|medium|low|free|<positive_integer>|-1" ); + } + tok = NextTok(); + if( tok == T_LEFT ) + { + if( NextTok() != T_type ) + Unexpected( CurText() ); + + tok = NextTok(); + if( tok!=T_length && tok!=T_way ) + Expecting( "length|way" ); + + growth->cost_type = tok; + if( NextTok()!=T_RIGHT ) + Expecting(T_RIGHT); + + tok = NextTok(); + } + if( tok!=T_RIGHT ) + Expecting(T_RIGHT); + break; + + case T_use_net: + while( (tok = NextTok()) != T_RIGHT ) + { + if( !IsSymbol(tok) ) + Expecting( T_SYMBOL ); + + growth->use_net.push_back( CurText() ); + } + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doRULE( RULE* growth ) throw( IO_ERROR ) +{ + std::string builder; + int bracketNesting = 1; // we already saw the opening T_LEFT + T tok = T_NONE; + + while( bracketNesting!=0 && tok!=T_EOF ) + { + tok = NextTok(); + + if( tok==T_LEFT) + ++bracketNesting; + + else if( tok==T_RIGHT ) + --bracketNesting; + + if( bracketNesting >= 1 ) + { + if( PrevTok()!=T_LEFT && tok!=T_RIGHT && (tok!=T_LEFT || bracketNesting>2) ) + builder += ' '; + + if( tok==T_STRING ) + builder += quote_char; + + builder += CurText(); + + if( tok==T_STRING ) + builder += quote_char; + } + + // When the nested rule is closed with a T_RIGHT and we are back down + // to bracketNesting == 1, (inside the <rule_descriptor> but outside + // the last rule). Then save the last rule and clear the string builder. + if( bracketNesting == 1 ) + { + growth->rules.push_back( builder ); + builder.clear(); + } + } + + if( tok==T_EOF ) + Unexpected( T_EOF ); +} + + +#if 0 +void SPECCTRA_DB::doPLACE_RULE( PLACE_RULE* growth, bool expect_object_type ) throw( IO_ERROR ) +{ + /* (place_rule [<structure_place_rule_object> ] + {[<spacing_descriptor> | + <permit_orient_descriptor> | + <permit_side_descriptor> | + <opposite_side_descriptor> ]} + ) + */ + + T tok = NextTok(); + + if( tok!=T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + if( tok==T_object_type ) + { + if( !expect_object_type ) + Unexpected( tok ); + + /* [(object_type + [pcb | + image_set [large | small | discrete | capacitor | resistor] + [(image_type [smd | pin])]] + )] + */ + + tok = NextTok(); + switch( tok ) + { + case T_pcb: + growth->object_type = tok; + break; + + case T_image_set: + tok = NextTok(); + switch( tok ) + { + case T_large: + case T_small: + case T_discrete: + case T_capacitor: + case T_resistor: + growth->object_type = tok; + break; + default: + Unexpected( CurText() ); + } + break; + + default: + Unexpected( CurText() ); + } + + tok = NextTok(); + if( tok == T_LEFT ) + { + tok = NextTok(); + if( tok != T_image_type ) + Expecting( T_image_type ); + + tok = NextTok(); + if( tok!=T_smd && tok!=T_pin ) + Expecting( "smd|pin" ); + + NeedRIGHT(); + + tok = NextTok(); + } + + if( tok != T_RIGHT ) + Expecting( T_RIGHT ); + + tok = NextTok(); + } + + /* {[<spacing_descriptor> | + <permit_orient_descriptor> | + <permit_side_descriptor> | <opposite_side_descriptor> ]} + */ + doRULE( growth ); +} +#endif + + +void SPECCTRA_DB::doREGION( REGION* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok = NextTok(); + + if( IsSymbol(tok) ) + { + growth->region_id = CurText(); + tok = NextTok(); + } + + for(;;) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_rect: + if( growth->rectangle ) + Unexpected( tok ); + growth->rectangle = new RECTANGLE( growth ); + doRECTANGLE( growth->rectangle ); + break; + + case T_polygon: + if( growth->polygon ) + Unexpected( tok ); + growth->polygon = new PATH( growth, T_polygon ); + doPATH( growth->polygon ); + break; + + case T_region_net: + case T_region_class: + STRINGPROP* stringprop; + stringprop = new STRINGPROP( growth, tok ); + growth->Append( stringprop ); + doSTRINGPROP( stringprop ); + break; + + case T_region_class_class: + CLASS_CLASS* class_class; + class_class = new CLASS_CLASS( growth, tok ); + growth->Append( class_class ); + doCLASS_CLASS( class_class ); + break; + + case T_rule: + if( growth->rules ) + Unexpected( tok ); + growth->rules = new RULE( growth, T_rule ); + doRULE( growth->rules ); + break; + + default: + Unexpected( CurText() ); + } + + tok = NextTok(); + if( tok == T_RIGHT ) + { + if( !growth->rules ) + Expecting( T_rule ); + break; + } + } +} + + +void SPECCTRA_DB::doCLASS_CLASS( CLASS_CLASS* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok = NextTok(); + + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + while( (tok = NextTok()) != T_RIGHT ) + { + switch( tok ) + { + case T_classes: + if( growth->classes ) + Unexpected( tok ); + growth->classes = new CLASSES( growth ); + doCLASSES( growth->classes ); + break; + + case T_rule: + // only T_class_class takes a T_rule + if( growth->Type() == T_region_class_class ) + Unexpected( tok ); + RULE* rule; + rule = new RULE( growth, T_rule ); + growth->Append( rule ); + doRULE( rule ); + break; + + case T_layer_rule: + // only T_class_class takes a T_layer_rule + if( growth->Type() == T_region_class_class ) + Unexpected( tok ); + LAYER_RULE* layer_rule; + layer_rule = new LAYER_RULE( growth ); + growth->Append( layer_rule ); + doLAYER_RULE( layer_rule ); + break; + + default: + Unexpected( tok ); + } + } +} + + +void SPECCTRA_DB::doCLASSES( CLASSES* growth ) throw( IO_ERROR ) +{ + T tok = NextTok(); + + // require at least 2 class_ids + + if( !IsSymbol( tok ) ) + Expecting( "class_id" ); + + growth->class_ids.push_back( CurText() ); + + do + { + tok = NextTok(); + if( !IsSymbol( tok ) ) + Expecting( "class_id" ); + + growth->class_ids.push_back( CurText() ); + + } while( (tok = NextTok()) != T_RIGHT ); +} + + +void SPECCTRA_DB::doGRID( GRID* growth ) throw( IO_ERROR ) +{ + T tok = NextTok(); + + switch( tok ) + { + case T_via: + case T_wire: + case T_via_keepout: + case T_snap: + case T_place: + growth->grid_type = tok; + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->dimension = strtod( CurText(), 0 ); + tok = NextTok(); + if( tok == T_LEFT ) + { + while( (tok=NextTok()) != T_RIGHT ) + { + if( tok==T_direction ) + { + if( growth->grid_type == T_place ) + Unexpected( tok ); + tok = NextTok(); + if( tok!=T_x && tok!=T_y ) + Unexpected( CurText() ); + growth->direction = tok; + if( NextTok() != T_RIGHT ) + Expecting(T_RIGHT); + } + else if( tok==T_offset ) + { + if( growth->grid_type == T_place ) + Unexpected( tok ); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + + growth->offset = strtod( CurText(), 0 ); + + if( NextTok() != T_RIGHT ) + Expecting(T_RIGHT); + } + else if( tok==T_image_type ) + { + if( growth->grid_type != T_place ) + Unexpected( tok ); + tok = NextTok(); + if( tok!=T_smd && tok!=T_pin ) + Unexpected( CurText() ); + growth->image_type = tok; + if( NextTok() != T_RIGHT ) + Expecting(T_RIGHT); + } + } + } + break; + + default: + Unexpected( tok ); + } +} + + +void SPECCTRA_DB::doLAYER_RULE( LAYER_RULE* growth ) throw( IO_ERROR ) +{ + T tok; + + NeedSYMBOL(); + + do + { + growth->layer_ids.push_back( CurText() ); + + } while( IsSymbol(tok = NextTok()) ); + + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + if( NextTok() != T_rule ) + Expecting( T_rule ); + + growth->rule = new RULE( growth, T_rule ); + doRULE( growth->rule ); + + NeedRIGHT(); +} + + +void SPECCTRA_DB::doPLACE( PLACE* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok = NextTok(); + + if( !IsSymbol( tok ) ) + Expecting( "component_id" ); + + growth->component_id = CurText(); + + tok = NextTok(); + if( tok == T_NUMBER ) + { + POINT point; + + point.x = strtod( CurText(), 0 ); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + point.y = strtod( CurText(), 0 ); + + growth->SetVertex( point ); + + tok = NextTok(); + if( tok!=T_front && tok!=T_back ) + Expecting( "front|back" ); + growth->side = tok; + + if( NextTok() != T_NUMBER ) + Expecting( "rotation" ); + growth->SetRotation( strtod( CurText(), 0) ); + } + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_mirror: + tok = NextTok(); + if( tok==T_x || tok==T_y || tok==T_xy || tok==T_off ) + growth->mirror = tok; + else + Expecting("x|y|xy|off"); + break; + + case T_status: + tok = NextTok(); + if( tok==T_added || tok==T_deleted || tok==T_substituted ) + growth->status = tok; + else + Expecting("added|deleted|substituted"); + break; + + case T_logical_part: + if( growth->logical_part.size() ) + Unexpected( tok ); + tok = NextTok(); + if( !IsSymbol( tok ) ) + Expecting( "logical_part_id"); + growth->logical_part = CurText(); + break; + + case T_place_rule: + if( growth->place_rules ) + Unexpected( tok ); + growth->place_rules = new RULE( growth, T_place_rule ); + doRULE( growth->place_rules ); + break; + + case T_property: + if( growth->properties.size() ) + Unexpected( tok ); + doPROPERTIES( &growth->properties ); + break; + + case T_lock_type: + tok = NextTok(); + if( tok==T_position || tok==T_gate || tok==T_subgate || tok==T_pin ) + growth->lock_type = tok; + else + Expecting("position|gate|subgate|pin"); + break; + + case T_rule: + if( growth->rules || growth->region ) + Unexpected( tok ); + growth->rules = new RULE( growth, T_rule ); + doRULE( growth->rules ); + break; + + case T_region: + if( growth->rules || growth->region ) + Unexpected( tok ); + growth->region = new REGION( growth ); + doREGION( growth->region ); + break; + + case T_pn: + if( growth->part_number.size() ) + Unexpected( tok ); + NeedSYMBOLorNUMBER(); + growth->part_number = CurText(); + NeedRIGHT(); + break; + + default: + Unexpected( tok ); + } + } +} + + +void SPECCTRA_DB::doCOMPONENT( COMPONENT* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok = NextTok(); + + if( !IsSymbol( tok ) && tok != T_NUMBER ) + Expecting( "image_id" ); + growth->image_id = CurText(); + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_place: + PLACE* place; + place = new PLACE( growth ); + growth->places.push_back( place ); + doPLACE( place ); + break; + + default: + Unexpected(tok); + } + } +} + + +void SPECCTRA_DB::doPLACEMENT( PLACEMENT* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok == T_EOF ) + Unexpected( T_EOF ); + + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + + switch( tok ) + { + case T_unit: + case T_resolution: + growth->unit = new UNIT_RES( growth, tok ); + if( tok==T_resolution ) + doRESOLUTION( growth->unit ); + else + doUNIT( growth->unit ); + break; + + case T_place_control: + NeedRIGHT(); + tok = NextTok(); + if( tok != T_flip_style ) + Expecting( T_flip_style ); + + tok = NextTok(); + if( tok==T_mirror_first || tok==T_rotate_first ) + growth->flip_style = tok; + else + Expecting( "mirror_first|rotate_first" ); + + NeedRIGHT(); + NeedRIGHT(); + break; + + case T_component: + COMPONENT* component; + component = new COMPONENT( growth ); + growth->components.push_back( component ); + doCOMPONENT( component ); + break; + + default: + Unexpected( tok ); + } + } +} + + +void SPECCTRA_DB::doPADSTACK( PADSTACK* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok = NextTok(); + + /* (padstack <padstack_id > + [<unit_descriptor> ] + {(shape <shape_descriptor> + [<reduced_shape_descriptor> ] + [(connect [on | off])] + [{<window_descriptor> }] + )} + [<attach_descriptor> ] + [{<pad_via_site_descriptor> }] + [(rotate [on | off])] + [(absolute [on | off])] + [(rule <clearance_descriptor> )]) + */ + + // padstack_id may be a number + if( !IsSymbol( tok ) && tok!=T_NUMBER ) + Expecting( "padstack_id" ); + + growth->padstack_id = CurText(); + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_unit: + if( growth->unit ) + Unexpected( tok ); + growth->unit = new UNIT_RES( growth, tok ); + doUNIT( growth->unit ); + break; + + case T_rotate: + tok = NextTok(); + if( tok!=T_on && tok!=T_off ) + Expecting( "on|off" ); + growth->rotate = tok; + NeedRIGHT(); + break; + + case T_absolute: + tok = NextTok(); + if( tok!=T_on && tok!=T_off ) + Expecting( "on|off" ); + growth->absolute = tok; + NeedRIGHT(); + break; + + case T_shape: + SHAPE* shape; + shape = new SHAPE( growth ); + growth->Append( shape ); + doSHAPE( shape ); + break; + + case T_attach: + tok = NextTok(); + if( tok!=T_off && tok!=T_on ) + Expecting( "off|on" ); + growth->attach = tok; + tok = NextTok(); + if( tok == T_LEFT ) + { + if( NextTok() != T_use_via ) + Expecting( T_use_via ); + + NeedSYMBOL(); + growth->via_id = CurText(); + + NeedRIGHT(); + NeedRIGHT(); + } + break; + + /* + case T_via_site: not supported + break; + */ + + case T_rule: + if( growth->rules ) + Unexpected( tok ); + growth->rules = new RULE( growth, T_rule ); + doRULE( growth->rules ); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doSHAPE( SHAPE* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + /* (shape <shape_descriptor> + [<reduced_shape_descriptor> ] + [(connect [on | off])] + [{<window_descriptor> }]) + */ + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_polyline_path: + tok = T_path; + case T_rect: + case T_circle: + case T_path: + case T_polygon: + case T_qarc: +L_done_that: + if( growth->shape ) + Unexpected( tok ); + break; + default: + // the example in the spec uses "circ" instead of "circle". Bad! + if( !strcmp( "circ", CurText() ) ) + { + tok = T_circle; + goto L_done_that; + } + } + + switch( tok ) + { + case T_rect: + growth->shape = new RECTANGLE( growth ); + doRECTANGLE( (RECTANGLE*) growth->shape ); + break; + + case T_circle: + growth->shape = new CIRCLE( growth ); + doCIRCLE( (CIRCLE*)growth->shape ); + break; + + case T_path: + case T_polygon: + growth->shape = new PATH( growth, tok ); + doPATH( (PATH*)growth->shape ); + break; + + case T_qarc: + growth->shape = new QARC( growth ); + doQARC( (QARC*)growth->shape ); + break; + + case T_connect: + tok = NextTok(); + if( tok!=T_on && tok!=T_off ) + Expecting( "on|off" ); + growth->connect = tok; + NeedRIGHT(); + break; + + case T_window: + WINDOW* window; + window = new WINDOW( growth ); + growth->windows.push_back( window ); + doWINDOW( window ); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doIMAGE( IMAGE* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok = NextTok(); + + /* <image_descriptor >::= + (image <image_id > + [(side [front | back | both])] + [<unit_descriptor> ] + [<outline_descriptor> ] + {(pin <padstack_id > [(rotate <rotation> )] + [<reference_descriptor> | <pin_array_descriptor> ] + [<user_property_descriptor> ])} + [{<conductor_shape_descriptor> }] + [{<conductor_via_descriptor> }] + [<rule_descriptor> ] + [<place_rule_descriptor> ] + [{<keepout_descriptor> }] + [<image_property_descriptor> ] + ) + */ + + if( !IsSymbol( tok ) && tok != T_NUMBER ) + Expecting( "image_id" ); + + growth->image_id = CurText(); + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_unit: + if( growth->unit ) + Unexpected( tok ); + growth->unit = new UNIT_RES( growth, tok ); + doUNIT( growth->unit ); + break; + + case T_side: + tok = NextTok(); + if( tok!=T_front && tok!=T_back && tok!=T_both ) + Expecting( "front|back|both" ); + growth->side = tok; + NeedRIGHT(); + break; + + case T_outline: + SHAPE* outline; + outline = new SHAPE( growth, T_outline ); // use SHAPE for T_outline + growth->Append( outline ); + doSHAPE( outline ); + break; + + case T_pin: + PIN* pin; + pin = new PIN( growth ); + growth->pins.push_back( pin ); + doPIN( pin ); + break; + + case T_rule: + if( growth->rules ) + Unexpected( tok ); + growth->rules = new RULE( growth, tok ); + doRULE( growth->rules ); + break; + + case T_place_rule: + if( growth->place_rules ) + Unexpected( tok ); + growth->place_rules = new RULE( growth, tok ); + doRULE( growth->place_rules ); + break; + + case T_keepout: + case T_place_keepout: + case T_via_keepout: + case T_wire_keepout: + case T_bend_keepout: + case T_elongate_keepout: + KEEPOUT* keepout; + keepout = new KEEPOUT( growth, tok ); + growth->keepouts.push_back( keepout ); + doKEEPOUT( keepout ); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doPIN( PIN* growth ) throw( IO_ERROR ) +{ + T tok = NextTok(); + + /* (pin <padstack_id > [(rotate <rotation> )] + [<reference_descriptor> | <pin_array_descriptor> ] + [<user_property_descriptor> ]) + */ + + // a padstack_id may be a number + if( !IsSymbol( tok ) && tok!=T_NUMBER ) + Expecting( "padstack_id" ); + + growth->padstack_id = CurText(); + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok == T_LEFT ) + { + tok = NextTok(); + if( tok != T_rotate ) + Expecting( T_rotate ); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->SetRotation( strtod( CurText(), 0 ) ); + NeedRIGHT(); + } + else + { + if( !IsSymbol(tok) && tok!=T_NUMBER ) + Expecting( "pin_id" ); + + growth->pin_id = CurText(); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->vertex.x = strtod( CurText(), 0 ); + + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->vertex.y = strtod( CurText(), 0 ); + } + } +} + + +void SPECCTRA_DB::doLIBRARY( LIBRARY* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + /* <library_descriptor >::= + (library + [<unit_descriptor> ] + {<image_descriptor> } + [{<jumper_descriptor> }] + {<padstack_descriptor> } + {<via_array_template_descriptor> } + [<directory_descriptor> ] + [<extra_image_directory_descriptor> ] + [{<family_family_descriptor> }] + [{<image_image_descriptor> }] + ) + */ + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_unit: + if( growth->unit ) + Unexpected( tok ); + growth->unit = new UNIT_RES( growth, tok ); + doUNIT( growth->unit ); + break; + + case T_padstack: + PADSTACK* padstack; + padstack = new PADSTACK(); + growth->AddPadstack( padstack ); + doPADSTACK( padstack ); + break; + + case T_image: + IMAGE* image; + image = new IMAGE( growth ); + growth->images.push_back( image ); + doIMAGE( image ); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doNET( NET* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok = NextTok(); + PIN_REFS* pin_refs; + + /* <net_descriptor >::= + (net <net_id > + [(unassigned)] + [(net_number <integer >)] + [(pins {<pin_reference> }) | (order {<pin_reference> })] + [<component_order_descriptor> ] + [(type [fix | normal])] + [<user_property_descriptor> ] + [<circuit_descriptor> ] + [<rule_descriptor> ] + [{<layer_rule_descriptor> }] + [<fromto_descriptor> ] + [(expose {<pin_reference> })] + [(noexpose {<pin_reference> })] + [(source {<pin_reference> })] + [(load {<pin_reference> })] + [(terminator {<pin_reference> })] + [(supply [power | ground])] + ) + */ + + if( !IsSymbol( tok ) ) + Expecting( "net_id" ); + + growth->net_id = CurText(); + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_unassigned: + growth->unassigned = true; + NeedRIGHT(); + break; + + case T_net_number: + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->net_number = atoi( CurText() ); + NeedRIGHT(); + break; + + case T_pins: + case T_order: + growth->pins_type = tok; + pin_refs = &growth->pins; + goto L_pins; + + case T_expose: + pin_refs = &growth->expose; + goto L_pins; + + case T_noexpose: + pin_refs = &growth->noexpose; + goto L_pins; + + case T_source: + pin_refs = &growth->source; + goto L_pins; + + case T_load: + pin_refs = &growth->load; + goto L_pins; + + case T_terminator: + pin_refs = &growth->terminator; + //goto L_pins; + +L_pins: + { + PIN_REF empty( growth ); + while( (tok = NextTok()) != T_RIGHT ) + { + // copy the empty one, then fill its copy later thru pin_ref. + pin_refs->push_back( empty ); + + PIN_REF* pin_ref = &pin_refs->back(); + + readCOMPnPIN( &pin_ref->component_id, &pin_ref->pin_id ); + } + } + break; + + case T_comp_order: + if( growth->comp_order ) + Unexpected( tok ); + growth->comp_order = new COMP_ORDER( growth ); + doCOMP_ORDER( growth->comp_order ); + break; + + case T_type: + tok = NextTok(); + if( tok!=T_fix && tok!=T_normal ) + Expecting( "fix|normal" ); + growth->type = tok; + NeedRIGHT(); + break; + +/* @todo + case T_circuit: + break; +*/ + + case T_rule: + if( growth->rules ) + Unexpected( tok ); + growth->rules = new RULE( growth, T_rule ); + doRULE( growth->rules ); + break; + + case T_layer_rule: + LAYER_RULE* layer_rule; + layer_rule = new LAYER_RULE( growth ); + growth->layer_rules.push_back( layer_rule ); + doLAYER_RULE( layer_rule ); + break; + + case T_fromto: + FROMTO* fromto; + fromto = new FROMTO( growth ); + growth->fromtos.push_back( fromto ); + doFROMTO( fromto ); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doTOPOLOGY( TOPOLOGY* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + /* <topology_descriptor >::= + (topology {[<fromto_descriptor> | + <component_order_descriptor> ]}) + */ + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_fromto: + FROMTO* fromto; + fromto = new FROMTO( growth ); + growth->fromtos.push_back( fromto ); + doFROMTO( fromto ); + break; + + case T_comp_order: + COMP_ORDER* comp_order; + comp_order = new COMP_ORDER( growth ); + growth->comp_orders.push_back( comp_order ); + doCOMP_ORDER( comp_order ); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doCLASS( CLASS* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + /* <class_descriptor >::= + (class + <class_id > {[{<net_id >} | {<composite_name_list> }]} + [<circuit_descriptor> ] + [<rule_descriptor> ] + [{<layer_rule_descriptor> }] + [<topology_descriptor> ] + ) + */ + + NeedSYMBOL(); + + growth->class_id = CurText(); + + // do net_ids, do not support <composite_name_list>s at this time + while( IsSymbol(tok = NextTok()) ) + { + growth->net_ids.push_back( CurText() ); + } + + + while( tok != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_rule: + if( growth->rules ) + Unexpected( tok ); + growth->rules = new RULE( growth, T_rule ); + doRULE( growth->rules ); + break; + + case T_layer_rule: + LAYER_RULE* layer_rule; + layer_rule = new LAYER_RULE( growth ); + growth->layer_rules.push_back( layer_rule ); + doLAYER_RULE( layer_rule ); + break; + + case T_topology: + if( growth->topology ) + Unexpected( tok ); + growth->topology = new TOPOLOGY( growth ); + doTOPOLOGY( growth->topology ); + break; + + case T_circuit: // handle all the circuit_descriptor here as strings + { + std::string builder; + int bracketNesting = 1; // we already saw the opening T_LEFT + T tok = T_NONE; + + while( bracketNesting!=0 && tok!=T_EOF ) + { + tok = NextTok(); + + if( tok==T_LEFT) + ++bracketNesting; + + else if( tok==T_RIGHT ) + --bracketNesting; + + if( bracketNesting >= 1 ) + { + T prevTok = (T) PrevTok(); + + if( prevTok!=T_LEFT && prevTok!=T_circuit && tok!=T_RIGHT ) + builder += ' '; + + if( tok==T_STRING ) + builder += quote_char; + + builder += CurText(); + + if( tok==T_STRING ) + builder += quote_char; + } + + // When the nested rule is closed with a T_RIGHT and we are back down + // to bracketNesting == 0, then save the builder and break; + if( bracketNesting == 0 ) + { + growth->circuit.push_back( builder ); + break; + } + } + + if( tok==T_EOF ) + Unexpected( T_EOF ); + } // scope bracket + break; + + default: + Unexpected( CurText() ); + } // switch + + tok = NextTok(); + + } // while +} + + +void SPECCTRA_DB::doNETWORK( NETWORK* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + /* <network_descriptor >::= + (network + {<net_descriptor>} + [{<class_descriptor> }] + [{<class_class_descriptor> }] + [{<group_descriptor> }] + [{<group_set_descriptor> }] + [{<pair_descriptor> }] + [{<bundle_descriptor> }] + ) + */ + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_net: + NET* net; + net = new NET( growth ); + growth->nets.push_back( net ); + doNET( net ); + break; + + case T_class: + CLASS* myclass; + myclass = new CLASS( growth ); + growth->classes.push_back( myclass ); + doCLASS( myclass ); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doCOMP_ORDER( COMP_ORDER* growth ) throw( IO_ERROR ) +{ + T tok; + + /* <component_order_descriptor >::= + (comp_order {<placement_id> }) + */ + + while( IsSymbol(tok = NextTok()) ) + { + growth->placement_ids.push_back( CurText() ); + } + + if( tok != T_RIGHT ) + Expecting( T_RIGHT ); +} + + +void SPECCTRA_DB::doFROMTO( FROMTO* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + /* <fromto_descriptor >::= + {(fromto + [<pin_reference> | <virtual_pin_descriptor> ] | <component_id >] + [<pin_reference> | <virtual_pin_descriptor> | <component_id >] + [(type [fix | normal | soft])] + [(net <net_id >)] + [<rule_descriptor> ] + [<circuit_descriptor> ] + [{<layer_rule_descriptor> }] + )} + */ + + + // read the first two grammar items in as 2 single tokens, i.e. do not + // split apart the <pin_reference>s into 3 separate tokens. Do this by + // turning off the string delimiter in the lexer. + + char old = SetStringDelimiter( 0 ); + + if( !IsSymbol(NextTok() ) ) + { + SetStringDelimiter( old ); + Expecting( T_SYMBOL ); + } + growth->fromText = CurText(); + + if( !IsSymbol(NextTok() ) ) + { + SetStringDelimiter( old ); + Expecting( T_SYMBOL ); + } + growth->toText = CurText(); + + SetStringDelimiter( old ); + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_type: + tok = NextTok(); + if( tok!=T_fix && tok!=T_normal && tok!=T_soft ) + Expecting( "fix|normal|soft" ); + growth->fromto_type = tok; + NeedRIGHT(); + break; + + case T_rule: + if( growth->rules ) + Unexpected( tok ); + growth->rules = new RULE( growth, T_rule ); + doRULE( growth->rules ); + break; + + case T_layer_rule: + LAYER_RULE* layer_rule; + layer_rule = new LAYER_RULE( growth ); + growth->layer_rules.push_back( layer_rule ); + doLAYER_RULE( layer_rule ); + break; + + case T_net: + if( growth->net_id.size() ) + Unexpected( tok ); + NeedSYMBOL(); + growth->net_id = CurText(); + NeedRIGHT(); + break; + + // circuit descriptor not supported at this time + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doWIRE( WIRE* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + /* <wire_shape_descriptor >::= + (wire + <shape_descriptor> + [(net <net_id >)] + [(turret <turret#> )] + [(type [fix | route | normal | protect])] + [(attr [test | fanout | bus | jumper])] + [(shield <net_id >)] + [{<window_descriptor> }] + [(connect + (terminal <object_type> [<pin_reference> ]) + (terminal <object_type> [<pin_reference> ]) + )] + [(supply)] + ) + */ + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_rect: + if( growth->shape ) + Unexpected( tok ); + growth->shape = new RECTANGLE( growth ); + doRECTANGLE( (RECTANGLE*) growth->shape ); + break; + + case T_circle: + if( growth->shape ) + Unexpected( tok ); + growth->shape = new CIRCLE( growth ); + doCIRCLE( (CIRCLE*) growth->shape ); + break; + + case T_polyline_path: + tok = T_path; + case T_path: + case T_polygon: + if( growth->shape ) + Unexpected( tok ); + growth->shape = new PATH( growth, tok ); + doPATH( (PATH*) growth->shape ); + break; + + case T_qarc: + if( growth->shape ) + Unexpected( tok ); + growth->shape = new QARC( growth ); + doQARC( (QARC*) growth->shape ); + break; + + case T_net: + NeedSYMBOL(); + growth->net_id = CurText(); + NeedRIGHT(); + break; + + case T_turret: + if( NextTok() != T_NUMBER ) + Expecting( T_NUMBER ); + growth->turret = atoi( CurText() ); + NeedRIGHT(); + break; + + case T_type: + tok = NextTok(); + if( tok!=T_fix && tok!=T_route && tok!=T_normal && tok!=T_protect ) + Expecting( "fix|route|normal|protect" ); + growth->wire_type = tok; + NeedRIGHT(); + break; + + case T_attr: + tok = NextTok(); + if( tok!=T_test && tok!=T_fanout && tok!=T_bus && tok!=T_jumper ) + Expecting( "test|fanout|bus|jumper" ); + growth->attr = tok; + NeedRIGHT(); + break; + + case T_shield: + NeedSYMBOL(); + growth->shield = CurText(); + NeedRIGHT(); + break; + + case T_window: + WINDOW* window; + window = new WINDOW( growth ); + growth->windows.push_back( window ); + doWINDOW( window ); + break; + + case T_connect: + if( growth->connect ) + Unexpected( tok ); + growth->connect = new CONNECT( growth ); + doCONNECT( growth->connect ); + break; + + case T_supply: + growth->supply = true; + NeedRIGHT(); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doWIRE_VIA( WIRE_VIA* growth ) throw( IO_ERROR ) +{ + T tok; + POINT point; + + /* <wire_via_descriptor >::= + (via + <padstack_id > {<vertex> } + [(net <net_id >)] + [(via_number <via#> )] + [(type [fix | route | normal | protect])] + [(attr [test | fanout | jumper | + virtual_pin <virtual_pin_name> ])] + [(contact {<layer_id >})] + [(supply)] + ) + (virtual_pin + <virtual_pin_name> <vertex> (net <net_id >) + ) + */ + + NeedSYMBOL(); + growth->padstack_id = CurText(); + + while( (tok = NextTok()) == T_NUMBER ) + { + point.x = strtod( CurText(), 0 ); + + if( NextTok() != T_NUMBER ) + Expecting( "vertex.y" ); + + point.y = strtod( CurText(), 0 ); + + growth->vertexes.push_back( point ); + } + + while( tok != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_net: + NeedSYMBOL(); + growth->net_id = CurText(); + NeedRIGHT(); + break; + + case T_via_number: + if( NextTok() != T_NUMBER ) + Expecting( "<via#>" ); + growth->via_number = atoi( CurText() ); + NeedRIGHT(); + break; + + case T_type: + tok = NextTok(); + if( tok!=T_fix && tok!=T_route && tok!=T_normal && tok!=T_protect ) + Expecting( "fix|route|normal|protect" ); + growth->via_type = tok; + NeedRIGHT(); + break; + + case T_attr: + tok = NextTok(); + if( tok!=T_test && tok!=T_fanout && tok!=T_jumper && tok!=T_virtual_pin ) + Expecting( "test|fanout|jumper|virtual_pin" ); + growth->attr = tok; + if( tok == T_virtual_pin ) + { + NeedSYMBOL(); + growth->virtual_pin_name = CurText(); + } + NeedRIGHT(); + break; + + case T_contact: + NeedSYMBOL(); + tok = T_SYMBOL; + while( IsSymbol(tok) ) + { + growth->contact_layers.push_back( CurText() ); + tok = NextTok(); + } + if( tok != T_RIGHT ) + Expecting( T_RIGHT ); + break; + + case T_supply: + growth->supply = true; + NeedRIGHT(); + break; + + default: + Unexpected( CurText() ); + } + + tok = NextTok(); + } +} + + +void SPECCTRA_DB::doWIRING( WIRING* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + /* <wiring_descriptor >::= + (wiring + [<unit_descriptor> | <resolution_descriptor> | null] + {<wire_descriptor> } + [<test_points_descriptor> ] + {[<supply_pin_descriptor> ]} + ) + */ + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_unit: + if( growth->unit ) + Unexpected( tok ); + growth->unit = new UNIT_RES( growth, tok ); + doUNIT( growth->unit ); + break; + + case T_resolution: + if( growth->unit ) + Unexpected( tok ); + growth->unit = new UNIT_RES( growth, tok ); + doRESOLUTION( growth->unit ); + break; + + case T_wire: + WIRE* wire; + wire = new WIRE( growth ); + growth->wires.push_back( wire ); + doWIRE( wire ); + break; + + case T_via: + WIRE_VIA* wire_via; + wire_via = new WIRE_VIA( growth ); + growth->wire_vias.push_back( wire_via ); + doWIRE_VIA( wire_via ); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doANCESTOR( ANCESTOR* growth ) throw( IO_ERROR ) +{ + T tok; + + /* <ancestor_file_descriptor >::= + (ancestor <file_path_name> (created_time <time_stamp> ) + [(comment <comment_string> )]) + */ + + NeedSYMBOL(); + growth->filename = CurText(); + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_created_time: + readTIME( &growth->time_stamp ); + NeedRIGHT(); + break; + + case T_comment: + NeedSYMBOL(); + growth->comment = CurText(); + NeedRIGHT(); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doHISTORY( HISTORY* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + /* <history_descriptor >::= + (history [{<ancestor_file_descriptor> }] <self_descriptor> ) + */ + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_ancestor: + ANCESTOR* ancestor; + ancestor = new ANCESTOR( growth ); + growth->ancestors.push_back( ancestor ); + doANCESTOR( ancestor ); + break; + + case T_self: + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_created_time: + readTIME( &growth->time_stamp ); + NeedRIGHT(); + break; + + case T_comment: + NeedSYMBOL(); + growth->comments.push_back( CurText() ); + NeedRIGHT(); + break; + + default: + Unexpected( CurText() ); + } + } + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doSESSION( SESSION* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + /* <session_file_descriptor >::= + (session <session_id > + (base_design <path/filename >) + [<history_descriptor> ] + [<session_structure_descriptor> ] + [<placement_descriptor> ] + [<floor_plan_descriptor> ] + [<net_pin_changes_descriptor> ] + [<was_is_descriptor> ] + <swap_history_descriptor> ] + [<route_descriptor> ] + ) + */ + + NeedSYMBOL(); + growth->session_id = CurText(); + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_base_design: + NeedSYMBOL(); + growth->base_design = CurText(); + NeedRIGHT(); + break; + + case T_history: + if( growth->history ) + Unexpected( tok ); + growth->history = new HISTORY( growth ); + doHISTORY( growth->history ); + break; + + case T_structure: + if( growth->structure ) + Unexpected( tok ); + growth->structure = new STRUCTURE( growth ); + doSTRUCTURE( growth->structure ); + break; + + case T_placement: + if( growth->placement ) + Unexpected( tok ); + growth->placement = new PLACEMENT( growth ); + doPLACEMENT( growth->placement ); + break; + + case T_was_is: + if( growth->was_is ) + Unexpected( tok ); + growth->was_is = new WAS_IS( growth ); + doWAS_IS( growth->was_is ); + break; + + case T_routes: + if( growth->route ) + Unexpected( tok ); + growth->route = new ROUTE( growth ); + doROUTE( growth->route ); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doWAS_IS( WAS_IS* growth ) throw( IO_ERROR ) +{ + T tok; + PIN_PAIR empty( growth ); + PIN_PAIR* pin_pair; + + /* <was_is_descriptor >::= + (was_is {(pins <pin_reference> <pin_reference> )}) + */ + + // none of the pins is ok too + while( (tok = NextTok()) != T_RIGHT ) + { + + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_pins: + // copy the empty one, then fill its copy later thru pin_pair. + growth->pin_pairs.push_back( empty ); + pin_pair= &growth->pin_pairs.back(); + + NeedSYMBOL(); // readCOMPnPIN() expects 1st token to have been read + readCOMPnPIN( &pin_pair->was.component_id, &pin_pair->was.pin_id ); + + NeedSYMBOL(); // readCOMPnPIN() expects 1st token to have been read + readCOMPnPIN( &pin_pair->is.component_id, &pin_pair->is.pin_id ); + + NeedRIGHT(); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doROUTE( ROUTE* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + /* <route_descriptor >::= + (routes + <resolution_descriptor> + <parser_descriptor> + <structure_out_descriptor> + <library_out_descriptor> + <network_out_descriptor> + <test_points_descriptor> + ) + */ + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_resolution: + if( growth->resolution ) + Unexpected( tok ); + growth->resolution = new UNIT_RES( growth, tok ); + doRESOLUTION( growth->resolution ); + break; + + case T_parser: + if( growth->parser ) + { +#if 0 // Electra 2.9.1 emits two (parser ) elements in a row. + // Work around their bug for now. + Unexpected( tok ); +#else + delete growth->parser; +#endif + } + growth->parser = new PARSER( growth ); + doPARSER( growth->parser ); + break; + + case T_structure_out: + if( growth->structure_out ) + Unexpected( tok ); + growth->structure_out = new STRUCTURE_OUT( growth ); + doSTRUCTURE_OUT( growth->structure_out ); + break; + + case T_library_out: + if( growth->library ) + Unexpected( tok ); + growth->library = new LIBRARY( growth, tok ); + doLIBRARY( growth->library ); + break; + + case T_network_out: + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + if( tok != T_net ) // it is class NET_OUT, but token T_net + Unexpected( CurText() ); + + NET_OUT* net_out; + net_out = new NET_OUT( growth ); + + growth->net_outs.push_back( net_out ); + doNET_OUT( net_out ); + } + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doNET_OUT( NET_OUT* growth ) throw( IO_ERROR, boost::bad_pointer ) +{ + T tok; + + /* <net_out_descriptor >::= + (net <net_id > + [(net_number <integer >)] + [<rule_descriptor> ] + {[<wire_shape_descriptor> | <wire_guide_descriptor> | + <wire_via_descriptor> | <bond_shape_descriptor> ]} + {[<supply_pin_descriptor> ]} + ) + */ + + NeedSYMBOLorNUMBER(); + growth->net_id = CurText(); + + while( (tok = NextTok()) != T_RIGHT ) + { + if( tok != T_LEFT ) + Expecting( T_LEFT ); + + tok = NextTok(); + switch( tok ) + { + case T_net_number: + tok = NextTok(); + if( tok!= T_NUMBER ) + Expecting( T_NUMBER ); + growth->net_number = atoi( CurText() ); + NeedRIGHT(); + break; + + case T_rule: + if( growth->rules ) + Unexpected( tok ); + growth->rules = new RULE( growth, tok ); + doRULE( growth->rules ); + break; + + case T_wire: + WIRE* wire; + wire = new WIRE( growth ); + growth->wires.push_back( wire ); + doWIRE( wire ); + break; + + case T_via: + WIRE_VIA* wire_via; + wire_via = new WIRE_VIA( growth ); + growth->wire_vias.push_back( wire_via ); + doWIRE_VIA( wire_via ); + break; + + case T_supply_pin: + SUPPLY_PIN* supply_pin; + supply_pin = new SUPPLY_PIN( growth ); + growth->supply_pins.push_back( supply_pin ); + doSUPPLY_PIN( supply_pin ); + break; + + default: + Unexpected( CurText() ); + } + } +} + + +void SPECCTRA_DB::doSUPPLY_PIN( SUPPLY_PIN* growth ) throw( IO_ERROR ) +{ + T tok; + PIN_REF empty(growth); + + /* <supply_pin_descriptor >::= + (supply_pin {<pin_reference> } [(net <net_id >)]) + */ + + NeedSYMBOL(); + growth->net_id = CurText(); + + while( (tok = NextTok()) != T_RIGHT ) + { + if( IsSymbol(tok) ) + { + growth->pin_refs.push_back( empty ); + + PIN_REF* pin_ref = &growth->pin_refs.back(); + + readCOMPnPIN( &pin_ref->component_id, &pin_ref->pin_id ); + } + else if( tok == T_LEFT ) + { + tok = NextTok(); + if( tok != T_net ) + Expecting( T_net ); + growth->net_id = CurText(); + NeedRIGHT(); + } + else + Unexpected( CurText() ); + } +} + + +void SPECCTRA_DB::ExportPCB( wxString filename, bool aNameChange ) throw( IO_ERROR ) +{ + if( pcb ) + { + FILE_OUTPUTFORMATTER formatter( filename, wxT( "wt" ), quote_char[0] ); + + if( aNameChange ) + pcb->pcbname = TO_UTF8( filename ); + + pcb->Format( &formatter, 0 ); + } +} + + +void SPECCTRA_DB::ExportSESSION( wxString filename ) +{ + if( session ) + { + FILE_OUTPUTFORMATTER formatter( filename, wxT( "wt" ), quote_char[0] ); + + session->Format( &formatter, 0 ); + } +} + + +PCB* SPECCTRA_DB::MakePCB() +{ + PCB* pcb = new PCB(); + + pcb->parser = new PARSER( pcb ); + pcb->resolution = new UNIT_RES( pcb, T_resolution ); + pcb->unit = new UNIT_RES( pcb, T_unit ); + + pcb->structure = new STRUCTURE( pcb ); + pcb->structure->boundary = new BOUNDARY( pcb->structure ); + pcb->structure->via = new VIA( pcb->structure ); + pcb->structure->rules = new RULE( pcb->structure, T_rule ); + + pcb->placement = new PLACEMENT( pcb ); + + pcb->library = new LIBRARY( pcb ); + + pcb->network = new NETWORK( pcb ); + + pcb->wiring = new WIRING( pcb ); + + return pcb; +} + + +//-----<ELEM>--------------------------------------------------------------- + +ELEM::ELEM( T aType, ELEM* aParent ) : + type( aType ), + parent( aParent ) +{ +} + + +ELEM::~ELEM() +{ +} + +const char* ELEM::Name() const +{ + return SPECCTRA_DB::TokenName( type ); +} + +UNIT_RES* ELEM::GetUnits() const +{ + if( parent ) + return parent->GetUnits(); + + return &UNIT_RES::Default; +} + + +void ELEM::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) +{ + out->Print( nestLevel, "(%s\n", Name() ); + + FormatContents( out, nestLevel+1 ); + + out->Print( nestLevel, ")\n" ); +} + + +void ELEM_HOLDER::FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) +{ + for( int i=0; i<Length(); ++i ) + { + At(i)->Format( out, nestLevel ); + } +} + + +int ELEM_HOLDER::FindElem( T aType, int instanceNum ) +{ + int repeats=0; + for( unsigned i=0; i<kids.size(); ++i ) + { + if( kids[i].Type() == aType ) + { + if( repeats == instanceNum ) + return i; + ++repeats; + } + } + return -1; +} + + +// a reasonably small memory price to pay for improved performance +STRING_FORMATTER ELEM::sf; + + +//-----<UNIT_RES>--------------------------------------------------------- + +UNIT_RES UNIT_RES::Default( NULL, T_resolution ); + + +//-----<PADSTACK>--------------------------------------------------------- + +int PADSTACK::Compare( PADSTACK* lhs, PADSTACK* rhs ) +{ + // printf( "PADSTACK::Compare( %p, %p)\n", lhs, rhs ); + + if( !lhs->hash.size() ) + lhs->hash = lhs->makeHash(); + + if( !rhs->hash.size() ) + rhs->hash = rhs->makeHash(); + + int result = lhs->hash.compare( rhs->hash ); + if( result ) + return result; + + // Via names hold the drill diameters, so we have to include those to discern + // between two vias with same copper size but with different drill sizes. + result = lhs->padstack_id.compare( rhs->padstack_id ); + + return result; +} + + +//-----<IMAGE>------------------------------------------------------------ + +int IMAGE::Compare( IMAGE* lhs, IMAGE* rhs ) +{ + if( !lhs->hash.size() ) + lhs->hash = lhs->makeHash(); + + if( !rhs->hash.size() ) + rhs->hash = rhs->makeHash(); + + int result = lhs->hash.compare( rhs->hash ); + + // printf("\"%s\" \"%s\" ret=%d\n", lhs->hash.c_str(), rhs->hash.c_str(), result ); + + return result; +} + + +//-----<COMPONENT>-------------------------------------------------------- + +/* +int COMPONENT::Compare( COMPONENT* lhs, COMPONENT* rhs ) +{ + if( !lhs->hash.size() ) + lhs->hash = lhs->makeHash(); + + if( !rhs->hash.size() ) + rhs->hash = rhs->makeHash(); + + int result = lhs->hash.compare( rhs->hash ); + return result; +} +*/ + +//-----<PARSER>----------------------------------------------------------- +PARSER::PARSER( ELEM* aParent ) : + ELEM( T_parser, aParent ) +{ + string_quote = '"'; + space_in_quoted_tokens = false; + + case_sensitive = false; + wires_include_testpoint = false; + routes_include_testpoint = false; + routes_include_guides = false; + routes_include_image_conductor = false; + via_rotate_first = true; + generated_by_freeroute = false; + + host_cad = "KiCad's Pcbnew"; + wxString msg = GetBuildVersion(); + host_version = TO_UTF8(msg); +} + + +void PARSER::FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) +{ + out->Print( nestLevel, "(string_quote %c)\n", string_quote ); + out->Print( nestLevel, "(space_in_quoted_tokens %s)\n", space_in_quoted_tokens ? "on" : "off" ); + out->Print( nestLevel, "(host_cad \"%s\")\n", host_cad.c_str() ); + out->Print( nestLevel, "(host_version \"%s\")\n", host_version.c_str() ); + + for( STRINGS::iterator i=constants.begin(); i!=constants.end(); ) + { + const std::string& s1 = *i++; + const std::string& s2 = *i++; + + const char* q1 = out->GetQuoteChar( s1.c_str() ); + const char* q2 = out->GetQuoteChar( s2.c_str() ); + out->Print( nestLevel, "(constant %s%s%s %s%s%s)\n", + q1, s1.c_str(), q1, + q2, s2.c_str(), q2 ); + } + + if( routes_include_testpoint || routes_include_guides || routes_include_image_conductor ) + out->Print( nestLevel, "(routes_include%s%s%s)\n", + routes_include_testpoint ? " testpoint" : "", + routes_include_guides ? " guides" : "", + routes_include_image_conductor ? " image_conductor" : ""); + + if( wires_include_testpoint ) + out->Print( nestLevel, "(wires_include testpoint)\n" ); + + if( !via_rotate_first ) + out->Print( nestLevel, "(via_rotate_first off)\n" ); + + if( case_sensitive ) + out->Print( nestLevel, "(case_sensitive %s)\n", case_sensitive ? "on" : "off" ); +} + + +void PLACE::Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IO_ERROR ) +{ + bool useMultiLine; + + const char* quote = out->GetQuoteChar( component_id.c_str() ); + + if( place_rules || properties.size() || rules || region ) + { + useMultiLine = true; + + out->Print( nestLevel, "(%s %s%s%s\n", Name(), + quote, component_id.c_str(), quote ); + + out->Print( nestLevel+1, "%s", "" ); + } + else + { + useMultiLine = false; + + out->Print( nestLevel, "(%s %s%s%s", Name(), + quote, component_id.c_str(), quote ); + } + + if( hasVertex ) + { + out->Print( 0, " %.6g %.6g", vertex.x, vertex.y ); + + out->Print( 0, " %s", GetTokenText( side ) ); + + out->Print( 0, " %.6g", rotation ); + } + + const char* space = " "; // one space, as c string. + + if( mirror != T_NONE ) + { + out->Print( 0, "%s(mirror %s)", space, GetTokenText( mirror ) ); + space = ""; + } + + if( status != T_NONE ) + { + out->Print( 0, "%s(status %s)", space, GetTokenText( status ) ); + space = ""; + } + + if( logical_part.size() ) + { + quote = out->GetQuoteChar( logical_part.c_str() ); + out->Print( 0, "%s(logical_part %s%s%s)", space, + quote, logical_part.c_str(), quote ); + space = ""; + } + + if( useMultiLine ) + { + out->Print( 0, "\n" ); + if( place_rules ) + { + place_rules->Format( out, nestLevel+1 ); + } + + if( properties.size() ) + { + out->Print( nestLevel+1, "(property \n" ); + + for( PROPERTIES::const_iterator i = properties.begin(); + i != properties.end(); ++i ) + { + i->Format( out, nestLevel+2 ); + } + out->Print( nestLevel+1, ")\n" ); + } + if( lock_type != T_NONE ) + out->Print( nestLevel+1, "(lock_type %s)\n", GetTokenText(lock_type) ); + if( rules ) + rules->Format( out, nestLevel+1 ); + + if( region ) + region->Format( out, nestLevel+1 ); + + if( part_number.size() ) + { + const char* quote = out->GetQuoteChar( part_number.c_str() ); + out->Print( nestLevel+1, "(PN %s%s%s)\n", + quote, part_number.c_str(), quote ); + } + } + else + { + if( lock_type != T_NONE ) + { + out->Print( 0, "%s(lock_type %s)", space, GetTokenText(lock_type) ); + space = ""; + } + + if( part_number.size() ) + { + const char* quote = out->GetQuoteChar( part_number.c_str() ); + out->Print( 0, "%s(PN %s%s%s)", space, + quote, part_number.c_str(), quote ); + } + } + + out->Print( 0, ")\n" ); +} + +} // namespace DSN + + +//EOF |