123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766 |
- /* FLEX lexer for Ada expressions, for GDB. -*- c++ -*-
- Copyright (C) 1994-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- /*----------------------------------------------------------------------*/
- /* The converted version of this file is to be included in ada-exp.y, */
- /* the Ada parser for gdb. The function yylex obtains characters from */
- /* the global pointer lexptr. It returns a syntactic category for */
- /* each successive token and places a semantic value into yylval */
- /* (ada-lval), defined by the parser. */
- DIG [0-9]
- NUM10 ({DIG}({DIG}|_)*)
- HEXDIG [0-9a-f]
- NUM16 ({HEXDIG}({HEXDIG}|_)*)
- OCTDIG [0-7]
- LETTER [a-z_]
- ID ({LETTER}({LETTER}|{DIG}|[\x80-\xff])*|"<"{LETTER}({LETTER}|{DIG})*">")
- WHITE [ \t\n]
- TICK ("'"{WHITE}*)
- GRAPHIC [a-z0-9 #&'()*+,-./:;<>=_|!$%?@\[\]\\^`{}~]
- OPER ([-+*/=<>&]|"<="|">="|"**"|"/="|"and"|"or"|"xor"|"not"|"mod"|"rem"|"abs")
- EXP (e[+-]{NUM10})
- POSEXP (e"+"?{NUM10})
- /* This must agree with COMPLETION_CHAR below. See the comment there
- for the explanation. */
- COMPLETE "\001"
- NOT_COMPLETE [^\001]
- %{
- #include "diagnostics.h"
- /* Some old versions of flex generate code that uses the "register" keyword,
- which clang warns about. This was observed for example with flex 2.5.35,
- as shipped with macOS 10.12. The same happens with flex 2.5.37 and g++ 11
- which defaults to ISO C++17, that does not allow register storage class
- specifiers. */
- DIAGNOSTIC_PUSH
- DIAGNOSTIC_IGNORE_DEPRECATED_REGISTER
- #define NUMERAL_WIDTH 256
- #define LONGEST_SIGN ((ULONGEST) 1 << (sizeof(LONGEST) * HOST_CHAR_BIT - 1))
- /* Temporary staging for numeric literals. */
- static char numbuf[NUMERAL_WIDTH];
- static void canonicalizeNumeral (char *s1, const char *);
- static struct stoken processString (const char*, int);
- static int processInt (struct parser_state *, const char *, const char *,
- const char *);
- static int processReal (struct parser_state *, const char *);
- static struct stoken processId (const char *, int);
- static int processAttribute (const char *);
- static int find_dot_all (const char *);
- static void rewind_to_char (int);
- #undef YY_DECL
- #define YY_DECL static int yylex ( void )
- /* Flex generates a static function "input" which is not used.
- Defining YY_NO_INPUT comments it out. */
- #define YY_NO_INPUT
- /* When completing, we'll return a special character at the end of the
- input, to signal the completion position to the lexer. This is
- done because flex does not have a generally useful way to detect
- EOF in a pattern. This variable records whether the special
- character has been emitted. */
- static bool returned_complete = false;
- /* The character we use to represent the completion point. */
- #define COMPLETE_CHAR '\001'
- #undef YY_INPUT
- #define YY_INPUT(BUF, RESULT, MAX_SIZE) \
- if ( *pstate->lexptr == '\000' ) \
- { \
- if (pstate->parse_completion && !returned_complete) \
- { \
- returned_complete = true; \
- *(BUF) = COMPLETE_CHAR; \
- (RESULT) = 1; \
- } \
- else \
- (RESULT) = YY_NULL; \
- } \
- else \
- { \
- *(BUF) = *pstate->lexptr == COMPLETE_CHAR ? ' ' : *pstate->lexptr; \
- (RESULT) = 1; \
- pstate->lexptr += 1; \
- }
- /* Depth of parentheses. */
- static int paren_depth;
- %}
- %option case-insensitive interactive nodefault noyywrap
- %s BEFORE_QUAL_QUOTE
- %%
- {WHITE} { }
- "--".* { yyterminate(); }
- {NUM10}{POSEXP} {
- canonicalizeNumeral (numbuf, yytext);
- char *e_ptr = strrchr (numbuf, 'e');
- *e_ptr = '\0';
- return processInt (pstate, nullptr, numbuf, e_ptr + 1);
- }
- {NUM10} {
- canonicalizeNumeral (numbuf, yytext);
- return processInt (pstate, NULL, numbuf, NULL);
- }
- {NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#"{POSEXP} {
- canonicalizeNumeral (numbuf, yytext);
- char *e_ptr = strrchr (numbuf, 'e');
- *e_ptr = '\0';
- return processInt (pstate, numbuf,
- strchr (numbuf, '#') + 1,
- e_ptr + 1);
- }
- /* The "llf" is a gdb extension to allow a floating-point
- constant to be written in some other base. The
- floating-point number is formed by reinterpreting the
- bytes, allowing direct control over the bits. */
- {NUM10}(l{0,2}f)?"#"{HEXDIG}({HEXDIG}|_)*"#" {
- canonicalizeNumeral (numbuf, yytext);
- return processInt (pstate, numbuf, strchr (numbuf, '#') + 1,
- NULL);
- }
- "0x"{HEXDIG}+ {
- canonicalizeNumeral (numbuf, yytext+2);
- return processInt (pstate, "16#", numbuf, NULL);
- }
- {NUM10}"."{NUM10}{EXP} {
- canonicalizeNumeral (numbuf, yytext);
- return processReal (pstate, numbuf);
- }
- {NUM10}"."{NUM10} {
- canonicalizeNumeral (numbuf, yytext);
- return processReal (pstate, numbuf);
- }
- {NUM10}"#"{NUM16}"."{NUM16}"#"{EXP} {
- error (_("Based real literals not implemented yet."));
- }
- {NUM10}"#"{NUM16}"."{NUM16}"#" {
- error (_("Based real literals not implemented yet."));
- }
- <INITIAL>"'"({GRAPHIC}|\")"'" {
- yylval.typed_val.val = yytext[1];
- yylval.typed_val.type = type_for_char (pstate, yytext[1]);
- return CHARLIT;
- }
- <INITIAL>"'[\""{HEXDIG}{2,}"\"]'" {
- ULONGEST v = strtoulst (yytext+3, nullptr, 16);
- yylval.typed_val.val = v;
- yylval.typed_val.type = type_for_char (pstate, v);
- return CHARLIT;
- }
- /* Note that we don't handle bracket sequences of more than 2
- digits here. Currently there's no support for wide or
- wide-wide strings. */
- \"({GRAPHIC}|"[\""({HEXDIG}{2,}|\")"\"]")*\" {
- yylval.sval = processString (yytext+1, yyleng-2);
- return STRING;
- }
- \" {
- error (_("ill-formed or non-terminated string literal"));
- }
- if {
- rewind_to_char ('i');
- return 0;
- }
- task {
- rewind_to_char ('t');
- return 0;
- }
- thread{WHITE}+{DIG} {
- /* This keyword signals the end of the expression and
- will be processed separately. */
- rewind_to_char ('t');
- return 0;
- }
- /* ADA KEYWORDS */
- abs { return ABS; }
- and { return _AND_; }
- else { return ELSE; }
- in { return IN; }
- mod { return MOD; }
- new { return NEW; }
- not { return NOT; }
- null { return NULL_PTR; }
- or { return OR; }
- others { return OTHERS; }
- rem { return REM; }
- then { return THEN; }
- xor { return XOR; }
- /* BOOLEAN "KEYWORDS" */
- /* True and False are not keywords in Ada, but rather enumeration constants.
- However, the boolean type is no longer represented as an enum, so True
- and False are no longer defined in symbol tables. We compromise by
- making them keywords (when bare). */
- true { return TRUEKEYWORD; }
- false { return FALSEKEYWORD; }
- /* ATTRIBUTES */
- {TICK}([a-z][a-z_]*)?{COMPLETE}? { BEGIN INITIAL; return processAttribute (yytext); }
- /* PUNCTUATION */
- "=>" { return ARROW; }
- ".." { return DOTDOT; }
- "**" { return STARSTAR; }
- ":=" { return ASSIGN; }
- "/=" { return NOTEQUAL; }
- "<=" { return LEQ; }
- ">=" { return GEQ; }
- <BEFORE_QUAL_QUOTE>"'"/{NOT_COMPLETE} { BEGIN INITIAL; return '\''; }
- [-&*+{}@/:<>=|;\[\]] { return yytext[0]; }
- "," { if (paren_depth == 0 && pstate->comma_terminates)
- {
- rewind_to_char (',');
- return 0;
- }
- else
- return ',';
- }
- "(" { paren_depth += 1; return '('; }
- ")" { if (paren_depth == 0)
- {
- rewind_to_char (')');
- return 0;
- }
- else
- {
- paren_depth -= 1;
- return ')';
- }
- }
- "."{WHITE}*{ID}{COMPLETE}? {
- yylval.sval = processId (yytext+1, yyleng-1);
- if (yytext[yyleng - 1] == COMPLETE_CHAR)
- return DOT_COMPLETE;
- return DOT_ID;
- }
- "."{WHITE}*{COMPLETE} {
- yylval.sval.ptr = "";
- yylval.sval.length = 0;
- return DOT_COMPLETE;
- }
- {ID}({WHITE}*"."{WHITE}*({ID}|\"{OPER}\"))*(" "*"'"|{COMPLETE})? {
- int all_posn = find_dot_all (yytext);
- if (all_posn == -1 && yytext[yyleng-1] == '\'')
- {
- BEGIN BEFORE_QUAL_QUOTE;
- yyless (yyleng-1);
- }
- else if (all_posn >= 0)
- yyless (all_posn);
- bool is_completion = yytext[yyleng - 1] == COMPLETE_CHAR;
- yylval.sval = processId (yytext, yyleng);
- return is_completion ? NAME_COMPLETE : NAME;
- }
- /* GDB EXPRESSION CONSTRUCTS */
- "'"[^']+"'"{WHITE}*:: {
- yyless (yyleng - 2);
- yylval.sval = processId (yytext, yyleng);
- return NAME;
- }
- "::" { return COLONCOLON; }
- /* REGISTERS AND GDB CONVENIENCE VARIABLES */
- "$"({LETTER}|{DIG}|"$")* {
- yylval.sval.ptr = yytext;
- yylval.sval.length = yyleng;
- return DOLLAR_VARIABLE;
- }
- /* CATCH-ALL ERROR CASE */
- . { error (_("Invalid character '%s' in expression."), yytext); }
- %%
- #include <ctype.h>
- /* Initialize the lexer for processing new expression. */
- static void
- lexer_init (FILE *inp)
- {
- BEGIN INITIAL;
- paren_depth = 0;
- returned_complete = false;
- yyrestart (inp);
- }
- /* Copy S2 to S1, removing all underscores, and downcasing all letters. */
- static void
- canonicalizeNumeral (char *s1, const char *s2)
- {
- for (; *s2 != '\000'; s2 += 1)
- {
- if (*s2 != '_')
- {
- *s1 = tolower(*s2);
- s1 += 1;
- }
- }
- s1[0] = '\000';
- }
- /* Interprets the prefix of NUM that consists of digits of the given BASE
- as an integer of that BASE, with the string EXP as an exponent.
- Puts value in yylval, and returns INT, if the string is valid. Causes
- an error if the number is improperly formated. BASE, if NULL, defaults
- to "10", and EXP to "1". The EXP does not contain a leading 'e' or 'E'.
- */
- static int
- processInt (struct parser_state *par_state, const char *base0,
- const char *num0, const char *exp0)
- {
- long exp;
- int base;
- /* For the based literal with an "f" prefix, we'll return a
- floating-point number. This counts the the number of "l"s seen,
- to decide the width of the floating-point number to return. -1
- means no "f". */
- int floating_point_l_count = -1;
- if (base0 == NULL)
- base = 10;
- else
- {
- char *end_of_base;
- base = strtol (base0, &end_of_base, 10);
- if (base < 2 || base > 16)
- error (_("Invalid base: %d."), base);
- while (*end_of_base == 'l')
- {
- ++floating_point_l_count;
- ++end_of_base;
- }
- /* This assertion is ensured by the pattern. */
- gdb_assert (floating_point_l_count == -1 || *end_of_base == 'f');
- if (*end_of_base == 'f')
- {
- ++end_of_base;
- ++floating_point_l_count;
- }
- /* This assertion is ensured by the pattern. */
- gdb_assert (*end_of_base == '#');
- }
- if (exp0 == NULL)
- exp = 0;
- else
- exp = strtol(exp0, (char **) NULL, 10);
- gdb_mpz result;
- while (isxdigit (*num0))
- {
- int dig = fromhex (*num0);
- if (dig >= base)
- error (_("Invalid digit `%c' in based literal"), *num0);
- mpz_mul_ui (result.val, result.val, base);
- mpz_add_ui (result.val, result.val, dig);
- ++num0;
- }
- while (exp > 0)
- {
- mpz_mul_ui (result.val, result.val, base);
- exp -= 1;
- }
- if (floating_point_l_count > -1)
- {
- struct type *fp_type;
- if (floating_point_l_count == 0)
- fp_type = language_lookup_primitive_type (par_state->language (),
- par_state->gdbarch (),
- "float");
- else if (floating_point_l_count == 1)
- fp_type = language_lookup_primitive_type (par_state->language (),
- par_state->gdbarch (),
- "long_float");
- else
- {
- /* This assertion is ensured by the pattern. */
- gdb_assert (floating_point_l_count == 2);
- fp_type = language_lookup_primitive_type (par_state->language (),
- par_state->gdbarch (),
- "long_long_float");
- }
- yylval.typed_val_float.type = fp_type;
- result.write (gdb::make_array_view (yylval.typed_val_float.val,
- TYPE_LENGTH (fp_type)),
- type_byte_order (fp_type),
- true);
- return FLOAT;
- }
- gdb_mpz maxval (ULONGEST_MAX / base);
- if (mpz_cmp (result.val, maxval.val) > 0)
- error (_("Integer literal out of range"));
- LONGEST value = result.as_integer<LONGEST> ();
- if ((value >> (gdbarch_int_bit (par_state->gdbarch ())-1)) == 0)
- yylval.typed_val.type = type_int (par_state);
- else if ((value >> (gdbarch_long_bit (par_state->gdbarch ())-1)) == 0)
- yylval.typed_val.type = type_long (par_state);
- else if (((value >> (gdbarch_long_bit (par_state->gdbarch ())-1)) >> 1) == 0)
- {
- /* We have a number representable as an unsigned integer quantity.
- For consistency with the C treatment, we will treat it as an
- anonymous modular (unsigned) quantity. Alas, the types are such
- that we need to store .val as a signed quantity. Sorry
- for the mess, but C doesn't officially guarantee that a simple
- assignment does the trick (no, it doesn't; read the reference manual).
- */
- yylval.typed_val.type
- = builtin_type (par_state->gdbarch ())->builtin_unsigned_long;
- if (value & LONGEST_SIGN)
- yylval.typed_val.val =
- (LONGEST) (value & ~LONGEST_SIGN)
- - (LONGEST_SIGN>>1) - (LONGEST_SIGN>>1);
- else
- yylval.typed_val.val = (LONGEST) value;
- return INT;
- }
- else
- yylval.typed_val.type = type_long_long (par_state);
- yylval.typed_val.val = value;
- return INT;
- }
- static int
- processReal (struct parser_state *par_state, const char *num0)
- {
- yylval.typed_val_float.type = type_long_double (par_state);
- bool parsed = parse_float (num0, strlen (num0),
- yylval.typed_val_float.type,
- yylval.typed_val_float.val);
- gdb_assert (parsed);
- return FLOAT;
- }
- /* Store a canonicalized version of NAME0[0..LEN-1] in yylval.ssym. The
- resulting string is valid until the next call to ada_parse. If
- NAME0 contains the substring "___", it is assumed to be already
- encoded and the resulting name is equal to it. Similarly, if the name
- starts with '<', it is copied verbatim. Otherwise, it differs
- from NAME0 in that:
- + Characters between '...' are transfered verbatim to yylval.ssym.
- + Trailing "'" characters in quoted sequences are removed (a leading quote is
- preserved to indicate that the name is not to be GNAT-encoded).
- + Unquoted whitespace is removed.
- + Unquoted alphabetic characters are mapped to lower case.
- Result is returned as a struct stoken, but for convenience, the string
- is also null-terminated. Result string valid until the next call of
- ada_parse.
- */
- static struct stoken
- processId (const char *name0, int len)
- {
- char *name = (char *) obstack_alloc (&temp_parse_space, len + 11);
- int i0, i;
- struct stoken result;
- result.ptr = name;
- while (len > 0 && isspace (name0[len-1]))
- len -= 1;
- if (name0[0] == '<' || strstr (name0, "___") != NULL)
- {
- strncpy (name, name0, len);
- name[len] = '\000';
- result.length = len;
- return result;
- }
- bool in_quotes = false;
- i = i0 = 0;
- while (i0 < len)
- {
- if (name0[i0] == COMPLETE_CHAR)
- {
- /* Just ignore. */
- ++i0;
- }
- else if (in_quotes)
- name[i++] = name0[i0++];
- else if (isalnum (name0[i0]))
- {
- name[i] = tolower (name0[i0]);
- i += 1; i0 += 1;
- }
- else if (isspace (name0[i0]))
- i0 += 1;
- else if (name0[i0] == '\'')
- {
- /* Copy the starting quote, but not the ending quote. */
- if (!in_quotes)
- name[i++] = name0[i0++];
- in_quotes = !in_quotes;
- }
- else
- name[i++] = name0[i0++];
- }
- name[i] = '\000';
- result.length = i;
- return result;
- }
- /* Return TEXT[0..LEN-1], a string literal without surrounding quotes,
- with special hex character notations replaced with characters.
- Result valid until the next call to ada_parse. */
- static struct stoken
- processString (const char *text, int len)
- {
- const char *p;
- char *q;
- const char *lim = text + len;
- struct stoken result;
- q = (char *) obstack_alloc (&temp_parse_space, len);
- result.ptr = q;
- p = text;
- while (p < lim)
- {
- if (p[0] == '[' && p[1] == '"' && p+2 < lim)
- {
- if (p[2] == '"') /* "...["""]... */
- {
- *q = '"';
- p += 4;
- }
- else
- {
- const char *end;
- ULONGEST chr = strtoulst (p + 2, &end, 16);
- if (chr > 0xff)
- error (_("wide strings are not yet supported"));
- *q = (char) chr;
- p = end + 1;
- }
- }
- else
- *q = *p;
- q += 1;
- p += 1;
- }
- result.length = q - result.ptr;
- return result;
- }
- /* Returns the position within STR of the '.' in a
- '.{WHITE}*all' component of a dotted name, or -1 if there is none.
- Note: we actually don't need this routine, since 'all' can never be an
- Ada identifier. Thus, looking up foo.all or foo.all.x as a name
- must fail, and will eventually be interpreted as (foo).all or
- (foo).all.x. However, this does avoid an extraneous lookup. */
- static int
- find_dot_all (const char *str)
- {
- int i;
- for (i = 0; str[i] != '\000'; i++)
- if (str[i] == '.')
- {
- int i0 = i;
- do
- i += 1;
- while (isspace (str[i]));
- if (strncasecmp (str + i, "all", 3) == 0
- && !isalnum (str[i + 3]) && str[i + 3] != '_')
- return i0;
- }
- return -1;
- }
- /* Returns non-zero iff string SUBSEQ matches a subsequence of STR, ignoring
- case. */
- static int
- subseqMatch (const char *subseq, const char *str)
- {
- if (subseq[0] == '\0')
- return 1;
- else if (str[0] == '\0')
- return 0;
- else if (tolower (subseq[0]) == tolower (str[0]))
- return subseqMatch (subseq+1, str+1) || subseqMatch (subseq, str+1);
- else
- return subseqMatch (subseq, str+1);
- }
- static struct { const char *name; int code; }
- attributes[] = {
- { "address", TICK_ADDRESS },
- { "unchecked_access", TICK_ACCESS },
- { "unrestricted_access", TICK_ACCESS },
- { "access", TICK_ACCESS },
- { "first", TICK_FIRST },
- { "last", TICK_LAST },
- { "length", TICK_LENGTH },
- { "max", TICK_MAX },
- { "min", TICK_MIN },
- { "modulus", TICK_MODULUS },
- { "pos", TICK_POS },
- { "range", TICK_RANGE },
- { "size", TICK_SIZE },
- { "tag", TICK_TAG },
- { "val", TICK_VAL },
- };
- /* Return the syntactic code corresponding to the attribute name or
- abbreviation STR. */
- static int
- processAttribute (const char *str)
- {
- gdb_assert (*str == '\'');
- ++str;
- while (isspace (*str))
- ++str;
- int len = strlen (str);
- if (len > 0 && str[len - 1] == COMPLETE_CHAR)
- {
- /* This is enforced by YY_INPUT. */
- gdb_assert (pstate->parse_completion);
- yylval.sval.ptr = obstack_strndup (&temp_parse_space, str, len - 1);
- yylval.sval.length = len - 1;
- return TICK_COMPLETE;
- }
- for (const auto &item : attributes)
- if (strcasecmp (str, item.name) == 0)
- return item.code;
- gdb::optional<int> found;
- for (const auto &item : attributes)
- if (subseqMatch (str, item.name))
- {
- if (!found.has_value ())
- found = item.code;
- else
- error (_("ambiguous attribute name: `%s'"), str);
- }
- if (!found.has_value ())
- error (_("unrecognized attribute: `%s'"), str);
- return *found;
- }
- bool
- ada_tick_completer::complete (struct expression *exp,
- completion_tracker &tracker)
- {
- completion_list output;
- for (const auto &item : attributes)
- {
- if (strncasecmp (item.name, m_name.c_str (), m_name.length ()) == 0)
- output.emplace_back (xstrdup (item.name));
- }
- tracker.add_completions (std::move (output));
- return true;
- }
- /* Back up lexptr by yyleng and then to the rightmost occurrence of
- character CH, case-folded (there must be one). WARNING: since
- lexptr points to the next input character that Flex has not yet
- transferred to its internal buffer, the use of this function
- depends on the assumption that Flex calls YY_INPUT only when it is
- logically necessary to do so (thus, there is no reading ahead
- farther than needed to identify the next token.) */
- static void
- rewind_to_char (int ch)
- {
- pstate->lexptr -= yyleng;
- while (toupper (*pstate->lexptr) != toupper (ch))
- pstate->lexptr -= 1;
- yyrestart (NULL);
- }
- /* Dummy definition to suppress warnings about unused static definitions. */
- typedef void (*dummy_function) ();
- dummy_function ada_flex_use[] =
- {
- (dummy_function) yyunput
- };
- DIAGNOSTIC_POP
|