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 The KiCad Developers, see AUTHORS.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 while( ( token = NextTok() ) != T_RIGHT )
404 {
405 if( token == T_LEFT )
406 token = NextTok();
407
408 if( token == T_field )
409 {
410 wxString fieldName;
411 wxString fieldValue;
412
413 while( ( token = NextTok() ) != T_RIGHT )
414 {
415 if( token == T_LEFT )
416 token = NextTok();
417
418 if( token == T_name )
419 {
420 NeedSYMBOLorNUMBER();
421 fieldName = From_UTF8( CurText() );
422 NeedRIGHT();
423 }
424 else if( token == T_STRING )
425 {
426 fieldValue = From_UTF8( CurText() );
427 }
428 }
429
430 if( !fieldName.IsEmpty() )
431 fields[fieldName] = fieldValue;
432 }
433 else
434 {
435 Expecting( "field" );
436 }
437 }
438 break;
439
440 case T_sheetpath:
441 while( ( token = NextTok() ) != T_EOF )
442 {
443 if( token == T_names )
444 {
445 NeedSYMBOLorNUMBER();
446 humanSheetPath = From_UTF8( CurText() );
447 NeedRIGHT();
448 }
449
450 if( token == T_tstamps )
451 {
452 NeedSYMBOLorNUMBER();
453 path = KIID_PATH( From_UTF8( CurText() ) );
454 NeedRIGHT();
455 break;
456 }
457 }
458
459 NeedRIGHT();
460
461 break;
462
463 case T_tstamps:
464 while( ( token = NextTok() ) != T_EOF )
465 {
466 if( token == T_RIGHT )
467 break;
468
469 uuids.emplace_back( From_UTF8( CurText() ) );
470 }
471
472 break;
473
474 case T_component_classes:
475 while( ( token = NextTok() ) != T_RIGHT )
476 {
477 if( token != T_LEFT )
478 Expecting( T_LEFT );
479
480 if( ( token = NextTok() ) != T_class )
481 Expecting( T_class );
482
483 NeedSYMBOLorNUMBER();
484 componentClasses.insert( From_UTF8( CurText() ) );
485 NeedRIGHT();
486 }
487
488 break;
489
490 default:
491 // Skip not used data (i.e all other tokens)
492 skipCurrent();
493 break;
494 }
495 }
496
497 if( !footprint.IsEmpty() && fpid.Parse( footprint, true ) >= 0 )
498 {
499 wxString error;
500 error.Printf( _( "Invalid footprint ID in\nfile: '%s'\nline: %d\nofff: %d" ),
501 CurSource(), CurLineNumber(), CurOffset() );
502
503 THROW_IO_ERROR( error );
504 }
505
506 COMPONENT* component = new COMPONENT( fpid, ref, value, path, uuids );
507 component->SetName( name );
508 component->SetLibrary( library );
509 component->SetProperties( properties );
510 component->SetFields( fields );
511 component->SetHumanReadablePath( humanSheetPath );
512 component->SetComponentClassNames( componentClasses );
513 m_netlist->AddComponent( component );
514}
515
516
518{
519 /* Parses a section like
520 * (libpart (lib device) (part C)
521 * (aliases
522 * (alias Cxx)
523 * (alias Cyy))
524 * (description "Condensateur non polarise")
525 * (footprints
526 * (fp SM*)
527 * (fp C?)
528 * (fp C1-1))
529 * (fields
530 * (field (name Reference) C)
531 * (field (name Value) C))
532 * (pins
533 * (pin (num 1) (name ~) (type passive))
534 * (pin (num 2) (name ~) (type passive))))
535 *
536 * Currently footprints section/fp are read and data stored
537 * other fields (unused) are skipped
538 */
539 COMPONENT* component = NULL;
540 wxString libName;
541 wxString libPartName;
542 wxArrayString footprintFilters;
543 wxArrayString aliases;
544 int pinCount = 0;
545
546 // The last token read was libpart, so read the next token
547 while( (token = NextTok() ) != T_RIGHT )
548 {
549 if( token == T_LEFT )
550 token = NextTok();
551
552 switch( token )
553 {
554 case T_lib:
555 NeedSYMBOLorNUMBER();
556 libName = From_UTF8( CurText() );
557 NeedRIGHT();
558 break;
559
560 case T_part:
561 NeedSYMBOLorNUMBER();
562 libPartName = From_UTF8( CurText() );
563 NeedRIGHT();
564 break;
565
566 case T_footprints:
567 // Read all fp elements (footprint filter item)
568 while( (token = NextTok() ) != T_RIGHT )
569 {
570 if( token == T_LEFT )
571 token = NextTok();
572
573 if( token != T_fp )
574 Expecting( T_fp );
575
576 NeedSYMBOLorNUMBER();
577 footprintFilters.Add( From_UTF8( CurText() ) );
578 NeedRIGHT();
579 }
580 break;
581
582 case T_aliases:
583 while( (token = NextTok() ) != T_RIGHT )
584 {
585 if( token == T_LEFT )
586 token = NextTok();
587
588 if( token != T_alias )
589 Expecting( T_alias );
590
591 NeedSYMBOLorNUMBER();
592 aliases.Add( From_UTF8( CurText() ) );
593 NeedRIGHT();
594 }
595 break;
596
597 case T_pins:
598 while( (token = NextTok() ) != T_RIGHT )
599 {
600 if( token == T_LEFT )
601 token = NextTok();
602
603 if( token != T_pin )
604 Expecting( T_pin );
605
606 pinCount++;
607
608 skipCurrent();
609 }
610 break;
611
612 default:
613 // Skip not used data (i.e all other tokens)
614 skipCurrent();
615 break;
616 }
617 }
618
619 // Find all of the components that reference this component library part definition.
620 for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
621 {
622 component = m_netlist->GetComponent( i );
623
624 if( component->IsLibSource( libName, libPartName ) )
625 {
626 component->SetFootprintFilters( footprintFilters );
627 component->SetPinCount( pinCount );
628 }
629
630 for( unsigned jj = 0; jj < aliases.GetCount(); jj++ )
631 {
632 if( component->IsLibSource( libName, aliases[jj] ) )
633 {
634 component->SetFootprintFilters( footprintFilters );
635 component->SetPinCount( pinCount );
636 }
637 }
638
639 }
640}
const char * name
Definition: DXF_plotter.cpp:59
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)