%token CHAR NUMBER SECTEND SCDECL XSCDECL NAME PREVCCL EOF_OP
%token OPTION_OP OPT_OUTFILE OPT_PREFIX OPT_YYCLASS OPT_HEADER OPT_EXTRA_TYPE
%token OPT_TABLES
%token CCE_ALNUM CCE_ALPHA CCE_BLANK CCE_CNTRL CCE_DIGIT CCE_GRAPH
%token CCE_LOWER CCE_PRINT CCE_PUNCT CCE_SPACE CCE_UPPER CCE_XDIGIT
%token CCE_NEG_ALNUM CCE_NEG_ALPHA CCE_NEG_BLANK CCE_NEG_CNTRL CCE_NEG_DIGIT CCE_NEG_GRAPH
%token CCE_NEG_LOWER CCE_NEG_PRINT CCE_NEG_PUNCT CCE_NEG_SPACE CCE_NEG_UPPER CCE_NEG_XDIGIT
%left CCL_OP_DIFF CCL_OP_UNION
%token BEGIN_REPEAT_POSIX END_REPEAT_POSIX BEGIN_REPEAT_FLEX END_REPEAT_FLEX
%{
#include "flexdef.h"
#include "tables.h"
int pat, scnum, eps, headcnt, trailcnt, lastchar, i, rulelen;
int trlcontxt, xcluflg, currccl, cclsorted, varlength, variable_trail_rule;
int *scon_stk;
int scon_stk_ptr;
static int madeany = false;
static int ccldot, cclany;
int previous_continued_action;
#define format_warn3(fmt, a1, a2) \
do{ \
char fw3_msg[MAXLINE];\
snprintf( fw3_msg, MAXLINE,(fmt), (a1), (a2) );\
warn( fw3_msg );\
}while(0)
#define CCL_EXPR(func) \
do{ \
int c; \
for ( c = 0; c < csize; ++c ) \
if ( isascii(c) && func(c) ) \
ccladd( currccl, c ); \
}while(0)
#define CCL_NEG_EXPR(func) \
do{ \
int c; \
for ( c = 0; c < csize; ++c ) \
if ( !func(c) ) \
ccladd( currccl, c ); \
}while(0)
#define YYSTYPE int
%}
%%
goal : initlex sect1 sect1end sect2 initforrule
{
int def_rule;
pat = cclinit();
cclnegate( pat );
def_rule = mkstate( -pat );
default_rule = num_rules;
finish_rule( def_rule, false, 0, 0, 0);
for ( i = 1; i <= lastsc; ++i )
scset[i] = mkbranch( scset[i], def_rule );
if ( spprdflt )
add_action(
"YY_FATAL_ERROR( \"flex scanner jammed\" )" );
else
add_action( "ECHO" );
add_action( ";\n\tYY_BREAK\n" );
}
;
initlex :
{
scinstal( "INITIAL", false );
}
;
sect1 : sect1 startconddecl namelist1
| sect1 options
|
| error
{ synerr( _("unknown error processing section 1") ); }
;
sect1end : SECTEND
{
check_options();
scon_stk = allocate_integer_array( lastsc + 1 );
scon_stk_ptr = 0;
}
;
startconddecl : SCDECL
{ xcluflg = false; }
| XSCDECL
{ xcluflg = true; }
;
namelist1 : namelist1 NAME
{ scinstal( nmstr, xcluflg ); }
| NAME
{ scinstal( nmstr, xcluflg ); }
| error
{ synerr( _("bad start condition list") ); }
;
options : OPTION_OP optionlist
;
optionlist : optionlist option
|
;
option : OPT_OUTFILE '=' NAME
{
outfilename = copy_string( nmstr );
did_outfilename = 1;
}
| OPT_EXTRA_TYPE '=' NAME
{ extra_type = copy_string( nmstr ); }
| OPT_PREFIX '=' NAME
{ prefix = copy_string( nmstr ); }
| OPT_YYCLASS '=' NAME
{ yyclass = copy_string( nmstr ); }
| OPT_HEADER '=' NAME
{ headerfilename = copy_string( nmstr ); }
| OPT_TABLES '=' NAME
{ tablesext = true; tablesfilename = copy_string( nmstr ); }
;
sect2 : sect2 scon initforrule flexrule '\n'
{ scon_stk_ptr = $2; }
| sect2 scon '{' sect2 '}'
{ scon_stk_ptr = $2; }
|
;
initforrule :
{
trlcontxt = variable_trail_rule = varlength = false;
trailcnt = headcnt = rulelen = 0;
current_state_type = STATE_NORMAL;
previous_continued_action = continued_action;
in_rule = true;
new_rule();
}
;
flexrule : '^' rule
{
pat = $2;
finish_rule( pat, variable_trail_rule,
headcnt, trailcnt , previous_continued_action);
if ( scon_stk_ptr > 0 )
{
for ( i = 1; i <= scon_stk_ptr; ++i )
scbol[scon_stk[i]] =
mkbranch( scbol[scon_stk[i]],
pat );
}
else
{
for ( i = 1; i <= lastsc; ++i )
if ( ! scxclu[i] )
scbol[i] = mkbranch( scbol[i],
pat );
}
if ( ! bol_needed )
{
bol_needed = true;
if ( performance_report > 1 )
pinpoint_message(
"'^' operator results in sub-optimal performance" );
}
}
| rule
{
pat = $1;
finish_rule( pat, variable_trail_rule,
headcnt, trailcnt , previous_continued_action);
if ( scon_stk_ptr > 0 )
{
for ( i = 1; i <= scon_stk_ptr; ++i )
scset[scon_stk[i]] =
mkbranch( scset[scon_stk[i]],
pat );
}
else
{
for ( i = 1; i <= lastsc; ++i )
if ( ! scxclu[i] )
scset[i] =
mkbranch( scset[i],
pat );
}
}
| EOF_OP
{
if ( scon_stk_ptr > 0 )
build_eof_action();
else
{
for ( i = 1; i <= lastsc; ++i )
if ( ! sceof[i] )
scon_stk[++scon_stk_ptr] = i;
if ( scon_stk_ptr == 0 )
warn(
"all start conditions already have <<EOF>> rules" );
else
build_eof_action();
}
}
| error
{ synerr( _("unrecognized rule") ); }
;
scon_stk_ptr :
{ $$ = scon_stk_ptr; }
;
scon : '<' scon_stk_ptr namelist2 '>'
{ $$ = $2; }
| '<' '*' '>'
{
$$ = scon_stk_ptr;
for ( i = 1; i <= lastsc; ++i )
{
int j;
for ( j = 1; j <= scon_stk_ptr; ++j )
if ( scon_stk[j] == i )
break;
if ( j > scon_stk_ptr )
scon_stk[++scon_stk_ptr] = i;
}
}
|
{ $$ = scon_stk_ptr; }
;
namelist2 : namelist2 ',' sconname
| sconname
| error
{ synerr( _("bad start condition list") ); }
;
sconname : NAME
{
if ( (scnum = sclookup( nmstr )) == 0 )
format_pinpoint_message(
"undeclared start condition %s",
nmstr );
else
{
for ( i = 1; i <= scon_stk_ptr; ++i )
if ( scon_stk[i] == scnum )
{
format_warn(
"<%s> specified twice",
scname[scnum] );
break;
}
if ( i > scon_stk_ptr )
scon_stk[++scon_stk_ptr] = scnum;
}
}
;
rule : re2 re
{
if ( transchar[lastst[$2]] != SYM_EPSILON )
$2 = link_machines( $2,
mkstate( SYM_EPSILON ) );
mark_beginning_as_normal( $2 );
current_state_type = STATE_NORMAL;
if ( previous_continued_action )
{
if ( ! varlength || headcnt != 0 )
warn(
"trailing context made variable due to preceding '|' action" );
varlength = true;
headcnt = 0;
}
if ( lex_compat || (varlength && headcnt == 0) )
{
add_accept( $1,
num_rules | YY_TRAILING_HEAD_MASK );
variable_trail_rule = true;
}
else
trailcnt = rulelen;
$$ = link_machines( $1, $2 );
}
| re2 re '$'
{ synerr( _("trailing context used twice") ); }
| re '$'
{
headcnt = 0;
trailcnt = 1;
rulelen = 1;
varlength = false;
current_state_type = STATE_TRAILING_CONTEXT;
if ( trlcontxt )
{
synerr( _("trailing context used twice") );
$$ = mkstate( SYM_EPSILON );
}
else if ( previous_continued_action )
{
warn(
"trailing context made variable due to preceding '|' action" );
varlength = true;
}
if ( lex_compat || varlength )
{
add_accept( $1,
num_rules | YY_TRAILING_HEAD_MASK );
variable_trail_rule = true;
}
trlcontxt = true;
eps = mkstate( SYM_EPSILON );
$$ = link_machines( $1,
link_machines( eps, mkstate( '\n' ) ) );
}
| re
{
$$ = $1;
if ( trlcontxt )
{
if ( lex_compat || (varlength && headcnt == 0) )
variable_trail_rule = true;
else
trailcnt = rulelen;
}
}
;
re : re '|' series
{
varlength = true;
$$ = mkor( $1, $3 );
}
| series
{ $$ = $1; }
;
re2 : re '/'
{
if ( trlcontxt )
synerr( _("trailing context used twice") );
else
trlcontxt = true;
if ( varlength )
varlength = false;
else
headcnt = rulelen;
rulelen = 0;
current_state_type = STATE_TRAILING_CONTEXT;
$$ = $1;
}
;
series : series singleton
{
$$ = link_machines( $1, $2 );
}
| singleton
{ $$ = $1; }
| series BEGIN_REPEAT_POSIX NUMBER ',' NUMBER END_REPEAT_POSIX
{
varlength = true;
if ( $3 > $5 || $3 < 0 )
{
synerr( _("bad iteration values") );
$$ = $1;
}
else
{
if ( $3 == 0 )
{
if ( $5 <= 0 )
{
synerr(
_("bad iteration values") );
$$ = $1;
}
else
$$ = mkopt(
mkrep( $1, 1, $5 ) );
}
else
$$ = mkrep( $1, $3, $5 );
}
}
| series BEGIN_REPEAT_POSIX NUMBER ',' END_REPEAT_POSIX
{
varlength = true;
if ( $3 <= 0 )
{
synerr( _("iteration value must be positive") );
$$ = $1;
}
else
$$ = mkrep( $1, $3, INFINITE_REPEAT );
}
| series BEGIN_REPEAT_POSIX NUMBER END_REPEAT_POSIX
{
varlength = true;
if ( $3 <= 0 )
{
synerr( _("iteration value must be positive")
);
$$ = $1;
}
else
$$ = link_machines( $1,
copysingl( $1, $3 - 1 ) );
}
;
singleton : singleton '*'
{
varlength = true;
$$ = mkclos( $1 );
}
| singleton '+'
{
varlength = true;
$$ = mkposcl( $1 );
}
| singleton '?'
{
varlength = true;
$$ = mkopt( $1 );
}
| singleton BEGIN_REPEAT_FLEX NUMBER ',' NUMBER END_REPEAT_FLEX
{
varlength = true;
if ( $3 > $5 || $3 < 0 )
{
synerr( _("bad iteration values") );
$$ = $1;
}
else
{
if ( $3 == 0 )
{
if ( $5 <= 0 )
{
synerr(
_("bad iteration values") );
$$ = $1;
}
else
$$ = mkopt(
mkrep( $1, 1, $5 ) );
}
else
$$ = mkrep( $1, $3, $5 );
}
}
| singleton BEGIN_REPEAT_FLEX NUMBER ',' END_REPEAT_FLEX
{
varlength = true;
if ( $3 <= 0 )
{
synerr( _("iteration value must be positive") );
$$ = $1;
}
else
$$ = mkrep( $1, $3, INFINITE_REPEAT );
}
| singleton BEGIN_REPEAT_FLEX NUMBER END_REPEAT_FLEX
{
varlength = true;
if ( $3 <= 0 )
{
synerr( _("iteration value must be positive") );
$$ = $1;
}
else
$$ = link_machines( $1,
copysingl( $1, $3 - 1 ) );
}
| '.'
{
if ( ! madeany )
{
ccldot = cclinit();
ccladd( ccldot, '\n' );
cclnegate( ccldot );
if ( useecs )
mkeccl( ccltbl + cclmap[ccldot],
ccllen[ccldot], nextecm,
ecgroup, csize, csize );
cclany = cclinit();
cclnegate( cclany );
if ( useecs )
mkeccl( ccltbl + cclmap[cclany],
ccllen[cclany], nextecm,
ecgroup, csize, csize );
madeany = true;
}
++rulelen;
if (sf_dot_all())
$$ = mkstate( -cclany );
else
$$ = mkstate( -ccldot );
}
| fullccl
{
qsort( ccltbl + cclmap[$1], ccllen[$1], sizeof (*ccltbl), cclcmp );
if ( useecs )
mkeccl( ccltbl + cclmap[$1], ccllen[$1],
nextecm, ecgroup, csize, csize );
++rulelen;
if (ccl_has_nl[$1])
rule_has_nl[num_rules] = true;
$$ = mkstate( -$1 );
}
| PREVCCL
{
++rulelen;
if (ccl_has_nl[$1])
rule_has_nl[num_rules] = true;
$$ = mkstate( -$1 );
}
| '"' string '"'
{ $$ = $2; }
| '(' re ')'
{ $$ = $2; }
| CHAR
{
++rulelen;
if ($1 == nlch)
rule_has_nl[num_rules] = true;
if (sf_case_ins() && has_case($1))
$$ = mkor (mkstate($1), mkstate(reverse_case($1)));
else
$$ = mkstate( $1 );
}
;
fullccl:
fullccl CCL_OP_DIFF braceccl { $$ = ccl_set_diff ($1, $3); }
| fullccl CCL_OP_UNION braceccl { $$ = ccl_set_union ($1, $3); }
| braceccl
;
braceccl:
'[' ccl ']' { $$ = $2; }
| '[' '^' ccl ']'
{
cclnegate( $3 );
$$ = $3;
}
;
ccl : ccl CHAR '-' CHAR
{
if (sf_case_ins())
{
if (has_case ($2) != has_case ($4)
|| (has_case ($2) && (b_islower ($2) != b_islower ($4)))
|| (has_case ($2) && (b_isupper ($2) != b_isupper ($4))))
format_warn3 (
_("the character range [%c-%c] is ambiguous in a case-insensitive scanner"),
$2, $4);
else if (!has_case ($2) && !has_case ($4) && !range_covers_case ($2, $4))
format_warn3 (
_("the character range [%c-%c] is ambiguous in a case-insensitive scanner"),
$2, $4);
}
if ( $2 > $4 )
synerr( _("negative range in character class") );
else
{
for ( i = $2; i <= $4; ++i )
ccladd( $1, i );
cclsorted = cclsorted && ($2 > lastchar);
lastchar = $4;
if (sf_case_ins() && has_case($2) && has_case($4)){
$2 = reverse_case ($2);
$4 = reverse_case ($4);
for ( i = $2; i <= $4; ++i )
ccladd( $1, i );
cclsorted = cclsorted && ($2 > lastchar);
lastchar = $4;
}
}
$$ = $1;
}
| ccl CHAR
{
ccladd( $1, $2 );
cclsorted = cclsorted && ($2 > lastchar);
lastchar = $2;
if (sf_case_ins() && has_case($2)){
$2 = reverse_case ($2);
ccladd ($1, $2);
cclsorted = cclsorted && ($2 > lastchar);
lastchar = $2;
}
$$ = $1;
}
| ccl ccl_expr
{
cclsorted = false;
$$ = $1;
}
|
{
cclsorted = true;
lastchar = 0;
currccl = $$ = cclinit();
}
;
ccl_expr:
CCE_ALNUM { CCL_EXPR(isalnum); }
| CCE_ALPHA { CCL_EXPR(isalpha); }
| CCE_BLANK { CCL_EXPR(isblank); }
| CCE_CNTRL { CCL_EXPR(iscntrl); }
| CCE_DIGIT { CCL_EXPR(isdigit); }
| CCE_GRAPH { CCL_EXPR(isgraph); }
| CCE_LOWER {
CCL_EXPR(islower);
if (sf_case_ins())
CCL_EXPR(isupper);
}
| CCE_PRINT { CCL_EXPR(isprint); }
| CCE_PUNCT { CCL_EXPR(ispunct); }
| CCE_SPACE { CCL_EXPR(isspace); }
| CCE_XDIGIT { CCL_EXPR(isxdigit); }
| CCE_UPPER {
CCL_EXPR(isupper);
if (sf_case_ins())
CCL_EXPR(islower);
}
| CCE_NEG_ALNUM { CCL_NEG_EXPR(isalnum); }
| CCE_NEG_ALPHA { CCL_NEG_EXPR(isalpha); }
| CCE_NEG_BLANK { CCL_NEG_EXPR(isblank); }
| CCE_NEG_CNTRL { CCL_NEG_EXPR(iscntrl); }
| CCE_NEG_DIGIT { CCL_NEG_EXPR(isdigit); }
| CCE_NEG_GRAPH { CCL_NEG_EXPR(isgraph); }
| CCE_NEG_PRINT { CCL_NEG_EXPR(isprint); }
| CCE_NEG_PUNCT { CCL_NEG_EXPR(ispunct); }
| CCE_NEG_SPACE { CCL_NEG_EXPR(isspace); }
| CCE_NEG_XDIGIT { CCL_NEG_EXPR(isxdigit); }
| CCE_NEG_LOWER {
if ( sf_case_ins() )
warn(_("[:^lower:] is ambiguous in case insensitive scanner"));
else
CCL_NEG_EXPR(islower);
}
| CCE_NEG_UPPER {
if ( sf_case_ins() )
warn(_("[:^upper:] ambiguous in case insensitive scanner"));
else
CCL_NEG_EXPR(isupper);
}
;
string : string CHAR
{
if ( $2 == nlch )
rule_has_nl[num_rules] = true;
++rulelen;
if (sf_case_ins() && has_case($2))
$$ = mkor (mkstate($2), mkstate(reverse_case($2)));
else
$$ = mkstate ($2);
$$ = link_machines( $1, $$);
}
|
{ $$ = mkstate( SYM_EPSILON ); }
;
%%
void build_eof_action(void)
{
int i;
char action_text[MAXLINE];
for ( i = 1; i <= scon_stk_ptr; ++i )
{
if ( sceof[scon_stk[i]] )
format_pinpoint_message(
"multiple <<EOF>> rules for start condition %s",
scname[scon_stk[i]] );
else
{
sceof[scon_stk[i]] = true;
if (previous_continued_action )
add_action("YY_RULE_SETUP\n");
snprintf( action_text, sizeof(action_text), "case YY_STATE_EOF(%s):\n",
scname[scon_stk[i]] );
add_action( action_text );
}
}
line_directive_out( (FILE *) 0, 1 );
--num_rules;
++num_eof_rules;
}
void format_synerr(const char *msg, const char arg[])
{
char errmsg[MAXLINE];
(void) snprintf( errmsg, sizeof(errmsg), msg, arg );
synerr( errmsg );
}
void synerr(const char *str)
{
syntaxerror = true;
pinpoint_message( str );
}
void format_warn(const char *msg, const char arg[])
{
char warn_msg[MAXLINE];
snprintf( warn_msg, sizeof(warn_msg), msg, arg );
warn( warn_msg );
}
void warn(const char *str)
{
line_warning( str, linenum );
}
void format_pinpoint_message(const char *msg, const char arg[])
{
char errmsg[MAXLINE];
snprintf( errmsg, sizeof(errmsg), msg, arg );
pinpoint_message( errmsg );
}
void pinpoint_message(const char *str)
{
line_pinpoint( str, linenum );
}
void line_warning(const char *str, int line)
{
char warning[MAXLINE];
if ( ! nowarn )
{
snprintf( warning, sizeof(warning), "warning, %s", str );
line_pinpoint( warning, line );
}
}
void line_pinpoint(const char *str, int line)
{
fprintf( stderr, "%s:%d: %s\n", infilename, line, str );
}
void yyerror(const char *msg)
{
}