1 /* genlist.c - generate listing and error reports for assembler */
2 
3 #include "syshead.h"
4 #include "const.h"
5 #include "type.h"
6 #include "address.h"
7 #include "flag.h"
8 #include "file.h"
9 #include "globvar.h"
10 #include "macro.h"
11 #include "scan.h"
12 #include "source.h"
13 
14 #define CODE_LIST_LENGTH (sizeof (struct code_listing_s) - 1)
15 				/* length of formatted code listing */
16 #define MAXERR 6		/* maximum errors listed per line */
17 
18 struct error_s			/* to record error info */
19 {
20     char * err_str;
21     unsigned char position;
22 };
23 
24 /* code listing format */
25 
26 struct code_listing_s
27 {
28     union linum_macro_u
29     {
30 	char linum[LINUM_LEN];
31 	struct
32 	{
33 	    char pad[1];
34 	    char mark[1];
35 	    char level[1];
36 	}
37 	 macro;
38     }
39      linum_or_macro;
40     char padlinum[1];
41     char lc[4];
42     char padlc[1];
43 #ifdef I80386
44     char lprefix[2];
45     char aprefix[2];
46     char oprefix[2];
47     char sprefix[2];
48 #endif
49     char page[2];
50     char opcode[2];
51     char postb[2];
52 #ifdef I80386
53     char sib[2];
54 #endif
55     char padopcode[1];
56 #if SIZEOF_OFFSET_T > 2
57     char displ4[2];
58     char displ3[2];
59 #endif
60     char displ2[2];
61     char displ1[2];
62     char reldispl[1];
63     char paddispl[1];
64 #ifdef I80386
65     char imm4[2];
66     char imm3[2];
67     char imm2[2];
68     char imm1[2];
69     char relimm[1];
70     char padimm[1];
71 #endif
72     char nullterm;
73 };
74 
75 PRIVATE struct error_s errbuf[MAXERR];	/* error buffer */
76 PRIVATE unsigned char errcount;	/* # errors in line */
77 PRIVATE bool_t erroverflow;	/* set if too many errors on line */
78 
79 FORWARD char *build_1hex_number P((opcode_pt num, char *where));
80 FORWARD void list1 P((fd_t fd));
81 FORWARD void listcode P((void));
82 FORWARD void listerrors P((void));
83 FORWARD void paderrorline P((unsigned nspaces));
84 
85 /* format 1 byte number as 2 hex digits, return ptr to end */
86 
build_1hex_number(num,where)87 PRIVATE char *build_1hex_number(num, where)
88 opcode_pt num;
89 register char *where;
90 {
91     where[0] = hexdigit[((unsigned) num % 256) / 16];
92     where[1] = hexdigit[(unsigned) num % 16];
93     return where + 2;
94 }
95 
96 /* format 2 byte number as 4 hex digits, return ptr to end */
97 
build_2hex_number(num,where)98 PUBLIC char *build_2hex_number(num, where)
99 unsigned num;
100 char *where;
101 {
102     return build_1hex_number((opcode_pt) num,
103 			     build_1hex_number((opcode_pt) (num / 256), where));
104 }
105 
106 /* format 2 byte number as decimal with given width (pad with leading '0's) */
107 /* return ptr to end */
108 
build_number(num,width,where)109 PUBLIC char *build_number(num, width, where)
110 unsigned num;
111 unsigned width;
112 register char *where;
113 {
114     static unsigned powers_of_10[] = {1, 10, 100, 1000, 10000,};
115     unsigned char digit;
116     unsigned char power;
117     register unsigned power_of_10;
118 
119     power = 5;			/* actually 1 more than power */
120     do
121     {
122 	for (digit = '0', power_of_10 = powers_of_10[power - 1];
123 	     num >= power_of_10; num -= power_of_10)
124 	    ++digit;
125 	if (power <= width)
126 	    *where++ = digit;
127     }
128     while (--power != 0);
129     return where;
130 }
131 
132 /* record number and position of error (or error buffer overflow) */
133 
warning(err_str)134 PUBLIC void warning(err_str)
135 char * err_str;
136 {
137     if (!as_warn.current) return;
138     ++totwarn;
139     --toterr;
140     error(err_str);
141 }
142 
error(err_str)143 PUBLIC void error(err_str)
144 char * err_str;
145 {
146     register struct error_s *errptr;
147     register struct error_s *errptrlow;
148     unsigned char position;
149 
150     if (errcount >= MAXERR)
151 	erroverflow = TRUE;
152     else
153     {
154 	position = symname - linebuf;
155 	for (errptr = errbuf + errcount;
156 	     errptr > errbuf && errptr->position > position;
157 	     errptr = errptrlow)
158 	{
159 	    errptrlow = errptr - 1;
160 	    errptr->err_str = errptrlow->err_str;
161 	    errptr->position = errptrlow->position;
162 	}
163 	errptr->err_str = err_str;
164 	errptr->position = position;
165 	++errcount;
166 	++toterr;
167     }
168 }
169 
170 /* list 1 line to list file if any errors or flags permit */
171 /* list line to console as well if any errors and list file is not console */
172 
listline()173 PUBLIC void listline()
174 {
175     if (!listpre && lineptr != 0)
176     {
177 	if (errcount || (list.current && (!macflag || mcount != 0)) ||
178 	    (macflag && maclist.current) || list_force )
179 	    list1(lstfil);
180 	if (errcount)
181 	{
182 	    if (lstfil != STDOUT)
183 		list1(STDOUT);
184 	    errcount = 0;
185 	    erroverflow = FALSE;
186 	}
187     }
188 }
189 
190 /* list 1 line unconditionally */
191 
list1(fd)192 PRIVATE void list1(fd)
193 fd_t fd;
194 {
195     outfd = fd;
196     listcode();
197     write(outfd, linebuf, (unsigned) (lineptr - linebuf));
198     writenl();
199     if (errcount != 0)
200 	listerrors();
201     listpre = TRUE;
202     list_force=FALSE;
203 }
204 
205 /* list object code for 1 line */
206 
listcode()207 PRIVATE void listcode()
208 {
209     unsigned char count;
210     struct code_listing_s *listptr;
211     unsigned numlength;
212     char *numptr;
213 
214     listptr = (struct code_listing_s *) temp_buf();
215     memset((char *) listptr, ' ', sizeof *listptr);
216     listptr->nullterm = 0;
217     if (macflag)
218     {
219 	listptr->linum_or_macro.macro.mark[0] = '+';
220 	listptr->linum_or_macro.macro.level[0] = maclevel + ('a' - 1);
221     }
222     else
223     {
224 	numlength = LINUM_LEN;
225 	numptr = listptr->linum_or_macro.linum;
226 	if (infiln != infil0)
227 	{
228 	    *numptr++ = infiln - infil0 + ('a' - 1);
229 	    numlength = LINUM_LEN - 1;
230 	}
231 	build_number(linum, numlength, numptr);
232     }
233     if ((count = mcount) != 0 || popflags & POPLC)
234 	build_2hex_number((u16_T) lc, listptr->lc);
235     if (popflags & POPLO)
236     {
237 #if SIZEOF_OFFSET_T > 2
238 	if (popflags & POPLONG)
239 	    build_2hex_number((u16_T) (lastexp.offset / (offset_t) 0x10000L),
240 			      listptr->displ4);
241 #endif
242 	if (popflags & POPHI)
243 	    build_2hex_number((u16_T) lastexp.offset, listptr->displ2);
244 	else
245 	    build_1hex_number((opcode_pt) /* XXX */(u16_T) lastexp.offset, listptr->displ1);
246 	if (lastexp.data & RELBIT)
247 	    listptr->reldispl[0] = '>';
248     }
249     else if (count != 0)
250     {
251 #ifdef I80386
252 	if (aprefix != 0)
253 	{
254 	    --count;
255 	    build_1hex_number(aprefix, listptr->aprefix);
256 	}
257 	if (oprefix != 0)
258 	{
259 	    --count;
260 	    build_1hex_number(oprefix, listptr->oprefix);
261 	}
262 	if (sprefix != 0)
263 	{
264 	    --count;
265 	    build_1hex_number(sprefix, listptr->sprefix);
266 	}
267 #endif
268 	if (page != 0)
269 	{
270 	    build_1hex_number(page, listptr->page);
271 	    --count;
272 	}
273 	build_1hex_number(opcode, listptr->opcode);
274 	--count;
275 	if (postb != 0)
276 	{
277 	    --count;
278 	    build_1hex_number(postb,
279 #ifdef MC6809
280 			      count == 0 ? listptr->displ1 :
281 #endif
282 			      listptr->postb);
283 	}
284 #ifdef I80386
285 	if (sib != NO_SIB)
286 	{
287 	    --count;
288 	    build_1hex_number(sib, listptr->sib);
289 	}
290 #endif
291 	if (count > 0)
292 	{
293 	    build_1hex_number((opcode_pt) lastexp.offset, listptr->displ1);
294 	    if (lastexp.data & RELBIT)
295 		listptr->reldispl[0] = '>';
296 	}
297 	if (count > 1)
298 	    build_1hex_number((opcode_pt) (lastexp.offset >> 0x8),
299 			      listptr->displ2);
300 #if SIZEOF_OFFSET_T > 2
301 	if (count > 2)
302 	{
303 	    build_1hex_number((opcode_pt) (lastexp.offset >> 0x10),
304 			      listptr->displ3);
305 	    build_1hex_number((opcode_pt) (lastexp.offset >> 0x18),
306 			      listptr->displ4);
307 	}
308 #endif
309 #ifdef I80386
310 	if (immcount > 0)
311 	{
312 	    build_1hex_number((opcode_pt) immadr.offset, listptr->imm1);
313 	    if (immadr.data & RELBIT)
314 		listptr->relimm[0] = '>';
315 	}
316 	if (immcount > 1)
317 	    build_1hex_number((opcode_pt) (immadr.offset >> 0x8),
318 			      listptr->imm2);
319 	if (immcount > 2)
320 	{
321 	    build_1hex_number((opcode_pt) (immadr.offset >> 0x10),
322 			      listptr->imm3);
323 	    build_1hex_number((opcode_pt) (immadr.offset >> 0x18),
324 			      listptr->imm4);
325 	}
326 #endif
327     }
328     writes((char *) listptr);
329 }
330 
331 /* list errors, assuming some */
332 
listerrors()333 PRIVATE void listerrors()
334 {
335     unsigned char column;
336     unsigned char errcol;	/* column # in error line */
337     unsigned char errcolw;	/* working column in error line */
338     char *errmsg;
339     struct error_s *errptr;
340     char *linep;
341     unsigned char remaining;
342 
343 #ifdef I80386
344     paderrorline(1);
345 #else
346     paderrorline(CODE_LIST_LENGTH - LINUM_LEN);
347 #endif
348     remaining = errcount;
349     column = 0;			/* column to match with error column */
350     errcolw = errcol = CODE_LIST_LENGTH; /* working & col number on err line */
351     errptr = errbuf;
352     linep = linebuf;
353     do
354     {
355 #ifdef I80386
356         if(errcol != CODE_LIST_LENGTH)
357 	{
358 	    writenl(); paderrorline(1);
359 	}
360 	writes(errmsg = errptr->err_str);
361 	errcol = strlen(errmsg)+LINUM_LEN+1;
362 	column = 0; linep = linebuf;
363         errcolw = CODE_LIST_LENGTH;
364 	while (errcolw > errcol)
365 	{
366 	    writec('.');
367 	    ++errcol;
368 	}
369 #endif
370 	while (errptr && errptr->position < 132 && column < errptr->position)
371 	{
372 	    ++column;
373 	    if (*linep++ == '\t')	/* next tab (standard tabs only) */
374 		errcolw = (errcolw + 8) & 0xf8;
375 	    else
376 		++errcolw;
377 	    while (errcolw > errcol)
378 	    {
379 #ifdef I80386
380 	        writec('.');
381 #else
382 		writec(' ');
383 #endif
384 		++errcol;
385 	    }
386 	}
387 #ifdef I80386
388 	writec('^'); ++errcol;
389 #else
390 	if (errcolw < errcol)	/* position under error on new line */
391 	{
392 	    writenl();
393 	    paderrorline((unsigned) errcolw - LINUM_LEN);
394 	}
395 	writec('^');
396 	writes(errmsg = errptr->err_str);
397 	errcol += strlen(errmsg);
398 #endif
399 	++errptr;
400     }
401     while (--remaining != 0);
402     writenl();
403     if (erroverflow)
404     {
405 #ifdef I80386
406 	paderrorline(1);
407 #else
408 	paderrorline(CODE_LIST_LENGTH - LINUM_LEN);
409 #endif
410 	writesn(FURTHER);
411     }
412 }
413 
414 /* pad out error line to begin under 1st char of source listing */
415 
paderrorline(nspaces)416 PRIVATE void paderrorline(nspaces)
417 unsigned nspaces;
418 {
419     int nstars = LINUM_LEN;
420 
421     while (nstars-- != 0)
422 	writec('*');		/* stars under line number */
423     while (nspaces-- != 0)
424 	writec(' ');		/* spaces out to error position */
425 }
426 
427 /* write 1 character */
428 
writec(ch)429 PUBLIC void writec(ch)
430 char ch;
431 {
432     write(outfd, &ch, 1);
433 }
434 
435 /* write newline */
436 
writenl()437 PUBLIC void writenl()
438 {
439     writes(SOS_EOLSTR);
440 }
441 
442 /* write 1 offset_t, order to suit target */
443 
writeoff(offset)444 PUBLIC void writeoff(offset)
445 offset_t offset;
446 {
447     char buf[sizeof offset];
448 
449 #if SIZEOF_OFFSET_T > 2
450     u4c4(buf, offset);
451 #else
452     u2c2(buf, offset);
453 #endif
454     write(outfd, buf, sizeof buf);
455 }
456 
457 /* write string */
458 
writes(s)459 PUBLIC void writes(s)
460 char *s;
461 {
462     write(outfd, s, strlen(s));
463 }
464 
465 /* write string followed by newline */
466 
writesn(s)467 PUBLIC void writesn(s)
468 char *s;
469 {
470     writes(s);
471     writenl();
472 }
473 
474 /* write 1 word, order to suit target */
475 
writew(word)476 PUBLIC void writew(word)
477 unsigned word;
478 {
479     char buf[2];
480 
481     u2c2(buf, (u16_T) word);
482     write(outfd, buf, sizeof buf);
483 }
484