123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904 |
- /* Expression parser.
- Copyright (C) 2000-2015 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 "coretypes.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 %qs 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;
- gfc_gobble_whitespace ();
- 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)
- {
- /* Workaround -Wmaybe-uninitialized false positive during
- profiledbootstrap by initializing them. */
- gfc_expr *e = NULL, *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 (0, "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 (0, "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 = NULL;
- 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);
- if (m != MATCH_YES)
- {
- gfc_free_expr (all);
- 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;
- }
|