Build lexer and parser from libCom/Makefile. Since libCom now includes asLib.c and asLib_lex.c we must build antelope and flex without linking them to Com. This works because they only need epicsTempFile anyway. However make doesn't like a subdirectory with the same name as a target object, so the antelope source directory is now called yacc. The two main.c files were also renamed to avoid other build problems. Merge asHost into Com and remove mentions in CONFIG_BASE Lots of noise since SRCS must be renamed to Com_SRCS
708 lines
14 KiB
Plaintext
708 lines
14 KiB
Plaintext
|
|
/* parse.y - parser for flex input */
|
|
|
|
%token CHAR NUMBER SECTEND SCDECL XSCDECL WHITESPACE NAME PREVCCL EOF_OP
|
|
|
|
%{
|
|
/*-
|
|
* 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.
|
|
*
|
|
* Redistribution and use in source and binary forms are permitted provided
|
|
* that: (1) source distributions retain this entire copyright notice and
|
|
* comment, and (2) distributions including binaries display the following
|
|
* acknowledgement: ``This product includes software developed by the
|
|
* University of California, Berkeley and its contributors'' in the
|
|
* documentation or other materials provided with the distribution and in
|
|
* all advertising materials mentioning features or use of this software.
|
|
* 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.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] =
|
|
"@(#) $Revision-Id$ (LBL)";
|
|
#endif
|
|
|
|
#include "flexdef.h"
|
|
|
|
int pat, scnum, eps, headcnt, trailcnt, anyccl, lastchar, i, actvp, rulelen;
|
|
int trlcontxt, xcluflg, cclsorted, varlength, variable_trail_rule;
|
|
Char clower();
|
|
|
|
static int madeany = false; /* whether we've made the '.' character class */
|
|
int previous_continued_action; /* whether the previous rule's action was '|' */
|
|
|
|
%}
|
|
|
|
%%
|
|
goal : initlex sect1 sect1end sect2 initforrule
|
|
{ /* add default rule */
|
|
int def_rule;
|
|
|
|
pat = cclinit();
|
|
cclnegate( pat );
|
|
|
|
def_rule = mkstate( -pat );
|
|
|
|
finish_rule( def_rule, false, 0, 0 );
|
|
|
|
for ( i = 1; i <= lastsc; ++i )
|
|
scset[i] = mkbranch( scset[i], def_rule );
|
|
|
|
if ( spprdflt )
|
|
fputs( "YY_FATAL_ERROR( \"flex scanner jammed\" )",
|
|
temp_action_file );
|
|
else
|
|
fputs( "ECHO", temp_action_file );
|
|
|
|
fputs( ";\n\tYY_BREAK\n", temp_action_file );
|
|
}
|
|
;
|
|
|
|
initlex :
|
|
{
|
|
/* initialize for processing rules */
|
|
|
|
/* create default DFA start condition */
|
|
scinstal( "INITIAL", false );
|
|
}
|
|
;
|
|
|
|
sect1 : sect1 startconddecl WHITESPACE namelist1 '\n'
|
|
|
|
|
| error '\n'
|
|
{ synerr( "unknown error processing section 1" ); }
|
|
;
|
|
|
|
sect1end : SECTEND
|
|
;
|
|
|
|
startconddecl : SCDECL
|
|
{
|
|
/* these productions are separate from the s1object
|
|
* rule because the semantics must be done before
|
|
* we parse the remainder of an s1object
|
|
*/
|
|
|
|
xcluflg = false;
|
|
}
|
|
|
|
| XSCDECL
|
|
{ xcluflg = true; }
|
|
;
|
|
|
|
namelist1 : namelist1 WHITESPACE NAME
|
|
{ scinstal( nmstr, xcluflg ); }
|
|
|
|
| NAME
|
|
{ scinstal( nmstr, xcluflg ); }
|
|
|
|
| error
|
|
{ synerr( "bad start condition list" ); }
|
|
;
|
|
|
|
sect2 : sect2 initforrule flexrule '\n'
|
|
|
|
|
;
|
|
|
|
initforrule :
|
|
{
|
|
/* initialize for a parse of one rule */
|
|
trlcontxt = variable_trail_rule = varlength = false;
|
|
trailcnt = headcnt = rulelen = 0;
|
|
current_state_type = STATE_NORMAL;
|
|
previous_continued_action = continued_action;
|
|
new_rule();
|
|
}
|
|
;
|
|
|
|
flexrule : scon '^' rule
|
|
{
|
|
pat = $3;
|
|
finish_rule( pat, variable_trail_rule,
|
|
headcnt, trailcnt );
|
|
|
|
for ( i = 1; i <= actvp; ++i )
|
|
scbol[actvsc[i]] =
|
|
mkbranch( scbol[actvsc[i]], pat );
|
|
|
|
if ( ! bol_needed )
|
|
{
|
|
bol_needed = true;
|
|
|
|
if ( performance_report )
|
|
pinpoint_message(
|
|
"'^' operator results in sub-optimal performance" );
|
|
}
|
|
}
|
|
|
|
| scon rule
|
|
{
|
|
pat = $2;
|
|
finish_rule( pat, variable_trail_rule,
|
|
headcnt, trailcnt );
|
|
|
|
for ( i = 1; i <= actvp; ++i )
|
|
scset[actvsc[i]] =
|
|
mkbranch( scset[actvsc[i]], pat );
|
|
}
|
|
|
|
| '^' rule
|
|
{
|
|
pat = $2;
|
|
finish_rule( pat, variable_trail_rule,
|
|
headcnt, trailcnt );
|
|
|
|
/* add to all non-exclusive start conditions,
|
|
* including the default (0) start condition
|
|
*/
|
|
|
|
for ( i = 1; i <= lastsc; ++i )
|
|
if ( ! scxclu[i] )
|
|
scbol[i] = mkbranch( scbol[i], pat );
|
|
|
|
if ( ! bol_needed )
|
|
{
|
|
bol_needed = true;
|
|
|
|
if ( performance_report )
|
|
pinpoint_message(
|
|
"'^' operator results in sub-optimal performance" );
|
|
}
|
|
}
|
|
|
|
| rule
|
|
{
|
|
pat = $1;
|
|
finish_rule( pat, variable_trail_rule,
|
|
headcnt, trailcnt );
|
|
|
|
for ( i = 1; i <= lastsc; ++i )
|
|
if ( ! scxclu[i] )
|
|
scset[i] = mkbranch( scset[i], pat );
|
|
}
|
|
|
|
| scon EOF_OP
|
|
{ build_eof_action(); }
|
|
|
|
| EOF_OP
|
|
{
|
|
/* this EOF applies to all start conditions
|
|
* which don't already have EOF actions
|
|
*/
|
|
actvp = 0;
|
|
|
|
for ( i = 1; i <= lastsc; ++i )
|
|
if ( ! sceof[i] )
|
|
actvsc[++actvp] = i;
|
|
|
|
if ( actvp == 0 )
|
|
pinpoint_message(
|
|
"warning - all start conditions already have <<EOF>> rules" );
|
|
|
|
else
|
|
build_eof_action();
|
|
}
|
|
|
|
| error
|
|
{ synerr( "unrecognized rule" ); }
|
|
;
|
|
|
|
scon : '<' namelist2 '>'
|
|
;
|
|
|
|
namelist2 : namelist2 ',' NAME
|
|
{
|
|
if ( (scnum = sclookup( nmstr )) == 0 )
|
|
format_pinpoint_message(
|
|
"undeclared start condition %s", nmstr );
|
|
|
|
else
|
|
actvsc[++actvp] = scnum;
|
|
}
|
|
|
|
| NAME
|
|
{
|
|
if ( (scnum = sclookup( nmstr )) == 0 )
|
|
format_pinpoint_message(
|
|
"undeclared start condition %s", nmstr );
|
|
else
|
|
actvsc[actvp = 1] = scnum;
|
|
}
|
|
|
|
| error
|
|
{ synerr( "bad start condition list" ); }
|
|
;
|
|
|
|
rule : re2 re
|
|
{
|
|
if ( transchar[lastst[$2]] != SYM_EPSILON )
|
|
/* provide final transition \now/ so it
|
|
* will be marked as a trailing context
|
|
* state
|
|
*/
|
|
$2 = link_machines( $2, mkstate( SYM_EPSILON ) );
|
|
|
|
mark_beginning_as_normal( $2 );
|
|
current_state_type = STATE_NORMAL;
|
|
|
|
if ( previous_continued_action )
|
|
{
|
|
/* we need to treat this as variable trailing
|
|
* context so that the backup does not happen
|
|
* in the action but before the action switch
|
|
* statement. If the backup happens in the
|
|
* action, then the rules "falling into" this
|
|
* one's action will *also* do the backup,
|
|
* erroneously.
|
|
*/
|
|
if ( ! varlength || headcnt != 0 )
|
|
{
|
|
fprintf( stderr,
|
|
"%s: warning - trailing context rule at line %d made variable because\n",
|
|
program_name, linenum );
|
|
fprintf( stderr,
|
|
" of preceding '|' action\n" );
|
|
}
|
|
|
|
/* mark as variable */
|
|
varlength = true;
|
|
headcnt = 0;
|
|
}
|
|
|
|
if ( varlength && headcnt == 0 )
|
|
{ /* variable trailing context rule */
|
|
/* mark the first part of the rule as the accepting
|
|
* "head" part of a trailing context rule
|
|
*/
|
|
/* by the way, we didn't do this at the beginning
|
|
* of this production because back then
|
|
* current_state_type was set up for a trail
|
|
* rule, and add_accept() can create a new
|
|
* state ...
|
|
*/
|
|
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 '$'
|
|
{
|
|
if ( trlcontxt )
|
|
{
|
|
synerr( "trailing context used twice" );
|
|
$$ = mkstate( SYM_EPSILON );
|
|
}
|
|
|
|
else if ( previous_continued_action )
|
|
{
|
|
/* see the comment in the rule for "re2 re"
|
|
* above
|
|
*/
|
|
if ( ! varlength || headcnt != 0 )
|
|
{
|
|
fprintf( stderr,
|
|
"%s: warning - trailing context rule at line %d made variable because\n",
|
|
program_name, linenum );
|
|
fprintf( stderr,
|
|
" of preceding '|' action\n" );
|
|
}
|
|
|
|
/* mark as variable */
|
|
varlength = true;
|
|
headcnt = 0;
|
|
}
|
|
|
|
trlcontxt = true;
|
|
|
|
if ( ! varlength )
|
|
headcnt = rulelen;
|
|
|
|
++rulelen;
|
|
trailcnt = 1;
|
|
|
|
eps = mkstate( SYM_EPSILON );
|
|
$$ = link_machines( $1,
|
|
link_machines( eps, mkstate( '\n' ) ) );
|
|
}
|
|
|
|
| re
|
|
{
|
|
$$ = $1;
|
|
|
|
if ( trlcontxt )
|
|
{
|
|
if ( varlength && headcnt == 0 )
|
|
/* both head and trail are variable-length */
|
|
variable_trail_rule = true;
|
|
else
|
|
trailcnt = rulelen;
|
|
}
|
|
}
|
|
;
|
|
|
|
|
|
re : re '|' series
|
|
{
|
|
varlength = true;
|
|
$$ = mkor( $1, $3 );
|
|
}
|
|
|
|
| series
|
|
{ $$ = $1; }
|
|
;
|
|
|
|
|
|
re2 : re '/'
|
|
{
|
|
/* this rule is written separately so
|
|
* the reduction will occur before the trailing
|
|
* series is parsed
|
|
*/
|
|
|
|
if ( trlcontxt )
|
|
synerr( "trailing context used twice" );
|
|
else
|
|
trlcontxt = true;
|
|
|
|
if ( varlength )
|
|
/* we hope the trailing context is fixed-length */
|
|
varlength = false;
|
|
else
|
|
headcnt = rulelen;
|
|
|
|
rulelen = 0;
|
|
|
|
current_state_type = STATE_TRAILING_CONTEXT;
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
series : series singleton
|
|
{
|
|
/* this is where concatenation of adjacent patterns
|
|
* gets done
|
|
*/
|
|
$$ = link_machines( $1, $2 );
|
|
}
|
|
|
|
| singleton
|
|
{ $$ = $1; }
|
|
;
|
|
|
|
singleton : singleton '*'
|
|
{
|
|
varlength = true;
|
|
|
|
$$ = mkclos( $1 );
|
|
}
|
|
|
|
| singleton '+'
|
|
{
|
|
varlength = true;
|
|
|
|
$$ = mkposcl( $1 );
|
|
}
|
|
|
|
| singleton '?'
|
|
{
|
|
varlength = true;
|
|
|
|
$$ = mkopt( $1 );
|
|
}
|
|
|
|
| singleton '{' NUMBER ',' NUMBER '}'
|
|
{
|
|
varlength = true;
|
|
|
|
if ( $3 > $5 || $3 < 0 )
|
|
{
|
|
synerr( "bad iteration values" );
|
|
$$ = $1;
|
|
}
|
|
else
|
|
{
|
|
if ( $3 == 0 )
|
|
$$ = mkopt( mkrep( $1, $3, $5 ) );
|
|
else
|
|
$$ = mkrep( $1, $3, $5 );
|
|
}
|
|
}
|
|
|
|
| singleton '{' NUMBER ',' '}'
|
|
{
|
|
varlength = true;
|
|
|
|
if ( $3 <= 0 )
|
|
{
|
|
synerr( "iteration value must be positive" );
|
|
$$ = $1;
|
|
}
|
|
|
|
else
|
|
$$ = mkrep( $1, $3, INFINITY );
|
|
}
|
|
|
|
| singleton '{' NUMBER '}'
|
|
{
|
|
/* the singleton could be something like "(foo)",
|
|
* in which case we have no idea what its length
|
|
* is, so we punt here.
|
|
*/
|
|
varlength = true;
|
|
|
|
if ( $3 <= 0 )
|
|
{
|
|
synerr( "iteration value must be positive" );
|
|
$$ = $1;
|
|
}
|
|
|
|
else
|
|
$$ = link_machines( $1, copysingl( $1, $3 - 1 ) );
|
|
}
|
|
|
|
| '.'
|
|
{
|
|
if ( ! madeany )
|
|
{
|
|
/* create the '.' character class */
|
|
anyccl = cclinit();
|
|
ccladd( anyccl, '\n' );
|
|
cclnegate( anyccl );
|
|
|
|
if ( useecs )
|
|
mkeccl( ccltbl + cclmap[anyccl],
|
|
ccllen[anyccl], nextecm,
|
|
ecgroup, csize, csize );
|
|
|
|
madeany = true;
|
|
}
|
|
|
|
++rulelen;
|
|
|
|
$$ = mkstate( -anyccl );
|
|
}
|
|
|
|
| fullccl
|
|
{
|
|
if ( ! cclsorted )
|
|
/* sort characters for fast searching. We use a
|
|
* shell sort since this list could be large.
|
|
*/
|
|
cshell( ccltbl + cclmap[$1], ccllen[$1], true );
|
|
|
|
if ( useecs )
|
|
mkeccl( ccltbl + cclmap[$1], ccllen[$1],
|
|
nextecm, ecgroup, csize, csize );
|
|
|
|
++rulelen;
|
|
|
|
$$ = mkstate( -$1 );
|
|
}
|
|
|
|
| PREVCCL
|
|
{
|
|
++rulelen;
|
|
|
|
$$ = mkstate( -$1 );
|
|
}
|
|
|
|
| '"' string '"'
|
|
{ $$ = $2; }
|
|
|
|
| '(' re ')'
|
|
{ $$ = $2; }
|
|
|
|
| CHAR
|
|
{
|
|
++rulelen;
|
|
|
|
if ( caseins && $1 >= 'A' && $1 <= 'Z' )
|
|
$1 = clower( $1 );
|
|
|
|
$$ = mkstate( $1 );
|
|
}
|
|
;
|
|
|
|
fullccl : '[' ccl ']'
|
|
{ $$ = $2; }
|
|
|
|
| '[' '^' ccl ']'
|
|
{
|
|
/* *Sigh* - to be compatible Unix lex, negated ccls
|
|
* match newlines
|
|
*/
|
|
#ifdef NOTDEF
|
|
ccladd( $3, '\n' ); /* negated ccls don't match '\n' */
|
|
cclsorted = false; /* because we added the newline */
|
|
#endif
|
|
cclnegate( $3 );
|
|
$$ = $3;
|
|
}
|
|
;
|
|
|
|
ccl : ccl CHAR '-' CHAR
|
|
{
|
|
if ( $2 > $4 )
|
|
synerr( "negative range in character class" );
|
|
|
|
else
|
|
{
|
|
if ( caseins )
|
|
{
|
|
if ( $2 >= 'A' && $2 <= 'Z' )
|
|
$2 = clower( $2 );
|
|
if ( $4 >= 'A' && $4 <= 'Z' )
|
|
$4 = clower( $4 );
|
|
}
|
|
|
|
for ( i = $2; i <= $4; ++i )
|
|
ccladd( $1, i );
|
|
|
|
/* keep track if this ccl is staying in alphabetical
|
|
* order
|
|
*/
|
|
cclsorted = cclsorted && ($2 > lastchar);
|
|
lastchar = $4;
|
|
}
|
|
|
|
$$ = $1;
|
|
}
|
|
|
|
| ccl CHAR
|
|
{
|
|
if ( caseins )
|
|
if ( $2 >= 'A' && $2 <= 'Z' )
|
|
$2 = clower( $2 );
|
|
|
|
ccladd( $1, $2 );
|
|
cclsorted = cclsorted && ($2 > lastchar);
|
|
lastchar = $2;
|
|
$$ = $1;
|
|
}
|
|
|
|
|
|
|
{
|
|
cclsorted = true;
|
|
lastchar = 0;
|
|
$$ = cclinit();
|
|
}
|
|
;
|
|
|
|
string : string CHAR
|
|
{
|
|
if ( caseins )
|
|
if ( $2 >= 'A' && $2 <= 'Z' )
|
|
$2 = clower( $2 );
|
|
|
|
++rulelen;
|
|
|
|
$$ = link_machines( $1, mkstate( $2 ) );
|
|
}
|
|
|
|
|
|
|
{ $$ = mkstate( SYM_EPSILON ); }
|
|
;
|
|
|
|
%%
|
|
|
|
|
|
/* build_eof_action - build the "<<EOF>>" action for the active start
|
|
* conditions
|
|
*/
|
|
|
|
void build_eof_action()
|
|
|
|
{
|
|
int i;
|
|
|
|
for ( i = 1; i <= actvp; ++i )
|
|
{
|
|
if ( sceof[actvsc[i]] )
|
|
format_pinpoint_message(
|
|
"multiple <<EOF>> rules for start condition %s",
|
|
scname[actvsc[i]] );
|
|
|
|
else
|
|
{
|
|
sceof[actvsc[i]] = true;
|
|
fprintf( temp_action_file, "case YY_STATE_EOF(%s):\n",
|
|
scname[actvsc[i]] );
|
|
}
|
|
}
|
|
|
|
line_directive_out( temp_action_file );
|
|
}
|
|
|
|
|
|
/* synerr - report a syntax error */
|
|
|
|
void synerr( str )
|
|
char str[];
|
|
|
|
{
|
|
syntaxerror = true;
|
|
pinpoint_message( str );
|
|
}
|
|
|
|
|
|
/* format_pinpoint_message - write out a message formatted with one string,
|
|
* pinpointing its location
|
|
*/
|
|
|
|
void format_pinpoint_message( msg, arg )
|
|
char msg[], arg[];
|
|
|
|
{
|
|
char errmsg[MAXLINE];
|
|
|
|
(void) sprintf( errmsg, msg, arg );
|
|
pinpoint_message( errmsg );
|
|
}
|
|
|
|
|
|
/* pinpoint_message - write out a message, pinpointing its location */
|
|
|
|
void pinpoint_message( str )
|
|
char str[];
|
|
|
|
{
|
|
fprintf( stderr, "\"%s\", line %d: %s\n", infilename, linenum, str );
|
|
}
|
|
|
|
|
|
/* yyerror - eat up an error message from the parser;
|
|
* currently, messages are ignore
|
|
*/
|
|
|
|
void yyerror( msg )
|
|
char msg[];
|
|
|
|
{
|
|
}
|
|
|
|
#include "scan.c"
|
|
#include "yylex.c"
|
|
#include "flex.c"
|
|
|