KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kicad_netlist_reader.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 1992-2011 Jean-Pierre Charras.
5 * Copyright (C) 1992-2021 KiCad Developers, see change_log.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <netlist_lexer.h> // netlist_lexer is common to Eeschema and Pcbnew
26#include <macros.h>
27
28#include "pcb_netlist.h"
29#include "netlist_reader.h"
30
31using namespace NL_T;
32
33
35{
37
38 parser.Parse();
39
41 {
43
44 // Sort the component pins so they are in the same order as the legacy format. This
45 // is useful for comparing legacy and s-expression netlist dumps.
46 for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
48 }
49}
50
51
52// KICAD_NETLIST_PARSER
54 NETLIST_LEXER( aReader )
55{
56 m_lineReader = aReader;
57 m_netlist = aNetlist;
58 token = T_NONE;
59}
60
61
63{
64 int curr_level = 0;
65
66 while( ( token = NextTok() ) != T_EOF )
67 {
68 if( token == T_LEFT )
69 curr_level--;
70
71 if( token == T_RIGHT )
72 {
73 curr_level++;
74
75 if( curr_level > 0 )
76 return;
77 }
78 }
79}
80
81
83{
84 int plevel = 0; // the count of ')' to read at end of file after parsing all sections
85
86 while( ( token = NextTok() ) != T_EOF )
87 {
88 if( token == T_LEFT )
89 token = NextTok();
90
91 switch( token )
92 {
93 case T_export: // The netlist starts here.
94 // nothing to do here, just increment the count of ')' to read at end of file
95 plevel++;
96 break;
97
98 case T_version: // The netlist starts here.
99 // version id not yet used: read it but does not use it
100 NextTok();
101 NeedRIGHT();
102 break;
103
104 case T_components: // The section comp starts here.
105 while( ( token = NextTok() ) != T_EOF )
106 {
107 if( token == T_RIGHT )
108 break;
109 else if( token == T_LEFT )
110 token = NextTok();
111
112 if( token == T_comp ) // A component section found. Read it
114 }
115
116 break;
117
118 case T_nets: // The section nets starts here.
119 while( ( token = NextTok() ) != T_EOF )
120 {
121 if( token == T_RIGHT )
122 break;
123 else if( token == T_LEFT )
124 token = NextTok();
125
126 if( token == T_net ) // A net section if found. Read it
127 parseNet();
128 }
129
130 break;
131
132 case T_libparts: // The section libparts starts here.
133 while( ( token = NextTok() ) != T_EOF )
134 {
135 if( token == T_RIGHT )
136 break;
137 else if( token == T_LEFT )
138 token = NextTok();
139
140 if( token == T_libpart ) // A libpart section if found. Read it
142 }
143
144 break;
145
146 case T_libraries: // The section libraries starts here.
147 // List of libraries in use.
148 // Not used here, just skip it
149 skipCurrent();
150 break;
151
152 case T_design: // The section design starts here.
153 // Not used (mainly they are comments), just skip it
154 skipCurrent();
155 break;
156
157 case T_RIGHT: // The closing parenthesis of the file.
158 plevel--;
159 break;
160
161 default:
162 skipCurrent();
163 break;
164 }
165 }
166
167 if( plevel != 0 )
168 {
169 wxFAIL_MSG( wxString::Format( wxT( "KICAD_NETLIST_PARSER::Parse(): bad parenthesis "
170 "count (count = %d" ),
171 plevel ) );
172 }
173}
174
175
177{
178 /* Parses a section like
179 * (net (code 20) (name /PC-A0)
180 * (node (ref "BUS1") (pin "62)")
181 * (node (ref "U3") ("pin 3") (pin_function "clock"))
182 * (node (ref "U9") (pin "M6") (pin_function "reset")))
183 */
184
185 COMPONENT* component = NULL;
186 wxString code;
187 wxString name;
188 wxString reference;
189 wxString pin_number;
190 wxString pin_function;
191 wxString pin_type;
192
193 // The token net was read, so the next data is (code <number>)
194 while( (token = NextTok() ) != T_EOF )
195 {
196 if( token == T_RIGHT )
197 break;
198 else if( token == T_LEFT )
199 token = NextTok();
200
201 switch( token )
202 {
203 case T_code:
204 NeedSYMBOLorNUMBER();
205 code = FROM_UTF8( CurText() );
206 NeedRIGHT();
207 break;
208
209 case T_name:
210 NeedSYMBOLorNUMBER();
211 name = FROM_UTF8( CurText() );
212 NeedRIGHT();
213 break;
214
215 case T_node:
216 // By default: no pin function or type.
217 pin_function.Clear();
218 pin_type.Clear();
219
220 while( (token = NextTok() ) != T_EOF )
221 {
222 if( token == T_RIGHT )
223 break;
224 else if( token == T_LEFT )
225 token = NextTok();
226
227 switch( token )
228 {
229 case T_ref:
230 NeedSYMBOLorNUMBER();
231 reference = FROM_UTF8( CurText() );
232 NeedRIGHT();
233 break;
234
235 case T_pin:
236 NeedSYMBOLorNUMBER();
237 pin_number = FROM_UTF8( CurText() );
238 NeedRIGHT();
239 break;
240
241 case T_pinfunction:
242 NeedSYMBOLorNUMBER();
243 pin_function = FROM_UTF8( CurText() );
244 NeedRIGHT();
245 break;
246
247 case T_pintype:
248 NeedSYMBOLorNUMBER();
249 pin_type = FROM_UTF8( CurText() );
250 NeedRIGHT();
251 break;
252
253 default:
254 skipCurrent();
255 break;
256 }
257 }
258
259 if( strtol( code.c_str(), NULL, 10 ) >= 1 )
260 {
261 if( name.IsEmpty() ) // Give a dummy net name like N-000009
262 name = wxT("N-00000") + code;
263
264 component = m_netlist->GetComponentByReference( reference );
265
266 // Cannot happen if the netlist is valid.
267 if( component == NULL )
268 {
269 wxString msg;
270 msg.Printf( _( "Cannot find component with ref '%s' in netlist." ),
271 reference );
274 }
275
276 component->AddNet( pin_number, name, pin_function, pin_type );
277 }
278 break;
279
280 default:
281 skipCurrent();
282 break;
283 }
284 }
285}
286
287
289{
290 /* Parses a section like
291 * (comp (ref P1)
292 * (value DB25FEMALE)
293 * (footprint DB25FC)
294 * (libsource (lib conn) (part DB25))
295 * (property (name PINCOUNT) (value 25))
296 * (sheetpath (names /) (tstamps /))
297 * (tstamp 68183921-93a5-49ac-91b0-49d05a0e1647))
298 *
299 * other fields (unused) are skipped
300 * A component need a reference, value, footprint name and a full time stamp
301 * The full time stamp is the sheetpath time stamp + the component time stamp
302 */
303 LIB_ID fpid;
304 wxString footprint;
305 wxString ref;
306 wxString value;
307 wxString library;
308 wxString name;
310
311 std::vector<KIID> uuids;
312 std::map<wxString, wxString> properties;
313
314 // The token comp was read, so the next data is (ref P1)
315 while( (token = NextTok() ) != T_RIGHT )
316 {
317 if( token == T_LEFT )
318 token = NextTok();
319
320 switch( token )
321 {
322 case T_ref:
323 NeedSYMBOLorNUMBER();
324 ref = FROM_UTF8( CurText() );
325 NeedRIGHT();
326 break;
327
328 case T_value:
329 NeedSYMBOLorNUMBER();
330 value = FROM_UTF8( CurText() );
331 NeedRIGHT();
332 break;
333
334 case T_footprint:
335 NeedSYMBOLorNUMBER();
336 footprint = FromUTF8();
337 NeedRIGHT();
338 break;
339
340 case T_libsource:
341 // Read libsource
342 while( ( token = NextTok() ) != T_RIGHT )
343 {
344 if( token == T_LEFT )
345 token = NextTok();
346
347 if( token == T_lib )
348 {
349 NeedSYMBOLorNUMBER();
350 library = FROM_UTF8( CurText() );
351 NeedRIGHT();
352 }
353 else if( token == T_part )
354 {
355 NeedSYMBOLorNUMBER();
356 name = FROM_UTF8( CurText() );
357 NeedRIGHT();
358 }
359 else if( token == T_description )
360 {
361 NeedSYMBOLorNUMBER();
362 NeedRIGHT();
363 }
364 else
365 {
366 Expecting( "part, lib or description" );
367 }
368 }
369 break;
370
371 case T_property:
372 {
373 wxString propName;
374 wxString propValue;
375
376 while( (token = NextTok() ) != T_RIGHT )
377 {
378 if( token == T_LEFT )
379 token = NextTok();
380
381 if( token == T_name )
382 {
383 NeedSYMBOLorNUMBER();
384 propName = FROM_UTF8( CurText() );
385 NeedRIGHT();
386 }
387 else if( token == T_value )
388 {
389 NeedSYMBOLorNUMBER();
390 propValue = FROM_UTF8( CurText() );
391 NeedRIGHT();
392 }
393 else
394 {
395 Expecting( "name or value" );
396 }
397 }
398
399 if( !propName.IsEmpty() )
400 properties[ propName ] = propValue;
401 }
402 break;
403
404 case T_sheetpath:
405 while( ( token = NextTok() ) != T_EOF )
406 {
407 if( token == T_tstamps )
408 break;
409 }
410
411 NeedSYMBOLorNUMBER();
412 path = KIID_PATH( FROM_UTF8( CurText() ) );
413 NeedRIGHT();
414 NeedRIGHT();
415 break;
416
417 case T_tstamps:
418 while( ( token = NextTok() ) != T_EOF )
419 {
420 if( token == T_RIGHT )
421 break;
422
423 uuids.emplace_back( FROM_UTF8( CurText() ) );
424 }
425
426 break;
427
428 default:
429 // Skip not used data (i.e all other tokens)
430 skipCurrent();
431 break;
432 }
433 }
434
435 if( !footprint.IsEmpty() && fpid.Parse( footprint, true ) >= 0 )
436 {
437 wxString error;
438 error.Printf( _( "Invalid footprint ID in\nfile: '%s'\nline: %d\noffset: %d" ),
439 CurSource(), CurLineNumber(), CurOffset() );
440
441 THROW_IO_ERROR( error );
442 }
443
444 COMPONENT* component = new COMPONENT( fpid, ref, value, path, uuids );
445 component->SetName( name );
446 component->SetLibrary( library );
447 component->SetProperties( properties );
448 m_netlist->AddComponent( component );
449}
450
451
453{
454 /* Parses a section like
455 * (libpart (lib device) (part C)
456 * (aliases
457 * (alias Cxx)
458 * (alias Cyy))
459 * (description "Condensateur non polarise")
460 * (footprints
461 * (fp SM*)
462 * (fp C?)
463 * (fp C1-1))
464 * (fields
465 * (field (name Reference) C)
466 * (field (name Value) C))
467 * (pins
468 * (pin (num 1) (name ~) (type passive))
469 * (pin (num 2) (name ~) (type passive))))
470 *
471 * Currently footprints section/fp are read and data stored
472 * other fields (unused) are skipped
473 */
474 COMPONENT* component = NULL;
475 wxString libName;
476 wxString libPartName;
477 wxArrayString footprintFilters;
478 wxArrayString aliases;
479 int pinCount = 0;
480
481 // The last token read was libpart, so read the next token
482 while( (token = NextTok() ) != T_RIGHT )
483 {
484 if( token == T_LEFT )
485 token = NextTok();
486
487 switch( token )
488 {
489 case T_lib:
490 NeedSYMBOLorNUMBER();
491 libName = FROM_UTF8( CurText() );
492 NeedRIGHT();
493 break;
494
495 case T_part:
496 NeedSYMBOLorNUMBER();
497 libPartName = FROM_UTF8( CurText() );
498 NeedRIGHT();
499 break;
500
501 case T_footprints:
502 // Read all fp elements (footprint filter item)
503 while( (token = NextTok() ) != T_RIGHT )
504 {
505 if( token == T_LEFT )
506 token = NextTok();
507
508 if( token != T_fp )
509 Expecting( T_fp );
510
511 NeedSYMBOLorNUMBER();
512 footprintFilters.Add( FROM_UTF8( CurText() ) );
513 NeedRIGHT();
514 }
515 break;
516
517 case T_aliases:
518 while( (token = NextTok() ) != T_RIGHT )
519 {
520 if( token == T_LEFT )
521 token = NextTok();
522
523 if( token != T_alias )
524 Expecting( T_alias );
525
526 NeedSYMBOLorNUMBER();
527 aliases.Add( FROM_UTF8( CurText() ) );
528 NeedRIGHT();
529 }
530 break;
531
532 case T_pins:
533 while( (token = NextTok() ) != T_RIGHT )
534 {
535 if( token == T_LEFT )
536 token = NextTok();
537
538 if( token != T_pin )
539 Expecting( T_pin );
540
541 pinCount++;
542
543 skipCurrent();
544 }
545 break;
546
547 default:
548 // Skip not used data (i.e all other tokens)
549 skipCurrent();
550 break;
551 }
552 }
553
554 // Find all of the components that reference this component library part definition.
555 for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
556 {
557 component = m_netlist->GetComponent( i );
558
559 if( component->IsLibSource( libName, libPartName ) )
560 {
561 component->SetFootprintFilters( footprintFilters );
562 component->SetPinCount( pinCount );
563 }
564
565 for( unsigned jj = 0; jj < aliases.GetCount(); jj++ )
566 {
567 if( component->IsLibSource( libName, aliases[jj] ) )
568 {
569 component->SetFootprintFilters( footprintFilters );
570 component->SetPinCount( pinCount );
571 }
572 }
573
574 }
575}
const char * name
Definition: DXF_plotter.cpp:56
bool Load(NETLIST *aNetlist)
Read the *.cmp file format contains the component footprint assignments created by CvPcb into aNetlis...
Store all of the related footprint information found in a netlist.
Definition: pcb_netlist.h:85
void SetLibrary(const wxString &aLibrary)
Definition: pcb_netlist.h:122
void SetProperties(std::map< wxString, wxString > &aProps)
Definition: pcb_netlist.h:131
void SortPins()
Definition: pcb_netlist.h:117
void SetPinCount(int aPinCount)
Definition: pcb_netlist.h:150
bool IsLibSource(const wxString &aLibrary, const wxString &aName) const
Definition: pcb_netlist.h:160
void SetFootprintFilters(const wxArrayString &aFilters)
Definition: pcb_netlist.h:147
void AddNet(const wxString &aPinName, const wxString &aNetName, const wxString &aPinFunction, const wxString &aPinType)
Definition: pcb_netlist.h:103
void SetName(const wxString &aName)
Definition: pcb_netlist.h:119
The parser for reading the KiCad s-expression netlist format.
KICAD_NETLIST_PARSER(LINE_READER *aReader, NETLIST *aNetlist)
void parseComponent()
Parse a component description: (comp (ref P1) (value DB25FEMELLE) (footprint DB25FC) (libsource (lib ...
void Parse()
Function Parse parse the full netlist.
void parseNet()
Parse a net section (net (code 20) (name /PC-A0) (node (ref BUS1) (pin 62)) (node (ref U3) (pin 3)) (...
NETLIST * m_netlist
The netlist to parse into. Not owned.
void parseLibPartList()
Read the section "libparts" in the netlist: (libparts (libpart (lib device) (part C) (description "Co...
LINE_READER * m_lineReader
The line reader used to parse the netlist. Not owned.
void skipCurrent()
Skip the current token level, i.e search for the RIGHT parenthesis which closes the current descripti...
virtual void LoadNetlist() override
Load the contents of the netlist file into aNetlist.
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:50
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition: richio.h:93
virtual const wxString & GetSource() const
Returns the name of the source of the lines in an abstract sense.
Definition: richio.h:121
virtual unsigned LineNumber() const
Return the line number of the last line read from this LINE_READER.
Definition: richio.h:147
unsigned Length() const
Return the number of bytes in the last line read from this LINE_READER.
Definition: richio.h:155
char * Line() const
Return a pointer to the last line that was read in.
Definition: richio.h:129
NETLIST * m_netlist
The net list to read the file(s) into.
LINE_READER * m_lineReader
The line reader of the netlist.
CMP_READER * m_footprintReader
The reader used to load the footprint links. If NULL, footprint links are not read.
Store information read from a netlist along with the flags used to update the NETLIST in the BOARD.
Definition: pcb_netlist.h:213
unsigned GetCount() const
Definition: pcb_netlist.h:234
void AddComponent(COMPONENT *aComponent)
Add aComponent to the NETLIST.
COMPONENT * GetComponentByReference(const wxString &aReference)
Return a COMPONENT by aReference.
COMPONENT * GetComponent(unsigned aIndex)
Return the COMPONENT at aIndex.
Definition: pcb_netlist.h:242
#define _(s)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
This file contains miscellaneous commonly used macros and functions.
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110