2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // TOKEN.C - Token Handling
4 // Copyright (C) 199x Landon Dyer, 2011-2012 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source Utilised with the Kind Permission of Landon Dyer
15 #define DECL_KW // Declare keyword arrays
16 #define DEF_KW // Declare keyword values
17 #include "kwtab.h" // Incl generated keyword tables & defs
19 int lnsave; // 1; strcpy() text of current line
20 int curlineno; // Current line number
21 int totlines; // Total # of lines
22 int mjump_align = 0; // mjump alignment flag
23 char lntag; // Line tag
24 char * curfname; // Current filename
25 char tolowertab[128]; // Uppercase ==> lowercase
26 char hextab[128]; // Table of hex values
27 char dotxtab[128]; // Table for ".b", ".s", etc.
28 char irbuf[LNSIZ]; // Text for .rept block line
29 char lnbuf[LNSIZ]; // Text of current line
30 WORD filecount; // Unique file number counter
31 WORD cfileno; // Current file number
32 TOKEN * tok; // Ptr to current token
33 TOKEN * etok; // Ptr past last token in tokbuf[]
34 TOKEN tokeol[1] = {EOL}; // Bailout end-of-line token
35 char * string[TOKBUFSIZE]; // Token buffer string pointer storage
37 // File record, used to maintain a list of every include file ever visited
38 #define FILEREC struct _filerec
48 INOBJ * cur_inobj; // Ptr current input obj (IFILE/IMACRO)
49 static INOBJ * f_inobj; // Ptr list of free INOBJs
50 static IFILE * f_ifile; // Ptr list of free IFILEs
51 static IMACRO * f_imacro; // Ptr list of free IMACROs
53 static TOKEN tokbuf[TOKBUFSIZE]; // Token buffer (stack-like, all files)
56 ILLEG, ILLEG, ILLEG, ILLEG, // NUL SOH STX ETX
57 ILLEG, ILLEG, ILLEG, ILLEG, // EOT ENQ ACK BEL
58 ILLEG, WHITE, ILLEG, ILLEG, // BS HT LF VT
59 WHITE, ILLEG, ILLEG, ILLEG, // FF CR SO SI
61 ILLEG, ILLEG, ILLEG, ILLEG, // DLE DC1 DC2 DC3
62 ILLEG, ILLEG, ILLEG, ILLEG, // DC4 NAK SYN ETB
63 ILLEG, ILLEG, ILLEG, ILLEG, // CAN EM SUB ESC
64 ILLEG, ILLEG, ILLEG, ILLEG, // FS GS RS US
66 WHITE, MULTX, MULTX, SELF, // SP ! " #
67 MULTX+CTSYM, MULTX, SELF, MULTX, // $ % & '
68 SELF, SELF, SELF, SELF, // ( ) * +
69 SELF, SELF, STSYM, SELF, // , - . /
71 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 0 1
72 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 2 3
73 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 4 5
74 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 6 7
75 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 8 9
77 MULTX, MULTX, MULTX, STSYM+CTSYM, // < = > ?
79 MULTX, STSYM+CTSYM+HDIGIT, // @ A
80 (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // B C
81 STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // D E
82 STSYM+CTSYM+HDIGIT, STSYM+CTSYM, // F G
83 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // H I J K
84 (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // L M N O
86 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // P Q R S
87 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // T U V W
88 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF, // X Y Z [
89 SELF, SELF, MULTX, STSYM+CTSYM, // \ ] ^ _
91 ILLEG, STSYM+CTSYM+HDIGIT, // ` a
92 (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // b c
93 STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // d e
94 STSYM+CTSYM+HDIGIT, STSYM+CTSYM, // f g
95 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // h i j k
96 (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // l m n o
98 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // p q r s
99 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // t u v w
100 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF, // x y z {
101 SELF, SELF, SELF, ILLEG // | } ~ DEL
104 // Names of registers
105 static char * regname[] = {
106 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
107 "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
108 "pc", "ssp", "usp", "sr", "ccr"
111 static char * riscregname[] = {
112 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
113 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
114 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
115 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
120 // Make `fnum' the Current `curfname'
122 void setfnum(WORD fnum)
126 for(fr=filerec; fr!=NULL && fnum--; fr=fr->frec_next);
129 curfname = "(*top*)";
131 curfname = fr->frec_name;
136 // Allocate an IFILE or IMACRO
138 INOBJ * a_inobj(int typ)
144 // Allocate and initialize INOBJ first
146 // inobj = (INOBJ *)amem((LONG)sizeof(INOBJ));
147 inobj = (INOBJ *)malloc(sizeof(INOBJ));
151 f_inobj = f_inobj->in_link;
156 case SRC_IFILE: // Alloc and init an IFILE
158 // ifile = (IFILE *)amem((LONG)sizeof(IFILE));
159 ifile = (IFILE *)malloc(sizeof(IFILE));
163 f_ifile = f_ifile->if_link;
166 inobj->inobj.ifile = ifile;
168 case SRC_IMACRO: // Alloc and init an IMACRO
169 if (f_imacro == NULL)
170 // imacro = (IMACRO *)amem((LONG)sizeof(IMACRO));
171 imacro = (IMACRO *)malloc(sizeof(IMACRO));
175 f_imacro = f_imacro->im_link;
178 inobj->inobj.imacro = imacro;
180 case SRC_IREPT: // Alloc and init an IREPT
181 // inobj->inobj.irept = (IREPT *)amem((LONG)sizeof(IREPT));
182 inobj->inobj.irept = (IREPT *)malloc(sizeof(IREPT));
183 DEBUG printf("alloc IREPT\n");
187 // Install INOBJ on top of input stack
188 inobj->in_ifent = ifent; // Record .if context on entry
189 inobj->in_type = (WORD)typ;
190 inobj->in_otok = tok;
191 inobj->in_etok = etok;
192 inobj->in_link = cur_inobj;
200 // Perform macro substitution from 'orig' to 'dest'. Return OK or some error.
201 // A macro reference is in one of two forms:
202 // \name <non-name-character>
204 // A doubled backslash (\\) is compressed to a single backslash (\).
205 // Argument definitions have been pre-tokenized, so we have to turn them back
206 // into text. This means that numbers, in particular, become hex, regardless of
207 // their representation when the macro was invoked. This is a hack.
208 // A label may appear at the beginning of the line:
209 // :<name><whitespace>
210 // (the colon must be in the first column). These labels are stripped before
211 // macro expansion takes place.
213 int ExpandMacro(char * src, char * dest, int destsiz)
216 int questmark; // \? for testing argument existence
217 char mname[128]; // Assume max size of a formal arg name
218 char numbuf[20]; // Buffer for text of CONSTs
222 DEBUG { printf("EM: src=\"%s\"\n", src); }
224 IMACRO * imacro = cur_inobj->inobj.imacro;
225 int macnum = (int)(imacro->im_macro->sattr);
228 char * dst = dest; // Next dest slot
229 char * edst = dest + destsiz - 1; // End + 1(?) of dest buffer
231 // Check for (and skip over) any "label" on the line
237 while (*s != EOS && !(chrtab[*s] & WHITE))
241 s++; // Skip first whitespace
244 // Expand the rest of the line
247 // Copy single character
255 // Do macro expansion
263 case '\\': // \\, \ (collapse to single backslash)
269 case '?': // \? <macro> set `questmark' flag
273 case '#': // \#, number of arguments
274 sprintf(numbuf, "%d", (int)imacro->im_nargs);
276 case '!': // \! size suffix supplied on invocation
277 switch ((int)imacro->im_siz)
279 case SIZN: d = ""; break;
280 case SIZB: d = ".b"; break;
281 case SIZW: d = ".w"; break;
282 case SIZL: d = ".l"; break;
286 case '~': // ==> unique label string Mnnnn...
287 sprintf(numbuf, "M%ud", curuniq);
303 return error("missing argument name");
306 // \n ==> argument number 'n', 0..9
307 if (chrtab[*s] & DIGIT)
317 // Get argument name: \name, \{name}
327 while (chrtab[*s] & CTSYM);
332 for(++s; *s != EOS && *s != '}';)
336 return error("missing '}'");
343 // Lookup the argument and copy its (string) value into the
344 // destination string
345 DEBUG printf("argument='%s'\n", mname);
347 if ((arg = lookup(mname, MACARG, macnum)) == NULL)
348 return errors("undefined argument: '%s'", mname);
351 // Convert a string of tokens (terminated with EOL) back into
352 // text. If an argument is out of range (not specified in the
353 // macro invocation) then it is ignored.
354 i = (int)arg->svalue;
356 DEBUG printf("~argnumber=%d\n", i);
360 if (i < imacro->im_nargs)
365 // 0 if the argument is empty or non-existant,
366 // 1 if the argument is not empty
369 if (tk == NULL || *tk == EOL)
375 *dst++ = (char)(questmark + '0');
379 if (tk != NULL) // arg # is in range, so expand it
383 // Reverse-translation from a token number to a string.
384 // This is a hack. It might be better table-driven.
387 if ((*tk >= KW_D0) && !rdsp && !rgpu)
389 d = regname[(int)*tk++ - KW_D0];
392 else if ((*tk >= KW_R0) && (*tk <= KW_R31))
394 d = riscregname[(int)*tk++ - KW_R0];
402 // d = (char *)*tk++;
406 // d = (char *)*tk++;
428 // Shamus: Changing the format specifier from %lx to %ux caused
429 // the assembler to choke on legitimate code... Need to investigate
430 // this further before changing anything else here!
432 sprintf(numbuf, "$%lx", (LONG)*tk++);
493 *dst++ = (char)*(tk - 1);
498 // If 'd' != NULL, copy string to destination
502 DEBUG printf("d='%s'\n", d);
523 return fatal("line too long as a result of macro expansion");
528 // Get Next Line of Text from a Macro
532 unsigned source_addr;
534 IMACRO * imacro = cur_inobj->inobj.imacro;
535 // LONG * strp = imacro->im_nextln;
536 struct LineList * strp = imacro->im_nextln;
538 if (strp == NULL) // End-of-macro
541 // imacro->im_nextln = (LONG *)*strp;
542 imacro->im_nextln = strp->next;
543 // ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
544 ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
546 if (!strcmp(imacro->im_macro->sname, "mjump") && !mjump_align)
548 // if we need to adjust the alignment of the jump source address to
549 // meet the rules of gpu main execution we need to skip the first nop
550 // of the macro. This is simpler than trying to insert nop's mid macro.
551 source_addr = (orgactive ? orgaddr : sloc);
556 strp = imacro->im_nextln;
561 // imacro->im_nextln = (LONG *)*strp;
562 // ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
563 imacro->im_nextln = strp->next;
564 ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
570 return imacro->im_lnbuf;
575 // Get Next Line of Text from a Repeat Block
580 IREPT * irept = cur_inobj->inobj.irept;
581 LONG * strp = irept->ir_nextln; // initial null
583 // Do repeat at end of .rept block's string list
586 DEBUG printf("back-to-top-of-repeat-block count=%d\n", (int)irept->ir_count);
587 irept->ir_nextln = irept->ir_firstln; // copy first line
589 if (irept->ir_count-- == 0)
591 DEBUG printf("end-repeat-block\n");
595 strp = irept->ir_nextln; //strp
598 strcpy(irbuf, (char *)(irept->ir_nextln + 1));
599 DEBUG printf("repeat line='%s'\n", irbuf);
600 irept->ir_nextln = (LONG *)*strp;
607 // Include a Source File used at the Root, and for ".include" Files
609 int include(int handle, char * fname)
617 printf("[Including: %s]\n", fname);
619 // Alloc and initialize include-descriptors
620 inobj = a_inobj(SRC_IFILE);
621 ifile = inobj->inobj.ifile;
623 ifile->ifhandle = handle; // Setup file handle
624 ifile->ifind = ifile->ifcnt = 0; // Setup buffer indices
625 ifile->ifoldlineno = curlineno; // Save old line number
626 ifile->ifoldfname = curfname; // Save old filename
627 ifile->ifno = cfileno; // Save old file number
628 cfileno = filecount++; // Compute new file number
629 curfname = strdup(fname); // Set current filename (alloc storage)
630 curlineno = 0; // Start on line zero
632 // Add another file to the file-record
633 // fr = (FILEREC *)amem((LONG)sizeof(FILEREC));
634 fr = (FILEREC *)malloc(sizeof(FILEREC));
635 fr->frec_next = NULL;
636 fr->frec_name = curfname;
639 filerec = fr; // Add first filerec
641 last_fr->frec_next = fr; // Append to list of filerecs
650 // Initialize Tokenizer
652 void init_token(void)
655 char * htab = "0123456789abcdefABCDEF"; // Hex character table
657 lnsave = 0; // Don't save lines
658 curfname = ""; // No file, empty filename
659 filecount = (WORD)-1;
660 cfileno = (WORD)-1; // cfileno gets bumped to 0
672 // Initialize hex, "dot" and tolower tables
677 tolowertab[i] = (char)i;
680 for(i=0; htab[i]!=EOS; i++)
681 hextab[htab[i]] = (char)((i < 16) ? i : i - 6);
683 for(i='A'; i<='Z'; i++)
684 tolowertab[i] |= 0x20;
686 // These characters are legal immediately after a period
687 dotxtab['b'] = DOTB; // .b .B .s .S
691 dotxtab['w'] = DOTW; // .w .W
693 dotxtab['l'] = DOTL; // .l .L
695 dotxtab['I'] = DOTI; // .l .L
701 // Pop the Current Input Level
708 INOBJ * inobj = cur_inobj;
712 // Pop IFENT levels until we reach the conditional assembly context we
713 // were at when the input object was entered.
714 while (ifent != inobj->in_ifent)
717 tok = inobj->in_otok; // Restore tok and otok
718 etok = inobj->in_etok;
720 switch (inobj->in_type)
722 case SRC_IFILE: // Pop and release an IFILE
724 printf("[Leaving: %s]\n", curfname);
726 ifile = inobj->inobj.ifile;
727 ifile->if_link = f_ifile;
729 close(ifile->ifhandle); // Close source file
730 curfname = ifile->ifoldfname; // Set current filename
731 curlineno = ifile->ifoldlineno; // Set current line#
732 DEBUG printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno);
733 cfileno = ifile->ifno; // Restore current file number
735 case SRC_IMACRO: // Pop and release an IMACRO
736 imacro = inobj->inobj.imacro;
737 imacro->im_link = f_imacro;
740 case SRC_IREPT: // Pop and release an IREPT
741 DEBUG printf("dealloc IREPT\n");
742 p = inobj->inobj.irept->ir_firstln;
753 cur_inobj = inobj->in_link;
754 inobj->in_link = f_inobj;
763 // Get line from file into buf, return NULL on EOF or ptr to the start of a
770 int readamt = -1; // 0 if last read() yeilded 0 bytes
771 IFILE * fl = cur_inobj->inobj.ifile;
775 // Scan for next end-of-line; handle stupid text formats by treating
776 // \r\n the same as \n. (lone '\r' at end of buffer means we have to
780 d = &fl->ifbuf[fl->ifind];
782 for(p=d; i<j; i++, p++)
784 if (*p == '\r' || *p == '\n')
792 break; // Look for '\n' to eat
794 else if (p[1] == '\n')
808 // Handle hanging lines by ignoring them (Input file is exhausted, no
809 // \r or \n on last line)
810 if (!readamt && fl->ifcnt)
817 // Truncate and return absurdly long lines.
818 if (fl->ifcnt >= QUANTUM)
820 fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
822 return &fl->ifbuf[fl->ifind];
825 // Relocate what's left of a line to the beginning of the buffer, and
826 // read some more of the file in; return NULL if the buffer's empty and
830 p = &fl->ifbuf[fl->ifind];
831 d = &fl->ifbuf[fl->ifcnt & 1];
833 for(i=0; i<fl->ifcnt; i++)
836 fl->ifind = fl->ifcnt & 1;
839 if ((readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM)) < 0)
842 if ((fl->ifcnt += readamt) == 0)
853 char * ln = NULL; // Ptr to current position in line
854 char * p; // Random character ptr
855 TOKEN * tk; // Token-deposit ptr
856 int state = 0; // State for keyword detector
857 int j = 0; // Var for keyword detector
858 char c; // Random char
859 VALUE v; // Random value
860 char * nullspot = NULL; // Spot to clobber for SYMBOL terminatn
861 int stuffnull; // 1:terminate SYMBOL '\0' at *nullspot
863 int stringNum = 0; // Pointer to string locations in tokenized line
867 if (cur_inobj == NULL) // Return EOF if input stack is empty
870 // Get another line of input from the current input source: a file,
871 // a macro, or a repeat-block
872 switch (cur_inobj->in_type)
876 // o bump source line number;
877 // o tag the listing-line with a space;
878 // o kludge lines generated by Alcyon C.
880 if ((ln = getln()) == NULL)
882 fpop(); // Pop input level
883 goto retry; // Try for more lines
886 curlineno++; // Bump line number
891 // AS68 compatibility, throw away all lines starting with
892 // back-quotes, tildes, or '*'
893 // On other lines, turn the first '*' into a semi-colon.
894 if (*ln == '`' || *ln == '~' || *ln == '*')
898 for(p=ln; *p!=EOS; p++)
911 // o Handle end-of-macro;
912 // o tag the listing-line with an at (@) sign.
914 if ((ln = getmln()) == NULL)
916 exitmac(); // Exit macro (pop args, do fpop(), etc)
917 goto retry; // Try for more lines...
923 // o Handle end-of-repeat-block;
924 // o tag the listing-line with a pound (#) sign.
926 if ((ln = getrln()) == NULL)
936 // Save text of the line. We only do this during listings and within
937 // macro-type blocks, since it is expensive to unconditionally copy every
942 // General house-keeping
943 tok = tokeol; // Set "tok" to EOL in case of error
944 tk = etok; // Reset token ptr
945 stuffnull = 0; // Don't stuff nulls
946 totlines++; // Bump total #lines assembled
948 // See if the entire line is a comment. This is a win if the programmer
949 // puts in lots of comments
950 if (*ln == '*' || *ln == ';' || ((*ln == '/') && (*(ln + 1) == '/')))
953 // Main tokenization loop;
954 // o skip whitespace;
955 // o handle end-of-line;
957 // o handle single-character tokens (operators, etc.);
958 // o handle multiple-character tokens (constants, strings, etc.).
961 // Skip whitespace, handle EOL
962 while ((int)chrtab[*ln] & WHITE)
965 // Handle EOL, comment with ';'
966 if (*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln + 1) == '/')))
969 // Handle start of symbol. Symbols are null-terminated in place. The
970 // termination is always one symbol behind, since there may be no place
971 // for a null in the case that an operator immediately follows the name.
976 if (stuffnull) // Terminate old symbol from previous pass
979 v = 0; // Assume no DOT attrib follows symbol
981 p = nullspot = ln++; // Nullspot -> start of this symbol
983 // Find end of symbol (and compute its length)
984 for(j=1; (int)chrtab[*ln]&CTSYM; j++)
987 // Handle "DOT" special forms (like ".b") that follow a normal
988 // symbol or keyword:
991 *ln++ = EOS; // Terminate symbol
992 stuffnull = 0; // And never try it again
994 // Character following the `.' must have a DOT attribute, and
995 // the chararacter after THAT one must not have a start-symbol
996 // attribute (to prevent symbols that look like, for example,
997 // "zingo.barf", which might be a good idea anyway....)
998 if ((((int)chrtab[*ln] & DOT) == 0) || ((int)dotxtab[*ln] <= 0))
999 return error("[bwsl] must follow `.' in symbol");
1001 v = (VALUE)dotxtab[*ln++];
1003 if ((int)chrtab[*ln] & CTSYM)
1004 return error("misuse of `.', not allowed in symbols");
1007 // If the symbol is small, check to see if it's really the name of
1011 for(state=0; state>=0;)
1013 j = (int)tolowertab[*p++];
1016 if (kwcheck[j] != state)
1022 if (*p == EOS || p == ln)
1036 //make j = -1 if time, date etc with no preceeding ^^
1037 //defined, referenced, streq, macdef, date and time
1040 case 112: // defined
1041 case 113: // referenced
1050 if (j < 0 || state < 0)
1054 //problem here: nullspot is a char * but TOKEN is a uint32_t. On a 64-bit system,
1055 //this will cause all kinds of mischief.
1057 *tk++ = (TOKEN)nullspot;
1059 string[stringNum] = nullspot;
1070 if (v) // Record attribute token (if any)
1073 if (stuffnull) // Arrange for string termination on next pass
1079 // Handle identity tokens
1086 // Handle multiple-character tokens
1091 case '!': // ! or !=
1101 case '\'': // 'string'
1102 case '\"': // "string"
1106 // More char * stuffing (8 bytes) into the space of 4 (TOKEN).
1107 // Need to figure out how to fix this crap.
1111 string[stringNum] = ln;
1116 for(p=ln; *ln!=EOS && *ln!=c1;)
1125 return(error("unterminated string"));
1154 warn("bad backslash code in string");
1164 return error("unterminated string");
1168 case '$': // $, hex constant
1169 if ((int)chrtab[*ln] & HDIGIT)
1173 while ((int)hextab[*ln] >= 0)
1174 v = (v << 4) + (int)hextab[*ln++];
1178 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1184 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1190 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1203 case '<': // < or << or <> or <=
1222 case ':': // : or ::
1232 case '=': // = or ==
1242 case '>': // > or >> or >=
1257 case '%': // % or binary constant
1258 if (*ln < '0' || *ln > '1')
1266 while (*ln >= '0' && *ln <= '1')
1267 v = (v << 1) + *ln++ - '0';
1271 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1277 if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1283 if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1292 case '@': // @ or octal constant
1293 if (*ln < '0' || *ln > '7')
1301 while (*ln >= '0' && *ln <= '7')
1302 v = (v << 3) + *ln++ - '0';
1306 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1312 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1318 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1327 case '^': // ^ or ^^ <operator-name>
1334 if (((int)chrtab[*++ln] & STSYM) == 0)
1336 error("invalid symbol following ^^");
1342 while ((int)chrtab[*ln] & CTSYM)
1345 for(state=0; state>=0;)
1347 // Get char, convert to lowercase
1350 if (j >= 'A' && j <= 'Z')
1355 if (kwcheck[j] != state)
1361 if (*p == EOS || p == ln)
1370 if (j < 0 || state < 0)
1372 error("unknown symbol following ^^");
1379 interror(2); // Bad MULTX entry in chrtab
1384 // Handle decimal constant
1389 while ((int)chrtab[*ln] & DIGIT)
1390 v = (v * 10) + *ln++ - '0';
1392 // See if there's a .[bwl] after the constant, & deal with it
1395 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1401 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1407 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1418 // Handle illegal character
1419 return error("illegal character");
1422 // Terminate line of tokens and return "success."
1425 tok = etok; // Set tok to beginning of line
1427 if (stuffnull) // Terminate last SYMBOL
1437 // .GOTO <label> goto directive
1439 // The label is searched for starting from the first line of the current,
1440 // enclosing macro definition. If no enclosing macro exists, an error is
1443 // A label is of the form:
1445 // :<name><whitespace>
1447 // The colon must appear in column 1. The label is stripped prior to macro
1448 // expansion, and is NOT subject to macro expansion. The whitespace may also
1451 //int d_goto(WORD siz) {
1453 int d_goto(WORD unused)
1455 // char * sym; // Label to search for
1456 // LONG * defln; // Macro definition strings
1457 char * s1; // Temps for string comparison
1459 // IMACRO * imacro; // Macro invocation block
1461 // Setup for the search
1463 return error("missing label");
1465 // sym = (char *)tok[1];
1466 char * sym = string[tok[1]];
1469 if (cur_inobj->in_type != SRC_IMACRO)
1470 return error("goto not in macro");
1472 IMACRO * imacro = cur_inobj->inobj.imacro;
1473 // defln = (LONG *)imacro->im_macro->svalue;
1474 struct LineList * defln = imacro->im_macro->lineList;
1476 // Find the label, starting with the first line.
1477 // for(; defln!=NULL; defln=(LONG *)*defln)
1478 for(; defln!=NULL; defln=defln->next)
1480 // if (*(char *)(defln + 1) == ':')
1481 if (defln->line[0] == ':')
1483 // Compare names (sleazo string compare)
1484 // This string compare is not right. Doesn't check for lengths.
1485 #warning "!!! Bad string comparison !!!"
1487 // s2 = (char *)(defln + 1) + 1;
1501 // Found the label, set new macro next-line and return.
1502 if ((*s2 == EOS) || ((int)chrtab[*s2] & WHITE))
1504 imacro->im_nextln = defln;
1510 return error("goto label not found");
1513 void DumpTokenBuffer(void)
1518 for(t=tokbuf; *t!=EOL; t++)
1522 else if (*t == CONST)
1525 printf("[CONST: $%X]", (uint32_t)*t);
1527 else if (*t == ACONST)
1529 else if (*t == STRING)
1530 // printf("[STRING]");
1533 printf("[STRING:\"%s\"]", string[*t]);
1535 else if (*t == SYMBOL)
1538 printf("[SYMBOL:\"%s\"]", string[*t]);
1542 else if (*t == TKEOF)
1544 else if (*t == DEQUALS)
1545 printf("[DEQUALS]");
1550 else if (*t == DCOLON)
1562 else if (*t == UNMINUS)
1563 printf("[UNMINUS]");
1564 else if (*t == DOTB)
1566 else if (*t == DOTW)
1568 else if (*t == DOTL)
1570 else if (*t == DOTI)
1572 else if (*t == ENDEXPR)
1573 printf("[ENDEXPR]");
1574 else if (*t == CR_DEFINED)
1575 printf("[CR_DEFINED]");
1576 else if (*t == CR_REFERENCED)
1577 printf("[CR_REFERENCED]");
1578 else if (*t == CR_STREQ)
1579 printf("[CR_STREQ]");
1580 else if (*t == CR_MACDEF)
1581 printf("[CR_MACDEF]");
1582 else if (*t == CR_TIME)
1583 printf("[CR_TIME]");
1584 else if (*t == CR_DATE)
1585 printf("[CR_DATE]");
1586 else if (*t >= 0x20 && *t <= 0x2F)
1587 printf("[%c]", (char)*t);
1588 else if (*t >= 0x3A && *t <= 0x3F)
1589 printf("[%c]", (char)*t);
1590 else if (*t >= 0x80 && *t <= 0x87)
1591 printf("[D%u]", ((uint32_t)*t) - 0x80);
1592 else if (*t >= 0x88 && *t <= 0x8F)
1593 printf("[A%u]", ((uint32_t)*t) - 0x88);
1595 printf("[%X:%c]", (uint32_t)*t, (char)*t);
1596 // printf("[%X]", (uint32_t)*t);