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