along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-/* Parse a C expression from text in a string,
+/* Parse a Java 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.
+ come first in the result. Well, almost always; see ArrayAccess.
Note that malloc's and realloc's in this file are transformed to
xmalloc and xrealloc respectively by the same sed command in the
yyerror PARAMS ((char *));
static struct type * java_type_from_name PARAMS ((struct stoken));
-static void push_variable PARAMS ((struct stoken));
+static void push_expression_name PARAMS ((struct stoken));
+static void push_fieldnames PARAMS ((struct stoken));
+
+static struct expression *copy_exp PARAMS ((struct expression *, int));
+static void insert_exp PARAMS ((int, struct expression *));
%}
%type <lval> rcurly Dims Dims_opt
%type <tval> ClassOrInterfaceType ClassType /* ReferenceType Type ArrayType */
-%type <tval> IntegralType FloatingPointType NumericType PrimitiveType
+%type <tval> IntegralType FloatingPointType NumericType PrimitiveType ArrayType PrimitiveOrArrayType
%token <typed_val_int> INTEGER_LITERAL
%token <typed_val_float> FLOATING_POINT_LITERAL
%%
start : exp1
-/* | type_exp FIXME */
+ | type_exp
+ ;
+
+type_exp: PrimitiveOrArrayType
+ {
+ write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type($1);
+ write_exp_elt_opcode(OP_TYPE);
+ }
+ ;
+
+PrimitiveOrArrayType:
+ PrimitiveType
+ | ArrayType
;
StringLiteral:
}
;
-Literal :
+Literal:
INTEGER_LITERAL
{ write_exp_elt_opcode (OP_LONG);
write_exp_elt_type ($1.type);
ClassOrInterfaceType
;
-/* UNUSED:
ArrayType:
PrimitiveType Dims
{ $$ = java_array_type ($1, $2); }
| Name Dims
{ $$ = java_array_type (java_type_from_name ($1), $2); }
;
-*/
Name:
IDENTIFIER
FieldAccess:
Primary '.' SimpleName
- { write_exp_elt_opcode (STRUCTOP_STRUCT);
- write_exp_string ($3);
- write_exp_elt_opcode (STRUCTOP_STRUCT); }
+ { push_fieldnames ($3); }
+| VARIABLE '.' SimpleName
+ { push_fieldnames ($3); }
/*| SUPER '.' SimpleName { FIXME } */
;
ArrayAccess:
Name '[' Expression ']'
- { error ("ArrayAccess"); } /* FIXME - NASTY */
+ {
+ /* Emit code for the Name now, then exchange it in the
+ expout array with the Expression's code. We could
+ introduce a OP_SWAP code or a reversed version of
+ BINOP_SUBSCRIPT, but that makes the rest of GDB pay
+ for our parsing kludges. */
+ struct expression *name_expr;
+
+ push_expression_name ($1);
+ name_expr = copy_exp (expout, expout_ptr);
+ expout_ptr -= name_expr->nelts;
+ insert_exp (expout_ptr-length_of_subexp (expout, expout_ptr),
+ name_expr);
+ free (name_expr);
+ write_exp_elt_opcode (BINOP_SUBSCRIPT);
+ }
+| VARIABLE '[' Expression ']'
+ { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
| PrimaryNoNewArray '[' Expression ']'
{ write_exp_elt_opcode (BINOP_SUBSCRIPT); }
;
PostfixExpression:
Primary
| Name
- { push_variable ($1); }
+ { push_expression_name ($1); }
| VARIABLE
/* Already written by write_dollar_variable. */
| PostIncrementExpression
{ write_exp_elt_opcode (UNOP_CAST);
write_exp_elt_type (java_array_type ($2, $3));
write_exp_elt_opcode (UNOP_CAST); }
-| '(' Expression ')' UnaryExpressionNotPlusMinus /* FIXME */
+| '(' Expression ')' UnaryExpressionNotPlusMinus
+ {
+ int exp_size = expout_ptr;
+ int last_exp_size = length_of_subexp(expout, expout_ptr);
+ struct type *type;
+ int i;
+ int base = expout_ptr - last_exp_size - 3;
+ if (base < 0 || expout->elts[base+2].opcode != OP_TYPE)
+ error ("invalid cast expression");
+ type = expout->elts[base+1].type;
+ /* Remove the 'Expression' and slide the
+ UnaryExpressionNotPlusMinus down to replace it. */
+ for (i = 0; i < last_exp_size; i++)
+ expout->elts[base + i] = expout->elts[base + i + 3];
+ expout_ptr -= 3;
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ type = lookup_pointer_type (type);
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (type);
+ write_exp_elt_opcode (UNOP_CAST);
+ }
| '(' Name Dims ')' UnaryExpressionNotPlusMinus
{ write_exp_elt_opcode (UNOP_CAST);
write_exp_elt_type (java_array_type (java_type_from_name ($2), $3));
LeftHandSide:
ForcedName
- { push_variable ($1); }
+ { push_expression_name ($1); }
| VARIABLE
/* Already written by write_dollar_variable. */
| FieldAccess
num = sscanf (p, "%lg%c", (double *) &putithere->typed_val_float.dval, &c);
else
{
-#ifdef PRINTF_HAS_LONG_DOUBLE
+#ifdef SCANF_HAS_LONG_DOUBLE
num = sscanf (p, "%Lg%c", &putithere->typed_val_float.dval, &c);
#else
/* Scan it into a double, then assign it to the long double.
return ERROR;
return FLOATING_POINT_LITERAL;
-}
+ }
/* Handle base-switching prefixes 0x, 0t, 0d, 0 */
if (p[0] == '0')
c = *p++;
if (c >= '0' && c <= '9')
c -= '0';
+ else if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 10;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 10;
else
- {
- if (c >= 'A' && c <= 'Z')
- c += 'a' - 'A';
- if (c >= 'a' && c - 'a' + 10 < base)
- c -= 'a' + 10;
- else
- return ERROR; /* Char not a digit */
- }
+ return ERROR; /* Char not a digit */
if (c >= base)
return ERROR;
if (n > limit_div_base
(c == '_' || c == '$' || (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '<');)
{
- if (c == '<')
- {
- int i = namelen;
- while (tokstart[++i] && tokstart[i] != '>');
- if (tokstart[i] == '>')
- namelen = i;
- }
+ if (c == '<')
+ {
+ int i = namelen;
+ while (tokstart[++i] && tokstart[i] != '>');
+ if (tokstart[i] == '>')
+ namelen = i;
+ }
c = tokstart[++namelen];
}
return typ;
}
-static void
+/* If NAME is a valid variable name in this scope, push it and return 1.
+ Otherwise, return 0. */
+
+static int
push_variable (name)
struct stoken name;
char *tmp = copy_name (name);
int is_a_field_of_this = 0;
struct symbol *sym;
- struct type *typ;
sym = lookup_symbol (tmp, expression_context_block, VAR_NAMESPACE,
&is_a_field_of_this, (struct symtab **) NULL);
- if (sym)
+ if (sym && SYMBOL_CLASS (sym) != LOC_TYPEDEF)
{
if (symbol_read_needs_frame (sym))
{
write_exp_elt_block (NULL);
write_exp_elt_sym (sym);
write_exp_elt_opcode (OP_VAR_VALUE);
- return;
+ return 1;
}
if (is_a_field_of_this)
{
write_exp_elt_opcode (STRUCTOP_PTR);
write_exp_string (name);
write_exp_elt_opcode (STRUCTOP_PTR);
+ return 1;
+ }
+ return 0;
+}
+
+/* Assuming a reference expression has been pushed, emit the
+ STRUCTOP_STRUCT ops to access the field named NAME. If NAME is a
+ qualified name (has '.'), generate a field access for each part. */
+
+static void
+push_fieldnames (name)
+ struct stoken name;
+{
+ int i;
+ struct stoken token;
+ token.ptr = name.ptr;
+ for (i = 0; ; i++)
+ {
+ if (i == name.length || name.ptr[i] == '.')
+ {
+ /* token.ptr is start of current field name. */
+ token.length = &name.ptr[i] - token.ptr;
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string (token);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ token.ptr += token.length + 1;
+ }
+ if (i >= name.length)
+ break;
+ }
+}
+
+/* Helper routine for push_expression_name.
+ Handle a qualified name, where DOT_INDEX is the index of the first '.' */
+
+static void
+push_qualified_expression_name (name, dot_index)
+ struct stoken name;
+ int dot_index;
+{
+ struct stoken token;
+ char *tmp;
+ struct type *typ;
+
+ token.ptr = name.ptr;
+ token.length = dot_index;
+
+ if (push_variable (token))
+ {
+ token.ptr = name.ptr + dot_index + 1;
+ token.length = name.length - dot_index - 1;
+ push_fieldnames (token);
return;
}
+ token.ptr = name.ptr;
+ for (;;)
+ {
+ token.length = dot_index;
+ tmp = copy_name (token);
+ typ = java_lookup_class (tmp);
+ if (typ != NULL)
+ {
+ if (dot_index == name.length)
+ {
+ write_exp_elt_opcode(OP_TYPE);
+ write_exp_elt_type(typ);
+ write_exp_elt_opcode(OP_TYPE);
+ return;
+ }
+ dot_index++; /* Skip '.' */
+ name.ptr += dot_index;
+ name.length -= dot_index;
+ dot_index = 0;
+ while (dot_index < name.length && name.ptr[dot_index] != '.')
+ dot_index++;
+ token.ptr = name.ptr;
+ token.length = dot_index;
+ write_exp_elt_opcode (OP_SCOPE);
+ write_exp_elt_type (typ);
+ write_exp_string (token);
+ write_exp_elt_opcode (OP_SCOPE);
+ if (dot_index < name.length)
+ {
+ dot_index++;
+ name.ptr += dot_index;
+ name.length -= dot_index;
+ push_fieldnames (name);
+ }
+ return;
+ }
+ else if (dot_index >= name.length)
+ break;
+ dot_index++; /* Skip '.' */
+ while (dot_index < name.length && name.ptr[dot_index] != '.')
+ dot_index++;
+ }
+ error ("unknown type `%.*s'", name.length, name.ptr);
+}
+
+/* Handle Name in an expression (or LHS).
+ Handle VAR, TYPE, TYPE.FIELD1....FIELDN and VAR.FIELD1....FIELDN. */
+
+static void
+push_expression_name (name)
+ struct stoken name;
+{
+ char *tmp;
+ struct type *typ;
+ char *ptr;
+ int i;
+
+ for (i = 0; i < name.length; i++)
+ {
+ if (name.ptr[i] == '.')
+ {
+ /* It's a Qualified Expression Name. */
+ push_qualified_expression_name (name, i);
+ return;
+ }
+ }
+
+ /* It's a Simple Expression Name. */
+
+ if (push_variable (name))
+ return;
+ tmp = copy_name (name);
typ = java_lookup_class (tmp);
if (typ != NULL)
{
}
}
+
+
+/* The following two routines, copy_exp and insert_exp, aren't specific to
+ Java, so they could go in parse.c, but their only purpose is to support
+ the parsing kludges we use in this file, so maybe it's best to isolate
+ them here. */
+
+/* Copy the expression whose last element is at index ENDPOS - 1 in EXPR
+ into a freshly malloc'ed struct expression. Its language_defn is set
+ to null. */
+static struct expression *
+copy_exp (expr, endpos)
+ struct expression *expr;
+ int endpos;
+{
+ int len = length_of_subexp (expr, endpos);
+ struct expression *new
+ = (struct expression *) malloc (sizeof (*new) + EXP_ELEM_TO_BYTES (len));
+ new->nelts = len;
+ memcpy (new->elts, expr->elts + endpos - len, EXP_ELEM_TO_BYTES (len));
+ new->language_defn = 0;
+
+ return new;
+}
+
+/* Insert the expression NEW into the current expression (expout) at POS. */
+static void
+insert_exp (pos, new)
+ int pos;
+ struct expression *new;
+{
+ int newlen = new->nelts;
+
+ /* Grow expout if necessary. In this function's only use at present,
+ this should never be necessary. */
+ if (expout_ptr + newlen > expout_size)
+ {
+ expout_size = max (expout_size * 2, expout_ptr + newlen + 10);
+ expout = (struct expression *)
+ realloc ((char *) expout, (sizeof (struct expression)
+ + EXP_ELEM_TO_BYTES (expout_size)));
+ }
+
+ {
+ int i;
+
+ for (i = expout_ptr - 1; i >= pos; i--)
+ expout->elts[i + newlen] = expout->elts[i];
+ }
+
+ memcpy (expout->elts + pos, new->elts, EXP_ELEM_TO_BYTES (newlen));
+ expout_ptr += newlen;
+}