1 (* M2CaseList.mod implement ISO case label lists.
3 Copyright (C) 2009-2024 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 This file is part of GNU Modula-2.
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)
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.
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/>. *)
22 IMPLEMENTATION MODULE M2CaseList ;
25 FROM M2Debug IMPORT Assert ;
26 FROM M2GCCDeclare IMPORT TryDeclareConstant, GetTypeMin, GetTypeMax ;
27 FROM M2MetaError IMPORT MetaError1, MetaError2, MetaErrorT0, MetaErrorT1, MetaErrorT2, MetaErrorT3, MetaErrorT4, MetaErrorStringT0, 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, RemoveItemFromList, NoOfItemsInList, GetItemFromList ;
33 FROM NameKey IMPORT KeyToCharStar ;
34 FROM SymbolConversion IMPORT GccKnowsAbout, Mod2Gcc, AddModGcc ;
35 FROM DynamicStrings IMPORT InitString, InitStringCharStar, InitStringChar, ConCat, Mark, KillString ;
36 FROM m2tree IMPORT Tree ;
37 FROM m2block IMPORT RememberType ;
38 FROM m2type IMPORT GetMinFrom ;
39 FROM m2expr IMPORT GetIntegerOne, CSTIntToString, CSTIntToChar ;
40 FROM Storage IMPORT ALLOCATE ;
41 FROM M2Base IMPORT IsExpressionCompatible, Char ;
42 FROM M2Printf IMPORT printf1 ;
43 FROM M2LexBuf IMPORT TokenToLocation ;
45 FROM SymbolTable IMPORT NulSym, IsConst, IsFieldVarient, IsRecord, IsRecordField, GetVarientTag, GetType,
46 ForeachLocalSymDo, GetSymName, IsEnumeration, SkipType, NoOfElements, GetNth,
50 RangePair = POINTER TO RECORD
55 ConflictingPair = POINTER TO RECORD
59 CaseList = POINTER TO RECORD
60 maxRangeId : CARDINAL ;
62 currentRange: RangePair ;
63 varientField: CARDINAL ;
66 CaseDescriptor = POINTER TO RECORD
67 elseClause : BOOLEAN ;
68 elseField : CARDINAL ;
71 expression : CARDINAL ;
72 maxCaseId : CARDINAL ;
73 caseListArray: Index ;
74 currentCase : CaseList ;
75 next : CaseDescriptor ;
78 SetRange = POINTER TO RECORD
84 caseStack : CaseDescriptor ;
87 conflictArray: Index ;
88 FreeRangeList: SetRange ;
93 PushCase - create a case entity and push it to an internal stack.
94 rec is NulSym if this is a CASE statement.
95 If rec is a record then it indicates a possible
96 varients reside in the record to check.
97 Both rec and va might be NulSym and then the expr
98 will contain the selector expression to a case statement.
102 PROCEDURE PushCase (rec, va, expr: CARDINAL) : CARDINAL ;
110 InternalError ('out of memory error')
113 elseClause := FALSE ;
114 elseField := NulSym ;
119 caseListArray := InitIndex (1) ;
124 PutIndice (caseArray, caseId, c)
131 PopCase - pop the top element of the case entity from the internal
139 InternalError ('case stack is empty')
141 caseStack := caseStack^.next
146 ElseCase - indicates that this case varient does have an else clause.
149 PROCEDURE ElseCase (f: CARDINAL) ;
159 BeginCaseList - create a new label list.
162 PROCEDURE BeginCaseList (v: CARDINAL) ;
169 InternalError ('out of memory error')
173 rangeArray := InitIndex(1) ;
174 currentRange := NIL ;
179 PutIndice(caseListArray, maxCaseId, l) ;
186 EndCaseList - terminate the current label list.
189 PROCEDURE EndCaseList ;
191 caseStack^.currentCase := NIL
196 AddRange - add a range to the current label list.
199 PROCEDURE AddRange (r1, r2: CARDINAL; tok: CARDINAL) ;
206 InternalError ('out of memory error')
213 WITH caseStack^.currentCase^ DO
215 PutIndice(rangeArray, maxRangeId, r) ;
223 GetVariantTagType - returns the type associated with, variant.
226 PROCEDURE GetVariantTagType (variant: CARDINAL) : CARDINAL ;
230 tag := GetVarientTag(variant) ;
231 IF IsFieldVarient(tag) OR IsRecordField(tag)
233 RETURN( GetType(tag) )
237 END GetVariantTagType ;
241 CaseBoundsResolved - returns TRUE if all constants in the case list, c,
245 PROCEDURE CaseBoundsResolved (tokenno: CARDINAL; c: CARDINAL) : BOOLEAN ;
256 p := GetIndice(caseArray, c) ;
260 (* not a CASE statement, but a varient record containing without an ELSE clause *)
261 type := GetVariantTagType(varient) ;
263 IF NOT GccKnowsAbout(type)
265 (* do we need to add, type, to the list of types required to be resolved? *)
268 min := GetTypeMin(type) ;
269 IF NOT GccKnowsAbout(min)
271 TryDeclareConstant(tokenno, min) ;
274 max := GetTypeMax(type) ;
275 IF NOT GccKnowsAbout(max)
277 TryDeclareConstant(tokenno, max) ;
286 WHILE i<=maxCaseId DO
287 q := GetIndice(caseListArray, i) ;
289 WHILE j<=q^.maxRangeId DO
290 r := GetIndice(q^.rangeArray, j) ;
295 TryDeclareConstant(tokenno, r^.low) ;
296 IF NOT GccKnowsAbout(r^.low)
303 MetaError1('the CASE statement variant must be defined by a constant {%1Da:is a {%1d}}', r^.low)
305 MetaError1('the CASE statement variant low value in a range must be defined by a constant {%1Da:is a {%1d}}',
314 TryDeclareConstant(tokenno, r^.high) ;
315 IF NOT GccKnowsAbout(r^.high)
320 MetaError1('the CASE statement variant high value in a range must be defined by a constant {%1Da:is a {%1d}}',
330 END CaseBoundsResolved ;
334 IsSame - return TRUE if r, s, are in, e.
337 PROCEDURE IsSame (e: ConflictingPair; r, s: RangePair) : BOOLEAN ;
340 RETURN( ((a=r) AND (b=s)) OR ((a=s) AND (b=r)) )
349 PROCEDURE SeenBefore (r, s: RangePair) : BOOLEAN ;
352 e : ConflictingPair ;
354 h := HighIndice(conflictArray) ;
357 e := GetIndice(conflictArray, i) ;
369 PutIndice(conflictArray, h+1, e) ;
378 PROCEDURE Overlaps (r, s: RangePair) : BOOLEAN ;
380 a, b, c, d: CARDINAL ;
390 IF OverlapsRange(Mod2Gcc(a), Mod2Gcc(b), Mod2Gcc(c), Mod2Gcc(d))
392 IF NOT SeenBefore(r, s)
394 MetaErrorT2 (r^.tokenno, 'case label {%1ad} is a duplicate with {%2ad}', a, c) ;
395 MetaErrorT2 (s^.tokenno, 'case label {%1ad} is a duplicate with {%2ad}', c, a)
401 IF OverlapsRange(Mod2Gcc(a), Mod2Gcc(b), Mod2Gcc(c), Mod2Gcc(d))
403 IF NOT SeenBefore (r, s)
405 MetaErrorT3 (r^.tokenno, 'case label {%1ad} is a duplicate in the range {%2ad}..{%3ad}', a, c, d) ;
406 MetaErrorT3 (s^.tokenno, 'case range {%2ad}..{%3ad} is a duplicate of case label {%1ad}', c, d, a)
416 IF OverlapsRange (Mod2Gcc(a), Mod2Gcc(b), Mod2Gcc(c), Mod2Gcc(d))
418 IF NOT SeenBefore(r, s)
420 MetaErrorT3 (r^.tokenno, 'case range {%1ad}..{%2ad} is a duplicate with case label {%3ad}', a, b, c) ;
421 MetaErrorT3 (s^.tokenno, 'case label {%1ad} is a duplicate with case range %{2ad}..{%3ad}', c, a, b)
427 IF OverlapsRange(Mod2Gcc(a), Mod2Gcc(b), Mod2Gcc(c), Mod2Gcc(d))
429 IF NOT SeenBefore(r, s)
431 MetaErrorT4 (r^.tokenno, 'case range {%1ad}..{%2ad} overlaps case range {%3ad}..{%4ad}', a, b, c, d) ;
432 MetaErrorT4 (s^.tokenno, 'case range {%1ad}..{%2ad} overlaps case range {%3ad}..{%4ad}', c, d, a, b)
443 OverlappingCaseBound - returns TRUE if, r, overlaps any case bound in the
447 PROCEDURE OverlappingCaseBound (r: RangePair; c: CARDINAL) : BOOLEAN ;
455 p := GetIndice (caseArray, c) ;
459 WHILE i<=maxCaseId DO
460 q := GetIndice (caseListArray, i) ;
462 WHILE j<=q^.maxRangeId DO
463 s := GetIndice (q^.rangeArray, j) ;
464 IF (s#r) AND Overlaps (r, s)
474 END OverlappingCaseBound ;
478 OverlappingCaseBounds - returns TRUE if there were any overlapping bounds
479 in the case list, c. It will generate an error
480 messages for each overlapping bound found.
483 PROCEDURE OverlappingCaseBounds (c: CARDINAL) : BOOLEAN ;
491 p := GetIndice(caseArray, c) ;
495 WHILE i<=maxCaseId DO
496 q := GetIndice(caseListArray, i) ;
498 WHILE j<=q^.maxRangeId DO
499 r := GetIndice(q^.rangeArray, j) ;
500 IF OverlappingCaseBound (r, c)
510 END OverlappingCaseBounds ;
514 NewRanges - return a new range from the freelist or heap.
517 PROCEDURE NewRanges () : SetRange ;
526 FreeRangeList := FreeRangeList^.next
534 NewSet - returns a new set based on type with the low and high fields assigned
535 to the min and max values for the type.
538 PROCEDURE NewSet (type: CARDINAL) : SetRange ;
544 low := Mod2Gcc(GetTypeMin(type)) ;
545 high := Mod2Gcc(GetTypeMax(type)) ;
553 DisposeRanges - place set and its list onto the free list.
556 PROCEDURE DisposeRanges (set: SetRange) : SetRange ;
570 t^.next := FreeRangeList ;
579 RemoveRange - removes the range descriptor h from set and return the
580 possibly new head of set.
583 PROCEDURE RemoveRange (set: SetRange; h: SetRange) : SetRange ;
591 h := DisposeRanges(h) ;
601 i := DisposeRanges(i)
608 SubBitRange - subtracts bits, lo..hi, from, set.
611 PROCEDURE SubBitRange (set: SetRange; lo, hi: Tree; tokenno: CARDINAL) : SetRange ;
617 (* Check to see if a single set element h is obliterated by lo..hi. *)
618 IF (h^.high=NIL) OR IsEqual(h^.high, h^.low)
620 IF IsEqual(h^.low, lo) OR OverlapsRange(lo, hi, h^.low, h^.low)
622 set := RemoveRange (set, h) ;
627 (* Now check to see if the lo..hi match exactly with the set range. *)
628 ELSIF (h^.high#NIL) AND IsEqual (lo, h^.low) AND IsEqual (hi, h^.high)
630 (* Remove h and return as lo..hi have been removed. *)
631 RETURN RemoveRange (set, h)
633 (* All other cases require modifying the existing set range. *)
634 IF OverlapsRange(lo, hi, h^.low, h^.high)
636 IF IsGreater(h^.low, lo) OR IsGreater(hi, h^.high)
638 MetaErrorT0 (tokenno, 'variant case range lies outside tag value')
640 IF IsEqual(h^.low, lo)
642 PushIntegerTree(hi) ;
645 h^.low := PopIntegerTree()
646 ELSIF IsEqual(h^.high, hi)
648 PushIntegerTree(lo) ;
651 h^.high := PopIntegerTree()
653 (* lo..hi exist inside range h^.low..h^.high *)
658 PushIntegerTree(lo) ;
661 h^.high := PopIntegerTree() ;
662 PushIntegerTree(hi) ;
665 i^.low := PopIntegerTree()
678 CheckLowHigh - checks to see the low value <= high value and issues an error
682 PROCEDURE CheckLowHigh (rp: RangePair) ;
687 lo := Mod2Gcc (rp^.low) ;
688 hi := Mod2Gcc (rp^.high) ;
689 IF IsGreater (lo, hi)
691 MetaErrorT2 (rp^.tokenno, 'case range should be low..high rather than high..low, range specified as {%1Euad}..{%2Euad}', rp^.low, rp^.high) ;
693 rp^.high := rp^.low ;
700 ExcludeCaseRanges - excludes all case ranges found in, p, from, set
703 PROCEDURE ExcludeCaseRanges (set: SetRange; cd: CaseDescriptor) : SetRange ;
711 WHILE i <= maxCaseId DO
712 cl := GetIndice (caseListArray, i) ;
714 WHILE j <= cl^.maxRangeId DO
715 rp := GetIndice (cl^.rangeArray, j) ;
718 set := SubBitRange (set,
720 Mod2Gcc (rp^.low), rp^.tokenno)
723 set := SubBitRange (set,
725 Mod2Gcc (rp^.high), rp^.tokenno)
733 END ExcludeCaseRanges ;
737 errorString: String ;
741 IncludeElement - only include enumeration field into errorString if it lies between low..high.
744 PROCEDURE IncludeElement (enumList: List; field: CARDINAL; low, high: Tree) ;
750 fieldTree := Mod2Gcc (field) ;
751 IF OverlapsRange (fieldTree, fieldTree, low, high)
753 IncludeItemIntoList (enumList, field)
760 IncludeElements - only include enumeration field values low..high in errorString.
763 PROCEDURE IncludeElements (type: CARDINAL; enumList: List; low, high: Tree) ;
767 NoElements: CARDINAL ;
769 NoElements := NoOfElements (type) ;
771 WHILE i <= NoElements DO
772 field := GetNth (type, i) ;
773 IncludeElement (enumList, field, low, high) ;
776 END IncludeElements ;
780 ErrorRangeEnum - include enumeration fields Low to High in errorString.
783 PROCEDURE ErrorRangeEnum (type: CARDINAL; set: SetRange; enumList: List) ;
797 IF (Low # NIL) AND (High # NIL)
799 IncludeElements (type, enumList, Low, High)
805 ErrorRanges - return a list of all enumeration fields not present in the case statement.
806 The return value will be nil if type is not an enumeration type.
809 PROCEDURE ErrorRanges (type: CARDINAL; set: SetRange) : List ;
813 type := SkipType (type) ;
814 IF IsEnumeration (type)
818 ErrorRangeEnum (type, set, enumSet) ;
828 appendString - appends str to errorString.
831 PROCEDURE appendString (str: String) ;
833 errorString := ConCat (errorString, str)
838 appendEnum - appends enum to errorString.
841 PROCEDURE appendEnum (enum: CARDINAL) ;
843 appendString (Mark (InitStringCharStar (KeyToCharStar (GetSymName (enum)))))
848 appendStr - appends str to errorString.
851 PROCEDURE appendStr (str: ARRAY OF CHAR) ;
853 appendString (Mark (InitString (str)))
858 EnumerateErrors - populate errorString with the contents of enumList.
861 PROCEDURE EnumerateErrors (enumList: List) ;
865 n := NoOfItemsInList (enumList) ;
866 IF (enumList # NIL) AND (n > 0)
870 errorString := InitString ('{%W}the missing enumeration field is: ') ;
872 errorString := InitString ('{%W}the missing enumeration fields are: ') ;
874 appendEnum (GetItemFromList (enumList, 1)) ;
882 appendEnum (GetItemFromList (enumList, i)) ;
886 appendStr (' and ') ;
887 appendEnum (GetItemFromList (enumList, n))
890 END EnumerateErrors ;
894 NoOfSetElements - return the number of set elements.
897 PROCEDURE NoOfSetElements (set: SetRange) : Tree ;
901 IF ((set^.low # NIL) AND (set^.high = NIL)) OR
902 ((set^.low = NIL) AND (set^.high # NIL))
906 ELSIF (set^.low # NIL) AND (set^.high # NIL)
908 PushIntegerTree (set^.high) ;
909 PushIntegerTree (set^.low) ;
917 RETURN PopIntegerTree ()
918 END NoOfSetElements ;
922 isPrintableChar - a cautious isprint.
925 PROCEDURE isPrintableChar (value: Tree) : BOOLEAN ;
927 CASE CSTIntToChar (value) OF
929 'a'..'z': RETURN TRUE |
930 'A'..'Z': RETURN TRUE |
931 '0'..'9': RETURN TRUE |
932 '!', '@': RETURN TRUE |
933 '#', '$': RETURN TRUE |
934 '%', '^': RETURN TRUE |
935 '&', '*': RETURN TRUE |
936 '(', ')': RETURN TRUE |
937 '[', ']': RETURN TRUE |
938 '{', '}': RETURN TRUE |
939 '-', '+': RETURN TRUE |
940 '_', '=': RETURN TRUE |
941 ':', ';': RETURN TRUE |
942 "'", '"': RETURN TRUE |
943 ',', '.': RETURN TRUE |
944 '<', '>': RETURN TRUE |
945 '/', '?': RETURN TRUE |
946 '\', '|': RETURN TRUE |
947 '~', '`': RETURN TRUE |
953 END isPrintableChar ;
957 appendTree - append tree value to the errorString. It attempts to pretty print
958 CHAR constants and will fall back to CHR (x) if necessary.
961 PROCEDURE appendTree (value: Tree; type: CARDINAL) ;
963 IF SkipType (GetType (type)) = Char
965 IF isPrintableChar (value)
967 IF CSTIntToChar (value) = "'"
969 appendString (InitStringChar ('"')) ;
970 appendString (InitStringChar (CSTIntToChar (value))) ;
971 appendString (InitStringChar ('"'))
973 appendString (InitStringChar ("'")) ;
974 appendString (InitStringChar (CSTIntToChar (value))) ;
975 appendString (InitStringChar ("'"))
978 appendString (InitString ('CHR (')) ;
979 appendString (InitStringCharStar (CSTIntToString (value))) ;
980 appendString (InitStringChar (')'))
983 appendString (InitStringCharStar (CSTIntToString (value)))
989 SubrangeErrors - create an errorString containing all set ranges.
992 PROCEDURE SubrangeErrors (subrangetype: CARDINAL; set: SetRange) ;
999 nMissing := NoOfSetElements (set) ;
1001 zero := PopIntegerTree () ;
1002 IF IsGreater (nMissing, zero)
1005 one := PopIntegerTree () ;
1006 IF IsGreater (nMissing, one)
1008 errorString := InitString ('{%W}there are a total of ')
1010 errorString := InitString ('{%W}there is a total of ')
1012 appendString (InitStringCharStar (CSTIntToString (nMissing))) ;
1013 appendStr (' missing values in the subrange, the {%kCASE} statement needs labels (or an {%kELSE} statement)') ;
1014 appendStr (' for the following values: ') ;
1030 appendTree (sr^.high, subrangetype)
1031 ELSIF (sr^.high = NIL) OR IsEqual (sr^.low, sr^.high)
1033 appendTree (sr^.low, subrangetype)
1035 appendTree (sr^.low, subrangetype) ;
1037 appendTree (sr^.high, subrangetype)
1042 END SubrangeErrors ;
1046 EmitMissingRangeErrors - emits a singular/plural error message for an enumeration type.
1049 PROCEDURE EmitMissingRangeErrors (tokenno: CARDINAL; type: CARDINAL; set: SetRange) ;
1051 errorString := NIL ;
1052 IF IsEnumeration (type)
1054 EnumerateErrors (ErrorRanges (type, set))
1055 ELSIF IsSubrange (type)
1057 SubrangeErrors (type, set)
1059 IF errorString # NIL
1061 MetaErrorStringT0 (tokenno, errorString)
1063 END EmitMissingRangeErrors ;
1067 MissingCaseBounds - returns true if there were any missing bounds
1068 in the varient record case list, c. It will
1069 generate an error message for each missing
1073 PROCEDURE MissingCaseBounds (tokenno: CARDINAL; c: CARDINAL) : BOOLEAN ;
1075 p : CaseDescriptor ;
1080 p := GetIndice (caseArray, c) ;
1085 IF (record # NulSym) AND (varient # NulSym)
1087 (* Not a case statement, but a varient record without an else clause. *)
1088 type := GetVariantTagType (varient) ;
1089 set := NewSet (type) ;
1090 set := ExcludeCaseRanges (set, p) ;
1094 MetaErrorT2 (tokenno,
1095 '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',
1097 EmitMissingRangeErrors (tokenno, type, set)
1099 set := DisposeRanges (set)
1104 END MissingCaseBounds ;
1108 MissingCaseStatementBounds - returns true if the case statement has a missing
1109 clause. It will also generate error messages.
1112 PROCEDURE MissingCaseStatementBounds (tokenno: CARDINAL; c: CARDINAL) : BOOLEAN ;
1114 p : CaseDescriptor ;
1119 p := GetIndice (caseArray, c) ;
1124 IF expression # NulSym
1126 type := SkipType (GetType (expression)) ;
1129 IF IsEnumeration (type) OR IsSubrange (type)
1131 (* A case statement sequence without an else clause but
1132 selecting using an enumeration type. *)
1133 set := NewSet (type) ;
1134 set := ExcludeCaseRanges (set, p) ;
1138 MetaErrorT1 (tokenno,
1139 'not all {%1Wd} values in the {%kCASE} statements are specified, hint you either need to specify each value of {%1ad} or use an {%kELSE} clause',
1141 EmitMissingRangeErrors (tokenno, type, set)
1143 set := DisposeRanges (set)
1150 END MissingCaseStatementBounds ;
1154 InRangeList - returns true if the value, tag, is defined in the case list.
1156 procedure InRangeList (cl: CaseList; tag: cardinal) : boolean ;
1164 h := HighIndice(rangeArray) ;
1166 r := GetIndice(rangeArray, i) ;
1174 if OverlapsRange(Mod2Gcc(low), a, Mod2Gcc(tag), Mod2Gcc(tag))
1188 WriteCase - dump out the case list (internal debugging).
1191 PROCEDURE WriteCase (c: CARDINAL) ;
1193 (* this debugging PROCEDURE should be finished. *)
1199 checkTypes - checks to see that, constant, and, type, are compatible.
1202 PROCEDURE checkTypes (constant, type: CARDINAL) : BOOLEAN ;
1204 consttype: CARDINAL ;
1206 IF (constant # NulSym) AND IsConst (constant)
1208 consttype := GetType (constant) ;
1209 IF NOT IsExpressionCompatible (consttype, type)
1211 MetaError2 ('the case statement variant tag {%1ad} must be type compatible with the constant {%2Da:is a {%2d}}',
1221 inRange - returns true if, min <= i <= max.
1224 PROCEDURE inRange (i, min, max: CARDINAL) : BOOLEAN ;
1226 RETURN OverlapsRange (Mod2Gcc (i), Mod2Gcc (i), Mod2Gcc (min), Mod2Gcc (max))
1231 TypeCaseBounds - returns true if all bounds in case list, c, are
1232 compatible with the tagged type.
1235 PROCEDURE TypeCaseBounds (c: CARDINAL) : BOOLEAN ;
1237 p : CaseDescriptor ;
1243 compatible: BOOLEAN ;
1245 p := GetIndice(caseArray, c) ;
1251 (* not a CASE statement, but a varient record containing without an ELSE clause *)
1252 type := GetVariantTagType(varient) ;
1253 min := GetTypeMin(type) ;
1254 max := GetTypeMax(type)
1260 compatible := TRUE ;
1262 WHILE i<=maxCaseId DO
1263 q := GetIndice(caseListArray, i) ;
1265 WHILE j<=q^.maxRangeId DO
1266 r := GetIndice(q^.rangeArray, j) ;
1267 IF (r^.low#NulSym) AND (NOT inRange(r^.low, min, max))
1269 MetaError2('the CASE statement variant range {%1ad} exceeds that of the tag type {%2ad}',
1273 IF NOT checkTypes(r^.low, type)
1277 IF (r^.high#NulSym) AND (NOT inRange(r^.high, min, max))
1279 MetaError2('the CASE statement variant range {%1ad} exceeds that of the tag type {%2ad}',
1283 IF NOT checkTypes(r^.high, type)
1293 END TypeCaseBounds ;
1299 caseArray := InitIndex(1) ;
1300 conflictArray := InitIndex(1) ;
1301 FreeRangeList := NIL