KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcbnew/netlist_reader/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 <wx/log.h>
26
27#include <netlist_lexer.h> // netlist_lexer is common to Eeschema and Pcbnew
28#include <string_utils.h>
29#include <json_common.h>
30
31#include "pcb_netlist.h"
32#include "netlist_reader.h"
34
35using namespace NL_T;
36
37
39{
40 KICAD_NETLIST_PARSER parser( m_lineReader, m_netlist );
41
42 parser.Parse();
43
45 {
47
48 // Sort the component pins so they are in the same order as the legacy format. This
49 // is useful for comparing legacy and s-expression netlist dumps.
50 for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
51 m_netlist->GetComponent( i )->SortPins();
52 }
53}
54
55
56// KICAD_NETLIST_PARSER
58 NETLIST_LEXER( aReader )
59{
60 m_lineReader = aReader;
61 m_netlist = aNetlist;
62 token = T_NONE;
63}
64
65
67{
68 int curr_level = 0;
69
70 while( ( token = NextTok() ) != T_EOF )
71 {
72 if( token == T_LEFT )
73 curr_level--;
74
75 if( token == T_RIGHT )
76 {
77 curr_level++;
78
79 if( curr_level > 0 )
80 return;
81 }
82 }
83}
84
85
87{
88 int plevel = 0; // the count of ')' to read at end of file after parsing all sections
89
90 while( ( token = NextTok() ) != T_EOF )
91 {
92 if( token == T_LEFT )
93 token = NextTok();
94
95 switch( token )
96 {
97 case T_export: // The netlist starts here.
98 // nothing to do here, just increment the count of ')' to read at end of file
99 plevel++;
100 break;
101
102 case T_version: // The netlist starts here.
103 // version id not yet used: read it but does not use it
104 NextTok();
105 NeedRIGHT();
106 break;
107
108 case T_components: // The section comp starts here.
109 wxLogTrace( "CVPCB_PINCOUNT", wxT( "Parse: entering components section" ) );
110
111 while( ( token = NextTok() ) != T_EOF )
112 {
113 if( token == T_RIGHT )
114 break;
115 else if( token == T_LEFT )
116 token = NextTok();
117
118 if( token == T_comp ) // A component section found. Read it
120 }
121
122 break;
123
124 case T_groups: // The section groups starts here.
125 while( ( token = NextTok() ) != T_EOF )
126 {
127 if( token == T_RIGHT )
128 break;
129 else if( token == T_LEFT )
130 token = NextTok();
131
132 if( token == T_group ) // A group section found. Read it
133 parseGroup();
134 }
135
136 break;
137
138 case T_variants: // The section variants starts here.
139 while( ( token = NextTok() ) != T_EOF )
140 {
141 if( token == T_RIGHT )
142 break;
143 else if( token == T_LEFT )
144 token = NextTok();
145
146 if( token == T_variant ) // A variant section found. Read it
147 parseVariant();
148 }
149
150 break;
151
152 case T_nets: // The section nets starts here.
153 wxLogTrace( "CVPCB_PINCOUNT", wxT( "Parse: entering nets section" ) );
154
155 while( ( token = NextTok() ) != T_EOF )
156 {
157 if( token == T_RIGHT )
158 break;
159 else if( token == T_LEFT )
160 token = NextTok();
161
162 if( token == T_net ) // A net section if found. Read it
163 parseNet();
164 }
165
166 break;
167
168 case T_libparts: // The section libparts starts here.
169 wxLogTrace( "CVPCB_PINCOUNT", wxT( "Parse: entering libparts section" ) );
170
171 while( ( token = NextTok() ) != T_EOF )
172 {
173 if( token == T_RIGHT )
174 break;
175 else if( token == T_LEFT )
176 token = NextTok();
177
178 if( token == T_libpart ) // A libpart section if found. Read it
180 }
181
182 break;
183
184 case T_libraries: // The section libraries starts here.
185 // List of libraries in use.
186 // Not used here, just skip it
187 skipCurrent();
188 break;
189
190 case T_design: // The section design starts here.
191 // Not used (mainly they are comments), just skip it
192 skipCurrent();
193 break;
194
195 case T_RIGHT: // The closing parenthesis of the file.
196 plevel--;
197 break;
198
199 default:
200 skipCurrent();
201 break;
202 }
203 }
204
205 // Go back and apply group information to the components
206 m_netlist->ApplyGroupMembership();
207
208 if( plevel != 0 )
209 {
210 wxFAIL_MSG( wxString::Format( wxT( "KICAD_NETLIST_PARSER::Parse(): bad parenthesis "
211 "count (count = %d" ),
212 plevel ) );
213 }
214}
215
216
218{
219 /* Parses a section like
220 * (net (code 20) (name /PC-A0)
221 * (node (ref "BUS1") (pin "62)")
222 * (node (ref "U3") ("pin 3") (pin_function "clock"))
223 * (node (ref "U9") (pin "M6") (pin_function "reset")))
224 */
225
226 wxString code;
227 wxString name;
228 wxString reference;
229 wxString pin_number;
230 wxString pin_function;
231 wxString pin_type;
232
233 // The token net was read, so the next data is (code <number>)
234 while( (token = NextTok() ) != T_EOF )
235 {
236 if( token == T_RIGHT )
237 break;
238 else if( token == T_LEFT )
239 token = NextTok();
240
241 switch( token )
242 {
243 case T_code:
244 NeedSYMBOLorNUMBER();
245 code = From_UTF8( CurText() );
246 NeedRIGHT();
247 break;
248
249 case T_name:
250 NeedSYMBOLorNUMBER();
251 name = From_UTF8( CurText() );
252 NeedRIGHT();
253 break;
254
255 case T_node:
256 // By default: no pin function or type.
257 pin_function.Clear();
258 pin_type.Clear();
259
260 while( (token = NextTok() ) != T_EOF )
261 {
262 if( token == T_RIGHT )
263 break;
264 else if( token == T_LEFT )
265 token = NextTok();
266
267 switch( token )
268 {
269 case T_ref:
270 NeedSYMBOLorNUMBER();
271 reference = From_UTF8( CurText() );
272 NeedRIGHT();
273 break;
274
275 case T_pin:
276 NeedSYMBOLorNUMBER();
277 pin_number = From_UTF8( CurText() );
278 NeedRIGHT();
279 break;
280
281 case T_pinfunction:
282 NeedSYMBOLorNUMBER();
283 pin_function = From_UTF8( CurText() );
284 NeedRIGHT();
285 break;
286
287 case T_pintype:
288 NeedSYMBOLorNUMBER();
289 pin_type = From_UTF8( CurText() );
290 NeedRIGHT();
291 break;
292
293 default:
294 skipCurrent();
295 break;
296 }
297 }
298
299 // Don't assume component will be found; it might be "DNP" or "Exclude from board".
300 if( COMPONENT* component = m_netlist->GetComponentByReference( reference ) )
301 {
302 if( strtol( code.c_str(), nullptr, 10 ) >= 1 )
303 {
304 if( name.IsEmpty() ) // Give a dummy net name like N-000009
305 name = wxT("N-00000") + code;
306
307 component->AddNet( pin_number, name, pin_function, pin_type );
308 }
309 }
310
311 break;
312
313 default:
314 skipCurrent();
315 break;
316 }
317 }
318}
319
320
322{
323 /* Parses a section like
324 * (comp (ref P1)
325 * (value DB25FEMALE)
326 * (footprint DB25FC)
327 * (libsource (lib conn) (part DB25))
328 * (property (name PINCOUNT) (value 25))
329 * (sheetpath (names /) (tstamps /))
330 * (component_classes (class (name "CLASS")))
331 * (tstamp 68183921-93a5-49ac-91b0-49d05a0e1647))
332 *
333 * other fields (unused) are skipped
334 * A component need a reference, value, footprint name and a full time stamp
335 * The full time stamp is the sheetpath time stamp + the component time stamp
336 */
337 LIB_ID fpid;
338 wxString footprint;
339 wxString ref;
340 wxString value;
341 wxString library;
342 wxString name;
343 wxString humanSheetPath;
344 KIID_PATH path;
345
346 std::vector<KIID> uuids;
347 std::map<wxString, wxString> properties;
348 nlohmann::ordered_map<wxString, wxString> fields;
349 std::unordered_set<wxString> componentClasses;
350
351 bool duplicatePinsAreJumpers = false;
352 std::vector<std::set<wxString>> jumperPinGroups;
353
354 std::vector<COMPONENT::UNIT_INFO> parsedUnits;
355 std::vector<COMPONENT_VARIANT> parsedVariants;
356
357 // The token comp was read, so the next data is (ref P1)
358 while( (token = NextTok() ) != T_RIGHT )
359 {
360 if( token == T_LEFT )
361 token = NextTok();
362
363 switch( token )
364 {
365 case T_ref:
366 NeedSYMBOLorNUMBER();
367 ref = From_UTF8( CurText() );
368 NeedRIGHT();
369 break;
370
371 case T_value:
372 NeedSYMBOLorNUMBER();
373 value = From_UTF8( CurText() );
374 NeedRIGHT();
375 break;
376
377 case T_footprint:
378 NeedSYMBOLorNUMBER();
379 footprint = FromUTF8();
380 NeedRIGHT();
381 break;
382
383 case T_libsource:
384 // Read libsource
385 while( ( token = NextTok() ) != T_RIGHT )
386 {
387 if( token == T_LEFT )
388 token = NextTok();
389
390 if( token == T_lib )
391 {
392 NeedSYMBOLorNUMBER();
393 library = From_UTF8( CurText() );
394 NeedRIGHT();
395 }
396 else if( token == T_part )
397 {
398 NeedSYMBOLorNUMBER();
399 name = From_UTF8( CurText() );
400 NeedRIGHT();
401 }
402 else if( token == T_description )
403 {
404 NeedSYMBOLorNUMBER();
405 NeedRIGHT();
406 }
407 else
408 {
409 Expecting( "part, lib or description" );
410 }
411 }
412 wxLogTrace( "CVPCB_PINCOUNT", wxT( "parseComponent: ref='%s' libsource='%s:%s'" ),
413 ref, library, name );
414 break;
415
416 case T_property:
417 {
418 wxString propName;
419 wxString propValue;
420
421 while( (token = NextTok() ) != T_RIGHT )
422 {
423 if( token == T_LEFT )
424 token = NextTok();
425
426 if( token == T_name )
427 {
428 NeedSYMBOLorNUMBER();
429 propName = From_UTF8( CurText() );
430 NeedRIGHT();
431 }
432 else if( token == T_value )
433 {
434 NeedSYMBOLorNUMBER();
435 propValue = From_UTF8( CurText() );
436 NeedRIGHT();
437 }
438 else
439 {
440 Expecting( "name or value" );
441 }
442 }
443
444 if( !propName.IsEmpty() )
445 properties[propName] = std::move( propValue );
446 break;
447 }
448
449 case T_fields:
450 while( ( token = NextTok() ) != T_RIGHT )
451 {
452 if( token == T_LEFT )
453 token = NextTok();
454
455 if( token == T_field )
456 {
457 wxString fieldName;
458 wxString fieldValue;
459
460 while( ( token = NextTok() ) != T_RIGHT )
461 {
462 if( token == T_LEFT )
463 token = NextTok();
464
465 if( token == T_name )
466 {
467 NeedSYMBOLorNUMBER();
468 fieldName = From_UTF8( CurText() );
469 NeedRIGHT();
470 }
471 else if( token == T_STRING )
472 {
473 fieldValue = From_UTF8( CurText() );
474 }
475 }
476
477 if( !fieldName.IsEmpty() )
478 fields[fieldName] = std::move( fieldValue );
479 }
480 else
481 {
482 Expecting( "field" );
483 }
484 }
485 break;
486
487 case T_sheetpath:
488 while( ( token = NextTok() ) != T_EOF )
489 {
490 if( token == T_names )
491 {
492 NeedSYMBOLorNUMBER();
493 humanSheetPath = From_UTF8( CurText() );
494 NeedRIGHT();
495 }
496
497 if( token == T_tstamps )
498 {
499 NeedSYMBOLorNUMBER();
500 path = KIID_PATH( From_UTF8( CurText() ) );
501 NeedRIGHT();
502 break;
503 }
504 }
505
506 NeedRIGHT();
507
508 break;
509
510 case T_tstamps:
511 while( ( token = NextTok() ) != T_EOF )
512 {
513 if( token == T_RIGHT )
514 break;
515
516 uuids.emplace_back( From_UTF8( CurText() ) );
517 }
518
519 break;
520
521 case T_units:
522 {
523 // Parse a section like:
524 // (units (unit (ref "U1A") (name "A") (pins (pin "1") (pin "2"))))
525 while( ( token = NextTok() ) != T_RIGHT )
526 {
527 if( token == T_LEFT )
528 token = NextTok();
529
530 if( token == T_unit )
531 {
532 COMPONENT::UNIT_INFO info;
533
534 while( ( token = NextTok() ) != T_RIGHT )
535 {
536 if( token == T_LEFT )
537 token = NextTok();
538
539 switch( token )
540 {
541 case T_name:
542 NeedSYMBOLorNUMBER();
543 info.m_unitName = From_UTF8( CurText() );
544 NeedRIGHT();
545 break;
546
547 case T_pins:
548 while( ( token = NextTok() ) != T_RIGHT )
549 {
550 if( token == T_LEFT )
551 token = NextTok();
552
553 if( token == T_pin )
554 {
555 wxString pinNum;
556
557 // Parse pins in attribute style: (pin (num "1"))
558 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
559 {
560 if( token == T_LEFT )
561 token = NextTok();
562
563 if( token == T_num )
564 {
565 NeedSYMBOLorNUMBER();
566 pinNum = From_UTF8( CurText() );
567 NeedRIGHT();
568 }
569 else
570 {
571 // ignore other subfields of pin
572 // leave bare tokens untouched; they are not supported in this context
573 }
574 }
575
576 if( !pinNum.IsEmpty() )
577 info.m_pins.emplace_back( pinNum );
578 }
579 else
580 {
581 skipCurrent();
582 }
583 }
584 break;
585
586 default:
587 skipCurrent();
588 break;
589 }
590 }
591
592 parsedUnits.push_back( info );
593 }
594 else
595 {
596 skipCurrent();
597 }
598 }
599
600 break;
601 }
602
603 case T_component_classes:
604 while( ( token = NextTok() ) != T_RIGHT )
605 {
606 if( token != T_LEFT )
607 Expecting( T_LEFT );
608
609 if( ( token = NextTok() ) != T_class )
610 Expecting( T_class );
611
612 NeedSYMBOLorNUMBER();
613 componentClasses.insert( From_UTF8( CurText() ) );
614 NeedRIGHT();
615 }
616
617 break;
618
619 case T_duplicate_pin_numbers_are_jumpers:
620 {
621 NeedSYMBOLorNUMBER();
622 duplicatePinsAreJumpers = From_UTF8( CurText() ) == wxT( "1" );
623 NeedRIGHT();
624 break;
625 }
626
627 case T_jumper_pin_groups:
628 {
629 std::set<wxString>* currentGroup = nullptr;
630
631 for( token = NextTok(); currentGroup || token != T_RIGHT; token = NextTok() )
632 {
633 if( token == T_LEFT )
634 token = NextTok();
635
636 switch( token )
637 {
638 case T_group:
639 currentGroup = &jumperPinGroups.emplace_back();
640 break;
641
642 case T_pin:
643 {
644 NeedSYMBOLorNUMBER();
645 wxString padName = From_UTF8( CurText() );
646 NeedRIGHT();
647 wxCHECK2( currentGroup, continue );
648 currentGroup->insert( padName );
649 break;
650 }
651
652 case T_RIGHT:
653 currentGroup = nullptr;
654 break;
655
656 default:
657 Expecting( "group or pin" );
658 }
659 }
660
661 break;
662 }
663
664 case T_variants:
665 {
666 while( ( token = NextTok() ) != T_RIGHT )
667 {
668 if( token == T_LEFT )
669 token = NextTok();
670
671 if( token != T_variant )
672 {
673 skipCurrent();
674 continue;
675 }
676
677 COMPONENT_VARIANT variant;
678
679 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
680 {
681 if( token == T_LEFT )
682 token = NextTok();
683
684 switch( token )
685 {
686 case T_name:
687 NeedSYMBOLorNUMBER();
688 variant.m_name = From_UTF8( CurText() );
689 NeedRIGHT();
690 break;
691
692 case T_property:
693 {
694 wxString propName;
695 wxString propValue;
696 bool hasValue = false;
697
698 while( ( token = NextTok() ) != T_RIGHT )
699 {
700 if( token == T_LEFT )
701 token = NextTok();
702
703 if( token == T_name )
704 {
705 NeedSYMBOLorNUMBER();
706 propName = From_UTF8( CurText() );
707 NeedRIGHT();
708 }
709 else if( token == T_value )
710 {
711 NeedSYMBOLorNUMBER();
712 propValue = From_UTF8( CurText() );
713 hasValue = true;
714 NeedRIGHT();
715 }
716 else
717 {
718 Expecting( "name or value" );
719 }
720 }
721
722 if( propName.IsEmpty() )
723 break;
724
725 bool propBool = true;
726
727 if( hasValue )
728 {
729 wxString normalized = propValue;
730 normalized.MakeLower();
731
732 if( normalized == wxT( "0" ) || normalized == wxT( "false" ) )
733 propBool = false;
734 else if( normalized == wxT( "1" ) || normalized == wxT( "true" ) )
735 propBool = true;
736 else
737 propBool = !propValue.IsEmpty();
738 }
739
740 if( propName.CmpNoCase( wxT( "dnp" ) ) == 0 )
741 {
742 variant.m_dnp = propBool;
743 variant.m_hasDnp = true;
744 }
745 else if( propName.CmpNoCase( wxT( "exclude_from_bom" ) ) == 0 )
746 {
747 variant.m_excludedFromBOM = propBool;
748 variant.m_hasExcludedFromBOM = true;
749 }
750 else if( propName.CmpNoCase( wxT( "exclude_from_sim" ) ) == 0 )
751 {
752 variant.m_excludedFromSim = propBool;
753 variant.m_hasExcludedFromSim = true;
754 }
755 else if( propName.CmpNoCase( wxT( "exclude_from_pos_files" ) ) == 0 )
756 {
757 variant.m_excludedFromPosFiles = propBool;
758 variant.m_hasExcludedFromPosFiles = true;
759 }
760
761 break;
762 }
763
764 case T_fields:
765 while( ( token = NextTok() ) != T_RIGHT )
766 {
767 if( token == T_LEFT )
768 token = NextTok();
769
770 if( token == T_field )
771 {
772 wxString fieldName;
773 wxString fieldValue;
774
775 while( ( token = NextTok() ) != T_RIGHT )
776 {
777 if( token == T_LEFT )
778 token = NextTok();
779
780 if( token == T_name )
781 {
782 NeedSYMBOLorNUMBER();
783 fieldName = From_UTF8( CurText() );
784 NeedRIGHT();
785 }
786 else if( token == T_value )
787 {
788 NeedSYMBOLorNUMBER();
789 fieldValue = From_UTF8( CurText() );
790 NeedRIGHT();
791 }
792 else if( token == T_STRING )
793 {
794 fieldValue = From_UTF8( CurText() );
795 }
796 }
797
798 if( !fieldName.IsEmpty() )
799 variant.m_fields[fieldName] = std::move( fieldValue );
800 }
801 else
802 {
803 Expecting( "field" );
804 }
805 }
806 break;
807
808 default:
809 skipCurrent();
810 break;
811 }
812 }
813
814 if( !variant.m_name.IsEmpty() )
815 parsedVariants.push_back( std::move( variant ) );
816 }
817
818 break;
819 }
820
821 default:
822 // Skip not used data (i.e all other tokens)
823 skipCurrent();
824 break;
825 }
826 }
827
828 if( !footprint.IsEmpty() && fpid.Parse( footprint, true ) >= 0 )
829 {
830 wxString error;
831 error.Printf( _( "Invalid footprint ID in\nfile: '%s'\nline: %d\noffset: %d" ),
832 CurSource(), CurLineNumber(), CurOffset() );
833
834 THROW_IO_ERROR( error );
835 }
836
837 COMPONENT* component = new COMPONENT( fpid, ref, value, path, uuids );
838 component->SetName( name );
839 component->SetLibrary( library );
840 component->SetProperties( properties );
841 component->SetFields( fields );
842 component->SetHumanReadablePath( humanSheetPath );
843 component->SetComponentClassNames( componentClasses );
844 component->SetDuplicatePadNumbersAreJumpers( duplicatePinsAreJumpers );
845 std::ranges::copy( jumperPinGroups, std::inserter( component->JumperPadGroups(),
846 component->JumperPadGroups().end() ) );
847 component->SetUnitInfo( parsedUnits );
848
849 for( const COMPONENT_VARIANT& variant : parsedVariants )
850 component->AddVariant( variant );
851
852 m_netlist->AddComponent( component );
853}
854
855
857{
858 /* Parses a section like
859 * (groups
860 * (group (name "") (lib_id "DesignBlock:Block") (uuid "7b1488be-4c43-4004-94fc-e4a26dda8f5b")
861 * (members
862 * (member (uuid "dfef752d-e203-4feb-91de-483b44bc4062"))
863 */
864
865 wxString name;
866 KIID uuid;
867 wxString libId; // Design block library link
868 std::vector<KIID> members;
869
870 // The token net was read, so the next data is (code <number>)
871 while( (token = NextTok() ) != T_EOF )
872 {
873 if( token == T_RIGHT )
874 break;
875 else if( token == T_LEFT )
876 token = NextTok();
877
878 switch( token )
879 {
880 case T_name:
881 NeedSYMBOLorNUMBER();
882 name = From_UTF8( CurText() );
883 NeedRIGHT();
884 break;
885
886 case T_uuid:
887 NeedSYMBOLorNUMBER();
888 uuid = From_UTF8( CurText() );
889 NeedRIGHT();
890 break;
891
892 case T_lib_id:
893 NeedSYMBOLorNUMBER();
894 libId = FromUTF8();
895 NeedRIGHT();
896 break;
897
898 case T_members:
899 while( ( token = NextTok() ) != T_RIGHT )
900 {
901 if( token == T_LEFT )
902 token = NextTok();
903
904 if( token == T_member )
905 {
906 wxString memberUuid;
907
908 while( ( token = NextTok() ) != T_RIGHT )
909 {
910 if( token == T_LEFT )
911 token = NextTok();
912
913 if( token == T_uuid )
914 {
915 NeedSYMBOLorNUMBER();
916 memberUuid = From_UTF8( CurText() );
917 NeedRIGHT();
918 }
919 else
920 {
921 Expecting( "uuid" );
922 }
923 }
924
925 members.emplace_back( memberUuid );
926 }
927 else
928 {
929 Expecting( "member" );
930 }
931
932 }
933 break;
934
935 default:
936 skipCurrent();
937 break;
938 }
939 }
940
941 LIB_ID groupLibId;
942
943 if( !libId.IsEmpty() && groupLibId.Parse( libId, true ) >= 0 )
944 {
945 wxString error;
946 error.Printf( _( "Invalid lib_id ID in\nfile: '%s'\nline: %d\noffset: %d" ), CurSource(), CurLineNumber(),
947 CurOffset() );
948
949 THROW_IO_ERROR( error );
950 }
951
952 NETLIST_GROUP* group = new NETLIST_GROUP{ std::move( name ), std::move( uuid ), std::move( groupLibId ),
953 std::move( members ) };
954 m_netlist->AddGroup( group );
955}
956
957
959{
960 // Parses a variant section like:
961 // (variant (name "Variant1") (description "First variant"))
962
963 wxString name;
964 wxString description;
965
966 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
967 {
968 if( token == T_LEFT )
969 token = NextTok();
970
971 switch( token )
972 {
973 case T_name:
974 NeedSYMBOLorNUMBER();
975 name = From_UTF8( CurText() );
976 NeedRIGHT();
977 break;
978
979 case T_description:
980 NeedSYMBOLorNUMBER();
981 description = From_UTF8( CurText() );
982 NeedRIGHT();
983 break;
984
985 default:
986 skipCurrent();
987 break;
988 }
989 }
990
991 if( !name.IsEmpty() )
992 m_netlist->AddVariant( name, description );
993}
994
995
997{
998 /* Parses a section like
999 * (libpart (lib device) (part C)
1000 * (aliases
1001 * (alias Cxx)
1002 * (alias Cyy))
1003 * (description "Condensateur non polarise")
1004 * (footprints
1005 * (fp SM*)
1006 * (fp C?)
1007 * (fp C1-1))
1008 * (fields
1009 * (field (name Reference) C)
1010 * (field (name Value) C))
1011 * (pins
1012 * (pin (num 1) (name ~) (type passive))
1013 * (pin (num 2) (name ~) (type passive))))
1014 *
1015 * Currently footprints section/fp are read and data stored
1016 * other fields (unused) are skipped
1017 */
1018 COMPONENT* component = NULL;
1019 wxString libName;
1020 wxString libPartName;
1021 wxArrayString footprintFilters;
1022 wxArrayString aliases;
1023 int pinCount = 0;
1024
1025 // The last token read was libpart, so read the next token
1026 wxLogTrace( "CVPCB_PINCOUNT", wxT( "parseLibPartList: begin libpart" ) );
1027 while( (token = NextTok() ) != T_RIGHT )
1028 {
1029 if( token == T_LEFT )
1030 token = NextTok();
1031
1032 switch( token )
1033 {
1034 case T_lib:
1035 NeedSYMBOLorNUMBER();
1036 libName = From_UTF8( CurText() );
1037 NeedRIGHT();
1038 break;
1039
1040 case T_part:
1041 NeedSYMBOLorNUMBER();
1042 libPartName = From_UTF8( CurText() );
1043 NeedRIGHT();
1044 break;
1045
1046 case T_footprints:
1047 // Read all fp elements (footprint filter item)
1048 while( (token = NextTok() ) != T_RIGHT )
1049 {
1050 if( token == T_LEFT )
1051 token = NextTok();
1052
1053 if( token != T_fp )
1054 Expecting( T_fp );
1055
1056 token = NextTok();
1057
1058 // Accept an empty (fp) sexpr. We do write them out.
1059 if( token == T_RIGHT )
1060 continue;
1061
1062 if( !IsSymbol( token ) && !IsNumber( token ) )
1063 Expecting( "footprint ID" );
1064
1065 footprintFilters.Add( From_UTF8( CurText() ) );
1066 NeedRIGHT();
1067 }
1068 break;
1069
1070 case T_aliases:
1071 while( (token = NextTok() ) != T_RIGHT )
1072 {
1073 if( token == T_LEFT )
1074 token = NextTok();
1075
1076 if( token != T_alias )
1077 Expecting( T_alias );
1078
1079 NeedSYMBOLorNUMBER();
1080 aliases.Add( From_UTF8( CurText() ) );
1081 NeedRIGHT();
1082 }
1083 break;
1084
1085 case T_pins:
1086 wxLogTrace( "CVPCB_PINCOUNT", wxT( "parseLibPartList: entering pins for '%s:%s'" ),
1087 libName, libPartName );
1088 while( (token = NextTok() ) != T_RIGHT )
1089 {
1090 if( token == T_LEFT )
1091 token = NextTok();
1092
1093 if( token != T_pin )
1094 Expecting( T_pin );
1095
1096 pinCount++;
1097 wxLogTrace( "CVPCB_PINCOUNT", wxT( "parseLibPartList: pin #%d for '%s:%s'" ),
1098 pinCount, libName, libPartName );
1099
1100 skipCurrent();
1101 }
1102 wxLogTrace( "CVPCB_PINCOUNT", wxT( "Parsed libpart '%s:%s' pins => pinCount=%d" ),
1103 libName, libPartName, pinCount );
1104 break;
1105
1106 default:
1107 // Skip not used data (i.e all other tokens)
1108 skipCurrent();
1109 break;
1110 }
1111 }
1112
1113 // Find all of the components that reference this component library part definition.
1114 wxLogTrace( "CVPCB_PINCOUNT", wxT( "parseLibPartList: assigning pinCount=%d for libpart '%s:%s'" ),
1115 pinCount, libName, libPartName );
1116 for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
1117 {
1118 component = m_netlist->GetComponent( i );
1119
1120 if( component->IsLibSource( libName, libPartName ) )
1121 {
1122 component->SetFootprintFilters( footprintFilters );
1123 component->SetPinCount( pinCount );
1124 wxLogTrace( "CVPCB_PINCOUNT", wxT( "Assign pinCount=%d to component ref='%s' part='%s:%s'" ),
1125 pinCount, component->GetReference(), libName, libPartName );
1126 }
1127
1128 for( unsigned jj = 0; jj < aliases.GetCount(); jj++ )
1129 {
1130 if( component->IsLibSource( libName, aliases[jj] ) )
1131 {
1132 component->SetFootprintFilters( footprintFilters );
1133 component->SetPinCount( pinCount );
1134 wxLogTrace( "CVPCB_PINCOUNT",
1135 wxT( "Assign pinCount=%d to component ref='%s' via alias='%s:%s'" ),
1136 pinCount, component->GetReference(), libName, aliases[jj] );
1137 }
1138 }
1139
1140 }
1141}
const char * name
Store all of the related component information found in a netlist.
void SetLibrary(const wxString &aLibrary)
const wxString & GetReference() const
void AddVariant(const COMPONENT_VARIANT &aVariant)
void SetProperties(std::map< wxString, wxString > aProps)
void SetPinCount(int aPinCount)
void SetUnitInfo(const std::vector< UNIT_INFO > &aUnits)
bool IsLibSource(const wxString &aLibrary, const wxString &aName) const
void SetFootprintFilters(const wxArrayString &aFilters)
void SetFields(nlohmann::ordered_map< wxString, wxString > aFields)
void SetHumanReadablePath(const wxString &aPath)
void SetDuplicatePadNumbersAreJumpers(bool aEnabled)
void SetComponentClassNames(const std::unordered_set< wxString > &aClassNames)
std::vector< std::set< wxString > > & JumperPadGroups()
void SetName(const wxString &aName)
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 parseVariant()
Parse a variant section (variant (name "VariantName") (description "Description"))
void parseNet()
Parse a net section (net (code 20) (name /PC-A0) (node (ref BUS1) (pin 62)) (node (ref U3) (pin 3)) (...
void parseLibPartList()
Read the section "libparts" in the netlist: (libparts (libpart (lib device) (part C) (description "Co...
void parseGroup()
Parse a group section (group (name "GroupName") (member (uuid "..."))))
void skipCurrent()
Skip the current token level, i.e search for the RIGHT parenthesis which closes the current descripti...
NETLIST * m_netlist
The netlist to parse into. Not owned.
virtual void LoadNetlist() override
Load the contents of the netlist file into aNetlist.
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:52
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition richio.h:66
CMP_READER * m_footprintReader
The reader used to load the footprint links. If NULL, footprint links are not read.
LINE_READER * m_lineReader
The line reader of the netlist.
NETLIST * m_netlist
The net list to read the file(s) into.
Store information read from a netlist along with the flags used to update the NETLIST in the BOARD.
#define _(s)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
static bool IsNumber(char x)
wxString From_UTF8(const char *cstring)
bool m_hasExcludedFromPosFiles
nlohmann::ordered_map< wxString, wxString > m_fields
std::string path