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.

461 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-2011 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 )
  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. }
  52. void KICAD_NETLIST_PARSER::skipCurrent() throw( IO_ERROR, PARSE_ERROR )
  53. {
  54. int curr_level = 0;
  55. while( ( token = NextTok() ) != T_EOF )
  56. {
  57. if( token == T_LEFT )
  58. curr_level--;
  59. if( token == T_RIGHT )
  60. {
  61. curr_level++;
  62. if( curr_level > 0 )
  63. return;
  64. }
  65. }
  66. }
  67. void KICAD_NETLIST_PARSER::Parse() throw( IO_ERROR, PARSE_ERROR )
  68. {
  69. wxString text;
  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 )
  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. FPID fpid;
  234. wxString footprint;
  235. wxString tmp;
  236. wxString ref;
  237. wxString value;
  238. wxString library;
  239. wxString name;
  240. wxString pathtimestamp, timestamp;
  241. // The token comp was read, so the next data is (ref P1)
  242. while( (token = NextTok()) != T_RIGHT )
  243. {
  244. if( token == T_LEFT )
  245. token = NextTok();
  246. switch( token )
  247. {
  248. case T_ref:
  249. NeedSYMBOLorNUMBER();
  250. ref = FROM_UTF8( CurText() );
  251. NeedRIGHT();
  252. break;
  253. case T_value:
  254. NeedSYMBOLorNUMBER();
  255. value = FROM_UTF8( CurText() );
  256. NeedRIGHT();
  257. break;
  258. case T_footprint:
  259. NeedSYMBOLorNUMBER();
  260. footprint = FromUTF8();
  261. NeedRIGHT();
  262. break;
  263. case T_libsource:
  264. // Read libsource
  265. while( (token = NextTok()) != T_RIGHT )
  266. {
  267. if( token == T_LEFT )
  268. token = NextTok();
  269. if( token == T_lib )
  270. {
  271. NeedSYMBOLorNUMBER();
  272. library = FROM_UTF8( CurText() );
  273. NeedRIGHT();
  274. }
  275. else if( token == T_part )
  276. {
  277. NeedSYMBOLorNUMBER();
  278. name = FROM_UTF8( CurText() );
  279. NeedRIGHT();
  280. }
  281. else
  282. {
  283. Expecting( "part or lib" );
  284. }
  285. }
  286. break;
  287. case T_sheetpath:
  288. while( ( token = NextTok() ) != T_tstamps );
  289. NeedSYMBOLorNUMBER();
  290. pathtimestamp = FROM_UTF8( CurText() );
  291. NeedRIGHT();
  292. NeedRIGHT();
  293. break;
  294. case T_tstamp:
  295. NeedSYMBOLorNUMBER();
  296. timestamp = FROM_UTF8( CurText() );
  297. NeedRIGHT();
  298. break;
  299. default:
  300. // Skip not used data (i.e all other tokens)
  301. skipCurrent();
  302. break;
  303. }
  304. }
  305. if( !footprint.IsEmpty() && fpid.Parse( footprint ) >= 0 )
  306. {
  307. wxString error;
  308. error.Printf( _( "invalid PFID in\nfile: <%s>\nline: %d\noffset: %d" ),
  309. GetChars( CurSource() ), CurLineNumber(), CurOffset() );
  310. THROW_IO_ERROR( error );
  311. }
  312. pathtimestamp += timestamp;
  313. COMPONENT* component = new COMPONENT( fpid, ref, value, pathtimestamp );
  314. component->SetName( name );
  315. component->SetLibrary( library );
  316. m_netlist->AddComponent( component );
  317. }
  318. void KICAD_NETLIST_PARSER::parseLibPartList() throw( IO_ERROR, PARSE_ERROR )
  319. {
  320. /* Parses a section like
  321. * (libpart (lib device) (part C)
  322. * (description "Condensateur non polarise")
  323. * (footprints
  324. * (fp SM*)
  325. * (fp C?)
  326. * (fp C1-1))
  327. * (fields
  328. * (field (name Reference) C)
  329. * (field (name Value) C))
  330. * (pins
  331. * (pin (num 1) (name ~) (type passive))
  332. * (pin (num 2) (name ~) (type passive))))
  333. *
  334. * Currently footprints section/fp are read and data stored
  335. * other fields (unused) are skipped
  336. */
  337. COMPONENT* component = NULL;
  338. wxString libName;
  339. wxString libPartName;
  340. wxArrayString footprintFilters;
  341. // The last token read was libpart, so read the next token
  342. while( (token = NextTok()) != T_RIGHT )
  343. {
  344. if( token == T_LEFT )
  345. token = NextTok();
  346. switch( token )
  347. {
  348. case T_lib:
  349. NeedSYMBOLorNUMBER();
  350. libName = FROM_UTF8( CurText() );
  351. NeedRIGHT();
  352. break;
  353. case T_part:
  354. NeedSYMBOLorNUMBER();
  355. libPartName = FROM_UTF8( CurText() );
  356. NeedRIGHT();
  357. break;
  358. case T_footprints:
  359. // Read all fp elements (footprint filter item)
  360. while( (token = NextTok()) != T_RIGHT )
  361. {
  362. if( token == T_LEFT )
  363. token = NextTok();
  364. if( token != T_fp )
  365. Expecting( T_fp );
  366. NeedSYMBOLorNUMBER();
  367. footprintFilters.Add( FROM_UTF8( CurText() ) );
  368. NeedRIGHT();
  369. }
  370. break;
  371. default:
  372. // Skip not used data (i.e all other tokens)
  373. skipCurrent();
  374. break;
  375. }
  376. }
  377. // Find all of the components that reference this component library part definition.
  378. for( unsigned i = 0; i < m_netlist->GetCount(); i++ )
  379. {
  380. component = m_netlist->GetComponent( i );
  381. if( component->IsLibSource( libName, libPartName ) )
  382. component->SetFootprintFilters( footprintFilters );
  383. }
  384. }