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*2]; // 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 = malloc(sizeof(INOBJ));
150 f_inobj = f_inobj->in_link;
155 case SRC_IFILE: // Alloc and init an IFILE
157 ifile = malloc(sizeof(IFILE));
161 f_ifile = f_ifile->if_link;
164 inobj->inobj.ifile = ifile;
166 case SRC_IMACRO: // Alloc and init an IMACRO
167 if (f_imacro == NULL)
168 imacro = malloc(sizeof(IMACRO));
172 f_imacro = f_imacro->im_link;
175 inobj->inobj.imacro = imacro;
177 case SRC_IREPT: // Alloc and init an IREPT
178 inobj->inobj.irept = malloc(sizeof(IREPT));
179 DEBUG printf("alloc IREPT\n");
183 // Install INOBJ on top of input stack
184 inobj->in_ifent = ifent; // Record .if context on entry
185 inobj->in_type = (WORD)typ;
186 inobj->in_otok = tok;
187 inobj->in_etok = etok;
188 inobj->in_link = cur_inobj;
196 // Perform macro substitution from 'orig' to 'dest'. Return OK or some error.
197 // A macro reference is in one of two forms:
198 // \name <non-name-character>
200 // A doubled backslash (\\) is compressed to a single backslash (\).
201 // Argument definitions have been pre-tokenized, so we have to turn them back
202 // into text. This means that numbers, in particular, become hex, regardless of
203 // their representation when the macro was invoked. This is a hack.
204 // A label may appear at the beginning of the line:
205 // :<name><whitespace>
206 // (the colon must be in the first column). These labels are stripped before
207 // macro expansion takes place.
209 int ExpandMacro(char * src, char * dest, int destsiz)
212 int questmark; // \? for testing argument existence
213 char mname[128]; // Assume max size of a formal arg name
214 char numbuf[20]; // Buffer for text of CONSTs
217 char ** symbolString;
219 DEBUG { printf("ExM: src=\"%s\"\n", src); }
221 IMACRO * imacro = cur_inobj->inobj.imacro;
222 int macnum = (int)(imacro->im_macro->sattr);
225 char * dst = dest; // Next dest slot
226 char * edst = dest + destsiz - 1; // End + 1(?) of dest buffer
228 // Check for (and skip over) any "label" on the line
234 while (*s != EOS && !(chrtab[*s] & WHITE))
238 s++; // Skip first whitespace
241 // Expand the rest of the line
244 // Copy single character
252 // Do macro expansion
260 case '\\': // \\, \ (collapse to single backslash)
266 case '?': // \? <macro> set `questmark' flag
270 case '#': // \#, number of arguments
271 sprintf(numbuf, "%d", (int)imacro->im_nargs);
273 case '!': // \! size suffix supplied on invocation
274 switch ((int)imacro->im_siz)
276 case SIZN: d = ""; break;
277 case SIZB: d = ".b"; break;
278 case SIZW: d = ".w"; break;
279 case SIZL: d = ".l"; break;
283 case '~': // ==> unique label string Mnnnn...
284 sprintf(numbuf, "M%u", curuniq);
300 return error("missing argument name");
303 // \n ==> argument number 'n', 0..9
304 if (chrtab[*s] & DIGIT)
314 // Get argument name: \name, \{name}
324 while (chrtab[*s] & CTSYM);
329 for(++s; *s != EOS && *s != '}';)
333 return error("missing '}'");
340 // Lookup the argument and copy its (string) value into the
341 // destination string
342 DEBUG printf("argument='%s'\n", mname);
344 if ((arg = lookup(mname, MACARG, macnum)) == NULL)
345 return errors("undefined argument: '%s'", mname);
348 // Convert a string of tokens (terminated with EOL) back into
349 // text. If an argument is out of range (not specified in the
350 // macro invocation) then it is ignored.
351 i = (int)arg->svalue;
353 DEBUG printf("~argnumber=%d (argBase=%u)\n", i, imacro->argBase);
356 if (i < imacro->im_nargs)
361 tk = argPtrs[imacro->argBase + i];
363 tk = imacro->argument[i].token;
364 symbolString = imacro->argument[i].string;
367 // printf("ExM: Preparing to parse argument #%u...\n", i);
374 // 0 if the argument is empty or non-existant,
375 // 1 if the argument is not empty
378 if (tk == NULL || *tk == EOL)
384 *dst++ = (char)(questmark + '0');
388 if (tk != NULL) // arg # is in range, so expand it
392 // Reverse-translation from a token number to a string.
393 // This is a hack. It might be better table-driven.
396 if ((*tk >= KW_D0) && !rdsp && !rgpu)
398 d = regname[(int)*tk++ - KW_D0];
401 else if ((*tk >= KW_R0) && (*tk <= KW_R31))
403 d = riscregname[(int)*tk++ - KW_R0];
412 // d = (char *)*tk++;
415 // This fix should be done for strings too
416 d = symbolString[*tk++];
417 DEBUG printf("ExM: SYMBOL=\"%s\"", d);
422 // d = (char *)*tk++;
425 d = symbolString[*tk++];
446 // Shamus: Changing the format specifier from %lx to %ux caused
447 // the assembler to choke on legitimate code... Need to investigate
448 // this further before changing anything else here!
450 sprintf(numbuf, "$%lx", (LONG)*tk++);
511 *dst++ = (char)*(tk - 1);
516 // If 'd' != NULL, copy string to destination
520 DEBUG printf("d='%s'\n", d);
537 DEBUG { printf("ExM: dst=\"%s\"\n", dest); }
542 DEBUG printf("*** OVERFLOW LINE ***\n%s\n", dest);
543 return fatal("line too long as a result of macro expansion");
548 // Get Next Line of Text from a Macro
552 unsigned source_addr;
554 IMACRO * imacro = cur_inobj->inobj.imacro;
555 // LONG * strp = imacro->im_nextln;
556 struct LineList * strp = imacro->im_nextln;
558 if (strp == NULL) // End-of-macro
561 // imacro->im_nextln = (LONG *)*strp;
562 imacro->im_nextln = strp->next;
563 // ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
564 ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
566 if (!strcmp(imacro->im_macro->sname, "mjump") && !mjump_align)
568 // if we need to adjust the alignment of the jump source address to
569 // meet the rules of gpu main execution we need to skip the first nop
570 // of the macro. This is simpler than trying to insert nop's mid macro.
571 source_addr = (orgactive ? orgaddr : sloc);
576 strp = imacro->im_nextln;
581 // imacro->im_nextln = (LONG *)*strp;
582 // ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
583 imacro->im_nextln = strp->next;
584 ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
590 return imacro->im_lnbuf;
595 // Get Next Line of Text from a Repeat Block
600 IREPT * irept = cur_inobj->inobj.irept;
601 LONG * strp = irept->ir_nextln; // initial null
603 // Do repeat at end of .rept block's string list
606 DEBUG printf("back-to-top-of-repeat-block count=%d\n", (int)irept->ir_count);
607 irept->ir_nextln = irept->ir_firstln; // copy first line
609 if (irept->ir_count-- == 0)
611 DEBUG printf("end-repeat-block\n");
615 strp = irept->ir_nextln; //strp
618 strcpy(irbuf, (char *)(irept->ir_nextln + 1));
619 DEBUG printf("repeat line='%s'\n", irbuf);
620 irept->ir_nextln = (LONG *)*strp;
627 // Include a Source File used at the Root, and for ".include" Files
629 int include(int handle, char * fname)
637 printf("[Including: %s]\n", fname);
639 // Alloc and initialize include-descriptors
640 inobj = a_inobj(SRC_IFILE);
641 ifile = inobj->inobj.ifile;
643 ifile->ifhandle = handle; // Setup file handle
644 ifile->ifind = ifile->ifcnt = 0; // Setup buffer indices
645 ifile->ifoldlineno = curlineno; // Save old line number
646 ifile->ifoldfname = curfname; // Save old filename
647 ifile->ifno = cfileno; // Save old file number
648 cfileno = filecount++; // Compute new file number
649 curfname = strdup(fname); // Set current filename (alloc storage)
650 curlineno = 0; // Start on line zero
652 // Add another file to the file-record
653 // fr = (FILEREC *)amem((LONG)sizeof(FILEREC));
654 fr = (FILEREC *)malloc(sizeof(FILEREC));
655 fr->frec_next = NULL;
656 fr->frec_name = curfname;
659 filerec = fr; // Add first filerec
661 last_fr->frec_next = fr; // Append to list of filerecs
670 // Initialize Tokenizer
672 void init_token(void)
675 char * htab = "0123456789abcdefABCDEF"; // Hex character table
677 lnsave = 0; // Don't save lines
678 curfname = ""; // No file, empty filename
679 filecount = (WORD)-1;
680 cfileno = (WORD)-1; // cfileno gets bumped to 0
692 // Initialize hex, "dot" and tolower tables
697 tolowertab[i] = (char)i;
700 for(i=0; htab[i]!=EOS; i++)
701 hextab[htab[i]] = (char)((i < 16) ? i : i - 6);
703 for(i='A'; i<='Z'; i++)
704 tolowertab[i] |= 0x20;
706 // These characters are legal immediately after a period
707 dotxtab['b'] = DOTB; // .b .B .s .S
711 dotxtab['w'] = DOTW; // .w .W
713 dotxtab['l'] = DOTL; // .l .L
715 dotxtab['I'] = DOTI; // .l .L
721 // Pop the Current Input Level
728 INOBJ * inobj = cur_inobj;
732 // Pop IFENT levels until we reach the conditional assembly context we
733 // were at when the input object was entered.
734 while (ifent != inobj->in_ifent)
737 tok = inobj->in_otok; // Restore tok and otok
738 etok = inobj->in_etok;
740 switch (inobj->in_type)
742 case SRC_IFILE: // Pop and release an IFILE
744 printf("[Leaving: %s]\n", curfname);
746 ifile = inobj->inobj.ifile;
747 ifile->if_link = f_ifile;
749 close(ifile->ifhandle); // Close source file
750 curfname = ifile->ifoldfname; // Set current filename
751 curlineno = ifile->ifoldlineno; // Set current line#
752 DEBUG printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno);
753 cfileno = ifile->ifno; // Restore current file number
755 case SRC_IMACRO: // Pop and release an IMACRO
756 imacro = inobj->inobj.imacro;
757 imacro->im_link = f_imacro;
760 case SRC_IREPT: // Pop and release an IREPT
761 DEBUG printf("dealloc IREPT\n");
762 p = inobj->inobj.irept->ir_firstln;
773 cur_inobj = inobj->in_link;
774 inobj->in_link = f_inobj;
783 // Get line from file into buf, return NULL on EOF or ptr to the start of a
790 int readamt = -1; // 0 if last read() yeilded 0 bytes
791 IFILE * fl = cur_inobj->inobj.ifile;
795 // Scan for next end-of-line; handle stupid text formats by treating
796 // \r\n the same as \n. (lone '\r' at end of buffer means we have to
800 d = &fl->ifbuf[fl->ifind];
802 for(p=d; i<j; i++, p++)
804 if (*p == '\r' || *p == '\n')
812 break; // Look for '\n' to eat
814 else if (p[1] == '\n')
828 // Handle hanging lines by ignoring them (Input file is exhausted, no
829 // \r or \n on last line)
830 if (!readamt && fl->ifcnt)
837 // Truncate and return absurdly long lines.
838 if (fl->ifcnt >= QUANTUM)
840 fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
842 return &fl->ifbuf[fl->ifind];
845 // Relocate what's left of a line to the beginning of the buffer, and
846 // read some more of the file in; return NULL if the buffer's empty and
850 p = &fl->ifbuf[fl->ifind];
851 d = &fl->ifbuf[fl->ifcnt & 1];
853 for(i=0; i<fl->ifcnt; i++)
856 fl->ifind = fl->ifcnt & 1;
859 if ((readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM)) < 0)
862 if ((fl->ifcnt += readamt) == 0)
873 char * ln = NULL; // Ptr to current position in line
874 char * p; // Random character ptr
875 TOKEN * tk; // Token-deposit ptr
876 int state = 0; // State for keyword detector
877 int j = 0; // Var for keyword detector
878 char c; // Random char
879 VALUE v; // Random value
880 char * nullspot = NULL; // Spot to clobber for SYMBOL terminatn
881 int stuffnull; // 1:terminate SYMBOL '\0' at *nullspot
883 int stringNum = 0; // Pointer to string locations in tokenized line
887 if (cur_inobj == NULL) // Return EOF if input stack is empty
890 // Get another line of input from the current input source: a file,
891 // a macro, or a repeat-block
892 switch (cur_inobj->in_type)
896 // o bump source line number;
897 // o tag the listing-line with a space;
898 // o kludge lines generated by Alcyon C.
900 if ((ln = getln()) == NULL)
902 fpop(); // Pop input level
903 goto retry; // Try for more lines
906 curlineno++; // Bump line number
911 // AS68 compatibility, throw away all lines starting with
912 // back-quotes, tildes, or '*'
913 // On other lines, turn the first '*' into a semi-colon.
914 if (*ln == '`' || *ln == '~' || *ln == '*')
918 for(p=ln; *p!=EOS; p++)
931 // o Handle end-of-macro;
932 // o tag the listing-line with an at (@) sign.
934 if ((ln = getmln()) == NULL)
936 ExitMacro(); // Exit macro (pop args, do fpop(), etc)
937 goto retry; // Try for more lines...
943 // o Handle end-of-repeat-block;
944 // o tag the listing-line with a pound (#) sign.
946 if ((ln = getrln()) == NULL)
956 // Save text of the line. We only do this during listings and within
957 // macro-type blocks, since it is expensive to unconditionally copy every
962 // General house-keeping
963 tok = tokeol; // Set "tok" to EOL in case of error
964 tk = etok; // Reset token ptr
965 stuffnull = 0; // Don't stuff nulls
966 totlines++; // Bump total #lines assembled
968 // See if the entire line is a comment. This is a win if the programmer
969 // puts in lots of comments
970 if (*ln == '*' || *ln == ';' || ((*ln == '/') && (*(ln + 1) == '/')))
973 // Main tokenization loop;
974 // o skip whitespace;
975 // o handle end-of-line;
977 // o handle single-character tokens (operators, etc.);
978 // o handle multiple-character tokens (constants, strings, etc.).
981 // Skip whitespace, handle EOL
982 while ((int)chrtab[*ln] & WHITE)
985 // Handle EOL, comment with ';'
986 if (*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln + 1) == '/')))
989 // Handle start of symbol. Symbols are null-terminated in place. The
990 // termination is always one symbol behind, since there may be no place
991 // for a null in the case that an operator immediately follows the name.
996 if (stuffnull) // Terminate old symbol from previous pass
999 v = 0; // Assume no DOT attrib follows symbol
1001 p = nullspot = ln++; // Nullspot -> start of this symbol
1003 // Find end of symbol (and compute its length)
1004 for(j=1; (int)chrtab[*ln]&CTSYM; j++)
1007 // Handle "DOT" special forms (like ".b") that follow a normal
1008 // symbol or keyword:
1011 *ln++ = EOS; // Terminate symbol
1012 stuffnull = 0; // And never try it again
1014 // Character following the `.' must have a DOT attribute, and
1015 // the chararacter after THAT one must not have a start-symbol
1016 // attribute (to prevent symbols that look like, for example,
1017 // "zingo.barf", which might be a good idea anyway....)
1018 if ((((int)chrtab[*ln] & DOT) == 0) || ((int)dotxtab[*ln] <= 0))
1019 return error("[bwsl] must follow `.' in symbol");
1021 v = (VALUE)dotxtab[*ln++];
1023 if ((int)chrtab[*ln] & CTSYM)
1024 return error("misuse of `.', not allowed in symbols");
1027 // If the symbol is small, check to see if it's really the name of
1031 for(state=0; state>=0;)
1033 j = (int)tolowertab[*p++];
1036 if (kwcheck[j] != state)
1042 if (*p == EOS || p == ln)
1056 //make j = -1 if time, date etc with no preceeding ^^
1057 //defined, referenced, streq, macdef, date and time
1060 case 112: // defined
1061 case 113: // referenced
1070 if (j < 0 || state < 0)
1074 //problem here: nullspot is a char * but TOKEN is a uint32_t. On a 64-bit system,
1075 //this will cause all kinds of mischief.
1077 *tk++ = (TOKEN)nullspot;
1079 string[stringNum] = nullspot;
1090 if (v) // Record attribute token (if any)
1093 if (stuffnull) // Arrange for string termination on next pass
1099 // Handle identity tokens
1106 // Handle multiple-character tokens
1111 case '!': // ! or !=
1121 case '\'': // 'string'
1122 case '\"': // "string"
1126 // More char * stuffing (8 bytes) into the space of 4 (TOKEN).
1127 // Need to figure out how to fix this crap.
1131 string[stringNum] = ln;
1136 for(p=ln; *ln!=EOS && *ln!=c1;)
1145 return(error("unterminated string"));
1174 warn("bad backslash code in string");
1184 return error("unterminated string");
1188 case '$': // $, hex constant
1189 if ((int)chrtab[*ln] & HDIGIT)
1193 while ((int)hextab[*ln] >= 0)
1194 v = (v << 4) + (int)hextab[*ln++];
1198 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1204 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1210 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1223 case '<': // < or << or <> or <=
1242 case ':': // : or ::
1252 case '=': // = or ==
1262 case '>': // > or >> or >=
1277 case '%': // % or binary constant
1278 if (*ln < '0' || *ln > '1')
1286 while (*ln >= '0' && *ln <= '1')
1287 v = (v << 1) + *ln++ - '0';
1291 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1297 if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1303 if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1312 case '@': // @ or octal constant
1313 if (*ln < '0' || *ln > '7')
1321 while (*ln >= '0' && *ln <= '7')
1322 v = (v << 3) + *ln++ - '0';
1326 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1332 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1338 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1347 case '^': // ^ or ^^ <operator-name>
1354 if (((int)chrtab[*++ln] & STSYM) == 0)
1356 error("invalid symbol following ^^");
1362 while ((int)chrtab[*ln] & CTSYM)
1365 for(state=0; state>=0;)
1367 // Get char, convert to lowercase
1370 if (j >= 'A' && j <= 'Z')
1375 if (kwcheck[j] != state)
1381 if (*p == EOS || p == ln)
1390 if (j < 0 || state < 0)
1392 error("unknown symbol following ^^");
1399 interror(2); // Bad MULTX entry in chrtab
1404 // Handle decimal constant
1409 while ((int)chrtab[*ln] & DIGIT)
1410 v = (v * 10) + *ln++ - '0';
1412 // See if there's a .[bwl] after the constant, & deal with it
1415 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1421 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1427 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1438 // Handle illegal character
1439 return error("illegal character");
1442 // Terminate line of tokens and return "success."
1445 tok = etok; // Set tok to beginning of line
1447 if (stuffnull) // Terminate last SYMBOL
1457 // .GOTO <label> goto directive
1459 // The label is searched for starting from the first line of the current,
1460 // enclosing macro definition. If no enclosing macro exists, an error is
1463 // A label is of the form:
1465 // :<name><whitespace>
1467 // The colon must appear in column 1. The label is stripped prior to macro
1468 // expansion, and is NOT subject to macro expansion. The whitespace may also
1471 //int d_goto(WORD siz) {
1473 int d_goto(WORD unused)
1475 // char * sym; // Label to search for
1476 // LONG * defln; // Macro definition strings
1477 char * s1; // Temps for string comparison
1479 // IMACRO * imacro; // Macro invocation block
1481 // Setup for the search
1483 return error("missing label");
1485 // sym = (char *)tok[1];
1486 char * sym = string[tok[1]];
1489 if (cur_inobj->in_type != SRC_IMACRO)
1490 return error("goto not in macro");
1492 IMACRO * imacro = cur_inobj->inobj.imacro;
1493 // defln = (LONG *)imacro->im_macro->svalue;
1494 struct LineList * defln = imacro->im_macro->lineList;
1496 // Find the label, starting with the first line.
1497 // for(; defln!=NULL; defln=(LONG *)*defln)
1498 for(; defln!=NULL; defln=defln->next)
1500 // if (*(char *)(defln + 1) == ':')
1501 if (defln->line[0] == ':')
1503 // Compare names (sleazo string compare)
1504 // This string compare is not right. Doesn't check for lengths.
1505 #warning "!!! Bad string comparison !!!"
1507 // s2 = (char *)(defln + 1) + 1;
1521 // Found the label, set new macro next-line and return.
1522 if ((*s2 == EOS) || ((int)chrtab[*s2] & WHITE))
1524 imacro->im_nextln = defln;
1530 return error("goto label not found");
1533 void DumpTokenBuffer(void)
1536 printf("Tokens [%X]: ", sloc);
1538 for(t=tokbuf; *t!=EOL; t++)
1542 else if (*t == CONST)
1545 printf("[CONST: $%X]", (uint32_t)*t);
1547 else if (*t == ACONST)
1549 else if (*t == STRING)
1550 // printf("[STRING]");
1553 printf("[STRING:\"%s\"]", string[*t]);
1555 else if (*t == SYMBOL)
1558 printf("[SYMBOL:\"%s\"]", string[*t]);
1562 else if (*t == TKEOF)
1564 else if (*t == DEQUALS)
1565 printf("[DEQUALS]");
1570 else if (*t == DCOLON)
1582 else if (*t == UNMINUS)
1583 printf("[UNMINUS]");
1584 else if (*t == DOTB)
1586 else if (*t == DOTW)
1588 else if (*t == DOTL)
1590 else if (*t == DOTI)
1592 else if (*t == ENDEXPR)
1593 printf("[ENDEXPR]");
1594 else if (*t == CR_DEFINED)
1595 printf("[CR_DEFINED]");
1596 else if (*t == CR_REFERENCED)
1597 printf("[CR_REFERENCED]");
1598 else if (*t == CR_STREQ)
1599 printf("[CR_STREQ]");
1600 else if (*t == CR_MACDEF)
1601 printf("[CR_MACDEF]");
1602 else if (*t == CR_TIME)
1603 printf("[CR_TIME]");
1604 else if (*t == CR_DATE)
1605 printf("[CR_DATE]");
1606 else if (*t >= 0x20 && *t <= 0x2F)
1607 printf("[%c]", (char)*t);
1608 else if (*t >= 0x3A && *t <= 0x3F)
1609 printf("[%c]", (char)*t);
1610 else if (*t >= 0x80 && *t <= 0x87)
1611 printf("[D%u]", ((uint32_t)*t) - 0x80);
1612 else if (*t >= 0x88 && *t <= 0x8F)
1613 printf("[A%u]", ((uint32_t)*t) - 0x88);
1615 printf("[%X:%c]", (uint32_t)*t, (char)*t);
1616 // printf("[%X]", (uint32_t)*t);