]> Shamusworld >> Repos - rmac/blob - token.c
(c) message in header files and doc mini adjustments.
[rmac] / token.c
1 //
2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // TOKEN.C - Token Handling
4 // Copyright (C) 199x Landon Dyer, 2011-2017 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 "token.h"
10 #include "direct.h"
11 #include "error.h"
12 #include "macro.h"
13 #include "procln.h"
14 #include "sect.h"
15 #include "symbol.h"
16
17 #define DECL_KW                         // Declare keyword arrays
18 #define DEF_KW                          // Declare keyword values
19 #include "kwtab.h"                      // Incl generated keyword tables & defs
20
21
22 int lnsave;                                     // 1; strcpy() text of current line
23 uint16_t curlineno;                     // Current line number (64K max currently)
24 int totlines;                           // Total # of lines
25 int mjump_align = 0;            // mjump alignment flag
26 char lntag;                                     // Line tag
27 char * curfname;                        // Current filename
28 char tolowertab[128];           // Uppercase ==> lowercase
29 int8_t hextab[128];                     // Table of hex values
30 char dotxtab[128];                      // Table for ".b", ".s", etc.
31 char irbuf[LNSIZ];                      // Text for .rept block line
32 char lnbuf[LNSIZ];                      // Text of current line
33 WORD filecount;                         // Unique file number counter
34 WORD cfileno;                           // Current file number
35 TOKEN * tok;                            // Ptr to current token
36 TOKEN * etok;                           // Ptr past last token in tokbuf[]
37 TOKEN tokeol[1] = {EOL};        // Bailout end-of-line token
38 char * string[TOKBUFSIZE*2];    // Token buffer string pointer storage
39
40 // File record, used to maintain a list of every include file ever visited
41 #define FILEREC struct _filerec
42 FILEREC
43 {
44    FILEREC * frec_next;
45    char * frec_name;
46 };
47
48 FILEREC * filerec;
49 FILEREC * last_fr;
50
51 INOBJ * cur_inobj;                                              // Ptr current input obj (IFILE/IMACRO)
52 static INOBJ * f_inobj;                                 // Ptr list of free INOBJs
53 static IFILE * f_ifile;                                 // Ptr list of free IFILEs
54 static IMACRO * f_imacro;                               // Ptr list of free IMACROs
55
56 static TOKEN tokbuf[TOKBUFSIZE];                // Token buffer (stack-like, all files)
57
58 char chrtab[] = {
59         ILLEG, ILLEG, ILLEG, ILLEG,                     // NUL SOH STX ETX
60         ILLEG, ILLEG, ILLEG, ILLEG,                     // EOT ENQ ACK BEL
61         ILLEG, WHITE, ILLEG, ILLEG,                     // BS HT LF VT
62         WHITE, ILLEG, ILLEG, ILLEG,                     // FF CR SO SI
63
64         ILLEG, ILLEG, ILLEG, ILLEG,                     // DLE DC1 DC2 DC3
65         ILLEG, ILLEG, ILLEG, ILLEG,                     // DC4 NAK SYN ETB
66         ILLEG, ILLEG, ILLEG, ILLEG,                     // CAN EM SUB ESC
67         ILLEG, ILLEG, ILLEG, ILLEG,                     // FS GS RS US
68
69         WHITE, MULTX, MULTX, SELF,                      // SP ! " #
70         MULTX+CTSYM, MULTX, SELF, MULTX,        // $ % & '
71         SELF, SELF, SELF, SELF,                         // ( ) * +
72         SELF, SELF, STSYM, SELF,                        // , - . /
73
74         DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM,         // 0 1
75         DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM,         // 2 3
76         DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM,         // 4 5
77         DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM,         // 6 7
78         DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM,         // 8 9
79         MULTX, MULTX,                                                           // : ;
80         MULTX, MULTX, MULTX, STSYM+CTSYM,                       // < = > ?
81
82         MULTX, STSYM+CTSYM+HDIGIT,                                                                      // @ A
83         (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT,       // B C
84         (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT,                                               // D E
85         STSYM+CTSYM+HDIGIT, STSYM+CTSYM,                                                        // F G
86         STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM,                   // H I J K
87         (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM,   // L M N O
88
89         (char)((BYTE)DOT)+STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM,       // P Q R S
90         STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM,   // T U V W
91         STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF,                            // X Y Z [
92         SELF, SELF, MULTX, STSYM+CTSYM,                                                         // \ ] ^ _
93
94         ILLEG, STSYM+CTSYM+HDIGIT,                                                                      // ` a
95         (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT,       // b c
96         (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT,                                               // d e
97         STSYM+CTSYM+HDIGIT, STSYM+CTSYM,                                                        // f g
98         STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM,                   // h i j k
99         (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM,   // l m n o
100
101         (char)((BYTE)DOT)+STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM,       // p q r s
102         STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM,   // t u v w
103         (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF,                          // x y z {
104         SELF, SELF, SELF, ILLEG                                                                         // | } ~ DEL
105 };
106
107 // Names of registers
108 static char * regname[] = {
109         "d0","d1","d2","d3","d4","d5","d6","d7", // 128,135
110         "a0","a1","a2","a3","a4","a5","a6","sp", // 136,143
111         "ssp","pc","sr","ccr","regequ","set","reg","r0", // 144,151
112         "r1","r2","r3","r4","r5","r6","r7","r8", // 152,159
113         "r9","r10","r11","r12","r13","r14","r15","r16", // 160,167
114         "r17","r18","r19","r20","r21","r22","r23","r24", // 168,175
115         "r25","r26","r27","r28","r29","r30","r31","ccdef", // 176,183
116         "usp","ic40","dc40","bc40","sfc","dfc","","vbr", // 184,191
117         "cacr","caar","msp","isp","tc","itt0","itt1","dtt0", // 192,199
118         "dtt1","mmusr","urp","srp","iacr0","iacr1","dacr0","dacr1", // 200,207
119         "tt0","tt1","crp","","","","","", // 208,215
120         "","","","","fpiar","fpsr","fpcr","", // 216,223
121         "fp0","fp1","fp2","fp3","fp4","fp5","fp6","fp7", // 224,231
122         "","","","","","","","", // 232,239
123         "","","","","","","","", // 240,247
124         "","","","","","","","", // 248,255
125         "","","","","x0","x1","y0","y1", // 256,263
126         "","b0","","b2","","b1","a","b", // 264,271
127         "mr","omr","la","lc","ssh","ssl","ss","", // 272,279
128         "n0","n1","n2","n3","n4","n5","n6","n7", // 280,287
129         "m0","m1","m2","m3","m4","m5","m6","m7", // 288,295
130         "","","","","","","l","p", // 296,303
131         "mr","omr","la","lc","ssh","ssl","ss","", // 304,311
132         "a10","b10","x","y","","","ab","ba"  // 312,319
133 };
134
135 static char * riscregname[] = {
136          "r0",  "r1",  "r2",  "r3",  "r4", "r5",   "r6",  "r7",
137          "r8",  "r9", "r10", "r11", "r12", "r13", "r14", "r15",
138         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
139         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
140 };
141
142
143 //
144 // Initialize tokenizer
145 //
146 void InitTokenizer(void)
147 {
148         int i;                                                                  // Iterator
149         char * htab = "0123456789abcdefABCDEF"; // Hex character table
150
151         lnsave = 0;                                                             // Don't save lines
152         curfname = "";                                                  // No file, empty filename
153         filecount = (WORD)-1;
154         cfileno = (WORD)-1;                                             // cfileno gets bumped to 0
155         curlineno = 0;
156         totlines = 0;
157         etok = tokbuf;
158         f_inobj = NULL;
159         f_ifile = NULL;
160         f_imacro = NULL;
161         cur_inobj = NULL;
162         filerec = NULL;
163         last_fr = NULL;
164         lntag = SPACE;
165
166         // Initialize hex, "dot" and tolower tables
167         for(i=0; i<128; i++)
168         {
169                 hextab[i] = -1;
170                 dotxtab[i] = 0;
171                 tolowertab[i] = (char)i;
172         }
173
174         for(i=0; htab[i]!=EOS; i++)
175                 hextab[htab[i]] = (char)((i < 16) ? i : i - 6);
176
177         for(i='A'; i<='Z'; i++)
178                 tolowertab[i] |= 0x20;
179
180         // These characters are legal immediately after a period
181         dotxtab['b'] = DOTB;                                    // .b .B .s .S
182         dotxtab['B'] = DOTB;
183         //dotxtab['s'] = DOTB;
184         //dotxtab['S'] = DOTB;
185         dotxtab['w'] = DOTW;                                    // .w .W
186         dotxtab['W'] = DOTW;
187         dotxtab['l'] = DOTL;                                    // .l .L
188         dotxtab['L'] = DOTL;
189         dotxtab['i'] = DOTI;                                    // .i .I (???)
190         dotxtab['I'] = DOTI;
191         dotxtab['D'] = DOTD;                                    // .d .D (quad word)
192         dotxtab['d'] = DOTD;
193         dotxtab['S'] = DOTS;                                    // .s .S
194         dotxtab['s'] = DOTS;
195         dotxtab['Q'] = DOTQ;                                    // .q .Q
196         dotxtab['q'] = DOTQ;
197         dotxtab['X'] = DOTX;                                    // .x .x
198         dotxtab['x'] = DOTX;
199         dotxtab['P'] = DOTP;                                    // .p .P
200         dotxtab['p'] = DOTP;
201 }
202
203
204 void SetFilenameForErrorReporting(void)
205 {
206         WORD fnum = cfileno;
207
208         // Check for absolute top filename (this should never happen)
209         if (fnum == -1)
210         {
211                 curfname = "(*top*)";
212                 return;
213         }
214
215         FILEREC * fr = filerec;
216
217         // Advance to the correct record...
218         while (fr != NULL && fnum != 0)
219         {
220                 fr = fr->frec_next;
221                 fnum--;
222         }
223
224         // Check for file # record not found (this should never happen either)
225         if (fr == NULL)
226         {
227                 curfname = "(*NOT FOUND*)";
228                 return;
229         }
230
231         curfname = fr->frec_name;
232 }
233
234
235 //
236 // Allocate an IFILE or IMACRO
237 //
238 INOBJ * a_inobj(int typ)
239 {
240         INOBJ * inobj;
241         IFILE * ifile;
242         IMACRO * imacro;
243
244         // Allocate and initialize INOBJ first
245         if (f_inobj == NULL)
246                 inobj = malloc(sizeof(INOBJ));
247         else
248         {
249                 inobj = f_inobj;
250                 f_inobj = f_inobj->in_link;
251         }
252
253         switch (typ)
254         {
255         case SRC_IFILE:                                                 // Alloc and init an IFILE
256                 if (f_ifile == NULL)
257                         ifile = malloc(sizeof(IFILE));
258                 else
259                 {
260                         ifile = f_ifile;
261                         f_ifile = f_ifile->if_link;
262                 }
263
264                 inobj->inobj.ifile = ifile;
265                 break;
266         case SRC_IMACRO:                                                // Alloc and init an IMACRO
267                 if (f_imacro == NULL)
268                         imacro = malloc(sizeof(IMACRO));
269                 else
270                 {
271                         imacro = f_imacro;
272                         f_imacro = f_imacro->im_link;
273                 }
274
275                 inobj->inobj.imacro = imacro;
276                 break;
277         case SRC_IREPT:                                                 // Alloc and init an IREPT
278                 inobj->inobj.irept = malloc(sizeof(IREPT));
279                 DEBUG printf("alloc IREPT\n");
280                 break;
281         }
282
283         // Install INOBJ on top of input stack
284         inobj->in_ifent = ifent;                                // Record .if context on entry
285         inobj->in_type = (WORD)typ;
286         inobj->in_otok = tok;
287         inobj->in_etok = etok;
288         inobj->in_link = cur_inobj;
289         cur_inobj = inobj;
290
291         return inobj;
292 }
293
294
295 //
296 // Perform macro substitution from 'orig' to 'dest'. Return OK or some error.
297 // A macro reference is in one of two forms:
298 // \name <non-name-character>
299 // \{name}
300 // A doubled backslash (\\) is compressed to a single backslash (\).
301 // Argument definitions have been pre-tokenized, so we have to turn them back
302 // into text. This means that numbers, in particular, become hex, regardless of
303 // their representation when the macro was invoked. This is a hack.
304 // A label may appear at the beginning of the line:
305 // :<name><whitespace>
306 // (the colon must be in the first column). These labels are stripped before
307 // macro expansion takes place.
308 //
309 int ExpandMacro(char * src, char * dest, int destsiz)
310 {
311         int i;
312         int questmark;                  // \? for testing argument existence
313         char mname[128];                // Assume max size of a formal arg name
314         char numbuf[20];                // Buffer for text of CONSTs
315         TOKEN * tk;
316         SYM * arg;
317         char ** symbolString;
318
319         DEBUG { printf("ExM: src=\"%s\"\n", src); }
320
321         IMACRO * imacro = cur_inobj->inobj.imacro;
322         int macnum = (int)(imacro->im_macro->sattr);
323
324         char * dst = dest;                                              // Next dest slot
325         char * edst = dest + destsiz - 1;               // End + 1(?) of dest buffer
326
327         // Check for (and skip over) any "label" on the line
328         char * s = src;
329         char * d = NULL;
330
331         if (*s == ':')
332         {
333                 while (*s != EOS && !(chrtab[*s] & WHITE))
334                         s++;
335
336                 if (*s != EOS)
337                         s++;                                                    // Skip first whitespace
338         }
339
340         // Expand the rest of the line
341         while (*s != EOS)
342         {
343                 // Copy single character
344                 if (*s != '\\')
345                 {
346                         if (dst >= edst)
347                                 goto overflow;
348
349                         // Skip comments in case a loose @ or \ is in there
350                         // In that case the tokeniser was trying to expand it.
351                         if ((*s == ';') || ((*s == '/') && (*(s + 1) == '/')))
352                                 goto skipcomments;
353
354                         *dst++ = *s++;
355                 }
356                 // Do macro expansion
357                 else
358                 {
359                         questmark = 0;
360
361                         // Do special cases
362                         switch (*++s)
363                         {
364                         case '\\':                                              // \\, \ (collapse to single backslash)
365                                 if (dst >= edst)
366                                         goto overflow;
367
368                                 *dst++ = *s++;
369                                 continue;
370                         case '?':                                               // \? <macro>  set `questmark' flag
371                                 ++s;
372                                 questmark = 1;
373                                 break;
374                         case '#':                                               // \#, number of arguments
375                                 sprintf(numbuf, "%d", (int)imacro->im_nargs);
376                                 goto copystr;
377                         case '!':                                               // \! size suffix supplied on invocation
378                                 switch ((int)imacro->im_siz)
379                                 {
380                                 case SIZN: d = "";   break;
381                                 case SIZB: d = ".b"; break;
382                                 case SIZW: d = ".w"; break;
383                                 case SIZL: d = ".l"; break;
384                                 }
385
386                                 goto copy_d;
387                         case '~':                                               // ==> unique label string Mnnnn...
388                                 sprintf(numbuf, "M%u", curuniq);
389 copystr:
390                                 d = numbuf;
391 copy_d:
392                                 s++;
393
394                                 while (*d != EOS)
395                                 {
396                                         if (dst >= edst)
397                                                 goto overflow;
398                                         else
399                                                 *dst++ = *d++;
400                                 }
401
402                                 continue;
403                         case EOS:
404                                 return error("missing argument name");
405                         }
406
407                         // \n ==> argument number 'n', 0..9
408                         if (chrtab[*s] & DIGIT)
409                         {
410                                 i = *s++ - '1';
411
412                                 if (i < 0)
413                                         i = 9;
414
415                                 goto arg_num;
416                         }
417
418                         // Get argument name: \name, \{name}
419                         d = mname;
420
421                         // \label
422                         if (*s != '{')
423                         {
424                                 do
425                                 {
426                                         *d++ = *s++;
427                                 }
428                                 while (chrtab[*s] & CTSYM);
429                         }
430                         // \\{label}
431                         else
432                         {
433                                 for(++s; *s != EOS && *s != '}';)
434                                         *d++ = *s++;
435
436                                 if (*s != '}')
437                                         return error("missing '}'");
438                                 else
439                                         s++;
440                         }
441
442                         *d = EOS;
443
444                         // Lookup the argument and copy its (string) value into the
445                         // destination string
446                         DEBUG printf("argument='%s'\n", mname);
447
448                         if ((arg = lookup(mname, MACARG, macnum)) == NULL)
449                                 return errors("undefined argument: '%s'", mname);
450                         else
451                         {
452                                 // Convert a string of tokens (terminated with EOL) back into
453                                 // text. If an argument is out of range (not specified in the
454                                 // macro invocation) then it is ignored.
455                                 i = (int)arg->svalue;
456 arg_num:
457                                 DEBUG printf("~argnumber=%d (argBase=%u)\n", i, imacro->argBase);
458                                 tk = NULL;
459
460                                 if (i < imacro->im_nargs)
461                                 {
462 #if 0
463 //                                      tk = argp[i];
464 //                                      tk = argPtrs[i];
465                                         tk = argPtrs[imacro->argBase + i];
466 #else
467                                         tk = imacro->argument[i].token;
468                                         symbolString = imacro->argument[i].string;
469 //DEBUG
470 //{
471 //      printf("ExM: Preparing to parse argument #%u...\n", i);
472 //      dumptok(tk);
473 //}
474 #endif
475                                 }
476
477                                 // \?arg yields:
478                                 //    0  if the argument is empty or non-existant,
479                                 //    1  if the argument is not empty
480                                 if (questmark)
481                                 {
482                                         if (tk == NULL || *tk == EOL)
483                                                 questmark = 0;
484
485                                         if (dst >= edst)
486                                                 goto overflow;
487
488                                         *dst++ = (char)(questmark + '0');
489                                         continue;
490                                 }
491
492                                 // Argument # is in range, so expand it
493                                 if (tk != NULL)
494                                 {
495                                         while (*tk != EOL)
496                                         {
497                                                 // Reverse-translation from a token number to a string.
498                                                 // This is a hack. It might be better table-driven.
499                                                 d = NULL;
500
501                                                 if ((*tk >= KW_D0) && !rdsp && !rgpu)
502                                                 {
503                                                         d = regname[(int)*tk++ - KW_D0];
504                                                         goto strcopy;
505                                                 }
506                                                 else if ((*tk >= KW_R0) && (*tk <= KW_R31))
507                                                 {
508                                                         d = riscregname[(int)*tk++ - KW_R0];
509                                                         goto strcopy;
510                                                 }
511                                                 else
512                                                 {
513                                                         switch ((int)*tk++)
514                                                         {
515                                                         case SYMBOL:
516 #if 0
517 //                                                              d = (char *)*tk++;
518                                                                 d = string[*tk++];
519 #else
520                                                                 // This fix should be done for strings too
521                                                                 d = symbolString[*tk++];
522 DEBUG printf("ExM: SYMBOL=\"%s\"", d);
523 #endif
524                                                                 break;
525                                                         case STRING:
526 #if 0
527 //                                                              d = (char *)*tk++;
528                                                                 d = string[*tk++];
529 #else
530                                                                 d = symbolString[*tk++];
531 #endif
532                                                                 if (dst >= edst)
533                                                                         goto overflow;
534
535                                                                 *dst++ = '"';
536
537                                                                 while (*d != EOS)
538                                                                 {
539                                                                         if (dst >= edst)
540                                                                                 goto overflow;
541                                                                         else
542                                                                                 *dst++ = *d++;
543                                                                 }
544
545                                                                 if (dst >= edst)
546                                                                         goto overflow;
547
548                                                                 *dst++ = '"';
549                                                                 continue;
550                                                                 break;
551 // Shamus: Changing the format specifier from %lx to %ux caused the assembler
552 //         to choke on legitimate code... Need to investigate this further
553 //         before changing anything else here!
554                                                         case CONST:
555                                                                 sprintf(numbuf, "$%lx", (long unsigned int)*tk++);
556                                                                 d = numbuf;
557                                                                 break;
558                                                         case DEQUALS:
559                                                                 d = "==";
560                                                                 break;
561                                                         case SET:
562                                                                 d = "set";
563                                                                 break;
564                                                         case COLON:
565                                                                 d = ":";
566                                                                 break;
567                                                         case DCOLON:
568                                                                 d = "::";
569                                                                 break;
570                                                         case GE:
571                                                                 d = ">=";
572                                                                 break;
573                                                         case LE:
574                                                                 d = "<=";
575                                                                 break;
576                                                         case NE:
577                                                                 d = "<>";
578                                                                 break;
579                                                         case SHR:
580                                                                 d = ">>";
581                                                                 break;
582                                                         case SHL:
583                                                                 d = "<<";
584                                                                 break;
585                                                         case DOTB:
586                                                                 d = ".b";
587                                                                 break;
588                                                         case DOTW:
589                                                                 d = ".w";
590                                                                 break;
591                                                         case DOTL:
592                                                                 d = ".l";
593                                                                 break;
594                                                         case CR_ABSCOUNT:
595                                                                 d = "^^abscount";
596                                                                 break;
597                                                         case CR_DATE:
598                                                                 d = "^^date";
599                                                                 break;
600                                                         case CR_TIME:
601                                                                 d = "^^time";
602                                                                 break;
603                                                         case CR_DEFINED:
604                                                                 d = "^^defined ";
605                                                                 break;
606                                                         case CR_REFERENCED:
607                                                                 d = "^^referenced ";
608                                                                 break;
609                                                         case CR_STREQ:
610                                                                 d = "^^streq ";
611                                                                 break;
612                                                         case CR_MACDEF:
613                                                                 d = "^^macdef ";
614                                                                 break;
615                                                         default:
616                                                                 if (dst >= edst)
617                                                                         goto overflow;
618
619                                                                 *dst++ = (char)*(tk - 1);
620                                                                 break;
621                                                         }
622                                                 }
623
624                                                 // If 'd' != NULL, copy string to destination
625                                                 if (d != NULL)
626                                                 {
627 strcopy:
628                                                         DEBUG printf("d='%s'\n", d);
629
630                                                         while (*d != EOS)
631                                                         {
632                                                                 if (dst >= edst)
633                                                                         goto overflow;
634                                                                 else
635                                                                         *dst++ = *d++;
636                                                         }
637                                                 }
638                                         }
639                                 }
640                         }
641                 }
642         }
643
644 skipcomments:
645
646         *dst = EOS;
647         DEBUG { printf("ExM: dst=\"%s\"\n", dest); }
648         return OK;
649
650 overflow:
651         *dst = EOS;
652         DEBUG printf("*** OVERFLOW LINE ***\n%s\n", dest);
653         return fatal("line too long as a result of macro expansion");
654 }
655
656
657 //
658 // Get next line of text from a macro
659 //
660 char * GetNextMacroLine(void)
661 {
662         IMACRO * imacro = cur_inobj->inobj.imacro;
663 //      LONG * strp = imacro->im_nextln;
664         struct LineList * strp = imacro->im_nextln;
665
666         if (strp == NULL)                                               // End-of-macro
667                 return NULL;
668
669         imacro->im_nextln = strp->next;
670 //      ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
671         ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
672
673         return imacro->im_lnbuf;
674 }
675
676
677 //
678 // Get next line of text from a repeat block
679 //
680 char * GetNextRepeatLine(void)
681 {
682         IREPT * irept = cur_inobj->inobj.irept;
683         LONG * strp = irept->ir_nextln;                 // initial null
684
685         // Do repeat at end of .rept block's string list
686         if (strp == NULL)
687         {
688                 DEBUG printf("back-to-top-of-repeat-block count=%d\n", (int)irept->ir_count);
689                 irept->ir_nextln = irept->ir_firstln;   // copy first line
690
691                 if (irept->ir_count-- == 0)
692                 {
693                         DEBUG printf("end-repeat-block\n");
694                         return NULL;
695                 }
696
697                 strp = irept->ir_nextln;
698         }
699
700         strcpy(irbuf, (char *)(irept->ir_nextln + 1));
701         DEBUG printf("repeat line='%s'\n", irbuf);
702         irept->ir_nextln = (LONG *)*strp;
703
704         return irbuf;
705 }
706
707
708 //
709 // Include a source file used at the root, and for ".include" files
710 //
711 int include(int handle, char * fname)
712 {
713         // Debug mode
714         if (debug)
715                 printf("[include: %s, cfileno=%u]\n", fname, cfileno);
716
717         // Alloc and initialize include-descriptors
718         INOBJ * inobj = a_inobj(SRC_IFILE);
719         IFILE * ifile = inobj->inobj.ifile;
720
721         ifile->ifhandle = handle;                               // Setup file handle
722         ifile->ifind = ifile->ifcnt = 0;                // Setup buffer indices
723         ifile->ifoldlineno = curlineno;                 // Save old line number
724         ifile->ifoldfname = curfname;                   // Save old filename
725         ifile->ifno = cfileno;                                  // Save old file number
726
727         // NB: This *must* be preincrement, we're adding one to the filecount here!
728         cfileno = ++filecount;                                  // Compute NEW file number
729         curfname = strdup(fname);                               // Set current filename (alloc storage)
730         curlineno = 0;                                                  // Start on line zero
731
732         // Add another file to the file-record
733         FILEREC * fr = (FILEREC *)malloc(sizeof(FILEREC));
734         fr->frec_next = NULL;
735         fr->frec_name = curfname;
736
737         if (last_fr == NULL)
738                 filerec = fr;                                           // Add first filerec
739         else
740                 last_fr->frec_next = fr;                        // Append to list of filerecs
741
742         last_fr = fr;
743         DEBUG printf("[include: curfname: %s, cfileno=%u]\n", curfname, cfileno);
744
745         return OK;
746 }
747
748
749 //
750 // Pop the current input level
751 //
752 int fpop(void)
753 {
754         IFILE * ifile;
755         IMACRO * imacro;
756         LONG * p, * p1;
757         INOBJ * inobj = cur_inobj;
758
759         if (inobj != NULL)
760         {
761                 // Pop IFENT levels until we reach the conditional assembly context we
762                 // were at when the input object was entered.
763                 int numUnmatched = 0;
764
765                 while (ifent != inobj->in_ifent)
766                 {
767                         if (d_endif() != 0)             // Something bad happened during endif parsing?
768                                 return -1;                      // If yes, bail instead of getting stuck in a loop
769
770                         numUnmatched++;
771                 }
772
773                 // Give a warning to the user that we had to wipe their bum for them
774                 if (numUnmatched > 0)
775                         warni("missing %d .endif(s)", numUnmatched);
776
777                 tok = inobj->in_otok;           // Restore tok and otok
778                 etok = inobj->in_etok;
779
780                 switch (inobj->in_type)
781                 {
782                 case SRC_IFILE:                         // Pop and release an IFILE
783                         if (debug)
784                                 printf("[Leaving: %s]\n", curfname);
785
786                         ifile = inobj->inobj.ifile;
787                         ifile->if_link = f_ifile;
788                         f_ifile = ifile;
789                         close(ifile->ifhandle);                 // Close source file
790 if (debug)      printf("[fpop (pre):  curfname=%s]\n", curfname);
791                         curfname = ifile->ifoldfname;   // Set current filename
792 if (debug)      printf("[fpop (post): curfname=%s]\n", curfname);
793 if (debug)      printf("[fpop: (pre)  cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno);
794                         curlineno = ifile->ifoldlineno; // Set current line#
795                         DEBUG printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno);
796                         cfileno = ifile->ifno;                  // Restore current file number
797 if (debug)      printf("[fpop: (post) cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno);
798                         break;
799                 case SRC_IMACRO:                                        // Pop and release an IMACRO
800                         imacro = inobj->inobj.imacro;
801                         imacro->im_link = f_imacro;
802                         f_imacro = imacro;
803                         break;
804                 case SRC_IREPT:                                         // Pop and release an IREPT
805                         DEBUG printf("dealloc IREPT\n");
806                         p = inobj->inobj.irept->ir_firstln;
807
808                         while (p != NULL)
809                         {
810                                 p1 = (LONG *)*p;
811                                 p = p1;
812                         }
813
814                         break;
815                 }
816
817                 cur_inobj = inobj->in_link;
818                 inobj->in_link = f_inobj;
819                 f_inobj = inobj;
820         }
821
822         return 0;
823 }
824
825
826 //
827 // Get line from file into buf, return NULL on EOF or ptr to the start of a
828 // null-term line
829 //
830 char * GetNextLine(void)
831 {
832         int i, j;
833         char * p, * d;
834         int readamt = -1;                                               // 0 if last read() yeilded 0 bytes
835         IFILE * fl = cur_inobj->inobj.ifile;
836
837         for(;;)
838         {
839                 // Scan for next end-of-line; handle stupid text formats by treating
840                 // \r\n the same as \n. (lone '\r' at end of buffer means we have to
841                 // check for '\n').
842                 d = &fl->ifbuf[fl->ifind];
843
844                 for(p=d, i=0, j=fl->ifcnt; i<j; i++, p++)
845                 {
846                         if (*p == '\r' || *p == '\n')
847                         {
848                                 i++;
849
850                                 if (*p == '\r')
851                                 {
852                                         if (i >= j)
853                                                 break;  // Need to read more, then look for '\n' to eat
854                                         else if (p[1] == '\n')
855                                                 i++;
856                                 }
857
858                                 // Cover up the newline with end-of-string sentinel
859                                 *p = '\0';
860
861                                 fl->ifind += i;
862                                 fl->ifcnt -= i;
863                                 return d;
864                         }
865                 }
866
867                 // Handle hanging lines by ignoring them (Input file is exhausted, no
868                 // \r or \n on last line)
869                 // Shamus: This is retarded. Never ignore any input!
870                 if (!readamt && fl->ifcnt)
871                 {
872 #if 0
873                         fl->ifcnt = 0;
874                         *p = '\0';
875                         return NULL;
876 #else
877                         // Really should check to see if we're at the end of the buffer!
878                         // :-P
879                         fl->ifbuf[fl->ifind + fl->ifcnt] = '\0';
880                         fl->ifcnt = 0;
881                         return &fl->ifbuf[fl->ifind];
882 #endif
883                 }
884
885                 // Truncate and return absurdly long lines.
886                 if (fl->ifcnt >= QUANTUM)
887                 {
888                         fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
889                         fl->ifcnt = 0;
890                         return &fl->ifbuf[fl->ifind];
891                 }
892
893                 // Relocate what's left of a line to the beginning of the buffer, and
894                 // read some more of the file in; return NULL if the buffer's empty and
895                 // on EOF.
896                 if (fl->ifind != 0)
897                 {
898                         p = &fl->ifbuf[fl->ifind];
899                         d = &fl->ifbuf[fl->ifcnt & 1];
900
901                         for(i=0; i<fl->ifcnt; i++)
902                                 *d++ = *p++;
903
904                         fl->ifind = fl->ifcnt & 1;
905                 }
906
907                 readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM);
908
909                 if (readamt < 0)
910                         return NULL;
911
912                 if ((fl->ifcnt += readamt) == 0)
913                         return NULL;
914         }
915 }
916
917
918 //
919 // Tokenize a line
920 //
921 int TokenizeLine(void)
922 {
923         char * ln = NULL;                       // Ptr to current position in line
924         char * p;                                       // Random character ptr
925         TOKEN * tk;                                     // Token-deposit ptr
926         int state = 0;                          // State for keyword detector
927         int j = 0;                                      // Var for keyword detector
928         char c;                                         // Random char
929         VALUE v;                                        // Random value
930         char * nullspot = NULL;         // Spot to clobber for SYMBOL termination
931         int stuffnull;                          // 1:terminate SYMBOL '\0' at *nullspot
932         char c1;
933         int stringNum = 0;                      // Pointer to string locations in tokenized line
934
935 retry:
936
937         if (cur_inobj == NULL)                                  // Return EOF if input stack is empty
938                 return TKEOF;
939
940         // Get another line of input from the current input source: a file, a
941         // macro, or a repeat-block
942         switch (cur_inobj->in_type)
943         {
944         // Include-file:
945         // o  handle EOF;
946         // o  bump source line number;
947         // o  tag the listing-line with a space;
948         // o  kludge lines generated by Alcyon C.
949         case SRC_IFILE:
950                 if ((ln = GetNextLine()) == NULL)
951                 {
952 if (debug) printf("TokenizeLine: Calling fpop() from SRC_IFILE...\n");
953                         if (fpop() == 0)                                // Pop input level
954                                 goto retry;                                     // Try for more lines
955                         else
956                         {
957                                 ifent->if_prev = (IFENT *) - 1; //Signal Assemble() that we have reached EOF with unbalanced if/endifs
958                                 return TKEOF;
959                         }
960                 }
961
962                 curlineno++;                                            // Bump line number
963                 lntag = SPACE;
964
965                 if (as68_flag)
966                 {
967                         // AS68 compatibility, throw away all lines starting with
968                         // back-quotes, tildes, or '*'
969                         // On other lines, turn the first '*' into a semi-colon.
970                         if (*ln == '`' || *ln == '~' || *ln == '*')
971                                 *ln = ';';
972                         else
973                         {
974                                 for(p=ln; *p!=EOS; p++)
975                                 {
976                                         if (*p == '*')
977                                         {
978                                                 *p = ';';
979                                                 break;
980                                         }
981                                 }
982                         }
983                 }
984
985                 break;
986         // Macro-block:
987         // o  Handle end-of-macro;
988         // o  tag the listing-line with an at (@) sign.
989         case SRC_IMACRO:
990                 if ((ln = GetNextMacroLine()) == NULL)
991                 {
992                         if (ExitMacro() == 0)                   // Exit macro (pop args, do fpop(), etc)
993                                 goto retry;                                     // Try for more lines...
994                         else
995                                 return TKEOF;                           // Oops, we got a non zero return code, signal EOF
996                 }
997
998                 lntag = '@';
999                 break;
1000         // Repeat-block:
1001         // o  Handle end-of-repeat-block;
1002         // o  tag the listing-line with a pound (#) sign.
1003         case SRC_IREPT:
1004                 if ((ln = GetNextRepeatLine()) == NULL)
1005                 {
1006 if (debug) printf("TokenizeLine: Calling fpop() from SRC_IREPT...\n");
1007                         fpop();
1008                         goto retry;
1009                 }
1010
1011                 lntag = '#';
1012                 break;
1013         }
1014
1015         // Save text of the line.  We only do this during listings and within
1016         // macro-type blocks, since it is expensive to unconditionally copy every
1017         // line.
1018         if (lnsave)
1019                 strcpy(lnbuf, ln);
1020
1021         // General house-keeping
1022         tok = tokeol;                   // Set "tok" to EOL in case of error
1023         tk = etok;                              // Reset token ptr
1024         stuffnull = 0;                  // Don't stuff nulls
1025         totlines++;                             // Bump total #lines assembled
1026
1027         // See if the entire line is a comment. This is a win if the programmer
1028         // puts in lots of comments
1029         if (*ln == '*' || *ln == ';' || ((*ln == '/') && (*(ln + 1) == '/')))
1030                 goto goteol;
1031
1032         // Main tokenization loop;
1033         // o  skip whitespace;
1034         // o  handle end-of-line;
1035         // o  handle symbols;
1036         // o  handle single-character tokens (operators, etc.);
1037         // o  handle multiple-character tokens (constants, strings, etc.).
1038         for(; *ln!=EOS;)
1039         {
1040                 // Skip whitespace, handle EOL
1041                 while ((int)chrtab[*ln] & WHITE)
1042                         ln++;
1043
1044                 // Handle EOL, comment with ';'
1045                 if (*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln + 1) == '/')))
1046                         break;
1047
1048                 // Handle start of symbol. Symbols are null-terminated in place. The
1049                 // termination is always one symbol behind, since there may be no place
1050                 // for a null in the case that an operator immediately follows the name.
1051                 c = chrtab[*ln];
1052
1053                 if (c & STSYM)
1054                 {
1055                         if (stuffnull)                  // Terminate old symbol from previous pass
1056                                 *nullspot = EOS;
1057
1058                         v = 0;                                  // Assume no DOT attrib follows symbol
1059                         stuffnull = 1;
1060
1061                         // In some cases, we need to check for a DOTx at the *beginning*
1062                         // of a symbol, as the "start" of the line we're currently looking
1063                         // at could be somewhere in the middle of that line!
1064                         if (*ln == '.')
1065                         {
1066                                 // Make sure that it's *only* a .[bwsl] following, and not the
1067                                 // start of a local symbol:
1068                                 if ((chrtab[*(ln + 1)] & DOT)
1069                                         && (dotxtab[*(ln + 1)] != 0)
1070                                         && !(chrtab[*(ln + 2)] & CTSYM))
1071                                 {
1072                                         // We found a legitimate DOTx construct, so add it to the
1073                                         // token stream:
1074                                         ln++;
1075                                         stuffnull = 0;
1076                                         *tk++ = (TOKEN)dotxtab[*ln++];
1077                                         continue;
1078                                 }
1079                         }
1080
1081                         p = nullspot = ln++;    // Nullspot -> start of this symbol
1082
1083                         // Find end of symbol (and compute its length)
1084                         for(j=1; (int)chrtab[*ln]&CTSYM; j++)
1085                                 ln++;
1086
1087                         // Handle "DOT" special forms (like ".b") that follow a normal
1088                         // symbol or keyword:
1089                         if (*ln == '.')
1090                         {
1091                                 *ln++ = EOS;            // Terminate symbol
1092                                 stuffnull = 0;          // And never try it again
1093
1094                                 // Character following the `.' must have a DOT attribute, and
1095                                 // the chararacter after THAT one must not have a start-symbol
1096                                 // attribute (to prevent symbols that look like, for example,
1097                                 // "zingo.barf", which might be a good idea anyway....)
1098                                 if (((chrtab[*ln] & DOT) == 0) || (dotxtab[*ln] == 0))
1099                                         return error("[bwsl] must follow '.' in symbol");
1100
1101                                 v = (VALUE)dotxtab[*ln++];
1102
1103                                 if (chrtab[*ln] & CTSYM)
1104                                         return error("misuse of '.', not allowed in symbols");
1105                         }
1106
1107                         // If the symbol is small, check to see if it's really the name of
1108                         // a register.
1109                         if (j <= KWSIZE)
1110                         {
1111                                 for(state=0; state>=0;)
1112                                 {
1113                                         j = (int)tolowertab[*p++];
1114                                         j += kwbase[state];
1115
1116                                         if (kwcheck[j] != state)
1117                                         {
1118                                                 j = -1;
1119                                                 break;
1120                                         }
1121
1122                                         if (*p == EOS || p == ln)
1123                                         {
1124                                                 j = kwaccept[j];
1125                                                 break;
1126                                         }
1127
1128                                         state = kwtab[j];
1129                                 }
1130                         }
1131                         else
1132                         {
1133                                 j = -1;
1134                         }
1135
1136                         // Make j = -1 if user tries to use a RISC register while in 68K mode
1137                         if (!(rgpu || rdsp) && ((TOKEN)j >= KW_R0 && (TOKEN)j <= KW_R31))
1138                         {
1139                                 j = -1;
1140                         }
1141
1142                         // Make j = -1 if time, date etc with no preceeding ^^
1143                         // defined, referenced, streq, macdef, date and time
1144                         switch ((TOKEN)j)
1145                         {
1146                         case 112:   // defined
1147                         case 113:   // referenced
1148                         case 118:   // streq
1149                         case 119:   // macdef
1150                         case 120:   // time
1151                         case 121:   // date
1152                                 j = -1;
1153                         }
1154
1155                         // If not tokenized keyword OR token was not found
1156                         if ((j < 0) || (state < 0))
1157                         {
1158                                 *tk++ = SYMBOL;
1159 //#warning
1160 //problem here: nullspot is a char * but TOKEN is a uint32_t. On a 64-bit
1161 //system, this will cause all kinds of mischief.
1162 #if 0
1163                                 *tk++ = (TOKEN)nullspot;
1164 #else
1165                                 string[stringNum] = nullspot;
1166                                 *tk++ = stringNum;
1167                                 stringNum++;
1168 #endif
1169                         }
1170                         else
1171                         {
1172                                 *tk++ = (TOKEN)j;
1173                                 stuffnull = 0;
1174                         }
1175
1176                         if (v)                                                  // Record attribute token (if any)
1177                                 *tk++ = (TOKEN)v;
1178
1179                         if (stuffnull)                                  // Arrange for string termination on next pass
1180                                 nullspot = ln;
1181
1182                         continue;
1183                 }
1184
1185                 // Handle identity tokens
1186                 if (c & SELF)
1187                 {
1188                         *tk++ = *ln++;
1189                         continue;
1190                 }
1191
1192                 // Handle multiple-character tokens
1193                 if (c & MULTX)
1194                 {
1195
1196                         switch (*ln++)
1197                         {
1198                         case '!':               // ! or !=
1199                                 if (*ln == '=')
1200                                 {
1201                                         *tk++ = NE;
1202                                         ++ln;
1203                                 }
1204                                 else
1205                                         *tk++ = '!';
1206
1207                                 continue;
1208                         case '\'':              // 'string'
1209                                 if (m6502)
1210                                 {
1211                                         // Hardcoded for now, maybe this will change in the future
1212                                         *tk++ = STRINGA8;
1213                                         goto dostring;
1214                                 }
1215                                 // Fall through
1216                         case '\"':              // "string"
1217                                 *tk++ = STRING;
1218 dostring:
1219                                 c1 = ln[-1];
1220                                 string[stringNum] = ln;
1221                                 *tk++ = stringNum;
1222                                 stringNum++;
1223
1224                                 for(p=ln; *ln!=EOS && *ln!=c1;)
1225                                 {
1226                                         c = *ln++;
1227
1228                                         if (c == '\\')
1229                                         {
1230                                                 switch (*ln++)
1231                                                 {
1232                                                 case EOS:
1233                                                         return(error("unterminated string"));
1234                                                 case 'e':
1235                                                         c = '\033';
1236                                                         break;
1237                                                 case 'n':
1238                                                         c = '\n';
1239                                                         break;
1240                                                 case 'b':
1241                                                         c = '\b';
1242                                                         break;
1243                                                 case 't':
1244                                                         c = '\t';
1245                                                         break;
1246                                                 case 'r':
1247                                                         c = '\r';
1248                                                         break;
1249                                                 case 'f':
1250                                                         c = '\f';
1251                                                         break;
1252                                                 case '\"':
1253                                                         c = '\"';
1254                                                         break;
1255                                                 case '\'':
1256                                                         c = '\'';
1257                                                         break;
1258                                                 case '\\':
1259                                                         c = '\\';
1260                                                         break;
1261                                                 default:
1262                                                         warn("bad backslash code in string");
1263                                                         ln--;
1264                                                         break;
1265                                                 }
1266                                         }
1267
1268                                         *p++ = c;
1269                                 }
1270
1271                                 if (*ln++ != c1)
1272                                         return error("unterminated string");
1273
1274                                 *p++ = EOS;
1275                                 continue;
1276                         case '$':               // $, hex constant
1277                                 if (chrtab[*ln] & HDIGIT)
1278                                 {
1279                                         v = 0;
1280
1281                                         // Parse the hex value
1282                                         while (hextab[*ln] >= 0)
1283                                                 v = (v << 4) + (int)hextab[*ln++];
1284
1285                                         if (*ln == '.')
1286                                         {
1287                                                 if (obj_format == BSD)
1288                                                 {
1289                                                         if ((*(ln + 1) & 0xDF) == 'B')
1290                                                         {
1291                                                                 v &= 0x000000FF;
1292                                                                 ln += 2;
1293                                                         }
1294                                                         else if ((*(ln + 1) & 0xDF) == 'W')
1295                                                         {
1296                                                                 v &= 0x0000FFFF;
1297                                                                 ln += 2;
1298                                                         }
1299                                                         else if ((*(ln + 1) & 0xDF) == 'L')
1300                                                         {
1301                                                                 ln += 2;
1302                                                         }
1303                                                 }
1304                                         }
1305
1306                                         *tk++ = CONST;
1307                                         *tk++ = v;
1308
1309                                         if (obj_format == ALCYON)
1310                                         {
1311                                                 if (*ln == '.')
1312                                                 {
1313                                                         if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1314                                                         {
1315                                                                 *tk++ = DOTW;
1316                                                                 ln += 2;
1317                                                         }
1318                                                         else if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1319                                                         {
1320                                                                 *tk++ = DOTL;
1321                                                                 ln += 2;
1322                                                         }
1323                                                 }
1324                                         }
1325                                 }
1326                                 else
1327                                         *tk++ = '$';
1328
1329                                 continue;
1330                         case '<':               // < or << or <> or <=
1331                                 switch (*ln)
1332                                 {
1333                                 case '<':
1334                                         *tk++ = SHL;
1335                                         ++ln;
1336                                         continue;
1337                                 case '>':
1338                                         *tk++ = NE;
1339                                         ++ln;
1340                                         continue;
1341                                 case '=':
1342                                         *tk++ = LE;
1343                                         ++ln;
1344                                         continue;
1345                                 default:
1346                                         *tk++ = '<';
1347                                         continue;
1348                                 }
1349                         case ':':               // : or ::
1350                                 if (*ln == ':')
1351                                 {
1352                                         *tk++ = DCOLON;
1353                                         ++ln;
1354                                 }
1355                                 else
1356                                         *tk++ = ':';
1357
1358                                 continue;
1359                         case '=':               // = or ==
1360                                 if (*ln == '=')
1361                                 {
1362                                         *tk++ = DEQUALS;
1363                                         ++ln;
1364                                 }
1365                                 else
1366                                         *tk++ = '=';
1367
1368                                 continue;
1369                         case '>':               // > or >> or >=
1370                                 switch (*ln)
1371                                 {
1372                                 case '>':
1373                                         *tk++ = SHR;
1374                                         ln++;
1375                                         continue;
1376                                 case '=':
1377                                         *tk++ = GE;
1378                                         ln++;
1379                                         continue;
1380                                 default:
1381                                         *tk++ = '>';
1382                                         continue;
1383                                 }
1384                         case '%':               // % or binary constant
1385                                 if (*ln < '0' || *ln > '1')
1386                                 {
1387                                         *tk++ = '%';
1388                                         continue;
1389                                 }
1390
1391                                 v = 0;
1392
1393                                 while (*ln >= '0' && *ln <= '1')
1394                                         v = (v << 1) + *ln++ - '0';
1395
1396                                 if (*ln == '.')
1397                                 {
1398                                         if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1399                                         {
1400                                                 v &= 0x000000FF;
1401                                                 ln += 2;
1402                                         }
1403
1404                                         if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1405                                         {
1406                                                 v &= 0x0000FFFF;
1407                                                 ln += 2;
1408                                         }
1409
1410                                         if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1411                                         {
1412                                                 ln += 2;
1413                                         }
1414                                 }
1415
1416                                 *tk++ = CONST;
1417                                 *tk++ = v;
1418                                 continue;
1419                         case '@':               // @ or octal constant
1420                                 if (*ln < '0' || *ln > '7')
1421                                 {
1422                                         *tk++ = '@';
1423                                         continue;
1424                                 }
1425
1426                                 v = 0;
1427
1428                                 while (*ln >= '0' && *ln <= '7')
1429                                         v = (v << 3) + *ln++ - '0';
1430
1431                                 if (*ln == '.')
1432                                 {
1433                                         if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1434                                         {
1435                                                 v &= 0x000000FF;
1436                                                 ln += 2;
1437                                         }
1438
1439                                         if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1440                                         {
1441                                                 v &= 0x0000FFFF;
1442                                                 ln += 2;
1443                                         }
1444
1445                                         if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1446                                         {
1447                                                 ln += 2;
1448                                         }
1449                                 }
1450
1451                                 *tk++ = CONST;
1452                                 *tk++ = v;
1453                                 continue;
1454                         case '^':               // ^ or ^^ <operator-name>
1455                                 if (*ln != '^')
1456                                 {
1457                                         *tk++ = '^';
1458                                         continue;
1459                                 }
1460
1461                                 if (((int)chrtab[*++ln] & STSYM) == 0)
1462                                 {
1463                                         error("invalid symbol following ^^");
1464                                         continue;
1465                                 }
1466
1467                                 p = ln++;
1468
1469                                 while ((int)chrtab[*ln] & CTSYM)
1470                                         ++ln;
1471
1472                                 for(state=0; state>=0;)
1473                                 {
1474                                         // Get char, convert to lowercase
1475                                         j = *p++;
1476
1477                                         if (j >= 'A' && j <= 'Z')
1478                                                 j += 0x20;
1479
1480                                         j += kwbase[state];
1481
1482                                         if (kwcheck[j] != state)
1483                                         {
1484                                                 j = -1;
1485                                                 break;
1486                                         }
1487
1488                                         if (*p == EOS || p == ln)
1489                                         {
1490                                                 j = kwaccept[j];
1491                                                 break;
1492                                         }
1493
1494                                         state = kwtab[j];
1495                                 }
1496
1497                                 if (j < 0 || state < 0)
1498                                 {
1499                                         error("unknown symbol following ^^");
1500                                         continue;
1501                                 }
1502
1503                                 *tk++ = (TOKEN)j;
1504                                 continue;
1505                         default:
1506                                 interror(2);    // Bad MULTX entry in chrtab
1507                                 continue;
1508                         }
1509                 }
1510
1511                 // Handle decimal constant
1512                 if (c & DIGIT)
1513                 {
1514                         v = 0;
1515
1516                         while ((int)chrtab[*ln] & DIGIT)
1517                                 v = (v * 10) + *ln++ - '0';
1518
1519                         // See if there's a .[bwl] after the constant & deal with it if so
1520                         if (*ln == '.')
1521                         {
1522                                 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1523                                 {
1524                                         v &= 0x000000FF;
1525                                         ln += 2;
1526                                 }
1527                                 else if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1528                                 {
1529                                         v &= 0x0000FFFF;
1530                                         ln += 2;
1531                                 }
1532                                 else if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1533                                 {
1534                                         ln += 2;
1535                                 }
1536                         }
1537
1538                         *tk++ = CONST;
1539                         *tk++ = v;
1540 //printf("CONST: %i\n", v);
1541                         continue;
1542                 }
1543
1544                 // Handle illegal character
1545                 return error("illegal character");
1546         }
1547
1548         // Terminate line of tokens and return "success."
1549
1550 goteol:
1551         tok = etok;                                                             // Set tok to beginning of line
1552
1553         if (stuffnull)                                                  // Terminate last SYMBOL
1554                 *nullspot = EOS;
1555
1556         *tk++ = EOL;
1557
1558         return OK;
1559 }
1560
1561
1562 //
1563 // .GOTO <label>        goto directive
1564 //
1565 // The label is searched for starting from the first line of the current,
1566 // enclosing macro definition. If no enclosing macro exists, an error is
1567 // generated.
1568 //
1569 // A label is of the form:
1570 //
1571 // :<name><whitespace>
1572 //
1573 // The colon must appear in column 1.  The label is stripped prior to macro
1574 // expansion, and is NOT subject to macro expansion.  The whitespace may also
1575 // be EOL.
1576 //
1577 int d_goto(WORD unused)
1578 {
1579         // Setup for the search
1580         if (*tok != SYMBOL)
1581                 return error("missing label");
1582
1583         char * sym = string[tok[1]];
1584         tok += 2;
1585
1586         if (cur_inobj->in_type != SRC_IMACRO)
1587                 return error("goto not in macro");
1588
1589         IMACRO * imacro = cur_inobj->inobj.imacro;
1590         struct LineList * defln = imacro->im_macro->lineList;
1591
1592         // Attempt to find the label, starting with the first line.
1593         for(; defln!=NULL; defln=defln->next)
1594         {
1595                 // Must start with a colon
1596                 if (defln->line[0] == ':')
1597                 {
1598                         // Compare names (sleazo string compare)
1599                         char * s1 = sym;
1600                         char * s2 = defln->line;
1601
1602                         // Either we will match the strings to EOS on both, or we will
1603                         // match EOS on string 1 to whitespace on string 2. Otherwise, we
1604                         // have no match.
1605                         while ((*s1 == *s2) || ((*s1 == EOS) && (chrtab[*s2] & WHITE)))
1606                         {
1607                                 // If we reached the end of string 1 (sym), we're done.
1608                                 // Note that we're also checking for the end of string 2 as
1609                                 // well, since we've established they're equal above.
1610                                 if (*s1 == EOS)
1611                                 {
1612                                         // Found the label, set new macro next-line and return.
1613                                         imacro->im_nextln = defln;
1614                                         return 0;
1615                                 }
1616
1617                                 s1++;
1618                                 s2++;
1619                         }
1620                 }
1621         }
1622
1623         return error("goto label not found");
1624 }
1625
1626
1627 void DumpTokenBuffer(void)
1628 {
1629         TOKEN * t;
1630         printf("Tokens [%X]: ", sloc);
1631
1632         for(t=tokbuf; *t!=EOL; t++)
1633         {
1634                 if (*t == COLON)
1635                         printf("[COLON]");
1636                 else if (*t == CONST)
1637                 {
1638                         t++;
1639                         printf("[CONST: $%X]", (uint32_t)*t);
1640                 }
1641                 else if (*t == ACONST)
1642                         printf("[ACONST]");
1643                 else if (*t == STRING)
1644                 {
1645                         t++;
1646                         printf("[STRING:\"%s\"]", string[*t]);
1647                 }
1648                 else if (*t == SYMBOL)
1649                 {
1650                         t++;
1651                         printf("[SYMBOL:\"%s\"]", string[*t]);
1652                 }
1653                 else if (*t == EOS)
1654                         printf("[EOS]");
1655                 else if (*t == TKEOF)
1656                         printf("[TKEOF]");
1657                 else if (*t == DEQUALS)
1658                         printf("[DEQUALS]");
1659                 else if (*t == SET)
1660                         printf("[SET]");
1661                 else if (*t == REG)
1662                         printf("[REG]");
1663                 else if (*t == DCOLON)
1664                         printf("[DCOLON]");
1665                 else if (*t == GE)
1666                         printf("[GE]");
1667                 else if (*t == LE)
1668                         printf("[LE]");
1669                 else if (*t == NE)
1670                         printf("[NE]");
1671                 else if (*t == SHR)
1672                         printf("[SHR]");
1673                 else if (*t == SHL)
1674                         printf("[SHL]");
1675                 else if (*t == UNMINUS)
1676                         printf("[UNMINUS]");
1677                 else if (*t == DOTB)
1678                         printf("[DOTB]");
1679                 else if (*t == DOTW)
1680                         printf("[DOTW]");
1681                 else if (*t == DOTL)
1682                         printf("[DOTL]");
1683                 else if (*t == DOTI)
1684                         printf("[DOTI]");
1685                 else if (*t == ENDEXPR)
1686                         printf("[ENDEXPR]");
1687                 else if (*t == CR_ABSCOUNT)
1688                         printf("[CR_ABSCOUNT]");
1689                 else if (*t == CR_DEFINED)
1690                         printf("[CR_DEFINED]");
1691                 else if (*t == CR_REFERENCED)
1692                         printf("[CR_REFERENCED]");
1693                 else if (*t == CR_STREQ)
1694                         printf("[CR_STREQ]");
1695                 else if (*t == CR_MACDEF)
1696                         printf("[CR_MACDEF]");
1697                 else if (*t == CR_TIME)
1698                         printf("[CR_TIME]");
1699                 else if (*t == CR_DATE)
1700                         printf("[CR_DATE]");
1701                 else if (*t >= 0x20 && *t <= 0x2F)
1702                         printf("[%c]", (char)*t);
1703                 else if (*t >= 0x3A && *t <= 0x3F)
1704                         printf("[%c]", (char)*t);
1705                 else if (*t >= 0x80 && *t <= 0x87)
1706                         printf("[D%u]", ((uint32_t)*t) - 0x80);
1707                 else if (*t >= 0x88 && *t <= 0x8F)
1708                         printf("[A%u]", ((uint32_t)*t) - 0x88);
1709                 else
1710                         printf("[%X:%c]", (uint32_t)*t, (char)*t);
1711         }
1712
1713         printf("[EOL]\n");
1714 }
1715