/* gen - actual generation (writing) of flex scanners */
/* Copyright (c) 1990 The Regents of the University of California. */ /* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */ /* Vern Paxson. */
/* The United States Government has rights in this work pursuant */ /* to contract no. DE-AC03-76SF00098 between the United States */ /* Department of Energy and the University of California. */
/* This file is part of flex. */
/* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following conditions */ /* are met: */
/* 1. Redistributions of source code must retain the above copyright */ /* notice, this list of conditions and the following disclaimer. */ /* 2. Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in the */ /* documentation and/or other materials provided with the distribution. */
/* Neither the name of the University nor the names of its contributors */ /* may be used to endorse or promote products derived from this software */ /* without specific prior written permission. */
/* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */ /* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */ /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */ /* PURPOSE. */
#include"flexdef.h" #include"tables.h"
/* declare functions that have forward references */
void gen_next_state PROTO ((int)); void genecs PROTO ((void)); void indent_put2s PROTO ((constchar *, constchar *)); void indent_puts PROTO ((constchar *));
staticint indent_level = 0; /* each level is 8 spaces */
/* Almost everything is done in terms of arrays starting at 1, so provide * a null entry for the zero element of all C arrays. (The exception * to this is that the fast table representation generally uses the * 0 elements of its arrays, too.)
*/
/** Make the table for possible eol matches. * @return the newly allocated rule_can_match_eol table
*/ staticstruct yytbl_data *mkeoltbl (void)
{ int i;
flex_int8_t *tdata = 0; struct yytbl_data *tbl;
/* Generate the table for possible eol matches. */ staticvoid geneoltbl (void)
{ int i;
outn ("m4_ifdef( [[M4_YY_USE_LINENO]],[[");
outn ("/* Table of booleans, true if rule could match eol. */");
out_str_dec (get_int32_decl (), "yy_rule_can_match_eol",
num_rules + 1);
if (gentables) { for (i = 1; i <= num_rules; i++) {
out_dec ("%d, ", rule_has_nl[i] ? 1 : 0); /* format nicely, 20 numbers per line. */ if ((i % 20) == 19)
out ("\n ");
}
out (" };\n");
}
outn ("]])");
}
/* Generate the code to keep backing-up information. */
indent_puts ("case 0: /* must back up */");
indent_puts ("/* undo the effects of YY_DO_BEFORE_ACTION */");
indent_puts ("*yy_cp = YY_G(yy_hold_char);");
if (fullspd || fulltbl)
indent_puts ("yy_cp = YY_G(yy_last_accepting_cpos) + 1;"); else /* Backing-up info for compressed tables is taken \after/ * yy_cp has been incremented for the next state.
*/
indent_puts ("yy_cp = YY_G(yy_last_accepting_cpos);");
/** mkctbl - make full speed compressed transition table * This is an array of structs; each struct a pair of integers. * You should call mkssltbl() immediately after this. * Then, I think, mkecstbl(). Arrrg. * @return the newly allocated trans table
*/
/* We want the transition to be represented as the offset to the * next state, not the actual state number, which is what it currently * is. The offset is base[nxt[i]] - (base of current state)]. That's * just the difference between the starting points of the two involved * states (to - from). * * First, though, we need to find some way to put in our end-of-buffer * flags and states. We do this by making a state with absolutely no * transitions. We put it at the end of the table.
*/
/* We need to have room in nxt/chk for two more slots: One for the * action and one for the end-of-buffer transition. We now *assume* * that we're guaranteed the only character we'll try to index this * nxt/chk pair with is EOB, i.e., 0, so we don't have to make sure * there's room for jam entries for other characters.
*/
while (tblend + 2 >= current_max_xpairs)
expand_nxt_chk ();
while (lastdfa + 1 >= current_max_dfas)
increase_max_dfas ();
/* So that "make test" won't show arb. differences. */
nxt[tblend + 2] = 0;
/* Make sure every state has an end-of-buffer transition and an * action #.
*/ for (i = 0; i <= lastdfa; ++i) { int anum = dfaacc[i].dfaacc_state; int offset = base[i];
/* genctbl - generates full speed compressed transition table */
void genctbl (void)
{ int i; int end_of_buffer_action = num_rules + 1;
/* Table of verify for transition and offset to next state. */ if (gentables)
out_dec ("static yyconst struct yy_trans_info yy_transition[%d] =\n {\n", tblend + numecs + 1); else
outn ("static yyconst struct yy_trans_info *yy_transition = 0;");
/* We want the transition to be represented as the offset to the * next state, not the actual state number, which is what it currently * is. The offset is base[nxt[i]] - (base of current state)]. That's * just the difference between the starting points of the two involved * states (to - from). * * First, though, we need to find some way to put in our end-of-buffer * flags and states. We do this by making a state with absolutely no * transitions. We put it at the end of the table.
*/
/* We need to have room in nxt/chk for two more slots: One for the * action and one for the end-of-buffer transition. We now *assume* * that we're guaranteed the only character we'll try to index this * nxt/chk pair with is EOB, i.e., 0, so we don't have to make sure * there's room for jam entries for other characters.
*/
while (tblend + 2 >= current_max_xpairs)
expand_nxt_chk ();
while (lastdfa + 1 >= current_max_dfas)
increase_max_dfas ();
/* So that "make test" won't show arb. differences. */
nxt[tblend + 2] = 0;
/* Make sure every state has an end-of-buffer transition and an * action #.
*/ for (i = 0; i <= lastdfa; ++i) { int anum = dfaacc[i].dfaacc_state; int offset = base[i];
if (real_reject) { /* Remember matched text in case we back up * due to REJECT.
*/
indent_puts
("YY_G(yy_full_match) = yy_cp;");
indent_puts
("YY_G(yy_full_state) = YY_G(yy_state_ptr);");
indent_puts ("YY_G(yy_full_lp) = YY_G(yy_lp);");
}
else { /* Remember matched text in case we back up due to * trailing context plus REJECT.
*/
indent_up ();
indent_puts ("{");
indent_puts ("YY_G(yy_full_match) = yy_cp;");
indent_puts ("break;");
indent_puts ("}");
indent_down ();
}
indent_puts ("}");
indent_down ();
indent_puts ("--yy_cp;");
/* We could consolidate the following two lines with those at * the beginning, but at the cost of complaints that we're * branching inside a loop.
*/
indent_puts ("yy_current_state = *--YY_G(yy_state_ptr);");
indent_puts ("YY_G(yy_lp) = yy_accept[yy_current_state];");
if (interactive && !reject) { /* Do the guaranteed-needed backing up to figure out * the match.
*/
indent_puts ("if ( yy_act == 0 )");
indent_up ();
indent_puts ("{ /* have to back up */");
indent_puts
("yy_cp = YY_G(yy_last_accepting_cpos);");
indent_puts
("yy_current_state = YY_G(yy_last_accepting_state);");
indent_puts
("yy_act = yy_accept[yy_current_state];");
indent_puts ("}");
indent_down ();
}
}
}
/* mkftbl - make the full table and return the struct . * you should call mkecstbl() after this.
*/
struct yytbl_data *mkftbl (void)
{ int i; int end_of_buffer_action = num_rules + 1; struct yytbl_data *tbl;
flex_int32_t *tdata = 0;
/* Save the backing-up info \before/ computing the next state * because we always compute one more state than needed - we * always proceed until we reach a jam state
*/
gen_backing_up ();
if (usemecs) { /* We've arrange it so that templates are never chained * to one another. This means we can afford to make a * very simple test to see if we need to convert to * yy_c's meta-equivalence class without worrying * about erroneously looking up the meta-equivalence * class twice
*/
do_indent ();
/* lastdfa + 2 is the beginning of the templates */
out_dec ("if ( yy_current_state >= %d )\n", lastdfa + 2);
void gen_next_match (void)
{ /* NOTE - changes in here should be reflected in gen_next_state() and * gen_NUL_trans().
*/ char *char_map = useecs ? "yy_ec[YY_SC_TO_UI(*yy_cp)] " : "YY_SC_TO_UI(*yy_cp)";
if (!reject && !interactive) { /* Do the guaranteed-needed backing up to figure out * the match.
*/
indent_puts
("yy_cp = YY_G(yy_last_accepting_cpos);");
indent_puts
("yy_current_state = YY_G(yy_last_accepting_state);");
}
}
}
/* Generate the code to find the next state. */
void gen_next_state (worry_about_NULs) int worry_about_NULs;
{ /* NOTE - changes in here should be reflected in gen_next_match() */ char char_map[256];
if (reject)
indent_puts ("*YY_G(yy_state_ptr)++ = yy_current_state;");
}
/* Generate the code to make a NUL transition. */
void gen_NUL_trans (void)
{ /* NOTE - changes in here should be reflected in gen_next_match() */ /* Only generate a definition for "yy_cp" if we'll generate code * that uses it. Otherwise lint and the like complain.
*/ int need_backing_up = (num_backing_up > 0 && !reject);
if (need_backing_up && (!nultrans || fullspd || fulltbl)) /* We're going to need yy_cp lying around for the call * below to gen_backing_up().
*/
indent_puts ("char *yy_cp = YY_G(yy_c_buf_p);");
if (reject) { /* Only stack this state if it's a transition we * actually make. If we stack it on a jam, then * the state stack and yy_c_buf_p get out of sync.
*/
indent_puts ("if ( ! yy_is_jam )");
indent_up ();
indent_puts
("*YY_G(yy_state_ptr)++ = yy_current_state;");
indent_down ();
}
}
/* If we've entered an accepting state, back up; note that * compressed tables have *already* done such backing up, so * we needn't bother with it again.
*/ if (need_backing_up && (fullspd || fulltbl)) {
outc ('\n');
indent_puts ("if ( ! yy_is_jam )");
indent_up ();
indent_puts ("{");
gen_backing_up ();
indent_puts ("}");
indent_down ();
}
}
if (bol_needed)
indent_puts ("yy_current_state += YY_AT_BOL();");
if (reject) { /* Set up for storing up states. */
outn ("m4_ifdef( [[M4_YY_USES_REJECT]],\n[[");
indent_puts
("YY_G(yy_state_ptr) = YY_G(yy_state_buf);");
indent_puts
("*YY_G(yy_state_ptr)++ = yy_current_state;");
outn ("]])");
}
}
}
/* gentabs - generate data statements for the transition tables */
/* The compressed table format jams by entering the "jam state", * losing information about the previous state in the process. * In order to recover the previous state, we effectively need * to keep backing-up information.
*/
++num_backing_up;
if (reject) { /* Write out accepting list and pointer list.
* First we generate the "yy_acclist" array. In the process, * we compute the indices that will go into the "yy_accept" * array, and save the indices in the dfaacc array.
*/ int EOB_accepting_list[2];
/* Set up accepting structures for the End Of Buffer state. */
EOB_accepting_list[0] = 0;
EOB_accepting_list[1] = end_of_buffer_action;
accsiz[end_of_buffer_state] = 1;
dfaacc[end_of_buffer_state].dfaacc_set =
EOB_accepting_list;
if (trace)
fprintf (stderr,
_("state # %d accepts: "),
i);
for (k = 1; k <= nacc; ++k) { int accnum = accset[k];
++j;
if (variable_trailing_context_rules
&& !(accnum &
YY_TRAILING_HEAD_MASK)
&& accnum > 0
&& accnum <= num_rules
&& rule_type[accnum] ==
RULE_VARIABLE) { /* Special hack to flag * accepting number as part * of trailing context rule.
*/
accnum |= YY_TRAILING_MASK;
}
for (i = 1; i <= lastdfa; ++i)
acc_array[i] = dfaacc[i].dfaacc_state;
/* add accepting number for jam state */
acc_array[i] = 0;
}
/* Begin generating yy_accept */
/* Spit out "yy_accept" array. If we're doing "reject", it'll be * pointers into the "yy_acclist" array. Otherwise it's actual * accepting numbers. In either case, we just dump the numbers.
*/
/* "lastdfa + 2" is the size of "yy_accept"; includes room for C arrays * beginning at 0 and for "jam" state.
*/
k = lastdfa + 2;
if (reject) /* We put a "cap" on the table associating lists of accepting * numbers with state numbers. This is needed because we tell * where the end of an accepting list is by looking at where * the list for the next state starts.
*/
++k;
for (i = 1; i <= tblend; ++i) { /* Note, the order of the following test is important. * If chk[i] is 0, then nxt[i] is undefined.
*/ if (chk[i] == 0 || nxt[i] == 0)
nxt[i] = jamstate; /* new state is the JAM state */
mkdata (nxt[i]);
yynxt_data[i] = nxt[i];
}
dataend (); if (tablesext) {
yytbl_data_compress (yynxt_tbl); if (yytbl_data_fwrite (&tableswr, yynxt_tbl) < 0)
flexerror (_("Could not write yynxt_tbl"));
yytbl_data_destroy (yynxt_tbl);
yynxt_tbl = NULL;
} /* End generating yy_nxt */
if (fullspd) { /* Need to define the transet type as a size large * enough to hold the biggest offset.
*/ int total_table_size = tblend + numecs + 1; char *trans_offset_type =
(total_table_size >= INT16_MAX || long_align) ? "flex_int32_t" : "flex_int16_t";
/* We require that yy_verify and yy_nxt must be of the same size int. */
indent_put2s ("%s yy_verify;", trans_offset_type);
/* In cases where its sister yy_verify *is* a "yes, there is * a transition", yy_nxt is the offset (in records) to the * next state. In most cases where there is no transition, * the value of yy_nxt is irrelevant. If yy_nxt is the -1th * record of a state, though, then yy_nxt is the action number * for that state.
*/
indent_put2s ("%s yy_nxt;", trans_offset_type);
indent_puts ("};");
indent_down ();
} else { /* We generate a bogus 'struct yy_trans_info' data type * so we can guarantee that it is always declared in the skel. * This is so we can compile "sizeof(struct yy_trans_info)" * in any scanner.
*/
indent_puts
("/* This struct is not used in this scanner,");
indent_puts (" but its presence is necessary. */");
indent_puts ("struct yy_trans_info");
indent_up ();
indent_puts ("{");
indent_puts ("flex_int32_t yy_verify;");
indent_puts ("flex_int32_t yy_nxt;");
indent_puts ("};");
indent_down ();
}
if (fullspd) {
genctbl (); if (tablesext) { struct yytbl_data *tbl;
tbl = mkctbl ();
yytbl_data_compress (tbl); if (yytbl_data_fwrite (&tableswr, tbl) < 0)
flexerror (_("Could not write ftbl"));
yytbl_data_destroy (tbl);
/* Definitions for backing up. We don't need them if REJECT * is being used because then we use an alternative backin-up * technique instead.
*/ if (num_backing_up > 0 && !reject) { if (!C_plus_plus && !reentrant) {
indent_puts
("static yy_state_type yy_last_accepting_state;");
indent_puts
("static char *yy_last_accepting_cpos;\n");
}
}
if (nultrans) {
flex_int32_t *yynultrans_data = 0;
if (!C_plus_plus && !reentrant) {
indent_puts ("extern int yy_flex_debug;");
indent_put2s ("int yy_flex_debug = %s;\n",
ddebug ? "1" : "0");
}
if (ddebug) { /* Spit out table mapping rules to line numbers. */
out_str_dec (long_align ? get_int32_decl () :
get_int16_decl (), "yy_rule_linenum",
num_rules); for (i = 1; i < num_rules; ++i)
mkdata (rule_linenum[i]);
dataend ();
}
if (reject) {
outn ("m4_ifdef( [[M4_YY_USES_REJECT]],\n[["); /* Declare state buffer variables. */ if (!C_plus_plus && !reentrant) {
outn ("static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;");
outn ("static char *yy_full_match;");
outn ("static int yy_lp;");
}
if (variable_trailing_context_rules) { if (!C_plus_plus && !reentrant) {
outn ("static int yy_looking_for_trail_begin = 0;");
outn ("static int yy_full_lp;");
outn ("static int *yy_full_state;");
}
else {
outn ("/* The intent behind this definition is that it'll catch");
outn (" * any uses of REJECT which flex missed.");
outn (" */");
outn ("#define REJECT reject_used_but_not_detected");
}
if (yymore_used) { if (!C_plus_plus) { if (yytext_is_array) { if (!reentrant){
indent_puts ("static int yy_more_offset = 0;");
indent_puts ("static int yy_prev_more_offset = 0;");
}
} elseif (!reentrant) {
indent_puts
("static int yy_more_flag = 0;");
indent_puts
("static int yy_more_len = 0;");
}
}
/* Copy actions to output file. */
skelout (); /* %% [13.0] - break point in skel */
indent_up ();
gen_bu_action ();
out (&action_array[action_offset]);
line_directive_out (stdout, 0);
/* generate cases for any missing EOF rules */ for (i = 1; i <= lastsc; ++i) if (!sceof[i]) {
do_indent ();
out_str ("case YY_STATE_EOF(%s):\n", scname[i]);
did_eof_rule = true;
}
if (did_eof_rule) {
indent_up ();
indent_puts ("yyterminate();");
indent_down ();
}
/* Generate code for handling NUL's, if needed. */
/* First, deal with backing up and setting up yy_cp if the scanner * finds that it should JAM on the NUL.
*/
skelout (); /* %% [14.0] - break point in skel */
set_indent (4);
if (fullspd || fulltbl)
indent_puts ("yy_cp = YY_G(yy_c_buf_p);");
else { /* compressed table */ if (!reject && !interactive) { /* Do the guaranteed-needed backing up to figure * out the match.
*/
indent_puts
("yy_cp = YY_G(yy_last_accepting_cpos);");
indent_puts
("yy_current_state = YY_G(yy_last_accepting_state);");
}
else /* Still need to initialize yy_cp, though * yy_current_state was set up by * yy_get_previous_state().
*/
indent_puts ("yy_cp = YY_G(yy_c_buf_p);");
}
/* Generate code for yy_get_previous_state(). */
set_indent (1);
skelout (); /* %% [15.0] - break point in skel */
gen_start_state ();
set_indent (2);
skelout (); /* %% [16.0] - break point in skel */
gen_next_state (true);
set_indent (1);
skelout (); /* %% [17.0] - break point in skel */
gen_NUL_trans ();
skelout (); /* %% [18.0] - break point in skel */
skelout (); /* %% [19.0] - break point in skel */ /* Update BOL and yylineno inside of input(). */ if (bol_needed) {
indent_puts
("YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\\n');"); if (do_yylineno) {
indent_puts
("if ( YY_CURRENT_BUFFER_LVALUE->yy_at_bol )");
indent_up ();
indent_puts ("M4_YY_INCR_LINENO();");
indent_down ();
}
}