diff options
Diffstat (limited to 'bcc/output.c')
-rw-r--r-- | bcc/output.c | 813 |
1 files changed, 813 insertions, 0 deletions
diff --git a/bcc/output.c b/bcc/output.c new file mode 100644 index 0000000..c44ea3f --- /dev/null +++ b/bcc/output.c @@ -0,0 +1,813 @@ +/* output.c - output and error handling for bcc */ + +/* Copyright (C) 1992 Bruce Evans */ + +#include "const.h" +#include "types.h" +#include "input.h" +#include "os.h" +#include "sizes.h" +#include "table.h" + +#undef EXTERN +#define EXTERN +#include "output.h" + +#ifdef XENIX_AS +# define HEXSTARTCHAR '/' +#else +# define HEXSTARTCHAR '$' +#endif +#define OUTBUFSIZE 2048 +#define opcodeleadin() /* outtab() for fussy assemblers */ + +PRIVATE unsigned errcount; /* # errors in compilation */ + /* depends on zero init */ +PRIVATE char hexdigits[] = "0123456789ABCDEF"; +PRIVATE char *outbuf; +EXTERN char *outbufend; /* end of pair of output buffers */ +PRIVATE char *outbufmid; +PRIVATE fd_t output; +PRIVATE fastin_t outstage; /* depends on zero init */ + +FORWARD void errorsummary P((void)); +FORWARD void errsum1 P((void)); +#ifdef MC6809 +#ifdef DEBUG +FORWARD void outvaldigs P((uvalue_t num)); +#endif +#endif + +PUBLIC void bugerror(message) +char *message; +{ + error2error("compiler bug - ", message); +} + +PUBLIC void closeout() +{ + char *saveoutptr; + + if (outstage == 3) + { + saveoutptr = outbufptr; + flushout(); /* buffer from last stage */ + outbufptr = saveoutptr; + } + outstage = 0; /* flush from top to current ptr */ + flushout(); + close(output); +} + +/* error handler */ + +PUBLIC void error(message) +char *message; +{ + error2error(message, ""); +} + +/* error handler - concatenate 2 messages */ + +PUBLIC void error2error(message1, message2) +char *message1; +char *message2; +{ + char *warning; + + if (message1[0] == '%' && message1[1] == 'w') + { + message1 += 2; + warning = "warning: "; + } + else + { + ++errcount; + warning = "error: "; + } + if (output != 1) + { + char *old_outbuf; + char *old_outbufptr; + char *old_outbuftop; + fd_t old_output; + fastin_t old_outstage; + char smallbuf[81]; /* don't use heap - might be full or busy */ + + old_outbuf = outbuf; + old_outbufptr = outbufptr; + old_outbuftop = outbuftop; + old_output = output; + old_outstage = outstage; + + outbufptr = outbuf = &smallbuf[0]; + outbuftop = &smallbuf[sizeof smallbuf]; + output = 1; + outstage = 0; + errorloc(); + outstr(warning); + outstr(message1); + outstr(message2); + outnl(); + flushout(); + + outbuf = old_outbuf; + outbufptr = old_outbufptr; + outbuftop = old_outbuftop; + output = old_output; + outstage = old_outstage; + } + comment(); + errorloc(); + outstr(warning); + outstr(message1); + outstr(message2); + outnl(); +} + +/* summarise errors */ + +PRIVATE void errorsummary() +{ + if (errcount != 0) + { + outfail(); + errsum1(); + } + outnl(); + comment(); + errsum1(); +} + +PRIVATE void errsum1() +{ + outudec(errcount); + outnstr(" errors detected"); +} + +/* fatal error, exit early */ + +PUBLIC void fatalerror(message) +char *message; +{ + error(message); + finishup(); +} + +/* finish up compile */ + +PUBLIC void finishup() +{ + if (!cppmode) + { + if (watchlc) + { + cseg(); + outop0str("if *-.program.start-"); + outnhex(getlc()); + outfail(); + outnstr("phase error"); + outop0str("endif\n"); + } +#ifdef HOLDSTRINGS + dumpstrings(); +#endif + dumpglbs(); + errorsummary(); + } + closein(); + closeout(); + exit(errcount == 0 ? 0 : 1); +} + +/* flush output file */ + +PUBLIC void flushout() +{ + unsigned nbytes; + + switch (outstage) + { + case 0: + nbytes = (unsigned) (outbufptr - outbuf); + outbufptr = outbuf; + break; + case 2: + nbytes = OUTBUFSIZE; + outbufptr = outbuf; + outbuftop = outbufmid; + outstage = 3; + break; + default: + nbytes = OUTBUFSIZE; + if (outstage == 1) + nbytes = 0; + outbufptr = outbufmid; + outbuftop = outbufend; + outstage = 2; + break; + } + if (nbytes != 0) + { + if (!orig_cppmode) + clearlabels(outbufptr, outbufptr + nbytes); + if (write(output, outbufptr, nbytes) != nbytes) + { + write(2, "output file error\n", 18); + closein(); + close(output); + exit(1); + } + } +} + +PUBLIC void initout() +{ + static char smallbuf[1]; + + outbufend = outbuftop = (outbuf = outbufptr = smallbuf) + sizeof smallbuf; + output = 1; /* standard output */ +} + +PUBLIC void limiterror(message) +char *message; +{ + error2error("compiler limit exceeded - ", message); + finishup(); +} + +PUBLIC void openout(oname) +char *oname; +{ + if (output != 1) + fatalerror("more than one output file"); + if ((output = creat(oname, CREATPERMS)) < 0) + { + output = 1; + fatalerror("cannot open output"); + } +} + +/* print character */ + +PUBLIC void outbyte(c) +int c; +{ +#if C_CODE || __AS09__ + __AS386_16__ + __AS386_32__ != 1 + register char *outp; + + outp = outbufptr; + *outp++ = c; + outbufptr = outp; + if (outp >= outbuftop) + flushout(); +#else /* !C_CODE etc */ + +#if __AS09__ +# asm + TFR X,D + LDX _outbufptr,PC + STB ,X+ + STX _outbufptr,PC + CMPX _outbuftop,PC + LBHS CALL.FLUSHOUT +# endasm +#endif /* __AS09__ */ + +#if __AS386_16__ +# asm +# if !__FIRST_ARG_IN_AX__ + pop dx + pop ax + dec sp + dec sp +# else +# if ARGREG != DREG + xchg ax,bx +# endif +# endif + mov bx,[_outbufptr] + mov [bx],al + inc bx + mov [_outbufptr],bx + cmp bx,[_outbuftop] + jae OUTBYTE.FLUSH +# if !__FIRST_ARG_IN_AX__ + jmp dx +# else + ret +# endif + +OUTBYTE.FLUSH: +# if !__FIRST_ARG_IN_AX__ + push dx +# endif + br _flushout +# endasm +#endif /* __AS386_16__ */ + +#if __AS386_32__ +# asm +# if !__FIRST_ARG_IN_AX__ + mov eax,_outbyte.c[esp] +# else +# if ARGREG != DREG + xchg eax,ebx +# endif +# endif + mov ecx,[_outbufptr] + mov [ecx],al + inc ecx + mov [_outbufptr],ecx + cmp ecx,[_outbuftop] + jae OUTBYTE.FLUSH + ret + +OUTBYTE.FLUSH: + br _flushout +# endasm +#endif /* __AS386_32__ */ +#endif /* C_CODE etc */ +} + +/* print comma */ + +PUBLIC void outcomma() +{ + outbyte(','); +} + +/* print line number in format ("# %u \"%s\"%s", nr, fname, str) */ + +PUBLIC void outcpplinenumber(nr, fname, str) +unsigned nr; +char *fname; +char *str; +{ + outstr("# "); + outudec(nr); + outstr(" \""); + outstr(fname); + outstr("\""); + outnstr(str); +} + +/* print unsigned offset, hex format */ + +PUBLIC void outhex(num) +uoffset_t num; +{ +#ifdef HEXSTARTCHAR + if (num >= 10) + outbyte(HEXSTARTCHAR); +#endif + outhexdigs(num); +#ifdef HEXENDCHAR + if (num >= 10) + outbyte(HEXENDCHAR); +#endif +} + +/* print unsigned offset, hex format with digits only (no hex designator) */ + +PUBLIC void outhexdigs(num) +register uoffset_t num; +{ + if (num >= 0x10) + { + outhexdigs(num / 0x10); + num %= 0x10; + } + outbyte(hexdigits[(int) num]); +} + +/* print string terminated by EOL */ + +PUBLIC void outline(s) +char *s; +{ + register char *outp; + register char *rs; + + outp = outbufptr; + rs = s; +#ifdef COEOL + if (*rs == COEOL) + ++rs; +#endif + do + { + *outp++ = *rs; + if (outp >= outbuftop) + { + outbufptr = outp; + flushout(); + outp = outbufptr; + } + } + while (*rs++ != EOL); + outbufptr = outp; +#ifdef COEOL + if (*rs == COEOL) + outbyte(COEOL); +#endif +} + +/* print minus sign */ + +PUBLIC void outminus() +{ + outbyte('-'); +} + +/* print character, then newline */ + +PUBLIC void outnbyte(byte) +int byte; +{ + outbyte(byte); + outnl(); +} + +/* print unsigned offset, hex format, then newline */ + +PUBLIC void outnhex(num) +uoffset_t num; +{ + outhex(num); + outnl(); +} + +/* print newline */ + +PUBLIC void outnl() +{ + if (watchlc) + { + outtab(); + comment(); + outhex(getlc()); + } + outbyte('\n'); +} + +/* print opcode and newline, bump lc by 1 */ + +PUBLIC void outnop1str(s) +char *s; +{ + opcodeleadin(); + outstr(s); + bumplc(); + outnl(); +} + +/* print opcode and newline, bump lc by 2 */ + +PUBLIC void outnop2str(s) +char *s; +{ + opcodeleadin(); + outstr(s); + bumplc2(); + outnl(); +} + +/* print string, then newline */ + +PUBLIC void outnstr(s) +char *s; +{ + outstr(s); + outnl(); +} + +/* print opcode */ + +PUBLIC void outop0str(s) +char *s; +{ + opcodeleadin(); + outstr(s); +} + +/* print opcode, bump lc by 1 */ + +PUBLIC void outop1str(s) +char *s; +{ + opcodeleadin(); + outstr(s); + bumplc(); +} + +/* print opcode, bump lc by 2 */ + +PUBLIC void outop2str(s) +char *s; +{ + opcodeleadin(); + outstr(s); + bumplc2(); +} + +/* print opcode, bump lc by 3 */ + +PUBLIC void outop3str(s) +char *s; +{ + opcodeleadin(); + outstr(s); + bumplc3(); +} + +/* print plus sign */ + +PUBLIC void outplus() +{ + outbyte('+'); +} + +/* print signed offset, hex format */ + +PUBLIC void outshex(num) +offset_t num; +{ + if (num >= -(maxoffsetto + 1)) + { + outminus(); + num = -num; + } + outhex((uoffset_t) num); +} + +/* print string */ + +PUBLIC void outstr(s) +char *s; +{ +#if C_CODE || __AS09__ + __AS386_16__ + __AS386_32__ != 1 + register char *outp; + register char *rs; + + outp = outbufptr; + rs = s; + while (*rs) + { + *outp++ = *rs++; + if (outp >= outbuftop) + { + outbufptr = outp; + flushout(); + outp = outbufptr; + } + } + outbufptr = outp; +#else /* !C_CODE etc */ + +#if __AS09__ +# asm + LEAU ,X + LDX _outbuftop,PC + PSHS X + LDX _outbufptr,PC + BRA OUTSTR.NEXT + +CALL.FLUSHOUT + PSHS U,B + STX _outbufptr,PC + LBSR _flushout + LDX _outbufptr,PC + LDY _outbuftop,PC + PULS B,U,PC + +OUTSTR.LOOP + STB ,X+ + CMPX ,S + BLO OUTSTR.NEXT + BSR CALL.FLUSHOUT + STY ,S +OUTSTR.NEXT + LDB ,U+ + BNE OUTSTR.LOOP + STX _outbufptr,PC + LEAS 2,S +# endasm +#endif /* __AS09__ */ + +#if __AS386_16__ +# asm +# if !__CALLER_SAVES__ + mov dx,di + mov cx,si +# endif +# if !__FIRST_ARG_IN_AX__ + pop ax + pop si + dec sp + dec sp + push ax +# else +# if ARGREG == DREG + xchg si,ax +# else + mov si,bx +# endif +# endif + mov di,[_outbufptr] + mov bx,[_outbuftop] + br OUTSTR.NEXT + +CALL.FLUSHOUT: + push si +# if !__CALLER_SAVES__ + push dx + push cx +# endif + push ax + mov [_outbufptr],di + call _flushout + mov di,[_outbufptr] + mov bx,[_outbuftop] + pop ax +# if !__CALLER_SAVES__ + pop cx + pop dx +#endif + pop si + ret + +OUTSTR.LOOP: + stosb + cmp di,bx + jb OUTSTR.NEXT + call CALL.FLUSHOUT +OUTSTR.NEXT: + lodsb + test al,al + jne OUTSTR.LOOP + mov [_outbufptr],di +# if !__CALLER_SAVES__ + mov si,cx + mov di,dx +# endif +# endasm +#endif /* __AS386_16__ */ + +#if __AS386_32__ +# asm +# if !__CALLER_SAVES__ + mov edx,edi + push esi +# define TEMPS 4 +# else +# define TEMPS 0 +# endif +# if !__FIRST_ARG_IN_AX__ + mov esi,TEMPS+_outstr.s[esp] +# else +# if ARGREG == DREG + xchg esi,eax +# else + mov esi,ebx +# endif +# endif + mov edi,[_outbufptr] + mov ecx,[_outbuftop] + br OUTSTR.NEXT + +CALL.FLUSHOUT: + push esi +# if !__CALLER_SAVES__ + push edx +# endif + push eax + mov [_outbufptr],edi + call _flushout + mov edi,[_outbufptr] + mov ecx,[_outbuftop] + pop eax +# if !__CALLER_SAVES__ + pop edx +# endif + pop esi + ret + +OUTSTR.LOOP: + stosb + cmp edi,ecx + jb OUTSTR.NEXT + call CALL.FLUSHOUT +OUTSTR.NEXT: + lodsb + test al,al + jne OUTSTR.LOOP + mov [_outbufptr],edi +# if !__CALLER_SAVES__ + pop esi + mov edi,edx +# endif +# endasm +#endif /* __AS386_32__ */ +#endif /* C_CODE etc */ +} + +/* print tab */ + +PUBLIC void outtab() +{ + outbyte('\t'); +} + +/* print unsigned, decimal format */ + +PUBLIC void outudec(num) +unsigned num; +{ + char str[10 + 1]; + + str[sizeof str - 1] = 0; + outstr(pushudec(str + sizeof str - 1, num)); +} + +#ifdef MC6809 +#ifdef DEBUG + +/* print unsigned value, hex format (like outhex except value_t is larger) */ + +PUBLIC void outuvalue(num) +uvalue_t num; +{ +#ifdef HEXSTARTCHAR + if (num >= 10) + outbyte(HEXSTARTCHAR); +#endif + outvaldigs(num); +#ifdef HEXENDCHAR + if (num >= 10) + outbyte(HEXENDCHAR); +#endif +} + +/* print unsigned value, hex format with digits only (no hex designator) */ + +PRIVATE void outvaldigs(num) +register uvalue_t num; +{ + if (num >= 0x10) + { + outvaldigs(num / 0x10); + num %= 0x10; + } + outbyte(hexdigits[(fastin_t) num]); +} + +/* print signed value, hex format (like outshex except value_t is larger) */ + +PUBLIC void outvalue(num) +register value_t num; +{ + if (num < 0) + { + outminus(); + num = -num; + } + outuvalue((uoffset_t) num); +} + +#endif /* DEBUG */ +#endif /* MC6809 */ + +/* push decimal digits of an unsigned onto a stack of chars */ + +PUBLIC char *pushudec(s, num) +register char *s; +register unsigned num; +{ + register unsigned reduction; + + while (num >= 10) + { + reduction = num / 10; + *--s = num - 10 * reduction + '0'; + num = reduction; + } + *--s = num + '0'; + return s; +} + +PUBLIC void setoutbufs() +{ + if (!isatty(output)) + { + outbufptr = outbuf = ourmalloc(2 * OUTBUFSIZE); +#ifdef TS +ts_s_outputbuf += 2 * OUTBUFSIZE; +#endif + outbufmid = outbuftop = outbufptr + OUTBUFSIZE; + outbufend = outbufmid + OUTBUFSIZE; + outstage = 1; + } + if (watchlc) + outnstr(".program.start:\n"); /* kludge temp label */ +} |