/* genlist.c - generate listing and error reports for assembler */ #include "syshead.h" #include "const.h" #include "type.h" #include "address.h" #include "flag.h" #include "file.h" #include "globvar.h" #include "macro.h" #include "scan.h" #include "source.h" #define CODE_LIST_LENGTH (sizeof (struct code_listing_s) - 1) /* length of formatted code listing */ #define MAXERR 6 /* maximum errors listed per line */ struct error_s /* to record error info */ { char * err_str; unsigned char position; }; /* code listing format */ struct code_listing_s { union linum_macro_u { char linum[LINUM_LEN]; struct { char pad[1]; char mark[1]; char level[1]; } macro; } linum_or_macro; char padlinum[1]; char lc[4]; char padlc[1]; #ifdef I80386 char lprefix[2]; char aprefix[2]; char oprefix[2]; char sprefix[2]; #endif char page[2]; char opcode[2]; char postb[2]; #ifdef I80386 char sib[2]; #endif char padopcode[1]; #if SIZEOF_OFFSET_T > 2 char displ4[2]; char displ3[2]; #endif char displ2[2]; char displ1[2]; char reldispl[1]; char paddispl[1]; #ifdef I80386 char imm4[2]; char imm3[2]; char imm2[2]; char imm1[2]; char relimm[1]; char padimm[1]; #endif char nullterm; }; PRIVATE struct error_s errbuf[MAXERR]; /* error buffer */ PRIVATE unsigned char errcount; /* # errors in line */ PRIVATE bool_t erroverflow; /* set if too many errors on line */ FORWARD char *build_1hex_number P((opcode_pt num, char *where)); FORWARD void list1 P((fd_t fd)); FORWARD void listcode P((void)); FORWARD void listerrors P((void)); FORWARD void paderrorline P((unsigned nspaces)); /* format 1 byte number as 2 hex digits, return ptr to end */ PRIVATE char *build_1hex_number(num, where) opcode_pt num; register char *where; { where[0] = hexdigit[((unsigned) num % 256) / 16]; where[1] = hexdigit[(unsigned) num % 16]; return where + 2; } /* format 2 byte number as 4 hex digits, return ptr to end */ PUBLIC char *build_2hex_number(num, where) unsigned num; char *where; { return build_1hex_number((opcode_pt) num, build_1hex_number((opcode_pt) (num / 256), where)); } /* format 2 byte number as decimal with given width (pad with leading '0's) */ /* return ptr to end */ PUBLIC char *build_number(num, width, where) unsigned num; unsigned width; register char *where; { static unsigned powers_of_10[] = {1, 10, 100, 1000, 10000,}; unsigned char digit; unsigned char power; register unsigned power_of_10; power = 5; /* actually 1 more than power */ do { for (digit = '0', power_of_10 = (powers_of_10 - 1)[power]; num >= power_of_10; num -= power_of_10) ++digit; if (power <= width) *where++ = digit; } while (--power != 0); return where; } /* record number and position of error (or error buffer overflow) */ PUBLIC void warning(err_str) char * err_str; { if (!as_warn.current) return; ++totwarn; --toterr; error(err_str); } PUBLIC void error(err_str) char * err_str; { register struct error_s *errptr; register struct error_s *errptrlow; unsigned char position; if (errcount >= MAXERR) erroverflow = TRUE; else { position = symname - linebuf; for (errptr = errbuf + errcount; errptr > errbuf && errptr->position > position; errptr = errptrlow) { errptrlow = errptr - 1; errptr->err_str = errptrlow->err_str; errptr->position = errptrlow->position; } errptr->err_str = err_str; errptr->position = position; ++errcount; ++toterr; } } /* list 1 line to list file if any errors or flags permit */ /* list line to console as well if any errors and list file is not console */ PUBLIC void listline() { if (!listpre && lineptr != 0) { if (errcount || (list.current && (!macflag || mcount != 0)) || (macflag && maclist.current) || list_force ) list1(lstfil); if (errcount) { if (lstfil != STDOUT) list1(STDOUT); errcount = 0; erroverflow = FALSE; } } } /* list 1 line unconditionally */ PRIVATE void list1(fd) fd_t fd; { outfd = fd; listcode(); write(outfd, linebuf, (unsigned) (lineptr - linebuf)); writenl(); if (errcount != 0) listerrors(); listpre = TRUE; list_force=FALSE; } /* list object code for 1 line */ PRIVATE void listcode() { unsigned char count; struct code_listing_s *listptr; unsigned numlength; char *numptr; listptr = (struct code_listing_s *) temp_buf(); memset((char *) listptr, ' ', sizeof *listptr); listptr->nullterm = 0; if (macflag) { listptr->linum_or_macro.macro.mark[0] = '+'; listptr->linum_or_macro.macro.level[0] = maclevel + ('a' - 1); } else { numlength = LINUM_LEN; numptr = listptr->linum_or_macro.linum; if (infiln != infil0) { *numptr++ = infiln - infil0 + ('a' - 1); numlength = LINUM_LEN - 1; } build_number(linum, numlength, numptr); } if ((count = mcount) != 0 || popflags & POPLC) build_2hex_number((u16_T) lc, listptr->lc); if (popflags & POPLO) { #if SIZEOF_OFFSET_T > 2 if (popflags & POPLONG) build_2hex_number((u16_T) (lastexp.offset / (offset_t) 0x10000L), listptr->displ4); #endif if (popflags & POPHI) build_2hex_number((u16_T) lastexp.offset, listptr->displ2); else build_1hex_number((opcode_pt) /* XXX */(u16_T) lastexp.offset, listptr->displ1); if (lastexp.data & RELBIT) listptr->reldispl[0] = '>'; } else if (count != 0) { #ifdef I80386 if (aprefix != 0) { --count; build_1hex_number(aprefix, listptr->aprefix); } if (oprefix != 0) { --count; build_1hex_number(oprefix, listptr->oprefix); } if (sprefix != 0) { --count; build_1hex_number(sprefix, listptr->sprefix); } #endif if (page != 0) { build_1hex_number(page, listptr->page); --count; } build_1hex_number(opcode, listptr->opcode); --count; if (postb != 0) { --count; build_1hex_number(postb, #ifdef MC6809 count == 0 ? listptr->displ1 : #endif listptr->postb); } #ifdef I80386 if (sib != NO_SIB) { --count; build_1hex_number(sib, listptr->sib); } #endif if (count > 0) { build_1hex_number((opcode_pt) lastexp.offset, listptr->displ1); if (lastexp.data & RELBIT) listptr->reldispl[0] = '>'; } if (count > 1) build_1hex_number((opcode_pt) (lastexp.offset >> 0x8), listptr->displ2); #if SIZEOF_OFFSET_T > 2 if (count > 2) { build_1hex_number((opcode_pt) (lastexp.offset >> 0x10), listptr->displ3); build_1hex_number((opcode_pt) (lastexp.offset >> 0x18), listptr->displ4); } #endif #ifdef I80386 if (immcount > 0) { build_1hex_number((opcode_pt) immadr.offset, listptr->imm1); if (immadr.data & RELBIT) listptr->relimm[0] = '>'; } if (immcount > 1) build_1hex_number((opcode_pt) (immadr.offset >> 0x8), listptr->imm2); if (immcount > 2) { build_1hex_number((opcode_pt) (immadr.offset >> 0x10), listptr->imm3); build_1hex_number((opcode_pt) (immadr.offset >> 0x18), listptr->imm4); } #endif } writes((char *) listptr); } /* list errors, assuming some */ PRIVATE void listerrors() { unsigned char column; unsigned char errcol; /* column # in error line */ unsigned char errcolw; /* working column in error line */ char *errmsg; struct error_s *errptr; char *linep; unsigned char remaining; #ifdef I80386 paderrorline(1); #else paderrorline(CODE_LIST_LENGTH - LINUM_LEN); #endif remaining = errcount; column = 0; /* column to match with error column */ errcolw = errcol = CODE_LIST_LENGTH; /* working & col number on err line */ errptr = errbuf; linep = linebuf; do { #ifdef I80386 if(errcol != CODE_LIST_LENGTH) { writenl(); paderrorline(1); } writes(errmsg = errptr->err_str); errcol = strlen(errmsg)+LINUM_LEN+1; column = 0; linep = linebuf; errcolw = CODE_LIST_LENGTH; while (errcolw > errcol) { writec('.'); ++errcol; } #endif while (errptr && errptr->position < 132 && column < errptr->position) { ++column; if (*linep++ == '\t') /* next tab (standard tabs only) */ errcolw = (errcolw + 8) & 0xf8; else ++errcolw; while (errcolw > errcol) { #ifdef I80386 writec('.'); #else writec(' '); #endif ++errcol; } } #ifdef I80386 writec('^'); ++errcol; #else if (errcolw < errcol) /* position under error on new line */ { writenl(); paderrorline((unsigned) errcolw - LINUM_LEN); } writec('^'); writes(errmsg = errptr->err_str); errcol += strlen(errmsg); #endif ++errptr; } while (--remaining != 0); writenl(); if (erroverflow) { #ifdef I80386 paderrorline(1); #else paderrorline(CODE_LIST_LENGTH - LINUM_LEN); #endif writesn(FURTHER); } } /* pad out error line to begin under 1st char of source listing */ PRIVATE void paderrorline(nspaces) unsigned nspaces; { int nstars = LINUM_LEN; while (nstars-- != 0) writec('*'); /* stars under line number */ while (nspaces-- != 0) writec(' '); /* spaces out to error position */ } /* write 1 character */ PUBLIC void writec(ch) char ch; { write(outfd, &ch, 1); } /* write newline */ PUBLIC void writenl() { writes(SOS_EOLSTR); } /* write 1 offset_t, order to suit target */ PUBLIC void writeoff(offset) offset_t offset; { char buf[sizeof offset]; #if SIZEOF_OFFSET_T > 2 u4c4(buf, offset); #else u2c2(buf, offset); #endif write(outfd, buf, sizeof buf); } /* write string */ PUBLIC void writes(s) char *s; { write(outfd, s, strlen(s)); } /* write string followed by newline */ PUBLIC void writesn(s) char *s; { writes(s); writenl(); } /* write 1 word, order to suit target */ PUBLIC void writew(word) unsigned word; { char buf[2]; u2c2(buf, (u16_T) word); write(outfd, buf, sizeof buf); }