📄 sta.c
字号:
ffesta_possible_execs_.nil = ffesta_possible_nonexecs_.nil = NULL;}/* ffesta_init_3 -- Initialize for any program unit ffesta_init_3(); */voidffesta_init_3 (){ 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. */boolffesta_is_inhibited (){ 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. */voidffesta_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 (); }}voidffesta_ffebad_1sp (ffebad errnum, const char *s, ffelexToken names_token, 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 (); }}voidffesta_ffebad_1st (ffebad errnum, const char *s, ffelexToken t){ 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. */voidffesta_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 (); }}voidffesta_ffebad_2st (ffebad errnum, const char *s, ffelexToken t1, ffelexToken t2){ 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. */voidffesta_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 (); }}ffestaPooldispffesta_outpooldisp (){ return ffesta_outpooldisp_;}voidffesta_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. */voidffesta_shutdown (){ 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. */ffelexHandlerffesta_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. */ffelexHandlerffesta_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 ();#if FFECOM_targetCURRENT == FFECOM_targetFFE ffesymbol_report_all ();#endif } ffelex_set_names (TRUE); return (ffelexHandler) ffesta_first;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -