]> Shamusworld >> Repos - rmac/blob - symbol.c
Added new .cstruct construct. Thanks to GroovyBee for the suggestion!
[rmac] / symbol.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // SYMBOL.C - Symbol Handling
4 // Copyright (C) 199x Landon Dyer, 2011-2012 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source Utilised with the Kind Permission of Landon Dyer
7 //
8
9 #include "symbol.h"
10 #include "listing.h"
11 #include "procln.h"
12 #include "error.h"
13
14
15 // Macros
16 #define NBUCKETS 256                                    // Number of hash buckets (power of 2)
17
18 static SYM * symbolTable[NBUCKETS];             // User symbol-table header
19 int curenv;                                                             // Current enviroment number
20 static SYM * sorder;                                    // * -> Symbols, in order of reference
21 static SYM * sordtail;                                  // * -> Last symbol in sorder list
22 static SYM * sdecl;                                             // * -> Symbols, in order of declaration
23 static SYM * sdecltail;                                 // * -> Last symbol in sdecl list
24 static uint32_t currentUID;                             // Symbol UID tracking (done by NewSymbol())
25
26 // Tags for marking symbol spaces
27 // a = absolute
28 // t = text
29 // d = data
30 // ! = "impossible!"
31 // b = BSS
32 static char tdb_text[8] = {
33    'a', 't', 'd', '!', 'b', SPACE, SPACE, SPACE
34 };
35
36
37 //
38 // Initialize Symbol Table
39 //
40 void InitSymbolTable(void)
41 {
42         int i;                                                                  // Iterator
43
44         for(i=0; i<NBUCKETS; i++)                               // Initialise symbol hash table
45                 symbolTable[i] = NULL;
46
47         curenv = 1;                                                             // Init local symbol enviroment
48         sorder = NULL;                                                  // Init symbol-reference list
49         sordtail = NULL;
50         sdecl = NULL;                                                   // Init symbol-decl list
51         sdecltail = NULL;
52         currentUID = 0;
53 }
54
55
56 //
57 // Hash the Print Name and Enviroment Number
58 //
59 int HashSymbol(char * name, int envno)
60 {
61         int sum, k = 0;                                                 // Hash calculation
62
63         for(sum=envno; *name; name++)
64         {
65                 if (k++ == 1)
66                         sum += *name << 2;
67                 else
68                         sum += *name;
69         }
70
71         return sum & (NBUCKETS - 1);
72 }
73
74
75 //
76 // Make a new symbol of type `type' in enviroment `envno'
77 //
78 SYM * NewSymbol(char * name, int type, int envno)
79 {
80         // Allocate the symbol
81         SYM * symbol = malloc(sizeof(SYM));
82
83         if (symbol == NULL)
84         {
85                 printf("NewSymbol: MALLOC ERROR (symbol=\"%s\")\n", name);
86                 return NULL;
87         }
88
89         // Fill-in the symbol
90         symbol->sname  = strdup(name);
91         symbol->stype  = (BYTE)type;
92         symbol->senv   = (WORD)envno;
93         symbol->sattr  = 0;
94         symbol->sattre = (rgpu || rdsp ? RISCSYM : 0);
95         symbol->svalue = 0;
96         symbol->sorder = NULL;
97         symbol->uid    = currentUID++;
98
99         // Install symbol in symbol table
100         int hash = HashSymbol(name, envno);
101         symbol->snext = symbolTable[hash];
102         symbolTable[hash] = symbol;
103
104         // Append symbol to symbol-order list
105         if (sorder == NULL)
106                 sorder = symbol;                                        // Add first symbol 
107         else
108                 sordtail->sorder = symbol;                      // Or append to tail of list
109
110         sordtail = symbol;
111         return symbol;
112 }
113
114
115 //
116 // Look up the symbol name by its UID and return the pointer to the name.
117 // If it's not found, return NULL.
118 //
119 char * GetSymbolNameByUID(uint32_t uid)
120 {
121         //problem is with string lookup, that's why we're writing this
122         //so once this is written, we can put the uid in the token stream
123
124         // A much better approach to the symbol order list would be to make an
125         // array--that way you can do away with the UIDs and all the rest, and
126         // simply do an array lookup based on position. But meh, let's do this for
127         // now until we can rewrite things so they make sense.
128         SYM * symbol = sorder;
129
130         for(; symbol; symbol=symbol->sorder)
131         {
132                 if (symbol->uid == uid)
133                         return symbol->sname;
134         }
135
136         return NULL;
137 }
138
139
140 //
141 // Lookup the symbol `name', of the specified type, with the specified
142 // enviroment level
143 //
144 SYM * lookup(char * name, int type, int envno)
145 {
146         SYM * symbol = symbolTable[HashSymbol(name, envno)];
147
148         // Do linear-search for symbol in bucket
149         while (symbol != NULL)
150         {
151                 if (symbol->stype == type                       // Type, envno and name must match
152                         && symbol->senv  == envno
153                         && *name == *symbol->sname              // Fast check for first character
154                         && !strcmp(name, symbol->sname))
155                         break;
156
157                 symbol = symbol->snext;
158         }
159
160         return symbol;                                                  // Return NULL or matching symbol
161 }
162
163
164 //
165 // Put symbol on "order-of-declaration" list of symbols
166 //
167 void sym_decl(SYM * symbol)
168 {
169         if (symbol->sattr & SDECLLIST)
170                 return;                                                         // Already on list
171
172         symbol->sattr |= SDECLLIST;                             // Mark "already on list"
173
174         if (sdecl == NULL)
175                 sdecl = symbol;                                         // First on decl-list
176         else 
177                 sdecltail->sdecl = symbol;                      // Add to end of list
178
179         symbol->sdecl = NULL;                                   // Fix up list's tail
180         sdecltail = symbol;
181 }
182
183
184 //
185 // Make all referenced, undefined symbols global
186 //
187 int syg_fix(void)
188 {
189         SYM * sy;
190
191         DEBUG printf("~syg_fix()\n");
192
193         // Scan through all symbols;
194         // If a symbol is REFERENCED but not DEFINED, then make it global.
195         for(sy=sorder; sy!=NULL; sy=sy->sorder)
196         {
197                 if (sy->stype == LABEL && sy->senv == 0
198                         && ((sy->sattr & (REFERENCED | DEFINED)) == REFERENCED))
199                         sy->sattr |= GLOBAL;
200         }
201
202         return 0;
203 }
204
205
206 //
207 // Convert string to uppercase
208 //
209 int uc_string(char * s)
210 {
211         for(; *s; s++)
212         {
213                 if (*s >= 'a' && *s <= 'z')
214                         *s -= 32;
215         }
216
217         return 0;
218 }
219
220
221 //
222 // Assign numbers to symbols that are to be exported or imported. The symbol
223 // number is put in `.senv'. Return the number of symbols that will be in the
224 // symbol table.
225 //
226 int sy_assign(char * buf, char *(* constr)())
227 {
228         SYM * sy;
229         int scount;
230         //int i;
231
232         scount = 0;
233
234         if (buf == NULL)
235         {
236                 // Append all symbols not appearing on the .sdecl list to the end of
237                 // the .sdecl list
238                 for(sy=sorder; sy!=NULL; sy=sy->sorder)
239                 {
240                         // Essentially the same as 'sym_decl()' above:
241                         if (sy->sattr & SDECLLIST)
242                                 continue;                // Already on list 
243
244                         sy->sattr |= SDECLLIST;                            // Mark "on the list"
245
246                         if (sdecl == NULL)
247                                 sdecl = sy;                      // First on decl-list 
248                         else
249                                 sdecltail->sdecl = sy;                        // Add to end of list
250
251                         sy->sdecl = NULL;                                  // Fix up list's tail
252                         sdecltail = sy;
253                 }
254         }
255
256         // Run through all symbols (now on the .sdecl list) and assign numbers to
257         // them. We also pick which symbols should be global or not here.
258         for(sy=sdecl; sy!=NULL; sy=sy->sdecl)
259         {
260                 if (sy->sattre & UNDEF_EQUR)
261                         continue;                 // Don't want undefined on our list
262
263                 if (sy->sattre & UNDEF_CC)
264                         continue;                   
265                 
266                 // Export or import external references, and export COMMON blocks.
267                 if ((sy->stype == LABEL)
268                         && ((sy->sattr & (GLOBAL | DEFINED)) == (GLOBAL | DEFINED)
269                         || (sy->sattr & (GLOBAL | REFERENCED)) == (GLOBAL | REFERENCED))
270                         || (sy->sattr & COMMON))
271                 {
272                         sy->senv = (WORD)scount++;
273
274                         if (buf != NULL)
275                                 buf = (*constr)(buf, sy, 1);
276                 }
277                 // Export vanilla labels (but don't make them global). An exception is
278                 // made for equates, which are not exported unless they are referenced.
279                 else if (sy->stype == LABEL && lsym_flag
280                         && (sy->sattr & (DEFINED | REFERENCED)) != 0
281                         && (!as68_flag || *sy->sname != 'L'))
282                 {
283                         sy->senv = (WORD)scount++;
284                         if (buf != NULL) buf = (*constr)(buf, sy, 0);
285                 }
286         }
287
288         return scount;
289 }
290
291
292 //
293 // Generate symbol table for listing file
294 //
295 int symtable(void)
296 {
297         int i;
298         int j;
299         SYM * q = NULL;
300         SYM * p;
301         SYM * r;
302         SYM * k;
303         SYM ** sy;
304         SYM * colptr[4];
305         char ln[150];
306         char ln1[150];
307         char ln2[20];
308         char c, c1;
309         WORD w;
310         int ww;
311         int colhei;
312         extern int pagelen;
313
314         colhei = pagelen - 5;
315
316         // Allocate storage for list headers and partition all labels.  
317         // Throw away macros and macro arguments.
318 //      sy = (SYM **)amem((LONG)(128 * sizeof(LONG)));
319         sy = (SYM **)malloc(128 * sizeof(LONG));
320
321         for(i=0; i<128; ++i)
322                 sy[i] = NULL;
323
324         for(i=0; i<NBUCKETS; ++i)
325         {
326                 for(p=symbolTable[i]; p!=NULL; p=k)
327                 {
328                         k = p->snext;
329                         j = *p->sname;
330                         r = NULL;
331
332                         if (p->stype != LABEL)
333                                 continue;                   // Ignore non-labels
334
335                         if (p->sattre & UNDEF_EQUR)
336                                 continue;
337
338                         for(q=sy[j]; q!=NULL; q=q->snext)
339                         {
340                                 if (strcmp(p->sname, q->sname) < 0)
341                                         break;
342                                 else
343                                         r = q;
344                         }
345
346                         if (r == NULL)
347                         {                               // Insert at front of list
348                                 p->snext = sy[j];
349                                 sy[j] = p;
350                         }
351                         else
352                         {                               // Insert in middle or append to list
353                                 p->snext = r->snext;
354                                 r->snext = p;
355                         }
356                 }
357         }
358
359         // Link all symbols onto one list again
360         p = NULL;
361
362         for(i=0; i<128; ++i)
363         {
364                 if ((r = sy[i]) != NULL)
365                 {
366                         if (p == NULL)
367                                 q = r;
368                         else
369                                 q->snext = r;
370
371                         while (q->snext != NULL)
372                                 q = q->snext;
373
374                         if (p == NULL)
375                                 p = r;
376                 }
377         }
378
379         eject();
380         strcpy(subttl, "Symbol Table");
381
382         while (p != NULL)
383         {
384                 for(i=0; i<4; ++i)
385                 {
386                         colptr[i] = p;
387
388                         for(j=0; j<colhei; ++j)
389                         {
390                                 if (p == NULL)
391                                         break;
392                                 else
393                                         p = p->snext;
394                         }
395                 }
396
397                 for(i=0; i<colhei; ++i)
398                 {
399                         *ln = EOS;
400
401                         if (colptr[0] == NULL)
402                                 break;
403
404                         for(j=0; j<4; ++j)
405                         {
406                                 if ((q = colptr[j]) == NULL)
407                                         break;
408
409                                 colptr[j] = q->snext;
410                                 w = q->sattr;
411                                 ww = q->sattre;
412                                 // Pick a tag:
413                                 // c    common
414                                 // x    external reference
415                                 // g    global (export)
416                                 // space        nothing special
417                                 c1 = SPACE;
418                                 c = SPACE;
419
420                                 if (w & COMMON)
421                                         c = 'c';
422                                 else if ((w & (DEFINED|GLOBAL)) == GLOBAL)
423                                         c = 'x';
424                                 else if (w & GLOBAL)
425                                         c = 'g';
426
427                                 c1 = tdb_text[w & TDB];
428
429                                 if (c == 'x')
430                                         strcpy(ln2, "external");
431                                 else
432                                 {
433                                         sprintf(ln2, "%08X", q->svalue);
434                                         uc_string(ln2);
435                                 }
436
437                                 sprintf(ln1, "  %16s %s %c%c%c", q->sname, ln2, (ww & EQUATEDREG) ? 'e' : SPACE, c1, c);
438                                 strcat(ln, ln1);
439                         }
440
441                         ship_ln(ln);
442                 }
443
444                 eject();
445         }
446
447         return 0;
448 }