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