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