1999-08-26 09:30:50 +00:00
|
|
|
|
/* sta.c -- Implementation File (module.c template V1.0)
|
2004-07-28 03:11:36 +00:00
|
|
|
|
Copyright (C) 1995, 1996, 1997, 2003 Free Software Foundation, Inc.
|
1999-10-16 06:09:09 +00:00
|
|
|
|
Contributed by James Craig Burley.
|
1999-08-26 09:30:50 +00:00
|
|
|
|
|
|
|
|
|
This file is part of GNU Fortran.
|
|
|
|
|
|
|
|
|
|
GNU Fortran 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 2, or (at your option)
|
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
|
|
GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
|
|
|
|
|
the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
|
02111-1307, USA.
|
|
|
|
|
|
|
|
|
|
Related Modules:
|
|
|
|
|
None
|
|
|
|
|
|
|
|
|
|
Description:
|
|
|
|
|
Analyzes the first two tokens, figures out what statements are
|
|
|
|
|
possible, tries parsing the possible statements by calling on
|
|
|
|
|
the ffestb functions.
|
|
|
|
|
|
|
|
|
|
Modifications:
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Include files. */
|
|
|
|
|
|
|
|
|
|
#include "proj.h"
|
|
|
|
|
#include "sta.h"
|
|
|
|
|
#include "bad.h"
|
|
|
|
|
#include "implic.h"
|
|
|
|
|
#include "lex.h"
|
|
|
|
|
#include "malloc.h"
|
|
|
|
|
#include "stb.h"
|
|
|
|
|
#include "stc.h"
|
|
|
|
|
#include "std.h"
|
|
|
|
|
#include "str.h"
|
|
|
|
|
#include "storag.h"
|
|
|
|
|
#include "symbol.h"
|
|
|
|
|
|
|
|
|
|
/* Externals defined here. */
|
|
|
|
|
|
|
|
|
|
ffelexToken ffesta_tokens[FFESTA_tokensMAX]; /* For use by a possible. */
|
|
|
|
|
ffestrFirst ffesta_first_kw; /* First NAME(S) looked up. */
|
|
|
|
|
ffestrSecond ffesta_second_kw; /* Second NAME(S) looked up. */
|
|
|
|
|
mallocPool ffesta_output_pool; /* Pool for results of stmt handling. */
|
|
|
|
|
mallocPool ffesta_scratch_pool; /* Pool for stmt scratch handling. */
|
|
|
|
|
ffelexToken ffesta_construct_name;
|
|
|
|
|
ffelexToken ffesta_label_token; /* Pending label stuff. */
|
|
|
|
|
bool ffesta_seen_first_exec;
|
|
|
|
|
bool ffesta_is_entry_valid = FALSE; /* TRUE only in SUBROUTINE/FUNCTION. */
|
|
|
|
|
bool ffesta_line_has_semicolons = FALSE;
|
|
|
|
|
|
|
|
|
|
/* Simple definitions and enumerations. */
|
|
|
|
|
|
|
|
|
|
#define FFESTA_ABORT_ON_CONFIRM_ 1 /* 0=slow, tested way; 1=faster way
|
|
|
|
|
that might not always work. Here's
|
|
|
|
|
the old description of what used
|
|
|
|
|
to not work with ==1: (try
|
|
|
|
|
"CONTINUE\10
|
|
|
|
|
FORMAT('hi',I11)\END"). Problem
|
|
|
|
|
is that the "topology" of the
|
|
|
|
|
confirmed stmt's tokens with
|
|
|
|
|
regard to CHARACTER, HOLLERITH,
|
|
|
|
|
NAME/NAMES/NUMBER tokens (like hex
|
|
|
|
|
numbers), isn't traced if we abort
|
|
|
|
|
early, then other stmts might get
|
|
|
|
|
their grubby hands on those
|
|
|
|
|
unprocessed tokens and commit them
|
|
|
|
|
improperly. Ideal fix is to rerun
|
|
|
|
|
the confirmed stmt and forget the
|
|
|
|
|
rest. */
|
|
|
|
|
|
|
|
|
|
#define FFESTA_maxPOSSIBLES_ 8/* Never more than this # of possibles. */
|
|
|
|
|
|
|
|
|
|
/* Internal typedefs. */
|
|
|
|
|
|
|
|
|
|
typedef struct _ffesta_possible_ *ffestaPossible_;
|
|
|
|
|
|
|
|
|
|
/* Private include files. */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Internal structure definitions. */
|
|
|
|
|
|
|
|
|
|
struct _ffesta_possible_
|
|
|
|
|
{
|
|
|
|
|
ffestaPossible_ next;
|
|
|
|
|
ffestaPossible_ previous;
|
|
|
|
|
ffelexHandler handler;
|
|
|
|
|
bool named;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _ffesta_possible_root_
|
|
|
|
|
{
|
|
|
|
|
ffestaPossible_ first;
|
|
|
|
|
ffestaPossible_ last;
|
|
|
|
|
ffelexHandler nil;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Static objects accessed by functions in this module. */
|
|
|
|
|
|
|
|
|
|
static bool ffesta_is_inhibited_ = FALSE;
|
|
|
|
|
static ffelexToken ffesta_token_0_; /* For use by ffest possibility
|
|
|
|
|
handling. */
|
|
|
|
|
static ffestaPossible_ ffesta_possibles_[FFESTA_maxPOSSIBLES_];
|
|
|
|
|
static int ffesta_num_possibles_ = 0; /* Number of possibilities. */
|
|
|
|
|
static struct _ffesta_possible_root_ ffesta_possible_nonexecs_;
|
|
|
|
|
static struct _ffesta_possible_root_ ffesta_possible_execs_;
|
|
|
|
|
static ffestaPossible_ ffesta_current_possible_;
|
|
|
|
|
static ffelexHandler ffesta_current_handler_;
|
|
|
|
|
static bool ffesta_confirmed_current_ = FALSE;
|
|
|
|
|
static bool ffesta_confirmed_other_ = FALSE;
|
|
|
|
|
static ffestaPossible_ ffesta_confirmed_possible_;
|
|
|
|
|
static bool ffesta_current_shutdown_ = FALSE;
|
|
|
|
|
#if !FFESTA_ABORT_ON_CONFIRM_
|
|
|
|
|
static bool ffesta_is_two_into_statement_ = FALSE; /* For IF, WHERE stmts. */
|
|
|
|
|
static ffelexToken ffesta_twotokens_1_; /* For IF, WHERE stmts. */
|
|
|
|
|
static ffelexToken ffesta_twotokens_2_; /* For IF, WHERE stmts. */
|
|
|
|
|
#endif
|
|
|
|
|
static ffestaPooldisp ffesta_outpooldisp_; /* After statement dealt
|
|
|
|
|
with. */
|
|
|
|
|
static bool ffesta_inhibit_confirmation_ = FALSE;
|
|
|
|
|
|
|
|
|
|
/* Static functions (internal). */
|
|
|
|
|
|
|
|
|
|
static void ffesta_add_possible_ (ffelexHandler fn, bool exec, bool named);
|
|
|
|
|
static bool ffesta_inhibited_exec_transition_ (void);
|
|
|
|
|
static void ffesta_reset_possibles_ (void);
|
|
|
|
|
static ffelexHandler ffesta_save_ (ffelexToken t);
|
|
|
|
|
static ffelexHandler ffesta_second_ (ffelexToken t);
|
|
|
|
|
#if !FFESTA_ABORT_ON_CONFIRM_
|
|
|
|
|
static ffelexHandler ffesta_send_two_ (ffelexToken t);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Internal macros. */
|
|
|
|
|
|
|
|
|
|
#define ffesta_add_possible_exec_(fn) (ffesta_add_possible_ (fn, TRUE, TRUE))
|
|
|
|
|
#define ffesta_add_possible_nonexec_(fn) (ffesta_add_possible_ (fn, FALSE, TRUE))
|
|
|
|
|
#define ffesta_add_possible_unnamed_exec_(fn) (ffesta_add_possible_ (fn, TRUE, FALSE))
|
|
|
|
|
#define ffesta_add_possible_unnamed_nonexec_(fn) (ffesta_add_possible_ (fn, FALSE, FALSE))
|
|
|
|
|
|
|
|
|
|
/* Add possible statement to appropriate list. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ffesta_add_possible_ (ffelexHandler fn, bool exec, bool named)
|
|
|
|
|
{
|
|
|
|
|
ffestaPossible_ p;
|
|
|
|
|
|
|
|
|
|
assert (ffesta_num_possibles_ < FFESTA_maxPOSSIBLES_);
|
|
|
|
|
|
|
|
|
|
p = ffesta_possibles_[ffesta_num_possibles_++];
|
|
|
|
|
|
|
|
|
|
if (exec)
|
|
|
|
|
{
|
|
|
|
|
p->next = (ffestaPossible_) &ffesta_possible_execs_.first;
|
|
|
|
|
p->previous = ffesta_possible_execs_.last;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
p->next = (ffestaPossible_) &ffesta_possible_nonexecs_.first;
|
|
|
|
|
p->previous = ffesta_possible_nonexecs_.last;
|
|
|
|
|
}
|
|
|
|
|
p->next->previous = p;
|
|
|
|
|
p->previous->next = p;
|
|
|
|
|
|
|
|
|
|
p->handler = fn;
|
|
|
|
|
p->named = named;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_inhibited_exec_transition_ -- Do exec transition while inhibited
|
|
|
|
|
|
|
|
|
|
if (!ffesta_inhibited_exec_transition_()) // couldn't transition...
|
|
|
|
|
|
|
|
|
|
Invokes ffestc_exec_transition, but first enables ffebad and ffesta and
|
|
|
|
|
afterwards disables them again. Then returns the result of the
|
|
|
|
|
invocation of ffestc_exec_transition. */
|
|
|
|
|
|
|
|
|
|
static bool
|
2004-07-28 03:11:36 +00:00
|
|
|
|
ffesta_inhibited_exec_transition_ (void)
|
1999-08-26 09:30:50 +00:00
|
|
|
|
{
|
|
|
|
|
bool result;
|
|
|
|
|
|
|
|
|
|
assert (ffebad_inhibit ());
|
|
|
|
|
assert (ffesta_is_inhibited_);
|
|
|
|
|
|
|
|
|
|
ffebad_set_inhibit (FALSE);
|
|
|
|
|
ffesta_is_inhibited_ = FALSE;
|
|
|
|
|
|
|
|
|
|
result = ffestc_exec_transition ();
|
|
|
|
|
|
|
|
|
|
ffebad_set_inhibit (TRUE);
|
|
|
|
|
ffesta_is_inhibited_ = TRUE;
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_reset_possibles_ -- Reset (clear) lists of possible statements
|
|
|
|
|
|
|
|
|
|
ffesta_reset_possibles_();
|
|
|
|
|
|
|
|
|
|
Clears the lists of executable and nonexecutable statements. */
|
|
|
|
|
|
|
|
|
|
static void
|
2004-07-28 03:11:36 +00:00
|
|
|
|
ffesta_reset_possibles_ (void)
|
1999-08-26 09:30:50 +00:00
|
|
|
|
{
|
|
|
|
|
ffesta_num_possibles_ = 0;
|
|
|
|
|
|
|
|
|
|
ffesta_possible_execs_.first = ffesta_possible_execs_.last
|
|
|
|
|
= (ffestaPossible_) &ffesta_possible_execs_.first;
|
|
|
|
|
ffesta_possible_nonexecs_.first = ffesta_possible_nonexecs_.last
|
|
|
|
|
= (ffestaPossible_) &ffesta_possible_nonexecs_.first;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_save_ -- Save token on list, pass thru to current handler
|
|
|
|
|
|
|
|
|
|
return ffesta_save_; // to lexer.
|
|
|
|
|
|
|
|
|
|
Receives a token from the lexer. Saves it in the list of tokens. Calls
|
|
|
|
|
the current handler with the token.
|
|
|
|
|
|
|
|
|
|
If no shutdown error occurred (via
|
|
|
|
|
ffest_ffebad_start), then if the token was EOS or SEMICOLON, mark the
|
|
|
|
|
current possible as successful and confirmed but try the next possible
|
|
|
|
|
anyway until ambiguities in the form handling are ironed out. */
|
|
|
|
|
|
|
|
|
|
static ffelexHandler
|
|
|
|
|
ffesta_save_ (ffelexToken t)
|
|
|
|
|
{
|
|
|
|
|
static ffelexToken *saved_tokens = NULL; /* A variable-sized array. */
|
|
|
|
|
static unsigned int num_saved_tokens = 0; /* Number currently saved. */
|
|
|
|
|
static unsigned int max_saved_tokens = 0; /* Maximum to be saved. */
|
|
|
|
|
unsigned int toknum; /* Index into saved_tokens array. */
|
|
|
|
|
ffelexToken eos; /* EOS created on-the-fly for shutdown
|
|
|
|
|
purposes. */
|
|
|
|
|
ffelexToken t2; /* Another temporary token (no intersect with
|
|
|
|
|
eos, btw). */
|
|
|
|
|
|
|
|
|
|
/* Save the current token. */
|
|
|
|
|
|
|
|
|
|
if (saved_tokens == NULL)
|
|
|
|
|
{
|
|
|
|
|
saved_tokens
|
2004-07-28 03:11:36 +00:00
|
|
|
|
= malloc_new_ksr (malloc_pool_image (), "FFEST Saved Tokens",
|
|
|
|
|
(max_saved_tokens = 8) * sizeof (ffelexToken));
|
1999-08-26 09:30:50 +00:00
|
|
|
|
/* Start off with 8. */
|
|
|
|
|
}
|
|
|
|
|
else if (num_saved_tokens >= max_saved_tokens)
|
|
|
|
|
{
|
|
|
|
|
toknum = max_saved_tokens;
|
|
|
|
|
max_saved_tokens <<= 1; /* Multiply by two. */
|
|
|
|
|
assert (max_saved_tokens > toknum);
|
|
|
|
|
saved_tokens
|
2004-07-28 03:11:36 +00:00
|
|
|
|
= malloc_resize_ksr (malloc_pool_image (), saved_tokens,
|
|
|
|
|
max_saved_tokens * sizeof (ffelexToken),
|
|
|
|
|
toknum * sizeof (ffelexToken));
|
1999-08-26 09:30:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*(saved_tokens + num_saved_tokens++) = ffelex_token_use (t);
|
|
|
|
|
|
|
|
|
|
/* Transmit the current token to the current handler. */
|
|
|
|
|
|
|
|
|
|
ffesta_current_handler_ = (ffelexHandler) (*ffesta_current_handler_) (t);
|
|
|
|
|
|
|
|
|
|
/* See if this possible has been shut down, or confirmed in which case we
|
|
|
|
|
might as well shut it down anyway to save time. */
|
|
|
|
|
|
|
|
|
|
if ((ffesta_current_shutdown_ || (FFESTA_ABORT_ON_CONFIRM_
|
|
|
|
|
&& ffesta_confirmed_current_))
|
|
|
|
|
&& !ffelex_expecting_character ())
|
|
|
|
|
{
|
|
|
|
|
switch (ffelex_token_type (t))
|
|
|
|
|
{
|
|
|
|
|
case FFELEX_typeEOS:
|
|
|
|
|
case FFELEX_typeSEMICOLON:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
eos = ffelex_token_new_eos (ffelex_token_where_line (t),
|
|
|
|
|
ffelex_token_where_column (t));
|
|
|
|
|
ffesta_inhibit_confirmation_ = ffesta_current_shutdown_;
|
|
|
|
|
(*ffesta_current_handler_) (eos);
|
|
|
|
|
ffesta_inhibit_confirmation_ = FALSE;
|
|
|
|
|
ffelex_token_kill (eos);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* If this is an EOS or SEMICOLON token, switch to next handler, else
|
|
|
|
|
return self as next handler for lexer. */
|
|
|
|
|
|
|
|
|
|
switch (ffelex_token_type (t))
|
|
|
|
|
{
|
|
|
|
|
case FFELEX_typeEOS:
|
|
|
|
|
case FFELEX_typeSEMICOLON:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return (ffelexHandler) ffesta_save_;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next_handler: /* :::::::::::::::::::: */
|
|
|
|
|
|
|
|
|
|
/* Note that a shutdown also happens after seeing the first two tokens
|
|
|
|
|
after "IF (expr)" or "WHERE (expr)" where a statement follows, even
|
|
|
|
|
though there is no error. This causes the IF or WHERE form to be
|
|
|
|
|
implemented first before ffest_first is called for the first token in
|
|
|
|
|
the following statement. */
|
|
|
|
|
|
|
|
|
|
if (ffesta_current_shutdown_)
|
|
|
|
|
ffesta_current_shutdown_ = FALSE; /* Only after sending EOS! */
|
|
|
|
|
else
|
|
|
|
|
assert (ffesta_confirmed_current_);
|
|
|
|
|
|
|
|
|
|
if (ffesta_confirmed_current_)
|
|
|
|
|
{
|
|
|
|
|
ffesta_confirmed_current_ = FALSE;
|
|
|
|
|
ffesta_confirmed_other_ = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pick next handler. */
|
|
|
|
|
|
|
|
|
|
ffesta_current_possible_ = ffesta_current_possible_->next;
|
|
|
|
|
ffesta_current_handler_ = ffesta_current_possible_->handler;
|
|
|
|
|
if (ffesta_current_handler_ == NULL)
|
|
|
|
|
{ /* No handler in this list, try exec list if
|
|
|
|
|
not tried yet. */
|
|
|
|
|
if (ffesta_current_possible_
|
2004-07-28 03:11:36 +00:00
|
|
|
|
== (ffestaPossible_) &ffesta_possible_nonexecs_.first)
|
1999-08-26 09:30:50 +00:00
|
|
|
|
{
|
|
|
|
|
ffesta_current_possible_ = ffesta_possible_execs_.first;
|
|
|
|
|
ffesta_current_handler_ = ffesta_current_possible_->handler;
|
|
|
|
|
}
|
|
|
|
|
if ((ffesta_current_handler_ == NULL)
|
|
|
|
|
|| (!ffesta_seen_first_exec
|
|
|
|
|
&& ((ffesta_confirmed_possible_ != NULL)
|
|
|
|
|
|| !ffesta_inhibited_exec_transition_ ())))
|
|
|
|
|
/* Don't run execs if: (decoding the "if" ^^^ up here ^^^) - we
|
|
|
|
|
have no exec handler available, or - we haven't seen the first
|
|
|
|
|
executable statement yet, and - we've confirmed a nonexec
|
|
|
|
|
(otherwise even a nonexec would cause a transition), or - a
|
|
|
|
|
nonexec-to-exec transition can't be made at the statement context
|
|
|
|
|
level (as in an executable statement in the middle of a STRUCTURE
|
|
|
|
|
definition); if it can be made, ffestc_exec_transition makes the
|
|
|
|
|
corresponding transition at the statement state level so
|
|
|
|
|
specification statements are no longer accepted following an
|
|
|
|
|
unrecognized statement. (Note: it is valid for f_e_t_ to decide
|
|
|
|
|
to always return TRUE by "shrieking" away the statement state
|
|
|
|
|
stack until a transitionable state is reached. Or it can leave
|
|
|
|
|
the stack as is and return FALSE.)
|
|
|
|
|
|
|
|
|
|
If we decide not to run execs, enter this block to rerun the
|
|
|
|
|
confirmed statement, if any. */
|
|
|
|
|
{ /* At end of both lists! Pick confirmed or
|
|
|
|
|
first possible. */
|
|
|
|
|
ffebad_set_inhibit (FALSE);
|
|
|
|
|
ffesta_is_inhibited_ = FALSE;
|
|
|
|
|
ffesta_confirmed_other_ = FALSE;
|
|
|
|
|
ffesta_tokens[0] = ffesta_token_0_;
|
|
|
|
|
if (ffesta_confirmed_possible_ == NULL)
|
|
|
|
|
{ /* No confirmed success, just use first
|
|
|
|
|
named possible, or first possible if
|
|
|
|
|
no named possibles. */
|
|
|
|
|
ffestaPossible_ possible = ffesta_possible_nonexecs_.first;
|
|
|
|
|
ffestaPossible_ first = NULL;
|
|
|
|
|
ffestaPossible_ first_named = NULL;
|
|
|
|
|
ffestaPossible_ first_exec = NULL;
|
|
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
if (possible->handler == NULL)
|
|
|
|
|
{
|
2004-07-28 03:11:36 +00:00
|
|
|
|
if (possible == (ffestaPossible_) &ffesta_possible_nonexecs_.first)
|
1999-08-26 09:30:50 +00:00
|
|
|
|
{
|
|
|
|
|
possible = first_exec = ffesta_possible_execs_.first;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (first == NULL)
|
|
|
|
|
first = possible;
|
|
|
|
|
if (possible->named
|
|
|
|
|
&& (first_named == NULL))
|
|
|
|
|
first_named = possible;
|
|
|
|
|
|
|
|
|
|
possible = possible->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (first_named != NULL)
|
|
|
|
|
ffesta_current_possible_ = first_named;
|
|
|
|
|
else if (ffesta_seen_first_exec
|
|
|
|
|
&& (first_exec != NULL))
|
|
|
|
|
ffesta_current_possible_ = first_exec;
|
|
|
|
|
else
|
|
|
|
|
ffesta_current_possible_ = first;
|
|
|
|
|
|
|
|
|
|
ffesta_current_handler_ = ffesta_current_possible_->handler;
|
|
|
|
|
assert (ffesta_current_handler_ != NULL);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ /* Confirmed success, use it. */
|
|
|
|
|
ffesta_current_possible_ = ffesta_confirmed_possible_;
|
|
|
|
|
ffesta_current_handler_ = ffesta_confirmed_possible_->handler;
|
|
|
|
|
}
|
|
|
|
|
ffesta_reset_possibles_ ();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ /* Switching from [empty?] list of nonexecs
|
|
|
|
|
to nonempty list of execs at this point. */
|
|
|
|
|
ffesta_tokens[0] = ffelex_token_use (ffesta_token_0_);
|
|
|
|
|
ffesymbol_set_retractable (ffesta_scratch_pool);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ffesta_tokens[0] = ffelex_token_use (ffesta_token_0_);
|
|
|
|
|
ffesymbol_set_retractable (ffesta_scratch_pool);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Send saved tokens to current handler until either shut down or all
|
|
|
|
|
tokens sent. */
|
|
|
|
|
|
|
|
|
|
for (toknum = 0; toknum < num_saved_tokens; ++toknum)
|
|
|
|
|
{
|
|
|
|
|
t = *(saved_tokens + toknum);
|
|
|
|
|
switch (ffelex_token_type (t))
|
|
|
|
|
{
|
|
|
|
|
case FFELEX_typeCHARACTER:
|
|
|
|
|
ffelex_set_expecting_hollerith (0, '\0',
|
|
|
|
|
ffewhere_line_unknown (),
|
|
|
|
|
ffewhere_column_unknown ());
|
|
|
|
|
ffesta_current_handler_
|
|
|
|
|
= (ffelexHandler) (*ffesta_current_handler_) (t);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFELEX_typeNAMES:
|
|
|
|
|
if (ffelex_is_names_expected ())
|
|
|
|
|
ffesta_current_handler_
|
|
|
|
|
= (ffelexHandler) (*ffesta_current_handler_) (t);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
t2 = ffelex_token_name_from_names (t, 0, 0);
|
|
|
|
|
ffesta_current_handler_
|
|
|
|
|
= (ffelexHandler) (*ffesta_current_handler_) (t2);
|
|
|
|
|
ffelex_token_kill (t2);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ffesta_current_handler_
|
|
|
|
|
= (ffelexHandler) (*ffesta_current_handler_) (t);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ffesta_is_inhibited_)
|
|
|
|
|
ffelex_token_kill (t); /* Won't need this any more. */
|
|
|
|
|
|
|
|
|
|
/* See if this possible has been shut down. */
|
|
|
|
|
|
|
|
|
|
else if ((ffesta_current_shutdown_ || (FFESTA_ABORT_ON_CONFIRM_
|
|
|
|
|
&& ffesta_confirmed_current_))
|
|
|
|
|
&& !ffelex_expecting_character ())
|
|
|
|
|
{
|
|
|
|
|
switch (ffelex_token_type (t))
|
|
|
|
|
{
|
|
|
|
|
case FFELEX_typeEOS:
|
|
|
|
|
case FFELEX_typeSEMICOLON:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
eos = ffelex_token_new_eos (ffelex_token_where_line (t),
|
|
|
|
|
ffelex_token_where_column (t));
|
|
|
|
|
ffesta_inhibit_confirmation_ = ffesta_current_shutdown_;
|
|
|
|
|
(*ffesta_current_handler_) (eos);
|
|
|
|
|
ffesta_inhibit_confirmation_ = FALSE;
|
|
|
|
|
ffelex_token_kill (eos);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
goto next_handler; /* :::::::::::::::::::: */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Finished sending all the tokens so far. If still trying possibilities,
|
|
|
|
|
then if we've just sent an EOS or SEMICOLON token through, go to the
|
|
|
|
|
next handler. Otherwise, return self so we can gather and process more
|
|
|
|
|
tokens. */
|
|
|
|
|
|
|
|
|
|
if (ffesta_is_inhibited_)
|
|
|
|
|
{
|
|
|
|
|
switch (ffelex_token_type (t))
|
|
|
|
|
{
|
|
|
|
|
case FFELEX_typeEOS:
|
|
|
|
|
case FFELEX_typeSEMICOLON:
|
|
|
|
|
goto next_handler; /* :::::::::::::::::::: */
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
#if FFESTA_ABORT_ON_CONFIRM_
|
|
|
|
|
assert (!ffesta_confirmed_other_); /* Catch ambiguities. */
|
|
|
|
|
#endif
|
|
|
|
|
return (ffelexHandler) ffesta_save_;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This was the one final possibility, uninhibited, so send the final
|
|
|
|
|
handler it sent. */
|
|
|
|
|
|
|
|
|
|
num_saved_tokens = 0;
|
|
|
|
|
#if !FFESTA_ABORT_ON_CONFIRM_
|
|
|
|
|
if (ffesta_is_two_into_statement_)
|
|
|
|
|
{ /* End of the line for the previous two
|
|
|
|
|
tokens, resurrect them. */
|
|
|
|
|
ffelexHandler next;
|
|
|
|
|
|
|
|
|
|
ffesta_is_two_into_statement_ = FALSE;
|
|
|
|
|
next = (ffelexHandler) ffesta_first (ffesta_twotokens_1_);
|
|
|
|
|
ffelex_token_kill (ffesta_twotokens_1_);
|
|
|
|
|
next = (ffelexHandler) (*next) (ffesta_twotokens_2_);
|
|
|
|
|
ffelex_token_kill (ffesta_twotokens_2_);
|
|
|
|
|
return (ffelexHandler) next;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
assert (ffesta_current_handler_ != NULL);
|
|
|
|
|
return (ffelexHandler) ffesta_current_handler_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_second_ -- Parse the token after a NAME/NAMES in a statement
|
|
|
|
|
|
|
|
|
|
return ffesta_second_; // to lexer.
|
|
|
|
|
|
|
|
|
|
The second token cannot be a NAMES, since the first token is a NAME or
|
|
|
|
|
NAMES. If the second token is a NAME, look up its name in the list of
|
|
|
|
|
second names for use by whoever needs it.
|
|
|
|
|
|
|
|
|
|
Then make a list of all the possible statements this could be, based on
|
|
|
|
|
looking at the first two tokens. Two lists of possible statements are
|
|
|
|
|
created, one consisting of nonexecutable statements, the other consisting
|
|
|
|
|
of executable statements.
|
|
|
|
|
|
|
|
|
|
If the total number of possibilities is one, just fire up that
|
|
|
|
|
possibility by calling its handler function, passing the first two
|
|
|
|
|
tokens through it and so on.
|
|
|
|
|
|
|
|
|
|
Otherwise, start up a process whereby tokens are passed to the first
|
|
|
|
|
possibility on the list until EOS or SEMICOLON is reached or an error
|
|
|
|
|
is detected. But inhibit any actual reporting of errors; just record
|
|
|
|
|
their existence in the list. If EOS or SEMICOLON is reached with no
|
|
|
|
|
errors (other than non-form errors happening downstream, such as an
|
|
|
|
|
overflowing value for an integer or a GOTO statement identifying a label
|
|
|
|
|
on a FORMAT statement), then that is the only possible statement. Rerun
|
|
|
|
|
the statement with error-reporting turned on if any non-form errors were
|
|
|
|
|
generated, otherwise just use its results, then erase the list of tokens
|
|
|
|
|
memorized during the search process. If a form error occurs, immediately
|
|
|
|
|
cancel that possibility by sending EOS as the next token, remember the
|
|
|
|
|
error code for that possibility, and try the next possibility on the list,
|
|
|
|
|
first sending it the list of tokens memorized while handling the first
|
|
|
|
|
possibility, then continuing on as before.
|
|
|
|
|
|
|
|
|
|
Ultimately, either the end of the list of possibilities will be reached
|
|
|
|
|
without any successful forms being detected, in which case we pick one
|
|
|
|
|
based on hueristics (usually the first possibility) and rerun it with
|
|
|
|
|
error reporting turned on using the list of memorized tokens so the user
|
|
|
|
|
sees the error, or one of the possibilities will effectively succeed. */
|
|
|
|
|
|
|
|
|
|
static ffelexHandler
|
|
|
|
|
ffesta_second_ (ffelexToken t)
|
|
|
|
|
{
|
|
|
|
|
ffelexHandler next;
|
|
|
|
|
ffesymbol s;
|
|
|
|
|
|
|
|
|
|
assert (ffelex_token_type (t) != FFELEX_typeNAMES);
|
|
|
|
|
|
|
|
|
|
if (ffelex_token_type (t) == FFELEX_typeNAME)
|
|
|
|
|
ffesta_second_kw = ffestr_second (t);
|
|
|
|
|
|
|
|
|
|
/* Here we use switch on the first keyword name and handle each possible
|
|
|
|
|
recognizable name by looking at the second token, and building the list
|
|
|
|
|
of possible names accordingly. For now, just put every possible
|
|
|
|
|
statement on the list for ambiguity checking. */
|
|
|
|
|
|
|
|
|
|
switch (ffesta_first_kw)
|
|
|
|
|
{
|
|
|
|
|
case FFESTR_firstASSIGN:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R838);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstBACKSPACE:
|
|
|
|
|
ffestb_args.beru.len = FFESTR_firstlBACKSPACE;
|
|
|
|
|
ffestb_args.beru.badname = "BACKSPACE";
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_beru);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstBLOCK:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_block);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstBLOCKDATA:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_blockdata);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstBYTE:
|
|
|
|
|
ffestb_args.decl.len = FFESTR_firstlBYTE;
|
|
|
|
|
ffestb_args.decl.type = FFESTP_typeBYTE;
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_gentype);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstCALL:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R1212);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstCASE:
|
|
|
|
|
case FFESTR_firstCASEDEFAULT:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R810);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstCHRCTR:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_chartype);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstCLOSE:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R907);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstCOMMON:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R547);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstCMPLX:
|
|
|
|
|
ffestb_args.decl.len = FFESTR_firstlCMPLX;
|
|
|
|
|
ffestb_args.decl.type = FFESTP_typeCOMPLEX;
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_gentype);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstCONTINUE:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R841);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstCYCLE:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R834);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstDATA:
|
|
|
|
|
if (ffe_is_pedantic_not_90 ())
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R528);
|
|
|
|
|
else
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R528);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstDIMENSION:
|
|
|
|
|
ffestb_args.R524.len = FFESTR_firstlDIMENSION;
|
|
|
|
|
ffestb_args.R524.badname = "DIMENSION";
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R524);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstDO:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_do);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstDBL:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_double);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstDBLCMPLX:
|
|
|
|
|
ffestb_args.decl.len = FFESTR_firstlDBLCMPLX;
|
|
|
|
|
ffestb_args.decl.type = FFESTP_typeDBLCMPLX;
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_dbltype);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstDBLPRCSN:
|
|
|
|
|
ffestb_args.decl.len = FFESTR_firstlDBLPRCSN;
|
|
|
|
|
ffestb_args.decl.type = FFESTP_typeDBLPRCSN;
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_dbltype);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstDOWHILE:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_dowhile);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstELSE:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_else);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstELSEIF:
|
|
|
|
|
ffestb_args.elsexyz.second = FFESTR_secondIF;
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_elsexyz);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstEND:
|
|
|
|
|
if ((ffelex_token_type (ffesta_token_0_) == FFELEX_typeNAMES)
|
|
|
|
|
|| (ffelex_token_type (t) != FFELEX_typeNAME))
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_end);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (ffesta_second_kw)
|
|
|
|
|
{
|
|
|
|
|
case FFESTR_secondBLOCK:
|
|
|
|
|
case FFESTR_secondBLOCKDATA:
|
|
|
|
|
case FFESTR_secondDO:
|
|
|
|
|
case FFESTR_secondFILE:
|
|
|
|
|
case FFESTR_secondFUNCTION:
|
|
|
|
|
case FFESTR_secondIF:
|
|
|
|
|
case FFESTR_secondPROGRAM:
|
|
|
|
|
case FFESTR_secondSELECT:
|
|
|
|
|
case FFESTR_secondSUBROUTINE:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_end);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_end);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstENDBLOCK:
|
|
|
|
|
ffestb_args.endxyz.len = FFESTR_firstlENDBLOCK;
|
|
|
|
|
ffestb_args.endxyz.second = FFESTR_secondBLOCK;
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstENDBLOCKDATA:
|
|
|
|
|
ffestb_args.endxyz.len = FFESTR_firstlENDBLOCKDATA;
|
|
|
|
|
ffestb_args.endxyz.second = FFESTR_secondBLOCKDATA;
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstENDDO:
|
|
|
|
|
ffestb_args.endxyz.len = FFESTR_firstlENDDO;
|
|
|
|
|
ffestb_args.endxyz.second = FFESTR_secondDO;
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstENDFILE:
|
|
|
|
|
ffestb_args.beru.len = FFESTR_firstlENDFILE;
|
|
|
|
|
ffestb_args.beru.badname = "ENDFILE";
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_beru);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstENDFUNCTION:
|
|
|
|
|
ffestb_args.endxyz.len = FFESTR_firstlENDFUNCTION;
|
|
|
|
|
ffestb_args.endxyz.second = FFESTR_secondFUNCTION;
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstENDIF:
|
|
|
|
|
ffestb_args.endxyz.len = FFESTR_firstlENDIF;
|
|
|
|
|
ffestb_args.endxyz.second = FFESTR_secondIF;
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstENDPROGRAM:
|
|
|
|
|
ffestb_args.endxyz.len = FFESTR_firstlENDPROGRAM;
|
|
|
|
|
ffestb_args.endxyz.second = FFESTR_secondPROGRAM;
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstENDSELECT:
|
|
|
|
|
ffestb_args.endxyz.len = FFESTR_firstlENDSELECT;
|
|
|
|
|
ffestb_args.endxyz.second = FFESTR_secondSELECT;
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstENDSUBROUTINE:
|
|
|
|
|
ffestb_args.endxyz.len = FFESTR_firstlENDSUBROUTINE;
|
|
|
|
|
ffestb_args.endxyz.second = FFESTR_secondSUBROUTINE;
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstENTRY:
|
|
|
|
|
ffestb_args.dummy.len = FFESTR_firstlENTRY;
|
|
|
|
|
ffestb_args.dummy.badname = "ENTRY";
|
|
|
|
|
ffestb_args.dummy.is_subr = ffestc_is_entry_in_subr ();
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_dummy);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstEQUIVALENCE:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R544);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstEXIT:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R835);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstEXTERNAL:
|
|
|
|
|
ffestb_args.varlist.len = FFESTR_firstlEXTERNAL;
|
|
|
|
|
ffestb_args.varlist.badname = "EXTERNAL";
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_varlist);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* WARNING: don't put anything that might cause an item to precede
|
|
|
|
|
FORMAT in the list of possible statements (it's added below) without
|
|
|
|
|
making sure FORMAT still is first. It has to run with
|
|
|
|
|
ffelex_set_names_pure(TRUE), to make sure the lexer delivers NAMES
|
|
|
|
|
tokens. */
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstFORMAT:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R1001);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstFUNCTION:
|
|
|
|
|
ffestb_args.dummy.len = FFESTR_firstlFUNCTION;
|
|
|
|
|
ffestb_args.dummy.badname = "FUNCTION";
|
|
|
|
|
ffestb_args.dummy.is_subr = FALSE;
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_dummy);
|
|
|
|
|
break;
|
|
|
|
|
|
2004-07-28 03:11:36 +00:00
|
|
|
|
case FFESTR_firstGO:
|
|
|
|
|
if ((ffelex_token_type (ffesta_token_0_) == FFELEX_typeNAMES)
|
|
|
|
|
|| (ffelex_token_type (t) != FFELEX_typeNAME))
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_goto);
|
|
|
|
|
else
|
|
|
|
|
switch (ffesta_second_kw)
|
|
|
|
|
{
|
|
|
|
|
case FFESTR_secondTO:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_goto);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_goto);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
1999-08-26 09:30:50 +00:00
|
|
|
|
case FFESTR_firstGOTO:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_goto);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstIF:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_if);
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R840);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstIMPLICIT:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_R539);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstINCLUDE:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_S3P4);
|
|
|
|
|
switch (ffelex_token_type (t))
|
|
|
|
|
{
|
|
|
|
|
case FFELEX_typeNUMBER:
|
|
|
|
|
case FFELEX_typeNAME:
|
|
|
|
|
case FFELEX_typeAPOSTROPHE:
|
|
|
|
|
case FFELEX_typeQUOTE:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstINQUIRE:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R923);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstINTGR:
|
|
|
|
|
ffestb_args.decl.len = FFESTR_firstlINTGR;
|
|
|
|
|
ffestb_args.decl.type = FFESTP_typeINTEGER;
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_gentype);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstINTRINSIC:
|
|
|
|
|
ffestb_args.varlist.len = FFESTR_firstlINTRINSIC;
|
|
|
|
|
ffestb_args.varlist.badname = "INTRINSIC";
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_varlist);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstLGCL:
|
|
|
|
|
ffestb_args.decl.len = FFESTR_firstlLGCL;
|
|
|
|
|
ffestb_args.decl.type = FFESTP_typeLOGICAL;
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_gentype);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstNAMELIST:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R542);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstOPEN:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R904);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstPARAMETER:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R537);
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_V027);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstPAUSE:
|
|
|
|
|
ffestb_args.halt.len = FFESTR_firstlPAUSE;
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_halt);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstPRINT:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R911);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstPROGRAM:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R1102);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstREAD:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R909);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstREAL:
|
|
|
|
|
ffestb_args.decl.len = FFESTR_firstlREAL;
|
|
|
|
|
ffestb_args.decl.type = FFESTP_typeREAL;
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_gentype);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstRETURN:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R1227);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstREWIND:
|
|
|
|
|
ffestb_args.beru.len = FFESTR_firstlREWIND;
|
|
|
|
|
ffestb_args.beru.badname = "REWIND";
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_beru);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstSAVE:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R522);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstSELECT:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R809);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstSELECTCASE:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R809);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstSTOP:
|
|
|
|
|
ffestb_args.halt.len = FFESTR_firstlSTOP;
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_halt);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstSUBROUTINE:
|
|
|
|
|
ffestb_args.dummy.len = FFESTR_firstlSUBROUTINE;
|
|
|
|
|
ffestb_args.dummy.badname = "SUBROUTINE";
|
|
|
|
|
ffestb_args.dummy.is_subr = TRUE;
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_dummy);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstTYPE:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_V020);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstVIRTUAL:
|
|
|
|
|
ffestb_args.R524.len = FFESTR_firstlVIRTUAL;
|
|
|
|
|
ffestb_args.R524.badname = "VIRTUAL";
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R524);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstVOLATILE:
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_V014);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstWORD:
|
|
|
|
|
ffestb_args.decl.len = FFESTR_firstlWORD;
|
|
|
|
|
ffestb_args.decl.type = FFESTP_typeWORD;
|
|
|
|
|
ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_gentype);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFESTR_firstWRITE:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R910);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now check the default cases, which are always "live" (meaning that no
|
|
|
|
|
other possibility can override them). These are where the second token
|
|
|
|
|
is OPEN_PAREN, PERCENT, EQUALS, POINTS, or COLON. */
|
|
|
|
|
|
|
|
|
|
switch (ffelex_token_type (t))
|
|
|
|
|
{
|
|
|
|
|
case FFELEX_typeOPEN_PAREN:
|
|
|
|
|
s = ffesymbol_lookup_local (ffesta_token_0_);
|
|
|
|
|
if (((s == NULL) || (ffesymbol_dims (s) == NULL))
|
|
|
|
|
&& !ffesta_seen_first_exec)
|
|
|
|
|
{ /* Not known as array; may be stmt function. */
|
|
|
|
|
ffesta_add_possible_unnamed_nonexec_ ((ffelexHandler) ffestb_R1229);
|
|
|
|
|
|
|
|
|
|
/* If the symbol is (or will be due to implicit typing) of
|
|
|
|
|
CHARACTER type, then the statement might be an assignment
|
|
|
|
|
statement. If so, since it can't be a function invocation nor
|
|
|
|
|
an array element reference, the open paren following the symbol
|
|
|
|
|
name must be followed by an expression and a colon. Without the
|
|
|
|
|
colon (which cannot appear in a stmt function definition), the
|
|
|
|
|
let stmt rejects. So CHARACTER_NAME(...)=expr, unlike any other
|
|
|
|
|
type, is not ambiguous alone. */
|
|
|
|
|
|
|
|
|
|
if (ffeimplic_peek_symbol_type (s,
|
|
|
|
|
ffelex_token_text (ffesta_token_0_))
|
|
|
|
|
== FFEINFO_basictypeCHARACTER)
|
|
|
|
|
ffesta_add_possible_unnamed_exec_ ((ffelexHandler) ffestb_let);
|
|
|
|
|
}
|
|
|
|
|
else /* Not statement function if known as an
|
|
|
|
|
array. */
|
|
|
|
|
ffesta_add_possible_unnamed_exec_ ((ffelexHandler) ffestb_let);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFELEX_typeEQUALS:
|
|
|
|
|
ffesta_add_possible_unnamed_exec_ ((ffelexHandler) ffestb_let);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case FFELEX_typeCOLON:
|
|
|
|
|
ffesta_add_possible_exec_ ((ffelexHandler) ffestb_construct);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now see how many possibilities are on the list. */
|
|
|
|
|
|
|
|
|
|
switch (ffesta_num_possibles_)
|
|
|
|
|
{
|
|
|
|
|
case 0: /* None, so invalid statement. */
|
|
|
|
|
no_stmts: /* :::::::::::::::::::: */
|
|
|
|
|
ffesta_tokens[0] = ffesta_token_0_;
|
|
|
|
|
ffesta_ffebad_2t (FFEBAD_UNREC_STMT, ffesta_token_0_, t);
|
|
|
|
|
next = (ffelexHandler) ffelex_swallow_tokens (NULL,
|
|
|
|
|
(ffelexHandler) ffesta_zero);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1: /* One, so just do it! */
|
|
|
|
|
ffesta_tokens[0] = ffesta_token_0_;
|
|
|
|
|
next = ffesta_possible_execs_.first->handler;
|
|
|
|
|
if (next == NULL)
|
|
|
|
|
{ /* Have a nonexec stmt. */
|
|
|
|
|
next = ffesta_possible_nonexecs_.first->handler;
|
|
|
|
|
assert (next != NULL);
|
|
|
|
|
}
|
|
|
|
|
else if (ffesta_seen_first_exec)
|
|
|
|
|
; /* Have an exec stmt after exec transition. */
|
|
|
|
|
else if (!ffestc_exec_transition ())
|
|
|
|
|
/* 1 exec stmt only, but not valid in context, so pretend as though
|
|
|
|
|
statement is unrecognized. */
|
|
|
|
|
goto no_stmts; /* :::::::::::::::::::: */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: /* More than one, so try them in order. */
|
|
|
|
|
ffesta_confirmed_possible_ = NULL;
|
|
|
|
|
ffesta_current_possible_ = ffesta_possible_nonexecs_.first;
|
|
|
|
|
ffesta_current_handler_ = ffesta_current_possible_->handler;
|
|
|
|
|
if (ffesta_current_handler_ == NULL)
|
|
|
|
|
{
|
|
|
|
|
ffesta_current_possible_ = ffesta_possible_execs_.first;
|
|
|
|
|
ffesta_current_handler_ = ffesta_current_possible_->handler;
|
|
|
|
|
assert (ffesta_current_handler_ != NULL);
|
|
|
|
|
if (!ffesta_seen_first_exec)
|
|
|
|
|
{ /* Need to do exec transition now. */
|
|
|
|
|
ffesta_tokens[0] = ffesta_token_0_;
|
|
|
|
|
if (!ffestc_exec_transition ())
|
|
|
|
|
goto no_stmts; /* :::::::::::::::::::: */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ffesta_tokens[0] = ffelex_token_use (ffesta_token_0_);
|
|
|
|
|
next = (ffelexHandler) ffesta_save_;
|
|
|
|
|
ffebad_set_inhibit (TRUE);
|
|
|
|
|
ffesta_is_inhibited_ = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ffesta_output_pool
|
|
|
|
|
= malloc_pool_new ("Statement Output", ffe_pool_program_unit (), 1024);
|
|
|
|
|
ffesta_scratch_pool
|
|
|
|
|
= malloc_pool_new ("Statement Scratch", ffe_pool_program_unit (), 1024);
|
|
|
|
|
ffesta_outpooldisp_ = FFESTA_pooldispDISCARD;
|
|
|
|
|
|
|
|
|
|
if (ffesta_is_inhibited_)
|
|
|
|
|
ffesymbol_set_retractable (ffesta_scratch_pool);
|
|
|
|
|
|
|
|
|
|
ffelex_set_names (FALSE); /* Most handlers will want this. If not,
|
|
|
|
|
they have to set it TRUE again (its value
|
|
|
|
|
at the beginning of a statement). */
|
|
|
|
|
|
|
|
|
|
return (ffelexHandler) (*next) (t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_send_two_ -- Send the two tokens saved by ffesta_two after all
|
|
|
|
|
|
|
|
|
|
return ffesta_send_two_; // to lexer.
|
|
|
|
|
|
|
|
|
|
Currently, if this function gets called, it means that the two tokens
|
|
|
|
|
saved by ffesta_two did not have their handlers derailed by
|
|
|
|
|
ffesta_save_, which probably means they weren't sent by ffesta_save_
|
|
|
|
|
but directly by the lexer, which probably means the original statement
|
|
|
|
|
(which should be IF (expr) or WHERE (expr)) somehow evaluated to only
|
|
|
|
|
one possibility in ffesta_second_ or somebody optimized FFEST to
|
|
|
|
|
immediately revert to one possibility upon confirmation but forgot to
|
|
|
|
|
change this function (and thus perhaps the entire resubmission
|
|
|
|
|
mechanism). */
|
|
|
|
|
|
|
|
|
|
#if !FFESTA_ABORT_ON_CONFIRM_
|
|
|
|
|
static ffelexHandler
|
|
|
|
|
ffesta_send_two_ (ffelexToken t)
|
|
|
|
|
{
|
|
|
|
|
assert ("what am I doing here?" == NULL);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
/* ffesta_confirmed -- Confirm current possibility as only one
|
|
|
|
|
|
|
|
|
|
ffesta_confirmed();
|
|
|
|
|
|
|
|
|
|
Sets the confirmation flag. During debugging for ambiguous constructs,
|
|
|
|
|
asserts that the confirmation flag for a previous possibility has not
|
|
|
|
|
yet been set. */
|
|
|
|
|
|
|
|
|
|
void
|
2004-07-28 03:11:36 +00:00
|
|
|
|
ffesta_confirmed (void)
|
1999-08-26 09:30:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (ffesta_inhibit_confirmation_)
|
|
|
|
|
return;
|
|
|
|
|
ffesta_confirmed_current_ = TRUE;
|
|
|
|
|
assert (!ffesta_confirmed_other_
|
|
|
|
|
|| (ffesta_confirmed_possible_ == ffesta_current_possible_));
|
|
|
|
|
ffesta_confirmed_possible_ = ffesta_current_possible_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_eof -- End of (non-INCLUDEd) source file
|
|
|
|
|
|
|
|
|
|
ffesta_eof();
|
|
|
|
|
|
|
|
|
|
Call after piping tokens through ffest_first, where the most recent
|
|
|
|
|
token sent through must be EOS.
|
|
|
|
|
|
|
|
|
|
20-Feb-91 JCB 1.1
|
|
|
|
|
Put new EOF token in ffesta_tokens[0], not NULL, because too much
|
|
|
|
|
code expects something there for error reporting and the like. Also,
|
|
|
|
|
do basically the same things ffest_second and ffesta_zero do for
|
|
|
|
|
processing a statement (make and destroy pools, et cetera). */
|
|
|
|
|
|
|
|
|
|
void
|
2004-07-28 03:11:36 +00:00
|
|
|
|
ffesta_eof (void)
|
1999-08-26 09:30:50 +00:00
|
|
|
|
{
|
|
|
|
|
ffesta_tokens[0] = ffelex_token_new_eof ();
|
|
|
|
|
|
|
|
|
|
ffesta_output_pool
|
|
|
|
|
= malloc_pool_new ("Statement Output", ffe_pool_program_unit (), 1024);
|
|
|
|
|
ffesta_scratch_pool
|
|
|
|
|
= malloc_pool_new ("Statement Scratch", ffe_pool_program_unit (), 1024);
|
|
|
|
|
ffesta_outpooldisp_ = FFESTA_pooldispDISCARD;
|
|
|
|
|
|
|
|
|
|
ffestc_eof ();
|
|
|
|
|
|
|
|
|
|
if (ffesta_tokens[0] != NULL)
|
|
|
|
|
ffelex_token_kill (ffesta_tokens[0]);
|
|
|
|
|
|
|
|
|
|
if (ffesta_output_pool != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (ffesta_outpooldisp_ == FFESTA_pooldispDISCARD)
|
|
|
|
|
malloc_pool_kill (ffesta_output_pool);
|
|
|
|
|
ffesta_output_pool = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ffesta_scratch_pool != NULL)
|
|
|
|
|
{
|
|
|
|
|
malloc_pool_kill (ffesta_scratch_pool);
|
|
|
|
|
ffesta_scratch_pool = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ffesta_label_token != NULL)
|
|
|
|
|
{
|
|
|
|
|
ffelex_token_kill (ffesta_label_token);
|
|
|
|
|
ffesta_label_token = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ffe_is_ffedebug ())
|
|
|
|
|
{
|
|
|
|
|
ffestorag_report ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_ffebad_here_current_stmt -- ffebad_here with ptr to current stmt
|
|
|
|
|
|
|
|
|
|
ffesta_ffebad_here_current_stmt(0);
|
|
|
|
|
|
|
|
|
|
Outsiders can call this fn if they have no more convenient place to
|
|
|
|
|
point to (via a token or pair of ffewhere objects) and they know a
|
|
|
|
|
current, useful statement is being evaluted by ffest (i.e. they are
|
|
|
|
|
being called from ffestb, ffestc, ffestd, ... functions). */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ffesta_ffebad_here_current_stmt (ffebadIndex i)
|
|
|
|
|
{
|
|
|
|
|
assert (ffesta_tokens[0] != NULL);
|
|
|
|
|
ffebad_here (i, ffelex_token_where_line (ffesta_tokens[0]),
|
|
|
|
|
ffelex_token_where_column (ffesta_tokens[0]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_ffebad_start -- Start a possibly inhibited error report
|
|
|
|
|
|
|
|
|
|
if (ffesta_ffebad_start(FFEBAD_SOME_ERROR))
|
|
|
|
|
{
|
|
|
|
|
ffebad_here, ffebad_string ...;
|
|
|
|
|
ffebad_finish();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Call if the error might indicate that ffest is evaluating the wrong
|
|
|
|
|
statement form, instead of calling ffebad_start directly. If ffest
|
|
|
|
|
is choosing between forms, it will return FALSE, send an EOS/SEMICOLON
|
|
|
|
|
token through as the next token (if the current one isn't already one
|
|
|
|
|
of those), and try another possible form. Otherwise, ffebad_start is
|
|
|
|
|
called with the argument and TRUE returned. */
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ffesta_ffebad_start (ffebad errnum)
|
|
|
|
|
{
|
|
|
|
|
if (!ffesta_is_inhibited_)
|
|
|
|
|
{
|
|
|
|
|
ffebad_start (errnum);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ffesta_confirmed_current_)
|
|
|
|
|
ffesta_current_shutdown_ = TRUE;
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_first -- Parse the first token in a statement
|
|
|
|
|
|
|
|
|
|
return ffesta_first; // to lexer. */
|
|
|
|
|
|
|
|
|
|
ffelexHandler
|
|
|
|
|
ffesta_first (ffelexToken t)
|
|
|
|
|
{
|
|
|
|
|
switch (ffelex_token_type (t))
|
|
|
|
|
{
|
|
|
|
|
case FFELEX_typeSEMICOLON:
|
|
|
|
|
case FFELEX_typeEOS:
|
|
|
|
|
ffesta_tokens[0] = ffelex_token_use (t);
|
|
|
|
|
if (ffesta_label_token != NULL)
|
|
|
|
|
{
|
|
|
|
|
ffebad_start (FFEBAD_LABEL_WITHOUT_STMT);
|
|
|
|
|
ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
|
|
|
|
|
ffelex_token_where_column (ffesta_label_token));
|
|
|
|
|
ffebad_string (ffelex_token_text (ffesta_label_token));
|
|
|
|
|
ffebad_here (1, ffelex_token_where_line (t), ffelex_token_where_column (t));
|
|
|
|
|
ffebad_finish ();
|
|
|
|
|
}
|
|
|
|
|
return (ffelexHandler) ffesta_zero (t);
|
|
|
|
|
|
|
|
|
|
case FFELEX_typeNAME:
|
|
|
|
|
case FFELEX_typeNAMES:
|
|
|
|
|
ffesta_token_0_ = ffelex_token_use (t);
|
|
|
|
|
ffesta_first_kw = ffestr_first (t);
|
|
|
|
|
return (ffelexHandler) ffesta_second_;
|
|
|
|
|
|
|
|
|
|
case FFELEX_typeNUMBER:
|
|
|
|
|
if (ffesta_line_has_semicolons
|
|
|
|
|
&& !ffe_is_free_form ()
|
|
|
|
|
&& ffe_is_pedantic ())
|
|
|
|
|
{
|
|
|
|
|
ffebad_start (FFEBAD_LABEL_WRONG_PLACE);
|
|
|
|
|
ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
|
|
|
|
|
ffebad_string (ffelex_token_text (t));
|
|
|
|
|
ffebad_finish ();
|
|
|
|
|
}
|
|
|
|
|
if (ffesta_label_token == NULL)
|
|
|
|
|
{
|
|
|
|
|
ffesta_label_token = ffelex_token_use (t);
|
|
|
|
|
return (ffelexHandler) ffesta_first;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ffebad_start (FFEBAD_EXTRA_LABEL_DEF);
|
|
|
|
|
ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
|
|
|
|
|
ffebad_string (ffelex_token_text (t));
|
|
|
|
|
ffebad_here (1, ffelex_token_where_line (ffesta_label_token),
|
|
|
|
|
ffelex_token_where_column (ffesta_label_token));
|
|
|
|
|
ffebad_string (ffelex_token_text (ffesta_label_token));
|
|
|
|
|
ffebad_finish ();
|
|
|
|
|
|
|
|
|
|
return (ffelexHandler) ffesta_first;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default: /* Invalid first token. */
|
|
|
|
|
ffesta_tokens[0] = ffelex_token_use (t);
|
|
|
|
|
ffebad_start (FFEBAD_STMT_BEGINS_BAD);
|
|
|
|
|
ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
|
|
|
|
|
ffebad_finish ();
|
|
|
|
|
return (ffelexHandler) ffelex_swallow_tokens (t,
|
|
|
|
|
(ffelexHandler) ffesta_zero);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_init_0 -- Initialize for entire image invocation
|
|
|
|
|
|
|
|
|
|
ffesta_init_0();
|
|
|
|
|
|
|
|
|
|
Call just once per invocation of the compiler (not once per invocation
|
|
|
|
|
of the front end).
|
|
|
|
|
|
|
|
|
|
Gets memory for the list of possibles once and for all, since this
|
|
|
|
|
list never gets larger than a certain size (FFESTA_maxPOSSIBLES_)
|
|
|
|
|
and is not particularly large. Initializes the array of pointers to
|
|
|
|
|
this list. Initializes the executable and nonexecutable lists. */
|
|
|
|
|
|
|
|
|
|
void
|
2004-07-28 03:11:36 +00:00
|
|
|
|
ffesta_init_0 (void)
|
1999-08-26 09:30:50 +00:00
|
|
|
|
{
|
|
|
|
|
ffestaPossible_ ptr;
|
|
|
|
|
int i;
|
|
|
|
|
|
2004-07-28 03:11:36 +00:00
|
|
|
|
ptr = malloc_new_kp (malloc_pool_image (), "FFEST possibles",
|
|
|
|
|
FFESTA_maxPOSSIBLES_ * sizeof (*ptr));
|
1999-08-26 09:30:50 +00:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < FFESTA_maxPOSSIBLES_; ++i)
|
|
|
|
|
ffesta_possibles_[i] = ptr++;
|
|
|
|
|
|
|
|
|
|
ffesta_possible_execs_.first = ffesta_possible_execs_.last
|
|
|
|
|
= (ffestaPossible_) &ffesta_possible_execs_.first;
|
|
|
|
|
ffesta_possible_nonexecs_.first = ffesta_possible_nonexecs_.last
|
|
|
|
|
= (ffestaPossible_) &ffesta_possible_nonexecs_.first;
|
|
|
|
|
ffesta_possible_execs_.nil = ffesta_possible_nonexecs_.nil = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_init_3 -- Initialize for any program unit
|
|
|
|
|
|
|
|
|
|
ffesta_init_3(); */
|
|
|
|
|
|
|
|
|
|
void
|
2004-07-28 03:11:36 +00:00
|
|
|
|
ffesta_init_3 (void)
|
1999-08-26 09:30:50 +00:00
|
|
|
|
{
|
|
|
|
|
ffesta_output_pool = NULL; /* May be doing this just before reaching */
|
|
|
|
|
ffesta_scratch_pool = NULL; /* ffesta_zero or ffesta_two. */
|
|
|
|
|
/* NOTE: we let the ffe_terminate_2 action of killing the program_unit pool
|
|
|
|
|
handle the killing of the output and scratch pools for us, which is why
|
|
|
|
|
we don't have a terminate_3 action to do so. */
|
|
|
|
|
ffesta_construct_name = NULL;
|
|
|
|
|
ffesta_label_token = NULL;
|
|
|
|
|
ffesta_seen_first_exec = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_is_inhibited -- Test whether the current possibility is inhibited
|
|
|
|
|
|
|
|
|
|
if (!ffesta_is_inhibited())
|
|
|
|
|
// implement the statement.
|
|
|
|
|
|
|
|
|
|
Just make sure the current possibility has been confirmed. If anyone
|
|
|
|
|
really needs to test whether the current possibility is inhibited prior
|
|
|
|
|
to confirming it, that indicates a need to begin statement processing
|
|
|
|
|
before it is certain that the given possibility is indeed the statement
|
|
|
|
|
to be processed. As of this writing, there does not appear to be such
|
|
|
|
|
a need. If there is, then when confirming a statement would normally
|
|
|
|
|
immediately disable the inhibition (whereas currently we leave the
|
|
|
|
|
confirmed statement disabled until we've tried the other possibilities,
|
|
|
|
|
to check for ambiguities), we must check to see if the possibility has
|
|
|
|
|
already tested for inhibition prior to confirmation and, if so, maintain
|
|
|
|
|
inhibition until the end of the statement (which may be forced right
|
|
|
|
|
away) and then rerun the entire statement from the beginning. Otherwise,
|
|
|
|
|
initial calls to ffestb functions won't have been made, but subsequent
|
|
|
|
|
calls (after confirmation) will, which is wrong. Of course, this all
|
|
|
|
|
applies only to those statements implemented via multiple calls to
|
|
|
|
|
ffestb, although if a statement requiring only a single ffestb call
|
|
|
|
|
tested for inhibition prior to confirmation, it would likely mean that
|
|
|
|
|
the ffestb call would be completely dropped without this mechanism. */
|
|
|
|
|
|
|
|
|
|
bool
|
2004-07-28 03:11:36 +00:00
|
|
|
|
ffesta_is_inhibited (void)
|
1999-08-26 09:30:50 +00:00
|
|
|
|
{
|
|
|
|
|
assert (ffesta_confirmed_current_ || ffesta_inhibit_confirmation_);
|
|
|
|
|
return ffesta_is_inhibited_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_ffebad_1p -- Issue diagnostic with one source character
|
|
|
|
|
|
|
|
|
|
ffelexToken names_token;
|
|
|
|
|
ffeTokenLength index;
|
|
|
|
|
ffelexToken next_token;
|
|
|
|
|
ffesta_ffebad_1p(FFEBAD_SOME_ERROR,names_token,index,next_token);
|
|
|
|
|
|
|
|
|
|
Equivalent to "if (ffest_ffebad_start(FFEBAD_SOME_ERROR))" followed by
|
|
|
|
|
sending one argument, the location of index with names_token, if TRUE is
|
|
|
|
|
returned. If index is equal to the length of names_token, meaning it
|
|
|
|
|
points to the end of the token, then uses the location in next_token
|
|
|
|
|
(which should be the token sent by the lexer after it sent names_token)
|
|
|
|
|
instead. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ffesta_ffebad_1p (ffebad errnum, ffelexToken names_token, ffeTokenLength index,
|
|
|
|
|
ffelexToken next_token)
|
|
|
|
|
{
|
|
|
|
|
ffewhereLine line;
|
|
|
|
|
ffewhereColumn col;
|
|
|
|
|
|
|
|
|
|
assert (index <= ffelex_token_length (names_token));
|
|
|
|
|
|
|
|
|
|
if (ffesta_ffebad_start (errnum))
|
|
|
|
|
{
|
|
|
|
|
if (index == ffelex_token_length (names_token))
|
|
|
|
|
{
|
|
|
|
|
assert (next_token != NULL);
|
|
|
|
|
line = ffelex_token_where_line (next_token);
|
|
|
|
|
col = ffelex_token_where_column (next_token);
|
|
|
|
|
ffebad_here (0, line, col);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ffewhere_set_from_track (&line, &col,
|
|
|
|
|
ffelex_token_where_line (names_token),
|
|
|
|
|
ffelex_token_where_column (names_token),
|
|
|
|
|
ffelex_token_wheretrack (names_token),
|
|
|
|
|
index);
|
|
|
|
|
ffebad_here (0, line, col);
|
|
|
|
|
ffewhere_line_kill (line);
|
|
|
|
|
ffewhere_column_kill (col);
|
|
|
|
|
}
|
|
|
|
|
ffebad_finish ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
1999-10-16 06:09:09 +00:00
|
|
|
|
ffesta_ffebad_1sp (ffebad errnum, const char *s, ffelexToken names_token,
|
1999-08-26 09:30:50 +00:00
|
|
|
|
ffeTokenLength index, ffelexToken next_token)
|
|
|
|
|
{
|
|
|
|
|
ffewhereLine line;
|
|
|
|
|
ffewhereColumn col;
|
|
|
|
|
|
|
|
|
|
assert (index <= ffelex_token_length (names_token));
|
|
|
|
|
|
|
|
|
|
if (ffesta_ffebad_start (errnum))
|
|
|
|
|
{
|
|
|
|
|
ffebad_string (s);
|
|
|
|
|
if (index == ffelex_token_length (names_token))
|
|
|
|
|
{
|
|
|
|
|
assert (next_token != NULL);
|
|
|
|
|
line = ffelex_token_where_line (next_token);
|
|
|
|
|
col = ffelex_token_where_column (next_token);
|
|
|
|
|
ffebad_here (0, line, col);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ffewhere_set_from_track (&line, &col,
|
|
|
|
|
ffelex_token_where_line (names_token),
|
|
|
|
|
ffelex_token_where_column (names_token),
|
|
|
|
|
ffelex_token_wheretrack (names_token),
|
|
|
|
|
index);
|
|
|
|
|
ffebad_here (0, line, col);
|
|
|
|
|
ffewhere_line_kill (line);
|
|
|
|
|
ffewhere_column_kill (col);
|
|
|
|
|
}
|
|
|
|
|
ffebad_finish ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
1999-10-16 06:09:09 +00:00
|
|
|
|
ffesta_ffebad_1st (ffebad errnum, const char *s, ffelexToken t)
|
1999-08-26 09:30:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (ffesta_ffebad_start (errnum))
|
|
|
|
|
{
|
|
|
|
|
ffebad_string (s);
|
|
|
|
|
ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
|
|
|
|
|
ffebad_finish ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_ffebad_1t -- Issue diagnostic with one source token
|
|
|
|
|
|
|
|
|
|
ffelexToken t;
|
|
|
|
|
ffesta_ffebad_1t(FFEBAD_SOME_ERROR,t);
|
|
|
|
|
|
|
|
|
|
Equivalent to "if (ffesta_ffebad_start(FFEBAD_SOME_ERROR))" followed by
|
|
|
|
|
sending one argument, the location of the token t, if TRUE is returned. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ffesta_ffebad_1t (ffebad errnum, ffelexToken t)
|
|
|
|
|
{
|
|
|
|
|
if (ffesta_ffebad_start (errnum))
|
|
|
|
|
{
|
|
|
|
|
ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
|
|
|
|
|
ffebad_finish ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
1999-10-16 06:09:09 +00:00
|
|
|
|
ffesta_ffebad_2st (ffebad errnum, const char *s, ffelexToken t1, ffelexToken t2)
|
1999-08-26 09:30:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (ffesta_ffebad_start (errnum))
|
|
|
|
|
{
|
|
|
|
|
ffebad_string (s);
|
|
|
|
|
ffebad_here (0, ffelex_token_where_line (t1), ffelex_token_where_column (t1));
|
|
|
|
|
ffebad_here (1, ffelex_token_where_line (t2), ffelex_token_where_column (t2));
|
|
|
|
|
ffebad_finish ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_ffebad_2t -- Issue diagnostic with two source tokens
|
|
|
|
|
|
|
|
|
|
ffelexToken t1, t2;
|
|
|
|
|
ffesta_ffebad_2t(FFEBAD_SOME_ERROR,t1,t2);
|
|
|
|
|
|
|
|
|
|
Equivalent to "if (ffesta_ffebad_start(FFEBAD_SOME_ERROR))" followed by
|
|
|
|
|
sending two argument, the locations of the tokens t1 and t2, if TRUE is
|
|
|
|
|
returned. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ffesta_ffebad_2t (ffebad errnum, ffelexToken t1, ffelexToken t2)
|
|
|
|
|
{
|
|
|
|
|
if (ffesta_ffebad_start (errnum))
|
|
|
|
|
{
|
|
|
|
|
ffebad_here (0, ffelex_token_where_line (t1), ffelex_token_where_column (t1));
|
|
|
|
|
ffebad_here (1, ffelex_token_where_line (t2), ffelex_token_where_column (t2));
|
|
|
|
|
ffebad_finish ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ffestaPooldisp
|
2004-07-28 03:11:36 +00:00
|
|
|
|
ffesta_outpooldisp (void)
|
1999-08-26 09:30:50 +00:00
|
|
|
|
{
|
|
|
|
|
return ffesta_outpooldisp_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ffesta_set_outpooldisp (ffestaPooldisp d)
|
|
|
|
|
{
|
|
|
|
|
ffesta_outpooldisp_ = d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Shut down current parsing possibility, but without bothering the
|
|
|
|
|
user with a diagnostic if we're not inhibited. */
|
|
|
|
|
|
|
|
|
|
void
|
2004-07-28 03:11:36 +00:00
|
|
|
|
ffesta_shutdown (void)
|
1999-08-26 09:30:50 +00:00
|
|
|
|
{
|
|
|
|
|
if (ffesta_is_inhibited_)
|
|
|
|
|
ffesta_current_shutdown_ = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_two -- Deal with the first two tokens after a swallowed statement
|
|
|
|
|
|
|
|
|
|
return ffesta_two(first_token,second_token); // to lexer.
|
|
|
|
|
|
|
|
|
|
Like ffesta_zero, except instead of expecting an EOS or SEMICOLON, it
|
|
|
|
|
expects the first two tokens of a statement that is part of another
|
|
|
|
|
statement: the first two tokens of statement in "IF (expr) statement" or
|
|
|
|
|
"WHERE (expr) statement", in particular. The first token must be a NAME
|
|
|
|
|
or NAMES, the second can be basically anything. The statement type MUST
|
|
|
|
|
be confirmed by now.
|
|
|
|
|
|
|
|
|
|
If we're not inhibited, just handle things as if we were ffesta_zero
|
|
|
|
|
and saw an EOS just before the two tokens.
|
|
|
|
|
|
|
|
|
|
If we're inhibited, set ffesta_current_shutdown_ to shut down the current
|
|
|
|
|
statement and continue with other possibilities, then (presumably) come
|
|
|
|
|
back to this one for real when not inhibited. */
|
|
|
|
|
|
|
|
|
|
ffelexHandler
|
|
|
|
|
ffesta_two (ffelexToken first, ffelexToken second)
|
|
|
|
|
{
|
|
|
|
|
#if FFESTA_ABORT_ON_CONFIRM_
|
|
|
|
|
ffelexHandler next;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
assert ((ffelex_token_type (first) == FFELEX_typeNAME)
|
|
|
|
|
|| (ffelex_token_type (first) == FFELEX_typeNAMES));
|
|
|
|
|
assert (ffesta_tokens[0] != NULL);
|
|
|
|
|
|
|
|
|
|
if (ffesta_is_inhibited_) /* Oh, not really done with statement. */
|
|
|
|
|
{
|
|
|
|
|
ffesta_current_shutdown_ = TRUE;
|
|
|
|
|
/* To catch the EOS on shutdown. */
|
|
|
|
|
return (ffelexHandler) ffelex_swallow_tokens (second,
|
|
|
|
|
(ffelexHandler) ffesta_zero);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ffestw_display_state ();
|
|
|
|
|
|
|
|
|
|
ffelex_token_kill (ffesta_tokens[0]);
|
|
|
|
|
|
|
|
|
|
if (ffesta_output_pool != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (ffesta_outpooldisp_ == FFESTA_pooldispDISCARD)
|
|
|
|
|
malloc_pool_kill (ffesta_output_pool);
|
|
|
|
|
ffesta_output_pool = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ffesta_scratch_pool != NULL)
|
|
|
|
|
{
|
|
|
|
|
malloc_pool_kill (ffesta_scratch_pool);
|
|
|
|
|
ffesta_scratch_pool = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ffesta_reset_possibles_ ();
|
|
|
|
|
ffesta_confirmed_current_ = FALSE;
|
|
|
|
|
|
|
|
|
|
/* What happens here is somewhat interesting. We effectively derail the
|
|
|
|
|
line of handlers for these two tokens, the first two in a statement, by
|
|
|
|
|
setting a flag to TRUE. This flag tells ffesta_save_ (or, conceivably,
|
|
|
|
|
the lexer via ffesta_second_'s case 1:, where it has only one possible
|
|
|
|
|
kind of statement -- someday this will be more likely, i.e. after
|
|
|
|
|
confirmation causes an immediate switch to only the one context rather
|
|
|
|
|
than just setting a flag and running through the remaining possibles to
|
|
|
|
|
look for ambiguities) that the last two tokens it sent did not reach the
|
|
|
|
|
truly desired targets (ffest_first and ffesta_second_) since that would
|
|
|
|
|
otherwise attempt to recursively invoke ffesta_save_ in most cases,
|
|
|
|
|
while the existing ffesta_save_ was still alive and making use of static
|
|
|
|
|
(nonrecursive) variables. Instead, ffesta_save_, upon seeing this flag
|
|
|
|
|
set TRUE, sets it to FALSE and resubmits the two tokens copied here to
|
|
|
|
|
ffest_first and, presumably, ffesta_second_, kills them, and returns the
|
|
|
|
|
handler returned by the handler for the second token. Thus, even though
|
|
|
|
|
ffesta_save_ is still (likely to be) recursively invoked, the former
|
|
|
|
|
invocation is past the use of any static variables possibly changed
|
|
|
|
|
during the first-two-token invocation of the latter invocation. */
|
|
|
|
|
|
|
|
|
|
#if FFESTA_ABORT_ON_CONFIRM_
|
|
|
|
|
/* Shouldn't be in ffesta_save_ at all here. */
|
|
|
|
|
|
|
|
|
|
next = (ffelexHandler) ffesta_first (first);
|
|
|
|
|
return (ffelexHandler) (*next) (second);
|
|
|
|
|
#else
|
|
|
|
|
ffesta_twotokens_1_ = ffelex_token_use (first);
|
|
|
|
|
ffesta_twotokens_2_ = ffelex_token_use (second);
|
|
|
|
|
|
|
|
|
|
ffesta_is_two_into_statement_ = TRUE;
|
|
|
|
|
return (ffelexHandler) ffesta_send_two_; /* Shouldn't get called. */
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ffesta_zero -- Deal with the end of a swallowed statement
|
|
|
|
|
|
|
|
|
|
return ffesta_zero; // to lexer.
|
|
|
|
|
|
|
|
|
|
NOTICE that this code is COPIED, largely, into a
|
|
|
|
|
similar function named ffesta_two that gets invoked in place of
|
|
|
|
|
_zero_ when the end of the statement happens before EOS or SEMICOLON and
|
|
|
|
|
to tokens into the next statement have been read (as is the case with the
|
|
|
|
|
logical-IF and WHERE-stmt statements). So any changes made here should
|
|
|
|
|
probably be made in _two_ at the same time. */
|
|
|
|
|
|
|
|
|
|
ffelexHandler
|
|
|
|
|
ffesta_zero (ffelexToken t)
|
|
|
|
|
{
|
|
|
|
|
assert ((ffelex_token_type (t) == FFELEX_typeEOS)
|
|
|
|
|
|| (ffelex_token_type (t) == FFELEX_typeSEMICOLON));
|
|
|
|
|
assert (ffesta_tokens[0] != NULL);
|
|
|
|
|
|
|
|
|
|
if (ffesta_is_inhibited_)
|
|
|
|
|
ffesymbol_retract (TRUE);
|
|
|
|
|
else
|
|
|
|
|
ffestw_display_state ();
|
|
|
|
|
|
|
|
|
|
/* Do CONTINUE if nothing else. This is done specifically so that "IF
|
|
|
|
|
(...) BLAH" causes the same things to happen as if "IF (...) CONTINUE"
|
|
|
|
|
was done, so that tracking of labels and such works. (Try a small
|
|
|
|
|
program like "DO 10 ...", "IF (...) BLAH", "10 CONTINUE", "END".)
|
|
|
|
|
|
|
|
|
|
But it turns out that just testing "!ffesta_confirmed_current_"
|
|
|
|
|
isn't enough, because then typing "GOTO" instead of "BLAH" above
|
|
|
|
|
doesn't work -- the statement is confirmed (we know the user
|
|
|
|
|
attempted a GOTO) but ffestc hasn't seen it. So, instead, just
|
|
|
|
|
always tell ffestc to do "any" statement it needs to reset. */
|
|
|
|
|
|
|
|
|
|
if (!ffesta_is_inhibited_
|
|
|
|
|
&& ffesta_seen_first_exec)
|
|
|
|
|
{
|
|
|
|
|
ffestc_any ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ffelex_token_kill (ffesta_tokens[0]);
|
|
|
|
|
|
|
|
|
|
if (ffesta_is_inhibited_) /* Oh, not really done with statement. */
|
|
|
|
|
return (ffelexHandler) ffesta_zero; /* Call me again when done! */
|
|
|
|
|
|
|
|
|
|
if (ffesta_output_pool != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (ffesta_outpooldisp_ == FFESTA_pooldispDISCARD)
|
|
|
|
|
malloc_pool_kill (ffesta_output_pool);
|
|
|
|
|
ffesta_output_pool = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ffesta_scratch_pool != NULL)
|
|
|
|
|
{
|
|
|
|
|
malloc_pool_kill (ffesta_scratch_pool);
|
|
|
|
|
ffesta_scratch_pool = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ffesta_reset_possibles_ ();
|
|
|
|
|
ffesta_confirmed_current_ = FALSE;
|
|
|
|
|
|
|
|
|
|
if (ffelex_token_type (t) == FFELEX_typeSEMICOLON)
|
|
|
|
|
{
|
|
|
|
|
ffesta_line_has_semicolons = TRUE;
|
|
|
|
|
if (ffe_is_pedantic_not_90 ())
|
|
|
|
|
{
|
|
|
|
|
ffebad_start (FFEBAD_SEMICOLON);
|
|
|
|
|
ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
|
|
|
|
|
ffebad_finish ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
ffesta_line_has_semicolons = FALSE;
|
|
|
|
|
|
|
|
|
|
if (ffesta_label_token != NULL)
|
|
|
|
|
{
|
|
|
|
|
ffelex_token_kill (ffesta_label_token);
|
|
|
|
|
ffesta_label_token = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ffe_is_ffedebug ())
|
|
|
|
|
{
|
|
|
|
|
ffestorag_report ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ffelex_set_names (TRUE);
|
|
|
|
|
return (ffelexHandler) ffesta_first;
|
|
|
|
|
}
|