static char sccsid
[] = "@(#)y2.c 4.1 (Berkeley) 2/11/83";
# define C_IDENTIFIER 265 /* name followed by colon */
/* communication variables between various I/O routines */
char *infile
; /* input file name */
int numbval
; /* value of an input number */
char tokname
[NAMESIZE
]; /* input token name */
char cnames
[CNAMSZ
]; /* place where token and nonterminal names are stored */
int cnamsz
= CNAMSZ
; /* size of cnames */
char * cnamp
= cnames
; /* place where next name is to be put in */
int ndefout
= 3; /* number of defined symbols output */
int ntypes
; /* number of types defined */
char * typeset
[NTYPES
]; /* pointers to type tags */
/* symbol tables for tokens and nonterminals */
struct toksymb tokset
[NTERMS
];
struct ntsymb nontrst
[NNONTERM
];
int start
; /* start symbol */
/* assigned token type values */
/* input and output file descriptors */
FILE * finput
; /* yacc input file */
FILE * faction
; /* file for saving actions */
FILE * fdefine
; /* file for # defines */
FILE * ftable
; /* y.tab.c file */
FILE * ftemp
; /* tempfile to pass 2 */
FILE * foutput
; /* y.output file */
/* storage for grammar rules */
int mem0
[MEMSIZE
] ; /* production storage */
int nprod
= 1; /* number of productions */
int *prdptr
[NPROD
]; /* pointers to descriptions of productions */
int levprd
[NPROD
] ; /* precedence levels for the productions */
setup(argc
,argv
) int argc
; char *argv
[];
while( argc
>= 2 && argv
[1][0] == '-' ) {
foutput
= fopen(FILEU
, "w" );
if( foutput
== NULL
) error( "cannot open y.output" );
fdefine
= fopen( FILED
, "w" );
fprintf( stderr
, "`o' flag now default in yacc\n" );
error( "Ratfor Yacc is dead: sorry...\n" );
error( "illegal option: %c", *argv
[1]);
ftable
= fopen( OFILE
, "w" );
if( ftable
== NULL
) error( "cannot open table file" );
ftemp
= fopen( TEMPNAME
, "w" );
faction
= fopen( ACTNAME
, "w" );
if( ftemp
==NULL
|| faction
==NULL
) error( "cannot open temp file" );
if( argc
< 2 || ((finput
=fopen( infile
=argv
[1], "r" )) == NULL
) ){
error( "cannot open input file" );
/* sorry -- no yacc parser here.....
we must bootstrap somehow... */
for( t
=gettok(); t
!=MARK
&& t
!= ENDFILE
; ){
if( (t
=gettok()) != IDENTIFIER
){
error( "bad %%start construction" );
start
= chfind(1,tokname
);
if( (t
=gettok()) != TYPENAME
) error( "bad syntax in %%type" );
if( (t
=chfind( 1, tokname
) ) < NTBASE
) {
error( "type redeclaration of token %s",
else SETTYPE( toklev
[t
],ty
);
j
= nontrst
[t
-NTBASE
].tvalue
;
error( "type redeclaration of nonterminal %s",
nontrst
[t
-NTBASE
].name
);
else nontrst
[t
-NTBASE
].tvalue
= ty
;
/* copy the union declaration to the output */
lev
= t
-TERM
; /* nonzero means new prec. and assoc. */
/* get identifiers so defined */
if( t
== TYPENAME
){ /* there is a type defined */
if( ASSOC(toklev
[j
]) ) error( "redeclaration of precedence of %s", tokname
);
if( TYPE(toklev
[j
]) ) error( "redeclaration of type of %s", tokname
);
if( (t
=gettok()) == NUMBER
){
tokset
[j
].value
= numbval
;
if( j
< ndefout
&& j
>2 ){
error( "please define type number of %s earlier",
error( "unexpected EOF before %%" );
fprintf( ftable
, "#define yyclearin yychar = -1\n" );
fprintf( ftable
, "#define yyerrok yyerrflag = 0\n" );
fprintf( ftable
, "extern int yychar;\nextern short yyerrflag;\n" );
fprintf( ftable
, "#ifndef YYMAXDEPTH\n#define YYMAXDEPTH 150\n#endif\n" );
if( !ntypes
) fprintf( ftable
, "#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n" );
fprintf( ftable
, "YYSTYPE yylval, yyval;\n" );
*mem
++ = start
; /* if start is 0, we will overwrite with the lhs of the first rule */
while( (t
=gettok()) == LCURLY
) cpycode();
if( t
!= C_IDENTIFIER
) error( "bad syntax on first rule" );
if( !start
) prdptr
[0][1] = chfind(1,tokname
);
while( t
!=MARK
&& t
!=ENDFILE
){
*mem
++ = *prdptr
[nprod
-1];
else if( t
== C_IDENTIFIER
){
*mem
= chfind(1,tokname
);
if( *mem
< NTBASE
) error( "token illegal on LHS of grammar rule" );
else error( "illegal rule: missing semicolon or | ?" );
while( t
== IDENTIFIER
) {
*mem
= chfind(1,tokname
);
if( *mem
<NTBASE
) levprd
[nprod
] = toklev
[*mem
];
if( gettok()!=IDENTIFIER
) error( "illegal %%prec syntax" );
if( j
>=NTBASE
)error("nonterminal %s illegal after %%prec", nontrst
[j
-NTBASE
].name
);
levprd
[nprod
] |= ACTFLAG
;
fprintf( faction
, "\ncase %d:", nprod
);
cpyact( mem
-prdptr
[nprod
]-1 );
fprintf( faction
, " break;" );
if( (t
=gettok()) == IDENTIFIER
){
/* action within rule... */
sprintf( actname
, "$$%d", nprod
);
j
= chfind(1,actname
); /* make it a nonterminal */
/* the current rule will become rule number nprod+1 */
/* move the contents down, and make room for the null */
for( p
=mem
; p
>=prdptr
[nprod
]; --p
) p
[2] = *p
;
/* enter null production for action */
/* update the production information */
levprd
[nprod
+1] = levprd
[nprod
] & ~ACTFLAG
;
if( ++nprod
>= NPROD
) error( "more than %d rules", NPROD
);
/* make the action appear in the original rule */
/* get some more of the rule */
while( t
== ';' ) t
= gettok();
/* check that default action is reasonable */
if( ntypes
&& !(levprd
[nprod
]&ACTFLAG
) && nontrst
[*prdptr
[nprod
]-NTBASE
].tvalue
){
/* no explicit action, LHS has value */
tempty
= prdptr
[nprod
][1];
if( tempty
< 0 ) error( "must return a value, since LHS has a type" );
else if( tempty
>= NTBASE
) tempty
= nontrst
[tempty
-NTBASE
].tvalue
;
else tempty
= TYPE( toklev
[tempty
] );
if( tempty
!= nontrst
[*prdptr
[nprod
]-NTBASE
].tvalue
){
error( "default action causes potential type clash" );
if( ++nprod
>= NPROD
) error( "more than %d rules", NPROD
);
fprintf( ftable
, "\n# line %d \"%s\"\n", lineno
, infile
);
while( (c
=getc(finput
)) != EOF
) putc( c
, ftable
);
/* finish action routine */
fprintf( ftable
, "# define YYERRCODE %d\n", tokset
[2].value
);
defin( t
, s
) register char *s
; {
/* define s to be a terminal if t=0
or a nonterminal if t=1 */
if( ++nnonter
>= NNONTERM
) error("too many nonterminals, limit %d",NNONTERM
);
nontrst
[nnonter
].name
= cstash(s
);
return( NTBASE
+ nnonter
);
if( ++ntokens
>= NTERMS
) error("too many terminals, limit %d",NTERMS
);
tokset
[ntokens
].name
= cstash(s
);
/* establish value for token */
if( s
[0]==' ' && s
[2]=='\0' ) /* single character literal */
else if ( s
[0]==' ' && s
[1]=='\\' ) { /* escape sequence */
if( s
[3] == '\0' ){ /* single character escape sequence */
/* character which is escaped */
case 'n': val
= '\n'; break;
case 'r': val
= '\r'; break;
case 'b': val
= '\b'; break;
case 't': val
= '\t'; break;
case 'f': val
= '\f'; break;
case '\'': val
= '\''; break;
case '"': val
= '"'; break;
case '\\': val
= '\\'; break;
default: error( "invalid escape" );
else if( s
[2] <= '7' && s
[2]>='0' ){ /* \nnn sequence */
if( s
[3]<'0' || s
[3] > '7' || s
[4]<'0' ||
s
[4]>'7' || s
[5] != '\0' ) error("illegal \\nnn construction" );
val
= 64*s
[2] + 8*s
[3] + s
[4] - 73*'0';
if( val
== 0 ) error( "'\\000' is illegal" );
tokset
[ntokens
].value
= val
;
defout(){ /* write out the defines (at the end of the declaration section) */
for( i
=ndefout
; i
<=ntokens
; ++i
){
if( *cp
== ' ' ) ++cp
; /* literals */
for( ; (c
= *cp
)!='\0'; ++cp
){
if( islower(c
) || isupper(c
) || isdigit(c
) || c
=='_' ); /* VOID */
fprintf( ftable
, "# define %s %d\n", tokset
[i
].name
, tokset
[i
].value
);
if( fdefine
!= NULL
) fprintf( fdefine
, "# define %s %d\n", tokset
[i
].name
, tokset
[i
].value
);
cstash( s
) register char *s
; {
if( cnamp
>= &cnames
[cnamsz
] ) error("too many characters in id's and literals" );
static int peekline
; /* number of '\n' seen in lookahead */
register c
, match
, reserve
;
while( c
==' ' || c
=='\n' || c
=='\t' || c
=='\f' ){
if( c
== '\n' ) ++lineno
;
if( c
== '/' ){ /* skip comment */
return( '=' ); /* action ... */
case '<': /* get, and look up, a type name (union member name) */
while( (c
=getc(finput
)) != '>' && c
>=0 && c
!= '\n' ){
if( ++i
>= NAMESIZE
) --i
;
if( c
!= '>' ) error( "unterminated < ... > clause" );
for( i
=1; i
<=ntypes
; ++i
){
if( !strcmp( typeset
[i
], tokname
) ){
typeset
[numbval
= ++ntypes
] = cstash( tokname
);
if( c
== '\n' || c
== EOF
)
error("illegal or missing ' or \"" );
if( ++i
>= NAMESIZE
) --i
;
else if( c
== match
) break;
if( ++i
>= NAMESIZE
) --i
;
case '2': return(BINARY
);
case '{': return(LCURLY
);
if( isdigit(c
) ){ /* number */
base
= (c
=='0') ? 8 : 10 ;
for( c
=getc(finput
); isdigit(c
) ; c
=getc(finput
) ){
numbval
= numbval
*base
+ c
- '0';
else if( islower(c
) || isupper(c
) || c
=='_' || c
=='.' || c
=='$' ){
while( islower(c
) || isupper(c
) || isdigit(c
) || c
=='_' || c
=='.' || c
=='$' ){
if( reserve
&& isupper(c
) ) tokname
[i
] += 'a'-'A';
if( ++i
>= NAMESIZE
) --i
;
if( reserve
){ /* find a reserved word */
if( !strcmp(tokname
,"term")) return( TERM
);
if( !strcmp(tokname
,"token")) return( TERM
);
if( !strcmp(tokname
,"left")) return( LEFT
);
if( !strcmp(tokname
,"nonassoc")) return( BINARY
);
if( !strcmp(tokname
,"binary")) return( BINARY
);
if( !strcmp(tokname
,"right")) return( RIGHT
);
if( !strcmp(tokname
,"prec")) return( PREC
);
if( !strcmp(tokname
,"start")) return( START
);
if( !strcmp(tokname
,"type")) return( TYPEDEF
);
if( !strcmp(tokname
,"union")) return( UNION
);
error("invalid escape, or illegal reserved word: %s", tokname
);
/* look ahead to distinguish IDENTIFIER from C_IDENTIFIER */
while( c
==' ' || c
=='\t'|| c
=='\n' || c
=='\f' || c
== '/' ) {
if( c
== '\n' ) ++peekline
;
else if( c
== '/' ){ /* look for comments */
if( c
== ':' ) return( C_IDENTIFIER
);
fdtype( t
){ /* determine the type of a symbol */
if( t
>= NTBASE
) v
= nontrst
[t
-NTBASE
].tvalue
;
else v
= TYPE( toklev
[t
] );
if( v
<= 0 ) error( "must specify type for %s", (t
>=NTBASE
)?nontrst
[t
-NTBASE
].name
:
chfind( t
, s
) register char *s
; {
if(!strcmp(s
,tokset
[i
].name
)){
if(!strcmp(s
,nontrst
[i
].name
)) {
error( "%s should have been defined earlier", s
);
/* copy the union declaration to the output, and the define file if present */
fprintf( ftable
, "\n# line %d \"%s\"\n", lineno
, infile
);
fprintf( ftable
, "typedef union " );
if( fdefine
) fprintf( fdefine
, "\ntypedef union " );
if( (c
=getc(finput
)) < 0 ) error( "EOF encountered while processing %%union" );
if( fdefine
) putc( c
, fdefine
);
if( level
== 0 ) { /* we are finished copying */
fprintf( ftable
, " YYSTYPE;\n" );
if( fdefine
) fprintf( fdefine
, " YYSTYPE;\nextern YYSTYPE yylval;\n" );
cpycode(){ /* copies code between \{ and \} */
fprintf( ftable
, "\n# line %d \"%s\"\n", lineno
, infile
);
if( (c
=getc(finput
)) == '}' ) return;
else putc('\\', ftable
);
if( (c
=getc(finput
)) == '}' ) return;
if( c
== '\n' ) ++lineno
;
error("eof before %%}" );
skipcom(){ /* skip over comments */
register c
, i
=0; /* i is the number of lines skipped */
/* skipcom is called after reading a / */
if( getc(finput
) != '*' ) error( "illegal comment" );
if( (c
=getc(finput
)) == '/' ) return( i
);
error( "EOF inside comment" );
cpyact(offset
){ /* copy C action to the next ; or closing } */
int brac
, c
, match
, j
, s
, tok
;
fprintf( faction
, "\n# line %d \"%s\"\n", lineno
, infile
);
if( c
== '<' ){ /* type description */
if( gettok() != TYPENAME
) error( "bad syntax on $<ident> clause" );
fprintf( faction
, "yyval");
if( ntypes
){ /* put out the proper tag... */
if( tok
< 0 ) tok
= fdtype( *prdptr
[nprod
] );
fprintf( faction
, ".%s", typeset
[tok
] );
error( "Illegal use of $%d", j
+offset
);
fprintf( faction
, "yypvt[-%d]", -j
);
if( ntypes
){ /* put out the proper tag */
if( j
+offset
<= 0 && tok
< 0 ) error( "must specify type of $%d", j
+offset
);
if( tok
< 0 ) tok
= fdtype( prdptr
[nprod
][j
+offset
] );
fprintf( faction
, ".%s", typeset
[tok
] );
if( s
<0 ) putc('-', faction
);
case '/': /* look for comments */
/* it really is a comment */
if( (c
=getc(finput
)) == '/' ) goto lcopy
;
error( "EOF inside comment" );
case '\'': /* character constant */
case '"': /* character string */
if( c
== '\n' ) ++lineno
;
else if( c
==match
) goto lcopy
;
else if( c
=='\n' ) error( "newline in string or char. const." );
error( "EOF in string or character constant" );
error("action does not terminate" );