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-2017 KiCad Developers, see AUTHORS.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 
84 void KICAD_NETLIST_PARSER::Parse() throw( IO_ERROR, PARSE_ERROR, boost::bad_pointer )
85 {
86  int plevel = 0; // the count of ')' to read and end of file,
87  // after parsing all sections
88 
89  while( ( token = NextTok() ) != T_EOF )
90  {
91  if( token == T_LEFT )
92  token = NextTok();
93 
94  switch( token )
95  {
96  case T_export: // The netlist starts here.
97  // nothing to do here,
98  // just increment the count of ')' to read and end of file
99  plevel++;
100  break;
101 
102  case T_version: // The netlist starts here.
103  // version id not yet used: read it but does not use it
104  NextTok();
105  NeedRIGHT();
106  break;
107 
108  case T_components: // The section comp starts here.
109  while( ( token = NextTok() ) != T_RIGHT )
110  {
111  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_RIGHT )
122  {
123  if( token == T_LEFT )
124  token = NextTok();
125 
126  if( token == T_net )
127  {
128  // A net section if found. Read it
129  parseNet();
130  }
131  }
132 
133  break;
134 
135  case T_libparts: // The section libparts starts here.
136  while( ( token = NextTok() ) != T_RIGHT )
137  {
138  if( token == T_LEFT )
139  token = NextTok();
140 
141  if( token == T_libpart )
142  {
143  // A libpart section if found. Read it
145  }
146  }
147 
148  break;
149 
150  case T_libraries: // The section libraries starts here.
151  // List of libraries in use.
152  // Not used here, just skip it
153  skipCurrent();
154  break;
155 
156  case T_design: // The section design starts here.
157  // Not used (mainly they are comments), just skip it
158  skipCurrent();
159  break;
160 
161  case T_RIGHT: // The closing parenthesis of the file.
162  // Not used (mainly they are comments), just skip it
163  plevel--;
164  break;
165 
166  default:
167  skipCurrent();
168  break;
169  }
170  }
171 
172  if( plevel != 0 )
173  {
174  wxLogDebug( wxT( "KICAD_NETLIST_PARSER::Parse(): bad parenthesis count (count = %d"),
175  plevel );
176  }
177 }
178 
179 
181 {
182  /* Parses a section like
183  * (net (code 20) (name /PC-A0)
184  * (node (ref BUS1) (pin 62))
185  * (node (ref U3) (pin 3))
186  * (node (ref U9) (pin M6)))
187  */
188 
189  COMPONENT* component = NULL;
190  wxString code;
191  wxString name;
192  wxString reference;
193  wxString pin;
194  int nodecount = 0;
195 
196  // The token net was read, so the next data is (code <number>)
197  while( (token = NextTok()) != T_RIGHT )
198  {
199  if( token == T_LEFT )
200  token = NextTok();
201 
202  switch( token )
203  {
204  case T_code:
206  code = FROM_UTF8( CurText() );
207  NeedRIGHT();
208  break;
209 
210  case T_name:
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  while( (token = NextTok()) != T_RIGHT )
222  {
223  if( token == T_LEFT )
224  token = NextTok();
225 
226  switch( token )
227  {
228  case T_ref:
230  reference = FROM_UTF8( CurText() );
231  NeedRIGHT();
232  break;
233 
234  case T_pin:
236  pin = FROM_UTF8( CurText() );
237  NeedRIGHT();
238  break;
239 
240  default:
241  skipCurrent();
242  break;
243  }
244  }
245 
246 
247  component = m_netlist->GetComponentByReference( reference );
248 
249  // Cannot happen if the netlist is valid.
250  if( component == NULL )
251  {
252  wxString msg;
253  msg.Printf( _( "Cannot find component with reference \"%s\" in netlist." ),
254  GetChars( reference ) );
257  }
258 
259  component->AddNet( pin, name );
260  nodecount++;
261  break;
262 
263  default:
264  skipCurrent();
265  break;
266  }
267  }
268 }
269 
270 
272 {
273  /* Parses a section like
274  * (comp (ref P1)
275  * (value DB25FEMELLE)
276  * (footprint DB25FC)
277  * (libsource (lib conn) (part DB25))
278  * (sheetpath (names /) (tstamps /))
279  * (tstamp 3256759C))
280  *
281  * other fields (unused) are skipped
282  * A component need a reference, value, footprint name and a full time stamp
283  * The full time stamp is the sheetpath time stamp + the component time stamp
284  */
285  LIB_ID fpid;
286  wxString footprint;
287  wxString ref;
288  wxString value;
289  wxString library;
290  wxString name;
291  wxString pathtimestamp, timestamp;
292 
293  // The token comp was read, so the next data is (ref P1)
294  while( (token = NextTok()) != T_RIGHT )
295  {
296  if( token == T_LEFT )
297  token = NextTok();
298 
299  switch( token )
300  {
301  case T_ref:
303  ref = FROM_UTF8( CurText() );
304  NeedRIGHT();
305  break;
306 
307  case T_value:
309  value = FROM_UTF8( CurText() );
310  NeedRIGHT();
311  break;
312 
313  case T_footprint:
315  footprint = FromUTF8();
316  NeedRIGHT();
317  break;
318 
319  case T_libsource:
320  // Read libsource
321  while( (token = NextTok()) != T_RIGHT )
322  {
323  if( token == T_LEFT )
324  token = NextTok();
325 
326  if( token == T_lib )
327  {
329  library = FROM_UTF8( CurText() );
330  NeedRIGHT();
331  }
332  else if( token == T_part )
333  {
335  name = FROM_UTF8( CurText() );
336  NeedRIGHT();
337  }
338  else
339  {
340  Expecting( "part or lib" );
341  }
342  }
343  break;
344 
345  case T_sheetpath:
346  while( ( token = NextTok() ) != T_tstamps );
348  pathtimestamp = FROM_UTF8( CurText() );
349  NeedRIGHT();
350  NeedRIGHT();
351  break;
352 
353  case T_tstamp:
355  timestamp = FROM_UTF8( CurText() );
356  NeedRIGHT();
357  break;
358 
359  default:
360  // Skip not used data (i.e all other tokens)
361  skipCurrent();
362  break;
363  }
364  }
365 
366  if( !footprint.IsEmpty() && fpid.Parse( TO_UTF8( footprint ) ) >= 0 )
367  {
368  wxString error;
369  error.Printf( _( "invalid footprint ID in\nfile: <%s>\nline: %d\noffset: %d" ),
371 
372  THROW_IO_ERROR( error );
373  }
374 
375  pathtimestamp += timestamp;
376  COMPONENT* component = new COMPONENT( fpid, ref, value, pathtimestamp );
377  component->SetName( name );
378  component->SetLibrary( library );
379  m_netlist->AddComponent( component );
380 }
381 
382 
384 {
385  /* Parses a section like
386  * (libpart (lib device) (part C)
387  * (aliases
388  * (alias Cxx)
389  * (alias Cyy))
390  * (description "Condensateur non polarise")
391  * (footprints
392  * (fp SM*)
393  * (fp C?)
394  * (fp C1-1))
395  * (fields
396  * (field (name Reference) C)
397  * (field (name Value) C))
398  * (pins
399  * (pin (num 1) (name ~) (type passive))
400  * (pin (num 2) (name ~) (type passive))))
401  *
402  * Currently footprints section/fp are read and data stored
403  * other fields (unused) are skipped
404  */
405  COMPONENT* component = NULL;
406  wxString libName;
407  wxString libPartName;
408  wxArrayString footprintFilters;
409  wxArrayString aliases;
410 
411  // The last token read was libpart, so read the next token
412  while( (token = NextTok()) != T_RIGHT )
413  {
414  if( token == T_LEFT )
415  token = NextTok();
416 
417  switch( token )
418  {
419  case T_lib:
421  libName = FROM_UTF8( CurText() );
422  NeedRIGHT();
423  break;
424 
425  case T_part:
427  libPartName = FROM_UTF8( CurText() );
428  NeedRIGHT();
429  break;
430 
431  case T_footprints:
432  // Read all fp elements (footprint filter item)
433  while( (token = NextTok()) != T_RIGHT )
434  {
435  if( token == T_LEFT )
436  token = NextTok();
437 
438  if( token != T_fp )
439  Expecting( T_fp );
440 
442  footprintFilters.Add( FROM_UTF8( CurText() ) );
443  NeedRIGHT();
444  }
445 
446  break;
447 
448  case T_aliases:
449  while( (token = NextTok()) != T_RIGHT )
450  {
451  if( token == T_LEFT )
452  token = NextTok();
453 
454  if( token != T_alias )
455  Expecting( T_alias );
456 
458  aliases.Add( FROM_UTF8( CurText() ) );
459  NeedRIGHT();
460  }
461  break;
462  default:
463  // Skip not used data (i.e all other tokens)
464  skipCurrent();
465  break;
466  }
467  }
468 
469  // Find all of the components that reference this component library part definition.
470  for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
471  {
472  component = m_netlist->GetComponent( i );
473 
474  if( component->IsLibSource( libName, libPartName ) )
475  component->SetFootprintFilters( footprintFilters );
476 
477  for( unsigned jj = 0; jj < aliases.GetCount(); jj++ )
478  {
479  if( component->IsLibSource( libName, aliases[jj] ) )
480  component->SetFootprintFilters( footprintFilters );
481  }
482 
483  }
484 }
Class LINE_READER is an abstract class from which implementation specific LINE_READERs may be derived...
Definition: richio.h:81
bool IsLibSource(const wxString &aLibrary, const wxString &aName) const
Definition: pcb_netlist.h:184
virtual unsigned LineNumber() const
Function Line Number returns the line number of the last line read from this LINE_READER.
Definition: richio.h:159
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:53
Class NETLIST_LEXER is an automatically generated class using the TokenList2DnsLexer.cmake technology, based on keywords provided by file: /home/kicad/workspace/kicad-doxygen/common/netlist.keywords.
Definition: netlist_lexer.h:92
void SetLibrary(const wxString &aLibrary)
Definition: pcb_netlist.h:146
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 ...
int Parse(const UTF8 &aId)
Function Parse.
Definition: lib_id.cpp:122
Class LIB_ID.
Definition: lib_id.h:56
wxString FromUTF8()
Function FromUTF8 returns the current token text as a wxString, assuming that the input byte stream i...
Definition: dsnlexer.h:498
This file contains miscellaneous commonly used macros and functions.
void AddComponent(COMPONENT *aComponent)
Function AddComponent adds aComponent to the NETLIST.
const wxString & CurSource()
Function CurFilename returns the current LINE_READER source.
Definition: dsnlexer.h:528
NL_T::T NextTok()
Function NextTok returns the next token found in the input file or T_EOF when reaching the end of fil...
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
virtual void LoadNetlist() override
Function LoadNetlist loads the contents of the netlist file into aNetlist.
KICAD_NETLIST_PARSER(LINE_READER *aReader, NETLIST *aNetlist)
void SetFootprintFilters(const wxArrayString &aFilterList)
Definition: pcb_netlist.h:170
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:133
void parseLibPartList()
Function parseLibPartList reads the section "libparts" in the netlist: (libparts (libpart (lib device...
Class NETLIST stores all of information read from a netlist along with the flags used to update the N...
Definition: pcb_netlist.h:205
LINE_READER * m_lineReader
The line reader used to parse the netlist. Not owned.
char * Line() const
Function Line returns a pointer to the last line that was read in.
Definition: richio.h:139
int CurOffset()
Function CurOffset returns the byte offset within the current line, using a 1 based index...
Definition: dsnlexer.h:538
#define THROW_IO_ERROR(x)
Definition: utf8.cpp:60
void Expecting(int aTok)
Function Expecting throws an IO_ERROR exception with an input file specific error message...
Definition: dsnlexer.cpp:353
NL_T::T NeedSYMBOLorNUMBER()
Function NeedSYMBOLorNUMBER calls NextTok() and then verifies that the token read in satisfies bool I...
unsigned Length() const
Function Length returns the number of bytes in the last line read from this LINE_READER.
Definition: richio.h:168
Class COMPONENT is used to store components and all of their related information found in a netlist...
Definition: pcb_netlist.h:83
COMPONENT * GetComponent(unsigned aIndex)
Function GetComponent returns the COMPONENT at aIndex.
Definition: pcb_netlist.h:256
void Parse()
Function Parse parse the full netlist.
Struct PARSE_ERROR contains a filename or source description, a problem input line, a line number, a byte offset, and an error message which contains the the caller's report and his call site information: CPP source file, function, and line number.
Definition: ki_exception.h:94
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
C++ does not put enum values in separate namespaces unless the enum itself is in a separate namespace...
Definition: netlist_lexer.h:23
void SetName(const wxString &aName)
Definition: pcb_netlist.h:143
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 parseNet()
Function parseNet Parses a section like (net (code 20) (name /PC-A0) (node (ref BUS1) (pin 62)) (node...
int CurLineNumber()
Function CurLineNumber returns the current line number within my LINE_READER.
Definition: dsnlexer.h:507
void AddNet(const wxString &aPinName, const wxString &aNetName)
Definition: pcb_netlist.h:130
const char * name
void NeedRIGHT()
Function NeedRIGHT calls NextTok() and then verifies that the token read in is a DSN_RIGHT.
Definition: dsnlexer.cpp:401
COMPONENT * GetComponentByReference(const wxString &aReference)
Function GetComponentByReference returns a COMPONENT by aReference.
unsigned GetCount() const
Function GetCount.
Definition: pcb_netlist.h:247
const char * CurText()
Function CurText returns a pointer to the current token's text.
Definition: dsnlexer.h:479
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47