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