1 %{#include "defs.h"
2 %}
3
4 %term NAME SHELLINE START MACRODEF COLON DOUBLECOLON GREATER AMPER AMPERAMPER
5 %union
6 {
7 struct shblock *yshblock;
8 depblkp ydepblock;
9 nameblkp ynameblock;
10 }
11
12 %type <yshblock> SHELLINE, shlist, shellist
13 %type <ynameblock> NAME, namelist
14 %type <ydepblock> deplist, dlist
15
16
17 %%
18
19 %{
20 struct depblock *pp;
21 static struct shblock *prevshp;
22
23 static struct nameblock *lefts[NLEFTS];
24 struct nameblock *leftp;
25 static int nlefts;
26
27 struct lineblock *lp, *lpp;
28 static struct depblock *prevdep;
29 static int sepc;
30 static int allnowait;
31
32 static struct fstack
33 {
34 FILE *fin;
35 char *fname;
36 int lineno;
37 } filestack[MAXINCLUDE];
38 static int ninclude = 0;
39 %}
40
41
42 file:
43 | file comline
44 ;
45
46 comline: START
47 | MACRODEF
48 | START namelist deplist shellist = {
49 while( --nlefts >= 0)
50 {
51 wildp wp;
52
53 leftp = lefts[nlefts];
54 if(wp = iswild(leftp->namep))
55 {
56 leftp->septype = SOMEDEPS;
57 if(lastwild)
58 lastwild->next = wp;
59 else
60 firstwild = wp;
61 lastwild = wp;
62 }
63
64 if(leftp->septype == 0)
65 leftp->septype = sepc;
66 else if(leftp->septype != sepc)
67 {
68 if(! wp)
69 fprintf(stderr,
70 "Inconsistent rules lines for `%s'\n",
71 leftp->namep);
72 }
73 else if(sepc==ALLDEPS && leftp->namep[0]!='.' && $4!=0)
74 {
75 for(lp=leftp->linep; lp->nxtlineblock; lp=lp->nxtlineblock)
76 if(lp->shp)
77 fprintf(stderr,
78 "Multiple rules lines for `%s'\n",
79 leftp->namep);
80 }
81
82 lp = ALLOC(lineblock);
83 lp->nxtlineblock = NULL;
84 lp->depp = $3;
85 lp->shp = $4;
86 if(wp)
87 wp->linep = lp;
88
89 if(equal(leftp->namep, ".SUFFIXES") && $3==0)
90 leftp->linep = 0;
91 else if(leftp->linep == 0)
92 leftp->linep = lp;
93 else {
94 for(lpp = leftp->linep; lpp->nxtlineblock;
95 lpp = lpp->nxtlineblock) ;
96 if(sepc==ALLDEPS && leftp->namep[0]=='.')
97 lpp->shp = 0;
98 lpp->nxtlineblock = lp;
99 }
100 }
101 }
102 | error
103 ;
104
105 namelist: NAME = { lefts[0] = $1; nlefts = 1; }
106 | namelist NAME = { lefts[nlefts++] = $2;
107 if(nlefts>=NLEFTS) fatal("Too many lefts"); }
108 ;
109
110 deplist:
111 {
112 char junk[100];
113 sprintf(junk, "%s:%d", filestack[ninclude-1].fname, yylineno);
114 fatal1("Must be a separator on rules line %s", junk);
115 }
116 | dlist
117 ;
118
119 dlist: sepchar = { prevdep = 0; $$ = 0; allnowait = NO; }
120 | sepchar AMPER = { prevdep = 0; $$ = 0; allnowait = YES; }
121 | dlist NAME = {
122 pp = ALLOC(depblock);
123 pp->nxtdepblock = NULL;
124 pp->depname = $2;
125 pp->nowait = allnowait;
126 if(prevdep == 0) $$ = pp;
127 else prevdep->nxtdepblock = pp;
128 prevdep = pp;
129 }
130 | dlist AMPER = { if(prevdep) prevdep->nowait = YES; }
131 | dlist AMPERAMPER
132 ;
133
134 sepchar: COLON = { sepc = ALLDEPS; }
135 | DOUBLECOLON = { sepc = SOMEDEPS; }
136 ;
137
138 shellist: = {$$ = 0; }
139 | shlist = { $$ = $1; }
140 ;
141
142 shlist: SHELLINE = { $$ = $1; prevshp = $1; }
143 | shlist SHELLINE = { $$ = $1;
144 prevshp->nxtshblock = $2;
145 prevshp = $2;
146 }
147 ;
148
149 %%
150
151 static char *zznextc; /* null if need another line;
152 otherwise points to next char */
153 static int yylineno;
154 static FILE * fin;
155 static int retsh(char *);
156 static int nextlin(void);
157 static int isinclude(char *);
158
159 int yyparse(void);
160
161 int
parse(char * name)162 parse(char *name)
163 {
164 FILE *stream;
165
166 if(name == CHNULL)
167 {
168 stream = NULL;
169 name = "(builtin-rules)";
170 }
171 else if(equal(name, "-"))
172 {
173 stream = stdin;
174 name = "(stdin)";
175 }
176 else if( (stream = fopen(name, "r")) == NULL)
177 return NO;
178 filestack[0].fname = copys(name);
179 ninclude = 1;
180 fin = stream;
181 yylineno = 0;
182 zznextc = 0;
183
184 if( yyparse() )
185 fatal("Description file error");
186
187 if(fin)
188 fclose(fin);
189 return YES;
190 }
191
192 int
yylex(void)193 yylex(void)
194 {
195 char *p;
196 char *q;
197 char word[INMAX];
198
199 if(! zznextc )
200 return nextlin() ;
201
202 while( isspace(*zznextc) )
203 ++zznextc;
204 switch(*zznextc)
205 {
206 case '\0':
207 return nextlin() ;
208
209 case '|':
210 if(zznextc[1]==':')
211 {
212 zznextc += 2;
213 return DOUBLECOLON;
214 }
215 break;
216 case ':':
217 if(*++zznextc == ':')
218 {
219 ++zznextc;
220 return DOUBLECOLON;
221 }
222 return COLON;
223 case '>':
224 ++zznextc;
225 return GREATER;
226 case '&':
227 if(*++zznextc == '&')
228 {
229 ++zznextc;
230 return AMPERAMPER;
231 }
232 return AMPER;
233 case ';':
234 return retsh(zznextc) ;
235 }
236
237 p = zznextc;
238 q = word;
239
240 while( ! ( funny[*p] & TERMINAL) )
241 *q++ = *p++;
242
243 if(p != zznextc)
244 {
245 *q = '\0';
246 if((yylval.ynameblock=srchname(word))==0)
247 yylval.ynameblock = makename(word);
248 zznextc = p;
249 return NAME;
250 }
251
252 else {
253 char junk[100];
254 sprintf(junk, "Bad character %c (octal %o), line %d of file %s",
255 *zznextc, *zznextc, yylineno, filestack[ninclude-1].fname);
256 fatal(junk);
257 }
258 return 0; /* never executed */
259 }
260
261
262
263
264 static int
retsh(char * q)265 retsh(char *q)
266 {
267 register char *p;
268 struct shblock *sp;
269
270 for(p=q+1 ; *p==' '||*p=='\t' ; ++p) ;
271
272 sp = ALLOC(shblock);
273 sp->nxtshblock = NULL;
274 sp->shbp = (fin ? copys(p) : p );
275 yylval.yshblock = sp;
276 zznextc = 0;
277 return SHELLINE;
278 }
279
280 static int
nextlin(void)281 nextlin(void)
282 {
283 static char yytext[INMAX];
284 static char *yytextl = yytext+INMAX;
285 char *text, templin[INMAX];
286 char c;
287 char *p, *t;
288 char lastch, *lastchp;
289 extern char **linesptr;
290 int incom;
291 int kc;
292
293 again:
294
295 incom = NO;
296 zznextc = 0;
297
298 if(fin == NULL)
299 {
300 if( (text = *linesptr++) == 0)
301 return 0;
302 ++yylineno;
303 }
304
305 else {
306 for(p = text = yytext ; p<yytextl ; *p++ = kc)
307 switch(kc = getc(fin))
308 {
309 case '\t':
310 if(p == yytext)
311 incom = YES;
312 break;
313
314 case ';':
315 incom = YES;
316 break;
317
318 case '#':
319 if(! incom)
320 kc = '\0';
321 break;
322
323 case '\n':
324 ++yylineno;
325 if(p==yytext || p[-1]!='\\')
326 {
327 *p = '\0';
328 goto endloop;
329 }
330 p[-1] = ' ';
331 while( (kc=getc(fin))=='\t' || kc==' ' || kc=='\n')
332 if(kc == '\n')
333 ++yylineno;
334
335 if(kc != EOF)
336 break;
337 case EOF:
338 *p = '\0';
339 if(ninclude > 1)
340 {
341 register struct fstack *stp;
342 fclose(fin);
343 --ninclude;
344 stp = filestack + ninclude;
345 fin = stp->fin;
346 yylineno = stp->lineno;
347 free(stp->fname);
348 goto again;
349 }
350 return 0;
351 }
352
353 fatal("line too long");
354 }
355
356 endloop:
357
358 if((c = text[0]) == '\t')
359 return retsh(text) ;
360
361 if(isalpha(c) || isdigit(c) || c==' ' || c=='.'|| c=='_')
362 for(p=text+1; *p!='\0'; )
363 if(*p == ':')
364 break;
365 else if(*p++ == '=')
366 {
367 eqsign(text);
368 return MACRODEF;
369 }
370
371 /* substitute for macros on dependency line up to the semicolon if any */
372
373 for(t = yytext ; *t!='\0' && *t!=';' ; ++t)
374 ;
375
376 lastchp = t;
377 lastch = *t;
378 *t = '\0'; /* replace the semi with a null so subst will stop */
379
380 /* Substitute for macros on dependency lines */
381 subst(yytext, templin, &templin[sizeof templin - 1]);
382
383 if(lastch) /* copy the stuff after the semicolon */
384 {
385 *lastchp = lastch;
386 strcat(templin, lastchp);
387 }
388
389 strcpy(yytext, templin);
390
391 /* process include files after macro substitution */
392 if(strncmp(text, "include", 7) == 0) {
393 if (isinclude(text+7))
394 goto again;
395 }
396
397 for(p = zznextc = text ; *p ; ++p )
398 if(*p!=' ' && *p!='\t')
399 return START;
400 goto again;
401 }
402
403
404 static int
isinclude(char * s)405 isinclude(char *s)
406 {
407 char *t;
408 struct fstack *p;
409
410 for(t=s; *t==' ' || *t=='\t' ; ++t)
411 ;
412 if(t == s)
413 return NO;
414
415 for(s = t; *s!='\n' && *s!='#' && *s!='\0' ; ++s)
416 if(*s == ':')
417 return NO;
418 *s = '\0';
419
420 if(ninclude >= MAXINCLUDE)
421 fatal("include depth exceeded");
422 p = filestack + ninclude;
423 p->fin = fin;
424 p->lineno = yylineno;
425 p->fname = copys(t);
426 if( (fin = fopen(t, "r")) == NULL)
427 fatal1("Cannot open include file %s", t);
428 yylineno = 0;
429 ++ninclude;
430 return YES;
431 }
432
433
434 int
yyerror(char * s,...)435 yyerror(char *s, ...)
436 {
437 char buf[100];
438
439 sprintf(buf, "line %d of file %s: %s",
440 yylineno, filestack[ninclude-1].fname, s);
441 fatal(buf);
442 return 0;
443 }
444