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.

511 lines
14 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()
  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()
  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()
  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()
  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()
  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 if( token == T_description )
  281. {
  282. NeedSYMBOLorNUMBER();
  283. NeedRIGHT();
  284. }
  285. else
  286. {
  287. Expecting( "part, lib or description" );
  288. }
  289. }
  290. break;
  291. case T_sheetpath:
  292. while( ( token = NextTok() ) != T_tstamps );
  293. NeedSYMBOLorNUMBER();
  294. pathtimestamp = FROM_UTF8( CurText() );
  295. NeedRIGHT();
  296. NeedRIGHT();
  297. break;
  298. case T_tstamp:
  299. NeedSYMBOLorNUMBER();
  300. timestamp = FROM_UTF8( CurText() );
  301. NeedRIGHT();
  302. break;
  303. default:
  304. // Skip not used data (i.e all other tokens)
  305. skipCurrent();
  306. break;
  307. }
  308. }
  309. if( !footprint.IsEmpty() && fpid.Parse( footprint, LIB_ID::ID_PCB, true ) >= 0 )
  310. {
  311. wxString error;
  312. error.Printf( _( "invalid footprint ID in\nfile: \"%s\"\nline: %d\noffset: %d" ),
  313. GetChars( CurSource() ), CurLineNumber(), CurOffset() );
  314. THROW_IO_ERROR( error );
  315. }
  316. pathtimestamp += timestamp;
  317. COMPONENT* component = new COMPONENT( fpid, ref, value, pathtimestamp );
  318. component->SetName( name );
  319. component->SetLibrary( library );
  320. m_netlist->AddComponent( component );
  321. }
  322. void KICAD_NETLIST_PARSER::parseLibPartList()
  323. {
  324. /* Parses a section like
  325. * (libpart (lib device) (part C)
  326. * (aliases
  327. * (alias Cxx)
  328. * (alias Cyy))
  329. * (description "Condensateur non polarise")
  330. * (footprints
  331. * (fp SM*)
  332. * (fp C?)
  333. * (fp C1-1))
  334. * (fields
  335. * (field (name Reference) C)
  336. * (field (name Value) C))
  337. * (pins
  338. * (pin (num 1) (name ~) (type passive))
  339. * (pin (num 2) (name ~) (type passive))))
  340. *
  341. * Currently footprints section/fp are read and data stored
  342. * other fields (unused) are skipped
  343. */
  344. COMPONENT* component = NULL;
  345. wxString libName;
  346. wxString libPartName;
  347. wxArrayString footprintFilters;
  348. wxArrayString aliases;
  349. int pinCount = 0;
  350. // The last token read was libpart, so read the next token
  351. while( (token = NextTok()) != T_RIGHT )
  352. {
  353. if( token == T_LEFT )
  354. token = NextTok();
  355. switch( token )
  356. {
  357. case T_lib:
  358. NeedSYMBOLorNUMBER();
  359. libName = FROM_UTF8( CurText() );
  360. NeedRIGHT();
  361. break;
  362. case T_part:
  363. NeedSYMBOLorNUMBER();
  364. libPartName = FROM_UTF8( CurText() );
  365. NeedRIGHT();
  366. break;
  367. case T_footprints:
  368. // Read all fp elements (footprint filter item)
  369. while( (token = NextTok()) != T_RIGHT )
  370. {
  371. if( token == T_LEFT )
  372. token = NextTok();
  373. if( token != T_fp )
  374. Expecting( T_fp );
  375. NeedSYMBOLorNUMBER();
  376. footprintFilters.Add( FROM_UTF8( CurText() ) );
  377. NeedRIGHT();
  378. }
  379. break;
  380. case T_aliases:
  381. while( (token = NextTok()) != T_RIGHT )
  382. {
  383. if( token == T_LEFT )
  384. token = NextTok();
  385. if( token != T_alias )
  386. Expecting( T_alias );
  387. NeedSYMBOLorNUMBER();
  388. aliases.Add( FROM_UTF8( CurText() ) );
  389. NeedRIGHT();
  390. }
  391. break;
  392. case T_pins:
  393. while( (token = NextTok()) != T_RIGHT )
  394. {
  395. if( token == T_LEFT )
  396. token = NextTok();
  397. if( token != T_pin )
  398. Expecting( T_pin );
  399. pinCount++;
  400. skipCurrent();
  401. }
  402. break;
  403. default:
  404. // Skip not used data (i.e all other tokens)
  405. skipCurrent();
  406. break;
  407. }
  408. }
  409. // Find all of the components that reference this component library part definition.
  410. for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
  411. {
  412. component = m_netlist->GetComponent( i );
  413. if( component->IsLibSource( libName, libPartName ) )
  414. {
  415. component->SetFootprintFilters( footprintFilters );
  416. component->SetPinCount( pinCount );
  417. }
  418. for( unsigned jj = 0; jj < aliases.GetCount(); jj++ )
  419. {
  420. if( component->IsLibSource( libName, aliases[jj] ) )
  421. {
  422. component->SetFootprintFilters( footprintFilters );
  423. component->SetPinCount( pinCount );
  424. }
  425. }
  426. }
  427. }