xref: /plan9-contrib/sys/src/cmd/cc/macbody (revision 272efad760864ee41cfe633b56aea9b4f5cf3ae7)
1#define VARMAC 0x80
2
3long
4getnsn(void)
5{
6	long n;
7	int c;
8
9	c = getnsc();
10	if(c < '0' || c > '9')
11		return -1;
12	n = 0;
13	while(c >= '0' && c <= '9') {
14		n = n*10 + c-'0';
15		c = getc();
16	}
17	unget(c);
18	return n;
19}
20
21static void
22nextsym(int c)
23{
24	int c1;
25	char *cp;
26
27	for(cp = symb;;) {
28		if(c >= Runeself) {
29			for(c1=0;;) {
30				if(cp <= symb+NSYMB-UTFmax)
31					cp[c1++] = c;
32				if(fullrune(cp, c1))
33					break;
34				c = getc();
35			}
36			cp += c1;
37		}else
38			if(cp <= symb+NSYMB-UTFmax)
39				*cp++ = c;
40		c = getc();
41		if(c >= Runeself || isalnum(c) || c == '_')
42			continue;
43		unget(c);
44		break;
45	}
46	*cp = 0;
47	if(cp > symb+NSYMB-UTFmax)
48		yyerror("symbol too large: %s", symb);
49}
50
51Sym*
52getsym(void)
53{
54	int c;
55
56	c = getnsc();
57	if(c < Runeself && !isalpha(c) && c != '_') {
58		unget(c);
59		return S;
60	}
61	nextsym(c);
62	return lookup();
63}
64
65Sym*
66getsymdots(int *dots)
67{
68	int c;
69	Sym *s;
70
71	s = getsym();
72	if(s != S)
73		return s;
74
75	c = getnsc();
76	if(c != '.'){
77		unget(c);
78		return S;
79	}
80	if(getc() != '.' || getc() != '.')
81		yyerror("bad dots in macro");
82	*dots = 1;
83	return slookup("__VA_ARGS__");
84}
85
86int
87getcom(void)
88{
89	int c;
90
91	for(;;) {
92		c = getnsc();
93		if(c != '/')
94			break;
95		c = getc();
96		if(c == '/') {
97			while(c != '\n')
98				c = getc();
99			break;
100		}
101		if(c != '*')
102			break;
103		c = getc();
104		for(;;) {
105			if(c == '*') {
106				c = getc();
107				if(c != '/')
108					continue;
109				c = getc();
110				break;
111			}
112			if(c == '\n') {
113				yyerror("comment across newline");
114				break;
115			}
116			c = getc();
117		}
118		if(c == '\n')
119			break;
120	}
121	return c;
122}
123
124void
125dodefine(char *cp)
126{
127	Sym *s;
128	char *p;
129	long l;
130
131	strcpy(symb, cp);
132	p = strchr(symb, '=');
133	if(p) {
134		*p++ = 0;
135		s = lookup();
136		l = strlen(p) + 2;	/* +1 null, +1 nargs */
137		while(l & 3)
138			l++;
139		while(nhunk < l)
140			gethunk();
141		*hunk = 0;
142		strcpy(hunk+1, p);
143		s->macro = hunk;
144		hunk += l;
145		nhunk -= l;
146	} else {
147		s = lookup();
148		s->macro = "\0001";	/* \000 is nargs */
149	}
150	if(debug['m'])
151		print("#define (-D) %s %s\n", s->name, s->macro+1);
152}
153
154struct
155{
156	char	*macname;
157	void	(*macf)(void);
158} mactab[] =
159{
160	"ifdef",	0,	/* macif(0) */
161	"ifndef",	0,	/* macif(1) */
162	"else",		0,	/* macif(2) */
163
164	"line",		maclin,
165	"define",	macdef,
166	"include",	macinc,
167	"undef",	macund,
168
169	"pragma",	macprag,
170	"endif",	macend,
171	0
172};
173
174void
175domacro(void)
176{
177	int i;
178	Sym *s;
179
180	s = getsym();
181	if(s == S)
182		s = slookup("endif");
183	for(i=0; mactab[i].macname; i++)
184		if(strcmp(s->name, mactab[i].macname) == 0) {
185			if(mactab[i].macf)
186				(*mactab[i].macf)();
187			else
188				macif(i);
189			return;
190		}
191	yyerror("unknown #: %s", s->name);
192	macend();
193}
194
195void
196macund(void)
197{
198	Sym *s;
199
200	s = getsym();
201	macend();
202	if(s == S) {
203		yyerror("syntax in #undef");
204		return;
205	}
206	s->macro = 0;
207}
208
209#define	NARG	25
210void
211macdef(void)
212{
213	Sym *s, *a;
214	char *args[NARG], *base;
215	int n, i, c, len, dots;
216	int ischr;
217
218	s = getsym();
219	if(s == S)
220		goto bad;
221	if(s->macro)
222		yyerror("macro redefined: %s", s->name);
223	c = getc();
224	n = -1;
225	dots = 0;
226	if(c == '(') {
227		n++;
228		c = getnsc();
229		if(c != ')') {
230			unget(c);
231			for(;;) {
232				a = getsymdots(&dots);
233				if(a == S)
234					goto bad;
235				if(n >= NARG) {
236					yyerror("too many arguments in #define: %s", s->name);
237					goto bad;
238				}
239				args[n++] = a->name;
240				c = getnsc();
241				if(c == ')')
242					break;
243				if(c != ',' || dots)
244					goto bad;
245			}
246		}
247		c = getc();
248	}
249	if(isspace(c))
250		if(c != '\n')
251			c = getnsc();
252	base = hunk;
253	len = 1;
254	ischr = 0;
255	for(;;) {
256		if(c >= Runeself || isalpha(c) || c == '_') {
257			nextsym(c);
258			c = getc();
259			for(i=0; i<n; i++)
260				if(strcmp(symb, args[i]) == 0)
261					break;
262			if(i >= n) {
263				i = strlen(symb);
264				base = allocn(base, len, i);
265				memcpy(base+len, symb, i);
266				len += i;
267				continue;
268			}
269			base = allocn(base, len, 2);
270			base[len++] = '#';
271			base[len++] = 'a' + i;
272			continue;
273		}
274		if(ischr){
275			if(c == '\\'){
276				base = allocn(base, len, 1);
277				base[len++] = c;
278				c = getc();
279			}else if(c == ischr)
280				ischr = 0;
281		}else{
282			if(c == '"' || c == '\''){
283				base = allocn(base, len, 1);
284				base[len++] = c;
285				ischr = c;
286				c = getc();
287				continue;
288			}
289			if(c == '/') {
290				c = getc();
291				if(c == '/'){
292					c = getc();
293					for(;;) {
294						if(c == '\n')
295							break;
296						c = getc();
297					}
298					continue;
299				}
300				if(c == '*'){
301					c = getc();
302					for(;;) {
303						if(c == '*') {
304							c = getc();
305							if(c != '/')
306								continue;
307							c = getc();
308							break;
309						}
310						if(0 && c == '\n') {
311							yyerror("comment and newline in define: %s", s->name);
312							break;
313						}
314						c = getc();
315					}
316					continue;
317				}
318				base = allocn(base, len, 1);
319				base[len++] = '/';
320				continue;
321			}
322		}
323		if(c == '\\') {
324			c = getc();
325			if(c == '\n') {
326				c = getc();
327				continue;
328			}
329			else if(c == '\r') {
330				c = getc();
331				if(c == '\n') {
332					c = getc();
333					continue;
334				}
335			}
336			base = allocn(base, len, 1);
337			base[len++] = '\\';
338			continue;
339		}
340		if(c == '\n')
341			break;
342		if(c == '#')
343		if(n > 0) {
344			base = allocn(base, len, 1);
345			base[len++] = c;
346		}
347		base = allocn(base, len, 1);
348		base[len++] = c;
349		c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
350		if(c == '\n')
351			lineno++;
352		if(c == -1) {
353			yyerror("eof in a macro: %s", s->name);
354			break;
355		}
356	}
357	do {
358		base = allocn(base, len, 1);
359		base[len++] = 0;
360	} while(len & 3);
361
362	*base = n+1;
363	if(dots)
364		*base |= VARMAC;
365	s->macro = base;
366	if(debug['m'])
367		print("#define %s %s\n", s->name, s->macro+1);
368	return;
369
370bad:
371	if(s == S)
372		yyerror("syntax in #define");
373	else
374		yyerror("syntax in #define: %s", s->name);
375	macend();
376}
377
378void
379macexpand(Sym *s, char *b)
380{
381	char buf[2000];
382	int n, l, c, nargs;
383	char *arg[NARG], *cp, *ob, *ecp, dots;
384
385	ob = b;
386	if(*s->macro == 0) {
387		strcpy(b, s->macro+1);
388		if(debug['m'])
389			print("#expand %s %s\n", s->name, ob);
390		return;
391	}
392
393	nargs = (char)(*s->macro & ~VARMAC) - 1;
394	dots = *s->macro & VARMAC;
395
396	c = getnsc();
397	if(c != '(')
398		goto bad;
399	n = 0;
400	c = getc();
401	if(c != ')') {
402		unget(c);
403		l = 0;
404		cp = buf;
405		ecp = cp + sizeof(buf)-UTFmax;
406		arg[n++] = cp;
407		for(;;) {
408			if(cp >= ecp)
409				goto toobig;
410			c = getc();
411			if(c == '"')
412				for(;;) {
413					if(cp >= ecp)
414						goto toobig;
415					*cp++ = c;
416					c = getc();
417					if(c == '\\') {
418						*cp++ = c;
419						c = getc();
420						continue;
421					}
422					if(c == '\n')
423						goto bad;
424					if(c == '"')
425						break;
426				}
427			if(c == '\'')
428				for(;;) {
429					if(cp >= ecp)
430						goto toobig;
431					*cp++ = c;
432					c = getc();
433					if(c == '\\') {
434						*cp++ = c;
435						c = getc();
436						continue;
437					}
438					if(c == '\n')
439						goto bad;
440					if(c == '\'')
441						break;
442				}
443			if(c == '/') {
444				c = getc();
445				switch(c) {
446				case '*':
447					for(;;) {
448						c = getc();
449						if(c == '*') {
450							c = getc();
451							if(c == '/')
452								break;
453						}
454					}
455					*cp++ = ' ';
456					continue;
457				case '/':
458					while((c = getc()) != '\n')
459						;
460					break;
461				default:
462					unget(c);
463					c = '/';
464				}
465			}
466			if(l == 0) {
467				if(c == ',') {
468					if(n == nargs && dots) {
469						*cp++ = ',';
470						continue;
471					}
472					*cp++ = 0;
473					arg[n++] = cp;
474					if(n > nargs)
475						break;
476					continue;
477				}
478				if(c == ')')
479					break;
480			}
481			if(c == '\n')
482				c = ' ';
483			*cp++ = c;
484			if(c == '(')
485				l++;
486			if(c == ')')
487				l--;
488		}
489		*cp = 0;
490	}
491	if(n != nargs) {
492		yyerror("argument mismatch expanding: %s", s->name);
493		*b = 0;
494		return;
495	}
496	cp = s->macro+1;
497	for(;;) {
498		c = *cp++;
499		if(c == '\n')
500			c = ' ';
501		if(c != '#') {
502			*b++ = c;
503			if(c == 0)
504				break;
505			continue;
506		}
507		c = *cp++;
508		if(c == 0)
509			goto bad;
510		if(c == '#') {
511			*b++ = c;
512			continue;
513		}
514		c -= 'a';
515		if(c < 0 || c >= n)
516			continue;
517		strcpy(b, arg[c]);
518		b += strlen(arg[c]);
519	}
520	*b = 0;
521	if(debug['m'])
522		print("#expand %s %s\n", s->name, ob);
523	return;
524
525bad:
526	yyerror("syntax in macro expansion: %s", s->name);
527	*b = 0;
528	return;
529
530toobig:
531	yyerror("too much text in macro expansion: %s", s->name);
532	*b = 0;
533}
534
535void
536macinc(void)
537{
538	int c0, c, i, f;
539	char str[STRINGSZ], *hp;
540
541	c0 = getnsc();
542	if(c0 != '"') {
543		c = c0;
544		if(c0 != '<')
545			goto bad;
546		c0 = '>';
547	}
548	for(hp = str;;) {
549		c = getc();
550		if(c == c0)
551			break;
552		if(c == '\n')
553			goto bad;
554		*hp++ = c;
555	}
556	*hp = 0;
557
558	c = getcom();
559	if(c != '\n')
560		goto bad;
561
562	f = -1;
563	for(i=0; i<ninclude; i++) {
564		if(i == 0 && c0 == '>')
565			continue;
566		strcpy(symb, include[i]);
567		strcat(symb, "/");
568		if(strcmp(symb, "./") == 0)
569			symb[0] = 0;
570		strcat(symb, str);
571		f = open(symb, 0);
572		if(f >= 0)
573			break;
574	}
575	if(f < 0)
576		strcpy(symb, str);
577	c = strlen(symb) + 1;
578	while(c & 3)
579		c++;
580	while(nhunk < c)
581		gethunk();
582	hp = hunk;
583	memcpy(hunk, symb, c);
584	nhunk -= c;
585	hunk += c;
586	newio();
587	pushio();
588	newfile(hp, f);
589	return;
590
591bad:
592	unget(c);
593	yyerror("syntax in #include");
594	macend();
595}
596
597void
598maclin(void)
599{
600	char *cp;
601	int c;
602	long n;
603
604	n = getnsn();
605	c = getc();
606	if(n < 0)
607		goto bad;
608
609	for(;;) {
610		if(c == ' ' || c == '\t') {
611			c = getc();
612			continue;
613		}
614		if(c == '"')
615			break;
616		if(c == '\n') {
617			strcpy(symb, "<noname>");
618			goto nn;
619		}
620		goto bad;
621	}
622	cp = symb;
623	for(;;) {
624		c = getc();
625		if(c == '"')
626			break;
627		*cp++ = c;
628	}
629	*cp = 0;
630	c = getcom();
631	if(c != '\n')
632		goto bad;
633
634nn:
635	c = strlen(symb) + 1;
636	while(c & 3)
637		c++;
638	while(nhunk < c)
639		gethunk();
640	cp = hunk;
641	memcpy(hunk, symb, c);
642	nhunk -= c;
643	hunk += c;
644	linehist(cp, n);
645	return;
646
647bad:
648	unget(c);
649	yyerror("syntax in #line");
650	macend();
651}
652
653void
654macif(int f)
655{
656	int c, l, bol;
657	Sym *s;
658
659	if(f == 2)
660		goto skip;
661	s = getsym();
662	if(s == S)
663		goto bad;
664	if(getcom() != '\n')
665		goto bad;
666	if((s->macro != 0) ^ f)
667		return;
668
669skip:
670	bol = 1;
671	l = 0;
672	for(;;) {
673		c = getc();
674		if(c != '#') {
675			if(!isspace(c))
676				bol = 0;
677			if(c == '\n')
678				bol = 1;
679			continue;
680		}
681		if(!bol)
682			continue;
683		s = getsym();
684		if(s == S)
685			continue;
686		if(strcmp(s->name, "endif") == 0) {
687			if(l) {
688				l--;
689				continue;
690			}
691			macend();
692			return;
693		}
694		if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
695			l++;
696			continue;
697		}
698		if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
699			macend();
700			return;
701		}
702	}
703
704bad:
705	yyerror("syntax in #if(n)def");
706	macend();
707}
708
709void
710macprag(void)
711{
712	Sym *s;
713	int c0, c;
714	char *hp;
715	Hist *h;
716
717	s = getsym();
718
719	if(s && strcmp(s->name, "lib") == 0)
720		goto praglib;
721	if(s && strcmp(s->name, "pack") == 0) {
722		pragpack();
723		return;
724	}
725	if(s && strcmp(s->name, "fpround") == 0) {
726		pragfpround();
727		return;
728	}
729	if(s && strcmp(s->name, "profile") == 0) {
730		pragprofile();
731		return;
732	}
733	if(s && strcmp(s->name, "varargck") == 0) {
734		pragvararg();
735		return;
736	}
737	if(s && strcmp(s->name, "incomplete") == 0) {
738		pragincomplete();
739		return;
740	}
741	while(getnsc() != '\n')
742		;
743	return;
744
745praglib:
746	c0 = getnsc();
747	if(c0 != '"') {
748		c = c0;
749		if(c0 != '<')
750			goto bad;
751		c0 = '>';
752	}
753	for(hp = symb;;) {
754		c = getc();
755		if(c == c0)
756			break;
757		if(c == '\n')
758			goto bad;
759		*hp++ = c;
760	}
761	*hp = 0;
762	c = getcom();
763	if(c != '\n')
764		goto bad;
765
766	/*
767	 * put pragma-line in as a funny history
768	 */
769	c = strlen(symb) + 1;
770	while(c & 3)
771		c++;
772	while(nhunk < c)
773		gethunk();
774	hp = hunk;
775	memcpy(hunk, symb, c);
776	nhunk -= c;
777	hunk += c;
778
779	h = alloc(sizeof(Hist));
780	h->name = hp;
781	h->line = lineno;
782	h->offset = -1;
783	h->link = H;
784	if(ehist == H) {
785		hist = h;
786		ehist = h;
787		return;
788	}
789	ehist->link = h;
790	ehist = h;
791	return;
792
793bad:
794	unget(c);
795	yyerror("syntax in #pragma lib");
796	macend();
797}
798
799void
800macend(void)
801{
802	int c;
803
804	for(;;) {
805		c = getnsc();
806		if(c < 0 || c == '\n')
807			return;
808	}
809}
810
811void
812linehist(char *f, int offset)
813{
814	Hist *h;
815
816	/*
817	 * overwrite the last #line directive if
818	 * no alloc has happened since the last one
819	 */
820	if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0)
821		if(f && ehist->name && strcmp(f, ehist->name) == 0) {
822			ehist->line = lineno;
823			ehist->offset = offset;
824			return;
825		}
826
827	if(debug['f'])
828		if(f) {
829			if(offset)
830				print("%4ld: %s (#line %d)\n", lineno, f, offset);
831			else
832				print("%4ld: %s\n", lineno, f);
833		} else
834			print("%4ld: <pop>\n", lineno);
835	newflag = 0;
836
837	h = alloc(sizeof(Hist));
838	h->name = f;
839	h->line = lineno;
840	h->offset = offset;
841	h->link = H;
842	if(ehist == H) {
843		hist = h;
844		ehist = h;
845		return;
846	}
847	ehist->link = h;
848	ehist = h;
849}
850
851void
852gethunk(void)
853{
854	char *h;
855	long nh;
856
857	nh = NHUNK;
858	if(thunk >= 10L*NHUNK)
859		nh = 10L*NHUNK;
860	h = (char*)mysbrk(nh);
861	if(h == (char*)-1) {
862		yyerror("out of memory");
863		errorexit();
864	}
865	hunk = h;
866	nhunk = nh;
867	thunk += nh;
868}
869