10 * flags without a description may be exclusive to certain architectures
11 * -. Inhibit search for includes in source directory
21 * -F format specification check
25 * -L print every NAME symbol
26 * -M constant multiplication
30 * -R print registerization
33 * -V enable void* conversion warnings
39 * -a acid declaration output
41 * -d print declarations
46 * -i print initialization
47 * -l generate little-endian code
48 * -m print add/sub/mul trees
49 * -n print acid to file (%.c=%.acid) (with -a or -aa)
51 * -p use standard cpp ANSI preprocessor (not on windows)
52 * -s print structure offsets (with -a or -aa)
61 main(int argc, char *argv[])
64 int nproc, nout, status, i, c, ndef;
66 memset(debug, 0, sizeof(debug));
72 profileflg = 1; /* #pragma can turn it off */
73 tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
76 include[ninclude++] = ".";
80 if(c >= 0 && c < sizeof(debug))
84 case 'l': /* for little-endian mips */
86 print("can only use -l with vc");
111 if(argc < 1 && outfile == 0) {
112 print("usage: %cc [-options] files\n", thechar);
115 if(argc > 1 && systemtype(Windows)){
116 print("can't compile multiple files on windows\n");
119 if(argc > 1 && !systemtype(Windows)) {
122 * if we're writing acid to standard output, don't compile
123 * concurrently, to avoid interleaving output.
125 if(((!debug['a'] && !debug['Z']) || debug['n']) &&
126 (p = getenv("NPROC")) != nil)
127 nproc = atol(p); /* */
131 while(nout < nproc && argc > 0) {
136 print("cannot create a process\n");
145 fprint(2, "%s:\n", *argv);
146 if (compile(*argv, defs, ndef))
167 c = compile("stdin", defs, ndef);
169 c = compile(argv[0], defs, ndef);
177 compile(char *file, char **defs, int ndef)
179 char ofile[400], incfile[20];
180 char *p, *av[100], opt[256];
182 static int first = 1;
185 p = utfrrune(ofile, pathchar());
189 include[0] = strdup(ofile);
196 if(p = utfrrune(outfile, '.'))
197 if(p[1] == 'c' && p[2] == 0)
199 p = utfrune(outfile, 0);
200 if(debug['a'] && debug['n'])
202 else if(debug['Z'] && debug['n'])
203 strcat(p, "_pickle.c");
210 outfile = "/dev/null";
213 if(p = getenv("INCLUDE")) {
216 if(systemtype(Plan9)) {
217 sprint(incfile, "/%s/include", thestring);
218 setinclude(strdup(incfile));
219 setinclude("/sys/include");
223 Binit(&diagbuf, 1, OWRITE);
225 * if we're writing acid to standard output, don't keep scratching
228 if((debug['a'] || debug['Z']) && !debug['n']) {
231 Binit(&outbuf, dup(1, -1), OWRITE);
235 c = mycreat(outfile, 0664);
237 diag(Z, "cannot open %s - %r", outfile);
241 Binit(&outbuf, c, OWRITE);
246 /* Use an ANSI preprocessor */
248 if(systemtype(Windows)) {
249 diag(Z, "-p option not supported on windows");
252 if(myaccess(file) < 0) {
253 diag(Z, "%s does not exist", file);
257 diag(Z, "pipe failed");
262 diag(Z, "fork failed");
271 av[i++] = strdup(opt);
274 av[i++] = strdup(opt);
276 for(c = 0; c < ndef; c++) {
277 sprint(opt, "-D%s", defs[c]);
278 av[i++] = strdup(opt);
280 for(c = 0; c < ninclude; c++) {
281 sprint(opt, "-I%s", include[c]);
282 av[i++] = strdup(opt);
284 if(strcmp(file, "stdin") != 0)
288 for(c = 0; c < i; c++)
289 fprint(2, "%s ", av[c]);
293 fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
297 newfile(file, fd[0]);
301 if(strcmp(file, "stdin") == 0)
307 if(!debug['a'] && !debug['Z'])
327 yyerror("botch in pushio");
338 static int pushdepth = 0;
343 if(pushdepth > 1000) {
344 yyerror("macro/io expansion too deep");
347 i = alloc(sizeof(*i));
356 newfile(char *s, int f)
361 print("%L: %s\n", lineno, s);
370 yyerror("%cc: %r: %s", thechar, s);
403 for(s = hash[h]; s != S; s = s->link) {
406 if(strcmp(s->name, symb) == 0)
409 s = alloc(sizeof(*s));
411 memmove(s->name, symb, n);
413 strcpy(s->name, symb);
437 #define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
469 * all multibyte runes are alpha
487 c = escchar('\'', 1, 0);
490 c1 = escchar('\'', 1, 0);
492 yyerror("missing '");
495 yylval.vval = convvtox(c, TRUNE);
532 strcpy(symb, "\"<string>\"");
538 c = escchar('"', 0, 1);
542 cp = allocn(cp, c1, 1);
547 cp = allocn(cp, c1, c);
548 runetochar(cp+c1, &rune);
554 cp = allocn(cp, c1, 1);
556 } while(c1 & MAXALIGN);
562 strcpy(symb, "\"L<string>\"");
566 c = escchar('"', 1, 0);
569 cp = allocn(cp, c1, sizeof(Rune));
570 *(Rune*)(cp + c1) = c;
575 cp = allocn(cp, c1, sizeof(Rune));
576 *(Rune*)(cp + c1) = 0;
578 } while(c1 & MAXALIGN);
584 c = escchar('\'', 0, 0);
587 c1 = escchar('\'', 0, 0);
589 yyerror("missing '");
593 yylval.vval = convvtox(vv, TUCHAR);
594 if(yylval.vval != vv)
595 yyerror("overflow in character constant: 0x%lx", c);
599 warn(Z, "sign-extended character constant");
601 yylval.vval = convvtox(vv, TCHAR);
615 yyerror("eof in comment");
626 yyerror("eof in comment");
733 * cp is set to symb and some
734 * prefix has been stored
737 if(cp >= &symb[NSYMB-UTFmax-1])
750 if(!isalnum(c) && c != '_')
757 print("%L: %s\n", lineno, symb);
765 ionext->link = iostack;
777 if(s->class == CTYPEDEF || s->class == CTYPESTR)
787 if(cp >= &symb[NSYMB-1])
798 if(c == 'x' || c == 'X')
800 if(cp >= &symb[NSYMB-1])
806 if(c >= 'a' && c <= 'f')
808 if(c >= 'A' && c <= 'F')
811 yyerror("malformed hex constant");
814 if(c < '0' || c > '7')
817 if(c >= '0' && c <= '7') {
818 if(cp >= &symb[NSYMB-1])
830 if(c == 'e' || c == 'E')
834 if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
839 if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
848 if(mpatov(symb, &yylval.vval))
849 yyerror("overflow in constant");
853 if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
863 if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
872 if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
882 yylval.vval = convvtox(vv, t);
883 if(yylval.vval != vv){
885 warn(Z, "truncated constant: %T %s", types[t], symb);
891 if(cp >= &symb[NSYMB-1])
898 if(c != 'e' && c != 'E')
902 if(cp >= &symb[NSYMB-2])
906 if(c == '+' || c == '-') {
911 yyerror("malformed fp constant exponent");
913 if(cp >= &symb[NSYMB-1])
920 if(c == 'L' || c == 'l') {
924 if(c == 'F' || c == 'f') {
930 yylval.dval = strtod(symb, nil);
931 if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) {
932 yyerror("overflow in float constant");
940 yyerror("token too long: %.*s...", utfnlen(symb, cp-symb), symb);
946 * convert a string, s, to vlong in *v
947 * return conversion overflow.
948 * required syntax is [0[x]]d*
951 mpatov(char *s, vlong *v)
961 if(c >= '0' && c <= '9')
974 if(c == 'x' || c == 'X')
977 if(c >= '0' || c <= '7')
990 if(c >= '0' && c <= '9')
993 if(c >= 'a' && c <= 'f')
996 if(c >= 'A' && c <= 'F')
1001 if(n < 0 && nn >= 0)
1027 yyerror("End of file");
1050 if(!fullrune(str, i))
1052 c = chartorune(&rune, str);
1053 if(rune == Runeerror && c == 1) {
1055 diag(Z, "illegal rune in string");
1057 print(" %.2x", *(uchar*)(str+c));
1074 if(c >= Runeself || !isspace(c))
1094 escchar(long e, int longflg, int escflg)
1102 yyerror("newline in string");
1113 * note this is not ansi,
1114 * supposed to only accept 2 hex
1122 if(c >= '0' && c <= '9') {
1126 if(c >= 'a' && c <= 'f') {
1127 l = l*16 + c-'a' + 10;
1130 if(c >= 'A' && c <= 'F') {
1131 l = l*16 + c-'A' + 10;
1141 if(c >= '0' && c <= '7') {
1143 * note this is not ansi,
1144 * supposed to only accept 3 oct
1152 if(c >= '0' && c <= '7') {
1164 case '\n': goto loop;
1165 case 'n': return '\n';
1166 case 't': return '\t';
1167 case 'b': return '\b';
1168 case 'r': return '\r';
1169 case 'f': return '\f';
1170 case 'a': return '\a';
1171 case 'v': return '\v';
1186 "char", LCHAR, TCHAR,
1187 "const", LCONSTNT, 0,
1188 "continue", LCONTINUE, 0,
1189 "default", LDEFAULT, 0,
1191 "double", LDOUBLE, TDOUBLE,
1194 "extern", LEXTERN, 0,
1195 "float", LFLOAT, TFLOAT,
1199 "inline", LINLINE, 0,
1201 "long", LLONG, TLONG,
1202 "register", LREGISTER, 0,
1203 "restrict", LRESTRICT, 0,
1204 "return", LRETURN, 0,
1206 "short", LSHORT, TSHORT,
1207 "signed", LSIGNED, 0,
1208 "signof", LSIGNOF, 0,
1209 "sizeof", LSIZEOF, 0,
1210 "static", LSTATIC, 0,
1211 "struct", LSTRUCT, 0,
1212 "switch", LSWITCH, 0,
1213 "typedef", LTYPEDEF, 0,
1214 "typestr", LTYPESTR, 0,
1216 "unsigned", LUNSIGNED, 0,
1218 "void", LVOID, TVOID,
1219 "volatile", LVOLATILE, 0,
1239 types[TCHAR] = typ(TCHAR, T);
1240 types[TUCHAR] = typ(TUCHAR, T);
1241 types[TSHORT] = typ(TSHORT, T);
1242 types[TUSHORT] = typ(TUSHORT, T);
1243 types[TINT] = typ(TINT, T);
1244 types[TUINT] = typ(TUINT, T);
1245 types[TLONG] = typ(TLONG, T);
1246 types[TULONG] = typ(TULONG, T);
1247 types[TVLONG] = typ(TVLONG, T);
1248 types[TUVLONG] = typ(TUVLONG, T);
1249 types[TFLOAT] = typ(TFLOAT, T);
1250 types[TDOUBLE] = typ(TDOUBLE, T);
1251 types[TVOID] = typ(TVOID, T);
1252 types[TENUM] = typ(TENUM, T);
1253 types[TFUNC] = typ(TFUNC, types[TINT]);
1254 types[TIND] = typ(TIND, types[TVOID]);
1256 for(i=0; i<NHASH; i++)
1258 for(i=0; itab[i].name; i++) {
1259 s = slookup(itab[i].name);
1260 s->lexical = itab[i].lexical;
1261 if(itab[i].type != 0)
1262 s->type = types[itab[i].type];
1268 t = typ(TARRAY, types[TCHAR]);
1270 symstring = slookup(".string");
1271 symstring->class = CSTATIC;
1272 symstring->type = t;
1274 t = typ(TARRAY, types[TCHAR]);
1277 nodproto = new(OPROTO, Z, Z);
1280 pathname = allocn(pathname, 0, 100);
1281 if(mygetwd(pathname, 99) == 0) {
1282 pathname = allocn(pathname, 100, 900);
1283 if(mygetwd(pathname, 999) == 0)
1284 strcpy(pathname, "/???");
1287 fmtinstall('O', Oconv);
1288 fmtinstall('T', Tconv);
1289 fmtinstall('F', FNconv);
1290 fmtinstall('L', Lconv);
1291 fmtinstall('Q', Qconv);
1292 fmtinstall('|', VBconv);
1306 fi.c = read(i->f, i->b, BUFSIZ) - 1;
1313 return i->b[0] & 0xff;
1326 return *fi.p++ & 0xff;
1334 a = va_arg(fp->args, int);
1335 if(a < OXXX || a > OEND)
1336 return fmtprint(fp, "***badO %d***", a);
1338 return fmtstrcpy(fp, onames[a]);
1344 char str[STRINGSZ], s[STRINGSZ];
1348 Hist* incl; /* start of this include file */
1349 long idel; /* delta line number to apply to include */
1350 Hist* line; /* start of this #line directive */
1351 long ldel; /* delta line number to apply to #line */
1356 l = va_arg(fp->args, long);
1358 for(h = hist; h != H; h = h->link) {
1362 if(h->offset != 0) { /* #line directive, not #pragma */
1363 if(n > 0 && n < HISTSZ && h->offset >= 0) {
1365 a[n-1].ldel = h->line - h->offset + 1;
1368 if(n < HISTSZ) { /* beginning of file */
1370 a[n].idel = h->line;
1378 if(n > 0 && n < HISTSZ) {
1379 d = h->line - a[n].incl->line;
1387 for(i=n-1; i>=0; i--) {
1389 if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */
1394 snprint(s, STRINGSZ, "%s:%ld[%s:%ld]",
1395 a[i].line->name, l-a[i].ldel+1,
1396 a[i].incl->name, l-a[i].idel+1);
1398 snprint(s, STRINGSZ, "%s:%ld",
1399 a[i].incl->name, l-a[i].idel+1);
1400 if(strlen(s)+strlen(str) >= STRINGSZ-10)
1403 l = a[i].incl->line - 1; /* now print out start of this file */
1406 strcat(str, "<eof>");
1407 return fmtstrcpy(fp, str);
1413 char str[STRINGSZ+20], s[STRINGSZ+20];
1419 for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
1423 if(t->garb&~GINCOMPLETE) {
1424 sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
1425 if(strlen(str) + strlen(s) < STRINGSZ)
1428 sprint(s, "%s", tnames[et]);
1429 if(strlen(str) + strlen(s) < STRINGSZ)
1431 if(et == TFUNC && (t1 = t->down)) {
1432 sprint(s, "(%T", t1);
1433 if(strlen(str) + strlen(s) < STRINGSZ)
1435 while(t1 = t1->down) {
1436 sprint(s, ", %T", t1);
1437 if(strlen(str) + strlen(s) < STRINGSZ)
1440 if(strlen(str) + strlen(s) < STRINGSZ)
1445 if(t->link && t->link->width)
1446 n /= t->link->width;
1447 sprint(s, "[%ld]", n);
1448 if(strlen(str) + strlen(s) < STRINGSZ)
1452 sprint(s, " %d:%d", t->shift, t->nbits);
1453 if(strlen(str) + strlen(s) < STRINGSZ)
1459 if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
1460 strcat(str, t->tag->name);
1466 return fmtstrcpy(fp, str);
1475 n = va_arg(fp->args, Node*);
1477 if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
1479 return fmtstrcpy(fp, str);
1485 char str[STRINGSZ+20], *s;
1490 for(b = va_arg(fp->args, long); b;) {
1495 if(strlen(str) + strlen(s) >= STRINGSZ)
1500 return fmtstrcpy(fp, str);
1509 n = va_arg(fp->args, int);
1510 pc = 0; /* BUG: was printcol */
1524 return fmtstrcpy(fp, str);
1538 for(i=1; i < ninclude; i++)
1539 if(strcmp(p, include[i]) == 0)
1543 if(ninclude >= nelem(include)) {
1544 diag(Z, "ninclude too small %d", nelem(include));
1547 include[ninclude++] = p;