1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189 |
- /* Parse C expressions for GDB.
- Copyright (C) 1986 Free Software Foundation, Inc.
- GDB is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY. No author or distributor accepts responsibility to anyone
- for the consequences of using it or for whether it serves any
- particular purpose or works at all, unless he says so in writing.
- Refer to the GDB General Public License for full details.
- Everyone is granted permission to copy, modify and redistribute GDB,
- but only under the conditions described in the GDB General Public
- License. A copy of this license is supposed to have been given to you
- along with GDB so you can know your rights and responsibilities. It
- should be in a file named COPYING. Among other things, the copyright
- notice and this notice must be preserved on all copies.
- In other words, go ahead and share GDB, but don't try to stop
- anyone else from sharing it farther. Help stamp out software hoarding!
- */
- /* Parse a C 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. */
-
- %{
- #include "defs.h"
- #include "param.h"
- #include "symtab.h"
- #include "frame.h"
- #include "expression.h"
- #include <stdio.h>
- static struct expression *expout;
- static int expout_size;
- static int expout_ptr;
- static int yylex ();
- static yyerror ();
- static void write_exp_elt ();
- static void write_exp_string ();
- static void start_arglist ();
- static int end_arglist ();
- static void free_funcalls ();
- static char *copy_name ();
- /* If this is nonzero, this block is used as the lexical context
- for symbol names. */
- static struct block *expression_context_block;
- /* Number of arguments seen so far in innermost function call. */
- static int arglist_len;
- /* Data structure for saving values of arglist_len
- for function calls whose arguments contain other function calls. */
- struct funcall
- {
- struct funcall *next;
- int arglist_len;
- };
- struct funcall *funcall_chain;
- /* This kind of datum is used to represent the name
- of a symbol token. */
- struct stoken
- {
- char *ptr;
- int length;
- };
- %}
- /* Although the yacc "value" of an expression is not used,
- since the result is stored in the structure being created,
- other node types do have values. */
- %union
- {
- long lval;
- double dval;
- struct symbol *sym;
- struct type *tval;
- struct stoken sval;
- int voidval;
- struct block *bval;
- enum exp_opcode opcode;
- struct internalvar *ivar;
- }
- %type <voidval> exp exp1 start variable
- %type <tval> type typebase
- %type <bval> block
- %token <lval> INT CHAR
- %token <dval> FLOAT
- /* 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> NAME TYPENAME STRING
- %type <sval> name
- %token STRUCT UNION ENUM SIZEOF UNSIGNED COLONCOLON
- %token <lval> LAST REGNAME
- %token <ivar> VARIABLE
- %token <opcode> ASSIGN_MODIFY
- %left ','
- %left ABOVE_COMMA
- %right '=' ASSIGN_MODIFY
- %left OR
- %left AND
- %left '|'
- %left '^'
- %left '&'
- %left EQUAL NOTEQUAL
- %left '<' '>' LEQ GEQ
- %left LSH RSH
- %left '+' '-'
- %left '*' '/' '%'
- %left '@'
- %right UNARY INCREMENT DECREMENT
- %right ARROW '.' '['
- %left COLONCOLON
- %%
- start : exp1
- ;
- /* Expressions, including the comma operator. */
- exp1 : exp
- | exp1 ',' exp
- { write_exp_elt (BINOP_COMMA); }
- ;
- /* Expressions, not including the comma operator. */
- exp : '*' exp %prec UNARY
- { write_exp_elt (UNOP_IND); }
- exp : '&' exp %prec UNARY
- { write_exp_elt (UNOP_ADDR); }
- exp : '-' exp %prec UNARY
- { write_exp_elt (UNOP_NEG); }
- ;
- exp : '!' exp %prec UNARY
- { write_exp_elt (UNOP_ZEROP); }
- ;
- exp : '~' exp %prec UNARY
- { write_exp_elt (UNOP_LOGNOT); }
- ;
- exp : INCREMENT exp %prec UNARY
- { write_exp_elt (UNOP_PREINCREMENT); }
- ;
- exp : DECREMENT exp %prec UNARY
- { write_exp_elt (UNOP_PREDECREMENT); }
- ;
- exp : exp INCREMENT %prec UNARY
- { write_exp_elt (UNOP_POSTINCREMENT); }
- ;
- exp : exp DECREMENT %prec UNARY
- { write_exp_elt (UNOP_POSTDECREMENT); }
- ;
- exp : SIZEOF exp %prec UNARY
- { write_exp_elt (UNOP_SIZEOF); }
- ;
- exp : exp ARROW name
- { write_exp_elt (STRUCTOP_PTR);
- write_exp_string ($3);
- write_exp_elt (STRUCTOP_PTR); }
- ;
- exp : exp '.' name
- { write_exp_elt (STRUCTOP_STRUCT);
- write_exp_string ($3);
- write_exp_elt (STRUCTOP_STRUCT); }
- ;
- exp : exp '[' exp1 ']'
- { write_exp_elt (BINOP_SUBSCRIPT); }
- ;
- exp : exp '('
- /* This is to save the value of arglist_len
- being accumulated by an outer function call. */
- { start_arglist (); }
- arglist ')'
- { write_exp_elt (OP_FUNCALL);
- write_exp_elt (end_arglist ());
- write_exp_elt (OP_FUNCALL); }
- ;
- arglist :
- ;
- arglist : exp
- { arglist_len = 1; }
- ;
- arglist : arglist ',' exp %prec ABOVE_COMMA
- { arglist_len++; }
- ;
- exp : '{' type '}' exp %prec UNARY
- { write_exp_elt (UNOP_MEMVAL);
- write_exp_elt ($2);
- write_exp_elt (UNOP_MEMVAL); }
- ;
- exp : '(' type ')' exp %prec UNARY
- { write_exp_elt (UNOP_CAST);
- write_exp_elt ($2);
- write_exp_elt (UNOP_CAST); }
- ;
- exp : '(' exp1 ')'
- { }
- ;
- /* Binary operators in order of decreasing precedence. */
- exp : exp '@' exp
- { write_exp_elt (BINOP_REPEAT); }
- ;
- exp : exp '*' exp
- { write_exp_elt (BINOP_MUL); }
- ;
- exp : exp '/' exp
- { write_exp_elt (BINOP_DIV); }
- ;
- exp : exp '%' exp
- { write_exp_elt (BINOP_REM); }
- ;
- exp : exp '+' exp
- { write_exp_elt (BINOP_ADD); }
- ;
- exp : exp '-' exp
- { write_exp_elt (BINOP_SUB); }
- ;
- exp : exp LSH exp
- { write_exp_elt (BINOP_LSH); }
- ;
- exp : exp RSH exp
- { write_exp_elt (BINOP_RSH); }
- ;
- exp : exp EQUAL exp
- { write_exp_elt (BINOP_EQUAL); }
- ;
- exp : exp NOTEQUAL exp
- { write_exp_elt (BINOP_NOTEQUAL); }
- ;
- exp : exp LEQ exp
- { write_exp_elt (BINOP_LEQ); }
- ;
- exp : exp GEQ exp
- { write_exp_elt (BINOP_GEQ); }
- ;
- exp : exp '<' exp
- { write_exp_elt (BINOP_LESS); }
- ;
- exp : exp '>' exp
- { write_exp_elt (BINOP_GTR); }
- ;
- exp : exp '&' exp
- { write_exp_elt (BINOP_LOGAND); }
- ;
- exp : exp '^' exp
- { write_exp_elt (BINOP_LOGXOR); }
- ;
- exp : exp '|' exp
- { write_exp_elt (BINOP_LOGIOR); }
- ;
- exp : exp AND exp
- { write_exp_elt (BINOP_AND); }
- ;
- exp : exp OR exp
- { write_exp_elt (BINOP_OR); }
- ;
- exp : exp '?' exp ':' exp
- { write_exp_elt (TERNOP_COND); }
- ;
-
- exp : exp '=' exp
- { write_exp_elt (BINOP_ASSIGN); }
- ;
- exp : exp ASSIGN_MODIFY exp
- { write_exp_elt (BINOP_ASSIGN_MODIFY);
- write_exp_elt ($2);
- write_exp_elt (BINOP_ASSIGN_MODIFY); }
- ;
- exp : INT
- { write_exp_elt (OP_LONG);
- write_exp_elt (builtin_type_long);
- write_exp_elt ($1);
- write_exp_elt (OP_LONG); }
- ;
- exp : CHAR
- { write_exp_elt (OP_LONG);
- write_exp_elt (builtin_type_char);
- write_exp_elt ($1);
- write_exp_elt (OP_LONG); }
- ;
- exp : FLOAT
- { write_exp_elt (OP_DOUBLE);
- write_exp_elt (builtin_type_double);
- write_exp_elt ($1);
- write_exp_elt (OP_DOUBLE); }
- ;
- exp : variable
- ;
- exp : LAST
- { write_exp_elt (OP_LAST);
- write_exp_elt ($1);
- write_exp_elt (OP_LAST); }
- ;
- exp : REGNAME
- { write_exp_elt (OP_REGISTER);
- write_exp_elt ($1);
- write_exp_elt (OP_REGISTER); }
- ;
- exp : VARIABLE
- { write_exp_elt (OP_INTERNALVAR);
- write_exp_elt ($1);
- write_exp_elt (OP_INTERNALVAR); }
- ;
- exp : SIZEOF '(' type ')'
- { write_exp_elt (OP_LONG);
- write_exp_elt (builtin_type_int);
- write_exp_elt ((long) TYPE_LENGTH ($3));
- write_exp_elt (OP_LONG); }
- ;
- exp : STRING
- { write_exp_elt (OP_STRING);
- write_exp_string ($1);
- write_exp_elt (OP_STRING); }
- ;
- block : name
- { struct symtab *tem = lookup_symtab (copy_name ($1));
- struct symbol *sym;
-
- if (tem)
- $$ = BLOCKVECTOR_BLOCK (BLOCKVECTOR (tem), 1);
- else
- {
- sym = lookup_symbol (copy_name ($1),
- expression_context_block,
- VAR_NAMESPACE);
- if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
- $$ = SYMBOL_BLOCK_VALUE (sym);
- else
- error ("No file or function \"%s\".",
- copy_name ($1));
- }}
- ;
- block : block COLONCOLON name
- { struct symbol *tem
- = lookup_symbol ($3, copy_name ($1), VAR_NAMESPACE);
- if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
- error ("No function \"%s\" in specified context.",
- copy_name ($1));
- $$ = SYMBOL_BLOCK_VALUE (tem); }
- ;
- variable: block COLONCOLON name
- { struct symbol *sym;
- sym = lookup_symbol ($3, copy_name ($1), VAR_NAMESPACE);
- if (sym == 0)
- error ("No symbol \"%s\" in specified context.",
- copy_name ($3));
- write_exp_elt (OP_VAR_VALUE);
- write_exp_elt (sym);
- write_exp_elt (OP_VAR_VALUE); }
- ;
- variable: NAME
- { struct symbol *sym;
- sym = lookup_symbol (copy_name ($1),
- expression_context_block,
- VAR_NAMESPACE);
- if (sym)
- {
- write_exp_elt (OP_VAR_VALUE);
- write_exp_elt (sym);
- write_exp_elt (OP_VAR_VALUE);
- }
- else
- {
- register char *arg = copy_name ($1);
- register int i;
- for (i = 0; i < misc_function_count; i++)
- if (!strcmp (misc_function_vector[i].name, arg))
- break;
- if (i < misc_function_count)
- {
- write_exp_elt (OP_LONG);
- write_exp_elt (builtin_type_int);
- write_exp_elt (misc_function_vector[i].address);
- write_exp_elt (OP_LONG);
- write_exp_elt (UNOP_MEMVAL);
- write_exp_elt (builtin_type_char);
- write_exp_elt (UNOP_MEMVAL);
- }
- else
- if (symtab_list == 0)
- error ("No symbol table is loaded. Use the \"symbol-file\" command.");
- else
- error ("No symbol \"%s\" in current context.",
- copy_name ($1));
- }
- }
- ;
- type : typebase
- | type '*'
- { $$ = lookup_pointer_type ($1); }
- ;
- typebase
- : TYPENAME
- { $$ = lookup_typename (copy_name ($1),
- expression_context_block, 0); }
- | STRUCT name
- { $$ = lookup_struct (copy_name ($2),
- expression_context_block); }
- | UNION name
- { $$ = lookup_union (copy_name ($2),
- expression_context_block); }
- | ENUM name
- { $$ = lookup_enum (copy_name ($2),
- expression_context_block); }
- | UNSIGNED name
- { $$ = lookup_unsigned_typename (copy_name ($2)); }
- ;
- name : NAME
- | TYPENAME
- ;
- %%
- /* Begin counting arguments for a function call,
- saving the data about any containing call. */
- static void
- start_arglist ()
- {
- register struct funcall *new = (struct funcall *) xmalloc (sizeof (struct funcall));
- new->next = funcall_chain;
- new->arglist_len = arglist_len;
- arglist_len = 0;
- funcall_chain = new;
- }
- /* Return the number of arguments in a function call just terminated,
- and restore the data for the containing function call. */
- static int
- end_arglist ()
- {
- register int val = arglist_len;
- register struct funcall *call = funcall_chain;
- funcall_chain = call->next;
- arglist_len = call->arglist_len;
- free (call);
- return val;
- }
- /* Free everything in the funcall chain.
- Used when there is an error inside parsing. */
- static void
- free_funcalls ()
- {
- register struct funcall *call, *next;
- for (call = funcall_chain; call; call = next)
- {
- next = call->next;
- free (call);
- }
- }
- /* This page contains the functions for adding data to the struct expression
- being constructed. */
- /* Add one element to the end of the expression. */
- static void
- write_exp_elt (expelt)
- union exp_element expelt;
- {
- if (expout_ptr >= expout_size)
- {
- expout_size *= 2;
- expout = (struct expression *) xrealloc (expout,
- sizeof (struct expression)
- + expout_size * sizeof (union exp_element));
- }
- expout->elts[expout_ptr++] = expelt;
- }
- /* Add a string constant to the end of the expression.
- Follow it by its length in bytes, as a separate exp_element. */
- static void
- write_exp_string (str)
- struct stoken str;
- {
- register int len = str.length;
- register int lenelt
- = (len + sizeof (union exp_element)) / sizeof (union exp_element);
- expout_ptr += lenelt;
- if (expout_ptr >= expout_size)
- {
- expout_size = max (expout_size * 2, expout_ptr + 10);
- expout = (struct expression *) xrealloc (expout,
- sizeof (struct expression)
- + expout_size * sizeof (union exp_element));
- }
- bcopy (str.ptr, (char *) &expout->elts[expout_ptr - lenelt], len);
- ((char *) &expout->elts[expout_ptr - lenelt])[len] = 0;
- write_exp_elt (len);
- }
- /* During parsing of a C expression, the pointer to the next character
- is in this variable. */
- static char *lexptr;
- /* Tokens that refer to names do so with explicit pointer and length,
- so they can share the storage that lexptr is parsing.
- When it is necessary to pass a name to a function that expects
- a null-terminated string, the substring is copied out
- into a block of storage that namecopy points to.
- namecopy is allocated once, guaranteed big enough, for each parsing. */
- static char *namecopy;
- /* Take care of parsing a number (anything that starts with a digit).
- Set yylval and return the token type; update lexptr.
- LEN is the number of characters in it. */
- /*** Needs some error checking for the float case ***/
- static int
- parse_number (olen)
- int olen;
- {
- register char *p = lexptr;
- register long n = 0;
- register int c;
- register int base = 10;
- register len = olen;
- char *err_copy;
- extern double atof ();
- for (c = 0; c < len; c++)
- if (p[c] == '.')
- {
- /* It's a float since it contains a point. */
- yylval.dval = atof (p);
- lexptr += len;
- return FLOAT;
- }
- if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2)))
- {
- p += 2;
- base = 16;
- len -= 2;
- }
- else if (*p == '0')
- base = 8;
- while (len-- > 0)
- {
- c = *p++;
- n *= base;
- if (c >= '0' && c <= '9')
- n += c - '0';
- else
- {
- if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
- if (base == 16 && c >= 'a' && c <= 'f')
- n += c - 'a' + 10;
- else if (len == 0 && c == 'l')
- ;
- else
- {
- err_copy = (char *) alloca (olen + 1);
- bcopy (lexptr, err_copy, olen);
- err_copy[olen] = 0;
- error ("Invalid number \"%s\".", err_copy);
- }
- }
- }
- lexptr = p;
- yylval.lval = n;
- return INT;
- }
- struct token
- {
- char *operator;
- int token;
- enum exp_opcode opcode;
- };
- static struct token tokentab3[] =
- {
- {">>=", ASSIGN_MODIFY, BINOP_RSH},
- {"<<=", ASSIGN_MODIFY, BINOP_LSH}
- };
- static struct token tokentab2[] =
- {
- {"+=", ASSIGN_MODIFY, BINOP_ADD},
- {"-=", ASSIGN_MODIFY, BINOP_SUB},
- {"*=", ASSIGN_MODIFY, BINOP_MUL},
- {"/=", ASSIGN_MODIFY, BINOP_DIV},
- {"%=", ASSIGN_MODIFY, BINOP_REM},
- {"|=", ASSIGN_MODIFY, BINOP_LOGIOR},
- {"&=", ASSIGN_MODIFY, BINOP_LOGAND},
- {"^=", ASSIGN_MODIFY, BINOP_LOGXOR},
- {"++", INCREMENT, BINOP_END},
- {"--", DECREMENT, BINOP_END},
- {"->", ARROW, BINOP_END},
- {"&&", AND, BINOP_END},
- {"||", OR, BINOP_END},
- {"::", COLONCOLON, BINOP_END},
- {"<<", LSH, BINOP_END},
- {">>", RSH, BINOP_END},
- {"==", EQUAL, BINOP_END},
- {"!=", NOTEQUAL, BINOP_END},
- {"<=", LEQ, BINOP_END},
- {">=", GEQ, BINOP_END}
- };
- /* Read one token, getting characters through lexptr. */
- static int
- yylex ()
- {
- register int c;
- register int namelen;
- register int i;
- register char *tokstart;
- retry:
- tokstart = lexptr;
- /* See if it is a special token of length 3. */
- for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
- if (!strncmp (tokstart, tokentab3[i].operator, 3))
- {
- lexptr += 3;
- yylval.opcode = tokentab3[i].opcode;
- return tokentab3[i].token;
- }
- /* See if it is a special token of length 2. */
- for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++)
- if (!strncmp (tokstart, tokentab2[i].operator, 2))
- {
- lexptr += 2;
- yylval.opcode = tokentab2[i].opcode;
- return tokentab2[i].token;
- }
- switch (c = *tokstart)
- {
- case 0:
- return 0;
- case ' ':
- case '\t':
- case '\n':
- lexptr++;
- goto retry;
- case '\'':
- lexptr++;
- c = *lexptr++;
- if (c == '\\')
- c = parse_escape (&lexptr);
- yylval.lval = c;
- c = *lexptr++;
- if (c != '\'')
- error ("Invalid character constant.");
- return CHAR;
- case '+':
- case '-':
- case '*':
- case '/':
- case '%':
- case '|':
- case '&':
- case '^':
- case '~':
- case '!':
- case '@':
- case '<':
- case '>':
- case '(':
- case ')':
- case '[':
- case ']':
- case '.':
- case '?':
- case ':':
- case '=':
- case '{':
- case '}':
- case ',':
- lexptr++;
- return c;
- case '"':
- for (namelen = 1; (c = tokstart[namelen]) != '"'; namelen++)
- if (c == '\\')
- {
- c = tokstart[++namelen];
- if (c >= '0' && c <= '9')
- {
- c = tokstart[++namelen];
- if (c >= '0' && c <= '9')
- c = tokstart[++namelen];
- }
- }
- yylval.sval.ptr = tokstart + 1;
- yylval.sval.length = namelen - 1;
- lexptr += namelen + 1;
- return STRING;
- }
- if (c >= '0' && c <= '9')
- {
- /* It's a number */
- for (namelen = 0;
- c = tokstart[namelen],
- (c == '_' || c == '$' || c == '.' || (c >= '0' && c <= '9')
- || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
- namelen++)
- ;
- return parse_number (namelen);
- }
- if (!(c == '_' || c == '$'
- || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
- error ("Invalid token in expression.");
- /* It is a name. See how long it is. */
- for (namelen = 0;
- c = tokstart[namelen],
- (c == '_' || c == '$' || (c >= '0' && c <= '9')
- || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
- namelen++)
- ;
- /* The token "if" terminates the expression and is NOT
- removed from the input stream. */
- if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
- {
- return 0;
- }
- lexptr += namelen;
- /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1)
- and $$digits (equivalent to $<-digits> if you could type that).
- Make token type LAST, and put the number (the digits) in yylval. */
- if (*tokstart == '$')
- {
- register int negate = 0;
- c = 1;
- /* Double dollar means negate the number and add -1 as well.
- Thus $$ alone means -1. */
- if (namelen >= 2 && tokstart[1] == '$')
- {
- negate = 1;
- c = 2;
- }
- if (c == namelen)
- {
- /* Just dollars (one or two) */
- yylval.lval = - negate;
- return LAST;
- }
- /* Is the rest of the token digits? */
- for (; c < namelen; c++)
- if (!(tokstart[c] >= '0' && tokstart[c] <= '9'))
- break;
- if (c == namelen)
- {
- yylval.lval = atoi (tokstart + 1 + negate);
- if (negate)
- yylval.lval = - yylval.lval;
- return LAST;
- }
- }
- /* Handle tokens that refer to machine registers:
- $ followed by a register name. */
- if (*tokstart == '$')
- for (c = 0; c < NUM_REGS; c++)
- if (namelen - 1 == strlen (reg_names[c])
- && !strncmp (tokstart + 1, reg_names[c], namelen - 1))
- {
- yylval.lval = c;
- return REGNAME;
- }
- if (namelen == 6 && !strncmp (tokstart, "struct", 6))
- {
- return STRUCT;
- }
- if (namelen == 5 && !strncmp (tokstart, "union", 5))
- {
- return UNION;
- }
- if (namelen == 4 && !strncmp (tokstart, "enum", 4))
- {
- return ENUM;
- }
- if (namelen == 6 && !strncmp (tokstart, "sizeof", 6))
- {
- return SIZEOF;
- }
- if (namelen == 8 && !strncmp (tokstart, "unsigned", 6))
- {
- return UNSIGNED;
- }
- yylval.sval.ptr = tokstart;
- yylval.sval.length = namelen;
- /* Any other names starting in $ are debugger internal variables. */
- if (*tokstart == '$')
- {
- yylval.ivar = (struct internalvar *) lookup_internalvar (copy_name (yylval.sval) + 1);
- return VARIABLE;
- }
- /* Use token-type TYPENAME for symbols that happen to be defined
- currently as names of types; NAME for other symbols.
- The caller is not constrained to care about the distinction. */
- if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1))
- return TYPENAME;
- return NAME;
- }
- static
- yyerror ()
- {
- error ("Invalid syntax in expression.");
- }
- /* Return a null-terminated temporary copy of the name
- of a string token. */
- static char *
- copy_name (token)
- struct stoken token;
- {
- bcopy (token.ptr, namecopy, token.length);
- namecopy[token.length] = 0;
- return namecopy;
- }
- /* Reverse an expression from suffix form (in which it is constructed)
- to prefix form (in which we can conveniently print or execute it). */
- static void prefixify_subexp ();
- static void
- prefixify_expression (expr)
- register struct expression *expr;
- {
- register int len = sizeof (struct expression) +
- expr->nelts * sizeof (union exp_element);
- register struct expression *temp
- = (struct expression *) alloca (len);
- register int inpos = expr->nelts, outpos = 0;
- /* Copy the original expression into temp. */
- bcopy (expr, temp, len);
- prefixify_subexp (temp, expr, inpos, outpos);
- }
- /* Return the number of exp_elements in the subexpression of EXPR
- whose last exp_element is at index ENDPOS - 1 in EXPR. */
- static int
- length_of_subexp (expr, endpos)
- register struct expression *expr;
- register int endpos;
- {
- register int oplen = 1;
- register int args = 0;
- register int i;
- i = (int) expr->elts[endpos - 1].opcode;
- switch (i)
- {
- case OP_LONG:
- case OP_DOUBLE:
- oplen = 4;
- break;
- case OP_VAR_VALUE:
- case OP_LAST:
- case OP_REGISTER:
- case OP_INTERNALVAR:
- oplen = 3;
- break;
- case OP_FUNCALL:
- oplen = 3;
- args = 1 + expr->elts[endpos - 2].longconst;
- break;
- case UNOP_CAST:
- case UNOP_MEMVAL:
- oplen = 3;
- args = 1;
- break;
- case STRUCTOP_STRUCT:
- case STRUCTOP_PTR:
- args = 1;
- case OP_STRING:
- oplen = 3 + ((expr->elts[endpos - 2].longconst
- + sizeof (union exp_element))
- / sizeof (union exp_element));
-
- break;
- case TERNOP_COND:
- args = 3;
- break;
- case BINOP_ASSIGN_MODIFY:
- oplen = 3;
- args = 2;
- break;
- default:
- args = 1 + (i < (int) BINOP_END);
- }
- while (args > 0)
- {
- oplen += length_of_subexp (expr, endpos - oplen);
- args--;
- }
- return oplen;
- }
- /* Copy the subexpression ending just before index INEND in INEXPR
- into OUTEXPR, starting at index OUTBEG.
- In the process, convert it from suffix to prefix form. */
- static void
- prefixify_subexp (inexpr, outexpr, inend, outbeg)
- register struct expression *inexpr;
- struct expression *outexpr;
- register int inend;
- int outbeg;
- {
- register int oplen = 1;
- register int args = 0;
- register int i;
- int *arglens;
- enum exp_opcode opcode;
- /* Compute how long the last operation is (in OPLEN),
- and also how many preceding subexpressions serve as
- arguments for it (in ARGS). */
- opcode = inexpr->elts[inend - 1].opcode;
- switch (opcode)
- {
- case OP_LONG:
- case OP_DOUBLE:
- oplen = 4;
- break;
- case OP_VAR_VALUE:
- case OP_LAST:
- case OP_REGISTER:
- case OP_INTERNALVAR:
- oplen = 3;
- break;
- case OP_FUNCALL:
- oplen = 3;
- args = 1 + inexpr->elts[inend - 2].longconst;
- break;
- case UNOP_CAST:
- case UNOP_MEMVAL:
- oplen = 3;
- args = 1;
- break;
- case STRUCTOP_STRUCT:
- case STRUCTOP_PTR:
- args = 1;
- case OP_STRING:
- oplen = 3 + ((inexpr->elts[inend - 2].longconst
- + sizeof (union exp_element))
- / sizeof (union exp_element));
-
- break;
- case TERNOP_COND:
- args = 3;
- break;
- case BINOP_ASSIGN_MODIFY:
- oplen = 3;
- args = 2;
- break;
- default:
- args = 1 + ((int) opcode < (int) BINOP_END);
- }
- /* Copy the final operator itself, from the end of the input
- to the beginning of the output. */
- inend -= oplen;
- bcopy (&inexpr->elts[inend], &outexpr->elts[outbeg],
- oplen * sizeof (union exp_element));
- outbeg += oplen;
- /* Find the lengths of the arg subexpressions. */
- arglens = (int *) alloca (args * sizeof (int));
- for (i = args - 1; i >= 0; i--)
- {
- oplen = length_of_subexp (inexpr, inend);
- arglens[i] = oplen;
- inend -= oplen;
- }
- /* Now copy each subexpression, preserving the order of
- the subexpressions, but prefixifying each one.
- In this loop, inend starts at the beginning of
- the expression this level is working on
- and marches forward over the arguments.
- outbeg does similarly in the output. */
- for (i = 0; i < args; i++)
- {
- oplen = arglens[i];
- inend += oplen;
- prefixify_subexp (inexpr, outexpr, inend, outbeg);
- outbeg += oplen;
- }
- }
- /* This page contains the two entry points to this file. */
- /* Read a C expression from the string *STRINGPTR points to,
- parse it, and return a pointer to a struct expression that we malloc.
- Use block BLOCK as the lexical context for variable names;
- if BLOCK is zero, use the block of the selected stack frame.
- Meanwhile, advance *STRINGPTR to point after the expression,
- at the first nonwhite character that is not part of the expression
- (possibly a null character). */
- struct expression *
- parse_c_1 (stringptr, block)
- char **stringptr;
- struct block *block;
- {
- struct cleanup *old_chain;
- lexptr = *stringptr;
- if (lexptr == 0 || *lexptr == 0)
- error_no_arg ("expression to compute");
- old_chain = make_cleanup (free_funcalls, 0);
- funcall_chain = 0;
- expression_context_block = block ? block : get_selected_block ();
- namecopy = (char *) alloca (strlen (lexptr) + 1);
- expout_size = 10;
- expout_ptr = 0;
- expout = (struct expression *) xmalloc (sizeof (struct expression)
- + expout_size * sizeof (union exp_element));
- make_cleanup (free_current_contents, &expout);
- if (yyparse ())
- yyerror ();
- discard_cleanups (old_chain);
- expout->nelts = expout_ptr;
- expout = (struct expression *)
- xrealloc (expout,
- sizeof (struct expression)
- + expout_ptr * sizeof (union exp_element));
- prefixify_expression (expout);
- *stringptr = lexptr;
- return expout;
- }
- /* Parse STRING as an expression, and complain if this fails
- to use up all of the contents of STRING. */
- struct expression *
- parse_c_expression (string)
- char *string;
- {
- register struct expression *exp;
- exp = parse_c_1 (&string, 0);
- if (*string)
- error ("Junk after end of expression.");
- return exp;
- }
|