blob: f6927b2f66f357e1d3c6d8f457ef75ef0a2892c3 [file] [log] [blame]
Brent Austinba3052e2015-04-21 16:08:23 -07001// Inferno utils/cc/macbody
2// http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody
3//
4// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
5// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6// Portions Copyright © 1997-1999 Vita Nuova Limited
7// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8// Portions Copyright © 2004,2006 Bruce Ellis
9// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11// Portions Copyright © 2009 The Go Authors. All rights reserved.
12//
13// Permission is hereby granted, free of charge, to any person obtaining a copy
14// of this software and associated documentation files (the "Software"), to deal
15// in the Software without restriction, including without limitation the rights
16// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17// copies of the Software, and to permit persons to whom the Software is
18// furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included in
21// all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29// THE SOFTWARE.
30
31#define VARMAC 0x80
32
33int32
34getnsn(void)
35{
36 int32 n;
37 int c;
38
39 c = getnsc();
40 if(c < '0' || c > '9')
41 return -1;
42 n = 0;
43 while(c >= '0' && c <= '9') {
44 n = n*10 + c-'0';
45 c = getc();
46 }
47 unget(c);
48 return n;
49}
50
51Sym*
52getsym(void)
53{
54 int c;
55 char *cp;
56
57 c = getnsc();
58 if(!isalpha(c) && c != '_' && c < 0x80) {
59 unget(c);
60 return S;
61 }
62 for(cp = symb;;) {
63 if(cp <= symb+NSYMB-4)
64 *cp++ = c;
65 c = getc();
66 if(isalnum(c) || c == '_' || c >= 0x80)
67 continue;
68 unget(c);
69 break;
70 }
71 *cp = 0;
72 if(cp > symb+NSYMB-4)
73 yyerror("symbol too large: %s", symb);
74 return lookup();
75}
76
77Sym*
78getsymdots(int *dots)
79{
80 int c;
81 Sym *s;
82
83 s = getsym();
84 if(s != S)
85 return s;
86
87 c = getnsc();
88 if(c != '.'){
89 unget(c);
90 return S;
91 }
92 if(getc() != '.' || getc() != '.')
93 yyerror("bad dots in macro");
94 *dots = 1;
95 return slookup("__VA_ARGS__");
96}
97
98int
99getcom(void)
100{
101 int c;
102
103 for(;;) {
104 c = getnsc();
105 if(c != '/')
106 break;
107 c = getc();
108 if(c == '/') {
109 while(c != '\n')
110 c = getc();
111 break;
112 }
113 if(c != '*')
114 break;
115 c = getc();
116 for(;;) {
117 if(c == '*') {
118 c = getc();
119 if(c != '/')
120 continue;
121 c = getc();
122 break;
123 }
124 if(c == '\n') {
125 yyerror("comment across newline");
126 break;
127 }
128 c = getc();
129 }
130 if(c == '\n')
131 break;
132 }
133 return c;
134}
135
136void
137dodefine(char *cp)
138{
139 Sym *s;
140 char *p;
141 int32 l;
142
143 ensuresymb(strlen(cp));
144 strcpy(symb, cp);
145 p = strchr(symb, '=');
146 if(p) {
147 *p++ = 0;
148 s = lookup();
149 l = strlen(p) + 2; /* +1 null, +1 nargs */
150 s->macro = alloc(l);
151 strcpy(s->macro+1, p);
152 } else {
153 s = lookup();
154 s->macro = "\0001"; /* \000 is nargs */
155 }
156 if(debug['m'])
157 print("#define (-D) %s %s\n", s->name, s->macro+1);
158}
159
160struct
161{
162 char *macname;
163 void (*macf)(void);
164} mactab[] =
165{
166 "ifdef", 0, /* macif(0) */
167 "ifndef", 0, /* macif(1) */
168 "else", 0, /* macif(2) */
169
170 "line", maclin,
171 "define", macdef,
172 "include", macinc,
173 "undef", macund,
174
175 "pragma", macprag,
176 "endif", macend,
177 0
178};
179
180void
181domacro(void)
182{
183 int i;
184 Sym *s;
185
186 s = getsym();
187 if(s == S)
188 s = slookup("endif");
189 for(i=0; mactab[i].macname; i++)
190 if(strcmp(s->name, mactab[i].macname) == 0) {
191 if(mactab[i].macf)
192 (*mactab[i].macf)();
193 else
194 macif(i);
195 return;
196 }
197 yyerror("unknown #: %s", s->name);
198 macend();
199}
200
201void
202macund(void)
203{
204 Sym *s;
205
206 s = getsym();
207 macend();
208 if(s == S) {
209 yyerror("syntax in #undef");
210 return;
211 }
212 s->macro = 0;
213}
214
215#define NARG 25
216void
217macdef(void)
218{
219 Sym *s, *a;
220 char *args[NARG], *np, *base;
221 int n, i, c, len, dots;
222 int ischr;
223
224 s = getsym();
225 if(s == S)
226 goto bad;
227 if(s->macro)
228 yyerror("macro redefined: %s", s->name);
229 c = getc();
230 n = -1;
231 dots = 0;
232 if(c == '(') {
233 n++;
234 c = getnsc();
235 if(c != ')') {
236 unget(c);
237 for(;;) {
238 a = getsymdots(&dots);
239 if(a == S)
240 goto bad;
241 if(n >= NARG) {
242 yyerror("too many arguments in #define: %s", s->name);
243 goto bad;
244 }
245 args[n++] = a->name;
246 c = getnsc();
247 if(c == ')')
248 break;
249 if(c != ',' || dots)
250 goto bad;
251 }
252 }
253 c = getc();
254 }
255 if(isspace(c))
256 if(c != '\n')
257 c = getnsc();
258 base = hunk;
259 len = 1;
260 ischr = 0;
261 for(;;) {
262 if(isalpha(c) || c == '_') {
263 np = symb;
264 *np++ = c;
265 c = getc();
266 while(isalnum(c) || c == '_') {
267 *np++ = c;
268 c = getc();
269 }
270 *np = 0;
271 for(i=0; i<n; i++)
272 if(strcmp(symb, args[i]) == 0)
273 break;
274 if(i >= n) {
275 i = strlen(symb);
276 base = allocn(base, len, i);
277 memcpy(base+len, symb, i);
278 len += i;
279 continue;
280 }
281 base = allocn(base, len, 2);
282 base[len++] = '#';
283 base[len++] = 'a' + i;
284 continue;
285 }
286 if(ischr){
287 if(c == '\\'){
288 base = allocn(base, len, 1);
289 base[len++] = c;
290 c = getc();
291 }else if(c == ischr)
292 ischr = 0;
293 }else{
294 if(c == '"' || c == '\''){
295 base = allocn(base, len, 1);
296 base[len++] = c;
297 ischr = c;
298 c = getc();
299 continue;
300 }
301 if(c == '/') {
302 c = getc();
303 if(c == '/'){
304 c = getc();
305 for(;;) {
306 if(c == '\n')
307 break;
308 c = getc();
309 }
310 continue;
311 }
312 if(c == '*'){
313 c = getc();
314 for(;;) {
315 if(c == '*') {
316 c = getc();
317 if(c != '/')
318 continue;
319 c = getc();
320 break;
321 }
322 if(c == '\n') {
323 yyerror("comment and newline in define: %s", s->name);
324 break;
325 }
326 c = getc();
327 }
328 continue;
329 }
330 base = allocn(base, len, 1);
331 base[len++] = '/';
332 continue;
333 }
334 }
335 if(c == '\\') {
336 c = getc();
337 if(c == '\n') {
338 c = getc();
339 continue;
340 }
341 else if(c == '\r') {
342 c = getc();
343 if(c == '\n') {
344 c = getc();
345 continue;
346 }
347 }
348 base = allocn(base, len, 1);
349 base[len++] = '\\';
350 continue;
351 }
352 if(c == '\n')
353 break;
354 if(c == '#')
355 if(n > 0) {
356 base = allocn(base, len, 1);
357 base[len++] = c;
358 }
359 base = allocn(base, len, 1);
360 base[len++] = c;
361 c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
362 if(c == '\n')
363 lineno++;
364 if(c == -1) {
365 yyerror("eof in a macro: %s", s->name);
366 break;
367 }
368 }
369 do {
370 base = allocn(base, len, 1);
371 base[len++] = 0;
372 } while(len & 3);
373
374 *base = n+1;
375 if(dots)
376 *base |= VARMAC;
377 s->macro = base;
378 if(debug['m'])
379 print("#define %s %s\n", s->name, s->macro+1);
380 return;
381
382bad:
383 if(s == S)
384 yyerror("syntax in #define");
385 else
386 yyerror("syntax in #define: %s", s->name);
387 macend();
388}
389
390void
391macexpand(Sym *s, char *b)
392{
393 char buf[2000];
394 int n, l, c, nargs;
395 char *arg[NARG], *cp, *ob, *ecp, dots;
396
397 ob = b;
398 if(*s->macro == 0) {
399 strcpy(b, s->macro+1);
400 if(debug['m'])
401 print("#expand %s %s\n", s->name, ob);
402 return;
403 }
404
405 nargs = (char)(*s->macro & ~VARMAC) - 1;
406 dots = *s->macro & VARMAC;
407
408 c = getnsc();
409 if(c != '(')
410 goto bad;
411 n = 0;
412 c = getc();
413 if(c != ')') {
414 unget(c);
415 l = 0;
416 cp = buf;
417 ecp = cp + sizeof(buf)-4;
418 arg[n++] = cp;
419 for(;;) {
420 if(cp >= ecp)
421 goto toobig;
422 c = getc();
423 if(c == '"')
424 for(;;) {
425 if(cp >= ecp)
426 goto toobig;
427 *cp++ = c;
428 c = getc();
429 if(c == '\\') {
430 *cp++ = c;
431 c = getc();
432 continue;
433 }
434 if(c == '\n')
435 goto bad;
436 if(c == '"')
437 break;
438 }
439 if(c == '\'')
440 for(;;) {
441 if(cp >= ecp)
442 goto toobig;
443 *cp++ = c;
444 c = getc();
445 if(c == '\\') {
446 *cp++ = c;
447 c = getc();
448 continue;
449 }
450 if(c == '\n')
451 goto bad;
452 if(c == '\'')
453 break;
454 }
455 if(c == '/') {
456 c = getc();
457 switch(c) {
458 case '*':
459 for(;;) {
460 c = getc();
461 if(c == '*') {
462 c = getc();
463 if(c == '/')
464 break;
465 }
466 }
467 *cp++ = ' ';
468 continue;
469 case '/':
470 while((c = getc()) != '\n')
471 ;
472 break;
473 default:
474 unget(c);
475 c = '/';
476 }
477 }
478 if(l == 0) {
479 if(c == ',') {
480 if(n == nargs && dots) {
481 *cp++ = ',';
482 continue;
483 }
484 *cp++ = 0;
485 arg[n++] = cp;
486 if(n > nargs)
487 break;
488 continue;
489 }
490 if(c == ')')
491 break;
492 }
493 if(c == '\n')
494 c = ' ';
495 *cp++ = c;
496 if(c == '(')
497 l++;
498 if(c == ')')
499 l--;
500 }
501 *cp = 0;
502 }
503 if(n != nargs) {
504 yyerror("argument mismatch expanding: %s", s->name);
505 *b = 0;
506 return;
507 }
508 cp = s->macro+1;
509 for(;;) {
510 c = *cp++;
511 if(c == '\n')
512 c = ' ';
513 if(c != '#') {
514 *b++ = c;
515 if(c == 0)
516 break;
517 continue;
518 }
519 c = *cp++;
520 if(c == 0)
521 goto bad;
522 if(c == '#') {
523 *b++ = c;
524 continue;
525 }
526 c -= 'a';
527 if(c < 0 || c >= n)
528 continue;
529 strcpy(b, arg[c]);
530 b += strlen(arg[c]);
531 }
532 *b = 0;
533 if(debug['m'])
534 print("#expand %s %s\n", s->name, ob);
535 return;
536
537bad:
538 yyerror("syntax in macro expansion: %s", s->name);
539 *b = 0;
540 return;
541
542toobig:
543 yyerror("too much text in macro expansion: %s", s->name);
544 *b = 0;
545}
546
547void
548macinc(void)
549{
550 int c0, c, i, f;
551 char str[STRINGSZ], *hp;
552
553 c0 = getnsc();
554 if(c0 != '"') {
555 c = c0;
556 if(c0 != '<')
557 goto bad;
558 c0 = '>';
559 }
560 for(hp = str;;) {
561 c = getc();
562 if(c == c0)
563 break;
564 if(c == '\n')
565 goto bad;
566 *hp++ = c;
567 }
568 *hp = 0;
569
570 c = getcom();
571 if(c != '\n')
572 goto bad;
573
574 f = -1;
575 for(i=0; i<ninclude; i++) {
576 if(i == 0 && c0 == '>')
577 continue;
578 ensuresymb(strlen(include[i])+strlen(str)+2);
579 strcpy(symb, include[i]);
580 strcat(symb, "/");
581 if(strcmp(symb, "./") == 0)
582 symb[0] = 0;
583 strcat(symb, str);
584 f = open(symb, OREAD);
585 if(f >= 0)
586 break;
587 }
588 if(f < 0)
589 strcpy(symb, str);
590 c = strlen(symb) + 1;
591 hp = alloc(c);
592 memcpy(hp, symb, c);
593 newio();
594 pushio();
595 newfile(hp, f);
596 return;
597
598bad:
599 unget(c);
600 yyerror("syntax in #include");
601 macend();
602}
603
604void
605maclin(void)
606{
607 char *cp;
608 int c;
609 int32 n;
610
611 n = getnsn();
612 c = getc();
613 if(n < 0)
614 goto bad;
615
616 for(;;) {
617 if(c == ' ' || c == '\t') {
618 c = getc();
619 continue;
620 }
621 if(c == '"')
622 break;
623 if(c == '\n') {
624 strcpy(symb, "<noname>");
625 goto nn;
626 }
627 goto bad;
628 }
629 cp = symb;
630 for(;;) {
631 c = getc();
632 if(c == '"')
633 break;
634 *cp++ = c;
635 }
636 *cp = 0;
637 c = getcom();
638 if(c != '\n')
639 goto bad;
640
641nn:
642 c = strlen(symb) + 1;
643 cp = alloc(c);
644 memcpy(cp, symb, c);
645 linklinehist(ctxt, lineno, cp, n);
646 return;
647
648bad:
649 unget(c);
650 yyerror("syntax in #line");
651 macend();
652}
653
654void
655macif(int f)
656{
657 int c, l, bol;
658 Sym *s;
659
660 if(f == 2)
661 goto skip;
662 s = getsym();
663 if(s == S)
664 goto bad;
665 if(getcom() != '\n')
666 goto bad;
667 if((s->macro != 0) ^ f)
668 return;
669
670skip:
671 bol = 1;
672 l = 0;
673 for(;;) {
674 c = getc();
675 if(c != '#') {
676 if(!isspace(c))
677 bol = 0;
678 if(c == '\n')
679 bol = 1;
680 continue;
681 }
682 if(!bol)
683 continue;
684 s = getsym();
685 if(s == S)
686 continue;
687 if(strcmp(s->name, "endif") == 0) {
688 if(l) {
689 l--;
690 continue;
691 }
692 macend();
693 return;
694 }
695 if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
696 l++;
697 continue;
698 }
699 if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
700 macend();
701 return;
702 }
703 }
704
705bad:
706 yyerror("syntax in #if(n)def");
707 macend();
708}
709
710void
711macprag(void)
712{
713 Sym *s;
714 int c0, c;
715 char *hp;
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, "textflag") == 0) {
730 pragtextflag();
731 return;
732 }
733 if(s && strcmp(s->name, "dataflag") == 0) {
734 pragdataflag();
735 return;
736 }
737 if(s && strcmp(s->name, "varargck") == 0) {
738 pragvararg();
739 return;
740 }
741 if(s && strcmp(s->name, "incomplete") == 0) {
742 pragincomplete();
743 return;
744 }
745 if(s && (strncmp(s->name, "cgo_", 4) == 0 || strncmp(s->name, "dyn", 3) == 0)) {
746 pragcgo(s->name);
747 return;
748 }
749 while(getnsc() != '\n')
750 ;
751 return;
752
753praglib:
754 c0 = getnsc();
755 if(c0 != '"') {
756 c = c0;
757 if(c0 != '<')
758 goto bad;
759 c0 = '>';
760 }
761 for(hp = symb;;) {
762 c = getc();
763 if(c == c0)
764 break;
765 if(c == '\n')
766 goto bad;
767 *hp++ = c;
768 }
769 *hp = 0;
770 c = getcom();
771 if(c != '\n')
772 goto bad;
773
774 /*
775 * put pragma-line in as a funny history
776 */
777 c = strlen(symb) + 1;
778 hp = alloc(c);
779 memcpy(hp, symb, c);
780
781 linklinehist(ctxt, lineno, hp, -1);
782 return;
783
784bad:
785 unget(c);
786 yyerror("syntax in #pragma lib");
787 macend();
788}
789
790void
791macend(void)
792{
793 int c;
794
795 for(;;) {
796 c = getnsc();
797 if(c < 0 || c == '\n')
798 return;
799 }
800}