/* SCCSID: @(#)gram.y 3.0 4/22/86 */ /********************************************************************** * Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. * * All Rights Reserved. * * Reference "/usr/src/COPYRIGHT" for applicable restrictions. * **********************************************************************/ /* Based on: @(#)gram.y 1.2 of 3/28/83 (System V) */ %{#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; } ; %% #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); }