KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_rule_parser.cpp
Go to the documentation of this file.
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
24
25#include <board.h>
26#include <zones.h>
27#include <drc/drc_rule_parser.h>
29#include <drc_rules_lexer.h>
30#include <pcbexpr_evaluator.h>
31#include <reporter.h>
33
34using namespace DRCRULE_T;
35
36
37DRC_RULES_PARSER::DRC_RULES_PARSER( const wxString& aSource, const wxString& aSourceDescr ) :
38 DRC_RULES_LEXER( aSource.ToStdString(), aSourceDescr ),
39 m_requiredVersion( 0 ),
40 m_tooRecent( false ),
41 m_reporter( nullptr )
42{
43}
44
45
46DRC_RULES_PARSER::DRC_RULES_PARSER( FILE* aFile, const wxString& aFilename ) :
47 DRC_RULES_LEXER( aFile, aFilename ),
48 m_requiredVersion( 0 ),
49 m_tooRecent( false ),
50 m_reporter( nullptr )
51{
52}
53
54
55void DRC_RULES_PARSER::reportError( const wxString& aMessage )
56{
57 wxString rest;
58 wxString first = aMessage.BeforeFirst( '|', &rest );
59
60 if( m_reporter )
61 {
62 wxString msg = wxString::Format( _( "ERROR: <a href='%d:%d'>%s</a>%s" ), CurLineNumber(),
63 CurOffset(), first, rest );
64
66 }
67 else
68 {
69 wxString msg = wxString::Format( _( "ERROR: %s%s" ), first, rest );
70
71 THROW_PARSE_ERROR( msg, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
72 }
73}
74
75
76void DRC_RULES_PARSER::reportDeprecation( const wxString& oldToken, const wxString newToken )
77{
78 if( m_reporter )
79 {
80 wxString msg = wxString::Format( _( "The '%s' keyword has been deprecated. "
81 "Please use '%s' instead." ),
82 oldToken,
83 newToken);
84
86 }
87}
88
89
91{
92 int depth = 1;
93
94 for( T token = NextTok(); token != T_EOF; token = NextTok() )
95 {
96 if( token == T_LEFT )
97 depth++;
98
99 if( token == T_RIGHT )
100 {
101 if( --depth == 0 )
102 break;
103 }
104 }
105}
106
107
108void DRC_RULES_PARSER::Parse( std::vector<std::shared_ptr<DRC_RULE>>& aRules, REPORTER* aReporter )
109{
110 bool haveVersion = false;
111 wxString msg;
112
113 m_reporter = aReporter;
114
115 for( T token = NextTok(); token != T_EOF; token = NextTok() )
116 {
117 if( token != T_LEFT )
118 reportError( _( "Missing '('." ) );
119
120 token = NextTok();
121
122 if( !haveVersion && token != T_version )
123 {
124 reportError( _( "Missing version statement." ) );
125 haveVersion = true; // don't keep on reporting it
126 }
127
128 switch( token )
129 {
130 case T_version:
131 haveVersion = true;
132 token = NextTok();
133
134 if( (int) token == DSN_RIGHT )
135 {
136 reportError( _( "Missing version number." ) );
137 break;
138 }
139
140 if( (int) token == DSN_NUMBER )
141 {
142 m_requiredVersion = (int)strtol( CurText(), nullptr, 10 );
144 token = NextTok();
145 }
146 else
147 {
148 msg.Printf( _( "Unrecognized item '%s'.| Expected version number." ),
149 FromUTF8() );
150 reportError( msg );
151 }
152
153 if( (int) token != DSN_RIGHT )
154 {
155 msg.Printf( _( "Unrecognized item '%s'." ),
156 FromUTF8() );
157 reportError( msg );
158 parseUnknown();
159 }
160
161 break;
162
163 case T_rule:
164 aRules.emplace_back( parseDRC_RULE() );
165 break;
166
167 case T_EOF:
168 reportError( _( "Incomplete statement." ) );
169 break;
170
171 default:
172 msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
173 wxT( "rule or version" ) );
174 reportError( msg );
175 parseUnknown();
176 }
177 }
178
179 if( m_reporter && !m_reporter->HasMessage() )
180 m_reporter->Report( _( "No errors found." ), RPT_SEVERITY_INFO );
181
182 m_reporter = nullptr;
183}
184
185
187 std::vector<std::shared_ptr<COMPONENT_CLASS_ASSIGNMENT_RULE>>& aRules, REPORTER* aReporter )
188{
189 bool haveVersion = false;
190 wxString msg;
191
192 m_reporter = aReporter;
193
194 for( T token = NextTok(); token != T_EOF; token = NextTok() )
195 {
196 if( token != T_LEFT )
197 reportError( _( "Missing '('." ) );
198
199 token = NextTok();
200
201 if( !haveVersion && token != T_version )
202 {
203 reportError( _( "Missing version statement." ) );
204 haveVersion = true; // don't keep on reporting it
205 }
206
207 switch( token )
208 {
209 case T_version:
210 haveVersion = true;
211 token = NextTok();
212
213 if( (int) token == DSN_RIGHT )
214 {
215 reportError( _( "Missing version number." ) );
216 break;
217 }
218
219 if( (int) token == DSN_NUMBER )
220 {
221 m_requiredVersion = (int) strtol( CurText(), nullptr, 10 );
223 token = NextTok();
224 }
225 else
226 {
227 msg.Printf( _( "Unrecognized item '%s'.| Expected version number." ), FromUTF8() );
228 reportError( msg );
229 }
230
231 if( (int) token != DSN_RIGHT )
232 {
233 msg.Printf( _( "Unrecognized item '%s'." ), FromUTF8() );
234 reportError( msg );
235 parseUnknown();
236 }
237
238 break;
239
240 case T_assign_component_class:
241 aRules.emplace_back( parseComponentClassAssignment() );
242 break;
243
244 case T_EOF: reportError( _( "Incomplete statement." ) ); break;
245
246 default:
247 msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
248 wxT( "assign_component_class or version" ) );
249 reportError( msg );
250 parseUnknown();
251 }
252 }
253
254 if( m_reporter && !m_reporter->HasMessage() )
255 m_reporter->Report( _( "No errors found." ), RPT_SEVERITY_INFO );
256
257 m_reporter = nullptr;
258}
259
260
261std::shared_ptr<DRC_RULE> DRC_RULES_PARSER::parseDRC_RULE()
262{
263 std::shared_ptr<DRC_RULE> rule = std::make_shared<DRC_RULE>();
264
265 T token = NextTok();
266 wxString msg;
267
268 if( !IsSymbol( token ) )
269 reportError( _( "Missing rule name." ) );
270
271 rule->m_Name = FromUTF8();
272
273 for( token = NextTok(); token != T_RIGHT && token != T_EOF; token = NextTok() )
274 {
275 if( token != T_LEFT )
276 reportError( _( "Missing '('." ) );
277
278 token = NextTok();
279
280 switch( token )
281 {
282 case T_constraint:
283 parseConstraint( rule.get() );
284 break;
285
286 case T_condition:
287 token = NextTok();
288
289 if( (int) token == DSN_RIGHT )
290 {
291 reportError( _( "Missing condition expression." ) );
292 break;
293 }
294
295 if( IsSymbol( token ) )
296 {
297 rule->m_Condition = new DRC_RULE_CONDITION( FromUTF8() );
298 rule->m_Condition->Compile( m_reporter, CurLineNumber(), CurOffset() );
299 }
300 else
301 {
302 msg.Printf( _( "Unrecognized item '%s'.| Expected quoted expression." ),
303 FromUTF8() );
304 reportError( msg );
305 }
306
307 if( (int) NextTok() != DSN_RIGHT )
308 {
309 reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
310 parseUnknown();
311 }
312
313 break;
314
315 case T_layer:
316 if( rule->m_LayerCondition != LSET::AllLayersMask() )
317 reportError( _( "'layer' keyword already present." ) );
318
319 rule->m_LayerCondition = parseLayer( &rule->m_LayerSource );
320 break;
321
322 case T_severity:
323 rule->m_Severity = parseSeverity();
324 break;
325
326 case T_EOF:
327 reportError( _( "Incomplete statement." ) );
328 return rule;
329
330 default:
331 msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
332 wxT( "constraint, condition, or disallow" ) );
333 reportError( msg );
334 parseUnknown();
335 }
336 }
337
338 if( (int) CurTok() != DSN_RIGHT )
339 reportError( _( "Missing ')'." ) );
340
341 return rule;
342}
343
344
345std::shared_ptr<COMPONENT_CLASS_ASSIGNMENT_RULE> DRC_RULES_PARSER::parseComponentClassAssignment()
346{
347 std::shared_ptr<DRC_RULE_CONDITION> condition;
348
349 T token = NextTok();
350 wxString msg;
351
352 if( !IsSymbol( token ) )
353 reportError( _( "Missing component class name." ) );
354
355 wxString componentClass = FromUTF8();
356
357 for( token = NextTok(); token != T_RIGHT && token != T_EOF; token = NextTok() )
358 {
359 if( token != T_LEFT )
360 reportError( _( "Missing '('." ) );
361
362 token = NextTok();
363
364 switch( token )
365 {
366 case T_condition:
367 token = NextTok();
368
369 if( (int) token == DSN_RIGHT )
370 {
371 reportError( _( "Missing condition expression." ) );
372 break;
373 }
374
375 if( IsSymbol( token ) )
376 {
377 condition = std::make_shared<DRC_RULE_CONDITION>( FromUTF8() );
378
379 if( !condition->Compile( m_reporter, CurLineNumber(), CurOffset() ) )
380 {
381 reportError( wxString::Format( _( "Could not parse expression '%s'." ),
382 FromUTF8() ) );
383 }
384 }
385 else
386 {
387 msg.Printf( _( "Unrecognized item '%s'.| Expected quoted expression." ),
388 FromUTF8() );
389 reportError( msg );
390 }
391
392 if( (int) NextTok() != DSN_RIGHT )
393 {
394 reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
395 parseUnknown();
396 }
397
398 break;
399
400 case T_EOF: reportError( _( "Incomplete statement." ) ); return nullptr;
401
402 default:
403 msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
404 wxT( "condition" ) );
405 reportError( msg );
406 parseUnknown();
407 }
408 }
409
410 if( (int) CurTok() != DSN_RIGHT )
411 reportError( _( "Missing ')'." ) );
412
413 return std::make_shared<COMPONENT_CLASS_ASSIGNMENT_RULE>( componentClass,
414 std::move( condition ) );
415 ;
416}
417
418
420{
422 int value;
423 EDA_UNITS units = EDA_UNITS::UNSCALED;
424 EDA_DATA_TYPE unitsType = EDA_DATA_TYPE::UNITLESS;
425 wxString msg;
426 bool allowsTimeDomain = false;
427
428 auto validateAndSetValueWithUnits =
429 [this, &allowsTimeDomain, &unitsType, &c]( int aValue, const EDA_UNITS aUnits, auto aSetter )
430 {
431 const EDA_DATA_TYPE unitsTypeTmp = UNITS_PROVIDER::GetTypeFromUnits( aUnits );
432
433 if( !allowsTimeDomain && unitsTypeTmp == EDA_DATA_TYPE::TIME )
434 reportError( _( "Time based units not allowed for constraint type." ) );
435
436 if( ( c.m_Value.HasMin() || c.m_Value.HasMax() || c.m_Value.HasOpt() ) && unitsType != unitsTypeTmp )
437 {
438 reportError( _( "Mixed units for constraint values." ) );
439 }
440
441 unitsType = unitsTypeTmp;
442 aSetter( aValue );
443
444 if( allowsTimeDomain )
445 {
446 if( unitsType == EDA_DATA_TYPE::TIME )
447 {
450 }
451 else
452 {
455 }
456 }
457 };
458
459 T token = NextTok();
460
461 if( token == T_mechanical_clearance )
462 {
463 reportDeprecation( wxT( "mechanical_clearance" ), wxT( "physical_clearance" ) );
464 token = T_physical_clearance;
465 }
466 else if( token == T_mechanical_hole_clearance )
467 {
468 reportDeprecation( wxT( "mechanical_hole_clearance" ), wxT( "physical_hole_clearance" ) );
469 token = T_physical_hole_clearance;
470 }
471 else if( token == T_hole )
472 {
473 reportDeprecation( wxT( "hole" ), wxT( "hole_size" ) );
474 token = T_hole_size;
475 }
476 else if( (int) token == DSN_RIGHT || token == T_EOF )
477 {
478 msg.Printf( _( "Missing constraint type.| Expected %s." ),
479 wxT( "assertion, clearance, hole_clearance, edge_clearance, "
480 "physical_clearance, physical_hole_clearance, courtyard_clearance, "
481 "silk_clearance, hole_size, hole_to_hole, track_width, annular_width, "
482 "via_diameter, disallow, zone_connection, thermal_relief_gap, "
483 "thermal_spoke_width, min_resolved_spokes, length, skew, via_count, "
484 "diff_pair_gap or diff_pair_uncoupled" ) );
485 reportError( msg );
486 return;
487 }
488
489 switch( token )
490 {
491 case T_assertion: c.m_Type = ASSERTION_CONSTRAINT; break;
492 case T_clearance: c.m_Type = CLEARANCE_CONSTRAINT; break;
493 case T_creepage: c.m_Type = CREEPAGE_CONSTRAINT; break;
494 case T_hole_clearance: c.m_Type = HOLE_CLEARANCE_CONSTRAINT; break;
495 case T_edge_clearance: c.m_Type = EDGE_CLEARANCE_CONSTRAINT; break;
496 case T_hole_size: c.m_Type = HOLE_SIZE_CONSTRAINT; break;
497 case T_hole_to_hole: c.m_Type = HOLE_TO_HOLE_CONSTRAINT; break;
498 case T_courtyard_clearance: c.m_Type = COURTYARD_CLEARANCE_CONSTRAINT; break;
499 case T_silk_clearance: c.m_Type = SILK_CLEARANCE_CONSTRAINT; break;
500 case T_text_height: c.m_Type = TEXT_HEIGHT_CONSTRAINT; break;
501 case T_text_thickness: c.m_Type = TEXT_THICKNESS_CONSTRAINT; break;
502 case T_track_width: c.m_Type = TRACK_WIDTH_CONSTRAINT; break;
503 case T_track_angle: c.m_Type = TRACK_ANGLE_CONSTRAINT; break;
504 case T_track_segment_length: c.m_Type = TRACK_SEGMENT_LENGTH_CONSTRAINT; break;
505 case T_connection_width: c.m_Type = CONNECTION_WIDTH_CONSTRAINT; break;
506 case T_annular_width: c.m_Type = ANNULAR_WIDTH_CONSTRAINT; break;
507 case T_via_diameter: c.m_Type = VIA_DIAMETER_CONSTRAINT; break;
508 case T_zone_connection: c.m_Type = ZONE_CONNECTION_CONSTRAINT; break;
509 case T_thermal_relief_gap: c.m_Type = THERMAL_RELIEF_GAP_CONSTRAINT; break;
510 case T_thermal_spoke_width: c.m_Type = THERMAL_SPOKE_WIDTH_CONSTRAINT; break;
511 case T_min_resolved_spokes: c.m_Type = MIN_RESOLVED_SPOKES_CONSTRAINT; break;
512 case T_disallow: c.m_Type = DISALLOW_CONSTRAINT; break;
513 case T_length: c.m_Type = LENGTH_CONSTRAINT; break;
514 case T_skew: c.m_Type = SKEW_CONSTRAINT; break;
515 case T_via_count: c.m_Type = VIA_COUNT_CONSTRAINT; break;
516 case T_diff_pair_gap: c.m_Type = DIFF_PAIR_GAP_CONSTRAINT; break;
517 case T_diff_pair_uncoupled: c.m_Type = MAX_UNCOUPLED_CONSTRAINT; break;
518 case T_physical_clearance: c.m_Type = PHYSICAL_CLEARANCE_CONSTRAINT; break;
519 case T_physical_hole_clearance: c.m_Type = PHYSICAL_HOLE_CLEARANCE_CONSTRAINT; break;
520 default:
521 msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
522 wxT( "assertion, clearance, hole_clearance, edge_clearance, "
523 "physical_clearance, physical_hole_clearance, courtyard_clearance, "
524 "silk_clearance, hole_size, hole_to_hole, track_width, track_angle, track_segment_length, annular_width, "
525 "disallow, zone_connection, thermal_relief_gap, thermal_spoke_width, "
526 "min_resolved_spokes, length, skew, via_count, via_diameter, "
527 "diff_pair_gap or diff_pair_uncoupled" ) );
528 reportError( msg );
529 }
530
531 if( aRule->FindConstraint( c.m_Type ) )
532 {
533 msg.Printf( _( "Rule already has a '%s' constraint." ), FromUTF8() );
534 reportError( msg );
535 }
536
537 bool unitless = c.m_Type == VIA_COUNT_CONSTRAINT
540
541 allowsTimeDomain = c.m_Type == LENGTH_CONSTRAINT || c.m_Type == SKEW_CONSTRAINT;
542
543 if( c.m_Type == DISALLOW_CONSTRAINT )
544 {
545 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
546 {
547 if( (int) token == DSN_STRING )
548 token = GetCurStrAsToken();
549
550 switch( token )
551 {
552 case T_track: c.m_DisallowFlags |= DRC_DISALLOW_TRACKS; break;
553 case T_via: c.m_DisallowFlags |= DRC_DISALLOW_VIAS; break;
554 case T_micro_via: c.m_DisallowFlags |= DRC_DISALLOW_MICRO_VIAS; break;
555 case T_buried_via: c.m_DisallowFlags |= DRC_DISALLOW_BB_VIAS; break;
556 case T_pad: c.m_DisallowFlags |= DRC_DISALLOW_PADS; break;
557 case T_zone: c.m_DisallowFlags |= DRC_DISALLOW_ZONES; break;
558 case T_text: c.m_DisallowFlags |= DRC_DISALLOW_TEXTS; break;
559 case T_graphic: c.m_DisallowFlags |= DRC_DISALLOW_GRAPHICS; break;
560 case T_hole: c.m_DisallowFlags |= DRC_DISALLOW_HOLES; break;
561 case T_footprint: c.m_DisallowFlags |= DRC_DISALLOW_FOOTPRINTS; break;
562
563 case T_EOF:
564 reportError( _( "Missing ')'." ) );
565 return;
566
567 default:
568 msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
569 wxT( "track, via, micro_via, buried_via, pad, zone, text, graphic, "
570 "hole, or footprint." ) );
571 reportError( msg );
572 break;
573 }
574 }
575
576 if( (int) CurTok() != DSN_RIGHT )
577 reportError( _( "Missing ')'." ) );
578
579 aRule->AddConstraint( c );
580 return;
581 }
582 else if( c.m_Type == ZONE_CONNECTION_CONSTRAINT )
583 {
584 token = NextTok();
585
586 if( (int) token == DSN_STRING )
587 token = GetCurStrAsToken();
588
589 switch( token )
590 {
591 case T_solid: c.m_ZoneConnection = ZONE_CONNECTION::FULL; break;
592 case T_thermal_reliefs: c.m_ZoneConnection = ZONE_CONNECTION::THERMAL; break;
593 case T_none: c.m_ZoneConnection = ZONE_CONNECTION::NONE; break;
594
595 case T_EOF:
596 reportError( _( "Missing ')'." ) );
597 return;
598
599 default:
600 msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ), FromUTF8(),
601 "solid, thermal_reliefs or none." );
602 reportError( msg );
603 break;
604 }
605
606 if( (int) NextTok() != DSN_RIGHT )
607 reportError( _( "Missing ')'." ) );
608
609 aRule->AddConstraint( c );
610 return;
611 }
613 {
614 // We don't use a min/max/opt structure here because it would give a strong implication
615 // that you could specify the optimal number of spokes. We don't want to open that door
616 // because the spoke generator is highly optimized around being able to "cheat" off of a
617 // cartesian coordinate system.
618
619 token = NextTok();
620
621 if( (int) token == DSN_NUMBER )
622 {
623 value = (int) strtol( CurText(), nullptr, 10 );
624 c.m_Value.SetMin( value );
625 }
626 else
627 {
628 reportError( _( "Expecting number." ) );
629 parseUnknown();
630 }
631
632 if( (int) NextTok() != DSN_RIGHT )
633 reportError( _( "Missing ')'." ) );
634
635 aRule->AddConstraint( c );
636 return;
637 }
638 else if( c.m_Type == ASSERTION_CONSTRAINT )
639 {
640 token = NextTok();
641
642 if( (int) token == DSN_RIGHT )
643 reportError( _( "Missing assertion expression." ) );
644
645 if( IsSymbol( token ) )
646 {
647 c.m_Test = new DRC_RULE_CONDITION( FromUTF8() );
648 c.m_Test->Compile( m_reporter, CurLineNumber(), CurOffset() );
649 }
650 else
651 {
652 msg.Printf( _( "Unrecognized item '%s'.| Expected quoted expression." ), FromUTF8() );
653 reportError( msg );
654 }
655
656 if( (int) NextTok() != DSN_RIGHT )
657 {
658 reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
659 parseUnknown();
660 }
661
662 aRule->AddConstraint( c );
663 return;
664 }
665
666 for( token = NextTok(); token != T_RIGHT && token != T_EOF; token = NextTok() )
667 {
668 if( token != T_LEFT )
669 reportError( _( "Missing '('." ) );
670
671 token = NextTok();
672
673 switch( token )
674 {
675 case T_within_diff_pairs:
676 if( c.m_Type != SKEW_CONSTRAINT )
677 {
678 reportError( _( "within_diff_pairs option invalid for constraint type." ) );
679 break;
680 }
681
683
684 if( (int) NextTok() != DSN_RIGHT )
685 {
686 reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
687 parseUnknown();
688 }
689
690 break;
691 case T_min:
692 token = NextTok();
693
694 if( (int) token == DSN_RIGHT )
695 {
696 reportError( _( "Missing min value." ) );
697 break;
698 }
699
700 parseValueWithUnits( FromUTF8(), value, units, unitless );
701 validateAndSetValueWithUnits( value, units,
702 [&c]( const int aValue )
703 {
704 c.m_Value.SetMin( aValue );
705 } );
706
707 if( (int) NextTok() != DSN_RIGHT )
708 {
709 reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
710 parseUnknown();
711 }
712
713 break;
714
715 case T_max:
716 token = NextTok();
717
718 if( (int) token == DSN_RIGHT )
719 {
720 reportError( _( "Missing max value." ) );
721 break;
722 }
723
724 parseValueWithUnits( FromUTF8(), value, units, unitless );
725 validateAndSetValueWithUnits( value, units,
726 [&c]( const int aValue )
727 {
728 c.m_Value.SetMax( aValue );
729 } );
730
731 if( (int) NextTok() != DSN_RIGHT )
732 {
733 reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
734 parseUnknown();
735 }
736
737 break;
738
739 case T_opt:
740 token = NextTok();
741
742 if( (int) token == DSN_RIGHT )
743 {
744 reportError( _( "Missing opt value." ) );
745 break;
746 }
747
748 parseValueWithUnits( FromUTF8(), value, units, unitless );
749 validateAndSetValueWithUnits( value, units,
750 [&c]( const int aValue )
751 {
752 c.m_Value.SetOpt( aValue );
753 } );
754
755 if( (int) NextTok() != DSN_RIGHT )
756 {
757 reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
758 parseUnknown();
759 }
760
761 break;
762
763 case T_EOF:
764 reportError( _( "Incomplete statement." ) );
765 return;
766
767 default:
768 msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ),
769 FromUTF8(),
770 wxT( "min, max, or opt" ) );
771 reportError( msg );
772 parseUnknown();
773 }
774 }
775
776 if( (int) CurTok() != DSN_RIGHT )
777 reportError( _( "Missing ')'." ) );
778
779 aRule->AddConstraint( c );
780}
781
782
783void DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult, EDA_UNITS& aUnits, bool aUnitless )
784{
785 aResult = 0.0;
786 aUnits = EDA_UNITS::UNSCALED;
787
788 auto errorHandler = [&]( const wxString& aMessage, int aOffset )
789 {
790 wxString rest;
791 wxString first = aMessage.BeforeFirst( '|', &rest );
792
793 if( m_reporter )
794 {
795 wxString msg = wxString::Format( _( "ERROR: <a href='%d:%d'>%s</a>%s" ),
796 CurLineNumber(), CurOffset() + aOffset, first, rest );
797
799 }
800 else
801 {
802 wxString msg = wxString::Format( _( "ERROR: %s%s" ), first, rest );
803
804 THROW_PARSE_ERROR( msg, CurSource(), CurLine(), CurLineNumber(),
805 CurOffset() + aOffset );
806 }
807 };
808
811 evaluator.SetErrorCallback( errorHandler );
812
813 if( evaluator.Evaluate( aExpr ) )
814 {
815 aResult = evaluator.Result();
816 aUnits = evaluator.Units();
817 }
818}
819
820
822{
823 LSET retVal;
824 int token = NextTok();
825
826 if( (int) token == DSN_RIGHT )
827 {
828 reportError( _( "Missing layer name or type." ) );
829 return LSET::AllCuMask();
830 }
831 else if( token == T_outer )
832 {
833 *aSource = GetTokenString( token );
834 retVal = LSET::ExternalCuMask();
835 }
836 else if( token == T_inner )
837 {
838 *aSource = GetTokenString( token );
839 retVal = LSET::InternalCuMask();
840 }
841 else
842 {
843 wxString layerName = FromUTF8();
844 wxPGChoices& layerMap = ENUM_MAP<PCB_LAYER_ID>::Instance().Choices();
845
846 for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
847 {
848 wxPGChoiceEntry& entry = layerMap[ii];
849
850 if( entry.GetText().Matches( layerName ) )
851 {
852 *aSource = layerName;
853 retVal.set( ToLAYER_ID( entry.GetValue() ) );
854 }
855 }
856
857 if( !retVal.any() )
858 {
859 reportError( wxString::Format( _( "Unrecognized layer '%s'." ), layerName ) );
860 retVal.set( Rescue );
861 }
862 }
863
864 if( (int) NextTok() != DSN_RIGHT )
865 {
866 reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
867 parseUnknown();
868 }
869
870 return retVal;
871}
872
873
875{
877 wxString msg;
878
879 T token = NextTok();
880
881 if( (int) token == DSN_RIGHT || token == T_EOF )
882 {
883 reportError( _( "Missing severity name." ) );
885 }
886
887 switch( token )
888 {
889 case T_ignore: retVal = RPT_SEVERITY_IGNORE; break;
890 case T_warning: retVal = RPT_SEVERITY_WARNING; break;
891 case T_error: retVal = RPT_SEVERITY_ERROR; break;
892 case T_exclusion: retVal = RPT_SEVERITY_EXCLUSION; break;
893
894 default:
895 msg.Printf( _( "Unrecognized item '%s'.| Expected %s." ),
896 FromUTF8(),
897 wxT( "ignore, warning, error, or exclusion" ) );
898 reportError( msg );
899 parseUnknown();
900 }
901
902 if( (int) NextTok() != DSN_RIGHT )
903 reportError( _( "Missing ')'." ) );
904
905 return retVal;
906}
BASE_SET & set(size_t pos)
Definition: base_set.h:116
DRC_RULE_CONDITION * m_Test
Definition: drc_rule.h:202
int m_DisallowFlags
Definition: drc_rule.h:200
void SetOption(OPTIONS option)
Definition: drc_rule.h:186
ZONE_CONNECTION m_ZoneConnection
Definition: drc_rule.h:201
MINOPTMAX< int > m_Value
Definition: drc_rule.h:199
DRC_CONSTRAINT_T m_Type
Definition: drc_rule.h:198
void ClearOption(OPTIONS option)
Definition: drc_rule.h:188
SEVERITY parseSeverity()
std::shared_ptr< COMPONENT_CLASS_ASSIGNMENT_RULE > parseComponentClassAssignment()
void Parse(std::vector< std::shared_ptr< DRC_RULE > > &aRules, REPORTER *aReporter)
REPORTER * m_reporter
void ParseComponentClassAssignmentRules(std::vector< std::shared_ptr< COMPONENT_CLASS_ASSIGNMENT_RULE > > &aRules, REPORTER *aReporter)
std::shared_ptr< DRC_RULE > parseDRC_RULE()
LSET parseLayer(wxString *aSource)
void parseConstraint(DRC_RULE *aRule)
void reportError(const wxString &aMessage)
DRC_RULES_PARSER(const wxString &aSource, const wxString &aSourceDescr)
void parseValueWithUnits(const wxString &aExpr, int &aResult, EDA_UNITS &aUnits, bool aUnitless=false)
void reportDeprecation(const wxString &oldToken, const wxString newToken)
bool Compile(REPORTER *aReporter, int aSourceLine=0, int aSourceOffset=0)
void AddConstraint(DRC_CONSTRAINT &aConstraint)
Definition: drc_rule.cpp:60
std::optional< DRC_CONSTRAINT > FindConstraint(DRC_CONSTRAINT_T aType)
Definition: drc_rule.cpp:67
static ENUM_MAP< T > & Instance()
Definition: property.h:681
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:583
static const LSET & ExternalCuMask()
Return a mask holding the Front and Bottom layers.
Definition: lset.cpp:620
static const LSET & AllLayersMask()
Definition: lset.cpp:627
static const LSET & InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Definition: lset.cpp:561
void SetMin(T v)
Definition: minoptmax.h:41
bool HasMax() const
Definition: minoptmax.h:38
void SetOpt(T v)
Definition: minoptmax.h:43
bool HasMin() const
Definition: minoptmax.h:37
void SetMax(T v)
Definition: minoptmax.h:42
bool HasOpt() const
Definition: minoptmax.h:39
bool Evaluate(const wxString &aExpr)
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
EDA_UNITS Units() const
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:73
virtual bool HasMessage() const =0
Returns true if the reporter client is non-empty.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition: reporter.h:102
static EDA_DATA_TYPE GetTypeFromUnits(const EDA_UNITS aUnits)
Gets the inferred type from the given units.
@ DRC_DISALLOW_PADS
Definition: drc_rule.h:88
@ DRC_DISALLOW_VIAS
Definition: drc_rule.h:84
@ DRC_DISALLOW_TEXTS
Definition: drc_rule.h:90
@ DRC_DISALLOW_ZONES
Definition: drc_rule.h:89
@ DRC_DISALLOW_HOLES
Definition: drc_rule.h:92
@ DRC_DISALLOW_GRAPHICS
Definition: drc_rule.h:91
@ DRC_DISALLOW_FOOTPRINTS
Definition: drc_rule.h:93
@ DRC_DISALLOW_TRACKS
Definition: drc_rule.h:87
@ DRC_DISALLOW_MICRO_VIAS
Definition: drc_rule.h:85
@ DRC_DISALLOW_BB_VIAS
Definition: drc_rule.h:86
@ ANNULAR_WIDTH_CONSTRAINT
Definition: drc_rule.h:61
@ COURTYARD_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:55
@ VIA_DIAMETER_CONSTRAINT
Definition: drc_rule.h:67
@ ZONE_CONNECTION_CONSTRAINT
Definition: drc_rule.h:62
@ DIFF_PAIR_GAP_CONSTRAINT
Definition: drc_rule.h:70
@ DISALLOW_CONSTRAINT
Definition: drc_rule.h:66
@ TRACK_WIDTH_CONSTRAINT
Definition: drc_rule.h:59
@ SILK_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:56
@ EDGE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:53
@ MIN_RESOLVED_SPOKES_CONSTRAINT
Definition: drc_rule.h:65
@ TRACK_SEGMENT_LENGTH_CONSTRAINT
Definition: drc_rule.h:60
@ TEXT_THICKNESS_CONSTRAINT
Definition: drc_rule.h:58
@ LENGTH_CONSTRAINT
Definition: drc_rule.h:68
@ VIA_COUNT_CONSTRAINT
Definition: drc_rule.h:73
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:75
@ CLEARANCE_CONSTRAINT
Definition: drc_rule.h:49
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
Definition: drc_rule.h:64
@ CONNECTION_WIDTH_CONSTRAINT
Definition: drc_rule.h:77
@ THERMAL_RELIEF_GAP_CONSTRAINT
Definition: drc_rule.h:63
@ MAX_UNCOUPLED_CONSTRAINT
Definition: drc_rule.h:71
@ ASSERTION_CONSTRAINT
Definition: drc_rule.h:76
@ SKEW_CONSTRAINT
Definition: drc_rule.h:69
@ HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:51
@ TRACK_ANGLE_CONSTRAINT
Definition: drc_rule.h:78
@ HOLE_SIZE_CONSTRAINT
Definition: drc_rule.h:54
@ TEXT_HEIGHT_CONSTRAINT
Definition: drc_rule.h:57
@ CREEPAGE_CONSTRAINT
Definition: drc_rule.h:50
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:74
@ HOLE_TO_HOLE_CONSTRAINT
Definition: drc_rule.h:52
#define DRC_RULE_FILE_VERSION
@ DSN_RIGHT
Definition: dsnlexer.h:68
@ DSN_NUMBER
Definition: dsnlexer.h:67
@ DSN_STRING
Definition: dsnlexer.h:70
#define _(s)
EDA_DATA_TYPE
The type of unit.
Definition: eda_units.h:38
EDA_UNITS
Definition: eda_units.h:48
unitsType
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:165
@ Rescue
Definition: layer_ids.h:121
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:747
SEVERITY
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_UNDEFINED
@ RPT_SEVERITY_EXCLUSION
@ RPT_SEVERITY_IGNORE
@ RPT_SEVERITY_INFO