You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

721 lines
22 KiB

  1. #ifndef NETLIST_READER_H
  2. #define NETLIST_READER_H
  3. /**
  4. * @file netlist_reader.h
  5. */
  6. /*
  7. * This program source code file is part of KiCad, a free EDA CAD application.
  8. *
  9. * Copyright (C) 2012 Jean-Pierre Charras.
  10. * Copyright (C) 2013 Wayne Stambaugh <stambaughw@verizon.net>.
  11. * Copyright (C) 2012 KiCad Developers, see CHANGELOG.TXT for contributors.
  12. *
  13. * This program is free software; you can redistribute it and/or
  14. * modify it under the terms of the GNU General Public License
  15. * as published by the Free Software Foundation; either version 2
  16. * of the License, or (at your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program; if not, you may find one here:
  25. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  26. * or you may search the http://www.gnu.org website for the version 2 license,
  27. * or you may write to the Free Software Foundation, Inc.,
  28. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  29. */
  30. #include <boost/ptr_container/ptr_vector.hpp>
  31. #include <fctsys.h>
  32. #include <macros.h>
  33. #include <netlist_lexer.h> // netlist_lexer is common to Eeschema and Pcbnew
  34. using namespace NL_T;
  35. class MODULE;
  36. class LINE_READER;
  37. class REPORTER;
  38. /**
  39. * Class COMPONENT_NET
  40. * is used to store the component pin name to net name associations stored in a netlist.
  41. */
  42. class COMPONENT_NET
  43. {
  44. wxString m_pinName;
  45. wxString m_netNumber;
  46. wxString m_netName;
  47. public:
  48. COMPONENT_NET() {}
  49. COMPONENT_NET( const wxString& aPinName, const wxString& aNetName )
  50. {
  51. m_pinName = aPinName;
  52. m_netName = aNetName;
  53. }
  54. const wxString& GetPinName() const { return m_pinName; }
  55. const wxString& GetNetName() const { return m_netName; }
  56. bool IsValid() const { return !m_pinName.IsEmpty(); }
  57. bool operator <( const COMPONENT_NET& aNet ) const
  58. {
  59. return m_pinName < aNet.m_pinName;
  60. }
  61. #if defined(DEBUG)
  62. /**
  63. * Function Show
  64. * is used to output the object tree, currently for debugging only.
  65. * @param aNestLevel An aid to prettier tree indenting, and is the level
  66. * of nesting of this object within the overall tree.
  67. * @param aReporter A reference to a #REPORTER object to output to.
  68. */
  69. virtual void Show( int aNestLevel, REPORTER& aReporter );
  70. #endif
  71. };
  72. typedef std::vector< COMPONENT_NET > COMPONENT_NETS;
  73. /**
  74. * Class COMPONENT
  75. * is used to store components and all of their related information found in a netlist.
  76. */
  77. class COMPONENT
  78. {
  79. COMPONENT_NETS m_nets;
  80. wxArrayString m_footprintFilters; ///< Footprint filters found in netlist.
  81. wxString m_reference; ///< The component reference designator found in netlist.
  82. wxString m_value; ///< The component value found in netlist.
  83. // ZZZ This timestamp is string, not time_t
  84. wxString m_timeStamp; ///< The component full time stamp found in netlist.
  85. /// The name of the component in #m_library used when it was placed on the schematic..
  86. wxString m_name;
  87. /**
  88. * The name of the component library where #m_name was found. This will be set to
  89. * wxEmptyString for legacy netlist files.
  90. */
  91. wxString m_library;
  92. /// The name of the footprint in the footprint library assigned to the component.
  93. wxString m_footprintName;
  94. /**
  95. * The name of the footprint library that #m_footprintName is located. This will be
  96. * set to wxEmptyString for legacy netlist formats indicating that all libraries need
  97. * to be searched.
  98. */
  99. wxString m_footprintLib;
  100. /// The #MODULE loaded for #m_footprintName found in #m_footprintLib.
  101. std::auto_ptr< MODULE > m_footprint;
  102. /// Set to true if #m_footprintName or #m_footprintLib was changed when the footprint
  103. /// link file was read.
  104. bool m_footprintChanged;
  105. static COMPONENT_NET m_emptyNet;
  106. public:
  107. COMPONENT( const wxString& aFootprintName,
  108. const wxString& aReference,
  109. const wxString& aValue,
  110. const wxString& aTimeStamp )
  111. {
  112. m_footprintName = aFootprintName;
  113. m_reference = aReference;
  114. m_value = aValue;
  115. m_timeStamp = aTimeStamp;
  116. m_footprintChanged = false;
  117. }
  118. virtual ~COMPONENT() { };
  119. void AddNet( const wxString& aPinName, const wxString& aNetName )
  120. {
  121. m_nets.push_back( COMPONENT_NET( aPinName, aNetName ) );
  122. }
  123. unsigned GetNetCount() const { return m_nets.size(); }
  124. const COMPONENT_NET& GetNet( unsigned aIndex ) const { return m_nets[aIndex]; }
  125. const COMPONENT_NET& GetNet( const wxString& aPinName );
  126. void SortPins() { sort( m_nets.begin(), m_nets.end() ); }
  127. void SetName( const wxString& aName ) { m_name = aName;}
  128. const wxString& GetName() const { return m_name; }
  129. void SetLibrary( const wxString& aLibrary ) { m_library = aLibrary; }
  130. const wxString& GetLibrary() const { return m_library; }
  131. const wxString& GetReference() const { return m_reference; }
  132. const wxString& GetValue() const { return m_value; }
  133. void SetFootprintName( const wxString& aFootprintName )
  134. {
  135. m_footprintChanged = !m_footprintName.IsEmpty() && (m_footprintName != aFootprintName);
  136. m_footprintName = aFootprintName;
  137. }
  138. const wxString& GetFootprintName() const { return m_footprintName; }
  139. void SetFootprintLib( const wxString& aFootprintLib )
  140. {
  141. m_footprintChanged = !m_footprintLib.IsEmpty() && (m_footprintLib != aFootprintLib);
  142. m_footprintLib = aFootprintLib;
  143. }
  144. const wxString& GetFootprintLib() const { return m_footprintLib; }
  145. const wxString& GetTimeStamp() const { return m_timeStamp; }
  146. void SetFootprintFilters( const wxArrayString& aFilterList )
  147. {
  148. m_footprintFilters = aFilterList;
  149. }
  150. const wxArrayString& GetFootprintFilters() const { return m_footprintFilters; }
  151. MODULE* GetModule( bool aRelease = false )
  152. {
  153. return ( aRelease ) ? m_footprint.release() : m_footprint.get();
  154. }
  155. void SetModule( MODULE* aModule );
  156. bool IsLibSource( const wxString& aLibrary, const wxString& aName ) const
  157. {
  158. return aLibrary == m_library && aName == m_name;
  159. }
  160. bool FootprintChanged() const { return m_footprintChanged; }
  161. #if defined(DEBUG)
  162. /**
  163. * Function Show
  164. * is used to output the object tree, currently for debugging only.
  165. * @param aNestLevel An aid to prettier tree indenting, and is the level
  166. * of nesting of this object within the overall tree.
  167. * @param aReporter A reference to a #REPORTER object to output to.
  168. */
  169. virtual void Show( int aNestLevel, REPORTER& aReporter );
  170. #endif
  171. };
  172. typedef boost::ptr_vector< COMPONENT > COMPONENTS;
  173. typedef COMPONENTS::iterator COMPONENTS_ITER;
  174. typedef COMPONENTS::const_iterator COMPONENTS_CITER;
  175. /**
  176. * Class NETLIST
  177. * stores all of information read from a netlist along with the flags used to update
  178. * the NETLIST in the #BOARD.
  179. */
  180. class NETLIST
  181. {
  182. COMPONENTS m_components; ///< Components found in the netlist.
  183. /// Remove footprints from #BOARD not found in netlist when true.
  184. bool m_deleteExtraFootprints;
  185. /// Do not actually make any changes. Only report changes to #BOARD from netlist
  186. /// when true.
  187. bool m_isDryRun;
  188. /// Find component by time stamp if true or reference designator if false.
  189. bool m_findByTimeStamp;
  190. /// Replace component footprints when they differ from the netlist if true.
  191. bool m_replaceFootprints;
  192. public:
  193. NETLIST() :
  194. m_deleteExtraFootprints( false ),
  195. m_isDryRun( false ),
  196. m_findByTimeStamp( false ),
  197. m_replaceFootprints( false )
  198. {
  199. }
  200. /**
  201. * Function IsEmpty()
  202. * @return true if there are no components in the netlist.
  203. */
  204. bool IsEmpty() const { return m_components.empty(); }
  205. /**
  206. * Function Clear
  207. * removes all components from the netlist.
  208. */
  209. void Clear() { m_components.clear(); }
  210. /**
  211. * Function GetCount
  212. * @return the number of components in the netlist.
  213. */
  214. unsigned GetCount() const { return m_components.size(); }
  215. /**
  216. * Function GetComponent
  217. * returns the #COMPONENT at \a aIndex.
  218. *
  219. * @param aIndex the index in #m_components to fetch.
  220. * @return a pointer to the #COMPONENT at \a Index.
  221. */
  222. COMPONENT* GetComponent( unsigned aIndex ) { return &m_components[ aIndex ]; }
  223. /**
  224. * Function AddComponent
  225. * adds \a aComponent to the NETLIST.
  226. *
  227. * @note If \a aComponent already exists in the NETLIST, \a aComponent is deleted
  228. * to prevent memory leaks. An assertion is raised in debug builds.
  229. *
  230. * @param aComponent is the COMPONENT to save to the NETLIST.
  231. */
  232. void AddComponent( COMPONENT* aComponent );
  233. /*
  234. * Function GetComponentByReference
  235. * returns a #COMPONENT by \a aReference.
  236. *
  237. * @param aReference is the reference designator the #COMPONENT.
  238. * @return a pointer to the #COMPONENT that matches \a aReference if found. Otherwise NULL.
  239. */
  240. COMPONENT* GetComponentByReference( const wxString& aReference );
  241. /*
  242. * Function GetComponentByTimeStamp
  243. * returns a #COMPONENT by \a aTimeStamp.
  244. *
  245. * @param aTimeStamp is the time stamp the #COMPONENT.
  246. * @return a pointer to the #COMPONENT that matches \a aTimeStamp if found. Otherwise NULL.
  247. */
  248. COMPONENT* GetComponentByTimeStamp( const wxString& aTimeStamp );
  249. void SortByFootprintName();
  250. void SortByReference();
  251. void SetDeleteExtraFootprints( bool aDeleteExtraFootprints )
  252. {
  253. m_deleteExtraFootprints = aDeleteExtraFootprints;
  254. }
  255. bool GetDeleteExtraFootprints() const { return m_deleteExtraFootprints; }
  256. void SetIsDryRun( bool aIsDryRun ) { m_isDryRun = aIsDryRun; }
  257. bool IsDryRun() const { return m_isDryRun; }
  258. void SetFindByTimeStamp( bool aFindByTimeStamp ) { m_findByTimeStamp = aFindByTimeStamp; }
  259. bool IsFindByTimeStamp() const { return m_findByTimeStamp; }
  260. void SetReplaceFootprints( bool aReplaceFootprints )
  261. {
  262. m_replaceFootprints = aReplaceFootprints;
  263. }
  264. bool GetReplaceFootprints() const { return m_replaceFootprints; }
  265. /**
  266. * Function AnyFootprintsLinked
  267. * @return true if any component with a footprint link is found.
  268. */
  269. bool AnyFootprintsLinked() const;
  270. /**
  271. * Function AllFootprintsLinked
  272. * @return true if all components have a footprint link.
  273. */
  274. bool AllFootprintsLinked() const;
  275. /**
  276. * Function NoFootprintsLinked
  277. * @return true if none of the components have a footprint link.
  278. */
  279. bool NoFootprintsLinked() const { return !AnyFootprintsLinked(); }
  280. /**
  281. * Function AnyFootprintsChanged
  282. * @return true if any components footprints were changed when the footprint link file
  283. * (*.cmp) was loaded.
  284. */
  285. bool AnyFootprintsChanged() const;
  286. #if defined(DEBUG)
  287. /**
  288. * Function Show
  289. * is used to output the object tree, currently for debugging only.
  290. * @param aNestLevel An aid to prettier tree indenting, and is the level
  291. * of nesting of this object within the overall tree.
  292. * @param aReporter A reference to a #REPORTER object to output to.
  293. */
  294. virtual void Show( int aNestLevel, REPORTER& aReporter );
  295. #endif
  296. };
  297. /**
  298. * Class CMP_READER
  299. * reads a component footprint link file (*.cmp) format.
  300. */
  301. class CMP_READER
  302. {
  303. LINE_READER* m_lineReader; ///< The line reader to read.
  304. public:
  305. CMP_READER( LINE_READER* aLineReader )
  306. {
  307. m_lineReader = aLineReader;
  308. }
  309. /**
  310. * Function Load
  311. * read the *.cmp file format contains the component footprint assignments created by CvPcb
  312. * into \a aNetlist.
  313. *
  314. * @param aNetlist is the #NETLIST to read into.
  315. *
  316. * @todo At some point in the future, use the footprint field in the new s-expression
  317. * netlist file to assign a footprint to a component instead of using a secondary
  318. * (*.cmp) file.
  319. *
  320. * Sample file footprint assignment entry:
  321. *
  322. * Cmp-Mod V01 Genere by CvPcb 29/10/2003-13: 11:6 *
  323. * BeginCmp
  324. * TimeStamp = /32307DE2/AA450F67;
  325. * Reference = C1;
  326. * ValeurCmp = 47uF;
  327. * IdModule = CP6;
  328. * EndCmp
  329. *
  330. * @throw IO_ERROR if a the #LINE_READER IO error occurs.
  331. * @throw PARSE_ERROR if an error occurs while parsing the file.
  332. * @return true if OK, false if a component reference found in the
  333. * .cmp file is not found in netlist, which means the .cmp file
  334. * is not updated. This is an usual case, in CvPcb, but can be used to
  335. * print a warning in Pcbnew.
  336. */
  337. bool Load( NETLIST* aNetlist ) throw( IO_ERROR, PARSE_ERROR );
  338. };
  339. /**
  340. * Class NETLIST_READER
  341. * is a pure virtual class to derive a specific type of netlist reader from.
  342. */
  343. class NETLIST_READER
  344. {
  345. protected:
  346. NETLIST* m_netlist; ///< The net list to read the file(s) into.
  347. bool m_loadFootprintFilters; ///< Load the component footprint filters section if true.
  348. bool m_loadNets; ///< Load the nets section of the netlist file if true.
  349. LINE_READER* m_lineReader; ///< The line reader of the netlist.
  350. /// The reader used to load the footprint links. If NULL, footprint links are not read.
  351. CMP_READER* m_footprintReader;
  352. public:
  353. enum NETLIST_FILE_T
  354. {
  355. UNKNOWN = -1,
  356. ORCAD,
  357. LEGACY,
  358. KICAD,
  359. // Add new types here. Don't forget to create the appropriate class derived from
  360. // NETCLASS_READER and add the entry to the NETLIST_READER::GetNetlistReader()
  361. // function.
  362. };
  363. NETLIST_READER( LINE_READER* aLineReader,
  364. NETLIST* aNetlist,
  365. CMP_READER* aFootprintLinkReader = NULL )
  366. {
  367. wxASSERT( aLineReader != NULL );
  368. m_lineReader = aLineReader;
  369. m_footprintReader = aFootprintLinkReader;
  370. m_netlist = aNetlist;
  371. m_loadFootprintFilters = true;
  372. m_loadNets = true;
  373. }
  374. virtual ~NETLIST_READER();
  375. /**
  376. * Function GuessNetlistFileType
  377. * looks at \a aFileHeaderLine to see if it matches any of the netlist file types it
  378. * knows about.
  379. *
  380. * @param aLineReader is the #LINE_READER object containing lines from the netlist to test.
  381. * @return the #NETLIST_FILE_T of \a aLineReader.
  382. */
  383. static NETLIST_FILE_T GuessNetlistFileType( LINE_READER* aLineReader );
  384. /**
  385. * Function GetNetlistReader
  386. * attempts to determine the net list file type of \a aNetlistFileName and return the
  387. * appropriate NETLIST_READER type.
  388. *
  389. * @param aNetlist is the netlist to load \a aNetlistFileName into.
  390. * @param aNetlistFileName is the full path and file name of the net list to read.
  391. * @param aCompFootprintFileName is the full path and file name of the component footprint
  392. * associations to read. Set to wxEmptyString if loading the
  393. * footprint association file is not required.
  394. * @return the appropriate NETLIST_READER if \a aNetlistFileName is a valid netlist or
  395. * NULL if \a aNetlistFileName is not a valid netlist files.
  396. */
  397. static NETLIST_READER* GetNetlistReader( NETLIST* aNetlist,
  398. const wxString& aNetlistFileName,
  399. const wxString& aCompFootprintFileName = wxEmptyString )
  400. throw( IO_ERROR );
  401. /**
  402. * Function LoadNetlist
  403. * loads the contents of the netlist file into \a aNetlist.
  404. *
  405. * @throw IO_ERROR if a file IO error occurs.
  406. * @throw PARSE_ERROR if an error occurs while parsing the file.
  407. */
  408. virtual void LoadNetlist() throw ( IO_ERROR, PARSE_ERROR ) = 0;
  409. /**
  410. * Function GetLineReader()
  411. * @return the #LINE_READER associated with the #NETLIST_READER.
  412. */
  413. LINE_READER* GetLineReader();
  414. };
  415. /**
  416. * Class LEGACY_NETLIST_READER
  417. * reads the KiCad legacy and the old Orcad netlist formats.
  418. *
  419. * The KiCad legacy netlist format was derived directly from an old Orcad netlist format. The
  420. * primary difference is the header was changed so this reader can read both formats.
  421. */
  422. class LEGACY_NETLIST_READER : public NETLIST_READER
  423. {
  424. /**
  425. * Function loadComponent
  426. * read the \a aLine containing the description of a component from a legacy format
  427. * netlist and add it to the netlist.
  428. *
  429. * Analyze the first line of a component description in netlist:
  430. * ( /40C08647 $noname R20 4.7K {Lib=R}
  431. *
  432. * @param aText contains the first line of description
  433. * @return the new component created by parsing \a aLine
  434. * @throw PARSE_ERROR when \a aLine is not a valid component description.
  435. */
  436. COMPONENT* loadComponent( char* aText ) throw( PARSE_ERROR );
  437. /**
  438. * Function loadFootprintFilters
  439. * loads the footprint filter section of netlist file.
  440. *
  441. * Sample legacy footprint filter section:
  442. * { Allowed footprints by component:
  443. * $component R11
  444. * R?
  445. * SM0603
  446. * SM0805
  447. * R?-*
  448. * SM1206
  449. * $endlist
  450. * $endfootprintlist
  451. * }
  452. *
  453. * @throw IO_ERROR if a file IO error occurs.
  454. * @throw PARSE_ERROR if an error occurs while parsing the file.
  455. */
  456. void loadFootprintFilters() throw( IO_ERROR, PARSE_ERROR );
  457. /**
  458. * Function loadNet
  459. * read a component net description from \a aText.
  460. *
  461. * @param aText is current line read from the netlist.
  462. * @param aComponent is the component to add the net to.
  463. * @throw PARSE_ERROR if a error occurs reading \a aText.
  464. */
  465. void loadNet( char* aText, COMPONENT* aComponent ) throw( PARSE_ERROR );
  466. public:
  467. LEGACY_NETLIST_READER( LINE_READER* aLineReader,
  468. NETLIST* aNetlist,
  469. CMP_READER* aFootprintLinkReader = NULL ) :
  470. NETLIST_READER( aLineReader, aNetlist, aFootprintLinkReader )
  471. {
  472. }
  473. /**
  474. * Function LoadNetlist
  475. * read the netlist file in the legacy format into \a aNetlist.
  476. *
  477. * The legacy netlist format is:
  478. * \# EESchema Netlist Version 1.0 generee le 18/5/2005-12:30:22
  479. * (
  480. * ( 40C08647 $noname R20 4,7K {Lib=R}
  481. * ( 1 VCC )
  482. * ( 2 MODB_1 )
  483. * )
  484. * ( 40C0863F $noname R18 4,7_k {Lib=R}
  485. * ( 1 VCC )
  486. * ( 2 MODA_1 )
  487. * )
  488. * }
  489. * \#End
  490. *
  491. * @throw IO_ERROR if a file IO error occurs.
  492. * @throw PARSE_ERROR if an error occurs while parsing the file.
  493. */
  494. virtual void LoadNetlist() throw ( IO_ERROR, PARSE_ERROR );
  495. };
  496. /**
  497. * Class KICAD_NETLIST_PARSER
  498. * is the parser for reading the KiCad s-expression netlist format.
  499. */
  500. class KICAD_NETLIST_PARSER : public NETLIST_LEXER
  501. {
  502. private:
  503. T token;
  504. LINE_READER* m_lineReader; ///< The line reader used to parse the netlist. Not owned.
  505. NETLIST* m_netlist; ///< The netlist to parse into. Not owned.
  506. /**
  507. * Function skipCurrent
  508. * Skip the current token level, i.e
  509. * search for the RIGHT parenthesis which closes the current description
  510. */
  511. void skipCurrent() throw( IO_ERROR, PARSE_ERROR );
  512. /**
  513. * Function parseComponent
  514. * parse a component description:
  515. * (comp (ref P1)
  516. * (value DB25FEMELLE)
  517. * (footprint DB25FC)
  518. * (libsource (lib conn) (part DB25))
  519. * (sheetpath (names /) (tstamps /))
  520. * (tstamp 3256759C))
  521. */
  522. void parseComponent() throw( IO_ERROR, PARSE_ERROR );
  523. /**
  524. * Function parseNet
  525. * Parses a section like
  526. * (net (code 20) (name /PC-A0)
  527. * (node (ref BUS1) (pin 62))
  528. * (node (ref U3) (pin 3))
  529. * (node (ref U9) (pin M6)))
  530. *
  531. * and set the corresponding pads netnames
  532. */
  533. void parseNet() throw( IO_ERROR, PARSE_ERROR );
  534. /**
  535. * Function parseLibPartList
  536. * reads the section "libparts" in the netlist:
  537. * (libparts
  538. * (libpart (lib device) (part C)
  539. * (description "Condensateur non polarise")
  540. * (footprints
  541. * (fp SM*)
  542. * (fp C?)
  543. * (fp C1-1))
  544. * (fields
  545. * (field (name Reference) C)
  546. * (field (name Value) C))
  547. * (pins
  548. * (pin (num 1) (name ~) (type passive))
  549. * (pin (num 2) (name ~) (type passive))))
  550. *
  551. * And add the strings giving the footprint filter (subsection footprints)
  552. * of the corresponding module info
  553. * <p>This section is used by CvPcb, and is not useful in Pcbnew,
  554. * therefore it it not always read </p>
  555. */
  556. void parseLibPartList() throw( IO_ERROR, PARSE_ERROR );
  557. public:
  558. KICAD_NETLIST_PARSER( LINE_READER* aReader, NETLIST* aNetlist );
  559. void SetLineReader( LINE_READER* aLineReader );
  560. void SetNetlist( NETLIST* aNetlist ) { m_netlist = aNetlist; }
  561. /**
  562. * Function Parse
  563. * parse the full netlist
  564. */
  565. void Parse() throw( IO_ERROR, PARSE_ERROR );
  566. // Useful for debug only:
  567. const char* getTokenName( T aTok )
  568. {
  569. return NETLIST_LEXER::TokenName( aTok );
  570. }
  571. };
  572. /**
  573. * Class KICAD_NETLIST_READER
  574. * read the new s-expression based KiCad netlist format.
  575. */
  576. class KICAD_NETLIST_READER : public NETLIST_READER
  577. {
  578. KICAD_NETLIST_PARSER* m_parser; ///< The s-expression format parser.
  579. public:
  580. KICAD_NETLIST_READER( LINE_READER* aLineReader,
  581. NETLIST* aNetlist,
  582. CMP_READER* aFootprintLinkReader = NULL ) :
  583. NETLIST_READER( aLineReader, aNetlist, aFootprintLinkReader ),
  584. m_parser( new KICAD_NETLIST_PARSER( aLineReader, aNetlist ) )
  585. {
  586. }
  587. virtual ~KICAD_NETLIST_READER()
  588. {
  589. if( m_parser )
  590. delete m_parser;
  591. }
  592. virtual void LoadNetlist() throw ( IO_ERROR, PARSE_ERROR );
  593. };
  594. #endif // NETLIST_READER_H