SysIII/usr/src/cmd/make/gram.y
/* @(#)gram.y 3.6 */
%{#include "defs"
%}
%term NAME SHELLINE START COLON DOUBLECOLON EQUAL A_STRING VERSION
%union
{
SHBLOCK yshblock;
DEPBLOCK ydepblock;
NAMEBLOCK ynameblock;
CHARSTAR ycharstring;
}
%type <yshblock> SHELLINE, shlist, shellist
%type <ynameblock> NAME, namelist, name
%type <ydepblock> deplist, dlist
%type <ycharstring> A_STRING
%%
%{
DEPBLOCK pp;
FSTATIC SHBLOCK prevshp;
FSTATIC NAMEBLOCK lefts[NLEFTS];
NAMEBLOCK leftp;
FSTATIC int nlefts;
LINEBLOCK lp, lpp;
FSTATIC DEPBLOCK prevdep;
FSTATIC int sepc;
%}
file:
| file comline
;
comline: START
| START macrodef
| START namelist deplist shellist = {
if(mainname == NULL && IS_OFF(INTRULE))
if(lefts[0]->namep[0] != DOT || any(lefts[0]->namep, SLASH) )
mainname = lefts[0];
while( --nlefts >= 0)
{
leftp = lefts[nlefts];
if(leftp->septype == 0)
leftp->septype = sepc;
else if(leftp->septype != sepc)
fprintf(stderr, "Inconsistent rules lines for `%s'\n",
leftp->namep);
else if(sepc==ALLDEPS && *(leftp->namep)!=DOT && $4!=0)
{
for(lp=leftp->linep; lp->nextline!=0; lp=lp->nextline)
if(lp->shp)
fprintf(stderr, "Multiple rules lines for `%s'\n",
leftp->namep);
}
lp = ALLOC(lineblock);
lp->nextline = 0;
lp->depp = $3;
lp->shp = $4;
if(equal(leftp->namep, ".SUFFIXES") && $3==0)
leftp->linep = 0;
else if(leftp->linep == 0)
leftp->linep = lp;
else
{
for(lpp = leftp->linep; lpp->nextline!=0;
lpp = lpp->nextline) ;
if(sepc==ALLDEPS && leftp->namep[0]==DOT)
lpp->shp = 0;
lpp->nextline = lp;
}
}
}
| error
;
macrodef: NAME EQUAL A_STRING =
{
setvar($1, $3);
}
;
namelist: name = { lefts[0] = $1; nlefts = 1; }
| namelist name = { lefts[nlefts++] = $2;
if(nlefts>NLEFTS) fatal("Too many lefts"); }
;
name: NAME =
{
if(($$ = srchname($1)) == 0)
$$ = makename($1);
}
| NAME VERSION =
{
if(($$ = srchname($1)) == 0)
$$ = makename($1);
}
;
deplist: = { fatal1("Must be a separator on rules line %d", yylineno); }
| dlist
;
dlist: sepchar = { prevdep = 0; $$ = 0; }
| dlist name = {
pp = ALLOC(depblock);
pp->nextdep = 0;
pp->depname = $2;
if(prevdep == 0) $$ = pp;
else prevdep->nextdep = pp;
prevdep = pp;
}
;
sepchar: COLON = { sepc = ALLDEPS; }
| DOUBLECOLON = { sepc = SOMEDEPS; }
;
shellist: = {$$ = 0; }
| shlist = { $$ = $1; }
;
shlist: SHELLINE = { $$ = $1; prevshp = $1; }
| shlist SHELLINE = { $$ = $1;
prevshp->nextsh = $2;
prevshp = $2;
}
;
%%
/* @(#)lex.c 3.1 */
#include "ctype.h"
CHARSTAR zznextc; /* zero if need another line; otherwise points to next char */
int yylineno;
static char inmacro = NO;
yylex()
{
register CHARSTAR p;
register CHARSTAR q;
static char word[128];
CHARSTAR pword;
pword = word;
if(zznextc == 0)
return( nextlin() );
while( isspace(*zznextc) )
++zznextc;
if(inmacro == YES)
{
inmacro = NO;
yylval.ycharstring = copys(zznextc);
zznextc = 0;
return(A_STRING);
}
if(*zznextc == CNULL)
return( nextlin() );
if(*zznextc == KOLON)
{
if(*++zznextc == KOLON)
{
++zznextc;
return(DOUBLECOLON);
}
else
return(COLON);
}
if(*zznextc == EQUALS)
{
inmacro = YES;
++zznextc;
return(EQUAL);
}
if(*zznextc == SKOLON)
return( retsh(zznextc) );
p = zznextc;
q = word;
while( ! ( funny[*p] & TERMINAL) )
*q++ = *p++;
if(p != zznextc)
{
*q = CNULL;
yylval.ycharstring = copys(pword);
if(*p == RCURLY)
{
zznextc = p+1;
return(VERSION);
}
if(*p == LCURLY)
p++;
zznextc = p;
return(NAME);
}
else
{
fprintf(stderr,"Bad character %c (octal %o), line %d",
*zznextc,*zznextc,yylineno);
fatal(Nullstr);
}
return(0); /* never executed */
}
retsh(q)
register CHARSTAR q;
{
register CHARSTAR p;
register int c;
extern CHARSTAR *linesptr;
SHBLOCK sp;
for(p=q+1 ; *p==BLANK||*p==TAB ; ++p) ;
sp = ALLOC(shblock);
sp->nextsh = 0;
sp->shbp = (fin == NULL ? p : copys(p) );
yylval.yshblock = sp;
zznextc = 0;
/*
* The following if-else "thing" eats up newlines within
* shell blocks.
*/
if(fin == NULL)
{
if(linesptr[0])
while(linesptr[1] && equal(linesptr[1], "\n"))
{
yylineno++;
linesptr++;
}
}
else
{
while((c = GETC()) == NEWLINE)
yylineno++;
if(c != EOF)
ungetc(c, fin);
}
return(SHELLINE);
}
nextlin()
{
register char c;
register CHARSTAR p, t;
static char yytext[INMAX];
static CHARSTAR yytextl = yytext+INMAX;
CHARSTAR text;
char templin[INMAX];
char lastch;
CHARSTAR lastchp;
extern CHARSTAR *linesptr;
int incom;
int kc;
int nflg;
int poundflg;
again:
incom = 0;
zznextc = 0;
poundflg = 0;
if(fin == NULL)
{
if( (text = *linesptr++) == 0)
return(0);
++yylineno;
copstr(yytext, text);
}
else
{
yytext[0] = CNULL;
for(p=yytext ; ; ++p)
{
if(p > yytextl)
fatal("line too long");
kc = GETC();
if(kc == EOF)
{
*p = CNULL;
return(0);
}
else if(kc == SKOLON)
++incom;
else if (kc == TAB && p == yytext)
++incom;
else if (kc==POUND && !incom && yytext[0] != TAB)
{
poundflg++;
kc = CNULL;
}
else if (kc == NEWLINE)
{
++yylineno;
if(p==yytext || p[-1]!=BACKSLASH)
break;
if(incom || yytext[0] == TAB)
*p++ = NEWLINE;
else
p[-1] = BLANK;
nflg = YES;
while( kc = GETC())
{
if(kc != TAB && kc != BLANK && kc != NEWLINE)
break;
if(incom || yytext[0] == TAB)
{
if(nflg == YES && kc == TAB)
{
nflg = NO;
continue;
}
if(kc == NEWLINE)
{
nflg = YES;
}
*p++ = kc;
}
if(kc == NEWLINE)
++yylineno;
}
if(kc == EOF)
{
*p = CNULL;
return(0);
}
}
*p = kc;
}
*p = CNULL;
text = yytext;
}
c = text[0];
if(c == TAB)
return( retsh(text) );
/*
* DO include FILES HERE.
*/
if(sindex(text, "include") == 0 && (text[7] == BLANK || text[7] == TAB))
{
CHARSTAR pfile;
for(p = &text[8]; *p != CNULL; p++)
if(*p != TAB ||
*p != BLANK)
break;
pfile = p;
for(; *p != CNULL &&
*p != NEWLINE &&
*p != TAB &&
*p != BLANK; p++);
if(*p != CNULL)
*p = CNULL;
/*
* Start using new file.
*/
fstack(pfile, &fin, &yylineno);
goto again;
}
if(isalpha(c) || isdigit(c) || c==BLANK || c==DOT)
for(p=text+1; *p!=CNULL; p++)
if(*p == KOLON || *p == EQUALS)
break;
/* substtitute for macros on dependency line up to the semicolon if any */
if(*p != EQUALS)
{
for(t = yytext ; *t!=CNULL && *t!=SKOLON ; ++t);
lastchp = t;
lastch = *t;
*t = CNULL;
subst(yytext, templin); /* Substitute for macros on dep lines */
if(lastch)
{
for(t = templin ; *t ; ++t);
*t = lastch;
while( *++t = *++lastchp ) ;
}
p = templin;
t = yytext;
while( *t++ = *p++ );
}
if(poundflg == 0 || yytext[0] != CNULL)
{
zznextc = text;
return(START);
}
else
goto again;
}
#include "stdio.h"
/*
* GETC automatically unravels stacked include files. That is,
* during include file processing, when a new file is encountered
* fstack will stack the FILE pointer argument. Subsequent
* calls to GETC with the new FILE pointer will get characters
* from the new file. When an EOF is encountered, GETC will
* check to see if the file pointer has been stacked. If so,
* a character from the previous file will be returned.
* The external references are "GETC()" and "fstack(fname,stream,lno)".
* "Fstack(stfname,ream,lno)" is used to stack an old file pointer before
* the new file is assigned to the same variable. Also stacked are the
* file name and the old current lineno, generally, yylineno.
*/
static int morefiles;
static struct sfiles
{
char sfname[64];
FILE *sfilep;
int syylno;
} sfiles[20];
GETC()
{
register int c;
c = getc(fin);
while(c == EOF && morefiles)
{
fclose(fin);
yylineno = sfiles[--morefiles].syylno;
fin = sfiles[morefiles].sfilep;
c = getc(fin);
}
return(c);
}
fstack(newname, oldfp, oldlno)
register char *newname;
register FILE **oldfp;
register int *oldlno;
{
if(access(newname, 4) != 0)
/*
* This get line can be removed if used elsewhere than make.
*/
if(get(newname, CD, Nullstr) == NO)
fatal1("Cannot read or get %s", newname);
if(IS_ON(DBUG))
printf("Include file: \"%s\"\n", newname);
/*
* Stack the new file name, the old file pointer and the
* old yylineno;
*/
strcat(sfiles[morefiles].sfname, newname);
sfiles[morefiles].sfilep = *oldfp;
sfiles[morefiles++].syylno = *oldlno;
yylineno = 0;
if((*oldfp=fopen(newname, "r")) == NULL)
fatal1("Cannot open %s", newname);
}