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);
77 include[ninclude++] = ".";
81 if(c >= 0 && c < sizeof(debug))
85 case 'l': /* for little-endian mips */
87 print("can only use -l with vc");
102 defs = allocn(defs, ndef*sizeof(defs[0]), 16*sizeof(defs[0]));
114 if(argc < 1 && outfile == 0) {
115 print("usage: %Cc [-options] files\n", thechar);
118 if(argc > 1 && systemtype(Windows)){
119 print("can't compile multiple files on windows\n");
122 if(argc > 1 && !systemtype(Windows)) {
125 * if we're writing acid to standard output, don't compile
126 * concurrently, to avoid interleaving output.
128 if(((!debug['a'] && !debug['Z']) || debug['n']) &&
129 (p = getenv("NPROC")) != nil)
130 nproc = atol(p); /* */
134 while(nout < nproc && argc > 0) {
139 print("cannot create a process\n");
148 fprint(2, "%s:\n", *argv);
149 if (compile(*argv, defs, ndef))
170 c = compile("stdin", defs, ndef);
172 c = compile(argv[0], defs, ndef);
180 compile(char *file, char **defs, int ndef)
182 char *ofile, *p, **av;
184 static int first = 1;
186 ofile = strdup(file);
187 p = utfrrune(ofile, pathchar());
191 include[0] = strdup(ofile);
198 if(p = utfrrune(outfile, '.'))
199 if(p[1] == 'c' && p[2] == 0)
201 if(debug['a'] && debug['n'])
202 outfile = smprint("%s.acid", outfile);
203 else if(debug['Z'] && debug['n'])
204 outfile = smprint("%s_pickle.c", outfile);
206 outfile = smprint("%s.%C", outfile, thechar);
208 outfile = "/dev/null";
211 if(p = getenv("INCLUDE")) {
214 if(systemtype(Plan9)) {
215 setinclude(smprint("/%s/include", thestring));
216 setinclude("/sys/include");
220 Binit(&diagbuf, 1, OWRITE);
222 * if we're writing acid to standard output, don't keep scratching
225 if((debug['a'] || debug['Z']) && !debug['n']) {
228 Binit(&outbuf, dup(1, -1), OWRITE);
232 c = mycreat(outfile, 0664);
234 diag(Z, "cannot open %s - %r", outfile);
238 Binit(&outbuf, c, OWRITE);
243 /* Use an ANSI preprocessor */
245 if(systemtype(Windows)) {
246 diag(Z, "-p option not supported on windows");
249 if(myaccess(file) < 0) {
250 diag(Z, "%s does not exist", file);
254 diag(Z, "pipe failed");
259 diag(Z, "fork failed");
267 av = alloc(i*sizeof(av[0]));
274 for(c = 0; c < ndef; c++)
275 av[i++] = smprint("-D%s", defs[c]);
276 for(c = 0; c < ninclude; c++)
277 av[i++] = smprint("-I%s", include[c]);
278 if(strcmp(file, "stdin") != 0)
282 for(c = 0; c < i; c++)
283 fprint(2, "%s ", av[c]);
287 fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
291 newfile(file, fd[0]);
295 if(strcmp(file, "stdin") == 0)
301 if(!debug['a'] && !debug['Z'])
321 yyerror("botch in pushio");
332 static int pushdepth = 0;
337 if(pushdepth > 1000) {
338 yyerror("macro/io expansion too deep");
341 i = alloc(sizeof(*i));
350 newfile(char *s, int f)
355 print("%L: %s\n", lineno, s);
364 yyerror("%Cc: %r: %s", thechar, s);
374 strncpy(symb, s, NSYMB);
375 if(symb[NSYMB-1] != '\0'){
376 yyerror("symbol too long: %s", s);
400 for(s = hash[h]; s != S; s = s->link) {
403 if(strcmp(s->name, symb) == 0)
406 s = alloc(sizeof(*s));
408 memmove(s->name, symb, n);
464 * all multibyte runes are alpha
482 c = escchar('\'', 1, 0);
485 c1 = escchar('\'', 1, 0);
487 yyerror("missing '");
490 yylval.vval = convvtox(c, TRUNE);
527 strcpy(symb, "\"<string>\"");
533 c = escchar('"', 0, 1);
537 cp = allocn(cp, c1, 1);
542 cp = allocn(cp, c1, c);
543 runetochar(cp+c1, &rune);
549 cp = allocn(cp, c1, 1);
551 } while(c1 & MAXALIGN);
557 strcpy(symb, "\"L<string>\"");
561 c = escchar('"', 1, 0);
564 cp = allocn(cp, c1, sizeof(Rune));
565 *(Rune*)(cp + c1) = c;
570 cp = allocn(cp, c1, sizeof(Rune));
571 *(Rune*)(cp + c1) = 0;
573 } while(c1 & MAXALIGN);
579 c = escchar('\'', 0, 0);
582 c1 = escchar('\'', 0, 0);
584 yyerror("missing '");
588 yylval.vval = convvtox(vv, TUCHAR);
589 if(yylval.vval != vv)
590 yyerror("overflow in character constant: 0x%lx", c);
594 warn(Z, "sign-extended character constant");
596 yylval.vval = convvtox(vv, TCHAR);
610 yyerror("eof in comment");
621 yyerror("eof in comment");
728 * cp is set to symb and some
729 * prefix has been stored
732 if(cp >= &symb[NSYMB-UTFmax-1])
745 if(!isalnum(c) && c != '_')
752 print("%L: %s\n", lineno, symb);
758 macexpand(s, cp, sizeof(ionext->b)-1);
760 ionext->link = iostack;
772 if(s->class == CTYPEDEF || s->class == CTYPESTR)
782 if(cp >= &symb[NSYMB-1])
793 if(c == 'x' || c == 'X')
795 if(cp >= &symb[NSYMB-1])
801 if(c >= 'a' && c <= 'f')
803 if(c >= 'A' && c <= 'F')
806 yyerror("malformed hex constant");
809 if(c < '0' || c > '7')
812 if(c >= '0' && c <= '7') {
813 if(cp >= &symb[NSYMB-1])
825 if(c == 'e' || c == 'E')
829 if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
834 if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
843 if(mpatov(symb, &yylval.vval))
844 yyerror("overflow in constant");
848 * c99 is silly: decimal constants stay signed,
849 * hex and octal go unsigned before widening.
852 if((c1 & (Numdec|Numuns)) == Numdec)
854 if(c1 & Numvlong || (c1 & Numlong) == 0 && (uvlong)vv >= 1ULL<<w){
855 if((c1&(Numdec|Numvlong)) == Numdec && vv < 1ULL<<32)
856 warn(Z, "int constant widened to vlong: %s", symb);
857 if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
867 if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
876 if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
886 yylval.vval = convvtox(vv, t);
887 if(yylval.vval != vv){
889 warn(Z, "truncated constant: %T %s", types[t], symb);
895 if(cp >= &symb[NSYMB-1])
902 if(c != 'e' && c != 'E')
906 if(cp >= &symb[NSYMB-2])
910 if(c == '+' || c == '-') {
915 yyerror("malformed fp constant exponent");
917 if(cp >= &symb[NSYMB-1])
924 if(c == 'L' || c == 'l') {
928 if(c == 'F' || c == 'f') {
934 yylval.dval = strtod(symb, nil);
935 if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) {
936 yyerror("overflow in float constant");
944 yyerror("token too long: %.*s...", utfnlen(symb, cp-symb), symb);
950 * convert a string, s, to vlong in *v
951 * return conversion overflow.
952 * required syntax is [0[x]]d*
955 mpatov(char *s, vlong *v)
965 if(c >= '0' && c <= '9')
978 if(c == 'x' || c == 'X')
981 if(c >= '0' || c <= '7')
994 if(c >= '0' && c <= '9')
997 if(c >= 'a' && c <= 'f')
1000 if(c >= 'A' && c <= 'F')
1005 if(n < 0 && nn >= 0)
1031 yyerror("End of file");
1054 if(!fullrune(str, i))
1056 c = chartorune(&rune, str);
1057 if(rune == Runeerror && c == 1) {
1059 diag(Z, "illegal rune in string");
1061 print(" %.2x", *(uchar*)(str+c));
1078 if(c >= Runeself || !isspace(c))
1098 escchar(long e, int longflg, int escflg)
1106 yyerror("newline in string");
1117 * note this is not ansi,
1118 * supposed to only accept 2 hex
1126 if(c >= '0' && c <= '9') {
1130 if(c >= 'a' && c <= 'f') {
1131 l = l*16 + c-'a' + 10;
1134 if(c >= 'A' && c <= 'F') {
1135 l = l*16 + c-'A' + 10;
1145 if(c >= '0' && c <= '7') {
1147 * note this is not ansi,
1148 * supposed to only accept 3 oct
1156 if(c >= '0' && c <= '7') {
1168 case '\n': goto loop;
1169 case 'n': return '\n';
1170 case 't': return '\t';
1171 case 'b': return '\b';
1172 case 'r': return '\r';
1173 case 'f': return '\f';
1174 case 'a': return '\a';
1175 case 'v': return '\v';
1190 "char", LCHAR, TCHAR,
1191 "const", LCONSTNT, 0,
1192 "continue", LCONTINUE, 0,
1193 "default", LDEFAULT, 0,
1195 "double", LDOUBLE, TDOUBLE,
1198 "extern", LEXTERN, 0,
1199 "float", LFLOAT, TFLOAT,
1203 "inline", LINLINE, 0,
1205 "long", LLONG, TLONG,
1206 "register", LREGISTER, 0,
1207 "restrict", LRESTRICT, 0,
1208 "return", LRETURN, 0,
1210 "short", LSHORT, TSHORT,
1211 "signed", LSIGNED, 0,
1212 "signof", LSIGNOF, 0,
1213 "sizeof", LSIZEOF, 0,
1214 "static", LSTATIC, 0,
1215 "struct", LSTRUCT, 0,
1216 "switch", LSWITCH, 0,
1217 "typedef", LTYPEDEF, 0,
1218 "typestr", LTYPESTR, 0,
1220 "unsigned", LUNSIGNED, 0,
1222 "void", LVOID, TVOID,
1223 "volatile", LVOLATILE, 0,
1242 types[TCHAR] = typ(TCHAR, T);
1243 types[TUCHAR] = typ(TUCHAR, T);
1244 types[TSHORT] = typ(TSHORT, T);
1245 types[TUSHORT] = typ(TUSHORT, T);
1246 types[TINT] = typ(TINT, T);
1247 types[TUINT] = typ(TUINT, T);
1248 types[TLONG] = typ(TLONG, T);
1249 types[TULONG] = typ(TULONG, T);
1250 types[TVLONG] = typ(TVLONG, T);
1251 types[TUVLONG] = typ(TUVLONG, T);
1252 types[TFLOAT] = typ(TFLOAT, T);
1253 types[TDOUBLE] = typ(TDOUBLE, T);
1254 types[TVOID] = typ(TVOID, T);
1255 types[TENUM] = typ(TENUM, T);
1256 types[TFUNC] = typ(TFUNC, types[TINT]);
1257 types[TIND] = typ(TIND, types[TVOID]);
1259 for(i=0; i<NHASH; i++)
1261 for(i=0; itab[i].name; i++) {
1262 s = slookup(itab[i].name);
1263 s->lexical = itab[i].lexical;
1264 if(itab[i].type != 0)
1265 s->type = types[itab[i].type];
1271 t = typ(TARRAY, types[TCHAR]);
1273 symstring = slookup(".string");
1274 symstring->class = CSTATIC;
1275 symstring->type = t;
1277 t = typ(TARRAY, types[TCHAR]);
1280 nodproto = new(OPROTO, Z, Z);
1283 pathname = allocn(pathname, 0, 100);
1284 if(mygetwd(pathname, 99) == 0) {
1285 pathname = allocn(pathname, 100, 900);
1286 if(mygetwd(pathname, 999) == 0)
1287 strcpy(pathname, "/???");
1290 fmtinstall('O', Oconv);
1291 fmtinstall('T', Tconv);
1292 fmtinstall('F', FNconv);
1293 fmtinstall('L', Lconv);
1294 fmtinstall('Q', Qconv);
1295 fmtinstall('|', VBconv);
1309 fi.c = read(i->f, i->b, BUFSIZ) - 1;
1316 return i->b[0] & 0xff;
1329 return *fi.p++ & 0xff;
1337 a = va_arg(fp->args, int);
1338 if(a < OXXX || a > OEND)
1339 return fmtprint(fp, "***badO %d***", a);
1341 return fmtstrcpy(fp, onames[a]);
1350 Hist* incl; /* start of this include file */
1351 long idel; /* delta line number to apply to include */
1352 Hist* line; /* start of this #line directive */
1353 long ldel; /* delta line number to apply to #line */
1358 l = va_arg(fp->args, long);
1360 for(h = hist; h != H; h = h->link) {
1364 if(h->offset != 0) { /* #line directive, not #pragma */
1365 if(n > 0 && n < HISTSZ && h->offset >= 0) {
1367 a[n-1].ldel = h->line - h->offset + 1;
1370 if(n < HISTSZ) { /* beginning of file */
1372 a[n].idel = h->line;
1380 if(n > 0 && n < HISTSZ) {
1381 d = h->line - a[n].incl->line;
1389 return fmtprint(fp, "<eof>");
1390 for(i=n-1; i>=0; i--) {
1392 if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */
1397 fmtprint(fp, "%s:%ld[%s:%ld]",
1398 a[i].line->name, l-a[i].ldel+1,
1399 a[i].incl->name, l-a[i].idel+1);
1401 fmtprint(fp, "%s:%ld",
1402 a[i].incl->name, l-a[i].idel+1);
1403 l = a[i].incl->line - 1; /* now print out start of this file */
1415 t = va_arg(fp->args, Type*);
1417 if(t->garb&~GINCOMPLETE)
1418 fmtprint(fp, "%s ", gnames[t->garb&~GINCOMPLETE]);
1420 fmtprint(fp, "%s", tnames[et]);
1421 if(et == TFUNC && (t1 = t->down) != T) {
1422 fmtprint(fp, "(%T", t1);
1423 while((t1 = t1->down) != T)
1424 fmtprint(fp, ", %T", t1);
1429 if(t->link != T && t->link->width)
1430 n /= t->link->width;
1431 fmtprint(fp, "[%ld]", n);
1434 fmtprint(fp, " %d:%d", t->shift, t->nbits);
1436 fmtprint(fp, " %s", t->tag? t->tag->name: "{}");
1439 if((t = t->link) == T)
1452 n = va_arg(fp->args, Node*);
1454 if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
1456 return fmtstrcpy(fp, str);
1465 b = va_arg(fp->args, long);
1469 fmtprint(fp, "%s%s", qnames[i], b? " ": "");
1479 n = va_arg(fp->args, int);
1480 pc = 0; /* BUG: was printcol */
1505 for(i=1; i < ninclude; i++)
1506 if(strcmp(p, include[i]) == 0)
1510 if(ninclude >= nelem(include)) {
1511 diag(Z, "ninclude too small %d", nelem(include));
1514 include[ninclude++] = p;