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 COMPONENT* component = NULL;
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 if( strtol( code.c_str(), NULL, 10 ) >= 1 )
261 {
262 if( name.IsEmpty() ) // Give a dummy net name like N-000009
263 name = wxT("N-00000") + code;
264
265 component = m_netlist->GetComponentByReference( reference );
266
267 // Cannot happen if the netlist is valid.
268 if( component == NULL )
269 {
270 wxString msg;
271 msg.Printf( _( "Cannot find component with ref '%s' in netlist." ),
272 reference );
275 }
276
277 component->AddNet( pin_number, name, pin_function, pin_type );
278 }
279 break;
280
281 default:
282 skipCurrent();
283 break;
284 }
285 }
286}
287
288
290{
291 /* Parses a section like
292 * (comp (ref P1)
293 * (value DB25FEMALE)
294 * (footprint DB25FC)
295 * (libsource (lib conn) (part DB25))
296 * (property (name PINCOUNT) (value 25))
297 * (sheetpath (names /) (tstamps /))
298 * (tstamp 68183921-93a5-49ac-91b0-49d05a0e1647))
299 *
300 * other fields (unused) are skipped
301 * A component need a reference, value, footprint name and a full time stamp
302 * The full time stamp is the sheetpath time stamp + the component time stamp
303 */
304 LIB_ID fpid;
305 wxString footprint;
306 wxString ref;
307 wxString value;
308 wxString library;
309 wxString name;
311
312 std::vector<KIID> uuids;
313 std::map<wxString, wxString> properties;
314 nlohmann::ordered_map<wxString, wxString> fields;
315
316 // The token comp was read, so the next data is (ref P1)
317 while( (token = NextTok() ) != T_RIGHT )
318 {
319 if( token == T_LEFT )
320 token = NextTok();
321
322 switch( token )
323 {
324 case T_ref:
325 NeedSYMBOLorNUMBER();
326 ref = From_UTF8( CurText() );
327 NeedRIGHT();
328 break;
329
330 case T_value:
331 NeedSYMBOLorNUMBER();
332 value = From_UTF8( CurText() );
333 NeedRIGHT();
334 break;
335
336 case T_footprint:
337 NeedSYMBOLorNUMBER();
338 footprint = FromUTF8();
339 NeedRIGHT();
340 break;
341
342 case T_libsource:
343 // Read libsource
344 while( ( token = NextTok() ) != T_RIGHT )
345 {
346 if( token == T_LEFT )
347 token = NextTok();
348
349 if( token == T_lib )
350 {
351 NeedSYMBOLorNUMBER();
352 library = From_UTF8( CurText() );
353 NeedRIGHT();
354 }
355 else if( token == T_part )
356 {
357 NeedSYMBOLorNUMBER();
358 name = From_UTF8( CurText() );
359 NeedRIGHT();
360 }
361 else if( token == T_description )
362 {
363 NeedSYMBOLorNUMBER();
364 NeedRIGHT();
365 }
366 else
367 {
368 Expecting( "part, lib or description" );
369 }
370 }
371 break;
372
373 case T_property:
374 {
375 wxString propName;
376 wxString propValue;
377
378 while( (token = NextTok() ) != T_RIGHT )
379 {
380 if( token == T_LEFT )
381 token = NextTok();
382
383 if( token == T_name )
384 {
385 NeedSYMBOLorNUMBER();
386 propName = From_UTF8( CurText() );
387 NeedRIGHT();
388 }
389 else if( token == T_value )
390 {
391 NeedSYMBOLorNUMBER();
392 propValue = From_UTF8( CurText() );
393 NeedRIGHT();
394 }
395 else
396 {
397 Expecting( "name or value" );
398 }
399 }
400
401 if( !propName.IsEmpty() )
402 properties[ propName ] = propValue;
403 }
404 break;
405
406 case T_fields:
407
408 // Read fields
409 while( ( token = NextTok() ) != T_RIGHT )
410 {
411 if( token == T_LEFT )
412 token = NextTok();
413
414 if( token == T_field )
415 {
416 wxString fieldName;
417 wxString fieldValue;
418
419 while( ( token = NextTok() ) != T_RIGHT )
420 {
421 if( token == T_LEFT )
422 token = NextTok();
423
424 if( token == T_name )
425 {
426 NeedSYMBOLorNUMBER();
427 fieldName = From_UTF8( CurText() );
428 NeedRIGHT();
429 }
430 else if( token == T_STRING )
431 {
432 fieldValue = CurText();
433 }
434 }
435
436 if( !fieldName.IsEmpty() )
437 fields[fieldName] = fieldValue;
438 }
439 else
440 {
441 Expecting( "field" );
442 }
443 }
444 break;
445
446 case T_sheetpath:
447 while( ( token = NextTok() ) != T_EOF )
448 {
449 if( token == T_tstamps )
450 break;
451 }
452
453 NeedSYMBOLorNUMBER();
454 path = KIID_PATH( From_UTF8( CurText() ) );
455 NeedRIGHT();
456 NeedRIGHT();
457 break;
458
459 case T_tstamps:
460 while( ( token = NextTok() ) != T_EOF )
461 {
462 if( token == T_RIGHT )
463 break;
464
465 uuids.emplace_back( From_UTF8( CurText() ) );
466 }
467
468 break;
469
470 default:
471 // Skip not used data (i.e all other tokens)
472 skipCurrent();
473 break;
474 }
475 }
476
477 if( !footprint.IsEmpty() && fpid.Parse( footprint, true ) >= 0 )
478 {
479 wxString error;
480 error.Printf( _( "Invalid footprint ID in\nfile: '%s'\nline: %d\noffset: %d" ),
481 CurSource(), CurLineNumber(), CurOffset() );
482
483 THROW_IO_ERROR( error );
484 }
485
486 COMPONENT* component = new COMPONENT( fpid, ref, value, path, uuids );
487 component->SetName( name );
488 component->SetLibrary( library );
489 component->SetProperties( properties );
490 component->SetFields( fields );
491 m_netlist->AddComponent( component );
492}
493
494
496{
497 /* Parses a section like
498 * (libpart (lib device) (part C)
499 * (aliases
500 * (alias Cxx)
501 * (alias Cyy))
502 * (description "Condensateur non polarise")
503 * (footprints
504 * (fp SM*)
505 * (fp C?)
506 * (fp C1-1))
507 * (fields
508 * (field (name Reference) C)
509 * (field (name Value) C))
510 * (pins
511 * (pin (num 1) (name ~) (type passive))
512 * (pin (num 2) (name ~) (type passive))))
513 *
514 * Currently footprints section/fp are read and data stored
515 * other fields (unused) are skipped
516 */
517 COMPONENT* component = NULL;
518 wxString libName;
519 wxString libPartName;
520 wxArrayString footprintFilters;
521 wxArrayString aliases;
522 int pinCount = 0;
523
524 // The last token read was libpart, so read the next token
525 while( (token = NextTok() ) != T_RIGHT )
526 {
527 if( token == T_LEFT )
528 token = NextTok();
529
530 switch( token )
531 {
532 case T_lib:
533 NeedSYMBOLorNUMBER();
534 libName = From_UTF8( CurText() );
535 NeedRIGHT();
536 break;
537
538 case T_part:
539 NeedSYMBOLorNUMBER();
540 libPartName = From_UTF8( CurText() );
541 NeedRIGHT();
542 break;
543
544 case T_footprints:
545 // Read all fp elements (footprint filter item)
546 while( (token = NextTok() ) != T_RIGHT )
547 {
548 if( token == T_LEFT )
549 token = NextTok();
550
551 if( token != T_fp )
552 Expecting( T_fp );
553
554 NeedSYMBOLorNUMBER();
555 footprintFilters.Add( From_UTF8( CurText() ) );
556 NeedRIGHT();
557 }
558 break;
559
560 case T_aliases:
561 while( (token = NextTok() ) != T_RIGHT )
562 {
563 if( token == T_LEFT )
564 token = NextTok();
565
566 if( token != T_alias )
567 Expecting( T_alias );
568
569 NeedSYMBOLorNUMBER();
570 aliases.Add( From_UTF8( CurText() ) );
571 NeedRIGHT();
572 }
573 break;
574
575 case T_pins:
576 while( (token = NextTok() ) != T_RIGHT )
577 {
578 if( token == T_LEFT )
579 token = NextTok();
580
581 if( token != T_pin )
582 Expecting( T_pin );
583
584 pinCount++;
585
586 skipCurrent();
587 }
588 break;
589
590 default:
591 // Skip not used data (i.e all other tokens)
592 skipCurrent();
593 break;
594 }
595 }
596
597 // Find all of the components that reference this component library part definition.
598 for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
599 {
600 component = m_netlist->GetComponent( i );
601
602 if( component->IsLibSource( libName, libPartName ) )
603 {
604 component->SetFootprintFilters( footprintFilters );
605 component->SetPinCount( pinCount );
606 }
607
608 for( unsigned jj = 0; jj < aliases.GetCount(); jj++ )
609 {
610 if( component->IsLibSource( libName, aliases[jj] ) )
611 {
612 component->SetFootprintFilters( footprintFilters );
613 component->SetPinCount( pinCount );
614 }
615 }
616
617 }
618}
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 AddNet(const wxString &aPinName, const wxString &aNetName, const wxString &aPinFunction, const wxString &aPinType)
Definition: pcb_netlist.h:104
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
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: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
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:165
wxString From_UTF8(const char *cstring)