]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cc/lex.c
091cda509b913e1720d61c153e5c8991d26302aa
[plan9front.git] / sys / src / cmd / cc / lex.c
1 #include        "cc.h"
2 #include        "y.tab.h"
3
4 #ifndef CPP
5 #define CPP     "/bin/cpp"
6 #endif
7
8 /*
9  * known debug flags
10  *      -a              acid declaration output
11  *      -A              !B
12  *      -B              non ANSI
13  *      -d              print declarations
14  *      -D name         define
15  *      -F              format specification check
16  *      -i              print initialization
17  *      -I path         include
18  *      -l              generate little-endian code
19  *      -L              print every NAME symbol
20  *      -M              constant multiplication
21  *      -m              print add/sub/mul trees
22  *      -n              print acid to file (%.c=%.acid) (with -a or -aa)
23  *      -o file         output file
24  *      -p              use standard cpp ANSI preprocessor (not on windows)
25  *      -r              print registerization
26  *      -s              print structure offsets (with -a or -aa)
27  *      -S              print assembly
28  *      -t              print type trees
29  *      -V              enable void* conversion warnings
30  *      -v              verbose printing
31  *      -w              print warnings
32  *      -X              abort on error
33  *      -.              Inhibit search for includes in source directory
34  */
35
36 void
37 main(int argc, char *argv[])
38 {
39         char *defs[50], *p;
40         int nproc, nout, status, i, c, ndef;
41
42         memset(debug, 0, sizeof(debug));
43         tinit();
44         cinit();
45         ginit();
46         arginit();
47
48         profileflg = 1; /* #pragma can turn it off */
49         tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
50         ndef = 0;
51         outfile = 0;
52         include[ninclude++] = ".";
53         ARGBEGIN {
54         default:
55                 c = ARGC();
56                 if(c >= 0 && c < sizeof(debug))
57                         debug[c]++;
58                 break;
59
60         case 'l':                       /* for little-endian mips */
61                 if(thechar != 'v'){
62                         print("can only use -l with vc");
63                         errorexit();
64                 }
65                 thechar = '0';
66                 thestring = "spim";
67                 break;
68
69         case 'o':
70                 outfile = ARGF();
71                 break;
72
73         case 'D':
74                 p = ARGF();
75                 if(p) {
76                         defs[ndef++] = p;
77                         dodefine(p);
78                 }
79                 break;
80
81         case 'I':
82                 p = ARGF();
83                 if(p)
84                         setinclude(p);
85                 break;
86         } ARGEND
87         if(argc < 1 && outfile == 0) {
88                 print("usage: %cc [-options] files\n", thechar);
89                 errorexit();
90         }
91         if(argc > 1 && systemtype(Windows)){
92                 print("can't compile multiple files on windows\n");
93                 errorexit();
94         }
95         if(argc > 1 && !systemtype(Windows)) {
96                 nproc = 1;
97                 /*
98                  * if we're writing acid to standard output, don't compile
99                  * concurrently, to avoid interleaving output.
100                  */
101                 if(((!debug['a'] && !debug['Z']) || debug['n']) &&
102                     (p = getenv("NPROC")) != nil)
103                         nproc = atol(p);        /* */
104                 c = 0;
105                 nout = 0;
106                 for(;;) {
107                         while(nout < nproc && argc > 0) {
108                                 i = myfork();
109                                 if(i < 0) {
110                                         i = mywait(&status);
111                                         if(i < 0) {
112                                                 print("cannot create a process\n");
113                                                 errorexit();
114                                         }
115                                         if(status)
116                                                 c++;
117                                         nout--;
118                                         continue;
119                                 }
120                                 if(i == 0) {
121                                         fprint(2, "%s:\n", *argv);
122                                         if (compile(*argv, defs, ndef))
123                                                 errorexit();
124                                         exits(0);
125                                 }
126                                 nout++;
127                                 argc--;
128                                 argv++;
129                         }
130                         i = mywait(&status);
131                         if(i < 0) {
132                                 if(c)
133                                         errorexit();
134                                 exits(0);
135                         }
136                         if(status)
137                                 c++;
138                         nout--;
139                 }
140         }
141
142         if(argc == 0)
143                 c = compile("stdin", defs, ndef);
144         else
145                 c = compile(argv[0], defs, ndef);
146
147         if(c)
148                 errorexit();
149         exits(0);
150 }
151
152 int
153 compile(char *file, char **defs, int ndef)
154 {
155         char ofile[400], incfile[20];
156         char *p, *av[100], opt[256];
157         int i, c, fd[2];
158         static int first = 1;
159
160         strcpy(ofile, file);
161         p = utfrrune(ofile, pathchar());
162         if(p) {
163                 *p++ = 0;
164                 if(!debug['.'])
165                         include[0] = strdup(ofile);
166         } else
167                 p = ofile;
168
169         if(outfile == 0) {
170                 outfile = p;
171                 if(outfile) {
172                         if(p = utfrrune(outfile, '.'))
173                                 if(p[1] == 'c' && p[2] == 0)
174                                         p[0] = 0;
175                         p = utfrune(outfile, 0);
176                         if(debug['a'] && debug['n'])
177                                 strcat(p, ".acid");
178                         else if(debug['Z'] && debug['n'])
179                                 strcat(p, "_pickle.c");
180                         else {
181                                 p[0] = '.';
182                                 p[1] = thechar;
183                                 p[2] = 0;
184                         }
185                 } else
186                         outfile = "/dev/null";
187         }
188
189         if(p = getenv("INCLUDE")) {
190                 setinclude(p);
191         } else {
192                 if(systemtype(Plan9)) {
193                         sprint(incfile, "/%s/include", thestring);
194                         setinclude(strdup(incfile));
195                         setinclude("/sys/include");
196                 }
197         }
198         if (first)
199                 Binit(&diagbuf, 1, OWRITE);
200         /*
201          * if we're writing acid to standard output, don't keep scratching
202          * outbuf.
203          */
204         if((debug['a'] || debug['Z']) && !debug['n']) {
205                 if (first) {
206                         outfile = 0;
207                         Binit(&outbuf, dup(1, -1), OWRITE);
208                         dup(2, 1);
209                 }
210         } else {
211                 c = mycreat(outfile, 0664);
212                 if(c < 0) {
213                         diag(Z, "cannot open %s - %r", outfile);
214                         outfile = 0;
215                         errorexit();
216                 }
217                 Binit(&outbuf, c, OWRITE);
218         }
219         newio();
220         first = 0;
221
222         /* Use an ANSI preprocessor */
223         if(debug['p']) {
224                 if(systemtype(Windows)) {
225                         diag(Z, "-p option not supported on windows");
226                         errorexit();
227                 }
228                 if(myaccess(file) < 0) {
229                         diag(Z, "%s does not exist", file);
230                         errorexit();
231                 }
232                 if(mypipe(fd) < 0) {
233                         diag(Z, "pipe failed");
234                         errorexit();
235                 }
236                 switch(myfork()) {
237                 case -1:
238                         diag(Z, "fork failed");
239                         errorexit();
240                 case 0:
241                         close(fd[0]);
242                         mydup(fd[1], 1);
243                         close(fd[1]);
244                         av[0] = CPP;
245                         i = 1;
246                         sprint(opt, "-+");
247                         av[i++] = strdup(opt);
248                         if(debug['.']){
249                                 sprint(opt, "-.");
250                                 av[i++] = strdup(opt);
251                         }
252                         for(c = 0; c < ndef; c++) {
253                                 sprint(opt, "-D%s", defs[c]);
254                                 av[i++] = strdup(opt);
255                         }
256                         for(c = 0; c < ninclude; c++) {
257                                 sprint(opt, "-I%s", include[c]);
258                                 av[i++] = strdup(opt);
259                         }
260                         if(strcmp(file, "stdin") != 0)
261                                 av[i++] = file;
262                         av[i] = 0;
263                         if(debug['p'] > 1) {
264                                 for(c = 0; c < i; c++)
265                                         fprint(2, "%s ", av[c]);
266                                 fprint(2, "\n");
267                         }
268                         myexec(av[0], av);
269                         fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
270                         errorexit();
271                 default:
272                         close(fd[1]);
273                         newfile(file, fd[0]);
274                         break;
275                 }
276         } else {
277                 if(strcmp(file, "stdin") == 0)
278                         newfile(file, 0);
279                 else
280                         newfile(file, -1);
281         }
282         yyparse();
283         if(!debug['a'] && !debug['Z'])
284                 gclean();
285         return nerrors;
286 }
287
288 void
289 errorexit(void)
290 {
291         if(outfile)
292                 remove(outfile);
293         exits("error");
294 }
295
296 void
297 pushio(void)
298 {
299         Io *i;
300
301         i = iostack;
302         if(i == I) {
303                 yyerror("botch in pushio");
304                 errorexit();
305         }
306         i->p = fi.p;
307         i->c = fi.c;
308 }
309
310 void
311 newio(void)
312 {
313         Io *i;
314         static int pushdepth = 0;
315
316         i = iofree;
317         if(i == I) {
318                 pushdepth++;
319                 if(pushdepth > 1000) {
320                         yyerror("macro/io expansion too deep");
321                         errorexit();
322                 }
323                 i = alloc(sizeof(*i));
324         } else
325                 iofree = i->link;
326         i->c = 0;
327         i->f = -1;
328         ionext = i;
329 }
330
331 void
332 newfile(char *s, int f)
333 {
334         Io *i;
335
336         if(debug['e'])
337                 print("%L: %s\n", lineno, s);
338
339         i = ionext;
340         i->link = iostack;
341         iostack = i;
342         i->f = f;
343         if(f < 0)
344                 i->f = open(s, 0);
345         if(i->f < 0) {
346                 yyerror("%cc: %r: %s", thechar, s);
347                 errorexit();
348         }
349         fi.c = 0;
350         linehist(s, 0);
351 }
352
353 Sym*
354 slookup(char *s)
355 {
356
357         strcpy(symb, s);
358         return lookup();
359 }
360
361 Sym*
362 lookup(void)
363 {
364         Sym *s;
365         ulong h;
366         char *p;
367         int c, n;
368
369         h = 0;
370         for(p=symb; *p;) {
371                 h = h * 3;
372                 h += *p++;
373         }
374         n = (p - symb) + 1;
375         if((long)h < 0)
376                 h = ~h;
377         h %= NHASH;
378         c = symb[0];
379         for(s = hash[h]; s != S; s = s->link) {
380                 if(s->name[0] != c)
381                         continue;
382                 if(strcmp(s->name, symb) == 0)
383                         return s;
384         }
385         s = alloc(sizeof(*s));
386         s->name = alloc(n);
387         memmove(s->name, symb, n);
388
389         strcpy(s->name, symb);
390         s->link = hash[h];
391         hash[h] = s;
392         syminit(s);
393
394         return s;
395 }
396
397 void
398 syminit(Sym *s)
399 {
400         s->lexical = LNAME;
401         s->block = 0;
402         s->offset = 0;
403         s->type = T;
404         s->suetag = T;
405         s->class = CXXX;
406         s->aused = 0;
407         s->sig = SIGNONE;
408 }
409
410 #define EOF     (-1)
411 #define IGN     (-2)
412 #define ESC     (1<<20)
413 #define GETC()  ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
414
415 enum
416 {
417         Numdec          = 1<<0,
418         Numlong         = 1<<1,
419         Numuns          = 1<<2,
420         Numvlong        = 1<<3,
421         Numflt          = 1<<4,
422 };
423
424 long
425 yylex(void)
426 {
427         vlong vv;
428         long c, c1, t;
429         char *cp;
430         Rune rune;
431         Sym *s;
432
433         if(peekc != IGN) {
434                 c = peekc;
435                 peekc = IGN;
436                 goto l1;
437         }
438 l0:
439         c = GETC();
440
441 l1:
442         if(c >= Runeself) {
443                 /*
444                  * extension --
445                  *      all multibyte runes are alpha
446                  */
447                 cp = symb;
448                 goto talph;
449         }
450         if(isspace(c)) {
451                 if(c == '\n')
452                         lineno++;
453                 goto l0;
454         }
455         if(isalpha(c)) {
456                 cp = symb;
457                 if(c != 'L')
458                         goto talph;
459                 *cp++ = c;
460                 c = GETC();
461                 if(c == '\'') {
462                         /* L'x' */
463                         c = escchar('\'', 1, 0);
464                         if(c == EOF)
465                                 c = '\'';
466                         c1 = escchar('\'', 1, 0);
467                         if(c1 != EOF) {
468                                 yyerror("missing '");
469                                 peekc = c1;
470                         }
471                         yylval.vval = convvtox(c, TRUNE);
472                         return LUCONST;
473                 }
474                 if(c == '"') {
475                         goto caselq;
476                 }
477                 goto talph;
478         }
479         if(isdigit(c))
480                 goto tnum;
481         switch(c)
482         {
483
484         case EOF:
485                 peekc = EOF;
486                 return -1;
487
488         case '_':
489                 cp = symb;
490                 goto talph;
491
492         case '#':
493                 domacro();
494                 goto l0;
495
496         case '.':
497                 c1 = GETC();
498                 if(isdigit(c1)) {
499                         cp = symb;
500                         *cp++ = c;
501                         c = c1;
502                         c1 = 0;
503                         goto casedot;
504                 }
505                 break;
506
507         case '"':
508                 strcpy(symb, "\"<string>\"");
509                 cp = alloc(0);
510                 c1 = 0;
511
512                 /* "..." */
513                 for(;;) {
514                         c = escchar('"', 0, 1);
515                         if(c == EOF)
516                                 break;
517                         if(c & ESC) {
518                                 cp = allocn(cp, c1, 1);
519                                 cp[c1++] = c;
520                         } else {
521                                 rune = c;
522                                 c = runelen(rune);
523                                 cp = allocn(cp, c1, c);
524                                 runetochar(cp+c1, &rune);
525                                 c1 += c;
526                         }
527                 }
528                 yylval.sval.l = c1;
529                 do {
530                         cp = allocn(cp, c1, 1);
531                         cp[c1++] = 0;
532                 } while(c1 & MAXALIGN);
533                 yylval.sval.s = cp;
534                 return LSTRING;
535
536         caselq:
537                 /* L"..." */
538                 strcpy(symb, "\"L<string>\"");
539                 cp = alloc(0);
540                 c1 = 0;
541                 for(;;) {
542                         c = escchar('"', 1, 0);
543                         if(c == EOF)
544                                 break;
545                         cp = allocn(cp, c1, sizeof(Rune));
546                         *(Rune*)(cp + c1) = c;
547                         c1 += sizeof(Rune);
548                 }
549                 yylval.sval.l = c1;
550                 do {
551                         cp = allocn(cp, c1, sizeof(Rune));
552                         *(Rune*)(cp + c1) = 0;
553                         c1 += sizeof(Rune);
554                 } while(c1 & MAXALIGN);
555                 yylval.sval.s = cp;
556                 return LLSTRING;
557
558         case '\'':
559                 /* '.' */
560                 c = escchar('\'', 0, 0);
561                 if(c == EOF)
562                         c = '\'';
563                 c1 = escchar('\'', 0, 0);
564                 if(c1 != EOF) {
565                         yyerror("missing '");
566                         peekc = c1;
567                 }
568                 vv = c;
569                 yylval.vval = convvtox(vv, TUCHAR);
570                 if(yylval.vval != vv)
571                         yyerror("overflow in character constant: 0x%lx", c);
572                 else
573                 if(c & 0x80){
574                         nearln = lineno;
575                         warn(Z, "sign-extended character constant");
576                 }
577                 yylval.vval = convvtox(vv, TCHAR);
578                 return LCONST;
579
580         case '/':
581                 c1 = GETC();
582                 if(c1 == '*') {
583                         for(;;) {
584                                 c = getr();
585                                 while(c == '*') {
586                                         c = getr();
587                                         if(c == '/')
588                                                 goto l0;
589                                 }
590                                 if(c == EOF) {
591                                         yyerror("eof in comment");
592                                         errorexit();
593                                 }
594                         }
595                 }
596                 if(c1 == '/') {
597                         for(;;) {
598                                 c = getr();
599                                 if(c == '\n')
600                                         goto l0;
601                                 if(c == EOF) {
602                                         yyerror("eof in comment");
603                                         errorexit();
604                                 }
605                         }
606                 }
607                 if(c1 == '=')
608                         return LDVE;
609                 break;
610
611         case '*':
612                 c1 = GETC();
613                 if(c1 == '=')
614                         return LMLE;
615                 break;
616
617         case '%':
618                 c1 = GETC();
619                 if(c1 == '=')
620                         return LMDE;
621                 break;
622
623         case '+':
624                 c1 = GETC();
625                 if(c1 == '+')
626                         return LPP;
627                 if(c1 == '=')
628                         return LPE;
629                 break;
630
631         case '-':
632                 c1 = GETC();
633                 if(c1 == '-')
634                         return LMM;
635                 if(c1 == '=')
636                         return LME;
637                 if(c1 == '>')
638                         return LMG;
639                 break;
640
641         case '>':
642                 c1 = GETC();
643                 if(c1 == '>') {
644                         c = LRSH;
645                         c1 = GETC();
646                         if(c1 == '=')
647                                 return LRSHE;
648                         break;
649                 }
650                 if(c1 == '=')
651                         return LGE;
652                 break;
653
654         case '<':
655                 c1 = GETC();
656                 if(c1 == '<') {
657                         c = LLSH;
658                         c1 = GETC();
659                         if(c1 == '=')
660                                 return LLSHE;
661                         break;
662                 }
663                 if(c1 == '=')
664                         return LLE;
665                 break;
666
667         case '=':
668                 c1 = GETC();
669                 if(c1 == '=')
670                         return LEQ;
671                 break;
672
673         case '!':
674                 c1 = GETC();
675                 if(c1 == '=')
676                         return LNE;
677                 break;
678
679         case '&':
680                 c1 = GETC();
681                 if(c1 == '&')
682                         return LANDAND;
683                 if(c1 == '=')
684                         return LANDE;
685                 break;
686
687         case '|':
688                 c1 = GETC();
689                 if(c1 == '|')
690                         return LOROR;
691                 if(c1 == '=')
692                         return LORE;
693                 break;
694
695         case '^':
696                 c1 = GETC();
697                 if(c1 == '=')
698                         return LXORE;
699                 break;
700
701         default:
702                 return c;
703         }
704         peekc = c1;
705         return c;
706
707 talph:
708         /*
709          * cp is set to symb and some
710          * prefix has been stored
711          */
712         for(;;) {
713                 if(c >= Runeself) {
714                         for(c1=0;;) {
715                                 cp[c1++] = c;
716                                 if(fullrune(cp, c1))
717                                         break;
718                                 c = GETC();
719                         }
720                         cp += c1;
721                         c = GETC();
722                         continue;
723                 }
724                 if(!isalnum(c) && c != '_')
725                         break;
726                 *cp++ = c;
727                 c = GETC();
728         }
729         *cp = 0;
730         if(debug['L'])
731                 print("%L: %s\n", lineno, symb);
732         peekc = c;
733         s = lookup();
734         if(s->macro) {
735                 newio();
736                 cp = ionext->b;
737                 macexpand(s, cp);
738                 pushio();
739                 ionext->link = iostack;
740                 iostack = ionext;
741                 fi.p = cp;
742                 fi.c = strlen(cp);
743                 if(peekc != IGN) {
744                         cp[fi.c++] = peekc;
745                         cp[fi.c] = 0;
746                         peekc = IGN;
747                 }
748                 goto l0;
749         }
750         yylval.sym = s;
751         if(s->class == CTYPEDEF || s->class == CTYPESTR)
752                 return LTYPE;
753         return s->lexical;
754
755 tnum:
756         c1 = 0;
757         cp = symb;
758         if(c != '0') {
759                 c1 |= Numdec;
760                 for(;;) {
761                         *cp++ = c;
762                         c = GETC();
763                         if(isdigit(c))
764                                 continue;
765                         goto dc;
766                 }
767         }
768         *cp++ = c;
769         c = GETC();
770         if(c == 'x' || c == 'X')
771                 for(;;) {
772                         *cp++ = c;
773                         c = GETC();
774                         if(isdigit(c))
775                                 continue;
776                         if(c >= 'a' && c <= 'f')
777                                 continue;
778                         if(c >= 'A' && c <= 'F')
779                                 continue;
780                         if(cp == symb+2)
781                                 yyerror("malformed hex constant");
782                         goto ncu;
783                 }
784         if(c < '0' || c > '7')
785                 goto dc;
786         for(;;) {
787                 if(c >= '0' && c <= '7') {
788                         *cp++ = c;
789                         c = GETC();
790                         continue;
791                 }
792                 goto ncu;
793         }
794
795 dc:
796         if(c == '.')
797                 goto casedot;
798         if(c == 'e' || c == 'E')
799                 goto casee;
800
801 ncu:
802         if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
803                 c = GETC();
804                 c1 |= Numuns;
805                 goto ncu;
806         }
807         if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
808                 c = GETC();
809                 if(c1 & Numlong)
810                         c1 |= Numvlong;
811                 c1 |= Numlong;
812                 goto ncu;
813         }
814         *cp = 0;
815         peekc = c;
816         if(mpatov(symb, &yylval.vval))
817                 yyerror("overflow in constant");
818
819         vv = yylval.vval;
820         if(c1 & Numvlong) {
821                 if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
822                         c = LUVLCONST;
823                         t = TUVLONG;
824                         goto nret;
825                 }
826                 c = LVLCONST;
827                 t = TVLONG;
828                 goto nret;
829         }
830         if(c1 & Numlong) {
831                 if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
832                         c = LULCONST;
833                         t = TULONG;
834                         goto nret;
835                 }
836                 c = LLCONST;
837                 t = TLONG;
838                 goto nret;
839         }
840         if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
841                 c = LUCONST;
842                 t = TUINT;
843                 goto nret;
844         }
845         c = LCONST;
846         t = TINT;
847         goto nret;
848
849 nret:
850         yylval.vval = convvtox(vv, t);
851         if(yylval.vval != vv){
852                 nearln = lineno;
853                 warn(Z, "truncated constant: %T %s", types[t], symb);
854         }
855         return c;
856
857 casedot:
858         for(;;) {
859                 *cp++ = c;
860                 c = GETC();
861                 if(!isdigit(c))
862                         break;
863         }
864         if(c != 'e' && c != 'E')
865                 goto caseout;
866
867 casee:
868         *cp++ = 'e';
869         c = GETC();
870         if(c == '+' || c == '-') {
871                 *cp++ = c;
872                 c = GETC();
873         }
874         if(!isdigit(c))
875                 yyerror("malformed fp constant exponent");
876         while(isdigit(c)) {
877                 *cp++ = c;
878                 c = GETC();
879         }
880
881 caseout:
882         if(c == 'L' || c == 'l') {
883                 c = GETC();
884                 c1 |= Numlong;
885         } else
886         if(c == 'F' || c == 'f') {
887                 c = GETC();
888                 c1 |= Numflt;
889         }
890         *cp = 0;
891         peekc = c;
892         yylval.dval = strtod(symb, nil);
893         if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) {
894                 yyerror("overflow in float constant");
895                 yylval.dval = 0;
896         }
897         if(c1 & Numflt)
898                 return LFCONST;
899         return LDCONST;
900 }
901
902 /*
903  * convert a string, s, to vlong in *v
904  * return conversion overflow.
905  * required syntax is [0[x]]d*
906  */
907 int
908 mpatov(char *s, vlong *v)
909 {
910         vlong n, nn;
911         int c;
912
913         n = 0;
914         c = *s;
915         if(c == '0')
916                 goto oct;
917         while(c = *s++) {
918                 if(c >= '0' && c <= '9')
919                         nn = n*10 + c-'0';
920                 else
921                         goto bad;
922                 if(n < 0 && nn >= 0)
923                         goto bad;
924                 n = nn;
925         }
926         goto out;
927
928 oct:
929         s++;
930         c = *s;
931         if(c == 'x' || c == 'X')
932                 goto hex;
933         while(c = *s++) {
934                 if(c >= '0' || c <= '7')
935                         nn = n*8 + c-'0';
936                 else
937                         goto bad;
938                 if(n < 0 && nn >= 0)
939                         goto bad;
940                 n = nn;
941         }
942         goto out;
943
944 hex:
945         s++;
946         while(c = *s++) {
947                 if(c >= '0' && c <= '9')
948                         c += 0-'0';
949                 else
950                 if(c >= 'a' && c <= 'f')
951                         c += 10-'a';
952                 else
953                 if(c >= 'A' && c <= 'F')
954                         c += 10-'A';
955                 else
956                         goto bad;
957                 nn = n*16 + c;
958                 if(n < 0 && nn >= 0)
959                         goto bad;
960                 n = nn;
961         }
962 out:
963         *v = n;
964         return 0;
965
966 bad:
967         *v = ~0;
968         return 1;
969 }
970
971 int
972 getc(void)
973 {
974         int c;
975
976         if(peekc != IGN) {
977                 c = peekc;
978                 peekc = IGN;
979         } else
980                 c = GETC();
981         if(c == '\n')
982                 lineno++;
983         if(c == EOF) {
984                 yyerror("End of file");
985                 errorexit();
986         }
987         return c;
988 }
989
990 long
991 getr(void)
992 {
993         int c, i;
994         char str[UTFmax+1];
995         Rune rune;
996
997
998         c = getc();
999         if(c < Runeself)
1000                 return c;
1001         i = 0;
1002         str[i++] = c;
1003
1004 loop:
1005         c = getc();
1006         str[i++] = c;
1007         if(!fullrune(str, i))
1008                 goto loop;
1009         c = chartorune(&rune, str);
1010         if(rune == Runeerror && c == 1) {
1011                 nearln = lineno;
1012                 diag(Z, "illegal rune in string");
1013                 for(c=0; c<i; c++)
1014                         print(" %.2x", *(uchar*)(str+c));
1015                 print("\n");
1016         }
1017         return rune;
1018 }
1019
1020 int
1021 getnsc(void)
1022 {
1023         int c;
1024
1025         if(peekc != IGN) {
1026                 c = peekc;
1027                 peekc = IGN;
1028         } else
1029                 c = GETC();
1030         for(;;) {
1031                 if(c >= Runeself || !isspace(c))
1032                         return c;
1033                 if(c == '\n') {
1034                         lineno++;
1035                         return c;
1036                 }
1037                 c = GETC();
1038         }
1039 }
1040
1041 void
1042 unget(int c)
1043 {
1044
1045         peekc = c;
1046         if(c == '\n')
1047                 lineno--;
1048 }
1049
1050 long
1051 escchar(long e, int longflg, int escflg)
1052 {
1053         long c, l;
1054         int i;
1055
1056 loop:
1057         c = getr();
1058         if(c == '\n') {
1059                 yyerror("newline in string");
1060                 return EOF;
1061         }
1062         if(c != '\\') {
1063                 if(c == e)
1064                         c = EOF;
1065                 return c;
1066         }
1067         c = getr();
1068         if(c == 'x') {
1069                 /*
1070                  * note this is not ansi,
1071                  * supposed to only accept 2 hex
1072                  */
1073                 i = 2;
1074                 if(longflg)
1075                         i = 4;
1076                 l = 0;
1077                 for(; i>0; i--) {
1078                         c = getc();
1079                         if(c >= '0' && c <= '9') {
1080                                 l = l*16 + c-'0';
1081                                 continue;
1082                         }
1083                         if(c >= 'a' && c <= 'f') {
1084                                 l = l*16 + c-'a' + 10;
1085                                 continue;
1086                         }
1087                         if(c >= 'A' && c <= 'F') {
1088                                 l = l*16 + c-'A' + 10;
1089                                 continue;
1090                         }
1091                         unget(c);
1092                         break;
1093                 }
1094                 if(escflg)
1095                         l |= ESC;
1096                 return l;
1097         }
1098         if(c >= '0' && c <= '7') {
1099                 /*
1100                  * note this is not ansi,
1101                  * supposed to only accept 3 oct
1102                  */
1103                 i = 2;
1104                 if(longflg)
1105                         i = 5;
1106                 l = c - '0';
1107                 for(; i>0; i--) {
1108                         c = getc();
1109                         if(c >= '0' && c <= '7') {
1110                                 l = l*8 + c-'0';
1111                                 continue;
1112                         }
1113                         unget(c);
1114                 }
1115                 if(escflg)
1116                         l |= ESC;
1117                 return l;
1118         }
1119         switch(c)
1120         {
1121         case '\n':      goto loop;
1122         case 'n':       return '\n';
1123         case 't':       return '\t';
1124         case 'b':       return '\b';
1125         case 'r':       return '\r';
1126         case 'f':       return '\f';
1127         case 'a':       return '\a';
1128         case 'v':       return '\v';
1129         }
1130         return c;
1131 }
1132
1133 struct
1134 {
1135         char    *name;
1136         ushort  lexical;
1137         ushort  type;
1138 } itab[] =
1139 {
1140         "auto",         LAUTO,          0,
1141         "break",        LBREAK,         0,
1142         "case",         LCASE,          0,
1143         "char",         LCHAR,          TCHAR,
1144         "const",        LCONSTNT,       0,
1145         "continue",     LCONTINUE,      0,
1146         "default",      LDEFAULT,       0,
1147         "do",           LDO,            0,
1148         "double",       LDOUBLE,        TDOUBLE,
1149         "else",         LELSE,          0,
1150         "enum",         LENUM,          0,
1151         "extern",       LEXTERN,        0,
1152         "float",        LFLOAT,         TFLOAT,
1153         "for",          LFOR,           0,
1154         "goto",         LGOTO,          0,
1155         "if",           LIF,            0,
1156         "inline",       LINLINE,        0,
1157         "int",          LINT,           TINT,
1158         "long",         LLONG,          TLONG,
1159         "register",     LREGISTER,      0,
1160         "restrict",     LRESTRICT,      0,
1161         "return",       LRETURN,        0,
1162         "SET",          LSET,           0,
1163         "short",        LSHORT,         TSHORT,
1164         "signed",       LSIGNED,        0,
1165         "signof",       LSIGNOF,        0,
1166         "sizeof",       LSIZEOF,        0,
1167         "static",       LSTATIC,        0,
1168         "struct",       LSTRUCT,        0,
1169         "switch",       LSWITCH,        0,
1170         "typedef",      LTYPEDEF,       0,
1171         "typestr",      LTYPESTR,       0,
1172         "union",        LUNION,         0,
1173         "unsigned",     LUNSIGNED,      0,
1174         "USED",         LUSED,          0,
1175         "void",         LVOID,          TVOID,
1176         "volatile",     LVOLATILE,      0,
1177         "while",        LWHILE,         0,
1178         0
1179 };
1180
1181 void
1182 cinit(void)
1183 {
1184         Sym *s;
1185         int i;
1186         Type *t;
1187
1188         nerrors = 0;
1189         lineno = 1;
1190         iostack = I;
1191         iofree = I;
1192         peekc = IGN;
1193         nhunk = 0;
1194
1195         types[TXXX] = T;
1196         types[TCHAR] = typ(TCHAR, T);
1197         types[TUCHAR] = typ(TUCHAR, T);
1198         types[TSHORT] = typ(TSHORT, T);
1199         types[TUSHORT] = typ(TUSHORT, T);
1200         types[TINT] = typ(TINT, T);
1201         types[TUINT] = typ(TUINT, T);
1202         types[TLONG] = typ(TLONG, T);
1203         types[TULONG] = typ(TULONG, T);
1204         types[TVLONG] = typ(TVLONG, T);
1205         types[TUVLONG] = typ(TUVLONG, T);
1206         types[TFLOAT] = typ(TFLOAT, T);
1207         types[TDOUBLE] = typ(TDOUBLE, T);
1208         types[TVOID] = typ(TVOID, T);
1209         types[TENUM] = typ(TENUM, T);
1210         types[TFUNC] = typ(TFUNC, types[TINT]);
1211         types[TIND] = typ(TIND, types[TVOID]);
1212
1213         for(i=0; i<NHASH; i++)
1214                 hash[i] = S;
1215         for(i=0; itab[i].name; i++) {
1216                 s = slookup(itab[i].name);
1217                 s->lexical = itab[i].lexical;
1218                 if(itab[i].type != 0)
1219                         s->type = types[itab[i].type];
1220         }
1221         blockno = 0;
1222         autobn = 0;
1223         autoffset = 0;
1224
1225         t = typ(TARRAY, types[TCHAR]);
1226         t->width = 0;
1227         symstring = slookup(".string");
1228         symstring->class = CSTATIC;
1229         symstring->type = t;
1230
1231         t = typ(TARRAY, types[TCHAR]);
1232         t->width = 0;
1233
1234         nodproto = new(OPROTO, Z, Z);
1235         dclstack = D;
1236
1237         pathname = allocn(pathname, 0, 100);
1238         if(mygetwd(pathname, 99) == 0) {
1239                 pathname = allocn(pathname, 100, 900);
1240                 if(mygetwd(pathname, 999) == 0)
1241                         strcpy(pathname, "/???");
1242         }
1243
1244         fmtinstall('O', Oconv);
1245         fmtinstall('T', Tconv);
1246         fmtinstall('F', FNconv);
1247         fmtinstall('L', Lconv);
1248         fmtinstall('Q', Qconv);
1249         fmtinstall('|', VBconv);
1250 }
1251
1252 int
1253 filbuf(void)
1254 {
1255         Io *i;
1256
1257 loop:
1258         i = iostack;
1259         if(i == I)
1260                 return EOF;
1261         if(i->f < 0)
1262                 goto pop;
1263         fi.c = read(i->f, i->b, BUFSIZ) - 1;
1264         if(fi.c < 0) {
1265                 close(i->f);
1266                 linehist(0, 0);
1267                 goto pop;
1268         }
1269         fi.p = i->b + 1;
1270         return i->b[0] & 0xff;
1271
1272 pop:
1273         iostack = i->link;
1274         i->link = iofree;
1275         iofree = i;
1276         i = iostack;
1277         if(i == I)
1278                 return EOF;
1279         fi.p = i->p;
1280         fi.c = i->c;
1281         if(--fi.c < 0)
1282                 goto loop;
1283         return *fi.p++ & 0xff;
1284 }
1285
1286 int
1287 Oconv(Fmt *fp)
1288 {
1289         int a;
1290
1291         a = va_arg(fp->args, int);
1292         if(a < OXXX || a > OEND)
1293                 return fmtprint(fp, "***badO %d***", a);
1294
1295         return fmtstrcpy(fp, onames[a]);
1296 }
1297
1298 int
1299 Lconv(Fmt *fp)
1300 {
1301         char str[STRINGSZ], s[STRINGSZ];
1302         Hist *h;
1303         struct
1304         {
1305                 Hist*   incl;   /* start of this include file */
1306                 long    idel;   /* delta line number to apply to include */
1307                 Hist*   line;   /* start of this #line directive */
1308                 long    ldel;   /* delta line number to apply to #line */
1309         } a[HISTSZ];
1310         long l, d;
1311         int i, n;
1312
1313         l = va_arg(fp->args, long);
1314         n = 0;
1315         for(h = hist; h != H; h = h->link) {
1316                 if(l < h->line)
1317                         break;
1318                 if(h->name) {
1319                         if(h->offset != 0) {            /* #line directive, not #pragma */
1320                                 if(n > 0 && n < HISTSZ && h->offset >= 0) {
1321                                         a[n-1].line = h;
1322                                         a[n-1].ldel = h->line - h->offset + 1;
1323                                 }
1324                         } else {
1325                                 if(n < HISTSZ) {        /* beginning of file */
1326                                         a[n].incl = h;
1327                                         a[n].idel = h->line;
1328                                         a[n].line = 0;
1329                                 }
1330                                 n++;
1331                         }
1332                         continue;
1333                 }
1334                 n--;
1335                 if(n > 0 && n < HISTSZ) {
1336                         d = h->line - a[n].incl->line;
1337                         a[n-1].ldel += d;
1338                         a[n-1].idel += d;
1339                 }
1340         }
1341         if(n > HISTSZ)
1342                 n = HISTSZ;
1343         str[0] = 0;
1344         for(i=n-1; i>=0; i--) {
1345                 if(i != n-1) {
1346                         if(fp->flags & ~(FmtWidth|FmtPrec))     /* BUG ROB - was f3 */
1347                                 break;
1348                         strcat(str, " ");
1349                 }
1350                 if(a[i].line)
1351                         snprint(s, STRINGSZ, "%s:%ld[%s:%ld]",
1352                                 a[i].line->name, l-a[i].ldel+1,
1353                                 a[i].incl->name, l-a[i].idel+1);
1354                 else
1355                         snprint(s, STRINGSZ, "%s:%ld",
1356                                 a[i].incl->name, l-a[i].idel+1);
1357                 if(strlen(s)+strlen(str) >= STRINGSZ-10)
1358                         break;
1359                 strcat(str, s);
1360                 l = a[i].incl->line - 1;        /* now print out start of this file */
1361         }
1362         if(n == 0)
1363                 strcat(str, "<eof>");
1364         return fmtstrcpy(fp, str);
1365 }
1366
1367 int
1368 Tconv(Fmt *fp)
1369 {
1370         char str[STRINGSZ+20], s[STRINGSZ+20];
1371         Type *t, *t1;
1372         int et;
1373         long n;
1374
1375         str[0] = 0;
1376         for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
1377                 et = t->etype;
1378                 if(str[0])
1379                         strcat(str, " ");
1380                 if(t->garb&~GINCOMPLETE) {
1381                         sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
1382                         if(strlen(str) + strlen(s) < STRINGSZ)
1383                                 strcat(str, s);
1384                 }
1385                 sprint(s, "%s", tnames[et]);
1386                 if(strlen(str) + strlen(s) < STRINGSZ)
1387                         strcat(str, s);
1388                 if(et == TFUNC && (t1 = t->down)) {
1389                         sprint(s, "(%T", t1);
1390                         if(strlen(str) + strlen(s) < STRINGSZ)
1391                                 strcat(str, s);
1392                         while(t1 = t1->down) {
1393                                 sprint(s, ", %T", t1);
1394                                 if(strlen(str) + strlen(s) < STRINGSZ)
1395                                         strcat(str, s);
1396                         }
1397                         if(strlen(str) + strlen(s) < STRINGSZ)
1398                                 strcat(str, ")");
1399                 }
1400                 if(et == TARRAY) {
1401                         n = t->width;
1402                         if(t->link && t->link->width)
1403                                 n /= t->link->width;
1404                         sprint(s, "[%ld]", n);
1405                         if(strlen(str) + strlen(s) < STRINGSZ)
1406                                 strcat(str, s);
1407                 }
1408                 if(t->nbits) {
1409                         sprint(s, " %d:%d", t->shift, t->nbits);
1410                         if(strlen(str) + strlen(s) < STRINGSZ)
1411                                 strcat(str, s);
1412                 }
1413                 if(typesu[et]) {
1414                         if(t->tag) {
1415                                 strcat(str, " ");
1416                                 if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
1417                                         strcat(str, t->tag->name);
1418                         } else
1419                                 strcat(str, " {}");
1420                         break;
1421                 }
1422         }
1423         return fmtstrcpy(fp, str);
1424 }
1425
1426 int
1427 FNconv(Fmt *fp)
1428 {
1429         char *str;
1430         Node *n;
1431
1432         n = va_arg(fp->args, Node*);
1433         str = "<indirect>";
1434         if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
1435                 str = n->sym->name;
1436         return fmtstrcpy(fp, str);
1437 }
1438
1439 int
1440 Qconv(Fmt *fp)
1441 {
1442         char str[STRINGSZ+20], *s;
1443         long b;
1444         int i;
1445
1446         str[0] = 0;
1447         for(b = va_arg(fp->args, long); b;) {
1448                 i = bitno(b);
1449                 if(str[0])
1450                         strcat(str, " ");
1451                 s = qnames[i];
1452                 if(strlen(str) + strlen(s) >= STRINGSZ)
1453                         break;
1454                 strcat(str, s);
1455                 b &= ~(1L << i);
1456         }
1457         return fmtstrcpy(fp, str);
1458 }
1459
1460 int
1461 VBconv(Fmt *fp)
1462 {
1463         char str[STRINGSZ];
1464         int i, n, t, pc;
1465
1466         n = va_arg(fp->args, int);
1467         pc = 0; /* BUG: was printcol */
1468         i = 0;
1469         while(pc < n) {
1470                 t = (pc+4) & ~3;
1471                 if(t <= n) {
1472                         str[i++] = '\t';
1473                         pc = t;
1474                         continue;
1475                 }
1476                 str[i++] = ' ';
1477                 pc++;
1478         }
1479         str[i] = 0;
1480
1481         return fmtstrcpy(fp, str);
1482 }
1483
1484 /*
1485  * real allocs
1486  */
1487 void*
1488 alloc(long n)
1489 {
1490         void *p;
1491
1492         while((uintptr)hunk & MAXALIGN) {
1493                 hunk++;
1494                 nhunk--;
1495         }
1496         while(nhunk < n)
1497                 gethunk();
1498         p = hunk;
1499         nhunk -= n;
1500         hunk += n;
1501         return p;
1502 }
1503
1504 void*
1505 allocn(void *p, long on, long n)
1506 {
1507         void *q;
1508
1509         q = (uchar*)p + on;
1510         if(q != hunk || nhunk < n) {
1511                 while(nhunk < on+n)
1512                         gethunk();
1513                 memmove(hunk, p, on);
1514                 p = hunk;
1515                 hunk += on;
1516                 nhunk -= on;
1517         }
1518         hunk += n;
1519         nhunk -= n;
1520         return p;
1521 }
1522
1523 void
1524 setinclude(char *p)
1525 {
1526         int i;
1527         char *e;
1528
1529         while(*p != 0) {
1530                 e = strchr(p, ' ');
1531                 if(e != 0)
1532                         *e = '\0';
1533
1534                 for(i=1; i < ninclude; i++)
1535                         if(strcmp(p, include[i]) == 0)
1536                                 break;
1537
1538                 if(i >= ninclude)
1539                         include[ninclude++] = p;
1540
1541                 if(ninclude > nelem(include)) {
1542                         diag(Z, "ninclude too small %d", nelem(include));
1543                         exits("ninclude");
1544                 }
1545
1546                 if(e == 0)
1547                         break;
1548                 p = e+1;
1549         }
1550 }