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