xref: /plan9-contrib/sys/src/ape/cmd/make/gram.y (revision b94bb474148e9d24a82a427863d9c9eb4c20f4ae)
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
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
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
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
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 subst(yytext, templin);		/* Substitute for macros on dependency lines */
381 
382 if(lastch)	/* copy the stuff after the semicolon */
383 	{
384 	*lastchp = lastch;
385 	strcat(templin, lastchp);
386 	}
387 
388 strcpy(yytext, templin);
389 
390 /* process include files after macro substitution */
391 if(strncmp(text, "include", 7) == 0) {
392  	if (isinclude(text+7))
393 		goto again;
394 }
395 
396 for(p = zznextc = text ; *p ; ++p )
397 	if(*p!=' ' && *p!='\t')
398 		return START;
399 goto again;
400 }
401 
402 
403 static int
404 isinclude(char *s)
405 {
406 char *t;
407 struct fstack *p;
408 
409 for(t=s; *t==' ' || *t=='\t' ; ++t)
410 	;
411 if(t == s)
412 	return NO;
413 
414 for(s = t; *s!='\n' && *s!='#' && *s!='\0' ; ++s)
415 	if(*s == ':')
416 		return NO;
417 *s = '\0';
418 
419 if(ninclude >= MAXINCLUDE)
420 	fatal("include depth exceeded");
421 p = filestack + ninclude;
422 p->fin = fin;
423 p->lineno = yylineno;
424 p->fname = copys(t);
425 if( (fin = fopen(t, "r")) == NULL)
426 	fatal1("Cannot open include file %s", t);
427 yylineno = 0;
428 ++ninclude;
429 return YES;
430 }
431 
432 
433 int
434 yyerror(char *s, ...)
435 {
436 char buf[100];
437 
438 sprintf(buf, "line %d of file %s: %s",
439 		yylineno, filestack[ninclude-1].fname, s);
440 fatal(buf);
441 return 0;
442 }
443