]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cc/macbody
cc: use UTFmax not 4 (djc)
[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 static void
22 nextsym(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
51 Sym*
52 getsym(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
65 Sym*
66 getsymdots(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
86 int
87 getcom(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
124 void
125 dodefine(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
154 struct
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
174 void
175 domacro(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
195 void
196 macund(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
210 void
211 macdef(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
370 bad:
371         if(s == S)
372                 yyerror("syntax in #define");
373         else
374                 yyerror("syntax in #define: %s", s->name);
375         macend();
376 }
377
378 void
379 macexpand(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
525 bad:
526         yyerror("syntax in macro expansion: %s", s->name);
527         *b = 0;
528         return;
529
530 toobig:
531         yyerror("too much text in macro expansion: %s", s->name);
532         *b = 0;
533 }
534
535 void
536 macinc(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
591 bad:
592         unget(c);
593         yyerror("syntax in #include");
594         macend();
595 }
596
597 void
598 maclin(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
634 nn:
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
647 bad:
648         unget(c);
649         yyerror("syntax in #line");
650         macend();
651 }
652
653 void
654 macif(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
669 skip:
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
704 bad:
705         yyerror("syntax in #if(n)def");
706         macend();
707 }
708
709 void
710 macprag(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
745 praglib:
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
793 bad:
794         unget(c);
795         yyerror("syntax in #pragma lib");
796         macend();
797 }
798
799 void
800 macend(void)
801 {
802         int c;
803
804         for(;;) {
805                 c = getnsc();
806                 if(c < 0 || c == '\n')
807                         return;
808         }
809 }
810
811 void
812 linehist(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
851 void
852 gethunk(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 }