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