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