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