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