10 * -a acid declaration output
13 * -d print declarations
15 * -F format specification check
16 * -i print initialization
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)
24 * -p use standard cpp ANSI preprocessor (not on windows)
25 * -r print registerization
26 * -s print structure offsets (with -a or -aa)
29 * -V enable void* conversion warnings
33 * -. Inhibit search for includes in source directory
37 main(int argc, char *argv[])
40 int nproc, nout, status, i, c, ndef;
42 memset(debug, 0, sizeof(debug));
48 profileflg = 1; /* #pragma can turn it off */
49 tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
52 include[ninclude++] = ".";
56 if(c >= 0 && c < sizeof(debug))
60 case 'l': /* for little-endian mips */
62 print("can only use -l with vc");
86 if(argc < 1 && outfile == 0) {
87 print("usage: %cc [-options] files\n", thechar);
90 if(argc > 1 && systemtype(Windows)){
91 print("can't compile multiple files on windows\n");
94 if(argc > 1 && !systemtype(Windows)) {
97 * if we're writing acid to standard output, don't compile
98 * concurrently, to avoid interleaving output.
100 if(((!debug['a'] && !debug['Z']) || debug['n']) &&
101 (p = getenv("NPROC")) != nil)
102 nproc = atol(p); /* */
106 while(nout < nproc && argc > 0) {
111 print("cannot create a process\n");
120 fprint(2, "%s:\n", *argv);
121 if (compile(*argv, defs, ndef))
142 c = compile("stdin", defs, ndef);
144 c = compile(argv[0], defs, ndef);
152 compile(char *file, char **defs, int ndef)
154 char ofile[400], incfile[20];
155 char *p, *av[100], opt[256];
157 static int first = 1;
160 p = utfrrune(ofile, pathchar());
164 include[0] = strdup(ofile);
171 if(p = utfrrune(outfile, '.'))
172 if(p[1] == 'c' && p[2] == 0)
174 p = utfrune(outfile, 0);
175 if(debug['a'] && debug['n'])
177 else if(debug['Z'] && debug['n'])
178 strcat(p, "_pickle.c");
185 outfile = "/dev/null";
188 if(p = getenv("INCLUDE")) {
191 if(systemtype(Plan9)) {
192 sprint(incfile, "/%s/include", thestring);
193 setinclude(strdup(incfile));
194 setinclude("/sys/include");
198 Binit(&diagbuf, 1, OWRITE);
200 * if we're writing acid to standard output, don't keep scratching
203 if((debug['a'] || debug['Z']) && !debug['n']) {
206 Binit(&outbuf, dup(1, -1), OWRITE);
210 c = mycreat(outfile, 0664);
212 diag(Z, "cannot open %s - %r", outfile);
216 Binit(&outbuf, c, OWRITE);
221 /* Use an ANSI preprocessor */
223 if(systemtype(Windows)) {
224 diag(Z, "-p option not supported on windows");
227 if(myaccess(file) < 0) {
228 diag(Z, "%s does not exist", file);
232 diag(Z, "pipe failed");
237 diag(Z, "fork failed");
247 av[i++] = strdup(opt);
251 av[i++] = strdup(opt);
253 for(c = 0; c < ndef; c++) {
254 sprint(opt, "-D%s", defs[c]);
255 av[i++] = strdup(opt);
257 for(c = 0; c < ninclude; c++) {
258 sprint(opt, "-I%s", include[c]);
259 av[i++] = strdup(opt);
261 if(strcmp(file, "stdin") != 0)
265 for(c = 0; c < i; c++)
266 fprint(2, "%s ", av[c]);
270 fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
274 newfile(file, fd[0]);
278 if(strcmp(file, "stdin") == 0)
284 if(!debug['a'] && !debug['Z'])
304 yyerror("botch in pushio");
315 static int pushdepth = 0;
320 if(pushdepth > 1000) {
321 yyerror("macro/io expansion too deep");
324 i = alloc(sizeof(*i));
333 newfile(char *s, int f)
338 print("%L: %s\n", lineno, s);
347 yyerror("%cc: %r: %s", thechar, s);
380 for(s = hash[h]; s != S; s = s->link) {
383 if(strcmp(s->name, symb) == 0)
386 s = alloc(sizeof(*s));
388 memmove(s->name, symb, n);
390 strcpy(s->name, symb);
414 #define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
446 * all multibyte runes are alpha
464 c = escchar('\'', 1, 0);
467 c1 = escchar('\'', 1, 0);
469 yyerror("missing '");
472 yylval.vval = convvtox(c, TUSHORT);
509 strcpy(symb, "\"<string>\"");
515 c = escchar('"', 0, 1);
519 cp = allocn(cp, c1, 1);
524 cp = allocn(cp, c1, c);
525 runetochar(cp+c1, &rune);
531 cp = allocn(cp, c1, 1);
533 } while(c1 & MAXALIGN);
539 strcpy(symb, "\"L<string>\"");
543 c = escchar('"', 1, 0);
546 cp = allocn(cp, c1, sizeof(ushort));
547 *(ushort*)(cp + c1) = c;
548 c1 += sizeof(ushort);
552 cp = allocn(cp, c1, sizeof(ushort));
553 *(ushort*)(cp + c1) = 0;
554 c1 += sizeof(ushort);
555 } while(c1 & MAXALIGN);
561 c = escchar('\'', 0, 0);
564 c1 = escchar('\'', 0, 0);
566 yyerror("missing '");
570 yylval.vval = convvtox(vv, TUCHAR);
571 if(yylval.vval != vv)
572 yyerror("overflow in character constant: 0x%lx", c);
576 warn(Z, "sign-extended character constant");
578 yylval.vval = convvtox(vv, TCHAR);
592 yyerror("eof in comment");
603 yyerror("eof in comment");
710 * cp is set to symb and some
711 * prefix has been stored
725 if(!isalnum(c) && c != '_')
732 print("%L: %s\n", lineno, symb);
740 ionext->link = iostack;
752 if(s->class == CTYPEDEF || s->class == CTYPESTR)
771 if(c == 'x' || c == 'X')
777 if(c >= 'a' && c <= 'f')
779 if(c >= 'A' && c <= 'F')
782 yyerror("malformed hex constant");
785 if(c < '0' || c > '7')
788 if(c >= '0' && c <= '7') {
799 if(c == 'e' || c == 'E')
803 if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
808 if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
817 if(mpatov(symb, &yylval.vval))
818 yyerror("overflow in constant");
822 if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
832 if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
841 if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
851 yylval.vval = convvtox(vv, t);
852 if(yylval.vval != vv){
854 warn(Z, "truncated constant: %T %s", types[t], symb);
865 if(c != 'e' && c != 'E')
871 if(c == '+' || c == '-') {
876 yyerror("malformed fp constant exponent");
883 if(c == 'L' || c == 'l') {
887 if(c == 'F' || c == 'f') {
893 yylval.dval = strtod(symb, nil);
894 if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) {
895 yyerror("overflow in float constant");
904 * convert a string, s, to vlong in *v
905 * return conversion overflow.
906 * required syntax is [0[x]]d*
909 mpatov(char *s, vlong *v)
919 if(c >= '0' && c <= '9')
932 if(c == 'x' || c == 'X')
935 if(c >= '0' || c <= '7')
948 if(c >= '0' && c <= '9')
951 if(c >= 'a' && c <= 'f')
954 if(c >= 'A' && c <= 'F')
985 yyerror("End of file");
1008 if(!fullrune(str, i))
1010 c = chartorune(&rune, str);
1011 if(rune == Runeerror && c == 1) {
1013 diag(Z, "illegal rune in string");
1015 print(" %.2x", *(uchar*)(str+c));
1052 escchar(long e, int longflg, int escflg)
1060 yyerror("newline in string");
1071 * note this is not ansi,
1072 * supposed to only accept 2 hex
1080 if(c >= '0' && c <= '9') {
1084 if(c >= 'a' && c <= 'f') {
1085 l = l*16 + c-'a' + 10;
1088 if(c >= 'A' && c <= 'F') {
1089 l = l*16 + c-'A' + 10;
1099 if(c >= '0' && c <= '7') {
1101 * note this is not ansi,
1102 * supposed to only accept 3 oct
1110 if(c >= '0' && c <= '7') {
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';
1144 "char", LCHAR, TCHAR,
1145 "const", LCONSTNT, 0,
1146 "continue", LCONTINUE, 0,
1147 "default", LDEFAULT, 0,
1149 "double", LDOUBLE, TDOUBLE,
1152 "extern", LEXTERN, 0,
1153 "float", LFLOAT, TFLOAT,
1157 "inline", LINLINE, 0,
1159 "long", LLONG, TLONG,
1160 "register", LREGISTER, 0,
1161 "restrict", LRESTRICT, 0,
1162 "return", LRETURN, 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,
1174 "unsigned", LUNSIGNED, 0,
1176 "void", LVOID, TVOID,
1177 "volatile", LVOLATILE, 0,
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]);
1214 for(i=0; i<NHASH; i++)
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];
1226 t = typ(TARRAY, types[TCHAR]);
1228 symstring = slookup(".string");
1229 symstring->class = CSTATIC;
1230 symstring->type = t;
1232 t = typ(TARRAY, types[TCHAR]);
1235 nodproto = new(OPROTO, Z, Z);
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, "/???");
1245 fmtinstall('O', Oconv);
1246 fmtinstall('T', Tconv);
1247 fmtinstall('F', FNconv);
1248 fmtinstall('L', Lconv);
1249 fmtinstall('Q', Qconv);
1250 fmtinstall('|', VBconv);
1264 fi.c = read(i->f, i->b, BUFSIZ) - 1;
1271 return i->b[0] & 0xff;
1284 return *fi.p++ & 0xff;
1292 a = va_arg(fp->args, int);
1293 if(a < OXXX || a > OEND)
1294 return fmtprint(fp, "***badO %d***", a);
1296 return fmtstrcpy(fp, onames[a]);
1302 char str[STRINGSZ], s[STRINGSZ];
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 */
1314 l = va_arg(fp->args, long);
1316 for(h = hist; h != H; h = h->link) {
1320 if(h->offset != 0) { /* #line directive, not #pragma */
1321 if(n > 0 && n < HISTSZ && h->offset >= 0) {
1323 a[n-1].ldel = h->line - h->offset + 1;
1326 if(n < HISTSZ) { /* beginning of file */
1328 a[n].idel = h->line;
1336 if(n > 0 && n < HISTSZ) {
1337 d = h->line - a[n].incl->line;
1345 for(i=n-1; i>=0; i--) {
1347 if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */
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);
1356 snprint(s, STRINGSZ, "%s:%ld",
1357 a[i].incl->name, l-a[i].idel+1);
1358 if(strlen(s)+strlen(str) >= STRINGSZ-10)
1361 l = a[i].incl->line - 1; /* now print out start of this file */
1364 strcat(str, "<eof>");
1365 return fmtstrcpy(fp, str);
1371 char str[STRINGSZ+20], s[STRINGSZ+20];
1377 for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
1381 if(t->garb&~GINCOMPLETE) {
1382 sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
1383 if(strlen(str) + strlen(s) < STRINGSZ)
1386 sprint(s, "%s", tnames[et]);
1387 if(strlen(str) + strlen(s) < STRINGSZ)
1389 if(et == TFUNC && (t1 = t->down)) {
1390 sprint(s, "(%T", t1);
1391 if(strlen(str) + strlen(s) < STRINGSZ)
1393 while(t1 = t1->down) {
1394 sprint(s, ", %T", t1);
1395 if(strlen(str) + strlen(s) < STRINGSZ)
1398 if(strlen(str) + strlen(s) < STRINGSZ)
1403 if(t->link && t->link->width)
1404 n /= t->link->width;
1405 sprint(s, "[%ld]", n);
1406 if(strlen(str) + strlen(s) < STRINGSZ)
1410 sprint(s, " %d:%d", t->shift, t->nbits);
1411 if(strlen(str) + strlen(s) < STRINGSZ)
1417 if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
1418 strcat(str, t->tag->name);
1424 return fmtstrcpy(fp, str);
1433 n = va_arg(fp->args, Node*);
1435 if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
1437 return fmtstrcpy(fp, str);
1443 char str[STRINGSZ+20], *s;
1448 for(b = va_arg(fp->args, long); b;) {
1453 if(strlen(str) + strlen(s) >= STRINGSZ)
1458 return fmtstrcpy(fp, str);
1467 n = va_arg(fp->args, int);
1468 pc = 0; /* BUG: was printcol */
1482 return fmtstrcpy(fp, str);
1493 while((uintptr)hunk & MAXALIGN) {
1506 allocn(void *p, long on, long n)
1511 if(q != hunk || nhunk < n) {
1514 memmove(hunk, p, on);
1535 for(i=1; i < ninclude; i++)
1536 if(strcmp(p, include[i]) == 0)
1540 include[ninclude++] = p;
1542 if(ninclude > nelem(include)) {
1543 diag(Z, "ninclude too small %d", nelem(include));