]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cc/macbody
kernel: keep segment locked for data2txt
[plan9front.git] / sys / src / cmd / cc / macbody
1 #define VARMAC 0x80
2
3 long
4 getnsn(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
21 Sym*
22 getsym(void)
23 {
24         int c;
25         char *cp;
26
27         c = getnsc();
28         if(!isalpha(c) && c != '_') {
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 == '_')
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
47 Sym*
48 getsymdots(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
68 int
69 getcom(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
106 void
107 dodefine(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
136 struct
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
156 void
157 domacro(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
177 void
178 macund(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
192 void
193 macdef(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
358 bad:
359         if(s == S)
360                 yyerror("syntax in #define");
361         else
362                 yyerror("syntax in #define: %s", s->name);
363         macend();
364 }
365
366 void
367 macexpand(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
513 bad:
514         yyerror("syntax in macro expansion: %s", s->name);
515         *b = 0;
516         return;
517
518 toobig:
519         yyerror("too much text in macro expansion: %s", s->name);
520         *b = 0;
521 }
522
523 void
524 macinc(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
579 bad:
580         unget(c);
581         yyerror("syntax in #include");
582         macend();
583 }
584
585 void
586 maclin(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
622 nn:
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
635 bad:
636         unget(c);
637         yyerror("syntax in #line");
638         macend();
639 }
640
641 void
642 macif(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
657 skip:
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
692 bad:
693         yyerror("syntax in #if(n)def");
694         macend();
695 }
696
697 void
698 macprag(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
733 praglib:
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
781 bad:
782         unget(c);
783         yyerror("syntax in #pragma lib");
784         macend();
785 }
786
787 void
788 macend(void)
789 {
790         int c;
791
792         for(;;) {
793                 c = getnsc();
794                 if(c < 0 || c == '\n')
795                         return;
796         }
797 }
798
799 void
800 linehist(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
839 void
840 gethunk(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 }