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
20 int lnsave; // 1; strcpy() text of current line
21 int curlineno; // Current line number
22 int totlines; // Total # of lines
23 int mjump_align = 0; // mjump alignment flag
24 char lntag; // Line tag
25 char * curfname; // Current filename
26 char tolowertab[128]; // Uppercase ==> lowercase
27 char hextab[128]; // Table of hex values
28 char dotxtab[128]; // Table for ".b", ".s", etc.
29 char irbuf[LNSIZ]; // Text for .rept block line
30 char lnbuf[LNSIZ]; // Text of current line
31 WORD filecount; // Unique file number counter
32 WORD cfileno; // Current file number
33 TOKEN * tok; // Ptr to current token
34 TOKEN * etok; // Ptr past last token in tokbuf[]
35 TOKEN tokeol[1] = {EOL}; // Bailout end-of-line token
36 char * string[TOKBUFSIZE*2]; // Token buffer string pointer storage
38 // File record, used to maintain a list of every include file ever visited
39 #define FILEREC struct _filerec
49 INOBJ * cur_inobj; // Ptr current input obj (IFILE/IMACRO)
50 static INOBJ * f_inobj; // Ptr list of free INOBJs
51 static IFILE * f_ifile; // Ptr list of free IFILEs
52 static IMACRO * f_imacro; // Ptr list of free IMACROs
54 static TOKEN tokbuf[TOKBUFSIZE]; // Token buffer (stack-like, all files)
57 ILLEG, ILLEG, ILLEG, ILLEG, // NUL SOH STX ETX
58 ILLEG, ILLEG, ILLEG, ILLEG, // EOT ENQ ACK BEL
59 ILLEG, WHITE, ILLEG, ILLEG, // BS HT LF VT
60 WHITE, ILLEG, ILLEG, ILLEG, // FF CR SO SI
62 ILLEG, ILLEG, ILLEG, ILLEG, // DLE DC1 DC2 DC3
63 ILLEG, ILLEG, ILLEG, ILLEG, // DC4 NAK SYN ETB
64 ILLEG, ILLEG, ILLEG, ILLEG, // CAN EM SUB ESC
65 ILLEG, ILLEG, ILLEG, ILLEG, // FS GS RS US
67 WHITE, MULTX, MULTX, SELF, // SP ! " #
68 MULTX+CTSYM, MULTX, SELF, MULTX, // $ % & '
69 SELF, SELF, SELF, SELF, // ( ) * +
70 SELF, SELF, STSYM, SELF, // , - . /
72 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 0 1
73 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 2 3
74 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 4 5
75 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 6 7
76 DIGIT+HDIGIT+CTSYM, DIGIT+HDIGIT+CTSYM, // 8 9
78 MULTX, MULTX, MULTX, STSYM+CTSYM, // < = > ?
80 MULTX, STSYM+CTSYM+HDIGIT, // @ A
81 (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // B C
82 STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // D E
83 STSYM+CTSYM+HDIGIT, STSYM+CTSYM, // F G
84 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // H I J K
85 (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // L M N O
87 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // P Q R S
88 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // T U V W
89 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF, // X Y Z [
90 SELF, SELF, MULTX, STSYM+CTSYM, // \ ] ^ _
92 ILLEG, STSYM+CTSYM+HDIGIT, // ` a
93 (char)((BYTE)DOT)+STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // b c
94 STSYM+CTSYM+HDIGIT, STSYM+CTSYM+HDIGIT, // d e
95 STSYM+CTSYM+HDIGIT, STSYM+CTSYM, // f g
96 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // h i j k
97 (char)((BYTE)DOT)+STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, // l m n o
99 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // p q r s
100 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, (char)((BYTE)DOT)+STSYM+CTSYM, // t u v w
101 STSYM+CTSYM, STSYM+CTSYM, STSYM+CTSYM, SELF, // x y z {
102 SELF, SELF, SELF, ILLEG // | } ~ DEL
105 // Names of registers
106 static char * regname[] = {
107 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
108 "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
109 "pc", "ssp", "usp", "sr", "ccr"
112 static char * riscregname[] = {
113 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
114 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
115 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
116 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
121 // Initialize Tokenizer
123 void InitTokenizer(void)
126 char * htab = "0123456789abcdefABCDEF"; // Hex character table
128 lnsave = 0; // Don't save lines
129 curfname = ""; // No file, empty filename
130 filecount = (WORD)-1;
131 cfileno = (WORD)-1; // cfileno gets bumped to 0
143 // Initialize hex, "dot" and tolower tables
148 tolowertab[i] = (char)i;
151 for(i=0; htab[i]!=EOS; i++)
152 hextab[htab[i]] = (char)((i < 16) ? i : i - 6);
154 for(i='A'; i<='Z'; i++)
155 tolowertab[i] |= 0x20;
157 // These characters are legal immediately after a period
158 dotxtab['b'] = DOTB; // .b .B .s .S
162 dotxtab['w'] = DOTW; // .w .W
164 dotxtab['l'] = DOTL; // .l .L
166 dotxtab['i'] = DOTI; // .i .I (???)
171 void SetFilenameForErrorReporting(void)
175 // Check for absolute top filename (this should never happen)
178 curfname = "(*top*)";
182 FILEREC * fr = filerec;
184 // Advance to the correct record...
185 while (fr != NULL && fnum != 0)
191 // Check for file # record not found (this should never happen either)
194 curfname = "(*NOT FOUND*)";
198 curfname = fr->frec_name;
203 // Allocate an IFILE or IMACRO
205 INOBJ * a_inobj(int typ)
211 // Allocate and initialize INOBJ first
213 inobj = malloc(sizeof(INOBJ));
217 f_inobj = f_inobj->in_link;
222 case SRC_IFILE: // Alloc and init an IFILE
224 ifile = malloc(sizeof(IFILE));
228 f_ifile = f_ifile->if_link;
231 inobj->inobj.ifile = ifile;
233 case SRC_IMACRO: // Alloc and init an IMACRO
234 if (f_imacro == NULL)
235 imacro = malloc(sizeof(IMACRO));
239 f_imacro = f_imacro->im_link;
242 inobj->inobj.imacro = imacro;
244 case SRC_IREPT: // Alloc and init an IREPT
245 inobj->inobj.irept = malloc(sizeof(IREPT));
246 DEBUG printf("alloc IREPT\n");
250 // Install INOBJ on top of input stack
251 inobj->in_ifent = ifent; // Record .if context on entry
252 inobj->in_type = (WORD)typ;
253 inobj->in_otok = tok;
254 inobj->in_etok = etok;
255 inobj->in_link = cur_inobj;
263 // Perform macro substitution from 'orig' to 'dest'. Return OK or some error.
264 // A macro reference is in one of two forms:
265 // \name <non-name-character>
267 // A doubled backslash (\\) is compressed to a single backslash (\).
268 // Argument definitions have been pre-tokenized, so we have to turn them back
269 // into text. This means that numbers, in particular, become hex, regardless of
270 // their representation when the macro was invoked. This is a hack.
271 // A label may appear at the beginning of the line:
272 // :<name><whitespace>
273 // (the colon must be in the first column). These labels are stripped before
274 // macro expansion takes place.
276 int ExpandMacro(char * src, char * dest, int destsiz)
279 int questmark; // \? for testing argument existence
280 char mname[128]; // Assume max size of a formal arg name
281 char numbuf[20]; // Buffer for text of CONSTs
284 char ** symbolString;
286 DEBUG { printf("ExM: src=\"%s\"\n", src); }
288 IMACRO * imacro = cur_inobj->inobj.imacro;
289 int macnum = (int)(imacro->im_macro->sattr);
292 char * dst = dest; // Next dest slot
293 char * edst = dest + destsiz - 1; // End + 1(?) of dest buffer
295 // Check for (and skip over) any "label" on the line
301 while (*s != EOS && !(chrtab[*s] & WHITE))
305 s++; // Skip first whitespace
308 // Expand the rest of the line
311 // Copy single character
319 // Do macro expansion
327 case '\\': // \\, \ (collapse to single backslash)
333 case '?': // \? <macro> set `questmark' flag
337 case '#': // \#, number of arguments
338 sprintf(numbuf, "%d", (int)imacro->im_nargs);
340 case '!': // \! size suffix supplied on invocation
341 switch ((int)imacro->im_siz)
343 case SIZN: d = ""; break;
344 case SIZB: d = ".b"; break;
345 case SIZW: d = ".w"; break;
346 case SIZL: d = ".l"; break;
350 case '~': // ==> unique label string Mnnnn...
351 sprintf(numbuf, "M%u", curuniq);
367 return error("missing argument name");
370 // \n ==> argument number 'n', 0..9
371 if (chrtab[*s] & DIGIT)
381 // Get argument name: \name, \{name}
391 while (chrtab[*s] & CTSYM);
396 for(++s; *s != EOS && *s != '}';)
400 return error("missing '}'");
407 // Lookup the argument and copy its (string) value into the
408 // destination string
409 DEBUG printf("argument='%s'\n", mname);
411 if ((arg = lookup(mname, MACARG, macnum)) == NULL)
412 return errors("undefined argument: '%s'", mname);
415 // Convert a string of tokens (terminated with EOL) back into
416 // text. If an argument is out of range (not specified in the
417 // macro invocation) then it is ignored.
418 i = (int)arg->svalue;
420 DEBUG printf("~argnumber=%d (argBase=%u)\n", i, imacro->argBase);
423 if (i < imacro->im_nargs)
428 tk = argPtrs[imacro->argBase + i];
430 tk = imacro->argument[i].token;
431 symbolString = imacro->argument[i].string;
434 // printf("ExM: Preparing to parse argument #%u...\n", i);
441 // 0 if the argument is empty or non-existant,
442 // 1 if the argument is not empty
445 if (tk == NULL || *tk == EOL)
451 *dst++ = (char)(questmark + '0');
455 if (tk != NULL) // arg # is in range, so expand it
459 // Reverse-translation from a token number to a string.
460 // This is a hack. It might be better table-driven.
463 if ((*tk >= KW_D0) && !rdsp && !rgpu)
465 d = regname[(int)*tk++ - KW_D0];
468 else if ((*tk >= KW_R0) && (*tk <= KW_R31))
470 d = riscregname[(int)*tk++ - KW_R0];
479 // d = (char *)*tk++;
482 // This fix should be done for strings too
483 d = symbolString[*tk++];
484 DEBUG printf("ExM: SYMBOL=\"%s\"", d);
489 // d = (char *)*tk++;
492 d = symbolString[*tk++];
513 // Shamus: Changing the format specifier from %lx to %ux caused
514 // the assembler to choke on legitimate code... Need to investigate
515 // this further before changing anything else here!
517 sprintf(numbuf, "$%lx", (LONG)*tk++);
578 *dst++ = (char)*(tk - 1);
583 // If 'd' != NULL, copy string to destination
587 DEBUG printf("d='%s'\n", d);
604 DEBUG { printf("ExM: dst=\"%s\"\n", dest); }
609 DEBUG printf("*** OVERFLOW LINE ***\n%s\n", dest);
610 return fatal("line too long as a result of macro expansion");
615 // Get Next Line of Text from a Macro
617 char * GetNextMacroLine(void)
619 unsigned source_addr;
621 IMACRO * imacro = cur_inobj->inobj.imacro;
622 // LONG * strp = imacro->im_nextln;
623 struct LineList * strp = imacro->im_nextln;
625 if (strp == NULL) // End-of-macro
628 // imacro->im_nextln = (LONG *)*strp;
629 imacro->im_nextln = strp->next;
630 // ExpandMacro((char *)(strp + 1), imacro->im_lnbuf, LNSIZ);
631 ExpandMacro(strp->line, imacro->im_lnbuf, LNSIZ);
633 return imacro->im_lnbuf;
638 // Get Next Line of Text from a Repeat Block
640 char * GetNextRepeatLine(void)
643 IREPT * irept = cur_inobj->inobj.irept;
644 LONG * strp = irept->ir_nextln; // initial null
646 // Do repeat at end of .rept block's string list
649 DEBUG printf("back-to-top-of-repeat-block count=%d\n", (int)irept->ir_count);
650 irept->ir_nextln = irept->ir_firstln; // copy first line
652 if (irept->ir_count-- == 0)
654 DEBUG printf("end-repeat-block\n");
658 strp = irept->ir_nextln;
661 strcpy(irbuf, (char *)(irept->ir_nextln + 1));
662 DEBUG printf("repeat line='%s'\n", irbuf);
663 irept->ir_nextln = (LONG *)*strp;
670 // Include a Source File used at the Root, and for ".include" Files
672 int include(int handle, char * fname)
680 printf("[include: %s, cfileno=%u]\n", fname, cfileno);
682 // Alloc and initialize include-descriptors
683 inobj = a_inobj(SRC_IFILE);
684 ifile = inobj->inobj.ifile;
686 ifile->ifhandle = handle; // Setup file handle
687 ifile->ifind = ifile->ifcnt = 0; // Setup buffer indices
688 ifile->ifoldlineno = curlineno; // Save old line number
689 ifile->ifoldfname = curfname; // Save old filename
690 ifile->ifno = cfileno; // Save old file number
692 // cfileno = filecount++; // Compute new file number
693 // NB: This *must* be preincrement, we're adding one to the filecount here!
694 cfileno = ++filecount; // Compute NEW file number
695 curfname = strdup(fname); // Set current filename (alloc storage)
696 curlineno = 0; // Start on line zero
698 // Add another file to the file-record
699 fr = (FILEREC *)malloc(sizeof(FILEREC));
700 fr->frec_next = NULL;
701 fr->frec_name = curfname;
704 filerec = fr; // Add first filerec
706 last_fr->frec_next = fr; // Append to list of filerecs
709 DEBUG printf("[include: curfname: %s, cfileno=%u]\n", curfname, cfileno);
716 // Pop the Current Input Level
723 INOBJ * inobj = cur_inobj;
727 // Pop IFENT levels until we reach the conditional assembly context we
728 // were at when the input object was entered.
729 while (ifent != inobj->in_ifent)
732 tok = inobj->in_otok; // Restore tok and otok
733 etok = inobj->in_etok;
735 switch (inobj->in_type)
737 case SRC_IFILE: // Pop and release an IFILE
739 printf("[Leaving: %s]\n", curfname);
741 ifile = inobj->inobj.ifile;
742 ifile->if_link = f_ifile;
744 close(ifile->ifhandle); // Close source file
745 if (verb_flag) printf("[fpop (pre): curfname=%s]\n", curfname);
746 curfname = ifile->ifoldfname; // Set current filename
747 if (verb_flag) printf("[fpop (post): curfname=%s]\n", curfname);
748 if (verb_flag) printf("[fpop: (pre) cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno);
749 curlineno = ifile->ifoldlineno; // Set current line#
750 DEBUG printf("cfileno=%d ifile->ifno=%d\n", (int)cfileno, (int)ifile->ifno);
751 cfileno = ifile->ifno; // Restore current file number
752 if (verb_flag) printf("[fpop: (post) cfileno=%d ifile->ifno=%d]\n", (int)cfileno, (int)ifile->ifno);
754 case SRC_IMACRO: // Pop and release an IMACRO
755 imacro = inobj->inobj.imacro;
756 imacro->im_link = f_imacro;
759 case SRC_IREPT: // Pop and release an IREPT
760 DEBUG printf("dealloc IREPT\n");
761 p = inobj->inobj.irept->ir_firstln;
772 cur_inobj = inobj->in_link;
773 inobj->in_link = f_inobj;
782 // Get line from file into buf, return NULL on EOF or ptr to the start of a
785 char * GetNextLine(void)
789 int readamt = -1; // 0 if last read() yeilded 0 bytes
790 IFILE * fl = cur_inobj->inobj.ifile;
794 // Scan for next end-of-line; handle stupid text formats by treating
795 // \r\n the same as \n. (lone '\r' at end of buffer means we have to
799 d = &fl->ifbuf[fl->ifind];
801 for(p=d; i<j; i++, p++)
803 if (*p == '\r' || *p == '\n')
811 break; // Look for '\n' to eat
813 else if (p[1] == '\n')
827 // Handle hanging lines by ignoring them (Input file is exhausted, no
828 // \r or \n on last line)
829 if (!readamt && fl->ifcnt)
836 // Truncate and return absurdly long lines.
837 if (fl->ifcnt >= QUANTUM)
839 fl->ifbuf[fl->ifind + fl->ifcnt - 1] = '\0';
841 return &fl->ifbuf[fl->ifind];
844 // Relocate what's left of a line to the beginning of the buffer, and
845 // read some more of the file in; return NULL if the buffer's empty and
849 p = &fl->ifbuf[fl->ifind];
850 d = &fl->ifbuf[fl->ifcnt & 1];
852 for(i=0; i<fl->ifcnt; i++)
855 fl->ifind = fl->ifcnt & 1;
858 if ((readamt = read(fl->ifhandle, &fl->ifbuf[fl->ifind + fl->ifcnt], QUANTUM)) < 0)
861 if ((fl->ifcnt += readamt) == 0)
870 int TokenizeLine(void)
872 char * ln = NULL; // Ptr to current position in line
873 char * p; // Random character ptr
874 TOKEN * tk; // Token-deposit ptr
875 int state = 0; // State for keyword detector
876 int j = 0; // Var for keyword detector
877 char c; // Random char
878 VALUE v; // Random value
879 char * nullspot = NULL; // Spot to clobber for SYMBOL terminatn
880 int stuffnull; // 1:terminate SYMBOL '\0' at *nullspot
882 int stringNum = 0; // Pointer to string locations in tokenized line
886 if (cur_inobj == NULL) // Return EOF if input stack is empty
889 // Get another line of input from the current input source: a file,
890 // a macro, or a repeat-block
891 switch (cur_inobj->in_type)
895 // o bump source line number;
896 // o tag the listing-line with a space;
897 // o kludge lines generated by Alcyon C.
899 if ((ln = GetNextLine()) == NULL)
901 if (verb_flag) printf("TokenizeLine: Calling fpop() from SRC_IFILE...\n");
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 = GetNextMacroLine()) == 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 = GetNextRepeatLine()) == NULL)
948 if (verb_flag) printf("TokenizeLine: Calling fpop() from SRC_IREPT...\n");
957 // Save text of the line. We only do this during listings and within
958 // macro-type blocks, since it is expensive to unconditionally copy every
963 // General house-keeping
964 tok = tokeol; // Set "tok" to EOL in case of error
965 tk = etok; // Reset token ptr
966 stuffnull = 0; // Don't stuff nulls
967 totlines++; // Bump total #lines assembled
969 // See if the entire line is a comment. This is a win if the programmer
970 // puts in lots of comments
971 if (*ln == '*' || *ln == ';' || ((*ln == '/') && (*(ln + 1) == '/')))
974 // Main tokenization loop;
975 // o skip whitespace;
976 // o handle end-of-line;
978 // o handle single-character tokens (operators, etc.);
979 // o handle multiple-character tokens (constants, strings, etc.).
982 // Skip whitespace, handle EOL
983 while ((int)chrtab[*ln] & WHITE)
986 // Handle EOL, comment with ';'
987 if (*ln == EOS || *ln == ';'|| ((*ln == '/') && (*(ln + 1) == '/')))
990 // Handle start of symbol. Symbols are null-terminated in place. The
991 // termination is always one symbol behind, since there may be no place
992 // for a null in the case that an operator immediately follows the name.
997 if (stuffnull) // Terminate old symbol from previous pass
1000 v = 0; // Assume no DOT attrib follows symbol
1002 p = nullspot = ln++; // Nullspot -> start of this symbol
1004 // Find end of symbol (and compute its length)
1005 for(j=1; (int)chrtab[*ln]&CTSYM; j++)
1008 // Handle "DOT" special forms (like ".b") that follow a normal
1009 // symbol or keyword:
1012 *ln++ = EOS; // Terminate symbol
1013 stuffnull = 0; // And never try it again
1015 // Character following the `.' must have a DOT attribute, and
1016 // the chararacter after THAT one must not have a start-symbol
1017 // attribute (to prevent symbols that look like, for example,
1018 // "zingo.barf", which might be a good idea anyway....)
1019 if ((((int)chrtab[*ln] & DOT) == 0) || ((int)dotxtab[*ln] <= 0))
1020 return error("[bwsl] must follow `.' in symbol");
1022 v = (VALUE)dotxtab[*ln++];
1024 if ((int)chrtab[*ln] & CTSYM)
1025 return error("misuse of `.', not allowed in symbols");
1028 // If the symbol is small, check to see if it's really the name of
1032 for(state=0; state>=0;)
1034 j = (int)tolowertab[*p++];
1037 if (kwcheck[j] != state)
1043 if (*p == EOS || p == ln)
1057 // Make j = -1 if user tries to use a RISC register while in 68K mode
1058 if (!(rgpu || rdsp) && ((TOKEN)j >= KW_R0 && (TOKEN)j <= KW_R31))
1063 //make j = -1 if time, date etc with no preceeding ^^
1064 //defined, referenced, streq, macdef, date and time
1067 case 112: // defined
1068 case 113: // referenced
1077 // If not tokenized keyword OR token was not found
1078 if (j < 0 || state < 0)
1082 //problem here: nullspot is a char * but TOKEN is a uint32_t. On a 64-bit system,
1083 //this will cause all kinds of mischief.
1085 *tk++ = (TOKEN)nullspot;
1087 string[stringNum] = nullspot;
1098 if (v) // Record attribute token (if any)
1101 if (stuffnull) // Arrange for string termination on next pass
1107 // Handle identity tokens
1114 // Handle multiple-character tokens
1119 case '!': // ! or !=
1129 case '\'': // 'string'
1130 case '\"': // "string"
1134 // More char * stuffing (8 bytes) into the space of 4 (TOKEN).
1135 // Need to figure out how to fix this crap.
1139 string[stringNum] = ln;
1144 for(p=ln; *ln!=EOS && *ln!=c1;)
1153 return(error("unterminated string"));
1182 warn("bad backslash code in string");
1192 return error("unterminated string");
1196 case '$': // $, hex constant
1197 if ((int)chrtab[*ln] & HDIGIT)
1201 while ((int)hextab[*ln] >= 0)
1202 v = (v << 4) + (int)hextab[*ln++];
1206 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1212 if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1218 if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1231 case '<': // < or << or <> or <=
1250 case ':': // : or ::
1260 case '=': // = or ==
1270 case '>': // > or >> or >=
1285 case '%': // % or binary constant
1286 if (*ln < '0' || *ln > '1')
1294 while (*ln >= '0' && *ln <= '1')
1295 v = (v << 1) + *ln++ - '0';
1299 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1305 if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1311 if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1320 case '@': // @ or octal constant
1321 if (*ln < '0' || *ln > '7')
1329 while (*ln >= '0' && *ln <= '7')
1330 v = (v << 3) + *ln++ - '0';
1334 if ((*(ln+1) == 'b') || (*(ln+1) == 'B'))
1340 if ((*(ln+1) == 'w') || (*(ln+1) == 'W'))
1346 if ((*(ln+1) == 'l') || (*(ln+1) == 'L'))
1355 case '^': // ^ or ^^ <operator-name>
1362 if (((int)chrtab[*++ln] & STSYM) == 0)
1364 error("invalid symbol following ^^");
1370 while ((int)chrtab[*ln] & CTSYM)
1373 for(state=0; state>=0;)
1375 // Get char, convert to lowercase
1378 if (j >= 'A' && j <= 'Z')
1383 if (kwcheck[j] != state)
1389 if (*p == EOS || p == ln)
1398 if (j < 0 || state < 0)
1400 error("unknown symbol following ^^");
1407 interror(2); // Bad MULTX entry in chrtab
1412 // Handle decimal constant
1417 while ((int)chrtab[*ln] & DIGIT)
1418 v = (v * 10) + *ln++ - '0';
1420 // See if there's a .[bwl] after the constant & deal with it if so
1423 if ((*(ln + 1) == 'b') || (*(ln + 1) == 'B'))
1428 else if ((*(ln + 1) == 'w') || (*(ln + 1) == 'W'))
1433 else if ((*(ln + 1) == 'l') || (*(ln + 1) == 'L'))
1444 // Handle illegal character
1445 return error("illegal character");
1448 // Terminate line of tokens and return "success."
1451 tok = etok; // Set tok to beginning of line
1453 if (stuffnull) // Terminate last SYMBOL
1463 // .GOTO <label> goto directive
1465 // The label is searched for starting from the first line of the current,
1466 // enclosing macro definition. If no enclosing macro exists, an error is
1469 // A label is of the form:
1471 // :<name><whitespace>
1473 // The colon must appear in column 1. The label is stripped prior to macro
1474 // expansion, and is NOT subject to macro expansion. The whitespace may also
1477 //int d_goto(WORD siz) {
1479 int d_goto(WORD unused)
1481 // char * sym; // Label to search for
1482 // LONG * defln; // Macro definition strings
1483 char * s1; // Temps for string comparison
1485 // IMACRO * imacro; // Macro invocation block
1487 // Setup for the search
1489 return error("missing label");
1491 // sym = (char *)tok[1];
1492 char * sym = string[tok[1]];
1495 if (cur_inobj->in_type != SRC_IMACRO)
1496 return error("goto not in macro");
1498 IMACRO * imacro = cur_inobj->inobj.imacro;
1499 // defln = (LONG *)imacro->im_macro->svalue;
1500 struct LineList * defln = imacro->im_macro->lineList;
1502 // Find the label, starting with the first line.
1503 // for(; defln!=NULL; defln=(LONG *)*defln)
1504 for(; defln!=NULL; defln=defln->next)
1506 // if (*(char *)(defln + 1) == ':')
1507 if (defln->line[0] == ':')
1509 // Compare names (sleazo string compare)
1510 // This string compare is not right. Doesn't check for lengths.
1511 // (actually it does, but in a crappy, unclear way.)
1512 #warning "!!! Bad string comparison !!!"
1514 // s2 = (char *)(defln + 1) + 1;
1528 // Found the label, set new macro next-line and return.
1529 if ((*s2 == EOS) || ((int)chrtab[*s2] & WHITE))
1531 imacro->im_nextln = defln;
1537 return error("goto label not found");
1541 void DumpTokenBuffer(void)
1544 printf("Tokens [%X]: ", sloc);
1546 for(t=tokbuf; *t!=EOL; t++)
1550 else if (*t == CONST)
1553 printf("[CONST: $%X]", (uint32_t)*t);
1555 else if (*t == ACONST)
1557 else if (*t == STRING)
1558 // printf("[STRING]");
1561 printf("[STRING:\"%s\"]", string[*t]);
1563 else if (*t == SYMBOL)
1566 printf("[SYMBOL:\"%s\"]", string[*t]);
1570 else if (*t == TKEOF)
1572 else if (*t == DEQUALS)
1573 printf("[DEQUALS]");
1578 else if (*t == DCOLON)
1590 else if (*t == UNMINUS)
1591 printf("[UNMINUS]");
1592 else if (*t == DOTB)
1594 else if (*t == DOTW)
1596 else if (*t == DOTL)
1598 else if (*t == DOTI)
1600 else if (*t == ENDEXPR)
1601 printf("[ENDEXPR]");
1602 else if (*t == CR_DEFINED)
1603 printf("[CR_DEFINED]");
1604 else if (*t == CR_REFERENCED)
1605 printf("[CR_REFERENCED]");
1606 else if (*t == CR_STREQ)
1607 printf("[CR_STREQ]");
1608 else if (*t == CR_MACDEF)
1609 printf("[CR_MACDEF]");
1610 else if (*t == CR_TIME)
1611 printf("[CR_TIME]");
1612 else if (*t == CR_DATE)
1613 printf("[CR_DATE]");
1614 else if (*t >= 0x20 && *t <= 0x2F)
1615 printf("[%c]", (char)*t);
1616 else if (*t >= 0x3A && *t <= 0x3F)
1617 printf("[%c]", (char)*t);
1618 else if (*t >= 0x80 && *t <= 0x87)
1619 printf("[D%u]", ((uint32_t)*t) - 0x80);
1620 else if (*t >= 0x88 && *t <= 0x8F)
1621 printf("[A%u]", ((uint32_t)*t) - 0x88);
1623 printf("[%X:%c]", (uint32_t)*t, (char)*t);
1624 // printf("[%X]", (uint32_t)*t);