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 <wx/wx.h>
29 #include <netlist_lexer.h> // netlist_lexer is common to Eeschema and Pcbnew
30 #include <macros.h>
31 
32 #include "pcb_netlist.h"
33 #include "netlist_reader.h"
34 
35 using namespace NL_T;
36 
37 
39 {
40  m_parser->Parse();
41 
42  if( m_footprintReader )
43  {
44  m_footprintReader->Load( m_netlist );
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  while( ( token = NextTok() ) != T_EOF )
108  {
109  if( token == T_RIGHT )
110  break;
111  else if( token == T_LEFT )
112  token = NextTok();
113 
114  if( token == T_comp ) // A component section found. Read it
115  parseComponent();
116  }
117 
118  break;
119 
120  case T_nets: // The section nets starts here.
121  while( ( token = NextTok() ) != T_EOF )
122  {
123  if( token == T_RIGHT )
124  break;
125  else if( token == T_LEFT )
126  token = NextTok();
127 
128  if( token == T_net ) // A net section if found. Read it
129  parseNet();
130  }
131 
132  break;
133 
134  case T_libparts: // The section libparts starts here.
135  while( ( token = NextTok() ) != T_EOF )
136  {
137  if( token == T_RIGHT )
138  break;
139  else if( token == T_LEFT )
140  token = NextTok();
141 
142  if( token == T_libpart ) // A libpart section if found. Read it
144  }
145 
146  break;
147 
148  case T_libraries: // The section libraries starts here.
149  // List of libraries in use.
150  // Not used here, just skip it
151  skipCurrent();
152  break;
153 
154  case T_design: // The section design starts here.
155  // Not used (mainly they are comments), just skip it
156  skipCurrent();
157  break;
158 
159  case T_RIGHT: // The closing parenthesis of the file.
160  plevel--;
161  break;
162 
163  default:
164  skipCurrent();
165  break;
166  }
167  }
168 
169  if( plevel != 0 )
170  {
171  wxFAIL_MSG( wxString::Format( "KICAD_NETLIST_PARSER::Parse(): bad parenthesis "
172  "count (count = %d", 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;
310  KIID_PATH path;
311 
312  std::vector<KIID> uuids;
313  std::map<wxString, wxString> properties;
314 
315  // The token comp was read, so the next data is (ref P1)
316  while( (token = NextTok() ) != T_RIGHT )
317  {
318  if( token == T_LEFT )
319  token = NextTok();
320 
321  switch( token )
322  {
323  case T_ref:
324  NeedSYMBOLorNUMBER();
325  ref = FROM_UTF8( CurText() );
326  NeedRIGHT();
327  break;
328 
329  case T_value:
330  NeedSYMBOLorNUMBER();
331  value = FROM_UTF8( CurText() );
332  NeedRIGHT();
333  break;
334 
335  case T_footprint:
336  NeedSYMBOLorNUMBER();
337  footprint = FromUTF8();
338  NeedRIGHT();
339  break;
340 
341  case T_libsource:
342  // Read libsource
343  while( ( token = NextTok() ) != T_RIGHT )
344  {
345  if( token == T_LEFT )
346  token = NextTok();
347 
348  if( token == T_lib )
349  {
350  NeedSYMBOLorNUMBER();
351  library = FROM_UTF8( CurText() );
352  NeedRIGHT();
353  }
354  else if( token == T_part )
355  {
356  NeedSYMBOLorNUMBER();
357  name = FROM_UTF8( CurText() );
358  NeedRIGHT();
359  }
360  else if( token == T_description )
361  {
362  NeedSYMBOLorNUMBER();
363  NeedRIGHT();
364  }
365  else
366  {
367  Expecting( "part, lib or description" );
368  }
369  }
370  break;
371 
372  case T_property:
373  {
374  wxString propName;
375  wxString propValue;
376 
377  while( (token = NextTok() ) != T_RIGHT )
378  {
379  if( token == T_LEFT )
380  token = NextTok();
381 
382  if( token == T_name )
383  {
384  NeedSYMBOLorNUMBER();
385  propName = FROM_UTF8( CurText() );
386  NeedRIGHT();
387  }
388  else if( token == T_value )
389  {
390  NeedSYMBOLorNUMBER();
391  propValue = FROM_UTF8( CurText() );
392  NeedRIGHT();
393  }
394  else
395  {
396  Expecting( "name or value" );
397  }
398  }
399 
400  if( !propName.IsEmpty() )
401  properties[ propName ] = propValue;
402  }
403  break;
404 
405  case T_sheetpath:
406  while( ( token = NextTok() ) != T_EOF )
407  {
408  if( token == T_tstamps )
409  break;
410  }
411 
412  NeedSYMBOLorNUMBER();
413  path = KIID_PATH( FROM_UTF8( CurText() ) );
414  NeedRIGHT();
415  NeedRIGHT();
416  break;
417 
418  case T_tstamps:
419  while( ( token = NextTok() ) != T_EOF )
420  {
421  if( token == T_RIGHT )
422  break;
423 
424  uuids.emplace_back( FROM_UTF8( CurText() ) );
425  }
426 
427  break;
428 
429  default:
430  // Skip not used data (i.e all other tokens)
431  skipCurrent();
432  break;
433  }
434  }
435 
436  if( !footprint.IsEmpty() && fpid.Parse( footprint, true ) >= 0 )
437  {
438  wxString error;
439  error.Printf( _( "Invalid footprint ID in\nfile: \"%s\"\nline: %d\noffset: %d" ),
440  CurSource(), CurLineNumber(), CurOffset() );
441 
442  THROW_IO_ERROR( error );
443  }
444 
445  COMPONENT* component = new COMPONENT( fpid, ref, value, path, uuids );
446  component->SetName( name );
447  component->SetLibrary( library );
448  component->SetProperties( properties );
449  m_netlist->AddComponent( component );
450 }
451 
452 
454 {
455  /* Parses a section like
456  * (libpart (lib device) (part C)
457  * (aliases
458  * (alias Cxx)
459  * (alias Cyy))
460  * (description "Condensateur non polarise")
461  * (footprints
462  * (fp SM*)
463  * (fp C?)
464  * (fp C1-1))
465  * (fields
466  * (field (name Reference) C)
467  * (field (name Value) C))
468  * (pins
469  * (pin (num 1) (name ~) (type passive))
470  * (pin (num 2) (name ~) (type passive))))
471  *
472  * Currently footprints section/fp are read and data stored
473  * other fields (unused) are skipped
474  */
475  COMPONENT* component = NULL;
476  wxString libName;
477  wxString libPartName;
478  wxArrayString footprintFilters;
479  wxArrayString aliases;
480  int pinCount = 0;
481 
482  // The last token read was libpart, so read the next token
483  while( (token = NextTok() ) != T_RIGHT )
484  {
485  if( token == T_LEFT )
486  token = NextTok();
487 
488  switch( token )
489  {
490  case T_lib:
491  NeedSYMBOLorNUMBER();
492  libName = FROM_UTF8( CurText() );
493  NeedRIGHT();
494  break;
495 
496  case T_part:
497  NeedSYMBOLorNUMBER();
498  libPartName = FROM_UTF8( CurText() );
499  NeedRIGHT();
500  break;
501 
502  case T_footprints:
503  // Read all fp elements (footprint filter item)
504  while( (token = NextTok() ) != T_RIGHT )
505  {
506  if( token == T_LEFT )
507  token = NextTok();
508 
509  if( token != T_fp )
510  Expecting( T_fp );
511 
512  NeedSYMBOLorNUMBER();
513  footprintFilters.Add( FROM_UTF8( CurText() ) );
514  NeedRIGHT();
515  }
516  break;
517 
518  case T_aliases:
519  while( (token = NextTok() ) != T_RIGHT )
520  {
521  if( token == T_LEFT )
522  token = NextTok();
523 
524  if( token != T_alias )
525  Expecting( T_alias );
526 
527  NeedSYMBOLorNUMBER();
528  aliases.Add( FROM_UTF8( CurText() ) );
529  NeedRIGHT();
530  }
531  break;
532 
533  case T_pins:
534  while( (token = NextTok() ) != T_RIGHT )
535  {
536  if( token == T_LEFT )
537  token = NextTok();
538 
539  if( token != T_pin )
540  Expecting( T_pin );
541 
542  pinCount++;
543 
544  skipCurrent();
545  }
546  break;
547 
548  default:
549  // Skip not used data (i.e all other tokens)
550  skipCurrent();
551  break;
552  }
553  }
554 
555  // Find all of the components that reference this component library part definition.
556  for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
557  {
558  component = m_netlist->GetComponent( i );
559 
560  if( component->IsLibSource( libName, libPartName ) )
561  {
562  component->SetFootprintFilters( footprintFilters );
563  component->SetPinCount( pinCount );
564  }
565 
566  for( unsigned jj = 0; jj < aliases.GetCount(); jj++ )
567  {
568  if( component->IsLibSource( libName, aliases[jj] ) )
569  {
570  component->SetFootprintFilters( footprintFilters );
571  component->SetPinCount( pinCount );
572  }
573  }
574 
575  }
576 }
bool IsLibSource(const wxString &aLibrary, const wxString &aName) const
Definition: pcb_netlist.h:190
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:155
NETLIST * m_netlist
The netlist to parse into. Not owned.
void parseComponent()
Function parseComponent parse a component description: (comp (ref P1) (value DB25FEMELLE) (footprint ...
void skipCurrent()
Function skipCurrent Skip the current token level, i.e search for the RIGHT parenthesis which closes ...
unsigned GetCount() const
Function GetCount.
Definition: pcb_netlist.h:237
void SetProperties(std::map< wxString, wxString > &aProps)
Definition: pcb_netlist.h:161
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)
Function AddComponent adds aComponent to the NETLIST.
virtual void LoadNetlist() override
Function LoadNetlist loads 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()
Function parseLibPartList reads the section "libparts" in the netlist: (libparts (libpart (lib device...
NETLIST stores all of information read from a netlist along with the flags used to update the NETLIST...
Definition: pcb_netlist.h:207
#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:180
COMPONENT is used to store components and all of their related information found in a netlist.
Definition: pcb_netlist.h:85
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)
Function GetComponent returns the COMPONENT at aIndex.
Definition: pcb_netlist.h:246
void SetFootprintFilters(const wxArrayString &aFilters)
Definition: pcb_netlist.h:177
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:122
const char * name
Definition: DXF_plotter.cpp:59
#define _(s)
Definition: 3d_actions.cpp:33
void SetName(const wxString &aName)
Definition: pcb_netlist.h:152
void parseNet()
Function parseNet Parses a section like (net (code 20) (name /PC-A0) (node (ref BUS1) (pin 62)) (node...
void AddNet(const wxString &aPinName, const wxString &aNetName, const wxString &aPinFunction, const wxString &aPinType)
Definition: pcb_netlist.h:138
COMPONENT * GetComponentByReference(const wxString &aReference)
Function GetComponentByReference returns a COMPONENT by aReference.
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38