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");
87 if(argc < 1 && outfile == 0) {
88 print("usage: %cc [-options] files\n", thechar);
91 if(argc > 1 && systemtype(Windows)){
92 print("can't compile multiple files on windows\n");
95 if(argc > 1 && !systemtype(Windows)) {
98 * if we're writing acid to standard output, don't compile
99 * concurrently, to avoid interleaving output.
101 if(((!debug['a'] && !debug['Z']) || debug['n']) &&
102 (p = getenv("NPROC")) != nil)
103 nproc = atol(p); /* */
107 while(nout < nproc && argc > 0) {
112 print("cannot create a process\n");
121 fprint(2, "%s:\n", *argv);
122 if (compile(*argv, defs, ndef))
143 c = compile("stdin", defs, ndef);
145 c = compile(argv[0], defs, ndef);
153 compile(char *file, char **defs, int ndef)
155 char ofile[400], incfile[20];
156 char *p, *av[100], opt[256];
158 static int first = 1;
161 p = utfrrune(ofile, pathchar());
165 include[0] = strdup(ofile);
172 if(p = utfrrune(outfile, '.'))
173 if(p[1] == 'c' && p[2] == 0)
175 p = utfrune(outfile, 0);
176 if(debug['a'] && debug['n'])
178 else if(debug['Z'] && debug['n'])
179 strcat(p, "_pickle.c");
186 outfile = "/dev/null";
189 if(p = getenv("INCLUDE")) {
192 if(systemtype(Plan9)) {
193 sprint(incfile, "/%s/include", thestring);
194 setinclude(strdup(incfile));
195 setinclude("/sys/include");
199 Binit(&diagbuf, 1, OWRITE);
201 * if we're writing acid to standard output, don't keep scratching
204 if((debug['a'] || debug['Z']) && !debug['n']) {
207 Binit(&outbuf, dup(1, -1), OWRITE);
211 c = mycreat(outfile, 0664);
213 diag(Z, "cannot open %s - %r", outfile);
217 Binit(&outbuf, c, OWRITE);
222 /* Use an ANSI preprocessor */
224 if(systemtype(Windows)) {
225 diag(Z, "-p option not supported on windows");
228 if(myaccess(file) < 0) {
229 diag(Z, "%s does not exist", file);
233 diag(Z, "pipe failed");
238 diag(Z, "fork failed");
247 av[i++] = strdup(opt);
250 av[i++] = strdup(opt);
252 for(c = 0; c < ndef; c++) {
253 sprint(opt, "-D%s", defs[c]);
254 av[i++] = strdup(opt);
256 for(c = 0; c < ninclude; c++) {
257 sprint(opt, "-I%s", include[c]);
258 av[i++] = strdup(opt);
260 if(strcmp(file, "stdin") != 0)
264 for(c = 0; c < i; c++)
265 fprint(2, "%s ", av[c]);
269 fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
273 newfile(file, fd[0]);
277 if(strcmp(file, "stdin") == 0)
283 if(!debug['a'] && !debug['Z'])
303 yyerror("botch in pushio");
314 static int pushdepth = 0;
319 if(pushdepth > 1000) {
320 yyerror("macro/io expansion too deep");
323 i = alloc(sizeof(*i));
332 newfile(char *s, int f)
337 print("%L: %s\n", lineno, s);
346 yyerror("%cc: %r: %s", thechar, s);
379 for(s = hash[h]; s != S; s = s->link) {
382 if(strcmp(s->name, symb) == 0)
385 s = alloc(sizeof(*s));
387 memmove(s->name, symb, n);
389 strcpy(s->name, symb);
413 #define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
445 * all multibyte runes are alpha
463 c = escchar('\'', 1, 0);
466 c1 = escchar('\'', 1, 0);
468 yyerror("missing '");
471 yylval.vval = convvtox(c, TRUNE);
508 strcpy(symb, "\"<string>\"");
514 c = escchar('"', 0, 1);
518 cp = allocn(cp, c1, 1);
523 cp = allocn(cp, c1, c);
524 runetochar(cp+c1, &rune);
530 cp = allocn(cp, c1, 1);
532 } while(c1 & MAXALIGN);
538 strcpy(symb, "\"L<string>\"");
542 c = escchar('"', 1, 0);
545 cp = allocn(cp, c1, sizeof(Rune));
546 *(Rune*)(cp + c1) = c;
551 cp = allocn(cp, c1, sizeof(Rune));
552 *(Rune*)(cp + c1) = 0;
554 } while(c1 & MAXALIGN);
560 c = escchar('\'', 0, 0);
563 c1 = escchar('\'', 0, 0);
565 yyerror("missing '");
569 yylval.vval = convvtox(vv, TUCHAR);
570 if(yylval.vval != vv)
571 yyerror("overflow in character constant: 0x%lx", c);
575 warn(Z, "sign-extended character constant");
577 yylval.vval = convvtox(vv, TCHAR);
591 yyerror("eof in comment");
602 yyerror("eof in comment");
709 * cp is set to symb and some
710 * prefix has been stored
724 if(!isalnum(c) && c != '_')
731 print("%L: %s\n", lineno, symb);
739 ionext->link = iostack;
751 if(s->class == CTYPEDEF || s->class == CTYPESTR)
770 if(c == 'x' || c == 'X')
776 if(c >= 'a' && c <= 'f')
778 if(c >= 'A' && c <= 'F')
781 yyerror("malformed hex constant");
784 if(c < '0' || c > '7')
787 if(c >= '0' && c <= '7') {
798 if(c == 'e' || c == 'E')
802 if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
807 if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
816 if(mpatov(symb, &yylval.vval))
817 yyerror("overflow in constant");
821 if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
831 if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
840 if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
850 yylval.vval = convvtox(vv, t);
851 if(yylval.vval != vv){
853 warn(Z, "truncated constant: %T %s", types[t], symb);
864 if(c != 'e' && c != 'E')
870 if(c == '+' || c == '-') {
875 yyerror("malformed fp constant exponent");
882 if(c == 'L' || c == 'l') {
886 if(c == 'F' || c == 'f') {
892 yylval.dval = strtod(symb, nil);
893 if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) {
894 yyerror("overflow in float constant");
903 * convert a string, s, to vlong in *v
904 * return conversion overflow.
905 * required syntax is [0[x]]d*
908 mpatov(char *s, vlong *v)
918 if(c >= '0' && c <= '9')
931 if(c == 'x' || c == 'X')
934 if(c >= '0' || c <= '7')
947 if(c >= '0' && c <= '9')
950 if(c >= 'a' && c <= 'f')
953 if(c >= 'A' && c <= 'F')
984 yyerror("End of file");
1007 if(!fullrune(str, i))
1009 c = chartorune(&rune, str);
1010 if(rune == Runeerror && c == 1) {
1012 diag(Z, "illegal rune in string");
1014 print(" %.2x", *(uchar*)(str+c));
1031 if(c >= Runeself || !isspace(c))
1051 escchar(long e, int longflg, int escflg)
1059 yyerror("newline in string");
1070 * note this is not ansi,
1071 * supposed to only accept 2 hex
1079 if(c >= '0' && c <= '9') {
1083 if(c >= 'a' && c <= 'f') {
1084 l = l*16 + c-'a' + 10;
1087 if(c >= 'A' && c <= 'F') {
1088 l = l*16 + c-'A' + 10;
1098 if(c >= '0' && c <= '7') {
1100 * note this is not ansi,
1101 * supposed to only accept 3 oct
1109 if(c >= '0' && c <= '7') {
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';
1143 "char", LCHAR, TCHAR,
1144 "const", LCONSTNT, 0,
1145 "continue", LCONTINUE, 0,
1146 "default", LDEFAULT, 0,
1148 "double", LDOUBLE, TDOUBLE,
1151 "extern", LEXTERN, 0,
1152 "float", LFLOAT, TFLOAT,
1156 "inline", LINLINE, 0,
1158 "long", LLONG, TLONG,
1159 "register", LREGISTER, 0,
1160 "restrict", LRESTRICT, 0,
1161 "return", LRETURN, 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,
1173 "unsigned", LUNSIGNED, 0,
1175 "void", LVOID, TVOID,
1176 "volatile", LVOLATILE, 0,
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]);
1213 for(i=0; i<NHASH; i++)
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];
1225 t = typ(TARRAY, types[TCHAR]);
1227 symstring = slookup(".string");
1228 symstring->class = CSTATIC;
1229 symstring->type = t;
1231 t = typ(TARRAY, types[TCHAR]);
1234 nodproto = new(OPROTO, Z, Z);
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, "/???");
1244 fmtinstall('O', Oconv);
1245 fmtinstall('T', Tconv);
1246 fmtinstall('F', FNconv);
1247 fmtinstall('L', Lconv);
1248 fmtinstall('Q', Qconv);
1249 fmtinstall('|', VBconv);
1263 fi.c = read(i->f, i->b, BUFSIZ) - 1;
1270 return i->b[0] & 0xff;
1283 return *fi.p++ & 0xff;
1291 a = va_arg(fp->args, int);
1292 if(a < OXXX || a > OEND)
1293 return fmtprint(fp, "***badO %d***", a);
1295 return fmtstrcpy(fp, onames[a]);
1301 char str[STRINGSZ], s[STRINGSZ];
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 */
1313 l = va_arg(fp->args, long);
1315 for(h = hist; h != H; h = h->link) {
1319 if(h->offset != 0) { /* #line directive, not #pragma */
1320 if(n > 0 && n < HISTSZ && h->offset >= 0) {
1322 a[n-1].ldel = h->line - h->offset + 1;
1325 if(n < HISTSZ) { /* beginning of file */
1327 a[n].idel = h->line;
1335 if(n > 0 && n < HISTSZ) {
1336 d = h->line - a[n].incl->line;
1344 for(i=n-1; i>=0; i--) {
1346 if(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */
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);
1355 snprint(s, STRINGSZ, "%s:%ld",
1356 a[i].incl->name, l-a[i].idel+1);
1357 if(strlen(s)+strlen(str) >= STRINGSZ-10)
1360 l = a[i].incl->line - 1; /* now print out start of this file */
1363 strcat(str, "<eof>");
1364 return fmtstrcpy(fp, str);
1370 char str[STRINGSZ+20], s[STRINGSZ+20];
1376 for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
1380 if(t->garb&~GINCOMPLETE) {
1381 sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
1382 if(strlen(str) + strlen(s) < STRINGSZ)
1385 sprint(s, "%s", tnames[et]);
1386 if(strlen(str) + strlen(s) < STRINGSZ)
1388 if(et == TFUNC && (t1 = t->down)) {
1389 sprint(s, "(%T", t1);
1390 if(strlen(str) + strlen(s) < STRINGSZ)
1392 while(t1 = t1->down) {
1393 sprint(s, ", %T", t1);
1394 if(strlen(str) + strlen(s) < STRINGSZ)
1397 if(strlen(str) + strlen(s) < STRINGSZ)
1402 if(t->link && t->link->width)
1403 n /= t->link->width;
1404 sprint(s, "[%ld]", n);
1405 if(strlen(str) + strlen(s) < STRINGSZ)
1409 sprint(s, " %d:%d", t->shift, t->nbits);
1410 if(strlen(str) + strlen(s) < STRINGSZ)
1416 if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
1417 strcat(str, t->tag->name);
1423 return fmtstrcpy(fp, str);
1432 n = va_arg(fp->args, Node*);
1434 if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
1436 return fmtstrcpy(fp, str);
1442 char str[STRINGSZ+20], *s;
1447 for(b = va_arg(fp->args, long); b;) {
1452 if(strlen(str) + strlen(s) >= STRINGSZ)
1457 return fmtstrcpy(fp, str);
1466 n = va_arg(fp->args, int);
1467 pc = 0; /* BUG: was printcol */
1481 return fmtstrcpy(fp, str);
1492 while((uintptr)hunk & MAXALIGN) {
1505 allocn(void *p, long on, long n)
1510 if(q != hunk || nhunk < n) {
1513 memmove(hunk, p, on);
1534 for(i=1; i < ninclude; i++)
1535 if(strcmp(p, include[i]) == 0)
1539 include[ninclude++] = p;
1541 if(ninclude > nelem(include)) {
1542 diag(Z, "ninclude too small %d", nelem(include));