1 /* ======================================================================== */
2 /* EMITTERS: Functions that emit a record to the intermediate file. */
3 /* */
4 /* This file is an attempt to collect up all the functions that write to */
5 /* the intermediate file in one place, increasing the abstraction level. */
6 /* The goal is to eventually eliminate the intermediate file altogether, */
7 /* once all direct references to it have been removed. */
8 /* */
9 /* Initially, though, this will just be a series of functions that wrap */
10 /* the fprintf statements collected from elsewhere. */
11 /* ======================================================================== */
12
13 #include "config.h"
14 #include "as1600_types.h"
15 #include "lzoe/lzoe.h"
16 #include "file/file.h"
17 #include "frasmdat.h"
18 #include "fragcon.h"
19 #include "protos.h"
20 #include "intermed.h"
21 #include "memo_string.h"
22 /*#include "malloc.h"*/
23
24 /* ------------------------------------------------------------------------ */
25 /* Render buffer for emitters. */
26 /* ------------------------------------------------------------------------ */
27 static char *emit_buf = NULL;
28 static size_t eb_len = 0;
29
30 /* ------------------------------------------------------------------------ */
31 /* Replace intermediate file with in-memory list. */
32 /* ------------------------------------------------------------------------ */
33
34 static irec_union *irec_tbl = NULL;
35 static unsigned irec_head = 0, irec_tail = 0, irec_total = 0;
36 static unsigned irec_mask = 0;
37
38 /* ------------------------------------------------------------------------ */
39 /* ALLOC_IREC -- Allocate an intermediate record that's already */
40 /* appended to the list, but must be populated. */
41 /* ------------------------------------------------------------------------ */
alloc_irec(const irec_type type)42 static intermed_rec *alloc_irec(const irec_type type)
43 {
44 if (irec_tail - irec_head >= irec_total)
45 {
46 assert(irec_total < (1 << 29));
47 irec_total = irec_total ? (irec_total << 2) : (1 << 16);
48 irec_tbl = (irec_union *)realloc(irec_tbl,
49 irec_total * sizeof(irec_union));
50
51 irec_mask = irec_total - 1;
52 assert((irec_total & (irec_total - 1)) == 0);
53 assert(irec_tbl);
54 }
55
56 irec_union *const irec = &irec_tbl[irec_tail++ % irec_total];
57
58 irec->irec.type = type;
59 irec->irec.line = infilestk[currfstk].line;
60
61 return (intermed_rec *)irec;
62 }
63
64 #define GET_IREC(type,TYPE) type *irec = (type *)(void *)alloc_irec(TYPE)
65
66
67 /* ------------------------------------------------------------------------ */
68 /* EMIT_LISTING_MODE -- This changes the output listing display mode */
69 /* ------------------------------------------------------------------------ */
emit_listing_mode(const listing_mode m)70 void emit_listing_mode(const listing_mode m)
71 {
72 GET_IREC(irec_list_mode, REC_LIST_MODE);
73 irec->mode = m;
74 }
75
76 /* ------------------------------------------------------------------------ */
77 /* EMIT_SET_EQU -- Output value associated with a SET or EQU. */
78 /* ------------------------------------------------------------------------ */
emit_set_equ(const unsigned int value)79 void emit_set_equ(const unsigned int value)
80 {
81 GET_IREC(irec_set_equ, REC_SET_EQU);
82 irec->value = value;
83 }
84
85
86 /* ------------------------------------------------------------------------ */
87 /* EMIT_COMMENT -- Emit a comment either for SET/EQU or a user's */
88 /* CMSG/SMSG. */
89 /* ------------------------------------------------------------------------ */
emit_comment(const int is_user,const char * const format,...)90 void emit_comment(const int is_user, const char *const format, ...)
91 {
92 GET_IREC(irec_string, is_user ? REC_USER_COMMENT : REC_COMMENT);
93 va_list ap;
94
95 assert(emit_buf);
96
97 again:
98 va_start(ap, format);
99 vsnprintf(emit_buf, eb_len, format, ap);
100 va_end(ap);
101
102 if (eb_len < 65536 && strlen(emit_buf) >= eb_len - 1)
103 {
104 eb_len <<= 2;
105 emit_buf = (char *)realloc(emit_buf, eb_len);
106 goto again;
107 }
108
109 irec->string = memoize_string(emit_buf);
110 }
111
112 /* ------------------------------------------------------------------------ */
113 /* EMIT_LOCATION -- Establish the current address we're assembling */
114 /* at, and what sort of memory mode. */
115 /* ------------------------------------------------------------------------ */
emit_location(const int seg,const int pag,const int loc,const int type,const char * const mode)116 void emit_location(const int seg, const int pag, const int loc,
117 const int type, const char *const mode)
118 /*
119 description output to the intermediate file, a 'P' record
120 giving the current location counter. Segment
121 is not used at this time.
122 */
123 {
124 GET_IREC(irec_loc_set, REC_LOC_SET);
125
126 irec->seg = seg;
127 irec->pag = pag;
128 irec->loc = loc;
129 irec->type = type;
130 irec->mode = mode;
131 }
132
133 /* ------------------------------------------------------------------------ */
134 /* EMIT_MARK_WITH_MODE -- Mark addresses lo to hi with a given mode. */
135 /* ------------------------------------------------------------------------ */
emit_mark_with_mode(const int lo,const int hi,const char * const mode)136 void emit_mark_with_mode(const int lo, const int hi, const char *const mode)
137 {
138 GET_IREC(irec_mark_range, REC_MARK_RANGE);
139
140 irec->lo = lo;
141 irec->hi = hi;
142 irec->mode = mode;
143 }
144
145 /* ------------------------------------------------------------------------ */
146 /* EMIT_RESERVE -- Reserve 'len' addresses. */
147 /* ------------------------------------------------------------------------ */
emit_reserve(const int endaddr)148 void emit_reserve(const int endaddr)
149 {
150 GET_IREC(irec_reserve_range, REC_RESERVE_RANGE);
151 irec->endaddr = endaddr;
152 }
153
154 /* ------------------------------------------------------------------------ */
155 /* EMIT_ENTERING_FILE -- Record that we're entering a new file. */
156 /* ------------------------------------------------------------------------ */
emit_entering_file(const char * const name)157 void emit_entering_file(const char *const name)
158 {
159 GET_IREC(irec_string, REC_FILE_START);
160 irec->string = name;
161 }
162
163 /* ------------------------------------------------------------------------ */
164 /* EMIT_EXITING_FILE -- Record that we're leaving a file. */
165 /* ------------------------------------------------------------------------ */
emit_exiting_file(const char * const name)166 void emit_exiting_file(const char *const name)
167 {
168 GET_IREC(irec_string, REC_FILE_EXIT);
169 irec->string = name;
170 }
171
172 /* ------------------------------------------------------------------------ */
173 /* EMIT_WARNERR -- Emit a warning or an error */
174 /* ------------------------------------------------------------------------ */
emit_warnerr(const char * const file,const int line,const warnerr type,const char * const format,...)175 void emit_warnerr(const char *const file, const int line, const warnerr type,
176 const char *const format, ...)
177 {
178 GET_IREC(irec_string, REC_ERROR);
179 va_list ap;
180
181 const size_t file_len = strlen(file);
182
183 if (file_len + 100 > eb_len)
184 {
185 free(emit_buf);
186 eb_len = 2 * (file_len + 100);
187 emit_buf = (char *)malloc(eb_len);
188 }
189
190 sprintf(emit_buf,
191 type == WARNING ? "%s:%d: WARNING - " : "%s:%d: ERROR - ",
192 file, line);
193
194 const size_t pf_len = strlen(emit_buf);
195
196 if (type == WARNING) warncnt++;
197 else errorcnt++;
198
199 size_t emit_len;
200 again:
201 va_start(ap, format);
202 vsnprintf(emit_buf + pf_len, eb_len - pf_len, format, ap);
203 va_end(ap);
204
205 emit_len = strlen(emit_buf);
206 if (eb_len < 65536 && emit_len >= eb_len - 1)
207 {
208 eb_len <<= 2;
209 emit_buf = (char *)realloc(emit_buf, eb_len);
210 goto again;
211 }
212
213 char *const final = (char *)malloc(emit_len + 2);
214 strcpy(final, emit_buf);
215 final[emit_len] = 0;
216
217 irec->string = final;
218 }
219
220 /* ------------------------------------------------------------------------ */
221 /* EMIT_RAW_ERROR -- Emit a raw error (typically as reported by */
222 /* the macro preprocessor). */
223 /* ------------------------------------------------------------------------ */
emit_raw_error(const char * const raw_error)224 void emit_raw_error(const char *const raw_error)
225 {
226 GET_IREC(irec_string, REC_ERROR);
227 irec->string = memoize_string(raw_error);
228 errorcnt++;
229 }
230
231 /* ------------------------------------------------------------------------ */
232 /* EMIT_LISTED_LINE -- A line to put directly in the listing file. */
233 /* ------------------------------------------------------------------------ */
emit_listed_line(const char * const buf)234 void emit_listed_line(const char *const buf)
235 {
236 GET_IREC(irec_string, REC_LIST_LINE);
237 irec->string = memoize_string(buf);
238 }
239
240 /* ------------------------------------------------------------------------ */
241 /* EMIT_UNLISTED_LINE -- Keep track of source lines consumed, even if */
242 /* they won't be replayed in the listing file. */
243 /* ------------------------------------------------------------------------ */
emit_unlisted_line(void)244 void emit_unlisted_line(void)
245 {
246 }
247
248 /* ------------------------------------------------------------------------ */
249 /* EMIT_GENERATED_INSTR -- Output the "polish notation" string for this */
250 /* instruction. */
251 /* ------------------------------------------------------------------------ */
emit_generated_instr(const char * const buf)252 void emit_generated_instr(const char *const buf)
253 {
254 GET_IREC(irec_string, REC_DATA_BLOCK);
255 irec->string = memoize_string(buf);
256 }
257
258 /* ------------------------------------------------------------------------ */
259 /* EMIT_CFGVAR_INT -- Output a .CFG variable with an integer value. */
260 /* ------------------------------------------------------------------------ */
emit_cfgvar_int(const char * const var,const int value)261 void emit_cfgvar_int(const char *const var, const int value)
262 {
263 GET_IREC(irec_cfgvar_int, REC_CFGVAR_INT);
264 irec->var = var;
265 irec->value = value;
266 }
267
268 /* ------------------------------------------------------------------------ */
269 /* EMIT_CFGVAR_STR -- Output a .CFG variable with a string value. */
270 /* ------------------------------------------------------------------------ */
emit_cfgvar_str(const char * const var,const char * const value)271 void emit_cfgvar_str(const char *const var, const char *const value)
272 {
273 GET_IREC(irec_cfgvar_str, REC_CFGVAR_STR);
274 irec->var = var;
275 irec->value = value;
276 }
277
278 /* ------------------------------------------------------------------------ */
279 /* EMIT_SRCFILE_OVERRIDE -- Allow HLLs to indicate orig source file, line */
280 /* ------------------------------------------------------------------------ */
emit_srcfile_override(const char * const file,const int line)281 void emit_srcfile_override(const char *const file, const int line)
282 {
283 GET_IREC(irec_srcfile_over, REC_SRCFILE_OVER);
284 irec->file = file;
285 irec->line = line;
286 }
287
288 /* ------------------------------------------------------------------------ */
289 /* EMIT_AS1600_CFG_INT -- Emit an AS1600 configuration parameter. */
290 /* ------------------------------------------------------------------------ */
emit_as1600_cfg_int(const as1600_cfg_item item,const int value)291 void emit_as1600_cfg_int(const as1600_cfg_item item, const int value)
292 {
293 GET_IREC(irec_as1600_cfg, REC_AS1600_CFG);
294 irec->item = item;
295 irec->int_value = value;
296 }
297
298 /* ------------------------------------------------------------------------ */
299 /* EMIT_LISTING_COLUMN -- Emit listing colunm configuration. */
300 /* ------------------------------------------------------------------------ */
emit_listing_column(const int hex_source,const int hex_no_src,const int source_col)301 void emit_listing_column
302 (
303 const int hex_source, /* Num hex values on a line with source */
304 const int hex_no_src, /* Num hex values on a line w/ no source */
305 const int source_col /* Column number of source on lines w/source */
306 )
307 {
308 GET_IREC(irec_listing_column, REC_LISTING_COLUMN);
309 irec->hex_source = hex_source;
310 irec->hex_no_src = hex_no_src;
311 irec->source_col = source_col;
312 }
313
314 /* ------------------------------------------------------------------------ */
315 /* Overwrite warning truth table: */
316 /* */
317 /* Force */
318 /* off ON */
319 /* Err off ok ok */
320 /* Err ON ERR ok */
321 /* ------------------------------------------------------------------------ */
322
323 /* ------------------------------------------------------------------------ */
324 /* EMIT_ERR_IF_OVERWRITTEN -- Boolean flag indicating whether it's */
325 /* unsafe to overwrite this data. */
326 /* ------------------------------------------------------------------------ */
emit_err_if_overwritten(const int enable_warning)327 void emit_err_if_overwritten(const int enable_warning)
328 {
329 GET_IREC(irec_overwrite, REC_OVERWRITE);
330 irec->err_if_overwritten = !!enable_warning;
331 irec->force_overwrite = -1; /* no change */
332 }
333
334 /* ------------------------------------------------------------------------ */
335 /* EMIT_FORCE_OVERWRITE -- Boolean flag indicating whether subsequent */
336 /* writes can overwrite without warnings. */
337 /* ------------------------------------------------------------------------ */
emit_force_overwrite(const int force_overwrite)338 void emit_force_overwrite(const int force_overwrite)
339 {
340 GET_IREC(irec_overwrite, REC_OVERWRITE);
341 irec->err_if_overwritten = -1; /* no change */
342 irec->force_overwrite = !!force_overwrite;
343 }
344
345 /* ------------------------------------------------------------------------ */
346 /* INTERMED_START_PASS_1 -- Initialize the intermediate file (and later, */
347 /* other data structures) for pass 1. */
348 /* ------------------------------------------------------------------------ */
intermed_start_pass_1(void)349 void intermed_start_pass_1(void)
350 {
351 intermed_finish(0);
352
353 if (!emit_buf)
354 {
355 emit_buf = (char *)malloc(4096);
356 eb_len = 4096;
357 }
358 }
359
360 /* ------------------------------------------------------------------------ */
361 /* INTERMED_START_PASS_2 -- Initialize the intermediate file (and later, */
362 /* other data structures) for pass 2. */
363 /* ------------------------------------------------------------------------ */
intermed_start_pass_2(void)364 void intermed_start_pass_2(void)
365 {
366 //fprintf(stderr, "total allocs = %d\n", allocs);
367 #if 0
368 struct mallinfo m = mallinfo();
369
370 # define M(x) printf("%-15s %ld\n", #x, (long)m.x);
371 M(arena)
372 M(ordblks)
373 M(smblks)
374 M(hblks)
375 M(hblkhd)
376 M(usmblks)
377 M(fsmblks)
378 M(uordblks)
379 M(fordblks)
380 M(keepcost)
381 #endif
382 }
383
384 /* ------------------------------------------------------------------------ */
385 /* INTERMED_FINISH -- Clean up all the intermediate file/data/etc. */
386 /* Optionally output debug info. */
387 /* ------------------------------------------------------------------------ */
intermed_finish(const int debugmode)388 void intermed_finish(const int debugmode)
389 {
390 UNUSED(debugmode);
391
392 if (irec_tbl)
393 {
394 while (irec_head < irec_tail)
395 pass2_release_rec(&irec_tbl[irec_head++ % irec_total]);
396
397 free(irec_tbl);
398 irec_head = irec_tail = irec_total = 0;
399 }
400 }
401
402 /* ------------------------------------------------------------------------ */
403 /* PASS2_NEXT_LINE -- Gets the next line of the intermediate data. */
404 /* ------------------------------------------------------------------------ */
pass2_next_rec(void)405 irec_union *pass2_next_rec(void)
406 {
407 if (irec_head > irec_total)
408 {
409 irec_head -= irec_total;
410 irec_tail -= irec_total;
411 }
412 return irec_head < irec_tail ? &irec_tbl[irec_head++ % irec_total] : NULL;
413 }
414
pass2_release_rec(irec_union * const irec)415 void pass2_release_rec(irec_union *const irec)
416 {
417 UNUSED(irec);
418 }
419