]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/ada-lex.l
136e6dd3c2c1ae9d75c544621165ad15894e6aab
[thirdparty/binutils-gdb.git] / gdb / ada-lex.l
1 /* FLEX lexer for Ada expressions, for GDB. -*- c++ -*-
2 Copyright (C) 1994-2024 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (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, see <http://www.gnu.org/licenses/>. */
18
19 /*----------------------------------------------------------------------*/
20
21 /* The converted version of this file is to be included in ada-exp.y, */
22 /* the Ada parser for gdb. The function yylex obtains characters from */
23 /* the global pointer lexptr. It returns a syntactic category for */
24 /* each successive token and places a semantic value into yylval */
25 /* (ada-lval), defined by the parser. */
26
27 DIG [0-9]
28 NUM10 ({DIG}({DIG}|_)*)
29 HEXDIG [0-9a-f]
30 NUM16 ({HEXDIG}({HEXDIG}|_)*)
31 OCTDIG [0-7]
32 LETTER [a-z_]
33 ID ({LETTER}({LETTER}|{DIG}|[\x80-\xff])*|"<"{LETTER}({LETTER}|{DIG})*">")
34 WHITE [ \t\n]
35 TICK ("'"{WHITE}*)
36 GRAPHIC [a-z0-9 #&'()*+,-./:;<>=_|!$%?@\[\]\\^`{}~]
37 OPER ([-+*/=<>&]|"<="|">="|"**"|"/="|"and"|"or"|"xor"|"not"|"mod"|"rem"|"abs")
38
39 EXP (e[+-]{NUM10})
40 POSEXP (e"+"?{NUM10})
41
42 /* This must agree with COMPLETION_CHAR below. See the comment there
43 for the explanation. */
44 COMPLETE "\001"
45 NOT_COMPLETE [^\001]
46
47 %{
48
49 #include "diagnostics.h"
50
51 /* Some old versions of flex (2.5.x) generate code that uses the "register"
52 keyword, which compilers warn about, because it is not allowed in ISO
53 C++17. */
54 DIAGNOSTIC_PUSH
55 DIAGNOSTIC_IGNORE_REGISTER
56
57 #define NUMERAL_WIDTH 256
58 #define LONGEST_SIGN ((ULONGEST) 1 << (sizeof(LONGEST) * HOST_CHAR_BIT - 1))
59
60 static void canonicalizeNumeral (char *s1, const char *);
61 static struct stoken processString (const char*, int);
62 static int processInt (struct parser_state *, const char *, const char *,
63 const char *);
64 static int processReal (struct parser_state *, const char *);
65 static struct stoken processId (const char *, int);
66 static int processAttribute (const char *);
67 static int find_dot_all (const char *);
68 static void rewind_to_char (int);
69
70 #undef YY_DECL
71 #define YY_DECL static int yylex ( void )
72
73 /* Flex generates a static function "input" which is not used.
74 Defining YY_NO_INPUT comments it out. */
75 #define YY_NO_INPUT
76
77 /* The character we use to represent the completion point. */
78 #define COMPLETE_CHAR '\001'
79
80 #undef YY_INPUT
81 #define YY_INPUT(BUF, RESULT, MAX_SIZE) \
82 if ( *pstate->lexptr == '\000' ) \
83 { \
84 if (pstate->parse_completion && !ada_parser->returned_complete) \
85 { \
86 ada_parser->returned_complete = true; \
87 *(BUF) = COMPLETE_CHAR; \
88 (RESULT) = 1; \
89 } \
90 else \
91 (RESULT) = YY_NULL; \
92 } \
93 else \
94 { \
95 *(BUF) = *pstate->lexptr == COMPLETE_CHAR ? ' ' : *pstate->lexptr; \
96 (RESULT) = 1; \
97 pstate->lexptr += 1; \
98 }
99
100 %}
101
102 %option case-insensitive interactive nodefault noyywrap
103
104 %s BEFORE_QUAL_QUOTE
105
106 %%
107
108 {WHITE} { }
109
110 "--".* { yyterminate(); }
111
112 {NUM10}{POSEXP} {
113 char numbuf[NUMERAL_WIDTH];
114 canonicalizeNumeral (numbuf, yytext);
115 char *e_ptr = strrchr (numbuf, 'e');
116 *e_ptr = '\0';
117 return processInt (pstate, nullptr, numbuf, e_ptr + 1);
118 }
119
120 {NUM10} {
121 char numbuf[NUMERAL_WIDTH];
122 canonicalizeNumeral (numbuf, yytext);
123 return processInt (pstate, NULL, numbuf, NULL);
124 }
125
126 {NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#"{POSEXP} {
127 char numbuf[NUMERAL_WIDTH];
128 canonicalizeNumeral (numbuf, yytext);
129 char *e_ptr = strrchr (numbuf, 'e');
130 *e_ptr = '\0';
131 return processInt (pstate, numbuf,
132 strchr (numbuf, '#') + 1,
133 e_ptr + 1);
134 }
135
136 /* The "llf" is a gdb extension to allow a floating-point
137 constant to be written in some other base. The
138 floating-point number is formed by reinterpreting the
139 bytes, allowing direct control over the bits. */
140 {NUM10}(l{0,2}f)?"#"{HEXDIG}({HEXDIG}|_)*"#" {
141 char numbuf[NUMERAL_WIDTH];
142 canonicalizeNumeral (numbuf, yytext);
143 return processInt (pstate, numbuf, strchr (numbuf, '#') + 1,
144 NULL);
145 }
146
147 "0x"{HEXDIG}+ {
148 char numbuf[NUMERAL_WIDTH];
149 canonicalizeNumeral (numbuf, yytext+2);
150 return processInt (pstate, "16#", numbuf, NULL);
151 }
152
153
154 {NUM10}"."{NUM10}{EXP} {
155 char numbuf[NUMERAL_WIDTH];
156 canonicalizeNumeral (numbuf, yytext);
157 return processReal (pstate, numbuf);
158 }
159
160 {NUM10}"."{NUM10} {
161 char numbuf[NUMERAL_WIDTH];
162 canonicalizeNumeral (numbuf, yytext);
163 return processReal (pstate, numbuf);
164 }
165
166 {NUM10}"#"{NUM16}"."{NUM16}"#"{EXP} {
167 error (_("Based real literals not implemented yet."));
168 }
169
170 {NUM10}"#"{NUM16}"."{NUM16}"#" {
171 error (_("Based real literals not implemented yet."));
172 }
173
174 <INITIAL>"'"({GRAPHIC}|\")"'" {
175 yylval.typed_char.val = yytext[1];
176 yylval.typed_char.type = type_for_char (pstate, yytext[1]);
177 return CHARLIT;
178 }
179
180 <INITIAL>"'[\""{HEXDIG}{2,}"\"]'" {
181 ULONGEST v = strtoulst (yytext+3, nullptr, 16);
182 yylval.typed_char.val = v;
183 yylval.typed_char.type = type_for_char (pstate, v);
184 return CHARLIT;
185 }
186
187 /* Note that we don't handle bracket sequences of more than 2
188 digits here. Currently there's no support for wide or
189 wide-wide strings. */
190 \"({GRAPHIC}|"[\""({HEXDIG}{2,}|\")"\"]")*\" {
191 yylval.sval = processString (yytext+1, yyleng-2);
192 return STRING;
193 }
194
195 \" {
196 error (_("ill-formed or non-terminated string literal"));
197 }
198
199
200 if {
201 rewind_to_char ('i');
202 return 0;
203 }
204
205 task {
206 rewind_to_char ('t');
207 return 0;
208 }
209
210 thread{WHITE}+{DIG} {
211 /* This keyword signals the end of the expression and
212 will be processed separately. */
213 rewind_to_char ('t');
214 return 0;
215 }
216
217 /* ADA KEYWORDS */
218
219 abs { return ABS; }
220 and { return _AND_; }
221 delta { return DELTA; }
222 else { return ELSE; }
223 for { return FOR; }
224 in { return IN; }
225 mod { return MOD; }
226 new { return NEW; }
227 not { return NOT; }
228 null { return NULL_PTR; }
229 or { return OR; }
230 others { return OTHERS; }
231 rem { return REM; }
232 then { return THEN; }
233 with { return WITH; }
234 xor { return XOR; }
235
236 /* BOOLEAN "KEYWORDS" */
237
238 /* True and False are not keywords in Ada, but rather enumeration constants.
239 However, the boolean type is no longer represented as an enum, so True
240 and False are no longer defined in symbol tables. We compromise by
241 making them keywords (when bare). */
242
243 true { return TRUEKEYWORD; }
244 false { return FALSEKEYWORD; }
245
246 /* ATTRIBUTES */
247
248 {TICK}([a-z][a-z_]*)?{COMPLETE}? { BEGIN INITIAL; return processAttribute (yytext); }
249
250 /* PUNCTUATION */
251
252 "=>" { return ARROW; }
253 ".." { return DOTDOT; }
254 "**" { return STARSTAR; }
255 ":=" { return ASSIGN; }
256 "/=" { return NOTEQUAL; }
257 "<=" { return LEQ; }
258 ">=" { return GEQ; }
259
260 <BEFORE_QUAL_QUOTE>"'"/{NOT_COMPLETE} { BEGIN INITIAL; return '\''; }
261
262 [-&*+{}@/:<>=|;\[\]] { return yytext[0]; }
263
264 "," { if (ada_parser->paren_depth == 0 && pstate->comma_terminates)
265 {
266 rewind_to_char (',');
267 return 0;
268 }
269 else
270 return ',';
271 }
272
273 "(" { ada_parser->paren_depth += 1; return '('; }
274 ")" { if (ada_parser->paren_depth == 0)
275 {
276 rewind_to_char (')');
277 return 0;
278 }
279 else
280 {
281 ada_parser->paren_depth -= 1;
282 return ')';
283 }
284 }
285
286 "."{WHITE}*{ID}{COMPLETE}? {
287 yylval.sval = processId (yytext+1, yyleng-1);
288 if (yytext[yyleng - 1] == COMPLETE_CHAR)
289 return DOT_COMPLETE;
290 return DOT_ID;
291 }
292
293 "."{WHITE}*{COMPLETE} {
294 yylval.sval.ptr = "";
295 yylval.sval.length = 0;
296 return DOT_COMPLETE;
297 }
298
299 {ID}({WHITE}*"."{WHITE}*({ID}|\"{OPER}\"))*(" "*"'"|{COMPLETE})? {
300 int all_posn = find_dot_all (yytext);
301
302 if (all_posn == -1 && yytext[yyleng-1] == '\'')
303 {
304 BEGIN BEFORE_QUAL_QUOTE;
305 yyless (yyleng-1);
306 }
307 else if (all_posn >= 0)
308 yyless (all_posn);
309 bool is_completion = yytext[yyleng - 1] == COMPLETE_CHAR;
310 yylval.sval = processId (yytext, yyleng);
311 return is_completion ? NAME_COMPLETE : NAME;
312 }
313
314
315 /* GDB EXPRESSION CONSTRUCTS */
316
317 "'"[^']+"'"{WHITE}*:: {
318 yyless (yyleng - 2);
319 yylval.sval = processId (yytext, yyleng);
320 return NAME;
321 }
322
323 "::" { return COLONCOLON; }
324
325 /* REGISTERS AND GDB CONVENIENCE VARIABLES */
326
327 "$"({LETTER}|{DIG}|"$")* {
328 yylval.sval.ptr = yytext;
329 yylval.sval.length = yyleng;
330 return DOLLAR_VARIABLE;
331 }
332
333 /* CATCH-ALL ERROR CASE */
334
335 . { error (_("Invalid character '%s' in expression."), yytext); }
336 %%
337
338 #include <ctype.h>
339 /* Initialize the lexer for processing new expression. */
340
341 static void
342 lexer_init (FILE *inp)
343 {
344 BEGIN INITIAL;
345 yyrestart (inp);
346 }
347
348
349 /* Copy S2 to S1, removing all underscores, and downcasing all letters. */
350
351 static void
352 canonicalizeNumeral (char *s1, const char *s2)
353 {
354 for (; *s2 != '\000'; s2 += 1)
355 {
356 if (*s2 != '_')
357 {
358 *s1 = tolower(*s2);
359 s1 += 1;
360 }
361 }
362 s1[0] = '\000';
363 }
364
365 /* Interprets the prefix of NUM that consists of digits of the given BASE
366 as an integer of that BASE, with the string EXP as an exponent.
367 Puts value in yylval, and returns INT, if the string is valid. Causes
368 an error if the number is improperly formatted. BASE, if NULL, defaults
369 to "10", and EXP to "1". The EXP does not contain a leading 'e' or 'E'.
370 */
371
372 static int
373 processInt (struct parser_state *par_state, const char *base0,
374 const char *num0, const char *exp0)
375 {
376 long exp;
377 int base;
378 /* For the based literal with an "f" prefix, we'll return a
379 floating-point number. This counts the the number of "l"s seen,
380 to decide the width of the floating-point number to return. -1
381 means no "f". */
382 int floating_point_l_count = -1;
383
384 if (base0 == NULL)
385 base = 10;
386 else
387 {
388 char *end_of_base;
389 base = strtol (base0, &end_of_base, 10);
390 if (base < 2 || base > 16)
391 error (_("Invalid base: %d."), base);
392 while (*end_of_base == 'l')
393 {
394 ++floating_point_l_count;
395 ++end_of_base;
396 }
397 /* This assertion is ensured by the pattern. */
398 gdb_assert (floating_point_l_count == -1 || *end_of_base == 'f');
399 if (*end_of_base == 'f')
400 {
401 ++end_of_base;
402 ++floating_point_l_count;
403 }
404 /* This assertion is ensured by the pattern. */
405 gdb_assert (*end_of_base == '#');
406 }
407
408 if (exp0 == NULL)
409 exp = 0;
410 else
411 exp = strtol(exp0, (char **) NULL, 10);
412
413 gdb_mpz result;
414 while (isxdigit (*num0))
415 {
416 int dig = fromhex (*num0);
417 if (dig >= base)
418 error (_("Invalid digit `%c' in based literal"), *num0);
419 result *= base;
420 result += dig;
421 ++num0;
422 }
423
424 while (exp > 0)
425 {
426 result *= base;
427 exp -= 1;
428 }
429
430 if (floating_point_l_count > -1)
431 {
432 struct type *fp_type;
433 if (floating_point_l_count == 0)
434 fp_type = language_lookup_primitive_type (par_state->language (),
435 par_state->gdbarch (),
436 "float");
437 else if (floating_point_l_count == 1)
438 fp_type = language_lookup_primitive_type (par_state->language (),
439 par_state->gdbarch (),
440 "long_float");
441 else
442 {
443 /* This assertion is ensured by the pattern. */
444 gdb_assert (floating_point_l_count == 2);
445 fp_type = language_lookup_primitive_type (par_state->language (),
446 par_state->gdbarch (),
447 "long_long_float");
448 }
449
450 yylval.typed_val_float.type = fp_type;
451 result.write (gdb::make_array_view (yylval.typed_val_float.val,
452 fp_type->length ()),
453 type_byte_order (fp_type),
454 true);
455
456 return FLOAT;
457 }
458
459 const gdb_mpz *value = ada_parser->push_integer (std::move (result));
460
461 int int_bits = gdbarch_int_bit (par_state->gdbarch ());
462 int long_bits = gdbarch_long_bit (par_state->gdbarch ());
463 int long_long_bits = gdbarch_long_long_bit (par_state->gdbarch ());
464
465 if (fits_in_type (1, *value, int_bits, true))
466 yylval.typed_val.type = parse_type (par_state)->builtin_int;
467 else if (fits_in_type (1, *value, long_bits, true))
468 yylval.typed_val.type = parse_type (par_state)->builtin_long;
469 else if (fits_in_type (1, *value, long_bits, false))
470 yylval.typed_val.type
471 = builtin_type (par_state->gdbarch ())->builtin_unsigned_long;
472 else if (fits_in_type (1, *value, long_long_bits, true))
473 yylval.typed_val.type = parse_type (par_state)->builtin_long_long;
474 else if (fits_in_type (1, *value, long_long_bits, false))
475 yylval.typed_val.type
476 = builtin_type (par_state->gdbarch ())->builtin_unsigned_long_long;
477 else if (fits_in_type (1, *value, 128, true))
478 yylval.typed_val.type
479 = language_lookup_primitive_type (par_state->language (),
480 par_state->gdbarch (),
481 "long_long_long_integer");
482 else if (fits_in_type (1, *value, 128, false))
483 yylval.typed_val.type
484 = language_lookup_primitive_type (par_state->language (),
485 par_state->gdbarch (),
486 "unsigned_long_long_long_integer");
487 else
488 error (_("Integer literal out of range"));
489
490 yylval.typed_val.val = value;
491 return INT;
492 }
493
494 static int
495 processReal (struct parser_state *par_state, const char *num0)
496 {
497 yylval.typed_val_float.type = parse_type (par_state)->builtin_long_double;
498
499 bool parsed = parse_float (num0, strlen (num0),
500 yylval.typed_val_float.type,
501 yylval.typed_val_float.val);
502 gdb_assert (parsed);
503 return FLOAT;
504 }
505
506
507 /* Store a canonicalized version of NAME0[0..LEN-1] in yylval.ssym. The
508 resulting string is valid until the next call to ada_parse. If
509 NAME0 contains the substring "___", it is assumed to be already
510 encoded and the resulting name is equal to it. Similarly, if the name
511 starts with '<', it is copied verbatim. Otherwise, it differs
512 from NAME0 in that:
513 + Characters between '...' are transfered verbatim to yylval.ssym.
514 + Trailing "'" characters in quoted sequences are removed (a leading quote is
515 preserved to indicate that the name is not to be GNAT-encoded).
516 + Unquoted whitespace is removed.
517 + Unquoted alphabetic characters are mapped to lower case.
518 Result is returned as a struct stoken, but for convenience, the string
519 is also null-terminated. Result string valid until the next call of
520 ada_parse.
521 */
522 static struct stoken
523 processId (const char *name0, int len)
524 {
525 char *name = (char *) obstack_alloc (&ada_parser->temp_space, len + 11);
526 int i0, i;
527 struct stoken result;
528
529 result.ptr = name;
530 while (len > 0 && isspace (name0[len-1]))
531 len -= 1;
532
533 if (name0[0] == '<' || strstr (name0, "___") != NULL)
534 {
535 strncpy (name, name0, len);
536 name[len] = '\000';
537 result.length = len;
538 return result;
539 }
540
541 bool in_quotes = false;
542 i = i0 = 0;
543 while (i0 < len)
544 {
545 if (name0[i0] == COMPLETE_CHAR)
546 {
547 /* Just ignore. */
548 ++i0;
549 }
550 else if (in_quotes)
551 name[i++] = name0[i0++];
552 else if (isalnum (name0[i0]))
553 {
554 name[i] = tolower (name0[i0]);
555 i += 1; i0 += 1;
556 }
557 else if (isspace (name0[i0]))
558 i0 += 1;
559 else if (name0[i0] == '\'')
560 {
561 /* Copy the starting quote, but not the ending quote. */
562 if (!in_quotes)
563 name[i++] = name0[i0++];
564 in_quotes = !in_quotes;
565 }
566 else
567 name[i++] = name0[i0++];
568 }
569 name[i] = '\000';
570
571 result.length = i;
572 return result;
573 }
574
575 /* Return TEXT[0..LEN-1], a string literal without surrounding quotes,
576 with special hex character notations replaced with characters.
577 Result valid until the next call to ada_parse. */
578
579 static struct stoken
580 processString (const char *text, int len)
581 {
582 const char *p;
583 char *q;
584 const char *lim = text + len;
585 struct stoken result;
586
587 q = (char *) obstack_alloc (&ada_parser->temp_space, len);
588 result.ptr = q;
589 p = text;
590 while (p < lim)
591 {
592 if (p[0] == '[' && p[1] == '"' && p+2 < lim)
593 {
594 if (p[2] == '"') /* "...["""]... */
595 {
596 *q = '"';
597 p += 4;
598 }
599 else
600 {
601 const char *end;
602 ULONGEST chr = strtoulst (p + 2, &end, 16);
603 if (chr > 0xff)
604 error (_("wide strings are not yet supported"));
605 *q = (char) chr;
606 p = end + 1;
607 }
608 }
609 else
610 *q = *p;
611 q += 1;
612 p += 1;
613 }
614 result.length = q - result.ptr;
615 return result;
616 }
617
618 /* Returns the position within STR of the '.' in a
619 '.{WHITE}*all' component of a dotted name, or -1 if there is none.
620 Note: we actually don't need this routine, since 'all' can never be an
621 Ada identifier. Thus, looking up foo.all or foo.all.x as a name
622 must fail, and will eventually be interpreted as (foo).all or
623 (foo).all.x. However, this does avoid an extraneous lookup. */
624
625 static int
626 find_dot_all (const char *str)
627 {
628 int i;
629
630 for (i = 0; str[i] != '\000'; i++)
631 if (str[i] == '.')
632 {
633 int i0 = i;
634
635 do
636 i += 1;
637 while (isspace (str[i]));
638
639 if (strncasecmp (str + i, "all", 3) == 0
640 && !isalnum (str[i + 3]) && str[i + 3] != '_')
641 return i0;
642 }
643 return -1;
644 }
645
646 /* Returns non-zero iff string SUBSEQ matches a subsequence of STR, ignoring
647 case. */
648
649 static int
650 subseqMatch (const char *subseq, const char *str)
651 {
652 if (subseq[0] == '\0')
653 return 1;
654 else if (str[0] == '\0')
655 return 0;
656 else if (tolower (subseq[0]) == tolower (str[0]))
657 return subseqMatch (subseq+1, str+1) || subseqMatch (subseq, str+1);
658 else
659 return subseqMatch (subseq, str+1);
660 }
661
662
663 static const struct { const char *name; int code; }
664 attributes[] = {
665 { "address", TICK_ADDRESS },
666 { "unchecked_access", TICK_ACCESS },
667 { "unrestricted_access", TICK_ACCESS },
668 { "access", TICK_ACCESS },
669 { "first", TICK_FIRST },
670 { "last", TICK_LAST },
671 { "length", TICK_LENGTH },
672 { "max", TICK_MAX },
673 { "min", TICK_MIN },
674 { "modulus", TICK_MODULUS },
675 { "pos", TICK_POS },
676 { "range", TICK_RANGE },
677 { "size", TICK_SIZE },
678 { "tag", TICK_TAG },
679 { "val", TICK_VAL },
680 { "enum_rep", TICK_ENUM_REP },
681 { "enum_val", TICK_ENUM_VAL },
682 };
683
684 /* Return the syntactic code corresponding to the attribute name or
685 abbreviation STR. */
686
687 static int
688 processAttribute (const char *str)
689 {
690 gdb_assert (*str == '\'');
691 ++str;
692 while (isspace (*str))
693 ++str;
694
695 int len = strlen (str);
696 if (len > 0 && str[len - 1] == COMPLETE_CHAR)
697 {
698 /* This is enforced by YY_INPUT. */
699 gdb_assert (pstate->parse_completion);
700 yylval.sval.ptr = obstack_strndup (&ada_parser->temp_space,
701 str, len - 1);
702 yylval.sval.length = len - 1;
703 return TICK_COMPLETE;
704 }
705
706 for (const auto &item : attributes)
707 if (strcasecmp (str, item.name) == 0)
708 return item.code;
709
710 std::optional<int> found;
711 for (const auto &item : attributes)
712 if (subseqMatch (str, item.name))
713 {
714 if (!found.has_value ())
715 found = item.code;
716 else
717 error (_("ambiguous attribute name: `%s'"), str);
718 }
719 if (!found.has_value ())
720 error (_("unrecognized attribute: `%s'"), str);
721
722 return *found;
723 }
724
725 bool
726 ada_tick_completer::complete (struct expression *exp,
727 completion_tracker &tracker)
728 {
729 completion_list output;
730 for (const auto &item : attributes)
731 {
732 if (strncasecmp (item.name, m_name.c_str (), m_name.length ()) == 0)
733 output.emplace_back (xstrdup (item.name));
734 }
735 tracker.add_completions (std::move (output));
736 return true;
737 }
738
739 /* Back up lexptr by yyleng and then to the rightmost occurrence of
740 character CH, case-folded (there must be one). WARNING: since
741 lexptr points to the next input character that Flex has not yet
742 transferred to its internal buffer, the use of this function
743 depends on the assumption that Flex calls YY_INPUT only when it is
744 logically necessary to do so (thus, there is no reading ahead
745 farther than needed to identify the next token.) */
746
747 static void
748 rewind_to_char (int ch)
749 {
750 pstate->lexptr -= yyleng;
751 while (toupper (*pstate->lexptr) != toupper (ch))
752 pstate->lexptr -= 1;
753 yyrestart (NULL);
754 }
755
756 /* Dummy definition to suppress warnings about unused static definitions. */
757 typedef void (*dummy_function) ();
758 dummy_function ada_flex_use[] =
759 {
760 (dummy_function) yyunput
761 };
762
763 DIAGNOSTIC_POP