/* Declaration statement matcher
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
Contributed by Andy Vaught
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
+#include "system.h"
#include "gfortran.h"
#include "match.h"
#include "parse.h"
-#include <string.h>
-/* This flag is set if a an old-style length selector is matched
+/* This flag is set if an old-style length selector is matched
during a type-declaration statement. */
static int old_char_selector;
-/* When variables aquire types and attributes from a declaration
+/* When variables acquire types and attributes from a declaration
statement, they get them from the following static variables. The
first part of a declaration sets these variables and the second
part copies these into symbol structures. */
gfc_symbol *gfc_new_block;
+/********************* DATA statement subroutines *********************/
+
+/* Free a gfc_data_variable structure and everything beneath it. */
+
+static void
+free_variable (gfc_data_variable * p)
+{
+ gfc_data_variable *q;
+
+ for (; p; p = q)
+ {
+ q = p->next;
+ gfc_free_expr (p->expr);
+ gfc_free_iterator (&p->iter, 0);
+ free_variable (p->list);
+
+ gfc_free (p);
+ }
+}
+
+
+/* Free a gfc_data_value structure and everything beneath it. */
+
+static void
+free_value (gfc_data_value * p)
+{
+ gfc_data_value *q;
+
+ for (; p; p = q)
+ {
+ q = p->next;
+ gfc_free_expr (p->expr);
+ gfc_free (p);
+ }
+}
+
+
+/* Free a list of gfc_data structures. */
+
+void
+gfc_free_data (gfc_data * p)
+{
+ gfc_data *q;
+
+ for (; p; p = q)
+ {
+ q = p->next;
+
+ free_variable (p->var);
+ free_value (p->value);
+
+ gfc_free (p);
+ }
+}
+
+
+static match var_element (gfc_data_variable *);
+
+/* Match a list of variables terminated by an iterator and a right
+ parenthesis. */
+
+static match
+var_list (gfc_data_variable * parent)
+{
+ gfc_data_variable *tail, var;
+ match m;
+
+ m = var_element (&var);
+ if (m == MATCH_ERROR)
+ return MATCH_ERROR;
+ if (m == MATCH_NO)
+ goto syntax;
+
+ tail = gfc_get_data_variable ();
+ *tail = var;
+
+ parent->list = tail;
+
+ for (;;)
+ {
+ if (gfc_match_char (',') != MATCH_YES)
+ goto syntax;
+
+ m = gfc_match_iterator (&parent->iter, 1);
+ if (m == MATCH_YES)
+ break;
+ if (m == MATCH_ERROR)
+ return MATCH_ERROR;
+
+ m = var_element (&var);
+ if (m == MATCH_ERROR)
+ return MATCH_ERROR;
+ if (m == MATCH_NO)
+ goto syntax;
+
+ tail->next = gfc_get_data_variable ();
+ tail = tail->next;
+
+ *tail = var;
+ }
+
+ if (gfc_match_char (')') != MATCH_YES)
+ goto syntax;
+ return MATCH_YES;
+
+syntax:
+ gfc_syntax_error (ST_DATA);
+ return MATCH_ERROR;
+}
+
+
+/* Match a single element in a data variable list, which can be a
+ variable-iterator list. */
+
+static match
+var_element (gfc_data_variable * new)
+{
+ match m;
+ gfc_symbol *sym;
+
+ memset (new, 0, sizeof (gfc_data_variable));
+
+ if (gfc_match_char ('(') == MATCH_YES)
+ return var_list (new);
+
+ m = gfc_match_variable (&new->expr, 0);
+ if (m != MATCH_YES)
+ return m;
+
+ sym = new->expr->symtree->n.sym;
+
+ if(sym->value != NULL)
+ {
+ gfc_error ("Variable '%s' at %C already has an initialization",
+ sym->name);
+ return MATCH_ERROR;
+ }
+
+#if 0 /* TODO: Find out where to move this message */
+ if (sym->attr.in_common)
+ /* See if sym is in the blank common block. */
+ for (t = &sym->ns->blank_common; t; t = t->common_next)
+ if (sym == t->head)
+ {
+ gfc_error ("DATA statement at %C may not initialize variable "
+ "'%s' from blank COMMON", sym->name);
+ return MATCH_ERROR;
+ }
+#endif
+
+ if (gfc_add_data (&sym->attr, sym->name, &new->expr->where) == FAILURE)
+ return MATCH_ERROR;
+
+ return MATCH_YES;
+}
+
+
+/* Match the top-level list of data variables. */
+
+static match
+top_var_list (gfc_data * d)
+{
+ gfc_data_variable var, *tail, *new;
+ match m;
+
+ tail = NULL;
+
+ for (;;)
+ {
+ m = var_element (&var);
+ if (m == MATCH_NO)
+ goto syntax;
+ if (m == MATCH_ERROR)
+ return MATCH_ERROR;
+
+ new = gfc_get_data_variable ();
+ *new = var;
+
+ if (tail == NULL)
+ d->var = new;
+ else
+ tail->next = new;
+
+ tail = new;
+
+ if (gfc_match_char ('/') == MATCH_YES)
+ break;
+ if (gfc_match_char (',') != MATCH_YES)
+ goto syntax;
+ }
+
+ return MATCH_YES;
+
+syntax:
+ gfc_syntax_error (ST_DATA);
+ return MATCH_ERROR;
+}
+
+
+static match
+match_data_constant (gfc_expr ** result)
+{
+ char name[GFC_MAX_SYMBOL_LEN + 1];
+ gfc_symbol *sym;
+ gfc_expr *expr;
+ match m;
+
+ m = gfc_match_literal_constant (&expr, 1);
+ if (m == MATCH_YES)
+ {
+ *result = expr;
+ return MATCH_YES;
+ }
+
+ if (m == MATCH_ERROR)
+ return MATCH_ERROR;
+
+ m = gfc_match_null (result);
+ if (m != MATCH_NO)
+ return m;
+
+ m = gfc_match_name (name);
+ if (m != MATCH_YES)
+ return m;
+
+ if (gfc_find_symbol (name, NULL, 1, &sym))
+ return MATCH_ERROR;
+
+ if (sym == NULL
+ || (sym->attr.flavor != FL_PARAMETER && sym->attr.flavor != FL_DERIVED))
+ {
+ gfc_error ("Symbol '%s' must be a PARAMETER in DATA statement at %C",
+ name);
+ return MATCH_ERROR;
+ }
+ else if (sym->attr.flavor == FL_DERIVED)
+ return gfc_match_structure_constructor (sym, result);
+
+ *result = gfc_copy_expr (sym->value);
+ return MATCH_YES;
+}
+
+
+/* Match a list of values in a DATA statement. The leading '/' has
+ already been seen at this point. */
+
+static match
+top_val_list (gfc_data * data)
+{
+ gfc_data_value *new, *tail;
+ gfc_expr *expr;
+ const char *msg;
+ match m;
+
+ tail = NULL;
+
+ for (;;)
+ {
+ m = match_data_constant (&expr);
+ if (m == MATCH_NO)
+ goto syntax;
+ if (m == MATCH_ERROR)
+ return MATCH_ERROR;
+
+ new = gfc_get_data_value ();
+
+ if (tail == NULL)
+ data->value = new;
+ else
+ tail->next = new;
+
+ tail = new;
+
+ if (expr->ts.type != BT_INTEGER || gfc_match_char ('*') != MATCH_YES)
+ {
+ tail->expr = expr;
+ tail->repeat = 1;
+ }
+ else
+ {
+ signed int tmp;
+ msg = gfc_extract_int (expr, &tmp);
+ gfc_free_expr (expr);
+ if (msg != NULL)
+ {
+ gfc_error (msg);
+ return MATCH_ERROR;
+ }
+ tail->repeat = tmp;
+
+ m = match_data_constant (&tail->expr);
+ if (m == MATCH_NO)
+ goto syntax;
+ if (m == MATCH_ERROR)
+ return MATCH_ERROR;
+ }
+
+ if (gfc_match_char ('/') == MATCH_YES)
+ break;
+ if (gfc_match_char (',') == MATCH_NO)
+ goto syntax;
+ }
+
+ return MATCH_YES;
+
+syntax:
+ gfc_syntax_error (ST_DATA);
+ return MATCH_ERROR;
+}
+
+
+/* Matches an old style initialization. */
+
+static match
+match_old_style_init (const char *name)
+{
+ match m;
+ gfc_symtree *st;
+ gfc_data *newdata;
+
+ /* Set up data structure to hold initializers. */
+ gfc_find_sym_tree (name, NULL, 0, &st);
+
+ newdata = gfc_get_data ();
+ newdata->var = gfc_get_data_variable ();
+ newdata->var->expr = gfc_get_variable_expr (st);
+
+ /* Match initial value list. This also eats the terminal
+ '/'. */
+ m = top_val_list (newdata);
+ if (m != MATCH_YES)
+ {
+ gfc_free (newdata);
+ return m;
+ }
+
+ if (gfc_pure (NULL))
+ {
+ gfc_error ("Initialization at %C is not allowed in a PURE procedure");
+ gfc_free (newdata);
+ return MATCH_ERROR;
+ }
+
+ /* Chain in namespace list of DATA initializers. */
+ newdata->next = gfc_current_ns->data;
+ gfc_current_ns->data = newdata;
+
+ return m;
+}
+
+/* Match the stuff following a DATA statement. If ERROR_FLAG is set,
+ we are matching a DATA statement and are therefore issuing an error
+ if we encounter something unexpected, if not, we're trying to match
+ an old-style initialization expression of the form INTEGER I /2/. */
+
+match
+gfc_match_data (void)
+{
+ gfc_data *new;
+ match m;
+
+ for (;;)
+ {
+ new = gfc_get_data ();
+ new->where = gfc_current_locus;
+
+ m = top_var_list (new);
+ if (m != MATCH_YES)
+ goto cleanup;
+
+ m = top_val_list (new);
+ if (m != MATCH_YES)
+ goto cleanup;
+
+ new->next = gfc_current_ns->data;
+ gfc_current_ns->data = new;
+
+ if (gfc_match_eos () == MATCH_YES)
+ break;
+
+ gfc_match_char (','); /* Optional comma */
+ }
+
+ if (gfc_pure (NULL))
+ {
+ gfc_error ("DATA statement at %C is not allowed in a PURE procedure");
+ return MATCH_ERROR;
+ }
+
+ return MATCH_YES;
+
+cleanup:
+ gfc_free_data (new);
+ return MATCH_ERROR;
+}
+
+
+/************************ Declaration statements *********************/
+
/* Match an intent specification. Since this can only happen after an
INTENT word, a legal intent-spec must follow. */
}
-/* Special subroutine for finding a symbol. If we're compiling a
- function or subroutine and the parent compilation unit is an
- interface, then check to see if the name we've been given is the
- name of the interface (located in another namespace). If so,
- return that symbol. If not, use gfc_get_symbol(). */
+/* Special subroutine for finding a symbol. Check if the name is found
+ in the current name space. If not, and we're compiling a function or
+ subroutine and the parent compilation unit is an interface, then check
+ to see if the name we've been given is the name of the interface
+ (located in another namespace). */
static int
find_special (const char *name, gfc_symbol ** result)
{
gfc_state_data *s;
+ int i;
+ i = gfc_get_symbol (name, NULL, result);
+ if (i==0)
+ goto end;
+
if (gfc_current_state () != COMP_SUBROUTINE
&& gfc_current_state () != COMP_FUNCTION)
- goto normal;
+ goto end;
s = gfc_state_stack->previous;
if (s == NULL)
- goto normal;
+ goto end;
if (s->state != COMP_INTERFACE)
- goto normal;
+ goto end;
if (s->sym == NULL)
- goto normal; /* Nameless interface */
+ goto end; /* Nameless interface */
if (strcmp (name, s->sym->name) == 0)
{
return 0;
}
-normal:
- return gfc_get_symbol (name, NULL, result);
+end:
+ return i;
}
if (*result == NULL)
return rc;
- /* Deal with ENTRY problem */
+ /* ??? Deal with ENTRY problem */
st = gfc_new_symtree (&gfc_current_ns->sym_root, name);
if (sym->ns->proc_name != NULL
&& sym->ns->proc_name->attr.flavor == FL_MODULE
&& sym->attr.proc != PROC_MODULE
- && gfc_add_procedure (&sym->attr, PROC_MODULE, NULL) == FAILURE)
+ && gfc_add_procedure (&sym->attr, PROC_MODULE,
+ sym->name, NULL) == FAILURE)
rc = 2;
return rc;
symbol_attribute attr;
gfc_symbol *sym;
- if (find_special (name, &sym))
+ /* if (find_special (name, &sym)) */
+ if (gfc_get_symbol (name, NULL, &sym))
return FAILURE;
/* Start updating the symbol table. Add basic type attribute
return SUCCESS;
}
+/* Set character constant to the given length. The constant will be padded or
+ truncated. */
+
+void
+gfc_set_constant_character_len (int len, gfc_expr * expr)
+{
+ char * s;
+ int slen;
+
+ gcc_assert (expr->expr_type == EXPR_CONSTANT);
+ gcc_assert (expr->ts.type == BT_CHARACTER && expr->ts.kind == 1);
+
+ slen = expr->value.character.length;
+ if (len != slen)
+ {
+ s = gfc_getmem (len);
+ memcpy (s, expr->value.character.string, MIN (len, slen));
+ if (len > slen)
+ memset (&s[slen], ' ', len - slen);
+ gfc_free (expr->value.character.string);
+ expr->value.character.string = s;
+ expr->value.character.length = len;
+ }
+}
/* Function called by variable_decl() that adds an initialization
expression to a symbol. */
return FAILURE;
}
- /* Checking a derived type parameter has to be put off until later. */
+ /* Check if the assignment can happen. This has to be put off
+ until later for a derived type variable. */
if (sym->ts.type != BT_DERIVED && init->ts.type != BT_DERIVED
&& gfc_check_assign_symbol (sym, init) == FAILURE)
return FAILURE;
+ if (sym->ts.type == BT_CHARACTER && sym->ts.cl)
+ {
+ /* Update symbol character length according initializer. */
+ if (sym->ts.cl->length == NULL)
+ {
+ /* If there are multiple CHARACTER variables declared on
+ the same line, we don't want them to share the same
+ length. */
+ sym->ts.cl = gfc_get_charlen ();
+ sym->ts.cl->next = gfc_current_ns->cl_list;
+ gfc_current_ns->cl_list = sym->ts.cl;
+
+ if (init->expr_type == EXPR_CONSTANT)
+ sym->ts.cl->length =
+ gfc_int_expr (init->value.character.length);
+ else if (init->expr_type == EXPR_ARRAY)
+ sym->ts.cl->length = gfc_copy_expr (init->ts.cl->length);
+ }
+ /* Update initializer character length according symbol. */
+ else if (sym->ts.cl->length->expr_type == EXPR_CONSTANT)
+ {
+ int len = mpz_get_si (sym->ts.cl->length->value.integer);
+ gfc_constructor * p;
+
+ if (init->expr_type == EXPR_CONSTANT)
+ gfc_set_constant_character_len (len, init);
+ else if (init->expr_type == EXPR_ARRAY)
+ {
+ gfc_free_expr (init->ts.cl->length);
+ init->ts.cl->length = gfc_copy_expr (sym->ts.cl->length);
+ for (p = init->value.constructor; p; p = p->next)
+ gfc_set_constant_character_len (len, p->expr);
+ }
+ }
+ }
+
/* Add initializer. Make sure we keep the ranks sane. */
if (sym->attr.dimension && init->rank == 0)
init->rank = sym->as->rank;
gfc_intrinsic_symbol (sym);
if (sym->attr.proc != PROC_INTRINSIC
- && (gfc_add_procedure (&sym->attr, PROC_INTRINSIC, NULL) == FAILURE
- || gfc_add_function (&sym->attr, NULL) == FAILURE))
+ && (gfc_add_procedure (&sym->attr, PROC_INTRINSIC,
+ sym->name, NULL) == FAILURE
+ || gfc_add_function (&sym->attr, sym->name, NULL) == FAILURE))
return MATCH_ERROR;
e = gfc_get_expr ();
symbol table or the current interface. */
static match
-variable_decl (void)
+variable_decl (int elem)
{
char name[GFC_MAX_SYMBOL_LEN + 1];
gfc_expr *initializer, *char_len;
cl->length = char_len;
break;
+ /* Non-constant lengths need to be copied after the first
+ element. */
case MATCH_NO:
- cl = current_ts.cl;
+ if (elem > 1 && current_ts.cl->length
+ && current_ts.cl->length->expr_type != EXPR_CONSTANT)
+ {
+ cl = gfc_get_charlen ();
+ cl->next = gfc_current_ns->cl_list;
+ gfc_current_ns->cl_list = cl;
+ cl->length = gfc_copy_expr (current_ts.cl->length);
+ }
+ else
+ cl = current_ts.cl;
+
break;
case MATCH_ERROR:
/* OK, we've successfully matched the declaration. Now put the
symbol in the current namespace, because it might be used in the
- optional intialization expression for this symbol, e.g. this is
+ optional initialization expression for this symbol, e.g. this is
perfectly legal:
integer, parameter :: i = huge(i)
goto cleanup;
}
+ /* We allow old-style initializations of the form
+ integer i /2/, j(4) /3*3, 1/
+ (if no colon has been seen). These are different from data
+ statements in that initializers are only allowed to apply to the
+ variable immediately preceding, i.e.
+ integer i, j /1, 2/
+ is not allowed. Therefore we have to do some work manually, that
+ could otherwise be left to the matchers for DATA statements. */
+
+ if (!colon_seen && gfc_match (" /") == MATCH_YES)
+ {
+ if (gfc_notify_std (GFC_STD_GNU, "Extension: Old-style "
+ "initialization at %C") == FAILURE)
+ return MATCH_ERROR;
+
+ return match_old_style_init (name);
+ }
+
/* The double colon must be present in order to have initializers.
Otherwise the statement is ambiguous with an assignment statement. */
if (colon_seen)
t = add_init_expr_to_sym (name, &initializer, &var_locus);
else
{
- if (current_ts.type == BT_DERIVED && !initializer)
+ if (current_ts.type == BT_DERIVED && !current_attr.pointer && !initializer)
initializer = gfc_default_initializer (¤t_ts);
t = build_struct (name, cl, &initializer, &as);
}
if (ts->type == BT_COMPLEX && ts->kind == 16)
ts->kind = 8;
- if (gfc_validate_kind (ts->type, ts->kind) == -1)
+ if (gfc_validate_kind (ts->type, ts->kind, true) < 0)
{
gfc_error ("Old-style kind %d not supported for type %s at %C",
ts->kind, gfc_basic_typename (ts->type));
gfc_free_expr (e);
e = NULL;
- if (gfc_validate_kind (ts->type, ts->kind) == -1)
+ if (gfc_validate_kind (ts->type, ts->kind, true) < 0)
{
gfc_error ("Kind %d not supported for type %s at %C", ts->kind,
gfc_basic_typename (ts->type));
gfc_expr *len;
match m;
- kind = gfc_default_character_kind ();
+ kind = gfc_default_character_kind;
len = NULL;
seen_length = 0;
gfc_match_small_int (&kind);
- if (gfc_validate_kind (BT_CHARACTER, kind) == -1)
+ if (gfc_validate_kind (BT_CHARACTER, kind, true) < 0)
{
gfc_error ("Kind %d is not a CHARACTER kind at %C", kind);
return MATCH_YES;
m = MATCH_ERROR;
done:
- if (m == MATCH_YES && gfc_validate_kind (BT_CHARACTER, kind) == -1)
+ if (m == MATCH_YES && gfc_validate_kind (BT_CHARACTER, kind, true) < 0)
{
gfc_error ("Kind %d is not a CHARACTER kind at %C", kind);
m = MATCH_ERROR;
gfc_clear_ts (ts);
+ if (gfc_match (" byte") == MATCH_YES)
+ {
+ if (gfc_notify_std(GFC_STD_GNU, "Extension: BYTE type at %C")
+ == FAILURE)
+ return MATCH_ERROR;
+
+ if (gfc_validate_kind (BT_INTEGER, 1, true) < 0)
+ {
+ gfc_error ("BYTE type used at %C "
+ "is not available on the target machine");
+ return MATCH_ERROR;
+ }
+
+ ts->type = BT_INTEGER;
+ ts->kind = 1;
+ return MATCH_YES;
+ }
+
if (gfc_match (" integer") == MATCH_YES)
{
ts->type = BT_INTEGER;
- ts->kind = gfc_default_integer_kind ();
+ ts->kind = gfc_default_integer_kind;
goto get_kind;
}
if (gfc_match (" real") == MATCH_YES)
{
ts->type = BT_REAL;
- ts->kind = gfc_default_real_kind ();
+ ts->kind = gfc_default_real_kind;
goto get_kind;
}
if (gfc_match (" double precision") == MATCH_YES)
{
ts->type = BT_REAL;
- ts->kind = gfc_default_double_kind ();
+ ts->kind = gfc_default_double_kind;
return MATCH_YES;
}
if (gfc_match (" complex") == MATCH_YES)
{
ts->type = BT_COMPLEX;
- ts->kind = gfc_default_complex_kind ();
+ ts->kind = gfc_default_complex_kind;
goto get_kind;
}
if (gfc_match (" double complex") == MATCH_YES)
{
ts->type = BT_COMPLEX;
- ts->kind = gfc_default_double_kind ();
+ ts->kind = gfc_default_double_kind;
return MATCH_YES;
}
if (gfc_match (" logical") == MATCH_YES)
{
ts->type = BT_LOGICAL;
- ts->kind = gfc_default_logical_kind ();
+ ts->kind = gfc_default_logical_kind;
goto get_kind;
}
}
if (sym->attr.flavor != FL_DERIVED
- && gfc_add_flavor (&sym->attr, FL_DERIVED, NULL) == FAILURE)
+ && gfc_add_flavor (&sym->attr, FL_DERIVED, sym->name, NULL) == FAILURE)
return MATCH_ERROR;
ts->type = BT_DERIVED;
/* Match the letter range(s) of an IMPLICIT statement. */
static match
-match_implicit_range (gfc_typespec * ts)
+match_implicit_range (void)
{
int c, c1, c2, inner;
locus cur_loc;
conflicts with whatever earlier IMPLICIT statements may have
set. This is done when we've successfully finished matching
the current one. */
- if (gfc_add_new_implicit_range (c1, c2, ts) != SUCCESS)
+ if (gfc_add_new_implicit_range (c1, c2) != SUCCESS)
goto bad;
}
return MATCH_ERROR;
}
- /* First cleanup. */
- gfc_clear_new_implicit ();
-
do
{
+ /* First cleanup. */
+ gfc_clear_new_implicit ();
+
/* A basic type is mandatory here. */
m = match_type_spec (&ts, 1);
if (m == MATCH_ERROR)
goto syntax;
cur_loc = gfc_current_locus;
- m = match_implicit_range (&ts);
-
- if (m != MATCH_YES && ts.type == BT_CHARACTER)
- {
- /* looks like we are matching CHARACTER (<len>) (<range>) */
- m = match_char_spec (&ts);
- }
+ m = match_implicit_range ();
if (m == MATCH_YES)
{
- /* Looks like we have the <TYPE> (<RANGE>). */
+ /* We may have <TYPE> (<RANGE>). */
gfc_gobble_whitespace ();
c = gfc_next_char ();
if ((c == '\n') || (c == ','))
- continue;
+ {
+ /* Check for CHARACTER with no length parameter. */
+ if (ts.type == BT_CHARACTER && !ts.cl)
+ {
+ ts.kind = gfc_default_character_kind;
+ ts.cl = gfc_get_charlen ();
+ ts.cl->next = gfc_current_ns->cl_list;
+ gfc_current_ns->cl_list = ts.cl;
+ ts.cl->length = gfc_int_expr (1);
+ }
+
+ /* Record the Successful match. */
+ if (gfc_merge_new_implicit (&ts) != SUCCESS)
+ return MATCH_ERROR;
+ continue;
+ }
gfc_current_locus = cur_loc;
}
- /* Last chance -- check <TYPE> (<KIND>) (<RANGE>). */
- m = gfc_match_kind_spec (&ts);
- if (m == MATCH_ERROR)
- goto error;
- if (m == MATCH_NO)
+ /* Discard the (incorrectly) matched range. */
+ gfc_clear_new_implicit ();
+
+ /* Last chance -- check <TYPE> <SELECTOR> (<RANGE>). */
+ if (ts.type == BT_CHARACTER)
+ m = match_char_spec (&ts);
+ else
{
- m = gfc_match_old_kind_spec (&ts);
- if (m == MATCH_ERROR)
- goto error;
+ m = gfc_match_kind_spec (&ts);
if (m == MATCH_NO)
- goto syntax;
+ {
+ m = gfc_match_old_kind_spec (&ts);
+ if (m == MATCH_ERROR)
+ goto error;
+ if (m == MATCH_NO)
+ goto syntax;
+ }
}
+ if (m == MATCH_ERROR)
+ goto error;
- m = match_implicit_range (&ts);
+ m = match_implicit_range ();
if (m == MATCH_ERROR)
goto error;
if (m == MATCH_NO)
if ((c != '\n') && (c != ','))
goto syntax;
+ if (gfc_merge_new_implicit (&ts) != SUCCESS)
+ return MATCH_ERROR;
}
while (c == ',');
- /* All we need to now is try to merge the new implicit types back
- into the existing types. This will fail if another implicit
- type is already defined for a letter. */
- return (gfc_merge_new_implicit () == SUCCESS) ?
- MATCH_YES : MATCH_ERROR;
+ return MATCH_YES;
syntax:
gfc_syntax_error (ST_IMPLICIT);
goto cleanup;
}
+ if ((d == DECL_PRIVATE || d == DECL_PUBLIC)
+ && gfc_current_state () != COMP_MODULE)
+ {
+ if (d == DECL_PRIVATE)
+ attr = "PRIVATE";
+ else
+ attr = "PUBLIC";
+
+ gfc_error ("%s attribute at %L is not allowed outside of a MODULE",
+ attr, &seen_at[d]);
+ m = MATCH_ERROR;
+ goto cleanup;
+ }
+
switch (d)
{
case DECL_ALLOCATABLE:
break;
case DECL_DIMENSION:
- t = gfc_add_dimension (¤t_attr, &seen_at[d]);
+ t = gfc_add_dimension (¤t_attr, NULL, &seen_at[d]);
break;
case DECL_EXTERNAL:
break;
case DECL_PARAMETER:
- t = gfc_add_flavor (¤t_attr, FL_PARAMETER, &seen_at[d]);
+ t = gfc_add_flavor (¤t_attr, FL_PARAMETER, NULL, &seen_at[d]);
break;
case DECL_POINTER:
break;
case DECL_PRIVATE:
- t = gfc_add_access (¤t_attr, ACCESS_PRIVATE, &seen_at[d]);
+ t = gfc_add_access (¤t_attr, ACCESS_PRIVATE, NULL,
+ &seen_at[d]);
break;
case DECL_PUBLIC:
- t = gfc_add_access (¤t_attr, ACCESS_PUBLIC, &seen_at[d]);
+ t = gfc_add_access (¤t_attr, ACCESS_PUBLIC, NULL,
+ &seen_at[d]);
break;
case DECL_SAVE:
- t = gfc_add_save (¤t_attr, &seen_at[d]);
+ t = gfc_add_save (¤t_attr, NULL, &seen_at[d]);
break;
case DECL_TARGET:
{
gfc_symbol *sym;
match m;
+ int elem;
m = match_type_spec (¤t_ts, 0);
if (m != MATCH_YES)
if (m == MATCH_NO && current_ts.type == BT_CHARACTER && old_char_selector)
gfc_match_char (',');
- /* Give the types/attributes to symbols that follow. */
+ /* Give the types/attributes to symbols that follow. Give the element
+ a number so that repeat character length expressions can be copied. */
+ elem = 1;
for (;;)
{
- m = variable_decl ();
+ m = variable_decl (elem++);
if (m == MATCH_ERROR)
goto cleanup;
if (m == MATCH_NO)
dummy procedure. We don't apply these attributes to formal
arguments of statement functions. */
if (sym != NULL && !st_flag
- && (gfc_add_dummy (&sym->attr, NULL) == FAILURE
+ && (gfc_add_dummy (&sym->attr, sym->name, NULL) == FAILURE
|| gfc_missing_attr (&sym->attr, NULL) == FAILURE))
{
m = MATCH_ERROR;
if (gfc_get_symbol (name, NULL, &r))
return MATCH_ERROR;
- if (gfc_add_flavor (&r->attr, FL_VARIABLE, NULL) == FAILURE
- || gfc_add_result (&r->attr, NULL) == FAILURE)
+ if (gfc_add_flavor (&r->attr, FL_VARIABLE, r->name, NULL) == FAILURE
+ || gfc_add_result (&r->attr, r->name, NULL) == FAILURE)
return MATCH_ERROR;
*result = r;
/* Make changes to the symbol. */
m = MATCH_ERROR;
- if (gfc_add_function (&sym->attr, NULL) == FAILURE)
+ if (gfc_add_function (&sym->attr, sym->name, NULL) == FAILURE)
goto cleanup;
if (gfc_missing_attr (&sym->attr, NULL) == FAILURE
match
gfc_match_entry (void)
{
- gfc_symbol *function, *result, *entry;
+ gfc_symbol *proc;
+ gfc_symbol *result;
+ gfc_symbol *entry;
char name[GFC_MAX_SYMBOL_LEN + 1];
gfc_compile_state state;
match m;
+ gfc_entry_list *el;
m = gfc_match_name (name);
if (m != MATCH_YES)
return m;
+ state = gfc_current_state ();
+ if (state != COMP_SUBROUTINE && state != COMP_FUNCTION)
+ {
+ switch (state)
+ {
+ case COMP_PROGRAM:
+ gfc_error ("ENTRY statement at %C cannot appear within a PROGRAM");
+ break;
+ case COMP_MODULE:
+ gfc_error ("ENTRY statement at %C cannot appear within a MODULE");
+ break;
+ case COMP_BLOCK_DATA:
+ gfc_error
+ ("ENTRY statement at %C cannot appear within a BLOCK DATA");
+ break;
+ case COMP_INTERFACE:
+ gfc_error
+ ("ENTRY statement at %C cannot appear within an INTERFACE");
+ break;
+ case COMP_DERIVED:
+ gfc_error
+ ("ENTRY statement at %C cannot appear "
+ "within a DERIVED TYPE block");
+ break;
+ case COMP_IF:
+ gfc_error
+ ("ENTRY statement at %C cannot appear within an IF-THEN block");
+ break;
+ case COMP_DO:
+ gfc_error
+ ("ENTRY statement at %C cannot appear within a DO block");
+ break;
+ case COMP_SELECT:
+ gfc_error
+ ("ENTRY statement at %C cannot appear within a SELECT block");
+ break;
+ case COMP_FORALL:
+ gfc_error
+ ("ENTRY statement at %C cannot appear within a FORALL block");
+ break;
+ case COMP_WHERE:
+ gfc_error
+ ("ENTRY statement at %C cannot appear within a WHERE block");
+ break;
+ case COMP_CONTAINS:
+ gfc_error
+ ("ENTRY statement at %C cannot appear "
+ "within a contained subprogram");
+ break;
+ default:
+ gfc_internal_error ("gfc_match_entry(): Bad state");
+ }
+ return MATCH_ERROR;
+ }
+
+ if (gfc_current_ns->parent != NULL
+ && gfc_current_ns->parent->proc_name
+ && gfc_current_ns->parent->proc_name->attr.flavor != FL_MODULE)
+ {
+ gfc_error("ENTRY statement at %C cannot appear in a "
+ "contained procedure");
+ return MATCH_ERROR;
+ }
+
if (get_proc_name (name, &entry))
return MATCH_ERROR;
- gfc_enclosing_unit (&state);
- switch (state)
+ proc = gfc_current_block ();
+
+ if (state == COMP_SUBROUTINE)
{
- case COMP_SUBROUTINE:
+ /* An entry in a subroutine. */
m = gfc_match_formal_arglist (entry, 0, 1);
if (m != MATCH_YES)
return MATCH_ERROR;
- if (gfc_current_state () != COMP_SUBROUTINE)
- goto exec_construct;
-
- if (gfc_add_entry (&entry->attr, NULL) == FAILURE
- || gfc_add_subroutine (&entry->attr, NULL) == FAILURE)
+ if (gfc_add_entry (&entry->attr, entry->name, NULL) == FAILURE
+ || gfc_add_subroutine (&entry->attr, entry->name, NULL) == FAILURE)
return MATCH_ERROR;
-
- break;
-
- case COMP_FUNCTION:
- m = gfc_match_formal_arglist (entry, 0, 0);
+ }
+ else
+ {
+ /* An entry in a function. */
+ m = gfc_match_formal_arglist (entry, 0, 1);
if (m != MATCH_YES)
return MATCH_ERROR;
- if (gfc_current_state () != COMP_FUNCTION)
- goto exec_construct;
- function = gfc_state_stack->sym;
-
result = NULL;
if (gfc_match_eos () == MATCH_YES)
{
- if (gfc_add_entry (&entry->attr, NULL) == FAILURE
- || gfc_add_function (&entry->attr, NULL) == FAILURE)
+ if (gfc_add_entry (&entry->attr, entry->name, NULL) == FAILURE
+ || gfc_add_function (&entry->attr, entry->name, NULL) == FAILURE)
return MATCH_ERROR;
- entry->result = function->result;
-
+ entry->result = entry;
}
else
{
- m = match_result (function, &result);
+ m = match_result (proc, &result);
if (m == MATCH_NO)
gfc_syntax_error (ST_ENTRY);
if (m != MATCH_YES)
return MATCH_ERROR;
- if (gfc_add_result (&result->attr, NULL) == FAILURE
- || gfc_add_entry (&entry->attr, NULL) == FAILURE
- || gfc_add_function (&entry->attr, NULL) == FAILURE)
+ if (gfc_add_result (&result->attr, result->name, NULL) == FAILURE
+ || gfc_add_entry (&entry->attr, result->name, NULL) == FAILURE
+ || gfc_add_function (&entry->attr, result->name,
+ NULL) == FAILURE)
return MATCH_ERROR;
+
+ entry->result = result;
}
- if (function->attr.recursive && result == NULL)
+ if (proc->attr.recursive && result == NULL)
{
gfc_error ("RESULT attribute required in ENTRY statement at %C");
return MATCH_ERROR;
}
-
- break;
-
- default:
- goto exec_construct;
}
if (gfc_match_eos () != MATCH_YES)
return MATCH_ERROR;
}
- return MATCH_YES;
+ entry->attr.recursive = proc->attr.recursive;
+ entry->attr.elemental = proc->attr.elemental;
+ entry->attr.pure = proc->attr.pure;
+
+ el = gfc_get_entry_list ();
+ el->sym = entry;
+ el->next = gfc_current_ns->entries;
+ gfc_current_ns->entries = el;
+ if (el->next)
+ el->id = el->next->id + 1;
+ else
+ el->id = 1;
-exec_construct:
- gfc_error ("ENTRY statement at %C cannot appear within %s",
- gfc_state_name (gfc_current_state ()));
+ new_st.op = EXEC_ENTRY;
+ new_st.ext.entry = el;
- return MATCH_ERROR;
+ return MATCH_YES;
}
return MATCH_ERROR;
gfc_new_block = sym;
- if (gfc_add_subroutine (&sym->attr, NULL) == FAILURE)
+ if (gfc_add_subroutine (&sym->attr, sym->name, NULL) == FAILURE)
return MATCH_ERROR;
if (gfc_match_formal_arglist (sym, 0, 1) != MATCH_YES)
}
-/* Return nonzero if we're currenly compiling a contained procedure. */
+/* Return nonzero if we're currently compiling a contained procedure. */
static int
contained_procedure (void)
if (!eos_ok)
{
/* We would have required END [something] */
- gfc_error ("%s statement expected at %C",
- gfc_ascii_statement (*st));
+ gfc_error ("%s statement expected at %L",
+ gfc_ascii_statement (*st), &old_loc);
goto cleanup;
}
if ((current_attr.external || current_attr.intrinsic)
&& sym->attr.flavor != FL_PROCEDURE
- && gfc_add_flavor (&sym->attr, FL_PROCEDURE, NULL) == FAILURE)
+ && gfc_add_flavor (&sym->attr, FL_PROCEDURE, sym->name, NULL) == FAILURE)
{
m = MATCH_ERROR;
goto cleanup;
{
gfc_clear_attr (¤t_attr);
- gfc_add_dimension (¤t_attr, NULL);
+ gfc_add_dimension (¤t_attr, NULL, NULL);
return attr_decl ();
}
if (gfc_add_access (&sym->attr,
(st ==
ST_PUBLIC) ? ACCESS_PUBLIC : ACCESS_PRIVATE,
- NULL) == FAILURE)
+ sym->name, NULL) == FAILURE)
return MATCH_ERROR;
break;
}
if (gfc_check_assign_symbol (sym, init) == FAILURE
- || gfc_add_flavor (&sym->attr, FL_PARAMETER, NULL) == FAILURE)
+ || gfc_add_flavor (&sym->attr, FL_PARAMETER, sym->name, NULL) == FAILURE)
{
m = MATCH_ERROR;
goto cleanup;
}
+ if (sym->ts.type == BT_CHARACTER
+ && sym->ts.cl != NULL
+ && sym->ts.cl->length != NULL
+ && sym->ts.cl->length->expr_type == EXPR_CONSTANT
+ && init->expr_type == EXPR_CONSTANT
+ && init->ts.type == BT_CHARACTER
+ && init->ts.kind == 1)
+ gfc_set_constant_character_len (
+ mpz_get_si (sym->ts.cl->length->value.integer), init);
+
sym->value = init;
return MATCH_YES;
switch (m)
{
case MATCH_YES:
- if (gfc_add_save (&sym->attr, &gfc_current_locus) == FAILURE)
+ if (gfc_add_save (&sym->attr, sym->name,
+ &gfc_current_locus) == FAILURE)
return MATCH_ERROR;
goto next_item;
if (m == MATCH_NO)
goto syntax;
- c = gfc_get_common (n);
-
- if (c->use_assoc)
- {
- gfc_error("COMMON block '%s' at %C is already USE associated", n);
- return MATCH_ERROR;
- }
-
+ c = gfc_get_common (n, 0);
c->saved = 1;
gfc_current_ns->seen_save = 1;
/* Match a module procedure statement. Note that we have to modify
symbols in the parent's namespace because the current one was there
- to receive symbols that are in a interface's formal argument list. */
+ to receive symbols that are in an interface's formal argument list. */
match
gfc_match_modproc (void)
return MATCH_ERROR;
if (sym->attr.proc != PROC_MODULE
- && gfc_add_procedure (&sym->attr, PROC_MODULE, NULL) == FAILURE)
+ && gfc_add_procedure (&sym->attr, PROC_MODULE,
+ sym->name, NULL) == FAILURE)
return MATCH_ERROR;
if (gfc_add_interface (sym) == FAILURE)
return MATCH_ERROR;
}
- if (gfc_add_access (&attr, ACCESS_PRIVATE, NULL) == FAILURE)
+ if (gfc_add_access (&attr, ACCESS_PRIVATE, NULL, NULL) == FAILURE)
return MATCH_ERROR;
goto loop;
}
return MATCH_ERROR;
}
- if (gfc_add_access (&attr, ACCESS_PUBLIC, NULL) == FAILURE)
+ if (gfc_add_access (&attr, ACCESS_PUBLIC, NULL, NULL) == FAILURE)
return MATCH_ERROR;
goto loop;
}
components. The ways this can happen is via a function
definition, an INTRINSIC statement or a subtype in another
derived type that is a pointer. The first part of the AND clause
- is true if a the symbol is not the return value of a function. */
+ is true if a the symbol is not the return value of a function. */
if (sym->attr.flavor != FL_DERIVED
- && gfc_add_flavor (&sym->attr, FL_DERIVED, NULL) == FAILURE)
+ && gfc_add_flavor (&sym->attr, FL_DERIVED, sym->name, NULL) == FAILURE)
return MATCH_ERROR;
if (sym->components != NULL)
}
if (attr.access != ACCESS_UNKNOWN
- && gfc_add_access (&sym->attr, attr.access, NULL) == FAILURE)
+ && gfc_add_access (&sym->attr, attr.access, sym->name, NULL) == FAILURE)
return MATCH_ERROR;
gfc_new_block = sym;