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