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  int nodecount = 0;
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 
215  if( name.IsEmpty() ) // Give a dummy net name like N-000109
216  name = wxT("N-00000") + code;
217 
218  break;
219 
220  case T_node:
221  pin_function.Clear(); // By default: no pin function.
222 
223  while( (token = NextTok()) != T_EOF )
224  {
225  if( token == T_RIGHT )
226  break;
227  else if( token == T_LEFT )
228  token = NextTok();
229 
230  switch( token )
231  {
232  case T_ref:
233  NeedSYMBOLorNUMBER();
234  reference = FROM_UTF8( CurText() );
235  NeedRIGHT();
236  break;
237 
238  case T_pin:
239  NeedSYMBOLorNUMBER();
240  pin_number = FROM_UTF8( CurText() );
241  NeedRIGHT();
242  break;
243 
244  case T_pinfunction:
245  NeedSYMBOLorNUMBER();
246  pin_function = FROM_UTF8( CurText() );
247  NeedRIGHT();
248  break;
249 
250  default:
251  skipCurrent();
252  break;
253  }
254  }
255 
256 
257  component = m_netlist->GetComponentByReference( reference );
258 
259  // Cannot happen if the netlist is valid.
260  if( component == NULL )
261  {
262  wxString msg;
263  msg.Printf( _( "Cannot find component with reference designator \"%s\" in netlist." ),
264  reference );
267  }
268 
269  component->AddNet( pin_number, name, pin_function );
270  nodecount++;
271  break;
272 
273  default:
274  skipCurrent();
275  break;
276  }
277  }
278 }
279 
280 
282 {
283  /* Parses a section like
284  * (comp (ref P1)
285  * (value DB25FEMALE)
286  * (footprint DB25FC)
287  * (libsource (lib conn) (part DB25))
288  * (property (name PINCOUNT) (value 25))
289  * (sheetpath (names /) (tstamps /))
290  * (tstamp 68183921-93a5-49ac-91b0-49d05a0e1647))
291  *
292  * other fields (unused) are skipped
293  * A component need a reference, value, footprint name and a full time stamp
294  * The full time stamp is the sheetpath time stamp + the component time stamp
295  */
296  LIB_ID fpid;
297  wxString footprint;
298  wxString ref;
299  wxString value;
300  wxString library;
301  wxString name;
302  KIID_PATH path;
303  KIID uuid;
304  std::map<wxString, wxString> properties;
305 
306  // The token comp was read, so the next data is (ref P1)
307  while( (token = NextTok()) != T_RIGHT )
308  {
309  if( token == T_LEFT )
310  token = NextTok();
311 
312  switch( token )
313  {
314  case T_ref:
315  NeedSYMBOLorNUMBER();
316  ref = FROM_UTF8( CurText() );
317  NeedRIGHT();
318  break;
319 
320  case T_value:
321  NeedSYMBOLorNUMBER();
322  value = FROM_UTF8( CurText() );
323  NeedRIGHT();
324  break;
325 
326  case T_footprint:
327  NeedSYMBOLorNUMBER();
328  footprint = FromUTF8();
329  NeedRIGHT();
330  break;
331 
332  case T_libsource:
333  // Read libsource
334  while( ( token = NextTok() ) != T_RIGHT )
335  {
336  if( token == T_LEFT )
337  token = NextTok();
338 
339  if( token == T_lib )
340  {
341  NeedSYMBOLorNUMBER();
342  library = FROM_UTF8( CurText() );
343  NeedRIGHT();
344  }
345  else if( token == T_part )
346  {
347  NeedSYMBOLorNUMBER();
348  name = FROM_UTF8( CurText() );
349  NeedRIGHT();
350  }
351  else if( token == T_description )
352  {
353  NeedSYMBOLorNUMBER();
354  NeedRIGHT();
355  }
356  else
357  {
358  Expecting( "part, lib or description" );
359  }
360  }
361  break;
362 
363  case T_property:
364  {
365  wxString propName;
366  wxString propValue;
367 
368  while( (token = NextTok() ) != T_RIGHT )
369  {
370  if( token == T_LEFT )
371  token = NextTok();
372 
373  if( token == T_name )
374  {
375  NeedSYMBOLorNUMBER();
376  propName = FROM_UTF8( CurText() );
377  NeedRIGHT();
378  }
379  else if( token == T_value )
380  {
381  NeedSYMBOLorNUMBER();
382  propValue = FROM_UTF8( CurText() );
383  NeedRIGHT();
384  }
385  else
386  {
387  Expecting( "name or value" );
388  }
389  }
390 
391  if( !propName.IsEmpty() )
392  properties[ propName ] = propValue;
393  }
394  break;
395 
396  case T_sheetpath:
397  while( ( token = NextTok() ) != T_EOF )
398  {
399  if( token == T_tstamps )
400  break;
401  }
402 
403  NeedSYMBOLorNUMBER();
404  path = KIID_PATH( FROM_UTF8( CurText() ) );
405  NeedRIGHT();
406  NeedRIGHT();
407  break;
408 
409  case T_tstamp:
410  NeedSYMBOLorNUMBER();
411  uuid = KIID( FROM_UTF8( CurText() ) );
412  NeedRIGHT();
413  break;
414 
415  default:
416  // Skip not used data (i.e all other tokens)
417  skipCurrent();
418  break;
419  }
420  }
421 
422  if( !footprint.IsEmpty() && fpid.Parse( footprint, LIB_ID::ID_PCB, true ) >= 0 )
423  {
424  wxString error;
425  error.Printf( _( "Invalid footprint ID in\nfile: \"%s\"\nline: %d\noffset: %d" ),
426  CurSource(), CurLineNumber(), CurOffset() );
427 
428  THROW_IO_ERROR( error );
429  }
430 
431  path.push_back( uuid );
432  COMPONENT* component = new COMPONENT( fpid, ref, value, path );
433  component->SetName( name );
434  component->SetLibrary( library );
435  component->SetProperties( properties );
436  m_netlist->AddComponent( component );
437 }
438 
439 
441 {
442  /* Parses a section like
443  * (libpart (lib device) (part C)
444  * (aliases
445  * (alias Cxx)
446  * (alias Cyy))
447  * (description "Condensateur non polarise")
448  * (footprints
449  * (fp SM*)
450  * (fp C?)
451  * (fp C1-1))
452  * (fields
453  * (field (name Reference) C)
454  * (field (name Value) C))
455  * (pins
456  * (pin (num 1) (name ~) (type passive))
457  * (pin (num 2) (name ~) (type passive))))
458  *
459  * Currently footprints section/fp are read and data stored
460  * other fields (unused) are skipped
461  */
462  COMPONENT* component = NULL;
463  wxString libName;
464  wxString libPartName;
465  wxArrayString footprintFilters;
466  wxArrayString aliases;
467  int pinCount = 0;
468 
469  // The last token read was libpart, so read the next token
470  while( (token = NextTok()) != T_RIGHT )
471  {
472  if( token == T_LEFT )
473  token = NextTok();
474 
475  switch( token )
476  {
477  case T_lib:
478  NeedSYMBOLorNUMBER();
479  libName = FROM_UTF8( CurText() );
480  NeedRIGHT();
481  break;
482 
483  case T_part:
484  NeedSYMBOLorNUMBER();
485  libPartName = FROM_UTF8( CurText() );
486  NeedRIGHT();
487  break;
488 
489  case T_footprints:
490  // Read all fp elements (footprint filter item)
491  while( (token = NextTok()) != T_RIGHT )
492  {
493  if( token == T_LEFT )
494  token = NextTok();
495 
496  if( token != T_fp )
497  Expecting( T_fp );
498 
499  NeedSYMBOLorNUMBER();
500  footprintFilters.Add( FROM_UTF8( CurText() ) );
501  NeedRIGHT();
502  }
503  break;
504 
505  case T_aliases:
506  while( (token = NextTok()) != T_RIGHT )
507  {
508  if( token == T_LEFT )
509  token = NextTok();
510 
511  if( token != T_alias )
512  Expecting( T_alias );
513 
514  NeedSYMBOLorNUMBER();
515  aliases.Add( FROM_UTF8( CurText() ) );
516  NeedRIGHT();
517  }
518  break;
519 
520  case T_pins:
521  while( (token = NextTok()) != T_RIGHT )
522  {
523  if( token == T_LEFT )
524  token = NextTok();
525 
526  if( token != T_pin )
527  Expecting( T_pin );
528 
529  pinCount++;
530 
531  skipCurrent();
532  }
533  break;
534 
535  default:
536  // Skip not used data (i.e all other tokens)
537  skipCurrent();
538  break;
539  }
540  }
541 
542  // Find all of the components that reference this component library part definition.
543  for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
544  {
545  component = m_netlist->GetComponent( i );
546 
547  if( component->IsLibSource( libName, libPartName ) )
548  {
549  component->SetFootprintFilters( footprintFilters );
550  component->SetPinCount( pinCount );
551  }
552 
553  for( unsigned jj = 0; jj < aliases.GetCount(); jj++ )
554  {
555  if( component->IsLibSource( libName, aliases[jj] ) )
556  {
557  component->SetFootprintFilters( footprintFilters );
558  component->SetPinCount( pinCount );
559  }
560  }
561 
562  }
563 }
bool IsLibSource(const wxString &aLibrary, const wxString &aName) const
Definition: pcb_netlist.h:177
LINE_READER is an abstract class from which implementation specific LINE_READERs may be derived to re...
Definition: richio.h:81
char * Line() const
Function Line returns a pointer to the last line that was read in.
Definition: richio.h:139
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:114
virtual const wxString & GetSource() const
Function GetSource returns the name of the source of the lines in an abstract sense.
Definition: richio.h:130
void SetLibrary(const wxString &aLibrary)
Definition: pcb_netlist.h:144
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:224
void SetProperties(std::map< wxString, wxString > &aProps)
Definition: pcb_netlist.h:150
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.
Definition: common.h:68
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:162
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:194
#define NULL
LINE_READER * m_lineReader
The line reader used to parse the netlist. Not owned.
virtual unsigned LineNumber() const
Function Line Number returns the line number of the last line read from this LINE_READER.
Definition: richio.h:159
void SetPinCount(int aPinCount)
Definition: pcb_netlist.h:167
COMPONENT is used to store components and all of their related information found in a netlist.
Definition: pcb_netlist.h:80
unsigned Length() const
Function Length returns the number of bytes in the last line read from this LINE_READER.
Definition: richio.h:168
COMPONENT * GetComponent(unsigned aIndex)
Function GetComponent returns the COMPONENT at aIndex.
Definition: pcb_netlist.h:233
void SetFootprintFilters(const wxArrayString &aFilters)
Definition: pcb_netlist.h:164
void Parse()
Function Parse parse the full netlist.
const char * name
Definition: DXF_plotter.cpp:60
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:201
#define _(s)
Definition: 3d_actions.cpp:33
void SetName(const wxString &aName)
Definition: pcb_netlist.h:141
void parseNet()
Function parseNet Parses a section like (net (code 20) (name /PC-A0) (node (ref BUS1) (pin 62)) (node...
COMPONENT * GetComponentByReference(const wxString &aReference)
Function GetComponentByReference returns a COMPONENT by aReference.
int Parse(const UTF8 &aId, LIB_ID_TYPE aType, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
void AddNet(const wxString &aPinName, const wxString &aNetName, const wxString &aPinFunction)
Definition: pcb_netlist.h:128
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38