2012-06-11 00:47:15 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012 CERN
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file pcb_parser.h
|
|
|
|
* @brief Pcbnew s-expression file format parser definition.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _PCBNEW_PARSER_H_
|
|
|
|
#define _PCBNEW_PARSER_H_
|
|
|
|
|
|
|
|
#include <pcb_lexer.h>
|
2012-11-14 07:15:59 +00:00
|
|
|
#include <hashtables.h>
|
2014-06-24 16:17:18 +00:00
|
|
|
#include <layers_id_colors_and_visibility.h> // LAYER_ID
|
2013-09-21 07:30:23 +00:00
|
|
|
#include <common.h> // KiROUND
|
2012-06-11 00:47:15 +00:00
|
|
|
|
2012-11-28 15:24:53 +00:00
|
|
|
using namespace PCB_KEYS_T;
|
2012-06-11 00:47:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
class BOARD;
|
|
|
|
class BOARD_ITEM;
|
|
|
|
class D_PAD;
|
|
|
|
class DIMENSION;
|
|
|
|
class DRAWSEGMENT;
|
2013-09-21 07:30:23 +00:00
|
|
|
class EDA_TEXT;
|
2012-06-11 00:47:15 +00:00
|
|
|
class EDGE_MODULE;
|
|
|
|
class TEXTE_MODULE;
|
|
|
|
class TEXTE_PCB;
|
2013-09-21 07:30:23 +00:00
|
|
|
class TRACK;
|
2012-06-11 00:47:15 +00:00
|
|
|
class MODULE;
|
|
|
|
class PCB_TARGET;
|
2014-04-25 06:00:04 +00:00
|
|
|
class VIA;
|
2012-06-11 00:47:15 +00:00
|
|
|
class S3D_MASTER;
|
|
|
|
class ZONE_CONTAINER;
|
2014-06-24 16:17:18 +00:00
|
|
|
struct LAYER;
|
2012-06-11 00:47:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Class PCB_PARSER
|
2012-07-05 17:02:45 +00:00
|
|
|
* reads a Pcbnew s-expression formatted #LINE_READER object and returns the appropriate
|
2012-06-11 00:47:15 +00:00
|
|
|
* #BOARD_ITEM object.
|
|
|
|
*/
|
|
|
|
class PCB_PARSER : public PCB_LEXER
|
|
|
|
{
|
2014-07-05 20:42:59 +00:00
|
|
|
typedef boost::unordered_map< std::string, LAYER_ID > LAYER_ID_MAP;
|
|
|
|
typedef boost::unordered_map< std::string, LSET > LSET_MAP;
|
2012-11-14 07:15:59 +00:00
|
|
|
|
2014-06-02 09:41:54 +00:00
|
|
|
BOARD* m_board;
|
2014-06-24 16:17:18 +00:00
|
|
|
LAYER_ID_MAP m_layerIndices; ///< map layer name to it's index
|
|
|
|
LSET_MAP m_layerMasks; ///< map layer names to their masks
|
2014-06-02 09:41:54 +00:00
|
|
|
std::vector<int> m_netCodes; ///< net codes mapping for boards being loaded
|
2012-10-24 18:20:33 +00:00
|
|
|
|
2014-06-03 07:32:57 +00:00
|
|
|
///> Converts net code using the mapping table if available,
|
|
|
|
///> otherwise returns unchanged net code
|
|
|
|
inline int getNetCode( int aNetCode )
|
|
|
|
{
|
|
|
|
if( aNetCode < (int) m_netCodes.size() )
|
|
|
|
return m_netCodes[aNetCode];
|
|
|
|
|
|
|
|
return aNetCode;
|
|
|
|
}
|
|
|
|
|
2012-10-24 18:20:33 +00:00
|
|
|
/**
|
|
|
|
* Function init
|
|
|
|
* clears and re-establishes m_layerMap with the default layer names.
|
|
|
|
* m_layerMap will have some of its entries overwritten whenever a (new) board
|
|
|
|
* is encountered.
|
|
|
|
*/
|
|
|
|
void init();
|
|
|
|
|
2012-06-11 00:47:15 +00:00
|
|
|
void parseHeader() throw( IO_ERROR, PARSE_ERROR );
|
|
|
|
void parseGeneralSection() throw( IO_ERROR, PARSE_ERROR );
|
|
|
|
void parsePAGE_INFO() throw( IO_ERROR, PARSE_ERROR );
|
|
|
|
void parseTITLE_BLOCK() throw( IO_ERROR, PARSE_ERROR );
|
2014-06-24 16:17:18 +00:00
|
|
|
|
2012-06-11 00:47:15 +00:00
|
|
|
void parseLayers() throw( IO_ERROR, PARSE_ERROR );
|
2014-06-24 16:17:18 +00:00
|
|
|
void parseLayer( LAYER* aLayer ) throw( IO_ERROR, PARSE_ERROR );
|
|
|
|
|
2012-06-11 00:47:15 +00:00
|
|
|
void parseSetup() throw( IO_ERROR, PARSE_ERROR );
|
|
|
|
void parseNETINFO_ITEM() throw( IO_ERROR, PARSE_ERROR );
|
|
|
|
void parseNETCLASS() throw( IO_ERROR, PARSE_ERROR );
|
2013-06-23 19:18:33 +00:00
|
|
|
|
|
|
|
DRAWSEGMENT* parseDRAWSEGMENT() throw( IO_ERROR, PARSE_ERROR );
|
|
|
|
TEXTE_PCB* parseTEXTE_PCB() throw( IO_ERROR, PARSE_ERROR );
|
|
|
|
DIMENSION* parseDIMENSION() throw( IO_ERROR, PARSE_ERROR );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function parseModule
|
|
|
|
* @param aInitialComments may be a pointer to a heap allocated initial comment block
|
|
|
|
* or NULL. If not NULL, then caller has given ownership of a wxArrayString to
|
|
|
|
* this function and care must be taken to delete it even on exception.
|
|
|
|
*/
|
|
|
|
MODULE* parseMODULE( wxArrayString* aInitialComments = 0 ) throw( IO_ERROR, PARSE_ERROR );
|
|
|
|
TEXTE_MODULE* parseTEXTE_MODULE() throw( IO_ERROR, PARSE_ERROR );
|
|
|
|
EDGE_MODULE* parseEDGE_MODULE() throw( IO_ERROR, PARSE_ERROR );
|
BOARD_CONNECTED_ITEMs do not store net code anymore (m_NetCode field), instead net info is stored using a pointer to NETINFO_ITEM.
GetNet() refers to the net code stored in the NETINFO_ITEM. SetNet() finds an appropriate NETINFO_ITEM and uses it.
Removing GetNet() & SetNet() (and the whole net code idea) requires too many changes in the code (~250 references to the mentioned functions).
BOARD_CONNECTED_ITEMs by default get a pointer to NETINFO_ITEM that stores unconnected items. This requires for all BOARD_CONNECTED_ITEMs to have a parent (so BOARD* is accessible). The only orphaned item is BOARD_DESIGN_SETTINGS::m_Pad_Master, but it does not cause any issues so far.
Items that do not have access to a BOARD (do not have set parents) and therefore cannot get net assigned, by default get const static NETINFO_LIST::ORPHANED.
Performed tests:
- loaded .kicad_pcb, KiCad legacy board, Eagle 6.0 board, P-CAD board - all ok
- load a simple project, reload netlist after changing connections in eeschema - ok
- save & reload a board - ok, but still contain empty nets
- remove everything, restore with undo - ok
- remove everything, reload netlist - ok
- changing net names (all possibilites: empty->existing, empty->not existing, existing->empty, existing->not existing) - all ok
- zones: when net is changed to a net that does not have any nodes besides the zone itself, it does not get filled
2014-01-15 17:03:06 +00:00
|
|
|
D_PAD* parseD_PAD( MODULE* aParent = NULL ) throw( IO_ERROR, PARSE_ERROR );
|
2013-06-23 19:18:33 +00:00
|
|
|
TRACK* parseTRACK() throw( IO_ERROR, PARSE_ERROR );
|
2014-04-25 06:00:04 +00:00
|
|
|
VIA* parseVIA() throw( IO_ERROR, PARSE_ERROR );
|
2012-06-11 00:47:15 +00:00
|
|
|
ZONE_CONTAINER* parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR );
|
2013-06-23 19:18:33 +00:00
|
|
|
PCB_TARGET* parsePCB_TARGET() throw( IO_ERROR, PARSE_ERROR );
|
|
|
|
BOARD* parseBOARD() throw( IO_ERROR, PARSE_ERROR );
|
2012-06-11 00:47:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function lookUpLayer
|
|
|
|
* parses the current token for the layer definition of a #BOARD_ITEM object.
|
|
|
|
*
|
2013-03-30 17:24:04 +00:00
|
|
|
* @param aMap is the LAYER_{NUM|MSK}_MAP to use for the lookup.
|
2012-11-14 07:15:59 +00:00
|
|
|
*
|
2012-06-11 00:47:15 +00:00
|
|
|
* @throw IO_ERROR if the layer is not valid.
|
|
|
|
* @throw PARSE_ERROR if the layer syntax is incorrect.
|
2012-11-14 07:15:59 +00:00
|
|
|
* @return int - The result of the parsed #BOARD_ITEM layer or set designator.
|
2012-06-11 00:47:15 +00:00
|
|
|
*/
|
2013-03-30 17:24:04 +00:00
|
|
|
template<class T, class M>
|
|
|
|
T lookUpLayer( const M& aMap ) throw( PARSE_ERROR, IO_ERROR );
|
2012-06-11 00:47:15 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Function parseBoardItemLayer
|
|
|
|
* parses the layer definition of a #BOARD_ITEM object.
|
|
|
|
*
|
|
|
|
* @throw IO_ERROR if the layer is not valid.
|
|
|
|
* @throw PARSE_ERROR if the layer syntax is incorrect.
|
|
|
|
* @return The index the parsed #BOARD_ITEM layer.
|
|
|
|
*/
|
2014-06-24 16:17:18 +00:00
|
|
|
LAYER_ID parseBoardItemLayer() throw( IO_ERROR, PARSE_ERROR );
|
2012-06-11 00:47:15 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Function parseBoardItemLayersAsMask
|
|
|
|
* parses the layers definition of a #BOARD_ITEM object.
|
|
|
|
*
|
|
|
|
* @throw IO_ERROR if any of the layers is not valid.
|
|
|
|
* @throw PARSE_ERROR if the layers syntax is incorrect.
|
|
|
|
* @return The mask of layers the parsed #BOARD_ITEM is on.
|
|
|
|
*/
|
2014-06-24 16:17:18 +00:00
|
|
|
LSET parseBoardItemLayersAsMask() throw( PARSE_ERROR, IO_ERROR );
|
2012-06-11 00:47:15 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Function parseXY
|
|
|
|
* parses a coordinate pair (xy X Y) in board units (mm).
|
|
|
|
*
|
|
|
|
* The parser checks if the previous token was T_LEFT and parses the remainder of
|
2012-07-05 17:02:45 +00:00
|
|
|
* the token syntax. This is used when parsing a list of coordinate points. This
|
2012-06-11 00:47:15 +00:00
|
|
|
* way the parser can be used in either case.
|
|
|
|
*
|
|
|
|
* @throw PARSE_ERROR if the coordinate pair syntax is incorrect.
|
|
|
|
* @return A wxPoint object containing the coordinate pair.
|
|
|
|
*/
|
|
|
|
wxPoint parseXY() throw( PARSE_ERROR );
|
|
|
|
|
|
|
|
void parseXY( int* aX, int* aY ) throw( PARSE_ERROR );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function parseEDA_TEXT
|
|
|
|
* parses the common settings for any object derived from #EDA_TEXT.
|
|
|
|
*
|
|
|
|
* @throw PARSE_ERROR if the text syntax is not valid.
|
|
|
|
* @param aText A point to the #EDA_TEXT object to save the parsed settings into.
|
|
|
|
*/
|
|
|
|
void parseEDA_TEXT( EDA_TEXT* aText ) throw( PARSE_ERROR );
|
|
|
|
|
|
|
|
S3D_MASTER* parse3DModel() throw( PARSE_ERROR );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function parseDouble
|
2013-03-27 14:01:50 +00:00
|
|
|
* parses the current token as an ASCII numeric string with possible leading
|
|
|
|
* whitespace into a double precision floating point number.
|
2012-06-11 00:47:15 +00:00
|
|
|
*
|
|
|
|
* @throw IO_ERROR if an error occurs attempting to convert the current token.
|
|
|
|
* @return The result of the parsed token.
|
|
|
|
*/
|
|
|
|
double parseDouble() throw( IO_ERROR );
|
|
|
|
|
|
|
|
inline double parseDouble( const char* aExpected ) throw( IO_ERROR )
|
|
|
|
{
|
|
|
|
NeedNUMBER( aExpected );
|
|
|
|
return parseDouble();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline double parseDouble( T aToken ) throw( IO_ERROR )
|
|
|
|
{
|
|
|
|
return parseDouble( GetTokenText( aToken ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int parseBoardUnits() throw( IO_ERROR )
|
|
|
|
{
|
2013-03-27 14:01:50 +00:00
|
|
|
// There should be no major rounding issues here, since the values in
|
|
|
|
// the file are in mm and get converted to nano-meters.
|
|
|
|
// See test program tools/test-nm-biu-to-ascii-mm-round-tripping.cpp
|
|
|
|
// to confirm or experiment. Use a similar strategy in both places, here
|
|
|
|
// and in the test program. Make that program with:
|
|
|
|
// $ make test-nm-biu-to-ascii-mm-round-tripping
|
2013-03-26 18:15:30 +00:00
|
|
|
return KiROUND( parseDouble() * IU_PER_MM );
|
2012-06-11 00:47:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline int parseBoardUnits( const char* aExpected ) throw( PARSE_ERROR )
|
|
|
|
{
|
2012-06-14 06:29:54 +00:00
|
|
|
// Use here KiROUND, not KIROUND (see comments about them)
|
|
|
|
// when having a function as argument, because it will be called twice
|
|
|
|
// with KIROUND
|
|
|
|
return KiROUND( parseDouble( aExpected ) * IU_PER_MM );
|
2012-06-11 00:47:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline int parseBoardUnits( T aToken ) throw( PARSE_ERROR )
|
|
|
|
{
|
|
|
|
return parseBoardUnits( GetTokenText( aToken ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int parseInt() throw( PARSE_ERROR )
|
|
|
|
{
|
|
|
|
return (int)strtol( CurText(), NULL, 10 );
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int parseInt( const char* aExpected ) throw( PARSE_ERROR )
|
|
|
|
{
|
|
|
|
NeedNUMBER( aExpected );
|
|
|
|
return parseInt();
|
|
|
|
}
|
|
|
|
|
2012-06-13 23:04:42 +00:00
|
|
|
inline long parseHex() throw( PARSE_ERROR )
|
2012-06-11 00:47:15 +00:00
|
|
|
{
|
2012-06-13 23:04:42 +00:00
|
|
|
NextTok();
|
|
|
|
return strtol( CurText(), NULL, 16 );
|
2012-06-11 00:47:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool parseBool() throw( PARSE_ERROR );
|
|
|
|
|
2012-10-24 18:20:33 +00:00
|
|
|
|
2012-06-11 00:47:15 +00:00
|
|
|
public:
|
2012-10-24 18:20:33 +00:00
|
|
|
|
|
|
|
PCB_PARSER( LINE_READER* aReader = NULL ) :
|
2012-06-11 00:47:15 +00:00
|
|
|
PCB_LEXER( aReader ),
|
2012-10-24 18:20:33 +00:00
|
|
|
m_board( 0 )
|
|
|
|
{
|
2012-11-09 06:58:00 +00:00
|
|
|
init();
|
2012-10-24 18:20:33 +00:00
|
|
|
}
|
|
|
|
|
2012-11-14 07:15:59 +00:00
|
|
|
// ~PCB_PARSER() {}
|
2012-10-24 18:20:33 +00:00
|
|
|
|
|
|
|
/**
|
2012-11-14 07:15:59 +00:00
|
|
|
* Function SetLineReader
|
2012-10-24 18:20:33 +00:00
|
|
|
* sets @a aLineReader into the parser, and returns the previous one, if any.
|
|
|
|
* @param aReader is what to read from for tokens, no ownership is received.
|
|
|
|
* @return LINE_READER* - previous LINE_READER or NULL if none.
|
|
|
|
*/
|
|
|
|
LINE_READER* SetLineReader( LINE_READER* aReader )
|
|
|
|
{
|
|
|
|
LINE_READER* ret = PopReader();
|
|
|
|
PushReader( aReader );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetBoard( BOARD* aBoard )
|
2012-06-11 00:47:15 +00:00
|
|
|
{
|
2012-10-24 18:20:33 +00:00
|
|
|
init();
|
|
|
|
m_board = aBoard;
|
2012-06-11 00:47:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOARD_ITEM* Parse() throw( IO_ERROR, PARSE_ERROR );
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#endif // _PCBNEW_PARSER_H_
|