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"
119 // Removing this, provided it doesn't cause unwanted side-effects :-P
122 // Make `fnum' the Current `curfname'
123 // NOTE: This is currently only called from error() in error.c
125 void setfnum(WORD fnum)
128 // NOTE: fnum is ZERO based, this can cause problems if you're not careful!
129 FILEREC * fr = filerec;
131 DEBUG printf("[setfnum: fnum=%u]\n", fnum);
133 // Advance to the correct record...
134 while (fr != NULL && fnum != 0)
141 curfname = "(*top*)";
143 curfname = fr->frec_name;
145 DEBUG printf("[setfnum: curfname=%s]\n", curfname);
147 // Check for absolute top filename (this should never happen)
150 curfname = "(*top*)";
154 FILEREC * fr = filerec;
156 // Advance to the correct record...
157 while (fr != NULL && fnum != 0)
163 // Check for file # record not found (this should never happen either)
166 curfname = "(*NOT FOUND*)";
170 curfname = fr->frec_name;
174 void SetFilenameForErrorReporting(void)
178 // Check for absolute top filename (this should never happen)
181 curfname = "(*top*)";
185 FILEREC * fr = filerec;
187 // Advance to the correct record...
188 while (fr != NULL && fnum != 0)
194 // Check for file # record not found (this should never happen either)
197 curfname = "(*NOT FOUND*)";
201 curfname = fr->frec_name;
207 // Allocate an IFILE or IMACRO
209 INOBJ * a_inobj(int typ)
215 // Allocate and initialize INOBJ first
217 inobj = malloc(sizeof(INOBJ));
221 f_inobj = f_inobj->in_link;
226 case SRC_IFILE: // Alloc and init an IFILE
228 ifile = malloc(sizeof(IFILE));
232 f_ifile = f_ifile->if_link;
235 inobj->inobj.ifile = ifile;
237 case SRC_IMACRO: // Alloc and init an IMACRO
238 if (f_imacro == NULL)
239 imacro = malloc(sizeof(IMACRO));
243 f_imacro = f_imacro->im_link;
246 inobj->inobj.imacro = imacro;
248 case SRC_IREPT: // Alloc and init an IREPT
249 inobj->inobj.irept = malloc(sizeof(IREPT));
250 DEBUG printf("alloc IREPT\n");
254 // Install INOBJ on top of input stack
255 inobj->in_ifent = ifent; // Record .if context on entry
256 inobj->in_type = (WORD)typ;
257 inobj->in_otok = tok;
258 inobj->in_etok = etok;
259 inobj->in_link = cur_inobj;
267 // Perform macro substitution from 'orig' to 'dest'. Return OK or some error.
268 // A macro reference is in one of two forms:
269 // \name <non-name-character>
271 // A doubled backslash (\\) is compressed to a single backslash (\).
272 // Argument definitions have been pre-tokenized, so we have to turn them back
273 // into text. This means that numbers, in particular, become hex, regardless of
274 // their representation when the macro was invoked. This is a hack.
275 // A label may appear at the beginning of the line:
276 // :<name><whitespace>
277 // (the colon must be in the first column). These labels are stripped before
278 // macro expansion takes place.
280 int ExpandMacro(char * src, char * dest, int destsiz)
283 int questmark; // \? for testing argument existence
284 char mname[128]; // Assume max size of a formal arg name
285 char numbuf[20]; // Buffer for text of CONSTs
288 char ** symbolString;
290 DEBUG { printf("ExM: src=\"%s\"\n", src); }
292 IMACRO * imacro = cur_inobj->inobj.imacro;
293 int macnum = (int)(imacro->im_macro->sattr);
296 char * dst = dest; // Next dest slot
297 char * edst = dest + destsiz - 1; // End + 1(?) of dest buffer
299 // Check for (and skip over) any "label" on the line
305 while (*s != EOS && !(chrtab[*s] & WHITE))
309 s++; // Skip first whitespace
312 // Expand the rest of the line
315 // Copy single character
323 // Do macro expansion
331 case '\\': // \\, \ (collapse to single backslash)
337 case '?': // \? <macro> set `questmark' flag
341 case '#': // \#, number of arguments
342 sprintf(numbuf, "%d", (int)imacro->im_nargs);
344 case '!': // \! size suffix supplied on invocation
345 switch ((int)imacro->im_siz)
347 case SIZN: d = ""; break;
348 case SIZB: d = ".b"; break;
349 case SIZW: d = ".w"; break;
350 case SIZL: d = ".l"; break;
354 case '~': // ==> unique label string Mnnnn...
355 sprintf(numbuf, "M%u", curuniq);
371 return error("missing argument name");
374 // \n ==> argument number 'n', 0..9
375 if (chrtab[*s] & DIGIT)
385 // Get argument name: \name, \{name}
395 while (chrtab[*s] & CTSYM);
400 for(++s; *s != EOS && *s != '}';)
404 return error("missing '}'");
411 // Lookup the argument and copy its (string) value into the
412 // destination string
413 DEBUG printf("argument='%s'\n", mname);
415 if ((arg = lookup(mname, MACARG, macnum)) == NULL)
416 return errors("undefined argument: '%s'", mname);
419 // Convert a string of tokens (terminated with EOL) back into
420 // text. If an argument is out of range (not specified in the
421 // macro invocation) then it is ignored.
422 i = (int)arg->svalue;
424 DEBUG printf("~argnumber=%d (argBase=%u)\n", i, imacro->argBase);
427 if (i < imacro->im_nargs)
432 tk = argPtrs[imacro->argBase + i];
434 tk = imacro->argument[i].token;
435 symbolString = imacro->argument[i].string;
438 // printf("ExM: Preparing to parse argument #%u...\n", i);
445 // 0 if the argument is empty or non-existant,
446 // 1 if the argument is not empty
449 if (tk == NULL || *tk == EOL)
455 *dst++ = (char)(questmark + '0');
459 if (tk != NULL) // arg # is in range, so expand it
463 // Reverse-translation from a token number to a string.
464 // This is a hack. It might be better table-driven.
467 if ((*tk >= KW_D0) && !rdsp && !rgpu)
469 d = regname[(int)*tk++ - KW_D0];
472 else if ((*tk >= KW_R0) && (*tk <= KW_R31))
474 d = riscregname[(int)*tk++ - KW_R0];
483 // d = (char *)*tk++;
486 // This fix should be done for strings too
487 d = symbolString[*tk++];
488 DEBUG printf("ExM: SYMBOL=\"%s\"", d);
493 // d = (char *)*tk++;
496 d = symbolString[*tk++];
517 // Shamus: Changing the format specifier from %lx to %ux caused
518 // the assembler to choke on legitimate code... Need to investigate
519 // this further before changing anything else here!
521 sprintf(numbuf, "$%lx", (LONG)*tk++);
582 *dst++ = (char)*(tk - 1);
587 // If 'd' != NULL, copy string to destination
591 DEBUG printf("d='%s'\n", d);
608 DEBUG { printf("ExM: dst=\"%s\"\n", dest); }
613 DEBUG printf("*** OVERFLOW LINE ***\n%s\n", dest);
614 return fatal("line too long as a result of macro expansion");
619 // Get Next Line of Text from a Macro
623 unsigned source_addr;
625 IMACRO * imacro = cur_inobj->inobj.imacro;
626 // LONG * strp = imacro->im_nextln;
627 struct LineList * strp = imacro->im_nextln;
629 if (strp == NULL) // End-of-macro
632 // imacro->im_nextln = (LONG *)*strp;
633 imacro->im_nextln = strp->next;
634 // ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
635 ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
637 if (!strcmp(imacro->im_macro->sname, "mjump") && !mjump_align)
639 // if we need to adjust the alignment of the jump source address to
640 // meet the rules of gpu main execution we need to skip the first nop
641 // of the macro. This is simpler than trying to insert nop's mid macro.
642 source_addr = (orgactive ? orgaddr : sloc);
647 strp = imacro->im_nextln;
652 // imacro->im_nextln = (LONG *)*strp;
653 // ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
654 imacro->im_nextln = strp->next;
655 ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
661 return imacro->im_lnbuf;
666 // Get Next Line of Text from a Repeat Block
671 IREPT * irept = cur_inobj->inobj.irept;
672 LONG * strp = irept->ir_nextln; // initial null
674 // Do repeat at end of .rept block's string list
677 DEBUG printf("back-to-top-of-repeat-block count=%d\n", (int)irept->ir_count);
678 irept->ir_nextln = irept->ir_firstln; // copy first line
680 if (irept->ir_count-- == 0)
682 DEBUG printf("end-repeat-block\n");
686 strp = irept->ir_nextln; //strp
689 strcpy(irbuf, (char *)(irept->ir_nextln + 1));
690 DEBUG printf("repeat line='%s'\n", irbuf);
691 irept->ir_nextln = (LONG *)*strp;
698 // Include a Source File used at the Root, and for ".include" Files
700 int include(int handle, char * fname)
708 printf("[include: %s, cfileno=%u]\n", fname, cfileno);
710 // Alloc and initialize include-descriptors
711 inobj = a_inobj(SRC_IFILE);
712 ifile = inobj->inobj.ifile;
714 ifile->ifhandle = handle; // Setup file handle
715 ifile->ifind = ifile->ifcnt = 0; // Setup buffer indices
716 ifile->ifoldlineno = curlineno; // Save old line number
717 ifile->ifoldfname = curfname; // Save old filename
718 ifile->ifno = cfileno; // Save old file number
720 // cfileno = filecount++; // Compute new file number
721 // NB: This *must* be preincrement, we're adding one to the filecount here!
722 cfileno = ++filecount; // Compute NEW file number
723 curfname = strdup(fname); // Set current filename (alloc storage)
724 curlineno = 0; // Start on line zero
726 // Add another file to the file-record
727 fr = (FILEREC *)malloc(sizeof(FILEREC));
728 fr->frec_next = NULL;
729 fr->frec_name = curfname;
732 filerec = fr; // Add first filerec
734 last_fr->frec_next = fr; // Append to list of filerecs
737 DEBUG printf("[include: curfname: %s, cfileno=%u]\n", curfname, cfileno);
744 // Initialize Tokenizer
746 void init_token(void)
749 char * htab = "0123456789abcdefABCDEF"; // Hex character table
751 lnsave = 0; // Don't save lines
752 curfname = ""; // No file, empty filename
753 filecount = (WORD)-1;
754 cfileno = (WORD)-1; // cfileno gets bumped to 0
766 // Initialize hex, "dot" and tolower tables
771 tolowertab[i] = (char)i;
774 for(i=0; htab[i]!=EOS; i++)
775 hextab[htab[i]] = (char)((i < 16) ? i : i - 6);
777 for(i='A'; i<='Z'; i++)
778 tolowertab[i] |= 0x20;
780 // These characters are legal immediately after a period
781 dotxtab['b'] = DOTB; // .b .B .s .S
785 dotxtab['w'] = DOTW; // .w .W
787 dotxtab['l'] = DOTL; // .l .L
789 dotxtab['I'] = DOTI; // .l .L
795 // Pop the Current Input Level
802 INOBJ * inobj = cur_inobj;
806 // Pop IFENT levels until we reach the conditional assembly context we
807 // were at when the input object was entered.
808 while (ifent != inobj->in_ifent)
811 tok = inobj->in_otok; // Restore tok and otok
812 etok = inobj->in_etok;
814 switch (inobj->in_type)
816 case SRC_IFILE: // Pop and release an IFILE
818 printf("[Leaving: %s]\n", curfname);
820 ifile = inobj->inobj.ifile;
821 ifile->if_link = f_ifile;
823 close(ifile->ifhandle); // Close source file
824 if (verb_flag) printf("[fpop (pre): curfname=%s]\n", curfname);
825 curfname = ifile->ifoldfname; // Set current filename
826 if (verb_flag) printf("[fpop (post): curfname=%s]\n", curfname);
827 if (verb_flag) printf("[fpop: (pre) cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno);
828 curlineno = ifile->ifoldlineno; // Set current line#
829 DEBUG printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno);
830 cfileno = ifile->ifno; // Restore current file number
831 if (verb_flag) printf("[fpop: (post) cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno);
833 case SRC_IMACRO: // Pop and release an IMACRO
834 imacro = inobj->inobj.imacro;
835 imacro->im_link = f_imacro;
838 case SRC_IREPT: // Pop and release an IREPT
839 DEBUG printf("dealloc IREPT\n");
840 p = inobj->inobj.irept->ir_firstln;
851 cur_inobj = inobj->in_link;
852 inobj->in_link = f_inobj;
861 // Get line from file into buf, return NULL on EOF or ptr to the start of a
868 int readamt = -1; // 0 if last read() yeilded 0 bytes
869 IFILE * fl = cur_inobj->inobj.ifile;
873 // Scan for next end-of-line; handle stupid text formats by treating
874 // \r\n the same as \n. (lone '\r' at end of buffer means we have to
878 d = &fl->ifbuf[fl->ifind];
880 for(p=d; i<j; i++, p++)
882 if (*p == '\r' || *p == '\n')
890 break; // Look for '\n' to eat
892 else if (p[1] == '\n')
906 // Handle hanging lines by ignoring them (Input file is exhausted, no
907 // \r or \n on last line)
908 if (!readamt && fl->ifcnt)
915 // Truncate and return absurdly long lines.
916 if (fl->ifcnt >= QUANTUM)
918 fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
920 return &fl->ifbuf[fl->ifind];
923 // Relocate what's left of a line to the beginning of the buffer, and
924 // read some more of the file in; return NULL if the buffer's empty and
928 p = &fl->ifbuf[fl->ifind];
929 d = &fl->ifbuf[fl->ifcnt & 1];
931 for(i=0; i<fl->ifcnt; i++)
934 fl->ifind = fl->ifcnt & 1;
937 if ((readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM)) < 0)
940 if ((fl->ifcnt += readamt) == 0)
951 char * ln = NULL; // Ptr to current position in line
952 char * p; // Random character ptr
953 TOKEN * tk; // Token-deposit ptr
954 int state = 0; // State for keyword detector
955 int j = 0; // Var for keyword detector
956 char c; // Random char
957 VALUE v; // Random value
958 char * nullspot = NULL; // Spot to clobber for SYMBOL terminatn
959 int stuffnull; // 1:terminate SYMBOL '\0' at *nullspot
961 int stringNum = 0; // Pointer to string locations in tokenized line
965 if (cur_inobj == NULL) // Return EOF if input stack is empty
968 // Get another line of input from the current input source: a file,
969 // a macro, or a repeat-block
970 switch (cur_inobj->in_type)
974 // o bump source line number;
975 // o tag the listing-line with a space;
976 // o kludge lines generated by Alcyon C.
978 if ((ln = getln()) == NULL)
980 if (verb_flag) printf("tokln: Calling fpop() from SRC_IFILE...\n");
981 fpop(); // Pop input level
982 goto retry; // Try for more lines
985 curlineno++; // Bump line number
990 // AS68 compatibility, throw away all lines starting with
991 // back-quotes, tildes, or '*'
992 // On other lines, turn the first '*' into a semi-colon.
993 if (*ln == '`' || *ln == '~' || *ln == '*')
997 for(p=ln; *p!=EOS; p++)
1010 // o Handle end-of-macro;
1011 // o tag the listing-line with an at (@) sign.
1013 if ((ln = getmln()) == NULL)
1015 ExitMacro(); // Exit macro (pop args, do fpop(), etc)
1016 goto retry; // Try for more lines...
1022 // o Handle end-of-repeat-block;
1023 // o tag the listing-line with a pound (#) sign.
1025 if ((ln = getrln()) == NULL)
1027 if (verb_flag) printf("tokln: Calling fpop() from SRC_IREPT...\n");
1036 // Save text of the line. We only do this during listings and within
1037 // macro-type blocks, since it is expensive to unconditionally copy every
1042 // General house-keeping
1043 tok = tokeol; // Set "tok" to EOL in case of error
1044 tk = etok; // Reset token ptr
1045 stuffnull = 0; // Don't stuff nulls
1046 totlines++; // Bump total #lines assembled
1048 // See if the entire line is a comment. This is a win if the programmer
1049 // puts in lots of comments
1050 if (*ln == '*' || *ln == ';' || ((*ln == '/') && (*(ln + 1) == '/')))
1053 // Main tokenization loop;
1054 // o skip whitespace;
1055 // o handle end-of-line;
1056 // o handle symbols;
1057 // o handle single-character tokens (operators, etc.);
1058 // o handle multiple-character tokens (constants, strings, etc.).
1061 // Skip whitespace, handle EOL
1062 while ((int)chrtab[*ln] & WHITE)
1065 // Handle EOL, comment with ';'
1066 if (*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln + 1) == '/')))
1069 // Handle start of symbol. Symbols are null-terminated in place. The
1070 // termination is always one symbol behind, since there may be no place
1071 // for a null in the case that an operator immediately follows the name.
1076 if (stuffnull) // Terminate old symbol from previous pass
1079 v = 0; // Assume no DOT attrib follows symbol
1081 p = nullspot = ln++; // Nullspot -> start of this symbol
1083 // Find end of symbol (and compute its length)
1084 for(j=1; (int)chrtab[*ln]&CTSYM; j++)
1087 // Handle "DOT" special forms (like ".b") that follow a normal
1088 // symbol or keyword:
1091 *ln++ = EOS; // Terminate symbol
1092 stuffnull = 0; // And never try it again
1094 // Character following the `.' must have a DOT attribute, and
1095 // the chararacter after THAT one must not have a start-symbol
1096 // attribute (to prevent symbols that look like, for example,
1097 // "zingo.barf", which might be a good idea anyway....)
1098 if ((((int)chrtab[*ln] & DOT) == 0) || ((int)dotxtab[*ln] <= 0))
1099 return error("[bwsl] must follow `.' in symbol");
1101 v = (VALUE)dotxtab[*ln++];
1103 if ((int)chrtab[*ln] & CTSYM)
1104 return error("misuse of `.', not allowed in symbols");
1107 // If the symbol is small, check to see if it's really the name of
1111 for(state=0; state>=0;)
1113 j = (int)tolowertab[*p++];
1116 if (kwcheck[j] != state)
1122 if (*p == EOS || p == ln)
1136 //make j = -1 if time, date etc with no preceeding ^^
1137 //defined, referenced, streq, macdef, date and time
1140 case 112: // defined
1141 case 113: // referenced
1150 if (j < 0 || state < 0)
1154 //problem here: nullspot is a char * but TOKEN is a uint32_t. On a 64-bit system,
1155 //this will cause all kinds of mischief.
1157 *tk++ = (TOKEN)nullspot;
1159 string[stringNum] = nullspot;
1170 if (v) // Record attribute token (if any)
1173 if (stuffnull) // Arrange for string termination on next pass
1179 // Handle identity tokens
1186 // Handle multiple-character tokens
1191 case '!': // ! or !=
1201 case '\'': // 'string'
1202 case '\"': // "string"
1206 // More char * stuffing (8 bytes) into the space of 4 (TOKEN).
1207 // Need to figure out how to fix this crap.
1211 string[stringNum] = ln;
1216 for(p=ln; *ln!=EOS && *ln!=c1;)
1225 return(error("unterminated string"));
1254 warn("bad backslash code in string");
1264 return error("unterminated string");
1268 case '$': // $, hex constant
1269 if ((int)chrtab[*ln] & HDIGIT)
1273 while ((int)hextab[*ln] >= 0)
1274 v = (v << 4) + (int)hextab[*ln++];
1278 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1284 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1290 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1303 case '<': // < or << or <> or <=
1322 case ':': // : or ::
1332 case '=': // = or ==
1342 case '>': // > or >> or >=
1357 case '%': // % or binary constant
1358 if (*ln < '0' || *ln > '1')
1366 while (*ln >= '0' && *ln <= '1')
1367 v = (v << 1) + *ln++ - '0';
1371 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1377 if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1383 if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1392 case '@': // @ or octal constant
1393 if (*ln < '0' || *ln > '7')
1401 while (*ln >= '0' && *ln <= '7')
1402 v = (v << 3) + *ln++ - '0';
1406 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1412 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1418 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1427 case '^': // ^ or ^^ <operator-name>
1434 if (((int)chrtab[*++ln] & STSYM) == 0)
1436 error("invalid symbol following ^^");
1442 while ((int)chrtab[*ln] & CTSYM)
1445 for(state=0; state>=0;)
1447 // Get char, convert to lowercase
1450 if (j >= 'A' && j <= 'Z')
1455 if (kwcheck[j] != state)
1461 if (*p == EOS || p == ln)
1470 if (j < 0 || state < 0)
1472 error("unknown symbol following ^^");
1479 interror(2); // Bad MULTX entry in chrtab
1484 // Handle decimal constant
1489 while ((int)chrtab[*ln] & DIGIT)
1490 v = (v * 10) + *ln++ - '0';
1492 // See if there's a .[bwl] after the constant, & deal with it
1495 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1501 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1507 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1518 // Handle illegal character
1519 return error("illegal character");
1522 // Terminate line of tokens and return "success."
1525 tok = etok; // Set tok to beginning of line
1527 if (stuffnull) // Terminate last SYMBOL
1537 // .GOTO <label> goto directive
1539 // The label is searched for starting from the first line of the current,
1540 // enclosing macro definition. If no enclosing macro exists, an error is
1543 // A label is of the form:
1545 // :<name><whitespace>
1547 // The colon must appear in column 1. The label is stripped prior to macro
1548 // expansion, and is NOT subject to macro expansion. The whitespace may also
1551 //int d_goto(WORD siz) {
1553 int d_goto(WORD unused)
1555 // char * sym; // Label to search for
1556 // LONG * defln; // Macro definition strings
1557 char * s1; // Temps for string comparison
1559 // IMACRO * imacro; // Macro invocation block
1561 // Setup for the search
1563 return error("missing label");
1565 // sym = (char *)tok[1];
1566 char * sym = string[tok[1]];
1569 if (cur_inobj->in_type != SRC_IMACRO)
1570 return error("goto not in macro");
1572 IMACRO * imacro = cur_inobj->inobj.imacro;
1573 // defln = (LONG *)imacro->im_macro->svalue;
1574 struct LineList * defln = imacro->im_macro->lineList;
1576 // Find the label, starting with the first line.
1577 // for(; defln!=NULL; defln=(LONG *)*defln)
1578 for(; defln!=NULL; defln=defln->next)
1580 // if (*(char *)(defln + 1) == ':')
1581 if (defln->line[0] == ':')
1583 // Compare names (sleazo string compare)
1584 // This string compare is not right. Doesn't check for lengths.
1585 #warning "!!! Bad string comparison !!!"
1587 // s2 = (char *)(defln + 1) + 1;
1601 // Found the label, set new macro next-line and return.
1602 if ((*s2 == EOS) || ((int)chrtab[*s2] & WHITE))
1604 imacro->im_nextln = defln;
1610 return error("goto label not found");
1613 void DumpTokenBuffer(void)
1616 printf("Tokens [%X]: ", sloc);
1618 for(t=tokbuf; *t!=EOL; t++)
1622 else if (*t == CONST)
1625 printf("[CONST: $%X]", (uint32_t)*t);
1627 else if (*t == ACONST)
1629 else if (*t == STRING)
1630 // printf("[STRING]");
1633 printf("[STRING:\"%s\"]", string[*t]);
1635 else if (*t == SYMBOL)
1638 printf("[SYMBOL:\"%s\"]", string[*t]);
1642 else if (*t == TKEOF)
1644 else if (*t == DEQUALS)
1645 printf("[DEQUALS]");
1650 else if (*t == DCOLON)
1662 else if (*t == UNMINUS)
1663 printf("[UNMINUS]");
1664 else if (*t == DOTB)
1666 else if (*t == DOTW)
1668 else if (*t == DOTL)
1670 else if (*t == DOTI)
1672 else if (*t == ENDEXPR)
1673 printf("[ENDEXPR]");
1674 else if (*t == CR_DEFINED)
1675 printf("[CR_DEFINED]");
1676 else if (*t == CR_REFERENCED)
1677 printf("[CR_REFERENCED]");
1678 else if (*t == CR_STREQ)
1679 printf("[CR_STREQ]");
1680 else if (*t == CR_MACDEF)
1681 printf("[CR_MACDEF]");
1682 else if (*t == CR_TIME)
1683 printf("[CR_TIME]");
1684 else if (*t == CR_DATE)
1685 printf("[CR_DATE]");
1686 else if (*t >= 0x20 && *t <= 0x2F)
1687 printf("[%c]", (char)*t);
1688 else if (*t >= 0x3A && *t <= 0x3F)
1689 printf("[%c]", (char)*t);
1690 else if (*t >= 0x80 && *t <= 0x87)
1691 printf("[D%u]", ((uint32_t)*t) - 0x80);
1692 else if (*t >= 0x88 && *t <= 0x8F)
1693 printf("[A%u]", ((uint32_t)*t) - 0x88);
1695 printf("[%X:%c]", (uint32_t)*t, (char)*t);
1696 // printf("[%X]", (uint32_t)*t);