]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/m2/gm2-compiler/M2CaseList.mod
Update copyright years.
[thirdparty/gcc.git] / gcc / m2 / gm2-compiler / M2CaseList.mod
1 (* M2CaseList.mod implement ISO case label lists.
2
3 Copyright (C) 2009-2023 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
5
6 This file is part of GNU Modula-2.
7
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
12
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU Modula-2; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. *)
21
22 IMPLEMENTATION MODULE M2CaseList ;
23
24
25 FROM M2Debug IMPORT Assert ;
26 FROM M2GCCDeclare IMPORT TryDeclareConstant, GetTypeMin, GetTypeMax ;
27 FROM M2MetaError IMPORT MetaError1, MetaError2, MetaErrorT0, MetaErrorT1, MetaErrorT2, MetaErrorT3, MetaErrorT4, MetaErrorString1 ;
28 FROM M2Error IMPORT InternalError ;
29 FROM M2Range IMPORT OverlapsRange, IsEqual, IsGreater ;
30 FROM M2ALU IMPORT PushIntegerTree, PopIntegerTree, Addn, Sub, PushInt ;
31 FROM Indexing IMPORT Index, InitIndex, PutIndice, GetIndice, ForeachIndiceInIndexDo, HighIndice ;
32 FROM Lists IMPORT InitList, IncludeItemIntoList ;
33 FROM NameKey IMPORT KeyToCharStar ;
34 FROM SymbolConversion IMPORT GccKnowsAbout, Mod2Gcc, AddModGcc ;
35 FROM DynamicStrings IMPORT InitString, InitStringCharStar, ConCat, Mark, KillString ;
36 FROM m2tree IMPORT Tree ;
37 FROM m2block IMPORT RememberType ;
38 FROM m2type IMPORT GetMinFrom ;
39 FROM Storage IMPORT ALLOCATE ;
40 FROM M2Base IMPORT IsExpressionCompatible ;
41 FROM M2Printf IMPORT printf1 ;
42
43 FROM SymbolTable IMPORT NulSym, IsConst, IsFieldVarient, IsRecord, IsRecordField, GetVarientTag, GetType,
44 ForeachLocalSymDo, GetSymName, IsEnumeration, SkipType ;
45
46 TYPE
47 RangePair = POINTER TO RECORD
48 low, high: CARDINAL ;
49 tokenno : CARDINAL ;
50 END ;
51
52 ConflictingPair = POINTER TO RECORD
53 a, b: RangePair ;
54 END ;
55
56 CaseList = POINTER TO RECORD
57 maxRangeId : CARDINAL ;
58 rangeArray : Index ;
59 currentRange: RangePair ;
60 varientField: CARDINAL ;
61 END ;
62
63 CaseDescriptor = POINTER TO RECORD
64 elseClause : BOOLEAN ;
65 elseField : CARDINAL ;
66 record : CARDINAL ;
67 varient : CARDINAL ;
68 maxCaseId : CARDINAL ;
69 caseListArray: Index ;
70 currentCase : CaseList ;
71 next : CaseDescriptor ;
72 END ;
73
74 SetRange = POINTER TO RECORD
75 low, high: Tree ;
76 next : SetRange ;
77 END ;
78
79 VAR
80 caseStack : CaseDescriptor ;
81 caseId : CARDINAL ;
82 caseArray : Index ;
83 conflictArray: Index ;
84 FreeRangeList: SetRange ;
85
86
87
88 (*
89 PushCase - create a case entity and push it to an internal stack.
90 r, is NulSym if this is a CASE statement.
91 If, r, is a record then it indicates it includes one
92 or more varients reside in the record. The particular
93 varient is, v.
94 Return the case id.
95 *)
96
97 PROCEDURE PushCase (r: CARDINAL; v: CARDINAL) : CARDINAL ;
98 VAR
99 c: CaseDescriptor ;
100 BEGIN
101 INC(caseId) ;
102 NEW(c) ;
103 IF c=NIL
104 THEN
105 InternalError ('out of memory error')
106 ELSE
107 WITH c^ DO
108 elseClause := FALSE ;
109 elseField := NulSym ;
110 record := r ;
111 varient := v ;
112 maxCaseId := 0 ;
113 caseListArray := InitIndex(1) ;
114 next := caseStack ;
115 currentCase := NIL
116 END ;
117 caseStack := c ;
118 PutIndice(caseArray, caseId, c)
119 END ;
120 RETURN( caseId )
121 END PushCase ;
122
123
124 (*
125 PopCase - pop the top element of the case entity from the internal
126 stack.
127 *)
128
129 PROCEDURE PopCase ;
130 BEGIN
131 IF caseStack=NIL
132 THEN
133 InternalError ('case stack is empty')
134 END ;
135 caseStack := caseStack^.next
136 END PopCase ;
137
138
139 (*
140 ElseCase - indicates that this case varient does have an else clause.
141 *)
142
143 PROCEDURE ElseCase (f: CARDINAL) ;
144 BEGIN
145 WITH caseStack^ DO
146 elseClause := TRUE ;
147 elseField := f
148 END
149 END ElseCase ;
150
151
152 (*
153 BeginCaseList - create a new label list.
154 *)
155
156 PROCEDURE BeginCaseList (v: CARDINAL) ;
157 VAR
158 l: CaseList ;
159 BEGIN
160 NEW(l) ;
161 IF l=NIL
162 THEN
163 InternalError ('out of memory error')
164 END ;
165 WITH l^ DO
166 maxRangeId := 0 ;
167 rangeArray := InitIndex(1) ;
168 currentRange := NIL ;
169 varientField := v
170 END ;
171 WITH caseStack^ DO
172 INC(maxCaseId) ;
173 PutIndice(caseListArray, maxCaseId, l) ;
174 currentCase := l
175 END
176 END BeginCaseList ;
177
178
179 (*
180 EndCaseList - terminate the current label list.
181 *)
182
183 PROCEDURE EndCaseList ;
184 BEGIN
185 caseStack^.currentCase := NIL
186 END EndCaseList ;
187
188
189 (*
190 AddRange - add a range to the current label list.
191 *)
192
193 PROCEDURE AddRange (r1, r2: CARDINAL; tok: CARDINAL) ;
194 VAR
195 r: RangePair ;
196 BEGIN
197 NEW(r) ;
198 IF r=NIL
199 THEN
200 InternalError ('out of memory error')
201 ELSE
202 WITH r^ DO
203 low := r1 ;
204 high := r2 ;
205 tokenno := tok
206 END ;
207 WITH caseStack^.currentCase^ DO
208 INC(maxRangeId) ;
209 PutIndice(rangeArray, maxRangeId, r) ;
210 currentRange := r
211 END
212 END
213 END AddRange ;
214
215
216 (*
217 GetVariantTagType - returns the type associated with, variant.
218 *)
219
220 PROCEDURE GetVariantTagType (variant: CARDINAL) : CARDINAL ;
221 VAR
222 tag: CARDINAL ;
223 BEGIN
224 tag := GetVarientTag(variant) ;
225 IF IsFieldVarient(tag) OR IsRecordField(tag)
226 THEN
227 RETURN( GetType(tag) )
228 ELSE
229 RETURN( tag )
230 END
231 END GetVariantTagType ;
232
233
234 (*
235 CaseBoundsResolved - returns TRUE if all constants in the case list, c,
236 are known to GCC.
237 *)
238
239 PROCEDURE CaseBoundsResolved (tokenno: CARDINAL; c: CARDINAL) : BOOLEAN ;
240 VAR
241 resolved: BOOLEAN ;
242 p : CaseDescriptor ;
243 q : CaseList ;
244 r : RangePair ;
245 min,
246 max,
247 type,
248 i, j : CARDINAL ;
249 BEGIN
250 p := GetIndice(caseArray, c) ;
251 WITH p^ DO
252 IF varient#NulSym
253 THEN
254 (* not a CASE statement, but a varient record containing without an ELSE clause *)
255 type := GetVariantTagType(varient) ;
256 resolved := TRUE ;
257 IF NOT GccKnowsAbout(type)
258 THEN
259 (* do we need to add, type, to the list of types required to be resolved? *)
260 resolved := FALSE
261 END ;
262 min := GetTypeMin(type) ;
263 IF NOT GccKnowsAbout(min)
264 THEN
265 TryDeclareConstant(tokenno, min) ;
266 resolved := FALSE
267 END ;
268 max := GetTypeMax(type) ;
269 IF NOT GccKnowsAbout(max)
270 THEN
271 TryDeclareConstant(tokenno, max) ;
272 resolved := FALSE
273 END ;
274 IF NOT resolved
275 THEN
276 RETURN( FALSE )
277 END
278 END ;
279 i := 1 ;
280 WHILE i<=maxCaseId DO
281 q := GetIndice(caseListArray, i) ;
282 j := 1 ;
283 WHILE j<=q^.maxRangeId DO
284 r := GetIndice(q^.rangeArray, j) ;
285 IF r^.low#NulSym
286 THEN
287 IF IsConst(r^.low)
288 THEN
289 TryDeclareConstant(tokenno, r^.low) ;
290 IF NOT GccKnowsAbout(r^.low)
291 THEN
292 RETURN( FALSE )
293 END
294 ELSE
295 IF r^.high=NulSym
296 THEN
297 MetaError1('the CASE statement variant must be defined by a constant {%1Da:is a {%1d}}', r^.low)
298 ELSE
299 MetaError1('the CASE statement variant low value in a range must be defined by a constant {%1Da:is a {%1d}}',
300 r^.low)
301 END
302 END
303 END ;
304 IF r^.high#NulSym
305 THEN
306 IF IsConst(r^.high)
307 THEN
308 TryDeclareConstant(tokenno, r^.high) ;
309 IF NOT GccKnowsAbout(r^.high)
310 THEN
311 RETURN( FALSE )
312 END
313 ELSE
314 MetaError1('the CASE statement variant high value in a range must be defined by a constant {%1Da:is a {%1d}}',
315 r^.high)
316 END
317 END ;
318 INC(j)
319 END ;
320 INC(i)
321 END
322 END ;
323 RETURN( TRUE )
324 END CaseBoundsResolved ;
325
326
327 (*
328 IsSame - return TRUE if r, s, are in, e.
329 *)
330
331 PROCEDURE IsSame (e: ConflictingPair; r, s: RangePair) : BOOLEAN ;
332 BEGIN
333 WITH e^ DO
334 RETURN( ((a=r) AND (b=s)) OR ((a=s) AND (b=r)) )
335 END
336 END IsSame ;
337
338
339 (*
340 SeenBefore -
341 *)
342
343 PROCEDURE SeenBefore (r, s: RangePair) : BOOLEAN ;
344 VAR
345 i, h: CARDINAL ;
346 e : ConflictingPair ;
347 BEGIN
348 h := HighIndice(conflictArray) ;
349 i := 1 ;
350 WHILE i<=h DO
351 e := GetIndice(conflictArray, i) ;
352 IF IsSame(e, r, s)
353 THEN
354 RETURN( TRUE )
355 END ;
356 INC(i)
357 END ;
358 NEW(e) ;
359 WITH e^ DO
360 a := r ;
361 b := s
362 END ;
363 PutIndice(conflictArray, h+1, e) ;
364 RETURN( FALSE )
365 END SeenBefore ;
366
367
368 (*
369 Overlaps -
370 *)
371
372 PROCEDURE Overlaps (r, s: RangePair) : BOOLEAN ;
373 VAR
374 a, b, c, d: CARDINAL ;
375 BEGIN
376 a := r^.low ;
377 c := s^.low ;
378 IF r^.high=NulSym
379 THEN
380 b := a ;
381 IF s^.high=NulSym
382 THEN
383 d := c ;
384 IF OverlapsRange(Mod2Gcc(a), Mod2Gcc(b), Mod2Gcc(c), Mod2Gcc(d))
385 THEN
386 IF NOT SeenBefore(r, s)
387 THEN
388 MetaErrorT2 (r^.tokenno, 'case label {%1ad} is a duplicate with {%2ad}', a, c) ;
389 MetaErrorT2 (s^.tokenno, 'case label {%1ad} is a duplicate with {%2ad}', c, a)
390 END ;
391 RETURN( TRUE )
392 END
393 ELSE
394 d := s^.high ;
395 IF OverlapsRange(Mod2Gcc(a), Mod2Gcc(b), Mod2Gcc(c), Mod2Gcc(d))
396 THEN
397 IF NOT SeenBefore (r, s)
398 THEN
399 MetaErrorT3 (r^.tokenno, 'case label {%1ad} is a duplicate in the range {%2ad}..{%3ad}', a, c, d) ;
400 MetaErrorT3 (s^.tokenno, 'case range {%2ad}..{%3ad} is a duplicate of case label {%1ad}', c, d, a)
401 END ;
402 RETURN( TRUE )
403 END
404 END
405 ELSE
406 b := r^.high ;
407 IF s^.high=NulSym
408 THEN
409 d := c ;
410 IF OverlapsRange (Mod2Gcc(a), Mod2Gcc(b), Mod2Gcc(c), Mod2Gcc(d))
411 THEN
412 IF NOT SeenBefore(r, s)
413 THEN
414 MetaErrorT3 (r^.tokenno, 'case range {%1ad}..{%2ad} is a duplicate with case label {%3ad}', a, b, c) ;
415 MetaErrorT3 (s^.tokenno, 'case label {%1ad} is a duplicate with case range %{2ad}..{%3ad}', c, a, b)
416 END ;
417 RETURN( TRUE )
418 END
419 ELSE
420 d := s^.high ;
421 IF OverlapsRange(Mod2Gcc(a), Mod2Gcc(b), Mod2Gcc(c), Mod2Gcc(d))
422 THEN
423 IF NOT SeenBefore(r, s)
424 THEN
425 MetaErrorT4 (r^.tokenno, 'case range {%1ad}..{%2ad} overlaps case range {%3ad}..{%4ad}', a, b, c, d) ;
426 MetaErrorT4 (s^.tokenno, 'case range {%1ad}..{%2ad} overlaps case range {%3ad}..{%4ad}', c, d, a, b)
427 END ;
428 RETURN( TRUE )
429 END
430 END
431 END ;
432 RETURN( FALSE )
433 END Overlaps ;
434
435
436 (*
437 OverlappingCaseBound - returns TRUE if, r, overlaps any case bound in the
438 case statement, c.
439 *)
440
441 PROCEDURE OverlappingCaseBound (r: RangePair; c: CARDINAL) : BOOLEAN ;
442 VAR
443 p : CaseDescriptor ;
444 q : CaseList ;
445 s : RangePair ;
446 i, j : CARDINAL ;
447 overlap: BOOLEAN ;
448 BEGIN
449 p := GetIndice (caseArray, c) ;
450 overlap := FALSE ;
451 WITH p^ DO
452 i := 1 ;
453 WHILE i<=maxCaseId DO
454 q := GetIndice (caseListArray, i) ;
455 j := 1 ;
456 WHILE j<=q^.maxRangeId DO
457 s := GetIndice (q^.rangeArray, j) ;
458 IF (s#r) AND Overlaps (r, s)
459 THEN
460 overlap := TRUE
461 END ;
462 INC (j)
463 END ;
464 INC (i)
465 END
466 END ;
467 RETURN( overlap )
468 END OverlappingCaseBound ;
469
470
471 (*
472 OverlappingCaseBounds - returns TRUE if there were any overlapping bounds
473 in the case list, c. It will generate an error
474 messages for each overlapping bound found.
475 *)
476
477 PROCEDURE OverlappingCaseBounds (c: CARDINAL) : BOOLEAN ;
478 VAR
479 p : CaseDescriptor ;
480 q : CaseList ;
481 r : RangePair ;
482 i, j : CARDINAL ;
483 overlap: BOOLEAN ;
484 BEGIN
485 p := GetIndice(caseArray, c) ;
486 overlap := FALSE ;
487 WITH p^ DO
488 i := 1 ;
489 WHILE i<=maxCaseId DO
490 q := GetIndice(caseListArray, i) ;
491 j := 1 ;
492 WHILE j<=q^.maxRangeId DO
493 r := GetIndice(q^.rangeArray, j) ;
494 IF OverlappingCaseBound (r, c)
495 THEN
496 overlap := TRUE
497 END ;
498 INC(j)
499 END ;
500 INC(i)
501 END
502 END ;
503 RETURN( overlap )
504 END OverlappingCaseBounds ;
505
506
507 (*
508 NewRanges -
509 *)
510
511 PROCEDURE NewRanges () : SetRange ;
512 VAR
513 s: SetRange ;
514 BEGIN
515 IF FreeRangeList=NIL
516 THEN
517 NEW(s)
518 ELSE
519 s := FreeRangeList ;
520 FreeRangeList := FreeRangeList^.next
521 END ;
522 s^.next := NIL ;
523 RETURN( s )
524 END NewRanges ;
525
526
527 (*
528 NewSet -
529 *)
530
531 PROCEDURE NewSet (type: CARDINAL) : SetRange ;
532 VAR
533 s: SetRange ;
534 BEGIN
535 s := NewRanges() ;
536 WITH s^ DO
537 low := Mod2Gcc(GetTypeMin(type)) ;
538 high := Mod2Gcc(GetTypeMax(type)) ;
539 next := NIL
540 END ;
541 RETURN( s )
542 END NewSet ;
543
544
545 (*
546 DisposeRanges -
547 *)
548
549 PROCEDURE DisposeRanges (set: SetRange) : SetRange ;
550 VAR
551 t: SetRange ;
552 BEGIN
553 IF set#NIL
554 THEN
555 IF FreeRangeList=NIL
556 THEN
557 FreeRangeList := set
558 ELSE
559 t := set ;
560 WHILE t^.next#NIL DO
561 t := t^.next
562 END ;
563 t^.next := FreeRangeList ;
564 FreeRangeList := set
565 END
566 END ;
567 RETURN( NIL )
568 END DisposeRanges ;
569
570
571 (*
572 SubBitRange - subtracts bits, lo..hi, from, set.
573 *)
574
575 PROCEDURE SubBitRange (set: SetRange; lo, hi: Tree; tokenno: CARDINAL) : SetRange ;
576 VAR
577 h, i : SetRange ;
578 BEGIN
579 h := set ;
580 WHILE h#NIL DO
581 IF (h^.high=NIL) OR IsEqual(h^.high, h^.low)
582 THEN
583 IF IsEqual(h^.low, lo) OR OverlapsRange(lo, hi, h^.low, h^.low)
584 THEN
585 IF h=set
586 THEN
587 set := set^.next ;
588 h^.next := NIL ;
589 h := DisposeRanges(h) ;
590 h := set
591 ELSE
592 i := set ;
593 WHILE i^.next#h DO
594 i := i^.next
595 END ;
596 i^.next := h^.next ;
597 i := h ;
598 h := h^.next ;
599 i^.next := NIL ;
600 i := DisposeRanges(i)
601 END
602 ELSE
603 h := h^.next
604 END
605 ELSE
606 IF OverlapsRange(lo, hi, h^.low, h^.high)
607 THEN
608 IF IsGreater(h^.low, lo) OR IsGreater(hi, h^.high)
609 THEN
610 MetaErrorT0 (tokenno, 'variant case range lies outside tag value')
611 ELSE
612 IF IsEqual(h^.low, lo)
613 THEN
614 PushIntegerTree(hi) ;
615 PushInt(1) ;
616 Addn ;
617 h^.low := PopIntegerTree()
618 ELSIF IsEqual(h^.high, hi)
619 THEN
620 PushIntegerTree(lo) ;
621 PushInt(1) ;
622 Sub ;
623 h^.high := PopIntegerTree()
624 ELSE
625 (* lo..hi exist inside range h^.low..h^.high *)
626 i := NewRanges() ;
627 i^.next := h^.next ;
628 h^.next := i ;
629 i^.high := h^.high ;
630 PushIntegerTree(lo) ;
631 PushInt(1) ;
632 Sub ;
633 h^.high := PopIntegerTree() ;
634 PushIntegerTree(hi) ;
635 PushInt(1) ;
636 Addn ;
637 i^.low := PopIntegerTree()
638 END
639 END
640 ELSE
641 h := h^.next
642 END
643 END
644 END ;
645 RETURN( set )
646 END SubBitRange ;
647
648
649 (*
650 ExcludeCaseRanges - excludes all case ranges found in, p, from, set
651 *)
652
653 PROCEDURE ExcludeCaseRanges (set: SetRange; p: CaseDescriptor) : SetRange ;
654 VAR
655 i, j: CARDINAL ;
656 q : CaseList ;
657 r : RangePair ;
658 BEGIN
659 WITH p^ DO
660 i := 1 ;
661 WHILE i<=maxCaseId DO
662 q := GetIndice(caseListArray, i) ;
663 j := 1 ;
664 WHILE j<=q^.maxRangeId DO
665 r := GetIndice(q^.rangeArray, j) ;
666 IF r^.high=NulSym
667 THEN
668 set := SubBitRange(set, Mod2Gcc(r^.low), Mod2Gcc(r^.low), r^.tokenno)
669 ELSE
670 set := SubBitRange(set, Mod2Gcc(r^.low), Mod2Gcc(r^.high), r^.tokenno)
671 END ;
672 INC(j)
673 END ;
674 INC(i)
675 END
676 END ;
677 RETURN( set )
678 END ExcludeCaseRanges ;
679
680
681 VAR
682 High, Low : Tree ;
683 errorString: String ;
684
685
686 (*
687 DoEnumValues -
688 *)
689
690 PROCEDURE DoEnumValues (sym: CARDINAL) ;
691 BEGIN
692 IF (Low#NIL) AND IsEqual(Mod2Gcc(sym), Low)
693 THEN
694 errorString := ConCat(errorString, InitStringCharStar(KeyToCharStar(GetSymName(sym)))) ;
695 Low := NIL
696 END ;
697 IF (High#NIL) AND IsEqual(Mod2Gcc(sym), High)
698 THEN
699 errorString := ConCat(errorString, Mark(InitString('..'))) ;
700 errorString := ConCat(errorString, Mark(InitStringCharStar(KeyToCharStar(GetSymName(sym))))) ;
701 High := NIL
702 END
703 END DoEnumValues ;
704
705
706 (*
707 ErrorRange -
708 *)
709
710 PROCEDURE ErrorRange (p: CaseDescriptor; type: CARDINAL; set: SetRange) ;
711 BEGIN
712 type := SkipType(type) ;
713 IF IsEnumeration(type)
714 THEN
715 Low := set^.low ;
716 High := set^.high ;
717 IF IsEqual(Low, High)
718 THEN
719 High := NIL ;
720 errorString := InitString('enumeration value ') ;
721 ForeachLocalSymDo(type, DoEnumValues) ;
722 errorString := ConCat(errorString, InitString(' is ignored by the CASE variant record {%1D}'))
723 ELSE
724 errorString := InitString('enumeration values ') ;
725 ForeachLocalSymDo(type, DoEnumValues) ;
726 errorString := ConCat(errorString, InitString(' are ignored by the CASE variant record {%1D}'))
727 END ;
728 MetaErrorString1(errorString, p^.varient)
729 END
730 END ErrorRange ;
731
732
733 (*
734 ErrorRanges -
735 *)
736
737 PROCEDURE ErrorRanges (p: CaseDescriptor; type: CARDINAL; set: SetRange) ;
738 BEGIN
739 WHILE set#NIL DO
740 ErrorRange(p, type, set) ;
741 set := set^.next
742 END
743 END ErrorRanges ;
744
745
746 (*
747 MissingCaseBounds - returns TRUE if there were any missing bounds
748 in the varient record case list, c. It will
749 generate an error message for each missing
750 bounds found.
751 *)
752
753 PROCEDURE MissingCaseBounds (tokenno: CARDINAL; c: CARDINAL) : BOOLEAN ;
754 VAR
755 p : CaseDescriptor ;
756 type : CARDINAL ;
757 missing: BOOLEAN ;
758 set : SetRange ;
759 BEGIN
760 p := GetIndice(caseArray, c) ;
761 missing := FALSE ;
762 WITH p^ DO
763 IF (record#NulSym) AND (varient#NulSym) AND (NOT elseClause)
764 THEN
765 (* not a CASE statement, but a varient record containing without an ELSE clause *)
766 type := GetVariantTagType(varient) ;
767 set := NewSet(type) ;
768 set := ExcludeCaseRanges(set, p) ;
769 IF set#NIL
770 THEN
771 missing := TRUE ;
772 MetaErrorT2 (tokenno,
773 'not all variant record alternatives in the {%kCASE} clause are specified, hint you either need to specify each value of {%2ad} or use an {%kELSE} clause',
774 varient, type) ;
775 ErrorRanges(p, type, set)
776 END ;
777 set := DisposeRanges(set)
778 END
779 END ;
780 RETURN( missing )
781 END MissingCaseBounds ;
782
783
784 (*
785 InRangeList - returns TRUE if the value, tag, is defined in the case list.
786
787 PROCEDURE InRangeList (cl: CaseList; tag: CARDINAL) : BOOLEAN ;
788 VAR
789 i, h: CARDINAL ;
790 r : RangePair ;
791 a : Tree ;
792 BEGIN
793 WITH cl^ DO
794 i := 1 ;
795 h := HighIndice(rangeArray) ;
796 WHILE i<=h DO
797 r := GetIndice(rangeArray, i) ;
798 WITH r^ DO
799 IF high=NulSym
800 THEN
801 a := Mod2Gcc(low)
802 ELSE
803 a := Mod2Gcc(high)
804 END ;
805 IF OverlapsRange(Mod2Gcc(low), a, Mod2Gcc(tag), Mod2Gcc(tag))
806 THEN
807 RETURN( TRUE )
808 END
809 END ;
810 INC(i)
811 END
812 END ;
813 RETURN( FALSE )
814 END InRangeList ;
815 *)
816
817
818 (*
819 WriteCase - dump out the case list (internal debugging).
820 *)
821
822 PROCEDURE WriteCase (c: CARDINAL) ;
823 BEGIN
824 (* this debugging procedure should be finished. *)
825 printf1 ("%d", c)
826 END WriteCase ;
827
828
829 (*
830 checkTypes - checks to see that, constant, and, type, are compatible.
831 *)
832
833 PROCEDURE checkTypes (constant, type: CARDINAL) : BOOLEAN ;
834 VAR
835 consttype: CARDINAL ;
836 BEGIN
837 IF (constant#NulSym) AND IsConst(constant)
838 THEN
839 consttype := GetType(constant) ;
840 IF NOT IsExpressionCompatible(consttype, type)
841 THEN
842 MetaError2('the CASE statement variant tag {%1ad} must be type compatible with the constant {%2Da:is a {%2d}}',
843 type, constant) ;
844 RETURN( FALSE )
845 END
846 END ;
847 RETURN( TRUE )
848 END checkTypes ;
849
850
851 (*
852 inRange - returns TRUE if, min <= i <= max.
853 *)
854
855 PROCEDURE inRange (i, min, max: CARDINAL) : BOOLEAN ;
856 BEGIN
857 RETURN( OverlapsRange(Mod2Gcc(i), Mod2Gcc(i), Mod2Gcc(min), Mod2Gcc(max)) )
858 END inRange ;
859
860
861 (*
862 TypeCaseBounds - returns TRUE if all bounds in case list, c, are
863 compatible with the tagged type.
864 *)
865
866 PROCEDURE TypeCaseBounds (c: CARDINAL) : BOOLEAN ;
867 VAR
868 p : CaseDescriptor ;
869 q : CaseList ;
870 r : RangePair ;
871 min, max,
872 type,
873 i, j : CARDINAL ;
874 compatible: BOOLEAN ;
875 BEGIN
876 p := GetIndice(caseArray, c) ;
877 type := NulSym ;
878 WITH p^ DO
879 type := NulSym ;
880 IF varient#NulSym
881 THEN
882 (* not a CASE statement, but a varient record containing without an ELSE clause *)
883 type := GetVariantTagType(varient) ;
884 min := GetTypeMin(type) ;
885 max := GetTypeMax(type)
886 END ;
887 IF type=NulSym
888 THEN
889 RETURN( TRUE )
890 END ;
891 compatible := TRUE ;
892 i := 1 ;
893 WHILE i<=maxCaseId DO
894 q := GetIndice(caseListArray, i) ;
895 j := 1 ;
896 WHILE j<=q^.maxRangeId DO
897 r := GetIndice(q^.rangeArray, j) ;
898 IF (r^.low#NulSym) AND (NOT inRange(r^.low, min, max))
899 THEN
900 MetaError2('the CASE statement variant range {%1ad} exceeds that of the tag type {%2ad}',
901 r^.low, type) ;
902 compatible := FALSE
903 END ;
904 IF NOT checkTypes(r^.low, type)
905 THEN
906 compatible := FALSE
907 END ;
908 IF (r^.high#NulSym) AND (NOT inRange(r^.high, min, max))
909 THEN
910 MetaError2('the CASE statement variant range {%1ad} exceeds that of the tag type {%2ad}',
911 r^.high, type) ;
912 compatible := FALSE
913 END ;
914 IF NOT checkTypes(r^.high, type)
915 THEN
916 compatible := FALSE
917 END ;
918 INC(j)
919 END ;
920 INC(i)
921 END ;
922 RETURN( compatible )
923 END
924 END TypeCaseBounds ;
925
926
927 BEGIN
928 caseStack := NIL ;
929 caseId := 0 ;
930 caseArray := InitIndex(1) ;
931 conflictArray := InitIndex(1) ;
932 FreeRangeList := NIL
933 END M2CaseList.