fgen.l revision 1.27 1 %{
2 /* $NetBSD: fgen.l,v 1.27 2006/04/22 17:51:09 christos 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.27 2006/04/22 17:51:09 christos 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: [-d level] [-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 free(alias->name);
1277 free(alias);
1278 (void)printf( "EOF in alias definition\n");
1279 return;
1280 }
1281 alias->equiv = strdup(token->text);
1282 if (!aadd(aliases, alias)) {
1283 (void)printf( "ERROR: Duplicate alias %s\n",
1284 alias->name);
1285 exit(1);
1286 }
1287 }
1288 break;
1289 case TOK_GETTOKEN:
1290 STATE(token->text, "TOK_GETTOKEN");
1291 /* This is caused by ['] */
1292 emit("b(')");
1293 token = yylex();
1294 if (token == NULL) {
1295 (void)printf( "EOF in [']\n");
1296 return;
1297 }
1298 if ((fcode = flookup(dictionary, token->text)) == NULL) {
1299 (void)printf( "[']: %s not found\n", token->text);
1300 exit(1);
1301 }
1302 spit(fcode->num);
1303 break;
1304 case TOK_ASCII:
1305 STATE(token->text, "TOK_ASCII");
1306 token = yylex();
1307 if (token == NULL) {
1308 (void)printf( "EOF after \"ascii\"\n");
1309 exit(1);
1310 }
1311 emit("b(lit)");
1312 spit(0);
1313 spit(0);
1314 spit(0);
1315 spit(token->text[0]);
1316 break;
1317 case TOK_BEGIN:
1318 STATE(token->text, "TOK_BEGIN");
1319 emit("b(<mark)");
1320 push(outpos);
1321 break;
1322 case TOK_BUFFER:
1323 STATE(token->text, "TOK_BUFFER");
1324
1325 token = yylex();
1326 if (token == NULL) {
1327 (void)printf( "EOF in colon definition\n");
1328 return;
1329 }
1330
1331 /* Add new code to dictionary */
1332 fcode = malloc(sizeof(*fcode));
1333 fcode->num = nextfcode++;
1334 fcode->name = strdup(token->text);
1335 fadd(dictionary, fcode);
1336
1337 if (state == 0)
1338 emit("new-token");
1339 else {
1340 if (state == TOK_EXTERNAL)
1341 emit("external-token");
1342 else
1343 /* Here we have a choice of new-token or named-token */
1344 emit("named-token");
1345 sspit(token->text);
1346 }
1347 spit(fcode->num);
1348 emit("b(buffer:)");
1349 break;
1350 case TOK_CASE:
1351 STATE(token->text, "TOK_CASE");
1352 emit("b(case)");
1353 push(0);
1354 break;
1355 case TOK_CONSTANT:
1356 STATE(token->text, "TOK_CONSTANT");
1357
1358 token = yylex();
1359 if (token == NULL) {
1360 (void)printf( "EOF in constant definition\n");
1361 return;
1362 }
1363
1364 /* Add new code to dictionary */
1365 fcode = malloc(sizeof(*fcode));
1366 fcode->num = nextfcode++;
1367 fcode->name = strdup(token->text);
1368 fadd(dictionary, fcode);
1369
1370 if (state == 0)
1371 emit("new-token");
1372 else {
1373 if (state == TOK_EXTERNAL)
1374 emit("external-token");
1375 else
1376 /* Here we have a choice of new-token or named-token */
1377 emit("named-token");
1378 sspit(token->text);
1379 }
1380 spit(fcode->num);
1381 emit("b(constant)");
1382 break;
1383 case TOK_CONTROL:
1384 STATE(token->text, "TOK_CONTROL");
1385 token = yylex();
1386 if (token == NULL) {
1387 (void)printf( "EOF after \"ascii\"\n");
1388 exit(1);
1389 }
1390 emit("b(lit)");
1391 spit(0);
1392 spit(0);
1393 spit(0);
1394 spit(token->text[0]&0x1f);
1395 break;
1396 case TOK_CREATE:
1397 STATE(token->text, "TOK_CREATE");
1398 /* Don't know what this does or if it's right */
1399 token = yylex();
1400 if (token == NULL) {
1401 (void)printf( "EOF in create definition\n");
1402 return;
1403 }
1404
1405 /* Add new code to dictionary */
1406 fcode = malloc(sizeof(*fcode));
1407 fcode->num = nextfcode++;
1408 fcode->name = strdup(token->text);
1409 fadd(dictionary, fcode);
1410
1411 if (state == 0)
1412 emit("new-token");
1413 else {
1414 if (state == TOK_EXTERNAL)
1415 emit("external-token");
1416 else
1417 /* Here we have a choice of new-token or named-token */
1418 emit("named-token");
1419 sspit(token->text);
1420 }
1421 spit(fcode->num);
1422 emit("b(create)");
1423 break;
1424 case TOK_DECIMAL:
1425 STATE(token->text, "TOK_DECIMAL");
1426 if (token->text[1] != '#') {
1427 if (defining) {
1428 spit(10);
1429 emit("base");
1430 emit("!");
1431 } else
1432 base = TOK_DECIMAL;
1433 } else {
1434 char *end;
1435 Cell value;
1436
1437 token = yylex();
1438 if (token == NULL) {
1439 (void)printf( "EOF after d#\n");
1440 return;
1441 }
1442 if (token->type == TOK_OTHER) {
1443 if (strcmp("-1", token->text) == 0) {
1444 emit(token->text);
1445 break;
1446 }
1447 }
1448 value = strtol(token->text, &end, 10);
1449 if (*end != 0)
1450 token_err(yylineno, infile, NULL,
1451 "Illegal number conversion: %s", token->text);
1452
1453 /*
1454 * If this is a 64-bit value we need to store two literals
1455 * and issue a `lxjoin' to combine them. But that's a future
1456 * project.
1457 */
1458 emit("b(lit)");
1459 spit((value>>24)&0x0ff);
1460 spit((value>>16)&0x0ff);
1461 spit((value>>8)&0x0ff);
1462 spit(value&0x0ff);
1463 if ((value>>32) != value && (value>>32) != 0) {
1464 emit("b(lit)");
1465 spit((value>>56)&0x0ff);
1466 spit((value>>48)&0x0ff);
1467 spit((value>>40)&0x0ff);
1468 spit((value>>32)&0x0ff);
1469 emit("lxjoin");
1470 }
1471 }
1472 break;
1473 case TOK_DEFER:
1474 STATE(token->text, "TOK_DEFER");
1475 /* Don't know what this does or if it's right */
1476 token = yylex();
1477 if (token == NULL) {
1478 (void)printf( "EOF in colon definition\n");
1479 return;
1480 }
1481
1482 /* Add new code to dictionary */
1483 fcode = malloc(sizeof(*fcode));
1484 fcode->num = nextfcode++;
1485 fcode->name = strdup(token->text);
1486 fadd(dictionary, fcode);
1487
1488 if (state == 0)
1489 emit("new-token");
1490 else {
1491 if (state == TOK_EXTERNAL)
1492 emit("external-token");
1493 else
1494 /* Here we have a choice of new-token or named-token */
1495 emit("named-token");
1496 sspit(token->text);
1497 }
1498 spit(fcode->num);
1499 emit("b(defer)");
1500 break;
1501 case TOK_DO:
1502 STATE(token->text, "TOK_DO");
1503 /*
1504 * From the 1275 spec. B is branch location, T is branch target.
1505 *
1506 * b(do) offset1 ... b(loop) offset2 ...
1507 * b(do) offset1 ... b(+loop) offset2 ...
1508 * b(?do) offset1 ... b(loop) offset2 ...
1509 * b(?do) offset1 ... b(+loop) offset2 ...
1510 * ^ ^
1511 * B1 ^ ^ T1
1512 * T2 B2
1513 *
1514 * How we do this is we generate the b(do) or b(?do), spit out a
1515 * zero offset while remembering b1 and t2. Then we call tokenize()
1516 * to generate the body. When tokenize() finds a b(loop) or b(+loop),
1517 * it generates the FCode and returns, with outpos at b2. We then
1518 * calculate the offsets, put them in the right slots and finishup.
1519 */
1520
1521 if (token->text[0] == '?')
1522 emit("b(?do)");
1523 else
1524 emit("b(do)");
1525 push(outpos);
1526 if (offsetsize == 16) {
1527 spit(0);
1528 }
1529 spit(0); /* Place holder for later */
1530 push(outpos);
1531 break;
1532 case TOK_ELSE:
1533 STATE(token->text, "TOK_ELSE");
1534 /* Get where we need to patch */
1535 off = pop();
1536 emit("bbranch");
1537 /* Save where we are now. */
1538 push(outpos);
1539 if (offsetsize == 16) {
1540 spit(0); /* Place holder for later */
1541 }
1542 spit(0); /* Place holder for later */
1543 emit("b(>resolve)");
1544 /* Rewind and patch the if branch */
1545 pos = outpos;
1546 outpos = off;
1547 off = pos - off;
1548 if (offsetsize == 16) {
1549 spit(0); /* Place holder for later */
1550 }
1551 spit(0); /* Place holder for later */
1552 /* revert to the end */
1553 outpos = pos;
1554 break;
1555 case TOK_ENDCASE:
1556 STATE(token->text, "TOK_ENDCASE:");
1557 pos = outpos; /* Remember where we need to branch to */
1558
1559 /* Thread our way backwards and install proper offsets */
1560 off = pop();
1561 while (off) {
1562 int tmp;
1563
1564 /* Move to this offset */
1565 outpos = off;
1566 /* Load next offset to process */
1567 tmp = outbuf[outpos];
1568
1569 /* process this offset */
1570 off = pos - outpos;
1571 if (offsetsize == 16) {
1572 spit((off>>8)&0xff);
1573 }
1574 spit(off&0xff);
1575 off = tmp;
1576 }
1577 outpos = pos;
1578 emit("b(endcase)");
1579 break;
1580 case TOK_ENDOF:
1581 STATE(token->text, "TOK_ENDOF");
1582 off = pop();
1583 emit("b(endof)");
1584 /*
1585 * Save back pointer in the offset field so we can traverse
1586 * the linked list and patch it in the endcase.
1587 */
1588 pos = pop(); /* get position of prev link. */
1589 push(outpos); /* save position of this link. */
1590 spit(pos); /* save potision of prev link. */
1591 if (offsetsize == 16) {
1592 spit(0);
1593 }
1594 pos = outpos;
1595 /* Now point the offset from b(of) here. */
1596 outpos = off;
1597 off = outpos - off;
1598 if (offsetsize == 16) {
1599 spit((off>>8)&0xff);
1600 }
1601 spit(off&0xff);
1602 /* Restore position */
1603 outpos = pos;
1604 break;
1605 case TOK_EXTERNAL:
1606 STATE(token->text, "TOK_EXTERNAL");
1607 state = TOK_EXTERNAL;
1608 break;
1609 case TOK_FIELD:
1610 STATE(token->text, "TOK_FIELD");
1611
1612 token = yylex();
1613 if (token == NULL) {
1614 (void)printf( "EOF in field definition\n");
1615 return;
1616 }
1617
1618 /* Add new code to dictionary */
1619 fcode = malloc(sizeof(*fcode));
1620 fcode->num = nextfcode++;
1621 fcode->name = strdup(token->text);
1622 fadd(dictionary, fcode);
1623
1624 if (state == 0)
1625 emit("new-token");
1626 else {
1627 if (state == TOK_EXTERNAL)
1628 emit("external-token");
1629 else
1630 /* Here we have a choice of new-token or named-token */
1631 emit("named-token");
1632 sspit(token->text);
1633 }
1634 spit(fcode->num);
1635 emit("b(field)");
1636 break;
1637
1638 case TOK_HEX:
1639 STATE(token->text, "TOK_HEX");
1640 if (token->text[1] != '#') {
1641 if (defining) {
1642 spit(16);
1643 emit("base");
1644 emit("!");
1645 } else
1646 base = TOK_HEX;
1647 } else {
1648 char *end;
1649 Cell value;
1650
1651 token = yylex();
1652 if (token == NULL) {
1653 (void)printf( "EOF after h#\n");
1654 return;
1655 }
1656 value = strtol(token->text, &end, 16);
1657 if (*end != 0) {
1658 (void)printf("Illegal number conversion:%s:%d: %s\n",
1659 infile, yylineno, yytext);
1660 exit(1);
1661 }
1662 /*
1663 * If this is a 64-bit value we need to store two literals
1664 * and issue a `lxjoin' to combine them. But that's a future
1665 * project.
1666 */
1667 emit("b(lit)");
1668 spit((value>>24)&0x0ff);
1669 spit((value>>16)&0x0ff);
1670 spit((value>>8)&0x0ff);
1671 spit(value&0x0ff);
1672 if ((value>>32) != value && (value>>32) != 0) {
1673 emit("b(lit)");
1674 spit((value>>56)&0x0ff);
1675 spit((value>>48)&0x0ff);
1676 spit((value>>40)&0x0ff);
1677 spit((value>>32)&0x0ff);
1678 emit("lxjoin");
1679 }
1680 }
1681 break;
1682 case TOK_HEADERLESS:
1683 STATE(token->text, "TOK_HEADERLESS");
1684 state = 0;
1685 break;
1686 case TOK_HEADERS:
1687 STATE(token->text, "TOK_HEADERS");
1688 state = TOK_HEADERS;
1689 break;
1690 case TOK_OFFSET16:
1691 STATE(token->text, "TOK_OFFSET16");
1692 offsetsize = 16;
1693 emit("offset16");
1694 break;
1695 case TOK_IF:
1696 STATE(token->text, "TOK_IF");
1697 /*
1698 * Similar to do but simpler since we only deal w/one branch.
1699 */
1700 emit("b?branch");
1701 push(outpos);
1702 if (offsetsize == 16) {
1703 spit(0); /* Place holder for later */
1704 }
1705 spit(0); /* Place holder for later */
1706 break;
1707 case TOK_LEAVE:
1708 STATE(token->text, "TOK_LEAVE");
1709 emit("b(leave)");
1710 break;
1711 case TOK_LOOP:
1712 STATE(token->text, "TOK_LOOP");
1713
1714 if (token->text[0] == '+')
1715 emit("b(+loop)");
1716 else
1717 emit("b(loop)");
1718 /* First do backwards branch of loop */
1719 pos = pop();
1720 off = pos - outpos;
1721 if (offsetsize == 16) {
1722 spit((off>>8)&0xff);
1723 }
1724 spit(off&0xff);
1725 /* Now do forward branch of do */
1726 pos = outpos;
1727 outpos = pop();
1728 off = pos - outpos;
1729 if (offsetsize == 16) {
1730 spit((off>>8)&0xff);
1731 }
1732 spit(off&0xff);
1733 /* Restore output position */
1734 outpos = pos;
1735 break;
1736 case TOK_OCTAL:
1737 STATE(token->text, "TOK_OCTAL");
1738 if (token->text[1] != '#') {
1739 if (defining) {
1740 spit(16);
1741 emit("base");
1742 emit("!");
1743 } else
1744 base = TOK_OCTAL;
1745 } else {
1746 char *end;
1747 Cell value;
1748
1749 token = yylex();
1750 if (token == NULL) {
1751 (void)printf( "EOF after o#\n");
1752 return;
1753 }
1754 value = strtol(token->text, &end, 8);
1755 if (*end != 0) {
1756 (void)printf("Illegal number conversion:%s:%d: %s\n",
1757 infile, yylineno, yytext);
1758 exit(1);
1759 }
1760 /*
1761 * If this is a 64-bit value we need to store two literals
1762 * and issue a `lxjoin' to combine them. But that's a future
1763 * project.
1764 */
1765 emit("b(lit)");
1766 spit((value>>24)&0x0ff);
1767 spit((value>>16)&0x0ff);
1768 spit((value>>8)&0x0ff);
1769 spit(value&0x0ff);
1770 if ((value>>32) != value && (value>>32) != 0) {
1771 emit("b(lit)");
1772 spit((value>>56)&0x0ff);
1773 spit((value>>48)&0x0ff);
1774 spit((value>>40)&0x0ff);
1775 spit((value>>32)&0x0ff);
1776 emit("lxjoin");
1777 }
1778 }
1779 break;
1780 case TOK_OF:
1781 STATE(token->text, "TOK_OF");
1782 /*
1783 * Let's hope I get the semantics right.
1784 *
1785 * The `of' behaves almost the same as an
1786 * `if'. The difference is that `endof'
1787 * takes a branch offset to the associated
1788 * `endcase'. Here we will generate a temporary
1789 * offset of the `of' associated with the `endof'.
1790 * Then in `endcase' we should be pointing just
1791 * after the offset of the last `endof' so we
1792 * calculate the offset and thread our way backwards
1793 * searching for the previous `b(case)' or `b(endof)'.
1794 */
1795 emit("b(of)");
1796 push(outpos);
1797 if (offsetsize == 16) {
1798 spit(0);
1799 }
1800 spit(0); /* Place holder for later */
1801 break;
1802 case TOK_REPEAT:
1803 STATE(token->text, "TOK_REPEAT");
1804 emit("bbranch");
1805 pos = pop();
1806 off = pop();
1807 /* First the offset for the branch back to the begin */
1808 off -= outpos;
1809 if (offsetsize == 16) {
1810 spit((off>>8)&0xff);
1811 }
1812 spit(off&0xff);
1813 emit("b(>resolve)");
1814 /* Now point the offset of the while here. */
1815 off = outpos;
1816 outpos = pos;
1817 pos = off - pos;
1818 if (offsetsize == 16) {
1819 spit((pos>>8)&0xff);
1820 }
1821 spit(pos&0xff);
1822 /* Return to the end of the output */
1823 outpos = off;
1824 break;
1825 case TOK_THEN:
1826 STATE(token->text, "TOK_THEN");
1827 emit("b(>resolve)");
1828 pos = outpos;
1829 outpos = pop();
1830 off = pos - outpos;
1831 if (offsetsize == 16) {
1832 spit((off>>8)&0xff);
1833 }
1834 spit(off&0xff);
1835 outpos = pos;
1836 break;
1837 case TOK_TO:
1838 STATE(token->text, "TOK_TO");
1839 /* The next pass should tokenize the FCODE number */
1840 emit("b(to)");
1841 break;
1842 case TOK_UNTIL:
1843 STATE(token->text, "TOK_UNTIL");
1844 {
1845 int pos;
1846
1847 emit("b?branch");
1848 pos = pop();
1849 pos -= outpos;
1850 if (offsetsize == 16) {
1851 spit((pos>>8)&0xff);
1852 }
1853 spit(pos&0xff);
1854 }
1855 break;
1856 case TOK_VALUE:
1857 STATE(token->text, "TOK_VALUE");
1858
1859 token = yylex();
1860 if (token == NULL) {
1861 (void)printf( "EOF in value definition\n");
1862 return;
1863 }
1864
1865 /* Add new code to dictionary */
1866 fcode = malloc(sizeof(*fcode));
1867 fcode->num = nextfcode++;
1868 fcode->name = strdup(token->text);
1869 fadd(dictionary, fcode);
1870
1871 if (state == 0)
1872 emit("new-token");
1873 else {
1874 if (state == TOK_EXTERNAL)
1875 emit("external-token");
1876 else
1877 /* Here we have a choice of new-token or named-token */
1878 emit("named-token");
1879 sspit(token->text);
1880 }
1881 spit(fcode->num);
1882 emit("b(value)");
1883 break;
1884 case TOK_VARIABLE:
1885 STATE(token->text, "TOK_VARIABLE");
1886
1887 token = yylex();
1888 if (token == NULL) {
1889 (void)printf( "EOF in variable definition\n");
1890 return;
1891 }
1892
1893 /* Add new code to dictionary */
1894 fcode = malloc(sizeof(*fcode));
1895 fcode->num = nextfcode++;
1896 fcode->name = strdup(token->text);
1897 fadd(dictionary, fcode);
1898
1899 if (state == 0)
1900 emit("new-token");
1901 else {
1902 if (state == TOK_EXTERNAL)
1903 emit("external-token");
1904 else
1905 /* Here we have a choice of new-token or named-token */
1906 emit("named-token");
1907 sspit(token->text);
1908 }
1909 spit(fcode->num);
1910 emit("b(variable)");
1911 break;
1912 case TOK_WHILE:
1913 STATE(token->text, "TOK_WHILE");
1914 emit("b?branch");
1915 push(outpos);
1916 if (offsetsize == 16) {
1917 spit(0);
1918 }
1919 spit(0);
1920 break;
1921
1922 /* Tokenizer directives */
1923 case TOK_BEGTOK:
1924 STATE(token->text, "TOK_BEGTOK");
1925 tokenizer = 1;
1926 break;
1927 case TOK_EMIT_BYTE:
1928 STATE(token->text, "TOK_EMIT_BYTE");
1929 spit(pop());
1930 break;
1931 case TOK_ENDTOK:
1932 STATE(token->text, "TOK_ENDTOK");
1933 tokenizer = 0;
1934 break;
1935 case TOK_FLOAD:
1936 STATE(token->text, "TOK_FLOAD");
1937 /* Parse a different file for a while */
1938 token = yylex();
1939 if ((inf = fopen(token->text, "r")) == NULL) {
1940 (void)printf("%s: Could not open %s: %s\n",
1941 myname, token->text, strerror(errno));
1942 break;
1943 }
1944 inbuf = yy_create_buffer(inf, YY_BUF_SIZE);
1945 yy_switch_to_buffer(inbuf);
1946 {
1947 char *oldinfile = infile;
1948
1949 infile = token->text;
1950 tokenize(inbuf);
1951 infile = oldinfile;
1952 }
1953 yy_switch_to_buffer(input);
1954 yy_delete_buffer(inbuf);
1955 fclose(inf);
1956 break;
1957 case TOK_OTHER:
1958 STATE(token->text, "TOK_OTHER");
1959 if (apply_macros(input, token->text))
1960 break;
1961 if (emit(token->text)) {
1962 #if 0
1963 /*
1964 * Call an external command
1965 *
1966 * XXXXX assumes it will always find the command
1967 */
1968 sspit(token->text);
1969 emit("$find");
1970 emit("drop");
1971 emit("execute");
1972 #else
1973 (void)printf( "%s: undefined token `%s'\n",
1974 myname, token->text);
1975 fflush(stderr);
1976 exit(1);
1977 #endif
1978 }
1979 break;
1980 default:
1981 /* Nothing */ ;
1982 }
1983 }
1984 return;
1985 }
1986
1987 /*
1988 * print a tokenizer error message
1989 */
1990 void
1991 token_err(int lineno, char *infile, char *text, char *fmt, ...)
1992 {
1993 va_list ap;
1994
1995 va_start(ap, fmt);
1996 if (infile)
1997 (void)fprintf(stderr, "%s:%d: ", infile, lineno);
1998 if (fmt)
1999 (void)vfprintf(stderr, fmt, ap);
2000 fputc('\n', stderr);
2001 if (text)
2002 fprintf(stderr, "\t%s", text);
2003 va_end(ap);
2004 exit(1);
2005 }
2006
2007 /*
2008 * Lookup fcode string in dictionary and spit it out.
2009 *
2010 * Fcode must be in dictionary. No alias conversion done.
2011 */
2012 int
2013 emit(str)
2014 char *str;
2015 {
2016 struct fcode *code;
2017 if ((code = flookup( dictionary, str)))
2018 spit(code->num);
2019 #ifdef DEBUG
2020 if (debug > 1) {
2021 if (code)
2022 (void)printf( "emitting `%s'\n", code->name);
2023 else
2024 (void)printf( "emit: not found `%s'\n", str);
2025 }
2026 #endif
2027 return (code == NULL);
2028 }
2029
2030 /*
2031 * Spit out an integral value as a series of FCodes.
2032 *
2033 * It will spit out one zero byte or as many bytes as are
2034 * non-zero.
2035 */
2036 int
2037 spit(n)
2038 long n;
2039 {
2040 int count = 1;
2041
2042 if (n >> 8)
2043 count += spit(n >> 8);
2044 if (outpos >= outbufsiz) {
2045 while (outpos >= outbufsiz) outbufsiz += BUFCLICK;
2046 if (!(outbuf = realloc(outbuf, outbufsiz))) {
2047 (void)printf( "realloc of %ld bytes failed -- out of memory\n",
2048 (long)outbufsiz);
2049 exit(1);
2050 }
2051 }
2052 if (debug > 1) printf("spitting %2.2x\n", (unsigned char)n);
2053 outbuf[outpos++] = n;
2054 return (count);
2055 }
2056
2057 /*
2058 * Spit out an FCode string.
2059 */
2060 void
2061 sspit(s)
2062 char *s;
2063 {
2064 int len = strlen(s);
2065
2066 if (len > 255) {
2067 (void)printf( "string length %d too long\n", len);
2068 return;
2069 }
2070 #ifdef DEBUG
2071 if (debug > 1)
2072 (void)printf( "sspit: len %d str `%s'\n", len, s);
2073 #endif
2074 spit(len);
2075 while (*s)
2076 spit(*s++);
2077 }
2078
2079 int
2080 yywrap()
2081 {
2082 /* Always generate EOF */
2083 return (1);
2084 }
2085