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.

484 lines
13 KiB

  1. /**
  2. * @file kicad_netlist_reader.cpp
  3. */
  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-2016 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. #include <wx/wx.h>
  28. #include <netlist_lexer.h> // netlist_lexer is common to Eeschema and Pcbnew
  29. #include <macros.h>
  30. #include <pcb_netlist.h>
  31. #include <netlist_reader.h>
  32. using namespace NL_T;
  33. void KICAD_NETLIST_READER::LoadNetlist() throw ( IO_ERROR, PARSE_ERROR, boost::bad_pointer )
  34. {
  35. m_parser->Parse();
  36. if( m_footprintReader )
  37. {
  38. m_footprintReader->Load( m_netlist );
  39. // Sort the component pins so they are in the same order as the legacy format. This
  40. // is useful for comparing legacy and s-expression netlist dumps.
  41. for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
  42. m_netlist->GetComponent( i )->SortPins();
  43. }
  44. }
  45. // KICAD_NETLIST_PARSER
  46. KICAD_NETLIST_PARSER::KICAD_NETLIST_PARSER( LINE_READER* aReader, NETLIST* aNetlist ) :
  47. NETLIST_LEXER( aReader )
  48. {
  49. m_lineReader = aReader;
  50. m_netlist = aNetlist;
  51. token = T_NONE;
  52. }
  53. void KICAD_NETLIST_PARSER::skipCurrent() throw( IO_ERROR, PARSE_ERROR )
  54. {
  55. int curr_level = 0;
  56. while( ( token = NextTok() ) != T_EOF )
  57. {
  58. if( token == T_LEFT )
  59. curr_level--;
  60. if( token == T_RIGHT )
  61. {
  62. curr_level++;
  63. if( curr_level > 0 )
  64. return;
  65. }
  66. }
  67. }
  68. void KICAD_NETLIST_PARSER::Parse() throw( IO_ERROR, PARSE_ERROR, boost::bad_pointer )
  69. {
  70. int plevel = 0; // the count of ')' to read and end of file,
  71. // after parsing all sections
  72. while( ( token = NextTok() ) != T_EOF )
  73. {
  74. if( token == T_LEFT )
  75. token = NextTok();
  76. switch( token )
  77. {
  78. case T_export: // The netlist starts here.
  79. // nothing to do here,
  80. // just increment the count of ')' to read and end of file
  81. plevel++;
  82. break;
  83. case T_version: // The netlist starts here.
  84. // version id not yet used: read it but does not use it
  85. NextTok();
  86. NeedRIGHT();
  87. break;
  88. case T_components: // The section comp starts here.
  89. while( ( token = NextTok() ) != T_RIGHT )
  90. {
  91. if( token == T_LEFT )
  92. token = NextTok();
  93. if( token == T_comp ) // A component section found. Read it
  94. parseComponent();
  95. }
  96. break;
  97. case T_nets: // The section nets starts here.
  98. while( ( token = NextTok() ) != T_RIGHT )
  99. {
  100. if( token == T_LEFT )
  101. token = NextTok();
  102. if( token == T_net )
  103. {
  104. // A net section if found. Read it
  105. parseNet();
  106. }
  107. }
  108. break;
  109. case T_libparts: // The section libparts starts here.
  110. while( ( token = NextTok() ) != T_RIGHT )
  111. {
  112. if( token == T_LEFT )
  113. token = NextTok();
  114. if( token == T_libpart )
  115. {
  116. // A libpart section if found. Read it
  117. parseLibPartList();
  118. }
  119. }
  120. break;
  121. case T_libraries: // The section libraries starts here.
  122. // List of libraries in use.
  123. // Not used here, just skip it
  124. skipCurrent();
  125. break;
  126. case T_design: // The section design starts here.
  127. // Not used (mainly they are comments), just skip it
  128. skipCurrent();
  129. break;
  130. case T_RIGHT: // The closing parenthesis of the file.
  131. // Not used (mainly they are comments), just skip it
  132. plevel--;
  133. break;
  134. default:
  135. skipCurrent();
  136. break;
  137. }
  138. }
  139. if( plevel != 0 )
  140. {
  141. wxLogDebug( wxT( "KICAD_NETLIST_PARSER::Parse(): bad parenthesis count (count = %d"),
  142. plevel );
  143. }
  144. }
  145. void KICAD_NETLIST_PARSER::parseNet() throw( IO_ERROR, PARSE_ERROR )
  146. {
  147. /* Parses a section like
  148. * (net (code 20) (name /PC-A0)
  149. * (node (ref BUS1) (pin 62))
  150. * (node (ref U3) (pin 3))
  151. * (node (ref U9) (pin M6)))
  152. */
  153. COMPONENT* component = NULL;
  154. wxString code;
  155. wxString name;
  156. wxString reference;
  157. wxString pin;
  158. int nodecount = 0;
  159. // The token net was read, so the next data is (code <number>)
  160. while( (token = NextTok()) != T_RIGHT )
  161. {
  162. if( token == T_LEFT )
  163. token = NextTok();
  164. switch( token )
  165. {
  166. case T_code:
  167. NeedSYMBOLorNUMBER();
  168. code = FROM_UTF8( CurText() );
  169. NeedRIGHT();
  170. break;
  171. case T_name:
  172. NeedSYMBOLorNUMBER();
  173. name = FROM_UTF8( CurText() );
  174. NeedRIGHT();
  175. if( name.IsEmpty() ) // Give a dummy net name like N-000109
  176. name = wxT("N-00000") + code;
  177. break;
  178. case T_node:
  179. while( (token = NextTok()) != T_RIGHT )
  180. {
  181. if( token == T_LEFT )
  182. token = NextTok();
  183. switch( token )
  184. {
  185. case T_ref:
  186. NeedSYMBOLorNUMBER();
  187. reference = FROM_UTF8( CurText() );
  188. NeedRIGHT();
  189. break;
  190. case T_pin:
  191. NeedSYMBOLorNUMBER();
  192. pin = FROM_UTF8( CurText() );
  193. NeedRIGHT();
  194. break;
  195. default:
  196. skipCurrent();
  197. break;
  198. }
  199. }
  200. component = m_netlist->GetComponentByReference( reference );
  201. // Cannot happen if the netlist is valid.
  202. if( component == NULL )
  203. {
  204. wxString msg;
  205. msg.Printf( _( "Cannot find component with reference \"%s\" in netlist." ),
  206. GetChars( reference ) );
  207. THROW_PARSE_ERROR( msg, m_lineReader->GetSource(), m_lineReader->Line(),
  208. m_lineReader->LineNumber(), m_lineReader->Length() );
  209. }
  210. component->AddNet( pin, name );
  211. nodecount++;
  212. break;
  213. default:
  214. skipCurrent();
  215. break;
  216. }
  217. }
  218. }
  219. void KICAD_NETLIST_PARSER::parseComponent() throw( IO_ERROR, PARSE_ERROR, boost::bad_pointer )
  220. {
  221. /* Parses a section like
  222. * (comp (ref P1)
  223. * (value DB25FEMELLE)
  224. * (footprint DB25FC)
  225. * (libsource (lib conn) (part DB25))
  226. * (sheetpath (names /) (tstamps /))
  227. * (tstamp 3256759C))
  228. *
  229. * other fields (unused) are skipped
  230. * A component need a reference, value, footprint name and a full time stamp
  231. * The full time stamp is the sheetpath time stamp + the component time stamp
  232. */
  233. LIB_ID fpid;
  234. wxString footprint;
  235. wxString ref;
  236. wxString value;
  237. wxString library;
  238. wxString name;
  239. wxString pathtimestamp, timestamp;
  240. // The token comp was read, so the next data is (ref P1)
  241. while( (token = NextTok()) != T_RIGHT )
  242. {
  243. if( token == T_LEFT )
  244. token = NextTok();
  245. switch( token )
  246. {
  247. case T_ref:
  248. NeedSYMBOLorNUMBER();
  249. ref = FROM_UTF8( CurText() );
  250. NeedRIGHT();
  251. break;
  252. case T_value:
  253. NeedSYMBOLorNUMBER();
  254. value = FROM_UTF8( CurText() );
  255. NeedRIGHT();
  256. break;
  257. case T_footprint:
  258. NeedSYMBOLorNUMBER();
  259. footprint = FromUTF8();
  260. NeedRIGHT();
  261. break;
  262. case T_libsource:
  263. // Read libsource
  264. while( (token = NextTok()) != T_RIGHT )
  265. {
  266. if( token == T_LEFT )
  267. token = NextTok();
  268. if( token == T_lib )
  269. {
  270. NeedSYMBOLorNUMBER();
  271. library = FROM_UTF8( CurText() );
  272. NeedRIGHT();
  273. }
  274. else if( token == T_part )
  275. {
  276. NeedSYMBOLorNUMBER();
  277. name = FROM_UTF8( CurText() );
  278. NeedRIGHT();
  279. }
  280. else
  281. {
  282. Expecting( "part or lib" );
  283. }
  284. }
  285. break;
  286. case T_sheetpath:
  287. while( ( token = NextTok() ) != T_tstamps );
  288. NeedSYMBOLorNUMBER();
  289. pathtimestamp = FROM_UTF8( CurText() );
  290. NeedRIGHT();
  291. NeedRIGHT();
  292. break;
  293. case T_tstamp:
  294. NeedSYMBOLorNUMBER();
  295. timestamp = FROM_UTF8( CurText() );
  296. NeedRIGHT();
  297. break;
  298. default:
  299. // Skip not used data (i.e all other tokens)
  300. skipCurrent();
  301. break;
  302. }
  303. }
  304. if( !footprint.IsEmpty() && fpid.Parse( footprint ) >= 0 )
  305. {
  306. wxString error;
  307. error.Printf( _( "invalid footprint ID in\nfile: <%s>\nline: %d\noffset: %d" ),
  308. GetChars( CurSource() ), CurLineNumber(), CurOffset() );
  309. THROW_IO_ERROR( error );
  310. }
  311. pathtimestamp += timestamp;
  312. COMPONENT* component = new COMPONENT( fpid, ref, value, pathtimestamp );
  313. component->SetName( name );
  314. component->SetLibrary( library );
  315. m_netlist->AddComponent( component );
  316. }
  317. void KICAD_NETLIST_PARSER::parseLibPartList() throw( IO_ERROR, PARSE_ERROR )
  318. {
  319. /* Parses a section like
  320. * (libpart (lib device) (part C)
  321. * (aliases
  322. * (alias Cxx)
  323. * (alias Cyy))
  324. * (description "Condensateur non polarise")
  325. * (footprints
  326. * (fp SM*)
  327. * (fp C?)
  328. * (fp C1-1))
  329. * (fields
  330. * (field (name Reference) C)
  331. * (field (name Value) C))
  332. * (pins
  333. * (pin (num 1) (name ~) (type passive))
  334. * (pin (num 2) (name ~) (type passive))))
  335. *
  336. * Currently footprints section/fp are read and data stored
  337. * other fields (unused) are skipped
  338. */
  339. COMPONENT* component = NULL;
  340. wxString libName;
  341. wxString libPartName;
  342. wxArrayString footprintFilters;
  343. wxArrayString aliases;
  344. // The last token read was libpart, so read the next token
  345. while( (token = NextTok()) != T_RIGHT )
  346. {
  347. if( token == T_LEFT )
  348. token = NextTok();
  349. switch( token )
  350. {
  351. case T_lib:
  352. NeedSYMBOLorNUMBER();
  353. libName = FROM_UTF8( CurText() );
  354. NeedRIGHT();
  355. break;
  356. case T_part:
  357. NeedSYMBOLorNUMBER();
  358. libPartName = FROM_UTF8( CurText() );
  359. NeedRIGHT();
  360. break;
  361. case T_footprints:
  362. // Read all fp elements (footprint filter item)
  363. while( (token = NextTok()) != T_RIGHT )
  364. {
  365. if( token == T_LEFT )
  366. token = NextTok();
  367. if( token != T_fp )
  368. Expecting( T_fp );
  369. NeedSYMBOLorNUMBER();
  370. footprintFilters.Add( FROM_UTF8( CurText() ) );
  371. NeedRIGHT();
  372. }
  373. break;
  374. case T_aliases:
  375. while( (token = NextTok()) != T_RIGHT )
  376. {
  377. if( token == T_LEFT )
  378. token = NextTok();
  379. if( token != T_alias )
  380. Expecting( T_alias );
  381. NeedSYMBOLorNUMBER();
  382. aliases.Add( FROM_UTF8( CurText() ) );
  383. NeedRIGHT();
  384. }
  385. break;
  386. default:
  387. // Skip not used data (i.e all other tokens)
  388. skipCurrent();
  389. break;
  390. }
  391. }
  392. // Find all of the components that reference this component library part definition.
  393. for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
  394. {
  395. component = m_netlist->GetComponent( i );
  396. if( component->IsLibSource( libName, libPartName ) )
  397. component->SetFootprintFilters( footprintFilters );
  398. for( unsigned jj = 0; jj < aliases.GetCount(); jj++ )
  399. {
  400. if( component->IsLibSource( libName, aliases[jj] ) )
  401. component->SetFootprintFilters( footprintFilters );
  402. }
  403. }
  404. }