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