diff options
-rw-r--r-- | gdb/ada-exp.tab.c | 2389 | ||||
-rw-r--r-- | gdb/ada-exp.y | 962 | ||||
-rw-r--r-- | gdb/ada-lang.c | 8626 | ||||
-rw-r--r-- | gdb/ada-lang.h | 365 | ||||
-rw-r--r-- | gdb/ada-lex.c | 3174 | ||||
-rw-r--r-- | gdb/ada-lex.l | 928 | ||||
-rw-r--r-- | gdb/ada-tasks.c | 806 | ||||
-rw-r--r-- | gdb/ada-typeprint.c | 896 | ||||
-rw-r--r-- | gdb/ada-valprint.c | 1058 |
9 files changed, 19204 insertions, 0 deletions
diff --git a/gdb/ada-exp.tab.c b/gdb/ada-exp.tab.c new file mode 100644 index 0000000..bb6d29b --- /dev/null +++ b/gdb/ada-exp.tab.c @@ -0,0 +1,2389 @@ +/* A Bison parser, made from ./ada-exp.y + by GNU bison 1.35. */ + +#define YYBISON 1 /* Identify Bison output. */ + +# define INT 257 +# define NULL_PTR 258 +# define CHARLIT 259 +# define FLOAT 260 +# define TYPENAME 261 +# define BLOCKNAME 262 +# define STRING 263 +# define NAME 264 +# define DOT_ID 265 +# define OBJECT_RENAMING 266 +# define DOT_ALL 267 +# define LAST 268 +# define REGNAME 269 +# define INTERNAL_VARIABLE 270 +# define ASSIGN 271 +# define _AND_ 272 +# define OR 273 +# define XOR 274 +# define THEN 275 +# define ELSE 276 +# define NOTEQUAL 277 +# define LEQ 278 +# define GEQ 279 +# define IN 280 +# define DOTDOT 281 +# define UNARY 282 +# define MOD 283 +# define REM 284 +# define STARSTAR 285 +# define ABS 286 +# define NOT 287 +# define TICK_ACCESS 288 +# define TICK_ADDRESS 289 +# define TICK_FIRST 290 +# define TICK_LAST 291 +# define TICK_LENGTH 292 +# define TICK_MAX 293 +# define TICK_MIN 294 +# define TICK_MODULUS 295 +# define TICK_POS 296 +# define TICK_RANGE 297 +# define TICK_SIZE 298 +# define TICK_TAG 299 +# define TICK_VAL 300 +# define ARROW 301 +# define NEW 302 + +#line 38 "./ada-exp.y" + + +#include "defs.h" +#include <string.h> +#include <ctype.h> +#include "expression.h" +#include "value.h" +#include "parser-defs.h" +#include "language.h" +#include "ada-lang.h" +#include "bfd.h" /* Required by objfiles.h. */ +#include "symfile.h" /* Required by objfiles.h. */ +#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */ +#include "frame.h" + +/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), + as well as gratuitiously global symbol names, so we can have multiple + yacc generated parsers in gdb. These are only the variables + produced by yacc. If other parser generators (bison, byacc, etc) produce + additional global names that conflict at link time, then those parser + generators need to be fixed instead of adding those names to this list. */ + +/* NOTE: This is clumsy, especially since BISON and FLEX provide --prefix + options. I presume we are maintaining it to accommodate systems + without BISON? (PNH) */ + +#define yymaxdepth ada_maxdepth +#define yyparse _ada_parse /* ada_parse calls this after initialization */ +#define yylex ada_lex +#define yyerror ada_error +#define yylval ada_lval +#define yychar ada_char +#define yydebug ada_debug +#define yypact ada_pact +#define yyr1 ada_r1 +#define yyr2 ada_r2 +#define yydef ada_def +#define yychk ada_chk +#define yypgo ada_pgo +#define yyact ada_act +#define yyexca ada_exca +#define yyerrflag ada_errflag +#define yynerrs ada_nerrs +#define yyps ada_ps +#define yypv ada_pv +#define yys ada_s +#define yy_yys ada_yys +#define yystate ada_state +#define yytmp ada_tmp +#define yyv ada_v +#define yy_yyv ada_yyv +#define yyval ada_val +#define yylloc ada_lloc +#define yyreds ada_reds /* With YYDEBUG defined */ +#define yytoks ada_toks /* With YYDEBUG defined */ + +#ifndef YYDEBUG +#define YYDEBUG 0 /* Default to no yydebug support */ +#endif + +struct name_info { + struct symbol* sym; + struct minimal_symbol* msym; + struct block* block; + struct stoken stoken; +}; + +/* If expression is in the context of TYPE'(...), then TYPE, else + * NULL. */ +static struct type* type_qualifier; + +int yyparse (void); + +static int yylex (void); + +void yyerror (char *); + +static struct stoken string_to_operator (struct stoken); + +static void write_attribute_call0 (enum ada_attribute); + +static void write_attribute_call1 (enum ada_attribute, LONGEST); + +static void write_attribute_calln (enum ada_attribute, int); + +static void write_object_renaming (struct block*, struct symbol*); + +static void write_var_from_name (struct block*, struct name_info); + +static LONGEST +convert_char_literal (struct type*, LONGEST); + +#line 131 "./ada-exp.y" +#ifndef YYSTYPE +typedef union + { + LONGEST lval; + struct { + LONGEST val; + struct type *type; + } typed_val; + struct { + DOUBLEST dval; + struct type *type; + } typed_val_float; + struct type *tval; + struct stoken sval; + struct name_info ssym; + int voidval; + struct block *bval; + struct internalvar *ivar; + + } yystype; +# define YYSTYPE yystype +# define YYSTYPE_IS_TRIVIAL 1 +#endif +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + + + +#define YYFINAL 184 +#define YYFLAG -32768 +#define YYNTBASE 68 + +/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ +#define YYTRANSLATE(x) ((unsigned)(x) <= 302 ? yytranslate[x] : 82) + +/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ +static const char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 34, 63, + 57, 62, 36, 32, 64, 33, 56, 37, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, + 25, 23, 26, 2, 31, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 58, 2, 67, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 65, 2, 66, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 24, 27, 28, + 29, 30, 35, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 59, 60 +}; + +#if YYDEBUG +static const short yyprhs[] = +{ + 0, 0, 2, 4, 6, 10, 13, 16, 21, 26, + 27, 35, 36, 43, 47, 49, 51, 53, 55, 57, + 61, 64, 67, 70, 73, 74, 76, 80, 84, 90, + 95, 99, 103, 107, 111, 115, 119, 123, 127, 131, + 135, 139, 143, 149, 155, 159, 166, 173, 178, 182, + 186, 190, 194, 199, 203, 208, 212, 215, 218, 222, + 226, 230, 233, 236, 244, 252, 258, 262, 266, 270, + 276, 279, 280, 284, 286, 288, 289, 291, 293, 295, + 297, 299, 302, 304, 307, 309, 312, 314, 316, 318, + 320, 323, 325, 328, 331, 335, 338, 341 +}; +static const short yyrhs[] = +{ + 69, 0, 81, 0, 73, 0, 69, 61, 73, 0, + 70, 13, 0, 70, 11, 0, 70, 57, 74, 62, + 0, 81, 57, 73, 62, 0, 0, 81, 63, 72, + 71, 57, 73, 62, 0, 0, 70, 57, 73, 30, + 73, 62, 0, 57, 69, 62, 0, 78, 0, 15, + 0, 16, 0, 70, 0, 14, 0, 73, 17, 73, + 0, 33, 73, 0, 32, 73, 0, 42, 73, 0, + 41, 73, 0, 0, 73, 0, 79, 59, 73, 0, + 74, 64, 73, 0, 74, 64, 79, 59, 73, 0, + 65, 81, 66, 73, 0, 73, 40, 73, 0, 73, + 36, 73, 0, 73, 37, 73, 0, 73, 39, 73, + 0, 73, 38, 73, 0, 73, 31, 73, 0, 73, + 32, 73, 0, 73, 34, 73, 0, 73, 33, 73, + 0, 73, 23, 73, 0, 73, 24, 73, 0, 73, + 27, 73, 0, 73, 29, 73, 30, 73, 0, 73, + 29, 73, 52, 75, 0, 73, 29, 7, 0, 73, + 42, 29, 73, 30, 73, 0, 73, 42, 29, 73, + 52, 75, 0, 73, 42, 29, 7, 0, 73, 28, + 73, 0, 73, 25, 73, 0, 73, 26, 73, 0, + 73, 18, 73, 0, 73, 18, 21, 73, 0, 73, + 19, 73, 0, 73, 19, 22, 73, 0, 73, 20, + 73, 0, 70, 43, 0, 70, 44, 0, 70, 45, + 75, 0, 70, 46, 75, 0, 70, 47, 75, 0, + 70, 53, 0, 70, 54, 0, 77, 49, 57, 73, + 64, 73, 62, 0, 77, 48, 57, 73, 64, 73, + 62, 0, 77, 51, 57, 73, 62, 0, 76, 45, + 75, 0, 76, 46, 75, 0, 76, 47, 75, 0, + 76, 55, 57, 73, 62, 0, 76, 50, 0, 0, + 57, 3, 62, 0, 7, 0, 76, 0, 0, 3, + 0, 5, 0, 6, 0, 4, 0, 9, 0, 60, + 7, 0, 10, 0, 80, 10, 0, 12, 0, 80, + 12, 0, 10, 0, 7, 0, 12, 0, 8, 0, + 80, 8, 0, 7, 0, 80, 7, 0, 7, 43, + 0, 80, 7, 43, 0, 36, 73, 0, 34, 73, + 0, 73, 58, 73, 67, 0 +}; + +#endif + +#if YYDEBUG +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const short yyrline[] = +{ + 0, 203, 204, 210, 211, 216, 220, 227, 235, 243, + 243, 254, 256, 261, 264, 267, 274, 282, 285, 292, + 296, 300, 304, 308, 312, 315, 317, 319, 321, 325, + 335, 339, 343, 347, 351, 355, 359, 363, 367, 371, + 375, 379, 383, 387, 393, 400, 405, 413, 423, 427, + 431, 435, 439, 443, 447, 451, 455, 457, 463, 465, + 467, 469, 471, 473, 475, 477, 479, 481, 483, 485, + 487, 491, 493, 497, 504, 506, 513, 521, 533, 541, + 548, 575, 579, 580, 582, 583, 587, 588, 589, 592, + 594, 599, 600, 601, 603, 610, 612, 614 +}; +#endif + + +#if (YYDEBUG) || defined YYERROR_VERBOSE + +/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ +static const char *const yytname[] = +{ + "$", "error", "$undefined.", "INT", "NULL_PTR", "CHARLIT", "FLOAT", + "TYPENAME", "BLOCKNAME", "STRING", "NAME", "DOT_ID", "OBJECT_RENAMING", + "DOT_ALL", "LAST", "REGNAME", "INTERNAL_VARIABLE", "ASSIGN", "_AND_", + "OR", "XOR", "THEN", "ELSE", "'='", "NOTEQUAL", "'<'", "'>'", "LEQ", + "GEQ", "IN", "DOTDOT", "'@'", "'+'", "'-'", "'&'", "UNARY", "'*'", + "'/'", "MOD", "REM", "STARSTAR", "ABS", "NOT", "TICK_ACCESS", + "TICK_ADDRESS", "TICK_FIRST", "TICK_LAST", "TICK_LENGTH", "TICK_MAX", + "TICK_MIN", "TICK_MODULUS", "TICK_POS", "TICK_RANGE", "TICK_SIZE", + "TICK_TAG", "TICK_VAL", "'.'", "'('", "'['", "ARROW", "NEW", "';'", + "')'", "'\\''", "','", "'{'", "'}'", "']'", "start", "exp1", + "simple_exp", "@1", "save_qualifier", "exp", "arglist", "tick_arglist", + "type_prefix", "opt_type_prefix", "variable", "any_name", "block", + "type", 0 +}; +#endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const short yyr1[] = +{ + 0, 68, 68, 69, 69, 70, 70, 70, 70, 71, + 70, 72, 70, 70, 70, 70, 70, 73, 70, 73, + 73, 73, 73, 73, 74, 74, 74, 74, 74, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 75, 75, 76, 77, 77, 73, 73, 73, 73, + 73, 73, 78, 78, 78, 78, 79, 79, 79, 80, + 80, 81, 81, 81, 81, 73, 73, 73 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const short yyr2[] = +{ + 0, 1, 1, 1, 3, 2, 2, 4, 4, 0, + 7, 0, 6, 3, 1, 1, 1, 1, 1, 3, + 2, 2, 2, 2, 0, 1, 3, 3, 5, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 5, 5, 3, 6, 6, 4, 3, 3, + 3, 3, 4, 3, 4, 3, 2, 2, 3, 3, + 3, 2, 2, 7, 7, 5, 3, 3, 3, 5, + 2, 0, 3, 1, 1, 0, 1, 1, 1, 1, + 1, 2, 1, 2, 1, 2, 1, 1, 1, 1, + 2, 1, 2, 2, 3, 2, 2, 4 +}; + +/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE + doesn't specify something else to do. Zero means the default is an + error. */ +static const short yydefact[] = +{ + 75, 76, 79, 77, 78, 73, 89, 80, 82, 84, + 18, 15, 16, 75, 75, 75, 75, 75, 75, 75, + 0, 0, 1, 17, 3, 74, 0, 14, 0, 2, + 93, 21, 0, 20, 96, 95, 23, 22, 0, 81, + 91, 0, 0, 75, 6, 5, 56, 57, 71, 71, + 71, 61, 62, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 0, 75, 71, 71, 71, 70, + 0, 0, 0, 0, 92, 90, 83, 85, 75, 11, + 13, 75, 4, 0, 58, 59, 60, 73, 82, 84, + 25, 0, 0, 19, 75, 51, 75, 53, 55, 39, + 40, 49, 50, 41, 48, 44, 0, 35, 36, 38, + 37, 31, 32, 34, 33, 30, 75, 0, 66, 67, + 68, 75, 75, 75, 75, 94, 0, 9, 29, 0, + 75, 7, 75, 75, 52, 54, 75, 71, 47, 0, + 97, 0, 0, 0, 0, 8, 0, 72, 0, 27, + 0, 26, 42, 43, 75, 71, 69, 75, 75, 65, + 75, 12, 75, 45, 46, 0, 0, 0, 28, 64, + 63, 10, 0, 0, 0 +}; + +static const short yydefgoto[] = +{ + 182, 22, 23, 156, 137, 24, 101, 94, 25, 26, + 27, 102, 28, 32 +}; + +static const short yypact[] = +{ + 251,-32768,-32768,-32768,-32768, 20,-32768,-32768,-32768,-32768, + -32768,-32768,-32768, 251, 251, 251, 251, 251, 251, 251, + 2, 79, -47, 53, 958, -23, 54,-32768, 104, -32, + -32768, 31, -32, 31, -22, -22, 31, 31, 33,-32768, + -5, 101, -27, 251,-32768,-32768,-32768,-32768, 4, 4, + 4,-32768,-32768, 131, 251, 171, 211, 251, 251, 251, + 251, 251, 251, 251, 291, 251, 251, 251, 251, 251, + 251, 251, 251, 251, 47, 251, 4, 4, 4,-32768, + 23, 25, 27, 35, 45,-32768,-32768,-32768, 251,-32768, + -32768, 251, 958, 98,-32768,-32768,-32768, 22, 56, 58, + 930, -36, 64, 986, 251, 1009, 251, 1009, 1009, -21, + -21, -21, -21, -21, -21, 534, 858, 387, 31, 31, + 31, 32, 32, 32, 32, 32, 331, 415,-32768,-32768, + -32768, 251, 251, 251, 251,-32768, 536,-32768, -22, 62, + 251,-32768, 371, 251, 1009, 1009, 251, 4, 534, 894, + -32768, 582, 452, 494, 628,-32768, 68,-32768, 674, 958, + 67, 958, -21,-32768, 251, 4,-32768, 251, 251,-32768, + 251,-32768, 251, -21,-32768, 720, 766, 812, 958,-32768, + -32768,-32768, 128, 132,-32768 +}; + +static const short yypgoto[] = +{ + -32768, 112,-32768,-32768,-32768, -13,-32768, -43,-32768,-32768, + -32768, 0, 123, 8 +}; + + +#define YYLAST 1067 + + +static const short yytable[] = +{ + 31, 33, 34, 35, 36, 37, 95, 96, 29, 39, + 65, 66, 67, 68, 43, 69, 70, 71, 72, 73, + -91, 74, 76, 77, 78, 88, 141, 79, 142, 42, + 92, 89, 80, 128, 129, 130, 75, 75, 30, 91, + 100, 103, 105, 107, 108, 109, 110, 111, 112, 113, + 114, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 93, 127, 30, 44, 30, 45, 69, 70, 71, + 72, 73, 73, 74, 74, 136, 126, -91, 138, -91, + 131, -87, 132, -91, 133, -91, 40, 6, 135, 75, + 75, 144, 134, 145, 43, 90, 46, 47, 48, 49, + 50, 139, 81, 82, 163, 83, 51, 52, 84, 85, + 53, 84, 85, 149, 86, -86, 87, -88, 151, 152, + 153, 154, 174, 143, 157, 170, 172, 158, 183, 159, + 161, 38, 184, 162, 1, 2, 3, 4, 97, 6, + 7, 98, 160, 99, 41, 10, 11, 12, 0, 0, + 0, 173, 0, 0, 175, 176, 0, 177, 0, 178, + 0, 0, 0, 13, 14, 15, 0, 16, 0, 0, + 0, 0, 17, 18, 1, 2, 3, 4, 5, 6, + 7, 8, 0, 9, 0, 10, 11, 12, 19, 0, + 0, 20, 104, -24, 0, -24, 21, 0, 0, 0, + 0, 0, 0, 13, 14, 15, 0, 16, 0, 0, + 0, 0, 17, 18, 1, 2, 3, 4, 5, 6, + 7, 8, 0, 9, 0, 10, 11, 12, 19, 0, + 0, 20, 0, 106, 0, 0, 21, 0, 0, 0, + 0, 0, 0, 13, 14, 15, 0, 16, 0, 0, + 0, 0, 17, 18, 1, 2, 3, 4, 5, 6, + 7, 8, 0, 9, 0, 10, 11, 12, 19, 0, + 0, 20, 0, 0, 0, 0, 21, 0, 0, 0, + 0, 0, 0, 13, 14, 15, 0, 16, 0, 0, + 0, 0, 17, 18, 1, 2, 3, 4, 115, 6, + 7, 8, 0, 9, 0, 10, 11, 12, 19, 0, + 0, 20, 0, 0, 0, 0, 21, 0, 0, 0, + 0, 0, 0, 13, 14, 15, 0, 16, 0, 0, + 0, 0, 17, 18, 1, 2, 3, 4, 148, 6, + 7, 8, 0, 9, 0, 10, 11, 12, 19, 0, + 0, 20, 0, 0, 0, 0, 21, 0, 0, 0, + 0, 0, 0, 13, 14, 15, 0, 16, 0, 0, + 0, 0, 17, 18, 1, 2, 3, 4, 97, 6, + 7, 98, 0, 99, 0, 10, 11, 12, 19, 0, + 0, 20, 0, 0, 0, 0, 21, 0, 0, 0, + 0, 0, 0, 13, 14, 15, 0, 16, 0, 0, + 0, 0, 17, 18, 0, 0, 0, 0, 0, 66, + 67, 68, 0, 69, 70, 71, 72, 73, 19, 74, + 0, 20, 54, 55, 56, 57, 21, 0, 58, 59, + 60, 61, 62, 63, 64, 75, 65, 66, 67, 68, + 0, 69, 70, 71, 72, 73, 0, 74, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, + 55, 56, 57, 75, 0, 58, 59, 60, 61, 62, + 63, 64, 150, 65, 66, 67, 68, 0, 69, 70, + 71, 72, 73, 0, 74, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 75, 54, 55, 56, 57, 0, 167, 58, 59, 60, + 61, 62, 63, 64, 0, 65, 66, 67, 68, 0, + 69, 70, 71, 72, 73, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 75, 54, 55, 56, 57, 0, 168, 58, + 59, 60, 61, 62, 63, 64, 0, 65, 66, 67, + 68, 0, 69, 70, 71, 72, 73, 30, 74, -73, + -73, -73, -73, -73, -73, -73, 0, 0, 0, -73, + 0, -91, 0, 0, 75, 0, 0, -91, 155, 54, + 55, 56, 57, 0, 0, 58, 59, 60, 61, 62, + 63, 64, 0, 65, 66, 67, 68, 0, 69, 70, + 71, 72, 73, 0, 74, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 75, 0, 0, 0, 166, 54, 55, 56, 57, 0, + 0, 58, 59, 60, 61, 62, 63, 64, 0, 65, + 66, 67, 68, 0, 69, 70, 71, 72, 73, 0, + 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, + 169, 54, 55, 56, 57, 0, 0, 58, 59, 60, + 61, 62, 63, 64, 0, 65, 66, 67, 68, 0, + 69, 70, 71, 72, 73, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 75, 0, 0, 0, 171, 54, 55, 56, + 57, 0, 0, 58, 59, 60, 61, 62, 63, 64, + 0, 65, 66, 67, 68, 0, 69, 70, 71, 72, + 73, 0, 74, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 75, 0, + 0, 0, 179, 54, 55, 56, 57, 0, 0, 58, + 59, 60, 61, 62, 63, 64, 0, 65, 66, 67, + 68, 0, 69, 70, 71, 72, 73, 0, 74, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 75, 0, 0, 0, 180, 54, + 55, 56, 57, 0, 0, 58, 59, 60, 61, 62, + 63, 64, 0, 65, 66, 67, 68, 0, 69, 70, + 71, 72, 73, 0, 74, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 75, 0, 0, 0, 181, 54, 55, 56, 57, 0, + 0, 58, 59, 60, 61, 62, 63, 64, 146, 65, + 66, 67, 68, 0, 69, 70, 71, 72, 73, 0, + 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 147, 54, 55, 56, 57, 0, 75, 58, 59, 60, + 61, 62, 63, 64, 164, 65, 66, 67, 68, 0, + 69, 70, 71, 72, 73, 0, 74, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 165, 54, 55, 56, + 57, 0, 75, 58, 59, 60, 61, 62, 63, 64, + 140, 65, 66, 67, 68, 0, 69, 70, 71, 72, + 73, 0, 74, 0, 0, 54, 55, 56, 57, 0, + 0, 58, 59, 60, 61, 62, 63, 64, 75, 65, + 66, 67, 68, 0, 69, 70, 71, 72, 73, 0, + 74, 0, 0,-32768, 55, 56, 57, 0, 0, 58, + 59, 60, 61, 62, 63, 64, 75, 65, 66, 67, + 68, 0, 69, 70, 71, 72, 73, 0, 74, 0, + 0, 0, 58, 59, 60, 61, 62, 63, 64, 0, + 65, 66, 67, 68, 75, 69, 70, 71, 72, 73, + 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 75 +}; + +static const short yycheck[] = +{ + 13, 14, 15, 16, 17, 18, 49, 50, 0, 7, + 31, 32, 33, 34, 61, 36, 37, 38, 39, 40, + 0, 42, 45, 46, 47, 57, 62, 50, 64, 21, + 43, 63, 55, 76, 77, 78, 58, 58, 43, 66, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 57, 75, 43, 11, 43, 13, 36, 37, 38, + 39, 40, 40, 42, 42, 88, 29, 57, 91, 57, + 57, 59, 57, 63, 57, 63, 7, 8, 43, 58, + 58, 104, 57, 106, 61, 62, 43, 44, 45, 46, + 47, 3, 48, 49, 147, 51, 53, 54, 7, 8, + 57, 7, 8, 126, 10, 59, 12, 59, 131, 132, + 133, 134, 165, 59, 62, 57, 59, 140, 0, 142, + 143, 19, 0, 146, 3, 4, 5, 6, 7, 8, + 9, 10, 142, 12, 21, 14, 15, 16, -1, -1, + -1, 164, -1, -1, 167, 168, -1, 170, -1, 172, + -1, -1, -1, 32, 33, 34, -1, 36, -1, -1, + -1, -1, 41, 42, 3, 4, 5, 6, 7, 8, + 9, 10, -1, 12, -1, 14, 15, 16, 57, -1, + -1, 60, 21, 62, -1, 64, 65, -1, -1, -1, + -1, -1, -1, 32, 33, 34, -1, 36, -1, -1, + -1, -1, 41, 42, 3, 4, 5, 6, 7, 8, + 9, 10, -1, 12, -1, 14, 15, 16, 57, -1, + -1, 60, -1, 22, -1, -1, 65, -1, -1, -1, + -1, -1, -1, 32, 33, 34, -1, 36, -1, -1, + -1, -1, 41, 42, 3, 4, 5, 6, 7, 8, + 9, 10, -1, 12, -1, 14, 15, 16, 57, -1, + -1, 60, -1, -1, -1, -1, 65, -1, -1, -1, + -1, -1, -1, 32, 33, 34, -1, 36, -1, -1, + -1, -1, 41, 42, 3, 4, 5, 6, 7, 8, + 9, 10, -1, 12, -1, 14, 15, 16, 57, -1, + -1, 60, -1, -1, -1, -1, 65, -1, -1, -1, + -1, -1, -1, 32, 33, 34, -1, 36, -1, -1, + -1, -1, 41, 42, 3, 4, 5, 6, 7, 8, + 9, 10, -1, 12, -1, 14, 15, 16, 57, -1, + -1, 60, -1, -1, -1, -1, 65, -1, -1, -1, + -1, -1, -1, 32, 33, 34, -1, 36, -1, -1, + -1, -1, 41, 42, 3, 4, 5, 6, 7, 8, + 9, 10, -1, 12, -1, 14, 15, 16, 57, -1, + -1, 60, -1, -1, -1, -1, 65, -1, -1, -1, + -1, -1, -1, 32, 33, 34, -1, 36, -1, -1, + -1, -1, 41, 42, -1, -1, -1, -1, -1, 32, + 33, 34, -1, 36, 37, 38, 39, 40, 57, 42, + -1, 60, 17, 18, 19, 20, 65, -1, 23, 24, + 25, 26, 27, 28, 29, 58, 31, 32, 33, 34, + -1, 36, 37, 38, 39, 40, -1, 42, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, + 18, 19, 20, 58, -1, 23, 24, 25, 26, 27, + 28, 29, 67, 31, 32, 33, 34, -1, 36, 37, + 38, 39, 40, -1, 42, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 58, 17, 18, 19, 20, -1, 64, 23, 24, 25, + 26, 27, 28, 29, -1, 31, 32, 33, 34, -1, + 36, 37, 38, 39, 40, -1, 42, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 58, 17, 18, 19, 20, -1, 64, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + 34, -1, 36, 37, 38, 39, 40, 43, 42, 45, + 46, 47, 48, 49, 50, 51, -1, -1, -1, 55, + -1, 57, -1, -1, 58, -1, -1, 63, 62, 17, + 18, 19, 20, -1, -1, 23, 24, 25, 26, 27, + 28, 29, -1, 31, 32, 33, 34, -1, 36, 37, + 38, 39, 40, -1, 42, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 58, -1, -1, -1, 62, 17, 18, 19, 20, -1, + -1, 23, 24, 25, 26, 27, 28, 29, -1, 31, + 32, 33, 34, -1, 36, 37, 38, 39, 40, -1, + 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 58, -1, -1, -1, + 62, 17, 18, 19, 20, -1, -1, 23, 24, 25, + 26, 27, 28, 29, -1, 31, 32, 33, 34, -1, + 36, 37, 38, 39, 40, -1, 42, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 58, -1, -1, -1, 62, 17, 18, 19, + 20, -1, -1, 23, 24, 25, 26, 27, 28, 29, + -1, 31, 32, 33, 34, -1, 36, 37, 38, 39, + 40, -1, 42, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 58, -1, + -1, -1, 62, 17, 18, 19, 20, -1, -1, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + 34, -1, 36, 37, 38, 39, 40, -1, 42, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 58, -1, -1, -1, 62, 17, + 18, 19, 20, -1, -1, 23, 24, 25, 26, 27, + 28, 29, -1, 31, 32, 33, 34, -1, 36, 37, + 38, 39, 40, -1, 42, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 58, -1, -1, -1, 62, 17, 18, 19, 20, -1, + -1, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, -1, 36, 37, 38, 39, 40, -1, + 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 52, 17, 18, 19, 20, -1, 58, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, -1, + 36, 37, 38, 39, 40, -1, 42, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 52, 17, 18, 19, + 20, -1, 58, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, -1, 36, 37, 38, 39, + 40, -1, 42, -1, -1, 17, 18, 19, 20, -1, + -1, 23, 24, 25, 26, 27, 28, 29, 58, 31, + 32, 33, 34, -1, 36, 37, 38, 39, 40, -1, + 42, -1, -1, 17, 18, 19, 20, -1, -1, 23, + 24, 25, 26, 27, 28, 29, 58, 31, 32, 33, + 34, -1, 36, 37, 38, 39, 40, -1, 42, -1, + -1, -1, 23, 24, 25, 26, 27, 28, 29, -1, + 31, 32, 33, 34, 58, 36, 37, 38, 39, 40, + -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 58 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/local/share/bison/bison.simple" + +/* Skeleton output parser for bison, + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software + Foundation, Inc. + + 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 2, 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser when + the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) + +/* The parser invokes alloca or xmalloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC xmalloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short yyss; + YYSTYPE yyvs; +# if YYLSP_NEEDED + YYLTYPE yyls; +# endif +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# if YYLSP_NEEDED +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAX) +# else +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAX) +# endif + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up"); \ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). + + When YYLLOC_DEFAULT is run, CURRENT is set the location of the + first token. By default, to implement support for ranges, extend + its range to the last symbol. */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#if YYPURE +# if YYLSP_NEEDED +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval, &yylloc) +# endif +# else /* !YYLSP_NEEDED */ +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval) +# endif +# endif /* !YYLSP_NEEDED */ +#else /* !YYPURE */ +# define YYLEX yylex () +#endif /* !YYPURE */ + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +#endif /* !YYDEBUG */ + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + +#ifdef YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif +#endif + +#line 315 "/usr/local/share/bison/bison.simple" + + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +# define YYPARSE_PARAM_DECL +# else +# define YYPARSE_PARAM_ARG YYPARSE_PARAM +# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +# endif +#else /* !YYPARSE_PARAM */ +# define YYPARSE_PARAM_ARG +# define YYPARSE_PARAM_DECL +#endif /* !YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +# ifdef YYPARSE_PARAM +int yyparse (void *); +# else +int yyparse (void); +# endif +#endif + +/* YY_DECL_VARIABLES -- depending whether we use a pure parser, + variables are global, or local to YYPARSE. */ + +#define YY_DECL_NON_LSP_VARIABLES \ +/* The lookahead symbol. */ \ +int yychar; \ + \ +/* The semantic value of the lookahead symbol. */ \ +YYSTYPE yylval; \ + \ +/* Number of parse errors so far. */ \ +int yynerrs; + +#if YYLSP_NEEDED +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES \ + \ +/* Location data for the lookahead symbol. */ \ +YYLTYPE yylloc; +#else +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES +#endif + + +/* If nonreentrant, generate the variables here. */ + +#if !YYPURE +YY_DECL_VARIABLES +#endif /* !YYPURE */ + +int +yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + /* If reentrant, generate the variables here. */ +#if YYPURE + YY_DECL_VARIABLES +#endif /* !YYPURE */ + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yychar1 = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to xreallocate them elsewhere. */ + + /* The state stack. */ + short yyssa[YYINITDEPTH]; + short *yyss = yyssa; + register short *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + +#if YYLSP_NEEDED + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; +#endif + +#if YYLSP_NEEDED +# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +# define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + YYSIZE_T yystacksize = YYINITDEPTH; + + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; +#if YYLSP_NEEDED + YYLTYPE yyloc; +#endif + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; +#if YYLSP_NEEDED + yylsp = yyls; +#endif + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to xreallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. */ +# if YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + yyls = yyls1; +# else + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); +# endif + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + goto yyoverflowlab; + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + + { + short *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); +# if YYLSP_NEEDED + YYSTACK_RELOCATE (yyls); +# endif +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; +#if YYLSP_NEEDED + yylsp = yyls + yysize - 1; +#endif + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yychar1 = YYTRANSLATE (yychar); + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables + which are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + YYFPRINTF (stderr, "Next token is %d (%s", + yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise + meaning of a token, for further debugging info. */ +# ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +# endif + YYFPRINTF (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %d (%s), ", + yychar, yytname[yychar1])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to the semantic value of + the lookahead token. This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + +#if YYLSP_NEEDED + /* Similarly for the default location. Let the user run additional + commands if for instance locations are ranges. */ + yyloc = yylsp[1-yylen]; + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); +#endif + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables which + are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + int yyi; + + YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) + YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); + YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + switch (yyn) { + +case 2: +#line 204 "./ada-exp.y" +{ write_exp_elt_opcode (OP_TYPE); + write_exp_elt_type (yyvsp[0].tval); + write_exp_elt_opcode (OP_TYPE); } + break; +case 4: +#line 212 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_COMMA); } + break; +case 5: +#line 217 "./ada-exp.y" +{ write_exp_elt_opcode (UNOP_IND); } + break; +case 6: +#line 221 "./ada-exp.y" +{ write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string (yyvsp[0].ssym.stoken); + write_exp_elt_opcode (STRUCTOP_STRUCT); + } + break; +case 7: +#line 228 "./ada-exp.y" +{ + write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst (yyvsp[-1].lval); + write_exp_elt_opcode (OP_FUNCALL); + } + break; +case 8: +#line 236 "./ada-exp.y" +{ + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (yyvsp[-3].tval); + write_exp_elt_opcode (UNOP_CAST); + } + break; +case 9: +#line 243 "./ada-exp.y" +{ type_qualifier = yyvsp[-2].tval; } + break; +case 10: +#line 244 "./ada-exp.y" +{ + /* write_exp_elt_opcode (UNOP_QUAL); */ + /* FIXME: UNOP_QUAL should be defined in expression.h */ + write_exp_elt_type (yyvsp[-6].tval); + /* write_exp_elt_opcode (UNOP_QUAL); */ + /* FIXME: UNOP_QUAL should be defined in expression.h */ + type_qualifier = yyvsp[-4].tval; + } + break; +case 11: +#line 254 "./ada-exp.y" +{ yyval.tval = type_qualifier; } + break; +case 12: +#line 258 "./ada-exp.y" +{ write_exp_elt_opcode (TERNOP_SLICE); } + break; +case 13: +#line 261 "./ada-exp.y" +{ } + break; +case 15: +#line 268 "./ada-exp.y" +{ write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_REGISTER); + } + break; +case 16: +#line 275 "./ada-exp.y" +{ write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern (yyvsp[0].ivar); + write_exp_elt_opcode (OP_INTERNALVAR); + } + break; +case 18: +#line 286 "./ada-exp.y" +{ write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + write_exp_elt_opcode (OP_LAST); + } + break; +case 19: +#line 293 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_ASSIGN); } + break; +case 20: +#line 297 "./ada-exp.y" +{ write_exp_elt_opcode (UNOP_NEG); } + break; +case 21: +#line 301 "./ada-exp.y" +{ write_exp_elt_opcode (UNOP_PLUS); } + break; +case 22: +#line 305 "./ada-exp.y" +{ write_exp_elt_opcode (UNOP_LOGICAL_NOT); } + break; +case 23: +#line 309 "./ada-exp.y" +{ write_exp_elt_opcode (UNOP_ABS); } + break; +case 24: +#line 312 "./ada-exp.y" +{ yyval.lval = 0; } + break; +case 25: +#line 316 "./ada-exp.y" +{ yyval.lval = 1; } + break; +case 26: +#line 318 "./ada-exp.y" +{ yyval.lval = 1; } + break; +case 27: +#line 320 "./ada-exp.y" +{ yyval.lval = yyvsp[-2].lval + 1; } + break; +case 28: +#line 322 "./ada-exp.y" +{ yyval.lval = yyvsp[-4].lval + 1; } + break; +case 29: +#line 327 "./ada-exp.y" +{ write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type (yyvsp[-2].tval); + write_exp_elt_opcode (UNOP_MEMVAL); + } + break; +case 30: +#line 336 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_EXP); } + break; +case 31: +#line 340 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_MUL); } + break; +case 32: +#line 344 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_DIV); } + break; +case 33: +#line 348 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_REM); } + break; +case 34: +#line 352 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_MOD); } + break; +case 35: +#line 356 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_REPEAT); } + break; +case 36: +#line 360 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_ADD); } + break; +case 37: +#line 364 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_CONCAT); } + break; +case 38: +#line 368 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_SUB); } + break; +case 39: +#line 372 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_EQUAL); } + break; +case 40: +#line 376 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_NOTEQUAL); } + break; +case 41: +#line 380 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_LEQ); } + break; +case 42: +#line 384 "./ada-exp.y" +{ /*write_exp_elt_opcode (TERNOP_MBR); */ } + break; +case 43: +#line 388 "./ada-exp.y" +{ /*write_exp_elt_opcode (BINOP_MBR); */ + /* FIXME: BINOP_MBR should be defined in expression.h */ + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + /*write_exp_elt_opcode (BINOP_MBR); */ + } + break; +case 44: +#line 394 "./ada-exp.y" +{ /*write_exp_elt_opcode (UNOP_MBR); */ + /* FIXME: UNOP_QUAL should be defined in expression.h */ + write_exp_elt_type (yyvsp[0].tval); + /* write_exp_elt_opcode (UNOP_MBR); */ + /* FIXME: UNOP_MBR should be defined in expression.h */ + } + break; +case 45: +#line 401 "./ada-exp.y" +{ /*write_exp_elt_opcode (TERNOP_MBR); */ + /* FIXME: TERNOP_MBR should be defined in expression.h */ + write_exp_elt_opcode (UNOP_LOGICAL_NOT); + } + break; +case 46: +#line 406 "./ada-exp.y" +{ /* write_exp_elt_opcode (BINOP_MBR); */ + /* FIXME: BINOP_MBR should be defined in expression.h */ + write_exp_elt_longcst ((LONGEST) yyvsp[0].lval); + /*write_exp_elt_opcode (BINOP_MBR);*/ + /* FIXME: BINOP_MBR should be defined in expression.h */ + write_exp_elt_opcode (UNOP_LOGICAL_NOT); + } + break; +case 47: +#line 414 "./ada-exp.y" +{ /*write_exp_elt_opcode (UNOP_MBR);*/ + /* FIXME: UNOP_MBR should be defined in expression.h */ + write_exp_elt_type (yyvsp[0].tval); + /* write_exp_elt_opcode (UNOP_MBR);*/ + /* FIXME: UNOP_MBR should be defined in expression.h */ + write_exp_elt_opcode (UNOP_LOGICAL_NOT); + } + break; +case 48: +#line 424 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_GEQ); } + break; +case 49: +#line 428 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_LESS); } + break; +case 50: +#line 432 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_GTR); } + break; +case 51: +#line 436 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_BITWISE_AND); } + break; +case 52: +#line 440 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_LOGICAL_AND); } + break; +case 53: +#line 444 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_BITWISE_IOR); } + break; +case 54: +#line 448 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_LOGICAL_OR); } + break; +case 55: +#line 452 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_BITWISE_XOR); } + break; +case 56: +#line 456 "./ada-exp.y" +{ write_exp_elt_opcode (UNOP_ADDR); } + break; +case 57: +#line 458 "./ada-exp.y" +{ write_exp_elt_opcode (UNOP_ADDR); + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (builtin_type_ada_system_address); + write_exp_elt_opcode (UNOP_CAST); + } + break; +case 58: +#line 464 "./ada-exp.y" +{ write_attribute_call1 (ATR_FIRST, yyvsp[0].lval); } + break; +case 59: +#line 466 "./ada-exp.y" +{ write_attribute_call1 (ATR_LAST, yyvsp[0].lval); } + break; +case 60: +#line 468 "./ada-exp.y" +{ write_attribute_call1 (ATR_LENGTH, yyvsp[0].lval); } + break; +case 61: +#line 470 "./ada-exp.y" +{ write_attribute_call0 (ATR_SIZE); } + break; +case 62: +#line 472 "./ada-exp.y" +{ write_attribute_call0 (ATR_TAG); } + break; +case 63: +#line 474 "./ada-exp.y" +{ write_attribute_calln (ATR_MIN, 2); } + break; +case 64: +#line 476 "./ada-exp.y" +{ write_attribute_calln (ATR_MAX, 2); } + break; +case 65: +#line 478 "./ada-exp.y" +{ write_attribute_calln (ATR_POS, 1); } + break; +case 66: +#line 480 "./ada-exp.y" +{ write_attribute_call1 (ATR_FIRST, yyvsp[0].lval); } + break; +case 67: +#line 482 "./ada-exp.y" +{ write_attribute_call1 (ATR_LAST, yyvsp[0].lval); } + break; +case 68: +#line 484 "./ada-exp.y" +{ write_attribute_call1 (ATR_LENGTH, yyvsp[0].lval); } + break; +case 69: +#line 486 "./ada-exp.y" +{ write_attribute_calln (ATR_VAL, 1); } + break; +case 70: +#line 488 "./ada-exp.y" +{ write_attribute_call0 (ATR_MODULUS); } + break; +case 71: +#line 492 "./ada-exp.y" +{ yyval.lval = 1; } + break; +case 72: +#line 494 "./ada-exp.y" +{ yyval.lval = yyvsp[-1].typed_val.val; } + break; +case 73: +#line 499 "./ada-exp.y" +{ write_exp_elt_opcode (OP_TYPE); + write_exp_elt_type (yyvsp[0].tval); + write_exp_elt_opcode (OP_TYPE); } + break; +case 75: +#line 507 "./ada-exp.y" +{ write_exp_elt_opcode (OP_TYPE); + write_exp_elt_type (builtin_type_void); + write_exp_elt_opcode (OP_TYPE); } + break; +case 76: +#line 514 "./ada-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (yyvsp[0].typed_val.type); + write_exp_elt_longcst ((LONGEST)(yyvsp[0].typed_val.val)); + write_exp_elt_opcode (OP_LONG); + } + break; +case 77: +#line 522 "./ada-exp.y" +{ write_exp_elt_opcode (OP_LONG); + if (type_qualifier == NULL) + write_exp_elt_type (yyvsp[0].typed_val.type); + else + write_exp_elt_type (type_qualifier); + write_exp_elt_longcst + (convert_char_literal (type_qualifier, yyvsp[0].typed_val.val)); + write_exp_elt_opcode (OP_LONG); + } + break; +case 78: +#line 534 "./ada-exp.y" +{ write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (yyvsp[0].typed_val_float.type); + write_exp_elt_dblcst (yyvsp[0].typed_val_float.dval); + write_exp_elt_opcode (OP_DOUBLE); + } + break; +case 79: +#line 542 "./ada-exp.y" +{ write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST)(0)); + write_exp_elt_opcode (OP_LONG); + } + break; +case 80: +#line 549 "./ada-exp.y" +{ /* Ada strings are converted into array constants + a lower bound of 1. Thus, the array upper bound + is the string length. */ + char *sp = yyvsp[0].sval.ptr; int count; + if (yyvsp[0].sval.length == 0) + { /* One dummy character for the type */ + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_ada_char); + write_exp_elt_longcst ((LONGEST)(0)); + write_exp_elt_opcode (OP_LONG); + } + for (count = yyvsp[0].sval.length; count > 0; count -= 1) + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_ada_char); + write_exp_elt_longcst ((LONGEST)(*sp)); + sp += 1; + write_exp_elt_opcode (OP_LONG); + } + write_exp_elt_opcode (OP_ARRAY); + write_exp_elt_longcst ((LONGEST) 1); + write_exp_elt_longcst ((LONGEST) (yyvsp[0].sval.length)); + write_exp_elt_opcode (OP_ARRAY); + } + break; +case 81: +#line 576 "./ada-exp.y" +{ error ("NEW not implemented."); } + break; +case 82: +#line 579 "./ada-exp.y" +{ write_var_from_name (NULL, yyvsp[0].ssym); } + break; +case 83: +#line 581 "./ada-exp.y" +{ write_var_from_name (yyvsp[-1].bval, yyvsp[0].ssym); } + break; +case 84: +#line 582 "./ada-exp.y" +{ write_object_renaming (NULL, yyvsp[0].ssym.sym); } + break; +case 85: +#line 584 "./ada-exp.y" +{ write_object_renaming (yyvsp[-1].bval, yyvsp[0].ssym.sym); } + break; +case 86: +#line 587 "./ada-exp.y" +{ } + break; +case 87: +#line 588 "./ada-exp.y" +{ } + break; +case 88: +#line 589 "./ada-exp.y" +{ } + break; +case 89: +#line 593 "./ada-exp.y" +{ yyval.bval = yyvsp[0].bval; } + break; +case 90: +#line 595 "./ada-exp.y" +{ yyval.bval = yyvsp[0].bval; } + break; +case 91: +#line 599 "./ada-exp.y" +{ yyval.tval = yyvsp[0].tval; } + break; +case 92: +#line 600 "./ada-exp.y" +{ yyval.tval = yyvsp[0].tval; } + break; +case 93: +#line 602 "./ada-exp.y" +{ yyval.tval = lookup_pointer_type (yyvsp[-1].tval); } + break; +case 94: +#line 604 "./ada-exp.y" +{ yyval.tval = lookup_pointer_type (yyvsp[-1].tval); } + break; +case 95: +#line 611 "./ada-exp.y" +{ write_exp_elt_opcode (UNOP_IND); } + break; +case 96: +#line 613 "./ada-exp.y" +{ write_exp_elt_opcode (UNOP_ADDR); } + break; +case 97: +#line 615 "./ada-exp.y" +{ write_exp_elt_opcode (BINOP_SUBSCRIPT); } + break; +} + +#line 705 "/usr/local/share/bison/bison.simple" + + + yyvsp -= yylen; + yyssp -= yylen; +#if YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; +#if YYLSP_NEEDED + *++yylsp = yyloc; +#endif + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + char *yymsg; + int yyx, yycount; + + yycount = 0; + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) + if (yycheck[yyx + yyn] == yyx) + yysize += yystrlen (yytname[yyx]) + 15, yycount++; + yysize += yystrlen ("parse error, unexpected ") + 1; + yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "parse error, unexpected "); + yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); + + if (yycount < 5) + { + yycount = 0; + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); + yyx++) + if (yycheck[yyx + yyn] == yyx) + { + const char *yyq = ! yycount ? ", expecting " : " or "; + yyp = yystpcpy (yyp, yyq); + yyp = yystpcpy (yyp, yytname[yyx]); + yycount++; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("parse error; also virtual memory exhausted"); + } + else +#endif /* defined (YYERROR_VERBOSE) */ + yyerror ("parse error"); + } + goto yyerrlab1; + + +/*--------------------------------------------------. +| yyerrlab1 -- error raised explicitly by an action | +`--------------------------------------------------*/ +yyerrlab1: + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + YYDPRINTF ((stderr, "Discarding token %d (%s).\n", + yychar, yytname[yychar1])); + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + + +/*-------------------------------------------------------------------. +| yyerrdefault -- current state does not do anything special for the | +| error token. | +`-------------------------------------------------------------------*/ +yyerrdefault: +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + + /* If its default is to accept any token, ok. Otherwise pop it. */ + yyn = yydefact[yystate]; + if (yyn) + goto yydefault; +#endif + + +/*---------------------------------------------------------------. +| yyerrpop -- pop the current state because it cannot handle the | +| error token | +`---------------------------------------------------------------*/ +yyerrpop: + if (yyssp == yyss) + YYABORT; + yyvsp--; + yystate = *--yyssp; +#if YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "Error: state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + +/*--------------. +| yyerrhandle. | +`--------------*/ +yyerrhandle: + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +/*---------------------------------------------. +| yyoverflowab -- parser overflow comes here. | +`---------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} +#line 618 "./ada-exp.y" + + +/* yylex defined in ada-lex.c: Reads one token, getting characters */ +/* through lexptr. */ + +/* Remap normal flex interface names (yylex) as well as gratuitiously */ +/* global symbol names, so we can have multiple flex-generated parsers */ +/* in gdb. */ + +/* (See note above on previous definitions for YACC.) */ + +#define yy_create_buffer ada_yy_create_buffer +#define yy_delete_buffer ada_yy_delete_buffer +#define yy_init_buffer ada_yy_init_buffer +#define yy_load_buffer_state ada_yy_load_buffer_state +#define yy_switch_to_buffer ada_yy_switch_to_buffer +#define yyrestart ada_yyrestart +#define yytext ada_yytext +#define yywrap ada_yywrap + +/* The following kludge was found necessary to prevent conflicts between */ +/* defs.h and non-standard stdlib.h files. */ +#define qsort __qsort__dummy +#include "ada-lex.c" + +int +ada_parse () +{ + lexer_init (yyin); /* (Re-)initialize lexer. */ + left_block_context = NULL; + type_qualifier = NULL; + + return _ada_parse (); +} + +void +yyerror (msg) + char *msg; +{ + error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr); +} + +/* The operator name corresponding to operator symbol STRING (adds + quotes and maps to lower-case). Destroys the previous contents of + the array pointed to by STRING.ptr. Error if STRING does not match + a valid Ada operator. Assumes that STRING.ptr points to a + null-terminated string and that, if STRING is a valid operator + symbol, the array pointed to by STRING.ptr contains at least + STRING.length+3 characters. */ + +static struct stoken +string_to_operator (string) + struct stoken string; +{ + int i; + + for (i = 0; ada_opname_table[i].mangled != NULL; i += 1) + { + if (string.length == strlen (ada_opname_table[i].demangled)-2 + && strncasecmp (string.ptr, ada_opname_table[i].demangled+1, + string.length) == 0) + { + strncpy (string.ptr, ada_opname_table[i].demangled, + string.length+2); + string.length += 2; + return string; + } + } + error ("Invalid operator symbol `%s'", string.ptr); +} + +/* Emit expression to access an instance of SYM, in block BLOCK (if + * non-NULL), and with :: qualification ORIG_LEFT_CONTEXT. */ +static void +write_var_from_sym (orig_left_context, block, sym) + struct block* orig_left_context; + struct block* block; + struct symbol* sym; +{ + if (orig_left_context == NULL && symbol_read_needs_frame (sym)) + { + if (innermost_block == 0 || + contained_in (block, innermost_block)) + innermost_block = block; + } + + write_exp_elt_opcode (OP_VAR_VALUE); + /* We want to use the selected frame, not another more inner frame + which happens to be in the same block */ + write_exp_elt_block (NULL); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); +} + +/* Emit expression to access an instance of NAME. */ +static void +write_var_from_name (orig_left_context, name) + struct block* orig_left_context; + struct name_info name; +{ + if (name.msym != NULL) + { + write_exp_msymbol (name.msym, + lookup_function_type (builtin_type_int), + builtin_type_int); + } + else if (name.sym == NULL) + { + /* Multiple matches: record name and starting block for later + resolution by ada_resolve. */ + /* write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */ + /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */ + write_exp_elt_block (name.block); + /* write_exp_elt_name (name.stoken.ptr); */ + /* FIXME: write_exp_elt_name should be defined in defs.h, located in parse.c */ + /* write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */ + /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */ + } + else + write_var_from_sym (orig_left_context, name.block, name.sym); +} + +/* Write a call on parameterless attribute ATR. */ + +static void +write_attribute_call0 (atr) + enum ada_attribute atr; +{ + /* write_exp_elt_opcode (OP_ATTRIBUTE); */ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ + write_exp_elt_longcst ((LONGEST) 0); + write_exp_elt_longcst ((LONGEST) atr); + /* write_exp_elt_opcode (OP_ATTRIBUTE); */ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ +} + +/* Write a call on an attribute ATR with one constant integer + * parameter. */ + +static void +write_attribute_call1 (atr, arg) + enum ada_attribute atr; + LONGEST arg; +{ + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst (arg); + write_exp_elt_opcode (OP_LONG); + /*write_exp_elt_opcode (OP_ATTRIBUTE);*/ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ + write_exp_elt_longcst ((LONGEST) 1); + write_exp_elt_longcst ((LONGEST) atr); + /*write_exp_elt_opcode (OP_ATTRIBUTE);*/ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ +} + +/* Write a call on an attribute ATR with N parameters, whose code must have + * been generated previously. */ + +static void +write_attribute_calln (atr, n) + enum ada_attribute atr; + int n; +{ + /*write_exp_elt_opcode (OP_ATTRIBUTE);*/ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ + write_exp_elt_longcst ((LONGEST) n); + write_exp_elt_longcst ((LONGEST) atr); + /* write_exp_elt_opcode (OP_ATTRIBUTE);*/ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ +} + +/* Emit expression corresponding to the renamed object designated by + * the type RENAMING, which must be the referent of an object renaming + * type, in the context of ORIG_LEFT_CONTEXT (?). */ +static void +write_object_renaming (orig_left_context, renaming) + struct block* orig_left_context; + struct symbol* renaming; +{ + const char* qualification = SYMBOL_NAME (renaming); + const char* simple_tail; + const char* expr = TYPE_FIELD_NAME (SYMBOL_TYPE (renaming), 0); + const char* suffix; + char* name; + struct symbol* sym; + enum { SIMPLE_INDEX, LOWER_BOUND, UPPER_BOUND } slice_state; + + /* if orig_left_context is null, then use the currently selected + block, otherwise we might fail our symbol lookup below */ + if (orig_left_context == NULL) + orig_left_context = get_selected_block (NULL); + + for (simple_tail = qualification + strlen (qualification); + simple_tail != qualification; simple_tail -= 1) + { + if (*simple_tail == '.') + { + simple_tail += 1; + break; + } + else if (STREQN (simple_tail, "__", 2)) + { + simple_tail += 2; + break; + } + } + + suffix = strstr (expr, "___XE"); + if (suffix == NULL) + goto BadEncoding; + + name = (char*) xmalloc (suffix - expr + 1); + /* add_name_string_cleanup (name); */ + /* FIXME: add_name_string_cleanup should be defined in + parser-defs.h, implemented in parse.c */ + strncpy (name, expr, suffix-expr); + name[suffix-expr] = '\000'; + sym = lookup_symbol (name, orig_left_context, VAR_NAMESPACE, 0, NULL); + /* if (sym == NULL) + error ("Could not find renamed variable: %s", ada_demangle (name)); + */ + /* FIXME: ada_demangle should be defined in defs.h, implemented in ada-lang.c */ + write_var_from_sym (orig_left_context, block_found, sym); + + suffix += 5; + slice_state = SIMPLE_INDEX; + while (*suffix == 'X') + { + suffix += 1; + + switch (*suffix) { + case 'L': + slice_state = LOWER_BOUND; + case 'S': + suffix += 1; + if (isdigit (*suffix)) + { + char* next; + long val = strtol (suffix, &next, 10); + if (next == suffix) + goto BadEncoding; + suffix = next; + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_ada_int); + write_exp_elt_longcst ((LONGEST) val); + write_exp_elt_opcode (OP_LONG); + } + else + { + const char* end; + char* index_name; + int index_len; + struct symbol* index_sym; + + end = strchr (suffix, 'X'); + if (end == NULL) + end = suffix + strlen (suffix); + + index_len = simple_tail - qualification + 2 + (suffix - end) + 1; + index_name = (char*) xmalloc (index_len); + memset (index_name, '\000', index_len); + /* add_name_string_cleanup (index_name);*/ + /* FIXME: add_name_string_cleanup should be defined in + parser-defs.h, implemented in parse.c */ + strncpy (index_name, qualification, simple_tail - qualification); + index_name[simple_tail - qualification] = '\000'; + strncat (index_name, suffix, suffix-end); + suffix = end; + + index_sym = + lookup_symbol (index_name, NULL, VAR_NAMESPACE, 0, NULL); + if (index_sym == NULL) + error ("Could not find %s", index_name); + write_var_from_sym (NULL, block_found, sym); + } + if (slice_state == SIMPLE_INDEX) + { + write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) 1); + write_exp_elt_opcode (OP_FUNCALL); + } + else if (slice_state == LOWER_BOUND) + slice_state = UPPER_BOUND; + else if (slice_state == UPPER_BOUND) + { + write_exp_elt_opcode (TERNOP_SLICE); + slice_state = SIMPLE_INDEX; + } + break; + + case 'R': + { + struct stoken field_name; + const char* end; + suffix += 1; + + if (slice_state != SIMPLE_INDEX) + goto BadEncoding; + end = strchr (suffix, 'X'); + if (end == NULL) + end = suffix + strlen (suffix); + field_name.length = end - suffix; + field_name.ptr = (char*) xmalloc (end - suffix + 1); + strncpy (field_name.ptr, suffix, end - suffix); + field_name.ptr[end - suffix] = '\000'; + suffix = end; + write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string (field_name); + write_exp_elt_opcode (STRUCTOP_STRUCT); + break; + } + + default: + goto BadEncoding; + } + } + if (slice_state == SIMPLE_INDEX) + return; + + BadEncoding: + error ("Internal error in encoding of renaming declaration: %s", + SYMBOL_NAME (renaming)); +} + +/* Convert the character literal whose ASCII value would be VAL to the + appropriate value of type TYPE, if there is a translation. + Otherwise return VAL. Hence, in an enumeration type ('A', 'B'), + the literal 'A' (VAL == 65), returns 0. */ +static LONGEST +convert_char_literal (struct type* type, LONGEST val) +{ + char name[7]; + int f; + + if (type == NULL || TYPE_CODE (type) != TYPE_CODE_ENUM) + return val; + sprintf (name, "QU%02x", (int) val); + for (f = 0; f < TYPE_NFIELDS (type); f += 1) + { + if (STREQ (name, TYPE_FIELD_NAME (type, f))) + return TYPE_FIELD_BITPOS (type, f); + } + return val; +} diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y new file mode 100644 index 0000000..7d46dd2 --- /dev/null +++ b/gdb/ada-exp.y @@ -0,0 +1,962 @@ +/* YACC parser for Ada expressions, for GDB. + Copyright (C) 1986, 1989, 1990, 1991, 1993, 1994, 1997, 2000 + 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 2 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, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Parse an Ada expression from text in a string, + and return the result as a struct expression pointer. + That structure contains arithmetic operations in reverse polish, + with constants represented by operations that are followed by special data. + See expression.h for the details of the format. + What is important here is that it can be built up sequentially + during the process of parsing; the lower levels of the tree always + come first in the result. + + malloc's and realloc's in this file are transformed to + xmalloc and xrealloc respectively by the same sed command in the + makefile that remaps any other malloc/realloc inserted by the parser + generator. Doing this with #defines and trying to control the interaction + with include files (<malloc.h> and <stdlib.h> for example) just became + too messy, particularly when such includes can be inserted at random + times by the parser generator. */ + +%{ + +#include "defs.h" +#include <string.h> +#include <ctype.h> +#include "expression.h" +#include "value.h" +#include "parser-defs.h" +#include "language.h" +#include "ada-lang.h" +#include "bfd.h" /* Required by objfiles.h. */ +#include "symfile.h" /* Required by objfiles.h. */ +#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */ +#include "frame.h" + +/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), + as well as gratuitiously global symbol names, so we can have multiple + yacc generated parsers in gdb. These are only the variables + produced by yacc. If other parser generators (bison, byacc, etc) produce + additional global names that conflict at link time, then those parser + generators need to be fixed instead of adding those names to this list. */ + +/* NOTE: This is clumsy, especially since BISON and FLEX provide --prefix + options. I presume we are maintaining it to accommodate systems + without BISON? (PNH) */ + +#define yymaxdepth ada_maxdepth +#define yyparse _ada_parse /* ada_parse calls this after initialization */ +#define yylex ada_lex +#define yyerror ada_error +#define yylval ada_lval +#define yychar ada_char +#define yydebug ada_debug +#define yypact ada_pact +#define yyr1 ada_r1 +#define yyr2 ada_r2 +#define yydef ada_def +#define yychk ada_chk +#define yypgo ada_pgo +#define yyact ada_act +#define yyexca ada_exca +#define yyerrflag ada_errflag +#define yynerrs ada_nerrs +#define yyps ada_ps +#define yypv ada_pv +#define yys ada_s +#define yy_yys ada_yys +#define yystate ada_state +#define yytmp ada_tmp +#define yyv ada_v +#define yy_yyv ada_yyv +#define yyval ada_val +#define yylloc ada_lloc +#define yyreds ada_reds /* With YYDEBUG defined */ +#define yytoks ada_toks /* With YYDEBUG defined */ + +#ifndef YYDEBUG +#define YYDEBUG 0 /* Default to no yydebug support */ +#endif + +struct name_info { + struct symbol* sym; + struct minimal_symbol* msym; + struct block* block; + struct stoken stoken; +}; + +/* If expression is in the context of TYPE'(...), then TYPE, else + * NULL. */ +static struct type* type_qualifier; + +int yyparse (void); + +static int yylex (void); + +void yyerror (char *); + +static struct stoken string_to_operator (struct stoken); + +static void write_attribute_call0 (enum ada_attribute); + +static void write_attribute_call1 (enum ada_attribute, LONGEST); + +static void write_attribute_calln (enum ada_attribute, int); + +static void write_object_renaming (struct block*, struct symbol*); + +static void write_var_from_name (struct block*, struct name_info); + +static LONGEST +convert_char_literal (struct type*, LONGEST); +%} + +%union + { + LONGEST lval; + struct { + LONGEST val; + struct type *type; + } typed_val; + struct { + DOUBLEST dval; + struct type *type; + } typed_val_float; + struct type *tval; + struct stoken sval; + struct name_info ssym; + int voidval; + struct block *bval; + struct internalvar *ivar; + + } + +%type <voidval> exp exp1 simple_exp start variable +%type <tval> type + +%token <typed_val> INT NULL_PTR CHARLIT +%token <typed_val_float> FLOAT +%token <tval> TYPENAME +%token <bval> BLOCKNAME + +/* Both NAME and TYPENAME tokens represent symbols in the input, + and both convey their data as strings. + But a TYPENAME is a string that happens to be defined as a typedef + or builtin type name (such as int or char) + and a NAME is any other symbol. + Contexts where this distinction is not important can use the + nonterminal "name", which matches either NAME or TYPENAME. */ + +%token <sval> STRING +%token <ssym> NAME DOT_ID OBJECT_RENAMING +%type <bval> block +%type <lval> arglist tick_arglist + +%type <tval> save_qualifier + +%token DOT_ALL + +/* Special type cases, put in to allow the parser to distinguish different + legal basetypes. */ +%token <lval> LAST REGNAME + +%token <ivar> INTERNAL_VARIABLE + +%nonassoc ASSIGN +%left _AND_ OR XOR THEN ELSE +%left '=' NOTEQUAL '<' '>' LEQ GEQ IN DOTDOT +%left '@' +%left '+' '-' '&' +%left UNARY +%left '*' '/' MOD REM +%right STARSTAR ABS NOT + /* The following are right-associative only so that reductions at this + precedence have lower precedence than '.' and '('. The syntax still + forces a.b.c, e.g., to be LEFT-associated. */ +%right TICK_ACCESS TICK_ADDRESS TICK_FIRST TICK_LAST TICK_LENGTH +%right TICK_MAX TICK_MIN TICK_MODULUS +%right TICK_POS TICK_RANGE TICK_SIZE TICK_TAG TICK_VAL +%right '.' '(' '[' DOT_ID DOT_ALL + +%token ARROW NEW + + +%% + +start : exp1 + | type { write_exp_elt_opcode (OP_TYPE); + write_exp_elt_type ($1); + write_exp_elt_opcode (OP_TYPE); } + ; + +/* Expressions, including the sequencing operator. */ +exp1 : exp + | exp1 ';' exp + { write_exp_elt_opcode (BINOP_COMMA); } + ; + +/* Expressions, not including the sequencing operator. */ +simple_exp : simple_exp DOT_ALL + { write_exp_elt_opcode (UNOP_IND); } + ; + +simple_exp : simple_exp DOT_ID + { write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string ($2.stoken); + write_exp_elt_opcode (STRUCTOP_STRUCT); + } + ; + +simple_exp : simple_exp '(' arglist ')' + { + write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ($3); + write_exp_elt_opcode (OP_FUNCALL); + } + ; + +simple_exp : type '(' exp ')' + { + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type ($1); + write_exp_elt_opcode (UNOP_CAST); + } + ; + +simple_exp : type '\'' save_qualifier { type_qualifier = $1; } '(' exp ')' + { + /* write_exp_elt_opcode (UNOP_QUAL); */ + /* FIXME: UNOP_QUAL should be defined in expression.h */ + write_exp_elt_type ($1); + /* write_exp_elt_opcode (UNOP_QUAL); */ + /* FIXME: UNOP_QUAL should be defined in expression.h */ + type_qualifier = $3; + } + ; + +save_qualifier : { $$ = type_qualifier; } + +simple_exp : + simple_exp '(' exp DOTDOT exp ')' + { write_exp_elt_opcode (TERNOP_SLICE); } + ; + +simple_exp : '(' exp1 ')' { } + ; + +simple_exp : variable + ; + +simple_exp: REGNAME /* GDB extension */ + { write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_REGISTER); + } + ; + +simple_exp: INTERNAL_VARIABLE /* GDB extension */ + { write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern ($1); + write_exp_elt_opcode (OP_INTERNALVAR); + } + ; + + +exp : simple_exp + ; + +simple_exp: LAST + { write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LAST); + } + ; + +exp : exp ASSIGN exp /* Extension for convenience */ + { write_exp_elt_opcode (BINOP_ASSIGN); } + ; + +exp : '-' exp %prec UNARY + { write_exp_elt_opcode (UNOP_NEG); } + ; + +exp : '+' exp %prec UNARY + { write_exp_elt_opcode (UNOP_PLUS); } + ; + +exp : NOT exp %prec UNARY + { write_exp_elt_opcode (UNOP_LOGICAL_NOT); } + ; + +exp : ABS exp %prec UNARY + { write_exp_elt_opcode (UNOP_ABS); } + ; + +arglist : { $$ = 0; } + ; + +arglist : exp + { $$ = 1; } + | any_name ARROW exp + { $$ = 1; } + | arglist ',' exp + { $$ = $1 + 1; } + | arglist ',' any_name ARROW exp + { $$ = $1 + 1; } + ; + +exp : '{' type '}' exp %prec '.' + /* GDB extension */ + { write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type ($2); + write_exp_elt_opcode (UNOP_MEMVAL); + } + ; + +/* Binary operators in order of decreasing precedence. */ + +exp : exp STARSTAR exp + { write_exp_elt_opcode (BINOP_EXP); } + ; + +exp : exp '*' exp + { write_exp_elt_opcode (BINOP_MUL); } + ; + +exp : exp '/' exp + { write_exp_elt_opcode (BINOP_DIV); } + ; + +exp : exp REM exp /* May need to be fixed to give correct Ada REM */ + { write_exp_elt_opcode (BINOP_REM); } + ; + +exp : exp MOD exp + { write_exp_elt_opcode (BINOP_MOD); } + ; + +exp : exp '@' exp /* GDB extension */ + { write_exp_elt_opcode (BINOP_REPEAT); } + ; + +exp : exp '+' exp + { write_exp_elt_opcode (BINOP_ADD); } + ; + +exp : exp '&' exp + { write_exp_elt_opcode (BINOP_CONCAT); } + ; + +exp : exp '-' exp + { write_exp_elt_opcode (BINOP_SUB); } + ; + +exp : exp '=' exp + { write_exp_elt_opcode (BINOP_EQUAL); } + ; + +exp : exp NOTEQUAL exp + { write_exp_elt_opcode (BINOP_NOTEQUAL); } + ; + +exp : exp LEQ exp + { write_exp_elt_opcode (BINOP_LEQ); } + ; + +exp : exp IN exp DOTDOT exp + { /*write_exp_elt_opcode (TERNOP_MBR); */ } + /* FIXME: TERNOP_MBR should be defined in + expression.h */ + | exp IN exp TICK_RANGE tick_arglist + { /*write_exp_elt_opcode (BINOP_MBR); */ + /* FIXME: BINOP_MBR should be defined in expression.h */ + write_exp_elt_longcst ((LONGEST) $5); + /*write_exp_elt_opcode (BINOP_MBR); */ + } + | exp IN TYPENAME %prec TICK_ACCESS + { /*write_exp_elt_opcode (UNOP_MBR); */ + /* FIXME: UNOP_QUAL should be defined in expression.h */ + write_exp_elt_type ($3); + /* write_exp_elt_opcode (UNOP_MBR); */ + /* FIXME: UNOP_MBR should be defined in expression.h */ + } + | exp NOT IN exp DOTDOT exp + { /*write_exp_elt_opcode (TERNOP_MBR); */ + /* FIXME: TERNOP_MBR should be defined in expression.h */ + write_exp_elt_opcode (UNOP_LOGICAL_NOT); + } + | exp NOT IN exp TICK_RANGE tick_arglist + { /* write_exp_elt_opcode (BINOP_MBR); */ + /* FIXME: BINOP_MBR should be defined in expression.h */ + write_exp_elt_longcst ((LONGEST) $6); + /*write_exp_elt_opcode (BINOP_MBR);*/ + /* FIXME: BINOP_MBR should be defined in expression.h */ + write_exp_elt_opcode (UNOP_LOGICAL_NOT); + } + | exp NOT IN TYPENAME %prec TICK_ACCESS + { /*write_exp_elt_opcode (UNOP_MBR);*/ + /* FIXME: UNOP_MBR should be defined in expression.h */ + write_exp_elt_type ($4); + /* write_exp_elt_opcode (UNOP_MBR);*/ + /* FIXME: UNOP_MBR should be defined in expression.h */ + write_exp_elt_opcode (UNOP_LOGICAL_NOT); + } + ; + +exp : exp GEQ exp + { write_exp_elt_opcode (BINOP_GEQ); } + ; + +exp : exp '<' exp + { write_exp_elt_opcode (BINOP_LESS); } + ; + +exp : exp '>' exp + { write_exp_elt_opcode (BINOP_GTR); } + ; + +exp : exp _AND_ exp /* Fix for Ada elementwise AND. */ + { write_exp_elt_opcode (BINOP_BITWISE_AND); } + ; + +exp : exp _AND_ THEN exp %prec _AND_ + { write_exp_elt_opcode (BINOP_LOGICAL_AND); } + ; + +exp : exp OR exp /* Fix for Ada elementwise OR */ + { write_exp_elt_opcode (BINOP_BITWISE_IOR); } + ; + +exp : exp OR ELSE exp + { write_exp_elt_opcode (BINOP_LOGICAL_OR); } + ; + +exp : exp XOR exp /* Fix for Ada elementwise XOR */ + { write_exp_elt_opcode (BINOP_BITWISE_XOR); } + ; + +simple_exp : simple_exp TICK_ACCESS + { write_exp_elt_opcode (UNOP_ADDR); } + | simple_exp TICK_ADDRESS + { write_exp_elt_opcode (UNOP_ADDR); + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type (builtin_type_ada_system_address); + write_exp_elt_opcode (UNOP_CAST); + } + | simple_exp TICK_FIRST tick_arglist + { write_attribute_call1 (ATR_FIRST, $3); } + | simple_exp TICK_LAST tick_arglist + { write_attribute_call1 (ATR_LAST, $3); } + | simple_exp TICK_LENGTH tick_arglist + { write_attribute_call1 (ATR_LENGTH, $3); } + | simple_exp TICK_SIZE + { write_attribute_call0 (ATR_SIZE); } + | simple_exp TICK_TAG + { write_attribute_call0 (ATR_TAG); } + | opt_type_prefix TICK_MIN '(' exp ',' exp ')' + { write_attribute_calln (ATR_MIN, 2); } + | opt_type_prefix TICK_MAX '(' exp ',' exp ')' + { write_attribute_calln (ATR_MAX, 2); } + | opt_type_prefix TICK_POS '(' exp ')' + { write_attribute_calln (ATR_POS, 1); } + | type_prefix TICK_FIRST tick_arglist + { write_attribute_call1 (ATR_FIRST, $3); } + | type_prefix TICK_LAST tick_arglist + { write_attribute_call1 (ATR_LAST, $3); } + | type_prefix TICK_LENGTH tick_arglist + { write_attribute_call1 (ATR_LENGTH, $3); } + | type_prefix TICK_VAL '(' exp ')' + { write_attribute_calln (ATR_VAL, 1); } + | type_prefix TICK_MODULUS + { write_attribute_call0 (ATR_MODULUS); } + ; + +tick_arglist : %prec '(' + { $$ = 1; } + | '(' INT ')' + { $$ = $2.val; } + ; + +type_prefix : + TYPENAME + { write_exp_elt_opcode (OP_TYPE); + write_exp_elt_type ($1); + write_exp_elt_opcode (OP_TYPE); } + ; + +opt_type_prefix : + type_prefix + | /* EMPTY */ + { write_exp_elt_opcode (OP_TYPE); + write_exp_elt_type (builtin_type_void); + write_exp_elt_opcode (OP_TYPE); } + ; + + +exp : INT + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type ($1.type); + write_exp_elt_longcst ((LONGEST)($1.val)); + write_exp_elt_opcode (OP_LONG); + } + ; + +exp : CHARLIT + { write_exp_elt_opcode (OP_LONG); + if (type_qualifier == NULL) + write_exp_elt_type ($1.type); + else + write_exp_elt_type (type_qualifier); + write_exp_elt_longcst + (convert_char_literal (type_qualifier, $1.val)); + write_exp_elt_opcode (OP_LONG); + } + + +exp : FLOAT + { write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type ($1.type); + write_exp_elt_dblcst ($1.dval); + write_exp_elt_opcode (OP_DOUBLE); + } + ; + +exp : NULL_PTR + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST)(0)); + write_exp_elt_opcode (OP_LONG); + } + +exp : STRING + { /* Ada strings are converted into array constants + a lower bound of 1. Thus, the array upper bound + is the string length. */ + char *sp = $1.ptr; int count; + if ($1.length == 0) + { /* One dummy character for the type */ + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_ada_char); + write_exp_elt_longcst ((LONGEST)(0)); + write_exp_elt_opcode (OP_LONG); + } + for (count = $1.length; count > 0; count -= 1) + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_ada_char); + write_exp_elt_longcst ((LONGEST)(*sp)); + sp += 1; + write_exp_elt_opcode (OP_LONG); + } + write_exp_elt_opcode (OP_ARRAY); + write_exp_elt_longcst ((LONGEST) 1); + write_exp_elt_longcst ((LONGEST) ($1.length)); + write_exp_elt_opcode (OP_ARRAY); + } + ; + +exp : NEW TYPENAME + { error ("NEW not implemented."); } + ; + +variable: NAME { write_var_from_name (NULL, $1); } + | block NAME /* GDB extension */ + { write_var_from_name ($1, $2); } + | OBJECT_RENAMING { write_object_renaming (NULL, $1.sym); } + | block OBJECT_RENAMING + { write_object_renaming ($1, $2.sym); } + ; + +any_name : NAME { } + | TYPENAME { } + | OBJECT_RENAMING { } + ; + +block : BLOCKNAME /* GDB extension */ + { $$ = $1; } + | block BLOCKNAME /* GDB extension */ + { $$ = $2; } + ; + + +type : TYPENAME { $$ = $1; } + | block TYPENAME { $$ = $2; } + | TYPENAME TICK_ACCESS + { $$ = lookup_pointer_type ($1); } + | block TYPENAME TICK_ACCESS + { $$ = lookup_pointer_type ($2); } + ; + +/* Some extensions borrowed from C, for the benefit of those who find they + can't get used to Ada notation in GDB. */ + +exp : '*' exp %prec '.' + { write_exp_elt_opcode (UNOP_IND); } + | '&' exp %prec '.' + { write_exp_elt_opcode (UNOP_ADDR); } + | exp '[' exp ']' + { write_exp_elt_opcode (BINOP_SUBSCRIPT); } + ; + +%% + +/* yylex defined in ada-lex.c: Reads one token, getting characters */ +/* through lexptr. */ + +/* Remap normal flex interface names (yylex) as well as gratuitiously */ +/* global symbol names, so we can have multiple flex-generated parsers */ +/* in gdb. */ + +/* (See note above on previous definitions for YACC.) */ + +#define yy_create_buffer ada_yy_create_buffer +#define yy_delete_buffer ada_yy_delete_buffer +#define yy_init_buffer ada_yy_init_buffer +#define yy_load_buffer_state ada_yy_load_buffer_state +#define yy_switch_to_buffer ada_yy_switch_to_buffer +#define yyrestart ada_yyrestart +#define yytext ada_yytext +#define yywrap ada_yywrap + +/* The following kludge was found necessary to prevent conflicts between */ +/* defs.h and non-standard stdlib.h files. */ +#define qsort __qsort__dummy +#include "ada-lex.c" + +int +ada_parse () +{ + lexer_init (yyin); /* (Re-)initialize lexer. */ + left_block_context = NULL; + type_qualifier = NULL; + + return _ada_parse (); +} + +void +yyerror (msg) + char *msg; +{ + error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr); +} + +/* The operator name corresponding to operator symbol STRING (adds + quotes and maps to lower-case). Destroys the previous contents of + the array pointed to by STRING.ptr. Error if STRING does not match + a valid Ada operator. Assumes that STRING.ptr points to a + null-terminated string and that, if STRING is a valid operator + symbol, the array pointed to by STRING.ptr contains at least + STRING.length+3 characters. */ + +static struct stoken +string_to_operator (string) + struct stoken string; +{ + int i; + + for (i = 0; ada_opname_table[i].mangled != NULL; i += 1) + { + if (string.length == strlen (ada_opname_table[i].demangled)-2 + && strncasecmp (string.ptr, ada_opname_table[i].demangled+1, + string.length) == 0) + { + strncpy (string.ptr, ada_opname_table[i].demangled, + string.length+2); + string.length += 2; + return string; + } + } + error ("Invalid operator symbol `%s'", string.ptr); +} + +/* Emit expression to access an instance of SYM, in block BLOCK (if + * non-NULL), and with :: qualification ORIG_LEFT_CONTEXT. */ +static void +write_var_from_sym (orig_left_context, block, sym) + struct block* orig_left_context; + struct block* block; + struct symbol* sym; +{ + if (orig_left_context == NULL && symbol_read_needs_frame (sym)) + { + if (innermost_block == 0 || + contained_in (block, innermost_block)) + innermost_block = block; + } + + write_exp_elt_opcode (OP_VAR_VALUE); + /* We want to use the selected frame, not another more inner frame + which happens to be in the same block */ + write_exp_elt_block (NULL); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); +} + +/* Emit expression to access an instance of NAME. */ +static void +write_var_from_name (orig_left_context, name) + struct block* orig_left_context; + struct name_info name; +{ + if (name.msym != NULL) + { + write_exp_msymbol (name.msym, + lookup_function_type (builtin_type_int), + builtin_type_int); + } + else if (name.sym == NULL) + { + /* Multiple matches: record name and starting block for later + resolution by ada_resolve. */ + /* write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */ + /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */ + write_exp_elt_block (name.block); + /* write_exp_elt_name (name.stoken.ptr); */ + /* FIXME: write_exp_elt_name should be defined in defs.h, located in parse.c */ + /* write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */ + /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */ + } + else + write_var_from_sym (orig_left_context, name.block, name.sym); +} + +/* Write a call on parameterless attribute ATR. */ + +static void +write_attribute_call0 (atr) + enum ada_attribute atr; +{ + /* write_exp_elt_opcode (OP_ATTRIBUTE); */ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ + write_exp_elt_longcst ((LONGEST) 0); + write_exp_elt_longcst ((LONGEST) atr); + /* write_exp_elt_opcode (OP_ATTRIBUTE); */ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ +} + +/* Write a call on an attribute ATR with one constant integer + * parameter. */ + +static void +write_attribute_call1 (atr, arg) + enum ada_attribute atr; + LONGEST arg; +{ + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst (arg); + write_exp_elt_opcode (OP_LONG); + /*write_exp_elt_opcode (OP_ATTRIBUTE);*/ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ + write_exp_elt_longcst ((LONGEST) 1); + write_exp_elt_longcst ((LONGEST) atr); + /*write_exp_elt_opcode (OP_ATTRIBUTE);*/ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ +} + +/* Write a call on an attribute ATR with N parameters, whose code must have + * been generated previously. */ + +static void +write_attribute_calln (atr, n) + enum ada_attribute atr; + int n; +{ + /*write_exp_elt_opcode (OP_ATTRIBUTE);*/ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ + write_exp_elt_longcst ((LONGEST) n); + write_exp_elt_longcst ((LONGEST) atr); + /* write_exp_elt_opcode (OP_ATTRIBUTE);*/ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ +} + +/* Emit expression corresponding to the renamed object designated by + * the type RENAMING, which must be the referent of an object renaming + * type, in the context of ORIG_LEFT_CONTEXT (?). */ +static void +write_object_renaming (orig_left_context, renaming) + struct block* orig_left_context; + struct symbol* renaming; +{ + const char* qualification = SYMBOL_NAME (renaming); + const char* simple_tail; + const char* expr = TYPE_FIELD_NAME (SYMBOL_TYPE (renaming), 0); + const char* suffix; + char* name; + struct symbol* sym; + enum { SIMPLE_INDEX, LOWER_BOUND, UPPER_BOUND } slice_state; + + /* if orig_left_context is null, then use the currently selected + block, otherwise we might fail our symbol lookup below */ + if (orig_left_context == NULL) + orig_left_context = get_selected_block (NULL); + + for (simple_tail = qualification + strlen (qualification); + simple_tail != qualification; simple_tail -= 1) + { + if (*simple_tail == '.') + { + simple_tail += 1; + break; + } + else if (STREQN (simple_tail, "__", 2)) + { + simple_tail += 2; + break; + } + } + + suffix = strstr (expr, "___XE"); + if (suffix == NULL) + goto BadEncoding; + + name = (char*) malloc (suffix - expr + 1); + /* add_name_string_cleanup (name); */ + /* FIXME: add_name_string_cleanup should be defined in + parser-defs.h, implemented in parse.c */ + strncpy (name, expr, suffix-expr); + name[suffix-expr] = '\000'; + sym = lookup_symbol (name, orig_left_context, VAR_NAMESPACE, 0, NULL); + /* if (sym == NULL) + error ("Could not find renamed variable: %s", ada_demangle (name)); + */ + /* FIXME: ada_demangle should be defined in defs.h, implemented in ada-lang.c */ + write_var_from_sym (orig_left_context, block_found, sym); + + suffix += 5; + slice_state = SIMPLE_INDEX; + while (*suffix == 'X') + { + suffix += 1; + + switch (*suffix) { + case 'L': + slice_state = LOWER_BOUND; + case 'S': + suffix += 1; + if (isdigit (*suffix)) + { + char* next; + long val = strtol (suffix, &next, 10); + if (next == suffix) + goto BadEncoding; + suffix = next; + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_ada_int); + write_exp_elt_longcst ((LONGEST) val); + write_exp_elt_opcode (OP_LONG); + } + else + { + const char* end; + char* index_name; + int index_len; + struct symbol* index_sym; + + end = strchr (suffix, 'X'); + if (end == NULL) + end = suffix + strlen (suffix); + + index_len = simple_tail - qualification + 2 + (suffix - end) + 1; + index_name = (char*) malloc (index_len); + memset (index_name, '\000', index_len); + /* add_name_string_cleanup (index_name);*/ + /* FIXME: add_name_string_cleanup should be defined in + parser-defs.h, implemented in parse.c */ + strncpy (index_name, qualification, simple_tail - qualification); + index_name[simple_tail - qualification] = '\000'; + strncat (index_name, suffix, suffix-end); + suffix = end; + + index_sym = + lookup_symbol (index_name, NULL, VAR_NAMESPACE, 0, NULL); + if (index_sym == NULL) + error ("Could not find %s", index_name); + write_var_from_sym (NULL, block_found, sym); + } + if (slice_state == SIMPLE_INDEX) + { + write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) 1); + write_exp_elt_opcode (OP_FUNCALL); + } + else if (slice_state == LOWER_BOUND) + slice_state = UPPER_BOUND; + else if (slice_state == UPPER_BOUND) + { + write_exp_elt_opcode (TERNOP_SLICE); + slice_state = SIMPLE_INDEX; + } + break; + + case 'R': + { + struct stoken field_name; + const char* end; + suffix += 1; + + if (slice_state != SIMPLE_INDEX) + goto BadEncoding; + end = strchr (suffix, 'X'); + if (end == NULL) + end = suffix + strlen (suffix); + field_name.length = end - suffix; + field_name.ptr = (char*) malloc (end - suffix + 1); + strncpy (field_name.ptr, suffix, end - suffix); + field_name.ptr[end - suffix] = '\000'; + suffix = end; + write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string (field_name); + write_exp_elt_opcode (STRUCTOP_STRUCT); + break; + } + + default: + goto BadEncoding; + } + } + if (slice_state == SIMPLE_INDEX) + return; + + BadEncoding: + error ("Internal error in encoding of renaming declaration: %s", + SYMBOL_NAME (renaming)); +} + +/* Convert the character literal whose ASCII value would be VAL to the + appropriate value of type TYPE, if there is a translation. + Otherwise return VAL. Hence, in an enumeration type ('A', 'B'), + the literal 'A' (VAL == 65), returns 0. */ +static LONGEST +convert_char_literal (struct type* type, LONGEST val) +{ + char name[7]; + int f; + + if (type == NULL || TYPE_CODE (type) != TYPE_CODE_ENUM) + return val; + sprintf (name, "QU%02x", (int) val); + for (f = 0; f < TYPE_NFIELDS (type); f += 1) + { + if (STREQ (name, TYPE_FIELD_NAME (type, f))) + return TYPE_FIELD_BITPOS (type, f); + } + return val; +} diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c new file mode 100644 index 0000000..2c4f1d9 --- /dev/null +++ b/gdb/ada-lang.c @@ -0,0 +1,8626 @@ +/* Ada language support routines for GDB, the GNU debugger. Copyright + 1992, 1993, 1994, 1997, 1998, 1999, 2000 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 2 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, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdarg.h> +#include "demangle.h" +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcmd.h" +#include "expression.h" +#include "parser-defs.h" +#include "language.h" +#include "c-lang.h" +#include "inferior.h" +#include "symfile.h" +#include "objfiles.h" +#include "breakpoint.h" +#include "gdbcore.h" +#include "ada-lang.h" +#ifdef UI_OUT +#include "ui-out.h" +#endif + +struct cleanup* unresolved_names; + +void extract_string (CORE_ADDR addr, char *buf); + +static struct type * ada_create_fundamental_type (struct objfile *, int); + +static void modify_general_field (char *, LONGEST, int, int); + +static struct type* desc_base_type (struct type*); + +static struct type* desc_bounds_type (struct type*); + +static struct value* desc_bounds (struct value*); + +static int fat_pntr_bounds_bitpos (struct type*); + +static int fat_pntr_bounds_bitsize (struct type*); + +static struct type* desc_data_type (struct type*); + +static struct value* desc_data (struct value*); + +static int fat_pntr_data_bitpos (struct type*); + +static int fat_pntr_data_bitsize (struct type*); + +static struct value* desc_one_bound (struct value*, int, int); + +static int desc_bound_bitpos (struct type*, int, int); + +static int desc_bound_bitsize (struct type*, int, int); + +static struct type* desc_index_type (struct type*, int); + +static int desc_arity (struct type*); + +static int ada_type_match (struct type*, struct type*, int); + +static int ada_args_match (struct symbol*, struct value**, int); + +static struct value* place_on_stack (struct value*, CORE_ADDR*); + +static struct value* convert_actual (struct value*, struct type*, CORE_ADDR*); + +static struct value* make_array_descriptor (struct type*, struct value*, CORE_ADDR*); + +static void ada_add_block_symbols (struct block*, const char*, + namespace_enum, struct objfile*, int); + +static void fill_in_ada_prototype (struct symbol*); + +static int is_nonfunction (struct symbol**, int); + +static void add_defn_to_vec (struct symbol*, struct block*); + +static struct partial_symbol* +ada_lookup_partial_symbol (struct partial_symtab*, const char*, + int, namespace_enum, int); + +static struct symtab* symtab_for_sym (struct symbol*); + +static struct value* ada_resolve_subexp (struct expression**, int*, int, struct type*); + +static void replace_operator_with_call (struct expression**, int, int, int, + struct symbol*, struct block*); + +static int possible_user_operator_p (enum exp_opcode, struct value**); + +static const char* ada_op_name (enum exp_opcode); + +static int numeric_type_p (struct type*); + +static int integer_type_p (struct type*); + +static int scalar_type_p (struct type*); + +static int discrete_type_p (struct type*); + +static char* extended_canonical_line_spec (struct symtab_and_line, const char*); + +static struct value* evaluate_subexp (struct type*, struct expression*, int*, enum noside); + +static struct value* evaluate_subexp_type (struct expression*, int*); + +static struct type * ada_create_fundamental_type (struct objfile*, int); + +static int is_dynamic_field (struct type *, int); + +static struct type* +to_fixed_variant_branch_type (struct type*, char*, CORE_ADDR, struct value*); + +static struct type* to_fixed_range_type (char*, struct value*, struct objfile*); + +static struct type* to_static_fixed_type (struct type*); + +static struct value* unwrap_value (struct value*); + +static struct type* packed_array_type (struct type*, long*); + +static struct type* decode_packed_array_type (struct type*); + +static struct value* decode_packed_array (struct value*); + +static struct value* value_subscript_packed (struct value*, int, struct value**); + +static struct value* coerce_unspec_val_to_type (struct value*, long, struct type*); + +static struct value* get_var_value (char*, char*); + +static int lesseq_defined_than (struct symbol*, struct symbol*); + +static int equiv_types (struct type*, struct type*); + +static int is_name_suffix (const char*); + +static int wild_match (const char*, int, const char*); + +static struct symtabs_and_lines find_sal_from_funcs_and_line (const char*, int, struct symbol**, int); + +static int +find_line_in_linetable (struct linetable*, int, struct symbol**, int, int*); + +static int find_next_line_in_linetable (struct linetable*, int, int, int); + +static struct symtabs_and_lines all_sals_for_line (const char*, int, char***); + +static void read_all_symtabs (const char*); + +static int is_plausible_func_for_line (struct symbol*, int); + +static struct value* ada_coerce_ref (struct value*); + +static struct value* value_pos_atr (struct value*); + +static struct value* value_val_atr (struct type*, struct value*); + +static struct symbol* standard_lookup (const char*, namespace_enum); + +extern void markTimeStart (int index); +extern void markTimeStop (int index); + + + +/* Maximum-sized dynamic type. */ +static unsigned int varsize_limit; + +static const char* ada_completer_word_break_characters = + " \t\n!@#$%^&*()+=|~`}{[]\";:?/,-"; + +/* The name of the symbol to use to get the name of the main subprogram */ +#define ADA_MAIN_PROGRAM_SYMBOL_NAME "__gnat_ada_main_program_name" + + /* Utilities */ + +/* extract_string + * + * read the string located at ADDR from the inferior and store the + * result into BUF + */ +void +extract_string (CORE_ADDR addr, char *buf) +{ + int char_index = 0; + + /* Loop, reading one byte at a time, until we reach the '\000' + end-of-string marker */ + do + { + target_read_memory (addr + char_index * sizeof (char), + buf + char_index * sizeof (char), + sizeof (char)); + char_index++; + } + while (buf[char_index - 1] != '\000'); +} + +/* Assuming *OLD_VECT points to an array of *SIZE objects of size + ELEMENT_SIZE, grow it to contain at least MIN_SIZE objects, + updating *OLD_VECT and *SIZE as necessary. */ + +void +grow_vect (old_vect, size, min_size, element_size) + void** old_vect; + size_t* size; + size_t min_size; + int element_size; +{ + if (*size < min_size) { + *size *= 2; + if (*size < min_size) + *size = min_size; + *old_vect = xrealloc (*old_vect, *size * element_size); + } +} + +/* True (non-zero) iff TARGET matches FIELD_NAME up to any trailing + suffix of FIELD_NAME beginning "___" */ + +static int +field_name_match (field_name, target) + const char *field_name; + const char *target; +{ + int len = strlen (target); + return + STREQN (field_name, target, len) + && (field_name[len] == '\0' + || (STREQN (field_name + len, "___", 3) + && ! STREQ (field_name + strlen (field_name) - 6, "___XVN"))); +} + + +/* The length of the prefix of NAME prior to any "___" suffix. */ + +int +ada_name_prefix_len (name) + const char* name; +{ + if (name == NULL) + return 0; + else + { + const char* p = strstr (name, "___"); + if (p == NULL) + return strlen (name); + else + return p - name; + } +} + +/* SUFFIX is a suffix of STR. False if STR is null. */ +static int +is_suffix (const char* str, const char* suffix) +{ + int len1, len2; + if (str == NULL) + return 0; + len1 = strlen (str); + len2 = strlen (suffix); + return (len1 >= len2 && STREQ (str + len1 - len2, suffix)); +} + +/* Create a value of type TYPE whose contents come from VALADDR, if it + * is non-null, and whose memory address (in the inferior) is + * ADDRESS. */ +struct value* +value_from_contents_and_address (type, valaddr, address) + struct type* type; + char* valaddr; + CORE_ADDR address; +{ + struct value* v = allocate_value (type); + if (valaddr == NULL) + VALUE_LAZY (v) = 1; + else + memcpy (VALUE_CONTENTS_RAW (v), valaddr, TYPE_LENGTH (type)); + VALUE_ADDRESS (v) = address; + if (address != 0) + VALUE_LVAL (v) = lval_memory; + return v; +} + +/* The contents of value VAL, beginning at offset OFFSET, treated as a + value of type TYPE. The result is an lval in memory if VAL is. */ + +static struct value* +coerce_unspec_val_to_type (val, offset, type) + struct value* val; + long offset; + struct type *type; +{ + CHECK_TYPEDEF (type); + if (VALUE_LVAL (val) == lval_memory) + return value_at_lazy (type, + VALUE_ADDRESS (val) + VALUE_OFFSET (val) + offset, NULL); + else + { + struct value* result = allocate_value (type); + VALUE_LVAL (result) = not_lval; + if (VALUE_ADDRESS (val) == 0) + memcpy (VALUE_CONTENTS_RAW (result), VALUE_CONTENTS (val) + offset, + TYPE_LENGTH (type) > TYPE_LENGTH (VALUE_TYPE (val)) + ? TYPE_LENGTH (VALUE_TYPE (val)) : TYPE_LENGTH (type)); + else + { + VALUE_ADDRESS (result) = + VALUE_ADDRESS (val) + VALUE_OFFSET (val) + offset; + VALUE_LAZY (result) = 1; + } + return result; + } +} + +static char* +cond_offset_host (valaddr, offset) + char* valaddr; + long offset; +{ + if (valaddr == NULL) + return NULL; + else + return valaddr + offset; +} + +static CORE_ADDR +cond_offset_target (address, offset) + CORE_ADDR address; + long offset; +{ + if (address == 0) + return 0; + else + return address + offset; +} + +/* Perform execute_command on the result of concatenating all + arguments up to NULL. */ +static void +do_command (const char* arg, ...) +{ + int len; + char* cmd; + const char* s; + va_list ap; + + va_start (ap, arg); + len = 0; + s = arg; + cmd = ""; + for (; s != NULL; s = va_arg (ap, const char*)) + { + char* cmd1; + len += strlen (s); + cmd1 = alloca (len+1); + strcpy (cmd1, cmd); + strcat (cmd1, s); + cmd = cmd1; + } + va_end (ap); + execute_command (cmd, 0); +} + + + /* Language Selection */ + +/* If the main program is in Ada, return language_ada, otherwise return LANG + (the main program is in Ada iif the adainit symbol is found). + + MAIN_PST is not used. */ + +enum language +ada_update_initial_language (lang, main_pst) + enum language lang; + struct partial_symtab* main_pst; +{ + if (lookup_minimal_symbol ("adainit", (const char*) NULL, + (struct objfile*) NULL) != NULL) + /* return language_ada; */ + /* FIXME: language_ada should be defined in defs.h */ + return language_unknown; + + return lang; +} + + + /* Symbols */ + +/* Table of Ada operators and their GNAT-mangled names. Last entry is pair + of NULLs. */ + +const struct ada_opname_map ada_opname_table[] = +{ + { "Oadd", "\"+\"", BINOP_ADD }, + { "Osubtract", "\"-\"", BINOP_SUB }, + { "Omultiply", "\"*\"", BINOP_MUL }, + { "Odivide", "\"/\"", BINOP_DIV }, + { "Omod", "\"mod\"", BINOP_MOD }, + { "Orem", "\"rem\"", BINOP_REM }, + { "Oexpon", "\"**\"", BINOP_EXP }, + { "Olt", "\"<\"", BINOP_LESS }, + { "Ole", "\"<=\"", BINOP_LEQ }, + { "Ogt", "\">\"", BINOP_GTR }, + { "Oge", "\">=\"", BINOP_GEQ }, + { "Oeq", "\"=\"", BINOP_EQUAL }, + { "One", "\"/=\"", BINOP_NOTEQUAL }, + { "Oand", "\"and\"", BINOP_BITWISE_AND }, + { "Oor", "\"or\"", BINOP_BITWISE_IOR }, + { "Oxor", "\"xor\"", BINOP_BITWISE_XOR }, + { "Oconcat", "\"&\"", BINOP_CONCAT }, + { "Oabs", "\"abs\"", UNOP_ABS }, + { "Onot", "\"not\"", UNOP_LOGICAL_NOT }, + { "Oadd", "\"+\"", UNOP_PLUS }, + { "Osubtract", "\"-\"", UNOP_NEG }, + { NULL, NULL } +}; + +/* True if STR should be suppressed in info listings. */ +static int +is_suppressed_name (str) + const char* str; +{ + if (STREQN (str, "_ada_", 5)) + str += 5; + if (str[0] == '_' || str[0] == '\000') + return 1; + else + { + const char* p; + const char* suffix = strstr (str, "___"); + if (suffix != NULL && suffix[3] != 'X') + return 1; + if (suffix == NULL) + suffix = str + strlen (str); + for (p = suffix-1; p != str; p -= 1) + if (isupper (*p)) + { + int i; + if (p[0] == 'X' && p[-1] != '_') + goto OK; + if (*p != 'O') + return 1; + for (i = 0; ada_opname_table[i].mangled != NULL; i += 1) + if (STREQN (ada_opname_table[i].mangled, p, + strlen (ada_opname_table[i].mangled))) + goto OK; + return 1; + OK: ; + } + return 0; + } +} + +/* The "mangled" form of DEMANGLED, according to GNAT conventions. + * The result is valid until the next call to ada_mangle. */ +char * +ada_mangle (demangled) + const char* demangled; +{ + static char* mangling_buffer = NULL; + static size_t mangling_buffer_size = 0; + const char* p; + int k; + + if (demangled == NULL) + return NULL; + + GROW_VECT (mangling_buffer, mangling_buffer_size, 2*strlen (demangled) + 10); + + k = 0; + for (p = demangled; *p != '\0'; p += 1) + { + if (*p == '.') + { + mangling_buffer[k] = mangling_buffer[k+1] = '_'; + k += 2; + } + else if (*p == '"') + { + const struct ada_opname_map* mapping; + + for (mapping = ada_opname_table; + mapping->mangled != NULL && + ! STREQN (mapping->demangled, p, strlen (mapping->demangled)); + p += 1) + ; + if (mapping->mangled == NULL) + error ("invalid Ada operator name: %s", p); + strcpy (mangling_buffer+k, mapping->mangled); + k += strlen (mapping->mangled); + break; + } + else + { + mangling_buffer[k] = *p; + k += 1; + } + } + + mangling_buffer[k] = '\0'; + return mangling_buffer; +} + +/* Return NAME folded to lower case, or, if surrounded by single + * quotes, unfolded, but with the quotes stripped away. Result good + * to next call. */ +char* +ada_fold_name (const char* name) +{ + static char* fold_buffer = NULL; + static size_t fold_buffer_size = 0; + + int len = strlen (name); + GROW_VECT (fold_buffer, fold_buffer_size, len+1); + + if (name[0] == '\'') + { + strncpy (fold_buffer, name+1, len-2); + fold_buffer[len-2] = '\000'; + } + else + { + int i; + for (i = 0; i <= len; i += 1) + fold_buffer[i] = tolower (name[i]); + } + + return fold_buffer; +} + +/* Demangle: + 1. Discard final __{DIGIT}+ or ${DIGIT}+ + 2. Convert other instances of embedded "__" to `.'. + 3. Discard leading _ada_. + 4. Convert operator names to the appropriate quoted symbols. + 5. Remove everything after first ___ if it is followed by + 'X'. + 6. Replace TK__ with __, and a trailing B or TKB with nothing. + 7. Put symbols that should be suppressed in <...> brackets. + 8. Remove trailing X[bn]* suffix (indicating names in package bodies). + The resulting string is valid until the next call of ada_demangle. + */ + +char * +ada_demangle (mangled) + const char* mangled; +{ + int i, j; + int len0; + const char* p; + char* demangled; + int at_start_name; + static char* demangling_buffer = NULL; + static size_t demangling_buffer_size = 0; + + if (STREQN (mangled, "_ada_", 5)) + mangled += 5; + + if (mangled[0] == '_' || mangled[0] == '<') + goto Suppress; + + p = strstr (mangled, "___"); + if (p == NULL) + len0 = strlen (mangled); + else + { + if (p[3] == 'X') + len0 = p - mangled; + else + goto Suppress; + } + if (len0 > 3 && STREQ (mangled + len0 - 3, "TKB")) + len0 -= 3; + if (len0 > 1 && STREQ (mangled + len0 - 1, "B")) + len0 -= 1; + + /* Make demangled big enough for possible expansion by operator name. */ + GROW_VECT (demangling_buffer, demangling_buffer_size, 2*len0+1); + demangled = demangling_buffer; + + if (isdigit (mangled[len0 - 1])) { + for (i = len0-2; i >= 0 && isdigit (mangled[i]); i -= 1) + ; + if (i > 1 && mangled[i] == '_' && mangled[i-1] == '_') + len0 = i - 1; + else if (mangled[i] == '$') + len0 = i; + } + + for (i = 0, j = 0; i < len0 && ! isalpha (mangled[i]); i += 1, j += 1) + demangled[j] = mangled[i]; + + at_start_name = 1; + while (i < len0) + { + if (at_start_name && mangled[i] == 'O') + { + int k; + for (k = 0; ada_opname_table[k].mangled != NULL; k += 1) + { + int op_len = strlen (ada_opname_table[k].mangled); + if (STREQN (ada_opname_table[k].mangled+1, mangled+i+1, op_len-1) + && ! isalnum (mangled[i + op_len])) + { + strcpy (demangled + j, ada_opname_table[k].demangled); + at_start_name = 0; + i += op_len; + j += strlen (ada_opname_table[k].demangled); + break; + } + } + if (ada_opname_table[k].mangled != NULL) + continue; + } + at_start_name = 0; + + if (i < len0-4 && STREQN (mangled+i, "TK__", 4)) + i += 2; + if (mangled[i] == 'X' && i != 0 && isalnum (mangled[i-1])) + { + do + i += 1; + while (i < len0 && (mangled[i] == 'b' || mangled[i] == 'n')); + if (i < len0) + goto Suppress; + } + else if (i < len0-2 && mangled[i] == '_' && mangled[i+1] == '_') + { + demangled[j] = '.'; + at_start_name = 1; + i += 2; j += 1; + } + else + { + demangled[j] = mangled[i]; + i += 1; j += 1; + } + } + demangled[j] = '\000'; + + for (i = 0; demangled[i] != '\0'; i += 1) + if (isupper (demangled[i]) || demangled[i] == ' ') + goto Suppress; + + return demangled; + +Suppress: + GROW_VECT (demangling_buffer, demangling_buffer_size, + strlen (mangled) + 3); + demangled = demangling_buffer; + if (mangled[0] == '<') + strcpy (demangled, mangled); + else + sprintf (demangled, "<%s>", mangled); + return demangled; + +} + +/* Returns non-zero iff SYM_NAME matches NAME, ignoring any trailing + * suffixes that encode debugging information or leading _ada_ on + * SYM_NAME (see is_name_suffix commentary for the debugging + * information that is ignored). If WILD, then NAME need only match a + * suffix of SYM_NAME minus the same suffixes. Also returns 0 if + * either argument is NULL. */ + +int +ada_match_name (sym_name, name, wild) + const char* sym_name; + const char* name; + int wild; +{ + if (sym_name == NULL || name == NULL) + return 0; + else if (wild) + return wild_match (name, strlen (name), sym_name); + else { + int len_name = strlen (name); + return (STREQN (sym_name, name, len_name) + && is_name_suffix (sym_name+len_name)) + || (STREQN (sym_name, "_ada_", 5) + && STREQN (sym_name+5, name, len_name) + && is_name_suffix (sym_name+len_name+5)); + } +} + +/* True (non-zero) iff in Ada mode, the symbol SYM should be + suppressed in info listings. */ + +int +ada_suppress_symbol_printing (sym) + struct symbol *sym; +{ + if (SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE) + return 1; + else + return is_suppressed_name (SYMBOL_NAME (sym)); +} + + + /* Arrays */ + +/* Names of MAX_ADA_DIMENS bounds in P_BOUNDS fields of + array descriptors. */ + +static char* bound_name[] = { + "LB0", "UB0", "LB1", "UB1", "LB2", "UB2", "LB3", "UB3", + "LB4", "UB4", "LB5", "UB5", "LB6", "UB6", "LB7", "UB7" +}; + +/* Maximum number of array dimensions we are prepared to handle. */ + +#define MAX_ADA_DIMENS (sizeof(bound_name) / (2*sizeof(char*))) + +/* Like modify_field, but allows bitpos > wordlength. */ + +static void +modify_general_field (addr, fieldval, bitpos, bitsize) + char *addr; + LONGEST fieldval; + int bitpos, bitsize; +{ + modify_field (addr + sizeof (LONGEST) * bitpos / (8 * sizeof (LONGEST)), + fieldval, bitpos % (8 * sizeof (LONGEST)), + bitsize); +} + + +/* The desc_* routines return primitive portions of array descriptors + (fat pointers). */ + +/* The descriptor or array type, if any, indicated by TYPE; removes + level of indirection, if needed. */ +static struct type* +desc_base_type (type) + struct type* type; +{ + if (type == NULL) + return NULL; + CHECK_TYPEDEF (type); + if (type != NULL && TYPE_CODE (type) == TYPE_CODE_PTR) + return check_typedef (TYPE_TARGET_TYPE (type)); + else + return type; +} + +/* True iff TYPE indicates a "thin" array pointer type. */ +static int +is_thin_pntr (struct type* type) +{ + return + is_suffix (ada_type_name (desc_base_type (type)), "___XUT") + || is_suffix (ada_type_name (desc_base_type (type)), "___XUT___XVE"); +} + +/* The descriptor type for thin pointer type TYPE. */ +static struct type* +thin_descriptor_type (struct type* type) +{ + struct type* base_type = desc_base_type (type); + if (base_type == NULL) + return NULL; + if (is_suffix (ada_type_name (base_type), "___XVE")) + return base_type; + else + { + struct type* alt_type = + ada_find_parallel_type (base_type, "___XVE"); + if (alt_type == NULL) + return base_type; + else + return alt_type; + } +} + +/* A pointer to the array data for thin-pointer value VAL. */ +static struct value* +thin_data_pntr (struct value* val) +{ + struct type* type = VALUE_TYPE (val); + if (TYPE_CODE (type) == TYPE_CODE_PTR) + return value_cast (desc_data_type (thin_descriptor_type (type)), + value_copy (val)); + else + return value_from_longest (desc_data_type (thin_descriptor_type (type)), + VALUE_ADDRESS (val) + VALUE_OFFSET (val)); +} + +/* True iff TYPE indicates a "thick" array pointer type. */ +static int +is_thick_pntr (struct type* type) +{ + type = desc_base_type (type); + return (type != NULL && TYPE_CODE (type) == TYPE_CODE_STRUCT + && lookup_struct_elt_type (type, "P_BOUNDS", 1) != NULL); +} + +/* If TYPE is the type of an array descriptor (fat or thin pointer) or a + pointer to one, the type of its bounds data; otherwise, NULL. */ +static struct type* +desc_bounds_type (type) + struct type* type; +{ + struct type* r; + + type = desc_base_type (type); + + if (type == NULL) + return NULL; + else if (is_thin_pntr (type)) + { + type = thin_descriptor_type (type); + if (type == NULL) + return NULL; + r = lookup_struct_elt_type (type, "BOUNDS", 1); + if (r != NULL) + return check_typedef (r); + } + else if (TYPE_CODE (type) == TYPE_CODE_STRUCT) + { + r = lookup_struct_elt_type (type, "P_BOUNDS", 1); + if (r != NULL) + return check_typedef (TYPE_TARGET_TYPE (check_typedef (r))); + } + return NULL; +} + +/* If ARR is an array descriptor (fat or thin pointer), or pointer to + one, a pointer to its bounds data. Otherwise NULL. */ +static struct value* +desc_bounds (arr) + struct value* arr; +{ + struct type* type = check_typedef (VALUE_TYPE (arr)); + if (is_thin_pntr (type)) + { + struct type* bounds_type = desc_bounds_type (thin_descriptor_type (type)); + LONGEST addr; + + if (desc_bounds_type == NULL) + error ("Bad GNAT array descriptor"); + + /* NOTE: The following calculation is not really kosher, but + since desc_type is an XVE-encoded type (and shouldn't be), + the correct calculation is a real pain. FIXME (and fix GCC). */ + if (TYPE_CODE (type) == TYPE_CODE_PTR) + addr = value_as_long (arr); + else + addr = VALUE_ADDRESS (arr) + VALUE_OFFSET (arr); + + return + value_from_longest (lookup_pointer_type (bounds_type), + addr - TYPE_LENGTH (bounds_type)); + } + + else if (is_thick_pntr (type)) + return value_struct_elt (&arr, NULL, "P_BOUNDS", NULL, + "Bad GNAT array descriptor"); + else + return NULL; +} + +/* If TYPE is the type of an array-descriptor (fat pointer), the bit + position of the field containing the address of the bounds data. */ +static int +fat_pntr_bounds_bitpos (type) + struct type* type; +{ + return TYPE_FIELD_BITPOS (desc_base_type (type), 1); +} + +/* If TYPE is the type of an array-descriptor (fat pointer), the bit + size of the field containing the address of the bounds data. */ +static int +fat_pntr_bounds_bitsize (type) + struct type* type; +{ + type = desc_base_type (type); + + if (TYPE_FIELD_BITSIZE (type, 1) > 0) + return TYPE_FIELD_BITSIZE (type, 1); + else + return 8 * TYPE_LENGTH (check_typedef (TYPE_FIELD_TYPE (type, 1))); +} + +/* If TYPE is the type of an array descriptor (fat or thin pointer) or a + pointer to one, the type of its array data (a + pointer-to-array-with-no-bounds type); otherwise, NULL. Use + ada_type_of_array to get an array type with bounds data. */ +static struct type* +desc_data_type (type) + struct type* type; +{ + type = desc_base_type (type); + + /* NOTE: The following is bogus; see comment in desc_bounds. */ + if (is_thin_pntr (type)) + return lookup_pointer_type + (desc_base_type (TYPE_FIELD_TYPE (thin_descriptor_type (type),1))); + else if (is_thick_pntr (type)) + return lookup_struct_elt_type (type, "P_ARRAY", 1); + else + return NULL; +} + +/* If ARR is an array descriptor (fat or thin pointer), a pointer to + its array data. */ +static struct value* +desc_data (arr) + struct value* arr; +{ + struct type* type = VALUE_TYPE (arr); + if (is_thin_pntr (type)) + return thin_data_pntr (arr); + else if (is_thick_pntr (type)) + return value_struct_elt (&arr, NULL, "P_ARRAY", NULL, + "Bad GNAT array descriptor"); + else + return NULL; +} + + +/* If TYPE is the type of an array-descriptor (fat pointer), the bit + position of the field containing the address of the data. */ +static int +fat_pntr_data_bitpos (type) + struct type* type; +{ + return TYPE_FIELD_BITPOS (desc_base_type (type), 0); +} + +/* If TYPE is the type of an array-descriptor (fat pointer), the bit + size of the field containing the address of the data. */ +static int +fat_pntr_data_bitsize (type) + struct type* type; +{ + type = desc_base_type (type); + + if (TYPE_FIELD_BITSIZE (type, 0) > 0) + return TYPE_FIELD_BITSIZE (type, 0); + else + return TARGET_CHAR_BIT * TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)); +} + +/* If BOUNDS is an array-bounds structure (or pointer to one), return + the Ith lower bound stored in it, if WHICH is 0, and the Ith upper + bound, if WHICH is 1. The first bound is I=1. */ +static struct value* +desc_one_bound (bounds, i, which) + struct value* bounds; + int i; + int which; +{ + return value_struct_elt (&bounds, NULL, bound_name[2*i+which-2], NULL, + "Bad GNAT array descriptor bounds"); +} + +/* If BOUNDS is an array-bounds structure type, return the bit position + of the Ith lower bound stored in it, if WHICH is 0, and the Ith upper + bound, if WHICH is 1. The first bound is I=1. */ +static int +desc_bound_bitpos (type, i, which) + struct type* type; + int i; + int which; +{ + return TYPE_FIELD_BITPOS (desc_base_type (type), 2*i+which-2); +} + +/* If BOUNDS is an array-bounds structure type, return the bit field size + of the Ith lower bound stored in it, if WHICH is 0, and the Ith upper + bound, if WHICH is 1. The first bound is I=1. */ +static int +desc_bound_bitsize (type, i, which) + struct type* type; + int i; + int which; +{ + type = desc_base_type (type); + + if (TYPE_FIELD_BITSIZE (type, 2*i+which-2) > 0) + return TYPE_FIELD_BITSIZE (type, 2*i+which-2); + else + return 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (type, 2*i+which-2)); +} + +/* If TYPE is the type of an array-bounds structure, the type of its + Ith bound (numbering from 1). Otherwise, NULL. */ +static struct type* +desc_index_type (type, i) + struct type* type; + int i; +{ + type = desc_base_type (type); + + if (TYPE_CODE (type) == TYPE_CODE_STRUCT) + return lookup_struct_elt_type (type, bound_name[2*i-2], 1); + else + return NULL; +} + +/* The number of index positions in the array-bounds type TYPE. 0 + if TYPE is NULL. */ +static int +desc_arity (type) + struct type* type; +{ + type = desc_base_type (type); + + if (type != NULL) + return TYPE_NFIELDS (type) / 2; + return 0; +} + + +/* Non-zero iff type is a simple array type (or pointer to one). */ +int +ada_is_simple_array (type) + struct type* type; +{ + if (type == NULL) + return 0; + CHECK_TYPEDEF (type); + return (TYPE_CODE (type) == TYPE_CODE_ARRAY + || (TYPE_CODE (type) == TYPE_CODE_PTR + && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_ARRAY)); +} + +/* Non-zero iff type belongs to a GNAT array descriptor. */ +int +ada_is_array_descriptor (type) + struct type* type; +{ + struct type* data_type = desc_data_type (type); + + if (type == NULL) + return 0; + CHECK_TYPEDEF (type); + return + data_type != NULL + && ((TYPE_CODE (data_type) == TYPE_CODE_PTR + && TYPE_TARGET_TYPE (data_type) != NULL + && TYPE_CODE (TYPE_TARGET_TYPE (data_type)) == TYPE_CODE_ARRAY) + || + TYPE_CODE (data_type) == TYPE_CODE_ARRAY) + && desc_arity (desc_bounds_type (type)) > 0; +} + +/* Non-zero iff type is a partially mal-formed GNAT array + descriptor. (FIXME: This is to compensate for some problems with + debugging output from GNAT. Re-examine periodically to see if it + is still needed. */ +int +ada_is_bogus_array_descriptor (type) + struct type *type; +{ + return + type != NULL + && TYPE_CODE (type) == TYPE_CODE_STRUCT + && (lookup_struct_elt_type (type, "P_BOUNDS", 1) != NULL + || lookup_struct_elt_type (type, "P_ARRAY", 1) != NULL) + && ! ada_is_array_descriptor (type); +} + + +/* If ARR has a record type in the form of a standard GNAT array descriptor, + (fat pointer) returns the type of the array data described---specifically, + a pointer-to-array type. If BOUNDS is non-zero, the bounds data are filled + in from the descriptor; otherwise, they are left unspecified. If + the ARR denotes a null array descriptor and BOUNDS is non-zero, + returns NULL. The result is simply the type of ARR if ARR is not + a descriptor. */ +struct type* +ada_type_of_array (arr, bounds) + struct value* arr; + int bounds; +{ + if (ada_is_packed_array_type (VALUE_TYPE (arr))) + return decode_packed_array_type (VALUE_TYPE (arr)); + + if (! ada_is_array_descriptor (VALUE_TYPE (arr))) + return VALUE_TYPE (arr); + + if (! bounds) + return check_typedef (TYPE_TARGET_TYPE (desc_data_type (VALUE_TYPE (arr)))); + else + { + struct type* elt_type; + int arity; + struct value* descriptor; + struct objfile *objf = TYPE_OBJFILE (VALUE_TYPE (arr)); + + elt_type = ada_array_element_type (VALUE_TYPE (arr), -1); + arity = ada_array_arity (VALUE_TYPE (arr)); + + if (elt_type == NULL || arity == 0) + return check_typedef (VALUE_TYPE (arr)); + + descriptor = desc_bounds (arr); + if (value_as_long (descriptor) == 0) + return NULL; + while (arity > 0) { + struct type* range_type = alloc_type (objf); + struct type* array_type = alloc_type (objf); + struct value* low = desc_one_bound (descriptor, arity, 0); + struct value* high = desc_one_bound (descriptor, arity, 1); + arity -= 1; + + create_range_type (range_type, VALUE_TYPE (low), + (int) value_as_long (low), + (int) value_as_long (high)); + elt_type = create_array_type (array_type, elt_type, range_type); + } + + return lookup_pointer_type (elt_type); + } +} + +/* If ARR does not represent an array, returns ARR unchanged. + Otherwise, returns either a standard GDB array with bounds set + appropriately or, if ARR is a non-null fat pointer, a pointer to a standard + GDB array. Returns NULL if ARR is a null fat pointer. */ +struct value* +ada_coerce_to_simple_array_ptr (arr) + struct value* arr; +{ + if (ada_is_array_descriptor (VALUE_TYPE (arr))) + { + struct type* arrType = ada_type_of_array (arr, 1); + if (arrType == NULL) + return NULL; + return value_cast (arrType, value_copy (desc_data (arr))); + } + else if (ada_is_packed_array_type (VALUE_TYPE (arr))) + return decode_packed_array (arr); + else + return arr; +} + +/* If ARR does not represent an array, returns ARR unchanged. + Otherwise, returns a standard GDB array describing ARR (which may + be ARR itself if it already is in the proper form). */ +struct value* +ada_coerce_to_simple_array (arr) + struct value* arr; +{ + if (ada_is_array_descriptor (VALUE_TYPE (arr))) + { + struct value* arrVal = ada_coerce_to_simple_array_ptr (arr); + if (arrVal == NULL) + error ("Bounds unavailable for null array pointer."); + return value_ind (arrVal); + } + else if (ada_is_packed_array_type (VALUE_TYPE (arr))) + return decode_packed_array (arr); + else + return arr; +} + +/* If TYPE represents a GNAT array type, return it translated to an + ordinary GDB array type (possibly with BITSIZE fields indicating + packing). For other types, is the identity. */ +struct type* +ada_coerce_to_simple_array_type (type) + struct type* type; +{ + struct value* mark = value_mark (); + struct value* dummy = value_from_longest (builtin_type_long, 0); + struct type* result; + VALUE_TYPE (dummy) = type; + result = ada_type_of_array (dummy, 0); + value_free_to_mark (dummy); + return result; +} + +/* Non-zero iff TYPE represents a standard GNAT packed-array type. */ +int +ada_is_packed_array_type (type) + struct type* type; +{ + if (type == NULL) + return 0; + CHECK_TYPEDEF (type); + return + ada_type_name (type) != NULL + && strstr (ada_type_name (type), "___XP") != NULL; +} + +/* Given that TYPE is a standard GDB array type with all bounds filled + in, and that the element size of its ultimate scalar constituents + (that is, either its elements, or, if it is an array of arrays, its + elements' elements, etc.) is *ELT_BITS, return an identical type, + but with the bit sizes of its elements (and those of any + constituent arrays) recorded in the BITSIZE components of its + TYPE_FIELD_BITSIZE values, and with *ELT_BITS set to its total size + in bits. */ +static struct type* +packed_array_type (type, elt_bits) + struct type* type; + long* elt_bits; +{ + struct type* new_elt_type; + struct type* new_type; + LONGEST low_bound, high_bound; + + CHECK_TYPEDEF (type); + if (TYPE_CODE (type) != TYPE_CODE_ARRAY) + return type; + + new_type = alloc_type (TYPE_OBJFILE (type)); + new_elt_type = packed_array_type (check_typedef (TYPE_TARGET_TYPE (type)), + elt_bits); + create_array_type (new_type, new_elt_type, TYPE_FIELD_TYPE (type, 0)); + TYPE_FIELD_BITSIZE (new_type, 0) = *elt_bits; + TYPE_NAME (new_type) = ada_type_name (type); + + if (get_discrete_bounds (TYPE_FIELD_TYPE (type, 0), + &low_bound, &high_bound) < 0) + low_bound = high_bound = 0; + if (high_bound < low_bound) + *elt_bits = TYPE_LENGTH (new_type) = 0; + else + { + *elt_bits *= (high_bound - low_bound + 1); + TYPE_LENGTH (new_type) = + (*elt_bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT; + } + + /* TYPE_FLAGS (new_type) |= TYPE_FLAG_FIXED_INSTANCE; */ + /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */ + return new_type; +} + +/* The array type encoded by TYPE, where ada_is_packed_array_type (TYPE). + */ +static struct type* +decode_packed_array_type (type) + struct type* type; +{ + struct symbol** syms; + struct block** blocks; + const char* raw_name = ada_type_name (check_typedef (type)); + char* name = (char*) alloca (strlen (raw_name) + 1); + char* tail = strstr (raw_name, "___XP"); + struct type* shadow_type; + long bits; + int i, n; + + memcpy (name, raw_name, tail - raw_name); + name[tail - raw_name] = '\000'; + + /* NOTE: Use ada_lookup_symbol_list because of bug in some versions + * of gcc (Solaris, e.g.). FIXME when compiler is fixed. */ + n = ada_lookup_symbol_list (name, get_selected_block (NULL), + VAR_NAMESPACE, &syms, &blocks); + for (i = 0; i < n; i += 1) + if (syms[i] != NULL && SYMBOL_CLASS (syms[i]) == LOC_TYPEDEF + && STREQ (name, ada_type_name (SYMBOL_TYPE (syms[i])))) + break; + if (i >= n) + { + warning ("could not find bounds information on packed array"); + return NULL; + } + shadow_type = SYMBOL_TYPE (syms[i]); + + if (TYPE_CODE (shadow_type) != TYPE_CODE_ARRAY) + { + warning ("could not understand bounds information on packed array"); + return NULL; + } + + if (sscanf (tail + sizeof ("___XP") - 1, "%ld", &bits) != 1) + { + warning ("could not understand bit size information on packed array"); + return NULL; + } + + return packed_array_type (shadow_type, &bits); +} + +/* Given that ARR is a struct value* indicating a GNAT packed array, + returns a simple array that denotes that array. Its type is a + standard GDB array type except that the BITSIZEs of the array + target types are set to the number of bits in each element, and the + type length is set appropriately. */ + +static struct value* +decode_packed_array (arr) + struct value* arr; +{ + struct type* type = decode_packed_array_type (VALUE_TYPE (arr)); + + if (type == NULL) + { + error ("can't unpack array"); + return NULL; + } + else + return coerce_unspec_val_to_type (arr, 0, type); +} + + +/* The value of the element of packed array ARR at the ARITY indices + given in IND. ARR must be a simple array. */ + +static struct value* +value_subscript_packed (arr, arity, ind) + struct value* arr; + int arity; + struct value** ind; +{ + int i; + int bits, elt_off, bit_off; + long elt_total_bit_offset; + struct type* elt_type; + struct value* v; + + bits = 0; + elt_total_bit_offset = 0; + elt_type = check_typedef (VALUE_TYPE (arr)); + for (i = 0; i < arity; i += 1) + { + if (TYPE_CODE (elt_type) != TYPE_CODE_ARRAY + || TYPE_FIELD_BITSIZE (elt_type, 0) == 0) + error ("attempt to do packed indexing of something other than a packed array"); + else + { + struct type *range_type = TYPE_INDEX_TYPE (elt_type); + LONGEST lowerbound, upperbound; + LONGEST idx; + + if (get_discrete_bounds (range_type, &lowerbound, + &upperbound) < 0) + { + warning ("don't know bounds of array"); + lowerbound = upperbound = 0; + } + + idx = value_as_long (value_pos_atr (ind[i])); + if (idx < lowerbound || idx > upperbound) + warning ("packed array index %ld out of bounds", (long) idx); + bits = TYPE_FIELD_BITSIZE (elt_type, 0); + elt_total_bit_offset += (idx - lowerbound) * bits; + elt_type = check_typedef (TYPE_TARGET_TYPE (elt_type)); + } + } + elt_off = elt_total_bit_offset / HOST_CHAR_BIT; + bit_off = elt_total_bit_offset % HOST_CHAR_BIT; + + v = ada_value_primitive_packed_val (arr, NULL, elt_off, bit_off, + bits, elt_type); + if (VALUE_LVAL (arr) == lval_internalvar) + VALUE_LVAL (v) = lval_internalvar_component; + else + VALUE_LVAL (v) = VALUE_LVAL (arr); + return v; +} + +/* Non-zero iff TYPE includes negative integer values. */ + +static int +has_negatives (type) + struct type* type; +{ + switch (TYPE_CODE (type)) { + default: + return 0; + case TYPE_CODE_INT: + return ! TYPE_UNSIGNED (type); + case TYPE_CODE_RANGE: + return TYPE_LOW_BOUND (type) < 0; + } +} + + +/* Create a new value of type TYPE from the contents of OBJ starting + at byte OFFSET, and bit offset BIT_OFFSET within that byte, + proceeding for BIT_SIZE bits. If OBJ is an lval in memory, then + assigning through the result will set the field fetched from. OBJ + may also be NULL, in which case, VALADDR+OFFSET must address the + start of storage containing the packed value. The value returned + in this case is never an lval. + Assumes 0 <= BIT_OFFSET < HOST_CHAR_BIT. */ + +struct value* +ada_value_primitive_packed_val (obj, valaddr, offset, bit_offset, + bit_size, type) + struct value* obj; + char* valaddr; + long offset; + int bit_offset; + int bit_size; + struct type* type; +{ + struct value* v; + int src, /* Index into the source area. */ + targ, /* Index into the target area. */ + i, + srcBitsLeft, /* Number of source bits left to move. */ + nsrc, ntarg, /* Number of source and target bytes. */ + unusedLS, /* Number of bits in next significant + * byte of source that are unused. */ + accumSize; /* Number of meaningful bits in accum */ + unsigned char* bytes; /* First byte containing data to unpack. */ + unsigned char* unpacked; + unsigned long accum; /* Staging area for bits being transferred */ + unsigned char sign; + int len = (bit_size + bit_offset + HOST_CHAR_BIT - 1) / 8; + /* Transmit bytes from least to most significant; delta is the + * direction the indices move. */ + int delta = BITS_BIG_ENDIAN ? -1 : 1; + + CHECK_TYPEDEF (type); + + if (obj == NULL) + { + v = allocate_value (type); + bytes = (unsigned char*) (valaddr + offset); + } + else if (VALUE_LAZY (obj)) + { + v = value_at (type, + VALUE_ADDRESS (obj) + VALUE_OFFSET (obj) + offset, NULL); + bytes = (unsigned char*) alloca (len); + read_memory (VALUE_ADDRESS (v), bytes, len); + } + else + { + v = allocate_value (type); + bytes = (unsigned char*) VALUE_CONTENTS (obj) + offset; + } + + if (obj != NULL) + { + VALUE_LVAL (v) = VALUE_LVAL (obj); + if (VALUE_LVAL (obj) == lval_internalvar) + VALUE_LVAL (v) = lval_internalvar_component; + VALUE_ADDRESS (v) = VALUE_ADDRESS (obj) + VALUE_OFFSET (obj) + offset; + VALUE_BITPOS (v) = bit_offset + VALUE_BITPOS (obj); + VALUE_BITSIZE (v) = bit_size; + if (VALUE_BITPOS (v) >= HOST_CHAR_BIT) + { + VALUE_ADDRESS (v) += 1; + VALUE_BITPOS (v) -= HOST_CHAR_BIT; + } + } + else + VALUE_BITSIZE (v) = bit_size; + unpacked = (unsigned char*) VALUE_CONTENTS (v); + + srcBitsLeft = bit_size; + nsrc = len; + ntarg = TYPE_LENGTH (type); + sign = 0; + if (bit_size == 0) + { + memset (unpacked, 0, TYPE_LENGTH (type)); + return v; + } + else if (BITS_BIG_ENDIAN) + { + src = len-1; + if (has_negatives (type) && + ((bytes[0] << bit_offset) & (1 << (HOST_CHAR_BIT-1)))) + sign = ~0; + + unusedLS = + (HOST_CHAR_BIT - (bit_size + bit_offset) % HOST_CHAR_BIT) + % HOST_CHAR_BIT; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + case TYPE_CODE_UNION: + case TYPE_CODE_STRUCT: + /* Non-scalar values must be aligned at a byte boundary. */ + accumSize = + (HOST_CHAR_BIT - bit_size % HOST_CHAR_BIT) % HOST_CHAR_BIT; + /* And are placed at the beginning (most-significant) bytes + * of the target. */ + targ = src; + break; + default: + accumSize = 0; + targ = TYPE_LENGTH (type) - 1; + break; + } + } + else + { + int sign_bit_offset = (bit_size + bit_offset - 1) % 8; + + src = targ = 0; + unusedLS = bit_offset; + accumSize = 0; + + if (has_negatives (type) && (bytes[len-1] & (1 << sign_bit_offset))) + sign = ~0; + } + + accum = 0; + while (nsrc > 0) + { + /* Mask for removing bits of the next source byte that are not + * part of the value. */ + unsigned int unusedMSMask = + (1 << (srcBitsLeft >= HOST_CHAR_BIT ? HOST_CHAR_BIT : srcBitsLeft))-1; + /* Sign-extend bits for this byte. */ + unsigned int signMask = sign & ~unusedMSMask; + accum |= + (((bytes[src] >> unusedLS) & unusedMSMask) | signMask) << accumSize; + accumSize += HOST_CHAR_BIT - unusedLS; + if (accumSize >= HOST_CHAR_BIT) + { + unpacked[targ] = accum & ~(~0L << HOST_CHAR_BIT); + accumSize -= HOST_CHAR_BIT; + accum >>= HOST_CHAR_BIT; + ntarg -= 1; + targ += delta; + } + srcBitsLeft -= HOST_CHAR_BIT - unusedLS; + unusedLS = 0; + nsrc -= 1; + src += delta; + } + while (ntarg > 0) + { + accum |= sign << accumSize; + unpacked[targ] = accum & ~(~0L << HOST_CHAR_BIT); + accumSize -= HOST_CHAR_BIT; + accum >>= HOST_CHAR_BIT; + ntarg -= 1; + targ += delta; + } + + return v; +} + +/* Move N bits from SOURCE, starting at bit offset SRC_OFFSET to + TARGET, starting at bit offset TARG_OFFSET. SOURCE and TARGET must + not overlap. */ +static void +move_bits (char* target, int targ_offset, char* source, int src_offset, int n) +{ + unsigned int accum, mask; + int accum_bits, chunk_size; + + target += targ_offset / HOST_CHAR_BIT; + targ_offset %= HOST_CHAR_BIT; + source += src_offset / HOST_CHAR_BIT; + src_offset %= HOST_CHAR_BIT; + if (BITS_BIG_ENDIAN) + { + accum = (unsigned char) *source; + source += 1; + accum_bits = HOST_CHAR_BIT - src_offset; + + while (n > 0) + { + int unused_right; + accum = (accum << HOST_CHAR_BIT) + (unsigned char) *source; + accum_bits += HOST_CHAR_BIT; + source += 1; + chunk_size = HOST_CHAR_BIT - targ_offset; + if (chunk_size > n) + chunk_size = n; + unused_right = HOST_CHAR_BIT - (chunk_size + targ_offset); + mask = ((1 << chunk_size) - 1) << unused_right; + *target = + (*target & ~mask) + | ((accum >> (accum_bits - chunk_size - unused_right)) & mask); + n -= chunk_size; + accum_bits -= chunk_size; + target += 1; + targ_offset = 0; + } + } + else + { + accum = (unsigned char) *source >> src_offset; + source += 1; + accum_bits = HOST_CHAR_BIT - src_offset; + + while (n > 0) + { + accum = accum + ((unsigned char) *source << accum_bits); + accum_bits += HOST_CHAR_BIT; + source += 1; + chunk_size = HOST_CHAR_BIT - targ_offset; + if (chunk_size > n) + chunk_size = n; + mask = ((1 << chunk_size) - 1) << targ_offset; + *target = + (*target & ~mask) | ((accum << targ_offset) & mask); + n -= chunk_size; + accum_bits -= chunk_size; + accum >>= chunk_size; + target += 1; + targ_offset = 0; + } + } +} + + +/* Store the contents of FROMVAL into the location of TOVAL. + Return a new value with the location of TOVAL and contents of + FROMVAL. Handles assignment into packed fields that have + floating-point or non-scalar types. */ + +static struct value* +ada_value_assign (struct value* toval, struct value* fromval) +{ + struct type* type = VALUE_TYPE (toval); + int bits = VALUE_BITSIZE (toval); + + if (!toval->modifiable) + error ("Left operand of assignment is not a modifiable lvalue."); + + COERCE_REF (toval); + + if (VALUE_LVAL (toval) == lval_memory + && bits > 0 + && (TYPE_CODE (type) == TYPE_CODE_FLT + || TYPE_CODE (type) == TYPE_CODE_STRUCT)) + { + int len = + (VALUE_BITPOS (toval) + bits + HOST_CHAR_BIT - 1) + / HOST_CHAR_BIT; + char* buffer = (char*) alloca (len); + struct value* val; + + if (TYPE_CODE (type) == TYPE_CODE_FLT) + fromval = value_cast (type, fromval); + + read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), buffer, len); + if (BITS_BIG_ENDIAN) + move_bits (buffer, VALUE_BITPOS (toval), + VALUE_CONTENTS (fromval), + TYPE_LENGTH (VALUE_TYPE (fromval)) * TARGET_CHAR_BIT - bits, + bits); + else + move_bits (buffer, VALUE_BITPOS (toval), VALUE_CONTENTS (fromval), + 0, bits); + write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), buffer, len); + + val = value_copy (toval); + memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS (fromval), + TYPE_LENGTH (type)); + VALUE_TYPE (val) = type; + + return val; + } + + return value_assign (toval, fromval); +} + + +/* The value of the element of array ARR at the ARITY indices given in IND. + ARR may be either a simple array, GNAT array descriptor, or pointer + thereto. */ + +struct value* +ada_value_subscript (arr, arity, ind) + struct value* arr; + int arity; + struct value** ind; +{ + int k; + struct value* elt; + struct type* elt_type; + + elt = ada_coerce_to_simple_array (arr); + + elt_type = check_typedef (VALUE_TYPE (elt)); + if (TYPE_CODE (elt_type) == TYPE_CODE_ARRAY + && TYPE_FIELD_BITSIZE (elt_type, 0) > 0) + return value_subscript_packed (elt, arity, ind); + + for (k = 0; k < arity; k += 1) + { + if (TYPE_CODE (elt_type) != TYPE_CODE_ARRAY) + error("too many subscripts (%d expected)", k); + elt = value_subscript (elt, value_pos_atr (ind[k])); + } + return elt; +} + +/* Assuming ARR is a pointer to a standard GDB array of type TYPE, the + value of the element of *ARR at the ARITY indices given in + IND. Does not read the entire array into memory. */ + +struct value* +ada_value_ptr_subscript (arr, type, arity, ind) + struct value* arr; + struct type* type; + int arity; + struct value** ind; +{ + int k; + + for (k = 0; k < arity; k += 1) + { + LONGEST lwb, upb; + struct value* idx; + + if (TYPE_CODE (type) != TYPE_CODE_ARRAY) + error("too many subscripts (%d expected)", k); + arr = value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (type)), + value_copy (arr)); + get_discrete_bounds (TYPE_INDEX_TYPE (type), &lwb, &upb); + if (lwb == 0) + idx = ind[k]; + else + idx = value_sub (ind[k], value_from_longest (builtin_type_int, lwb)); + arr = value_add (arr, idx); + type = TYPE_TARGET_TYPE (type); + } + + return value_ind (arr); +} + +/* If type is a record type in the form of a standard GNAT array + descriptor, returns the number of dimensions for type. If arr is a + simple array, returns the number of "array of"s that prefix its + type designation. Otherwise, returns 0. */ + +int +ada_array_arity (type) + struct type* type; +{ + int arity; + + if (type == NULL) + return 0; + + type = desc_base_type (type); + + arity = 0; + if (TYPE_CODE (type) == TYPE_CODE_STRUCT) + return desc_arity (desc_bounds_type (type)); + else + while (TYPE_CODE (type) == TYPE_CODE_ARRAY) + { + arity += 1; + type = check_typedef (TYPE_TARGET_TYPE (type)); + } + + return arity; +} + +/* If TYPE is a record type in the form of a standard GNAT array + descriptor or a simple array type, returns the element type for + TYPE after indexing by NINDICES indices, or by all indices if + NINDICES is -1. Otherwise, returns NULL. */ + +struct type* +ada_array_element_type (type, nindices) + struct type* type; + int nindices; +{ + type = desc_base_type (type); + + if (TYPE_CODE (type) == TYPE_CODE_STRUCT) + { + int k; + struct type* p_array_type; + + p_array_type = desc_data_type (type); + + k = ada_array_arity (type); + if (k == 0) + return NULL; + + /* Initially p_array_type = elt_type(*)[]...(k times)...[] */ + if (nindices >= 0 && k > nindices) + k = nindices; + p_array_type = TYPE_TARGET_TYPE (p_array_type); + while (k > 0 && p_array_type != NULL) + { + p_array_type = check_typedef (TYPE_TARGET_TYPE (p_array_type)); + k -= 1; + } + return p_array_type; + } + else if (TYPE_CODE (type) == TYPE_CODE_ARRAY) + { + while (nindices != 0 && TYPE_CODE (type) == TYPE_CODE_ARRAY) + { + type = TYPE_TARGET_TYPE (type); + nindices -= 1; + } + return type; + } + + return NULL; +} + +/* The type of nth index in arrays of given type (n numbering from 1). Does + not examine memory. */ + +struct type* +ada_index_type (type, n) + struct type* type; + int n; +{ + type = desc_base_type (type); + + if (n > ada_array_arity (type)) + return NULL; + + if (ada_is_simple_array (type)) + { + int i; + + for (i = 1; i < n; i += 1) + type = TYPE_TARGET_TYPE (type); + + return TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, 0)); + } + else + return desc_index_type (desc_bounds_type (type), n); +} + +/* Given that arr is an array type, returns the lower bound of the + Nth index (numbering from 1) if WHICH is 0, and the upper bound if + WHICH is 1. This returns bounds 0 .. -1 if ARR_TYPE is an + array-descriptor type. If TYPEP is non-null, *TYPEP is set to the + bounds type. It works for other arrays with bounds supplied by + run-time quantities other than discriminants. */ + +LONGEST +ada_array_bound_from_type (arr_type, n, which, typep) + struct type* arr_type; + int n; + int which; + struct type** typep; +{ + struct type* type; + struct type* index_type_desc; + + if (ada_is_packed_array_type (arr_type)) + arr_type = decode_packed_array_type (arr_type); + + if (arr_type == NULL || ! ada_is_simple_array (arr_type)) + { + if (typep != NULL) + *typep = builtin_type_int; + return (LONGEST) -which; + } + + if (TYPE_CODE (arr_type) == TYPE_CODE_PTR) + type = TYPE_TARGET_TYPE (arr_type); + else + type = arr_type; + + index_type_desc = ada_find_parallel_type (type, "___XA"); + if (index_type_desc == NULL) + { + struct type* range_type; + struct type* index_type; + + while (n > 1) + { + type = TYPE_TARGET_TYPE (type); + n -= 1; + } + + range_type = TYPE_INDEX_TYPE (type); + index_type = TYPE_TARGET_TYPE (range_type); + if (TYPE_CODE (index_type) == TYPE_CODE_UNDEF) + index_type = builtin_type_long; + if (typep != NULL) + *typep = index_type; + return + (LONGEST) (which == 0 + ? TYPE_LOW_BOUND (range_type) + : TYPE_HIGH_BOUND (range_type)); + } + else + { + struct type* index_type = + to_fixed_range_type (TYPE_FIELD_NAME (index_type_desc, n-1), + NULL, TYPE_OBJFILE (arr_type)); + if (typep != NULL) + *typep = TYPE_TARGET_TYPE (index_type); + return + (LONGEST) (which == 0 + ? TYPE_LOW_BOUND (index_type) + : TYPE_HIGH_BOUND (index_type)); + } +} + +/* Given that arr is an array value, returns the lower bound of the + nth index (numbering from 1) if which is 0, and the upper bound if + which is 1. This routine will also work for arrays with bounds + supplied by run-time quantities other than discriminants. */ + +struct value* +ada_array_bound (arr, n, which) + struct value* arr; + int n; + int which; +{ + struct type* arr_type = VALUE_TYPE (arr); + + if (ada_is_packed_array_type (arr_type)) + return ada_array_bound (decode_packed_array (arr), n, which); + else if (ada_is_simple_array (arr_type)) + { + struct type* type; + LONGEST v = ada_array_bound_from_type (arr_type, n, which, &type); + return value_from_longest (type, v); + } + else + return desc_one_bound (desc_bounds (arr), n, which); +} + +/* Given that arr is an array value, returns the length of the + nth index. This routine will also work for arrays with bounds + supplied by run-time quantities other than discriminants. Does not + work for arrays indexed by enumeration types with representation + clauses at the moment. */ + +struct value* +ada_array_length (arr, n) + struct value* arr; + int n; +{ + struct type* arr_type = check_typedef (VALUE_TYPE (arr)); + struct type* index_type_desc; + + if (ada_is_packed_array_type (arr_type)) + return ada_array_length (decode_packed_array (arr), n); + + if (ada_is_simple_array (arr_type)) + { + struct type* type; + LONGEST v = + ada_array_bound_from_type (arr_type, n, 1, &type) - + ada_array_bound_from_type (arr_type, n, 0, NULL) + 1; + return value_from_longest (type, v); + } + else + return + value_from_longest (builtin_type_ada_int, + value_as_long (desc_one_bound (desc_bounds (arr), + n, 1)) + - value_as_long (desc_one_bound (desc_bounds (arr), + n, 0)) + + 1); +} + + + /* Name resolution */ + +/* The "demangled" name for the user-definable Ada operator corresponding + to op. */ + +static const char* +ada_op_name (op) + enum exp_opcode op; +{ + int i; + + for (i = 0; ada_opname_table[i].mangled != NULL; i += 1) + { + if (ada_opname_table[i].op == op) + return ada_opname_table[i].demangled; + } + error ("Could not find operator name for opcode"); +} + + +/* Same as evaluate_type (*EXP), but resolves ambiguous symbol + references (OP_UNRESOLVED_VALUES) and converts operators that are + user-defined into appropriate function calls. If CONTEXT_TYPE is + non-null, it provides a preferred result type [at the moment, only + type void has any effect---causing procedures to be preferred over + functions in calls]. A null CONTEXT_TYPE indicates that a non-void + return type is preferred. The variable unresolved_names contains a list + of character strings referenced by expout that should be freed. + May change (expand) *EXP. */ + +void +ada_resolve (expp, context_type) + struct expression** expp; + struct type* context_type; +{ + int pc; + pc = 0; + ada_resolve_subexp (expp, &pc, 1, context_type); +} + +/* Resolve the operator of the subexpression beginning at + position *POS of *EXPP. "Resolving" consists of replacing + OP_UNRESOLVED_VALUE with an appropriate OP_VAR_VALUE, replacing + built-in operators with function calls to user-defined operators, + where appropriate, and (when DEPROCEDURE_P is non-zero), converting + function-valued variables into parameterless calls. May expand + EXP. The CONTEXT_TYPE functions as in ada_resolve, above. */ + +static struct value* +ada_resolve_subexp (expp, pos, deprocedure_p, context_type) + struct expression** expp; + int *pos; + int deprocedure_p; + struct type* context_type; +{ + int pc = *pos; + int i; + struct expression* exp; /* Convenience: == *expp */ + enum exp_opcode op = (*expp)->elts[pc].opcode; + struct value** argvec; /* Vector of operand types (alloca'ed). */ + int nargs; /* Number of operands */ + + argvec = NULL; + nargs = 0; + exp = *expp; + + /* Pass one: resolve operands, saving their types and updating *pos. */ + switch (op) + { + case OP_VAR_VALUE: + /* case OP_UNRESOLVED_VALUE:*/ + /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */ + *pos += 4; + break; + + case OP_FUNCALL: + nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1; + /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */ + /* if (exp->elts[pc+3].opcode == OP_UNRESOLVED_VALUE) + { + *pos += 7; + + argvec = (struct value* *) alloca (sizeof (struct value*) * (nargs + 1)); + for (i = 0; i < nargs-1; i += 1) + argvec[i] = ada_resolve_subexp (expp, pos, 1, NULL); + argvec[i] = NULL; + } + else + { + *pos += 3; + ada_resolve_subexp (expp, pos, 0, NULL); + for (i = 1; i < nargs; i += 1) + ada_resolve_subexp (expp, pos, 1, NULL); + } + */ + exp = *expp; + break; + + /* FIXME: UNOP_QUAL should be defined in expression.h */ + /* case UNOP_QUAL: + nargs = 1; + *pos += 3; + ada_resolve_subexp (expp, pos, 1, exp->elts[pc + 1].type); + exp = *expp; + break; + */ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ + /* case OP_ATTRIBUTE: + nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1; + *pos += 4; + for (i = 0; i < nargs; i += 1) + ada_resolve_subexp (expp, pos, 1, NULL); + exp = *expp; + break; + */ + case UNOP_ADDR: + nargs = 1; + *pos += 1; + ada_resolve_subexp (expp, pos, 0, NULL); + exp = *expp; + break; + + case BINOP_ASSIGN: + { + struct value* arg1; + nargs = 2; + *pos += 1; + arg1 = ada_resolve_subexp (expp, pos, 0, NULL); + if (arg1 == NULL) + ada_resolve_subexp (expp, pos, 1, NULL); + else + ada_resolve_subexp (expp, pos, 1, VALUE_TYPE (arg1)); + break; + } + + default: + switch (op) + { + default: + error ("Unexpected operator during name resolution"); + case UNOP_CAST: + /* case UNOP_MBR: + nargs = 1; + *pos += 3; + break; + */ + case BINOP_ADD: + case BINOP_SUB: + case BINOP_MUL: + case BINOP_DIV: + case BINOP_REM: + case BINOP_MOD: + case BINOP_EXP: + case BINOP_CONCAT: + case BINOP_LOGICAL_AND: + case BINOP_LOGICAL_OR: + case BINOP_BITWISE_AND: + case BINOP_BITWISE_IOR: + case BINOP_BITWISE_XOR: + + case BINOP_EQUAL: + case BINOP_NOTEQUAL: + case BINOP_LESS: + case BINOP_GTR: + case BINOP_LEQ: + case BINOP_GEQ: + + case BINOP_REPEAT: + case BINOP_SUBSCRIPT: + case BINOP_COMMA: + nargs = 2; + *pos += 1; + break; + + case UNOP_NEG: + case UNOP_PLUS: + case UNOP_LOGICAL_NOT: + case UNOP_ABS: + case UNOP_IND: + nargs = 1; + *pos += 1; + break; + + case OP_LONG: + case OP_DOUBLE: + case OP_VAR_VALUE: + *pos += 4; + break; + + case OP_TYPE: + case OP_BOOL: + case OP_LAST: + case OP_REGISTER: + case OP_INTERNALVAR: + *pos += 3; + break; + + case UNOP_MEMVAL: + *pos += 3; + nargs = 1; + break; + + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + nargs = 1; + *pos += 4 + BYTES_TO_EXP_ELEM (exp->elts[pc + 1].longconst + 1); + break; + + case OP_ARRAY: + *pos += 4; + nargs = longest_to_int (exp->elts[pc + 2].longconst) + 1; + nargs -= longest_to_int (exp->elts[pc + 1].longconst); + /* A null array contains one dummy element to give the type. */ + /* if (nargs == 0) + nargs = 1; + break;*/ + + case TERNOP_SLICE: + /* FIXME: TERNOP_MBR should be defined in expression.h */ + /* case TERNOP_MBR: + *pos += 1; + nargs = 3; + break; + */ + /* FIXME: BINOP_MBR should be defined in expression.h */ + /* case BINOP_MBR: + *pos += 3; + nargs = 2; + break;*/ + } + + argvec = (struct value* *) alloca (sizeof (struct value*) * (nargs + 1)); + for (i = 0; i < nargs; i += 1) + argvec[i] = ada_resolve_subexp (expp, pos, 1, NULL); + argvec[i] = NULL; + exp = *expp; + break; + } + + /* Pass two: perform any resolution on principal operator. */ + switch (op) + { + default: + break; + + /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */ + /* case OP_UNRESOLVED_VALUE: + { + struct symbol** candidate_syms; + struct block** candidate_blocks; + int n_candidates; + + n_candidates = ada_lookup_symbol_list (exp->elts[pc + 2].name, + exp->elts[pc + 1].block, + VAR_NAMESPACE, + &candidate_syms, + &candidate_blocks); + + if (n_candidates > 1) + {*/ + /* Types tend to get re-introduced locally, so if there + are any local symbols that are not types, first filter + out all types.*/ /* + int j; + for (j = 0; j < n_candidates; j += 1) + switch (SYMBOL_CLASS (candidate_syms[j])) + { + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + goto FoundNonType; + default: + break; + } + FoundNonType: + if (j < n_candidates) + { + j = 0; + while (j < n_candidates) + { + if (SYMBOL_CLASS (candidate_syms[j]) == LOC_TYPEDEF) + { + candidate_syms[j] = candidate_syms[n_candidates-1]; + candidate_blocks[j] = candidate_blocks[n_candidates-1]; + n_candidates -= 1; + } + else + j += 1; + } + } + } + + if (n_candidates == 0) + error ("No definition found for %s", + ada_demangle (exp->elts[pc + 2].name)); + else if (n_candidates == 1) + i = 0; + else if (deprocedure_p + && ! is_nonfunction (candidate_syms, n_candidates)) + { + i = ada_resolve_function (candidate_syms, candidate_blocks, + n_candidates, NULL, 0, + exp->elts[pc + 2].name, context_type); + if (i < 0) + error ("Could not find a match for %s", + ada_demangle (exp->elts[pc + 2].name)); + } + else + { + printf_filtered ("Multiple matches for %s\n", + ada_demangle (exp->elts[pc+2].name)); + user_select_syms (candidate_syms, candidate_blocks, + n_candidates, 1); + i = 0; + } + + exp->elts[pc].opcode = exp->elts[pc + 3].opcode = OP_VAR_VALUE; + exp->elts[pc + 1].block = candidate_blocks[i]; + exp->elts[pc + 2].symbol = candidate_syms[i]; + if (innermost_block == NULL || + contained_in (candidate_blocks[i], innermost_block)) + innermost_block = candidate_blocks[i]; + }*/ + /* FALL THROUGH */ + + case OP_VAR_VALUE: + if (deprocedure_p && + TYPE_CODE (SYMBOL_TYPE (exp->elts[pc+2].symbol)) == TYPE_CODE_FUNC) + { + replace_operator_with_call (expp, pc, 0, 0, + exp->elts[pc+2].symbol, + exp->elts[pc+1].block); + exp = *expp; + } + break; + + case OP_FUNCALL: + { + /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */ + /* if (exp->elts[pc+3].opcode == OP_UNRESOLVED_VALUE) + { + struct symbol** candidate_syms; + struct block** candidate_blocks; + int n_candidates; + + n_candidates = ada_lookup_symbol_list (exp->elts[pc + 5].name, + exp->elts[pc + 4].block, + VAR_NAMESPACE, + &candidate_syms, + &candidate_blocks); + if (n_candidates == 1) + i = 0; + else + { + i = ada_resolve_function (candidate_syms, candidate_blocks, + n_candidates, argvec, nargs-1, + exp->elts[pc + 5].name, context_type); + if (i < 0) + error ("Could not find a match for %s", + ada_demangle (exp->elts[pc + 5].name)); + } + + exp->elts[pc + 3].opcode = exp->elts[pc + 6].opcode = OP_VAR_VALUE; + exp->elts[pc + 4].block = candidate_blocks[i]; + exp->elts[pc + 5].symbol = candidate_syms[i]; + if (innermost_block == NULL || + contained_in (candidate_blocks[i], innermost_block)) + innermost_block = candidate_blocks[i]; + }*/ + + } + break; + case BINOP_ADD: + case BINOP_SUB: + case BINOP_MUL: + case BINOP_DIV: + case BINOP_REM: + case BINOP_MOD: + case BINOP_CONCAT: + case BINOP_BITWISE_AND: + case BINOP_BITWISE_IOR: + case BINOP_BITWISE_XOR: + case BINOP_EQUAL: + case BINOP_NOTEQUAL: + case BINOP_LESS: + case BINOP_GTR: + case BINOP_LEQ: + case BINOP_GEQ: + case BINOP_EXP: + case UNOP_NEG: + case UNOP_PLUS: + case UNOP_LOGICAL_NOT: + case UNOP_ABS: + if (possible_user_operator_p (op, argvec)) + { + struct symbol** candidate_syms; + struct block** candidate_blocks; + int n_candidates; + + n_candidates = ada_lookup_symbol_list (ada_mangle (ada_op_name (op)), + (struct block*) NULL, + VAR_NAMESPACE, + &candidate_syms, + &candidate_blocks); + i = ada_resolve_function (candidate_syms, candidate_blocks, + n_candidates, argvec, nargs, + ada_op_name (op), NULL); + if (i < 0) + break; + + replace_operator_with_call (expp, pc, nargs, 1, + candidate_syms[i], candidate_blocks[i]); + exp = *expp; + } + break; + } + + *pos = pc; + return evaluate_subexp_type (exp, pos); +} + +/* Return non-zero if formal type FTYPE matches actual type ATYPE. If + MAY_DEREF is non-zero, the formal may be a pointer and the actual + a non-pointer. */ +/* The term "match" here is rather loose. The match is heuristic and + liberal. FIXME: TOO liberal, in fact. */ + +static int +ada_type_match (ftype, atype, may_deref) + struct type* ftype; + struct type* atype; + int may_deref; +{ + CHECK_TYPEDEF (ftype); + CHECK_TYPEDEF (atype); + + if (TYPE_CODE (ftype) == TYPE_CODE_REF) + ftype = TYPE_TARGET_TYPE (ftype); + if (TYPE_CODE (atype) == TYPE_CODE_REF) + atype = TYPE_TARGET_TYPE (atype); + + if (TYPE_CODE (ftype) == TYPE_CODE_VOID + || TYPE_CODE (atype) == TYPE_CODE_VOID) + return 1; + + switch (TYPE_CODE (ftype)) + { + default: + return 1; + case TYPE_CODE_PTR: + if (TYPE_CODE (atype) == TYPE_CODE_PTR) + return ada_type_match (TYPE_TARGET_TYPE (ftype), + TYPE_TARGET_TYPE (atype), 0); + else return (may_deref && + ada_type_match (TYPE_TARGET_TYPE (ftype), atype, 0)); + case TYPE_CODE_INT: + case TYPE_CODE_ENUM: + case TYPE_CODE_RANGE: + switch (TYPE_CODE (atype)) + { + case TYPE_CODE_INT: + case TYPE_CODE_ENUM: + case TYPE_CODE_RANGE: + return 1; + default: + return 0; + } + + case TYPE_CODE_ARRAY: + return (TYPE_CODE (atype) == TYPE_CODE_ARRAY + || ada_is_array_descriptor (atype)); + + case TYPE_CODE_STRUCT: + if (ada_is_array_descriptor (ftype)) + return (TYPE_CODE (atype) == TYPE_CODE_ARRAY + || ada_is_array_descriptor (atype)); + else + return (TYPE_CODE (atype) == TYPE_CODE_STRUCT + && ! ada_is_array_descriptor (atype)); + + case TYPE_CODE_UNION: + case TYPE_CODE_FLT: + return (TYPE_CODE (atype) == TYPE_CODE (ftype)); + } +} + +/* Return non-zero if the formals of FUNC "sufficiently match" the + vector of actual argument types ACTUALS of size N_ACTUALS. FUNC + may also be an enumeral, in which case it is treated as a 0- + argument function. */ + +static int +ada_args_match (func, actuals, n_actuals) + struct symbol* func; + struct value** actuals; + int n_actuals; +{ + int i; + struct type* func_type = SYMBOL_TYPE (func); + + if (SYMBOL_CLASS (func) == LOC_CONST && + TYPE_CODE (func_type) == TYPE_CODE_ENUM) + return (n_actuals == 0); + else if (func_type == NULL || TYPE_CODE (func_type) != TYPE_CODE_FUNC) + return 0; + + if (TYPE_NFIELDS (func_type) != n_actuals) + return 0; + + for (i = 0; i < n_actuals; i += 1) + { + struct type* ftype = check_typedef (TYPE_FIELD_TYPE (func_type, i)); + struct type* atype = check_typedef (VALUE_TYPE (actuals[i])); + + if (! ada_type_match (TYPE_FIELD_TYPE (func_type, i), + VALUE_TYPE (actuals[i]), 1)) + return 0; + } + return 1; +} + +/* False iff function type FUNC_TYPE definitely does not produce a value + compatible with type CONTEXT_TYPE. Conservatively returns 1 if + FUNC_TYPE is not a valid function type with a non-null return type + or an enumerated type. A null CONTEXT_TYPE indicates any non-void type. */ + +static int +return_match (func_type, context_type) + struct type* func_type; + struct type* context_type; +{ + struct type* return_type; + + if (func_type == NULL) + return 1; + + /* FIXME: base_type should be declared in gdbtypes.h, implemented in valarith.c */ + /* if (TYPE_CODE (func_type) == TYPE_CODE_FUNC) + return_type = base_type (TYPE_TARGET_TYPE (func_type)); + else + return_type = base_type (func_type);*/ + if (return_type == NULL) + return 1; + + /* FIXME: base_type should be declared in gdbtypes.h, implemented in valarith.c */ + /* context_type = base_type (context_type);*/ + + if (TYPE_CODE (return_type) == TYPE_CODE_ENUM) + return context_type == NULL || return_type == context_type; + else if (context_type == NULL) + return TYPE_CODE (return_type) != TYPE_CODE_VOID; + else + return TYPE_CODE (return_type) == TYPE_CODE (context_type); +} + + +/* Return the index in SYMS[0..NSYMS-1] of symbol for the + function (if any) that matches the types of the NARGS arguments in + ARGS. If CONTEXT_TYPE is non-null, and there is at least one match + that returns type CONTEXT_TYPE, then eliminate other matches. If + CONTEXT_TYPE is null, prefer a non-void-returning function. + Asks the user if there is more than one match remaining. Returns -1 + if there is no such symbol or none is selected. NAME is used + solely for messages. May re-arrange and modify SYMS in + the process; the index returned is for the modified vector. BLOCKS + is modified in parallel to SYMS. */ + +int +ada_resolve_function (syms, blocks, nsyms, args, nargs, name, context_type) + struct symbol* syms[]; + struct block* blocks[]; + struct value** args; + int nsyms, nargs; + const char* name; + struct type* context_type; +{ + int k; + int m; /* Number of hits */ + struct type* fallback; + struct type* return_type; + + return_type = context_type; + if (context_type == NULL) + fallback = builtin_type_void; + else + fallback = NULL; + + m = 0; + while (1) + { + for (k = 0; k < nsyms; k += 1) + { + struct type* type = check_typedef (SYMBOL_TYPE (syms[k])); + + if (ada_args_match (syms[k], args, nargs) + && return_match (SYMBOL_TYPE (syms[k]), return_type)) + { + syms[m] = syms[k]; + if (blocks != NULL) + blocks[m] = blocks[k]; + m += 1; + } + } + if (m > 0 || return_type == fallback) + break; + else + return_type = fallback; + } + + if (m == 0) + return -1; + else if (m > 1) + { + printf_filtered ("Multiple matches for %s\n", name); + user_select_syms (syms, blocks, m, 1); + return 0; + } + return 0; +} + +/* Returns true (non-zero) iff demangled name N0 should appear before N1 */ +/* in a listing of choices during disambiguation (see sort_choices, below). */ +/* The idea is that overloadings of a subprogram name from the */ +/* same package should sort in their source order. We settle for ordering */ +/* such symbols by their trailing number (__N or $N). */ +static int +mangled_ordered_before (char* N0, char* N1) +{ + if (N1 == NULL) + return 0; + else if (N0 == NULL) + return 1; + else + { + int k0, k1; + for (k0 = strlen (N0)-1; k0 > 0 && isdigit (N0[k0]); k0 -= 1) + ; + for (k1 = strlen (N1)-1; k1 > 0 && isdigit (N1[k1]); k1 -= 1) + ; + if ((N0[k0] == '_' || N0[k0] == '$') && N0[k0+1] != '\000' + && (N1[k1] == '_' || N1[k1] == '$') && N1[k1+1] != '\000') + { + int n0, n1; + n0 = k0; + while (N0[n0] == '_' && n0 > 0 && N0[n0-1] == '_') + n0 -= 1; + n1 = k1; + while (N1[n1] == '_' && n1 > 0 && N1[n1-1] == '_') + n1 -= 1; + if (n0 == n1 && STREQN (N0, N1, n0)) + return (atoi (N0+k0+1) < atoi (N1+k1+1)); + } + return (strcmp (N0, N1) < 0); + } +} + +/* Sort SYMS[0..NSYMS-1] to put the choices in a canonical order by their */ +/* mangled names, rearranging BLOCKS[0..NSYMS-1] according to the same */ +/* permutation. */ +static void +sort_choices (syms, blocks, nsyms) + struct symbol* syms[]; + struct block* blocks[]; + int nsyms; +{ + int i, j; + for (i = 1; i < nsyms; i += 1) + { + struct symbol* sym = syms[i]; + struct block* block = blocks[i]; + int j; + + for (j = i-1; j >= 0; j -= 1) + { + if (mangled_ordered_before (SYMBOL_NAME (syms[j]), + SYMBOL_NAME (sym))) + break; + syms[j+1] = syms[j]; + blocks[j+1] = blocks[j]; + } + syms[j+1] = sym; + blocks[j+1] = block; + } +} + +/* Given a list of NSYMS symbols in SYMS and corresponding blocks in */ +/* BLOCKS, select up to MAX_RESULTS>0 by asking the user (if */ +/* necessary), returning the number selected, and setting the first */ +/* elements of SYMS and BLOCKS to the selected symbols and */ +/* corresponding blocks. Error if no symbols selected. BLOCKS may */ +/* be NULL, in which case it is ignored. */ + +/* NOTE: Adapted from decode_line_2 in symtab.c, with which it ought + to be re-integrated one of these days. */ + +int +user_select_syms (syms, blocks, nsyms, max_results) + struct symbol* syms[]; + struct block* blocks[]; + int nsyms; + int max_results; +{ + int i; + int* chosen = (int*) alloca (sizeof(int) * nsyms); + int n_chosen; + int first_choice = (max_results == 1) ? 1 : 2; + + if (max_results < 1) + error ("Request to select 0 symbols!"); + if (nsyms <= 1) + return nsyms; + + printf_unfiltered("[0] cancel\n"); + if (max_results > 1) + printf_unfiltered("[1] all\n"); + + sort_choices (syms, blocks, nsyms); + + for (i = 0; i < nsyms; i += 1) + { + if (syms[i] == NULL) + continue; + + if (SYMBOL_CLASS (syms[i]) == LOC_BLOCK) + { + struct symtab_and_line sal = find_function_start_sal (syms[i], 1); + printf_unfiltered ("[%d] %s at %s:%d\n", + i + first_choice, + SYMBOL_SOURCE_NAME (syms[i]), + sal.symtab == NULL + ? "<no source file available>" + : sal.symtab->filename, + sal.line); + continue; + } + else + { + int is_enumeral = + (SYMBOL_CLASS (syms[i]) == LOC_CONST + && SYMBOL_TYPE (syms[i]) != NULL + && TYPE_CODE (SYMBOL_TYPE (syms[i])) + == TYPE_CODE_ENUM); + struct symtab* symtab = symtab_for_sym (syms[i]); + + if (SYMBOL_LINE (syms[i]) != 0 && symtab != NULL) + printf_unfiltered ("[%d] %s at %s:%d\n", + i + first_choice, + SYMBOL_SOURCE_NAME (syms[i]), + symtab->filename, SYMBOL_LINE (syms[i])); + else if (is_enumeral && + TYPE_NAME (SYMBOL_TYPE (syms[i])) != NULL) + { + printf_unfiltered ("[%d] ", i + first_choice); + ada_print_type (SYMBOL_TYPE (syms[i]), NULL, gdb_stdout, -1, 0); + printf_unfiltered ("'(%s) (enumeral)\n", + SYMBOL_SOURCE_NAME (syms[i])); + } + else if (symtab != NULL) + printf_unfiltered (is_enumeral + ? "[%d] %s in %s (enumeral)\n" + : "[%d] %s at %s:?\n", + i + first_choice, + SYMBOL_SOURCE_NAME (syms[i]), + symtab->filename); + else + printf_unfiltered (is_enumeral + ? "[%d] %s (enumeral)\n" + : "[%d] %s at ?\n", + i + first_choice, SYMBOL_SOURCE_NAME (syms[i])); + } + } + + n_chosen = get_selections (chosen, nsyms, max_results, max_results > 1, + "overload-choice"); + + for (i = 0; i < n_chosen; i += 1) + { + syms[i] = syms[chosen[i]]; + if (blocks != NULL) + blocks[i] = blocks[chosen[i]]; + } + + return n_chosen; +} + +/* Read and validate a set of numeric choices from the user in the + range 0 .. N_CHOICES-1. Place the results in increasing + order in CHOICES[0 .. N-1], and return N. + + The user types choices as a sequence of numbers on one line + separated by blanks, encoding them as follows: + + + A choice of 0 means to cancel the selection, throwing an error. + + If IS_ALL_CHOICE, a choice of 1 selects the entire set 0 .. N_CHOICES-1. + + The user chooses k by typing k+IS_ALL_CHOICE+1. + + The user is not allowed to choose more than MAX_RESULTS values. + + ANNOTATION_SUFFIX, if present, is used to annotate the input + prompts (for use with the -f switch). */ + +int +get_selections (choices, n_choices, max_results, is_all_choice, + annotation_suffix) + int* choices; + int n_choices; + int max_results; + int is_all_choice; + char* annotation_suffix; +{ + int i; + char* args; + const char* prompt; + int n_chosen; + int first_choice = is_all_choice ? 2 : 1; + + prompt = getenv ("PS2"); + if (prompt == NULL) + prompt = ">"; + + printf_unfiltered ("%s ", prompt); + gdb_flush (gdb_stdout); + + args = command_line_input ((char *) NULL, 0, annotation_suffix); + + if (args == NULL) + error_no_arg ("one or more choice numbers"); + + n_chosen = 0; + + /* Set choices[0 .. n_chosen-1] to the users' choices in ascending + order, as given in args. Choices are validated. */ + while (1) + { + char* args2; + int choice, j; + + while (isspace (*args)) + args += 1; + if (*args == '\0' && n_chosen == 0) + error_no_arg ("one or more choice numbers"); + else if (*args == '\0') + break; + + choice = strtol (args, &args2, 10); + if (args == args2 || choice < 0 || choice > n_choices + first_choice - 1) + error ("Argument must be choice number"); + args = args2; + + if (choice == 0) + error ("cancelled"); + + if (choice < first_choice) + { + n_chosen = n_choices; + for (j = 0; j < n_choices; j += 1) + choices[j] = j; + break; + } + choice -= first_choice; + + for (j = n_chosen-1; j >= 0 && choice < choices[j]; j -= 1) + {} + + if (j < 0 || choice != choices[j]) + { + int k; + for (k = n_chosen-1; k > j; k -= 1) + choices[k+1] = choices[k]; + choices[j+1] = choice; + n_chosen += 1; + } + } + + if (n_chosen > max_results) + error ("Select no more than %d of the above", max_results); + + return n_chosen; +} + +/* Replace the operator of length OPLEN at position PC in *EXPP with a call */ +/* on the function identified by SYM and BLOCK, and taking NARGS */ +/* arguments. Update *EXPP as needed to hold more space. */ + +static void +replace_operator_with_call (expp, pc, nargs, oplen, sym, block) + struct expression** expp; + int pc, nargs, oplen; + struct symbol* sym; + struct block* block; +{ + /* A new expression, with 6 more elements (3 for funcall, 4 for function + symbol, -oplen for operator being replaced). */ + struct expression* newexp = (struct expression*) + xmalloc (sizeof (struct expression) + + EXP_ELEM_TO_BYTES ((*expp)->nelts + 7 - oplen)); + struct expression* exp = *expp; + + newexp->nelts = exp->nelts + 7 - oplen; + newexp->language_defn = exp->language_defn; + memcpy (newexp->elts, exp->elts, EXP_ELEM_TO_BYTES (pc)); + memcpy (newexp->elts + pc + 7, exp->elts + pc + oplen, + EXP_ELEM_TO_BYTES (exp->nelts - pc - oplen)); + + newexp->elts[pc].opcode = newexp->elts[pc + 2].opcode = OP_FUNCALL; + newexp->elts[pc + 1].longconst = (LONGEST) nargs; + + newexp->elts[pc + 3].opcode = newexp->elts[pc + 6].opcode = OP_VAR_VALUE; + newexp->elts[pc + 4].block = block; + newexp->elts[pc + 5].symbol = sym; + + *expp = newexp; + free (exp); +} + +/* Type-class predicates */ + +/* True iff TYPE is numeric (i.e., an INT, RANGE (of numeric type), or */ +/* FLOAT.) */ + +static int +numeric_type_p (type) + struct type* type; +{ + if (type == NULL) + return 0; + else { + switch (TYPE_CODE (type)) + { + case TYPE_CODE_INT: + case TYPE_CODE_FLT: + return 1; + case TYPE_CODE_RANGE: + return (type == TYPE_TARGET_TYPE (type) + || numeric_type_p (TYPE_TARGET_TYPE (type))); + default: + return 0; + } + } +} + +/* True iff TYPE is integral (an INT or RANGE of INTs). */ + +static int +integer_type_p (type) + struct type* type; +{ + if (type == NULL) + return 0; + else { + switch (TYPE_CODE (type)) + { + case TYPE_CODE_INT: + return 1; + case TYPE_CODE_RANGE: + return (type == TYPE_TARGET_TYPE (type) + || integer_type_p (TYPE_TARGET_TYPE (type))); + default: + return 0; + } + } +} + +/* True iff TYPE is scalar (INT, RANGE, FLOAT, ENUM). */ + +static int +scalar_type_p (type) + struct type* type; +{ + if (type == NULL) + return 0; + else { + switch (TYPE_CODE (type)) + { + case TYPE_CODE_INT: + case TYPE_CODE_RANGE: + case TYPE_CODE_ENUM: + case TYPE_CODE_FLT: + return 1; + default: + return 0; + } + } +} + +/* True iff TYPE is discrete (INT, RANGE, ENUM). */ + +static int +discrete_type_p (type) + struct type* type; +{ + if (type == NULL) + return 0; + else { + switch (TYPE_CODE (type)) + { + case TYPE_CODE_INT: + case TYPE_CODE_RANGE: + case TYPE_CODE_ENUM: + return 1; + default: + return 0; + } + } +} + +/* Returns non-zero if OP with operatands in the vector ARGS could be + a user-defined function. Errs on the side of pre-defined operators + (i.e., result 0). */ + +static int +possible_user_operator_p (op, args) + enum exp_opcode op; + struct value* args[]; +{ + struct type* type0 = check_typedef (VALUE_TYPE (args[0])); + struct type* type1 = + (args[1] == NULL) ? NULL : check_typedef (VALUE_TYPE (args[1])); + + switch (op) + { + default: + return 0; + + case BINOP_ADD: + case BINOP_SUB: + case BINOP_MUL: + case BINOP_DIV: + return (! (numeric_type_p (type0) && numeric_type_p (type1))); + + case BINOP_REM: + case BINOP_MOD: + case BINOP_BITWISE_AND: + case BINOP_BITWISE_IOR: + case BINOP_BITWISE_XOR: + return (! (integer_type_p (type0) && integer_type_p (type1))); + + case BINOP_EQUAL: + case BINOP_NOTEQUAL: + case BINOP_LESS: + case BINOP_GTR: + case BINOP_LEQ: + case BINOP_GEQ: + return (! (scalar_type_p (type0) && scalar_type_p (type1))); + + case BINOP_CONCAT: + return ((TYPE_CODE (type0) != TYPE_CODE_ARRAY && + (TYPE_CODE (type0) != TYPE_CODE_PTR || + TYPE_CODE (TYPE_TARGET_TYPE (type0)) + != TYPE_CODE_ARRAY)) + || (TYPE_CODE (type1) != TYPE_CODE_ARRAY && + (TYPE_CODE (type1) != TYPE_CODE_PTR || + TYPE_CODE (TYPE_TARGET_TYPE (type1)) + != TYPE_CODE_ARRAY))); + + case BINOP_EXP: + return (! (numeric_type_p (type0) && integer_type_p (type1))); + + case UNOP_NEG: + case UNOP_PLUS: + case UNOP_LOGICAL_NOT: + case UNOP_ABS: + return (! numeric_type_p (type0)); + + } +} + + /* Renaming */ + +/** NOTE: In the following, we assume that a renaming type's name may + * have an ___XD suffix. It would be nice if this went away at some + * point. */ + +/* If TYPE encodes a renaming, returns the renaming suffix, which + * is XR for an object renaming, XRP for a procedure renaming, XRE for + * an exception renaming, and XRS for a subprogram renaming. Returns + * NULL if NAME encodes none of these. */ +const char* +ada_renaming_type (type) + struct type* type; +{ + if (type != NULL && TYPE_CODE (type) == TYPE_CODE_ENUM) + { + const char* name = type_name_no_tag (type); + const char* suffix = (name == NULL) ? NULL : strstr (name, "___XR"); + if (suffix == NULL + || (suffix[5] != '\000' && strchr ("PES_", suffix[5]) == NULL)) + return NULL; + else + return suffix + 3; + } + else + return NULL; +} + +/* Return non-zero iff SYM encodes an object renaming. */ +int +ada_is_object_renaming (sym) + struct symbol* sym; +{ + const char* renaming_type = ada_renaming_type (SYMBOL_TYPE (sym)); + return renaming_type != NULL + && (renaming_type[2] == '\0' || renaming_type[2] == '_'); +} + +/* Assuming that SYM encodes a non-object renaming, returns the original + * name of the renamed entity. The name is good until the end of + * parsing. */ +const char* +ada_simple_renamed_entity (sym) + struct symbol* sym; +{ + struct type* type; + const char* raw_name; + int len; + char* result; + + type = SYMBOL_TYPE (sym); + if (type == NULL || TYPE_NFIELDS (type) < 1) + error ("Improperly encoded renaming."); + + raw_name = TYPE_FIELD_NAME (type, 0); + len = (raw_name == NULL ? 0 : strlen (raw_name)) - 5; + if (len <= 0) + error ("Improperly encoded renaming."); + + result = xmalloc (len + 1); + /* FIXME: add_name_string_cleanup should be defined in parse.c */ + /* add_name_string_cleanup (result);*/ + strncpy (result, raw_name, len); + result[len] = '\000'; + return result; +} + + + /* Evaluation: Function Calls */ + +/* Copy VAL onto the stack, using and updating *SP as the stack + pointer. Return VAL as an lvalue. */ + +static struct value* +place_on_stack (val, sp) + struct value* val; + CORE_ADDR* sp; +{ + CORE_ADDR old_sp = *sp; + +#ifdef STACK_ALIGN + *sp = push_bytes (*sp, VALUE_CONTENTS_RAW (val), + STACK_ALIGN (TYPE_LENGTH (check_typedef (VALUE_TYPE (val))))); +#else + *sp = push_bytes (*sp, VALUE_CONTENTS_RAW (val), + TYPE_LENGTH (check_typedef (VALUE_TYPE (val)))); +#endif + + VALUE_LVAL (val) = lval_memory; + if (INNER_THAN (1, 2)) + VALUE_ADDRESS (val) = *sp; + else + VALUE_ADDRESS (val) = old_sp; + + return val; +} + +/* Return the value ACTUAL, converted to be an appropriate value for a + formal of type FORMAL_TYPE. Use *SP as a stack pointer for + allocating any necessary descriptors (fat pointers), or copies of + values not residing in memory, updating it as needed. */ + +static struct value* +convert_actual (actual, formal_type0, sp) + struct value* actual; + struct type* formal_type0; + CORE_ADDR* sp; +{ + struct type* actual_type = check_typedef (VALUE_TYPE (actual)); + struct type* formal_type = check_typedef (formal_type0); + struct type* formal_target = + TYPE_CODE (formal_type) == TYPE_CODE_PTR + ? check_typedef (TYPE_TARGET_TYPE (formal_type)) : formal_type; + struct type* actual_target = + TYPE_CODE (actual_type) == TYPE_CODE_PTR + ? check_typedef (TYPE_TARGET_TYPE (actual_type)) : actual_type; + + if (ada_is_array_descriptor (formal_target) + && TYPE_CODE (actual_target) == TYPE_CODE_ARRAY) + return make_array_descriptor (formal_type, actual, sp); + else if (TYPE_CODE (formal_type) == TYPE_CODE_PTR) + { + if (TYPE_CODE (formal_target) == TYPE_CODE_ARRAY + && ada_is_array_descriptor (actual_target)) + return desc_data (actual); + else if (TYPE_CODE (actual_type) != TYPE_CODE_PTR) + { + if (VALUE_LVAL (actual) != lval_memory) + { + struct value* val; + actual_type = check_typedef (VALUE_TYPE (actual)); + val = allocate_value (actual_type); + memcpy ((char*) VALUE_CONTENTS_RAW (val), + (char*) VALUE_CONTENTS (actual), + TYPE_LENGTH (actual_type)); + actual = place_on_stack (val, sp); + } + return value_addr (actual); + } + } + else if (TYPE_CODE (actual_type) == TYPE_CODE_PTR) + return ada_value_ind (actual); + + return actual; +} + + +/* Push a descriptor of type TYPE for array value ARR on the stack at + *SP, updating *SP to reflect the new descriptor. Return either + an lvalue representing the new descriptor, or (if TYPE is a pointer- + to-descriptor type rather than a descriptor type), a struct value* + representing a pointer to this descriptor. */ + +static struct value* +make_array_descriptor (type, arr, sp) + struct type* type; + struct value* arr; + CORE_ADDR* sp; +{ + struct type* bounds_type = desc_bounds_type (type); + struct type* desc_type = desc_base_type (type); + struct value* descriptor = allocate_value (desc_type); + struct value* bounds = allocate_value (bounds_type); + CORE_ADDR bounds_addr; + int i; + + for (i = ada_array_arity (check_typedef (VALUE_TYPE (arr))); i > 0; i -= 1) + { + modify_general_field (VALUE_CONTENTS (bounds), + value_as_long (ada_array_bound (arr, i, 0)), + desc_bound_bitpos (bounds_type, i, 0), + desc_bound_bitsize (bounds_type, i, 0)); + modify_general_field (VALUE_CONTENTS (bounds), + value_as_long (ada_array_bound (arr, i, 1)), + desc_bound_bitpos (bounds_type, i, 1), + desc_bound_bitsize (bounds_type, i, 1)); + } + + bounds = place_on_stack (bounds, sp); + + modify_general_field (VALUE_CONTENTS (descriptor), + arr, + fat_pntr_data_bitpos (desc_type), + fat_pntr_data_bitsize (desc_type)); + modify_general_field (VALUE_CONTENTS (descriptor), + VALUE_ADDRESS (bounds), + fat_pntr_bounds_bitpos (desc_type), + fat_pntr_bounds_bitsize (desc_type)); + + descriptor = place_on_stack (descriptor, sp); + + if (TYPE_CODE (type) == TYPE_CODE_PTR) + return value_addr (descriptor); + else + return descriptor; +} + + +/* Assuming a dummy frame has been established on the target, perform any + conversions needed for calling function FUNC on the NARGS actual + parameters in ARGS, other than standard C conversions. Does + nothing if FUNC does not have Ada-style prototype data, or if NARGS + does not match the number of arguments expected. Use *SP as a + stack pointer for additional data that must be pushed, updating its + value as needed. */ + +void +ada_convert_actuals (func, nargs, args, sp) + struct value* func; + int nargs; + struct value* args[]; + CORE_ADDR* sp; +{ + int i; + + if (TYPE_NFIELDS (VALUE_TYPE (func)) == 0 + || nargs != TYPE_NFIELDS (VALUE_TYPE (func))) + return; + + for (i = 0; i < nargs; i += 1) + args[i] = + convert_actual (args[i], + TYPE_FIELD_TYPE (VALUE_TYPE (func), i), + sp); +} + + + /* Symbol Lookup */ + + +/* The vectors of symbols and blocks ultimately returned from */ +/* ada_lookup_symbol_list. */ + +/* Current size of defn_symbols and defn_blocks */ +static size_t defn_vector_size = 0; + +/* Current number of symbols found. */ +static int ndefns = 0; + +static struct symbol** defn_symbols = NULL; +static struct block** defn_blocks = NULL; + +/* Return the result of a standard (literal, C-like) lookup of NAME in + * given NAMESPACE. */ + +static struct symbol* +standard_lookup (name, namespace) + const char* name; + namespace_enum namespace; +{ + struct symbol* sym; + struct symtab* symtab; + sym = lookup_symbol (name, (struct block*) NULL, namespace, 0, &symtab); + return sym; +} + + +/* Non-zero iff there is at least one non-function/non-enumeral symbol */ +/* in SYMS[0..N-1]. We treat enumerals as functions, since they */ +/* contend in overloading in the same way. */ +static int +is_nonfunction (syms, n) + struct symbol* syms[]; + int n; +{ + int i; + + for (i = 0; i < n; i += 1) + if (TYPE_CODE (SYMBOL_TYPE (syms[i])) != TYPE_CODE_FUNC + && TYPE_CODE (SYMBOL_TYPE (syms[i])) != TYPE_CODE_ENUM) + return 1; + + return 0; +} + +/* If true (non-zero), then TYPE0 and TYPE1 represent equivalent + struct types. Otherwise, they may not. */ + +static int +equiv_types (type0, type1) + struct type* type0; + struct type* type1; +{ + if (type0 == type1) + return 1; + if (type0 == NULL || type1 == NULL + || TYPE_CODE (type0) != TYPE_CODE (type1)) + return 0; + if ((TYPE_CODE (type0) == TYPE_CODE_STRUCT + || TYPE_CODE (type0) == TYPE_CODE_ENUM) + && ada_type_name (type0) != NULL && ada_type_name (type1) != NULL + && STREQ (ada_type_name (type0), ada_type_name (type1))) + return 1; + + return 0; +} + +/* True iff SYM0 represents the same entity as SYM1, or one that is + no more defined than that of SYM1. */ + +static int +lesseq_defined_than (sym0, sym1) + struct symbol* sym0; + struct symbol* sym1; +{ + if (sym0 == sym1) + return 1; + if (SYMBOL_NAMESPACE (sym0) != SYMBOL_NAMESPACE (sym1) + || SYMBOL_CLASS (sym0) != SYMBOL_CLASS (sym1)) + return 0; + + switch (SYMBOL_CLASS (sym0)) + { + case LOC_UNDEF: + return 1; + case LOC_TYPEDEF: + { + struct type* type0 = SYMBOL_TYPE (sym0); + struct type* type1 = SYMBOL_TYPE (sym1); + char* name0 = SYMBOL_NAME (sym0); + char* name1 = SYMBOL_NAME (sym1); + int len0 = strlen (name0); + return + TYPE_CODE (type0) == TYPE_CODE (type1) + && (equiv_types (type0, type1) + || (len0 < strlen (name1) && STREQN (name0, name1, len0) + && STREQN (name1 + len0, "___XV", 5))); + } + case LOC_CONST: + return SYMBOL_VALUE (sym0) == SYMBOL_VALUE (sym1) + && equiv_types (SYMBOL_TYPE (sym0), SYMBOL_TYPE (sym1)); + default: + return 0; + } +} + +/* Append SYM to the end of defn_symbols, and BLOCK to the end of + defn_blocks, updating ndefns, and expanding defn_symbols and + defn_blocks as needed. Do not include SYM if it is a duplicate. */ + +static void +add_defn_to_vec (sym, block) + struct symbol* sym; + struct block* block; +{ + int i; + size_t tmp; + + if (SYMBOL_TYPE (sym) != NULL) + CHECK_TYPEDEF (SYMBOL_TYPE (sym)); + for (i = 0; i < ndefns; i += 1) + { + if (lesseq_defined_than (sym, defn_symbols[i])) + return; + else if (lesseq_defined_than (defn_symbols[i], sym)) + { + defn_symbols[i] = sym; + defn_blocks[i] = block; + return; + } + } + + tmp = defn_vector_size; + GROW_VECT (defn_symbols, tmp, ndefns+2); + GROW_VECT (defn_blocks, defn_vector_size, ndefns+2); + + defn_symbols[ndefns] = sym; + defn_blocks[ndefns] = block; + ndefns += 1; +} + +/* Look, in partial_symtab PST, for symbol NAME in given namespace. + Check the global symbols if GLOBAL, the static symbols if not. Do + wild-card match if WILD. */ + +static struct partial_symbol * +ada_lookup_partial_symbol (pst, name, global, namespace, wild) + struct partial_symtab *pst; + const char *name; + int global; + namespace_enum namespace; + int wild; +{ + struct partial_symbol **start; + int name_len = strlen (name); + int length = (global ? pst->n_global_syms : pst->n_static_syms); + int i; + + if (length == 0) + { + return (NULL); + } + + start = (global ? + pst->objfile->global_psymbols.list + pst->globals_offset : + pst->objfile->static_psymbols.list + pst->statics_offset ); + + if (wild) + { + for (i = 0; i < length; i += 1) + { + struct partial_symbol* psym = start[i]; + + if (SYMBOL_NAMESPACE (psym) == namespace && + wild_match (name, name_len, SYMBOL_NAME (psym))) + return psym; + } + return NULL; + } + else + { + if (global) + { + int U; + i = 0; U = length-1; + while (U - i > 4) + { + int M = (U+i) >> 1; + struct partial_symbol* psym = start[M]; + if (SYMBOL_NAME (psym)[0] < name[0]) + i = M+1; + else if (SYMBOL_NAME (psym)[0] > name[0]) + U = M-1; + else if (strcmp (SYMBOL_NAME (psym), name) < 0) + i = M+1; + else + U = M; + } + } + else + i = 0; + + while (i < length) + { + struct partial_symbol *psym = start[i]; + + if (SYMBOL_NAMESPACE (psym) == namespace) + { + int cmp = strncmp (name, SYMBOL_NAME (psym), name_len); + + if (cmp < 0) + { + if (global) + break; + } + else if (cmp == 0 + && is_name_suffix (SYMBOL_NAME (psym) + name_len)) + return psym; + } + i += 1; + } + + if (global) + { + int U; + i = 0; U = length-1; + while (U - i > 4) + { + int M = (U+i) >> 1; + struct partial_symbol *psym = start[M]; + if (SYMBOL_NAME (psym)[0] < '_') + i = M+1; + else if (SYMBOL_NAME (psym)[0] > '_') + U = M-1; + else if (strcmp (SYMBOL_NAME (psym), "_ada_") < 0) + i = M+1; + else + U = M; + } + } + else + i = 0; + + while (i < length) + { + struct partial_symbol* psym = start[i]; + + if (SYMBOL_NAMESPACE (psym) == namespace) + { + int cmp; + + cmp = (int) '_' - (int) SYMBOL_NAME (psym)[0]; + if (cmp == 0) + { + cmp = strncmp ("_ada_", SYMBOL_NAME (psym), 5); + if (cmp == 0) + cmp = strncmp (name, SYMBOL_NAME (psym) + 5, name_len); + } + + if (cmp < 0) + { + if (global) + break; + } + else if (cmp == 0 + && is_name_suffix (SYMBOL_NAME (psym) + name_len + 5)) + return psym; + } + i += 1; + } + + } + return NULL; +} + + +/* Find a symbol table containing symbol SYM or NULL if none. */ +static struct symtab* +symtab_for_sym (sym) + struct symbol* sym; +{ + struct symtab* s; + struct objfile *objfile; + struct block *b; + int i, j; + + ALL_SYMTABS (objfile, s) + { + switch (SYMBOL_CLASS (sym)) + { + case LOC_CONST: + case LOC_STATIC: + case LOC_TYPEDEF: + case LOC_REGISTER: + case LOC_LABEL: + case LOC_BLOCK: + case LOC_CONST_BYTES: + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK); + for (i = 0; i < BLOCK_NSYMS (b); i += 1) + if (sym == BLOCK_SYM (b, i)) + return s; + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK); + for (i = 0; i < BLOCK_NSYMS (b); i += 1) + if (sym == BLOCK_SYM (b, i)) + return s; + break; + default: + break; + } + switch (SYMBOL_CLASS (sym)) + { + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_TYPEDEF: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + for (j = FIRST_LOCAL_BLOCK; + j < BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (s)); j += 1) + { + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), j); + for (i = 0; i < BLOCK_NSYMS (b); i += 1) + if (sym == BLOCK_SYM (b, i)) + return s; + } + break; + default: + break; + } + } + return NULL; +} + +/* Return a minimal symbol matching NAME according to Ada demangling + rules. Returns NULL if there is no such minimal symbol. */ + +struct minimal_symbol* +ada_lookup_minimal_symbol (name) + const char* name; +{ + struct objfile* objfile; + struct minimal_symbol* msymbol; + int wild_match = (strstr (name, "__") == NULL); + + ALL_MSYMBOLS (objfile, msymbol) + { + if (ada_match_name (SYMBOL_NAME (msymbol), name, wild_match) + && MSYMBOL_TYPE (msymbol) != mst_solib_trampoline) + return msymbol; + } + + return NULL; +} + +/* For all subprograms that statically enclose the subprogram of the + * selected frame, add symbols matching identifier NAME in NAMESPACE + * and their blocks to vectors *defn_symbols and *defn_blocks, as for + * ada_add_block_symbols (q.v.). If WILD, treat as NAME with a + * wildcard prefix. At the moment, this function uses a heuristic to + * find the frames of enclosing subprograms: it treats the + * pointer-sized value at location 0 from the local-variable base of a + * frame as a static link, and then searches up the call stack for a + * frame with that same local-variable base. */ +static void +add_symbols_from_enclosing_procs (name, namespace, wild_match) + const char* name; + namespace_enum namespace; + int wild_match; +{ +#ifdef i386 + static struct symbol static_link_sym; + static struct symbol *static_link; + + struct cleanup* old_chain = make_cleanup (null_cleanup, NULL); + struct frame_info* frame; + struct frame_info* target_frame; + + if (static_link == NULL) + { + /* Initialize the local variable symbol that stands for the + * static link (when it exists). */ + static_link = &static_link_sym; + SYMBOL_NAME (static_link) = ""; + SYMBOL_LANGUAGE (static_link) = language_unknown; + SYMBOL_CLASS (static_link) = LOC_LOCAL; + SYMBOL_NAMESPACE (static_link) = VAR_NAMESPACE; + SYMBOL_TYPE (static_link) = lookup_pointer_type (builtin_type_void); + SYMBOL_VALUE (static_link) = + - (long) TYPE_LENGTH (SYMBOL_TYPE (static_link)); + } + + frame = selected_frame; + while (frame != NULL && ndefns == 0) + { + struct block* block; + struct value* target_link_val = read_var_value (static_link, frame); + CORE_ADDR target_link; + + if (target_link_val == NULL) + break; + QUIT; + + target_link = target_link_val; + do { + QUIT; + frame = get_prev_frame (frame); + } while (frame != NULL && FRAME_LOCALS_ADDRESS (frame) != target_link); + + if (frame == NULL) + break; + + block = get_frame_block (frame, 0); + while (block != NULL && block_function (block) != NULL && ndefns == 0) + { + ada_add_block_symbols (block, name, namespace, NULL, wild_match); + + block = BLOCK_SUPERBLOCK (block); + } + } + + do_cleanups (old_chain); +#endif +} + +/* True if TYPE is definitely an artificial type supplied to a symbol + * for which no debugging information was given in the symbol file. */ +static int +is_nondebugging_type (type) + struct type* type; +{ + char* name = ada_type_name (type); + return (name != NULL && STREQ (name, "<variable, no debug info>")); +} + +/* Remove any non-debugging symbols in SYMS[0 .. NSYMS-1] that definitely + * duplicate other symbols in the list. (The only case I know of where + * this happens is when object files containing stabs-in-ecoff are + * linked with files containing ordinary ecoff debugging symbols (or no + * debugging symbols)). Modifies SYMS to squeeze out deleted symbols, + * and applies the same modification to BLOCKS to maintain the + * correspondence between SYMS[i] and BLOCKS[i]. Returns the number + * of symbols in the modified list. */ +static int +remove_extra_symbols (syms, blocks, nsyms) + struct symbol** syms; + struct block** blocks; + int nsyms; +{ + int i, j; + + i = 0; + while (i < nsyms) + { + if (SYMBOL_NAME (syms[i]) != NULL && SYMBOL_CLASS (syms[i]) == LOC_STATIC + && is_nondebugging_type (SYMBOL_TYPE (syms[i]))) + { + for (j = 0; j < nsyms; j += 1) + { + if (i != j + && SYMBOL_NAME (syms[j]) != NULL + && STREQ (SYMBOL_NAME (syms[i]), SYMBOL_NAME (syms[j])) + && SYMBOL_CLASS (syms[i]) == SYMBOL_CLASS (syms[j]) + && SYMBOL_VALUE_ADDRESS (syms[i]) + == SYMBOL_VALUE_ADDRESS (syms[j])) + { + int k; + for (k = i+1; k < nsyms; k += 1) + { + syms[k-1] = syms[k]; + blocks[k-1] = blocks[k]; + } + nsyms -= 1; + goto NextSymbol; + } + } + } + i += 1; + NextSymbol: + ; + } + return nsyms; +} + +/* Find symbols in NAMESPACE matching NAME, in BLOCK0 and enclosing + scope and in global scopes, returning the number of matches. Sets + *SYMS to point to a vector of matching symbols, with *BLOCKS + pointing to the vector of corresponding blocks in which those + symbols reside. These two vectors are transient---good only to the + next call of ada_lookup_symbol_list. Any non-function/non-enumeral symbol + match within the nest of blocks whose innermost member is BLOCK0, + is the outermost match returned (no other matches in that or + enclosing blocks is returned). If there are any matches in or + surrounding BLOCK0, then these alone are returned. */ + +int +ada_lookup_symbol_list (name, block0, namespace, syms, blocks) + const char *name; + struct block *block0; + namespace_enum namespace; + struct symbol*** syms; + struct block*** blocks; +{ + struct symbol *sym; + struct symtab *s; + struct partial_symtab *ps; + struct blockvector *bv; + struct objfile *objfile; + struct block *b; + struct block *block; + struct minimal_symbol *msymbol; + int wild_match = (strstr (name, "__") == NULL); + int cacheIfUnique; + +#ifdef TIMING + markTimeStart (0); +#endif + + ndefns = 0; + cacheIfUnique = 0; + + /* Search specified block and its superiors. */ + + block = block0; + while (block != NULL) + { + ada_add_block_symbols (block, name, namespace, NULL, wild_match); + + /* If we found a non-function match, assume that's the one. */ + if (is_nonfunction (defn_symbols, ndefns)) + goto done; + + block = BLOCK_SUPERBLOCK (block); + } + + /* If we found ANY matches in the specified BLOCK, we're done. */ + + if (ndefns > 0) + goto done; + + cacheIfUnique = 1; + + /* Now add symbols from all global blocks: symbol tables, minimal symbol + tables, and psymtab's */ + + ALL_SYMTABS (objfile, s) + { + QUIT; + if (! s->primary) + continue; + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + ada_add_block_symbols (block, name, namespace, objfile, wild_match); + } + + if (namespace == VAR_NAMESPACE) + { + ALL_MSYMBOLS (objfile, msymbol) + { + if (ada_match_name (SYMBOL_NAME (msymbol), name, wild_match)) + { + switch (MSYMBOL_TYPE (msymbol)) + { + case mst_solib_trampoline: + break; + default: + s = find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)); + if (s != NULL) + { + int old_ndefns = ndefns; + QUIT; + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + ada_add_block_symbols (block, + SYMBOL_NAME (msymbol), + namespace, objfile, wild_match); + if (ndefns == old_ndefns) + { + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + ada_add_block_symbols (block, + SYMBOL_NAME (msymbol), + namespace, objfile, + wild_match); + } + } + } + } + } + } + + ALL_PSYMTABS (objfile, ps) + { + QUIT; + if (!ps->readin + && ada_lookup_partial_symbol (ps, name, 1, namespace, wild_match)) + { + s = PSYMTAB_TO_SYMTAB (ps); + if (! s->primary) + continue; + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + ada_add_block_symbols (block, name, namespace, objfile, wild_match); + } + } + + /* Now add symbols from all per-file blocks if we've gotten no hits. + (Not strictly correct, but perhaps better than an error). + Do the symtabs first, then check the psymtabs */ + + if (ndefns == 0) + { + + ALL_SYMTABS (objfile, s) + { + QUIT; + if (! s->primary) + continue; + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + ada_add_block_symbols (block, name, namespace, objfile, wild_match); + } + + ALL_PSYMTABS (objfile, ps) + { + QUIT; + if (!ps->readin + && ada_lookup_partial_symbol (ps, name, 0, namespace, wild_match)) + { + s = PSYMTAB_TO_SYMTAB(ps); + bv = BLOCKVECTOR (s); + if (! s->primary) + continue; + block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + ada_add_block_symbols (block, name, namespace, + objfile, wild_match); + } + } + } + + /* Finally, we try to find NAME as a local symbol in some lexically + enclosing block. We do this last, expecting this case to be + rare. */ + if (ndefns == 0) + { + add_symbols_from_enclosing_procs (name, namespace, wild_match); + if (ndefns > 0) + goto done; + } + + done: + ndefns = remove_extra_symbols (defn_symbols, defn_blocks, ndefns); + + + *syms = defn_symbols; + *blocks = defn_blocks; +#ifdef TIMING + markTimeStop (0); +#endif + return ndefns; +} + +/* Return a symbol in NAMESPACE matching NAME, in BLOCK0 and enclosing + * scope and in global scopes, or NULL if none. NAME is folded to + * lower case first, unless it is surrounded in single quotes. + * Otherwise, the result is as for ada_lookup_symbol_list, but is + * disambiguated by user query if needed. */ + +struct symbol* +ada_lookup_symbol (name, block0, namespace) + const char *name; + struct block *block0; + namespace_enum namespace; +{ + struct symbol** candidate_syms; + struct block** candidate_blocks; + int n_candidates; + + n_candidates = ada_lookup_symbol_list (name, + block0, namespace, + &candidate_syms, &candidate_blocks); + + if (n_candidates == 0) + return NULL; + else if (n_candidates != 1) + user_select_syms (candidate_syms, candidate_blocks, n_candidates, 1); + + return candidate_syms[0]; +} + + +/* True iff STR is a possible encoded suffix of a normal Ada name + * that is to be ignored for matching purposes. Suffixes of parallel + * names (e.g., XVE) are not included here. Currently, the possible suffixes + * are given by the regular expression: + * (X[nb]*)?(__[0-9]+|\$[0-9]+|___(LJM|X([FDBUP].*|R[^T]?)))?$ + * + */ +static int +is_name_suffix (str) + const char* str; +{ + int k; + if (str[0] == 'X') + { + str += 1; + while (str[0] != '_' && str[0] != '\0') + { + if (str[0] != 'n' && str[0] != 'b') + return 0; + str += 1; + } + } + if (str[0] == '\000') + return 1; + if (str[0] == '_') + { + if (str[1] != '_' || str[2] == '\000') + return 0; + if (str[2] == '_') + { + if (STREQ (str+3, "LJM")) + return 1; + if (str[3] != 'X') + return 0; + if (str[4] == 'F' || str[4] == 'D' || str[4] == 'B' || + str[4] == 'U' || str[4] == 'P') + return 1; + if (str[4] == 'R' && str[5] != 'T') + return 1; + return 0; + } + for (k = 2; str[k] != '\0'; k += 1) + if (!isdigit (str[k])) + return 0; + return 1; + } + if (str[0] == '$' && str[1] != '\000') + { + for (k = 1; str[k] != '\0'; k += 1) + if (!isdigit (str[k])) + return 0; + return 1; + } + return 0; +} + +/* True if NAME represents a name of the form A1.A2....An, n>=1 and + * PATN[0..PATN_LEN-1] = Ak.Ak+1.....An for some k >= 1. Ignores + * informational suffixes of NAME (i.e., for which is_name_suffix is + * true). */ +static int +wild_match (patn, patn_len, name) + const char* patn; + int patn_len; + const char* name; +{ + int name_len; + int s, e; + + name_len = strlen (name); + if (name_len >= patn_len+5 && STREQN (name, "_ada_", 5) + && STREQN (patn, name+5, patn_len) + && is_name_suffix (name+patn_len+5)) + return 1; + + while (name_len >= patn_len) + { + if (STREQN (patn, name, patn_len) + && is_name_suffix (name+patn_len)) + return 1; + do { + name += 1; name_len -= 1; + } while (name_len > 0 + && name[0] != '.' && (name[0] != '_' || name[1] != '_')); + if (name_len <= 0) + return 0; + if (name[0] == '_') + { + if (! islower (name[2])) + return 0; + name += 2; name_len -= 2; + } + else + { + if (! islower (name[1])) + return 0; + name += 1; name_len -= 1; + } + } + + return 0; +} + + +/* Add symbols from BLOCK matching identifier NAME in NAMESPACE to + vector *defn_symbols, updating *defn_symbols (if necessary), *SZ (the size of + the vector *defn_symbols), and *ndefns (the number of symbols + currently stored in *defn_symbols). If WILD, treat as NAME with a + wildcard prefix. OBJFILE is the section containing BLOCK. */ + +static void +ada_add_block_symbols (block, name, namespace, objfile, wild) + struct block* block; + const char* name; + namespace_enum namespace; + struct objfile* objfile; + int wild; +{ + int i; + int name_len = strlen (name); + /* A matching argument symbol, if any. */ + struct symbol *arg_sym; + /* Set true when we find a matching non-argument symbol */ + int found_sym; + int is_sorted = BLOCK_SHOULD_SORT (block); + + arg_sym = NULL; found_sym = 0; + if (wild) + { + for (i = 0; i < BLOCK_NSYMS (block); i += 1) + { + struct symbol *sym = BLOCK_SYM (block, i); + + if (SYMBOL_NAMESPACE (sym) == namespace && + wild_match (name, name_len, SYMBOL_NAME (sym))) + { + switch (SYMBOL_CLASS (sym)) + { + case LOC_ARG: + case LOC_LOCAL_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_BASEREG_ARG: + arg_sym = sym; + break; + case LOC_UNRESOLVED: + continue; + default: + found_sym = 1; + fill_in_ada_prototype (sym); + add_defn_to_vec (fixup_symbol_section (sym, objfile), block); + break; + } + } + } + } + else + { + if (is_sorted) + { + int U; + i = 0; U = BLOCK_NSYMS (block)-1; + while (U - i > 4) + { + int M = (U+i) >> 1; + struct symbol *sym = BLOCK_SYM (block, M); + if (SYMBOL_NAME (sym)[0] < name[0]) + i = M+1; + else if (SYMBOL_NAME (sym)[0] > name[0]) + U = M-1; + else if (strcmp (SYMBOL_NAME (sym), name) < 0) + i = M+1; + else + U = M; + } + } + else + i = 0; + + for (; i < BLOCK_NSYMS (block); i += 1) + { + struct symbol *sym = BLOCK_SYM (block, i); + + if (SYMBOL_NAMESPACE (sym) == namespace) + { + int cmp = strncmp (name, SYMBOL_NAME (sym), name_len); + + if (cmp < 0) + { + if (is_sorted) + break; + } + else if (cmp == 0 + && is_name_suffix (SYMBOL_NAME (sym) + name_len)) + { + switch (SYMBOL_CLASS (sym)) + { + case LOC_ARG: + case LOC_LOCAL_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_BASEREG_ARG: + arg_sym = sym; + break; + case LOC_UNRESOLVED: + break; + default: + found_sym = 1; + fill_in_ada_prototype (sym); + add_defn_to_vec (fixup_symbol_section (sym, objfile), + block); + break; + } + } + } + } + } + + if (! found_sym && arg_sym != NULL) + { + fill_in_ada_prototype (arg_sym); + add_defn_to_vec (fixup_symbol_section (arg_sym, objfile), block); + } + + if (! wild) + { + arg_sym = NULL; found_sym = 0; + if (is_sorted) + { + int U; + i = 0; U = BLOCK_NSYMS (block)-1; + while (U - i > 4) + { + int M = (U+i) >> 1; + struct symbol *sym = BLOCK_SYM (block, M); + if (SYMBOL_NAME (sym)[0] < '_') + i = M+1; + else if (SYMBOL_NAME (sym)[0] > '_') + U = M-1; + else if (strcmp (SYMBOL_NAME (sym), "_ada_") < 0) + i = M+1; + else + U = M; + } + } + else + i = 0; + + for (; i < BLOCK_NSYMS (block); i += 1) + { + struct symbol *sym = BLOCK_SYM (block, i); + + if (SYMBOL_NAMESPACE (sym) == namespace) + { + int cmp; + + cmp = (int) '_' - (int) SYMBOL_NAME (sym)[0]; + if (cmp == 0) + { + cmp = strncmp ("_ada_", SYMBOL_NAME (sym), 5); + if (cmp == 0) + cmp = strncmp (name, SYMBOL_NAME (sym) + 5, name_len); + } + + if (cmp < 0) + { + if (is_sorted) + break; + } + else if (cmp == 0 + && is_name_suffix (SYMBOL_NAME (sym) + name_len + 5)) + { + switch (SYMBOL_CLASS (sym)) + { + case LOC_ARG: + case LOC_LOCAL_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_BASEREG_ARG: + arg_sym = sym; + break; + case LOC_UNRESOLVED: + break; + default: + found_sym = 1; + fill_in_ada_prototype (sym); + add_defn_to_vec (fixup_symbol_section (sym, objfile), + block); + break; + } + } + } + } + + /* NOTE: This really shouldn't be needed for _ada_ symbols. + They aren't parameters, right? */ + if (! found_sym && arg_sym != NULL) + { + fill_in_ada_prototype (arg_sym); + add_defn_to_vec (fixup_symbol_section (arg_sym, objfile), block); + } + } +} + + + /* Function Types */ + +/* Assuming that SYM is the symbol for a function, fill in its type + with prototype information, if it is not already there. + + Why is there provision in struct type for BOTH an array of argument + types (TYPE_ARG_TYPES) and for an array of typed fields, whose + comment suggests it may also represent argument types? I presume + this is some attempt to save space. The problem is that argument + names in Ada are significant. Therefore, for Ada we use the + (apparently older) TYPE_FIELD_* stuff to store argument types. */ + + +static void +fill_in_ada_prototype (func) + struct symbol* func; +{ + struct block* b; + int nargs, nsyms; + int i; + struct type* ftype; + struct type* rtype; + size_t max_fields; + + if (func == NULL + || TYPE_CODE (SYMBOL_TYPE (func)) != TYPE_CODE_FUNC + || TYPE_FIELDS (SYMBOL_TYPE (func)) != NULL) + return; + + /* We make each function type unique, so that each may have its own */ + /* parameter types. This particular way of doing so wastes space: */ + /* it would be nicer to build the argument types while the original */ + /* function type is being built (FIXME). */ + rtype = check_typedef (TYPE_TARGET_TYPE (SYMBOL_TYPE (func))); + ftype = alloc_type (TYPE_OBJFILE (SYMBOL_TYPE (func))); + make_function_type (rtype, &ftype); + SYMBOL_TYPE (func) = ftype; + + b = SYMBOL_BLOCK_VALUE (func); + nsyms = BLOCK_NSYMS (b); + + nargs = 0; + max_fields = 8; + TYPE_FIELDS (ftype) = + (struct field*) xmalloc (sizeof (struct field) * max_fields); + for (i = 0; i < nsyms; i += 1) + { + struct symbol *sym = BLOCK_SYM (b, i); + + GROW_VECT (TYPE_FIELDS (ftype), max_fields, nargs+1); + + switch (SYMBOL_CLASS (sym)) + { + case LOC_REF_ARG: + case LOC_REGPARM_ADDR: + TYPE_FIELD_BITPOS (ftype, nargs) = nargs; + TYPE_FIELD_BITSIZE (ftype, nargs) = 0; + TYPE_FIELD_TYPE (ftype, nargs) = + lookup_pointer_type (check_typedef (SYMBOL_TYPE (sym))); + TYPE_FIELD_NAME (ftype, nargs) = SYMBOL_NAME (sym); + nargs += 1; + + break; + + case LOC_ARG: + case LOC_REGPARM: + case LOC_LOCAL_ARG: + case LOC_BASEREG_ARG: + TYPE_FIELD_BITPOS (ftype, nargs) = nargs; + TYPE_FIELD_BITSIZE (ftype, nargs) = 0; + TYPE_FIELD_TYPE (ftype, nargs) = check_typedef (SYMBOL_TYPE (sym)); + TYPE_FIELD_NAME (ftype, nargs) = SYMBOL_NAME (sym); + nargs += 1; + + break; + + default: + break; + } + } + + /* Re-allocate fields vector; if there are no fields, make the */ + /* fields pointer non-null anyway, to mark that this function type */ + /* has been filled in. */ + + TYPE_NFIELDS (ftype) = nargs; + if (nargs == 0) + { + static struct field dummy_field = {0, 0, 0, 0}; + free (TYPE_FIELDS (ftype)); + TYPE_FIELDS (ftype) = &dummy_field; + } + else + { + struct field* fields = + (struct field*) TYPE_ALLOC (ftype, nargs * sizeof (struct field)); + memcpy ((char*) fields, + (char*) TYPE_FIELDS (ftype), + nargs * sizeof (struct field)); + free (TYPE_FIELDS (ftype)); + TYPE_FIELDS (ftype) = fields; + } +} + + + /* Breakpoint-related */ + +char no_symtab_msg[] = "No symbol table is loaded. Use the \"file\" command."; + +/* Assuming that LINE is pointing at the beginning of an argument to + 'break', return a pointer to the delimiter for the initial segment + of that name. This is the first ':', ' ', or end of LINE. +*/ +char* +ada_start_decode_line_1 (line) + char* line; +{ + /* [NOTE: strpbrk would be more elegant, but I am reluctant to be + the first to use such a library function in GDB code.] */ + char* p; + for (p = line; *p != '\000' && *p != ' ' && *p != ':'; p += 1) + ; + return p; +} + +/* *SPEC points to a function and line number spec (as in a break + command), following any initial file name specification. + + Return all symbol table/line specfications (sals) consistent with the + information in *SPEC and FILE_TABLE in the + following sense: + + FILE_TABLE is null, or the sal refers to a line in the file + named by FILE_TABLE. + + If *SPEC points to an argument with a trailing ':LINENUM', + then the sal refers to that line (or one following it as closely as + possible). + + If *SPEC does not start with '*', the sal is in a function with + that name. + + Returns with 0 elements if no matching non-minimal symbols found. + + If *SPEC begins with a function name of the form <NAME>, then NAME + is taken as a literal name; otherwise the function name is subject + to the usual mangling. + + *SPEC is updated to point after the function/line number specification. + + FUNFIRSTLINE is non-zero if we desire the first line of real code + in each function (this is ignored in the presence of a LINENUM spec.). + + If CANONICAL is non-NULL, and if any of the sals require a + 'canonical line spec', then *CANONICAL is set to point to an array + of strings, corresponding to and equal in length to the returned + list of sals, such that (*CANONICAL)[i] is non-null and contains a + canonical line spec for the ith returned sal, if needed. If no + canonical line specs are required and CANONICAL is non-null, + *CANONICAL is set to NULL. + + A 'canonical line spec' is simply a name (in the format of the + breakpoint command) that uniquely identifies a breakpoint position, + with no further contextual information or user selection. It is + needed whenever the file name, function name, and line number + information supplied is insufficient for this unique + identification. Currently overloaded functions, the name '*', + or static functions without a filename yield a canonical line spec. + The array and the line spec strings are allocated on the heap; it + is the caller's responsibility to free them. */ + +struct symtabs_and_lines +ada_finish_decode_line_1 (spec, file_table, funfirstline, canonical) + char** spec; + struct symtab* file_table; + int funfirstline; + char*** canonical; +{ + struct symbol** symbols; + struct block** blocks; + struct block* block; + int n_matches, i, line_num; + struct symtabs_and_lines selected; + struct cleanup* old_chain = make_cleanup (null_cleanup, NULL); + char* name; + + int len; + char* lower_name; + char* unquoted_name; + + if (file_table == NULL) + block = get_selected_block (NULL); + else + block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_table), STATIC_BLOCK); + + if (canonical != NULL) + *canonical = (char**) NULL; + + name = *spec; + if (**spec == '*') + *spec += 1; + else + { + while (**spec != '\000' && + ! strchr (ada_completer_word_break_characters, **spec)) + *spec += 1; + } + len = *spec - name; + + line_num = -1; + if (file_table != NULL && (*spec)[0] == ':' && isdigit ((*spec)[1])) + { + line_num = strtol (*spec + 1, spec, 10); + while (**spec == ' ' || **spec == '\t') + *spec += 1; + } + + if (name[0] == '*') + { + if (line_num == -1) + error ("Wild-card function with no line number or file name."); + + return all_sals_for_line (file_table->filename, line_num, canonical); + } + + if (name[0] == '\'') + { + name += 1; + len -= 2; + } + + if (name[0] == '<') + { + unquoted_name = (char*) alloca (len-1); + memcpy (unquoted_name, name+1, len-2); + unquoted_name[len-2] = '\000'; + lower_name = NULL; + } + else + { + unquoted_name = (char*) alloca (len+1); + memcpy (unquoted_name, name, len); + unquoted_name[len] = '\000'; + lower_name = (char*) alloca (len + 1); + for (i = 0; i < len; i += 1) + lower_name[i] = tolower (name[i]); + lower_name[len] = '\000'; + } + + n_matches = 0; + if (lower_name != NULL) + n_matches = ada_lookup_symbol_list (ada_mangle (lower_name), block, + VAR_NAMESPACE, &symbols, &blocks); + if (n_matches == 0) + n_matches = ada_lookup_symbol_list (unquoted_name, block, + VAR_NAMESPACE, &symbols, &blocks); + if (n_matches == 0 && line_num >= 0) + error ("No line number information found for %s.", unquoted_name); + else if (n_matches == 0) + { +#ifdef HPPA_COMPILER_BUG + /* FIXME: See comment in symtab.c::decode_line_1 */ +#undef volatile + volatile struct symtab_and_line val; +#define volatile /*nothing*/ +#else + struct symtab_and_line val; +#endif + struct minimal_symbol* msymbol; + + INIT_SAL (&val); + + msymbol = NULL; + if (lower_name != NULL) + msymbol = ada_lookup_minimal_symbol (ada_mangle (lower_name)); + if (msymbol == NULL) + msymbol = ada_lookup_minimal_symbol (unquoted_name); + if (msymbol != NULL) + { + val.pc = SYMBOL_VALUE_ADDRESS (msymbol); + val.section = SYMBOL_BFD_SECTION (msymbol); + if (funfirstline) + { + val.pc += FUNCTION_START_OFFSET; + SKIP_PROLOGUE (val.pc); + } + selected.sals = (struct symtab_and_line *) + xmalloc (sizeof (struct symtab_and_line)); + selected.sals[0] = val; + selected.nelts = 1; + return selected; + } + + if (!have_full_symbols () && + !have_partial_symbols () && !have_minimal_symbols ()) + error (no_symtab_msg); + + error ("Function \"%s\" not defined.", unquoted_name); + return selected; /* for lint */ + } + + if (line_num >= 0) + { + return + find_sal_from_funcs_and_line (file_table->filename, line_num, + symbols, n_matches); + } + else + { + selected.nelts = user_select_syms (symbols, blocks, n_matches, n_matches); + } + + selected.sals = (struct symtab_and_line*) + xmalloc (sizeof (struct symtab_and_line) * selected.nelts); + memset (selected.sals, 0, selected.nelts * sizeof (selected.sals[i])); + make_cleanup (free, selected.sals); + + i = 0; + while (i < selected.nelts) + { + if (SYMBOL_CLASS (symbols[i]) == LOC_BLOCK) + selected.sals[i] = find_function_start_sal (symbols[i], funfirstline); + else if (SYMBOL_LINE (symbols[i]) != 0) + { + selected.sals[i].symtab = symtab_for_sym (symbols[i]); + selected.sals[i].line = SYMBOL_LINE (symbols[i]); + } + else if (line_num >= 0) + { + /* Ignore this choice */ + symbols[i] = symbols[selected.nelts-1]; + blocks[i] = blocks[selected.nelts-1]; + selected.nelts -= 1; + continue; + } + else + error ("Line number not known for symbol \"%s\"", unquoted_name); + i += 1; + } + + if (canonical != NULL && (line_num >= 0 || n_matches > 1)) + { + *canonical = (char**) xmalloc (sizeof(char*) * selected.nelts); + for (i = 0; i < selected.nelts; i += 1) + (*canonical)[i] = + extended_canonical_line_spec (selected.sals[i], + SYMBOL_SOURCE_NAME (symbols[i])); + } + + discard_cleanups (old_chain); + return selected; +} + +/* The (single) sal corresponding to line LINE_NUM in a symbol table + with file name FILENAME that occurs in one of the functions listed + in SYMBOLS[0 .. NSYMS-1]. */ +static struct symtabs_and_lines +find_sal_from_funcs_and_line (filename, line_num, symbols, nsyms) + const char* filename; + int line_num; + struct symbol** symbols; + int nsyms; +{ + struct symtabs_and_lines sals; + int best_index, best; + struct linetable* best_linetable; + struct objfile* objfile; + struct symtab* s; + struct symtab* best_symtab; + + read_all_symtabs (filename); + + best_index = 0; best_linetable = NULL; best_symtab = NULL; + best = 0; + ALL_SYMTABS (objfile, s) + { + struct linetable *l; + int ind, exact; + + QUIT; + + if (!STREQ (filename, s->filename)) + continue; + l = LINETABLE (s); + ind = find_line_in_linetable (l, line_num, symbols, nsyms, &exact); + if (ind >= 0) + { + if (exact) + { + best_index = ind; + best_linetable = l; + best_symtab = s; + goto done; + } + if (best == 0 || l->item[ind].line < best) + { + best = l->item[ind].line; + best_index = ind; + best_linetable = l; + best_symtab = s; + } + } + } + + if (best == 0) + error ("Line number not found in designated function."); + + done: + + sals.nelts = 1; + sals.sals = (struct symtab_and_line*) xmalloc (sizeof (sals.sals[0])); + + INIT_SAL (&sals.sals[0]); + + sals.sals[0].line = best_linetable->item[best_index].line; + sals.sals[0].pc = best_linetable->item[best_index].pc; + sals.sals[0].symtab = best_symtab; + + return sals; +} + +/* Return the index in LINETABLE of the best match for LINE_NUM whose + pc falls within one of the functions denoted by SYMBOLS[0..NSYMS-1]. + Set *EXACTP to the 1 if the match is exact, and 0 otherwise. */ +static int +find_line_in_linetable (linetable, line_num, symbols, nsyms, exactp) + struct linetable* linetable; + int line_num; + struct symbol** symbols; + int nsyms; + int* exactp; +{ + int i, len, best_index, best; + + if (line_num <= 0 || linetable == NULL) + return -1; + + len = linetable->nitems; + for (i = 0, best_index = -1, best = 0; i < len; i += 1) + { + int k; + struct linetable_entry* item = &(linetable->item[i]); + + for (k = 0; k < nsyms; k += 1) + { + if (symbols[k] != NULL && SYMBOL_CLASS (symbols[k]) == LOC_BLOCK + && item->pc >= BLOCK_START (SYMBOL_BLOCK_VALUE (symbols[k])) + && item->pc < BLOCK_END (SYMBOL_BLOCK_VALUE (symbols[k]))) + goto candidate; + } + continue; + + candidate: + + if (item->line == line_num) + { + *exactp = 1; + return i; + } + + if (item->line > line_num && (best == 0 || item->line < best)) + { + best = item->line; + best_index = i; + } + } + + *exactp = 0; + return best_index; +} + +/* Find the smallest k >= LINE_NUM such that k is a line number in + LINETABLE, and k falls strictly within a named function that begins at + or before LINE_NUM. Return -1 if there is no such k. */ +static int +nearest_line_number_in_linetable (linetable, line_num) + struct linetable* linetable; + int line_num; +{ + int i, len, best; + + if (line_num <= 0 || linetable == NULL || linetable->nitems == 0) + return -1; + len = linetable->nitems; + + i = 0; best = INT_MAX; + while (i < len) + { + int k; + struct linetable_entry* item = &(linetable->item[i]); + + if (item->line >= line_num && item->line < best) + { + char* func_name; + CORE_ADDR start, end; + + func_name = NULL; + find_pc_partial_function (item->pc, &func_name, &start, &end); + + if (func_name != NULL && item->pc < end) + { + if (item->line == line_num) + return line_num; + else + { + struct symbol* sym = + standard_lookup (func_name, VAR_NAMESPACE); + if (is_plausible_func_for_line (sym, line_num)) + best = item->line; + else + { + do + i += 1; + while (i < len && linetable->item[i].pc < end); + continue; + } + } + } + } + + i += 1; + } + + return (best == INT_MAX) ? -1 : best; +} + + +/* Return the next higher index, k, into LINETABLE such that k > IND, + entry k in LINETABLE has a line number equal to LINE_NUM, k + corresponds to a PC that is in a function different from that + corresponding to IND, and falls strictly within a named function + that begins at a line at or preceding STARTING_LINE. + Return -1 if there is no such k. + IND == -1 corresponds to no function. */ + +static int +find_next_line_in_linetable (linetable, line_num, starting_line, ind) + struct linetable* linetable; + int line_num; + int starting_line; + int ind; +{ + int i, len; + + if (line_num <= 0 || linetable == NULL || ind >= linetable->nitems) + return -1; + len = linetable->nitems; + + if (ind >= 0) + { + CORE_ADDR start, end; + + if (find_pc_partial_function (linetable->item[ind].pc, + (char**) NULL, &start, &end)) + { + while (ind < len && linetable->item[ind].pc < end) + ind += 1; + } + else + ind += 1; + } + else + ind = 0; + + i = ind; + while (i < len) + { + int k; + struct linetable_entry* item = &(linetable->item[i]); + + if (item->line >= line_num) + { + char* func_name; + CORE_ADDR start, end; + + func_name = NULL; + find_pc_partial_function (item->pc, &func_name, &start, &end); + + if (func_name != NULL && item->pc < end) + { + if (item->line == line_num) + { + struct symbol* sym = + standard_lookup (func_name, VAR_NAMESPACE); + if (is_plausible_func_for_line (sym, starting_line)) + return i; + else + { + while ((i+1) < len && linetable->item[i+1].pc < end) + i += 1; + } + } + } + } + i += 1; + } + + return -1; +} + +/* True iff function symbol SYM starts somewhere at or before line # + LINE_NUM. */ +static int +is_plausible_func_for_line (sym, line_num) + struct symbol* sym; + int line_num; +{ + struct symtab_and_line start_sal; + + if (sym == NULL) + return 0; + + start_sal = find_function_start_sal (sym, 0); + + return (start_sal.line != 0 && line_num >= start_sal.line); +} + +static void +debug_print_lines (lt) + struct linetable* lt; +{ + int i; + + if (lt == NULL) + return; + + fprintf (stderr, "\t"); + for (i = 0; i < lt->nitems; i += 1) + fprintf (stderr, "(%d->%p) ", lt->item[i].line, (void *) lt->item[i].pc); + fprintf (stderr, "\n"); +} + +static void +debug_print_block (b) + struct block* b; +{ + int i; + fprintf (stderr, "Block: %p; [0x%lx, 0x%lx]", + b, BLOCK_START(b), BLOCK_END(b)); + if (BLOCK_FUNCTION(b) != NULL) + fprintf (stderr, " Function: %s", SYMBOL_NAME (BLOCK_FUNCTION(b))); + fprintf (stderr, "\n"); + fprintf (stderr, "\t Superblock: %p\n", BLOCK_SUPERBLOCK(b)); + fprintf (stderr, "\t Symbols:"); + for (i = 0; i < BLOCK_NSYMS (b); i += 1) + { + if (i > 0 && i % 4 == 0) + fprintf (stderr, "\n\t\t "); + fprintf (stderr, " %s", SYMBOL_NAME (BLOCK_SYM (b, i))); + } + fprintf (stderr, "\n"); +} + +static void +debug_print_blocks (bv) + struct blockvector* bv; +{ + int i; + + if (bv == NULL) + return; + for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i += 1) { + fprintf (stderr, "%6d. ", i); + debug_print_block (BLOCKVECTOR_BLOCK (bv, i)); + } +} + +static void +debug_print_symtab (s) + struct symtab* s; +{ + fprintf (stderr, "Symtab %p\n File: %s; Dir: %s\n", s, + s->filename, s->dirname); + fprintf (stderr, " Blockvector: %p, Primary: %d\n", + BLOCKVECTOR(s), s->primary); + debug_print_blocks (BLOCKVECTOR(s)); + fprintf (stderr, " Line table: %p\n", LINETABLE (s)); + debug_print_lines (LINETABLE(s)); +} + +/* Read in all symbol tables corresponding to partial symbol tables + with file name FILENAME. */ +static void +read_all_symtabs (filename) + const char* filename; +{ + struct partial_symtab* ps; + struct objfile* objfile; + + ALL_PSYMTABS (objfile, ps) + { + QUIT; + + if (STREQ (filename, ps->filename)) + PSYMTAB_TO_SYMTAB (ps); + } +} + +/* All sals corresponding to line LINE_NUM in a symbol table from file + FILENAME, as filtered by the user. If CANONICAL is not null, set + it to a corresponding array of canonical line specs. */ +static struct symtabs_and_lines +all_sals_for_line (filename, line_num, canonical) + const char* filename; + int line_num; + char*** canonical; +{ + struct symtabs_and_lines result; + struct objfile* objfile; + struct symtab* s; + struct cleanup* old_chain = make_cleanup (null_cleanup, NULL); + size_t len; + + read_all_symtabs (filename); + + result.sals = (struct symtab_and_line*) xmalloc (4 * sizeof (result.sals[0])); + result.nelts = 0; + len = 4; + make_cleanup (free_current_contents, &result.sals); + + ALL_SYMTABS (objfile, s) + { + int ind, target_line_num; + + QUIT; + + if (!STREQ (s->filename, filename)) + continue; + + target_line_num = + nearest_line_number_in_linetable (LINETABLE (s), line_num); + if (target_line_num == -1) + continue; + + ind = -1; + while (1) + { + ind = + find_next_line_in_linetable (LINETABLE (s), + target_line_num, line_num, ind); + + if (ind < 0) + break; + + GROW_VECT (result.sals, len, result.nelts+1); + INIT_SAL (&result.sals[result.nelts]); + result.sals[result.nelts].line = LINETABLE(s)->item[ind].line; + result.sals[result.nelts].pc = LINETABLE(s)->item[ind].pc; + result.sals[result.nelts].symtab = s; + result.nelts += 1; + } + } + + if (canonical != NULL || result.nelts > 1) + { + int k; + char** func_names = (char**) alloca (result.nelts * sizeof (char*)); + int first_choice = (result.nelts > 1) ? 2 : 1; + int n; + int* choices = (int*) alloca (result.nelts * sizeof (int)); + + for (k = 0; k < result.nelts; k += 1) + { + find_pc_partial_function (result.sals[k].pc, &func_names[k], + (CORE_ADDR*) NULL, (CORE_ADDR*) NULL); + if (func_names[k] == NULL) + error ("Could not find function for one or more breakpoints."); + } + + if (result.nelts > 1) + { + printf_unfiltered("[0] cancel\n"); + if (result.nelts > 1) + printf_unfiltered("[1] all\n"); + for (k = 0; k < result.nelts; k += 1) + printf_unfiltered ("[%d] %s\n", k + first_choice, + ada_demangle (func_names[k])); + + n = get_selections (choices, result.nelts, result.nelts, + result.nelts > 1, "instance-choice"); + + for (k = 0; k < n; k += 1) + { + result.sals[k] = result.sals[choices[k]]; + func_names[k] = func_names[choices[k]]; + } + result.nelts = n; + } + + if (canonical != NULL) + { + *canonical = (char**) xmalloc (result.nelts * sizeof (char**)); + make_cleanup (free, *canonical); + for (k = 0; k < result.nelts; k += 1) + { + (*canonical)[k] = + extended_canonical_line_spec (result.sals[k], func_names[k]); + if ((*canonical)[k] == NULL) + error ("Could not locate one or more breakpoints."); + make_cleanup (free, (*canonical)[k]); + } + } + } + + discard_cleanups (old_chain); + return result; +} + + +/* A canonical line specification of the form FILE:NAME:LINENUM for + symbol table and line data SAL. NULL if insufficient + information. The caller is responsible for releasing any space + allocated. */ + +static char* +extended_canonical_line_spec (sal, name) + struct symtab_and_line sal; + const char* name; +{ + char* r; + + if (sal.symtab == NULL || sal.symtab->filename == NULL || + sal.line <= 0) + return NULL; + + r = (char*) xmalloc (strlen (name) + strlen (sal.symtab->filename) + + sizeof(sal.line)*3 + 3); + sprintf (r, "%s:'%s':%d", sal.symtab->filename, name, sal.line); + return r; +} + +#if 0 +int begin_bnum = -1; +#endif +int begin_annotate_level = 0; + +static void +begin_cleanup (void* dummy) +{ + begin_annotate_level = 0; +} + +static void +begin_command (args, from_tty) + char *args; + int from_tty; +{ + struct minimal_symbol *msym; + CORE_ADDR main_program_name_addr; + char main_program_name[1024]; + struct cleanup* old_chain = make_cleanup (begin_cleanup, NULL); + begin_annotate_level = 2; + + /* Check that there is a program to debug */ + if (!have_full_symbols () && !have_partial_symbols ()) + error ("No symbol table is loaded. Use the \"file\" command."); + + /* Check that we are debugging an Ada program */ + /* if (ada_update_initial_language (language_unknown, NULL) != language_ada) + error ("Cannot find the Ada initialization procedure. Is this an Ada main program?"); + */ + /* FIXME: language_ada should be defined in defs.h */ + + /* Get the address of the name of the main procedure */ + msym = lookup_minimal_symbol (ADA_MAIN_PROGRAM_SYMBOL_NAME, NULL, NULL); + + if (msym != NULL) + { + main_program_name_addr = SYMBOL_VALUE_ADDRESS (msym); + if (main_program_name_addr == 0) + error ("Invalid address for Ada main program name."); + + /* Read the name of the main procedure */ + extract_string (main_program_name_addr, main_program_name); + + /* Put a temporary breakpoint in the Ada main program and run */ + do_command ("tbreak ", main_program_name, 0); + do_command ("run ", args, 0); + } + else + { + /* If we could not find the symbol containing the name of the + main program, that means that the compiler that was used to build + was not recent enough. In that case, we fallback to the previous + mechanism, which is a little bit less reliable, but has proved to work + in most cases. The only cases where it will fail is when the user + has set some breakpoints which will be hit before the end of the + begin command processing (eg in the initialization code). + + The begining of the main Ada subprogram is located by breaking + on the adainit procedure. Since we know that the binder generates + the call to this procedure exactly 2 calls before the call to the + Ada main subprogram, it is then easy to put a breakpoint on this + Ada main subprogram once we hit adainit. + */ + do_command ("tbreak adainit", 0); + do_command ("run ", args, 0); + do_command ("up", 0); + do_command ("tbreak +2", 0); + do_command ("continue", 0); + do_command ("step", 0); + } + + do_cleanups (old_chain); +} + +int +is_ada_runtime_file (filename) + char *filename; +{ + return (STREQN (filename, "s-", 2) || + STREQN (filename, "a-", 2) || + STREQN (filename, "g-", 2) || + STREQN (filename, "i-", 2)); +} + +/* find the first frame that contains debugging information and that is not + part of the Ada run-time, starting from fi and moving upward. */ + +int +find_printable_frame (fi, level) + struct frame_info *fi; + int level; +{ + struct symtab_and_line sal; + + for (; fi != NULL; level += 1, fi = get_prev_frame (fi)) + { + /* If fi is not the innermost frame, that normally means that fi->pc + points to *after* the call instruction, and we want to get the line + containing the call, never the next line. But if the next frame is + a signal_handler_caller or a dummy frame, then the next frame was + not entered as the result of a call, and we want to get the line + containing fi->pc. */ + sal = + find_pc_line (fi->pc, + fi->next != NULL + && !fi->next->signal_handler_caller + && !frame_in_dummy (fi->next)); + if (sal.symtab && !is_ada_runtime_file (sal.symtab->filename)) + { +#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET) + /* libpthread.so contains some debugging information that prevents us + from finding the right frame */ + + if (sal.symtab->objfile && + STREQ (sal.symtab->objfile->name, "/usr/shlib/libpthread.so")) + continue; +#endif + selected_frame = fi; + break; + } + } + + return level; +} + +void +ada_report_exception_break (b) + struct breakpoint *b; +{ +#ifdef UI_OUT + /* FIXME: break_on_exception should be defined in breakpoint.h */ + /* if (b->break_on_exception == 1) + { + /* Assume that cond has 16 elements, the 15th + being the exception */ /* + if (b->cond && b->cond->nelts == 16) + { + ui_out_text (uiout, "on "); + ui_out_field_string (uiout, "exception", + SYMBOL_NAME (b->cond->elts[14].symbol)); + } + else + ui_out_text (uiout, "on all exceptions"); + } + else if (b->break_on_exception == 2) + ui_out_text (uiout, "on unhandled exception"); + else if (b->break_on_exception == 3) + ui_out_text (uiout, "on assert failure"); +#else + if (b->break_on_exception == 1) + {*/ + /* Assume that cond has 16 elements, the 15th + being the exception */ /* + if (b->cond && b->cond->nelts == 16) + { + fputs_filtered ("on ", gdb_stdout); + fputs_filtered (SYMBOL_NAME + (b->cond->elts[14].symbol), gdb_stdout); + } + else + fputs_filtered ("on all exceptions", gdb_stdout); + } + else if (b->break_on_exception == 2) + fputs_filtered ("on unhandled exception", gdb_stdout); + else if (b->break_on_exception == 3) + fputs_filtered ("on assert failure", gdb_stdout); +*/ +#endif +} + +int +ada_is_exception_sym (struct symbol* sym) +{ + char *type_name = type_name_no_tag (SYMBOL_TYPE (sym)); + + return (SYMBOL_CLASS (sym) != LOC_TYPEDEF + && SYMBOL_CLASS (sym) != LOC_BLOCK + && SYMBOL_CLASS (sym) != LOC_CONST + && type_name != NULL + && STREQ (type_name, "exception")); +} + +int +ada_maybe_exception_partial_symbol (struct partial_symbol* sym) +{ + return (SYMBOL_CLASS (sym) != LOC_TYPEDEF + && SYMBOL_CLASS (sym) != LOC_BLOCK + && SYMBOL_CLASS (sym) != LOC_CONST); +} + +/* If ARG points to an Ada exception or assert breakpoint, rewrite + into equivalent form. Return resulting argument string. Set + *BREAK_ON_EXCEPTIONP to 1 for ordinary break on exception, 2 for + break on unhandled, 3 for assert, 0 otherwise. */ +char* ada_breakpoint_rewrite (char* arg, int* break_on_exceptionp) +{ + if (arg == NULL) + return arg; + *break_on_exceptionp = 0; + /* FIXME: language_ada should be defined in defs.h */ + /* if (current_language->la_language == language_ada + && STREQN (arg, "exception", 9) && + (arg[9] == ' ' || arg[9] == '\t' || arg[9] == '\0')) + { + char *tok, *end_tok; + int toklen; + + *break_on_exceptionp = 1; + + tok = arg+9; + while (*tok == ' ' || *tok == '\t') + tok += 1; + + end_tok = tok; + + while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000') + end_tok += 1; + + toklen = end_tok - tok; + + arg = (char*) xmalloc (sizeof ("__gnat_raise_nodefer_with_msg if " + "long_integer(e) = long_integer(&)") + + toklen + 1); + make_cleanup (free, arg); + if (toklen == 0) + strcpy (arg, "__gnat_raise_nodefer_with_msg"); + else if (STREQN (tok, "unhandled", toklen)) + { + *break_on_exceptionp = 2; + strcpy (arg, "__gnat_unhandled_exception"); + } + else + { + sprintf (arg, "__gnat_raise_nodefer_with_msg if " + "long_integer(e) = long_integer(&%.*s)", + toklen, tok); + } + } + else if (current_language->la_language == language_ada + && STREQN (arg, "assert", 6) && + (arg[6] == ' ' || arg[6] == '\t' || arg[6] == '\0')) + { + char *tok = arg + 6; + + *break_on_exceptionp = 3; + + arg = (char*) + xmalloc (sizeof ("system__assertions__raise_assert_failure") + + strlen (tok) + 1); + make_cleanup (free, arg); + sprintf (arg, "system__assertions__raise_assert_failure%s", tok); + } + */ + return arg; +} + + + /* Field Access */ + +/* True if field number FIELD_NUM in struct or union type TYPE is supposed + to be invisible to users. */ + +int +ada_is_ignored_field (type, field_num) + struct type *type; + int field_num; +{ + if (field_num < 0 || field_num > TYPE_NFIELDS (type)) + return 1; + else + { + const char* name = TYPE_FIELD_NAME (type, field_num); + return (name == NULL + || (name[0] == '_' && ! STREQN (name, "_parent", 7))); + } +} + +/* True iff structure type TYPE has a tag field. */ + +int +ada_is_tagged_type (type) + struct type *type; +{ + if (type == NULL || TYPE_CODE (type) != TYPE_CODE_STRUCT) + return 0; + + return (ada_lookup_struct_elt_type (type, "_tag", 1, NULL) != NULL); +} + +/* The type of the tag on VAL. */ + +struct type* +ada_tag_type (val) + struct value* val; +{ + return ada_lookup_struct_elt_type (VALUE_TYPE (val), "_tag", 0, NULL); +} + +/* The value of the tag on VAL. */ + +struct value* +ada_value_tag (val) + struct value* val; +{ + return ada_value_struct_elt (val, "_tag", "record"); +} + +/* The parent type of TYPE, or NULL if none. */ + +struct type* +ada_parent_type (type) + struct type *type; +{ + int i; + + CHECK_TYPEDEF (type); + + if (type == NULL || TYPE_CODE (type) != TYPE_CODE_STRUCT) + return NULL; + + for (i = 0; i < TYPE_NFIELDS (type); i += 1) + if (ada_is_parent_field (type, i)) + return check_typedef (TYPE_FIELD_TYPE (type, i)); + + return NULL; +} + +/* True iff field number FIELD_NUM of structure type TYPE contains the + parent-type (inherited) fields of a derived type. Assumes TYPE is + a structure type with at least FIELD_NUM+1 fields. */ + +int +ada_is_parent_field (type, field_num) + struct type *type; + int field_num; +{ + const char* name = TYPE_FIELD_NAME (check_typedef (type), field_num); + return (name != NULL && + (STREQN (name, "PARENT", 6) || STREQN (name, "_parent", 7))); +} + +/* True iff field number FIELD_NUM of structure type TYPE is a + transparent wrapper field (which should be silently traversed when doing + field selection and flattened when printing). Assumes TYPE is a + structure type with at least FIELD_NUM+1 fields. Such fields are always + structures. */ + +int +ada_is_wrapper_field (type, field_num) + struct type *type; + int field_num; +{ + const char* name = TYPE_FIELD_NAME (type, field_num); + return (name != NULL + && (STREQN (name, "PARENT", 6) || STREQ (name, "REP") + || STREQN (name, "_parent", 7) + || name[0] == 'S' || name[0] == 'R' || name[0] == 'O')); +} + +/* True iff field number FIELD_NUM of structure or union type TYPE + is a variant wrapper. Assumes TYPE is a structure type with at least + FIELD_NUM+1 fields. */ + +int +ada_is_variant_part (type, field_num) + struct type *type; + int field_num; +{ + struct type* field_type = TYPE_FIELD_TYPE (type, field_num); + return (TYPE_CODE (field_type) == TYPE_CODE_UNION + || (is_dynamic_field (type, field_num) + && TYPE_CODE (TYPE_TARGET_TYPE (field_type)) == TYPE_CODE_UNION)); +} + +/* Assuming that VAR_TYPE is a variant wrapper (type of the variant part) + whose discriminants are contained in the record type OUTER_TYPE, + returns the type of the controlling discriminant for the variant. */ + +struct type* +ada_variant_discrim_type (var_type, outer_type) + struct type *var_type; + struct type *outer_type; +{ + char* name = ada_variant_discrim_name (var_type); + struct type *type = + ada_lookup_struct_elt_type (outer_type, name, 1, NULL); + if (type == NULL) + return builtin_type_int; + else + return type; +} + +/* Assuming that TYPE is the type of a variant wrapper, and FIELD_NUM is a + valid field number within it, returns 1 iff field FIELD_NUM of TYPE + represents a 'when others' clause; otherwise 0. */ + +int +ada_is_others_clause (type, field_num) + struct type *type; + int field_num; +{ + const char* name = TYPE_FIELD_NAME (type, field_num); + return (name != NULL && name[0] == 'O'); +} + +/* Assuming that TYPE0 is the type of the variant part of a record, + returns the name of the discriminant controlling the variant. The + value is valid until the next call to ada_variant_discrim_name. */ + +char * +ada_variant_discrim_name (type0) + struct type *type0; +{ + static char* result = NULL; + static size_t result_len = 0; + struct type* type; + const char* name; + const char* discrim_end; + const char* discrim_start; + + if (TYPE_CODE (type0) == TYPE_CODE_PTR) + type = TYPE_TARGET_TYPE (type0); + else + type = type0; + + name = ada_type_name (type); + + if (name == NULL || name[0] == '\000') + return ""; + + for (discrim_end = name + strlen (name) - 6; discrim_end != name; + discrim_end -= 1) + { + if (STREQN (discrim_end, "___XVN", 6)) + break; + } + if (discrim_end == name) + return ""; + + for (discrim_start = discrim_end; discrim_start != name+3; + discrim_start -= 1) + { + if (discrim_start == name+1) + return ""; + if ((discrim_start > name+3 && STREQN (discrim_start-3, "___", 3)) + || discrim_start[-1] == '.') + break; + } + + GROW_VECT (result, result_len, discrim_end - discrim_start + 1); + strncpy (result, discrim_start, discrim_end - discrim_start); + result[discrim_end-discrim_start] = '\0'; + return result; +} + +/* Scan STR for a subtype-encoded number, beginning at position K. Put the + position of the character just past the number scanned in *NEW_K, + if NEW_K!=NULL. Put the scanned number in *R, if R!=NULL. Return 1 + if there was a valid number at the given position, and 0 otherwise. A + "subtype-encoded" number consists of the absolute value in decimal, + followed by the letter 'm' to indicate a negative number. Assumes 0m + does not occur. */ + +int +ada_scan_number (str, k, R, new_k) + const char str[]; + int k; + LONGEST *R; + int *new_k; +{ + ULONGEST RU; + + if (! isdigit (str[k])) + return 0; + + /* Do it the hard way so as not to make any assumption about + the relationship of unsigned long (%lu scan format code) and + LONGEST. */ + RU = 0; + while (isdigit (str[k])) + { + RU = RU*10 + (str[k] - '0'); + k += 1; + } + + if (str[k] == 'm') + { + if (R != NULL) + *R = (- (LONGEST) (RU-1)) - 1; + k += 1; + } + else if (R != NULL) + *R = (LONGEST) RU; + + /* NOTE on the above: Technically, C does not say what the results of + - (LONGEST) RU or (LONGEST) -RU are for RU == largest positive + number representable as a LONGEST (although either would probably work + in most implementations). When RU>0, the locution in the then branch + above is always equivalent to the negative of RU. */ + + if (new_k != NULL) + *new_k = k; + return 1; +} + +/* Assuming that TYPE is a variant part wrapper type (a VARIANTS field), + and FIELD_NUM is a valid field number within it, returns 1 iff VAL is + in the range encoded by field FIELD_NUM of TYPE; otherwise 0. */ + +int +ada_in_variant (val, type, field_num) + LONGEST val; + struct type *type; + int field_num; +{ + const char* name = TYPE_FIELD_NAME (type, field_num); + int p; + + p = 0; + while (1) + { + switch (name[p]) + { + case '\0': + return 0; + case 'S': + { + LONGEST W; + if (! ada_scan_number (name, p + 1, &W, &p)) + return 0; + if (val == W) + return 1; + break; + } + case 'R': + { + LONGEST L, U; + if (! ada_scan_number (name, p + 1, &L, &p) + || name[p] != 'T' + || ! ada_scan_number (name, p + 1, &U, &p)) + return 0; + if (val >= L && val <= U) + return 1; + break; + } + case 'O': + return 1; + default: + return 0; + } + } +} + +/* Given a value ARG1 (offset by OFFSET bytes) + of a struct or union type ARG_TYPE, + extract and return the value of one of its (non-static) fields. + FIELDNO says which field. Differs from value_primitive_field only + in that it can handle packed values of arbitrary type. */ + +struct value* +ada_value_primitive_field (arg1, offset, fieldno, arg_type) + struct value* arg1; + int offset; + int fieldno; + struct type *arg_type; +{ + struct value* v; + struct type *type; + + CHECK_TYPEDEF (arg_type); + type = TYPE_FIELD_TYPE (arg_type, fieldno); + + /* Handle packed fields */ + + if (TYPE_FIELD_BITSIZE (arg_type, fieldno) != 0) + { + int bit_pos = TYPE_FIELD_BITPOS (arg_type, fieldno); + int bit_size = TYPE_FIELD_BITSIZE (arg_type, fieldno); + + return ada_value_primitive_packed_val (arg1, VALUE_CONTENTS (arg1), + offset + bit_pos/8, bit_pos % 8, + bit_size, type); + } + else + return value_primitive_field (arg1, offset, fieldno, arg_type); +} + + +/* Look for a field NAME in ARG. Adjust the address of ARG by OFFSET bytes, + and search in it assuming it has (class) type TYPE. + If found, return value, else return NULL. + + Searches recursively through wrapper fields (e.g., '_parent'). */ + +struct value* +ada_search_struct_field (name, arg, offset, type) + char *name; + struct value* arg; + int offset; + struct type *type; +{ + int i; + CHECK_TYPEDEF (type); + + for (i = TYPE_NFIELDS (type)-1; i >= 0; i -= 1) + { + char *t_field_name = TYPE_FIELD_NAME (type, i); + + if (t_field_name == NULL) + continue; + + else if (field_name_match (t_field_name, name)) + return ada_value_primitive_field (arg, offset, i, type); + + else if (ada_is_wrapper_field (type, i)) + { + struct value* v = + ada_search_struct_field (name, arg, + offset + TYPE_FIELD_BITPOS (type, i) / 8, + TYPE_FIELD_TYPE (type, i)); + if (v != NULL) + return v; + } + + else if (ada_is_variant_part (type, i)) + { + int j; + struct type *field_type = check_typedef (TYPE_FIELD_TYPE (type, i)); + int var_offset = offset + TYPE_FIELD_BITPOS (type, i) / 8; + + for (j = TYPE_NFIELDS (field_type) - 1; j >= 0; j -= 1) + { + struct value* v = + ada_search_struct_field (name, arg, + var_offset + + TYPE_FIELD_BITPOS (field_type, j)/8, + TYPE_FIELD_TYPE (field_type, j)); + if (v != NULL) + return v; + } + } + } + return NULL; +} + +/* Given ARG, a value of type (pointer to a)* structure/union, + extract the component named NAME from the ultimate target structure/union + and return it as a value with its appropriate type. + + The routine searches for NAME among all members of the structure itself + and (recursively) among all members of any wrapper members + (e.g., '_parent'). + + ERR is a name (for use in error messages) that identifies the class + of entity that ARG is supposed to be. */ + +struct value* +ada_value_struct_elt (arg, name, err) + struct value* arg; + char *name; + char *err; +{ + struct type *t; + struct value* v; + + arg = ada_coerce_ref (arg); + t = check_typedef (VALUE_TYPE (arg)); + + /* Follow pointers until we get to a non-pointer. */ + + while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF) + { + arg = ada_value_ind (arg); + t = check_typedef (VALUE_TYPE (arg)); + } + + if ( TYPE_CODE (t) != TYPE_CODE_STRUCT + && TYPE_CODE (t) != TYPE_CODE_UNION) + error ("Attempt to extract a component of a value that is not a %s.", err); + + v = ada_search_struct_field (name, arg, 0, t); + if (v == NULL) + error ("There is no member named %s.", name); + + return v; +} + +/* Given a type TYPE, look up the type of the component of type named NAME. + If DISPP is non-null, add its byte displacement from the beginning of a + structure (pointed to by a value) of type TYPE to *DISPP (does not + work for packed fields). + + Matches any field whose name has NAME as a prefix, possibly + followed by "___". + + TYPE can be either a struct or union, or a pointer or reference to + a struct or union. If it is a pointer or reference, its target + type is automatically used. + + Looks recursively into variant clauses and parent types. + + If NOERR is nonzero, return NULL if NAME is not suitably defined. */ + +struct type * +ada_lookup_struct_elt_type (type, name, noerr, dispp) + struct type *type; + char *name; + int noerr; + int *dispp; +{ + int i; + + if (name == NULL) + goto BadName; + + while (1) + { + CHECK_TYPEDEF (type); + if (TYPE_CODE (type) != TYPE_CODE_PTR + && TYPE_CODE (type) != TYPE_CODE_REF) + break; + type = TYPE_TARGET_TYPE (type); + } + + if (TYPE_CODE (type) != TYPE_CODE_STRUCT && + TYPE_CODE (type) != TYPE_CODE_UNION) + { + target_terminal_ours (); + gdb_flush (gdb_stdout); + fprintf_unfiltered (gdb_stderr, "Type "); + type_print (type, "", gdb_stderr, -1); + error (" is not a structure or union type"); + } + + type = to_static_fixed_type (type); + + for (i = 0; i < TYPE_NFIELDS (type); i += 1) + { + char *t_field_name = TYPE_FIELD_NAME (type, i); + struct type *t; + int disp; + + if (t_field_name == NULL) + continue; + + else if (field_name_match (t_field_name, name)) + { + if (dispp != NULL) + *dispp += TYPE_FIELD_BITPOS (type, i) / 8; + return check_typedef (TYPE_FIELD_TYPE (type, i)); + } + + else if (ada_is_wrapper_field (type, i)) + { + disp = 0; + t = ada_lookup_struct_elt_type (TYPE_FIELD_TYPE (type, i), name, + 1, &disp); + if (t != NULL) + { + if (dispp != NULL) + *dispp += disp + TYPE_FIELD_BITPOS (type, i) / 8; + return t; + } + } + + else if (ada_is_variant_part (type, i)) + { + int j; + struct type *field_type = check_typedef (TYPE_FIELD_TYPE (type, i)); + + for (j = TYPE_NFIELDS (field_type) - 1; j >= 0; j -= 1) + { + disp = 0; + t = ada_lookup_struct_elt_type (TYPE_FIELD_TYPE (field_type, j), + name, 1, &disp); + if (t != NULL) + { + if (dispp != NULL) + *dispp += disp + TYPE_FIELD_BITPOS (type, i) / 8; + return t; + } + } + } + + } + +BadName: + if (! noerr) + { + target_terminal_ours (); + gdb_flush (gdb_stdout); + fprintf_unfiltered (gdb_stderr, "Type "); + type_print (type, "", gdb_stderr, -1); + fprintf_unfiltered (gdb_stderr, " has no component named "); + error ("%s", name == NULL ? "<null>" : name); + } + + return NULL; +} + +/* Assuming that VAR_TYPE is the type of a variant part of a record (a union), + within a value of type OUTER_TYPE that is stored in GDB at + OUTER_VALADDR, determine which variant clause (field number in VAR_TYPE, + numbering from 0) is applicable. Returns -1 if none are. */ + +int +ada_which_variant_applies (var_type, outer_type, outer_valaddr) + struct type *var_type; + struct type *outer_type; + char* outer_valaddr; +{ + int others_clause; + int i; + int disp; + struct type* discrim_type; + char* discrim_name = ada_variant_discrim_name (var_type); + LONGEST discrim_val; + + disp = 0; + discrim_type = + ada_lookup_struct_elt_type (outer_type, discrim_name, 1, &disp); + if (discrim_type == NULL) + return -1; + discrim_val = unpack_long (discrim_type, outer_valaddr + disp); + + others_clause = -1; + for (i = 0; i < TYPE_NFIELDS (var_type); i += 1) + { + if (ada_is_others_clause (var_type, i)) + others_clause = i; + else if (ada_in_variant (discrim_val, var_type, i)) + return i; + } + + return others_clause; +} + + + + /* Dynamic-Sized Records */ + +/* Strategy: The type ostensibly attached to a value with dynamic size + (i.e., a size that is not statically recorded in the debugging + data) does not accurately reflect the size or layout of the value. + Our strategy is to convert these values to values with accurate, + conventional types that are constructed on the fly. */ + +/* There is a subtle and tricky problem here. In general, we cannot + determine the size of dynamic records without its data. However, + the 'struct value' data structure, which GDB uses to represent + quantities in the inferior process (the target), requires the size + of the type at the time of its allocation in order to reserve space + for GDB's internal copy of the data. That's why the + 'to_fixed_xxx_type' routines take (target) addresses as parameters, + rather than struct value*s. + + However, GDB's internal history variables ($1, $2, etc.) are + struct value*s containing internal copies of the data that are not, in + general, the same as the data at their corresponding addresses in + the target. Fortunately, the types we give to these values are all + conventional, fixed-size types (as per the strategy described + above), so that we don't usually have to perform the + 'to_fixed_xxx_type' conversions to look at their values. + Unfortunately, there is one exception: if one of the internal + history variables is an array whose elements are unconstrained + records, then we will need to create distinct fixed types for each + element selected. */ + +/* The upshot of all of this is that many routines take a (type, host + address, target address) triple as arguments to represent a value. + The host address, if non-null, is supposed to contain an internal + copy of the relevant data; otherwise, the program is to consult the + target at the target address. */ + +/* Assuming that VAL0 represents a pointer value, the result of + dereferencing it. Differs from value_ind in its treatment of + dynamic-sized types. */ + +struct value* +ada_value_ind (val0) + struct value* val0; +{ + struct value* val = unwrap_value (value_ind (val0)); + return ada_to_fixed_value (VALUE_TYPE (val), 0, + VALUE_ADDRESS (val) + VALUE_OFFSET (val), + val); +} + +/* The value resulting from dereferencing any "reference to" + * qualifiers on VAL0. */ +static struct value* +ada_coerce_ref (val0) + struct value* val0; +{ + if (TYPE_CODE (VALUE_TYPE (val0)) == TYPE_CODE_REF) { + struct value* val = val0; + COERCE_REF (val); + val = unwrap_value (val); + return ada_to_fixed_value (VALUE_TYPE (val), 0, + VALUE_ADDRESS (val) + VALUE_OFFSET (val), + val); + } else + return val0; +} + +/* Return OFF rounded upward if necessary to a multiple of + ALIGNMENT (a power of 2). */ + +static unsigned int +align_value (off, alignment) + unsigned int off; + unsigned int alignment; +{ + return (off + alignment - 1) & ~(alignment - 1); +} + +/* Return the additional bit offset required by field F of template + type TYPE. */ + +static unsigned int +field_offset (type, f) + struct type *type; + int f; +{ + int n = TYPE_FIELD_BITPOS (type, f); + /* Kludge (temporary?) to fix problem with dwarf output. */ + if (n < 0) + return (unsigned int) n & 0xffff; + else + return n; +} + + +/* Return the bit alignment required for field #F of template type TYPE. */ + +static unsigned int +field_alignment (type, f) + struct type *type; + int f; +{ + const char* name = TYPE_FIELD_NAME (type, f); + int len = (name == NULL) ? 0 : strlen (name); + int align_offset; + + if (len < 8 || ! isdigit (name[len-1])) + return TARGET_CHAR_BIT; + + if (isdigit (name[len-2])) + align_offset = len - 2; + else + align_offset = len - 1; + + if (align_offset < 7 || ! STREQN ("___XV", name+align_offset-6, 5)) + return TARGET_CHAR_BIT; + + return atoi (name+align_offset) * TARGET_CHAR_BIT; +} + +/* Find a type named NAME. Ignores ambiguity. */ +struct type* +ada_find_any_type (name) + const char *name; +{ + struct symbol* sym; + + sym = standard_lookup (name, VAR_NAMESPACE); + if (sym != NULL && SYMBOL_CLASS (sym) == LOC_TYPEDEF) + return SYMBOL_TYPE (sym); + + sym = standard_lookup (name, STRUCT_NAMESPACE); + if (sym != NULL) + return SYMBOL_TYPE (sym); + + return NULL; +} + +/* Because of GNAT encoding conventions, several GDB symbols may match a + given type name. If the type denoted by TYPE0 is to be preferred to + that of TYPE1 for purposes of type printing, return non-zero; + otherwise return 0. */ +int +ada_prefer_type (type0, type1) + struct type* type0; + struct type* type1; +{ + if (type1 == NULL) + return 1; + else if (type0 == NULL) + return 0; + else if (TYPE_CODE (type1) == TYPE_CODE_VOID) + return 1; + else if (TYPE_CODE (type0) == TYPE_CODE_VOID) + return 0; + else if (ada_is_packed_array_type (type0)) + return 1; + else if (ada_is_array_descriptor (type0) && ! ada_is_array_descriptor (type1)) + return 1; + else if (ada_renaming_type (type0) != NULL + && ada_renaming_type (type1) == NULL) + return 1; + return 0; +} + +/* The name of TYPE, which is either its TYPE_NAME, or, if that is + null, its TYPE_TAG_NAME. Null if TYPE is null. */ +char* +ada_type_name (type) + struct type* type; +{ + if (type == NULL) + return NULL; + else if (TYPE_NAME (type) != NULL) + return TYPE_NAME (type); + else + return TYPE_TAG_NAME (type); +} + +/* Find a parallel type to TYPE whose name is formed by appending + SUFFIX to the name of TYPE. */ + +struct type* +ada_find_parallel_type (type, suffix) + struct type *type; + const char *suffix; +{ + static char* name; + static size_t name_len = 0; + struct symbol** syms; + struct block** blocks; + int nsyms; + int len; + char* typename = ada_type_name (type); + + if (typename == NULL) + return NULL; + + len = strlen (typename); + + GROW_VECT (name, name_len, len+strlen (suffix)+1); + + strcpy (name, typename); + strcpy (name + len, suffix); + + return ada_find_any_type (name); +} + + +/* If TYPE is a variable-size record type, return the corresponding template + type describing its fields. Otherwise, return NULL. */ + +static struct type* +dynamic_template_type (type) + struct type* type; +{ + CHECK_TYPEDEF (type); + + if (type == NULL || TYPE_CODE (type) != TYPE_CODE_STRUCT + || ada_type_name (type) == NULL) + return NULL; + else + { + int len = strlen (ada_type_name (type)); + if (len > 6 && STREQ (ada_type_name (type) + len - 6, "___XVE")) + return type; + else + return ada_find_parallel_type (type, "___XVE"); + } +} + +/* Assuming that TEMPL_TYPE is a union or struct type, returns + non-zero iff field FIELD_NUM of TEMPL_TYPE has dynamic size. */ + +static int +is_dynamic_field (templ_type, field_num) + struct type* templ_type; + int field_num; +{ + const char *name = TYPE_FIELD_NAME (templ_type, field_num); + return name != NULL + && TYPE_CODE (TYPE_FIELD_TYPE (templ_type, field_num)) == TYPE_CODE_PTR + && strstr (name, "___XVL") != NULL; +} + +/* Assuming that TYPE is a struct type, returns non-zero iff TYPE + contains a variant part. */ + +static int +contains_variant_part (type) + struct type* type; +{ + int f; + + if (type == NULL || TYPE_CODE (type) != TYPE_CODE_STRUCT + || TYPE_NFIELDS (type) <= 0) + return 0; + return ada_is_variant_part (type, TYPE_NFIELDS (type) - 1); +} + +/* A record type with no fields, . */ +static struct type* +empty_record (objfile) + struct objfile* objfile; +{ + struct type* type = alloc_type (objfile); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + TYPE_NFIELDS (type) = 0; + TYPE_FIELDS (type) = NULL; + TYPE_NAME (type) = "<empty>"; + TYPE_TAG_NAME (type) = NULL; + TYPE_FLAGS (type) = 0; + TYPE_LENGTH (type) = 0; + return type; +} + +/* An ordinary record type (with fixed-length fields) that describes + the value of type TYPE at VALADDR or ADDRESS (see comments at + the beginning of this section) VAL according to GNAT conventions. + DVAL0 should describe the (portion of a) record that contains any + necessary discriminants. It should be NULL if VALUE_TYPE (VAL) is + an outer-level type (i.e., as opposed to a branch of a variant.) A + variant field (unless unchecked) is replaced by a particular branch + of the variant. */ +/* NOTE: Limitations: For now, we assume that dynamic fields and + * variants occupy whole numbers of bytes. However, they need not be + * byte-aligned. */ + +static struct type* +template_to_fixed_record_type (type, valaddr, address, dval0) + struct type* type; + char* valaddr; + CORE_ADDR address; + struct value* dval0; + +{ + struct value* mark = value_mark(); + struct value* dval; + struct type* rtype; + int nfields, bit_len; + long off; + int f; + + nfields = TYPE_NFIELDS (type); + rtype = alloc_type (TYPE_OBJFILE (type)); + TYPE_CODE (rtype) = TYPE_CODE_STRUCT; + INIT_CPLUS_SPECIFIC (rtype); + TYPE_NFIELDS (rtype) = nfields; + TYPE_FIELDS (rtype) = (struct field*) + TYPE_ALLOC (rtype, nfields * sizeof (struct field)); + memset (TYPE_FIELDS (rtype), 0, sizeof (struct field) * nfields); + TYPE_NAME (rtype) = ada_type_name (type); + TYPE_TAG_NAME (rtype) = NULL; + /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in + gdbtypes.h */ + /* TYPE_FLAGS (rtype) |= TYPE_FLAG_FIXED_INSTANCE;*/ + + off = 0; bit_len = 0; + for (f = 0; f < nfields; f += 1) + { + int fld_bit_len, bit_incr; + off = + align_value (off, field_alignment (type, f))+TYPE_FIELD_BITPOS (type,f); + /* NOTE: used to use field_offset above, but that causes + * problems with really negative bit positions. So, let's + * rediscover why we needed field_offset and fix it properly. */ + TYPE_FIELD_BITPOS (rtype, f) = off; + TYPE_FIELD_BITSIZE (rtype, f) = 0; + + if (ada_is_variant_part (type, f)) + { + struct type *branch_type; + + if (dval0 == NULL) + dval = + value_from_contents_and_address (rtype, valaddr, address); + else + dval = dval0; + + branch_type = + to_fixed_variant_branch_type + (TYPE_FIELD_TYPE (type, f), + cond_offset_host (valaddr, off / TARGET_CHAR_BIT), + cond_offset_target (address, off / TARGET_CHAR_BIT), + dval); + if (branch_type == NULL) + TYPE_NFIELDS (rtype) -= 1; + else + { + TYPE_FIELD_TYPE (rtype, f) = branch_type; + TYPE_FIELD_NAME (rtype, f) = "S"; + } + bit_incr = 0; + fld_bit_len = + TYPE_LENGTH (TYPE_FIELD_TYPE (rtype, f)) * TARGET_CHAR_BIT; + } + else if (is_dynamic_field (type, f)) + { + if (dval0 == NULL) + dval = + value_from_contents_and_address (rtype, valaddr, address); + else + dval = dval0; + + TYPE_FIELD_TYPE (rtype, f) = + ada_to_fixed_type + (ada_get_base_type + (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, f))), + cond_offset_host (valaddr, off / TARGET_CHAR_BIT), + cond_offset_target (address, off / TARGET_CHAR_BIT), + dval); + TYPE_FIELD_NAME (rtype, f) = TYPE_FIELD_NAME (type, f); + bit_incr = fld_bit_len = + TYPE_LENGTH (TYPE_FIELD_TYPE (rtype, f)) * TARGET_CHAR_BIT; + } + else + { + TYPE_FIELD_TYPE (rtype, f) = TYPE_FIELD_TYPE (type, f); + TYPE_FIELD_NAME (rtype, f) = TYPE_FIELD_NAME (type, f); + if (TYPE_FIELD_BITSIZE (type, f) > 0) + bit_incr = fld_bit_len = + TYPE_FIELD_BITSIZE (rtype, f) = TYPE_FIELD_BITSIZE (type, f); + else + bit_incr = fld_bit_len = + TYPE_LENGTH (TYPE_FIELD_TYPE (type, f)) * TARGET_CHAR_BIT; + } + if (off + fld_bit_len > bit_len) + bit_len = off + fld_bit_len; + off += bit_incr; + TYPE_LENGTH (rtype) = bit_len / TARGET_CHAR_BIT; + } + TYPE_LENGTH (rtype) = align_value (TYPE_LENGTH (rtype), TYPE_LENGTH (type)); + + value_free_to_mark (mark); + if (TYPE_LENGTH (rtype) > varsize_limit) + error ("record type with dynamic size is larger than varsize-limit"); + return rtype; +} + +/* As for template_to_fixed_record_type, but uses no run-time values. + As a result, this type can only be approximate, but that's OK, + since it is used only for type determinations. Works on both + structs and unions. + Representation note: to save space, we memoize the result of this + function in the TYPE_TARGET_TYPE of the template type. */ + +static struct type* +template_to_static_fixed_type (templ_type) + struct type* templ_type; +{ + struct type *type; + int nfields; + int f; + + if (TYPE_TARGET_TYPE (templ_type) != NULL) + return TYPE_TARGET_TYPE (templ_type); + + nfields = TYPE_NFIELDS (templ_type); + TYPE_TARGET_TYPE (templ_type) = type = alloc_type (TYPE_OBJFILE (templ_type)); + TYPE_CODE (type) = TYPE_CODE (templ_type); + INIT_CPLUS_SPECIFIC (type); + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = (struct field*) + TYPE_ALLOC (type, nfields * sizeof (struct field)); + memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields); + TYPE_NAME (type) = ada_type_name (templ_type); + TYPE_TAG_NAME (type) = NULL; + /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */ + /* TYPE_FLAGS (type) |= TYPE_FLAG_FIXED_INSTANCE; */ + TYPE_LENGTH (type) = 0; + + for (f = 0; f < nfields; f += 1) + { + TYPE_FIELD_BITPOS (type, f) = 0; + TYPE_FIELD_BITSIZE (type, f) = 0; + + if (is_dynamic_field (templ_type, f)) + { + TYPE_FIELD_TYPE (type, f) = + to_static_fixed_type (TYPE_TARGET_TYPE + (TYPE_FIELD_TYPE (templ_type, f))); + TYPE_FIELD_NAME (type, f) = TYPE_FIELD_NAME (templ_type, f); + } + else + { + TYPE_FIELD_TYPE (type, f) = + check_typedef (TYPE_FIELD_TYPE (templ_type, f)); + TYPE_FIELD_NAME (type, f) = TYPE_FIELD_NAME (templ_type, f); + } + } + + return type; +} + +/* A revision of TYPE0 -- a non-dynamic-sized record with a variant + part -- in which the variant part is replaced with the appropriate + branch. */ +static struct type* +to_record_with_fixed_variant_part (type, valaddr, address, dval) + struct type* type; + char* valaddr; + CORE_ADDR address; + struct value* dval; +{ + struct value* mark = value_mark(); + struct type* rtype; + struct type *branch_type; + int nfields = TYPE_NFIELDS (type); + + if (dval == NULL) + return type; + + rtype = alloc_type (TYPE_OBJFILE (type)); + TYPE_CODE (rtype) = TYPE_CODE_STRUCT; + INIT_CPLUS_SPECIFIC (type); + TYPE_NFIELDS (rtype) = TYPE_NFIELDS (type); + TYPE_FIELDS (rtype) = + (struct field*) TYPE_ALLOC (rtype, nfields * sizeof (struct field)); + memcpy (TYPE_FIELDS (rtype), TYPE_FIELDS (type), + sizeof (struct field) * nfields); + TYPE_NAME (rtype) = ada_type_name (type); + TYPE_TAG_NAME (rtype) = NULL; + /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */ + /* TYPE_FLAGS (rtype) |= TYPE_FLAG_FIXED_INSTANCE; */ + TYPE_LENGTH (rtype) = TYPE_LENGTH (type); + + branch_type = + to_fixed_variant_branch_type + (TYPE_FIELD_TYPE (type, nfields - 1), + cond_offset_host (valaddr, + TYPE_FIELD_BITPOS (type, nfields-1) / TARGET_CHAR_BIT), + cond_offset_target (address, + TYPE_FIELD_BITPOS (type, nfields-1) / TARGET_CHAR_BIT), + dval); + if (branch_type == NULL) + { + TYPE_NFIELDS (rtype) -= 1; + TYPE_LENGTH (rtype) -= TYPE_LENGTH (TYPE_FIELD_TYPE (type, nfields - 1)); + } + else + { + TYPE_FIELD_TYPE (rtype, nfields-1) = branch_type; + TYPE_FIELD_NAME (rtype, nfields-1) = "S"; + TYPE_FIELD_BITSIZE (rtype, nfields-1) = 0; + TYPE_LENGTH (rtype) += TYPE_LENGTH (branch_type); + - TYPE_LENGTH (TYPE_FIELD_TYPE (type, nfields - 1)); + } + + return rtype; +} + +/* An ordinary record type (with fixed-length fields) that describes + the value at (TYPE0, VALADDR, ADDRESS) [see explanation at + beginning of this section]. Any necessary discriminants' values + should be in DVAL, a record value; it should be NULL if the object + at ADDR itself contains any necessary discriminant values. A + variant field (unless unchecked) is replaced by a particular branch + of the variant. */ + +static struct type* +to_fixed_record_type (type0, valaddr, address, dval) + struct type* type0; + char* valaddr; + CORE_ADDR address; + struct value* dval; +{ + struct type* templ_type; + + /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */ + /* if (TYPE_FLAGS (type0) & TYPE_FLAG_FIXED_INSTANCE) + return type0; + */ + templ_type = dynamic_template_type (type0); + + if (templ_type != NULL) + return template_to_fixed_record_type (templ_type, valaddr, address, dval); + else if (contains_variant_part (type0)) + return to_record_with_fixed_variant_part (type0, valaddr, address, dval); + else + { + /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */ + /* TYPE_FLAGS (type0) |= TYPE_FLAG_FIXED_INSTANCE; */ + return type0; + } + +} + +/* An ordinary record type (with fixed-length fields) that describes + the value at (VAR_TYPE0, VALADDR, ADDRESS), where VAR_TYPE0 is a + union type. Any necessary discriminants' values should be in DVAL, + a record value. That is, this routine selects the appropriate + branch of the union at ADDR according to the discriminant value + indicated in the union's type name. */ + +static struct type* +to_fixed_variant_branch_type (var_type0, valaddr, address, dval) + struct type* var_type0; + char* valaddr; + CORE_ADDR address; + struct value* dval; +{ + int which; + struct type* templ_type; + struct type* var_type; + + if (TYPE_CODE (var_type0) == TYPE_CODE_PTR) + var_type = TYPE_TARGET_TYPE (var_type0); + else + var_type = var_type0; + + templ_type = ada_find_parallel_type (var_type, "___XVU"); + + if (templ_type != NULL) + var_type = templ_type; + + which = + ada_which_variant_applies (var_type, + VALUE_TYPE (dval), VALUE_CONTENTS (dval)); + + if (which < 0) + return empty_record (TYPE_OBJFILE (var_type)); + else if (is_dynamic_field (var_type, which)) + return + to_fixed_record_type + (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (var_type, which)), + valaddr, address, dval); + else if (contains_variant_part (TYPE_FIELD_TYPE (var_type, which))) + return + to_fixed_record_type + (TYPE_FIELD_TYPE (var_type, which), valaddr, address, dval); + else + return TYPE_FIELD_TYPE (var_type, which); +} + +/* Assuming that TYPE0 is an array type describing the type of a value + at ADDR, and that DVAL describes a record containing any + discriminants used in TYPE0, returns a type for the value that + contains no dynamic components (that is, no components whose sizes + are determined by run-time quantities). Unless IGNORE_TOO_BIG is + true, gives an error message if the resulting type's size is over + varsize_limit. +*/ + +static struct type* +to_fixed_array_type (type0, dval, ignore_too_big) + struct type* type0; + struct value* dval; + int ignore_too_big; +{ + struct type* index_type_desc; + struct type* result; + + /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */ + /* if (ada_is_packed_array_type (type0) /* revisit? */ /* + || (TYPE_FLAGS (type0) & TYPE_FLAG_FIXED_INSTANCE)) + return type0;*/ + + index_type_desc = ada_find_parallel_type (type0, "___XA"); + if (index_type_desc == NULL) + { + struct type *elt_type0 = check_typedef (TYPE_TARGET_TYPE (type0)); + /* NOTE: elt_type---the fixed version of elt_type0---should never + * depend on the contents of the array in properly constructed + * debugging data. */ + struct type *elt_type = + ada_to_fixed_type (elt_type0, 0, 0, dval); + + if (elt_type0 == elt_type) + result = type0; + else + result = create_array_type (alloc_type (TYPE_OBJFILE (type0)), + elt_type, TYPE_INDEX_TYPE (type0)); + } + else + { + int i; + struct type *elt_type0; + + elt_type0 = type0; + for (i = TYPE_NFIELDS (index_type_desc); i > 0; i -= 1) + elt_type0 = TYPE_TARGET_TYPE (elt_type0); + + /* NOTE: result---the fixed version of elt_type0---should never + * depend on the contents of the array in properly constructed + * debugging data. */ + result = + ada_to_fixed_type (check_typedef (elt_type0), 0, 0, dval); + for (i = TYPE_NFIELDS (index_type_desc) - 1; i >= 0; i -= 1) + { + struct type *range_type = + to_fixed_range_type (TYPE_FIELD_NAME (index_type_desc, i), + dval, TYPE_OBJFILE (type0)); + result = create_array_type (alloc_type (TYPE_OBJFILE (type0)), + result, range_type); + } + if (! ignore_too_big && TYPE_LENGTH (result) > varsize_limit) + error ("array type with dynamic size is larger than varsize-limit"); + } + +/* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */ +/* TYPE_FLAGS (result) |= TYPE_FLAG_FIXED_INSTANCE; */ + return result; +} + + +/* A standard type (containing no dynamically sized components) + corresponding to TYPE for the value (TYPE, VALADDR, ADDRESS) + DVAL describes a record containing any discriminants used in TYPE0, + and may be NULL if there are none. */ + +struct type* +ada_to_fixed_type (type, valaddr, address, dval) + struct type* type; + char* valaddr; + CORE_ADDR address; + struct value* dval; +{ + CHECK_TYPEDEF (type); + switch (TYPE_CODE (type)) { + default: + return type; + case TYPE_CODE_STRUCT: + return to_fixed_record_type (type, valaddr, address, NULL); + case TYPE_CODE_ARRAY: + return to_fixed_array_type (type, dval, 0); + case TYPE_CODE_UNION: + if (dval == NULL) + return type; + else + return to_fixed_variant_branch_type (type, valaddr, address, dval); + } +} + +/* A standard (static-sized) type corresponding as well as possible to + TYPE0, but based on no runtime data. */ + +static struct type* +to_static_fixed_type (type0) + struct type* type0; +{ + struct type* type; + + if (type0 == NULL) + return NULL; + + /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */ + /* if (TYPE_FLAGS (type0) & TYPE_FLAG_FIXED_INSTANCE) + return type0; + */ + CHECK_TYPEDEF (type0); + + switch (TYPE_CODE (type0)) + { + default: + return type0; + case TYPE_CODE_STRUCT: + type = dynamic_template_type (type0); + if (type != NULL) + return template_to_static_fixed_type (type); + return type0; + case TYPE_CODE_UNION: + type = ada_find_parallel_type (type0, "___XVU"); + if (type != NULL) + return template_to_static_fixed_type (type); + return type0; + } +} + +/* A static approximation of TYPE with all type wrappers removed. */ +static struct type* +static_unwrap_type (type) + struct type* type; +{ + if (ada_is_aligner_type (type)) + { + struct type* type1 = TYPE_FIELD_TYPE (check_typedef (type), 0); + if (ada_type_name (type1) == NULL) + TYPE_NAME (type1) = ada_type_name (type); + + return static_unwrap_type (type1); + } + else + { + struct type* raw_real_type = ada_get_base_type (type); + if (raw_real_type == type) + return type; + else + return to_static_fixed_type (raw_real_type); + } +} + +/* In some cases, incomplete and private types require + cross-references that are not resolved as records (for example, + type Foo; + type FooP is access Foo; + V: FooP; + type Foo is array ...; + ). In these cases, since there is no mechanism for producing + cross-references to such types, we instead substitute for FooP a + stub enumeration type that is nowhere resolved, and whose tag is + the name of the actual type. Call these types "non-record stubs". */ + +/* A type equivalent to TYPE that is not a non-record stub, if one + exists, otherwise TYPE. */ +struct type* +ada_completed_type (type) + struct type* type; +{ + CHECK_TYPEDEF (type); + if (type == NULL || TYPE_CODE (type) != TYPE_CODE_ENUM + || (TYPE_FLAGS (type) & TYPE_FLAG_STUB) == 0 + || TYPE_TAG_NAME (type) == NULL) + return type; + else + { + char* name = TYPE_TAG_NAME (type); + struct type* type1 = ada_find_any_type (name); + return (type1 == NULL) ? type : type1; + } +} + +/* A value representing the data at VALADDR/ADDRESS as described by + type TYPE0, but with a standard (static-sized) type that correctly + describes it. If VAL0 is not NULL and TYPE0 already is a standard + type, then return VAL0 [this feature is simply to avoid redundant + creation of struct values]. */ + +struct value* +ada_to_fixed_value (type0, valaddr, address, val0) + struct type* type0; + char* valaddr; + CORE_ADDR address; + struct value* val0; +{ + struct type* type = ada_to_fixed_type (type0, valaddr, address, NULL); + if (type == type0 && val0 != NULL) + return val0; + else return value_from_contents_and_address (type, valaddr, address); +} + +/* A value representing VAL, but with a standard (static-sized) type + chosen to approximate the real type of VAL as well as possible, but + without consulting any runtime values. For Ada dynamic-sized + types, therefore, the type of the result is likely to be inaccurate. */ + +struct value* +ada_to_static_fixed_value (val) + struct value* val; +{ + struct type *type = + to_static_fixed_type (static_unwrap_type (VALUE_TYPE (val))); + if (type == VALUE_TYPE (val)) + return val; + else + return coerce_unspec_val_to_type (val, 0, type); +} + + + + + +/* Attributes */ + +/* Table mapping attribute numbers to names */ +/* NOTE: Keep up to date with enum ada_attribute definition in ada-lang.h */ + +static const char* attribute_names[] = { + "<?>", + + "first", + "last", + "length", + "image", + "img", + "max", + "min", + "pos" + "tag", + "val", + + 0 +}; + +const char* +ada_attribute_name (n) + int n; +{ + if (n > 0 && n < (int) ATR_END) + return attribute_names[n]; + else + return attribute_names[0]; +} + +/* Evaluate the 'POS attribute applied to ARG. */ + +static struct value* +value_pos_atr (arg) + struct value* arg; +{ + struct type *type = VALUE_TYPE (arg); + + if (! discrete_type_p (type)) + error ("'POS only defined on discrete types"); + + if (TYPE_CODE (type) == TYPE_CODE_ENUM) + { + int i; + LONGEST v = value_as_long (arg); + + for (i = 0; i < TYPE_NFIELDS (type); i += 1) + { + if (v == TYPE_FIELD_BITPOS (type, i)) + return value_from_longest (builtin_type_ada_int, i); + } + error ("enumeration value is invalid: can't find 'POS"); + } + else + return value_from_longest (builtin_type_ada_int, value_as_long (arg)); +} + +/* Evaluate the TYPE'VAL attribute applied to ARG. */ + +static struct value* +value_val_atr (type, arg) + struct type *type; + struct value* arg; +{ + if (! discrete_type_p (type)) + error ("'VAL only defined on discrete types"); + if (! integer_type_p (VALUE_TYPE (arg))) + error ("'VAL requires integral argument"); + + if (TYPE_CODE (type) == TYPE_CODE_ENUM) + { + long pos = value_as_long (arg); + if (pos < 0 || pos >= TYPE_NFIELDS (type)) + error ("argument to 'VAL out of range"); + return + value_from_longest (type, TYPE_FIELD_BITPOS (type, pos)); + } + else + return value_from_longest (type, value_as_long (arg)); +} + + + /* Evaluation */ + +/* True if TYPE appears to be an Ada character type. + * [At the moment, this is true only for Character and Wide_Character; + * It is a heuristic test that could stand improvement]. */ + +int +ada_is_character_type (type) + struct type* type; +{ + const char* name = ada_type_name (type); + return + name != NULL + && (TYPE_CODE (type) == TYPE_CODE_CHAR + || TYPE_CODE (type) == TYPE_CODE_INT + || TYPE_CODE (type) == TYPE_CODE_RANGE) + && (STREQ (name, "character") || STREQ (name, "wide_character") + || STREQ (name, "unsigned char")); +} + +/* True if TYPE appears to be an Ada string type. */ + +int +ada_is_string_type (type) + struct type *type; +{ + CHECK_TYPEDEF (type); + if (type != NULL + && TYPE_CODE (type) != TYPE_CODE_PTR + && (ada_is_simple_array (type) || ada_is_array_descriptor (type)) + && ada_array_arity (type) == 1) + { + struct type *elttype = ada_array_element_type (type, 1); + + return ada_is_character_type (elttype); + } + else + return 0; +} + + +/* True if TYPE is a struct type introduced by the compiler to force the + alignment of a value. Such types have a single field with a + distinctive name. */ + +int +ada_is_aligner_type (type) + struct type *type; +{ + CHECK_TYPEDEF (type); + return (TYPE_CODE (type) == TYPE_CODE_STRUCT + && TYPE_NFIELDS (type) == 1 + && STREQ (TYPE_FIELD_NAME (type, 0), "F")); +} + +/* If there is an ___XVS-convention type parallel to SUBTYPE, return + the parallel type. */ + +struct type* +ada_get_base_type (raw_type) + struct type* raw_type; +{ + struct type* real_type_namer; + struct type* raw_real_type; + struct type* real_type; + + if (raw_type == NULL || TYPE_CODE (raw_type) != TYPE_CODE_STRUCT) + return raw_type; + + real_type_namer = ada_find_parallel_type (raw_type, "___XVS"); + if (real_type_namer == NULL + || TYPE_CODE (real_type_namer) != TYPE_CODE_STRUCT + || TYPE_NFIELDS (real_type_namer) != 1) + return raw_type; + + raw_real_type = ada_find_any_type (TYPE_FIELD_NAME (real_type_namer, 0)); + if (raw_real_type == NULL) + return raw_type; + else + return raw_real_type; +} + +/* The type of value designated by TYPE, with all aligners removed. */ + +struct type* +ada_aligned_type (type) + struct type* type; +{ + if (ada_is_aligner_type (type)) + return ada_aligned_type (TYPE_FIELD_TYPE (type, 0)); + else + return ada_get_base_type (type); +} + + +/* The address of the aligned value in an object at address VALADDR + having type TYPE. Assumes ada_is_aligner_type (TYPE). */ + +char* +ada_aligned_value_addr (type, valaddr) + struct type *type; + char *valaddr; +{ + if (ada_is_aligner_type (type)) + return ada_aligned_value_addr (TYPE_FIELD_TYPE (type, 0), + valaddr + + TYPE_FIELD_BITPOS (type, 0)/TARGET_CHAR_BIT); + else + return valaddr; +} + +/* The printed representation of an enumeration literal with encoded + name NAME. The value is good to the next call of ada_enum_name. */ +const char* +ada_enum_name (name) + const char* name; +{ + char* tmp; + + while (1) + { + if ((tmp = strstr (name, "__")) != NULL) + name = tmp+2; + else if ((tmp = strchr (name, '.')) != NULL) + name = tmp+1; + else + break; + } + + if (name[0] == 'Q') + { + static char result[16]; + int v; + if (name[1] == 'U' || name[1] == 'W') + { + if (sscanf (name+2, "%x", &v) != 1) + return name; + } + else + return name; + + if (isascii (v) && isprint (v)) + sprintf (result, "'%c'", v); + else if (name[1] == 'U') + sprintf (result, "[\"%02x\"]", v); + else + sprintf (result, "[\"%04x\"]", v); + + return result; + } + else + return name; +} + +static struct value* +evaluate_subexp (expect_type, exp, pos, noside) + struct type *expect_type; + struct expression *exp; + int *pos; + enum noside noside; +{ + return (*exp->language_defn->evaluate_exp) (expect_type, exp, pos, noside); +} + +/* Evaluate the subexpression of EXP starting at *POS as for + evaluate_type, updating *POS to point just past the evaluated + expression. */ + +static struct value* +evaluate_subexp_type (exp, pos) + struct expression* exp; + int* pos; +{ + return (*exp->language_defn->evaluate_exp) + (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); +} + +/* If VAL is wrapped in an aligner or subtype wrapper, return the + value it wraps. */ + +static struct value* +unwrap_value (val) + struct value* val; +{ + struct type* type = check_typedef (VALUE_TYPE (val)); + if (ada_is_aligner_type (type)) + { + struct value* v = value_struct_elt (&val, NULL, "F", + NULL, "internal structure"); + struct type* val_type = check_typedef (VALUE_TYPE (v)); + if (ada_type_name (val_type) == NULL) + TYPE_NAME (val_type) = ada_type_name (type); + + return unwrap_value (v); + } + else + { + struct type* raw_real_type = + ada_completed_type (ada_get_base_type (type)); + + if (type == raw_real_type) + return val; + + return + coerce_unspec_val_to_type + (val, 0, ada_to_fixed_type (raw_real_type, 0, + VALUE_ADDRESS (val) + VALUE_OFFSET (val), + NULL)); + } +} + +static struct value* +cast_to_fixed (type, arg) + struct type *type; + struct value* arg; +{ + LONGEST val; + + if (type == VALUE_TYPE (arg)) + return arg; + else if (ada_is_fixed_point_type (VALUE_TYPE (arg))) + val = ada_float_to_fixed (type, + ada_fixed_to_float (VALUE_TYPE (arg), + value_as_long (arg))); + else + { + DOUBLEST argd = + value_as_double (value_cast (builtin_type_double, value_copy (arg))); + val = ada_float_to_fixed (type, argd); + } + + return value_from_longest (type, val); +} + +static struct value* +cast_from_fixed_to_double (arg) + struct value* arg; +{ + DOUBLEST val = ada_fixed_to_float (VALUE_TYPE (arg), + value_as_long (arg)); + return value_from_double (builtin_type_double, val); +} + +/* Coerce VAL as necessary for assignment to an lval of type TYPE, and + * return the converted value. */ +static struct value* +coerce_for_assign (type, val) + struct type* type; + struct value* val; +{ + struct type* type2 = VALUE_TYPE (val); + if (type == type2) + return val; + + CHECK_TYPEDEF (type2); + CHECK_TYPEDEF (type); + + if (TYPE_CODE (type2) == TYPE_CODE_PTR && TYPE_CODE (type) == TYPE_CODE_ARRAY) + { + val = ada_value_ind (val); + type2 = VALUE_TYPE (val); + } + + if (TYPE_CODE (type2) == TYPE_CODE_ARRAY + && TYPE_CODE (type) == TYPE_CODE_ARRAY) + { + if (TYPE_LENGTH (type2) != TYPE_LENGTH (type) + || TYPE_LENGTH (TYPE_TARGET_TYPE (type2)) + != TYPE_LENGTH (TYPE_TARGET_TYPE (type2))) + error ("Incompatible types in assignment"); + VALUE_TYPE (val) = type; + } + return val; +} + +struct value* +ada_evaluate_subexp (expect_type, exp, pos, noside) + struct type *expect_type; + struct expression *exp; + int *pos; + enum noside noside; +{ + enum exp_opcode op; + enum ada_attribute atr; + int tem, tem2, tem3; + int pc; + struct value *arg1 = NULL, *arg2 = NULL, *arg3; + struct type *type; + int nargs; + struct value* *argvec; + + pc = *pos; *pos += 1; + op = exp->elts[pc].opcode; + + switch (op) + { + default: + *pos -= 1; + return unwrap_value (evaluate_subexp_standard (expect_type, exp, pos, noside)); + + case UNOP_CAST: + (*pos) += 2; + type = exp->elts[pc + 1].type; + arg1 = evaluate_subexp (type, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (type != check_typedef (VALUE_TYPE (arg1))) + { + if (ada_is_fixed_point_type (type)) + arg1 = cast_to_fixed (type, arg1); + else if (ada_is_fixed_point_type (VALUE_TYPE (arg1))) + arg1 = value_cast (type, cast_from_fixed_to_double (arg1)); + else if (VALUE_LVAL (arg1) == lval_memory) + { + /* This is in case of the really obscure (and undocumented, + but apparently expected) case of (Foo) Bar.all, where Bar + is an integer constant and Foo is a dynamic-sized type. + If we don't do this, ARG1 will simply be relabeled with + TYPE. */ + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (to_static_fixed_type (type), not_lval); + arg1 = + ada_to_fixed_value + (type, 0, VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1), 0); + } + else + arg1 = value_cast (type, arg1); + } + return arg1; + + /* FIXME: UNOP_QUAL should be defined in expression.h */ + /* case UNOP_QUAL: + (*pos) += 2; + type = exp->elts[pc + 1].type; + return ada_evaluate_subexp (type, exp, pos, noside); + */ + case BINOP_ASSIGN: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL); + else + { + if (ada_is_fixed_point_type (VALUE_TYPE (arg1))) + arg2 = cast_to_fixed (VALUE_TYPE (arg1), arg2); + else if (ada_is_fixed_point_type (VALUE_TYPE (arg2))) + error ("Fixed-point values must be assigned to fixed-point variables"); + else + arg2 = coerce_for_assign (VALUE_TYPE (arg1), arg2); + return ada_value_assign (arg1, arg2); + } + + case BINOP_ADD: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL); + else + { + if ((ada_is_fixed_point_type (VALUE_TYPE (arg1)) + || ada_is_fixed_point_type (VALUE_TYPE (arg2))) + && VALUE_TYPE (arg1) != VALUE_TYPE (arg2)) + error ("Operands of fixed-point addition must have the same type"); + return value_cast (VALUE_TYPE (arg1), value_add (arg1, arg2)); + } + + case BINOP_SUB: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL); + else + { + if ((ada_is_fixed_point_type (VALUE_TYPE (arg1)) + || ada_is_fixed_point_type (VALUE_TYPE (arg2))) + && VALUE_TYPE (arg1) != VALUE_TYPE (arg2)) + error ("Operands of fixed-point subtraction must have the same type"); + return value_cast (VALUE_TYPE (arg1), value_sub (arg1, arg2)); + } + + case BINOP_MUL: + case BINOP_DIV: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL); + else + if (noside == EVAL_AVOID_SIDE_EFFECTS + && (op == BINOP_DIV || op == BINOP_REM || op == BINOP_MOD)) + return value_zero (VALUE_TYPE (arg1), not_lval); + else + { + if (ada_is_fixed_point_type (VALUE_TYPE (arg1))) + arg1 = cast_from_fixed_to_double (arg1); + if (ada_is_fixed_point_type (VALUE_TYPE (arg2))) + arg2 = cast_from_fixed_to_double (arg2); + return value_binop (arg1, arg2, op); + } + + case UNOP_NEG: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (unop_user_defined_p (op, arg1)) + return value_x_unop (arg1, op, EVAL_NORMAL); + else if (ada_is_fixed_point_type (VALUE_TYPE (arg1))) + return value_cast (VALUE_TYPE (arg1), value_neg (arg1)); + else + return value_neg (arg1); + + /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */ + /* case OP_UNRESOLVED_VALUE: + /* Only encountered when an unresolved symbol occurs in a + context other than a function call, in which case, it is + illegal. *//* + (*pos) += 3; + if (noside == EVAL_SKIP) + goto nosideret; + else + error ("Unexpected unresolved symbol, %s, during evaluation", + ada_demangle (exp->elts[pc + 2].name)); + */ + case OP_VAR_VALUE: + *pos -= 1; + if (noside == EVAL_SKIP) + { + *pos += 4; + goto nosideret; + } + else if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + *pos += 4; + return value_zero + (to_static_fixed_type + (static_unwrap_type (SYMBOL_TYPE (exp->elts[pc+2].symbol))), + not_lval); + } + else + { + arg1 = unwrap_value (evaluate_subexp_standard (expect_type, exp, pos, + noside)); + return ada_to_fixed_value (VALUE_TYPE (arg1), 0, + VALUE_ADDRESS (arg1) + VALUE_OFFSET(arg1), + arg1); + } + + case OP_ARRAY: + (*pos) += 3; + tem2 = longest_to_int (exp->elts[pc + 1].longconst); + tem3 = longest_to_int (exp->elts[pc + 2].longconst); + nargs = tem3 - tem2 + 1; + type = expect_type ? check_typedef (expect_type) : NULL_TYPE; + + argvec = (struct value* *) alloca (sizeof (struct value*) * (nargs + 1)); + for (tem = 0; tem == 0 || tem < nargs; tem += 1) + /* At least one element gets inserted for the type */ + { + /* Ensure that array expressions are coerced into pointer objects. */ + argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside); + } + if (noside == EVAL_SKIP) + goto nosideret; + return value_array (tem2, tem3, argvec); + + case OP_FUNCALL: + (*pos) += 2; + + /* Allocate arg vector, including space for the function to be + called in argvec[0] and a terminating NULL */ + nargs = longest_to_int (exp->elts[pc + 1].longconst); + argvec = (struct value* *) alloca (sizeof (struct value*) * (nargs + 2)); + + /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */ + /* FIXME: name should be defined in expresion.h */ + /* if (exp->elts[*pos].opcode == OP_UNRESOLVED_VALUE) + error ("Unexpected unresolved symbol, %s, during evaluation", + ada_demangle (exp->elts[pc + 5].name)); + */ + if (0) + { + error ("unexpected code path, FIXME"); + } + else + { + for (tem = 0; tem <= nargs; tem += 1) + argvec[tem] = evaluate_subexp (NULL_TYPE, exp, pos, noside); + argvec[tem] = 0; + + if (noside == EVAL_SKIP) + goto nosideret; + } + + if (TYPE_CODE (VALUE_TYPE (argvec[0])) == TYPE_CODE_REF) + argvec[0] = value_addr (argvec[0]); + + if (ada_is_packed_array_type (VALUE_TYPE (argvec[0]))) + argvec[0] = ada_coerce_to_simple_array (argvec[0]); + + type = check_typedef (VALUE_TYPE (argvec[0])); + if (TYPE_CODE (type) == TYPE_CODE_PTR) + { + switch (TYPE_CODE (check_typedef (TYPE_TARGET_TYPE (type)))) + { + case TYPE_CODE_FUNC: + type = check_typedef (TYPE_TARGET_TYPE (type)); + break; + case TYPE_CODE_ARRAY: + break; + case TYPE_CODE_STRUCT: + if (noside != EVAL_AVOID_SIDE_EFFECTS) + argvec[0] = ada_value_ind (argvec[0]); + type = check_typedef (TYPE_TARGET_TYPE (type)); + break; + default: + error ("cannot subscript or call something of type `%s'", + ada_type_name (VALUE_TYPE (argvec[0]))); + break; + } + } + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_FUNC: + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return allocate_value (TYPE_TARGET_TYPE (type)); + return call_function_by_hand (argvec[0], nargs, argvec + 1); + case TYPE_CODE_STRUCT: + { + int arity = ada_array_arity (type); + type = ada_array_element_type (type, nargs); + if (type == NULL) + error ("cannot subscript or call a record"); + if (arity != nargs) + error ("wrong number of subscripts; expecting %d", arity); + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return allocate_value (ada_aligned_type (type)); + return unwrap_value (ada_value_subscript (argvec[0], nargs, argvec+1)); + } + case TYPE_CODE_ARRAY: + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + type = ada_array_element_type (type, nargs); + if (type == NULL) + error ("element type of array unknown"); + else + return allocate_value (ada_aligned_type (type)); + } + return + unwrap_value (ada_value_subscript + (ada_coerce_to_simple_array (argvec[0]), + nargs, argvec+1)); + case TYPE_CODE_PTR: /* Pointer to array */ + type = to_fixed_array_type (TYPE_TARGET_TYPE (type), NULL, 1); + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + type = ada_array_element_type (type, nargs); + if (type == NULL) + error ("element type of array unknown"); + else + return allocate_value (ada_aligned_type (type)); + } + return + unwrap_value (ada_value_ptr_subscript (argvec[0], type, + nargs, argvec+1)); + + default: + error ("Internal error in evaluate_subexp"); + } + + case TERNOP_SLICE: + { + struct value* array = evaluate_subexp (NULL_TYPE, exp, pos, noside); + int lowbound + = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside)); + int upper + = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside)); + if (noside == EVAL_SKIP) + goto nosideret; + + /* If this is a reference to an array, then dereference it */ + if (TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_REF + && TYPE_TARGET_TYPE (VALUE_TYPE (array)) != NULL + && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (array))) == + TYPE_CODE_ARRAY + && !ada_is_array_descriptor (check_typedef (VALUE_TYPE + (array)))) + { + array = ada_coerce_ref (array); + } + + if (noside == EVAL_AVOID_SIDE_EFFECTS && + ada_is_array_descriptor (check_typedef (VALUE_TYPE (array)))) + { + /* Try to dereference the array, in case it is an access to array */ + struct type * arrType = ada_type_of_array (array, 0); + if (arrType != NULL) + array = value_at_lazy (arrType, 0, NULL); + } + if (ada_is_array_descriptor (VALUE_TYPE (array))) + array = ada_coerce_to_simple_array (array); + + /* If at this point we have a pointer to an array, it means that + it is a pointer to a simple (non-ada) array. We just then + dereference it */ + if (TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_PTR + && TYPE_TARGET_TYPE (VALUE_TYPE (array)) != NULL + && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (array))) == + TYPE_CODE_ARRAY) + { + array = ada_value_ind (array); + } + + if (noside == EVAL_AVOID_SIDE_EFFECTS) + /* The following will get the bounds wrong, but only in contexts + where the value is not being requested (FIXME?). */ + return array; + else + return value_slice (array, lowbound, upper - lowbound + 1); + } + + /* FIXME: UNOP_MBR should be defined in expression.h */ + /* case UNOP_MBR: + (*pos) += 2; + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + type = exp->elts[pc + 1].type; + + if (noside == EVAL_SKIP) + goto nosideret; + + switch (TYPE_CODE (type)) + { + default: + warning ("Membership test incompletely implemented; always returns true"); + return value_from_longest (builtin_type_int, (LONGEST) 1); + + case TYPE_CODE_RANGE: + arg2 = value_from_longest (builtin_type_int, + (LONGEST) TYPE_LOW_BOUND (type)); + arg3 = value_from_longest (builtin_type_int, + (LONGEST) TYPE_HIGH_BOUND (type)); + return + value_from_longest (builtin_type_int, + (value_less (arg1,arg3) + || value_equal (arg1,arg3)) + && (value_less (arg2,arg1) + || value_equal (arg2,arg1))); + } + */ + /* FIXME: BINOP_MBR should be defined in expression.h */ + /* case BINOP_MBR: + (*pos) += 2; + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + + if (noside == EVAL_SKIP) + goto nosideret; + + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (builtin_type_int, not_lval); + + tem = longest_to_int (exp->elts[pc + 1].longconst); + + if (tem < 1 || tem > ada_array_arity (VALUE_TYPE (arg2))) + error ("invalid dimension number to '%s", "range"); + + arg3 = ada_array_bound (arg2, tem, 1); + arg2 = ada_array_bound (arg2, tem, 0); + + return + value_from_longest (builtin_type_int, + (value_less (arg1,arg3) + || value_equal (arg1,arg3)) + && (value_less (arg2,arg1) + || value_equal (arg2,arg1))); + */ + /* FIXME: TERNOP_MBR should be defined in expression.h */ + /* case TERNOP_MBR: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg3 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + + if (noside == EVAL_SKIP) + goto nosideret; + + return + value_from_longest (builtin_type_int, + (value_less (arg1,arg3) + || value_equal (arg1,arg3)) + && (value_less (arg2,arg1) + || value_equal (arg2,arg1))); + */ + /* FIXME: OP_ATTRIBUTE should be defined in expression.h */ + /* case OP_ATTRIBUTE: + *pos += 3; + atr = (enum ada_attribute) longest_to_int (exp->elts[pc + 2].longconst); + switch (atr) + { + default: + error ("unexpected attribute encountered"); + + case ATR_FIRST: + case ATR_LAST: + case ATR_LENGTH: + { + struct type* type_arg; + if (exp->elts[*pos].opcode == OP_TYPE) + { + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + arg1 = NULL; + type_arg = exp->elts[pc + 5].type; + } + else + { + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + type_arg = NULL; + } + + if (exp->elts[*pos].opcode != OP_LONG) + error ("illegal operand to '%s", ada_attribute_name (atr)); + tem = longest_to_int (exp->elts[*pos+2].longconst); + *pos += 4; + + if (noside == EVAL_SKIP) + goto nosideret; + + if (type_arg == NULL) + { + arg1 = ada_coerce_ref (arg1); + + if (ada_is_packed_array_type (VALUE_TYPE (arg1))) + arg1 = ada_coerce_to_simple_array (arg1); + + if (tem < 1 || tem > ada_array_arity (VALUE_TYPE (arg1))) + error ("invalid dimension number to '%s", + ada_attribute_name (atr)); + + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + type = ada_index_type (VALUE_TYPE (arg1), tem); + if (type == NULL) + error ("attempt to take bound of something that is not an array"); + return allocate_value (type); + } + + switch (atr) + { + default: + error ("unexpected attribute encountered"); + case ATR_FIRST: + return ada_array_bound (arg1, tem, 0); + case ATR_LAST: + return ada_array_bound (arg1, tem, 1); + case ATR_LENGTH: + return ada_array_length (arg1, tem); + } + } + else if (TYPE_CODE (type_arg) == TYPE_CODE_RANGE + || TYPE_CODE (type_arg) == TYPE_CODE_INT) + { + struct type* range_type; + char* name = ada_type_name (type_arg); + if (name == NULL) + { + if (TYPE_CODE (type_arg) == TYPE_CODE_RANGE) + range_type = type_arg; + else + error ("unimplemented type attribute"); + } + else + range_type = + to_fixed_range_type (name, NULL, TYPE_OBJFILE (type_arg)); + switch (atr) + { + default: + error ("unexpected attribute encountered"); + case ATR_FIRST: + return value_from_longest (TYPE_TARGET_TYPE (range_type), + TYPE_LOW_BOUND (range_type)); + case ATR_LAST: + return value_from_longest (TYPE_TARGET_TYPE (range_type), + TYPE_HIGH_BOUND (range_type)); + } + } + else if (TYPE_CODE (type_arg) == TYPE_CODE_ENUM) + { + switch (atr) + { + default: + error ("unexpected attribute encountered"); + case ATR_FIRST: + return value_from_longest + (type_arg, TYPE_FIELD_BITPOS (type_arg, 0)); + case ATR_LAST: + return value_from_longest + (type_arg, + TYPE_FIELD_BITPOS (type_arg, + TYPE_NFIELDS (type_arg) - 1)); + } + } + else if (TYPE_CODE (type_arg) == TYPE_CODE_FLT) + error ("unimplemented type attribute"); + else + { + LONGEST low, high; + + if (ada_is_packed_array_type (type_arg)) + type_arg = decode_packed_array_type (type_arg); + + if (tem < 1 || tem > ada_array_arity (type_arg)) + error ("invalid dimension number to '%s", + ada_attribute_name (atr)); + + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + type = ada_index_type (type_arg, tem); + if (type == NULL) + error ("attempt to take bound of something that is not an array"); + return allocate_value (type); + } + + switch (atr) + { + default: + error ("unexpected attribute encountered"); + case ATR_FIRST: + low = ada_array_bound_from_type (type_arg, tem, 0, &type); + return value_from_longest (type, low); + case ATR_LAST: + high = ada_array_bound_from_type (type_arg, tem, 1, &type); + return value_from_longest (type, high); + case ATR_LENGTH: + low = ada_array_bound_from_type (type_arg, tem, 0, &type); + high = ada_array_bound_from_type (type_arg, tem, 1, NULL); + return value_from_longest (type, high-low+1); + } + } + } + + case ATR_TAG: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return + value_zero (ada_tag_type (arg1), not_lval); + + return ada_value_tag (arg1); + + case ATR_MIN: + case ATR_MAX: + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + else if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (VALUE_TYPE (arg1), not_lval); + else + return value_binop (arg1, arg2, + atr == ATR_MIN ? BINOP_MIN : BINOP_MAX); + + case ATR_MODULUS: + { + struct type* type_arg = exp->elts[pc + 5].type; + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + *pos += 4; + + if (noside == EVAL_SKIP) + goto nosideret; + + if (! ada_is_modular_type (type_arg)) + error ("'modulus must be applied to modular type"); + + return value_from_longest (TYPE_TARGET_TYPE (type_arg), + ada_modulus (type_arg)); + } + + + case ATR_POS: + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + else if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (builtin_type_ada_int, not_lval); + else + return value_pos_atr (arg1); + + case ATR_SIZE: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + else if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (builtin_type_ada_int, not_lval); + else + return value_from_longest (builtin_type_ada_int, + TARGET_CHAR_BIT + * TYPE_LENGTH (VALUE_TYPE (arg1))); + + case ATR_VAL: + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + type = exp->elts[pc + 5].type; + if (noside == EVAL_SKIP) + goto nosideret; + else if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (type, not_lval); + else + return value_val_atr (type, arg1); + }*/ + case BINOP_EXP: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (binop_user_defined_p (op, arg1, arg2)) + return unwrap_value (value_x_binop (arg1, arg2, op, OP_NULL, + EVAL_NORMAL)); + else + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (VALUE_TYPE (arg1), not_lval); + else + return value_binop (arg1, arg2, op); + + case UNOP_PLUS: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (unop_user_defined_p (op, arg1)) + return unwrap_value (value_x_unop (arg1, op, EVAL_NORMAL)); + else + return arg1; + + case UNOP_ABS: + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (value_less (arg1, value_zero (VALUE_TYPE (arg1), not_lval))) + return value_neg (arg1); + else + return arg1; + + case UNOP_IND: + if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR) + expect_type = TYPE_TARGET_TYPE (check_typedef (expect_type)); + arg1 = evaluate_subexp (expect_type, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + type = check_typedef (VALUE_TYPE (arg1)); + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + if (ada_is_array_descriptor (type)) + /* GDB allows dereferencing GNAT array descriptors. */ + { + struct type* arrType = ada_type_of_array (arg1, 0); + if (arrType == NULL) + error ("Attempt to dereference null array pointer."); + return value_at_lazy (arrType, 0, NULL); + } + else if (TYPE_CODE (type) == TYPE_CODE_PTR + || TYPE_CODE (type) == TYPE_CODE_REF + /* In C you can dereference an array to get the 1st elt. */ + || TYPE_CODE (type) == TYPE_CODE_ARRAY + ) + return + value_zero + (to_static_fixed_type + (ada_aligned_type (check_typedef (TYPE_TARGET_TYPE (type)))), + lval_memory); + else if (TYPE_CODE (type) == TYPE_CODE_INT) + /* GDB allows dereferencing an int. */ + return value_zero (builtin_type_int, lval_memory); + else + error ("Attempt to take contents of a non-pointer value."); + } + arg1 = ada_coerce_ref (arg1); + type = check_typedef (VALUE_TYPE (arg1)); + + if (ada_is_array_descriptor (type)) + /* GDB allows dereferencing GNAT array descriptors. */ + return ada_coerce_to_simple_array (arg1); + else + return ada_value_ind (arg1); + + case STRUCTOP_STRUCT: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (ada_aligned_type + (ada_lookup_struct_elt_type (VALUE_TYPE (arg1), + &exp->elts[pc + 2].string, + 0, NULL)), + lval_memory); + else + return unwrap_value (ada_value_struct_elt (arg1, + &exp->elts[pc + 2].string, + "record")); + case OP_TYPE: + /* The value is not supposed to be used. This is here to make it + easier to accommodate expressions that contain types. */ + (*pos) += 2; + if (noside == EVAL_SKIP) + goto nosideret; + else if (noside == EVAL_AVOID_SIDE_EFFECTS) + return allocate_value (builtin_type_void); + else + error ("Attempt to use a type name as an expression"); + + case STRUCTOP_PTR: + tem = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1); + arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (ada_aligned_type + (ada_lookup_struct_elt_type (VALUE_TYPE (arg1), + &exp->elts[pc + 2].string, + 0, NULL)), + lval_memory); + else + return unwrap_value (ada_value_struct_elt (arg1, + &exp->elts[pc + 2].string, + "record access")); + } + +nosideret: + return value_from_longest (builtin_type_long, (LONGEST) 1); +} + + + /* Fixed point */ + +/* If TYPE encodes an Ada fixed-point type, return the suffix of the + type name that encodes the 'small and 'delta information. + Otherwise, return NULL. */ + +static const char* +fixed_type_info (type) + struct type *type; +{ + const char* name = ada_type_name (type); + enum type_code code = (type == NULL) ? TYPE_CODE_UNDEF : TYPE_CODE (type); + + if ((code == TYPE_CODE_INT || code == TYPE_CODE_RANGE) + && name != NULL) + { + const char *tail = strstr (name, "___XF_"); + if (tail == NULL) + return NULL; + else + return tail + 5; + } + else if (code == TYPE_CODE_RANGE && TYPE_TARGET_TYPE (type) != type) + return fixed_type_info (TYPE_TARGET_TYPE (type)); + else + return NULL; +} + +/* Returns non-zero iff TYPE represents an Ada fixed-point type. */ + +int +ada_is_fixed_point_type (type) + struct type *type; +{ + return fixed_type_info (type) != NULL; +} + +/* Assuming that TYPE is the representation of an Ada fixed-point + type, return its delta, or -1 if the type is malformed and the + delta cannot be determined. */ + +DOUBLEST +ada_delta (type) + struct type *type; +{ + const char *encoding = fixed_type_info (type); + long num, den; + + if (sscanf (encoding, "_%ld_%ld", &num, &den) < 2) + return -1.0; + else + return (DOUBLEST) num / (DOUBLEST) den; +} + +/* Assuming that ada_is_fixed_point_type (TYPE), return the scaling + factor ('SMALL value) associated with the type. */ + +static DOUBLEST +scaling_factor (type) + struct type *type; +{ + const char *encoding = fixed_type_info (type); + unsigned long num0, den0, num1, den1; + int n; + + n = sscanf (encoding, "_%lu_%lu_%lu_%lu", &num0, &den0, &num1, &den1); + + if (n < 2) + return 1.0; + else if (n == 4) + return (DOUBLEST) num1 / (DOUBLEST) den1; + else + return (DOUBLEST) num0 / (DOUBLEST) den0; +} + + +/* Assuming that X is the representation of a value of fixed-point + type TYPE, return its floating-point equivalent. */ + +DOUBLEST +ada_fixed_to_float (type, x) + struct type *type; + LONGEST x; +{ + return (DOUBLEST) x * scaling_factor (type); +} + +/* The representation of a fixed-point value of type TYPE + corresponding to the value X. */ + +LONGEST +ada_float_to_fixed (type, x) + struct type *type; + DOUBLEST x; +{ + return (LONGEST) (x / scaling_factor (type) + 0.5); +} + + + /* VAX floating formats */ + +/* Non-zero iff TYPE represents one of the special VAX floating-point + types. */ +int +ada_is_vax_floating_type (type) + struct type* type; +{ + int name_len = + (ada_type_name (type) == NULL) ? 0 : strlen (ada_type_name (type)); + return + name_len > 6 + && (TYPE_CODE (type) == TYPE_CODE_INT + || TYPE_CODE (type) == TYPE_CODE_RANGE) + && STREQN (ada_type_name (type) + name_len - 6, "___XF", 5); +} + +/* The type of special VAX floating-point type this is, assuming + ada_is_vax_floating_point */ +int +ada_vax_float_type_suffix (type) + struct type* type; +{ + return ada_type_name (type)[strlen (ada_type_name (type))-1]; +} + +/* A value representing the special debugging function that outputs + VAX floating-point values of the type represented by TYPE. Assumes + ada_is_vax_floating_type (TYPE). */ +struct value* +ada_vax_float_print_function (type) + + struct type* type; +{ + switch (ada_vax_float_type_suffix (type)) { + case 'F': + return + get_var_value ("DEBUG_STRING_F", 0); + case 'D': + return + get_var_value ("DEBUG_STRING_D", 0); + case 'G': + return + get_var_value ("DEBUG_STRING_G", 0); + default: + error ("invalid VAX floating-point type"); + } +} + + + /* Range types */ + +/* Scan STR beginning at position K for a discriminant name, and + return the value of that discriminant field of DVAL in *PX. If + PNEW_K is not null, put the position of the character beyond the + name scanned in *PNEW_K. Return 1 if successful; return 0 and do + not alter *PX and *PNEW_K if unsuccessful. */ + +static int +scan_discrim_bound (str, k, dval, px, pnew_k) + char *str; + int k; + struct value* dval; + LONGEST *px; + int *pnew_k; +{ + static char *bound_buffer = NULL; + static size_t bound_buffer_len = 0; + char *bound; + char *pend; + struct value* bound_val; + + if (dval == NULL || str == NULL || str[k] == '\0') + return 0; + + pend = strstr (str+k, "__"); + if (pend == NULL) + { + bound = str+k; + k += strlen (bound); + } + else + { + GROW_VECT (bound_buffer, bound_buffer_len, pend - (str+k) + 1); + bound = bound_buffer; + strncpy (bound_buffer, str+k, pend-(str+k)); + bound[pend-(str+k)] = '\0'; + k = pend-str; + } + + bound_val = + ada_search_struct_field (bound, dval, 0, VALUE_TYPE (dval)); + if (bound_val == NULL) + return 0; + + *px = value_as_long (bound_val); + if (pnew_k != NULL) + *pnew_k = k; + return 1; +} + +/* Value of variable named NAME in the current environment. If + no such variable found, then if ERR_MSG is null, returns 0, and + otherwise causes an error with message ERR_MSG. */ +static struct value* +get_var_value (name, err_msg) + char* name; + char* err_msg; +{ + struct symbol** syms; + struct block** blocks; + int nsyms; + + nsyms = ada_lookup_symbol_list (name, get_selected_block (NULL), VAR_NAMESPACE, + &syms, &blocks); + + if (nsyms != 1) + { + if (err_msg == NULL) + return 0; + else + error ("%s", err_msg); + } + + return value_of_variable (syms[0], blocks[0]); +} + +/* Value of integer variable named NAME in the current environment. If + no such variable found, then if ERR_MSG is null, returns 0, and sets + *FLAG to 0. If successful, sets *FLAG to 1. */ +LONGEST +get_int_var_value (name, err_msg, flag) + char* name; + char* err_msg; + int* flag; +{ + struct value* var_val = get_var_value (name, err_msg); + + if (var_val == 0) + { + if (flag != NULL) + *flag = 0; + return 0; + } + else + { + if (flag != NULL) + *flag = 1; + return value_as_long (var_val); + } +} + + +/* Return a range type whose base type is that of the range type named + NAME in the current environment, and whose bounds are calculated + from NAME according to the GNAT range encoding conventions. + Extract discriminant values, if needed, from DVAL. If a new type + must be created, allocate in OBJFILE's space. The bounds + information, in general, is encoded in NAME, the base type given in + the named range type. */ + +static struct type* +to_fixed_range_type (name, dval, objfile) + char *name; + struct value *dval; + struct objfile *objfile; +{ + struct type *raw_type = ada_find_any_type (name); + struct type *base_type; + LONGEST low, high; + char* subtype_info; + + if (raw_type == NULL) + base_type = builtin_type_int; + else if (TYPE_CODE (raw_type) == TYPE_CODE_RANGE) + base_type = TYPE_TARGET_TYPE (raw_type); + else + base_type = raw_type; + + subtype_info = strstr (name, "___XD"); + if (subtype_info == NULL) + return raw_type; + else + { + static char *name_buf = NULL; + static size_t name_len = 0; + int prefix_len = subtype_info - name; + LONGEST L, U; + struct type *type; + char *bounds_str; + int n; + + GROW_VECT (name_buf, name_len, prefix_len + 5); + strncpy (name_buf, name, prefix_len); + name_buf[prefix_len] = '\0'; + + subtype_info += 5; + bounds_str = strchr (subtype_info, '_'); + n = 1; + + if (*subtype_info == 'L') + { + if (! ada_scan_number (bounds_str, n, &L, &n) + && ! scan_discrim_bound (bounds_str, n, dval, &L, &n)) + return raw_type; + if (bounds_str[n] == '_') + n += 2; + else if (bounds_str[n] == '.') /* FIXME? SGI Workshop kludge. */ + n += 1; + subtype_info += 1; + } + else + { + strcpy (name_buf+prefix_len, "___L"); + L = get_int_var_value (name_buf, "Index bound unknown.", NULL); + } + + if (*subtype_info == 'U') + { + if (! ada_scan_number (bounds_str, n, &U, &n) + && !scan_discrim_bound (bounds_str, n, dval, &U, &n)) + return raw_type; + } + else + { + strcpy (name_buf+prefix_len, "___U"); + U = get_int_var_value (name_buf, "Index bound unknown.", NULL); + } + + if (objfile == NULL) + objfile = TYPE_OBJFILE (base_type); + type = create_range_type (alloc_type (objfile), base_type, L, U); + TYPE_NAME (type) = name; + return type; + } +} + +/* True iff NAME is the name of a range type. */ +int +ada_is_range_type_name (name) + const char* name; +{ + return (name != NULL && strstr (name, "___XD")); +} + + + /* Modular types */ + +/* True iff TYPE is an Ada modular type. */ +int +ada_is_modular_type (type) + struct type* type; +{ + /* FIXME: base_type should be declared in gdbtypes.h, implemented in + valarith.c */ + struct type* subranged_type; /* = base_type (type);*/ + + return (subranged_type != NULL && TYPE_CODE (type) == TYPE_CODE_RANGE + && TYPE_CODE (subranged_type) != TYPE_CODE_ENUM + && TYPE_UNSIGNED (subranged_type)); +} + +/* Assuming ada_is_modular_type (TYPE), the modulus of TYPE. */ +LONGEST +ada_modulus (type) + struct type* type; +{ + return TYPE_HIGH_BOUND (type) + 1; +} + + + + /* Operators */ + +/* Table mapping opcodes into strings for printing operators + and precedences of the operators. */ + +static const struct op_print ada_op_print_tab[] = + { + {":=", BINOP_ASSIGN, PREC_ASSIGN, 1}, + {"or else", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0}, + {"and then", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0}, + {"or", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0}, + {"xor", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0}, + {"and", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0}, + {"=", BINOP_EQUAL, PREC_EQUAL, 0}, + {"/=", BINOP_NOTEQUAL, PREC_EQUAL, 0}, + {"<=", BINOP_LEQ, PREC_ORDER, 0}, + {">=", BINOP_GEQ, PREC_ORDER, 0}, + {">", BINOP_GTR, PREC_ORDER, 0}, + {"<", BINOP_LESS, PREC_ORDER, 0}, + {">>", BINOP_RSH, PREC_SHIFT, 0}, + {"<<", BINOP_LSH, PREC_SHIFT, 0}, + {"+", BINOP_ADD, PREC_ADD, 0}, + {"-", BINOP_SUB, PREC_ADD, 0}, + {"&", BINOP_CONCAT, PREC_ADD, 0}, + {"*", BINOP_MUL, PREC_MUL, 0}, + {"/", BINOP_DIV, PREC_MUL, 0}, + {"rem", BINOP_REM, PREC_MUL, 0}, + {"mod", BINOP_MOD, PREC_MUL, 0}, + {"**", BINOP_EXP, PREC_REPEAT, 0 }, + {"@", BINOP_REPEAT, PREC_REPEAT, 0}, + {"-", UNOP_NEG, PREC_PREFIX, 0}, + {"+", UNOP_PLUS, PREC_PREFIX, 0}, + {"not ", UNOP_LOGICAL_NOT, PREC_PREFIX, 0}, + {"not ", UNOP_COMPLEMENT, PREC_PREFIX, 0}, + {"abs ", UNOP_ABS, PREC_PREFIX, 0}, + {".all", UNOP_IND, PREC_SUFFIX, 1}, /* FIXME: postfix .ALL */ + {"'access", UNOP_ADDR, PREC_SUFFIX, 1}, /* FIXME: postfix 'ACCESS */ + {NULL, 0, 0, 0} +}; + + /* Assorted Types and Interfaces */ + +struct type* builtin_type_ada_int; +struct type* builtin_type_ada_short; +struct type* builtin_type_ada_long; +struct type* builtin_type_ada_long_long; +struct type* builtin_type_ada_char; +struct type* builtin_type_ada_float; +struct type* builtin_type_ada_double; +struct type* builtin_type_ada_long_double; +struct type* builtin_type_ada_natural; +struct type* builtin_type_ada_positive; +struct type* builtin_type_ada_system_address; + +struct type ** const (ada_builtin_types[]) = +{ + + &builtin_type_ada_int, + &builtin_type_ada_long, + &builtin_type_ada_short, + &builtin_type_ada_char, + &builtin_type_ada_float, + &builtin_type_ada_double, + &builtin_type_ada_long_long, + &builtin_type_ada_long_double, + &builtin_type_ada_natural, + &builtin_type_ada_positive, + + /* The following types are carried over from C for convenience. */ + &builtin_type_int, + &builtin_type_long, + &builtin_type_short, + &builtin_type_char, + &builtin_type_float, + &builtin_type_double, + &builtin_type_long_long, + &builtin_type_void, + &builtin_type_signed_char, + &builtin_type_unsigned_char, + &builtin_type_unsigned_short, + &builtin_type_unsigned_int, + &builtin_type_unsigned_long, + &builtin_type_unsigned_long_long, + &builtin_type_long_double, + &builtin_type_complex, + &builtin_type_double_complex, + 0 +}; + +/* Not really used, but needed in the ada_language_defn. */ +static void emit_char (int c, struct ui_file* stream, int quoter) +{ + ada_emit_char (c, stream, quoter, 1); +} + +const struct language_defn ada_language_defn = { + "ada", /* Language name */ + /* language_ada, */ + language_unknown, + /* FIXME: language_ada should be defined in defs.h */ + ada_builtin_types, + range_check_off, + type_check_off, + case_sensitive_on, /* Yes, Ada is case-insensitive, but + * that's not quite what this means. */ + ada_parse, + ada_error, + ada_evaluate_subexp, + ada_printchar, /* Print a character constant */ + ada_printstr, /* Function to print string constant */ + emit_char, /* Function to print single char (not used) */ + ada_create_fundamental_type, /* Create fundamental type in this language */ + ada_print_type, /* Print a type using appropriate syntax */ + ada_val_print, /* Print a value using appropriate syntax */ + ada_value_print, /* Print a top-level value */ + {"", "", "", ""}, /* Binary format info */ +#if 0 + {"8#%lo#", "8#", "o", "#"}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"16#%lx#", "16#", "x", "#"}, /* Hex format info */ +#else + /* Copied from c-lang.c. */ + {"0%lo", "0", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0x%lx", "0x", "x", ""}, /* Hex format info */ +#endif + ada_op_print_tab, /* expression operators for printing */ + 1, /* c-style arrays (FIXME?) */ + 0, /* String lower bound (FIXME?) */ + &builtin_type_ada_char, + LANG_MAGIC +}; + +void +_initialize_ada_language () +{ + builtin_type_ada_int = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, + "integer", (struct objfile *) NULL); + builtin_type_ada_long = + init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, + "long_integer", (struct objfile *) NULL); + builtin_type_ada_short = + init_type (TYPE_CODE_INT, TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, + "short_integer", (struct objfile *) NULL); + builtin_type_ada_char = + init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, + "character", (struct objfile *) NULL); + builtin_type_ada_float = + init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, + "float", (struct objfile *) NULL); + builtin_type_ada_double = + init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "long_float", (struct objfile *) NULL); + builtin_type_ada_long_long = + init_type (TYPE_CODE_INT, TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + 0, + "long_long_integer", (struct objfile *) NULL); + builtin_type_ada_long_double = + init_type (TYPE_CODE_FLT, TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, + "long_long_float", (struct objfile *) NULL); + builtin_type_ada_natural = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, + "natural", (struct objfile *) NULL); + builtin_type_ada_positive = + init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, + "positive", (struct objfile *) NULL); + + + builtin_type_ada_system_address = + lookup_pointer_type (init_type (TYPE_CODE_VOID, 1, 0, "void", + (struct objfile *) NULL)); + TYPE_NAME (builtin_type_ada_system_address) = "system__address"; + + add_language (&ada_language_defn); + + add_show_from_set + (add_set_cmd ("varsize-limit", class_support, var_uinteger, + (char*) &varsize_limit, + "Set maximum bytes in dynamic-sized object.", + &setlist), + &showlist); + varsize_limit = 65536; + + add_com ("begin", class_breakpoint, begin_command, + "Start the debugged program, stopping at the beginning of the\n\ +main program. You may specify command-line arguments to give it, as for\n\ +the \"run\" command (q.v.)."); +} + + +/* Create a fundamental Ada type using default reasonable for the current + target machine. + + Some object/debugging file formats (DWARF version 1, COFF, etc) do not + define fundamental types such as "int" or "double". Others (stabs or + DWARF version 2, etc) do define fundamental types. For the formats which + don't provide fundamental types, gdb can create such types using this + function. + + FIXME: Some compilers distinguish explicitly signed integral types + (signed short, signed int, signed long) from "regular" integral types + (short, int, long) in the debugging information. There is some dis- + agreement as to how useful this feature is. In particular, gcc does + not support this. Also, only some debugging formats allow the + distinction to be passed on to a debugger. For now, we always just + use "short", "int", or "long" as the type name, for both the implicit + and explicitly signed types. This also makes life easier for the + gdb test suite since we don't have to account for the differences + in output depending upon what the compiler and debugging format + support. We will probably have to re-examine the issue when gdb + starts taking it's fundamental type information directly from the + debugging information supplied by the compiler. fnf@cygnus.com */ + +static struct type * +ada_create_fundamental_type (objfile, typeid) + struct objfile *objfile; + int typeid; +{ + struct type *type = NULL; + + switch (typeid) + { + default: + /* FIXME: For now, if we are asked to produce a type not in this + language, create the equivalent of a C integer type with the + name "<?type?>". When all the dust settles from the type + reconstruction work, this should probably become an error. */ + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "<?type?>", objfile); + warning ("internal error: no Ada fundamental type %d", typeid); + break; + case FT_VOID: + type = init_type (TYPE_CODE_VOID, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "void", objfile); + break; + case FT_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "character", objfile); + break; + case FT_SIGNED_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + 0, "signed char", objfile); + break; + case FT_UNSIGNED_CHAR: + type = init_type (TYPE_CODE_INT, + TARGET_CHAR_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned char", objfile); + break; + case FT_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, "short_integer", objfile); + break; + case FT_SIGNED_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + 0, "short_integer", objfile); + break; + case FT_UNSIGNED_SHORT: + type = init_type (TYPE_CODE_INT, + TARGET_SHORT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned short", objfile); + break; + case FT_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "integer", objfile); + break; + case FT_SIGNED_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + 0, "integer", objfile); /* FIXME -fnf */ + break; + case FT_UNSIGNED_INTEGER: + type = init_type (TYPE_CODE_INT, + TARGET_INT_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned int", objfile); + break; + case FT_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, "long_integer", objfile); + break; + case FT_SIGNED_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + 0, "long_integer", objfile); + break; + case FT_UNSIGNED_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long", objfile); + break; + case FT_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + 0, "long_long_integer", objfile); + break; + case FT_SIGNED_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + 0, "long_long_integer", objfile); + break; + case FT_UNSIGNED_LONG_LONG: + type = init_type (TYPE_CODE_INT, + TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT, + TYPE_FLAG_UNSIGNED, "unsigned long long", objfile); + break; + case FT_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_FLOAT_BIT / TARGET_CHAR_BIT, + 0, "float", objfile); + break; + case FT_DBL_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "long_float", objfile); + break; + case FT_EXT_PREC_FLOAT: + type = init_type (TYPE_CODE_FLT, + TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT, + 0, "long_long_float", objfile); + break; + } + return (type); +} + +void ada_dump_symtab (struct symtab* s) +{ + int i; + fprintf (stderr, "New symtab: [\n"); + fprintf (stderr, " Name: %s/%s;\n", + s->dirname ? s->dirname : "?", + s->filename ? s->filename : "?"); + fprintf (stderr, " Format: %s;\n", s->debugformat); + if (s->linetable != NULL) + { + fprintf (stderr, " Line table (section %d):\n", s->block_line_section); + for (i = 0; i < s->linetable->nitems; i += 1) + { + struct linetable_entry* e = s->linetable->item + i; + fprintf (stderr, " %4ld: %8lx\n", (long) e->line, (long) e->pc); + } + } + fprintf (stderr, "]\n"); +} + diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h new file mode 100644 index 0000000..e5353f8 --- /dev/null +++ b/gdb/ada-lang.h @@ -0,0 +1,365 @@ +/* Ada language support definitions for GDB, the GNU debugger. + Copyright 1992, 1997 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 2 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, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (ADA_LANG_H) +#define ADA_LANG_H 1 + +#include "value.h" +#include "gdbtypes.h" + +/* A macro to reorder the bytes of an address depending on the endiannes + of the target */ +#define EXTRACT_ADDRESS(x) ((void *) extract_address (&(x), sizeof (x))) +/* A macro to reorder the bytes of an int depending on the endiannes + of the target */ +#define EXTRACT_INT(x) ((int) extract_signed_integer (&(x), sizeof (x))) + +/* Chain of cleanups for arguments of OP_UNRESOLVED_VALUE names. Created in + yyparse and freed in ada_resolve. */ +extern struct cleanup* unresolved_names; + +/* Corresponding mangled/demangled names and opcodes for Ada user-definable + operators. */ +struct ada_opname_map { + const char* mangled; + const char* demangled; + enum exp_opcode op; +}; + +/* Table of Ada operators in mangled and demangled forms. */ +/* Defined in ada-lang.c */ +extern const struct ada_opname_map ada_opname_table[]; + +/* The maximum number of tasks known to the Ada runtime */ +extern const int MAX_NUMBER_OF_KNOWN_TASKS; + +/* Identifiers for Ada attributes that need special processing. Be sure + to update the table attribute_names in ada-lang.c whenever you change this. + */ + +enum ada_attribute { + /* Invalid attribute for error checking. */ + ATR_INVALID, + + ATR_FIRST, + ATR_LAST, + ATR_LENGTH, + ATR_IMAGE, + ATR_IMG, + ATR_MAX, + ATR_MIN, + ATR_MODULUS, + ATR_POS, + ATR_SIZE, + ATR_TAG, + ATR_VAL, + + /* Dummy last attribute. */ + ATR_END +}; + +enum task_states { + Unactivated, + Runnable, + Terminated, + Activator_Sleep, + Acceptor_Sleep, + Entry_Caller_Sleep, + Async_Select_Sleep, + Delay_Sleep, + Master_Completion_Sleep, + Master_Phase_2_Sleep +}; + +extern char *ada_task_states[]; + +typedef struct { + char *P_ARRAY; + int *P_BOUNDS; +} fat_string; + +typedef struct entry_call { + void *self; +} *entry_call_link; + +struct task_fields +{ + int entry_num; +#if (defined (VXWORKS_TARGET) || !defined (i386)) \ + && !(defined (VXWORKS_TARGET) && defined (M68K_TARGET)) + int pad1; +#endif + char state; +#if (defined (VXWORKS_TARGET) && defined (M68K_TARGET)) + char pad_8bits; +#endif + void *parent; + int priority; + int current_priority; + fat_string image; + entry_call_link call; +#if (defined (sun) && defined (__SVR4)) && !defined (VXWORKS_TARGET) + int pad2; + unsigned thread; + unsigned lwp; +#else + void *thread; + void *lwp; +#endif +} +#if (defined (VXWORKS_TARGET) && defined (M68K_TARGET)) +__attribute__ ((packed)) +#endif +; + +struct task_entry +{ + void *task_id; + int task_num; + int known_tasks_index; + struct task_entry *next_task; + void *thread; + void *lwp; + int stack_per; +}; + +extern struct type* builtin_type_ada_int; +extern struct type* builtin_type_ada_short; +extern struct type* builtin_type_ada_long; +extern struct type* builtin_type_ada_long_long; +extern struct type* builtin_type_ada_char; +extern struct type* builtin_type_ada_float; +extern struct type* builtin_type_ada_double; +extern struct type* builtin_type_ada_long_double; +extern struct type* builtin_type_ada_natural; +extern struct type* builtin_type_ada_positive; +extern struct type* builtin_type_ada_system_address; + +/* Assuming V points to an array of S objects, make sure that it contains at + least M objects, updating V and S as necessary. */ + +#define GROW_VECT(v, s, m) \ + if ((s) < (m)) grow_vect ((void**) &(v), &(s), (m), sizeof(*(v))); + +extern void grow_vect (void**, size_t*, size_t, int); + +extern int ada_parse (void); /* Defined in ada-exp.y */ + +extern void ada_error (char *); /* Defined in ada-exp.y */ + + /* Defined in ada-typeprint.c */ +extern void ada_print_type (struct type*, char*, struct ui_file*, int, int); + +extern int ada_val_print (struct type*, char*, int, CORE_ADDR, + struct ui_file*, int, int, int, enum val_prettyprint); + +extern int ada_value_print (struct value*, struct ui_file*, int, + enum val_prettyprint); + + /* Defined in ada-lang.c */ + +extern struct value* value_from_contents_and_address (struct type*, char*, CORE_ADDR); + +extern void ada_emit_char (int, struct ui_file *, int, int); + +extern void ada_printchar (int, struct ui_file*); + +extern void ada_printstr (struct ui_file*, char *, unsigned int, int, int); + +extern void ada_convert_actuals (struct value*, int, struct value**, CORE_ADDR*); + +extern struct value* ada_value_subscript (struct value*, int, struct value**); + +extern struct type* ada_array_element_type (struct type*, int); + +extern int ada_array_arity (struct type*); + +struct type* ada_type_of_array (struct value*, int); + +extern struct value* ada_coerce_to_simple_array (struct value*); + +extern struct value* ada_coerce_to_simple_array_ptr (struct value*); + +extern int ada_is_simple_array (struct type*); + +extern int ada_is_array_descriptor (struct type*); + +extern int ada_is_bogus_array_descriptor (struct type*); + +extern struct type* ada_index_type (struct type*, int); + +extern struct value* ada_array_bound (struct value*, int, int); + +extern int ada_lookup_symbol_list (const char*, struct block*, namespace_enum, + struct symbol***, struct block***); + +extern char* ada_fold_name (const char*); + +extern struct symbol* ada_lookup_symbol (const char*, struct block*, namespace_enum); + +extern struct minimal_symbol* ada_lookup_minimal_symbol (const char*); + +extern void ada_resolve (struct expression**, struct type*); + +extern int ada_resolve_function (struct symbol**, struct block**, int, + struct value**, int, const char*, struct type*); + +extern void ada_fill_in_ada_prototype (struct symbol*); + +extern int user_select_syms (struct symbol**, struct block**, int, int); + +extern int get_selections (int*, int, int, int, char*); + +extern char* ada_start_decode_line_1 (char*); + +extern struct symtabs_and_lines ada_finish_decode_line_1 (char**, struct symtab*, int, char***); + +extern int ada_scan_number (const char*, int, LONGEST*, int*); + +extern struct type* ada_parent_type (struct type*); + +extern int ada_is_ignored_field (struct type*, int); + +extern int ada_is_packed_array_type (struct type*); + +extern struct value* ada_value_primitive_packed_val (struct value*, char*, long, int, + int, struct type*); + +extern struct type* ada_coerce_to_simple_array_type (struct type*); + +extern int ada_is_character_type (struct type*); + +extern int ada_is_string_type (struct type*); + +extern int ada_is_tagged_type (struct type*); + +extern struct type* ada_tag_type (struct value*); + +extern struct value* ada_value_tag (struct value*); + +extern int ada_is_parent_field (struct type*, int); + +extern int ada_is_wrapper_field (struct type*, int); + +extern int ada_is_variant_part (struct type*, int); + +extern struct type* ada_variant_discrim_type (struct type*, struct type*); + +extern int ada_is_others_clause (struct type*, int); + +extern int ada_in_variant (LONGEST, struct type*, int); + +extern char* ada_variant_discrim_name (struct type*); + +extern struct type* ada_lookup_struct_elt_type (struct type*, char*, int, int*); + +extern struct value* ada_value_struct_elt (struct value*, char*, char*); + +extern struct value* ada_search_struct_field (char*, struct value*, int, struct type*); + +extern int ada_is_aligner_type (struct type*); + +extern struct type* ada_aligned_type (struct type*); + +extern char* ada_aligned_value_addr (struct type*, char*); + +extern const char* ada_attribute_name (int); + +extern int ada_is_fixed_point_type (struct type*); + +extern DOUBLEST ada_delta (struct type*); + +extern DOUBLEST ada_fixed_to_float (struct type *, LONGEST); + +extern LONGEST ada_float_to_fixed (struct type*, DOUBLEST); + +extern int ada_is_vax_floating_type (struct type*); + +extern int ada_vax_float_type_suffix (struct type*); + +extern struct value* ada_vax_float_print_function (struct type*); + +extern struct type* ada_system_address_type (void); + +extern int ada_which_variant_applies (struct type*, struct type*, char*); + +extern struct value* ada_to_fixed_value (struct type*, char*, CORE_ADDR, struct value*); + +extern struct type* ada_to_fixed_type (struct type*, char*, CORE_ADDR, struct value*); + +extern int ada_name_prefix_len (const char*); + +extern char* ada_type_name (struct type*); + +extern struct type* ada_find_parallel_type (struct type*, const char *suffix); + +extern LONGEST get_int_var_value (char*, char*, int* ); + +extern struct type* ada_find_any_type (const char *name); + +extern int ada_prefer_type (struct type*, struct type*); + +extern struct type* ada_get_base_type (struct type*); + +extern struct type* ada_completed_type (struct type*); + +extern char* ada_mangle (const char*); + +extern const char* ada_enum_name (const char*); + +extern int ada_is_modular_type (struct type*); + +extern LONGEST ada_modulus (struct type*); + +extern struct value* ada_value_ind (struct value*); + +extern void ada_print_scalar (struct type*, LONGEST, struct ui_file*); + +extern int ada_is_range_type_name (const char*); + +extern const char* ada_renaming_type (struct type*); + +extern int ada_is_object_renaming (struct symbol*); + +extern const char* ada_simple_renamed_entity (struct symbol*); + +extern char* ada_breakpoint_rewrite (char*, int*); + +/* Tasking-related: ada-tasks.c */ + +extern int valid_task_id (int); + +extern int get_current_task (void); + +extern void init_task_list (void); + +extern void* get_self_id (void); + +extern int get_current_task (void); + +extern int get_entry_number (void*); + +extern void ada_report_exception_break (struct breakpoint *); + +extern int ada_maybe_exception_partial_symbol (struct partial_symbol* sym); + +extern int ada_is_exception_sym (struct symbol* sym); + + +#endif diff --git a/gdb/ada-lex.c b/gdb/ada-lex.c new file mode 100644 index 0000000..9538f76 --- /dev/null +++ b/gdb/ada-lex.c @@ -0,0 +1,3174 @@ +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header$ + * $FreeBSD: src/usr.bin/lex/flex.skl,v 1.4 1999/10/27 07:56:44 obrien Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include <stdio.h> + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include <stdlib.h> +#include <unistd.h> + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include <io.h> +#include <stdlib.h> +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + + +#define YY_USES_REJECT +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 57 +#define YY_END_OF_BUFFER 58 +static yyconst short int yy_acclist[386] = + { 0, + 58, 56, 57, 1, 56, 57, 1, 57, 15, 56, + 57, 53, 56, 57, 41, 56, 57, 56, 57, 43, + 56, 57, 44, 56, 57, 41, 56, 57, 42, 56, + 57, 41, 56, 57, 41, 56, 57, 41, 56, 57, + 4, 56, 57, 4, 56, 57, 41, 56, 57, 41, + 56, 57, 41, 56, 57, 41, 56, 57, 50, 56, + 57, 47, 56, 57, 47, 56, 57, 47, 56, 57, + 47, 56, 57, 47, 56, 57, 47, 56, 57, 47, + 56, 57, 47, 56, 57, 47, 56, 57, 47, 56, + 57, 1, 56, 57, 56, 57, 16, 56, 57, 53, + + 56, 57, 41, 56, 57, 56, 57, 43, 56, 57, + 44, 56, 57, 41, 56, 57, 42, 56, 57, 41, + 56, 57, 41, 56, 57, 41, 56, 57, 4, 56, + 57, 4, 56, 57, 41, 56, 57, 41, 56, 57, + 41, 56, 57, 41, 56, 57, 50, 56, 57, 41, + 56, 57, 47, 56, 57, 47, 56, 57, 47, 56, + 57, 47, 56, 57, 47, 56, 57, 47, 56, 57, + 47, 56, 57, 47, 56, 57, 47, 56, 57, 47, + 56, 57, 56, 57, 40, 56, 57, 51, 55, 54, + 55, 55, 35, 2, 34, 46, 46, 37, 4, 36, + + 38, 33, 39, 47, 47, 47, 47, 47, 19, 47, + 23, 47, 47, 47, 47, 47, 28, 47, 47, 47, + 47, 16, 51, 55, 54, 55, 55, 16, 35, 2, + 34, 46, 46, 37, 4, 36, 38, 33, 39, 16, + 47, 47, 47, 47, 47, 19, 47, 23, 47, 47, + 47, 47, 47, 28, 47, 47, 47, 47,16398, 52, + 55, 12, 12, 32, 2, 46, 46, 9, 3, 7, + 47, 47, 49, 20, 47, 21, 47, 47, 24, 47, + 25, 47, 26, 47, 47, 29, 47, 47, 31, 47, + 52, 55, 16, 32, 2, 2, 16, 2, 46, 46, + + 9, 3, 7, 47, 16, 47, 49, 20, 47, 21, + 47, 47, 24, 47, 25, 47, 26, 47, 47, 29, + 47, 47, 31, 47, 8206, 46, 45, 46, 6, 9, + 3, 47, 22, 47, 27, 47, 30, 47, 2, 16, + 46, 45, 46, 6, 9, 3, 47, 22, 47, 27, + 47, 30, 47, 48, 47, 48, 2, 2, 18, 47, + 5, 11, 8, 18, 2, 2, 5, 11, 8, 17, + 5, 8, 17, 2, 18, 2, 5, 8, 13, 2, + 17, 10, 10, 10, 10 + } ; + +static yyconst short int yy_accept[364] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 2, 4, 7, + 9, 12, 15, 18, 20, 23, 26, 29, 32, 35, + 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, + 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, + 97, 100, 103, 106, 108, 111, 114, 117, 120, 123, + 126, 129, 132, 135, 138, 141, 144, 147, 150, 153, + 156, 159, 162, 165, 168, 171, 174, 177, 180, 183, + 185, 188, 188, 188, 188, 188, 188, 188, 188, 188, + 188, 188, 188, 190, 192, 193, 193, 193, 193, 193, + 193, 193, 193, 194, 195, 195, 196, 196, 197, 198, + + 199, 199, 199, 200, 200, 200, 201, 202, 202, 203, + 204, 204, 204, 205, 205, 206, 206, 207, 208, 209, + 211, 213, 214, 215, 216, 217, 219, 220, 221, 222, + 222, 223, 223, 225, 227, 228, 228, 228, 229, 229, + 229, 230, 231, 231, 232, 232, 233, 234, 235, 235, + 235, 236, 236, 236, 237, 238, 238, 239, 240, 241, + 241, 242, 242, 243, 243, 244, 245, 246, 248, 250, + 251, 252, 253, 254, 256, 257, 258, 259, 259, 260, + 260, 260, 260, 260, 260, 260, 262, 262, 263, 264, + 264, 265, 266, 266, 267, 268, 268, 269, 269, 270, + + 271, 271, 272, 272, 272, 272, 273, 274, 276, 278, + 279, 281, 283, 285, 286, 288, 289, 291, 293, 293, + 294, 295, 296, 298, 299, 299, 300, 301, 301, 302, + 302, 303, 304, 304, 305, 305, 305, 305, 306, 306, + 307, 308, 310, 312, 313, 315, 317, 319, 320, 322, + 323, 325, 325, 326, 326, 326, 326, 326, 327, 329, + 330, 330, 330, 331, 331, 332, 332, 332, 332, 332, + 332, 332, 332, 332, 332, 332, 332, 332, 333, 335, + 337, 339, 339, 339, 339, 339, 341, 341, 342, 344, + 345, 345, 345, 346, 346, 347, 347, 347, 347, 348, + + 350, 352, 354, 355, 355, 355, 355, 355, 356, 356, + 356, 356, 356, 356, 356, 356, 357, 357, 357, 358, + 359, 359, 359, 359, 360, 360, 360, 361, 361, 361, + 362, 363, 363, 364, 365, 365, 366, 367, 367, 368, + 369, 369, 370, 371, 371, 372, 372, 373, 374, 376, + 377, 378, 378, 379, 380, 380, 382, 382, 383, 384, + 385, 386, 386 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 5, 6, 7, 8, 5, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 21, 22, 23, + 24, 25, 5, 26, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 36, 36, 39, 40, 41, 42, 36, + 36, 43, 44, 45, 46, 36, 47, 48, 36, 36, + 27, 5, 28, 5, 29, 5, 30, 31, 32, 33, + + 34, 35, 36, 37, 38, 36, 36, 39, 40, 41, + 42, 36, 36, 43, 44, 45, 46, 36, 47, 48, + 36, 36, 26, 22, 26, 5, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[49] = + { 0, + 1, 2, 3, 4, 5, 6, 7, 8, 5, 9, + 5, 5, 5, 5, 5, 5, 10, 5, 11, 11, + 9, 5, 12, 13, 14, 5, 5, 5, 15, 16, + 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17 + } ; + +static yyconst short int yy_base[385] = + { 0, + 0, 0, 48, 0, 91, 92, 1405, 1771, 1771, 1771, + 94, 96, 1771, 142, 1771, 1771, 1391, 1771, 1387, 189, + 1378, 188, 194, 1377, 1376, 1374, 1361, 1771, 222, 242, + 82, 91, 89, 196, 68, 163, 179, 97, 100, 194, + 0, 280, 223, 328, 227, 228, 234, 229, 235, 375, + 242, 418, 1335, 243, 463, 247, 251, 252, 254, 510, + 168, 1343, 161, 1333, 234, 1331, 1336, 1323, 1316, 0, + 558, 1340, 127, 258, 420, 422, 398, 1299, 1285, 1258, + 1266, 1257, 411, 413, 0, 605, 1288, 1287, 1286, 1285, + 119, 644, 1771, 0, 691, 1771, 0, 0, 1255, 1771, + + 0, 421, 690, 429, 0, 1771, 1771, 1244, 1771, 1771, + 608, 696, 1771, 699, 419, 1247, 420, 422, 582, 583, + 586, 587, 624, 625, 591, 590, 627, 628, 684, 430, + 1771, 705, 653, 1256, 710, 1252, 731, 0, 1254, 750, + 710, 798, 1222, 717, 802, 832, 1199, 720, 875, 730, + 1189, 732, 892, 733, 795, 924, 796, 797, 1230, 971, + 800, 997, 0, 876, 1183, 1191, 1176, 0, 0, 1174, + 1151, 1150, 1097, 0, 1095, 1100, 1089, 1096, 805, 1043, + 1047, 1043, 1023, 1016, 1010, 439, 808, 883, 1771, 1027, + 1041, 0, 971, 0, 952, 736, 864, 614, 799, 0, + + 965, 976, 1046, 1061, 0, 1061, 1771, 714, 717, 858, + 774, 789, 859, 1042, 860, 953, 954, 1047, 1086, 1108, + 0, 1092, 0, 1094, 1140, 0, 950, 1182, 1091, 1110, + 1199, 1210, 0, 1244, 981, 0, 0, 0, 1243, 1273, + 890, 0, 0, 949, 0, 0, 0, 943, 0, 935, + 0, 1120, 1771, 1188, 900, 1303, 895, 1771, 0, 882, + 0, 1098, 1174, 440, 1177, 909, 421, 1048, 1093, 1102, + 1169, 846, 818, 814, 822, 779, 792, 1249, 1190, 1191, + 1192, 1322, 1228, 750, 1331, 1361, 0, 1106, 0, 1229, + 1378, 0, 1325, 1326, 1349, 726, 725, 1410, 0, 0, + + 0, 0, 1771, 722, 839, 713, 644, 1369, 668, 671, + 663, 615, 617, 576, 591, 1198, 540, 459, 456, 1440, + 1462, 1483, 1458, 1771, 414, 0, 1517, 249, 794, 1238, + 237, 258, 1310, 0, 203, 190, 209, 1460, 1477, 1350, + 0, 1480, 1771, 131, 1328, 726, 1472, 0, 0, 86, + 1516, 1523, 1522, 1385, 835, 0, 1505, 1511, 1527, 1533, + 1549, 1771, 1571, 1587, 1592, 1608, 1622, 1639, 1642, 1649, + 89, 187, 1656, 1672, 1689, 1701, 1707, 1718, 1720, 1736, + 902, 903, 1743, 1754 + } ; + +static yyconst short int yy_def[385] = + { 0, + 362, 1, 362, 3, 1, 1, 362, 362, 362, 362, + 362, 363, 362, 362, 362, 362, 362, 362, 362, 364, + 362, 362, 362, 362, 365, 362, 362, 362, 366, 366, + 30, 30, 30, 30, 30, 30, 30, 30, 367, 367, + 11, 362, 367, 362, 367, 367, 367, 367, 367, 362, + 367, 367, 52, 367, 362, 367, 367, 367, 367, 362, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 11, + 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, + 362, 362, 363, 363, 363, 71, 71, 71, 86, 362, + 86, 86, 362, 368, 364, 362, 369, 370, 370, 362, + + 371, 362, 362, 362, 372, 362, 362, 373, 362, 362, + 362, 362, 362, 374, 30, 362, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 367, + 362, 367, 42, 42, 42, 44, 44, 86, 137, 137, + 367, 375, 50, 367, 55, 145, 146, 367, 367, 367, + 52, 367, 149, 367, 367, 362, 367, 367, 376, 367, + 367, 362, 60, 367, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 92, 362, 362, + 362, 362, 362, 362, 362, 363, 362, 362, 362, 86, + 92, 368, 377, 370, 370, 378, 362, 362, 362, 372, + + 373, 362, 374, 362, 379, 380, 362, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 42, 367, 86, + 140, 375, 368, 375, 362, 146, 146, 149, 367, 367, + 367, 149, 156, 367, 362, 381, 162, 204, 145, 60, + 367, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 362, 362, 362, 362, 86, 377, 362, 370, 362, + 382, 378, 362, 362, 362, 362, 362, 362, 362, 362, + 362, 362, 362, 362, 362, 362, 383, 380, 30, 30, + 30, 367, 367, 86, 86, 368, 225, 367, 146, 367, + 149, 228, 367, 367, 367, 362, 362, 362, 240, 60, + + 60, 60, 362, 86, 362, 384, 362, 362, 362, 362, + 362, 362, 362, 362, 383, 367, 86, 86, 368, 368, + 367, 149, 367, 362, 362, 298, 367, 86, 362, 362, + 362, 384, 362, 86, 86, 368, 368, 367, 367, 367, + 322, 367, 362, 86, 362, 362, 362, 86, 368, 368, + 367, 367, 367, 362, 362, 368, 367, 362, 367, 362, + 367, 0, 362, 362, 362, 362, 362, 362, 362, 362, + 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, + 362, 362, 362, 362 + } ; + +static yyconst short int yy_nxt[1820] = + { 0, + 8, 9, 10, 9, 8, 11, 8, 12, 13, 14, + 15, 16, 17, 13, 18, 19, 20, 21, 22, 23, + 24, 13, 25, 26, 27, 28, 13, 13, 29, 30, + 29, 29, 29, 31, 29, 29, 29, 32, 29, 33, + 34, 35, 36, 29, 37, 29, 29, 38, 8, 9, + 10, 39, 40, 41, 40, 42, 43, 44, 45, 46, + 47, 43, 48, 49, 50, 51, 52, 53, 54, 43, + 55, 56, 57, 58, 59, 43, 60, 61, 60, 60, + 60, 62, 60, 60, 60, 63, 60, 64, 65, 66, + 67, 60, 68, 60, 60, 69, 70, 70, 115, 196, + + 71, 71, 72, 83, 196, 131, 73, 72, 115, 72, + 126, 74, 115, 356, 84, 84, 75, 72, 76, 115, + 119, 115, 115, 77, 190, 120, 132, 115, 188, 115, + 122, 121, 179, 78, 79, 80, 81, 115, 129, 72, + 354, 82, 86, 87, 87, 88, 89, 89, 89, 89, + 89, 90, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 91, 89, + 89, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 95, 95, 95, 115, 101, 168, 127, 200, 165, 131, + + 101, 169, 200, 115, 102, 96, 103, 103, 166, 115, + 102, 97, 103, 103, 350, 128, 103, 349, 99, 115, + 132, 104, 103, 111, 111, 112, 115, 104, 131, 123, + 348, 113, 131, 131, 131, 105, 115, 124, 114, 131, + 131, 125, 116, 111, 111, 112, 141, 131, 131, 132, + 142, 113, 131, 132, 132, 132, 131, 131, 114, 159, + 132, 132, 116, 179, 331, 148, 154, 171, 132, 132, + 346, 157, 117, 132, 158, 172, 344, 132, 132, 173, + 132, 72, 118, 130, 130, 131, 130, 133, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 134, 134, + + 130, 130, 130, 130, 130, 130, 132, 130, 135, 135, + 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 135, 135, 135, 135, 135, 86, 87, + 87, 136, 137, 138, 137, 137, 137, 130, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 139, 137, 137, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 95, 95, 143, 130, + 131, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 144, 130, 130, 130, 130, 130, 145, 130, 130, + + 130, 132, 130, 146, 147, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 131, 149, 179, 308, 179, 180, 186, + 186, 84, 84, 266, 150, 131, 151, 151, 181, 197, + 197, 343, 198, 72, 132, 72, 151, 199, 199, 115, + 115, 152, 115, 307, 209, 307, 132, 186, 186, 115, + 115, 336, 115, 208, 335, 153, 130, 130, 131, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 155, 130, 130, 132, + 130, 156, 156, 156, 156, 156, 156, 156, 156, 156, + + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 111, 111, 160, 130, 131, 130, 130, 130, 161, + 130, 130, 130, 130, 130, 130, 162, 130, 163, 163, + 164, 130, 130, 130, 130, 130, 132, 130, 163, 163, + 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, + 163, 163, 163, 163, 163, 163, 163, 163, 86, 87, + 87, 87, 86, 86, 86, 86, 86, 334, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 178, 178, 178, + 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, + + 178, 178, 178, 178, 178, 178, 86, 86, 86, 111, + 111, 111, 115, 115, 187, 308, 115, 115, 266, 211, + 115, 115, 115, 115, 114, 210, 115, 115, 116, 214, + 115, 115, 199, 199, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 188, 115, 115, 266, 115, 115, 266, + 135, 216, 333, 333, 115, 115, 215, 115, 115, 213, + 212, 218, 218, 191, 191, 191, 191, 191, 191, 191, + 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, + 191, 191, 95, 95, 95, 266, 101, 111, 111, 112, + + 203, 203, 203, 266, 204, 113, 102, 362, 103, 103, + 159, 266, 114, 97, 115, 131, 116, 135, 103, 331, + 99, 205, 131, 104, 115, 131, 217, 328, 135, 135, + 325, 132, 86, 86, 137, 131, 132, 131, 131, 355, + 219, 355, 260, 132, 115, 230, 132, 115, 229, 229, + 231, 231, 261, 324, 115, 317, 132, 115, 132, 132, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, + 221, 221, 221, 221, 221, 221, 221, 221, 192, 192, + + 131, 131, 131, 223, 115, 131, 252, 252, 252, 254, + 254, 254, 330, 330, 115, 253, 308, 265, 265, 115, + 314, 132, 132, 132, 224, 130, 132, 265, 255, 115, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 226, 226, 329, 358, 358, 313, 266, 330, 330, 312, + 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, + 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, + 131, 131, 263, 263, 254, 254, 254, 311, 115, 115, + 115, 279, 263, 228, 228, 131, 241, 264, 115, 115, + + 115, 132, 132, 255, 228, 228, 228, 228, 228, 228, + 232, 232, 297, 306, 308, 305, 132, 297, 306, 258, + 303, 232, 232, 232, 232, 232, 232, 130, 130, 131, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 233, 233, 130, 130, 130, 130, 234, 130, + 132, 130, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 111, 111, 160, 302, 131, 111, 111, 112, + 161, 301, 300, 115, 115, 113, 296, 162, 289, 202, + 259, 164, 114, 281, 115, 258, 116, 132, 203, 203, + + 237, 130, 238, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 239, + 130, 130, 130, 132, 130, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 256, 256, 203, 203, 203, + 187, 204, 72, 308, 135, 72, 256, 256, 256, 256, + 256, 256, 111, 111, 112, 218, 218, 72, 205, 266, + 113, 266, 115, 267, 266, 72, 266, 114, 268, 72, + 280, 116, 115, 269, 266, 270, 72, 254, 254, 282, + 271, 131, 192, 192, 192, 192, 131, 223, 308, 286, + + 272, 273, 274, 275, 260, 187, 283, 308, 276, 293, + 293, 131, 132, 284, 261, 131, 266, 132, 224, 293, + 224, 252, 252, 252, 294, 266, 285, 285, 231, 231, + 253, 251, 132, 250, 249, 248, 132, 285, 285, 285, + 285, 285, 285, 130, 130, 131, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 287, 287, + 130, 130, 130, 130, 288, 130, 132, 130, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, 290, 254, + 254, 254, 263, 263, 247, 265, 265, 246, 291, 309, + + 292, 292, 263, 131, 131, 265, 245, 264, 255, 310, + 292, 292, 292, 292, 292, 292, 292, 295, 295, 244, + 115, 115, 115, 243, 132, 132, 242, 295, 232, 232, + 115, 115, 115, 131, 131, 235, 130, 227, 130, 232, + 232, 232, 232, 232, 232, 111, 111, 160, 316, 131, + 111, 111, 112, 161, 132, 132, 345, 345, 113, 220, + 162, 219, 321, 135, 164, 114, 345, 207, 202, 116, + 132, 298, 298, 298, 298, 298, 298, 298, 298, 298, + 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, + 298, 299, 299, 195, 189, 188, 188, 187, 185, 184, + + 72, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 304, 304, 254, 254, 282, 183, 131, 347, 347, + 131, 131, 304, 304, 304, 304, 304, 304, 347, 323, + 182, 323, 283, 293, 293, 179, 345, 345, 132, 318, + 318, 132, 132, 293, 131, 131, 345, 177, 294, 176, + 318, 318, 318, 318, 318, 318, 319, 295, 295, 175, + 111, 111, 112, 174, 170, 132, 132, 295, 113, 320, + 320, 167, 130, 352, 110, 114, 254, 254, 254, 116, + 320, 320, 320, 320, 320, 320, 322, 322, 109, 107, + + 106, 100, 94, 93, 362, 255, 362, 322, 322, 322, + 322, 322, 322, 130, 130, 131, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 326, 326, + 130, 130, 130, 130, 327, 130, 132, 130, 326, 326, + 326, 326, 326, 326, 326, 326, 326, 326, 326, 326, + 326, 326, 326, 326, 326, 326, 326, 326, 337, 337, + 362, 362, 362, 131, 362, 131, 362, 131, 362, 337, + 337, 337, 337, 337, 337, 338, 342, 342, 339, 339, + 339, 339, 131, 362, 132, 131, 132, 362, 132, 340, + 347, 347, 362, 362, 362, 351, 351, 362, 353, 353, + + 347, 341, 341, 132, 362, 351, 132, 362, 353, 362, + 131, 341, 341, 341, 341, 341, 341, 341, 111, 111, + 160, 131, 131, 359, 359, 362, 161, 131, 131, 360, + 360, 132, 131, 162, 351, 351, 357, 164, 357, 360, + 353, 353, 132, 132, 351, 361, 361, 362, 132, 132, + 353, 360, 360, 132, 131, 361, 362, 362, 362, 362, + 362, 360, 362, 362, 362, 362, 362, 361, 361, 362, + 362, 362, 362, 362, 362, 132, 362, 361, 85, 362, + 362, 85, 362, 362, 362, 85, 85, 85, 98, 98, + 98, 362, 362, 362, 362, 362, 98, 362, 98, 362, + + 362, 98, 98, 98, 108, 362, 108, 108, 108, 115, + 115, 115, 362, 362, 362, 362, 115, 115, 115, 362, + 362, 362, 115, 115, 115, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 192, + 192, 362, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 193, 193, 193, 194, + 362, 362, 362, 194, 194, 194, 201, 362, 362, 201, + 201, 201, 201, 206, 206, 206, 362, 206, 362, 362, + 362, 362, 362, 206, 362, 362, 206, 206, 206, 222, + 222, 362, 222, 222, 222, 222, 222, 222, 222, 222, + + 222, 222, 222, 222, 222, 222, 236, 362, 362, 362, + 362, 236, 362, 362, 362, 362, 236, 257, 362, 362, + 257, 257, 257, 257, 262, 362, 362, 262, 262, 362, + 362, 362, 262, 262, 277, 277, 277, 278, 278, 278, + 362, 362, 362, 362, 278, 278, 278, 362, 362, 362, + 278, 278, 278, 315, 362, 362, 315, 315, 315, 315, + 332, 362, 362, 362, 332, 362, 362, 362, 332, 332, + 7, 362, 362, 362, 362, 362, 362, 362, 362, 362, + 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, + 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, + + 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, + 362, 362, 362, 362, 362, 362, 362, 362, 362 + } ; + +static yyconst short int yy_chk[1820] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 5, 6, 35, 371, + + 5, 6, 11, 12, 371, 39, 11, 11, 35, 11, + 35, 11, 31, 350, 12, 12, 11, 11, 11, 33, + 31, 32, 31, 11, 91, 32, 39, 38, 91, 33, + 33, 32, 73, 11, 11, 11, 11, 38, 38, 73, + 344, 11, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 20, 20, 20, 36, 22, 63, 36, 372, 61, 40, + + 23, 63, 372, 36, 22, 20, 22, 22, 61, 37, + 23, 20, 23, 23, 337, 37, 22, 336, 20, 37, + 40, 22, 23, 29, 29, 29, 34, 23, 43, 34, + 335, 29, 45, 46, 48, 22, 34, 34, 29, 47, + 49, 34, 29, 30, 30, 30, 47, 51, 54, 43, + 49, 30, 56, 45, 46, 48, 57, 58, 30, 59, + 47, 49, 30, 74, 332, 51, 54, 65, 51, 54, + 331, 56, 30, 56, 57, 65, 328, 57, 58, 65, + 59, 74, 30, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 52, 52, 75, 267, 76, 77, 83, + 83, 84, 84, 267, 52, 130, 52, 52, 77, 102, + 102, 325, 104, 75, 52, 76, 52, 104, 104, 115, + 117, 52, 118, 264, 118, 264, 130, 186, 186, 115, + 117, 319, 118, 117, 318, 52, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 317, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + + 71, 71, 71, 71, 71, 71, 86, 86, 86, 111, + 111, 111, 119, 120, 86, 315, 121, 122, 314, 122, + 126, 125, 119, 120, 111, 119, 121, 122, 111, 125, + 126, 125, 198, 198, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 92, 123, 124, 313, 127, 128, 312, + 133, 128, 307, 307, 123, 124, 127, 127, 128, 124, + 123, 133, 133, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 95, 95, 95, 311, 103, 112, 112, 112, + + 114, 114, 114, 310, 114, 112, 103, 95, 103, 103, + 132, 309, 112, 95, 129, 141, 112, 135, 103, 306, + 95, 114, 144, 103, 129, 148, 129, 304, 135, 135, + 297, 132, 137, 137, 137, 150, 141, 152, 154, 346, + 137, 346, 196, 144, 208, 152, 148, 209, 150, 150, + 152, 152, 196, 296, 208, 284, 150, 209, 152, 154, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 142, 142, + + 155, 157, 158, 142, 211, 161, 179, 179, 179, 187, + 187, 187, 329, 329, 211, 179, 277, 199, 199, 212, + 276, 155, 157, 158, 142, 145, 161, 199, 187, 212, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 146, 146, 305, 355, 355, 275, 274, 305, 305, 273, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, + 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, + 149, 164, 197, 197, 188, 188, 188, 272, 210, 213, + 215, 210, 197, 149, 149, 241, 164, 197, 210, 213, + + 215, 149, 164, 188, 149, 149, 149, 149, 149, 149, + 153, 153, 381, 382, 266, 260, 241, 381, 382, 257, + 255, 153, 153, 153, 153, 153, 153, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 160, 160, 160, 250, 160, 202, 202, 202, + 160, 248, 244, 216, 217, 202, 235, 160, 227, 201, + 195, 160, 202, 216, 217, 193, 202, 160, 162, 162, + + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 190, 190, 203, 203, 203, + 191, 203, 185, 268, 218, 184, 190, 190, 190, 190, + 190, 190, 206, 206, 206, 218, 218, 183, 203, 204, + 206, 268, 214, 204, 204, 182, 204, 206, 204, 181, + 214, 206, 214, 204, 204, 204, 180, 219, 219, 219, + 204, 219, 222, 222, 224, 224, 229, 222, 269, 224, + + 204, 204, 204, 204, 262, 178, 219, 270, 204, 229, + 229, 288, 219, 220, 262, 230, 269, 229, 222, 229, + 224, 252, 252, 252, 229, 270, 220, 220, 230, 230, + 252, 177, 288, 176, 175, 173, 230, 220, 220, 220, + 220, 220, 220, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, 228, 254, + 254, 254, 263, 263, 172, 265, 265, 171, 228, 271, + + 228, 228, 263, 316, 231, 265, 170, 263, 254, 271, + 228, 228, 228, 228, 228, 228, 228, 231, 231, 167, + 279, 280, 281, 166, 316, 231, 165, 231, 232, 232, + 279, 280, 281, 283, 290, 159, 151, 147, 143, 232, + 232, 232, 232, 232, 232, 234, 234, 234, 283, 234, + 278, 278, 278, 234, 283, 290, 330, 330, 278, 139, + 234, 136, 290, 134, 234, 278, 330, 116, 108, 278, + 234, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 240, 240, 99, 90, 89, 88, 87, 82, 81, + + 80, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, + 240, 256, 256, 282, 282, 282, 79, 282, 333, 333, + 293, 294, 256, 256, 256, 256, 256, 256, 333, 294, + 78, 294, 282, 293, 293, 72, 345, 345, 282, 285, + 285, 293, 294, 293, 295, 340, 345, 69, 293, 68, + 285, 285, 285, 285, 285, 285, 286, 295, 295, 67, + 308, 308, 308, 66, 64, 295, 340, 295, 308, 286, + 286, 62, 53, 340, 27, 308, 354, 354, 354, 308, + 286, 286, 286, 286, 286, 286, 291, 291, 26, 25, + + 24, 21, 19, 17, 7, 354, 0, 291, 291, 291, + 291, 291, 291, 298, 298, 298, 298, 298, 298, 298, + 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, + 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, + 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, + 298, 298, 298, 298, 298, 298, 298, 298, 320, 320, + 0, 0, 0, 323, 0, 338, 0, 321, 0, 320, + 320, 320, 320, 320, 320, 321, 323, 323, 338, 338, + 321, 321, 339, 0, 323, 342, 338, 0, 321, 322, + 347, 347, 0, 0, 0, 339, 339, 0, 342, 342, + + 347, 322, 322, 339, 0, 339, 342, 0, 342, 0, + 357, 322, 322, 322, 322, 322, 322, 322, 327, 327, + 327, 351, 327, 357, 357, 0, 327, 353, 352, 358, + 358, 357, 359, 327, 351, 351, 352, 327, 352, 358, + 353, 353, 351, 327, 351, 359, 359, 0, 353, 352, + 353, 360, 360, 359, 361, 359, 0, 0, 0, 0, + 0, 360, 0, 0, 0, 0, 0, 361, 361, 0, + 0, 0, 0, 0, 0, 361, 0, 361, 363, 0, + 0, 363, 0, 0, 0, 363, 363, 363, 364, 364, + 364, 0, 0, 0, 0, 0, 364, 0, 364, 0, + + 0, 364, 364, 364, 365, 0, 365, 365, 365, 366, + 366, 366, 0, 0, 0, 0, 366, 366, 366, 0, + 0, 0, 366, 366, 366, 367, 367, 367, 367, 367, + 367, 367, 367, 367, 367, 367, 367, 367, 367, 368, + 368, 0, 368, 368, 368, 368, 368, 368, 368, 368, + 368, 368, 368, 368, 368, 368, 369, 369, 369, 370, + 0, 0, 0, 370, 370, 370, 373, 0, 0, 373, + 373, 373, 373, 374, 374, 374, 0, 374, 0, 0, + 0, 0, 0, 374, 0, 0, 374, 374, 374, 375, + 375, 0, 375, 375, 375, 375, 375, 375, 375, 375, + + 375, 375, 375, 375, 375, 375, 376, 0, 0, 0, + 0, 376, 0, 0, 0, 0, 376, 377, 0, 0, + 377, 377, 377, 377, 378, 0, 0, 378, 378, 0, + 0, 0, 378, 378, 379, 379, 379, 380, 380, 380, + 0, 0, 0, 0, 380, 380, 380, 0, 0, 0, + 380, 380, 380, 383, 0, 0, 383, 383, 383, 383, + 384, 0, 0, 0, 384, 0, 0, 0, 384, 384, + 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, + 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, + 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, + + 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, + 362, 362, 362, 362, 362, 362, 362, 362, 362 + } ; + +static yy_state_type yy_state_buf[YY_BUF_SIZE + 2], *yy_state_ptr; +static char *yy_full_match; +static int yy_lp; +static int yy_looking_for_trail_begin = 0; +static int yy_full_lp; +static int *yy_full_state; +#define YY_TRAILING_MASK 0x2000 +#define YY_TRAILING_HEAD_MASK 0x4000 +#define REJECT \ +{ \ +*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ \ +yy_cp = yy_full_match; /* restore poss. backed-over text */ \ +yy_lp = yy_full_lp; /* restore orig. accepting pos. */ \ +yy_state_ptr = yy_full_state; /* restore orig. state */ \ +yy_current_state = *yy_state_ptr; /* restore curr. state */ \ +++yy_lp; \ +goto find_rule; \ +} +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "./ada-lex.l" +#define INITIAL 0 +/* FLEX lexer for Ada expressions, for GDB. + Copyright (C) 1994, 1997, 2000 + 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 2 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, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/*----------------------------------------------------------------------*/ +/* 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. */ +/* Run flex with (at least) the -i option (case-insensitive), and the -I */ +/* option (interactive---no unnecessary lookahead). */ +#line 48 "./ada-lex.l" +#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 int processInt (const char*, const char*, const char*); +static int processReal (const char*); +static int processId (const char*, int); +static int processAttribute (const char*); +static int find_dot_all (const char*); + +#undef YY_DECL +#define YY_DECL static int yylex ( void ) + +#undef YY_INPUT +#define YY_INPUT(BUF, RESULT, MAX_SIZE) \ + if ( *lexptr == '\000' ) \ + (RESULT) = YY_NULL; \ + else \ + { \ + *(BUF) = *lexptr; \ + (RESULT) = 1; \ + lexptr += 1; \ + } + +static char *tempbuf = NULL; +static int tempbufsize = 0; +static int tempbuf_len; +static struct block* left_block_context; + +static void resize_tempbuf (unsigned int); + +static void block_lookup (char*, char*); + +static int name_lookup (char*, char*, int*); + +static int find_dot_all (const char*); + +#define IN_STRING 1 +#define BEFORE_QUAL_QUOTE 2 + + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include <stdlib.h> +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 91 "./ada-lex.l" + + + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; + yy_state_ptr = yy_state_buf; + *yy_state_ptr++ = yy_current_state; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 363 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + *yy_state_ptr++ = yy_current_state; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 1771 ); + +yy_find_action: + yy_current_state = *--yy_state_ptr; + yy_lp = yy_accept[yy_current_state]; +find_rule: /* we branch to this label when backing up */ + for ( ; ; ) /* until we find what rule we matched */ + { + if ( yy_lp && yy_lp < yy_accept[yy_current_state + 1] ) + { + yy_act = yy_acclist[yy_lp]; + if ( yy_act & YY_TRAILING_HEAD_MASK || + yy_looking_for_trail_begin ) + { + if ( yy_act == yy_looking_for_trail_begin ) + { + yy_looking_for_trail_begin = 0; + yy_act &= ~YY_TRAILING_HEAD_MASK; + break; + } + } + else if ( yy_act & YY_TRAILING_MASK ) + { + yy_looking_for_trail_begin = yy_act & ~YY_TRAILING_MASK; + yy_looking_for_trail_begin |= YY_TRAILING_HEAD_MASK; + } + else + { + yy_full_match = yy_cp; + yy_full_state = yy_state_ptr; + yy_full_lp = yy_lp; + break; + } + ++yy_lp; + goto find_rule; + } + --yy_cp; + yy_current_state = *--yy_state_ptr; + yy_lp = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ +case 1: +YY_RULE_SETUP +#line 93 "./ada-lex.l" +{ } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 95 "./ada-lex.l" +{ yyterminate(); } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 97 "./ada-lex.l" +{ + canonicalizeNumeral (numbuf, yytext); + return processInt (NULL, numbuf, strrchr(numbuf, 'e')+1); + } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 102 "./ada-lex.l" +{ + canonicalizeNumeral (numbuf, yytext); + return processInt (NULL, numbuf, NULL); + } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 107 "./ada-lex.l" +{ + canonicalizeNumeral (numbuf, yytext); + return processInt (numbuf, + strchr (numbuf, '#') + 1, + strrchr(numbuf, '#') + 1); + } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 114 "./ada-lex.l" +{ + canonicalizeNumeral (numbuf, yytext); + return processInt (numbuf, strchr (numbuf, '#') + 1, NULL); + } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 119 "./ada-lex.l" +{ + canonicalizeNumeral (numbuf, yytext+2); + return processInt ("16#", numbuf, NULL); + } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 125 "./ada-lex.l" +{ + canonicalizeNumeral (numbuf, yytext); + return processReal (numbuf); + } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 130 "./ada-lex.l" +{ + canonicalizeNumeral (numbuf, yytext); + return processReal (numbuf); + } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 135 "./ada-lex.l" +{ + error ("Based real literals not implemented yet."); + } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 139 "./ada-lex.l" +{ + error ("Based real literals not implemented yet."); + } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 143 "./ada-lex.l" +{ + yylval.typed_val.type = builtin_type_ada_char; + yylval.typed_val.val = yytext[1]; + return CHARLIT; + } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 149 "./ada-lex.l" +{ + int v; + yylval.typed_val.type = builtin_type_ada_char; + sscanf (yytext+3, "%2x", &v); + yylval.typed_val.val = v; + return CHARLIT; + } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 157 "./ada-lex.l" +{ return processId (yytext, yyleng); } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 159 "./ada-lex.l" +{ + tempbuf_len = 0; + BEGIN IN_STRING; + } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 164 "./ada-lex.l" +{ + resize_tempbuf (yyleng+tempbuf_len); + strncpy (tempbuf+tempbuf_len, yytext, yyleng-1); + tempbuf_len += yyleng-1; + yylval.sval.ptr = tempbuf; + yylval.sval.length = tempbuf_len; + BEGIN INITIAL; + return STRING; + } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 174 "./ada-lex.l" +{ + int n; + resize_tempbuf (yyleng-5+tempbuf_len+1); + strncpy (tempbuf+tempbuf_len, yytext, yyleng-6); + sscanf(yytext+yyleng-4, "%2x", &n); + tempbuf[yyleng-6+tempbuf_len] = (char) n; + tempbuf_len += yyleng-5; + } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 183 "./ada-lex.l" +{ + int n; + resize_tempbuf (yyleng-4+tempbuf_len+1); + strncpy (tempbuf+tempbuf_len, yytext, yyleng-6); + tempbuf[yyleng-5+tempbuf_len] = '"'; + tempbuf_len += yyleng-4; + } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 191 "./ada-lex.l" +{ + while (*lexptr != 'i' && *lexptr != 'I') + lexptr -= 1; + yyrestart(NULL); + return 0; + } + YY_BREAK +/* ADA KEYWORDS */ +case 20: +YY_RULE_SETUP +#line 200 "./ada-lex.l" +{ return ABS; } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 201 "./ada-lex.l" +{ return _AND_; } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 202 "./ada-lex.l" +{ return ELSE; } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 203 "./ada-lex.l" +{ return IN; } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 204 "./ada-lex.l" +{ return MOD; } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 205 "./ada-lex.l" +{ return NEW; } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 206 "./ada-lex.l" +{ return NOT; } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 207 "./ada-lex.l" +{ return NULL_PTR; } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 208 "./ada-lex.l" +{ return OR; } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 209 "./ada-lex.l" +{ return REM; } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 210 "./ada-lex.l" +{ return THEN; } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 211 "./ada-lex.l" +{ return XOR; } + YY_BREAK +/* ATTRIBUTES */ +case 32: +YY_RULE_SETUP +#line 215 "./ada-lex.l" +{ return processAttribute (yytext+1); } + YY_BREAK +/* PUNCTUATION */ +case 33: +YY_RULE_SETUP +#line 219 "./ada-lex.l" +{ return ARROW; } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 220 "./ada-lex.l" +{ return DOTDOT; } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 221 "./ada-lex.l" +{ return STARSTAR; } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 222 "./ada-lex.l" +{ return ASSIGN; } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 223 "./ada-lex.l" +{ return NOTEQUAL; } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 224 "./ada-lex.l" +{ return LEQ; } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 225 "./ada-lex.l" +{ return GEQ; } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 227 "./ada-lex.l" +{ BEGIN INITIAL; return '\''; } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 229 "./ada-lex.l" +{ return yytext[0]; } + YY_BREAK +case 42: +YY_RULE_SETUP +#line 231 "./ada-lex.l" +{ if (paren_depth == 0 && comma_terminates) + { + lexptr -= 1; + yyrestart(NULL); + return 0; + } + else + return ','; + } + YY_BREAK +case 43: +YY_RULE_SETUP +#line 241 "./ada-lex.l" +{ paren_depth += 1; return '('; } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 242 "./ada-lex.l" +{ if (paren_depth == 0) + { + lexptr -= 1; + yyrestart(NULL); + return 0; + } + else + { + paren_depth -= 1; + return ')'; + } + } + YY_BREAK +case 45: +YY_RULE_SETUP +#line 255 "./ada-lex.l" +{ return DOT_ALL; } + YY_BREAK +case 46: +YY_RULE_SETUP +#line 257 "./ada-lex.l" +{ + processId (yytext+1, yyleng-1); + return DOT_ID; + } + YY_BREAK +case 47: +YY_RULE_SETUP +#line 262 "./ada-lex.l" +{ + int all_posn = find_dot_all (yytext); + int token_type, segments, k; + int quote_follows; + + if (all_posn == -1 && yytext[yyleng-1] == '\'') + { + quote_follows = 1; + do { + yyless (yyleng-1); + } while (yytext[yyleng-1] == ' '); + } + else + quote_follows = 0; + + if (all_posn >= 0) + yyless (all_posn); + processId(yytext, yyleng); + segments = name_lookup (ada_mangle (yylval.ssym.stoken.ptr), + yylval.ssym.stoken.ptr, &token_type); + left_block_context = NULL; + for (k = yyleng; segments > 0 && k > 0; k -= 1) + { + if (yytext[k-1] == '.') + segments -= 1; + quote_follows = 0; + } + if (k <= 0) + error ("confused by name %s", yytext); + yyless (k); + if (quote_follows) + BEGIN BEFORE_QUAL_QUOTE; + return token_type; + } + YY_BREAK +/* GDB EXPRESSION CONSTRUCTS */ +case 48: +YY_RULE_SETUP +#line 300 "./ada-lex.l" +{ + processId(yytext, yyleng-2); + block_lookup (yylval.ssym.stoken.ptr, yylval.ssym.stoken.ptr); + return BLOCKNAME; + } + YY_BREAK +case 49: +YY_RULE_SETUP +#line 306 "./ada-lex.l" +{ + processId(yytext, yyleng-2); + block_lookup (ada_mangle (yylval.ssym.stoken.ptr), + yylval.ssym.stoken.ptr); + return BLOCKNAME; + } + YY_BREAK +case 50: +YY_RULE_SETUP +#line 313 "./ada-lex.l" +{ return yytext[0]; } + YY_BREAK +case 51: +YY_RULE_SETUP +#line 315 "./ada-lex.l" +{ yylval.lval = -1; return LAST; } + YY_BREAK +case 52: +YY_RULE_SETUP +#line 316 "./ada-lex.l" +{ yylval.lval = -atoi(yytext+2); return LAST; } + YY_BREAK +case 53: +YY_RULE_SETUP +#line 317 "./ada-lex.l" +{ yylval.lval = 0; return LAST; } + YY_BREAK +case 54: +YY_RULE_SETUP +#line 318 "./ada-lex.l" +{ yylval.lval = atoi(yytext+1); return LAST; } + YY_BREAK +/* REGISTERS AND GDB CONVENIENCE VARIABLES */ +case 55: +YY_RULE_SETUP +#line 323 "./ada-lex.l" +{ + int c; + for (c = 0; c < NUM_REGS; c++) + if (REGISTER_NAME (c) && + strcmp (yytext + 1, REGISTER_NAME (c)) == 0) + { + yylval.lval = c; + return REGNAME; + } + yylval.sval.ptr = yytext; + yylval.sval.length = yyleng; + yylval.ivar = + lookup_internalvar (copy_name (yylval.sval) + 1); + return INTERNAL_VARIABLE; + } + YY_BREAK +/* CATCH-ALL ERROR CASE */ +case 56: +YY_RULE_SETUP +#line 341 "./ada-lex.l" +{ error ("Invalid character '%s' in expression.", yytext); } + YY_BREAK +case 57: +YY_RULE_SETUP +#line 342 "./ada-lex.l" +YY_FATAL_ERROR( "flex scanner jammed" ); + YY_BREAK + case YY_STATE_EOF(INITIAL): + case YY_STATE_EOF(IN_STRING): + case YY_STATE_EOF(BEFORE_QUAL_QUOTE): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + yy_state_ptr = yy_state_buf; + *yy_state_ptr++ = yy_current_state; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 363 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + *yy_state_ptr++ = yy_current_state; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + + register YY_CHAR yy_c = 1; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 363 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 362); + if ( ! yy_is_jam ) + *yy_state_ptr++ = yy_current_state; + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +extern int isatty YY_PROTO(( int )); +#endif +#endif + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 342 "./ada-lex.l" + + +#include <ctype.h> +#include <string.h> + +/* Initialize the lexer for processing new expression */ +void +lexer_init (FILE* inp) +{ + BEGIN INITIAL; + yyrestart (inp); +} + + +/* Make sure that tempbuf points at an array at least N characters long. */ + +static void +resize_tempbuf (n) + unsigned int n; +{ + if (tempbufsize < n) + { + tempbufsize = (n+63) & ~63; + tempbuf = (char*) xrealloc (tempbuf, tempbufsize); + } +} + +/* Copy S2 to S1, removing all underscores, and downcasing all letters. */ + +static void +canonicalizeNumeral (s1,s2) + char* s1; + const char* s2; +{ + for (; *s2 != '\000'; s2 += 1) + { + if (*s2 != '_') + { + *s1 = tolower(*s2); + s1 += 1; + } + } + s1[0] = '\000'; +} + +#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT) + +/* True (non-zero) iff DIGIT is a valid digit in radix BASE, + where 2 <= BASE <= 16. */ + +static int +is_digit_in_base (digit, base) + unsigned char digit; + int base; +{ + if (!isxdigit (digit)) + return 0; + if (base <= 10) + return (isdigit (digit) && digit < base + '0'); + else + return (isdigit (digit) || tolower (digit) < base - 10 + 'a'); +} + +static int +digit_to_int (c) + unsigned char c; +{ + if (isdigit (c)) + return c - '0'; + else + return tolower (c) - 'a' + 10; +} + +/* As for strtoul, but for ULONGEST results. */ +ULONGEST +strtoulst (num, trailer, base) + const char *num; + const char **trailer; + int base; +{ + unsigned int high_part; + ULONGEST result; + int i; + unsigned char lim; + + if (base < 2 || base > 16) + { + errno = EINVAL; + return 0; + } + lim = base - 1 + '0'; + + result = high_part = 0; + for (i = 0; is_digit_in_base (num[i], base); i += 1) + { + result = result*base + digit_to_int (num[i]); + high_part = high_part*base + (unsigned int) (result >> HIGH_BYTE_POSN); + result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1; + if (high_part > 0xff) + { + errno = ERANGE; + result = high_part = 0; + break; + } + } + + if (trailer != NULL) + *trailer = &num[i]; + + return result + ((ULONGEST) high_part << HIGH_BYTE_POSN); +} + + + +/* 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 (base0, num0, exp0) + const char* num0; + const char* base0; + const char* exp0; +{ + ULONGEST result; + long exp; + int base; + + char* trailer; + + if (base0 == NULL) + base = 10; + else + { + base = strtol (base0, (char**) NULL, 10); + if (base < 2 || base > 16) + error ("Invalid base: %d.", base); + } + + if (exp0 == NULL) + exp = 0; + else + exp = strtol(exp0, (char**) NULL, 10); + + errno = 0; + result = strtoulst (num0, &trailer, base); + if (errno == ERANGE) + error ("Integer literal out of range"); + if (isxdigit(*trailer)) + error ("Invalid digit `%c' in based literal", *trailer); + + while (exp > 0) + { + if (result > (ULONG_MAX / base)) + error ("Integer literal out of range"); + result *= base; + exp -= 1; + } + + if ((result >> (TARGET_INT_BIT-1)) == 0) + yylval.typed_val.type = builtin_type_ada_int; + else if ((result >> (TARGET_LONG_BIT-1)) == 0) + yylval.typed_val.type = builtin_type_ada_long; + else if (((result >> (TARGET_LONG_BIT-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_unsigned_long; + if (result & LONGEST_SIGN) + yylval.typed_val.val = + (LONGEST) (result & ~LONGEST_SIGN) + - (LONGEST_SIGN>>1) - (LONGEST_SIGN>>1); + else + yylval.typed_val.val = (LONGEST) result; + return INT; + } + else + yylval.typed_val.type = builtin_type_ada_long_long; + + yylval.typed_val.val = (LONGEST) result; + return INT; +} + +static int +processReal (num0) + const char* num0; +{ + if (sizeof (DOUBLEST) <= sizeof (float)) + sscanf (num0, "%g", &yylval.typed_val_float.dval); + else if (sizeof (DOUBLEST) <= sizeof (double)) + sscanf (num0, "%lg", &yylval.typed_val_float.dval); + else + { +#ifdef PRINTF_HAS_LONG_DOUBLE + sscanf (num0, "%Lg", &yylval.typed_val_float.dval); +#else + /* Scan it into a double, then convert and assign it to the + long double. This at least wins with values representable + in the range of doubles. */ + double temp; + sscanf (num0, "%lg", &temp); + yylval.typed_val_float.dval = temp; +#endif + } + + yylval.typed_val_float.type = builtin_type_ada_float; + if (sizeof(DOUBLEST) >= TARGET_DOUBLE_BIT / TARGET_CHAR_BIT) + yylval.typed_val_float.type = builtin_type_ada_double; + if (sizeof(DOUBLEST) >= TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT) + yylval.typed_val_float.type = builtin_type_ada_long_double; + + return FLOAT; +} + +static int +processId (name0, len) + const char *name0; + int len; +{ + char* name = xmalloc (len + 11); + int i0, i; + +/* add_name_string_cleanup (name); */ +/* FIXME: add_name_string_cleanup should be defined in parse.c */ + while (len > 0 && isspace (name0[len-1])) + len -= 1; + i = i0 = 0; + while (i0 < len) + { + if (isalnum (name0[i0])) + { + name[i] = tolower (name0[i0]); + i += 1; i0 += 1; + } + else switch (name0[i0]) + { + default: + name[i] = name0[i0]; + i += 1; i0 += 1; + break; + case ' ': case '\t': + i0 += 1; + break; + case '\'': + i0 += 1; + while (i0 < len && name0[i0] != '\'') + { + name[i] = name0[i0]; + i += 1; i0 += 1; + } + i0 += 1; + break; + case '<': + i0 += 1; + while (i0 < len && name0[i0] != '>') + { + name[i] = name0[i0]; + i += 1; i0 += 1; + } + i0 += 1; + break; + } + } + name[i] = '\000'; + + yylval.ssym.sym = NULL; + yylval.ssym.stoken.ptr = name; + yylval.ssym.stoken.length = i; + return NAME; +} + +static void +block_lookup (name, err_name) + char* name; + char* err_name; +{ + struct symbol** syms; + struct block** blocks; + int nsyms; + struct symtab *symtab; + nsyms = ada_lookup_symbol_list (name, left_block_context, + VAR_NAMESPACE, &syms, &blocks); + if (left_block_context == NULL && + (nsyms == 0 || SYMBOL_CLASS (syms[0]) != LOC_BLOCK)) + symtab = lookup_symtab (name); + else + symtab = NULL; + + if (symtab != NULL) + left_block_context = yylval.bval = + BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK); + else if (nsyms == 0 || SYMBOL_CLASS (syms[0]) != LOC_BLOCK) + { + if (left_block_context == NULL) + error ("No file or function \"%s\".", err_name); + else + error ("No function \"%s\" in specified context.", err_name); + } + else + { + left_block_context = yylval.bval = SYMBOL_BLOCK_VALUE (syms[0]); + if (nsyms > 1) + warning ("Function name \"%s\" ambiguous here", err_name); + } +} + +/* Look up NAME0 (assumed to be mangled) as a name in VAR_NAMESPACE, + setting *TOKEN_TYPE to NAME or TYPENAME, depending on what is + found. Try first the entire name, then the name without the last + segment (i.e., after the last .id), etc., and return the number of + segments that had to be removed to get a match. Calls error if no + matches are found, using ERR_NAME in any error message. When + exactly one symbol match is found, it is placed in yylval. */ + +static int +name_lookup (name0, err_name, token_type) + char* name0; + char* err_name; + int* token_type; +{ + struct symbol** syms; + struct block** blocks; + struct type* type; + int len0 = strlen (name0); + char* name = savestring (name0, len0); + int nsyms; + int segments; + +/* add_name_string_cleanup (name);*/ +/* FIXME: add_name_string_cleanup should be defined in parse.c */ + yylval.ssym.stoken.ptr = name; + yylval.ssym.stoken.length = strlen (name); + for (segments = 0; ; segments += 1) + { + struct type* preferred_type; + int i, preferred_index; + + if (left_block_context == NULL) + nsyms = ada_lookup_symbol_list (name, expression_context_block, + VAR_NAMESPACE, &syms, &blocks); + else + nsyms = ada_lookup_symbol_list (name, left_block_context, + VAR_NAMESPACE, &syms, &blocks); + + /* Check for a type definition. */ + + /* Look for a symbol that doesn't denote void. This is (I think) a */ + /* temporary kludge to get around problems in GNAT output. */ + preferred_index = -1; preferred_type = NULL; + for (i = 0; i < nsyms; i += 1) + switch (SYMBOL_CLASS (syms[i])) + { + case LOC_TYPEDEF: + if (ada_prefer_type (SYMBOL_TYPE (syms[i]), preferred_type)) + { + preferred_index = i; + preferred_type = SYMBOL_TYPE (syms[i]); + } + break; + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + goto NotType; + default: + break; + } + if (preferred_type != NULL) + { +/* if (TYPE_CODE (preferred_type) == TYPE_CODE_VOID) + error ("`%s' matches only void type name(s)", + ada_demangle (name)); +*/ +/* FIXME: ada_demangle should be defined in defs.h, and is located in ada-lang.c */ +/* else*/ if (ada_is_object_renaming (syms[preferred_index])) + { + yylval.ssym.sym = syms[preferred_index]; + *token_type = OBJECT_RENAMING; + return segments; + } + else if (ada_renaming_type (SYMBOL_TYPE (syms[preferred_index])) + != NULL) + { + int result; + const char* renaming = + ada_simple_renamed_entity (syms[preferred_index]); + char* new_name = xmalloc (strlen (renaming) + len0 + - yylval.ssym.stoken.length + 1); +/* add_name_string_cleanup (new_name);*/ +/* FIXME: add_name_string_cleanup should be defined in parse.c */ + strcpy (new_name, renaming); + strcat (new_name, name0 + yylval.ssym.stoken.length); + result = name_lookup (new_name, err_name, token_type); + if (result > segments) + error ("Confused by renamed symbol."); + return result; + } + else if (segments == 0) + { + yylval.tval = preferred_type; + *token_type = TYPENAME; + return 0; + } + } + + if (segments == 0) + { + type = lookup_primitive_typename (name); + if (type == NULL && STREQ ("system__address", name)) + type = builtin_type_ada_system_address; + if (type != NULL) + { + yylval.tval = type; + *token_type = TYPENAME; + return 0; + } + } + + NotType: + if (nsyms == 1) + { + *token_type = NAME; + yylval.ssym.sym = syms[0]; + yylval.ssym.msym = NULL; + yylval.ssym.block = blocks[0]; + return segments; + } + else if (nsyms == 0) { + int i; + yylval.ssym.msym = ada_lookup_minimal_symbol (name); + if (yylval.ssym.msym != NULL) + { + yylval.ssym.sym = NULL; + yylval.ssym.block = NULL; + *token_type = NAME; + return segments; + } + + for (i = yylval.ssym.stoken.length - 1; i > 0; i -= 1) + { + if (name[i] == '.') + { + name[i] = '\0'; + yylval.ssym.stoken.length = i; + break; + } + else if (name[i] == '_' && name[i-1] == '_') + { + i -= 1; + name[i] = '\0'; + yylval.ssym.stoken.length = i; + break; + } + } + if (i <= 0) + { + if (!have_full_symbols () && !have_partial_symbols () + && left_block_context == NULL) + error ("No symbol table is loaded. Use the \"file\" command."); + if (left_block_context == NULL) + error ("No definition of \"%s\" in current context.", + err_name); + else + error ("No definition of \"%s\" in specified context.", + err_name); + } + } + else + { + *token_type = NAME; + yylval.ssym.sym = NULL; + yylval.ssym.msym = NULL; + if (left_block_context == NULL) + yylval.ssym.block = expression_context_block; + else + yylval.ssym.block = left_block_context; + return segments; + } + } +} + +/* Returns the position within STR of the '.' in a + '.{WHITE}*all' component of a dotted name, or -1 if there is none. */ +static int +find_dot_all (str) + const char* str; +{ + int i; + for (i = 0; str[i] != '\000'; i += 1) + { + if (str[i] == '.') + { + int i0 = i; + do + i += 1; + while (isspace (str[i])); + if (strcmp (str+i, "all") == 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 (subseq, str) + 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 }, + { NULL, -1 } +}; + +/* Return the syntactic code corresponding to the attribute name or + abbreviation STR. */ + +static int +processAttribute (str) + const char* str; +{ + int i, k; + + for (i = 0; attributes[i].code != -1; i += 1) + if (strcasecmp (str, attributes[i].name) == 0) + return attributes[i].code; + + for (i = 0, k = -1; attributes[i].code != -1; i += 1) + if (subseqMatch (str, attributes[i].name)) + { + if (k == -1) + k = i; + else + error ("ambiguous attribute name: `%s'", str); + } + if (k == -1) + error ("unrecognized attribute: `%s'", str); + + return attributes[k].code; +} + +int +yywrap() +{ + return 1; +} diff --git a/gdb/ada-lex.l b/gdb/ada-lex.l new file mode 100644 index 0000000..2252d52 --- /dev/null +++ b/gdb/ada-lex.l @@ -0,0 +1,928 @@ +/* FLEX lexer for Ada expressions, for GDB. + Copyright (C) 1994, 1997, 2000 + 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 2 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, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/*----------------------------------------------------------------------*/ + +/* 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. */ + +/* Run flex with (at least) the -i option (case-insensitive), and the -I */ +/* option (interactive---no unnecessary lookahead). */ + +DIG [0-9] +NUM10 ({DIG}({DIG}|_)*) +HEXDIG [0-9a-f] +NUM16 ({HEXDIG}({HEXDIG}|_)*) +OCTDIG [0-7] +LETTER [a-z_] +ID ({LETTER}({LETTER}|{DIG})*|"<"{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}) + +%{ +#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 int processInt (const char*, const char*, const char*); +static int processReal (const char*); +static int processId (const char*, int); +static int processAttribute (const char*); +static int find_dot_all (const char*); + +#undef YY_DECL +#define YY_DECL static int yylex ( void ) + +#undef YY_INPUT +#define YY_INPUT(BUF, RESULT, MAX_SIZE) \ + if ( *lexptr == '\000' ) \ + (RESULT) = YY_NULL; \ + else \ + { \ + *(BUF) = *lexptr; \ + (RESULT) = 1; \ + lexptr += 1; \ + } + +static char *tempbuf = NULL; +static int tempbufsize = 0; +static int tempbuf_len; +static struct block* left_block_context; + +static void resize_tempbuf (unsigned int); + +static void block_lookup (char*, char*); + +static int name_lookup (char*, char*, int*); + +static int find_dot_all (const char*); + +%} + +%s IN_STRING BEFORE_QUAL_QUOTE + +%% + +{WHITE} { } + +"--".* { yyterminate(); } + +{NUM10}{POSEXP} { + canonicalizeNumeral (numbuf, yytext); + return processInt (NULL, numbuf, strrchr(numbuf, 'e')+1); + } + +{NUM10} { + canonicalizeNumeral (numbuf, yytext); + return processInt (NULL, numbuf, NULL); + } + +{NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#"{POSEXP} { + canonicalizeNumeral (numbuf, yytext); + return processInt (numbuf, + strchr (numbuf, '#') + 1, + strrchr(numbuf, '#') + 1); + } + +{NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#" { + canonicalizeNumeral (numbuf, yytext); + return processInt (numbuf, strchr (numbuf, '#') + 1, NULL); + } + +"0x"{HEXDIG}+ { + canonicalizeNumeral (numbuf, yytext+2); + return processInt ("16#", numbuf, NULL); + } + + +{NUM10}"."{NUM10}{EXP} { + canonicalizeNumeral (numbuf, yytext); + return processReal (numbuf); + } + +{NUM10}"."{NUM10} { + canonicalizeNumeral (numbuf, yytext); + return processReal (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.type = builtin_type_ada_char; + yylval.typed_val.val = yytext[1]; + return CHARLIT; + } + +<INITIAL>"'[\""{HEXDIG}{2}"\"]'" { + int v; + yylval.typed_val.type = builtin_type_ada_char; + sscanf (yytext+3, "%2x", &v); + yylval.typed_val.val = v; + return CHARLIT; + } + +\"{OPER}\"/{WHITE}*"(" { return processId (yytext, yyleng); } + +<INITIAL>\" { + tempbuf_len = 0; + BEGIN IN_STRING; + } + +<IN_STRING>{GRAPHIC}*\" { + resize_tempbuf (yyleng+tempbuf_len); + strncpy (tempbuf+tempbuf_len, yytext, yyleng-1); + tempbuf_len += yyleng-1; + yylval.sval.ptr = tempbuf; + yylval.sval.length = tempbuf_len; + BEGIN INITIAL; + return STRING; + } + +<IN_STRING>{GRAPHIC}*"[\""{HEXDIG}{2}"\"]" { + int n; + resize_tempbuf (yyleng-5+tempbuf_len+1); + strncpy (tempbuf+tempbuf_len, yytext, yyleng-6); + sscanf(yytext+yyleng-4, "%2x", &n); + tempbuf[yyleng-6+tempbuf_len] = (char) n; + tempbuf_len += yyleng-5; + } + +<IN_STRING>{GRAPHIC}*"[\"\"\"]" { + int n; + resize_tempbuf (yyleng-4+tempbuf_len+1); + strncpy (tempbuf+tempbuf_len, yytext, yyleng-6); + tempbuf[yyleng-5+tempbuf_len] = '"'; + tempbuf_len += yyleng-4; + } + +if { + while (*lexptr != 'i' && *lexptr != 'I') + lexptr -= 1; + yyrestart(NULL); + 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; } +rem { return REM; } +then { return THEN; } +xor { return XOR; } + + /* ATTRIBUTES */ + +{TICK}[a-zA-Z][a-zA-Z]+ { return processAttribute (yytext+1); } + + /* PUNCTUATION */ + +"=>" { return ARROW; } +".." { return DOTDOT; } +"**" { return STARSTAR; } +":=" { return ASSIGN; } +"/=" { return NOTEQUAL; } +"<=" { return LEQ; } +">=" { return GEQ; } + +<BEFORE_QUAL_QUOTE>"'" { BEGIN INITIAL; return '\''; } + +[-&*+./:<>=|;\[\]] { return yytext[0]; } + +"," { if (paren_depth == 0 && comma_terminates) + { + lexptr -= 1; + yyrestart(NULL); + return 0; + } + else + return ','; + } + +"(" { paren_depth += 1; return '('; } +")" { if (paren_depth == 0) + { + lexptr -= 1; + yyrestart(NULL); + return 0; + } + else + { + paren_depth -= 1; + return ')'; + } + } + +"."{WHITE}*all { return DOT_ALL; } + +"."{WHITE}*{ID} { + processId (yytext+1, yyleng-1); + return DOT_ID; + } + +{ID}({WHITE}*"."{WHITE}*({ID}|\"{OPER}\"))*(" "*"'")? { + int all_posn = find_dot_all (yytext); + int token_type, segments, k; + int quote_follows; + + if (all_posn == -1 && yytext[yyleng-1] == '\'') + { + quote_follows = 1; + do { + yyless (yyleng-1); + } while (yytext[yyleng-1] == ' '); + } + else + quote_follows = 0; + + if (all_posn >= 0) + yyless (all_posn); + processId(yytext, yyleng); + segments = name_lookup (ada_mangle (yylval.ssym.stoken.ptr), + yylval.ssym.stoken.ptr, &token_type); + left_block_context = NULL; + for (k = yyleng; segments > 0 && k > 0; k -= 1) + { + if (yytext[k-1] == '.') + segments -= 1; + quote_follows = 0; + } + if (k <= 0) + error ("confused by name %s", yytext); + yyless (k); + if (quote_follows) + BEGIN BEFORE_QUAL_QUOTE; + return token_type; + } + + /* GDB EXPRESSION CONSTRUCTS */ + + +"'"[^']+"'"{WHITE}*:: { + processId(yytext, yyleng-2); + block_lookup (yylval.ssym.stoken.ptr, yylval.ssym.stoken.ptr); + return BLOCKNAME; + } + +{ID}({WHITE}*"."{WHITE}*({ID}|\"{OPER}\"))*{WHITE}*:: { + processId(yytext, yyleng-2); + block_lookup (ada_mangle (yylval.ssym.stoken.ptr), + yylval.ssym.stoken.ptr); + return BLOCKNAME; + } + +[{}@] { return yytext[0]; } + +"$$" { yylval.lval = -1; return LAST; } +"$$"{DIG}+ { yylval.lval = -atoi(yytext+2); return LAST; } +"$" { yylval.lval = 0; return LAST; } +"$"{DIG}+ { yylval.lval = atoi(yytext+1); return LAST; } + + + /* REGISTERS AND GDB CONVENIENCE VARIABLES */ + +"$"({LETTER}|{DIG}|"$")+ { + int c; + for (c = 0; c < NUM_REGS; c++) + if (REGISTER_NAME (c) && + strcmp (yytext + 1, REGISTER_NAME (c)) == 0) + { + yylval.lval = c; + return REGNAME; + } + yylval.sval.ptr = yytext; + yylval.sval.length = yyleng; + yylval.ivar = + lookup_internalvar (copy_name (yylval.sval) + 1); + return INTERNAL_VARIABLE; + } + + /* CATCH-ALL ERROR CASE */ + +. { error ("Invalid character '%s' in expression.", yytext); } +%% + +#include <ctype.h> +#include <string.h> + +/* Initialize the lexer for processing new expression */ +void +lexer_init (FILE* inp) +{ + BEGIN INITIAL; + yyrestart (inp); +} + + +/* Make sure that tempbuf points at an array at least N characters long. */ + +static void +resize_tempbuf (n) + unsigned int n; +{ + if (tempbufsize < n) + { + tempbufsize = (n+63) & ~63; + tempbuf = (char*) xrealloc (tempbuf, tempbufsize); + } +} + +/* Copy S2 to S1, removing all underscores, and downcasing all letters. */ + +static void +canonicalizeNumeral (s1,s2) + char* s1; + const char* s2; +{ + for (; *s2 != '\000'; s2 += 1) + { + if (*s2 != '_') + { + *s1 = tolower(*s2); + s1 += 1; + } + } + s1[0] = '\000'; +} + +#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT) + +/* True (non-zero) iff DIGIT is a valid digit in radix BASE, + where 2 <= BASE <= 16. */ + +static int +is_digit_in_base (digit, base) + unsigned char digit; + int base; +{ + if (!isxdigit (digit)) + return 0; + if (base <= 10) + return (isdigit (digit) && digit < base + '0'); + else + return (isdigit (digit) || tolower (digit) < base - 10 + 'a'); +} + +static int +digit_to_int (c) + unsigned char c; +{ + if (isdigit (c)) + return c - '0'; + else + return tolower (c) - 'a' + 10; +} + +/* As for strtoul, but for ULONGEST results. */ +ULONGEST +strtoulst (num, trailer, base) + const char *num; + const char **trailer; + int base; +{ + unsigned int high_part; + ULONGEST result; + int i; + unsigned char lim; + + if (base < 2 || base > 16) + { + errno = EINVAL; + return 0; + } + lim = base - 1 + '0'; + + result = high_part = 0; + for (i = 0; is_digit_in_base (num[i], base); i += 1) + { + result = result*base + digit_to_int (num[i]); + high_part = high_part*base + (unsigned int) (result >> HIGH_BYTE_POSN); + result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1; + if (high_part > 0xff) + { + errno = ERANGE; + result = high_part = 0; + break; + } + } + + if (trailer != NULL) + *trailer = &num[i]; + + return result + ((ULONGEST) high_part << HIGH_BYTE_POSN); +} + + + +/* 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 (base0, num0, exp0) + const char* num0; + const char* base0; + const char* exp0; +{ + ULONGEST result; + long exp; + int base; + + char* trailer; + + if (base0 == NULL) + base = 10; + else + { + base = strtol (base0, (char**) NULL, 10); + if (base < 2 || base > 16) + error ("Invalid base: %d.", base); + } + + if (exp0 == NULL) + exp = 0; + else + exp = strtol(exp0, (char**) NULL, 10); + + errno = 0; + result = strtoulst (num0, &trailer, base); + if (errno == ERANGE) + error ("Integer literal out of range"); + if (isxdigit(*trailer)) + error ("Invalid digit `%c' in based literal", *trailer); + + while (exp > 0) + { + if (result > (ULONG_MAX / base)) + error ("Integer literal out of range"); + result *= base; + exp -= 1; + } + + if ((result >> (TARGET_INT_BIT-1)) == 0) + yylval.typed_val.type = builtin_type_ada_int; + else if ((result >> (TARGET_LONG_BIT-1)) == 0) + yylval.typed_val.type = builtin_type_ada_long; + else if (((result >> (TARGET_LONG_BIT-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_unsigned_long; + if (result & LONGEST_SIGN) + yylval.typed_val.val = + (LONGEST) (result & ~LONGEST_SIGN) + - (LONGEST_SIGN>>1) - (LONGEST_SIGN>>1); + else + yylval.typed_val.val = (LONGEST) result; + return INT; + } + else + yylval.typed_val.type = builtin_type_ada_long_long; + + yylval.typed_val.val = (LONGEST) result; + return INT; +} + +static int +processReal (num0) + const char* num0; +{ + if (sizeof (DOUBLEST) <= sizeof (float)) + sscanf (num0, "%g", &yylval.typed_val_float.dval); + else if (sizeof (DOUBLEST) <= sizeof (double)) + sscanf (num0, "%lg", &yylval.typed_val_float.dval); + else + { +#ifdef PRINTF_HAS_LONG_DOUBLE + sscanf (num0, "%Lg", &yylval.typed_val_float.dval); +#else + /* Scan it into a double, then convert and assign it to the + long double. This at least wins with values representable + in the range of doubles. */ + double temp; + sscanf (num0, "%lg", &temp); + yylval.typed_val_float.dval = temp; +#endif + } + + yylval.typed_val_float.type = builtin_type_ada_float; + if (sizeof(DOUBLEST) >= TARGET_DOUBLE_BIT / TARGET_CHAR_BIT) + yylval.typed_val_float.type = builtin_type_ada_double; + if (sizeof(DOUBLEST) >= TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT) + yylval.typed_val_float.type = builtin_type_ada_long_double; + + return FLOAT; +} + +static int +processId (name0, len) + const char *name0; + int len; +{ + char* name = xmalloc (len + 11); + int i0, i; + +/* add_name_string_cleanup (name); */ +/* FIXME: add_name_string_cleanup should be defined in parse.c */ + while (len > 0 && isspace (name0[len-1])) + len -= 1; + i = i0 = 0; + while (i0 < len) + { + if (isalnum (name0[i0])) + { + name[i] = tolower (name0[i0]); + i += 1; i0 += 1; + } + else switch (name0[i0]) + { + default: + name[i] = name0[i0]; + i += 1; i0 += 1; + break; + case ' ': case '\t': + i0 += 1; + break; + case '\'': + i0 += 1; + while (i0 < len && name0[i0] != '\'') + { + name[i] = name0[i0]; + i += 1; i0 += 1; + } + i0 += 1; + break; + case '<': + i0 += 1; + while (i0 < len && name0[i0] != '>') + { + name[i] = name0[i0]; + i += 1; i0 += 1; + } + i0 += 1; + break; + } + } + name[i] = '\000'; + + yylval.ssym.sym = NULL; + yylval.ssym.stoken.ptr = name; + yylval.ssym.stoken.length = i; + return NAME; +} + +static void +block_lookup (name, err_name) + char* name; + char* err_name; +{ + struct symbol** syms; + struct block** blocks; + int nsyms; + struct symtab *symtab; + nsyms = ada_lookup_symbol_list (name, left_block_context, + VAR_NAMESPACE, &syms, &blocks); + if (left_block_context == NULL && + (nsyms == 0 || SYMBOL_CLASS (syms[0]) != LOC_BLOCK)) + symtab = lookup_symtab (name); + else + symtab = NULL; + + if (symtab != NULL) + left_block_context = yylval.bval = + BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK); + else if (nsyms == 0 || SYMBOL_CLASS (syms[0]) != LOC_BLOCK) + { + if (left_block_context == NULL) + error ("No file or function \"%s\".", err_name); + else + error ("No function \"%s\" in specified context.", err_name); + } + else + { + left_block_context = yylval.bval = SYMBOL_BLOCK_VALUE (syms[0]); + if (nsyms > 1) + warning ("Function name \"%s\" ambiguous here", err_name); + } +} + +/* Look up NAME0 (assumed to be mangled) as a name in VAR_NAMESPACE, + setting *TOKEN_TYPE to NAME or TYPENAME, depending on what is + found. Try first the entire name, then the name without the last + segment (i.e., after the last .id), etc., and return the number of + segments that had to be removed to get a match. Calls error if no + matches are found, using ERR_NAME in any error message. When + exactly one symbol match is found, it is placed in yylval. */ + +static int +name_lookup (name0, err_name, token_type) + char* name0; + char* err_name; + int* token_type; +{ + struct symbol** syms; + struct block** blocks; + struct type* type; + int len0 = strlen (name0); + char* name = savestring (name0, len0); + int nsyms; + int segments; + +/* add_name_string_cleanup (name);*/ +/* FIXME: add_name_string_cleanup should be defined in parse.c */ + yylval.ssym.stoken.ptr = name; + yylval.ssym.stoken.length = strlen (name); + for (segments = 0; ; segments += 1) + { + struct type* preferred_type; + int i, preferred_index; + + if (left_block_context == NULL) + nsyms = ada_lookup_symbol_list (name, expression_context_block, + VAR_NAMESPACE, &syms, &blocks); + else + nsyms = ada_lookup_symbol_list (name, left_block_context, + VAR_NAMESPACE, &syms, &blocks); + + /* Check for a type definition. */ + + /* Look for a symbol that doesn't denote void. This is (I think) a */ + /* temporary kludge to get around problems in GNAT output. */ + preferred_index = -1; preferred_type = NULL; + for (i = 0; i < nsyms; i += 1) + switch (SYMBOL_CLASS (syms[i])) + { + case LOC_TYPEDEF: + if (ada_prefer_type (SYMBOL_TYPE (syms[i]), preferred_type)) + { + preferred_index = i; + preferred_type = SYMBOL_TYPE (syms[i]); + } + break; + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + goto NotType; + default: + break; + } + if (preferred_type != NULL) + { +/* if (TYPE_CODE (preferred_type) == TYPE_CODE_VOID) + error ("`%s' matches only void type name(s)", + ada_demangle (name)); +*/ +/* FIXME: ada_demangle should be defined in defs.h, and is located in ada-lang.c */ +/* else*/ if (ada_is_object_renaming (syms[preferred_index])) + { + yylval.ssym.sym = syms[preferred_index]; + *token_type = OBJECT_RENAMING; + return segments; + } + else if (ada_renaming_type (SYMBOL_TYPE (syms[preferred_index])) + != NULL) + { + int result; + const char* renaming = + ada_simple_renamed_entity (syms[preferred_index]); + char* new_name = xmalloc (strlen (renaming) + len0 + - yylval.ssym.stoken.length + 1); +/* add_name_string_cleanup (new_name);*/ +/* FIXME: add_name_string_cleanup should be defined in parse.c */ + strcpy (new_name, renaming); + strcat (new_name, name0 + yylval.ssym.stoken.length); + result = name_lookup (new_name, err_name, token_type); + if (result > segments) + error ("Confused by renamed symbol."); + return result; + } + else if (segments == 0) + { + yylval.tval = preferred_type; + *token_type = TYPENAME; + return 0; + } + } + + if (segments == 0) + { + type = lookup_primitive_typename (name); + if (type == NULL && STREQ ("system__address", name)) + type = builtin_type_ada_system_address; + if (type != NULL) + { + yylval.tval = type; + *token_type = TYPENAME; + return 0; + } + } + + NotType: + if (nsyms == 1) + { + *token_type = NAME; + yylval.ssym.sym = syms[0]; + yylval.ssym.msym = NULL; + yylval.ssym.block = blocks[0]; + return segments; + } + else if (nsyms == 0) { + int i; + yylval.ssym.msym = ada_lookup_minimal_symbol (name); + if (yylval.ssym.msym != NULL) + { + yylval.ssym.sym = NULL; + yylval.ssym.block = NULL; + *token_type = NAME; + return segments; + } + + for (i = yylval.ssym.stoken.length - 1; i > 0; i -= 1) + { + if (name[i] == '.') + { + name[i] = '\0'; + yylval.ssym.stoken.length = i; + break; + } + else if (name[i] == '_' && name[i-1] == '_') + { + i -= 1; + name[i] = '\0'; + yylval.ssym.stoken.length = i; + break; + } + } + if (i <= 0) + { + if (!have_full_symbols () && !have_partial_symbols () + && left_block_context == NULL) + error ("No symbol table is loaded. Use the \"file\" command."); + if (left_block_context == NULL) + error ("No definition of \"%s\" in current context.", + err_name); + else + error ("No definition of \"%s\" in specified context.", + err_name); + } + } + else + { + *token_type = NAME; + yylval.ssym.sym = NULL; + yylval.ssym.msym = NULL; + if (left_block_context == NULL) + yylval.ssym.block = expression_context_block; + else + yylval.ssym.block = left_block_context; + return segments; + } + } +} + +/* Returns the position within STR of the '.' in a + '.{WHITE}*all' component of a dotted name, or -1 if there is none. */ +static int +find_dot_all (str) + const char* str; +{ + int i; + for (i = 0; str[i] != '\000'; i += 1) + { + if (str[i] == '.') + { + int i0 = i; + do + i += 1; + while (isspace (str[i])); + if (strcmp (str+i, "all") == 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 (subseq, str) + 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 }, + { NULL, -1 } +}; + +/* Return the syntactic code corresponding to the attribute name or + abbreviation STR. */ + +static int +processAttribute (str) + const char* str; +{ + int i, k; + + for (i = 0; attributes[i].code != -1; i += 1) + if (strcasecmp (str, attributes[i].name) == 0) + return attributes[i].code; + + for (i = 0, k = -1; attributes[i].code != -1; i += 1) + if (subseqMatch (str, attributes[i].name)) + { + if (k == -1) + k = i; + else + error ("ambiguous attribute name: `%s'", str); + } + if (k == -1) + error ("unrecognized attribute: `%s'", str); + + return attributes[k].code; +} + +int +yywrap() +{ + return 1; +} diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c new file mode 100644 index 0000000..23dc105 --- /dev/null +++ b/gdb/ada-tasks.c @@ -0,0 +1,806 @@ +/* file ada-tasks.c: Ada tasking control for GDB + Copyright 1997 Free Software Foundation, Inc. + Contributed by Ada Core Technologies, Inc +. + This file is part of GDB. + + [$Id$] + Authors: Roch-Alexandre Nomine Beguin, Arnaud Charlet <charlet@gnat.com> + + 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 2 of the License, or + (at your option) any later version. + +*/ + +#include <ctype.h> +#include "defs.h" +#include "command.h" +#include "value.h" +#include "language.h" +#include "inferior.h" +#include "symtab.h" +#include "target.h" +#include "gdbcore.h" + +#if (defined(__alpha__) && defined(__osf__) && !defined(__alpha_vxworks)) +#include <sys/procfs.h> +#endif + +#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)) +#include "gregset.h" +#endif + +#include "ada-lang.h" + +/* FIXME: move all this conditional compilation in description + files or in configure.in */ + +#if defined (VXWORKS_TARGET) +#define THREAD_TO_PID(tid,lwpid) (tid) + +#elif defined (linux) +#define THREAD_TO_PID(tid,lwpid) (0) + +#elif (defined (sun) && defined (__SVR4)) +#define THREAD_TO_PID thread_to_pid + +#elif defined (sgi) || defined (__WIN32__) || defined (hpux) +#define THREAD_TO_PID(tid,lwpid) ((int)lwpid) + +#else +#define THREAD_TO_PID(tid,lwpid) (0) +#endif + +#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET) +#define THREAD_FETCH_REGISTERS dec_thread_fetch_registers +#define GET_CURRENT_THREAD dec_thread_get_current_thread +extern int dec_thread_get_registers (gdb_gregset_t *, gdb_fpregset_t *); +#endif + +#if defined (_AIX) +#define THREAD_FETCH_REGISTERS aix_thread_fetch_registers +#define GET_CURRENT_THREAD aix_thread_get_current_thread +#endif + +#if defined(VXWORKS_TARGET) +#define GET_CURRENT_THREAD() ((void*)inferior_pid) +#define THREAD_FETCH_REGISTERS() (-1) + +#elif defined (sun) && defined (__SVR4) +#define GET_CURRENT_THREAD solaris_thread_get_current_thread +#define THREAD_FETCH_REGISTERS() (-1) +extern void *GET_CURRENT_THREAD(); + +#elif defined (_AIX) || (defined(__alpha__) && defined(__osf__)) +extern void *GET_CURRENT_THREAD(); + +#elif defined (__WIN32__) || defined (hpux) +#define GET_CURRENT_THREAD() (inferior_pid) +#define THREAD_FETCH_REGISTERS() (-1) + +#else +#define GET_CURRENT_THREAD() (NULL) +#define THREAD_FETCH_REGISTERS() (-1) +#endif + +#define KNOWN_TASKS_NAME "system__tasking__debug__known_tasks" + +#define READ_MEMORY(addr, var) read_memory (addr, (char*) &var, sizeof (var)) +/* external declarations */ + +extern struct value* find_function_in_inferior (char *); + +/* Global visible variables */ + +struct task_entry *task_list = NULL; +int ada__tasks_check_symbol_table = 1; +void *pthread_kern_addr = NULL; + +#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)) +gdb_gregset_t gregset_saved; +gdb_fpregset_t fpregset_saved; +#endif + +/* The maximum number of tasks known to the Ada runtime */ +const int MAX_NUMBER_OF_KNOWN_TASKS = 1000; + +/* the current task */ +int current_task = -1, current_task_id = -1, current_task_index; +void *current_thread, *current_lwp; + +char *ada_task_states[] = +{ + "Unactivated", + "Runnable", + "Terminated", + "Child Activation Wait", + "Accept Statement", + "Waiting on entry call", + "Async Select Wait", + "Delay Sleep", + "Child Termination Wait", + "Wait Child in Term Alt", + "", + "", + "", + "", + "Asynchronous Hold" +}; + +/* Global internal types */ + +static char *ada_long_task_states[] = +{ + "Unactivated", + "Runnable", + "Terminated", + "Waiting for child activation", + "Blocked in accept statement", + "Waiting on entry call", + "Asynchronous Selective Wait", + "Delay Sleep", + "Waiting for children termination", + "Waiting for children in terminate alternative", + "", + "", + "", + "", + "Asynchronous Hold" +}; + +/* Global internal variables */ + +static int highest_task_num = 0; +int thread_support = 0; /* 1 if the thread library in use is supported */ +static int gdbtk_task_initialization = 0; + +static int add_task_entry (p_task_id, index) + void *p_task_id; + int index; +{ + struct task_entry *new_task_entry = NULL; + struct task_entry *pt; + + highest_task_num++; + new_task_entry = malloc (sizeof (struct task_entry)); + new_task_entry->task_num = highest_task_num; + new_task_entry->task_id = p_task_id; + new_task_entry->known_tasks_index = index; + new_task_entry->next_task = NULL; + pt = task_list; + if (pt) + { + while (pt->next_task) + pt = pt->next_task; + pt->next_task = new_task_entry; + pt->stack_per = 0; + } + else task_list = new_task_entry; + return new_task_entry->task_num; +} + +int +get_entry_number (p_task_id) + void *p_task_id; +{ + struct task_entry *pt; + + pt = task_list; + while (pt != NULL) + { + if (pt->task_id == p_task_id) + return pt->task_num; + pt = pt->next_task; + } + return 0; +} + +static struct task_entry *get_thread_entry_vptr (thread) + void *thread; +{ + struct task_entry *pt; + + pt = task_list; + while (pt != NULL) + { + if (pt->thread == thread) + return pt; + pt = pt->next_task; + } + return 0; +} + +static struct task_entry *get_entry_vptr (p_task_num) + int p_task_num; +{ + struct task_entry *pt; + + pt = task_list; + while (pt) + { + if (pt->task_num == p_task_num) + return pt; + pt = pt->next_task; + } + return NULL; +} + +void init_task_list () +{ + struct task_entry *pt, *old_pt; + + pt = task_list; + while (pt) + { + old_pt = pt; + pt = pt->next_task; + free (old_pt); + }; + task_list = NULL; + highest_task_num = 0; +} + +int valid_task_id (task) + int task; +{ + return get_entry_vptr (task) != NULL; +} + +void *get_self_id () +{ + struct value* val; + void *self_id; + int result; + struct task_entry *ent; + extern int do_not_insert_breakpoints; + +#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__)) + if (thread_support) +#endif + { + ent = get_thread_entry_vptr (GET_CURRENT_THREAD ()); + return ent ? ent->task_id : 0; + } + + /* FIXME: calling a function in the inferior with a multithreaded application + is not reliable, so return NULL if there is no safe way to get the current + task */ + return NULL; +} + +int get_current_task () +{ + int result; + + /* FIXME: language_ada should be defined in defs.h */ + /* if (current_language->la_language != language_ada) return -1; */ + + result = get_entry_number (get_self_id ()); + + /* return -1 if not found */ + return result == 0 ? -1 : result; +} + +/* Print detailed information about specified task */ + +static void +info_task (arg, from_tty) + char *arg; + int from_tty; +{ + void *temp_task; + struct task_entry *pt, *pt2; + void *self_id, *caller; + struct task_fields atcb, atcb2; + struct entry_call call; + int bounds [2]; + char image [256]; + int num; + + /* FIXME: language_ada should be defined in defs.h */ + /* if (current_language->la_language != language_ada) + { + printf_filtered ("The current language does not support tasks.\n"); + return; + } + */ + pt = get_entry_vptr (atoi (arg)); + if (pt == NULL) + { + printf_filtered ("Task %s not found.\n", arg); + return; + } + + temp_task = pt->task_id; + + /* read the atcb in the inferior */ + READ_MEMORY ((CORE_ADDR) temp_task, atcb); + + /* print the Ada task id */ + printf_filtered ("Ada Task: %p\n", temp_task); + + /* print the name of the task */ + if (atcb.image.P_ARRAY != NULL) { + READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS), bounds); + bounds [1] = EXTRACT_INT (bounds [1]); + read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY), + (char*) &image, bounds [1]); + printf_filtered ("Name: %.*s\n", bounds [1], image); + } + else printf_filtered ("<no name>\n"); + + /* print the thread id */ + + if ((long) pt->thread < 65536) + printf_filtered ("Thread: %ld\n", (long int) pt->thread); + else + printf_filtered ("Thread: %p\n", pt->thread); + + if ((long) pt->lwp != 0) + { + if ((long) pt->lwp < 65536) + printf_filtered ("LWP: %ld\n", (long int) pt->lwp); + else + printf_filtered ("LWP: %p\n", pt->lwp); + } + + /* print the parent gdb task id */ + num = get_entry_number (EXTRACT_ADDRESS (atcb.parent)); + if (num != 0) + { + printf_filtered ("Parent: %d", num); + pt2 = get_entry_vptr (num); + READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2); + + /* print the name of the task */ + if (atcb2.image.P_ARRAY != NULL) { + READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS), + bounds); + bounds [1] = EXTRACT_INT (bounds [1]); + read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY), + (char*) &image, bounds [1]); + printf_filtered (" (%.*s)\n", bounds [1], image); + } + else + printf_filtered ("\n"); + } + else + printf_filtered ("No parent\n"); + + /* print the base priority of the task */ + printf_filtered ("Base Priority: %d\n", EXTRACT_INT (atcb.priority)); + + /* print the current state of the task */ + + /* check if this task is accepting a rendezvous */ + if (atcb.call == NULL) + caller = NULL; + else { + READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call); + caller = EXTRACT_ADDRESS (call.self); + } + + if (caller != NULL) + { + num = get_entry_number (caller); + printf_filtered ("Accepting rendezvous with %d", num); + + if (num != 0) + { + pt2 = get_entry_vptr (num); + READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2); + + /* print the name of the task */ + if (atcb2.image.P_ARRAY != NULL) { + READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS), + bounds); + bounds [1] = EXTRACT_INT (bounds [1]); + read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY), + (char*) &image, bounds [1]); + printf_filtered (" (%.*s)\n", bounds [1], image); + } + else + printf_filtered ("\n"); + } + else + printf_filtered ("\n"); + } + else + printf_filtered ("State: %s\n", ada_long_task_states [atcb.state]); +} + +#if 0 + +/* A useful function that shows the alignment of all the fields in the + tasks_fields structure + */ + +print_align () +{ + struct task_fields tf; + void *tf_base = &(tf); + void *tf_state = &(tf.state); + void *tf_entry_num = &(tf.entry_num); + void *tf_parent = &(tf.parent); + void *tf_priority = &(tf.priority); + void *tf_current_priority = &(tf.current_priority); + void *tf_image = &(tf.image); + void *tf_call = &(tf.call); + void *tf_thread = &(tf.thread); + void *tf_lwp = &(tf.lwp); + printf_filtered ("\n"); + printf_filtered ("(tf_base = 0x%x)\n", tf_base); + printf_filtered ("task_fields.entry_num at %3d (0x%x)\n", tf_entry_num - tf_base, tf_entry_num); + printf_filtered ("task_fields.state at %3d (0x%x)\n", tf_state - tf_base, tf_state); + printf_filtered ("task_fields.parent at %3d (0x%x)\n", tf_parent - tf_base, tf_parent); + printf_filtered ("task_fields.priority at %3d (0x%x)\n", tf_priority - tf_base, tf_priority); + printf_filtered ("task_fields.current_priority at %3d (0x%x)\n", tf_current_priority - tf_base, tf_current_priority); + printf_filtered ("task_fields.image at %3d (0x%x)\n", tf_image - tf_base, tf_image); + printf_filtered ("task_fields.call at %3d (0x%x)\n", tf_call - tf_base, tf_call); + printf_filtered ("task_fields.thread at %3d (0x%x)\n", tf_thread - tf_base, tf_thread); + printf_filtered ("task_fields.lwp at %3d (0x%x)\n", tf_lwp - tf_base, tf_lwp); + printf_filtered ("\n"); +} +#endif + +/* Print information about currently known tasks */ + +static void +info_tasks (arg, from_tty) + char *arg; + int from_tty; +{ + struct value* val; + int i, task_number, state; + void *temp_task, *temp_tasks [MAX_NUMBER_OF_KNOWN_TASKS]; + struct task_entry *pt; + void *self_id, *caller, *thread_id=NULL; + struct task_fields atcb; + struct entry_call call; + int bounds [2]; + char image [256]; + int size; + char car; + +#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET) + pthreadTeb_t thr; + gdb_gregset_t regs; +#endif + + static struct symbol *sym; + static struct minimal_symbol *msym; + static void *known_tasks_addr = NULL; + + int init_only = gdbtk_task_initialization; + gdbtk_task_initialization = 0; + + task_number = 0; + + if (PIDGET(inferior_ptid) == 0) + { + printf_filtered ("The program is not being run under gdb. "); + printf_filtered ("Use 'run' or 'attach' first.\n"); + return; + } + + if (ada__tasks_check_symbol_table) + { + thread_support = 0; +#if (defined(__alpha__) && defined(__osf__) & !defined(VXWORKS_TARGET)) || \ + defined (_AIX) + thread_support = 1; +#endif + + msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL); + if (msym != NULL) + known_tasks_addr = (void *) SYMBOL_VALUE_ADDRESS (msym); + else +#ifndef VXWORKS_TARGET + return; +#else + { + if (target_lookup_symbol (KNOWN_TASKS_NAME, &known_tasks_addr) != 0) + return; + } +#endif + + ada__tasks_check_symbol_table = 0; + } + + if (known_tasks_addr == NULL) + return; + +#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__) || defined (hpux)) + if (thread_support) +#endif + thread_id = GET_CURRENT_THREAD (); + + /* then we get a list of tasks created */ + + init_task_list (); + + READ_MEMORY ((CORE_ADDR) known_tasks_addr, temp_tasks); + + for (i=0; i<MAX_NUMBER_OF_KNOWN_TASKS; i++) + { + temp_task = EXTRACT_ADDRESS (temp_tasks[i]); + + if (temp_task != NULL) + { + task_number = get_entry_number (temp_task); + if (task_number == 0) + task_number = add_task_entry (temp_task, i); + } + } + + /* Return without printing anything if this function was called in + order to init GDBTK tasking. */ + + if (init_only) return; + + /* print the header */ + +#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET) + printf_filtered + (" ID TID P-ID Pri Stack %% State Name\n"); +#else + printf_filtered (" ID TID P-ID Pri State Name\n"); +#endif + + /* Now that we have a list of task id's, we can print them */ + pt = task_list; + while (pt) + { + temp_task = pt->task_id; + + /* read the atcb in the inferior */ + READ_MEMORY ((CORE_ADDR) temp_task, atcb); + + /* store the thread id for future use */ + pt->thread = EXTRACT_ADDRESS (atcb.thread); + +#if defined (linux) + pt->lwp = (void *) THREAD_TO_PID (atcb.thread, 0); +#else + pt->lwp = EXTRACT_ADDRESS (atcb.lwp); +#endif + + /* print a star if this task is the current one */ + if (thread_id) +#if defined (__WIN32__) || defined (SGI) || defined (hpux) + printf_filtered (pt->lwp == thread_id ? "*" : " "); +#else + printf_filtered (pt->thread == thread_id ? "*" : " "); +#endif + + /* print the gdb task id */ + printf_filtered ("%3d", pt->task_num); + + /* print the Ada task id */ +#ifndef VXWORKS_TARGET + printf_filtered (" %9lx", (long) temp_task); +#else +#ifdef TARGET_64 + printf_filtered (" %#9lx", (unsigned long)pt->thread & 0x3ffffffffff); +#else + printf_filtered (" %#9lx", (long)pt->thread); +#endif +#endif + + /* print the parent gdb task id */ + printf_filtered + (" %4d", get_entry_number (EXTRACT_ADDRESS (atcb.parent))); + + /* print the base priority of the task */ + printf_filtered (" %3d", EXTRACT_INT (atcb.priority)); + +#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET) + if (pt->task_num == 1 || atcb.state == Terminated) + { + printf_filtered (" Unknown"); + goto next; + } + + read_memory ((CORE_ADDR)atcb.thread, &thr, sizeof (thr)); + current_thread = atcb.thread; + regs.regs [SP_REGNUM] = 0; + if (dec_thread_get_registers (®s, NULL) == 0) { + pt->stack_per = (100 * ((long)thr.__stack_base - + regs.regs [SP_REGNUM])) / thr.__stack_size; + /* if the thread is terminated but still there, the + stack_base/size values are erroneous. Try to patch it */ + if (pt->stack_per < 0 || pt->stack_per > 100) pt->stack_per = 0; + } + + /* print information about stack space used in the thread */ + if (thr.__stack_size < 1024*1024) + { + size = thr.__stack_size / 1024; + car = 'K'; + } + else if (thr.__stack_size < 1024*1024*1024) + { + size = thr.__stack_size / 1024 / 1024; + car = 'M'; + } + else /* Who knows... */ + { + size = thr.__stack_size / 1024 / 1024 / 1024; + car = 'G'; + } + printf_filtered (" %4d%c %2d", size, car, pt->stack_per); +next: +#endif + + /* print the current state of the task */ + + /* check if this task is accepting a rendezvous */ + if (atcb.call == NULL) + caller = NULL; + else { + READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call); + caller = EXTRACT_ADDRESS (call.self); + } + + if (caller != NULL) + printf_filtered (" Accepting RV with %-4d", get_entry_number (caller)); + else + { + state = atcb.state; +#if defined (__WIN32__) || defined (SGI) || defined (hpux) + if (state == Runnable && (thread_id && pt->lwp == thread_id)) +#else + if (state == Runnable && (thread_id && pt->thread == thread_id)) +#endif + /* Replace "Runnable" by "Running" if this is the current task */ + printf_filtered (" %-22s", "Running"); + else + printf_filtered (" %-22s", ada_task_states [state]); + } + + /* finally, print the name of the task */ + if (atcb.image.P_ARRAY != NULL) { + READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS), bounds); + bounds [1] = EXTRACT_INT (bounds [1]); + read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY), + (char*)&image, bounds [1]); + printf_filtered (" %.*s\n", bounds [1], image); + } + else printf_filtered (" <no name>\n"); + + pt = pt->next_task; + } +} + +/* Task list initialization for GDB-Tk. We basically use info_tasks() + to initialize our variables, but abort that function before we + actually print anything. */ + +int +gdbtk_tcl_tasks_initialize () +{ + gdbtk_task_initialization = 1; + info_tasks ("", gdb_stdout); + + return (task_list != NULL); +} + +static void +info_tasks_command (arg, from_tty) + char *arg; + int from_tty; +{ + if (arg == NULL || *arg == '\000') + info_tasks (arg, from_tty); + else + info_task (arg, from_tty); +} + +/* Switch from one thread to another. */ + +static void +switch_to_thread (ptid_t ptid) + +{ + if (ptid_equal (ptid, inferior_ptid)) + return; + + inferior_ptid = ptid; + flush_cached_frames (); + registers_changed (); + stop_pc = read_pc (); + select_frame (get_current_frame ()); +} + +/* Switch to a specified task. */ + +static int task_switch (tid, lwpid) + void *tid, *lwpid; +{ + int res = 0, pid; + + if (thread_support) + { + flush_cached_frames (); + + if (current_task != current_task_id) + { + res = THREAD_FETCH_REGISTERS (); + } + else + { +#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)) + supply_gregset (&gregset_saved); + supply_fpregset (&fpregset_saved); +#endif + } + + if (res == 0) stop_pc = read_pc(); + select_frame (get_current_frame ()); + return res; + } + + return -1; +} + +static void task_command (tidstr, from_tty) + char *tidstr; + int from_tty; +{ + int num; + struct task_entry *e; + + if (!tidstr) + error ("Please specify a task ID. Use the \"info tasks\" command to\n" + "see the IDs of currently known tasks."); + + num = atoi (tidstr); + e = get_entry_vptr (num); + + if (e == NULL) + error ("Task ID %d not known. Use the \"info tasks\" command to\n" + "see the IDs of currently known tasks.", num); + + if (current_task_id == -1) + { +#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)) + fill_gregset (&gregset_saved, -1); + fill_fpregset (&fpregset_saved, -1); +#endif + current_task_id = get_current_task (); + } + + current_task = num; + current_task_index = e->known_tasks_index; + current_thread = e->thread; + current_lwp = e->lwp; + if (task_switch (e->thread, e->lwp) == 0) + { + /* FIXME: find_printable_frame should be defined in frame.h, and + implemented in ada-lang.c */ + /* find_printable_frame (selected_frame, frame_relative_level (selected_frame));*/ + printf_filtered ("[Switching to task %d]\n", num); + print_stack_frame (selected_frame, frame_relative_level (selected_frame), 1); + } + else + printf_filtered ("Unable to switch to task %d\n", num); +} + +void +_initialize_tasks () +{ + static struct cmd_list_element *task_cmd_list = NULL; + extern struct cmd_list_element *cmdlist; + + add_info ( + "tasks", info_tasks_command, + "Without argument: list all known Ada tasks, with status information.\n" + "info tasks n: print detailed information of task n.\n"); + + add_prefix_cmd ("task", class_run, task_command, + "Use this command to switch between tasks.\n\ + The new task ID must be currently known.", &task_cmd_list, "task ", 1, + &cmdlist); +} diff --git a/gdb/ada-typeprint.c b/gdb/ada-typeprint.c new file mode 100644 index 0000000..6773561 --- /dev/null +++ b/gdb/ada-typeprint.c @@ -0,0 +1,896 @@ +/* Support for printing Ada types for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991, 1997 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 2 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, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "obstack.h" +#include "bfd.h" /* Binary File Description */ +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "gdbcore.h" +#include "target.h" +#include "command.h" +#include "gdbcmd.h" +#include "language.h" +#include "demangle.h" +#include "c-lang.h" +#include "typeprint.h" +#include "ada-lang.h" + +#include <ctype.h> +#include <string.h> +#include <errno.h> + +static int print_record_field_types (struct type *, struct type *, + struct ui_file *, int, int); + +static void print_array_type (struct type*, struct ui_file*, int, int); + +static void print_choices (struct type*, int, struct ui_file*, struct type*); + +static void print_range (struct type*, struct ui_file*); + +static void print_range_bound (struct type*, char*, int*, struct ui_file*); + +static void +print_dynamic_range_bound (struct type*, const char*, int, + const char*, struct ui_file*); + +static void print_range_type_named (char*, struct ui_file*); + + + +static char* name_buffer; +static int name_buffer_len; + +/* The (demangled) Ada name of TYPE. This value persists until the + next call. */ + +static char* +demangled_type_name (type) + struct type *type; +{ + if (ada_type_name (type) == NULL) + return NULL; + else + { + char* raw_name = ada_type_name (type); + char *s, *q; + + if (name_buffer == NULL || name_buffer_len <= strlen (raw_name)) + { + name_buffer_len = 16 + 2 * strlen (raw_name); + name_buffer = xrealloc (name_buffer, name_buffer_len); + } + strcpy (name_buffer, raw_name); + + s = (char*) strstr (name_buffer, "___"); + if (s != NULL) + *s = '\0'; + + s = name_buffer + strlen (name_buffer) - 1; + while (s > name_buffer && (s[0] != '_' || s[-1] != '_')) + s -= 1; + + if (s == name_buffer) + return name_buffer; + + if (! islower (s[1])) + return NULL; + + for (s = q = name_buffer; *s != '\0'; q += 1) + { + if (s[0] == '_' && s[1] == '_') + { + *q = '.'; s += 2; + } + else + { + *q = *s; s += 1; + } + } + *q = '\0'; + return name_buffer; + } +} + + +/* Print a description of a type in the format of a + typedef for the current language. + NEW is the new name for a type TYPE. */ + +void +ada_typedef_print (type, new, stream) + struct type *type; + struct symbol *new; + struct ui_file *stream; +{ + fprintf_filtered (stream, "type %.*s is ", + ada_name_prefix_len (SYMBOL_SOURCE_NAME(new)), + SYMBOL_SOURCE_NAME(new)); + type_print (type, "", stream, 1); +} + +/* Print range type TYPE on STREAM. */ + +static void +print_range (type, stream) + struct type* type; + struct ui_file* stream; +{ + struct type* target_type; + target_type = TYPE_TARGET_TYPE (type); + if (target_type == NULL) + target_type = type; + + switch (TYPE_CODE (target_type)) + { + case TYPE_CODE_RANGE: + case TYPE_CODE_INT: + case TYPE_CODE_BOOL: + case TYPE_CODE_CHAR: + case TYPE_CODE_ENUM: + break; + default: + target_type = builtin_type_ada_int; + break; + } + + if (TYPE_NFIELDS (type) < 2) + { + /* A range needs at least 2 bounds to be printed. If there are less + than 2, just print the type name instead of the range itself. + This check handles cases such as characters, for example. + + Note that if the name is not defined, then we don't print anything. + */ + fprintf_filtered (stream, "%.*s", + ada_name_prefix_len (TYPE_NAME (type)), + TYPE_NAME (type)); + } + else + { + /* We extract the range type bounds respectively from the first element + and the last element of the type->fields array */ + const LONGEST lower_bound = (LONGEST) TYPE_LOW_BOUND (type); + const LONGEST upper_bound = + (LONGEST) TYPE_FIELD_BITPOS (type, TYPE_NFIELDS (type) -1); + + ada_print_scalar (target_type, lower_bound, stream); + fprintf_filtered (stream, " .. "); + ada_print_scalar (target_type, upper_bound, stream); + } +} + +/* Print the number or discriminant bound at BOUNDS+*N on STREAM, and + set *N past the bound and its delimiter, if any. */ + +static void +print_range_bound (type, bounds, n, stream) + struct type* type; + char* bounds; + int* n; + struct ui_file* stream; +{ + LONGEST B; + if (ada_scan_number (bounds, *n, &B, n)) + { + ada_print_scalar (type, B, stream); + if (bounds[*n] == '_') + *n += 2; + } + else + { + int bound_len; + char* bound = bounds + *n; + char* pend; + + pend = strstr (bound, "__"); + if (pend == NULL) + *n += bound_len = strlen (bound); + else + { + bound_len = pend - bound; + *n += bound_len + 2; + } + fprintf_filtered (stream, "%.*s", bound_len, bound); + } +} + +/* Assuming NAME[0 .. NAME_LEN-1] is the name of a range type, print + the value (if found) of the bound indicated by SUFFIX ("___L" or + "___U") according to the ___XD conventions. */ + +static void +print_dynamic_range_bound (type, name, name_len, suffix, stream) + struct type* type; + const char* name; + int name_len; + const char* suffix; + struct ui_file* stream; +{ + static char *name_buf = NULL; + static size_t name_buf_len = 0; + LONGEST B; + int OK; + + GROW_VECT (name_buf, name_buf_len, name_len + strlen (suffix) + 1); + strncpy (name_buf, name, name_len); + strcpy (name_buf + name_len, suffix); + + B = get_int_var_value (name_buf, 0, &OK); + if (OK) + ada_print_scalar (type, B, stream); + else + fprintf_filtered (stream, "?"); +} + +/* Print the range type named NAME. */ + +static void +print_range_type_named (name, stream) + char* name; + struct ui_file* stream; +{ + struct type *raw_type = ada_find_any_type (name); + struct type *base_type; + LONGEST low, high; + char* subtype_info; + + if (raw_type == NULL) + base_type = builtin_type_int; + else if (TYPE_CODE (raw_type) == TYPE_CODE_RANGE) + base_type = TYPE_TARGET_TYPE (raw_type); + else + base_type = raw_type; + + subtype_info = strstr (name, "___XD"); + if (subtype_info == NULL && raw_type == NULL) + fprintf_filtered (stream, "? .. ?"); + else if (subtype_info == NULL) + print_range (raw_type, stream); + else + { + int prefix_len = subtype_info - name; + char *bounds_str; + int n; + + subtype_info += 5; + bounds_str = strchr (subtype_info, '_'); + n = 1; + + if (*subtype_info == 'L') + { + print_range_bound (raw_type, bounds_str, &n, stream); + subtype_info += 1; + } + else + print_dynamic_range_bound (raw_type, name, prefix_len, "___L", stream); + + fprintf_filtered (stream, " .. "); + + if (*subtype_info == 'U') + print_range_bound (raw_type, bounds_str, &n, stream); + else + print_dynamic_range_bound (raw_type, name, prefix_len, "___U", stream); + } +} + +/* Print enumerated type TYPE on STREAM. */ + +static void +print_enum_type (type, stream) + struct type *type; + struct ui_file *stream; +{ + int len = TYPE_NFIELDS (type); + int i, lastval; + + fprintf_filtered (stream, "("); + wrap_here (" "); + + lastval = 0; + for (i = 0; i < len; i++) + { + QUIT; + if (i) fprintf_filtered (stream, ", "); + wrap_here (" "); + fputs_filtered (ada_enum_name (TYPE_FIELD_NAME (type, i)), stream); + if (lastval != TYPE_FIELD_BITPOS (type, i)) + { + fprintf_filtered (stream, " => %d", TYPE_FIELD_BITPOS (type, i)); + lastval = TYPE_FIELD_BITPOS (type, i); + } + lastval += 1; + } + fprintf_filtered (stream, ")"); +} + +/* Print representation of Ada fixed-point type TYPE on STREAM. */ + +static void +print_fixed_point_type (type, stream) + struct type *type; + struct ui_file *stream; +{ + DOUBLEST delta = ada_delta (type); + DOUBLEST small = ada_fixed_to_float (type, 1.0); + + if (delta < 0.0) + fprintf_filtered (stream, "delta ??"); + else + { + fprintf_filtered (stream, "delta %g", (double) delta); + if (delta != small) + fprintf_filtered (stream, " <'small = %g>", (double) small); + } +} + +/* Print representation of special VAX floating-point type TYPE on STREAM. */ + +static void +print_vax_floating_point_type (type, stream) + struct type *type; + struct ui_file *stream; +{ + fprintf_filtered (stream, "<float format %c>", + ada_vax_float_type_suffix (type)); +} + +/* Print simple (constrained) array type TYPE on STREAM. LEVEL is the + recursion (indentation) level, in case the element type itself has + nested structure, and SHOW is the number of levels of internal + structure to show (see ada_print_type). */ + +static void +print_array_type (type, stream, show, level) + struct type *type; + struct ui_file *stream; + int show; + int level; +{ + int bitsize; + int n_indices; + + bitsize = 0; + fprintf_filtered (stream, "array ("); + + n_indices = -1; + if (show < 0) + fprintf_filtered (stream, "..."); + else + { + if (ada_is_packed_array_type (type)) + type = ada_coerce_to_simple_array_type (type); + if (ada_is_simple_array (type)) + { + struct type* range_desc_type = + ada_find_parallel_type (type, "___XA"); + struct type* arr_type; + + bitsize = 0; + if (range_desc_type == NULL) + { + for (arr_type = type; TYPE_CODE (arr_type) == TYPE_CODE_ARRAY; + arr_type = TYPE_TARGET_TYPE (arr_type)) + { + if (arr_type != type) + fprintf_filtered (stream, ", "); + print_range (TYPE_INDEX_TYPE (arr_type), stream); + if (TYPE_FIELD_BITSIZE (arr_type, 0) > 0) + bitsize = TYPE_FIELD_BITSIZE (arr_type, 0); + } + } + else + { + int k; + n_indices = TYPE_NFIELDS (range_desc_type); + for (k = 0, arr_type = type; + k < n_indices; + k += 1, arr_type = TYPE_TARGET_TYPE (arr_type)) + { + if (k > 0) + fprintf_filtered (stream, ", "); + print_range_type_named (TYPE_FIELD_NAME (range_desc_type, k), + stream); + if (TYPE_FIELD_BITSIZE (arr_type, 0) > 0) + bitsize = TYPE_FIELD_BITSIZE (arr_type, 0); + } + } + } + else + { + int i, i0; + for (i = i0 = ada_array_arity (type); i > 0; i -= 1) + fprintf_filtered (stream, "%s<>", i == i0 ? "" : ", "); + } + } + + fprintf_filtered (stream, ") of "); + wrap_here (""); + ada_print_type (ada_array_element_type (type, n_indices), "", stream, + show == 0 ? 0 : show-1, level+1); + if (bitsize > 0) + fprintf_filtered (stream, " <packed: %d-bit elements>", bitsize); +} + +/* Print the choices encoded by field FIELD_NUM of variant-part TYPE on + STREAM, assuming the VAL_TYPE is the type of the values. */ + +static void +print_choices (type, field_num, stream, val_type) + struct type *type; + int field_num; + struct ui_file *stream; + struct type *val_type; +{ + int have_output; + int p; + const char* name = TYPE_FIELD_NAME (type, field_num); + + have_output = 0; + + /* Skip over leading 'V': NOTE soon to be obsolete. */ + if (name[0] == 'V') + { + if (! ada_scan_number (name, 1, NULL, &p)) + goto Huh; + } + else + p = 0; + + while (1) + { + switch (name[p]) + { + default: + return; + case 'S': + case 'R': + case 'O': + if (have_output) + fprintf_filtered (stream, " | "); + have_output = 1; + break; + } + + switch (name[p]) + { + case 'S': + { + LONGEST W; + if (! ada_scan_number (name, p + 1, &W, &p)) + goto Huh; + ada_print_scalar (val_type, W, stream); + break; + } + case 'R': + { + LONGEST L, U; + if (! ada_scan_number (name, p + 1, &L, &p) + || name[p] != 'T' + || ! ada_scan_number (name, p + 1, &U, &p)) + goto Huh; + ada_print_scalar (val_type, L, stream); + fprintf_filtered (stream, " .. "); + ada_print_scalar (val_type, U, stream); + break; + } + case 'O': + fprintf_filtered (stream, "others"); + p += 1; + break; + } + } + +Huh: + fprintf_filtered (stream, "??"); + +} + +/* Assuming that field FIELD_NUM of TYPE is a VARIANTS field whose + discriminant is contained in OUTER_TYPE, print its variants on STREAM. + LEVEL is the recursion + (indentation) level, in case any of the fields themselves have + nested structure, and SHOW is the number of levels of internal structure + to show (see ada_print_type). For this purpose, fields nested in a + variant part are taken to be at the same level as the fields + immediately outside the variant part. */ + +static void +print_variant_clauses (type, field_num, outer_type, stream, show, level) + struct type *type; + int field_num; + struct type *outer_type; + struct ui_file *stream; + int show; + int level; +{ + int i; + struct type *var_type; + struct type *discr_type; + + var_type = TYPE_FIELD_TYPE (type, field_num); + discr_type = ada_variant_discrim_type (var_type, outer_type); + + if (TYPE_CODE (var_type) == TYPE_CODE_PTR) + { + var_type = TYPE_TARGET_TYPE (var_type); + if (TYPE_FLAGS (var_type) & TYPE_FLAG_STUB) + { + var_type = ada_find_parallel_type (var_type, "___XVU"); + if (var_type == NULL) + return; + } + } + + for (i = 0; i < TYPE_NFIELDS (var_type); i += 1) + { + fprintf_filtered (stream, "\n%*swhen ", level + 4, ""); + print_choices (var_type, i, stream, discr_type); + fprintf_filtered (stream, " =>"); + if (print_record_field_types (TYPE_FIELD_TYPE (var_type, i), + outer_type, stream, show, level+4) <= 0) + fprintf_filtered (stream, " null;"); + } +} + +/* Assuming that field FIELD_NUM of TYPE is a variant part whose + discriminants are contained in OUTER_TYPE, print a description of it + on STREAM. LEVEL is the recursion (indentation) level, in case any of + the fields themselves have nested structure, and SHOW is the number of + levels of internal structure to show (see ada_print_type). For this + purpose, fields nested in a variant part are taken to be at the same + level as the fields immediately outside the variant part. */ + +static void +print_variant_part (type, field_num, outer_type, stream, show, level) + struct type *type; + int field_num; + struct type *outer_type; + struct ui_file *stream; + int show; + int level; +{ + fprintf_filtered (stream, "\n%*scase %s is", level + 4, "", + ada_variant_discrim_name + (TYPE_FIELD_TYPE (type, field_num))); + print_variant_clauses (type, field_num, outer_type, stream, show, level + 4); + fprintf_filtered (stream, "\n%*send case;", level + 4, ""); +} + +/* Print a description on STREAM of the fields in record type TYPE, whose + discriminants are in OUTER_TYPE. LEVEL is the recursion (indentation) + level, in case any of the fields themselves have nested structure, + and SHOW is the number of levels of internal structure to show + (see ada_print_type). Does not print parent type information of TYPE. + Returns 0 if no fields printed, -1 for an incomplete type, else > 0. + Prints each field beginning on a new line, but does not put a new line at + end. */ + +static int +print_record_field_types (type, outer_type, stream, show, level) + struct type *type; + struct type *outer_type; + struct ui_file *stream; + int show; + int level; +{ + int len, i, flds; + + flds = 0; + len = TYPE_NFIELDS (type); + + if (len == 0 && (TYPE_FLAGS (type) & TYPE_FLAG_STUB) != 0) + return -1; + + for (i = 0; i < len; i += 1) + { + QUIT; + + if (ada_is_parent_field (type, i) + || ada_is_ignored_field (type, i)) + ; + else if (ada_is_wrapper_field (type, i)) + flds += print_record_field_types (TYPE_FIELD_TYPE (type, i), type, + stream, show, level); + else if (ada_is_variant_part (type, i)) + { + print_variant_part (type, i, outer_type, stream, show, level); + flds = 1; + } + else + { + flds += 1; + fprintf_filtered (stream, "\n%*s", level + 4, ""); + ada_print_type (TYPE_FIELD_TYPE (type, i), + TYPE_FIELD_NAME (type, i), + stream, show - 1, level + 4); + fprintf_filtered (stream, ";"); + } + } + + return flds; +} + +/* Print record type TYPE on STREAM. LEVEL is the recursion (indentation) + level, in case the element type itself has nested structure, and SHOW is + the number of levels of internal structure to show (see ada_print_type). */ + +static void +print_record_type (type0, stream, show, level) + struct type* type0; + struct ui_file* stream; + int show; + int level; +{ + struct type* parent_type; + struct type* type; + + type = type0; + if (TYPE_FLAGS (type) & TYPE_FLAG_STUB) + { + struct type* type1 = ada_find_parallel_type (type, "___XVE"); + if (type1 != NULL) + type = type1; + } + + parent_type = ada_parent_type (type); + if (ada_type_name (parent_type) != NULL) + fprintf_filtered (stream, "new %s with ", + demangled_type_name (parent_type)); + else if (parent_type == NULL && ada_is_tagged_type (type)) + fprintf_filtered (stream, "tagged "); + + fprintf_filtered (stream, "record"); + + if (show < 0) + fprintf_filtered (stream, " ... end record"); + else + { + int flds; + + flds = 0; + if (parent_type != NULL && ada_type_name (parent_type) == NULL) + flds += print_record_field_types (parent_type, parent_type, + stream, show, level); + flds += print_record_field_types (type, type, stream, show, level); + + if (flds > 0) + fprintf_filtered (stream, "\n%*send record", level, ""); + else if (flds < 0) + fprintf_filtered (stream, " <incomplete type> end record"); + else + fprintf_filtered (stream, " null; end record"); + } +} + +/* Print the unchecked union type TYPE in something resembling Ada + format on STREAM. LEVEL is the recursion (indentation) level + in case the element type itself has nested structure, and SHOW is the + number of levels of internal structure to show (see ada_print_type). */ +static void +print_unchecked_union_type (struct type* type, struct ui_file* stream, + int show, int level) +{ + fprintf_filtered (stream, "record (?) is"); + + if (show < 0) + fprintf_filtered (stream, " ... end record"); + else if (TYPE_NFIELDS (type) == 0) + fprintf_filtered (stream, " null; end record"); + else + { + int i; + + fprintf_filtered (stream, "\n%*scase ? is", + level+4, ""); + + for (i = 0; i < TYPE_NFIELDS (type); i += 1) + { + fprintf_filtered (stream, "\n%*swhen ? =>\n%*s", level+8, "", + level+12, ""); + ada_print_type (TYPE_FIELD_TYPE (type, i), + TYPE_FIELD_NAME (type, i), + stream, show - 1, level + 12); + fprintf_filtered (stream, ";"); + } + + fprintf_filtered (stream, "\n%*send case;\n%*send record", + level+4, "", level, ""); + } +} + + + +/* Print function or procedure type TYPE on STREAM. Make it a header + for function or procedure NAME if NAME is not null. */ + +static void +print_func_type (type, stream, name) + struct type *type; + struct ui_file *stream; + char* name; +{ + int i, len = TYPE_NFIELDS (type); + + if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID) + fprintf_filtered (stream, "procedure"); + else + fprintf_filtered (stream, "function"); + + if (name != NULL && name[0] != '\0') + fprintf_filtered (stream, " %s", name); + + if (len > 0) + { + fprintf_filtered (stream, " ("); + for (i = 0; i < len; i += 1) + { + if (i > 0) + { + fputs_filtered ("; ", stream); + wrap_here (" "); + } + fprintf_filtered (stream, "a%d: ", i+1); + ada_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0); + } + fprintf_filtered (stream, ")"); + } + + if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID) + { + fprintf_filtered (stream, " return "); + ada_print_type (TYPE_TARGET_TYPE (type), "", stream, 0, 0); + } +} + + +/* Print a description of a type TYPE0. + Output goes to STREAM (via stdio). + If VARSTRING is a non-empty string, print as an Ada variable/field + declaration. + SHOW+1 is the maximum number of levels of internal type structure + to show (this applies to record types, enumerated types, and + array types). + SHOW is the number of levels of internal type structure to show + when there is a type name for the SHOWth deepest level (0th is + outer level). + When SHOW<0, no inner structure is shown. + LEVEL indicates level of recursion (for nested definitions). */ + +void +ada_print_type (type0, varstring, stream, show, level) + struct type* type0; + char* varstring; + struct ui_file* stream; + int show; + int level; +{ + enum type_code code; + int demangled_args; + struct type* type = ada_completed_type (ada_get_base_type (type0)); + char* type_name = demangled_type_name (type); + int is_var_decl = (varstring != NULL && varstring[0] != '\0'); + + if (type == NULL) + { + if (is_var_decl) + fprintf_filtered (stream, "%.*s: ", + ada_name_prefix_len(varstring), + varstring); + fprintf_filtered (stream, "<null type?>"); + return; + } + + if (show > 0) + CHECK_TYPEDEF (type); + + if (is_var_decl && TYPE_CODE (type) != TYPE_CODE_FUNC) + fprintf_filtered (stream, "%.*s: ", + ada_name_prefix_len (varstring), varstring); + + if (type_name != NULL && show <= 0) + { + fprintf_filtered (stream, "%.*s", + ada_name_prefix_len (type_name), type_name); + return; + } + + if (ada_is_aligner_type (type)) + ada_print_type (ada_aligned_type (type), "", stream, show, level); + else if (ada_is_packed_array_type (type)) + print_array_type (type, stream, show, level); + else + switch (TYPE_CODE (type)) + { + default: + fprintf_filtered (stream, "<"); + c_print_type (type, "", stream, show, level); + fprintf_filtered (stream, ">"); + break; + case TYPE_CODE_PTR: + fprintf_filtered (stream, "access "); + ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show, + level); + break; + case TYPE_CODE_REF: + fprintf_filtered (stream, "<ref> "); + ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show, + level); + break; + case TYPE_CODE_ARRAY: + print_array_type (type, stream, show, level); + break; + case TYPE_CODE_INT: + if (ada_is_fixed_point_type (type)) + print_fixed_point_type (type, stream); + else if (ada_is_vax_floating_type (type)) + print_vax_floating_point_type (type, stream); + else + { + char* name = ada_type_name (type); + if (! ada_is_range_type_name (name)) + fprintf_filtered (stream, "<%d-byte integer>", TYPE_LENGTH (type)); + else + { + fprintf_filtered (stream, "range "); + print_range_type_named (name, stream); + } + } + break; + case TYPE_CODE_RANGE: + if (ada_is_fixed_point_type (type)) + print_fixed_point_type (type, stream); + else if (ada_is_vax_floating_type (type)) + print_vax_floating_point_type (type, stream); + else if (ada_is_modular_type (type)) + fprintf_filtered (stream, "mod %ld", (long) ada_modulus (type)); + else + { + fprintf_filtered (stream, "range "); + print_range (type, stream); + } + break; + case TYPE_CODE_FLT: + fprintf_filtered (stream, "<%d-byte float>", TYPE_LENGTH (type)); + break; + case TYPE_CODE_ENUM: + if (show < 0) + fprintf_filtered (stream, "(...)"); + else + print_enum_type (type, stream); + break; + case TYPE_CODE_STRUCT: + if (ada_is_array_descriptor (type)) + print_array_type (type, stream, show, level); + else if (ada_is_bogus_array_descriptor (type)) + fprintf_filtered (stream, "array (?) of ? (<mal-formed descriptor>)"); + else + print_record_type (type, stream, show, level); + break; + case TYPE_CODE_UNION: + print_unchecked_union_type (type, stream, show, level); + break; + case TYPE_CODE_FUNC: + print_func_type (type, stream, varstring); + break; + } +} diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c new file mode 100644 index 0000000..6db18eb --- /dev/null +++ b/gdb/ada-valprint.c @@ -0,0 +1,1058 @@ +/* Support for printing Ada values for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1997, 2001 + 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 2 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, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <ctype.h> +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "value.h" +#include "demangle.h" +#include "valprint.h" +#include "language.h" +#include "annotate.h" +#include "ada-lang.h" +#include "c-lang.h" + +/* Encapsulates arguments to ada_val_print. */ +struct ada_val_print_args { + struct type* type; + char* valaddr0; + int embedded_offset; + CORE_ADDR address; + struct ui_file *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +}; + +extern int inspect_it; +extern unsigned int repeat_count_threshold; + +static void print_record (struct type*, char*, struct ui_file*, int, + int, enum val_prettyprint); + +static int print_field_values (struct type*, char*, struct ui_file*, + int, int, enum val_prettyprint, + int, struct type*, char*); + +static int print_variant_part (struct type*, int, char*, + struct ui_file*, int, int, enum val_prettyprint, + int, struct type*, char*); + +static void +val_print_packed_array_elements (struct type*, char *valaddr, int, + struct ui_file*, int, int, + enum val_prettyprint); + +static void adjust_type_signedness (struct type*); + +static int ada_val_print_stub (PTR args0); + +static int +ada_val_print_1 (struct type*, char*, int, CORE_ADDR, struct ui_file*, + int, int, int, enum val_prettyprint); + + +/* Make TYPE unsigned if its range of values includes no negatives. */ +static void +adjust_type_signedness (type) + struct type* type; +{ + if (type != NULL && TYPE_CODE (type) == TYPE_CODE_RANGE + && TYPE_LOW_BOUND (type) >= 0) + TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED; +} + +/* Assuming TYPE is a simple array type, prints its lower bound on STREAM, + if non-standard (i.e., other than 1 for numbers, other than lower bound + of index type for enumerated type). Returns 1 if something printed, + otherwise 0. */ + +static int +print_optional_low_bound (stream, type) + struct ui_file *stream; + struct type *type; +{ + struct type *index_type; + long low_bound; + + index_type = TYPE_INDEX_TYPE (type); + low_bound = 0; + + if (index_type == NULL) + return 0; + if (TYPE_CODE (index_type) == TYPE_CODE_RANGE) + { + low_bound = TYPE_LOW_BOUND (index_type); + index_type = TYPE_TARGET_TYPE (index_type); + } + else + return 0; + + switch (TYPE_CODE (index_type)) { + case TYPE_CODE_ENUM: + if (low_bound == TYPE_FIELD_BITPOS (index_type, 0)) + return 0; + break; + case TYPE_CODE_UNDEF: + index_type = builtin_type_long; + /* FALL THROUGH */ + default: + if (low_bound == 1) + return 0; + break; + } + + ada_print_scalar (index_type, (LONGEST) low_bound, stream); + fprintf_filtered (stream, " => "); + return 1; +} + +/* Version of val_print_array_elements for GNAT-style packed arrays. + Prints elements of packed array of type TYPE at bit offset + BITOFFSET from VALADDR on STREAM. Formats according to FORMAT and + separates with commas. RECURSE is the recursion (nesting) level. + If PRETTY, uses "prettier" format. TYPE must have been decoded (as + by ada_coerce_to_simple_array). */ + +static void +val_print_packed_array_elements (type, valaddr, bitoffset, stream, format, + recurse, pretty) + struct type *type; + char *valaddr; + int bitoffset; + struct ui_file *stream; + int format; + int recurse; + enum val_prettyprint pretty; +{ + unsigned int i; + unsigned int things_printed = 0; + unsigned len; + struct type *elttype; + unsigned eltlen; + /* Position of the array element we are examining to see + whether it is repeated. */ + unsigned int rep1; + /* Number of repetitions we have detected so far. */ + unsigned int reps; + unsigned long bitsize = TYPE_FIELD_BITSIZE (type, 0); + struct value* mark = value_mark (); + + elttype = TYPE_TARGET_TYPE (type); + eltlen = TYPE_LENGTH (check_typedef (elttype)); + + { + LONGEST low, high; + if (get_discrete_bounds (TYPE_FIELD_TYPE (type, 0), &low, &high) < 0) + len = 1; + else + len = high - low + 1; + } + + i = 0; + annotate_array_section_begin (i, elttype); + + while (i < len && things_printed < print_max) + { + struct value *v0, *v1; + int i0; + + if (i != 0) + { + if (prettyprint_arrays) + { + fprintf_filtered (stream, ",\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + } + else + { + fprintf_filtered (stream, ", "); + } + } + wrap_here (n_spaces (2 + 2 * recurse)); + + i0 = i; + v0 = ada_value_primitive_packed_val (NULL, valaddr, + (i0 * bitsize) / HOST_CHAR_BIT, + (i0 * bitsize) % HOST_CHAR_BIT, + bitsize, elttype); + while (1) + { + i += 1; + if (i >= len) + break; + v1 = ada_value_primitive_packed_val (NULL, valaddr, + (i * bitsize) / HOST_CHAR_BIT, + (i * bitsize) % HOST_CHAR_BIT, + bitsize, elttype); + if (memcmp (VALUE_CONTENTS (v0), VALUE_CONTENTS (v1), eltlen) + != 0) + break; + } + + if (i - i0 > repeat_count_threshold) + { + val_print (elttype, VALUE_CONTENTS (v0), 0, 0, stream, format, + 0, recurse + 1, pretty); + annotate_elt_rep (i - i0); + fprintf_filtered (stream, " <repeats %u times>", i - i0); + annotate_elt_rep_end (); + + } + else + { + int j; + for (j = i0; j < i; j += 1) + { + if (j > i0) + { + if (prettyprint_arrays) + { + fprintf_filtered (stream, ",\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + } + else + { + fprintf_filtered (stream, ", "); + } + wrap_here (n_spaces (2 + 2 * recurse)); + } + val_print (elttype, VALUE_CONTENTS (v0), 0, 0, stream, format, + 0, recurse + 1, pretty); + annotate_elt (); + } + } + things_printed += i - i0; + } + annotate_array_section_end (); + if (i < len) + { + fprintf_filtered (stream, "..."); + } + + value_free_to_mark (mark); +} + +static struct type* +printable_val_type (type, valaddr) + struct type* type; + char* valaddr; +{ + return ada_to_fixed_type (ada_aligned_type (type), valaddr, 0, NULL); +} + +/* Print the character C on STREAM as part of the contents of a literal + string whose delimiter is QUOTER. TYPE_LEN is the length in bytes + (1 or 2) of the character. */ + +void +ada_emit_char (c, stream, quoter, type_len) + int c; + struct ui_file *stream; + int quoter; + int type_len; +{ + if (type_len != 2) + type_len = 1; + + c &= (1 << (type_len * TARGET_CHAR_BIT)) - 1; + + if (isascii (c) && isprint (c)) + { + if (c == quoter && c == '"') + fprintf_filtered (stream, "[\"%c\"]", quoter); + else + fprintf_filtered (stream, "%c", c); + } + else + fprintf_filtered (stream, "[\"%0*x\"]", type_len*2, c); +} + +/* Character #I of STRING, given that TYPE_LEN is the size in bytes (1 + or 2) of a character. */ + +static int +char_at (string, i, type_len) + char* string; + int i; + int type_len; +{ + if (type_len == 1) + return string[i]; + else + return (int) extract_unsigned_integer (string + 2*i, 2); +} + +void +ada_printchar (c, stream) + int c; + struct ui_file *stream; +{ + fputs_filtered ("'", stream); + ada_emit_char (c, stream, '\'', 1); + fputs_filtered ("'", stream); +} + +/* [From print_type_scalar in typeprint.c]. Print VAL on STREAM in a + form appropriate for TYPE. */ + +void +ada_print_scalar (type, val, stream) + struct type *type; + LONGEST val; + struct ui_file *stream; +{ + unsigned int i; + unsigned len; + + CHECK_TYPEDEF (type); + + switch (TYPE_CODE (type)) + { + + case TYPE_CODE_ENUM: + len = TYPE_NFIELDS (type); + for (i = 0; i < len; i++) + { + if (TYPE_FIELD_BITPOS (type, i) == val) + { + break; + } + } + if (i < len) + { + fputs_filtered (ada_enum_name (TYPE_FIELD_NAME (type, i)), stream); + } + else + { + print_longest (stream, 'd', 0, val); + } + break; + + case TYPE_CODE_INT: + print_longest (stream, TYPE_UNSIGNED (type) ? 'u' : 'd', 0, val); + break; + + case TYPE_CODE_CHAR: + LA_PRINT_CHAR ((unsigned char) val, stream); + break; + + case TYPE_CODE_BOOL: + fprintf_filtered (stream, val ? "true" : "false"); + break; + + case TYPE_CODE_RANGE: + ada_print_scalar (TYPE_TARGET_TYPE (type), val, stream); + return; + + case TYPE_CODE_UNDEF: + case TYPE_CODE_PTR: + case TYPE_CODE_ARRAY: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_FUNC: + case TYPE_CODE_FLT: + case TYPE_CODE_VOID: + case TYPE_CODE_SET: + case TYPE_CODE_STRING: + case TYPE_CODE_ERROR: + case TYPE_CODE_MEMBER: + case TYPE_CODE_METHOD: + case TYPE_CODE_REF: + warning ("internal error: unhandled type in ada_print_scalar"); + break; + + default: + error ("Invalid type code in symbol table."); + } + gdb_flush (stream); +} + +/* Print the character string STRING, printing at most LENGTH characters. + Printing stops early if the number hits print_max; repeat counts + are printed as appropriate. Print ellipses at the end if we + had to stop before printing LENGTH characters, or if + FORCE_ELLIPSES. TYPE_LEN is the length (1 or 2) of the character type. + */ + +static void +printstr (stream, string, length, force_ellipses, type_len) + struct ui_file *stream; + char *string; + unsigned int length; + int force_ellipses; + int type_len; +{ + unsigned int i; + unsigned int things_printed = 0; + int in_quotes = 0; + int need_comma = 0; + + if (length == 0) + { + fputs_filtered ("\"\"", stream); + return; + } + + for (i = 0; i < length && things_printed < print_max; i += 1) + { + /* Position of the character we are examining + to see whether it is repeated. */ + unsigned int rep1; + /* Number of repetitions we have detected so far. */ + unsigned int reps; + + QUIT; + + if (need_comma) + { + fputs_filtered (", ", stream); + need_comma = 0; + } + + rep1 = i + 1; + reps = 1; + while (rep1 < length && + char_at(string, rep1, type_len) == char_at (string, i, type_len)) + { + rep1 += 1; + reps += 1; + } + + if (reps > repeat_count_threshold) + { + if (in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\", ", stream); + else + fputs_filtered ("\", ", stream); + in_quotes = 0; + } + fputs_filtered ("'", stream); + ada_emit_char (char_at (string, i, type_len), stream, '\'', type_len); + fputs_filtered ("'", stream); + fprintf_filtered (stream, " <repeats %u times>", reps); + i = rep1 - 1; + things_printed += repeat_count_threshold; + need_comma = 1; + } + else + { + if (!in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\"", stream); + else + fputs_filtered ("\"", stream); + in_quotes = 1; + } + ada_emit_char (char_at (string, i, type_len), stream, '"', + type_len); + things_printed += 1; + } + } + + /* Terminate the quotes if necessary. */ + if (in_quotes) + { + if (inspect_it) + fputs_filtered ("\\\"", stream); + else + fputs_filtered ("\"", stream); + } + + if (force_ellipses || i < length) + fputs_filtered ("...", stream); +} + +void +ada_printstr (stream, string, length, force_ellipses, width) + struct ui_file *stream; + char *string; + unsigned int length; + int force_ellipses; + int width; +{ + printstr (stream, string, length, force_ellipses, width); +} + + +/* Print data of type TYPE located at VALADDR (within GDB), which came from + the inferior at address ADDRESS, onto stdio stream STREAM according to + FORMAT (a letter as for the printf % codes or 0 for natural format). + The data at VALADDR is in target byte order. + + If the data is printed as a string, returns the number of string characters + printed. + + If DEREF_REF is nonzero, then dereference references, otherwise just print + them like pointers. + + RECURSE indicates the amount of indentation to supply before + continuation lines; this amount is roughly twice the value of RECURSE. + + When PRETTY is non-zero, prints record fields on separate lines. + (For some reason, the current version of gdb instead uses a global + variable---prettyprint_arrays--- to causes a similar effect on + arrays.) */ + +int +ada_val_print (type, valaddr0, embedded_offset, address, stream, + format, deref_ref, recurse, pretty) + struct type* type; + char* valaddr0; + int embedded_offset; + CORE_ADDR address; + struct ui_file *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + struct ada_val_print_args args; + args.type = type; args.valaddr0 = valaddr0; + args.embedded_offset = embedded_offset; + args.address = address; + args.stream = stream; + args.format = format; + args.deref_ref = deref_ref; + args.recurse = recurse; + args.pretty = pretty; + + return catch_errors (ada_val_print_stub, &args, NULL, RETURN_MASK_ALL); +} + +/* Helper for ada_val_print; used as argument to catch_errors to + unmarshal the arguments to ada_val_print_1, which does the work. */ +static int +ada_val_print_stub (PTR args0) +{ + struct ada_val_print_args* argsp = (struct ada_val_print_args*) args0; + return ada_val_print_1 (argsp->type, argsp->valaddr0, argsp->embedded_offset, + argsp->address, argsp->stream, argsp->format, + argsp->deref_ref, argsp->recurse, + argsp->pretty); +} + +/* See the comment on ada_val_print. This function differs in that it + * does not catch evaluation errors (leaving that to ada_val_print). */ + +static int +ada_val_print_1 (type, valaddr0, embedded_offset, address, stream, + format, deref_ref, recurse, pretty) + struct type* type; + char* valaddr0; + int embedded_offset; + CORE_ADDR address; + struct ui_file *stream; + int format; + int deref_ref; + int recurse; + enum val_prettyprint pretty; +{ + unsigned int len; + int i; + struct type *elttype; + unsigned int eltlen; + LONGEST val; + CORE_ADDR addr; + char* valaddr = valaddr0 + embedded_offset; + + CHECK_TYPEDEF (type); + + if (ada_is_array_descriptor (type) || ada_is_packed_array_type (type)) + { + int retn; + struct value* mark = value_mark (); + struct value* val; + val = value_from_contents_and_address (type, valaddr, address); + val = ada_coerce_to_simple_array_ptr (val); + if (val == NULL) + { + fprintf_filtered (stream, "(null)"); + retn = 0; + } + else + retn = ada_val_print_1 (VALUE_TYPE (val), VALUE_CONTENTS (val), 0, + VALUE_ADDRESS (val), stream, format, + deref_ref, recurse, pretty); + value_free_to_mark (mark); + return retn; + } + + valaddr = ada_aligned_value_addr (type, valaddr); + embedded_offset -= valaddr - valaddr0 - embedded_offset; + type = printable_val_type (type, valaddr); + + switch (TYPE_CODE (type)) + { + default: + return c_val_print (type, valaddr0, embedded_offset, address, stream, + format, deref_ref, recurse, pretty); + + case TYPE_CODE_INT: + case TYPE_CODE_RANGE: + if (ada_is_fixed_point_type (type)) + { + LONGEST v = unpack_long (type, valaddr); + int len = TYPE_LENGTH (type); + + fprintf_filtered (stream, len < 4 ? "%.11g" : "%.17g", + (double) ada_fixed_to_float (type, v)); + return 0; + } + else if (ada_is_vax_floating_type (type)) + { + struct value* val = + value_from_contents_and_address (type, valaddr, address); + struct value* func = ada_vax_float_print_function (type); + if (func != 0) + { + static struct type* parray_of_char = NULL; + struct value* printable_val; + + if (parray_of_char == NULL) + parray_of_char = + make_pointer_type + (create_array_type + (NULL, builtin_type_char, + create_range_type (NULL, builtin_type_int, 0, 32)), + NULL); + + printable_val = + value_ind (value_cast (parray_of_char, + call_function_by_hand (func, 1, &val))); + + fprintf_filtered (stream, "%s", VALUE_CONTENTS (printable_val)); + return 0; + } + /* No special printing function. Do as best we can. */ + } + else if (TYPE_CODE (type) == TYPE_CODE_RANGE) + { + struct type* target_type = TYPE_TARGET_TYPE (type); + if (TYPE_LENGTH (type) != TYPE_LENGTH (target_type)) + { + /* Obscure case of range type that has different length from + its base type. Perform a conversion, or we will get a + nonsense value. Actually, we could use the same + code regardless of lengths; I'm just avoiding a cast. */ + struct value* v = + value_cast (target_type, + value_from_contents_and_address (type, valaddr, 0)); + return ada_val_print_1 (target_type, VALUE_CONTENTS (v), 0, 0, + stream, format, 0, recurse + 1, pretty); + } + else + return ada_val_print_1 (TYPE_TARGET_TYPE (type), + valaddr0, embedded_offset, + address, stream, format, deref_ref, + recurse, pretty); + } + else + { + format = format ? format : output_format; + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + } + else + { + val_print_type_code_int (type, valaddr, stream); + if (ada_is_character_type (type)) + { + fputs_filtered (" ", stream); + ada_printchar ((unsigned char) unpack_long (type, valaddr), + stream); + } + } + return 0; + } + + case TYPE_CODE_ENUM: + if (format) + { + print_scalar_formatted (valaddr, type, format, 0, stream); + break; + } + len = TYPE_NFIELDS (type); + val = unpack_long (type, valaddr); + for (i = 0; i < len; i++) + { + QUIT; + if (val == TYPE_FIELD_BITPOS (type, i)) + { + break; + } + } + if (i < len) + { + const char* name = ada_enum_name (TYPE_FIELD_NAME (type, i)); + if (name[0] == '\'') + fprintf_filtered (stream, "%ld %s", (long) val, name); + else + fputs_filtered (name, stream); + } + else + { + print_longest (stream, 'd', 0, val); + } + break; + + case TYPE_CODE_UNION: + case TYPE_CODE_STRUCT: + if (ada_is_bogus_array_descriptor (type)) + { + fprintf_filtered (stream, "(...?)"); + return 0; + } + else + { + print_record (type, valaddr, stream, format, + recurse, pretty); + return 0; + } + + case TYPE_CODE_ARRAY: + if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0) + { + elttype = TYPE_TARGET_TYPE (type); + eltlen = TYPE_LENGTH (elttype); + len = TYPE_LENGTH (type) / eltlen; + + /* For an array of chars, print with string syntax. */ + if (ada_is_string_type (type) + && (format == 0 || format == 's')) + { + if (prettyprint_arrays) + { + print_spaces_filtered (2 + 2 * recurse, stream); + } + /* If requested, look for the first null char and only print + elements up to it. */ + if (stop_print_at_null) + { + int temp_len; + + /* Look for a NULL char. */ + for (temp_len = 0; + temp_len < len && temp_len < print_max + && char_at (valaddr, temp_len, eltlen) != 0; + temp_len += 1); + len = temp_len; + } + + printstr (stream, valaddr, len, 0, eltlen); + } + else + { + len = 0; + fprintf_filtered (stream, "("); + print_optional_low_bound (stream, type); + if (TYPE_FIELD_BITSIZE (type, 0) > 0) + val_print_packed_array_elements (type, valaddr, 0, stream, + format, recurse, + pretty); + else + val_print_array_elements (type, valaddr, address, stream, + format, deref_ref, recurse, + pretty, 0); + fprintf_filtered (stream, ")"); + } + gdb_flush (stream); + return len; + } + + case TYPE_CODE_REF: + elttype = check_typedef (TYPE_TARGET_TYPE (type)); + if (addressprint) + { + fprintf_filtered (stream, "@"); + print_address_numeric + (extract_address (valaddr, + TARGET_PTR_BIT / HOST_CHAR_BIT), 1, stream); + if (deref_ref) + fputs_filtered (": ", stream); + } + /* De-reference the reference */ + if (deref_ref) + { + if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF) + { + LONGEST deref_val_int = (LONGEST) + unpack_pointer (lookup_pointer_type (builtin_type_void), + valaddr); + if (deref_val_int != 0) + { + struct value* deref_val = + ada_value_ind (value_from_longest + (lookup_pointer_type (elttype), + deref_val_int)); + val_print (VALUE_TYPE (deref_val), + VALUE_CONTENTS (deref_val), 0, + VALUE_ADDRESS (deref_val), stream, format, + deref_ref, recurse + 1, pretty); + } + else + fputs_filtered ("(null)", stream); + } + else + fputs_filtered ("???", stream); + } + break; + } + return 0; +} + +static int +print_variant_part (type, field_num, valaddr, + stream, format, recurse, pretty, comma_needed, + outer_type, outer_valaddr) + struct type *type; + int field_num; + char *valaddr; + struct ui_file *stream; + int format; + int recurse; + enum val_prettyprint pretty; + int comma_needed; + struct type *outer_type; + char *outer_valaddr; +{ + struct type *var_type = TYPE_FIELD_TYPE (type, field_num); + int which = + ada_which_variant_applies (var_type, outer_type, outer_valaddr); + + if (which < 0) + return 0; + else + return print_field_values + (TYPE_FIELD_TYPE (var_type, which), + valaddr + TYPE_FIELD_BITPOS (type, field_num) / HOST_CHAR_BIT + + TYPE_FIELD_BITPOS (var_type, which) / HOST_CHAR_BIT, + stream, format, recurse, pretty, + comma_needed, outer_type, outer_valaddr); +} + +int +ada_value_print (val0, stream, format, pretty) + struct value* val0; + struct ui_file *stream; + int format; + enum val_prettyprint pretty; +{ + char* valaddr = VALUE_CONTENTS (val0); + CORE_ADDR address = VALUE_ADDRESS (val0) + VALUE_OFFSET (val0); + struct type* type = + ada_to_fixed_type (VALUE_TYPE (val0), valaddr, address, NULL); + struct value* val = value_from_contents_and_address (type, valaddr, address); + + /* If it is a pointer, indicate what it points to. */ + if (TYPE_CODE (type) == TYPE_CODE_PTR || + TYPE_CODE (type) == TYPE_CODE_REF) + { + /* Hack: remove (char *) for char strings. Their + type is indicated by the quoted string anyway. */ + if (TYPE_CODE (type) == TYPE_CODE_PTR && + TYPE_LENGTH (TYPE_TARGET_TYPE (type)) == sizeof(char) && + TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_INT && + !TYPE_UNSIGNED (TYPE_TARGET_TYPE (type))) + { + /* Print nothing */ + } + else + { + fprintf_filtered (stream, "("); + type_print (type, "", stream, -1); + fprintf_filtered (stream, ") "); + } + } + else if (ada_is_array_descriptor (type)) + { + fprintf_filtered (stream, "("); + type_print (type, "", stream, -1); + fprintf_filtered (stream, ") "); + } + else if (ada_is_bogus_array_descriptor (type)) + { + fprintf_filtered (stream, "("); + type_print (type, "", stream, -1); + fprintf_filtered (stream, ") (...?)"); + return 0; + } + return (val_print (type, VALUE_CONTENTS (val), 0, address, + stream, format, 1, 0, pretty)); +} + +static void +print_record (type, valaddr, stream, format, recurse, pretty) + struct type *type; + char *valaddr; + struct ui_file *stream; + int format; + int recurse; + enum val_prettyprint pretty; +{ + CHECK_TYPEDEF (type); + + fprintf_filtered (stream, "("); + + if (print_field_values (type, valaddr, stream, format, recurse, pretty, + 0, type, valaddr) != 0 + && pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 * recurse, stream); + } + + fprintf_filtered (stream, ")"); +} + +/* Print out fields of value at VALADDR having structure type TYPE. + + TYPE, VALADDR, STREAM, FORMAT, RECURSE, and PRETTY have the + same meanings as in ada_print_value and ada_val_print. + + OUTER_TYPE and OUTER_VALADDR give type and address of enclosing record + (used to get discriminant values when printing variant parts). + + COMMA_NEEDED is 1 if fields have been printed at the current recursion + level, so that a comma is needed before any field printed by this + call. + + Returns 1 if COMMA_NEEDED or any fields were printed. */ + +static int +print_field_values (type, valaddr, stream, format, recurse, pretty, + comma_needed, outer_type, outer_valaddr) + struct type *type; + char *valaddr; + struct ui_file *stream; + int format; + int recurse; + enum val_prettyprint pretty; + int comma_needed; + struct type *outer_type; + char *outer_valaddr; +{ + int i, len; + + len = TYPE_NFIELDS (type); + + for (i = 0; i < len; i += 1) + { + if (ada_is_ignored_field (type, i)) + continue; + + if (ada_is_wrapper_field (type, i)) + { + comma_needed = + print_field_values (TYPE_FIELD_TYPE (type, i), + valaddr + + TYPE_FIELD_BITPOS (type, i) / HOST_CHAR_BIT, + stream, format, recurse, pretty, + comma_needed, type, valaddr); + continue; + } + else if (ada_is_variant_part (type, i)) + { + comma_needed = + print_variant_part (type, i, valaddr, + stream, format, recurse, pretty, comma_needed, + outer_type, outer_valaddr); + continue; + } + + if (comma_needed) + fprintf_filtered (stream, ", "); + comma_needed = 1; + + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + } + else + { + wrap_here (n_spaces (2 + 2 * recurse)); + } + if (inspect_it) + { + if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_PTR) + fputs_filtered ("\"( ptr \"", stream); + else + fputs_filtered ("\"( nodef \"", stream); + fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i), + language_cplus, DMGL_NO_OPTS); + fputs_filtered ("\" \"", stream); + fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i), + language_cplus, DMGL_NO_OPTS); + fputs_filtered ("\") \"", stream); + } + else + { + annotate_field_begin (TYPE_FIELD_TYPE (type, i)); + fprintf_filtered (stream, "%.*s", + ada_name_prefix_len (TYPE_FIELD_NAME (type, i)), + TYPE_FIELD_NAME (type, i)); + annotate_field_name_end (); + fputs_filtered (" => ", stream); + annotate_field_value (); + } + + if (TYPE_FIELD_PACKED (type, i)) + { + struct value* v; + + /* Bitfields require special handling, especially due to byte + order problems. */ + if (TYPE_CPLUS_SPECIFIC (type) != NULL + && TYPE_FIELD_IGNORE (type, i)) + { + fputs_filtered ("<optimized out or zero length>", stream); + } + else + { + int bit_pos = TYPE_FIELD_BITPOS (type, i); + int bit_size = TYPE_FIELD_BITSIZE (type, i); + + adjust_type_signedness (TYPE_FIELD_TYPE (type, i)); + v = ada_value_primitive_packed_val (NULL, valaddr, + bit_pos / HOST_CHAR_BIT, + bit_pos % HOST_CHAR_BIT, + bit_size, + TYPE_FIELD_TYPE (type, i)); + val_print (TYPE_FIELD_TYPE(type, i), VALUE_CONTENTS (v), 0, 0, + stream, format, 0, recurse + 1, pretty); + } + } + else + ada_val_print (TYPE_FIELD_TYPE (type, i), + valaddr + TYPE_FIELD_BITPOS (type, i) / HOST_CHAR_BIT, + 0, 0, stream, format, 0, recurse + 1, pretty); + annotate_field_end (); + } + + return comma_needed; +} |