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.

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