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