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.

697 lines
22 KiB

5 years ago
4 years ago
4 years ago
4 years ago
4 years ago
1 year ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <board.h>
  24. #include <zones.h>
  25. #include <drc/drc_rule_parser.h>
  26. #include <drc/drc_rule_condition.h>
  27. #include <drc_rules_lexer.h>
  28. #include <pcbexpr_evaluator.h>
  29. #include <reporter.h>
  30. using namespace DRCRULE_T;
  31. DRC_RULES_PARSER::DRC_RULES_PARSER( const wxString& aSource, const wxString& aSourceDescr ) :
  32. DRC_RULES_LEXER( aSource.ToStdString(), aSourceDescr ),
  33. m_requiredVersion( 0 ),
  34. m_tooRecent( false ),
  35. m_reporter( nullptr )
  36. {
  37. }
  38. DRC_RULES_PARSER::DRC_RULES_PARSER( FILE* aFile, const wxString& aFilename ) :
  39. DRC_RULES_LEXER( aFile, aFilename ),
  40. m_requiredVersion( 0 ),
  41. m_tooRecent( false ),
  42. m_reporter( nullptr )
  43. {
  44. }
  45. void DRC_RULES_PARSER::reportError( const wxString& aMessage )
  46. {
  47. wxString rest;
  48. wxString first = aMessage.BeforeFirst( '|', &rest );
  49. if( m_reporter )
  50. {
  51. wxString msg = wxString::Format( _( "ERROR: <a href='%d:%d'>%s</a>%s" ), CurLineNumber(),
  52. CurOffset(), first, rest );
  53. m_reporter->Report( msg, RPT_SEVERITY_ERROR );
  54. }
  55. else
  56. {
  57. wxString msg = wxString::Format( _( "ERROR: %s%s" ), first, rest );
  58. THROW_PARSE_ERROR( msg, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
  59. }
  60. }
  61. void DRC_RULES_PARSER::reportDeprecation( const wxString& oldToken, const wxString newToken )
  62. {
  63. if( m_reporter )
  64. {
  65. wxString msg = wxString::Format( _( "The '%s' keyword has been deprecated. "
  66. "Please use '%s' instead." ),
  67. oldToken,
  68. newToken);
  69. m_reporter->Report( msg, RPT_SEVERITY_WARNING );
  70. }
  71. }
  72. void DRC_RULES_PARSER::parseUnknown()
  73. {
  74. int depth = 1;
  75. for( T token = NextTok(); token != T_EOF; token = NextTok() )
  76. {
  77. if( token == T_LEFT )
  78. depth++;
  79. if( token == T_RIGHT )
  80. {
  81. if( --depth == 0 )
  82. break;
  83. }
  84. }
  85. }
  86. void DRC_RULES_PARSER::Parse( std::vector<std::shared_ptr<DRC_RULE>>& aRules, REPORTER* aReporter )
  87. {
  88. bool haveVersion = false;
  89. wxString msg;
  90. m_reporter = aReporter;
  91. for( T token = NextTok(); token != T_EOF; token = NextTok() )
  92. {
  93. if( token != T_LEFT )
  94. reportError( _( "Missing '('." ) );
  95. token = NextTok();
  96. if( !haveVersion && token != T_version )
  97. {
  98. reportError( _( "Missing version statement." ) );
  99. haveVersion = true; // don't keep on reporting it
  100. }
  101. switch( token )
  102. {
  103. case T_version:
  104. haveVersion = true;
  105. token = NextTok();
  106. if( (int) token == DSN_RIGHT )
  107. {
  108. reportError( _( "Missing version number." ) );
  109. break;
  110. }
  111. if( (int) token == DSN_NUMBER )
  112. {
  113. m_requiredVersion = (int)strtol( CurText(), nullptr, 10 );
  114. m_tooRecent = ( m_requiredVersion > DRC_RULE_FILE_VERSION );
  115. token = NextTok();
  116. }
  117. else
  118. {
  119. msg.Printf( _( "Unrecognized item '%s'.| Expected version number." ),
  120. FromUTF8() );
  121. reportError( msg );
  122. }
  123. if( (int) token != DSN_RIGHT )
  124. {
  125. msg.Printf( _( "Unrecognized item '%s'." ),
  126. FromUTF8() );
  127. reportError( msg );
  128. parseUnknown();
  129. }
  130. break;
  131. case T_rule:
  132. aRules.emplace_back( parseDRC_RULE() );
  133. break;
  134. case T_EOF:
  135. reportError( _( "Incomplete statement." ) );
  136. break;
  137. default:
  138. msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
  139. wxT( "rule or version" ) );
  140. reportError( msg );
  141. parseUnknown();
  142. }
  143. }
  144. if( m_reporter && !m_reporter->HasMessage() )
  145. m_reporter->Report( _( "No errors found." ), RPT_SEVERITY_INFO );
  146. m_reporter = nullptr;
  147. }
  148. std::shared_ptr<DRC_RULE> DRC_RULES_PARSER::parseDRC_RULE()
  149. {
  150. std::shared_ptr<DRC_RULE> rule = std::make_shared<DRC_RULE>();
  151. T token = NextTok();
  152. wxString msg;
  153. if( !IsSymbol( token ) )
  154. reportError( _( "Missing rule name." ) );
  155. rule->m_Name = FromUTF8();
  156. for( token = NextTok(); token != T_RIGHT && token != T_EOF; token = NextTok() )
  157. {
  158. if( token != T_LEFT )
  159. reportError( _( "Missing '('." ) );
  160. token = NextTok();
  161. switch( token )
  162. {
  163. case T_constraint:
  164. parseConstraint( rule.get() );
  165. break;
  166. case T_condition:
  167. token = NextTok();
  168. if( (int) token == DSN_RIGHT )
  169. {
  170. reportError( _( "Missing condition expression." ) );
  171. break;
  172. }
  173. if( IsSymbol( token ) )
  174. {
  175. rule->m_Condition = new DRC_RULE_CONDITION( FromUTF8() );
  176. rule->m_Condition->Compile( m_reporter, CurLineNumber(), CurOffset() );
  177. }
  178. else
  179. {
  180. msg.Printf( _( "Unrecognized item '%s'.| Expected quoted expression." ),
  181. FromUTF8() );
  182. reportError( msg );
  183. }
  184. if( (int) NextTok() != DSN_RIGHT )
  185. {
  186. reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
  187. parseUnknown();
  188. }
  189. break;
  190. case T_layer:
  191. if( rule->m_LayerCondition != LSET::AllLayersMask() )
  192. reportError( _( "'layer' keyword already present." ) );
  193. rule->m_LayerSource = FromUTF8();
  194. rule->m_LayerCondition = parseLayer();
  195. break;
  196. case T_severity:
  197. rule->m_Severity = parseSeverity();
  198. break;
  199. case T_EOF:
  200. reportError( _( "Incomplete statement." ) );
  201. return rule;
  202. default:
  203. msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
  204. wxT( "constraint, condition, or disallow" ) );
  205. reportError( msg );
  206. parseUnknown();
  207. }
  208. }
  209. if( (int) CurTok() != DSN_RIGHT )
  210. reportError( _( "Missing ')'." ) );
  211. return rule;
  212. }
  213. void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
  214. {
  215. DRC_CONSTRAINT c;
  216. int value;
  217. wxString msg;
  218. T token = NextTok();
  219. if( token == T_mechanical_clearance )
  220. {
  221. reportDeprecation( wxT( "mechanical_clearance" ), wxT( "physical_clearance" ) );
  222. token = T_physical_clearance;
  223. }
  224. else if( token == T_mechanical_hole_clearance )
  225. {
  226. reportDeprecation( wxT( "mechanical_hole_clearance" ), wxT( "physical_hole_clearance" ) );
  227. token = T_physical_hole_clearance;
  228. }
  229. else if( token == T_hole )
  230. {
  231. reportDeprecation( wxT( "hole" ), wxT( "hole_size" ) );
  232. token = T_hole_size;
  233. }
  234. else if( (int) token == DSN_RIGHT || token == T_EOF )
  235. {
  236. msg.Printf( _( "Missing constraint type.| Expected %s." ),
  237. wxT( "assertion, clearance, hole_clearance, edge_clearance, "
  238. "physical_clearance, physical_hole_clearance, courtyard_clearance, "
  239. "silk_clearance, hole_size, hole_to_hole, track_width, annular_width, "
  240. "via_diameter, disallow, zone_connection, thermal_relief_gap, "
  241. "thermal_spoke_width, min_resolved_spokes, length, skew, via_count, "
  242. "diff_pair_gap or diff_pair_uncoupled" ) );
  243. reportError( msg );
  244. return;
  245. }
  246. switch( token )
  247. {
  248. case T_assertion: c.m_Type = ASSERTION_CONSTRAINT; break;
  249. case T_clearance: c.m_Type = CLEARANCE_CONSTRAINT; break;
  250. case T_creepage: c.m_Type = CREEPAGE_CONSTRAINT; break;
  251. case T_hole_clearance: c.m_Type = HOLE_CLEARANCE_CONSTRAINT; break;
  252. case T_edge_clearance: c.m_Type = EDGE_CLEARANCE_CONSTRAINT; break;
  253. case T_hole_size: c.m_Type = HOLE_SIZE_CONSTRAINT; break;
  254. case T_hole_to_hole: c.m_Type = HOLE_TO_HOLE_CONSTRAINT; break;
  255. case T_courtyard_clearance: c.m_Type = COURTYARD_CLEARANCE_CONSTRAINT; break;
  256. case T_silk_clearance: c.m_Type = SILK_CLEARANCE_CONSTRAINT; break;
  257. case T_text_height: c.m_Type = TEXT_HEIGHT_CONSTRAINT; break;
  258. case T_text_thickness: c.m_Type = TEXT_THICKNESS_CONSTRAINT; break;
  259. case T_track_width: c.m_Type = TRACK_WIDTH_CONSTRAINT; break;
  260. case T_track_angle: c.m_Type = TRACK_ANGLE_CONSTRAINT; break;
  261. case T_track_segment_length: c.m_Type = TRACK_SEGMENT_LENGTH_CONSTRAINT; break;
  262. case T_connection_width: c.m_Type = CONNECTION_WIDTH_CONSTRAINT; break;
  263. case T_annular_width: c.m_Type = ANNULAR_WIDTH_CONSTRAINT; break;
  264. case T_via_diameter: c.m_Type = VIA_DIAMETER_CONSTRAINT; break;
  265. case T_zone_connection: c.m_Type = ZONE_CONNECTION_CONSTRAINT; break;
  266. case T_thermal_relief_gap: c.m_Type = THERMAL_RELIEF_GAP_CONSTRAINT; break;
  267. case T_thermal_spoke_width: c.m_Type = THERMAL_SPOKE_WIDTH_CONSTRAINT; break;
  268. case T_min_resolved_spokes: c.m_Type = MIN_RESOLVED_SPOKES_CONSTRAINT; break;
  269. case T_disallow: c.m_Type = DISALLOW_CONSTRAINT; break;
  270. case T_length: c.m_Type = LENGTH_CONSTRAINT; break;
  271. case T_skew: c.m_Type = SKEW_CONSTRAINT; break;
  272. case T_via_count: c.m_Type = VIA_COUNT_CONSTRAINT; break;
  273. case T_diff_pair_gap: c.m_Type = DIFF_PAIR_GAP_CONSTRAINT; break;
  274. case T_diff_pair_uncoupled: c.m_Type = MAX_UNCOUPLED_CONSTRAINT; break;
  275. case T_physical_clearance: c.m_Type = PHYSICAL_CLEARANCE_CONSTRAINT; break;
  276. case T_physical_hole_clearance: c.m_Type = PHYSICAL_HOLE_CLEARANCE_CONSTRAINT; break;
  277. default:
  278. msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
  279. wxT( "assertion, clearance, hole_clearance, edge_clearance, "
  280. "physical_clearance, physical_hole_clearance, courtyard_clearance, "
  281. "silk_clearance, hole_size, hole_to_hole, track_width, track_angle, track_segment_length, annular_width, "
  282. "disallow, zone_connection, thermal_relief_gap, thermal_spoke_width, "
  283. "min_resolved_spokes, length, skew, via_count, via_diameter, "
  284. "diff_pair_gap or diff_pair_uncoupled" ) );
  285. reportError( msg );
  286. }
  287. if( aRule->FindConstraint( c.m_Type ) )
  288. {
  289. msg.Printf( _( "Rule already has a '%s' constraint." ), FromUTF8() );
  290. reportError( msg );
  291. }
  292. bool unitless = c.m_Type == VIA_COUNT_CONSTRAINT
  293. || c.m_Type == MIN_RESOLVED_SPOKES_CONSTRAINT
  294. || c.m_Type == TRACK_ANGLE_CONSTRAINT;
  295. if( c.m_Type == DISALLOW_CONSTRAINT )
  296. {
  297. for( token = NextTok(); token != T_RIGHT; token = NextTok() )
  298. {
  299. if( (int) token == DSN_STRING )
  300. token = GetCurStrAsToken();
  301. switch( token )
  302. {
  303. case T_track: c.m_DisallowFlags |= DRC_DISALLOW_TRACKS; break;
  304. case T_via: c.m_DisallowFlags |= DRC_DISALLOW_VIAS; break;
  305. case T_micro_via: c.m_DisallowFlags |= DRC_DISALLOW_MICRO_VIAS; break;
  306. case T_buried_via: c.m_DisallowFlags |= DRC_DISALLOW_BB_VIAS; break;
  307. case T_pad: c.m_DisallowFlags |= DRC_DISALLOW_PADS; break;
  308. case T_zone: c.m_DisallowFlags |= DRC_DISALLOW_ZONES; break;
  309. case T_text: c.m_DisallowFlags |= DRC_DISALLOW_TEXTS; break;
  310. case T_graphic: c.m_DisallowFlags |= DRC_DISALLOW_GRAPHICS; break;
  311. case T_hole: c.m_DisallowFlags |= DRC_DISALLOW_HOLES; break;
  312. case T_footprint: c.m_DisallowFlags |= DRC_DISALLOW_FOOTPRINTS; break;
  313. case T_EOF:
  314. reportError( _( "Missing ')'." ) );
  315. return;
  316. default:
  317. msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
  318. wxT( "track, via, micro_via, buried_via, pad, zone, text, graphic, "
  319. "hole, or footprint." ) );
  320. reportError( msg );
  321. break;
  322. }
  323. }
  324. if( (int) CurTok() != DSN_RIGHT )
  325. reportError( _( "Missing ')'." ) );
  326. aRule->AddConstraint( c );
  327. return;
  328. }
  329. else if( c.m_Type == ZONE_CONNECTION_CONSTRAINT )
  330. {
  331. token = NextTok();
  332. if( (int) token == DSN_STRING )
  333. token = GetCurStrAsToken();
  334. switch( token )
  335. {
  336. case T_solid: c.m_ZoneConnection = ZONE_CONNECTION::FULL; break;
  337. case T_thermal_reliefs: c.m_ZoneConnection = ZONE_CONNECTION::THERMAL; break;
  338. case T_none: c.m_ZoneConnection = ZONE_CONNECTION::NONE; break;
  339. case T_EOF:
  340. reportError( _( "Missing ')'." ) );
  341. return;
  342. default:
  343. msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
  344. "solid, thermal_reliefs or none." );
  345. reportError( msg );
  346. break;
  347. }
  348. if( (int) NextTok() != DSN_RIGHT )
  349. reportError( _( "Missing ')'." ) );
  350. aRule->AddConstraint( c );
  351. return;
  352. }
  353. else if( c.m_Type == MIN_RESOLVED_SPOKES_CONSTRAINT )
  354. {
  355. // We don't use a min/max/opt structure here because it would give a strong implication
  356. // that you could specify the optimal number of spokes. We don't want to open that door
  357. // because the spoke generator is highly optimized around being able to "cheat" off of a
  358. // cartesian coordinate system.
  359. token = NextTok();
  360. if( (int) token == DSN_NUMBER )
  361. {
  362. value = (int) strtol( CurText(), nullptr, 10 );
  363. c.m_Value.SetMin( value );
  364. }
  365. else
  366. {
  367. reportError( _( "Expecting number." ) );
  368. parseUnknown();
  369. }
  370. if( (int) NextTok() != DSN_RIGHT )
  371. reportError( _( "Missing ')'." ) );
  372. aRule->AddConstraint( c );
  373. return;
  374. }
  375. else if( c.m_Type == ASSERTION_CONSTRAINT )
  376. {
  377. token = NextTok();
  378. if( (int) token == DSN_RIGHT )
  379. reportError( _( "Missing assertion expression." ) );
  380. if( IsSymbol( token ) )
  381. {
  382. c.m_Test = new DRC_RULE_CONDITION( FromUTF8() );
  383. c.m_Test->Compile( m_reporter, CurLineNumber(), CurOffset() );
  384. }
  385. else
  386. {
  387. msg.Printf( _( "Unrecognized item '%s'.| Expected quoted expression." ), FromUTF8() );
  388. reportError( msg );
  389. }
  390. if( (int) NextTok() != DSN_RIGHT )
  391. {
  392. reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
  393. parseUnknown();
  394. }
  395. aRule->AddConstraint( c );
  396. return;
  397. }
  398. for( token = NextTok(); token != T_RIGHT && token != T_EOF; token = NextTok() )
  399. {
  400. if( token != T_LEFT )
  401. reportError( _( "Missing '('." ) );
  402. token = NextTok();
  403. switch( token )
  404. {
  405. case T_within_diff_pairs:
  406. if( c.m_Type != SKEW_CONSTRAINT )
  407. {
  408. reportError( _( "within_diff_pairs option invalid for constraint type." ) );
  409. break;
  410. }
  411. c.SetOption( DRC_CONSTRAINT::OPTIONS::SKEW_WITHIN_DIFF_PAIRS );
  412. if( (int) NextTok() != DSN_RIGHT )
  413. {
  414. reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
  415. parseUnknown();
  416. }
  417. break;
  418. case T_min:
  419. token = NextTok();
  420. if( (int) token == DSN_RIGHT )
  421. {
  422. reportError( _( "Missing min value." ) );
  423. break;
  424. }
  425. parseValueWithUnits( FromUTF8(), value, unitless );
  426. c.m_Value.SetMin( value );
  427. if( (int) NextTok() != DSN_RIGHT )
  428. {
  429. reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
  430. parseUnknown();
  431. }
  432. break;
  433. case T_max:
  434. token = NextTok();
  435. if( (int) token == DSN_RIGHT )
  436. {
  437. reportError( _( "Missing max value." ) );
  438. break;
  439. }
  440. parseValueWithUnits( FromUTF8(), value, unitless );
  441. c.m_Value.SetMax( value );
  442. if( (int) NextTok() != DSN_RIGHT )
  443. {
  444. reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
  445. parseUnknown();
  446. }
  447. break;
  448. case T_opt:
  449. token = NextTok();
  450. if( (int) token == DSN_RIGHT )
  451. {
  452. reportError( _( "Missing opt value." ) );
  453. break;
  454. }
  455. parseValueWithUnits( FromUTF8(), value, unitless );
  456. c.m_Value.SetOpt( value );
  457. if( (int) NextTok() != DSN_RIGHT )
  458. {
  459. reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
  460. parseUnknown();
  461. }
  462. break;
  463. case T_EOF:
  464. reportError( _( "Incomplete statement." ) );
  465. return;
  466. default:
  467. msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ),
  468. FromUTF8(),
  469. wxT( "min, max, or opt" ) );
  470. reportError( msg );
  471. parseUnknown();
  472. }
  473. }
  474. if( (int) CurTok() != DSN_RIGHT )
  475. reportError( _( "Missing ')'." ) );
  476. aRule->AddConstraint( c );
  477. }
  478. void DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult, bool aUnitless )
  479. {
  480. auto errorHandler = [&]( const wxString& aMessage, int aOffset )
  481. {
  482. wxString rest;
  483. wxString first = aMessage.BeforeFirst( '|', &rest );
  484. if( m_reporter )
  485. {
  486. wxString msg = wxString::Format( _( "ERROR: <a href='%d:%d'>%s</a>%s" ),
  487. CurLineNumber(), CurOffset() + aOffset, first, rest );
  488. m_reporter->Report( msg, RPT_SEVERITY_ERROR );
  489. }
  490. else
  491. {
  492. wxString msg = wxString::Format( _( "ERROR: %s%s" ), first, rest );
  493. THROW_PARSE_ERROR( msg, CurSource(), CurLine(), CurLineNumber(),
  494. CurOffset() + aOffset );
  495. }
  496. };
  497. PCBEXPR_EVALUATOR evaluator( aUnitless ? (LIBEVAL::UNIT_RESOLVER*) new PCBEXPR_UNITLESS_RESOLVER()
  498. : (LIBEVAL::UNIT_RESOLVER*) new PCBEXPR_UNIT_RESOLVER() );
  499. evaluator.SetErrorCallback( errorHandler );
  500. evaluator.Evaluate( aExpr );
  501. aResult = evaluator.Result();
  502. }
  503. LSET DRC_RULES_PARSER::parseLayer()
  504. {
  505. LSET retVal;
  506. int token = NextTok();
  507. if( (int) token == DSN_RIGHT )
  508. {
  509. reportError( _( "Missing layer name or type." ) );
  510. return LSET::AllCuMask();
  511. }
  512. else if( token == T_outer )
  513. {
  514. retVal = LSET::ExternalCuMask();
  515. }
  516. else if( token == T_inner )
  517. {
  518. retVal = LSET::InternalCuMask();
  519. }
  520. else
  521. {
  522. wxString layerName = FromUTF8();
  523. wxPGChoices& layerMap = ENUM_MAP<PCB_LAYER_ID>::Instance().Choices();
  524. for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
  525. {
  526. wxPGChoiceEntry& entry = layerMap[ii];
  527. if( entry.GetText().Matches( layerName ) )
  528. retVal.set( ToLAYER_ID( entry.GetValue() ) );
  529. }
  530. if( !retVal.any() )
  531. {
  532. reportError( wxString::Format( _( "Unrecognized layer '%s'." ), layerName ) );
  533. retVal.set( Rescue );
  534. }
  535. }
  536. if( (int) NextTok() != DSN_RIGHT )
  537. {
  538. reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
  539. parseUnknown();
  540. }
  541. return retVal;
  542. }
  543. SEVERITY DRC_RULES_PARSER::parseSeverity()
  544. {
  545. SEVERITY retVal = RPT_SEVERITY_UNDEFINED;
  546. wxString msg;
  547. T token = NextTok();
  548. if( (int) token == DSN_RIGHT || token == T_EOF )
  549. {
  550. reportError( _( "Missing severity name." ) );
  551. return RPT_SEVERITY_UNDEFINED;
  552. }
  553. switch( token )
  554. {
  555. case T_ignore: retVal = RPT_SEVERITY_IGNORE; break;
  556. case T_warning: retVal = RPT_SEVERITY_WARNING; break;
  557. case T_error: retVal = RPT_SEVERITY_ERROR; break;
  558. case T_exclusion: retVal = RPT_SEVERITY_EXCLUSION; break;
  559. default:
  560. msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ),
  561. FromUTF8(),
  562. wxT( "ignore, warning, error, or exclusion" ) );
  563. reportError( msg );
  564. parseUnknown();
  565. }
  566. if( (int) NextTok() != DSN_RIGHT )
  567. reportError( _( "Missing ')'." ) );
  568. return retVal;
  569. }