fgen.l revision 1.10 1 %{
2 /* $NetBSD: fgen.l,v 1.10 2000/10/11 14:46:02 is Exp $ */
3 /* FLEX input for FORTH input file scanner */
4 /*
5 * Copyright (c) 1998 Eduardo Horvath.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Eduardo Horvath.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software withough specific prior written permission
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 /*
34 Specifications are as follows:
35
36 The function "yylex()" always returns a pointer to a structure:
37
38 struct tok {
39 int type;
40 char *text;
41 }
42 #define TOKEN struct tok
43 */
44 %}
45
46 %option yylineno
47
48 decimal [0-9]
49 hex [0-9A-Fa-f]
50 octal [0-7]
51 white [ \t\n\r\f]
52 tail {white}
53
54 %{
55 #include <sys/types.h>
56
57 #include <assert.h>
58 #include <err.h>
59 #include <errno.h>
60 #include <fcntl.h>
61 #include <stdarg.h>
62 #include <stdio.h>
63 #include <string.h>
64 #include <unistd.h>
65
66 #include "fgen.h"
67 TOKEN token;
68
69 /*
70 * Global variables that control the parse state.
71 */
72
73 struct fcode *dictionary = NULL;
74 struct macro *aliases = NULL;
75 int outf = 1; /* stdout */
76 int state = 0;
77 int nextfcode = 0x800;
78 int base = TOK_HEX;
79 long outpos;
80 char *outbuf = NULL;
81 char *outfile, *infile;
82 #define BUFCLICK (1024*1024)
83 size_t outbufsiz = 0;
84 char *myname = NULL;
85 int offsetsize = 8;
86 int defining = 0;
87 int tokenizer = 0;
88
89 #define PSTKSIZ 1024
90 Cell parse_stack[PSTKSIZ];
91 int parse_stack_ptr = 0;
92
93 int main __P((int, char *[]));
94 void token_err __P((int, char *, char *, char *, ...))
95 __attribute__((__format__(__printf__, 4, 5)));
96 YY_DECL;
97
98 int debug = 0;
99 #define ASSERT if (debug) assert
100 #define STATE(y, x) do { if (debug) printf( "%ld State %s: token `%s'\n", outpos, x, y); } while (0)
101
102 #define YY_NO_UNPUT
103 %}
104
105 %%
106
107 0 { token.type = TOK_OTHER; token.text = yytext;
108 return &token; }
109
110 1 { token.type = TOK_OTHER; token.text = yytext;
111 return &token; }
112
113 2 { token.type = TOK_OTHER; token.text = yytext;
114 return &token; }
115
116 3 { token.type = TOK_OTHER; token.text = yytext;
117 return &token; }
118
119 -1 { token.type = TOK_OTHER; token.text = yytext;
120 return &token; }
121
122 {white}* /* whitespace -- keep looping */ ;
123
124 \\[^\n]*\n /* end of line comment -- keep looping */ { STATE(yytext, "EOL comment"); }
125
126 -?{hex}+ { token.type = TOK_NUMBER; token.text = yytext;
127 return &token; }
128
129 \'.\' { token.type = TOK_C_LIT; token.text = yytext; return &token; }
130
131 \"{white}*(\\\"|[^"])*\" { token.type = TOK_STRING_LIT; token.text = yytext;
132 return &token; } /* String started by `"' or `."' */
133
134 \.\({white}*(\\\"|[^)])*\) { token.type = TOK_PSTRING; token.text = yytext;
135 return &token; } /* String of type `.(.....)' */
136
137 \.\"{white}*(\\\"|[^"])*\" { token.type = TOK_PSTRING; token.text = yytext;
138 return &token; }
139
140 "(" { token.type = TOK_COMMENT; token.text = yytext;
141 return &token; }
142
143 ")" { token.type = TOK_ENDCOMMENT; token.text = yytext;
144 return &token; }
145
146 ":" { token.type = TOK_COLON; token.text = yytext;
147 return &token; }
148
149 ";" { token.type = TOK_SEMICOLON; token.text = yytext;
150 return &token; }
151
152 \' { token.type = TOK_TOKENIZE; token.text = yytext;
153 return &token; }
154
155 [aA][gG][aA][iI][nN] { token.type = TOK_AGAIN; token.text = yytext;
156 return &token; }
157
158 [aA][lL][iI][aA][sS] { token.type = TOK_ALIAS; token.text = yytext;
159 return &token; }
160
161 \[\'\] { token.type = TOK_GETTOKEN; token.text = yytext;
162 return &token; }
163
164 [aA][sS][cC][iI][iI] { token.type = TOK_ASCII; token.text = yytext;
165 return &token; }
166
167 [bB][eE][gG][iI][nN] { token.type = TOK_BEGIN; token.text = yytext;
168 return &token; }
169
170 [bB][uU][fF][fF][eE][rR]: { token.type = TOK_BUFFER; token.text = yytext;
171 return &token; }
172
173 [cC][aA][sS][eE] { token.type = TOK_CASE; token.text = yytext;
174 return &token; }
175
176 [cC][oO][nN][sS][tT][aA][nN][tT] { token.type = TOK_CONSTANT; token.text = yytext;
177 return &token; }
178
179 [cC][oO][nN][tT][rR][oO][lL] { token.type = TOK_CONTROL; token.text = yytext;
180 return &token; }
181
182 [cC][rR][eE][aA][tT][eE] { token.type = TOK_CREATE; token.text = yytext;
183 return &token; }
184
185 [dD]# { token.type = TOK_DECIMAL; token.text = yytext;
186 return &token; }
187
188 [dD][eE][cC][iI][mM][aA][lL] { token.type = TOK_DECIMAL; token.text = yytext;
189 return &token; }
190
191 [dD][eE][fF][eE][rR] { token.type = TOK_DEFER; token.text = yytext;
192 return &token; }
193
194 \??[dD][oO] { token.type = TOK_DO; token.text = yytext;
195 return &token; }
196
197 [eE][lL][sS][eE] { token.type = TOK_ELSE; token.text = yytext;
198 return &token; }
199
200 [eE][nN][dD][cC][aA][sS][eE] { token.type = TOK_ENDCASE; token.text = yytext;
201 return &token; }
202
203 [eE][nN][dD][oO][fF] { token.type = TOK_ENDOF; token.text = yytext;
204 return &token; }
205
206 [eE][xX][tT][eE][rR][nN][aA][lL] { token.type = TOK_EXTERNAL; token.text = yytext;
207 return &token; }
208
209 [fF][iI][eE][lL][dD] { token.type = TOK_FIELD; token.text = yytext;
210 return &token; }
211
212 [hH]# { token.type = TOK_HEX; token.text = yytext;
213 return &token; }
214
215 [hH][eE][aA][dD][eE][rR][lL][eE][sS][sS] { token.type = TOK_HEADERLESS; token.text = yytext;
216 return &token; }
217
218 [hH][eE][aA][dD][eE][rR][sS] { token.type = TOK_HEADERS; token.text = yytext;
219 return &token; }
220
221 [hH][eE][xX] { token.type = TOK_HEX; token.text = yytext;
222 return &token; }
223
224 [iI][fF] { token.type = TOK_IF; token.text = yytext;
225 return &token; }
226
227 \??[lL][eE][aA][vV][eE] { token.type = TOK_LEAVE; token.text = yytext;
228 return &token; }
229
230 \+?[lL][oO][oO][pP] { token.type = TOK_LOOP; token.text = yytext;
231 return &token; }
232
233 [oO]# { token.type = TOK_OCTAL; token.text = yytext;
234 return &token; }
235
236 [oO][cC][tT][aA][lL] { token.type = TOK_OCTAL; token.text = yytext;
237 return &token; }
238
239 [oO][fF] { token.type = TOK_OF; token.text = yytext;
240 return &token; }
241
242 [rR][eE][pP][eE][aA][tT] { token.type = TOK_REPEAT; token.text = yytext;
243 return &token; }
244
245 [tT][hH][eE][nN] { token.type = TOK_THEN; token.text = yytext;
246 return &token; }
247
248 [tT][oO] { token.type = TOK_TO; token.text = yytext;
249 return &token; }
250
251 [uU][nN][tT][iI][lL] { token.type = TOK_UNTIL; token.text = yytext;
252 return &token; }
253
254 [vV][aA][lL][uU][eE] { token.type = TOK_VALUE; token.text = yytext;
255 return &token; }
256
257 [vV][aA][rR][iI][aA][bB][lL][eE] { token.type = TOK_VARIABLE; token.text = yytext;
258 return &token; }
259
260 [wW][hH][iI][lL][eE] { token.type = TOK_WHILE; token.text = yytext;
261 return &token; }
262
263 offset16 { token.type = TOK_OFFSET16; token.text = yytext;
264 return &token; }
265
266 tokenizer\[ { token.type = TOK_BEGTOK; token.text = yytext;
267 return &token; }
268
269 emit-byte { token.type = TOK_EMIT_BYTE; token.text = yytext;
270 return &token; }
271
272 \]tokenizer { token.type = TOK_ENDTOK; token.text = yytext;
273 return &token; }
274
275 fload { token.type = TOK_FLOAD; token.text = yytext;
276 return &token; }
277
278
279 [^ \n\t\r\f]+ { token.type = TOK_OTHER; token.text = yytext;
280 return &token; }
281
282 <<EOF>> { return NULL; }
283 %%
284
285 /* Function definitions */
286 void push __P((Cell));
287 Cell pop __P((void));
288 int depth __P((void));
289 int fadd __P((struct fcode *, struct fcode *));
290 struct fcode *flookup __P((struct fcode *, char *));
291 int aadd __P((struct macro *, struct macro *));
292 struct macro *alookup __P((struct macro *, char *));
293 void initdic __P((void));
294 void usage __P((char *));
295 void tokenize __P((YY_BUFFER_STATE));
296 int emit __P((char *));
297 int spit __P((long));
298 void sspit __P((char *));
299 int apply_macros __P((YY_BUFFER_STATE, char *));
300 int main __P((int argc, char *argv[]));
301
302 /*
303 * Standard FCode names and numbers. Includes standard
304 * tokenizer aliases.
305 */
306 struct fcode fcodes[] = {
307 { "end0", 0x0000 },
308 { "b(lit)", 0x0010 },
309 { "b(')", 0x0011 },
310 { "b(\")", 0x0012 },
311 { "bbranch", 0x0013 },
312 { "b?branch", 0x0014 },
313 { "b(loop)", 0x0015 },
314 { "b(+loop)", 0x0016 },
315 { "b(do)", 0x0017 },
316 { "b(?do)", 0x0018 },
317 { "i", 0x0019 },
318 { "j", 0x001a },
319 { "b(leave)", 0x001b },
320 { "b(of)", 0x001c },
321 { "execute", 0x001d },
322 { "+", 0x001e },
323 { "-", 0x001f },
324 { "*", 0x0020 },
325 { "/", 0x0021 },
326 { "mod", 0x0022 },
327 { "and", 0x0023 },
328 { "or", 0x0024 },
329 { "xor", 0x0025 },
330 { "invert", 0x0026 },
331 { "lshift", 0x0027 },
332 { "rshift", 0x0028 },
333 { ">>a", 0x0029 },
334 { "/mod", 0x002a },
335 { "u/mod", 0x002b },
336 { "negate", 0x002c },
337 { "abs", 0x002d },
338 { "min", 0x002e },
339 { "max", 0x002f },
340 { ">r", 0x0030 },
341 { "r>", 0x0031 },
342 { "r@", 0x0032 },
343 { "exit", 0x0033 },
344 { "0=", 0x0034 },
345 { "0<>", 0x0035 },
346 { "0<", 0x0036 },
347 { "0<=", 0x0037 },
348 { "0>", 0x0038 },
349 { "0>=", 0x0039 },
350 { "<", 0x003a },
351 { ">", 0x003b },
352 { "=", 0x003c },
353 { "<>", 0x003d },
354 { "u>", 0x003e },
355 { "u<=", 0x003f },
356 { "u<", 0x0040 },
357 { "u>=", 0x0041 },
358 { ">=", 0x0042 },
359 { "<=", 0x0043 },
360 { "between", 0x0044 },
361 { "within", 0x0045 },
362 { "drop", 0x0046 },
363 { "dup", 0x0047 },
364 { "over", 0x0048 },
365 { "swap", 0x0049 },
366 { "rot", 0x004a },
367 { "-rot", 0x004b },
368 { "tuck", 0x004c },
369 { "nip", 0x004d },
370 { "pick", 0x004e },
371 { "roll", 0x004f },
372 { "?dup", 0x0050 },
373 { "depth", 0x0051 },
374 { "2drop", 0x0052 },
375 { "2dup", 0x0053 },
376 { "2over", 0x0054 },
377 { "2swap", 0x0055 },
378 { "2rot", 0x0056 },
379 { "2/", 0x0057 },
380 { "u2/", 0x0058 },
381 { "2*", 0x0059 },
382 { "/c", 0x005a },
383 { "/w", 0x005b },
384 { "/l", 0x005c },
385 { "/n", 0x005d },
386 { "ca+", 0x005e },
387 { "wa+", 0x005f },
388 { "la+", 0x0060 },
389 { "na+", 0x0061 },
390 { "char+", 0x0062 },
391 { "wa1+", 0x0063 },
392 { "la1+", 0x0064 },
393 { "cell+", 0x0065 },
394 { "chars", 0x0066 },
395 { "/w*", 0x0067 },
396 { "/l*", 0x0068 },
397 { "cells", 0x0069 },
398 { "on", 0x006a },
399 { "off", 0x006b },
400 { "+!", 0x006c },
401 { "@", 0x006d },
402 { "l@", 0x006e },
403 { "w@", 0x006f },
404 { "<w@", 0x0070 },
405 { "c@", 0x0071 },
406 { "!", 0x0072 },
407 { "l!", 0x0073 },
408 { "w!", 0x0074 },
409 { "c!", 0x0075 },
410 { "2@", 0x0076 },
411 { "2!", 0x0077 },
412 { "move", 0x0078 },
413 { "fill", 0x0079 },
414 { "comp", 0x007a },
415 { "noop", 0x007b },
416 { "lwsplit", 0x007c },
417 { "wjoin", 0x007d },
418 { "lbsplit", 0x007e },
419 { "bljoin", 0x007f },
420 { "wbflip", 0x0080 },
421 { "upc", 0x0081 },
422 { "lcc", 0x0082 },
423 { "pack", 0x0083 },
424 { "count", 0x0084 },
425 { "body>", 0x0085 },
426 { ">body", 0x0086 },
427 { "fcode-revision", 0x0087 },
428 { "span", 0x0088 },
429 { "unloop", 0x0089 },
430 { "expect", 0x008a },
431 { "alloc-mem", 0x008b },
432 { "free-mem", 0x008c },
433 { "key?", 0x008d },
434 { "key", 0x008e },
435 { "emit", 0x008f },
436 { "type", 0x0090 },
437 { "(cr", 0x0091 },
438 { "cr", 0x0092 },
439 { "#out", 0x0093 },
440 { "#line", 0x0094 },
441 { "hold", 0x0095 },
442 { "<#", 0x0096 },
443 { "u#>", 0x0097 },
444 { "sign", 0x0098 },
445 { "u#", 0x0099 },
446 { "u#s", 0x009a },
447 { "u.", 0x009b },
448 { "u.r", 0x009c },
449 { ".", 0x009d },
450 { ".r", 0x009e },
451 { ".s", 0x009f },
452 { "base", 0x00a0 },
453 { "convert", 0x00a1 },
454 { "$number", 0x00a2 },
455 { "digit", 0x00a3 },
456 { "-1", 0x00a4 },
457 { "true", 0x00a4 },
458 { "0", 0x00a5 },
459 { "1", 0x00a6 },
460 { "2", 0x00a7 },
461 { "3", 0x00a8 },
462 { "bl", 0x00a9 },
463 { "bs", 0x00aa },
464 { "bell", 0x00ab },
465 { "bounds", 0x00ac },
466 { "here", 0x00ad },
467 { "aligned", 0x00ae },
468 { "wbsplit", 0x00af },
469 { "bwjoin", 0x00b0 },
470 { "b(<mark)", 0x00b1 },
471 { "b(>resolve)", 0x00b2 },
472 { "set-token-table", 0x00b3 },
473 { "set-table", 0x00b4 },
474 { "new-token", 0x00b5 },
475 { "named-token", 0x00b6 },
476 { "b(:)", 0x00b7 },
477 { "b(value)", 0x00b8 },
478 { "b(variable)", 0x00b9 },
479 { "b(constant)", 0x00ba },
480 { "b(create)", 0x00bb },
481 { "b(defer)", 0x00bc },
482 { "b(buffer:)", 0x00bd },
483 { "b(field)", 0x00be },
484 { "b(code)", 0x00bf },
485 { "instance", 0x00c0 },
486 { "b(;)", 0x00c2 },
487 { "b(to)", 0x00c3 },
488 { "b(case)", 0x00c4 },
489 { "b(endcase)", 0x00c5 },
490 { "b(endof)", 0x00c6 },
491 { "#", 0x00c7 },
492 { "#s", 0x00c8 },
493 { "#>", 0x00c9 },
494 { "external-token", 0x00ca },
495 { "$find", 0x00cb },
496 { "offset16", 0x00cc },
497 { "evaluate", 0x00cd },
498 { "c,", 0x00d0 },
499 { "w,", 0x00d1 },
500 { "l,", 0x00d2 },
501 { "'", 0x00d3 },
502 { "um*", 0x00d4 },
503 { "um/mod", 0x00d5 },
504 { "d+", 0x00d8 },
505 { "d-", 0x00d9 },
506 { "get-token", 0x00da },
507 { "set-token", 0x00db },
508 { "state", 0x00dc },
509 { "compile,", 0x00dd },
510 { "behavior", 0x00de },
511 { "start0", 0x00f0 },
512 { "start1", 0x00f1 },
513 { "start2", 0x00f2 },
514 { "start4", 0x00f3 },
515 { "ferror", 0x00fc },
516 { "version1", 0x00fd },
517 { "4-byte-id", 0x00fe },
518 { "end1", 0x00ff },
519 { "dma-alloc", 0x0101 },
520 { "my-address", 0x0102 },
521 { "my-space", 0x0103 },
522 { "memmap", 0x0104 },
523 { "free-virtual", 0x0105 },
524 { ">physical", 0x0106 },
525 { "my-params", 0x010f },
526 { "property", 0x0110 },
527 { "encode-int", 0x0111 },
528 { "encode+", 0x0112 },
529 { "encode-phys", 0x0113 },
530 { "encode-string", 0x0114 },
531 { "encode-bytes", 0x0115 },
532 { "reg", 0x0116 },
533 { "intr", 0x0117 },
534 { "driver", 0x0118 },
535 { "model", 0x0119 },
536 { "device-type", 0x011a },
537 { "parse-2int", 0x011b },
538 { "is-install", 0x011c },
539 { "is-remove", 0x011d },
540 { "is-selftest", 0x011e },
541 { "new-device", 0x011f },
542 { "diagnostic-mode?", 0x0120 },
543 { "display-status", 0x0121 },
544 { "memory-test-suite", 0x0122 },
545 { "group-code", 0x0123 },
546 { "mask", 0x0124 },
547 { "get-msecs", 0x0125 },
548 { "ms", 0x0126 },
549 { "find-device", 0x0127 },
550 { "decode-phys", 0x0128 },
551 { "map-low", 0x0130 },
552 { "sbus-intr>cpu", 0x0131 },
553 { "#lines", 0x0150 },
554 { "#columns", 0x0151 },
555 { "line#", 0x0152 },
556 { "column#", 0x0153 },
557 { "inverse?", 0x0154 },
558 { "inverse-screen?", 0x0155 },
559 { "frame-buffer-busy?", 0x0156 },
560 { "draw-character", 0x0157 },
561 { "reset-screen", 0x0158 },
562 { "toggle-cursor", 0x0159 },
563 { "erase-screen", 0x015a },
564 { "blink-screen", 0x015b },
565 { "invert-screen", 0x015c },
566 { "insert-characters", 0x015d },
567 { "delete-characters", 0x015e },
568 { "insert-lines", 0x015f },
569 { "delete-lines", 0x0160 },
570 { "draw-logo", 0x0161 },
571 { "frame-buffer-addr", 0x0162 },
572 { "screen-height", 0x0163 },
573 { "screen-width", 0x0164 },
574 { "window-top", 0x0165 },
575 { "window-left", 0x0166 },
576 { "default-font", 0x016a },
577 { "set-font", 0x016b },
578 { "char-height", 0x016c },
579 { "char-width", 0x016d },
580 { ">font", 0x016e },
581 { "fontbytes", 0x016f },
582 { "fb8-draw-character", 0x0180 },
583 { "fb8-reset-screen", 0x0181 },
584 { "fb8-toggle-cursor", 0x0182 },
585 { "fb8-erase-screen", 0x0183 },
586 { "fb8-blink-screen", 0x0184 },
587 { "fb8-invert-screen", 0x0185 },
588 { "fb8-insert-characters", 0x0186 },
589 { "fb8-delete-characters", 0x0187 },
590 { "fb8-inisert-lines", 0x0188 },
591 { "fb8-delete-lines", 0x0189 },
592 { "fb8-draw-logo", 0x018a },
593 { "fb8-install", 0x018b },
594 { "return-buffer", 0x01a0 },
595 { "xmit-packet", 0x01a1 },
596 { "poll-packet", 0x01a2 },
597 { "mac-address", 0x01a4 },
598 { "device-name", 0x0201 },
599 { "my-args", 0x0202 },
600 { "my-self", 0x0203 },
601 { "find-package", 0x0204 },
602 { "open-package", 0x0205 },
603 { "close-package", 0x0206 },
604 { "find-method", 0x0207 },
605 { "call-package", 0x0208 },
606 { "$call-parent", 0x0209 },
607 { "my-parent", 0x020a },
608 { "ihandle>phandle", 0x020b },
609 { "my-unit", 0x020d },
610 { "$call-method", 0x020e },
611 { "$open-package", 0x020f },
612 { "processor-type", 0x0210 },
613 { "firmware-version", 0x0211 },
614 { "fcode-version", 0x0212 },
615 { "alarm", 0x0213 },
616 { "(is-user-word)", 0x0214 },
617 { "suspend-fcode", 0x0215 },
618 { "abort", 0x0216 },
619 { "catch", 0x0217 },
620 { "throw", 0x0218 },
621 { "user-abort", 0x0219 },
622 { "get-my-property", 0x021a },
623 { "decode-int", 0x021b },
624 { "decode-string", 0x021c },
625 { "get-inherited-property", 0x021d },
626 { "delete-property", 0x021e },
627 { "get-package-property", 0x021f },
628 { "cpeek", 0x0220 },
629 { "wpeek", 0x0221 },
630 { "lpeek", 0x0222 },
631 { "cpoke", 0x0223 },
632 { "wpoke", 0x0224 },
633 { "lpoke", 0x0225 },
634 { "lwflip", 0x0226 },
635 { "lbflip", 0x0227 },
636 { "lbflips", 0x0228 },
637 { "adr-mask", 0x0229 },
638 { "rb@", 0x0230 },
639 { "rb!", 0x0231 },
640 { "rw@", 0x0232 },
641 { "rw!", 0x0233 },
642 { "rl@", 0x0234 },
643 { "rl!", 0x0235 },
644 { "wbflips", 0x0236 },
645 { "lwflips", 0x0237 },
646 { "probe", 0x0238 },
647 { "probe-virtual", 0x0239 },
648 { "child", 0x023b },
649 { "peer", 0x023c },
650 { "next-property", 0x023d },
651 { "byte-load", 0x023e },
652 { "set-args", 0x023f },
653 { "left-parse-string", 0x0240 },
654 /* 64-bit FCode extensions */
655 { "bxjoin", 0x0241 },
656 { "<l@", 0x0242 },
657 { "lxjoin", 0x0243 },
658 { "rx@", 0x022e },
659 { "rx!", 0x022f },
660 { "wxjoin", 0x0244 },
661 { "x,", 0x0245 },
662 { "x@", 0x0246 },
663 { "x!", 0x0247 },
664 { "/x", 0x0248 },
665 { "/x*", 0x0249 },
666 { "xa+", 0x024a },
667 { "xa1+", 0x024b },
668 { "xbflip", 0x024c },
669 { "xbflips", 0x024d },
670 { "xbsplit", 0x024e },
671 { "xlflip", 0x024f },
672 { "xlflips", 0x0250 },
673 { "xlsplit", 0x0251 },
674 { "xwflip", 0x0252 },
675 { "xwflips", 0x0253 },
676 { "xwsplit", 0x0254 },
677 { NULL, NULL }
678 };
679
680 /*
681 * Default macros -- can be overridden by colon definitions.
682 */
683 struct macro macros[] = {
684 { "eval", "evaluate" }, /* Build a more balanced tree */
685 { "(.)", "dup abs <# u#s swap sign u#>" },
686 { "<<", "lshift" },
687 { ">>", "rshift" },
688 { "?", "@ ." },
689 { "1+", "1 +" },
690 { "1-", "1 -" },
691 { "2+", "2 +" },
692 { "2-", "2 -" },
693 { "abort\"", "-2 throw" },
694 { "accept", "span @ -rot expect span @ swap span !" },
695 { "allot", "0 max 0 ?do 0 c, loop" },
696 { "blank", "bl fill" },
697 { "/c*", "chars" },
698 { "ca1+", "char+" },
699 { "carret", "b(lit) 00 00 00 0x0d" },
700 { ".d" "base @ swap 0x0a base ! . base !" },
701 { "decode-bytes", ">r over r@ + swap r@ - rot r>" },
702 { "3drop", "drop 2drop" },
703 { "3dup", "2 pick 2 pick 2 pick" },
704 { "erase", "0 fill" },
705 { "false", "0" },
706 { ".h" "base @ swap 0x10 base ! . base !" },
707 { "linefeed", "b(lit) 00 00 00 0x0a" },
708 { "/n*", "cells" },
709 { "na1+", "cell+", },
710 { "not", "invert", },
711 { "s.", "(.) type space" },
712 { "space", "bl emit" },
713 { "spaces", "0 max 0 ?do space loop" },
714 { "struct", "0" },
715 { "true", "-1" },
716 { "(u,)", "<# u#s u#>" },
717 { NULL, NULL }
718 };
719
720 /*
721 * Parser stack control functions.
722 */
723
724 void
725 push(val)
726 Cell val;
727 {
728 parse_stack[parse_stack_ptr++] = val;
729 if (parse_stack_ptr >= PSTKSIZ) {
730 (void)printf( "Parse stack overflow\n");
731 exit(1);
732 }
733 }
734
735 Cell
736 pop()
737 {
738 ASSERT(parse_stack_ptr);
739 return parse_stack[--parse_stack_ptr];
740 }
741
742 int
743 depth()
744 {
745 return (parse_stack_ptr);
746 }
747
748 /*
749 * Insert fcode into dictionary.
750 */
751 int
752 fadd(dict, new)
753 struct fcode *dict, *new;
754 {
755 int res = strcmp(dict->name, new->name);
756
757 #ifdef DEBUG
758 new->type = FCODE;
759 ASSERT(dict->type == FCODE);
760 #endif
761 /* Don't allow duplicate entries. */
762 if (!res) return (0);
763 if (res < 0) {
764 if (dict->l)
765 return fadd(dict->l, new);
766 else {
767 #ifdef DEBUG
768 if (debug > 1)
769 (void)printf( "fadd: new FCode `%s' is %lx\n",
770 new->name, new->num);
771 #endif
772 new->l = new->r = NULL;
773 dict->l = new;
774 }
775 } else {
776 if (dict->r)
777 return fadd(dict->r, new);
778 else {
779 #ifdef DEBUG
780 if (debug > 1)
781 (void)printf( "fadd: new FCode `%s' is %lx\n",
782 new->name, new->num);
783 #endif
784 new->l = new->r = NULL;
785 dict->r = new;
786 }
787 }
788 return (1);
789 }
790
791 /*
792 * Look for a code in the dictionary.
793 */
794 struct fcode *
795 flookup(dict, str)
796 struct fcode *dict;
797 char *str;
798 {
799 int res;
800 if (!dict) return (dict);
801
802 res = strcmp(dict->name, str);
803 #ifdef DEBUG
804 ASSERT(dict->type == FCODE);
805 if (debug > 2)
806 (void)printf( "flookup: `%s' and `%s' %s match\n",
807 str, dict->name, res?"don't":"do");
808 #endif
809 if (!res) return (dict);
810 if (res < 0)
811 return (flookup(dict->l, str));
812 else
813 return (flookup(dict->r, str));
814
815 }
816
817 /*
818 * Insert alias into macros.
819 */
820 int
821 aadd(dict, new)
822 struct macro *dict, *new;
823 {
824 int res = strcmp(dict->name, new->name);
825
826 #ifdef DEBUG
827 new->type = MACRO;
828 ASSERT(dict->type == MACRO);
829 #endif
830 /* Don't allow duplicate entries. */
831 if (!res) return (0);
832 if (res < 0) {
833 if (dict->l)
834 return aadd(dict->l, new);
835 else {
836 new->l = new->r = NULL;
837 dict->l = new;
838 #ifdef DEBUG
839 if (debug > 1)
840 (void)printf( "aadd: new alias `%s' to `%s'\n",
841 new->name, new->equiv);
842 #endif
843 }
844 } else {
845 if (dict->r)
846 return aadd(dict->r, new);
847 else {
848 new->l = new->r = NULL;
849 dict->r = new;
850 #ifdef DEBUG
851 if (debug > 1)
852 (void)printf( "aadd: new alias `%s' to `%s'\n",
853 new->name, new->equiv);
854 #endif
855 }
856 }
857 return (1);
858 }
859
860 /*
861 * Look for a macro in the aliases.
862 */
863 struct macro *
864 alookup(dict, str)
865 struct macro *dict;
866 char *str;
867 {
868 int res;
869 if (!dict) return (dict);
870
871 #ifdef DEBUG
872 ASSERT(dict->type == MACRO);
873 #endif
874 res = strcmp(dict->name, str);
875 if (!res) return (dict);
876 if (res < 0)
877 return (alookup(dict->l, str));
878 else
879 return (alookup(dict->r, str));
880
881 }
882
883 /*
884 * Bootstrap the dictionary and then install
885 * all the standard FCodes.
886 */
887 void
888 initdic()
889 {
890 struct fcode *code = fcodes;
891 struct macro *alias = macros;
892
893 ASSERT(dictionary == NULL);
894 code->l = code->r = NULL;
895 dictionary = code;
896 #ifdef DEBUG
897 code->type = FCODE;
898 #endif
899
900 while ((++code)->name) {
901 if(!fadd(dictionary, code)) {
902 printf("init: duplicate dictionary entry %s\n",
903 code->name);
904 abort();
905 }
906 }
907
908 ASSERT(aliases == NULL);
909 aliases = alias;
910 alias->l = alias->r = NULL;
911 #ifdef DEBUG
912 alias->type = MACRO;
913 #endif
914 while ((++alias)->name) {
915 if(!aadd(aliases, alias)) {
916 printf("init: duplicate macro entry %s\n",
917 alias->name);
918 abort();
919 }
920 }
921
922 }
923
924 int
925 apply_macros(input, str)
926 YY_BUFFER_STATE input;
927 char *str;
928 {
929 struct macro *xform = alookup(aliases, str);
930
931 if (xform) {
932 YY_BUFFER_STATE newbuf;
933
934 newbuf = yy_scan_string(xform->equiv);
935 yy_switch_to_buffer(newbuf);
936 tokenize(newbuf);
937 yy_switch_to_buffer(input);
938 yy_delete_buffer(newbuf);
939 }
940 return (xform != NULL);
941 }
942
943 void
944 usage(me)
945 char *me;
946 {
947 (void)fprintf(stderr, "%s: [-o <outfile>] <infile>\n", me);
948 exit(1);
949 }
950
951 int
952 main(argc, argv)
953 int argc;
954 char *argv[];
955 {
956 int bflag, ch;
957 FILE *inf;
958 struct fcode_header *fheader;
959 YY_BUFFER_STATE inbuf;
960 char *hdrtype = "version1";
961 int i;
962
963 outf = 1; /* stdout */
964 myname = argv[0];
965
966 bflag = 0;
967 while ((ch = getopt(argc, argv, "d:o:")) != -1)
968 switch(ch) {
969 case 'd':
970 debug = atol(optarg);
971 break;
972 case 'o':
973 outfile = optarg;
974 break;
975 case '?':
976 default:
977 warnx("Illegal argument: %c\n", ch);
978 usage(myname);
979 }
980 argc -= optind;
981 argv += optind;
982
983 if (argc != 1)
984 usage(myname);
985
986 infile = argv[0];
987
988 /*
989 * Initialization stuff.
990 */
991 initdic();
992 outbufsiz = BUFCLICK;
993 outbuf = malloc(outbufsiz);
994 fheader = (struct fcode_header *)outbuf;
995 outpos = 0;
996 emit(hdrtype);
997 outpos = sizeof(*fheader);
998
999 /*
1000 * Do it.
1001 */
1002 if ((inf = fopen(infile, "r")) == NULL)
1003 (void)err(1, "can not open %s for reading", infile);
1004
1005 inbuf = yy_create_buffer( inf, YY_BUF_SIZE );
1006 yy_switch_to_buffer(inbuf);
1007 tokenize(inbuf);
1008 yy_delete_buffer(inbuf);
1009 fclose(inf);
1010 emit("end0");
1011
1012 /* Now calculate length and checksum and stick them in the header */
1013 fheader->format = 0x08;
1014 fheader->length = htonl(outpos);
1015 fheader->checksum = 0;
1016 for (i = sizeof(*fheader); i<outpos; i++)
1017 fheader->checksum += outbuf[i];
1018 fheader->checksum = htons(fheader->checksum);
1019
1020 if ((outf = open(outfile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == NULL)
1021 err(1, "can out open %s for writing", outfile);
1022
1023 if (write(outf, outbuf, outpos) != outpos) {
1024 close(outf);
1025 unlink(outfile);
1026 err(1, "write error");
1027 }
1028 close(outf);
1029 return (0);
1030 };
1031
1032 /*
1033 * Tokenize one file. This is a separate function so it can
1034 * be called recursively to parse mutiple levels of include files.
1035 */
1036
1037 void
1038 tokenize(input)
1039 YY_BUFFER_STATE input;
1040 {
1041 FILE *inf;
1042 YY_BUFFER_STATE inbuf;
1043 TOKEN *token;
1044 char *last_token = "";
1045 struct fcode *fcode;
1046 int pos, off;
1047
1048 while ((token = yylex()) != NULL) {
1049 switch (token->type) {
1050 case TOK_NUMBER:
1051 STATE(token->text, "TOK_NUMBER");
1052 {
1053 char *end;
1054 Cell value;
1055
1056 if (tokenizer) {
1057 push(strtol(token->text, &end, 16));
1058 break;
1059 }
1060 value = strtol(token->text, &end, base);
1061 if (*end != 0)
1062 token_err(yylineno, infile, yytext,
1063 "illegal number conversion");
1064
1065 /*
1066 * If this is a 64-bit value we need to store two literals
1067 * and issue a `lxjoin' to combine them. But that's a future
1068 * project.
1069 */
1070 emit("b(lit)");
1071 spit(value>>24);
1072 spit((value>>16)&0x0ff);
1073 spit((value>>8)&0x0ff);
1074 spit(value&0x0ff);
1075 }
1076 break;
1077 case TOK_C_LIT:
1078 STATE(token->text, "TOK_C_LIT");
1079 emit("b(lit)");
1080 spit(0);
1081 spit(0);
1082 spit(0);
1083 spit(token->text[1]);
1084 break;
1085 case TOK_STRING_LIT:
1086 STATE(token->text, "TOK_STRING_LIT:");
1087 {
1088 int len;
1089 char *p = token->text;
1090
1091 ++p; /* Skip the quote */
1092 len = strlen(++p); /* Skip the 1st space */
1093
1094 #define ERR_TOOLONG \
1095 token_err(yylineno, infile, yytext, "string length %d too long", len)
1096
1097 if (len > 255)
1098 ERR_TOOLONG;
1099
1100 if (p[len-1] == ')' ||
1101 p[len-1] == '"') {
1102 p[len-1] = 0;
1103 }
1104 emit("b(\")");
1105 sspit(p);
1106 }
1107 break;
1108 case TOK_PSTRING:
1109 STATE(token->text, "TOK_PSTRING:");
1110 {
1111 int len;
1112 char *p = token->text;
1113
1114 if (*p++ == '.') p++; /* Skip over delimiter */
1115 p++; /* Skip over space/tab */
1116
1117 len = strlen(p);
1118 if (len > 255)
1119 ERR_TOOLONG;
1120
1121 if (p[len-1] == ')' ||
1122 p[len-1] == '"') {
1123 p[len-1] = 0;
1124 }
1125 emit("b(\")");
1126 sspit(p);
1127 emit("type");
1128 }
1129 break;
1130 case TOK_TOKENIZE:
1131 STATE(token->text, "TOK_TOKENIZE");
1132 /* The next pass should tokenize the FCODE number */
1133 emit("b(')");
1134 break;
1135 case TOK_COMMENT:
1136 STATE(token->text, "TOK_COMMENT:");
1137 while (((token = yylex()) != NULL) && token->type != TOK_ENDCOMMENT)
1138 ;
1139 break;
1140 case TOK_ENDCOMMENT:
1141 STATE(token->text, "TOK_ENDCOMMENT");
1142 token_err(yylineno, infile, NULL,
1143 "ENDCOMMENT encountered outside comment");
1144 break;
1145 case TOK_COLON:
1146 STATE(token->text, "TOK_COLON:");
1147
1148 token = yylex();
1149 if (token == NULL)
1150 token_err(yylineno, infile, yytext,
1151 "EOF in colon definition");
1152
1153 /* Add new code to dictionary */
1154 fcode = malloc(sizeof(*fcode));
1155 fcode->num = nextfcode++;
1156 fcode->name = strdup(token->text);
1157 if (!fadd(dictionary, fcode))
1158 token_err(yylineno, infile, NULL,
1159 "Duplicate definition: `%s'\n", fcode->name);
1160 #ifdef DEBUG
1161 if (debug)
1162 (void)printf("Adding %s to dictionary\n", token->text);
1163 #endif
1164 if (state == 0)
1165 emit("new-token");
1166 else {
1167 if (state == TOK_EXTERNAL)
1168 emit("external-token");
1169 else
1170 /* Here we have a choice of new-token or named-token */
1171 emit("named-token");
1172 sspit(token->text);
1173 }
1174 spit(fcode->num);
1175 emit("b(:)");
1176 last_token = fcode->name;
1177 defining = 1;
1178 break;
1179 case TOK_SEMICOLON:
1180 STATE(token->text, "TOK_SEMICOLON:");
1181 emit("b(;)");
1182 defining = 0;
1183 if (depth()) {
1184 token_err(yylineno, infile, NULL,
1185 "Warning: stack depth %d at end of %s\n",
1186 depth(), last_token);
1187 }
1188 last_token = "";
1189 break;
1190
1191 /* These are special */
1192 case TOK_AGAIN:
1193 STATE(token->text, "TOK_AGAIN");
1194 emit("bbranch");
1195 pos = pop();
1196 pos -= outpos;
1197 if (offsetsize == 16) {
1198 spit((pos>>8)&0xff);
1199 }
1200 spit(pos&0xff);
1201 break;
1202 case TOK_ALIAS:
1203 STATE(token->text, "TOK_ALIAS");
1204 {
1205 struct macro *alias;
1206
1207 token = yylex();
1208 if (token == NULL) {
1209 (void)printf( "EOF in alias definition\n");
1210 return;
1211 }
1212 if (token->type != TOK_OTHER) {
1213 (void)printf( "ENDCOMMENT aliasing weird token type %d\n",
1214 token->type);
1215 }
1216 alias = malloc(sizeof(*alias));
1217 alias->name = strdup(token->text);
1218 token = yylex();
1219 if (token == NULL) {
1220 (void)printf( "EOF in alias definition\n");
1221 return;
1222 }
1223 alias->equiv = strdup(token->text);
1224 if (!aadd(aliases, alias)) {
1225 (void)printf( "ERROR: Duplicate alias %s\n",
1226 alias->name);
1227 exit(1);
1228 }
1229 }
1230 break;
1231 case TOK_GETTOKEN:
1232 STATE(token->text, "TOK_GETTOKEN");
1233 /* This is caused by ['] */
1234 emit("b(')");
1235 token = yylex();
1236 if (token == NULL) {
1237 (void)printf( "EOF in [']\n");
1238 return;
1239 }
1240 if ((fcode = flookup(dictionary, token->text)) == NULL) {
1241 (void)printf( "[']: %s not found\n", token->text);
1242 exit(1);
1243 }
1244 spit(fcode->num);
1245 break;
1246 case TOK_ASCII:
1247 STATE(token->text, "TOK_ASCII");
1248 token = yylex();
1249 if (token == NULL) {
1250 (void)printf( "EOF after \"ascii\"\n");
1251 exit(1);
1252 }
1253 emit("b(lit)");
1254 spit(0);
1255 spit(0);
1256 spit(0);
1257 spit(token->text[0]);
1258 break;
1259 case TOK_BEGIN:
1260 STATE(token->text, "TOK_BEGIN");
1261 emit("b(<mark)");
1262 push(outpos);
1263 break;
1264 case TOK_BUFFER:
1265 STATE(token->text, "TOK_BUFFER");
1266
1267 token = yylex();
1268 if (token == NULL) {
1269 (void)printf( "EOF in colon definition\n");
1270 return;
1271 }
1272
1273 /* Add new code to dictionary */
1274 fcode = malloc(sizeof(*fcode));
1275 fcode->num = nextfcode++;
1276 fcode->name = strdup(token->text);
1277 fadd(dictionary, fcode);
1278
1279 if (state == 0)
1280 emit("new-token");
1281 else {
1282 if (state == TOK_EXTERNAL)
1283 emit("external-token");
1284 else
1285 /* Here we have a choice of new-token or named-token */
1286 emit("named-token");
1287 sspit(token->text);
1288 }
1289 spit(fcode->num);
1290 emit("b(buffer:)");
1291 break;
1292 case TOK_CASE:
1293 STATE(token->text, "TOK_CASE");
1294 emit("b(case)");
1295 push(0);
1296 break;
1297 case TOK_CONSTANT:
1298 STATE(token->text, "TOK_CONSTANT");
1299
1300 token = yylex();
1301 if (token == NULL) {
1302 (void)printf( "EOF in constant definition\n");
1303 return;
1304 }
1305
1306 /* Add new code to dictionary */
1307 fcode = malloc(sizeof(*fcode));
1308 fcode->num = nextfcode++;
1309 fcode->name = strdup(token->text);
1310 fadd(dictionary, fcode);
1311
1312 if (state == 0)
1313 emit("new-token");
1314 else {
1315 if (state == TOK_EXTERNAL)
1316 emit("external-token");
1317 else
1318 /* Here we have a choice of new-token or named-token */
1319 emit("named-token");
1320 sspit(token->text);
1321 }
1322 spit(fcode->num);
1323 emit("b(constant)");
1324 break;
1325 case TOK_CONTROL:
1326 STATE(token->text, "TOK_CONTROL");
1327 token = yylex();
1328 if (token == NULL) {
1329 (void)printf( "EOF after \"ascii\"\n");
1330 exit(1);
1331 }
1332 emit("b(lit)");
1333 spit(0);
1334 spit(0);
1335 spit(0);
1336 spit(token->text[0]&0x1f);
1337 break;
1338 case TOK_CREATE:
1339 STATE(token->text, "TOK_CREATE");
1340 /* Don't know what this does or if it's right */
1341 token = yylex();
1342 if (token == NULL) {
1343 (void)printf( "EOF in create definition\n");
1344 return;
1345 }
1346
1347 /* Add new code to dictionary */
1348 fcode = malloc(sizeof(*fcode));
1349 fcode->num = nextfcode++;
1350 fcode->name = strdup(token->text);
1351 fadd(dictionary, fcode);
1352
1353 if (state == 0)
1354 emit("new-token");
1355 else {
1356 if (state == TOK_EXTERNAL)
1357 emit("external-token");
1358 else
1359 /* Here we have a choice of new-token or named-token */
1360 emit("named-token");
1361 sspit(token->text);
1362 }
1363 spit(fcode->num);
1364 emit("b(create)");
1365 break;
1366 case TOK_DECIMAL:
1367 STATE(token->text, "TOK_DECIMAL");
1368 if (token->text[1] != '#') {
1369 if (defining) {
1370 spit(10);
1371 emit("base");
1372 emit("!");
1373 } else
1374 base = TOK_DECIMAL;
1375 } else {
1376 char *end;
1377 Cell value;
1378
1379 token = yylex();
1380 if (token == NULL) {
1381 (void)printf( "EOF after d#\n");
1382 return;
1383 }
1384 if (token->type == TOK_OTHER) {
1385 if (strcmp("-1", token->text) == 0) {
1386 emit(token->text);
1387 break;
1388 }
1389 }
1390 value = strtol(token->text, &end, 10);
1391 if (*end != 0)
1392 token_err(yylineno, infile, NULL,
1393 "Illegal number conversion: %s", token->text);
1394
1395 /*
1396 * If this is a 64-bit value we need to store two literals
1397 * and issue a `lxjoin' to combine them. But that's a future
1398 * project.
1399 */
1400 emit("b(lit)");
1401 spit(value>>24);
1402 spit((value>>16)&0x0ff);
1403 spit((value>>8)&0x0ff);
1404 spit(value&0x0ff);
1405 }
1406 break;
1407 case TOK_DEFER:
1408 STATE(token->text, "TOK_DEFER");
1409 /* Don't know what this does or if it's right */
1410 token = yylex();
1411 if (token == NULL) {
1412 (void)printf( "EOF in colon definition\n");
1413 return;
1414 }
1415
1416 /* Add new code to dictionary */
1417 fcode = malloc(sizeof(*fcode));
1418 fcode->num = nextfcode++;
1419 fcode->name = strdup(token->text);
1420 fadd(dictionary, fcode);
1421
1422 if (state == 0)
1423 emit("new-token");
1424 else {
1425 if (state == TOK_EXTERNAL)
1426 emit("external-token");
1427 else
1428 /* Here we have a choice of new-token or named-token */
1429 emit("named-token");
1430 sspit(token->text);
1431 }
1432 spit(fcode->num);
1433 emit("b(defer)");
1434 break;
1435 case TOK_DO:
1436 STATE(token->text, "TOK_DO");
1437 /*
1438 * From the 1275 spec. B is branch location, T is branch target.
1439 *
1440 * b(do) offset1 ... b(loop) offset2 ...
1441 * b(do) offset1 ... b(+loop) offset2 ...
1442 * b(?do) offset1 ... b(loop) offset2 ...
1443 * b(?do) offset1 ... b(+loop) offset2 ...
1444 * ^ ^
1445 * B1 ^ ^ T1
1446 * T2 B2
1447 *
1448 * How we do this is we generate the b(do) or b(?do), spit out a
1449 * zero offset while remembering b1 and t2. Then we call tokenize()
1450 * to generate the body. When tokenize() finds a b(loop) or b(+loop),
1451 * it generates the FCode and returns, with outpos at b2. We then
1452 * calculate the offsets, put them in the right slots and finishup.
1453 */
1454
1455 if (token->text[0] == '?')
1456 emit("b(?do)");
1457 else
1458 emit("b(do)");
1459 push(outpos);
1460 if (offsetsize == 16) {
1461 spit(0);
1462 }
1463 spit(0); /* Place holder for later */
1464 push(outpos);
1465 break;
1466 case TOK_ELSE:
1467 STATE(token->text, "TOK_ELSE");
1468 /* Get where we need to patch */
1469 off = pop();
1470 emit("bbranch");
1471 /* Save where we are now. */
1472 push(outpos);
1473 if (offsetsize == 16) {
1474 spit(0); /* Place holder for later */
1475 }
1476 spit(0); /* Place holder for later */
1477 emit("b(>resolve)");
1478 /* Rewind and patch the if branch */
1479 pos = outpos;
1480 outpos = off;
1481 off = pos - off;
1482 if (offsetsize == 16) {
1483 spit(0); /* Place holder for later */
1484 }
1485 spit(0); /* Place holder for later */
1486 /* revert to the end */
1487 outpos = pos;
1488 break;
1489 case TOK_ENDCASE:
1490 STATE(token->text, "TOK_ENDCASE:");
1491 pos = outpos; /* Remember where we need to branch to */
1492
1493 /* Thread our way backwards and install proper offsets */
1494 off = pop();
1495 while (off) {
1496 int tmp;
1497
1498 /* Move to this offset */
1499 outpos = off;
1500 /* Load next offset to process */
1501 tmp = outbuf[outpos];
1502
1503 /* process this offset */
1504 off = pos - outpos;
1505 if (offsetsize == 16) {
1506 spit((off>>8)&0xff);
1507 }
1508 spit(off&0xff);
1509 off = tmp;
1510 }
1511 outpos = pos;
1512 emit("b(endcase)");
1513 break;
1514 case TOK_ENDOF:
1515 STATE(token->text, "TOK_ENDOF");
1516 off = pop();
1517 emit("b(endof)");
1518 /*
1519 * Save back pointer in the offset field so we can traverse
1520 * the linked list and patch it in the endcase.
1521 */
1522 pos = pop(); /* get position of prev link. */
1523 push(outpos); /* save position of this link. */
1524 spit(pos); /* save potision of prev link. */
1525 if (offsetsize == 16) {
1526 spit(0);
1527 }
1528 pos = outpos;
1529 /* Now point the offset from b(of) here. */
1530 outpos = off;
1531 off = outpos - off;
1532 if (offsetsize == 16) {
1533 spit((off>>8)&0xff);
1534 }
1535 spit(off&0xff);
1536 /* Restore position */
1537 outpos = pos;
1538 break;
1539 case TOK_EXTERNAL:
1540 STATE(token->text, "TOK_EXTERNAL");
1541 state = TOK_EXTERNAL;
1542 break;
1543 case TOK_FIELD:
1544 STATE(token->text, "TOK_FIELD");
1545
1546 token = yylex();
1547 if (token == NULL) {
1548 (void)printf( "EOF in field definition\n");
1549 return;
1550 }
1551
1552 /* Add new code to dictionary */
1553 fcode = malloc(sizeof(*fcode));
1554 fcode->num = nextfcode++;
1555 fcode->name = strdup(token->text);
1556 fadd(dictionary, fcode);
1557
1558 if (state == 0)
1559 emit("new-token");
1560 else {
1561 if (state == TOK_EXTERNAL)
1562 emit("external-token");
1563 else
1564 /* Here we have a choice of new-token or named-token */
1565 emit("named-token");
1566 sspit(token->text);
1567 }
1568 spit(fcode->num);
1569 emit("b(field)");
1570 break;
1571
1572 case TOK_HEX:
1573 STATE(token->text, "TOK_HEX");
1574 if (token->text[1] != '#') {
1575 if (defining) {
1576 spit(16);
1577 emit("base");
1578 emit("!");
1579 } else
1580 base = TOK_HEX;
1581 } else {
1582 char *end;
1583 Cell value;
1584
1585 token = yylex();
1586 if (token == NULL) {
1587 (void)printf( "EOF after h#\n");
1588 return;
1589 }
1590 value = strtol(token->text, &end, 16);
1591 if (*end != 0) {
1592 (void)printf("Illegal number conversion:%s:%d: %s\n",
1593 infile, yylineno, yytext);
1594 exit(1);
1595 }
1596 /*
1597 * If this is a 64-bit value we need to store two literals
1598 * and issue a `lxjoin' to combine them. But that's a future
1599 * project.
1600 */
1601 emit("b(lit)");
1602 spit(value>>24);
1603 spit((value>>16)&0x0ff);
1604 spit((value>>8)&0x0ff);
1605 spit(value&0x0ff);
1606 }
1607 break;
1608 case TOK_HEADERLESS:
1609 STATE(token->text, "TOK_HEADERLESS");
1610 state = 0;
1611 break;
1612 case TOK_HEADERS:
1613 STATE(token->text, "TOK_HEADERS");
1614 state = TOK_HEADERS;
1615 break;
1616 case TOK_OFFSET16:
1617 STATE(token->text, "TOK_OFFSET16");
1618 offsetsize = 16;
1619 emit("offset16");
1620 break;
1621 case TOK_IF:
1622 STATE(token->text, "TOK_IF");
1623 /*
1624 * Similar to do but simpler since we only deal w/one branch.
1625 */
1626 emit("b?branch");
1627 push(outpos);
1628 if (offsetsize == 16) {
1629 spit(0); /* Place holder for later */
1630 }
1631 spit(0); /* Place holder for later */
1632 break;
1633 case TOK_LEAVE:
1634 STATE(token->text, "TOK_LEAVE");
1635 emit("b(leave)");
1636 break;
1637 case TOK_LOOP:
1638 STATE(token->text, "TOK_LOOP");
1639
1640 if (token->text[0] == '+')
1641 emit("b(+loop)");
1642 else
1643 emit("b(loop)");
1644 /* First do backwards branch of loop */
1645 pos = pop();
1646 off = pos - outpos;
1647 if (offsetsize == 16) {
1648 spit((off>>8)&0xff);
1649 }
1650 spit(off&0xff);
1651 /* Now do forward branch of do */
1652 pos = outpos;
1653 outpos = pop();
1654 off = pos - outpos;
1655 if (offsetsize == 16) {
1656 spit((off>>8)&0xff);
1657 }
1658 spit(off&0xff);
1659 /* Restore output position */
1660 outpos = pos;
1661 break;
1662 case TOK_OCTAL:
1663 STATE(token->text, "TOK_OCTAL");
1664 if (token->text[1] != '#') {
1665 if (defining) {
1666 spit(16);
1667 emit("base");
1668 emit("!");
1669 } else
1670 base = TOK_OCTAL;
1671 } else {
1672 char *end;
1673 Cell value;
1674
1675 token = yylex();
1676 if (token == NULL) {
1677 (void)printf( "EOF after o#\n");
1678 return;
1679 }
1680 value = strtol(token->text, &end, 8);
1681 if (*end != 0) {
1682 (void)printf("Illegal number conversion:%s:%d: %s\n",
1683 infile, yylineno, yytext);
1684 exit(1);
1685 }
1686 /*
1687 * If this is a 64-bit value we need to store two literals
1688 * and issue a `lxjoin' to combine them. But that's a future
1689 * project.
1690 */
1691 emit("b(lit)");
1692 spit(value>>24);
1693 spit((value>>16)&0x0ff);
1694 spit((value>>8)&0x0ff);
1695 spit(value&0x0ff);
1696 }
1697 break;
1698 case TOK_OF:
1699 STATE(token->text, "TOK_OF");
1700 /*
1701 * Let's hope I get the semantics right.
1702 *
1703 * The `of' behaves almost the same as an
1704 * `if'. The difference is that `endof'
1705 * takes a branch offset to the associated
1706 * `endcase'. Here we will generate a temporary
1707 * offset of the `of' associated with the `endof'.
1708 * Then in `endcase' we should be pointing just
1709 * after the offset of the last `endof' so we
1710 * calculate the offset and thread our way backwards
1711 * searching for the previous `b(case)' or `b(endof)'.
1712 */
1713 emit("b(of)");
1714 push(outpos);
1715 if (offsetsize == 16) {
1716 spit(0);
1717 }
1718 spit(0); /* Place holder for later */
1719 break;
1720 case TOK_REPEAT:
1721 STATE(token->text, "TOK_REPEAT");
1722 emit("bbranch");
1723 pos = pop();
1724 off = pop();
1725 /* First the offset for the branch back to the begin */
1726 off -= outpos;
1727 if (offsetsize == 16) {
1728 spit((off>>8)&0xff);
1729 }
1730 spit(off&0xff);
1731 emit("b(>resolve)");
1732 /* Now point the offset of the while here. */
1733 off = outpos;
1734 outpos = pos;
1735 pos = off - pos;
1736 if (offsetsize == 16) {
1737 spit((pos>>8)&0xff);
1738 }
1739 spit(pos&0xff);
1740 /* Return to the end of the output */
1741 outpos = off;
1742 break;
1743 case TOK_THEN:
1744 STATE(token->text, "TOK_THEN");
1745 emit("b(>resolve)");
1746 pos = outpos;
1747 outpos = pop();
1748 off = pos - outpos;
1749 if (offsetsize == 16) {
1750 spit((off>>8)&0xff);
1751 }
1752 spit(off&0xff);
1753 outpos = pos;
1754 break;
1755 case TOK_TO:
1756 STATE(token->text, "TOK_TO");
1757 /* The next pass should tokenize the FCODE number */
1758 emit("b(to)");
1759 break;
1760 case TOK_UNTIL:
1761 STATE(token->text, "TOK_UNTIL");
1762 {
1763 int pos;
1764
1765 emit("b?branch");
1766 pos = pop();
1767 pos -= outpos;
1768 if (offsetsize == 16) {
1769 spit((pos>>8)&0xff);
1770 }
1771 spit(pos&0xff);
1772 }
1773 break;
1774 case TOK_VALUE:
1775 STATE(token->text, "TOK_VALUE");
1776
1777 token = yylex();
1778 if (token == NULL) {
1779 (void)printf( "EOF in value definition\n");
1780 return;
1781 }
1782
1783 /* Add new code to dictionary */
1784 fcode = malloc(sizeof(*fcode));
1785 fcode->num = nextfcode++;
1786 fcode->name = strdup(token->text);
1787 fadd(dictionary, fcode);
1788
1789 if (state == 0)
1790 emit("new-token");
1791 else {
1792 if (state == TOK_EXTERNAL)
1793 emit("external-token");
1794 else
1795 /* Here we have a choice of new-token or named-token */
1796 emit("named-token");
1797 sspit(token->text);
1798 }
1799 spit(fcode->num);
1800 emit("b(value)");
1801 break;
1802 case TOK_VARIABLE:
1803 STATE(token->text, "TOK_VARIABLE");
1804
1805 token = yylex();
1806 if (token == NULL) {
1807 (void)printf( "EOF in variable definition\n");
1808 return;
1809 }
1810
1811 /* Add new code to dictionary */
1812 fcode = malloc(sizeof(*fcode));
1813 fcode->num = nextfcode++;
1814 fcode->name = strdup(token->text);
1815 fadd(dictionary, fcode);
1816
1817 if (state == 0)
1818 emit("new-token");
1819 else {
1820 if (state == TOK_EXTERNAL)
1821 emit("external-token");
1822 else
1823 /* Here we have a choice of new-token or named-token */
1824 emit("named-token");
1825 sspit(token->text);
1826 }
1827 spit(fcode->num);
1828 emit("b(variable)");
1829 break;
1830 case TOK_WHILE:
1831 STATE(token->text, "TOK_WHILE");
1832 emit("b?branch");
1833 push(outpos);
1834 if (offsetsize == 16) {
1835 spit(0);
1836 }
1837 spit(0);
1838 break;
1839
1840 /* Tokenizer directives */
1841 case TOK_BEGTOK:
1842 STATE(token->text, "TOK_BEGTOK");
1843 tokenizer = 1;
1844 break;
1845 case TOK_EMIT_BYTE:
1846 STATE(token->text, "TOK_EMIT_BYTE");
1847 spit(pop());
1848 break;
1849 case TOK_ENDTOK:
1850 STATE(token->text, "TOK_ENDTOK");
1851 tokenizer = 0;
1852 break;
1853 case TOK_FLOAD:
1854 STATE(token->text, "TOK_FLOAD");
1855 /* Parse a different file for a while */
1856 token = yylex();
1857 if ((inf = fopen(token->text, "r")) == NULL) {
1858 (void)printf("%s: Could not open %s: %s\n",
1859 myname, token->text, strerror(errno));
1860 break;
1861 }
1862 inbuf = yy_create_buffer(inf, YY_BUF_SIZE);
1863 yy_switch_to_buffer(inbuf);
1864 {
1865 char *oldinfile = infile;
1866
1867 infile = token->text;
1868 tokenize(inbuf);
1869 infile = oldinfile;
1870 }
1871 yy_switch_to_buffer(input);
1872 yy_delete_buffer(inbuf);
1873 fclose(inf);
1874 break;
1875 case TOK_OTHER:
1876 STATE(token->text, "TOK_OTHER");
1877 if (apply_macros(input, token->text))
1878 break;
1879 if (emit(token->text)) {
1880 #if 0
1881 /*
1882 * Call an external command
1883 *
1884 * XXXXX assumes it will always find the command
1885 */
1886 sspit(token->text);
1887 emit("$find");
1888 emit("drop");
1889 emit("execute");
1890 #else
1891 (void)printf( "%s: undefined token `%s'\n",
1892 myname, token->text);
1893 fflush(stderr);
1894 exit(1);
1895 #endif
1896 }
1897 break;
1898 default:
1899 }
1900 }
1901 return;
1902 }
1903
1904 /*
1905 * print a tokenizer error message
1906 */
1907 void
1908 token_err(int lineno, char *infile, char *text, char *fmt, ...)
1909 {
1910 va_list ap;
1911
1912 va_start(ap, fmt);
1913 if (infile)
1914 (void)fprintf(stderr, "%s:%d: ", infile, lineno);
1915 if (fmt)
1916 (void)vfprintf(stderr, fmt, ap);
1917 fputc('\n', stderr);
1918 if (text)
1919 fprintf(stderr, "\t%s", text);
1920 va_end(ap);
1921 exit(1);
1922 }
1923
1924 /*
1925 * Lookup fcode string in dictionary and spit it out.
1926 *
1927 * Fcode must be in dictionary. No alias conversion done.
1928 */
1929 int
1930 emit(str)
1931 char *str;
1932 {
1933 struct fcode *code;
1934 if ((code = flookup( dictionary, str)))
1935 spit(code->num);
1936 #ifdef DEBUG
1937 if (debug > 1) {
1938 if (code)
1939 (void)printf( "emitting `%s'\n", code->name);
1940 else
1941 (void)printf( "emit: not found `%s'\n", str);
1942 }
1943 #endif
1944 return (code == NULL);
1945 }
1946
1947 /*
1948 * Spit out an integral value as a series of FCodes.
1949 *
1950 * It will spit out one zero byte or as many bytes as are
1951 * non-zero.
1952 */
1953 int
1954 spit(n)
1955 long n;
1956 {
1957 int count = 1;
1958
1959 if (n >> 8)
1960 count += spit(n >> 8);
1961 if (outpos >= outbufsiz) {
1962 while (outpos >= outbufsiz) outbufsiz += BUFCLICK;
1963 if (!(outbuf = realloc(outbuf, outbufsiz))) {
1964 (void)printf( "realloc of %ld bytes failed -- out of memory\n",
1965 (long)outbufsiz);
1966 exit(1);
1967 }
1968 }
1969 outbuf[outpos++] = n;
1970 return (count);
1971 }
1972
1973 /*
1974 * Spit out an FCode string.
1975 */
1976 void
1977 sspit(s)
1978 char *s;
1979 {
1980 int len = strlen(s);
1981
1982 if (len > 255) {
1983 (void)printf( "string length %d too long\n", len);
1984 return;
1985 }
1986 #ifdef DEBUG
1987 if (debug > 1)
1988 (void)printf( "sspit: len %d str `%s'\n", len, s);
1989 #endif
1990 spit(len);
1991 while (*s)
1992 spit(*s++);
1993 }
1994
1995 int
1996 yywrap()
1997 {
1998 /* Always generate EOF */
1999 return (1);
2000 }
2001