8sa1-gcc/gcc/fortran/matchexp.c
Jerry DeLisle b7e757713c [multiple changes]
2010-04-12  Jerry DeLisle  <jvdelisle@gcc.gnu.org>

	* array.c (extract_element): Restore function from trunk.
	(gfc_get_array_element): Restore function from trunk.
	(gfc_expand_constructor): Restore check against
	flag_max_array_constructor.
	* constructor.c (node_copy_and_append): Delete unused.
	* gfortran.h: Delete comment and extra include.
	* constructor.h: Bump copyright and clean up TODO comments.
	* resolve.c: Whitespace.

2010-04-12  Daniel Franke  <franke.daniel@gmail.com>

	* simplify.c (compute_dot_product): Replaced usage of ADVANCE macro
	with direct access access to elements. Adjusted prototype, fixed all
	callers.
	(gfc_simplify_dot_product): Removed duplicate check for zero-sized
	array.
	(gfc_simplify_matmul): Removed usage of ADVANCE macro.
	(gfc_simplify_spread): Removed workaround, directly insert elements
	at a given array position.
	(gfc_simplify_transpose): Likewise.
	(gfc_simplify_pack): Replaced usage of ADVANCE macro with corresponding
	function calls.
	(gfc_simplify_unpack): Likewise.

2010-04-12  Daniel Franke  <franke.daniel@gmail.com>

	* simplify.c (only_convert_cmplx_boz): Renamed to ...
	(convert_boz): ... this and moved to start of file.
	(gfc_simplify_abs): Whitespace fix.
	(gfc_simplify_acos): Whitespace fix.
	(gfc_simplify_acosh): Whitespace fix.
	(gfc_simplify_aint): Whitespace fix.
	(gfc_simplify_dint): Whitespace fix.
	(gfc_simplify_anint): Whitespace fix.
	(gfc_simplify_and): Replaced if-gate by more common switch-over-type.
	(gfc_simplify_dnint): Whitespace fix.
	(gfc_simplify_asin): Whitespace fix.
	(gfc_simplify_asinh): Moved creation of result-expr out of switch.
	(gfc_simplify_atan): Likewise.
	(gfc_simplify_atanh): Whitespace fix.
	(gfc_simplify_atan2): Whitespace fix.
	(gfc_simplify_bessel_j0): Removed ATTRIBUTE_UNUSED.
	(gfc_simplify_bessel_j1): Likewise.
	(gfc_simplify_bessel_jn): Likewise.
	(gfc_simplify_bessel_y0): Likewise.
	(gfc_simplify_bessel_y1): Likewise.
	(gfc_simplify_bessel_yn): Likewise.
	(gfc_simplify_ceiling): Reorderd statements.
	(simplify_cmplx): Use convert_boz(), check for constant arguments.
	Whitespace fix.
	(gfc_simplify_cmplx): Use correct default kind. Removed check for
	constant arguments.
	(gfc_simplify_complex): Replaced if-gate. Removed check for
	constant arguments.
	(gfc_simplify_conjg): Whitespace fix.
	(gfc_simplify_cos): Whitespace fix.
	(gfc_simplify_cosh): Replaced if-gate by more common switch-over-type.
	(gfc_simplify_dcmplx): Removed check for constant arguments.
	(gfc_simplify_dble): Use convert_boz() and gfc_convert_constant().
	(gfc_simplify_digits): Whitespace fix.
	(gfc_simplify_dim): Whitespace fix.
	(gfc_simplify_dprod): Reordered statements.
	(gfc_simplify_erf): Whitespace fix.
	(gfc_simplify_erfc): Whitespace fix.
	(gfc_simplify_epsilon): Whitespace fix.
	(gfc_simplify_exp): Whitespace fix.
	(gfc_simplify_exponent): Use convert_boz().
	(gfc_simplify_floor): Reorderd statements.
	(gfc_simplify_gamma): Whitespace fix.
	(gfc_simplify_huge): Whitespace fix.
	(gfc_simplify_iand): Whitespace fix.
	(gfc_simplify_ieor): Whitespace fix.
	(simplify_intconv): Use gfc_convert_constant().
	(gfc_simplify_int): Use simplify_intconv().
	(gfc_simplify_int2): Reorderd statements.
	(gfc_simplify_idint): Reorderd statements.
	(gfc_simplify_ior): Whitespace fix.
	(gfc_simplify_ishftc): Removed duplicate type check.
	(gfc_simplify_len): Use range_check() instead of manual range check.
	(gfc_simplify_lgamma): Removed ATTRIBUTE_UNUSED. Whitespace fix.
	(gfc_simplify_log): Whitespace fix.
	(gfc_simplify_log10): Whitespace fix.
	(gfc_simplify_minval): Whitespace fix.
	(gfc_simplify_maxval): Whitespace fix.
	(gfc_simplify_mod): Whitespace fix.
	(gfc_simplify_modulo): Whitespace fix.
	(simplify_nint): Reorderd statements.
	(gfc_simplify_not): Whitespace fix.
	(gfc_simplify_or): Replaced if-gate by more common switch-over-type.
	(gfc_simplify_radix): Removed unused result-variable. Whitespace fix.
	(gfc_simplify_range): Removed unused result-variable. Whitespace fix.
	(gfc_simplify_real): Use convert_boz() and gfc_convert_constant().
	(gfc_simplify_realpart): Whitespace fix.
	(gfc_simplify_selected_char_kind): Removed unused result-variable.
	(gfc_simplify_selected_int_kind): Removed unused result-variable.
	(gfc_simplify_selected_real_kind): Removed unused result-variable.
	(gfc_simplify_sign): Whitespace fix.
	(gfc_simplify_sin): Whitespace fix.
	(gfc_simplify_sinh): Replaced if-gate by more common switch-over-type.
	(gfc_simplify_sqrt): Avoided goto by inlining check. Whitespace fix.
	(gfc_simplify_tan): Replaced if-gate by more common switch-over-type.
	(gfc_simplify_tanh): Replaced if-gate by more common switch-over-type.
	(gfc_simplify_xor): Replaced if-gate by more common switch-over-type.

2010-04-12  Daniel Franke  <franke.daniel@gmail.com>

	* gfortran.h (gfc_start_constructor): Removed.
	(gfc_get_array_element): Removed.
	* array.c (gfc_start_constructor): Removed, use gfc_get_array_expr 
	instead. Fixed all callers.
	(extract_element): Removed.
	(gfc_expand_constructor): Temporarily removed check for
	max-array-constructor. Will be re-introduced later if still required.
	(gfc_get_array_element): Removed, use gfc_constructor_lookup_expr
	instead. Fixed all callers.
	* expr.c (find_array_section): Replaced manual lookup of elements
	by gfc_constructor_lookup.

2010-04-12  Daniel Franke  <franke.daniel@gmail.com>

        * gfortran.h (gfc_get_null_expr): New prototype.
        (gfc_get_operator_expr): New prototype.
        (gfc_get_character_expr): New prototype.
        (gfc_get_iokind_expr): New prototype.
        * expr.c (gfc_get_null_expr): New.
        (gfc_get_character_expr): New.
        (gfc_get_iokind_expr): New.
        (gfc_get_operator_expr): Moved here from matchexp.c (build_node).
        * matchexp.c (build_node): Renamed and moved to
        expr.c (gfc_get_operator_expr). Reordered arguments to match 
        other functions. Fixed all callers.
        (gfc_get_parentheses): Use specific function to build expr.
        * array.c (gfc_match_array_constructor): Likewise.
        * arith.c (eval_intrinsic): Likewise.
        (gfc_hollerith2int): Likewise.
        (gfc_hollerith2real): Likewise.
        (gfc_hollerith2complex): Likewise.
        (gfc_hollerith2logical): Likewise.
        * data.c (create_character_intializer): Likewise.
        * decl.c (gfc_match_null): Likewise.
        (enum_initializer): Likewise.
        * io.c (gfc_match_format): Likewise.
        (match_io): Likewise.
        * match.c (gfc_match_nullify): Likewise.
        * primary.c (match_string_constant): Likewise.
        (match_logical_constant): Likewise.
        (build_actual_constructor): Likewise.
        * resolve.c (build_default_init_expr): Likewise.
        * symbol.c (generate_isocbinding_symbol): Likewise.
        (gfc_build_class_symbol): Likewise.
        (gfc_find_derived_vtab): Likewise.
        * simplify.c (simplify_achar_char): Likewise.
        (gfc_simplify_adjustl): Likewise.
        (gfc_simplify_adjustr): Likewise.
        (gfc_simplify_and): Likewise.
        (gfc_simplify_bit_size): Likewise.
        (gfc_simplify_is_iostat_end): Likewise.
        (gfc_simplify_is_iostat_eor): Likewise.
        (gfc_simplify_isnan): Likewise.
        (simplify_bound): Likewise.
        (gfc_simplify_leadz): Likewise.
        (gfc_simplify_len_trim): Likewise.
        (gfc_simplify_logical): Likewise.
        (gfc_simplify_maxexponent): Likewise.
        (gfc_simplify_minexponent): Likewise.
        (gfc_simplify_new_line): Likewise.
        (gfc_simplify_null): Likewise.
        (gfc_simplify_or): Likewise.
        (gfc_simplify_precision): Likewise.
        (gfc_simplify_repeat): Likewise.
        (gfc_simplify_scan): Likewise.
        (gfc_simplify_size): Likewise.
        (gfc_simplify_trailz): Likewise.
        (gfc_simplify_trim): Likewise.
        (gfc_simplify_verify): Likewise.
        (gfc_simplify_xor): Likewise.
        * trans-io.c (build_dt): Likewise.
        (gfc_new_nml_name_expr): Removed.

2010-04-12  Daniel Franke  <franke.daniel@gmail.com>

	* arith.h (gfc_constant_result): Removed prototype.
	* constructor.h (gfc_build_array_expr): Removed prototype.
	(gfc_build_structure_constructor_expr): Removed prototype.
	* gfortran.h (gfc_int_expr): Removed prototype.
	(gfc_logical_expr): Removed prototype.
	(gfc_get_array_expr): New prototype.
	(gfc_get_structure_constructor_expr): New prototype.
	(gfc_get_constant_expr): New prototype.
	(gfc_get_int_expr): New prototype.
	(gfc_get_logical_expr): New prototype.
	* arith.c (gfc_constant_result): Moved and renamed to
	expr.c (gfc_get_constant_expr). Fixed all callers.
	* constructor.c (gfc_build_array_expr): Moved and renamed to
	expr.c (gfc_get_array_expr). Split gfc_typespec argument to type
	and kind. Fixed all callers.
	(gfc_build_structure_constructor_expr): Moved and renamed to
	expr.c (gfc_get_structure_constructor_expr). Split gfc_typespec argument
	to type and kind. Fixed all callers.
	* expr.c (gfc_logical_expr): Renamed to ...
	(gfc_get_logical_expr): ... this. Added kind argument. Fixed all callers.
	(gfc_int_expr): Renamed to ...
	(gfc_get_int_expr): ... this. Added kind and where arguments. Fixed all
	callers.
	(gfc_get_constant_expr): New.
	(gfc_get_array_expr): New.
	(gfc_get_structure_constructor_expr): New.
	* simplify.c (int_expr_with_kind): Removed, callers use gfc_get_int_expr
	instead.

2010-04-12  Daniel Franke  <franke.daniel@gmail.com>

	* constructor.h: New.
	* constructor.c: New.
	* Make-lang.in: Add new files to F95_PARSER_OBJS.
	* arith.c (reducy_unary): Use constructor API.
	(reduce_binary_ac): Likewise.
	(reduce_binary_ca): Likewise.
	(reduce_binary_aa): Likewise.
	* check.c (gfc_check_pack): Likewise.
	(gfc_check_reshape): Likewise.
	(gfc_check_unpack): Likewise.
	* decl.c (add_init_expr_to_sym): Likewise.
	(build_struct): Likewise.
	* dependency.c (gfc_check_dependency): Likewise.
	(contains_forall_index_p): Likewise.
	* dump-parse-tree.c (show_constructor): Likewise.
	* expr.c (free_expr0): Likewise.
	(gfc_copy_expr): Likewise.
	(gfc_is_constant_expr): Likewise.
	(simplify_constructor): Likewise.
	(find_array_element): Likewise.
	(find_component_ref): Likewise.
	(find_array_section): Likewise.
	(find_substring_ref): Likewise.
	(simplify_const_ref): Likewise.
	(scalarize_intrinsic_call): Likewise.
	(check_alloc_comp_init): Likewise.
	(gfc_default_initializer): Likewise.
	(gfc_traverse_expr): Likewise.
	* iresolve.c (check_charlen_present): Likewise.
	(gfc_resolve_reshape): Likewise.
	(gfc_resolve_transfer): Likewise.
	* module.c (mio_constructor): Likewise.
	* primary.c (build_actual_constructor): Likewise.
	(gfc_match_structure_constructor): Likewise.
	* resolve.c (resolve_structure_cons): Likewise.
	* simplify.c (is_constant_array_expr): Likewise.
	(init_result_expr): Likewise.
	(transformational_result): Likewise.
	(simplify_transformation_to_scalar): Likewise.
	(simplify_transformation_to_array): Likewise.
	(gfc_simplify_dot_product): Likewise.
	(simplify_bound): Likewise.
	(simplify_matmul): Likewise.
	(simplify_minval_maxval): Likewise.
	(gfc_simplify_pack): Likewise.
	(gfc_simplify_reshape): Likewise.
	(gfc_simplify_shape): Likewise.
	(gfc_simplify_spread): Likewise.
	(gfc_simplify_transpose): Likewise.
	(gfc_simplify_unpack): Likewise.q
	(gfc_convert_constant): Likewise.
	(gfc_convert_char_constant): Likewise.
	* target-memory.c (size_array): Likewise.
	(encode_array): Likewise.
	(encode_derived): Likewise.
	(interpret_array): Likewise.
	(gfc_interpret_derived): Likewise.
	(expr_to_char): Likewise.
	(gfc_merge_initializers): Likewise.
	* trans-array.c (gfc_get_array_constructor_size): Likewise.
	(gfc_trans_array_constructor_value): Likewise.
	(get_array_ctor_strlen): Likewise.
	(gfc_constant_array_constructor_p): Likewise.
	(gfc_build_constant_array_constructor): Likewise.
	(gfc_trans_array_constructor): Likewise.
	(gfc_conv_array_initializer): Likewise.
	* trans-decl.c (check_constant_initializer): Likewise.
	* trans-expr.c (flatten_array_ctors_without_strlen): Likewise.
	(gfc_apply_interface_mapping_to_cons): Likewise.
	(gfc_trans_structure_assign): Likewise.
	(gfc_conv_structure): Likewise.
	* array.c (check_duplicate_iterator): Likewise.
	(match_array_list): Likewise.
	(match_array_cons_element): Likewise.
	(gfc_match_array_constructor): Likewise.
	(check_constructor_type): Likewise.
	(check_constructor): Likewise.
	(expand): Likewise.
	(expand_constructor): Likewise.
	(extract_element): Likewise.
	(gfc_expanded_ac): Likewise.
	(resolve_array_list): Likewise.
	(gfc_resolve_character_array_constructor): Likewise.
	(copy_iterator): Renamed to ...
	(gfc_copy_iterator): ... this.
	(gfc_append_constructor): Removed.
	(gfc_insert_constructor): Removed unused function.
	(gfc_get_constructor): Removed.
	(gfc_free_constructor): Removed.
	(qgfc_copy_constructor): Removed.
	* gfortran.h (struct gfc_expr): Removed member 'con_by_offset'.
	Removed all references. Replaced constructor list by splay-tree.
	(struct gfc_constructor): Removed member 'next', moved 'offset' from
	the inner struct, added member 'base'.
	(gfc_append_constructor): Removed prototype.
	(gfc_insert_constructor): Removed prototype.
	(gfc_get_constructor): Removed prototype.
	(gfc_free_constructor): Removed prototype.
	(qgfc_copy_constructor): Removed prototype.
	(gfc_copy_iterator): New prototype.
	* trans-array.h (gfc_constant_array_constructor_p): Adjusted prototype.

From-SVN: r158253
2010-04-13 01:59:35 +00:00

901 lines
16 KiB
C

/* Expression parser.
Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
Contributed by Andy Vaught
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC 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 GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "gfortran.h"
#include "arith.h"
#include "match.h"
static char expression_syntax[] = N_("Syntax error in expression at %C");
/* Match a user-defined operator name. This is a normal name with a
few restrictions. The error_flag controls whether an error is
raised if 'true' or 'false' are used or not. */
match
gfc_match_defined_op_name (char *result, int error_flag)
{
static const char * const badops[] = {
"and", "or", "not", "eqv", "neqv", "eq", "ne", "ge", "le", "lt", "gt",
NULL
};
char name[GFC_MAX_SYMBOL_LEN + 1];
locus old_loc;
match m;
int i;
old_loc = gfc_current_locus;
m = gfc_match (" . %n .", name);
if (m != MATCH_YES)
return m;
/* .true. and .false. have interpretations as constants. Trying to
use these as operators will fail at a later time. */
if (strcmp (name, "true") == 0 || strcmp (name, "false") == 0)
{
if (error_flag)
goto error;
gfc_current_locus = old_loc;
return MATCH_NO;
}
for (i = 0; badops[i]; i++)
if (strcmp (badops[i], name) == 0)
goto error;
for (i = 0; name[i]; i++)
if (!ISALPHA (name[i]))
{
gfc_error ("Bad character '%c' in OPERATOR name at %C", name[i]);
return MATCH_ERROR;
}
strcpy (result, name);
return MATCH_YES;
error:
gfc_error ("The name '%s' cannot be used as a defined operator at %C",
name);
gfc_current_locus = old_loc;
return MATCH_ERROR;
}
/* Match a user defined operator. The symbol found must be an
operator already. */
static match
match_defined_operator (gfc_user_op **result)
{
char name[GFC_MAX_SYMBOL_LEN + 1];
match m;
m = gfc_match_defined_op_name (name, 0);
if (m != MATCH_YES)
return m;
*result = gfc_get_uop (name);
return MATCH_YES;
}
/* Check to see if the given operator is next on the input. If this
is not the case, the parse pointer remains where it was. */
static int
next_operator (gfc_intrinsic_op t)
{
gfc_intrinsic_op u;
locus old_loc;
old_loc = gfc_current_locus;
if (gfc_match_intrinsic_op (&u) == MATCH_YES && t == u)
return 1;
gfc_current_locus = old_loc;
return 0;
}
/* Call the INTRINSIC_PARENTHESES function. This is both
used explicitly, as below, or by resolve.c to generate
temporaries. */
gfc_expr *
gfc_get_parentheses (gfc_expr *e)
{
gfc_expr *e2;
e2 = gfc_get_operator_expr (&e->where, INTRINSIC_PARENTHESES, e, NULL);
e2->ts = e->ts;
e2->rank = e->rank;
return e2;
}
/* Match a primary expression. */
static match
match_primary (gfc_expr **result)
{
match m;
gfc_expr *e;
m = gfc_match_literal_constant (result, 0);
if (m != MATCH_NO)
return m;
m = gfc_match_array_constructor (result);
if (m != MATCH_NO)
return m;
m = gfc_match_rvalue (result);
if (m != MATCH_NO)
return m;
/* Match an expression in parentheses. */
if (gfc_match_char ('(') != MATCH_YES)
return MATCH_NO;
m = gfc_match_expr (&e);
if (m == MATCH_NO)
goto syntax;
if (m == MATCH_ERROR)
return m;
m = gfc_match_char (')');
if (m == MATCH_NO)
gfc_error ("Expected a right parenthesis in expression at %C");
/* Now we have the expression inside the parentheses, build the
expression pointing to it. By 7.1.7.2, any expression in
parentheses shall be treated as a data entity. */
*result = gfc_get_parentheses (e);
if (m != MATCH_YES)
{
gfc_free_expr (*result);
return MATCH_ERROR;
}
return MATCH_YES;
syntax:
gfc_error (expression_syntax);
return MATCH_ERROR;
}
/* Match a level 1 expression. */
static match
match_level_1 (gfc_expr **result)
{
gfc_user_op *uop;
gfc_expr *e, *f;
locus where;
match m;
where = gfc_current_locus;
uop = NULL;
m = match_defined_operator (&uop);
if (m == MATCH_ERROR)
return m;
m = match_primary (&e);
if (m != MATCH_YES)
return m;
if (uop == NULL)
*result = e;
else
{
f = gfc_get_operator_expr (&where, INTRINSIC_USER, e, NULL);
f->value.op.uop = uop;
*result = f;
}
return MATCH_YES;
}
/* As a GNU extension we support an expanded level-2 expression syntax.
Via this extension we support (arbitrary) nesting of unary plus and
minus operations following unary and binary operators, such as **.
The grammar of section 7.1.1.3 is effectively rewritten as:
R704 mult-operand is level-1-expr [ power-op ext-mult-operand ]
R704' ext-mult-operand is add-op ext-mult-operand
or mult-operand
R705 add-operand is add-operand mult-op ext-mult-operand
or mult-operand
R705' ext-add-operand is add-op ext-add-operand
or add-operand
R706 level-2-expr is [ level-2-expr ] add-op ext-add-operand
or add-operand
*/
static match match_ext_mult_operand (gfc_expr **result);
static match match_ext_add_operand (gfc_expr **result);
static int
match_add_op (void)
{
if (next_operator (INTRINSIC_MINUS))
return -1;
if (next_operator (INTRINSIC_PLUS))
return 1;
return 0;
}
static match
match_mult_operand (gfc_expr **result)
{
gfc_expr *e, *exp, *r;
locus where;
match m;
m = match_level_1 (&e);
if (m != MATCH_YES)
return m;
if (!next_operator (INTRINSIC_POWER))
{
*result = e;
return MATCH_YES;
}
where = gfc_current_locus;
m = match_ext_mult_operand (&exp);
if (m == MATCH_NO)
gfc_error ("Expected exponent in expression at %C");
if (m != MATCH_YES)
{
gfc_free_expr (e);
return MATCH_ERROR;
}
r = gfc_power (e, exp);
if (r == NULL)
{
gfc_free_expr (e);
gfc_free_expr (exp);
return MATCH_ERROR;
}
r->where = where;
*result = r;
return MATCH_YES;
}
static match
match_ext_mult_operand (gfc_expr **result)
{
gfc_expr *all, *e;
locus where;
match m;
int i;
where = gfc_current_locus;
i = match_add_op ();
if (i == 0)
return match_mult_operand (result);
if (gfc_notification_std (GFC_STD_GNU) == ERROR)
{
gfc_error ("Extension: Unary operator following "
"arithmetic operator (use parentheses) at %C");
return MATCH_ERROR;
}
else
gfc_warning ("Extension: Unary operator following "
"arithmetic operator (use parentheses) at %C");
m = match_ext_mult_operand (&e);
if (m != MATCH_YES)
return m;
if (i == -1)
all = gfc_uminus (e);
else
all = gfc_uplus (e);
if (all == NULL)
{
gfc_free_expr (e);
return MATCH_ERROR;
}
all->where = where;
*result = all;
return MATCH_YES;
}
static match
match_add_operand (gfc_expr **result)
{
gfc_expr *all, *e, *total;
locus where, old_loc;
match m;
gfc_intrinsic_op i;
m = match_mult_operand (&all);
if (m != MATCH_YES)
return m;
for (;;)
{
/* Build up a string of products or quotients. */
old_loc = gfc_current_locus;
if (next_operator (INTRINSIC_TIMES))
i = INTRINSIC_TIMES;
else
{
if (next_operator (INTRINSIC_DIVIDE))
i = INTRINSIC_DIVIDE;
else
break;
}
where = gfc_current_locus;
m = match_ext_mult_operand (&e);
if (m == MATCH_NO)
{
gfc_current_locus = old_loc;
break;
}
if (m == MATCH_ERROR)
{
gfc_free_expr (all);
return MATCH_ERROR;
}
if (i == INTRINSIC_TIMES)
total = gfc_multiply (all, e);
else
total = gfc_divide (all, e);
if (total == NULL)
{
gfc_free_expr (all);
gfc_free_expr (e);
return MATCH_ERROR;
}
all = total;
all->where = where;
}
*result = all;
return MATCH_YES;
}
static match
match_ext_add_operand (gfc_expr **result)
{
gfc_expr *all, *e;
locus where;
match m;
int i;
where = gfc_current_locus;
i = match_add_op ();
if (i == 0)
return match_add_operand (result);
if (gfc_notification_std (GFC_STD_GNU) == ERROR)
{
gfc_error ("Extension: Unary operator following "
"arithmetic operator (use parentheses) at %C");
return MATCH_ERROR;
}
else
gfc_warning ("Extension: Unary operator following "
"arithmetic operator (use parentheses) at %C");
m = match_ext_add_operand (&e);
if (m != MATCH_YES)
return m;
if (i == -1)
all = gfc_uminus (e);
else
all = gfc_uplus (e);
if (all == NULL)
{
gfc_free_expr (e);
return MATCH_ERROR;
}
all->where = where;
*result = all;
return MATCH_YES;
}
/* Match a level 2 expression. */
static match
match_level_2 (gfc_expr **result)
{
gfc_expr *all, *e, *total;
locus where;
match m;
int i;
where = gfc_current_locus;
i = match_add_op ();
if (i != 0)
{
m = match_ext_add_operand (&e);
if (m == MATCH_NO)
{
gfc_error (expression_syntax);
m = MATCH_ERROR;
}
}
else
m = match_add_operand (&e);
if (m != MATCH_YES)
return m;
if (i == 0)
all = e;
else
{
if (i == -1)
all = gfc_uminus (e);
else
all = gfc_uplus (e);
if (all == NULL)
{
gfc_free_expr (e);
return MATCH_ERROR;
}
}
all->where = where;
/* Append add-operands to the sum. */
for (;;)
{
where = gfc_current_locus;
i = match_add_op ();
if (i == 0)
break;
m = match_ext_add_operand (&e);
if (m == MATCH_NO)
gfc_error (expression_syntax);
if (m != MATCH_YES)
{
gfc_free_expr (all);
return MATCH_ERROR;
}
if (i == -1)
total = gfc_subtract (all, e);
else
total = gfc_add (all, e);
if (total == NULL)
{
gfc_free_expr (all);
gfc_free_expr (e);
return MATCH_ERROR;
}
all = total;
all->where = where;
}
*result = all;
return MATCH_YES;
}
/* Match a level three expression. */
static match
match_level_3 (gfc_expr **result)
{
gfc_expr *all, *e, *total;
locus where;
match m;
m = match_level_2 (&all);
if (m != MATCH_YES)
return m;
for (;;)
{
if (!next_operator (INTRINSIC_CONCAT))
break;
where = gfc_current_locus;
m = match_level_2 (&e);
if (m == MATCH_NO)
{
gfc_error (expression_syntax);
gfc_free_expr (all);
}
if (m != MATCH_YES)
return MATCH_ERROR;
total = gfc_concat (all, e);
if (total == NULL)
{
gfc_free_expr (all);
gfc_free_expr (e);
return MATCH_ERROR;
}
all = total;
all->where = where;
}
*result = all;
return MATCH_YES;
}
/* Match a level 4 expression. */
static match
match_level_4 (gfc_expr **result)
{
gfc_expr *left, *right, *r;
gfc_intrinsic_op i;
locus old_loc;
locus where;
match m;
m = match_level_3 (&left);
if (m != MATCH_YES)
return m;
old_loc = gfc_current_locus;
if (gfc_match_intrinsic_op (&i) != MATCH_YES)
{
*result = left;
return MATCH_YES;
}
if (i != INTRINSIC_EQ && i != INTRINSIC_NE && i != INTRINSIC_GE
&& i != INTRINSIC_LE && i != INTRINSIC_LT && i != INTRINSIC_GT
&& i != INTRINSIC_EQ_OS && i != INTRINSIC_NE_OS && i != INTRINSIC_GE_OS
&& i != INTRINSIC_LE_OS && i != INTRINSIC_LT_OS && i != INTRINSIC_GT_OS)
{
gfc_current_locus = old_loc;
*result = left;
return MATCH_YES;
}
where = gfc_current_locus;
m = match_level_3 (&right);
if (m == MATCH_NO)
gfc_error (expression_syntax);
if (m != MATCH_YES)
{
gfc_free_expr (left);
return MATCH_ERROR;
}
switch (i)
{
case INTRINSIC_EQ:
case INTRINSIC_EQ_OS:
r = gfc_eq (left, right, i);
break;
case INTRINSIC_NE:
case INTRINSIC_NE_OS:
r = gfc_ne (left, right, i);
break;
case INTRINSIC_LT:
case INTRINSIC_LT_OS:
r = gfc_lt (left, right, i);
break;
case INTRINSIC_LE:
case INTRINSIC_LE_OS:
r = gfc_le (left, right, i);
break;
case INTRINSIC_GT:
case INTRINSIC_GT_OS:
r = gfc_gt (left, right, i);
break;
case INTRINSIC_GE:
case INTRINSIC_GE_OS:
r = gfc_ge (left, right, i);
break;
default:
gfc_internal_error ("match_level_4(): Bad operator");
}
if (r == NULL)
{
gfc_free_expr (left);
gfc_free_expr (right);
return MATCH_ERROR;
}
r->where = where;
*result = r;
return MATCH_YES;
}
static match
match_and_operand (gfc_expr **result)
{
gfc_expr *e, *r;
locus where;
match m;
int i;
i = next_operator (INTRINSIC_NOT);
where = gfc_current_locus;
m = match_level_4 (&e);
if (m != MATCH_YES)
return m;
r = e;
if (i)
{
r = gfc_not (e);
if (r == NULL)
{
gfc_free_expr (e);
return MATCH_ERROR;
}
}
r->where = where;
*result = r;
return MATCH_YES;
}
static match
match_or_operand (gfc_expr **result)
{
gfc_expr *all, *e, *total;
locus where;
match m;
m = match_and_operand (&all);
if (m != MATCH_YES)
return m;
for (;;)
{
if (!next_operator (INTRINSIC_AND))
break;
where = gfc_current_locus;
m = match_and_operand (&e);
if (m == MATCH_NO)
gfc_error (expression_syntax);
if (m != MATCH_YES)
{
gfc_free_expr (all);
return MATCH_ERROR;
}
total = gfc_and (all, e);
if (total == NULL)
{
gfc_free_expr (all);
gfc_free_expr (e);
return MATCH_ERROR;
}
all = total;
all->where = where;
}
*result = all;
return MATCH_YES;
}
static match
match_equiv_operand (gfc_expr **result)
{
gfc_expr *all, *e, *total;
locus where;
match m;
m = match_or_operand (&all);
if (m != MATCH_YES)
return m;
for (;;)
{
if (!next_operator (INTRINSIC_OR))
break;
where = gfc_current_locus;
m = match_or_operand (&e);
if (m == MATCH_NO)
gfc_error (expression_syntax);
if (m != MATCH_YES)
{
gfc_free_expr (all);
return MATCH_ERROR;
}
total = gfc_or (all, e);
if (total == NULL)
{
gfc_free_expr (all);
gfc_free_expr (e);
return MATCH_ERROR;
}
all = total;
all->where = where;
}
*result = all;
return MATCH_YES;
}
/* Match a level 5 expression. */
static match
match_level_5 (gfc_expr **result)
{
gfc_expr *all, *e, *total;
locus where;
match m;
gfc_intrinsic_op i;
m = match_equiv_operand (&all);
if (m != MATCH_YES)
return m;
for (;;)
{
if (next_operator (INTRINSIC_EQV))
i = INTRINSIC_EQV;
else
{
if (next_operator (INTRINSIC_NEQV))
i = INTRINSIC_NEQV;
else
break;
}
where = gfc_current_locus;
m = match_equiv_operand (&e);
if (m == MATCH_NO)
gfc_error (expression_syntax);
if (m != MATCH_YES)
{
gfc_free_expr (all);
return MATCH_ERROR;
}
if (i == INTRINSIC_EQV)
total = gfc_eqv (all, e);
else
total = gfc_neqv (all, e);
if (total == NULL)
{
gfc_free_expr (all);
gfc_free_expr (e);
return MATCH_ERROR;
}
all = total;
all->where = where;
}
*result = all;
return MATCH_YES;
}
/* Match an expression. At this level, we are stringing together
level 5 expressions separated by binary operators. */
match
gfc_match_expr (gfc_expr **result)
{
gfc_expr *all, *e;
gfc_user_op *uop;
locus where;
match m;
m = match_level_5 (&all);
if (m != MATCH_YES)
return m;
for (;;)
{
uop = NULL;
m = match_defined_operator (&uop);
if (m == MATCH_NO)
break;
if (m == MATCH_ERROR)
{
gfc_free_expr (all);
return MATCH_ERROR;
}
where = gfc_current_locus;
m = match_level_5 (&e);
if (m == MATCH_NO)
gfc_error (expression_syntax);
if (m != MATCH_YES)
{
gfc_free_expr (all);
return MATCH_ERROR;
}
all = gfc_get_operator_expr (&where, INTRINSIC_USER, all, e);
all->value.op.uop = uop;
}
*result = all;
return MATCH_YES;
}