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