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:154
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:119
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
Definition: pcb_netlist.h:227
void SetProperties(std::map< wxString, wxString > &aProps)
Definition: pcb_netlist.h:125
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
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...
Store information read from a netlist along with the flags used to update the NETLIST in the BOARD.
Definition: pcb_netlist.h:205
#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:144
Store all of the related footprint information found in a netlist.
Definition: pcb_netlist.h:83
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)
Returns the COMPONENT at aIndex.
Definition: pcb_netlist.h:235
void SetFootprintFilters(const wxArrayString &aFilters)
Definition: pcb_netlist.h:141
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:116
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:102
COMPONENT * GetComponentByReference(const wxString &aReference)
Return a COMPONENT by aReference.
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38