707 lines
15 KiB
Plaintext
707 lines
15 KiB
Plaintext
/* Copyright (c) 1993 UNIX System Laboratories, Inc. */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
|
|
/* UNIX System Laboratories, Inc. */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
/* Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
|
|
/* Copyright (c) 1988, 1990 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
|
|
/* UNIX System Laboratories, Inc. */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
%{
|
|
#ident "@(#)make:gram.y 1.22.1.1"
|
|
|
|
#include "defs"
|
|
#include <pfmt.h>
|
|
#define NLEFTS 200
|
|
#define INMAX 10000
|
|
%}
|
|
|
|
%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
|
|
|
|
%%
|
|
|
|
%{
|
|
extern NAMEBLOCK mainname; /* from main.c */
|
|
extern desc_start; /* from main.c */
|
|
int firstrule = YES;
|
|
#define TURNON(a) (Mflags |= (a))
|
|
void setvar();
|
|
DEPBLOCK pp;
|
|
NAMEBLOCK leftp;
|
|
LINEBLOCK lp, lpp;
|
|
FSTATIC SHBLOCK prevshp;
|
|
FSTATIC NAMEBLOCK *lefts;
|
|
FSTATIC DEPBLOCK prevdep;
|
|
FSTATIC int nlefts, szlefts,
|
|
sepc;
|
|
char yyfilename[PATH_MAX];
|
|
static int nextlin();
|
|
static void fstack(char *, FILE **, int *, int);
|
|
static int GETC();
|
|
static int retsh(CHARSTAR);
|
|
%}
|
|
|
|
|
|
file:
|
|
| file comline
|
|
;
|
|
|
|
comline: START
|
|
| START macrodef
|
|
| START namelist deplist shellist
|
|
{
|
|
if ( !(mainname || IS_ON(INTRULE)) &&
|
|
((lefts[0]->namep[0] != DOT) ||
|
|
ANY(lefts[0]->namep, SLASH)))
|
|
mainname = lefts[0];
|
|
while( --nlefts >= 0) {
|
|
leftp = lefts[nlefts];
|
|
if ( !(leftp->septype) )
|
|
leftp->septype = sepc;
|
|
else if (leftp->septype != sepc)
|
|
yprintf(stderr,
|
|
":158:inconsistent rules lines for `%s' (bu36)\n",
|
|
leftp->namep);
|
|
else if (sepc==ALLDEPS &&
|
|
*(leftp->namep)!=DOT &&
|
|
$4) {
|
|
for (lp = leftp->linep;
|
|
lp->nextline;
|
|
lp = lp->nextline)
|
|
if (lp->shp)
|
|
yprintf(stderr,
|
|
":159:multiple make lines for %s (bu37)\n",
|
|
leftp->namep);
|
|
}
|
|
|
|
lp = ALLOC(lineblock);
|
|
lp->nextline = NULL;
|
|
lp->depp = $3;
|
|
lp->shp = $4;
|
|
|
|
if (STREQ(leftp->namep, ".SUFFIXES") && $3==0)
|
|
leftp->linep = 0;
|
|
else if (STREQ(leftp->namep, ".MAKEOPTS") && $3==0)
|
|
leftp->linep = 0;
|
|
else if (STREQ(leftp->namep, ".POSIX")) {
|
|
if($3 != 0 || $4 != 0)
|
|
fatal1(":168:special target `%s:' illegal prerequisites or commands",leftp->namep);
|
|
if(firstrule != POSIX)
|
|
yprintf(stderr,":167:special target `%s:' not first rule: ignoring\n", leftp->namep);
|
|
leftp->linep = 0;
|
|
} else if ( !(leftp->linep) )
|
|
leftp->linep = lp;
|
|
else {
|
|
for (lpp = leftp->linep;
|
|
lpp->nextline;
|
|
lpp = lpp->nextline)
|
|
;
|
|
if (sepc==ALLDEPS &&
|
|
leftp->namep[0]==DOT &&
|
|
!ANY(leftp->namep, SLASH))
|
|
lpp->shp = 0;
|
|
lpp->nextline = lp;
|
|
}
|
|
}
|
|
free(lefts);
|
|
lefts = NULL;
|
|
}
|
|
| error
|
|
;
|
|
|
|
macrodef: NAME EQUAL A_STRING
|
|
{
|
|
setvar((CHARSTAR) $1, $3);
|
|
}
|
|
;
|
|
|
|
name: NAME
|
|
{
|
|
if( !($$ = SRCHNAME((CHARSTAR) $1)) )
|
|
$$ = makename((CHARSTAR) $1);
|
|
}
|
|
| NAME VERSION
|
|
{
|
|
if( !($$ = SRCHNAME((CHARSTAR) $1)) )
|
|
$$ = makename((CHARSTAR) $1);
|
|
}
|
|
;
|
|
|
|
namelist: name
|
|
{
|
|
if ((lefts = (NAMEBLOCK *)malloc(NLEFTS * sizeof(NAMEBLOCK)))
|
|
== NULL) {
|
|
fatal(":161:Too many lefts");
|
|
}
|
|
szlefts = NLEFTS;
|
|
lefts[0] = $1;
|
|
nlefts = 1;
|
|
}
|
|
| namelist name
|
|
{
|
|
lefts[nlefts++] = $2;
|
|
if(nlefts >= szlefts) {
|
|
if ((lefts = (NAMEBLOCK *)realloc(lefts,
|
|
(szlefts + NLEFTS) * sizeof(NAMEBLOCK))) == NULL) {
|
|
fatal(":161:Too many lefts");
|
|
}
|
|
szlefts += NLEFTS;
|
|
}
|
|
}
|
|
;
|
|
|
|
dlist: sepchar
|
|
{
|
|
prevdep = 0;
|
|
$$ = 0;
|
|
}
|
|
| dlist name
|
|
{
|
|
pp = ALLOC(depblock);
|
|
pp->nextdep = NULL;
|
|
pp->depname = $2;
|
|
if ( !prevdep )
|
|
$$ = pp;
|
|
else
|
|
prevdep->nextdep = pp;
|
|
prevdep = pp;
|
|
}
|
|
;
|
|
|
|
deplist:
|
|
{
|
|
yprintf(stderr, _SGI_MMX_make_sep ":Must be a separator (: or ::) for rules (bu39)\n");
|
|
$$ = 0;
|
|
}
|
|
| dlist
|
|
;
|
|
|
|
sepchar: COLON
|
|
{
|
|
sepc = ALLDEPS;
|
|
}
|
|
| DOUBLECOLON
|
|
{
|
|
sepc = SOMEDEPS;
|
|
}
|
|
;
|
|
|
|
|
|
shlist: SHELLINE
|
|
{
|
|
$$ = $1;
|
|
prevshp = $1;
|
|
}
|
|
| shlist SHELLINE
|
|
{
|
|
$$ = $1;
|
|
prevshp->nextsh = $2;
|
|
prevshp = $2;
|
|
}
|
|
;
|
|
|
|
shellist:
|
|
{
|
|
$$ = 0;
|
|
}
|
|
| shlist
|
|
{
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
%%
|
|
|
|
/* @(#)make:gram.y 1.6 of 5/9/86 */
|
|
|
|
#include <ctype.h>
|
|
|
|
CHARSTAR zznextc; /* zero if need another line; otherwise points to next char */
|
|
int yylineno;
|
|
static char inmacro = NO;
|
|
|
|
static char *word;
|
|
static int word_count;
|
|
void
|
|
init_lex()
|
|
{
|
|
word_count = 128;
|
|
word = ck_malloc(word_count);
|
|
}
|
|
|
|
int
|
|
yylex()
|
|
{
|
|
register CHARSTAR lq, p, q;
|
|
CHARSTAR pword;
|
|
int indollar = 0;
|
|
|
|
if ( !zznextc )
|
|
return( nextlin() );
|
|
|
|
while ( isspace(*zznextc) )
|
|
++zznextc;
|
|
|
|
if ( inmacro ) {
|
|
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) );
|
|
|
|
q = pword = word;
|
|
|
|
p = zznextc;
|
|
|
|
lq = word + word_count;
|
|
while ( !( funny[(unsigned char) *p] & TERMINAL) ) {
|
|
again:
|
|
if (q == lq) {
|
|
if ((word = realloc(word, word_count + 128)) == NULL)
|
|
fatal1(":140:couldn't malloc len=%d", word_count + 128);
|
|
/* recompute pointers - realloc may change */
|
|
pword = word;
|
|
q = word + word_count;
|
|
word_count += 128;
|
|
lq = word + word_count;
|
|
}
|
|
*q++ = *p++;
|
|
}
|
|
/*
|
|
* Permit $$(@:.c=.o)
|
|
*/
|
|
if (*p == DOLLAR) {
|
|
indollar++;
|
|
goto again;
|
|
}
|
|
if (indollar) {
|
|
if (*p == KOLON || *p == EQUALS)
|
|
goto again;
|
|
else if (*p == RPAREN)
|
|
indollar = 0;
|
|
}
|
|
|
|
if (p != zznextc) {
|
|
*q = CNULL;
|
|
yylval.ycharstring = copys(pword);
|
|
if (*p == RCURLY) {
|
|
zznextc = p+1;
|
|
return(VERSION);
|
|
}
|
|
if (*p == LCURLY)
|
|
p++;
|
|
zznextc = p;
|
|
if(desc_start == YES && firstrule == YES) {
|
|
desc_start = firstrule = NO;
|
|
/* capture this here so that we know as
|
|
* soon as possible that we're in POSIX
|
|
* mode
|
|
*/
|
|
if(STREQ(".POSIX",yylval.ycharstring)){
|
|
TURNON(POSIX);
|
|
posix_env();
|
|
firstrule = POSIX;
|
|
}
|
|
/* Not POSIX - convert MAKEFLAGS back */
|
|
else convtmflgs();
|
|
}
|
|
return(NAME);
|
|
} else {
|
|
yprintf(stderr, _SGI_MMX_make_badc ":bad character %c (octal %o)\n",
|
|
*zznextc,*zznextc);
|
|
fatal(NULL);
|
|
}
|
|
return(0); /* never executed */
|
|
}
|
|
|
|
|
|
static int
|
|
retsh(q)
|
|
register CHARSTAR q;
|
|
{
|
|
extern CHARSTAR *linesptr;
|
|
register CHARSTAR p;
|
|
SHBLOCK sp = ALLOC(shblock);
|
|
|
|
for (p = q + 1; *p==BLANK || *p==TAB; ++p)
|
|
;
|
|
sp->nextsh = 0;
|
|
sp->shbp = ( !fin ? p : copys(p) );
|
|
yylval.yshblock = sp;
|
|
zznextc = 0;
|
|
/*
|
|
* The following if-else "thing" eats up newlines within
|
|
* shell blocks.
|
|
*/
|
|
if ( !fin ) {
|
|
if (linesptr[0])
|
|
while (linesptr[1] && STREQ(linesptr[1], "\n")) {
|
|
yylineno++;
|
|
linesptr++;
|
|
}
|
|
} else {
|
|
register int c;
|
|
while ((c = GETC()) == NEWLINE)
|
|
yylineno++;
|
|
if (c != EOF)
|
|
(void)ungetc(c, fin);
|
|
}
|
|
return(SHELLINE);
|
|
}
|
|
|
|
static int morefiles;
|
|
|
|
static int
|
|
nextlin()
|
|
{
|
|
extern CHARSTAR *linesptr;
|
|
static char yytext[INMAX*10];
|
|
static CHARSTAR yytextl = yytext+INMAX*10;
|
|
register char c;
|
|
register CHARSTAR p, t;
|
|
/* templin needs to be large enough to hold entire dependency line
|
|
* with full macros expanded as does yytext
|
|
*/
|
|
char templin[INMAX*10], lastch;
|
|
CHARSTAR text, lastchp, subst();
|
|
int sindex();
|
|
int incom, kc, nflg, poundflg, poundfirst;
|
|
|
|
again: incom = 0;
|
|
zznextc = 0;
|
|
poundflg = 0;
|
|
poundfirst = 0;
|
|
|
|
if ( !fin ) {
|
|
if ( !(text = *linesptr++) )
|
|
return(0);
|
|
++yylineno;
|
|
(void)copstr(yytext, text);
|
|
} else {
|
|
yytext[0] = CNULL;
|
|
for (p = yytext; ; ++p) {
|
|
if(p > yytextl)
|
|
fatal(":164:line too long");
|
|
if ((kc = GETC()) == EOF) {
|
|
*p = CNULL;
|
|
return(0);
|
|
}
|
|
else if(kc == '!' && poundfirst && morefiles == 0
|
|
&& yylineno == 0 && p == yytext+1) {
|
|
/* special #! 'pick-a-make' */
|
|
p = yytext;
|
|
while (kc = GETC()) {
|
|
if (kc == NEWLINE) {
|
|
yylineno++;
|
|
break;
|
|
}
|
|
if (kc == EOF)
|
|
break;
|
|
*p++ = kc;
|
|
}
|
|
*p = CNULL;
|
|
donmake(yytext);
|
|
/* if returns then failed - ignore line */
|
|
goto again;
|
|
}
|
|
else if ((kc == SKOLON) ||
|
|
(kc == TAB && p == yytext))
|
|
++incom;
|
|
else if (p[-1] == BACKSLASH && kc == POUND && !incom && yytext[0] != TAB) {
|
|
/* permit \# to work */
|
|
p--;
|
|
} else if (kc == POUND && !incom && yytext[0] != TAB) {
|
|
poundflg++;
|
|
kc = CNULL;
|
|
/* identify if first line is #! */
|
|
if (p == yytext)
|
|
poundfirst++;
|
|
}
|
|
else if (kc == NEWLINE) {
|
|
++yylineno;
|
|
/*
|
|
* ATT has additional '|| poundflg' but
|
|
* this breaks the ability to comment out
|
|
* continuation lines. I hope this isn't
|
|
* a POSIX feature!
|
|
*/
|
|
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) {
|
|
/*
|
|
* do not put TABS into shell
|
|
* command lines
|
|
*/
|
|
if (nflg && 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;
|
|
}
|
|
|
|
if ((c = text[0]) == TAB)
|
|
return( retsh(text) );
|
|
/*
|
|
* DO include FILES HERE.
|
|
*/
|
|
if ( !sindex(text, "include") &&
|
|
(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.
|
|
*/
|
|
(void)subst(pfile, templin, 0);
|
|
fstack(templin, &fin, &yylineno, 1);
|
|
goto again;
|
|
}
|
|
|
|
if ( !sindex(text, "sinclude") &&
|
|
(text[8] == BLANK || text[8] == TAB)) {
|
|
CHARSTAR pfile;
|
|
|
|
for (p = &text[9]; *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.
|
|
*/
|
|
(void)subst(pfile, templin, 0);
|
|
fstack(templin, &fin, &yylineno, 0);
|
|
goto again;
|
|
}
|
|
if (isalpha(c) || isdigit(c) || c==BLANK || c==DOT || c=='_')
|
|
for (p = text+1; *p!=CNULL; p++)
|
|
if (*p == KOLON || *p == EQUALS)
|
|
break;
|
|
|
|
/* substitute for macros on dependency line up to the semicolon if any */
|
|
if (p && *p != EQUALS) {
|
|
for (t = yytext ; *t!=CNULL && *t!=SKOLON ; ++t)
|
|
;
|
|
|
|
lastchp = t;
|
|
lastch = *t;
|
|
*t = CNULL;
|
|
|
|
(void)subst(yytext, templin, 0);
|
|
|
|
if (lastch) {
|
|
for (t = templin ; *t ; ++t)
|
|
;
|
|
*t = lastch;
|
|
while ( *++t = *++lastchp )
|
|
;
|
|
}
|
|
|
|
p = templin;
|
|
t = yytext;
|
|
while ( *t++ = *p++ )
|
|
;
|
|
}
|
|
|
|
if ( !poundflg || yytext[0] != CNULL) {
|
|
zznextc = text;
|
|
return(START);
|
|
} else
|
|
goto again;
|
|
}
|
|
|
|
|
|
#include "stdio.h"
|
|
|
|
|
|
static struct sfiles {
|
|
CHARSTAR sfname;
|
|
FILE *sfilep;
|
|
int syylno;
|
|
} sfiles[MAX_INC];
|
|
|
|
|
|
/* GETC() automatically unravels stacked include files. 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.
|
|
*/
|
|
static int
|
|
GETC()
|
|
{
|
|
register int c;
|
|
|
|
while ((c = getc(fin)) == EOF && morefiles) {
|
|
(void)fclose(fin);
|
|
yylineno = sfiles[--morefiles].syylno;
|
|
fin = sfiles[morefiles].sfilep;
|
|
strcpy(yyfilename, sfiles[morefiles].sfname);
|
|
free(sfiles[morefiles].sfname);
|
|
if(IS_ON(DBUG) || IS_ON(DBUG2))
|
|
pfmt(stdout, MM_NOSTD,
|
|
_SGI_MMX_make_backi ":Back to file: \"%s\"\n",
|
|
yyfilename);
|
|
}
|
|
return(c);
|
|
}
|
|
|
|
|
|
/* 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 void
|
|
fstack(newname, oldfp, oldlno, force)
|
|
register char *newname;
|
|
register FILE **oldfp;
|
|
register int *oldlno;
|
|
int force;
|
|
{
|
|
FILE *newfp; /* new file descriptor */
|
|
char *strcat();
|
|
|
|
/* if unable to open file */
|
|
if ( !(newfp = fopen(newname, "r")) ) {
|
|
/* try sccs get of file */
|
|
if ( !get(newname, 0, 0) ) {
|
|
if (force)
|
|
fatal1(":165:cannot get %s for including",
|
|
newname);
|
|
else {
|
|
#ifdef MKDEBUG
|
|
if (IS_ON(DBUG))
|
|
printf(
|
|
"cannot get include file (skipped) %s\n",
|
|
newname);
|
|
return;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if ( !(newfp = fopen(newname, "r")) )
|
|
if (force)
|
|
fatal1(":166:cannot open %s for including",
|
|
newname);
|
|
else {
|
|
#ifdef MKDEBUG
|
|
if (IS_ON(DBUG))
|
|
printf(
|
|
"cannot open include file (skipped) %s\n",
|
|
newname);
|
|
return;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifdef MKDEBUG
|
|
if (IS_ON(DBUG) || IS_ON(DBUG2))
|
|
pfmt(stdout, MM_NOSTD,
|
|
_SGI_MMX_make_inc ":Include file: \"%s\"\n",newname);
|
|
#endif
|
|
/*
|
|
* Stack the new file name, the old file pointer and the
|
|
* old yylineno;
|
|
*/
|
|
|
|
if(morefiles >= MAX_INC)
|
|
fatal1(_SGI_MMX_make_tooinc ":include files nested more than %d deep", MAX_INC-1);
|
|
sfiles[morefiles].sfname = ck_malloc(strlen(yyfilename) + 1);
|
|
(void)strcpy(sfiles[morefiles].sfname, yyfilename);
|
|
sfiles[morefiles].sfilep = *oldfp;
|
|
sfiles[morefiles++].syylno = *oldlno;
|
|
yylineno = 0;
|
|
*oldfp = newfp; /* set the file pointer */
|
|
(void)strcpy(yyfilename, newname);
|
|
}
|
|
|