1 /* ccl - routines for character classes */
3 /* Copyright (c) 1990 The Regents of the University of California. */
4 /* All rights reserved. */
6 /* This code is derived from software contributed to Berkeley by */
9 /* The United States Government has rights in this work pursuant */
10 /* to contract no. DE-AC03-76SF00098 between the United States */
11 /* Department of Energy and the University of California. */
13 /* This file is part of flex. */
15 /* Redistribution and use in source and binary forms, with or without */
16 /* modification, are permitted provided that the following conditions */
19 /* 1. Redistributions of source code must retain the above copyright */
20 /* notice, this list of conditions and the following disclaimer. */
21 /* 2. Redistributions in binary form must reproduce the above copyright */
22 /* notice, this list of conditions and the following disclaimer in the */
23 /* documentation and/or other materials provided with the distribution. */
25 /* Neither the name of the University nor the names of its contributors */
26 /* may be used to endorse or promote products derived from this software */
27 /* without specific prior written permission. */
29 /* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */
30 /* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
31 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
36 /* return true if the chr is in the ccl. Takes negation into account. */
38 ccl_contains (const int cclp
, const int ch
)
45 for (i
= 0; i
< len
; ++i
)
46 if (ccltbl
[ind
+ i
] == ch
)
53 /* ccladd - add a single character to a ccl */
55 void ccladd (cclp
, ch
)
59 int ind
, len
, newpos
, i
;
66 /* check to see if the character is already in the ccl */
68 for (i
= 0; i
< len
; ++i
)
69 if (ccltbl
[ind
+ i
] == ch
)
74 ccl_has_nl
[cclp
] = true;
78 if (newpos
>= current_max_ccl_tbl_size
) {
79 current_max_ccl_tbl_size
+= MAX_CCL_TBL_SIZE_INCREMENT
;
83 ccltbl
= reallocate_Character_array (ccltbl
,
84 current_max_ccl_tbl_size
);
87 ccllen
[cclp
] = len
+ 1;
91 /* dump_cclp - same thing as list_character_set, but for cclps. */
93 static void dump_cclp (FILE* file
, int cclp
)
99 for (i
= 0; i
< csize
; ++i
) {
100 if (ccl_contains(cclp
, i
)){
101 register int start_char
= i
;
105 fputs (readable_form (i
), file
);
107 while (++i
< csize
&& ccl_contains(cclp
,i
)) ;
109 if (i
- 1 > start_char
)
111 fprintf (file
, "-%s",
112 readable_form (i
- 1));
123 /* ccl_set_diff - create a new ccl as the set difference of the two given ccls. */
125 ccl_set_diff (int a
, int b
)
129 /* create new class */
132 /* In order to handle negation, we spin through all possible chars,
133 * addding each char in a that is not in b.
134 * (This could be O(n^2), but n is small and bounded.)
136 for ( ch
= 0; ch
< csize
; ++ch
)
137 if (ccl_contains (a
, ch
) && !ccl_contains(b
, ch
))
142 fprintf(stderr
, "ccl_set_diff (");
143 fprintf(stderr
, "\n ");
144 dump_cclp (stderr
, a
);
145 fprintf(stderr
, "\n ");
146 dump_cclp (stderr
, b
);
147 fprintf(stderr
, "\n ");
148 dump_cclp (stderr
, d
);
149 fprintf(stderr
, "\n)\n");
154 /* ccl_set_union - create a new ccl as the set union of the two given ccls. */
156 ccl_set_union (int a
, int b
)
160 /* create new class */
164 for (i
= 0; i
< ccllen
[a
]; ++i
)
165 ccladd (d
, ccltbl
[cclmap
[a
] + i
]);
168 for (i
= 0; i
< ccllen
[b
]; ++i
)
169 ccladd (d
, ccltbl
[cclmap
[b
] + i
]);
173 fprintf(stderr
, "ccl_set_union (%d + %d = %d", a
, b
, d
);
174 fprintf(stderr
, "\n ");
175 dump_cclp (stderr
, a
);
176 fprintf(stderr
, "\n ");
177 dump_cclp (stderr
, b
);
178 fprintf(stderr
, "\n ");
179 dump_cclp (stderr
, d
);
180 fprintf(stderr
, "\n)\n");
186 /* cclinit - return an empty ccl */
190 if (++lastccl
>= current_maxccls
) {
191 current_maxccls
+= MAX_CCLS_INCREMENT
;
196 reallocate_integer_array (cclmap
, current_maxccls
);
198 reallocate_integer_array (ccllen
, current_maxccls
);
199 cclng
= reallocate_integer_array (cclng
, current_maxccls
);
201 reallocate_bool_array (ccl_has_nl
,
206 /* we're making the first ccl */
210 /* The new pointer is just past the end of the last ccl.
211 * Since the cclmap points to the \first/ character of a
212 * ccl, adding the length of the ccl to the cclmap pointer
213 * will produce a cursor to the first free space.
216 cclmap
[lastccl
- 1] + ccllen
[lastccl
- 1];
219 cclng
[lastccl
] = 0; /* ccl's start out life un-negated */
220 ccl_has_nl
[lastccl
] = false;
226 /* cclnegate - negate the given ccl */
228 void cclnegate (cclp
)
232 ccl_has_nl
[cclp
] = !ccl_has_nl
[cclp
];
236 /* list_character_set - list the members of a set of characters in CCL form
238 * Writes to the given file a character-class representation of those
239 * characters present in the given CCL. A character is present if it
240 * has a non-zero value in the cset array.
243 void list_character_set (file
, cset
)
251 for (i
= 0; i
< csize
; ++i
) {
253 register int start_char
= i
;
257 fputs (readable_form (i
), file
);
259 while (++i
< csize
&& cset
[i
]) ;
261 if (i
- 1 > start_char
)
263 fprintf (file
, "-%s",
264 readable_form (i
- 1));
273 /** Determines if the range [c1-c2] is unambiguous in a case-insensitive
274 * scanner. Specifically, if a lowercase or uppercase character, x, is in the
275 * range [c1-c2], then we require that UPPERCASE(x) and LOWERCASE(x) must also
276 * be in the range. If not, then this range is ambiguous, and the function
277 * returns false. For example, [@-_] spans [a-z] but not [A-Z]. Beware that
278 * [a-z] will be labeled ambiguous because it does not include [A-Z].
280 * @param c1 the lower end of the range
281 * @param c2 the upper end of the range
282 * @return true if [c1-c2] is not ambiguous for a caseless scanner.
284 bool range_covers_case (int c1
, int c2
)
288 for (i
= c1
; i
<= c2
; i
++) {
290 o
= reverse_case (i
);
291 if (o
< c1
|| c2
< o
)
298 /** Reverse the case of a character, if possible.
299 * @return c if case-reversal does not apply.
301 int reverse_case (int c
)
303 return isupper (c
) ? tolower (c
) : (islower (c
) ? toupper (c
) : c
);
306 /** Return true if c is uppercase or lowercase. */
307 bool has_case (int c
)
309 return (isupper (c
) || islower (c
)) ? true : false;