* Copyright (c) 1979 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
static char sccsid
[] = "@(#)ey2.c 5.1 (Berkeley) %G%";
# define C_IDENTIFIER 265 /* name followed by colon */
setup(argc
,argv
) int argc
; char *argv
[];
while( argc
>= 2 && argv
[1][0] == '-' ) {
foutput
= copen("y.output", 'w' );
if( foutput
== 0 ) error( "cannot open y.output");
default: error( "illegal option: %c", *argv
[1]);
ftable
= copen( oflag
? "yacc.tmp" : "y.tab.c" , 'w' );
if( ftable
==0 ) error( "cannot open table file" );
if( argc
> 1 ) { cin
= copen( argv
[1], 'r' );
if( cin
== 0 ) error( "cannot open input" );
extval
= 0400; /* beginning of assigned values */
while( ( t
= gettok() ) != EOF
) {
case IDENTIFIER
: j
= chfind(0);
case TERM
: lev
=0; continue;
case LEFT
: lev
=(++i
<<3)|01; continue;
case BINARY
: lev
=(++i
<<3)|02; continue;
case RIGHT
: lev
=(++i
<<3)|03; continue;
if( rflag
){ /* RATFOR */
fprintf( cout
, "define yyerrok yyerrf = 0\n" );
fprintf( cout
, "define yyclearin yychar = -1\n" );
fprintf( cout
, "subroutine yyactr(yyprdn)\n");
fprintf( cout
, "common/yycomn/yylval,yyval,yypv,yyvalv(150)\n" );
fprintf( cout
, "common/yylcom/yychar,yyerrf,yydebu\n" );
fprintf( cout
, "integer yychar, yyerrf, yydebu\n" );
fprintf( cout
, "integer yyprdn,yyval,yylval,yypv,yyvalv\n" );
fprintf( cout
, "#define yyclearin yychar = -1\n" );
fprintf( cout
, "#define yyerrok yyerrflag = 0\n" );
fprintf( cout
, "extern int yychar, yyerrflag;\n" );
fprintf( cout
, "\nint yyval 0;\nint *yypv;\nint yylval 0;");
fprintf( cout
, "\nyyactr(__np__){\n");
trmset
[j
].value
= numbval
;
error("please define type # of %s earlier", trmset
[j
].name
);
default: error("bad precedence syntax, input %d", t
);
/* i is 0 when a rule can begin, 1 otherwise */
for(;;) switch( t
=gettok() ) {
case C_IDENTIFIER
: if( mem
== prdptr
[1] ) { /* first time */
fprintf( cout
, "goto 1000\n" );
else fprintf( cout
, "\nswitch(__np__){\n");
if( i
!= 0 ) error( "previous rule not terminated" );
if( *mem
< NTBASE
)error( "token illegal on lhs of grammar rule" );
if(*mem
< NTBASE
)levprd
[nprod
]=trmlev
[*mem
];
if(i
==0) error("missing :");
case '=': levprd
[nprod
] |= 04;
if( i
==0 ) error("semicolon preceeds action");
fprintf( cout
, rflag
?"\n%d ":"\ncase %d:", nprod
);
fprintf( cout
, rflag
? " return" : " break;" );
if (t
=='|'){i
=1;*mem
++ = *prdptr
[nprod
-1];}
case 0: /* End Of File */
case MARK
: if( i
!= 0 ) error( "rule not terminated before %%%% or EOF" );
/* copy the programs which follow the rules */
while (( c
=fgetc( cin
)) != EOF
) fputc(c
,cout
);
if( i
==0 ) error( "%%prec must appear inside rule" );
if( gettok()!=IDENTIFIER
)error("illegal %%prec syntax" );
if(j
>=NTBASE
)error("nonterminal %s illegal after %%prec", nontrst
[j
-NTBASE
].name
);
if( i
!=0 ) error( "%%{ appears within a rule" );
default: error( "syntax error, input %d", t
);
/* finish action routine */
fprintf( cout
, "\n1000 goto(" );
for( i
=1; i
<nprod
; ++i
){
fprintf( cout
, "%d,", (levprd
[i
]&04)==0?999:i
);
fprintf( cout
, "999),yyprdn\n" );
fprintf( cout
, "999 return\nend\n" );
fprintf( cout
, "define YYERRCODE %d\n", trmset
[2].value
);
fprintf( cout
, "\n}\n}\n" );
fprintf( cout
, "int yyerrval %d;\n", trmset
[2].value
);
/* define ctokn to be a terminal if t=0
or a nonterminal if t=1 */
if( ++nnonter
>= ntlim
) error("too many nonterminals, limit %d",ntlim
);
nontrst
[nnonter
].name
= ctokn
;
return( NTBASE
+ nnonter
);
if( ++nterms
>= tlim
) error("too many terminals, limit %d",tlim
);
trmset
[nterms
].name
= ctokn
;
if( ctokn
[0]==' ' && ctokn
[2]=='\0' ) /* single character literal */
trmset
[nterms
].value
= ctokn
[1];
else if ( ctokn
[0]==' ' && ctokn
[1]=='\\' ) { /* escape sequence */
if( ctokn
[3] == '\0' ){ /* single character escape sequence */
/* character which is escaped */
case 'n': trmset
[nterms
].value
= '\n'; break;
case 'r': trmset
[nterms
].value
= '\r'; break;
case 'b': trmset
[nterms
].value
= '\b'; break;
case 't': trmset
[nterms
].value
= '\t'; break;
case '\'': trmset
[nterms
].value
= '\''; break;
case '"': trmset
[nterms
].value
= '"'; break;
case '\\': trmset
[nterms
].value
= '\\'; break;
default: error( "invalid escape" );
else if( ctokn
[2] <= '7' && ctokn
[2]>='0' ){ /* \nnn sequence */
if( ctokn
[3]<'0' || ctokn
[3] > '7' || ctokn
[4]<'0' ||
ctokn
[4]>'7' || ctokn
[5] != '\0' ) error("illegal \\nnn construction" );
trmset
[nterms
].value
= 64*(ctokn
[2]-'0')+8*(ctokn
[3]-'0')+ctokn
[4]-'0';
if( trmset
[nterms
].value
== 0 ) error( "'\\000' is illegal" );
trmset
[nterms
].value
= extval
++;
defout(){ /* write out the defines (at the end of the declaration section) */
for( i
=ndefout
; i
<=nterms
; ++i
){
if( *cp
== ' ' ) ++cp
; /* literals */
for( ; (c
= *cp
)!='\0'; ++cp
){
fprintf( cout
, "%c define %s %d\n", rflag
?' ':'#', trmset
[i
].name
, trmset
[i
].value
);
/* put character away into cnames */
if( cnamp
>= &cnames
[cnamsz
] ) error("too many characters in id's and literals" );
static int peekline
; /* number of '\n' seen in lookahead */
auto int c
, match
, reserve
;
while( c
==' ' || c
=='\n' || c
=='\t' || c
== '\014'){
if( c
== '\n' ) ++lineno
;
{if (fgetc( cin
)!='*')error("illegal /");
if( c
== '\n' ) ++lineno
;
{if((c
=fgetc( cin
))=='/')break;}
if( c
== '\n' || c
== '\0' )
error("illegal or missing ' or \"");
else if( c
== match
) break;
case '\\': switch(c
=fgetc( cin
))
case '2': return(BINARY
);
case '{': return(LCURLY
);
default: if( c
>= '0' && c
<= '9' ){ /* number */
base
= (c
=='0') ? 8 : 10 ;
for( c
=fgetc( cin
); c
>='0' && c
<='9'; c
=fgetc( cin
) ){
numbval
= numbval
*base
+ c
- '0';
else if( (c
>='a'&&c
<='z')||(c
>='A'&&c
<='Z')||c
=='_'||c
=='.'||c
=='$'){
while( (c
>='a'&&c
<='z') ||
c
=='_' || c
=='.' || c
=='$' ) {
if( peekc
>=0 ) { c
= peekc
; peekc
= -1; }
if( reserve
){ /* find a reserved word */
if( compare("term")) return( TERM
);
if( compare("TERM")) return( TERM
);
if( compare("token")) return( TERM
);
if( compare("TOKEN")) return( TERM
);
if( compare("left")) return( LEFT
);
if( compare("LEFT")) return( LEFT
);
if( compare("nonassoc")) return( BINARY
);
if( compare("NONASSOC")) return( BINARY
);
if( compare("binary")) return( BINARY
);
if( compare("BINARY")) return( BINARY
);
if( compare("right")) return( RIGHT
);
if( compare("RIGHT")) return( RIGHT
);
if( compare("prec")) return( PREC
);
if( compare("PREC")) return( PREC
);
error("invalid escape, or illegal reserved word: %s", ctokn
);
/* look ahead to distinguish IDENTIFIER from C_IDENTIFIER */
while( peekc
==' ' || peekc
=='\t' || peekc
== '\n' || peekc
== '\014' )
if( peekc
== '\n' ) ++peekline
;
if( peekc
!= ':' ) return( IDENTIFIER
);
if(compare(trmset
[i
].name
)){
if(compare(nontrst
[i
].name
)) {
if( t
>1 && ctokn
[0] != ' ' )
error( "%s should have been defined earlier", ctokn
);
cpycode(){ /* copies code between \{ and \} */
if( (c
=fgetc( cin
)) == '}' ) return;
if( (c
=fgetc( cin
)) == '}' ) return;
if( c
== '\n' ) ++lineno
;
cpyact(){ /* copy C action to the next ; or closing } */
int brac
, c
, match
, *i
, j
, s
;
fprintf( cout
, "yyval");
if( c
>='0' && c
<= '9' ){
while( c
>='0' && c
<= '9' ){
if( rflag
) fprintf( cout
, "yyvalv(yypv%c%d)", s
==1?'+':'-', j
);
else fprintf( cout
, "yypv[%d]", s
*j
);
if( s
<0 ) fputc('-', cout
);
case '/': /* look for comments */
/* it really is a comment */
while( (c
=fgetc( cin
)) != EOF
){
if( (c
=fgetc( cin
)) == '/' ) goto lcopy
;
error( "EOF inside comment" );
case '\'': /* character constant */
case '"': /* character string */
while( (c
=fgetc( cin
)) != EOF
){
else if( c
==match
) goto lcopy
;
error( "EOF in string or character constant" );
error("action does not terminate");