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.

278 lines
8.0 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2020 KiCad Developers, see change_log.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 <fctsys.h>
  24. #include <drc/drc_rule_parser.h>
  25. #include <drc_rules_lexer.h>
  26. #include <class_board.h>
  27. #include <class_board_item.h>
  28. using namespace DRCRULE_T;
  29. DRC_RULES_PARSER::DRC_RULES_PARSER( BOARD* aBoard, FILE* aFile, const wxString& aFilename ) :
  30. DRC_RULES_LEXER( aFile, aFilename ),
  31. m_board( aBoard ),
  32. m_requiredVersion( 0 ),
  33. m_tooRecent( false )
  34. {
  35. for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
  36. {
  37. std::string untranslated = TO_UTF8( wxString( LSET::Name( PCB_LAYER_ID( layer ) ) ) );
  38. m_layerMap[ untranslated ] = PCB_LAYER_ID( layer );
  39. }
  40. }
  41. void DRC_RULES_PARSER::Parse( std::vector<DRC_SELECTOR*>& aSelectors,
  42. std::vector<DRC_RULE*>& aRules )
  43. {
  44. std::vector< std::pair<DRC_SELECTOR*, wxString> > selectorRules;
  45. T token;
  46. NeedLEFT();
  47. if( NextTok() != T_version )
  48. Expecting( "version" );
  49. NeedNUMBER( "version" );
  50. m_requiredVersion = (int)strtol( CurText(), NULL, 10 );
  51. m_tooRecent = ( m_requiredVersion > DRC_RULE_FILE_VERSION );
  52. NeedRIGHT();
  53. for( token = NextTok(); token != T_EOF; token = NextTok() )
  54. {
  55. if( token != T_LEFT )
  56. Expecting( T_LEFT );
  57. token = NextTok();
  58. switch( token )
  59. {
  60. case T_selector:
  61. {
  62. wxString ruleName;
  63. aSelectors.push_back( parseDRC_SELECTOR( &ruleName ) );
  64. selectorRules.emplace_back( aSelectors.back(), ruleName );
  65. }
  66. break;
  67. case T_rule:
  68. aRules.push_back( parseDRC_RULE() );
  69. break;
  70. default:
  71. Expecting( "selector or rule" );
  72. }
  73. }
  74. // Hook up the selectors to their rules
  75. std::map<wxString, DRC_RULE*> ruleMap;
  76. for( DRC_RULE* rule : aRules )
  77. ruleMap[ rule->m_Name ] = rule;
  78. for( const std::pair<DRC_SELECTOR*, wxString>& entry : selectorRules )
  79. entry.first->m_Rule = ruleMap[ entry.second ];
  80. }
  81. DRC_SELECTOR* DRC_RULES_PARSER::parseDRC_SELECTOR( wxString* aRuleName )
  82. {
  83. NETCLASSES& netclasses = m_board->GetDesignSettings().m_NetClasses;
  84. DRC_SELECTOR* selector = new DRC_SELECTOR();
  85. T token;
  86. for( token = NextTok(); token != T_RIGHT; token = NextTok() )
  87. {
  88. if( token != T_LEFT )
  89. Expecting( T_LEFT );
  90. token = NextTok();
  91. switch( token )
  92. {
  93. case T_match_netclass:
  94. NeedSYMBOL();
  95. selector->m_MatchNetclasses.push_back( netclasses.Find( FromUTF8() ).get() );
  96. NeedRIGHT();
  97. break;
  98. case T_match_type:
  99. switch( NextTok() )
  100. {
  101. case T_track: selector->m_MatchTypes.push_back( PCB_TRACE_T ); break;
  102. case T_via: selector->m_MatchTypes.push_back( PCB_LOCATE_STDVIA_T ); break;
  103. case T_micro_via: selector->m_MatchTypes.push_back( PCB_LOCATE_UVIA_T ); break;
  104. case T_blind_via: selector->m_MatchTypes.push_back( PCB_LOCATE_BBVIA_T ); break;
  105. case T_pad: selector->m_MatchTypes.push_back( PCB_PAD_T ); break;
  106. case T_zone: selector->m_MatchTypes.push_back( PCB_ZONE_AREA_T ); break;
  107. case T_text: selector->m_MatchTypes.push_back( PCB_LOCATE_TEXT_T ); break;
  108. case T_graphic: selector->m_MatchTypes.push_back( PCB_LOCATE_GRAPHIC_T ); break;
  109. case T_hole: selector->m_MatchTypes.push_back( PCB_LOCATE_HOLE_T ); break;
  110. case T_npth: selector->m_MatchTypes.push_back( PCB_LOCATE_NPTH_T ); break;
  111. case T_pth: selector->m_MatchTypes.push_back( PCB_LOCATE_PTH_T ); break;
  112. case T_board_edge: selector->m_MatchTypes.push_back( PCB_LOCATE_BOARD_EDGE_T ); break;
  113. default: Expecting( "track, via, micro_via, blind_via, pad, zone, text, "
  114. "graphic, hole, npth, pth, or board_edge" );
  115. }
  116. NeedRIGHT();
  117. break;
  118. case T_match_layer:
  119. NeedSYMBOL();
  120. selector->m_MatchLayers.push_back( m_layerMap[ curText ] );
  121. NeedRIGHT();
  122. break;
  123. case T_match_area:
  124. // TODO
  125. break;
  126. case T_rule:
  127. NeedSYMBOL();
  128. *aRuleName = FromUTF8();
  129. NeedRIGHT();
  130. break;
  131. case T_priority:
  132. NeedNUMBER( "priority" );
  133. selector->m_Priority = (int)strtol( CurText(), NULL, 10 );
  134. NeedRIGHT();
  135. break;
  136. default:
  137. Expecting( "match_netclass, match_type, match_layer, match_area, rule, or priority" );
  138. }
  139. }
  140. return selector;
  141. }
  142. DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
  143. {
  144. DRC_RULE* rule = new DRC_RULE();
  145. T token;
  146. NeedSYMBOL();
  147. rule->m_Name = FromUTF8();
  148. for( token = NextTok(); token != T_RIGHT; token = NextTok() )
  149. {
  150. if( token != T_LEFT )
  151. Expecting( T_LEFT );
  152. int sign = 1;
  153. token = NextTok();
  154. switch( token )
  155. {
  156. case T_allow:
  157. // TODO
  158. break;
  159. case T_clearance:
  160. if( NextTok() == T_relaxed )
  161. {
  162. sign = -1;
  163. NextTok();
  164. }
  165. rule->m_Clearance = parseValue( T_clearance ) * sign;
  166. NeedRIGHT();
  167. break;
  168. case T_track_width:
  169. if( NextTok() == T_relaxed )
  170. {
  171. sign = -1;
  172. NextTok();
  173. }
  174. rule->m_TrackWidth = parseValue( T_track_width ) * sign;
  175. NeedRIGHT();
  176. break;
  177. case T_annulus_width:
  178. if( NextTok() == T_relaxed )
  179. {
  180. sign = -1;
  181. NextTok();
  182. }
  183. rule->m_AnnulusWidth = parseValue( T_annulus_width ) * sign;
  184. NeedRIGHT();
  185. break;
  186. case T_hole:
  187. if( NextTok() == T_relaxed )
  188. {
  189. sign = -1;
  190. NextTok();
  191. }
  192. rule->m_Hole = parseValue( T_hole ) * sign;
  193. NeedRIGHT();
  194. break;
  195. default:
  196. Expecting( "allow, clearance, track_width, annulus_width, or hole" );
  197. }
  198. }
  199. return rule;
  200. }
  201. int DRC_RULES_PARSER::parseValue( DRCRULE_T::T aToken )
  202. {
  203. char* tmp;
  204. errno = 0;
  205. double fval = strtod( CurText(), &tmp );
  206. if( errno )
  207. {
  208. wxString error;
  209. error.Printf( _( "Invalid floating point number in\nfile: \"%s\"\nline: %d\noffset: %d" ),
  210. GetChars( CurSource() ), CurLineNumber(), CurOffset() );
  211. THROW_IO_ERROR( error );
  212. }
  213. if( CurText() == tmp )
  214. {
  215. wxString error;
  216. error.Printf( _( "Missing floating point number in\nfile: \"%s\"\nline: %d\noffset: %d" ),
  217. GetChars( CurSource() ), CurLineNumber(), CurOffset() );
  218. THROW_IO_ERROR( error );
  219. }
  220. return KiROUND( fval * IU_PER_MM );
  221. }