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 <string_utils.h>
27#include <nlohmann/json.hpp>
28
29#include "pcb_netlist.h"
30#include "netlist_reader.h"
32
33using namespace NL_T;
34
35
37{
39
40 parser.Parse();
41
43 {
45
46 // Sort the component pins so they are in the same order as the legacy format. This
47 // is useful for comparing legacy and s-expression netlist dumps.
48 for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
50 }
51}
52
53
54// KICAD_NETLIST_PARSER
56 NETLIST_LEXER( aReader )
57{
58 m_lineReader = aReader;
59 m_netlist = aNetlist;
60 token = T_NONE;
61}
62
63
65{
66 int curr_level = 0;
67
68 while( ( token = NextTok() ) != T_EOF )
69 {
70 if( token == T_LEFT )
71 curr_level--;
72
73 if( token == T_RIGHT )
74 {
75 curr_level++;
76
77 if( curr_level > 0 )
78 return;
79 }
80 }
81}
82
83
85{
86 int plevel = 0; // the count of ')' to read at end of file after parsing all sections
87
88 while( ( token = NextTok() ) != T_EOF )
89 {
90 if( token == T_LEFT )
91 token = NextTok();
92
93 switch( token )
94 {
95 case T_export: // The netlist starts here.
96 // nothing to do here, just increment the count of ')' to read at end of file
97 plevel++;
98 break;
99
100 case T_version: // The netlist starts here.
101 // version id not yet used: read it but does not use it
102 NextTok();
103 NeedRIGHT();
104 break;
105
106 case T_components: // The section comp starts here.
107 while( ( token = NextTok() ) != T_EOF )
108 {
109 if( token == T_RIGHT )
110 break;
111 else if( token == T_LEFT )
112 token = NextTok();
113
114 if( token == T_comp ) // A component section found. Read it
116 }
117
118 break;
119
120 case T_nets: // The section nets starts here.
121 while( ( token = NextTok() ) != T_EOF )
122 {
123 if( token == T_RIGHT )
124 break;
125 else if( token == T_LEFT )
126 token = NextTok();
127
128 if( token == T_net ) // A net section if found. Read it
129 parseNet();
130 }
131
132 break;
133
134 case T_libparts: // The section libparts starts here.
135 while( ( token = NextTok() ) != T_EOF )
136 {
137 if( token == T_RIGHT )
138 break;
139 else if( token == T_LEFT )
140 token = NextTok();
141
142 if( token == T_libpart ) // A libpart section if found. Read it
144 }
145
146 break;
147
148 case T_libraries: // The section libraries starts here.
149 // List of libraries in use.
150 // Not used here, just skip it
151 skipCurrent();
152 break;
153
154 case T_design: // The section design starts here.
155 // Not used (mainly they are comments), just skip it
156 skipCurrent();
157 break;
158
159 case T_RIGHT: // The closing parenthesis of the file.
160 plevel--;
161 break;
162
163 default:
164 skipCurrent();
165 break;
166 }
167 }
168
169 if( plevel != 0 )
170 {
171 wxFAIL_MSG( wxString::Format( wxT( "KICAD_NETLIST_PARSER::Parse(): bad parenthesis "
172 "count (count = %d" ),
173 plevel ) );
174 }
175}
176
177
179{
180 /* Parses a section like
181 * (net (code 20) (name /PC-A0)
182 * (node (ref "BUS1") (pin "62)")
183 * (node (ref "U3") ("pin 3") (pin_function "clock"))
184 * (node (ref "U9") (pin "M6") (pin_function "reset")))
185 */
186
187 wxString code;
188 wxString name;
189 wxString reference;
190 wxString pin_number;
191 wxString pin_function;
192 wxString pin_type;
193
194 // The token net was read, so the next data is (code <number>)
195 while( (token = NextTok() ) != T_EOF )
196 {
197 if( token == T_RIGHT )
198 break;
199 else if( token == T_LEFT )
200 token = NextTok();
201
202 switch( token )
203 {
204 case T_code:
205 NeedSYMBOLorNUMBER();
206 code = From_UTF8( CurText() );
207 NeedRIGHT();
208 break;
209
210 case T_name:
211 NeedSYMBOLorNUMBER();
212 name = From_UTF8( CurText() );
213 NeedRIGHT();
214 break;
215
216 case T_node:
217 // By default: no pin function or type.
218 pin_function.Clear();
219 pin_type.Clear();
220
221 while( (token = NextTok() ) != T_EOF )
222 {
223 if( token == T_RIGHT )
224 break;
225 else if( token == T_LEFT )
226 token = NextTok();
227
228 switch( token )
229 {
230 case T_ref:
231 NeedSYMBOLorNUMBER();
232 reference = From_UTF8( CurText() );
233 NeedRIGHT();
234 break;
235
236 case T_pin:
237 NeedSYMBOLorNUMBER();
238 pin_number = From_UTF8( CurText() );
239 NeedRIGHT();
240 break;
241
242 case T_pinfunction:
243 NeedSYMBOLorNUMBER();
244 pin_function = From_UTF8( CurText() );
245 NeedRIGHT();
246 break;
247
248 case T_pintype:
249 NeedSYMBOLorNUMBER();
250 pin_type = From_UTF8( CurText() );
251 NeedRIGHT();
252 break;
253
254 default:
255 skipCurrent();
256 break;
257 }
258 }
259
260 // Don't assume component will be found; it might be "DNP" or "Exclude from board".
261 if( COMPONENT* component = m_netlist->GetComponentByReference( reference ) )
262 {
263 if( strtol( code.c_str(), nullptr, 10 ) >= 1 )
264 {
265 if( name.IsEmpty() ) // Give a dummy net name like N-000009
266 name = wxT("N-00000") + code;
267
268 component->AddNet( pin_number, name, pin_function, pin_type );
269 }
270 }
271
272 break;
273
274 default:
275 skipCurrent();
276 break;
277 }
278 }
279}
280
281
283{
284 /* Parses a section like
285 * (comp (ref P1)
286 * (value DB25FEMALE)
287 * (footprint DB25FC)
288 * (libsource (lib conn) (part DB25))
289 * (property (name PINCOUNT) (value 25))
290 * (sheetpath (names /) (tstamps /))
291 * (component_classes (class (name "CLASS")))
292 * (tstamp 68183921-93a5-49ac-91b0-49d05a0e1647))
293 *
294 * other fields (unused) are skipped
295 * A component need a reference, value, footprint name and a full time stamp
296 * The full time stamp is the sheetpath time stamp + the component time stamp
297 */
298 LIB_ID fpid;
299 wxString footprint;
300 wxString ref;
301 wxString value;
302 wxString library;
303 wxString name;
304 wxString humanSheetPath;
306
307 std::vector<KIID> uuids;
308 std::map<wxString, wxString> properties;
309 nlohmann::ordered_map<wxString, wxString> fields;
310 std::unordered_set<wxString> componentClasses;
311
312 // The token comp was read, so the next data is (ref P1)
313 while( (token = NextTok() ) != T_RIGHT )
314 {
315 if( token == T_LEFT )
316 token = NextTok();
317
318 switch( token )
319 {
320 case T_ref:
321 NeedSYMBOLorNUMBER();
322 ref = From_UTF8( CurText() );
323 NeedRIGHT();
324 break;
325
326 case T_value:
327 NeedSYMBOLorNUMBER();
328 value = From_UTF8( CurText() );
329 NeedRIGHT();
330 break;
331
332 case T_footprint:
333 NeedSYMBOLorNUMBER();
334 footprint = FromUTF8();
335 NeedRIGHT();
336 break;
337
338 case T_libsource:
339 // Read libsource
340 while( ( token = NextTok() ) != T_RIGHT )
341 {
342 if( token == T_LEFT )
343 token = NextTok();
344
345 if( token == T_lib )
346 {
347 NeedSYMBOLorNUMBER();
348 library = From_UTF8( CurText() );
349 NeedRIGHT();
350 }
351 else if( token == T_part )
352 {
353 NeedSYMBOLorNUMBER();
354 name = From_UTF8( CurText() );
355 NeedRIGHT();
356 }
357 else if( token == T_description )
358 {
359 NeedSYMBOLorNUMBER();
360 NeedRIGHT();
361 }
362 else
363 {
364 Expecting( "part, lib or description" );
365 }
366 }
367 break;
368
369 case T_property:
370 {
371 wxString propName;
372 wxString propValue;
373
374 while( (token = NextTok() ) != T_RIGHT )
375 {
376 if( token == T_LEFT )
377 token = NextTok();
378
379 if( token == T_name )
380 {
381 NeedSYMBOLorNUMBER();
382 propName = From_UTF8( CurText() );
383 NeedRIGHT();
384 }
385 else if( token == T_value )
386 {
387 NeedSYMBOLorNUMBER();
388 propValue = From_UTF8( CurText() );
389 NeedRIGHT();
390 }
391 else
392 {
393 Expecting( "name or value" );
394 }
395 }
396
397 if( !propName.IsEmpty() )
398 properties[ propName ] = propValue;
399 }
400 break;
401
402 case T_fields:
403
404 // Read fields
405 while( ( token = NextTok() ) != T_RIGHT )
406 {
407 if( token == T_LEFT )
408 token = NextTok();
409
410 if( token == T_field )
411 {
412 wxString fieldName;
413 wxString fieldValue;
414
415 while( ( token = NextTok() ) != T_RIGHT )
416 {
417 if( token == T_LEFT )
418 token = NextTok();
419
420 if( token == T_name )
421 {
422 NeedSYMBOLorNUMBER();
423 fieldName = From_UTF8( CurText() );
424 NeedRIGHT();
425 }
426 else if( token == T_STRING )
427 {
428 fieldValue = From_UTF8( CurText() );
429 }
430 }
431
432 if( !fieldName.IsEmpty() )
433 fields[fieldName] = fieldValue;
434 }
435 else
436 {
437 Expecting( "field" );
438 }
439 }
440 break;
441
442 case T_sheetpath:
443 while( ( token = NextTok() ) != T_EOF )
444 {
445 if( token == T_names )
446 {
447 NeedSYMBOLorNUMBER();
448 humanSheetPath = From_UTF8( CurText() );
449 NeedRIGHT();
450 }
451 if( token == T_tstamps )
452 {
453 NeedSYMBOLorNUMBER();
454 path = KIID_PATH( From_UTF8( CurText() ) );
455 NeedRIGHT();
456 break;
457 }
458 }
459
460 NeedRIGHT();
461
462 break;
463
464 case T_tstamps:
465 while( ( token = NextTok() ) != T_EOF )
466 {
467 if( token == T_RIGHT )
468 break;
469
470 uuids.emplace_back( From_UTF8( CurText() ) );
471 }
472
473 break;
474
475 case T_component_classes:
476 {
477 while( ( token = NextTok() ) != T_RIGHT )
478 {
479 if( token != T_LEFT )
480 Expecting( T_LEFT );
481
482 if( ( token = NextTok() ) != T_class )
483 Expecting( T_class );
484
485 NeedSYMBOLorNUMBER();
486 componentClasses.insert( From_UTF8( CurText() ) );
487 NeedRIGHT();
488 }
489
490 break;
491 }
492
493 default:
494 // Skip not used data (i.e all other tokens)
495 skipCurrent();
496 break;
497 }
498 }
499
500 if( !footprint.IsEmpty() && fpid.Parse( footprint, true ) >= 0 )
501 {
502 wxString error;
503 error.Printf( _( "Invalid footprint ID in\nfile: '%s'\nline: %d\nofff: %d" ),
504 CurSource(), CurLineNumber(), CurOffset() );
505
506 THROW_IO_ERROR( error );
507 }
508
509 COMPONENT* component = new COMPONENT( fpid, ref, value, path, uuids );
510 component->SetName( name );
511 component->SetLibrary( library );
512 component->SetProperties( properties );
513 component->SetFields( fields );
514 component->SetHumanReadablePath( humanSheetPath );
515 component->SetComponentClassNames( componentClasses );
516 m_netlist->AddComponent( component );
517}
518
519
521{
522 /* Parses a section like
523 * (libpart (lib device) (part C)
524 * (aliases
525 * (alias Cxx)
526 * (alias Cyy))
527 * (description "Condensateur non polarise")
528 * (footprints
529 * (fp SM*)
530 * (fp C?)
531 * (fp C1-1))
532 * (fields
533 * (field (name Reference) C)
534 * (field (name Value) C))
535 * (pins
536 * (pin (num 1) (name ~) (type passive))
537 * (pin (num 2) (name ~) (type passive))))
538 *
539 * Currently footprints section/fp are read and data stored
540 * other fields (unused) are skipped
541 */
542 COMPONENT* component = NULL;
543 wxString libName;
544 wxString libPartName;
545 wxArrayString footprintFilters;
546 wxArrayString aliases;
547 int pinCount = 0;
548
549 // The last token read was libpart, so read the next token
550 while( (token = NextTok() ) != T_RIGHT )
551 {
552 if( token == T_LEFT )
553 token = NextTok();
554
555 switch( token )
556 {
557 case T_lib:
558 NeedSYMBOLorNUMBER();
559 libName = From_UTF8( CurText() );
560 NeedRIGHT();
561 break;
562
563 case T_part:
564 NeedSYMBOLorNUMBER();
565 libPartName = From_UTF8( CurText() );
566 NeedRIGHT();
567 break;
568
569 case T_footprints:
570 // Read all fp elements (footprint filter item)
571 while( (token = NextTok() ) != T_RIGHT )
572 {
573 if( token == T_LEFT )
574 token = NextTok();
575
576 if( token != T_fp )
577 Expecting( T_fp );
578
579 NeedSYMBOLorNUMBER();
580 footprintFilters.Add( From_UTF8( CurText() ) );
581 NeedRIGHT();
582 }
583 break;
584
585 case T_aliases:
586 while( (token = NextTok() ) != T_RIGHT )
587 {
588 if( token == T_LEFT )
589 token = NextTok();
590
591 if( token != T_alias )
592 Expecting( T_alias );
593
594 NeedSYMBOLorNUMBER();
595 aliases.Add( From_UTF8( CurText() ) );
596 NeedRIGHT();
597 }
598 break;
599
600 case T_pins:
601 while( (token = NextTok() ) != T_RIGHT )
602 {
603 if( token == T_LEFT )
604 token = NextTok();
605
606 if( token != T_pin )
607 Expecting( T_pin );
608
609 pinCount++;
610
611 skipCurrent();
612 }
613 break;
614
615 default:
616 // Skip not used data (i.e all other tokens)
617 skipCurrent();
618 break;
619 }
620 }
621
622 // Find all of the components that reference this component library part definition.
623 for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
624 {
625 component = m_netlist->GetComponent( i );
626
627 if( component->IsLibSource( libName, libPartName ) )
628 {
629 component->SetFootprintFilters( footprintFilters );
630 component->SetPinCount( pinCount );
631 }
632
633 for( unsigned jj = 0; jj < aliases.GetCount(); jj++ )
634 {
635 if( component->IsLibSource( libName, aliases[jj] ) )
636 {
637 component->SetFootprintFilters( footprintFilters );
638 component->SetPinCount( pinCount );
639 }
640 }
641
642 }
643}
const char * name
Definition: DXF_plotter.cpp:57
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:88
void SetFields(nlohmann::ordered_map< wxString, wxString > &aFields)
Definition: pcb_netlist.h:134
void SetLibrary(const wxString &aLibrary)
Definition: pcb_netlist.h:125
void SetProperties(std::map< wxString, wxString > &aProps)
Definition: pcb_netlist.h:140
void SortPins()
Definition: pcb_netlist.h:120
void SetPinCount(int aPinCount)
Definition: pcb_netlist.h:159
bool IsLibSource(const wxString &aLibrary, const wxString &aName) const
Definition: pcb_netlist.h:169
void SetFootprintFilters(const wxArrayString &aFilters)
Definition: pcb_netlist.h:156
void SetHumanReadablePath(const wxString &aPath)
Definition: pcb_netlist.h:176
void SetComponentClassNames(const std::unordered_set< wxString > &aClassNames)
Definition: pcb_netlist.h:179
void SetName(const wxString &aName)
Definition: pcb_netlist.h:122
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:51
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition: richio.h:93
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:241
unsigned GetCount() const
Definition: pcb_netlist.h:262
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:270
#define _(s)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
wxString From_UTF8(const char *cstring)