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
901 lines
16 KiB
C
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;
|
|
}
|