697 lines
12 KiB
C
697 lines
12 KiB
C
#define EXTERN
|
|
#include "a.h"
|
|
#include "y.tab.h"
|
|
#include <ctype.h>
|
|
|
|
void
|
|
main(int argc, char *argv[])
|
|
{
|
|
char *p;
|
|
int nout, nproc, status, i, c;
|
|
|
|
thechar = 'v';
|
|
thestring = "mips";
|
|
memset(debug, 0, sizeof(debug));
|
|
cinit();
|
|
outfile = 0;
|
|
include[ninclude++] = ".";
|
|
ARGBEGIN {
|
|
default:
|
|
c = ARGC();
|
|
if(c >= 0 || c < sizeof(debug))
|
|
debug[c] = 1;
|
|
break;
|
|
|
|
case 'o':
|
|
outfile = ARGF();
|
|
break;
|
|
|
|
case 'D':
|
|
p = ARGF();
|
|
if(p)
|
|
Dlist[nDlist++] = p;
|
|
break;
|
|
|
|
case 'I':
|
|
p = ARGF();
|
|
setinclude(p);
|
|
break;
|
|
case 'L': /* for little-endian mips */
|
|
thechar = '0';
|
|
thestring = "spim";
|
|
break;
|
|
} ARGEND
|
|
if(*argv == 0) {
|
|
print("usage: %Ca [-options] file.s\n", thechar);
|
|
errorexit();
|
|
}
|
|
if(argc > 1 && systemtype(Windows)){
|
|
print("can't assemble multiple files on windows\n");
|
|
errorexit();
|
|
}
|
|
if(argc > 1 && !systemtype(Windows)) {
|
|
nproc = 1;
|
|
if(p = getenv("NPROC"))
|
|
nproc = atol(p); /* */
|
|
c = 0;
|
|
nout = 0;
|
|
for(;;) {
|
|
while(nout < nproc && argc > 0) {
|
|
i = myfork();
|
|
if(i < 0) {
|
|
i = mywait(&status);
|
|
if(i < 0)
|
|
errorexit();
|
|
if(status)
|
|
c++;
|
|
nout--;
|
|
continue;
|
|
}
|
|
if(i == 0) {
|
|
print("%s:\n", *argv);
|
|
if(assemble(*argv))
|
|
errorexit();
|
|
exits(0);
|
|
}
|
|
nout++;
|
|
argc--;
|
|
argv++;
|
|
}
|
|
i = mywait(&status);
|
|
if(i < 0) {
|
|
if(c)
|
|
errorexit();
|
|
exits(0);
|
|
}
|
|
if(status)
|
|
c++;
|
|
nout--;
|
|
}
|
|
}
|
|
if(assemble(argv[0]))
|
|
errorexit();
|
|
exits(0);
|
|
}
|
|
|
|
int
|
|
assemble(char *file)
|
|
{
|
|
char *ofile, *p;
|
|
int i, of;
|
|
|
|
ofile = strdup(file);
|
|
p = utfrrune(ofile, pathchar());
|
|
if(p) {
|
|
include[0] = ofile;
|
|
*p++ = 0;
|
|
} else
|
|
p = ofile;
|
|
if(outfile == 0) {
|
|
if(p){
|
|
outfile = p;
|
|
p = utfrrune(outfile, '.');
|
|
if(p)
|
|
if(p[1] == 's' && p[2] == 0)
|
|
p[0] = 0;
|
|
outfile = smprint("%s.%C", outfile, thechar);
|
|
} else
|
|
outfile = "/dev/null";
|
|
}
|
|
p = getenv("INCLUDE");
|
|
if(p) {
|
|
setinclude(p);
|
|
} else {
|
|
if(systemtype(Plan9))
|
|
setinclude(smprint("/%s/include", thestring));
|
|
}
|
|
|
|
of = mycreat(outfile, 0664);
|
|
if(of < 0) {
|
|
yyerror("%Ca: cannot create %s", thechar, outfile);
|
|
errorexit();
|
|
}
|
|
Binit(&obuf, of, OWRITE);
|
|
|
|
pass = 1;
|
|
pinit(file);
|
|
for(i=0; i<nDlist; i++)
|
|
dodefine(Dlist[i]);
|
|
yyparse();
|
|
if(nerrors) {
|
|
cclean();
|
|
return nerrors;
|
|
}
|
|
|
|
pass = 2;
|
|
outhist();
|
|
pinit(file);
|
|
for(i=0; i<nDlist; i++)
|
|
dodefine(Dlist[i]);
|
|
yyparse();
|
|
cclean();
|
|
return nerrors;
|
|
}
|
|
|
|
struct
|
|
{
|
|
char *name;
|
|
ushort type;
|
|
ushort value;
|
|
} itab[] =
|
|
{
|
|
"SP", LSP, D_AUTO,
|
|
"SB", LSB, D_EXTERN,
|
|
"FP", LFP, D_PARAM,
|
|
"PC", LPC, D_BRANCH,
|
|
"HI", LHI, D_HI,
|
|
"LO", LLO, D_LO,
|
|
|
|
"R", LR, 0,
|
|
"R0", LREG, 0,
|
|
"R1", LREG, 1,
|
|
"R2", LREG, 2,
|
|
"R3", LREG, 3,
|
|
"R4", LREG, 4,
|
|
"R5", LREG, 5,
|
|
"R6", LREG, 6,
|
|
"R7", LREG, 7,
|
|
"R8", LREG, 8,
|
|
"R9", LREG, 9,
|
|
"R10", LREG, 10,
|
|
"R11", LREG, 11,
|
|
"R12", LREG, 12,
|
|
"R13", LREG, 13,
|
|
"R14", LREG, 14,
|
|
"R15", LREG, 15,
|
|
"R16", LREG, 16,
|
|
"R17", LREG, 17,
|
|
"R18", LREG, 18,
|
|
"R19", LREG, 19,
|
|
"R20", LREG, 20,
|
|
"R21", LREG, 21,
|
|
"R22", LREG, 22,
|
|
"R23", LREG, 23,
|
|
"R24", LREG, 24,
|
|
"R25", LREG, 25,
|
|
"R26", LREG, 26,
|
|
"R27", LREG, 27,
|
|
"R28", LREG, 28,
|
|
"R29", LREG, 29,
|
|
"R30", LREG, 30,
|
|
"R31", LREG, 31,
|
|
|
|
"M", LM, 0,
|
|
"M0", LMREG, 0,
|
|
"M1", LMREG, 1,
|
|
"M2", LMREG, 2,
|
|
"M3", LMREG, 3,
|
|
"M4", LMREG, 4,
|
|
"M5", LMREG, 5,
|
|
"M6", LMREG, 6,
|
|
"M7", LMREG, 7,
|
|
"M8", LMREG, 8,
|
|
"M9", LMREG, 9,
|
|
"M10", LMREG, 10,
|
|
"M11", LMREG, 11,
|
|
"M12", LMREG, 12,
|
|
"M13", LMREG, 13,
|
|
"M14", LMREG, 14,
|
|
"M15", LMREG, 15,
|
|
"M16", LMREG, 16,
|
|
"M17", LMREG, 17,
|
|
"M18", LMREG, 18,
|
|
"M19", LMREG, 19,
|
|
"M20", LMREG, 20,
|
|
"M21", LMREG, 21,
|
|
"M22", LMREG, 22,
|
|
"M23", LMREG, 23,
|
|
"M24", LMREG, 24,
|
|
"M25", LMREG, 25,
|
|
"M26", LMREG, 26,
|
|
"M27", LMREG, 27,
|
|
"M28", LMREG, 28,
|
|
"M29", LMREG, 29,
|
|
"M30", LMREG, 30,
|
|
"M31", LMREG, 31,
|
|
|
|
"F", LF, 0,
|
|
|
|
"F0", LFREG, 0,
|
|
"F1", LFREG, 1,
|
|
"F2", LFREG, 2,
|
|
"F3", LFREG, 3,
|
|
"F4", LFREG, 4,
|
|
"F5", LFREG, 5,
|
|
"F6", LFREG, 6,
|
|
"F7", LFREG, 7,
|
|
"F8", LFREG, 8,
|
|
"F9", LFREG, 9,
|
|
"F10", LFREG, 10,
|
|
"F11", LFREG, 11,
|
|
"F12", LFREG, 12,
|
|
"F13", LFREG, 13,
|
|
"F14", LFREG, 14,
|
|
"F15", LFREG, 15,
|
|
"F16", LFREG, 16,
|
|
"F17", LFREG, 17,
|
|
"F18", LFREG, 18,
|
|
"F19", LFREG, 19,
|
|
"F20", LFREG, 20,
|
|
"F21", LFREG, 21,
|
|
"F22", LFREG, 22,
|
|
"F23", LFREG, 23,
|
|
"F24", LFREG, 24,
|
|
"F25", LFREG, 25,
|
|
"F26", LFREG, 26,
|
|
"F27", LFREG, 27,
|
|
"F28", LFREG, 28,
|
|
"F29", LFREG, 29,
|
|
"F30", LFREG, 30,
|
|
"F31", LFREG, 31,
|
|
|
|
"FCR", LFCR, 0,
|
|
"FCR0", LFCREG, 0,
|
|
"FCR1", LFCREG, 1,
|
|
"FCR2", LFCREG, 2,
|
|
"FCR3", LFCREG, 3,
|
|
"FCR4", LFCREG, 4,
|
|
"FCR5", LFCREG, 5,
|
|
"FCR6", LFCREG, 6,
|
|
"FCR7", LFCREG, 7,
|
|
"FCR8", LFCREG, 8,
|
|
"FCR9", LFCREG, 9,
|
|
"FCR10", LFCREG, 10,
|
|
"FCR11", LFCREG, 11,
|
|
"FCR12", LFCREG, 12,
|
|
"FCR13", LFCREG, 13,
|
|
"FCR14", LFCREG, 14,
|
|
"FCR15", LFCREG, 15,
|
|
"FCR16", LFCREG, 16,
|
|
"FCR17", LFCREG, 17,
|
|
"FCR18", LFCREG, 18,
|
|
"FCR19", LFCREG, 19,
|
|
"FCR20", LFCREG, 20,
|
|
"FCR21", LFCREG, 21,
|
|
"FCR22", LFCREG, 22,
|
|
"FCR23", LFCREG, 23,
|
|
"FCR24", LFCREG, 24,
|
|
"FCR25", LFCREG, 25,
|
|
"FCR26", LFCREG, 26,
|
|
"FCR27", LFCREG, 27,
|
|
"FCR28", LFCREG, 28,
|
|
"FCR29", LFCREG, 29,
|
|
"FCR30", LFCREG, 30,
|
|
"FCR31", LFCREG, 31,
|
|
|
|
"ADD", LTYPE1, AADD,
|
|
"ADDU", LTYPE1, AADDU,
|
|
"SUB", LTYPE1, ASUB, /* converted to ADD(-) in loader */
|
|
"SUBU", LTYPE1, ASUBU,
|
|
"SGT", LTYPE1, ASGT,
|
|
"SGTU", LTYPE1, ASGTU,
|
|
"AND", LTYPE1, AAND,
|
|
"OR", LTYPE1, AOR,
|
|
"XOR", LTYPE1, AXOR,
|
|
"SLL", LTYPE1, ASLL,
|
|
"SRL", LTYPE1, ASRL,
|
|
"SRA", LTYPE1, ASRA,
|
|
|
|
"ADDV", LTYPE1, AADDV,
|
|
"ADDVU", LTYPE1, AADDVU,
|
|
"SUBV", LTYPE1, ASUBV, /* converted to ADD(-) in loader */
|
|
"SUBVU", LTYPE1, ASUBVU,
|
|
"SLLV", LTYPE1, ASLLV,
|
|
"SRLV", LTYPE1, ASRLV,
|
|
"SRAV", LTYPE1, ASRAV,
|
|
|
|
"NOR", LTYPE2, ANOR,
|
|
|
|
"MOVB", LTYPE3, AMOVB,
|
|
"MOVBU", LTYPE3, AMOVBU,
|
|
"MOVH", LTYPE3, AMOVH,
|
|
"MOVHU", LTYPE3, AMOVHU,
|
|
"MOVWL", LTYPE3, AMOVWL,
|
|
"MOVWR", LTYPE3, AMOVWR,
|
|
"MOVVL", LTYPE3, AMOVVL,
|
|
"MOVVR", LTYPE3, AMOVVR,
|
|
|
|
"BREAK", LTYPEJ, ABREAK, /* overloaded CACHE opcode */
|
|
"END", LTYPE4, AEND,
|
|
"REM", LTYPE6, AREM,
|
|
"REMU", LTYPE6, AREMU,
|
|
"RET", LTYPE4, ARET,
|
|
"SYSCALL", LTYPE4, ASYSCALL,
|
|
"TLBP", LTYPE4, ATLBP,
|
|
"TLBR", LTYPE4, ATLBR,
|
|
"TLBWI", LTYPE4, ATLBWI,
|
|
"TLBWR", LTYPE4, ATLBWR,
|
|
|
|
"MOVW", LTYPE5, AMOVW,
|
|
"MOVV", LTYPE5, AMOVV,
|
|
"MOVD", LTYPE5, AMOVD,
|
|
"MOVF", LTYPE5, AMOVF,
|
|
|
|
"DIV", LTYPE6, ADIV,
|
|
"DIVU", LTYPE6, ADIVU,
|
|
"MUL", LTYPE6, AMUL,
|
|
"MULU", LTYPE6, AMULU,
|
|
"DIVV", LTYPE6, ADIVV,
|
|
"DIVVU", LTYPE6, ADIVVU,
|
|
"MULV", LTYPE6, AMULV,
|
|
"MULVU", LTYPE6, AMULVU,
|
|
|
|
"RFE", LTYPE7, ARFE,
|
|
"JMP", LTYPE7, AJMP,
|
|
|
|
"JAL", LTYPE8, AJAL,
|
|
|
|
"BEQ", LTYPE9, ABEQ,
|
|
"BNE", LTYPE9, ABNE,
|
|
|
|
"BGEZ", LTYPEA, ABGEZ,
|
|
"BGEZAL", LTYPEA, ABGEZAL,
|
|
"BGTZ", LTYPEA, ABGTZ,
|
|
"BLEZ", LTYPEA, ABLEZ,
|
|
"BLTZ", LTYPEA, ABLTZ,
|
|
"BLTZAL", LTYPEA, ABLTZAL,
|
|
|
|
"TEXT", LTYPEB, ATEXT,
|
|
"GLOBL", LTYPEB, AGLOBL,
|
|
|
|
"DATA", LTYPEC, ADATA,
|
|
|
|
"MOVDF", LTYPE5, AMOVDF,
|
|
"MOVDW", LTYPE5, AMOVDW,
|
|
"MOVFD", LTYPE5, AMOVFD,
|
|
"MOVFW", LTYPE5, AMOVFW,
|
|
"MOVWD", LTYPE5, AMOVWD,
|
|
"MOVWF", LTYPE5, AMOVWF,
|
|
|
|
"ABSD", LTYPED, AABSD,
|
|
"ABSF", LTYPED, AABSF,
|
|
"ABSW", LTYPED, AABSW,
|
|
"NEGD", LTYPED, ANEGD,
|
|
"NEGF", LTYPED, ANEGF,
|
|
"NEGW", LTYPED, ANEGW,
|
|
|
|
"CMPEQD", LTYPEF, ACMPEQD,
|
|
"CMPEQF", LTYPEF, ACMPEQF,
|
|
"CMPGED", LTYPEF, ACMPGED,
|
|
"CMPGEF", LTYPEF, ACMPGEF,
|
|
"CMPGTD", LTYPEF, ACMPGTD,
|
|
"CMPGTF", LTYPEF, ACMPGTF,
|
|
|
|
"ADDD", LTYPEE, AADDD,
|
|
"ADDF", LTYPEE, AADDF,
|
|
"ADDW", LTYPEE, AADDW,
|
|
"DIVD", LTYPEE, ADIVD,
|
|
"DIVF", LTYPEE, ADIVF,
|
|
"DIVW", LTYPEE, ADIVW,
|
|
"MULD", LTYPEE, AMULD,
|
|
"MULF", LTYPEE, AMULF,
|
|
"MULW", LTYPEE, AMULW,
|
|
"SUBD", LTYPEE, ASUBD,
|
|
"SUBF", LTYPEE, ASUBF,
|
|
"SUBW", LTYPEE, ASUBW,
|
|
|
|
"BFPT", LTYPEG, ABFPT,
|
|
"BFPF", LTYPEG, ABFPF,
|
|
|
|
"WORD", LTYPEH, AWORD,
|
|
"NOP", LTYPEI, ANOP,
|
|
"SCHED", LSCHED, 0,
|
|
"NOSCHED", LSCHED, 0x80,
|
|
0
|
|
};
|
|
|
|
void
|
|
cinit(void)
|
|
{
|
|
Sym *s;
|
|
int i;
|
|
|
|
nullgen.sym = S;
|
|
nullgen.offset = 0;
|
|
nullgen.type = D_NONE;
|
|
nullgen.name = D_NONE;
|
|
nullgen.reg = NREG;
|
|
if(FPCHIP)
|
|
nullgen.dval = 0;
|
|
for(i=0; i<sizeof(nullgen.sval); i++)
|
|
nullgen.sval[i] = 0;
|
|
|
|
nerrors = 0;
|
|
iostack = I;
|
|
iofree = I;
|
|
peekc = IGN;
|
|
for(i=0; i<NHASH; i++)
|
|
hash[i] = S;
|
|
for(i=0; itab[i].name; i++) {
|
|
s = slookup(itab[i].name);
|
|
s->type = itab[i].type;
|
|
s->value = itab[i].value;
|
|
}
|
|
|
|
pathname = allocn(pathname, 0, 100);
|
|
if(mygetwd(pathname, 99) == 0) {
|
|
pathname = allocn(pathname, 100, 900);
|
|
if(mygetwd(pathname, 999) == 0)
|
|
strcpy(pathname, "/???");
|
|
}
|
|
}
|
|
|
|
void
|
|
syminit(Sym *s)
|
|
{
|
|
|
|
s->type = LNAME;
|
|
s->value = 0;
|
|
}
|
|
|
|
int
|
|
isreg(Gen *g)
|
|
{
|
|
|
|
USED(g);
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
cclean(void)
|
|
{
|
|
|
|
outcode(AEND, &nullgen, NREG, &nullgen);
|
|
Bflush(&obuf);
|
|
}
|
|
|
|
void
|
|
zname(char *n, int t, int s)
|
|
{
|
|
|
|
Bputc(&obuf, ANAME);
|
|
Bputc(&obuf, t); /* type */
|
|
Bputc(&obuf, s); /* sym */
|
|
while(*n) {
|
|
Bputc(&obuf, *n);
|
|
n++;
|
|
}
|
|
Bputc(&obuf, 0);
|
|
}
|
|
|
|
void
|
|
zaddr(Gen *a, int s)
|
|
{
|
|
long l;
|
|
int i;
|
|
char *n;
|
|
Ieee e;
|
|
|
|
Bputc(&obuf, a->type);
|
|
Bputc(&obuf, a->reg);
|
|
Bputc(&obuf, s);
|
|
Bputc(&obuf, a->name);
|
|
switch(a->type) {
|
|
default:
|
|
print("unknown type %d\n", a->type);
|
|
exits("arg");
|
|
|
|
case D_NONE:
|
|
case D_REG:
|
|
case D_FREG:
|
|
case D_MREG:
|
|
case D_FCREG:
|
|
case D_LO:
|
|
case D_HI:
|
|
break;
|
|
|
|
case D_OREG:
|
|
case D_CONST:
|
|
case D_OCONST:
|
|
case D_BRANCH:
|
|
l = a->offset;
|
|
Bputc(&obuf, l);
|
|
Bputc(&obuf, l>>8);
|
|
Bputc(&obuf, l>>16);
|
|
Bputc(&obuf, l>>24);
|
|
break;
|
|
|
|
case D_SCONST:
|
|
n = a->sval;
|
|
for(i=0; i<NSNAME; i++) {
|
|
Bputc(&obuf, *n);
|
|
n++;
|
|
}
|
|
break;
|
|
|
|
case D_FCONST:
|
|
ieeedtod(&e, a->dval);
|
|
Bputc(&obuf, e.l);
|
|
Bputc(&obuf, e.l>>8);
|
|
Bputc(&obuf, e.l>>16);
|
|
Bputc(&obuf, e.l>>24);
|
|
Bputc(&obuf, e.h);
|
|
Bputc(&obuf, e.h>>8);
|
|
Bputc(&obuf, e.h>>16);
|
|
Bputc(&obuf, e.h>>24);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
outcode(int a, Gen *g1, int reg, Gen *g2)
|
|
{
|
|
int sf, st, t;
|
|
Sym *s;
|
|
|
|
if(pass == 1)
|
|
goto out;
|
|
jackpot:
|
|
sf = 0;
|
|
s = g1->sym;
|
|
while(s != S) {
|
|
sf = s->sym;
|
|
if(sf < 0 || sf >= NSYM)
|
|
sf = 0;
|
|
t = g1->name;
|
|
if(h[sf].type == t)
|
|
if(h[sf].sym == s)
|
|
break;
|
|
zname(s->name, t, sym);
|
|
s->sym = sym;
|
|
h[sym].sym = s;
|
|
h[sym].type = t;
|
|
sf = sym;
|
|
sym++;
|
|
if(sym >= NSYM)
|
|
sym = 1;
|
|
break;
|
|
}
|
|
st = 0;
|
|
s = g2->sym;
|
|
while(s != S) {
|
|
st = s->sym;
|
|
if(st < 0 || st >= NSYM)
|
|
st = 0;
|
|
t = g2->name;
|
|
if(h[st].type == t)
|
|
if(h[st].sym == s)
|
|
break;
|
|
zname(s->name, t, sym);
|
|
s->sym = sym;
|
|
h[sym].sym = s;
|
|
h[sym].type = t;
|
|
st = sym;
|
|
sym++;
|
|
if(sym >= NSYM)
|
|
sym = 1;
|
|
if(st == sf)
|
|
goto jackpot;
|
|
break;
|
|
}
|
|
Bputc(&obuf, a);
|
|
Bputc(&obuf, reg|nosched);
|
|
Bputc(&obuf, lineno);
|
|
Bputc(&obuf, lineno>>8);
|
|
Bputc(&obuf, lineno>>16);
|
|
Bputc(&obuf, lineno>>24);
|
|
zaddr(g1, sf);
|
|
zaddr(g2, st);
|
|
|
|
out:
|
|
if(a != AGLOBL && a != ADATA)
|
|
pc++;
|
|
}
|
|
|
|
void
|
|
outhist(void)
|
|
{
|
|
Gen g;
|
|
Hist *h;
|
|
char *p, *q, *op, c;
|
|
int n;
|
|
|
|
g = nullgen;
|
|
c = pathchar();
|
|
for(h = hist; h != H; h = h->link) {
|
|
p = h->name;
|
|
op = 0;
|
|
/* on windows skip drive specifier in pathname */
|
|
if(systemtype(Windows) && p && p[1] == ':'){
|
|
p += 2;
|
|
c = *p;
|
|
}
|
|
if(p && p[0] != c && h->offset == 0 && pathname){
|
|
/* on windows skip drive specifier in pathname */
|
|
if(systemtype(Windows) && pathname[1] == ':') {
|
|
op = p;
|
|
p = pathname+2;
|
|
c = *p;
|
|
} else if(pathname[0] == c){
|
|
op = p;
|
|
p = pathname;
|
|
}
|
|
}
|
|
while(p) {
|
|
q = strchr(p, c);
|
|
if(q) {
|
|
n = q-p;
|
|
if(n == 0){
|
|
n = 1; /* leading "/" */
|
|
*p = '/'; /* don't emit "\" on windows */
|
|
}
|
|
q++;
|
|
} else {
|
|
n = strlen(p);
|
|
q = 0;
|
|
}
|
|
if(n) {
|
|
Bputc(&obuf, ANAME);
|
|
Bputc(&obuf, D_FILE); /* type */
|
|
Bputc(&obuf, 1); /* sym */
|
|
Bputc(&obuf, '<');
|
|
Bwrite(&obuf, p, n);
|
|
Bputc(&obuf, 0);
|
|
}
|
|
p = q;
|
|
if(p == 0 && op) {
|
|
p = op;
|
|
op = 0;
|
|
}
|
|
}
|
|
g.offset = h->offset;
|
|
|
|
Bputc(&obuf, AHISTORY);
|
|
Bputc(&obuf, 0);
|
|
Bputc(&obuf, h->line);
|
|
Bputc(&obuf, h->line>>8);
|
|
Bputc(&obuf, h->line>>16);
|
|
Bputc(&obuf, h->line>>24);
|
|
zaddr(&nullgen, 0);
|
|
zaddr(&g, 0);
|
|
}
|
|
}
|
|
|
|
#include "../cc/lexbody"
|
|
#include "../cc/macbody"
|
|
#include "../cc/compat"
|