]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cc/macbody
cc: promote integer constants according to c99 spec.
[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         strncpy(symb, cp, NSYMB);
132         if(symb[NSYMB-1] != '\0'){
133                 yyerror("macro too long: %s", cp);
134                 symb[NSYMB-1] = 0;
135         }
136         p = strchr(symb, '=');
137         if(p) {
138                 *p++ = 0;
139                 s = lookup();
140                 l = strlen(p) + 2;      /* +1 null, +1 nargs */
141                 s->macro = alloc(l);
142                 memcpy(s->macro, p-1, l);
143         } else {
144                 s = lookup();
145                 s->macro = "\0001";     /* \000 is nargs */
146         }
147         if(debug['m'])
148                 print("#define (-D) %s %s\n", s->name, s->macro+1);
149 }
150
151 struct
152 {
153         char    *macname;
154         void    (*macf)(void);
155 } mactab[] =
156 {
157         "ifdef",        0,      /* macif(0) */
158         "ifndef",       0,      /* macif(1) */
159         "else",         0,      /* macif(2) */
160
161         "line",         maclin,
162         "define",       macdef,
163         "include",      macinc,
164         "undef",        macund,
165
166         "pragma",       macprag,
167         "endif",        macend,
168         0
169 };
170
171 void
172 domacro(void)
173 {
174         int i;
175         Sym *s;
176
177         s = getsym();
178         if(s == S)
179                 s = slookup("endif");
180         for(i=0; mactab[i].macname; i++)
181                 if(strcmp(s->name, mactab[i].macname) == 0) {
182                         if(mactab[i].macf)
183                                 (*mactab[i].macf)();
184                         else
185                                 macif(i);
186                         return;
187                 }
188         yyerror("unknown #: %s", s->name);
189         macend();
190 }
191
192 void
193 macund(void)
194 {
195         Sym *s;
196
197         s = getsym();
198         macend();
199         if(s == S) {
200                 yyerror("syntax in #undef");
201                 return;
202         }
203         s->macro = 0;
204 }
205
206 #define NARG    25
207 void
208 macdef(void)
209 {
210         Sym *s, *a;
211         char *args[NARG], *base;
212         int n, i, c, len, dots;
213         int ischr;
214
215         s = getsym();
216         if(s == S)
217                 goto bad;
218         if(s->macro)
219                 yyerror("macro redefined: %s", s->name);
220         c = getc();
221         n = -1;
222         dots = 0;
223         if(c == '(') {
224                 n++;
225                 c = getnsc();
226                 if(c != ')') {
227                         unget(c);
228                         for(;;) {
229                                 a = getsymdots(&dots);
230                                 if(a == S)
231                                         goto bad;
232                                 if(n >= NARG) {
233                                         yyerror("too many arguments in #define: %s", s->name);
234                                         goto bad;
235                                 }
236                                 args[n++] = a->name;
237                                 c = getnsc();
238                                 if(c == ')')
239                                         break;
240                                 if(c != ',' || dots)
241                                         goto bad;
242                         }
243                 }
244                 c = getc();
245         }
246         if(isspace(c))
247                 if(c != '\n')
248                         c = getnsc();
249         base = alloc(1);
250         len = 1;
251         ischr = 0;
252         for(;;) {
253                 if(c >= Runeself || isalpha(c) || c == '_') {
254                         nextsym(c);
255                         c = getc();
256                         for(i=0; i<n; i++)
257                                 if(strcmp(symb, args[i]) == 0)
258                                         break;
259                         if(i >= n) {
260                                 i = strlen(symb);
261                                 base = allocn(base, len, i);
262                                 memcpy(base+len, symb, i);
263                                 len += i;
264                                 continue;
265                         }
266                         base = allocn(base, len, 2);
267                         base[len++] = '#';
268                         base[len++] = 'a' + i;
269                         continue;
270                 }
271                 if(ischr){
272                         if(c == '\\'){ 
273                                 base = allocn(base, len, 1);
274                                 base[len++] = c;
275                                 c = getc();
276                         }else if(c == ischr)
277                                 ischr = 0;
278                 }else{
279                         if(c == '"' || c == '\''){
280                                 base = allocn(base, len, 1);
281                                 base[len++] = c;
282                                 ischr = c;
283                                 c = getc();
284                                 continue;
285                         }
286                         if(c == '/') {
287                                 c = getc();
288                                 if(c == '/'){
289                                         c = getc();
290                                         for(;;) {
291                                                 if(c == '\n')
292                                                         break;
293                                                 c = getc();
294                                         }
295                                         continue;
296                                 }
297                                 if(c == '*'){
298                                         c = getc();
299                                         for(;;) {
300                                                 if(c == '*') {
301                                                         c = getc();
302                                                         if(c != '/')
303                                                                 continue;
304                                                         c = getc();
305                                                         break;
306                                                 }
307                                                 if(0 && c == '\n') {
308                                                         yyerror("comment and newline in define: %s", s->name);
309                                                         break;
310                                                 }
311                                                 c = getc();
312                                         }
313                                         continue;
314                                 }
315                                 base = allocn(base, len, 1);
316                                 base[len++] = '/';
317                                 continue;
318                         }
319                 }
320                 if(c == '\\') {
321                         c = getc();
322                         if(c == '\n') {
323                                 c = getc();
324                                 continue;
325                         }
326                         else if(c == '\r') {
327                                 c = getc();
328                                 if(c == '\n') {
329                                         c = getc();
330                                         continue;
331                                 }
332                         }
333                         base = allocn(base, len, 1);
334                         base[len++] = '\\';
335                         continue;
336                 }
337                 if(c == '\n')
338                         break;
339                 if(c == '#')
340                 if(n > 0) {
341                         base = allocn(base, len, 1);
342                         base[len++] = c;
343                 }
344                 base = allocn(base, len, 1);
345                 base[len++] = c;
346                 c = GETC();
347                 if(c == '\n')
348                         lineno++;
349                 if(c == -1) {
350                         yyerror("eof in a macro: %s", s->name);
351                         break;
352                 }
353         }
354         do {
355                 base = allocn(base, len, 1);
356                 base[len++] = 0;
357         } while(len & 3);
358
359         *base = n+1;
360         if(dots)
361                 *base |= VARMAC;
362         s->macro = base;
363         if(debug['m'])
364                 print("#define %s %s\n", s->name, s->macro+1);
365         return;
366
367 bad:
368         if(s == S)
369                 yyerror("syntax in #define");
370         else
371                 yyerror("syntax in #define: %s", s->name);
372         macend();
373 }
374
375 void
376 macexpand(Sym *s, char *b, int blen)
377 {
378         char buf[2000];
379         int n, l, c, nargs;
380         char *arg[NARG], *cp, *ob, *eb, *ecp, dots;
381
382         if(*s->macro == 0) {
383                 b[blen-1] = 0;
384                 strncpy(b, s->macro+1, blen);
385                 if(b[blen-1] != '\0')
386                         goto toobig;
387                 if(debug['m'])
388                         print("#expand %s %s\n", s->name, b);
389                 return;
390         }
391         
392         nargs = (char)(*s->macro & ~VARMAC) - 1;
393         dots = *s->macro & VARMAC;
394
395         c = getnsc();
396         if(c != '(')
397                 goto bad;
398         n = 0;
399         c = getc();
400         if(c != ')') {
401                 unget(c);
402                 l = 0;
403                 cp = buf;
404                 ecp = cp + sizeof(buf)-UTFmax;
405                 arg[n++] = cp;
406                 for(;;) {
407                         if(cp >= ecp)
408                                 goto toobig;
409                         c = getc();
410                         if(c == '"')
411                                 for(;;) {
412                                         if(cp >= ecp)
413                                                 goto toobig;
414                                         *cp++ = c;
415                                         c = getc();
416                                         if(c == '\\') {
417                                                 *cp++ = c;
418                                                 c = getc();
419                                                 continue;
420                                         }
421                                         if(c == '\n')
422                                                 goto bad;
423                                         if(c == '"')
424                                                 break;
425                                 }
426                         if(c == '\'')
427                                 for(;;) {
428                                         if(cp >= ecp)
429                                                 goto toobig;
430                                         *cp++ = c;
431                                         c = getc();
432                                         if(c == '\\') {
433                                                 *cp++ = c;
434                                                 c = getc();
435                                                 continue;
436                                         }
437                                         if(c == '\n')
438                                                 goto bad;
439                                         if(c == '\'')
440                                                 break;
441                                 }
442                         if(c == '/') {
443                                 c = getc();
444                                 switch(c) {
445                                 case '*':
446                                         for(;;) {
447                                                 c = getc();
448                                                 if(c == '*') {
449                                                         c = getc();
450                                                         if(c == '/')
451                                                                 break;
452                                                 }
453                                         }
454                                         *cp++ = ' ';
455                                         continue;
456                                 case '/':
457                                         while((c = getc()) != '\n')
458                                                 ;
459                                         break;
460                                 default:
461                                         unget(c);
462                                         c = '/';
463                                 }
464                         }
465                         if(l == 0) {
466                                 if(c == ',') {
467                                         if(n == nargs && dots) {
468                                                 *cp++ = ',';
469                                                 continue;
470                                         }
471                                         *cp++ = 0;
472                                         arg[n++] = cp;
473                                         if(n > nargs)
474                                                 break;
475                                         continue;
476                                 }
477                                 if(c == ')')
478                                         break;
479                         }
480                         if(c == '\n')
481                                 c = ' ';
482                         *cp++ = c;
483                         if(c == '(')
484                                 l++;
485                         if(c == ')')
486                                 l--;
487                 }
488                 *cp = 0;
489         }
490         if(n != nargs) {
491                 yyerror("argument mismatch expanding: %s", s->name);
492                 *b = 0;
493                 return;
494         }
495         ob = b;
496         eb = b + blen-1;
497         cp = s->macro+1;
498         for(;;) {
499                 if(b >= eb)
500                         goto toobig;
501                 c = *cp++;
502                 if(c == '\n')
503                         c = ' ';
504                 if(c != '#') {
505                         *b++ = c;
506                         if(c == 0)
507                                 break;
508                         continue;
509                 }
510                 c = *cp++;
511                 if(c == 0)
512                         goto bad;
513                 if(c == '#') {
514                         *b++ = c;
515                         continue;
516                 }
517                 c -= 'a';
518                 if(c < 0 || c >= n)
519                         continue;
520                 l = strlen(arg[c]);
521                 if(b+l > eb)
522                         goto toobig;
523                 memmove(b, arg[c], l);
524                 b += l;
525         }
526         *b = 0;
527         if(debug['m'])
528                 print("#expand %s %s\n", s->name, ob);
529         return;
530
531 bad:
532         yyerror("syntax in macro expansion: %s", s->name);
533         *b = 0;
534         return;
535
536 toobig:
537         yyerror("too much text in macro expansion: %s", s->name);
538         *b = 0;
539 }
540
541 void
542 macinc(void)
543 {
544         int c0, c, i, f;
545         char str[STRINGSZ], *hp;
546
547         c0 = getnsc();
548         if(c0 != '"') {
549                 c = c0;
550                 if(c0 != '<')
551                         goto bad;
552                 c0 = '>';
553         }
554         for(hp = str;;) {
555                 c = getc();
556                 if(c == c0)
557                         break;
558                 if(c == '\n')
559                         goto bad;
560                 if(hp >= &str[STRINGSZ-1]){
561                         yyerror("name too long for #include");
562                         break;
563                 }
564                 *hp++ = c;
565         }
566         *hp = 0;
567
568         c = getcom();
569         if(c != '\n')
570                 goto bad;
571         f = -1;
572         for(i=0; i<ninclude; i++) {
573                 if(i == 0 && c0 == '>')
574                         continue;
575                 c = snprint(symb, NSYMB, "%s/%s", include[i], str);;
576                 while(strncmp(symb, "./", 2) == 0){
577                         c -= 2;
578                         memmove(symb, symb+2, c+1);
579                 }
580                 f = open(symb, 0);
581                 if(f >= 0)
582                         break;
583         }
584         if(f < 0)
585                 snprint(symb, NSYMB, "%s", str);
586         newio();
587         pushio();
588         newfile(strdup(symb), 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         cp = alloc(c);
637         memcpy(cp, symb, c);
638         linehist(cp, n);
639         return;
640
641 bad:
642         unget(c);
643         yyerror("syntax in #line");
644         macend();
645 }
646
647 void
648 macif(int f)
649 {
650         int c, l, bol;
651         Sym *s;
652
653         if(f == 2)
654                 goto skip;
655         s = getsym();
656         if(s == S)
657                 goto bad;
658         if(getcom() != '\n')
659                 goto bad;
660         if((s->macro != 0) ^ f)
661                 return;
662
663 skip:
664         bol = 1;
665         l = 0;
666         for(;;) {
667                 c = getc();
668                 if(c != '#') {
669                         if(!isspace(c))
670                                 bol = 0;
671                         if(c == '\n')
672                                 bol = 1;
673                         continue;
674                 }
675                 if(!bol)
676                         continue;
677                 s = getsym();
678                 if(s == S)
679                         continue;
680                 if(strcmp(s->name, "endif") == 0) {
681                         if(l) {
682                                 l--;
683                                 continue;
684                         }
685                         macend();
686                         return;
687                 }
688                 if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
689                         l++;
690                         continue;
691                 }
692                 if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
693                         macend();
694                         return;
695                 }
696         }
697
698 bad:
699         yyerror("syntax in #if(n)def");
700         macend();
701 }
702
703 void
704 macprag(void)
705 {
706         Sym *s;
707         int c0, c;
708         char *hp;
709         Hist *h;
710
711         s = getsym();
712
713         if(s && strcmp(s->name, "lib") == 0)
714                 goto praglib;
715         if(s && strcmp(s->name, "pack") == 0) {
716                 pragpack();
717                 return;
718         }
719         if(s && strcmp(s->name, "fpround") == 0) {
720                 pragfpround();
721                 return;
722         }
723         if(s && strcmp(s->name, "profile") == 0) {
724                 pragprofile();
725                 return;
726         }
727         if(s && strcmp(s->name, "varargck") == 0) {
728                 pragvararg();
729                 return;
730         }
731         if(s && strcmp(s->name, "incomplete") == 0) {
732                 pragincomplete();
733                 return;
734         }
735         while(getnsc() != '\n')
736                 ;
737         return;
738
739 praglib:
740         c0 = getnsc();
741         if(c0 != '"') {
742                 c = c0;
743                 if(c0 != '<')
744                         goto bad;
745                 c0 = '>';
746         }
747         for(hp = symb;;) {
748                 c = getc();
749                 if(c == c0)
750                         break;
751                 if(c == '\n')
752                         goto bad;
753                 *hp++ = c;
754         }
755         *hp = 0;
756         c = getcom();
757         if(c != '\n')
758                 goto bad;
759
760         /*
761          * put pragma-line in as a funny history 
762          */
763         c = strlen(symb) + 1;
764         h = alloc(sizeof(Hist));
765         h->name = alloc(c);
766         memcpy(h->name, symb, c);
767         h->line = lineno;
768         h->offset = -1;
769         h->link = H;
770         if(ehist == H) {
771                 hist = h;
772                 ehist = h;
773                 return;
774         }
775         ehist->link = h;
776         ehist = h;
777         return;
778
779 bad:
780         unget(c);
781         yyerror("syntax in #pragma lib");
782         macend();
783 }
784
785 void
786 macend(void)
787 {
788         int c;
789
790         for(;;) {
791                 c = getnsc();
792                 if(c < 0 || c == '\n')
793                         return;
794         }
795 }
796
797 void
798 linehist(char *f, int offset)
799 {
800         Hist *h;
801
802         /*
803          * overwrite the last #line directive if
804          * no alloc has happened since the last one
805          */
806         if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0)
807                 if(f && ehist->name && strcmp(f, ehist->name) == 0) {
808                         ehist->line = lineno;
809                         ehist->offset = offset;
810                         return;
811                 }
812
813         if(debug['f'])
814                 if(f) {
815                         if(offset)
816                                 print("%4ld: %s (#line %d)\n", lineno, f, offset);
817                         else
818                                 print("%4ld: %s\n", lineno, f);
819                 } else
820                         print("%4ld: <pop>\n", lineno);
821         newflag = 0;
822
823         h = alloc(sizeof(Hist));
824         h->name = f;
825         h->line = lineno;
826         h->offset = offset;
827         h->link = H;
828         if(ehist == H) {
829                 hist = h;
830                 ehist = h;
831                 return;
832         }
833         ehist->link = h;
834         ehist = h;
835 }