1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
|
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2012 CERN
* Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.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
*/
/**
* @file pcb_parser.h
* @brief Pcbnew s-expression file format parser definition.
*/
#ifndef _PCBNEW_PARSER_H_
#define _PCBNEW_PARSER_H_
#include <pcb_lexer.h>
#include <hashtables.h>
#include <layers_id_colors_and_visibility.h> // LAYER_ID
#include <common.h> // KiROUND
#include <convert_to_biu.h> // IU_PER_MM
class BOARD;
class BOARD_ITEM;
class D_PAD;
class DIMENSION;
class DRAWSEGMENT;
class EDA_TEXT;
class EDGE_MODULE;
class TEXTE_MODULE;
class TEXTE_PCB;
class TRACK;
class MODULE;
class PCB_TARGET;
class VIA;
class S3D_MASTER;
class ZONE_CONTAINER;
struct LAYER;
/**
* Class PCB_PARSER
* reads a Pcbnew s-expression formatted #LINE_READER object and returns the appropriate
* #BOARD_ITEM object.
*/
class PCB_PARSER : public PCB_LEXER
{
typedef boost::unordered_map< std::string, LAYER_ID > LAYER_ID_MAP;
typedef boost::unordered_map< std::string, LSET > LSET_MAP;
BOARD* m_board;
LAYER_ID_MAP m_layerIndices; ///< map layer name to it's index
LSET_MAP m_layerMasks; ///< map layer names to their masks
std::vector<int> m_netCodes; ///< net codes mapping for boards being loaded
bool m_tooRecent; ///< true if version parses as later than supported
int m_requiredVersion; ///< set to the KiCad format version this board requires
///> Converts net code using the mapping table if available,
///> otherwise returns unchanged net code if < 0 or if is is out of range
inline int getNetCode( int aNetCode )
{
if( ( aNetCode >= 0 ) && ( aNetCode < (int) m_netCodes.size() ) )
return m_netCodes[aNetCode];
return aNetCode;
}
/**
* function pushValueIntoMap
* Add aValue value in netcode mapping (m_netCodes) at index aIndex
* ensure there is room in m_netCodes for that, and add room if needed.
* @param aIndex = the index ( expected >=0 )of the location to use in m_netCodes
* @param aValue = the netcode value to map
*/
void pushValueIntoMap( int aIndex, int aValue );
/**
* 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();
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 );
void parseLayers() throw( IO_ERROR, PARSE_ERROR );
void parseLayer( LAYER* aLayer ) throw( IO_ERROR, PARSE_ERROR );
void parseSetup() throw( IO_ERROR, PARSE_ERROR );
void parseNETINFO_ITEM() throw( IO_ERROR, PARSE_ERROR );
void parseNETCLASS() throw( IO_ERROR, PARSE_ERROR );
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, FUTURE_FORMAT_ERROR );
/**
* Function parseMODULE_unchecked
* Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERROR automatically.
*/
MODULE* parseMODULE_unchecked( 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 );
D_PAD* parseD_PAD( MODULE* aParent = NULL ) throw( IO_ERROR, PARSE_ERROR );
TRACK* parseTRACK() throw( IO_ERROR, PARSE_ERROR );
VIA* parseVIA() throw( IO_ERROR, PARSE_ERROR );
ZONE_CONTAINER* parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR );
PCB_TARGET* parsePCB_TARGET() throw( IO_ERROR, PARSE_ERROR );
BOARD* parseBOARD() throw( IO_ERROR, PARSE_ERROR, FUTURE_FORMAT_ERROR );
/**
* Function parseBOARD_unchecked
* Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERROR automatically.
*/
BOARD* parseBOARD_unchecked() throw( IO_ERROR, PARSE_ERROR );
/**
* Function lookUpLayer
* parses the current token for the layer definition of a #BOARD_ITEM object.
*
* @param aMap is the LAYER_{NUM|MSK}_MAP to use for the lookup.
*
* @throw IO_ERROR if the layer is not valid.
* @throw PARSE_ERROR if the layer syntax is incorrect.
* @return int - The result of the parsed #BOARD_ITEM layer or set designator.
*/
template<class T, class M>
T lookUpLayer( const M& aMap ) throw( PARSE_ERROR, IO_ERROR );
/**
* 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.
*/
LAYER_ID parseBoardItemLayer() throw( IO_ERROR, PARSE_ERROR );
/**
* 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.
*/
LSET parseBoardItemLayersAsMask() throw( PARSE_ERROR, IO_ERROR );
/**
* 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
* the token syntax. This is used when parsing a list of coordinate points. This
* 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, IO_ERROR );
void parseXY( int* aX, int* aY ) throw( PARSE_ERROR, IO_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, IO_ERROR );
S3D_MASTER* parse3DModel() throw( PARSE_ERROR, IO_ERROR );
/**
* Function parseDouble
* parses the current token as an ASCII numeric string with possible leading
* whitespace into a double precision floating point number.
*
* @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( PCB_KEYS_T::T aToken ) throw( IO_ERROR )
{
return parseDouble( GetTokenText( aToken ) );
}
inline int parseBoardUnits() throw( IO_ERROR )
{
// 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
return KiROUND( parseDouble() * IU_PER_MM );
}
inline int parseBoardUnits( const char* aExpected ) throw( PARSE_ERROR, IO_ERROR )
{
// 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 );
}
inline int parseBoardUnits( PCB_KEYS_T::T aToken ) throw( PARSE_ERROR, IO_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();
}
inline long parseHex() throw( PARSE_ERROR )
{
NextTok();
return strtol( CurText(), NULL, 16 );
}
bool parseBool() throw( PARSE_ERROR );
/**
* Parse a format version tag like (version 20160417) return the version.
* Expects to start on 'version', and eats the closing paren.
*/
int parseVersion() throw( IO_ERROR, PARSE_ERROR );
public:
PCB_PARSER( LINE_READER* aReader = NULL ) :
PCB_LEXER( aReader ),
m_board( 0 )
{
init();
}
// ~PCB_PARSER() {}
/**
* Function SetLineReader
* 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 )
{
init();
m_board = aBoard;
}
BOARD_ITEM* Parse() throw( IO_ERROR, PARSE_ERROR );
/**
* Return whether a version number, if any was parsed, was too recent
*/
bool IsTooRecent()
{
return m_tooRecent;
}
/**
* Return a string representing the version of kicad required to open this
* file. Not particularly meaningful if IsTooRecent() returns false.
*/
wxString GetRequiredVersion();
};
#endif // _PCBNEW_PARSER_H_
|