KiCad PCB EDA Suite
kicad_netlist_reader.cpp
Go to the documentation of this file.
1 
4 /*
5  * This program source code file is part of KiCad, a free EDA CAD application.
6  *
7  * Copyright (C) 1992-2011 Jean-Pierre Charras.
8  * Copyright (C) 1992-2020 KiCad Developers, see change_log.txt for contributors.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, you may find one here:
22  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23  * or you may search the http://www.gnu.org website for the version 2 license,
24  * or you may write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26  */
27 
28 #include <netlist_lexer.h> // netlist_lexer is common to Eeschema and Pcbnew
29 #include <macros.h>
30 
31 #include "pcb_netlist.h"
32 #include "netlist_reader.h"
33 
34 using namespace NL_T;
35 
36 
38 {
39  m_parser->Parse();
40 
41  if( m_footprintReader )
42  {
43  m_footprintReader->Load( m_netlist );
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++ )
48  m_netlist->GetComponent( i )->SortPins();
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
114  parseComponent();
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( "KICAD_NETLIST_PARSER::Parse(): bad parenthesis "
171  "count (count = %d", plevel ) );
172  }
173 }
174 
175 
177 {
178  /* Parses a section like
179  * (net (code 20) (name /PC-A0)
180  * (node (ref "BUS1") (pin "62)")
181  * (node (ref "U3") ("pin 3") (pin_function "clock"))
182  * (node (ref "U9") (pin "M6") (pin_function "reset")))
183  */
184 
185  COMPONENT* component = NULL;
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  if( strtol( code.c_str(), NULL, 10 ) >= 1 )
260  {
261  if( name.IsEmpty() ) // Give a dummy net name like N-000009
262  name = wxT("N-00000") + code;
263 
264  component = m_netlist->GetComponentByReference( reference );
265 
266  // Cannot happen if the netlist is valid.
267  if( component == NULL )
268  {
269  wxString msg;
270  msg.Printf( _( "Cannot find component with ref '%s' in netlist." ),
271  reference );
274  }
275 
276  component->AddNet( pin_number, name, pin_function, pin_type );
277  }
278  break;
279 
280  default:
281  skipCurrent();
282  break;
283  }
284  }
285 }
286 
287 
289 {
290  /* Parses a section like
291  * (comp (ref P1)
292  * (value DB25FEMALE)
293  * (footprint DB25FC)
294  * (libsource (lib conn) (part DB25))
295  * (property (name PINCOUNT) (value 25))
296  * (sheetpath (names /) (tstamps /))
297  * (tstamp 68183921-93a5-49ac-91b0-49d05a0e1647))
298  *
299  * other fields (unused) are skipped
300  * A component need a reference, value, footprint name and a full time stamp
301  * The full time stamp is the sheetpath time stamp + the component time stamp
302  */
303  LIB_ID fpid;
304  wxString footprint;
305  wxString ref;
306  wxString value;
307  wxString library;
308  wxString name;
309  KIID_PATH path;
310 
311  std::vector<KIID> uuids;
312  std::map<wxString, wxString> properties;
313 
314  // The token comp was read, so the next data is (ref P1)
315  while( (token = NextTok() ) != T_RIGHT )
316  {
317  if( token == T_LEFT )
318  token = NextTok();
319 
320  switch( token )
321  {
322  case T_ref:
323  NeedSYMBOLorNUMBER();
324  ref = FROM_UTF8( CurText() );
325  NeedRIGHT();
326  break;
327 
328  case T_value:
329  NeedSYMBOLorNUMBER();
330  value = FROM_UTF8( CurText() );
331  NeedRIGHT();
332  break;
333 
334  case T_footprint:
335  NeedSYMBOLorNUMBER();
336  footprint = FromUTF8();
337  NeedRIGHT();
338  break;
339 
340  case T_libsource:
341  // Read libsource
342  while( ( token = NextTok() ) != T_RIGHT )
343  {
344  if( token == T_LEFT )
345  token = NextTok();
346 
347  if( token == T_lib )
348  {
349  NeedSYMBOLorNUMBER();
350  library = FROM_UTF8( CurText() );
351  NeedRIGHT();
352  }
353  else if( token == T_part )
354  {
355  NeedSYMBOLorNUMBER();
356  name = FROM_UTF8( CurText() );
357  NeedRIGHT();
358  }
359  else if( token == T_description )
360  {
361  NeedSYMBOLorNUMBER();
362  NeedRIGHT();
363  }
364  else
365  {
366  Expecting( "part, lib or description" );
367  }
368  }
369  break;
370 
371  case T_property:
372  {
373  wxString propName;
374  wxString propValue;
375 
376  while( (token = NextTok() ) != T_RIGHT )
377  {
378  if( token == T_LEFT )
379  token = NextTok();
380 
381  if( token == T_name )
382  {
383  NeedSYMBOLorNUMBER();
384  propName = FROM_UTF8( CurText() );
385  NeedRIGHT();
386  }
387  else if( token == T_value )
388  {
389  NeedSYMBOLorNUMBER();
390  propValue = FROM_UTF8( CurText() );
391  NeedRIGHT();
392  }
393  else
394  {
395  Expecting( "name or value" );
396  }
397  }
398 
399  if( !propName.IsEmpty() )
400  properties[ propName ] = propValue;
401  }
402  break;
403 
404  case T_sheetpath:
405  while( ( token = NextTok() ) != T_EOF )
406  {
407  if( token == T_tstamps )
408  break;
409  }
410 
411  NeedSYMBOLorNUMBER();
412  path = KIID_PATH( FROM_UTF8( CurText() ) );
413  NeedRIGHT();
414  NeedRIGHT();
415  break;
416 
417  case T_tstamps:
418  while( ( token = NextTok() ) != T_EOF )
419  {
420  if( token == T_RIGHT )
421  break;
422 
423  uuids.emplace_back( FROM_UTF8( CurText() ) );
424  }
425 
426  break;
427 
428  default:
429  // Skip not used data (i.e all other tokens)
430  skipCurrent();
431  break;
432  }
433  }
434 
435  if( !footprint.IsEmpty() && fpid.Parse( footprint, true ) >= 0 )
436  {
437  wxString error;
438  error.Printf( _( "Invalid footprint ID in\nfile: '%s'\nline: %d\noffset: %d" ),
439  CurSource(), CurLineNumber(), CurOffset() );
440 
441  THROW_IO_ERROR( error );
442  }
443 
444  COMPONENT* component = new COMPONENT( fpid, ref, value, path, uuids );
445  component->SetName( name );
446  component->SetLibrary( library );
447  component->SetProperties( properties );
448  m_netlist->AddComponent( component );
449 }
450 
451 
453 {
454  /* Parses a section like
455  * (libpart (lib device) (part C)
456  * (aliases
457  * (alias Cxx)
458  * (alias Cyy))
459  * (description "Condensateur non polarise")
460  * (footprints
461  * (fp SM*)
462  * (fp C?)
463  * (fp C1-1))
464  * (fields
465  * (field (name Reference) C)
466  * (field (name Value) C))
467  * (pins
468  * (pin (num 1) (name ~) (type passive))
469  * (pin (num 2) (name ~) (type passive))))
470  *
471  * Currently footprints section/fp are read and data stored
472  * other fields (unused) are skipped
473  */
474  COMPONENT* component = NULL;
475  wxString libName;
476  wxString libPartName;
477  wxArrayString footprintFilters;
478  wxArrayString aliases;
479  int pinCount = 0;
480 
481  // The last token read was libpart, so read the next token
482  while( (token = NextTok() ) != T_RIGHT )
483  {
484  if( token == T_LEFT )
485  token = NextTok();
486 
487  switch( token )
488  {
489  case T_lib:
490  NeedSYMBOLorNUMBER();
491  libName = FROM_UTF8( CurText() );
492  NeedRIGHT();
493  break;
494 
495  case T_part:
496  NeedSYMBOLorNUMBER();
497  libPartName = FROM_UTF8( CurText() );
498  NeedRIGHT();
499  break;
500 
501  case T_footprints:
502  // Read all fp elements (footprint filter item)
503  while( (token = NextTok() ) != T_RIGHT )
504  {
505  if( token == T_LEFT )
506  token = NextTok();
507 
508  if( token != T_fp )
509  Expecting( T_fp );
510 
511  NeedSYMBOLorNUMBER();
512  footprintFilters.Add( FROM_UTF8( CurText() ) );
513  NeedRIGHT();
514  }
515  break;
516 
517  case T_aliases:
518  while( (token = NextTok() ) != T_RIGHT )
519  {
520  if( token == T_LEFT )
521  token = NextTok();
522 
523  if( token != T_alias )
524  Expecting( T_alias );
525 
526  NeedSYMBOLorNUMBER();
527  aliases.Add( FROM_UTF8( CurText() ) );
528  NeedRIGHT();
529  }
530  break;
531 
532  case T_pins:
533  while( (token = NextTok() ) != T_RIGHT )
534  {
535  if( token == T_LEFT )
536  token = NextTok();
537 
538  if( token != T_pin )
539  Expecting( T_pin );
540 
541  pinCount++;
542 
543  skipCurrent();
544  }
545  break;
546 
547  default:
548  // Skip not used data (i.e all other tokens)
549  skipCurrent();
550  break;
551  }
552  }
553 
554  // Find all of the components that reference this component library part definition.
555  for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
556  {
557  component = m_netlist->GetComponent( i );
558 
559  if( component->IsLibSource( libName, libPartName ) )
560  {
561  component->SetFootprintFilters( footprintFilters );
562  component->SetPinCount( pinCount );
563  }
564 
565  for( unsigned jj = 0; jj < aliases.GetCount(); jj++ )
566  {
567  if( component->IsLibSource( libName, aliases[jj] ) )
568  {
569  component->SetFootprintFilters( footprintFilters );
570  component->SetPinCount( pinCount );
571  }
572  }
573 
574  }
575 }
bool IsLibSource(const wxString &aLibrary, const wxString &aName) const
Definition: pcb_netlist.h:155
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition: richio.h:80
char * Line() const
Return a pointer to the last line that was read in.
Definition: richio.h:117
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
virtual const wxString & GetSource() const
Returns the name of the source of the lines in an abstract sense.
Definition: richio.h:109
void SetLibrary(const wxString &aLibrary)
Definition: pcb_netlist.h:120
NETLIST * m_netlist
The netlist to parse into. Not owned.
void parseComponent()
Parse a component description: (comp (ref P1) (value DB25FEMELLE) (footprint DB25FC) (libsource (lib ...
void skipCurrent()
Skip the current token level, i.e search for the RIGHT parenthesis which closes the current descripti...
unsigned GetCount() const
Definition: pcb_netlist.h:228
void SetProperties(std::map< wxString, wxString > &aProps)
Definition: pcb_netlist.h:126
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
This file contains miscellaneous commonly used macros and functions.
void AddComponent(COMPONENT *aComponent)
Add aComponent to the NETLIST.
virtual void LoadNetlist() override
Load the contents of the netlist file into aNetlist.
KICAD_NETLIST_PARSER(LINE_READER *aReader, NETLIST *aNetlist)
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
void parseLibPartList()
Read the section "libparts" in the netlist: (libparts (libpart (lib device) (part C) (description "Co...
Store information read from a netlist along with the flags used to update the NETLIST in the BOARD.
Definition: pcb_netlist.h:206
#define NULL
LINE_READER * m_lineReader
The line reader used to parse the netlist. Not owned.
virtual unsigned LineNumber() const
Return the line number of the last line read from this LINE_READER.
Definition: richio.h:135
void SetPinCount(int aPinCount)
Definition: pcb_netlist.h:145
#define _(s)
Store all of the related footprint information found in a netlist.
Definition: pcb_netlist.h:84
unsigned Length() const
Return the number of bytes in the last line read from this LINE_READER.
Definition: richio.h:143
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
COMPONENT * GetComponent(unsigned aIndex)
Return the COMPONENT at aIndex.
Definition: pcb_netlist.h:236
void SetFootprintFilters(const wxArrayString &aFilters)
Definition: pcb_netlist.h:142
void Parse()
Function Parse parse the full netlist.
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:49
const char * name
Definition: DXF_plotter.cpp:56
void SetName(const wxString &aName)
Definition: pcb_netlist.h:117
void parseNet()
Parse a net section (net (code 20) (name /PC-A0) (node (ref BUS1) (pin 62)) (node (ref U3) (pin 3)) (...
void AddNet(const wxString &aPinName, const wxString &aNetName, const wxString &aPinFunction, const wxString &aPinType)
Definition: pcb_netlist.h:103
COMPONENT * GetComponentByReference(const wxString &aReference)
Return a COMPONENT by aReference.
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38