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