Author: stepan Date: 2006-08-18 14:47:12 +0200 (Fri, 18 Aug 2006) New Revision: 76
Added: fcode-utils/detok/addfcodes.c fcode-utils/detok/addfcodes.h fcode-utils/detok/pcihdr.c fcode-utils/detok/printformats.c fcode-utils/toke/clflags.c fcode-utils/toke/clflags.h fcode-utils/toke/conditl.c fcode-utils/toke/conditl.h fcode-utils/toke/devnode.c fcode-utils/toke/devnode.h fcode-utils/toke/errhandler.c fcode-utils/toke/errhandler.h fcode-utils/toke/flowcontrol.c fcode-utils/toke/flowcontrol.h fcode-utils/toke/macros.h fcode-utils/toke/nextfcode.c fcode-utils/toke/nextfcode.h fcode-utils/toke/parselocals.c fcode-utils/toke/parselocals.h fcode-utils/toke/scanner.h fcode-utils/toke/strsubvocab.c fcode-utils/toke/strsubvocab.h fcode-utils/toke/ticvocab.c fcode-utils/toke/ticvocab.h fcode-utils/toke/tokzesc.c fcode-utils/toke/tokzesc.h fcode-utils/toke/tracesyms.c fcode-utils/toke/tracesyms.h fcode-utils/toke/usersymbols.c fcode-utils/toke/usersymbols.h fcode-utils/toke/vocabfuncts.h Removed: fcode-utils/detok/Rules.make fcode-utils/toke/Rules.make Modified: fcode-utils/detok/Makefile fcode-utils/detok/decode.c fcode-utils/detok/detok.c fcode-utils/detok/detok.h fcode-utils/detok/dictionary.c fcode-utils/detok/stream.c fcode-utils/detok/stream.h fcode-utils/romheaders/Makefile fcode-utils/romheaders/romheaders.c fcode-utils/toke/Makefile fcode-utils/toke/dictionary.c fcode-utils/toke/dictionary.h fcode-utils/toke/emit.c fcode-utils/toke/emit.h fcode-utils/toke/macros.c fcode-utils/toke/scanner.c fcode-utils/toke/stack.c fcode-utils/toke/stack.h fcode-utils/toke/stream.c fcode-utils/toke/stream.h fcode-utils/toke/toke.c fcode-utils/toke/toke.h Log: initial merge of David Paktor's fine work.
I redid all of the Makefiles and fixed some minor issues with the code.
Modified: fcode-utils/detok/Makefile =================================================================== --- fcode-utils/detok/Makefile 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/detok/Makefile 2006-08-18 12:47:12 UTC (rev 76) @@ -1,11 +1,12 @@ # -# OpenBIOS - free your system! -# ( detokenizer ) -# -# This program is part of a free implementation of the IEEE 1275-1994 +# OpenBIOS - free your system! +# ( Utilities ) +# +# This program is part of a free implementation of the IEEE 1275-1994 # Standard for Boot (Initialization Configuration) Firmware. # -# Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org +# Copyright (C) 2001-2006 Stefan Reinauer stepan@openbios.org +# Copyright (C) 2006 coresystems GmbH info@coresystems.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,48 +22,37 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA #
-ARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/x86_64/amd64/ -e "s/Power Macintosh/ppc/") -TOPDIR := $(shell /bin/pwd) -BUILDDIR ?= $(TOPDIR)/obj-$(ARCH) +PROGRAM = detok
-VPATH := $(BUILDDIR) +CC = gcc +STRIP = strip +INCLUDES = -I../shared +#CFLAGS = -O2 -g -Wall +CFLAGS = -Os -Wall -Wno-pointer-sign +LDFLAGS =
+OBJS = addfcodes.o decode.o detok.o dictionary.o pcihdr.o printformats.o \ + stream.o ../shared/classcodes.o
-include $(TOPDIR)/Rules.make +all: .dependencies $(PROGRAM)
+$(PROGRAM): $(OBJS) + $(CC) -o $(PROGRAM) $(OBJS) $(LDFLAGS) + $(STRIP) -s $(PROGRAM)
-CC = gcc -CFLAGS = -O2 -Wall -ansi +clean: + rm -f $(OBJS) *~
-# For debugging the indentation code of detok, define DEBUG_INDENT -#CFLAGS := $(CFLAGS) -DDEBUG_INDENT +distclean: clean + rm -f $(PROGRAM) .dependencies + +.dependencies: *.c + @$(CC) $(CFLAGS) $(INCLUDES) -MM *.c > .dependencies
-all: main detok - @echo -e "\nOpenBIOS detokenizer detok build finished\n" +.PHONY: all clean distclean
-main: - @echo -e "\nWelcome to the OpenBIOS detokenizer.." - @test -r $(BUILDDIR) || ( mkdir -p $(BUILDDIR); \ - echo -e "\nCreating build directory $(BUILDDIR)" ) - -detok: detok.o dictionary.o decode.o stream.o - @echo -en "\nLinking fcode detokenizer detok..." - @cd $(BUILDDIR) && ( $(CC) $(CFLAGS) $^ -o $@; strip detok ) - @echo -e "\tok" - -clean: - @test ! -d $(BUILDDIR) && \ - echo "Architecture $(ARCH) is already clean." || \ - ( \ - echo "Cleaning up architecture $(ARCH)"; \ - rm -rf $(BUILDDIR) \ - rm forth.dict.core \ - ) +-include .dependencies
-distclean: clean - rm -f detok +.c.o: + $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@
-detok.o: detok.h stream.h detok.c -stream.o: detok.h stream.c -decode.o: detok.h stream.h decode.c Makefile -dictionary.o: detok.h dictionary.c
Deleted: fcode-utils/detok/Rules.make =================================================================== --- fcode-utils/detok/Rules.make 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/detok/Rules.make 2006-08-18 12:47:12 UTC (rev 76) @@ -1,17 +0,0 @@ -# tag: Makefile rules - -VPATH := $(VPATH):. - -.S.o: - echo -n " assembling $<... " - $(CC) -c -nostdlib $(INCLUDES) $(CFLAGS) $< -o $(BUILDDIR)/$@ && \ - echo -e " \t\tok" || \ - echo -e " \t\tfailed" - -.c.o: - @echo -n " compiling $<... " - @$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $(BUILDDIR)/$@ && \ - echo -e " \t\tok" || \ - echo -e " \t\failed" - -
Added: fcode-utils/detok/addfcodes.c =================================================================== --- fcode-utils/detok/addfcodes.c (rev 0) +++ fcode-utils/detok/addfcodes.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,343 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Function(s) for entering Vendor-Specific FCodes to detokenizer. + * + * (C) Copyright 2006 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Functions Exported: + * add_fcodes_from_list Add Vendor-Specific FCodes from + * the file whose name is supplied. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Revision History: + * Tue, 25 Apr 2006 by David L. Paktor + * Identified this need when working with in-house code, + * which uses some custom functions. This solution + * is (hoped to be) general enough to cover all cases. + * + **************************************************************************** */ + + +/* ************************************************************************** + * + * Global Variables Imported + * indata Buffer into which the file will be read + * stream_max Size of the file buffer. + * + **************************************************************************** */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "detok.h" +#include "stream.h" +#include "addfcodes.h" + +/* ************************************************************************** + * + * Internal Static Variables + * current_vfc_line Line to be scanned in Vendor-FCodes buffer + * vfc_remainder Remainder of Vendor-FCodes buffer to be scanned + * vfc_line_no Number of current line in Vendor-FCodes buffer + * vfc_buf_end Pointer to end of Vendor-FCodes buffer + * + **************************************************************************** */ + +static char *current_vfc_line; +static char *vfc_remainder; +static int vfc_line_no = 0; +static char *vfc_buf_end; + +/* ************************************************************************** + * + * Function name: skip_whitespace + * Synopsis: Advance the given string-pointer past blanks and tabs. + * (String is presumed to end before new-line) + * + * Inputs: + * Parameters: + * string_line_ptr Address of pointer to string + * + * Outputs: + * Returned Value: None + * *string_line_ptr Advanced past blanks and tabs + * + **************************************************************************** */ + +static void skip_whitespace( char **string_line_ptr) +{ + char *cur_char_ptr = *string_line_ptr; + for ( ; *cur_char_ptr != 0 ; cur_char_ptr++ ) + { + if ( (*cur_char_ptr != '\t') && (*cur_char_ptr != ' ') ) + { + *string_line_ptr = cur_char_ptr; + break; + } + } +} + +/* ************************************************************************** + * + * Function name: get_next_vfc_line + * Synopsis: Advance to the next vfc_line to be processed. + * Skip blanks and comments. Indicate when end reached. + * + * Inputs: + * Parameters: None + * Local Static Variables: + * vfc_remainder + * vfc_buf_end + * + * Outputs: + * Returned Value: FALSE if reached end of buffer + * Local Static Variables: + * current_vfc_line Advanced to next line to be scanned + * vfc_line_no Kept in sync with line number in file + * + * Process Explanation: + * Comments begin with a pound-sign ('#') or a backslash ('') + * Comment-lines or blank or empty lines will be skipped. + * + **************************************************************************** */ + +static bool get_next_vfc_line( void ) +{ + bool retval = FALSE; /* TRUE = not at end yet */ + while ( vfc_remainder < vfc_buf_end ) + { + current_vfc_line = vfc_remainder; + vfc_remainder = strchr( current_vfc_line, '\n'); + *vfc_remainder = 0; + vfc_remainder++; + vfc_line_no++; + skip_whitespace( ¤t_vfc_line); + if ( *current_vfc_line == 0 ) continue; /* Blank line */ + if ( *current_vfc_line == '#' ) continue; /* Comment */ + if ( *current_vfc_line == '\' ) continue; /* Comment */ + retval = TRUE; + break; /* Found something */ + } + return( retval); +} + +/* ************************************************************************** + * + * Function name: vfc_splash + * Synopsis: Print a "splash" message to show that we + * are processing Vendor-Specific FCodes, + * but only once. + * + * Inputs: + * Parameters: + * vf_file_name Vendor-Specific FCodes file name + * Local Static Variables: + * did_not_splash Control printing; once only. + * + * Outputs: + * Returned Value: None + * Local Static Variables: + * did_not_splash FALSE after first call. + * Printout: + * "Splash" message... + * + **************************************************************************** */ +static bool did_not_splash = TRUE; +static void vfc_splash( char *vf_file_name) +{ + if ( did_not_splash ) + { + /* Temporary substring buffer */ + /* Guarantee that the malloc will be big enough. */ + char *strbfr = malloc( strlen( vf_file_name) +65 ) ; + sprintf( strbfr, + "Reading additional FCodes from file: %s\n", + vf_file_name); + printremark( strbfr); + free( strbfr); + did_not_splash = FALSE; + } +} + +/* ************************************************************************** + * + * Function name: add_fcodes_from_list + * Synopsis: Add Vendor-Specific FCodes from the named file + * to the permanent resident dictionary. + * + * Inputs: + * Parameters: + * vf_file_name Vendor-Specific FCodes file name + * Global Variables: + * verbose "Verbose" flag. + * indata Start of file buffer + * stream_max Size of the file buffer. + * + * Outputs: + * Returned Value: TRUE if FCodes have actually been added + * Global Variables: + * check_tok_seq Cleared to FALSE, then restored to TRUE + * Local Static Variables: + * vfc_remainder Initted to start of file buffer + * vfc_buf_end Initted to end of file buffer + * Memory Allocated + * Permanent copy of FCode Name + * When Freed? + * Never. Rmeains until program termination. + * Printout: + * If verbose, "Splash" line and count of added entries. + * + * Error Detection: + * Fail to open or read Vendor-FCodes file -- Exit program + * Improperly formatted input line -- print message and ignore + * FCode value out of valid range -- print message and ignore + * FCode value already in use -- print message and ignore + * + * Process Explanation: + * Valid lines are formatted with the FCode number first + * and the name after, one entry per line. Extra text + * after the name will be ignored, so an extra "comment" + * is permitted. The FCode number must be in hex, with + * an optional leading 0x or 0X For example: 0X407 + * The valid range is 0x010 to 0x7ff. Numbers above 0x800 + * infringe upon the are reserved for FCodes generated + * by the tokenization process. + * Numbers already in use will be ignored. A Message will be + * printed even if the name matches the one on the line. + * + **************************************************************************** */ + +bool add_fcodes_from_list( char *vf_file_name) +{ + bool retval = FALSE; + int added_fc_count = 0; + check_tok_seq = FALSE; + + if ( verbose ) vfc_splash( vf_file_name); + + if ( init_stream( vf_file_name) != 0 ) + { + char *strbfr = malloc( strlen( vf_file_name) +65 ); + sprintf( strbfr, + "Could not open Additional FCodes file: %s\n", + vf_file_name); + printremark( strbfr); + free( strbfr); + exit(1); + } + vfc_remainder = indata; + vfc_buf_end = indata + stream_max -1; + + while ( get_next_vfc_line() ) + { + char vs_fc_name[36]; + int vs_fc_number; + int scan_result; + char *lookup_result; + char *fc_name_cpy; + + scan_result = sscanf( current_vfc_line, "0x%x %32s", + &vs_fc_number, vs_fc_name); + + if ( scan_result != 2 ) /* Allow a capital 0X */ + { + scan_result = sscanf( current_vfc_line, "0X%x %32s", + &vs_fc_number, vs_fc_name); + } + if ( scan_result != 2 ) /* Try it without the 0x */ + { + scan_result = sscanf( current_vfc_line, "%x %32s", + &vs_fc_number, vs_fc_name); + } + + if ( scan_result != 2 ) /* That's it... */ + { + char *strbfr = malloc( strlen( current_vfc_line) +65 ); + vfc_splash( vf_file_name); + sprintf( strbfr, + "Line #%d, invalid format. Ignoring: %s\n", + vfc_line_no, current_vfc_line); + printremark( strbfr); + free( strbfr); + continue; + } + + if ( ( vs_fc_number < 0x10 ) || ( vs_fc_number > 0x7ff ) ) + { + char *strbfr = malloc( 85 ); + vfc_splash( vf_file_name); + sprintf( strbfr, + "Line #%d, FCode number out of range: 0x%x Ignoring.\n", + vfc_line_no, vs_fc_number); + printremark( strbfr); + free( strbfr); + continue; + } + + lookup_result = lookup_token( (u16)vs_fc_number); + if ( strcmp( lookup_result, "ferror") != 0 ) + { + char *strbfr = malloc( strlen( lookup_result) + 85 ); + vfc_splash( vf_file_name); + sprintf( strbfr, + "Line #%d. FCode number 0x%x is already " + "defined as %s Ignoring.\n", + vfc_line_no, vs_fc_number, lookup_result); + printremark( strbfr); + free( strbfr); + continue; + } + + /* We've passed all the tests! */ + fc_name_cpy = strdup( vs_fc_name); + add_token( (u16)vs_fc_number, fc_name_cpy); + added_fc_count++; + retval = TRUE; + } + + if ( verbose ) + { + char *strbfr = malloc( 85 ); + sprintf( strbfr, + "Added %d FCode numbers\n", added_fc_count); + printremark( strbfr); + free( strbfr); + } + + close_stream(); + check_tok_seq = TRUE; + return( retval); +}
Added: fcode-utils/detok/addfcodes.h =================================================================== --- fcode-utils/detok/addfcodes.h (rev 0) +++ fcode-utils/detok/addfcodes.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,48 @@ +#ifndef _DETOK_VSFCODES_H +#define _DETOK_VSFCODES_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Header for function for entering Vendor-Specific FCodes + * to detokenizer. + * + * (C) Copyright 2006 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +#include "types.h" + +/* ************************************************************************** * + * + * Function Prototypes / Functions Exported: + * + **************************************************************************** */ + +bool add_fcodes_from_list( char *vf_file_name); + +#endif /* _DETOK_VSFCODES_H */
Modified: fcode-utils/detok/decode.c =================================================================== --- fcode-utils/detok/decode.c 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/detok/decode.c 2006-08-18 12:47:12 UTC (rev 76) @@ -24,96 +24,322 @@ * */
+/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <ctype.h> +#include <setjmp.h>
#include "detok.h" #include "stream.h"
-/* Dictionary function prototypes */ -char *lookup_token(u16 number); -int add_token(u16 number, char *name); +static int indent; /* Current level of indentation */
-extern u16 fcode; +/* ************************************************************************** + * + * Still to be done: + * Handling of indent-level is not correct. Branches should + * balance with their resolvers; constructs like do..loop + * case/of/endof/endcase are a few major examples. + * This will be tricky; the rules need to be carefully thought + * out, and the implementation might be more complex than + * at first meets the eye... + * + **************************************************************************** */
+static bool ended_okay = TRUE; /* FALSE if finished prematurely */ + bool offs16=TRUE; -int indent, verbose=0, decode_all=0, linenumbers=0, linenum; -u32 fclen; +unsigned int linenum; +bool end_found=FALSE; +unsigned int token_streampos; /* Streampos() of currently-gotten token */ +u16 last_defined_token = 0;
-static u8 *unnamed=(u8 *)"(unnamed-fcode)"; +jmp_buf eof_exception;
-void pretty_string(u8 *string) +static int fclen; +static const char *unnamed = "(unnamed-fcode)" ; + +static void decode_indent(void) { - u8 c; - unsigned int i; - bool qopen=TRUE; + int i; + if (indent<0) { +#ifdef DEBUG_INDENT + printf("detok: error in indentation code.\n"); +#endif + indent=0; + } + for (i=0; i<indent; i++) + printf (" "); +} +/* Print forth string ( [len] char[0] ... char[len] ) */ +static void pretty_print_string(void) +{ + u8 len; + u8 *strptr; + int indx; + bool in_parens = FALSE ; /* Are we already inside parentheses? */ + + strptr = get_string( &len ); + + printf("( len=%s%x", len >= 10 ? "0x":"", len); + if ( len >= 10 ) printf(" [%d bytes]", len); + printf(" )\n"); + if (show_linenumbers) printf(" "); + decode_indent(); printf("" ");
- for (i=1; i<1+(unsigned int)string[0]; i++) { - c=string[i]; + for ( indx = 0; indx < len; indx++ ) + { + u8 c = *strptr++; if (isprint(c)) { - if (!qopen) { + if ( in_parens ) + { printf(" )"); - qopen=TRUE; + in_parens = FALSE; } printf("%c",c); + /* Quote-mark must escape itself */ + if ( c == '"' ) printf("%c",c); } else { - if (qopen) { + if ( !in_parens ) + { printf(""("); - qopen=FALSE; + in_parens = TRUE; } printf(" %02x",c); } } - if (!qopen) + if ( in_parens ) printf(" )"); printf("""); }
-static void decode_indent(void) +static void decode_lines(void) { - int i; -#ifdef DEBUG_INDENT - if (indent<0) { - printf("detok: error in indentation code.\n"); - indent=0; + if (show_linenumbers) { + printf("%6d: ",show_offsets ? token_streampos : linenum++); } -#endif - for (i=0; i<indent; i++) - printf (" "); }
-static void decode_lines(void) +/* ************************************************************************** + * + * Function name: output_token_name + * Synopsis: Print the name of the token just retrieved + * along with any interesting related information... + * + * Inputs: + * Global/Static Variables: + * fcode The token # just retrieved + * last_defined_token Used to screen invalid tokens. + * token_streampos Location of token just retrieved + * Global/Static Constants: + * unnamed Namefield of headerless token + * + * Outputs: + * Printout: + * Print the function name (if known) and the FCode number, + * if interesting. + * The fcode number is interesting if either + * a) the token has no name + * or + * b) verbose mode is in effect. + * If the token is named, show its FCode number in + * the syntax of a FORTH Comment, otherwise, its + * FCode number -- in [brackets] -- acts as its name. + * + * Error Detection: + * If the token # is larger than the last defined token, it is + * probably an artifact of an error that was allowed in the + * tokenization; if it were treated normally, it would lead + * to a cascade of failures. Print a message, skip the first + * byte, and return. + * + * Revision History: + * Refactored. The line number or offset (if selected) and the + * indent are printed in the output_token() routine, which + * calls this one. + * Add Error Detection + * + * + **************************************************************************** */ + +static void output_token_name(void) { - if (linenumbers) { - printf("%6d: ",linenumbers==1?linenum:get_streampos()); - linenum++; + char *tname; + + /* Run error detection only if last_defined_token was assigned */ + if ( (fcode > last_defined_token) && (last_defined_token > 0) ) + { + char temp_buf[80]; + int buf_pos; + u8 top_byte = fcode >> 8; + printf ("Invalid token: [0x%03x]\n", fcode); + sprintf(temp_buf, "Backing up over first byte, which is "); + buf_pos = strlen(temp_buf); + if ( top_byte < 10 ) + { + sprintf(&temp_buf[buf_pos], " %02x", top_byte); + }else{ + sprintf( &temp_buf[buf_pos], "0x%02x ( =dec %d)", + top_byte, top_byte); } + printremark(temp_buf); + set_streampos(token_streampos+1); + return; }
-static void output_token(void) -{ - u8 *tname=lookup_token(fcode); + tname = lookup_token(fcode); printf ("%s ", tname);
- /* The fcode number is interesting if - * a) detok is in verbose mode - * b) the token has no name. + /* The fcode number is interesting + * if either + * a) the token has no name + * or + * b) detok is in verbose mode. */ - if (verbose || tname == unnamed) + if ( tname == unnamed ) + { printf("[0x%03x] ", fcode); + } else { + if ( verbose ) + { + /* If the token is named, + * show its fcode number in + * the syntax of a FORTH Comment + */ + printf("( 0x%03x ) ", fcode); + } + } }
+/* ************************************************************************** + * + * Function name: output_token + * Synopsis: Print the full line for the token just retrieved: + * line number, indentation and name. + * + * Revision History: + * Updated Mon, 11 Jul 2005 by David L. Paktor + * Separate out output_token_name() for specific uses. + * Incorporate calls to decode_lines() and decode_indent() + * to allow better control of indentation. + * + **************************************************************************** */ + +static void output_token(void) +{ + decode_lines(); + decode_indent(); + output_token_name(); +} + + +/* ************************************************************************** + * + * Function name: decode_offset + * Synopsis: Gather and display an FCode-offset associated with + * a branch or suchlike function. + * + * Inputs: + * Parameters: NONE + * Global/Static Variables: + * show_offsets Whether to show offsets in full detail + * offs16 Whether 16- (or 8-) -bit offsets + * stream_max Maximum valid destimation + * Local Static Variables: + * + * Outputs: + * Returned Value: The offset, converted to signed 16-bit # + * Global/Static Variables: + * stream-position Reset if invalid destination; otherwise, + * advanced in the normal manner. + * Printout: + * The offset and destination, if display of offsets was specified + * or if the destination is invalid + * + * Error Detection: + * Crude and rudimentary: + * If the target-destination is outside the theoretical limits, + * it's obviously wrong. + * Notification remark is printed and the stream-position reset + * to the location of the offset, to allow it to be processed + * in the manner of normal tokens. + * If the offset is zero, that's obviously wrong, but don't reset + * the stream-position: zero gets processed as end0 and that + * is also wrong... + * + * Still to be done: + * More sophisticated error-checking for invalid offsets. Look + * at the type of branch, and what should be expected in the + * vicinity of the destination. (This might be best served + * by a separate routine). + * This might also help with handling the indent-level correctly... + * Also, if indentation were to be handled in this routine, + * there would be no need to return the value of the offset. + * + **************************************************************************** */ + static s16 decode_offset(void) { s16 offs; + int dest; + bool invalid_dest; + int streampos = get_streampos();
+ output_token(); offs=get_offset(); - output_token(); - printf("0x%x\n",offs); + + /* The target-destination is the source-byte offset + * at which the FCode-offset is found, plus + * the FCode-offset. + */ + dest = streampos + offs; + + /* A destination of zero is invalid because there must be a + * token -- such as b(<mark) or b(do) -- preceding + * the target of a backward branch. + * A destination at the end of the stream is unlikely but + * theoretically possible, so we'll treat it as valid. + * An offset of zero is also, of course, invalid. + */ + invalid_dest = BOOLVAL ( (dest <= 0) + || (dest > stream_max) + || (offs == 0) ); + + /* Show the offset in hex and again as a signed decimal number. */ + if ( offs16 ) + { + printf("0x%04x (", (u16)(offs & 0xffff) ); + }else{ + printf("0x%02x (", (u8)(offs & 0x00ff) ); + } + if ( (offs < 0) || (offs > 9) ) printf(" =dec %d", offs); + /* If we're showing source-byte offsets, show targets of offsets */ + if ( show_offsets || invalid_dest ) + { + printf(" dest = %d ",dest); + } + printf(")\n"); + + if ( invalid_dest ) + { + if (offs == 0) + { + printremark("Error: Unresolved offset."); + }else{ + printremark("Error: Invalid offset. Ignoring..."); + set_streampos( streampos); + } + } return offs; }
@@ -127,59 +353,39 @@ { u16 token; output_token(); - token=get_token(); + token = next_token(); printf("0x%03x\n",token); - add_token(token, unnamed); + add_token(token, (char *)unnamed); }
static void named_token(void) { u16 token; + u8 len; u8* string;
output_token(); /* get forth string ( [len] [char0] ... [charn] ) */ - string=get_string(); - token=get_token(); - - printf("%s 0x%03x\n", string+1, token); - - add_token(token,string+1); + string=get_name(&len); + token = next_token(); + printf("%s 0x%03x\n", string, token); + add_token(token,string); }
-static void external_token(void) +static void bquote(void) { - u16 token; - u8* string; - output_token(); /* get forth string ( [len] [char0] ... [charn] ) */ - string=get_string(); - token=get_token(); - - printf("%s 0x%03x\n", string+1, token); - - add_token(token,string+1); -} - -static void bquote(void) -{ - u8 *string; - - /* get forth string ( [len] [char0] ... [charn] ) */ - string=get_string(); - output_token(); - pretty_string(string); + pretty_print_string(); printf("\n"); - free(string); }
static void blit(void) { u32 lit;
+ output_token(); lit=get_num32(); - output_token(); printf("0x%x\n",lit); }
@@ -204,56 +410,81 @@ u16 token;
output_token(); - token=get_token(); - decode_default(); + token = next_token(); + output_token_name(); + printf ("\n"); }
+/* ************************************************************************** + * + * Function name: decode_start + * Synopsis: Display the (known valid) FCode block Header + * + * Outputs: + * Global/Static Variables: + * fclen Length of the FCode block as shown in its Header + * + **************************************************************************** */ + static void decode_start(void) { u8 fcformat; u16 fcchecksum, checksum=0; - long pos; - u32 i;
- decode_default(); + output_token(); + printf(" ( %d-bit offsets)\n", offs16 ? 16 : 8 ); + token_streampos = get_streampos(); decode_lines(); fcformat=get_num8(); printf(" format: 0x%02x\n", fcformat);
- decode_lines(); - fcchecksum=get_num16(); - /* missing: check for checksum correctness. */ - - fclen=get_num32(); /* skip len */ - pos=get_streampos(); - for (i=0; i<fclen-pos; i++) - checksum+=get_num8(); + /* Check for checksum correctness. */ - set_streampos(pos-4); + token_streampos = get_streampos(); + decode_lines(); + fcchecksum=get_num16(); /* Read the stored checksum */ + checksum = calc_checksum(); /* Calculate the actual checksum */ - printf(" checksum: 0x%04x (%sOk)\n", fcchecksum, - fcchecksum==checksum?"":"not "); + if ( fcchecksum==checksum ) + { + printf(" checksum: 0x%04x (Ok)\n", fcchecksum); + } else { + printf(" checksum should be: 0x%04x, but is 0x%04x\n", + checksum,fcchecksum); + }
+ token_streampos = get_streampos(); decode_lines(); fclen=get_num32(); - printf(" len: 0x%x (%d bytes)\n", fclen, fclen); + printf(" len: 0x%04x ( %d bytes)\n", fclen, fclen); }
-void decode_token(u16 token) +/* ************************************************************************** + * + * Function name: decode_token + * Synopsis: Display detokenization for one token. + * Handle complicated cases and dispatch simple ones. + * + * Revision History: + * Detect FCode-Starters in the middle of an FCode block. + * Some tuning of adjustment of indent, particularly wrt branches... + * + **************************************************************************** */ + +static void decode_token(u16 token) { + bool handy_flag = TRUE; switch (token) { case 0x0b5: new_token(); break; - case 0x0b6: + case 0x0b6: /* Named Token */ + case 0x0ca: /* External Token */ named_token(); break; - case 0x0ca: - external_token(); - break; case 0x012: bquote(); break; @@ -276,14 +507,14 @@ case 0x0c2: /* b(;) */ case 0x0b2: /* b(>resolve) */ case 0x0c5: /* b(endcase) */ + indent--; decode_default(); - indent--; break; case 0x015: /* b(loop) */ case 0x016: /* b(+loop) */ case 0x0c6: /* b(endof) */ + indent--; decode_offset(); - indent--; break; case 0x017: /* b(do) */ case 0x018: /* b/?do) */ @@ -295,38 +526,274 @@ case 0x0c3: /* b(to) */ decode_two(); break; + case 0x0fd: /* version1 */ + handy_flag = FALSE; case 0x0f0: /* start0 */ case 0x0f1: /* start1 */ case 0x0f2: /* start2 */ case 0x0f3: /* start4 */ + offs16 = handy_flag; + printremark("Unexpected FCode-Block Starter."); decode_start(); + printremark(" Ignoring length field."); break; + case 0: /* end0 */ + case 0xff: /* end1 */ + end_found=TRUE; + decode_default(); + break; + default: + decode_default(); + } +} + + +/* ************************************************************************** + * + * Function name: decode_fcode_header + * Synopsis: Detokenize the FCode Header. + * Check for file corruption + * + * Inputs: + * Parameters: NONE + * Global/Static Variables: + * stream_max Length of input stream + * + * Outputs: + * Returned Value: NONE + * Global/Static Variables: + * offs16 FALSE if Starter was version1, else TRUE + * fclen On error, gets set to reach end of input stream + * Otherwise, gets set by decode_start() + * Printout: + * + * Error Detection: + * First byte not a valid FCode Start: Print message, restore + * input pointer to initial value, set fclen to [(end of + * input stream) - (input pointer)], return FALSE. + * + * Process Explanation: + * This routine error-checks and dispatches to the routine that + * does the actual printing. + * Refrain from showing offset until correctness of starter-byte + * has been confirmed. + * + **************************************************************************** */ + +static void decode_fcode_header(void) +{ + long err_pos; + u16 token; + + err_pos = get_streampos(); + indent = 0; + token = next_token(); + offs16=TRUE; + switch (token) + { case 0x0fd: /* version1 */ - decode_start(); offs16=FALSE; + case 0x0f0: /* start0 */ + case 0x0f1: /* start1 */ + case 0x0f2: /* start2 */ + case 0x0f3: /* start4 */ + decode_start(); break; default: - decode_default(); + { + char temp_bufr[128] = + "Invalid FCode Start Byte. Ignoring FCode header." ; + set_streampos( err_pos ); + fclen = max - pc; + printf("\n"); + if (show_linenumbers) + { + sprintf( &(temp_bufr[strlen(temp_bufr)]), + " Remaining len = 0x%04x ( %d bytes)", fclen, fclen); + } + printremark( temp_bufr ); } } +}
-int detokenize(void) +/* ************************************************************************** + * + * Function name: decode_fcode_block + * Synopsis: Detokenize one FCode block. + * + * Inputs: + * Parameters: NONE + * Global/Static Variables: + * fclen Length of the FCode block as shown in its Header + * end_found Whether the END0 code was seen + * decode_all TRUE = continue even after END0 + * + * Outputs: + * Returned Value: NONE + * Global/Static Variables: + * end_found Whether the END0 code was seen + * Printout: + * A summary message at the end of FCode detokenization + * + * Error Detection: + * If the end of the FCode block, as calculated by its FCode length, + * was reached without encountering END0, print a message. + * Detect END0 that occurs before end of FCode block, + * even if decode_all is in effect. + * + * Process Explanation: + * This routine dispatches to the routines that do the actual + * printing of the detokenization. + * The end_found flag is not a direct input, but more of an + * intermediate input, so to speak... Clear it at the start. + * Detection of FCode-Starters in the middle of an FCode block + * is handled by decode_token() routine. + * + **************************************************************************** */ + +static void decode_fcode_block(void) { u16 token; + unsigned int fc_block_start; + unsigned int fc_block_end; - if (linenumbers) - linenum=1; + end_found = FALSE; + fc_block_start = get_streampos(); - do { - decode_lines(); - decode_indent(); - token=get_token(); + decode_fcode_header(); + + fc_block_end = fc_block_start + fclen; + + while ( ( !end_found || decode_all ) + && ( get_streampos() < fc_block_end ) ) + { + token = next_token(); decode_token(token); - } while ((token||decode_all) && ((get_streampos()-1)<=fclen)); + } + if ( !end_found ) + { + printremark("FCode-ender not found"); + } + { + char temp_bufr[80]; + /* Don't use fclen here, in case it got corrupted + * by an "Unexpected FCode-Block Starter" + */ + if ( get_streampos() == fc_block_end ) + { + sprintf( temp_bufr, + "Detokenization finished normally after %d bytes.", + fc_block_end - fc_block_start ); + }else{ + sprintf( temp_bufr, + "Detokenization finished prematurely after %d of %d bytes.", + get_streampos() - fc_block_start, + fc_block_end - fc_block_start ); + ended_okay = FALSE; + } + printremark( temp_bufr ); + } +}
- decode_lines(); - printf ("\ detokenizing finished after %d of %d bytes.\n", - get_streampos(), fclen ); +/* ************************************************************************** + * + * Function name: another_fcode_block + * Synopsis: Indicate whether there is a follow-on FCode block + * within the current PCI image. + * + * Inputs: + * Parameters: NONE + * Global/Static Variables: + * token_streampos Streampos() of token just gotten + * Next token in Input Stream + * + * Outputs: + * Returned Value: TRUE if next token shows the start + * of a valid FCode-block + * Printout: + * Message if there is a follow-on FCode block + * + * Error Detection: + * If next token is neither a valid FCode-block starter nor the + * start of a zero-fill field, print a message. + * + * Process Explanation: + * Extract the next token from the Input Stream but do not + * consume it. Then examine the token. + * + **************************************************************************** */
- return 0; +static bool another_fcode_block(void) +{ + bool retval = FALSE; + u16 token; + + token = next_token(); + set_streampos( token_streampos ); + + switch (token) + { + case 0x0fd: /* version1 */ + case 0x0f0: /* start0 */ + case 0x0f1: /* start1 */ + case 0x0f2: /* start2 */ + case 0x0f3: /* start4 */ + retval = TRUE; + printremark("Subsequent FCode Block detected. Detokenizing."); + break; + case 0: /* Start of a zero-fill field */ + /* retval already = FALSE . Nothing else to be done. */ + break; + default: + { + char temp_bufr[80]; + sprintf( temp_bufr, + "Unexpected token, 0x%02x, after end of FCode block.", + token); + printremark( temp_bufr); + } + } + return ( retval ); } + +/* ************************************************************************** + * + * Function name: detokenize + * Synopsis: Detokenize one input file + * + * + * + **************************************************************************** */ + +void detokenize(void) +{ + fclen = stream_max; + + if ( setjmp(eof_exception) == 0 ) + { + while ( more_to_go() ) + { + if ( ended_okay ) + { + init_fcode_block(); + } + ended_okay = TRUE; + + adjust_for_pci_header(); + + /* Allow for multiple FCode Blocks within the PCI image. + * The first one had better be a valid block, but the + * next may or may not be... + */ + do + { + decode_fcode_block(); + } while ( another_fcode_block() ); + + adjust_for_pci_filler(); + + } + } + + +}
Modified: fcode-utils/detok/detok.c =================================================================== --- fcode-utils/detok/detok.c 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/detok/detok.c 2006-08-18 12:47:12 UTC (rev 76) @@ -24,58 +24,76 @@ * */
+/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> + #ifdef __GLIBC__ #define _GNU_SOURCE #include <getopt.h> -#else -/* Some systems seem to have an incomplete unistd.h. - * We need to define getopt() and optind for them. - */ -extern int optind; -int getopt(int argc, char * const argv[], const char *optstring); #endif
#include "detok.h" #include "stream.h" +#include "addfcodes.h"
#define DETOK_VERSION "0.6.1"
-/* prototypes for dictionary handling */ -void init_dictionary(void); -void decode_token(u16 token); -/* prototype for detokenizer function */ -int detokenize(void); +#define IBM_COPYR "(C) Copyright 2005 IBM Corporation. All Rights Reserved."
-extern unsigned int decode_all, verbose, linenumbers; +bool verbose = FALSE ; +bool decode_all = FALSE ; +bool show_linenumbers = FALSE ; +bool show_offsets = FALSE ;
-void print_copyright(void) +/* Param is FALSE when beginning to detokenize, + * TRUE preceding error-exit */ +static void print_copyright(bool is_error) { - printf( "Welcome to the OpenBIOS detokenizer v%s\ndetok Copyright" + typedef void (*vfunct)(); /* Pointer to function returning void */ + vfunct pfunct ; + char buffr[512]; + + sprintf( buffr, + "Welcome to the OpenBIOS detokenizer v%s\ndetok Copyright" "(c) 2001-2005 by Stefan Reinauer.\nWritten by Stefan " "Reinauer, stepan@openbios.org\n" "This program is " "free software; you may redistribute it under the terms of\n" "the GNU General Public License. This program has absolutely" " no warranty.\n\n" ,DETOK_VERSION); + + pfunct = ( is_error ? (vfunct)printf : printremark ); + + (*pfunct) ( buffr ); + + (*pfunct) ( IBM_COPYR "\n" ); }
-void usage(char *name) +static void usage(char *name) { printf( "usage: %s [OPTION]... [FCODE-FILE]...\n\n" " -v, --verbose print fcode numbers\n" " -a, --all don't stop at end0\n" " -n, --linenumbers print line numbers\n" " -o, --offsets print byte offsets\n" + " -f, --fcodes add FCodes from list-file\n" " -h, --help print this help text\n\n", name); }
int main(int argc, char **argv) { int c; - const char *optstring="vhano?"; + const char *optstring="vhanof:?"; + int linenumbers = 0; + bool add_vfcodes = FALSE; + char *vfc_filnam = NULL;
while (1) { #ifdef __GLIBC__ @@ -86,6 +104,7 @@ { "all", 0, 0, 'a' }, { "linenumbers", 0, 0, 'n' }, { "offsets", 0, 0, 'o' }, + { "fcodes", 1, 0, 'f' }, { 0, 0, 0, 0 } };
@@ -99,24 +118,31 @@
switch (c) { case 'v': - verbose=1; + verbose=TRUE; break; case 'a': - decode_all=1; + decode_all=TRUE; break; case 'n': linenumbers|=1; + show_linenumbers = TRUE; break; case 'o': linenumbers|=2; + show_linenumbers = TRUE; + show_offsets = TRUE; break; + case 'f': + add_vfcodes = TRUE; + vfc_filnam = optarg; + break; case 'h': case '?': - print_copyright(); + print_copyright(TRUE); usage(argv[0]); return 0; default: - print_copyright(); + print_copyright(TRUE); printf ("%s: unknown option.\n",argv[0]); usage(argv[0]); return 1; @@ -124,13 +150,14 @@ }
if (verbose) - print_copyright(); + print_copyright(FALSE); if (linenumbers>2) - printf("Line numbers will be disabled in favour of offsets.\n"); + printremark( + "Line numbers will be disabled in favour of offsets.\n"); if (optind >= argc) { - print_copyright(); + print_copyright(TRUE); printf ("%s: filename missing.\n",argv[0]); usage(argv[0]); return 1; @@ -138,6 +165,14 @@ init_dictionary(); + if ( add_vfcodes ) + { + if ( add_fcodes_from_list( vfc_filnam) ) + { + freeze_dictionary(); + } + } + while (optind < argc) { if (init_stream(argv[optind])) {
Modified: fcode-utils/detok/detok.h =================================================================== --- fcode-utils/detok/detok.h 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/detok/detok.h 2006-08-18 12:47:12 UTC (rev 76) @@ -1,3 +1,6 @@ +#ifndef _UTILS_DETOK_DETOK_H +#define _UTILS_DETOK_DETOK_H + /* * OpenBIOS - free your system! * ( detokenizer ) @@ -24,10 +27,49 @@ * */
-#define u8 unsigned char -#define u16 unsigned short -#define u32 unsigned int -#define s16 short -#define bool int -#define TRUE (-1) -#define FALSE (0) +/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + +#include "types.h" + +/* Prototypes for functions exported from + * detok.c decode.c printformats.c pcihdr.c and dictionary.c + */ + +void add_token(u16 number, char *name); +void init_dictionary(void); +void reset_dictionary(void); +void freeze_dictionary(void); +char *lookup_token(u16 number); + +void detokenize(void); + +void printremark(char *str); + +int handle_pci_header ( u8 *data_ptr ); +void handle_pci_filler(u8 *filler_ptr); + + +/* External declarations for variables defined in or used by + * detok.c decode.c printformats.c pcihdr.c and dictionary.c + */ +extern bool verbose; +extern bool decode_all; +extern bool show_linenumbers; +extern bool show_offsets; + +extern bool check_tok_seq; + +extern u16 fcode; +extern bool offs16; +extern bool end_found; +extern unsigned int linenum; + +extern u8 *pci_image_end; +extern unsigned int token_streampos; +extern u16 last_defined_token; + +#endif /* _UTILS_DETOK_DETOK_H */
Modified: fcode-utils/detok/dictionary.c =================================================================== --- fcode-utils/detok/dictionary.c 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/detok/dictionary.c 2006-08-18 12:47:12 UTC (rev 76) @@ -24,20 +24,29 @@ * */
+/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + #include <stdio.h> #include <stdlib.h> #include <errno.h>
#include "detok.h"
+bool check_tok_seq = TRUE; + typedef struct token { - u8 *name; + char *name; u16 fcode; struct token *next; } token_t; +#define TOKEN_ENTRY(num, name) { name, (u16)num, (token_t *)NULL } +static token_t *dictionary; /* Initialize dynamically to accommodate AIX */
static char *fcerror="ferror"; -token_t *dictionary=NULL;
char *lookup_token(u16 number) { @@ -53,7 +62,51 @@ return fcerror; }
-int add_token(u16 number, char *name) +/* ************************************************************************** + * + * Function name: add_token + * Synopsis: Add an entry to the FCode-Tokens vocabulary. + * + * Inputs: + * Parameters: + * number Numeric value of the FCode token + * name Name of the function to display + * Global/Static Variables: + * dictionary Pointer to the "tail" of the + * FCode-Tokens vocabulary. + * check_tok_seq TRUE = "Check Token Sequence" + * A retro-fit to accommodate + * adding Vendor FCodes + * + * Outputs: + * Returned Value: NONE + * Global/Static Variables: + * dictionary Updated to point to the new entry. + * last_defined_token Updated to the given FCode token + * Memory Allocated + * For the new entry. + * When Freed? + * Never. Retained for duration of the program. + * + * Error Detection: + * Failure to allocate memory is a fatal error. + * If the given FCode token is not exactly one larger than the + * previous last_defined_token , then there's something + * odd going on; print a remark to alert the user. The + * value of last_defined_token will be used elsewhere + * for additional error-checking. + * + * Process Explanation: + * The name field pointer is presumed to already point to a stable + * memory-space. + * Memory will be allocated for the entry itself; its fields will + * be entered and the pointer-to-the-tail-of-the-vocabulary + * will be updated to point to the new entry. + * Error-check and update last_defined_token + * + **************************************************************************** */ + +void add_token(u16 number, char *name) { token_t *curr;
@@ -68,393 +121,451 @@ curr->name=name;
dictionary=curr; - return 0; + + if ( check_tok_seq ) + { + /* Error-check, but not for first time. */ + if ( (number == last_defined_token + 1) + || (last_defined_token == 0) ) + { + last_defined_token = number; + }else{ + if ( number <= last_defined_token ) + { + printremark("Warning: New token # might overlap " + "previously assigned token #(s)."); + }else{ + printremark("Warning: New token # out of sequence with " + "previously assigned token #(s)."); + /* It's increasing; update it. */ + last_defined_token = number; + } } + }
+} + +token_t detok_table[] = { + + TOKEN_ENTRY( 0x000, "end0" ), + TOKEN_ENTRY( 0x010, "b(lit)" ), + TOKEN_ENTRY( 0x011, "b(')" ), + TOKEN_ENTRY( 0x012, "b(")" ), + TOKEN_ENTRY( 0x013, "bbranch" ), + TOKEN_ENTRY( 0x014, "b?branch" ), + TOKEN_ENTRY( 0x015, "b(loop)" ), + TOKEN_ENTRY( 0x016, "b(+loop)" ), + TOKEN_ENTRY( 0x017, "b(do)" ), + TOKEN_ENTRY( 0x018, "b(?do)" ), + TOKEN_ENTRY( 0x019, "i" ), + TOKEN_ENTRY( 0x01a, "j" ), + TOKEN_ENTRY( 0x01b, "b(leave)" ), + TOKEN_ENTRY( 0x01c, "b(of)" ), + TOKEN_ENTRY( 0x01d, "execute" ), + TOKEN_ENTRY( 0x01e, "+" ), + TOKEN_ENTRY( 0x01f, "-" ), + TOKEN_ENTRY( 0x020, "*" ), + TOKEN_ENTRY( 0x021, "/" ), + TOKEN_ENTRY( 0x022, "mod" ), + TOKEN_ENTRY( 0x023, "and" ), + TOKEN_ENTRY( 0x024, "or" ), + TOKEN_ENTRY( 0x025, "xor" ), + TOKEN_ENTRY( 0x026, "invert" ), + TOKEN_ENTRY( 0x027, "lshift" ), + TOKEN_ENTRY( 0x028, "rshift" ), + TOKEN_ENTRY( 0x029, ">>a" ), + TOKEN_ENTRY( 0x02a, "/mod" ), + TOKEN_ENTRY( 0x02b, "u/mod" ), + TOKEN_ENTRY( 0x02c, "negate" ), + TOKEN_ENTRY( 0x02d, "abs" ), + TOKEN_ENTRY( 0x02e, "min" ), + TOKEN_ENTRY( 0x02f, "max" ), + TOKEN_ENTRY( 0x030, ">r" ), + TOKEN_ENTRY( 0x031, "r>" ), + TOKEN_ENTRY( 0x032, "r@" ), + TOKEN_ENTRY( 0x033, "exit" ), + TOKEN_ENTRY( 0x034, "0=" ), + TOKEN_ENTRY( 0x035, "0<>" ), + TOKEN_ENTRY( 0x036, "0<" ), + TOKEN_ENTRY( 0x037, "0<=" ), + TOKEN_ENTRY( 0x038, "0>" ), + TOKEN_ENTRY( 0x039, "0>=" ), + TOKEN_ENTRY( 0x03a, "<" ), + TOKEN_ENTRY( 0x03b, ">" ), + TOKEN_ENTRY( 0x03c, "=" ), + TOKEN_ENTRY( 0x03d, "<>" ), + TOKEN_ENTRY( 0x03e, "u>" ), + TOKEN_ENTRY( 0x03f, "u<=" ), + TOKEN_ENTRY( 0x040, "u<" ), + TOKEN_ENTRY( 0x041, "u>=" ), + TOKEN_ENTRY( 0x042, ">=" ), + TOKEN_ENTRY( 0x043, "<=" ), + TOKEN_ENTRY( 0x044, "between" ), + TOKEN_ENTRY( 0x045, "within" ), + TOKEN_ENTRY( 0x046, "drop" ), + TOKEN_ENTRY( 0x047, "dup" ), + TOKEN_ENTRY( 0x048, "over" ), + TOKEN_ENTRY( 0x049, "swap" ), + TOKEN_ENTRY( 0x04A, "rot" ), + TOKEN_ENTRY( 0x04b, "-rot" ), + TOKEN_ENTRY( 0x04c, "tuck" ), + TOKEN_ENTRY( 0x04d, "nip" ), + TOKEN_ENTRY( 0x04e, "pick" ), + TOKEN_ENTRY( 0x04f, "roll" ), + TOKEN_ENTRY( 0x050, "?dup" ), + TOKEN_ENTRY( 0x051, "depth" ), + TOKEN_ENTRY( 0x052, "2drop" ), + TOKEN_ENTRY( 0x053, "2dup" ), + TOKEN_ENTRY( 0x054, "2over" ), + TOKEN_ENTRY( 0x055, "2swap" ), + TOKEN_ENTRY( 0x056, "2rot" ), + TOKEN_ENTRY( 0x057, "2/" ), + TOKEN_ENTRY( 0x058, "u2/" ), + TOKEN_ENTRY( 0x059, "2*" ), + TOKEN_ENTRY( 0x05a, "/c" ), + TOKEN_ENTRY( 0x05b, "/w" ), + TOKEN_ENTRY( 0x05c, "/l" ), + TOKEN_ENTRY( 0x05d, "/n" ), + TOKEN_ENTRY( 0x05e, "ca+" ), + TOKEN_ENTRY( 0x05f, "wa+" ), + TOKEN_ENTRY( 0x060, "la+" ), + TOKEN_ENTRY( 0x061, "na+" ), + TOKEN_ENTRY( 0x062, "char+" ), + TOKEN_ENTRY( 0x063, "wa1+" ), + TOKEN_ENTRY( 0x064, "la1+" ), + TOKEN_ENTRY( 0x065, "cell+" ), + TOKEN_ENTRY( 0x066, "chars" ), + TOKEN_ENTRY( 0x067, "/w*" ), + TOKEN_ENTRY( 0x068, "/l*" ), + TOKEN_ENTRY( 0x069, "cells" ), + TOKEN_ENTRY( 0x06a, "on" ), + TOKEN_ENTRY( 0x06b, "off" ), + TOKEN_ENTRY( 0x06c, "+!" ), + TOKEN_ENTRY( 0x06d, "@" ), + TOKEN_ENTRY( 0x06e, "l@" ), + TOKEN_ENTRY( 0x06f, "w@" ), + TOKEN_ENTRY( 0x070, "<w@" ), + TOKEN_ENTRY( 0x071, "c@" ), + TOKEN_ENTRY( 0x072, "!" ), + TOKEN_ENTRY( 0x073, "l!" ), + TOKEN_ENTRY( 0x074, "w!" ), + TOKEN_ENTRY( 0x075, "c!" ), + TOKEN_ENTRY( 0x076, "2@" ), + TOKEN_ENTRY( 0x077, "2!" ), + TOKEN_ENTRY( 0x078, "move" ), + TOKEN_ENTRY( 0x079, "fill" ), + TOKEN_ENTRY( 0x07a, "comp" ), + TOKEN_ENTRY( 0x07b, "noop" ), + TOKEN_ENTRY( 0x07c, "lwsplit" ), + TOKEN_ENTRY( 0x07d, "wljoin" ), + TOKEN_ENTRY( 0x07e, "lbsplit" ), + TOKEN_ENTRY( 0x07f, "bljoin" ), + TOKEN_ENTRY( 0x080, "wbflip" ), + TOKEN_ENTRY( 0x081, "upc" ), + TOKEN_ENTRY( 0x082, "lcc" ), + TOKEN_ENTRY( 0x083, "pack" ), + TOKEN_ENTRY( 0x084, "count" ), + TOKEN_ENTRY( 0x085, "body>" ), + TOKEN_ENTRY( 0x086, ">body" ), + TOKEN_ENTRY( 0x087, "fcode-revision" ), + TOKEN_ENTRY( 0x088, "span" ), + TOKEN_ENTRY( 0x089, "unloop" ), + TOKEN_ENTRY( 0x08a, "expect" ), + TOKEN_ENTRY( 0x08b, "alloc-mem" ), + TOKEN_ENTRY( 0x08c, "free-mem" ), + TOKEN_ENTRY( 0x08d, "key?" ), + TOKEN_ENTRY( 0x08e, "key" ), + TOKEN_ENTRY( 0x08f, "emit" ), + TOKEN_ENTRY( 0x090, "type" ), + TOKEN_ENTRY( 0x091, "(cr" ), + TOKEN_ENTRY( 0x092, "cr" ), + TOKEN_ENTRY( 0x093, "#out" ), + TOKEN_ENTRY( 0x094, "#line" ), + TOKEN_ENTRY( 0x095, "hold" ), + TOKEN_ENTRY( 0x096, "<#" ), + TOKEN_ENTRY( 0x097, "u#>" ), + TOKEN_ENTRY( 0x098, "sign" ), + TOKEN_ENTRY( 0x099, "u#" ), + TOKEN_ENTRY( 0x09a, "u#s" ), + TOKEN_ENTRY( 0x09b, "u." ), + TOKEN_ENTRY( 0x09c, "u.r" ), + TOKEN_ENTRY( 0x09d, "." ), + TOKEN_ENTRY( 0x09e, ".r" ), + TOKEN_ENTRY( 0x09f, ".s" ), + TOKEN_ENTRY( 0x0a0, "base" ), + TOKEN_ENTRY( 0x0a1, "convert" ), + TOKEN_ENTRY( 0x0a2, "$number" ), + TOKEN_ENTRY( 0x0a3, "digit" ), + TOKEN_ENTRY( 0x0a4, "-1" ), + TOKEN_ENTRY( 0x0a5, "0" ), + TOKEN_ENTRY( 0x0a6, "1" ), + TOKEN_ENTRY( 0x0a7, "2" ), + TOKEN_ENTRY( 0x0a8, "3" ), + TOKEN_ENTRY( 0x0a9, "bl" ), + TOKEN_ENTRY( 0x0aa, "bs" ), + TOKEN_ENTRY( 0x0ab, "bell" ), + TOKEN_ENTRY( 0x0ac, "bounds" ), + TOKEN_ENTRY( 0x0ad, "here" ), + TOKEN_ENTRY( 0x0ae, "aligned" ), + TOKEN_ENTRY( 0x0af, "wbsplit" ), + TOKEN_ENTRY( 0x0b0, "bwjoin" ), + TOKEN_ENTRY( 0x0b1, "b(<mark)" ), + TOKEN_ENTRY( 0x0b2, "b(>resolve)" ), + TOKEN_ENTRY( 0x0b3, "set-token-table" ), + TOKEN_ENTRY( 0x0b4, "set-table" ), + TOKEN_ENTRY( 0x0b5, "new-token" ), + TOKEN_ENTRY( 0x0b6, "named-token" ), + TOKEN_ENTRY( 0x0b7, "b(:)" ), + TOKEN_ENTRY( 0x0b8, "b(value)" ), + TOKEN_ENTRY( 0x0b9, "b(variable)" ), + TOKEN_ENTRY( 0x0ba, "b(constant)" ), + TOKEN_ENTRY( 0x0bb, "b(create)" ), + TOKEN_ENTRY( 0x0bc, "b(defer)" ), + TOKEN_ENTRY( 0x0bd, "b(buffer:)" ), + TOKEN_ENTRY( 0x0be, "b(field)" ), + TOKEN_ENTRY( 0x0bf, "b(code)" ), + TOKEN_ENTRY( 0x0c0, "instance" ), + TOKEN_ENTRY( 0x0c2, "b(;)" ), + TOKEN_ENTRY( 0x0c3, "b(to)" ), + TOKEN_ENTRY( 0x0c4, "b(case)" ), + TOKEN_ENTRY( 0x0c5, "b(endcase)" ), + TOKEN_ENTRY( 0x0c6, "b(endof)" ), + TOKEN_ENTRY( 0x0c7, "#" ), + TOKEN_ENTRY( 0x0c8, "#s" ), + TOKEN_ENTRY( 0x0c9, "#>" ), + TOKEN_ENTRY( 0x0ca, "external-token" ), + TOKEN_ENTRY( 0x0cb, "$find" ), + TOKEN_ENTRY( 0x0cc, "offset16" ), + TOKEN_ENTRY( 0x0cd, "evaluate" ), + TOKEN_ENTRY( 0x0d0, "c," ), + TOKEN_ENTRY( 0x0d1, "w," ), + TOKEN_ENTRY( 0x0d2, "l," ), + TOKEN_ENTRY( 0x0d3, "," ), + TOKEN_ENTRY( 0x0d4, "um*" ), + TOKEN_ENTRY( 0x0d5, "um/mod" ), + TOKEN_ENTRY( 0x0d8, "d+" ), + TOKEN_ENTRY( 0x0d9, "d-" ), + TOKEN_ENTRY( 0x0da, "get-token" ), + TOKEN_ENTRY( 0x0db, "set-token" ), + TOKEN_ENTRY( 0x0dc, "state" ), + TOKEN_ENTRY( 0x0dd, "compile" ), + TOKEN_ENTRY( 0x0de, "behavior" ), + TOKEN_ENTRY( 0x0f0, "start0" ), + TOKEN_ENTRY( 0x0f1, "start1" ), + TOKEN_ENTRY( 0x0f2, "start2" ), + TOKEN_ENTRY( 0x0f3, "start4" ), + TOKEN_ENTRY( 0x0fc, "ferror" ), + TOKEN_ENTRY( 0x0fd, "version1" ), + TOKEN_ENTRY( 0x0fe, "4-byte-id" ), + TOKEN_ENTRY( 0x0ff, "end1" ), + TOKEN_ENTRY( 0x101, "dma-alloc" ), + TOKEN_ENTRY( 0x102, "my-address" ), + TOKEN_ENTRY( 0x103, "my-space" ), + TOKEN_ENTRY( 0x104, "memmap" ), + TOKEN_ENTRY( 0x105, "free-virtual" ), + TOKEN_ENTRY( 0x106, ">physical" ), + TOKEN_ENTRY( 0x10f, "my-params" ), + TOKEN_ENTRY( 0x110, "property" ), + TOKEN_ENTRY( 0x111, "encode-int" ), + TOKEN_ENTRY( 0x112, "encode+" ), + TOKEN_ENTRY( 0x113, "encode-phys" ), + TOKEN_ENTRY( 0x114, "encode-string" ), + TOKEN_ENTRY( 0x115, "encode-bytes" ), + TOKEN_ENTRY( 0x116, "reg" ), + TOKEN_ENTRY( 0x117, "intr" ), + TOKEN_ENTRY( 0x118, "driver" ), + TOKEN_ENTRY( 0x119, "model" ), + TOKEN_ENTRY( 0x11a, "device-type" ), + TOKEN_ENTRY( 0x11b, "parse-2int" ), + TOKEN_ENTRY( 0x11c, "is-install" ), + TOKEN_ENTRY( 0x11d, "is-remove" ), + TOKEN_ENTRY( 0x11e, "is-selftest" ), + TOKEN_ENTRY( 0x11f, "new-device" ), + TOKEN_ENTRY( 0x120, "diagnostic-mode?" ), + TOKEN_ENTRY( 0x121, "display-status" ), + TOKEN_ENTRY( 0x122, "memory-test-issue" ), + TOKEN_ENTRY( 0x123, "group-code" ), + TOKEN_ENTRY( 0x124, "mask" ), + TOKEN_ENTRY( 0x125, "get-msecs" ), + TOKEN_ENTRY( 0x126, "ms" ), + TOKEN_ENTRY( 0x127, "finish-device" ), + TOKEN_ENTRY( 0x128, "decode-phys" ), + TOKEN_ENTRY( 0x12b, "interpose" ), + TOKEN_ENTRY( 0x130, "map-low" ), + TOKEN_ENTRY( 0x131, "sbus-intr>cpu" ), + TOKEN_ENTRY( 0x150, "#lines" ), + TOKEN_ENTRY( 0x151, "#columns" ), + TOKEN_ENTRY( 0x152, "line#" ), + TOKEN_ENTRY( 0x153, "column#" ), + TOKEN_ENTRY( 0x154, "inverse?" ), + TOKEN_ENTRY( 0x155, "inverse-screen?" ), + TOKEN_ENTRY( 0x156, "frame-buffer-busy?" ), + TOKEN_ENTRY( 0x157, "draw-character" ), + TOKEN_ENTRY( 0x158, "reset-screen" ), + TOKEN_ENTRY( 0x159, "toggle-cursor" ), + TOKEN_ENTRY( 0x15a, "erase-screen" ), + TOKEN_ENTRY( 0x15b, "blink-screen" ), + TOKEN_ENTRY( 0x15c, "invert-screen" ), + TOKEN_ENTRY( 0x15d, "insert-characters" ), + TOKEN_ENTRY( 0x15e, "delete-characters" ), + TOKEN_ENTRY( 0x15f, "insert-lines" ), + TOKEN_ENTRY( 0x160, "delete-lines" ), + TOKEN_ENTRY( 0x161, "draw-logo" ), + TOKEN_ENTRY( 0x162, "frame-buffer-adr" ), + TOKEN_ENTRY( 0x163, "screen-height" ), + TOKEN_ENTRY( 0x164, "screen-width" ), + TOKEN_ENTRY( 0x165, "window-top" ), + TOKEN_ENTRY( 0x166, "window-left" ), + TOKEN_ENTRY( 0x16a, "default-font" ), + TOKEN_ENTRY( 0x16b, "set-font" ), + TOKEN_ENTRY( 0x16c, "char-height" ), + TOKEN_ENTRY( 0x16d, "char-width" ), + TOKEN_ENTRY( 0x16e, ">font" ), + TOKEN_ENTRY( 0x16f, "fontbytes" ), + TOKEN_ENTRY( 0x170, "fb1-draw-character" ), + TOKEN_ENTRY( 0x171, "fb1-reset-screen" ), + TOKEN_ENTRY( 0x172, "fb1-toggle-cursor" ), + TOKEN_ENTRY( 0x173, "fb1-erase-screen" ), + TOKEN_ENTRY( 0x174, "fb1-blink-screen" ), + TOKEN_ENTRY( 0x175, "fb1-invert-screen" ), + TOKEN_ENTRY( 0x176, "fb1-insert-characters" ), + TOKEN_ENTRY( 0x177, "fb1-delete-characters" ), + TOKEN_ENTRY( 0x178, "fb1-insert-lines" ), + TOKEN_ENTRY( 0x179, "fb1-delete-lines" ), + TOKEN_ENTRY( 0x17a, "fb1-draw-logo" ), + TOKEN_ENTRY( 0x17b, "fb1-install" ), + TOKEN_ENTRY( 0x17c, "fb1-slide-up" ), + TOKEN_ENTRY( 0x180, "fb8-draw-character" ), + TOKEN_ENTRY( 0x181, "fb8-reset-screen" ), + TOKEN_ENTRY( 0x182, "fb8-toggle-cursor" ), + TOKEN_ENTRY( 0x183, "fb8-erase-screen" ), + TOKEN_ENTRY( 0x184, "fb8-blink-screen" ), + TOKEN_ENTRY( 0x185, "fb8-invert-screen" ), + TOKEN_ENTRY( 0x186, "fb8-insert-characters" ), + TOKEN_ENTRY( 0x187, "fb8-delete-characters" ), + TOKEN_ENTRY( 0x188, "fb8-insert-lines" ), + TOKEN_ENTRY( 0x189, "fb8-delete-lines" ), + TOKEN_ENTRY( 0x18a, "fb8-draw-logo" ), + TOKEN_ENTRY( 0x18b, "fb8-install" ), + TOKEN_ENTRY( 0x1a0, "return-buffer" ), + TOKEN_ENTRY( 0x1a1, "xmit-packet" ), + TOKEN_ENTRY( 0x1a2, "poll-packet" ), + TOKEN_ENTRY( 0x1a4, "mac-address" ), + TOKEN_ENTRY( 0x201, "device-name" ), + TOKEN_ENTRY( 0x202, "my-args" ), + TOKEN_ENTRY( 0x203, "my-self" ), + TOKEN_ENTRY( 0x204, "find-package" ), + TOKEN_ENTRY( 0x205, "open-package" ), + TOKEN_ENTRY( 0x206, "close-package" ), + TOKEN_ENTRY( 0x207, "find-method" ), + TOKEN_ENTRY( 0x208, "call-package" ), + TOKEN_ENTRY( 0x209, "$call-parent" ), + TOKEN_ENTRY( 0x20a, "my-parent" ), + TOKEN_ENTRY( 0x20b, "ihandle>phandle" ), + TOKEN_ENTRY( 0x20d, "my-unit" ), + TOKEN_ENTRY( 0x20e, "$call-method" ), + TOKEN_ENTRY( 0x20f, "$open-package" ), + TOKEN_ENTRY( 0x210, "processor-type" ), + TOKEN_ENTRY( 0x211, "firmware-version" ), + TOKEN_ENTRY( 0x212, "fcode-version" ), + TOKEN_ENTRY( 0x213, "alarm" ), + TOKEN_ENTRY( 0x214, "(is-user-word)" ), + TOKEN_ENTRY( 0x215, "suspend-fcode" ), + TOKEN_ENTRY( 0x216, "abort" ), + TOKEN_ENTRY( 0x217, "catch" ), + TOKEN_ENTRY( 0x218, "throw" ), + TOKEN_ENTRY( 0x219, "user-abort" ), + TOKEN_ENTRY( 0x21a, "get-my-property" ), + TOKEN_ENTRY( 0x21b, "decode-int" ), + TOKEN_ENTRY( 0x21c, "decode-string" ), + TOKEN_ENTRY( 0x21d, "get-inherited-property" ), + TOKEN_ENTRY( 0x21e, "delete-property" ), + TOKEN_ENTRY( 0x21f, "get-package-property" ), + TOKEN_ENTRY( 0x220, "cpeek" ), + TOKEN_ENTRY( 0x221, "wpeek" ), + TOKEN_ENTRY( 0x222, "lpeek" ), + TOKEN_ENTRY( 0x223, "cpoke" ), + TOKEN_ENTRY( 0x224, "wpoke" ), + TOKEN_ENTRY( 0x225, "lpoke" ), + TOKEN_ENTRY( 0x226, "lwflip" ), + TOKEN_ENTRY( 0x227, "lbflip" ), + TOKEN_ENTRY( 0x228, "lbflips" ), + TOKEN_ENTRY( 0x229, "adr-mask" ), + TOKEN_ENTRY( 0x230, "rb@" ), + TOKEN_ENTRY( 0x231, "rb!" ), + TOKEN_ENTRY( 0x232, "rw@" ), + TOKEN_ENTRY( 0x233, "rw!" ), + TOKEN_ENTRY( 0x234, "rl@" ), + TOKEN_ENTRY( 0x235, "rl!" ), + TOKEN_ENTRY( 0x236, "wbflips" ), + TOKEN_ENTRY( 0x237, "lwflips" ), + TOKEN_ENTRY( 0x238, "probe" ), + TOKEN_ENTRY( 0x239, "probe-virtual" ), + TOKEN_ENTRY( 0x23b, "child" ), + TOKEN_ENTRY( 0x23c, "peer" ), + TOKEN_ENTRY( 0x23d, "next-property" ), + TOKEN_ENTRY( 0x23e, "byte-load" ), + TOKEN_ENTRY( 0x23f, "set-args" ), + TOKEN_ENTRY( 0x240, "left-parse-string" ), + + /* FCodes from 64bit extension addendum */ + TOKEN_ENTRY( 0x22e, "rx@" ), + TOKEN_ENTRY( 0x22f, "rx!" ), + TOKEN_ENTRY( 0x241, "bxjoin" ), + TOKEN_ENTRY( 0x242, "<l@" ), + TOKEN_ENTRY( 0x243, "lxjoin" ), + TOKEN_ENTRY( 0x244, "wxjoin" ), + TOKEN_ENTRY( 0x245, "x," ), + TOKEN_ENTRY( 0x246, "x@" ), + TOKEN_ENTRY( 0x247, "x!" ), + TOKEN_ENTRY( 0x248, "/x" ), + TOKEN_ENTRY( 0x249, "/x*" ), + TOKEN_ENTRY( 0x24a, "xa+" ), + TOKEN_ENTRY( 0x24b, "xa1+" ), + TOKEN_ENTRY( 0x24c, "xbflip" ), + TOKEN_ENTRY( 0x24d, "xbflips" ), + TOKEN_ENTRY( 0x24e, "xbsplit" ), + TOKEN_ENTRY( 0x24f, "xlflip" ), + TOKEN_ENTRY( 0x250, "xlflips" ), + TOKEN_ENTRY( 0x251, "xlsplit" ), + TOKEN_ENTRY( 0x252, "xwflip" ), + TOKEN_ENTRY( 0x253, "xwflips" ), + TOKEN_ENTRY( 0x254, "xwsplit" ), +}; + +static const int dictionary_indx_max = (sizeof(detok_table)/sizeof(token_t)) ; + +static token_t *dictionary_reset_position; + void init_dictionary(void) { - add_token( 0x000, "end0" ); - add_token( 0x010, "b(lit)" ); - add_token( 0x011, "b(')" ); - add_token( 0x012, "b(")" ); - add_token( 0x013, "bbranch" ); - add_token( 0x014, "b?branch" ); - add_token( 0x015, "b(loop)" ); - add_token( 0x016, "b(+loop)" ); - add_token( 0x017, "b(do)" ); - add_token( 0x018, "b(?do)" ); - add_token( 0x019, "i" ); - add_token( 0x01a, "j" ); - add_token( 0x01b, "b(leave)" ); - add_token( 0x01c, "b(of)" ); - add_token( 0x01d, "execute" ); - add_token( 0x01e, "+" ); - add_token( 0x01f, "-" ); - add_token( 0x020, "*" ); - add_token( 0x021, "/" ); - add_token( 0x022, "mod" ); - add_token( 0x023, "and" ); - add_token( 0x024, "or" ); - add_token( 0x025, "xor" ); - add_token( 0x026, "invert" ); - add_token( 0x027, "lshift" ); - add_token( 0x028, "rshift" ); - add_token( 0x029, ">>a" ); - add_token( 0x02a, "/mod" ); - add_token( 0x02b, "u/mod" ); - add_token( 0x02c, "negate" ); - add_token( 0x02d, "abs" ); - add_token( 0x02e, "min" ); - add_token( 0x02f, "max" ); - add_token( 0x030, ">r" ); - add_token( 0x031, "r>" ); - add_token( 0x032, "r@" ); - add_token( 0x033, "exit" ); - add_token( 0x034, "0=" ); - add_token( 0x035, "0<>" ); - add_token( 0x036, "0<" ); - add_token( 0x037, "0<=" ); - add_token( 0x038, "0>" ); - add_token( 0x039, "0>=" ); - add_token( 0x03a, "<" ); - add_token( 0x03b, ">" ); - add_token( 0x03c, "=" ); - add_token( 0x03d, "<>" ); - add_token( 0x03e, "u>" ); - add_token( 0x03f, "u<=" ); - add_token( 0x040, "u<" ); - add_token( 0x041, "u>=" ); - add_token( 0x042, ">=" ); - add_token( 0x043, "<=" ); - add_token( 0x044, "between" ); - add_token( 0x045, "within" ); - add_token( 0x046, "drop" ); - add_token( 0x047, "dup" ); - add_token( 0x048, "over" ); - add_token( 0x049, "swap" ); - add_token( 0x04A, "rot" ); - add_token( 0x04b, "-rot" ); - add_token( 0x04c, "tuck" ); - add_token( 0x04d, "nip" ); - add_token( 0x04e, "pick" ); - add_token( 0x04f, "roll" ); - add_token( 0x050, "?dup" ); - add_token( 0x051, "depth" ); - add_token( 0x052, "2drop" ); - add_token( 0x053, "2dup" ); - add_token( 0x054, "2over" ); - add_token( 0x055, "2swap" ); - add_token( 0x056, "2rot" ); - add_token( 0x057, "2/" ); - add_token( 0x058, "u2/" ); - add_token( 0x059, "2*" ); - add_token( 0x05a, "/c" ); - add_token( 0x05b, "/w" ); - add_token( 0x05c, "/l" ); - add_token( 0x05d, "/n" ); - add_token( 0x05e, "ca+" ); - add_token( 0x05f, "wa+" ); - add_token( 0x060, "la+" ); - add_token( 0x061, "na+" ); - add_token( 0x062, "char+" ); - add_token( 0x063, "wa1+" ); - add_token( 0x064, "la1+" ); - add_token( 0x065, "cell+" ); - add_token( 0x066, "chars" ); - add_token( 0x067, "/w*" ); - add_token( 0x068, "/l*" ); - add_token( 0x069, "cells" ); - add_token( 0x06a, "on" ); - add_token( 0x06b, "off" ); - add_token( 0x06c, "+!" ); - add_token( 0x06d, "@" ); - add_token( 0x06e, "l@" ); - add_token( 0x06f, "w@" ); - add_token( 0x070, "<w@" ); - add_token( 0x071, "c@" ); - add_token( 0x072, "!" ); - add_token( 0x073, "l!" ); - add_token( 0x074, "w!" ); - add_token( 0x075, "c!" ); - add_token( 0x076, "2@" ); - add_token( 0x077, "2!" ); - add_token( 0x078, "move" ); - add_token( 0x079, "fill" ); - add_token( 0x07a, "comp" ); - add_token( 0x07b, "noop" ); - add_token( 0x07c, "lwsplit" ); - add_token( 0x07d, "wljoin" ); - add_token( 0x07e, "lbsplit" ); - add_token( 0x07f, "bljoin" ); - add_token( 0x080, "wbflip" ); - add_token( 0x081, "upc" ); - add_token( 0x082, "lcc" ); - add_token( 0x083, "pack" ); - add_token( 0x084, "count" ); - add_token( 0x085, "body>" ); - add_token( 0x086, ">body" ); - add_token( 0x087, "fcode-revision" ); - add_token( 0x088, "span" ); - add_token( 0x089, "unloop" ); - add_token( 0x08a, "expect" ); - add_token( 0x08b, "alloc-mem" ); - add_token( 0x08c, "free-mem" ); - add_token( 0x08d, "key?" ); - add_token( 0x08e, "key" ); - add_token( 0x08f, "emit" ); - add_token( 0x090, "type" ); - add_token( 0x091, "(cr" ); - add_token( 0x092, "cr" ); - add_token( 0x093, "#out" ); - add_token( 0x094, "#line" ); - add_token( 0x095, "hold" ); - add_token( 0x096, "<#" ); - add_token( 0x097, "u#>" ); - add_token( 0x098, "sign" ); - add_token( 0x099, "u#" ); - add_token( 0x09a, "u#s" ); - add_token( 0x09b, "u." ); - add_token( 0x09c, "u.r" ); - add_token( 0x09d, "." ); - add_token( 0x09e, ".r" ); - add_token( 0x09f, ".s" ); - add_token( 0x0a0, "base" ); - add_token( 0x0a1, "convert" ); - add_token( 0x0a2, "$number" ); - add_token( 0x0a3, "digit" ); - add_token( 0x0a4, "-1" ); - add_token( 0x0a5, "0" ); - add_token( 0x0a6, "1" ); - add_token( 0x0a7, "2" ); - add_token( 0x0a8, "3" ); - add_token( 0x0a9, "bl" ); - add_token( 0x0aa, "bs" ); - add_token( 0x0ab, "bell" ); - add_token( 0x0ac, "bounds" ); - add_token( 0x0ad, "here" ); - add_token( 0x0ae, "aligned" ); - add_token( 0x0af, "wbsplit" ); - add_token( 0x0b0, "bwjoin" ); - add_token( 0x0b1, "b(<mark)" ); - add_token( 0x0b2, "b(>resolve)" ); - add_token( 0x0b3, "set-token-table" ); - add_token( 0x0b4, "set-table" ); - add_token( 0x0b5, "new-token" ); - add_token( 0x0b6, "named-token" ); - add_token( 0x0b7, "b(:)" ); - add_token( 0x0b8, "b(value)" ); - add_token( 0x0b9, "b(variable)" ); - add_token( 0x0ba, "b(constant)" ); - add_token( 0x0bb, "b(create)" ); - add_token( 0x0bc, "b(defer)" ); - add_token( 0x0bd, "b(buffer:)" ); - add_token( 0x0be, "b(field)" ); - add_token( 0x0bf, "b(code)" ); - add_token( 0x0c0, "instance" ); - add_token( 0x0c2, "b(;)" ); - add_token( 0x0c3, "b(to)" ); - add_token( 0x0c4, "b(case)" ); - add_token( 0x0c5, "b(endcase)" ); - add_token( 0x0c6, "b(endof)" ); - add_token( 0x0c7, "#" ); - add_token( 0x0c8, "#s" ); - add_token( 0x0c9, "#>" ); - add_token( 0x0ca, "external-token" ); - add_token( 0x0cb, "$find" ); - add_token( 0x0cc, "offset16" ); - add_token( 0x0cd, "evaluate" ); - add_token( 0x0d0, "c," ); - add_token( 0x0d1, "w," ); - add_token( 0x0d2, "l," ); - add_token( 0x0d3, "," ); - add_token( 0x0d4, "um*" ); - add_token( 0x0d5, "um/mod" ); - add_token( 0x0d8, "d+" ); - add_token( 0x0d9, "d-" ); - add_token( 0x0da, "get-token" ); - add_token( 0x0db, "set-token" ); - add_token( 0x0dc, "state" ); - add_token( 0x0dd, "compile" ); - add_token( 0x0de, "behavior" ); - add_token( 0x0f0, "start0" ); - add_token( 0x0f1, "start1" ); - add_token( 0x0f2, "start2" ); - add_token( 0x0f3, "start4" ); - add_token( 0x0fc, "ferror" ); - add_token( 0x0fd, "version1" ); - add_token( 0x0fe, "4-byte-id" ); - add_token( 0x0ff, "end1" ); - add_token( 0x101, "dma-alloc" ); - add_token( 0x102, "my-address" ); - add_token( 0x103, "my-space" ); - add_token( 0x104, "memmap" ); - add_token( 0x105, "free-virtual" ); - add_token( 0x106, ">physical" ); - add_token( 0x10f, "my-params" ); - add_token( 0x110, "property" ); - add_token( 0x111, "encode-int" ); - add_token( 0x112, "encode+" ); - add_token( 0x113, "encode-phys" ); - add_token( 0x114, "encode-string" ); - add_token( 0x115, "encode-bytes" ); - add_token( 0x116, "reg" ); - add_token( 0x117, "intr" ); - add_token( 0x118, "driver" ); - add_token( 0x119, "model" ); - add_token( 0x11a, "device-type" ); - add_token( 0x11b, "parse-2int" ); - add_token( 0x11c, "is-install" ); - add_token( 0x11d, "is-remove" ); - add_token( 0x11e, "is-selftest" ); - add_token( 0x11f, "new-device" ); - add_token( 0x120, "diagnostic-mode?" ); - add_token( 0x121, "display-status" ); - add_token( 0x122, "memory-test-issue" ); - add_token( 0x123, "group-code" ); - add_token( 0x124, "mask" ); - add_token( 0x125, "get-msecs" ); - add_token( 0x126, "ms" ); - add_token( 0x127, "finish-device" ); - add_token( 0x128, "decode-phys" ); - add_token( 0x12b, "interpose" ); - add_token( 0x130, "map-low" ); - add_token( 0x131, "sbus-intr>cpu" ); - add_token( 0x150, "#lines" ); - add_token( 0x151, "#columns" ); - add_token( 0x152, "line#" ); - add_token( 0x153, "column#" ); - add_token( 0x154, "inverse?" ); - add_token( 0x155, "inverse-screen?" ); - add_token( 0x156, "frame-buffer-busy?" ); - add_token( 0x157, "draw-character" ); - add_token( 0x158, "reset-screen" ); - add_token( 0x159, "toggle-cursor" ); - add_token( 0x15a, "erase-screen" ); - add_token( 0x15b, "blink-screen" ); - add_token( 0x15c, "invert-screen" ); - add_token( 0x15d, "insert-characters" ); - add_token( 0x15e, "delete-characters" ); - add_token( 0x15f, "insert-lines" ); - add_token( 0x160, "delete-lines" ); - add_token( 0x161, "draw-logo" ); - add_token( 0x162, "frame-buffer-adr" ); - add_token( 0x163, "screen-height" ); - add_token( 0x164, "screen-width" ); - add_token( 0x165, "window-top" ); - add_token( 0x166, "window-left" ); - add_token( 0x16a, "default-font" ); - add_token( 0x16b, "set-font" ); - add_token( 0x16c, "char-height" ); - add_token( 0x16d, "char-width" ); - add_token( 0x16e, ">font" ); - add_token( 0x16f, "fontbytes" ); - add_token( 0x170, "fb1-draw-character" ); - add_token( 0x171, "fb1-reset-screen" ); - add_token( 0x172, "fb1-toggle-cursor" ); - add_token( 0x173, "fb1-erase-screen" ); - add_token( 0x174, "fb1-blink-screen" ); - add_token( 0x175, "fb1-invert-screen" ); - add_token( 0x176, "fb1-insert-characters" ); - add_token( 0x177, "fb1-delete-characters" ); - add_token( 0x178, "fb1-insert-lines" ); - add_token( 0x179, "fb1-delete-lines" ); - add_token( 0x17a, "fb1-draw-logo" ); - add_token( 0x17b, "fb1-install" ); - add_token( 0x17c, "fb1-slide-up" ); - add_token( 0x180, "fb8-draw-character" ); - add_token( 0x181, "fb8-reset-screen" ); - add_token( 0x182, "fb8-toggle-cursor" ); - add_token( 0x183, "fb8-erase-screen" ); - add_token( 0x184, "fb8-blink-screen" ); - add_token( 0x185, "fb8-invert-screen" ); - add_token( 0x186, "fb8-insert-characters" ); - add_token( 0x187, "fb8-delete-characters" ); - add_token( 0x188, "fb8-insert-lines" ); - add_token( 0x189, "fb8-delete-lines" ); - add_token( 0x18a, "fb8-draw-logo" ); - add_token( 0x18b, "fb8-install" ); - add_token( 0x1a0, "return-buffer" ); - add_token( 0x1a1, "xmit-packet" ); - add_token( 0x1a2, "poll-packet" ); - add_token( 0x1a4, "mac-address" ); - add_token( 0x201, "device-name" ); - add_token( 0x202, "my-args" ); - add_token( 0x203, "my-self" ); - add_token( 0x204, "find-package" ); - add_token( 0x205, "open-package" ); - add_token( 0x206, "close-package" ); - add_token( 0x207, "find-method" ); - add_token( 0x208, "call-package" ); - add_token( 0x209, "$call-parent" ); - add_token( 0x20a, "my-package" ); - add_token( 0x20b, "ihandle>phandle" ); - add_token( 0x20d, "my-unit" ); - add_token( 0x20e, "$call-method" ); - add_token( 0x20f, "$open-package" ); - add_token( 0x210, "processor-type" ); - add_token( 0x211, "firmware-version" ); - add_token( 0x212, "fcode-version" ); - add_token( 0x213, "alarm" ); - add_token( 0x214, "(is-user-word)" ); - add_token( 0x215, "suspend-fcode" ); - add_token( 0x216, "abort" ); - add_token( 0x217, "catch" ); - add_token( 0x218, "throw" ); - add_token( 0x219, "user-abort" ); - add_token( 0x21a, "get-my-property" ); - add_token( 0x21b, "decode-int" ); - add_token( 0x21c, "decode-string" ); - add_token( 0x21d, "get-inherited-property" ); - add_token( 0x21e, "delete-property" ); - add_token( 0x21f, "get-package-property" ); - add_token( 0x220, "cpeek" ); - add_token( 0x221, "wpeek" ); - add_token( 0x222, "lpeek" ); - add_token( 0x223, "cpoke" ); - add_token( 0x224, "wpoke" ); - add_token( 0x225, "lpoke" ); - add_token( 0x226, "lwflip" ); - add_token( 0x227, "lbflip" ); - add_token( 0x228, "lbflips" ); - add_token( 0x229, "adr-mask" ); - add_token( 0x230, "rb@" ); - add_token( 0x231, "rb!" ); - add_token( 0x232, "rw@" ); - add_token( 0x233, "rw!" ); - add_token( 0x234, "rl@" ); - add_token( 0x235, "rl!" ); - add_token( 0x236, "wbflips" ); - add_token( 0x237, "lwflips" ); - add_token( 0x238, "probe" ); - add_token( 0x239, "probe-virtual" ); - add_token( 0x23b, "child" ); - add_token( 0x23c, "peer" ); - add_token( 0x23d, "next-property" ); - add_token( 0x23e, "byte-load" ); - add_token( 0x23f, "set-args" ); - add_token( 0x240, "left-parse-string" ); + int indx;
- /* FCodes from 64bit extension addendum */ - add_token( 0x22e, "rx@" ); - add_token( 0x22f, "rx!" ); - add_token( 0x241, "bxjoin" ); - add_token( 0x242, "<l@" ); - add_token( 0x243, "lxjoin" ); - add_token( 0x244, "wxjoin" ); - add_token( 0x245, "x," ); - add_token( 0x246, "x@" ); - add_token( 0x247, "x!" ); - add_token( 0x248, "/x" ); - add_token( 0x249, "/x*" ); - add_token( 0x24a, "xa+" ); - add_token( 0x24b, "xa1+" ); - add_token( 0x24c, "xbflip" ); - add_token( 0x24d, "xbflips" ); - add_token( 0x24e, "xbsplit" ); - add_token( 0x24f, "xlflip" ); - add_token( 0x250, "xlflips" ); - add_token( 0x251, "xlsplit" ); - add_token( 0x252, "xwflip" ); - add_token( 0x253, "xwflips" ); - add_token( 0x254, "xwsplit" ); + dictionary = &detok_table[dictionary_indx_max-1]; + dictionary_reset_position = dictionary; + + for (indx = 1; indx < dictionary_indx_max ; indx++ ) + { + detok_table[indx].next = &detok_table[indx-1]; + } } + +void reset_dictionary(void) +{ + token_t *next_t; + + next_t = dictionary; + while ( next_t != dictionary_reset_position ) + { + next_t = dictionary->next ; + free( dictionary->name ); + free( dictionary ); + dictionary = next_t ; + } +} + +/* If FCodes have been added by User, we need to update reset-position */ +void freeze_dictionary(void) +{ + dictionary_reset_position = dictionary; +}
Added: fcode-utils/detok/pcihdr.c =================================================================== --- fcode-utils/detok/pcihdr.c (rev 0) +++ fcode-utils/detok/pcihdr.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,478 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Support function for de-tokenizer. + * + * Identify and process PCI header at beginning of FCode binary file. + * "Processing" consists of recognizing the PCI Header and Data Structure, + * optionally printing a description thereof, and (mainly) allowing + * the given pointer to be bumped to the start of the actual FCode. + * + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + * Revision History: + * + * Updated Mon, 23 May 2005 by David L. Paktor + * Identify "Not Last" header. + * Updated Thu, 24 Feb 2005 by David L. Paktor + * Per notes after Code Review. + * Updated Fri, 04 Feb 2005 by David L. Paktor + * Updated Wed, 08 Jun 2005 by David L. Paktor + * Added support for multiple-PCI-image files. + * + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Functions Eported: + * handle_pci_header + * Handle all activities connected with presence of + * PCI Header/Data at beginning of FCode file, and + * facilitate "skipping" over to actual FCode data. + * + * handle_pci_filler + * Skip past "filler" between blocks in multi-PCI-image files. + * + * + **************************************************************************** */ + + +/* ************************************************************************** + * + * Still to be done: + * Print (as remarks) full descriptions of headers' fields + * Error check for wrong "Format" + * Skip past non-FCode blocks, thru multiple data-blocks + * Recognize PCI header in unexpected place or out-of-place + * + **************************************************************************** */ + +#include "pcihdr.h" +#include <stdio.h> + +#include "detok.h" + + +/* ************************************************************************** + * + * Global Variables Exported + * pci_image_end Pointer to just after end of current PCI image + * + **************************************************************************** */ + +u8 *pci_image_end = NULL; + +/* ************************************************************************** + * + * Internal Static Variables + * pci_image_len Length (in bytes) of current PCI image + * + **************************************************************************** */ + +static int pci_image_len = 0; + + +/* ************************************************************************** + * + * Function name: is_pci_header ( rom_header_t *pci_rom_hdr ) + * Synopsis: Indicate whether given pointer is pointing to + * something that might be a valid PCI header + * + * Inputs: + * Parameters: + * pci_rom_hdr pointer to start of data-stream to examine. + * Treat as pointer to rom_header_t + * + * Outputs: + * Returned Value: An integer. + * 0 Definitely *NOT* a PCI header + * Positive Number Appears to be a valid PCI header; + * value is offset to PCI Data Structure. + * Negative Number Appears to be a PCI header, but + * with errors. (Not Implemented Yet. + * See under "Still to be done".) + * + * Error Detection: + * (See under "Still to be done".) + * + * Process Explanation: + * Examine "signature" location for known value 0x55aa + * If a match, return value of "dptr" (Data-pointer offset) field. + * + * Revision History: + * Created Tue, 01 Feb 2005 by David L. Paktor + * + * Still to be done: + * Error-check; look for inconsistencies: + * Return a Negative Number if data-stream appears to be a PCI + * header, but has erroneous or inconsistent sub-field contents. + * Value and meaning of the Negative Number yet to be defined. + * + **************************************************************************** */ + +static int is_pci_header ( rom_header_t *pci_rom_hdr ) +{ + const u16 pci_header_signature = 0x55aa; + int retval ; + + retval = 0; + + if ( BIG_ENDIAN_WORD_FETCH(pci_rom_hdr->signature) == pci_header_signature ) + { + retval = LITTLE_ENDIAN_WORD_FETCH(pci_rom_hdr->data_ptr); + } + return(retval); +} + +/* ************************************************************************** + * + * Function name: is_pci_data_struct ( pci_data_t *pci_data_ptr ) + * Synopsis: Indicate whether given pointer is pointing to + * a valid PCI Data Structure + * + * Inputs: + * Parameters: + * pci_data_ptr pointer to start of data-stream to examine. + * Treat as pointer to pci_data_t + * + * Outputs: + * Returned Value: An integer. + * 0 Definitely *NOT* a PCI Data Structure + * Positive Number Appears to be valid PCI Data Structure; + * value is length of PCI Data Structure, + * (presumably, offset to start of FCode). + * Negative Number Appears to be a PCI Data Structure, + * but with errors. (Not Implemented Yet. + * See under "Still to be done".) + * + * Global/Static Variables: + * Does not alter the poiner passed-in; + * does not alter any Global/Static Variables + * Printout: NONE + * + * Error Detection: (Condition) (Action) + * (See under "Still to be done".) + * + * Process Explanation: + * Examine "signature" location for known value "PCIR" + * If a match, return value of "dlen" (Data Structure Length) field. + * + * Revision History: + * Created Tue, 01 Feb 2005 by David L. Paktor + * + * Still to be done: + * Error-check; look for wrong "Code Type" or other inconsistencies: + * Return a Negative Number if data-stream appears to be a + * valid PCI Data Structure, but has erroneous or inconsistent + * sub-field contents. + * Value and meaning of the Negative Number yet to be defined. + * Skip past non-FCode data-blocks, even multiple blocks + * + **************************************************************************** */ + +static int is_pci_data_struct ( pci_data_t *pci_data_ptr ) +{ + int retval ; + + retval = 0; + + if (BIG_ENDIAN_LONG_FETCH(pci_data_ptr->signature) == PCI_DATA_HDR) + { + retval = LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->dlen); + } + return(retval); +} + + +/* ************************************************************************** + * + * Function name: announce_pci_hdr ( rom_header_t *pci_rom_hdr ) + * Synopsis: Print indication that the PCI header was found, + * and other details, formatted as FORTH remarks. + * + * Inputs: + * Parameters: + * pci_rom_hdr Pointer to start of PCI header. + * + * Outputs: + * Returned Value: NONE + * Printout: Announcement. Size of data_ptr field. + * + **************************************************************************** */ + +static void announce_pci_hdr ( rom_header_t *pci_rom_hdr ) +{ + char temp_buf[80]; + u32 temp; + + printremark ( "PCI Header identified"); + temp=(u32)LITTLE_ENDIAN_WORD_FETCH(pci_rom_hdr->data_ptr); + sprintf(temp_buf, " Offset to Data Structure = 0x%04x (%d)\n", + temp, temp); + printremark ( temp_buf ); +} + +/* ************************************************************************** + * + * Function name: announce_pci_data_struct ( pci_data_t *pci_data_ptr ) + * Synopsis: Print indication that the PCI Data Structure + * was found, and some additional details. + * Format as FORTH remarks. + * + * Inputs: + * Parameters: + * pci_data_ptr Pointer to start of PCI Data Structure. + * + * Outputs: + * Returned Value: NONE + * Global/Static Variables: + * pci_image_len Updated to byte-length of current PCI image + * Printout: (See Synopsis) + * + * Process Explanation: + * Extract some details, format and print them, + * using the syntax of FORTH remarks. + * + * Revision History: + * Created Tue, 01 Feb 2005 by David L. Paktor + * Updated Wed, 25 May 2005 by David L. Paktor + * Added printout of several fields... + * + **************************************************************************** */ + +static void announce_pci_data_struct ( pci_data_t *pci_data_ptr ) +{ + char temp_buf[80]; + u32 temp; + + printremark ( "PCI Data Structure identified"); + + temp=(u32)LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->dlen); + sprintf(temp_buf, " Data Structure Length = 0x%04x (%d)\n", temp, temp); + printremark ( temp_buf ); + + sprintf(temp_buf, " Vendor ID: 0x%04x\n", + LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->vendor)); + printremark ( temp_buf ); + + sprintf(temp_buf, " Device ID: 0x%04x\n", + LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->device)); + printremark ( temp_buf ); + + temp=(u32)CLASS_CODE_FETCH(pci_data_ptr->class_code); + sprintf(temp_buf, " Class Code: 0x%06x (%s)", + temp, pci_device_class_name(temp)); + printremark ( temp_buf ); + + temp=(u32)LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->vpd); + if ( temp != 0 ) + { + sprintf(temp_buf, " Vital Prod Data: 0x%02x\n", temp); + printremark ( temp_buf ); + } + + temp=(u32)LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->irevision); + if ( temp != 0 ) + { + sprintf(temp_buf, " Image Revision: 0x%02x\n", temp); + printremark ( temp_buf ); + } + + sprintf(temp_buf, " Code Type: 0x%02x (%s)\n", pci_data_ptr->code_type, + pci_code_type_name(pci_data_ptr->code_type) ); + printremark ( temp_buf ); + + temp=(u32)LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->ilen); + pci_image_len = temp*512; + sprintf(temp_buf, " Image Length: 0x%04x blocks (%d bytes)\n", + temp, pci_image_len); + printremark ( temp_buf ); + + sprintf(temp_buf, " %sast PCI Image.\n", + pci_data_ptr->last_image_flag&&0x80 != 0 ? "L" : "Not l"); + printremark ( temp_buf ); + +} + + +/* ************************************************************************** + * + * Function name: handle_pci_header + * Synopsis: Handle PCI Header/Data at beginning of FCode file; + * facilitate "skipping" over to actual FCode data. + * + * Inputs: + * Parameters: + * data_ptr Pointer to start of data-stream to examine. + * Global/Static Variables: + * pci_image_len Length (in bytes) of current PCI image + * + * Outputs: + * Returned Value: + * Positive Number. Offset to start of FCode. + * Zero If no PCI header; may be treated as + * a valid offset. + * Negative Number PCI header or PCI Data Structure test + * returned error indication. + * (Not Implemented Yet. See + * under "Still to be done".) + * Global/Static Variables: + * pci_image_end Pointer to just after the end of + * the current PCI image + * Printout: As FORTH remarks, print indications that the + * PCI header was found, and maybe later more data. + * + * Error Detection: (Condition) (Action) + * (See under "Still to be done".) + * + * Process Explanation: + * Use the various support routines defined below. + * + * + * Revision History: + * + * Updated Wed, 09 Feb 2005 by David L. Paktor + * Extracted assignments from within if( ) statements. + * + * Created Tue, 01 Feb 2005 by David L. Paktor + * + * Still to be done: + * Handle error cases. At present, neither is_pci_header() + * nor is_pci_data_struct() returns a negative number, + * but when they are modified to do so, we must handle it. + * + **************************************************************************** */ + +int handle_pci_header ( u8 *data_ptr ) +{ + int hdrlen; + int data_struc_len; + /* int retval; */ /* Not needed until we handle error cases... */ + + data_struc_len = 0; + + hdrlen = is_pci_header( (rom_header_t *)data_ptr ); + /* retval = hdrlen; */ /* Not needed yet... */ + if ( hdrlen < 0 ) + { + /* Handle error case... */ + /* Leave null for now... */ + /* It might need to do a premature EXIT here... */ + } else { + /* if hdrlen == 0 then we don't need to check a Data Structure */ + if ( hdrlen > 0 ) + { + announce_pci_hdr ( (rom_header_t *)data_ptr ); + data_struc_len = is_pci_data_struct( + (pci_data_t *) &data_ptr[hdrlen] ); + /* + * A Data Structure Length of Zero would be an error + * that could be detected by is_pci_data_struct() + */ + if ( data_struc_len <= 0 ) + { + /* Handle error case... */ + /* Leave null for now... */ + /* It might need to do a premature EXIT here... */ + /* retval = -1; */ /* Not needed yet... */ + } else { + announce_pci_data_struct ( (pci_data_t *) &data_ptr[hdrlen] ); + pci_image_end = data_ptr + pci_image_len; + /* retval = hdrlen+data_struc_len; */ /* Not needed yet... */ + } + } + } + return (hdrlen+data_struc_len); +} + + +/* ************************************************************************** + * + * Function name: handle_pci_filler + * Synopsis: Examine and report on the "filler" padding after the + * end of an FCode-block but still within a PCI-image + * + * Inputs: + * Parameters: + * filler_ptr Pointer to start of PCI-filler in data-stream + * Global/Static Variables: + * pci_image_end Pointer to just after the end of + * the current PCI image + * + * Outputs: + * Returned Value: NONE + * Printout: + * Descriptive message. + * + * Error Detection: + * Non-zero filler field. Different message. + * + * Process Explanation: + * The calling routine has checked that there was, indeed, a PCI + * header present, so we know that pci_image_end is valid. + * If the entire filler is zero-bytes, print a simple message and + * we're out'a here! + * If there are non-zero bytes, identify loc'n of first non-zero. + * + * Still to be done: + * Come up with something more elegant for non-zero filler. + * + **************************************************************************** */ + +void handle_pci_filler(u8 *filler_ptr) +{ + u8 *scan_ptr; + int filler_len; + char temp_buf[80]; + bool all_zero = TRUE; + u8 filler_byte = *filler_ptr; + + filler_len = pci_image_end - filler_ptr; + + for ( scan_ptr = filler_ptr; + scan_ptr < pci_image_end; + filler_byte = *(++scan_ptr) ) + { + if ( filler_byte != 0 ) + { + all_zero = FALSE; + break; + } + } + + if ( all_zero ) + { + sprintf(temp_buf, "PCI Image padded with %d bytes of zero", filler_len); + }else{ + sprintf(temp_buf, "PCI Image padding-field of %d bytes " + "had first non-zero byte at offset %ld", + filler_len, scan_ptr - filler_ptr ); + } + printremark ( temp_buf ); +}
Added: fcode-utils/detok/printformats.c =================================================================== --- fcode-utils/detok/printformats.c (rev 0) +++ fcode-utils/detok/printformats.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,140 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Print, in various controlled formats, for the detokenizer. + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Ultimately, our goal is to produce output that can be run back + * through the tokenizer and produce the same binary. So, any + * extra text will have to be in a form that the tokenizer will + * treat as comments. + * + **************************************************************************** */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "detok.h" + + +/* ************************************************************************** + * + * Function name: printremark ( string ) + * Synopsis: Print the given string as a series of "Remark" lines, + * (i.e., preceded by backslash-space) + * + * Inputs: + * Parameters: + * str Pointer to the start of the string, + * however long it may be. The string + * may have any number of embedded new-lines. + * + * Outputs: + * Returned Value: *** NONE*** + * Printout: Each line of the string will be preceded by + * a backslash and two spaces. Backslash-space + * is the standard delimiter for a "remark", i.e. + * the entire line is ignored as a comment. The + * second space is "just" for aesthetics. + * + * Process Explanation: + * Parse the input string for new-lines. Print each separately. + * Do not alter the input string. + * + * + * Still to be done: + * Define a routine, call it PrintComment , to print the given + * string surrounded by open-paren-space ... space-close-paren + * Define a single central routine, call it safe_malloc , + * to do the test for null and print "No Memory" and exit. + * Define a single central routine, call it PrintError , to: + * Print the given error message + * Show the input file and line number + * Collect error-flags for failure-exit at end of operation. + * + **************************************************************************** */ + +void printremark ( char *str) +{ + char *strtmp ; /* Temporary pointer to current substring */ + int substrlen ; /* Length of current substring */ + char *substrend ; /* Pointer to end of current substring */ + char *strend ; /* Pointer to end of given string */ + + char *strbfr ; /* Temporary substring buffer */ + + /* Guarantee that the malloc will be big enough. */ + strbfr = (char *)malloc(strlen((char *)str)+1); + if ( !strbfr ) + { + printf ("No memory.\n"); + exit(-1); + } + + + strtmp = str; + strend = &str[strlen(str)]; + + /* ****************************************************************** + * + * Isolate the current substring; allow that the given + * string might not be terminated with a new-line. + * + * The strend pointer provides a convenient means to + * test for when we've reached the end. + * + ******************************************************************** */ + + while ( strtmp < strend ) + { + substrend = strchr(strtmp , '\n'); + substrlen = ( substrend ? (substrend-strtmp) : strlen(strtmp) ); + + strncpy (strbfr, strtmp, substrlen); + /* ********************************************************** + * + * strncpy() does not append a terminating null character, + * so we have to. + * + ************************************************************ */ + strbfr[substrlen] = (char)0; + + printf("\ %s\n",strbfr); + + strtmp = &strtmp[ substrlen + ( substrend ? 1 : 0 ) ] ; + + } + + free(strbfr) ; +} +
Modified: fcode-utils/detok/stream.c =================================================================== --- fcode-utils/detok/stream.c 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/detok/stream.c 2006-08-18 12:47:12 UTC (rev 76) @@ -24,20 +24,60 @@ * */
+/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/stat.h> +#include <setjmp.h>
+#include "stream.h" #include "detok.h" +#include "pcihdr.h"
-extern bool offs16; -extern u32 fcpos; +extern jmp_buf eof_exception;
+/* ************************************************************************** + * + * Global Variables Exported: + * Name Value + * fcode The FCode-token last read. Not necessarily the byte + * last read, if its function has in-line parameters + * stream_max The maximum position -- length -- of the input stream + * pc Pointer to "Current byte" in the input-data image. + * max Just after the end of the input-data image. + * This is *NOT* a byte-count. + * + **************************************************************************** */ + u16 fcode; -u8 inbyte; +unsigned int stream_max; +u8 *pc; +u8 *max;
-static u8 *indata, *pc, *max; +/* ************************************************************************** + * + * Local/Static Variables: + * Name Pointer to: + * indata Start of input-data image taken from input file. + * This memory was "malloc"ed; keep it around + * for when we "free" that memory. + * fc_start Start of the FCode. This might not be the same + * as the start of the input file data, especially + * if the input file data starts with a PCI header. + * pci_image_found TRUE iff a valid PCI header was found + * + **************************************************************************** */ +u8 *indata; +static u8 *fc_start; +static bool pci_image_found = FALSE;
+ int init_stream(char *name) { FILE *infile; @@ -62,119 +102,455 @@ fclose(infile);
pc=indata; + fc_start = indata; max=pc+finfo.st_size; + stream_max = finfo.st_size; + return 0; }
-int close_stream(void) +/* ************************************************************************** + * + * Function name: init_fcode_block + * Synopsis: Initialize all pointers and variables, etcetera, + * for an FCode-block. + * + **************************************************************************** */ + +void init_fcode_block(void) { + fc_start = pc; + linenum = 1 ; +} + + +void close_stream(void) +{ free(indata); - return 0; + stream_max = 0; }
int get_streampos(void) { - return (int)((long)pc-(long)indata); + return (int)( pc - fc_start ); }
-void set_streampos(long pos) +void set_streampos(int pos) { - pc=indata+pos; + pc = fc_start + pos; }
-static int get_byte(void) + +/* ************************************************************************** + * + * Function name: throw_eof + * Synopsis: Analyze and print the cause of the end-of-file + * and throw an exception. + * + * Inputs: + * Parameters: + * premature TRUE iff end-of-file was out-of-sync + * Global/Static Variables: + * end_found Indicates if normal end of fcode was read. + * eof_exception Long-Jump environment to which to jump. + * + * Outputs: Does a Long-Jump + * Returned Value: NONE + * Printout: + * "End-of-file" message, along with a descriptor, if applicable: + * Premature, Unexpected. + * The calling routine notifies us if the number of bytes requested + * overflowed the input buffer, by passing us a TRUE for the + * input parameter. That is a "Premature" end-of-file. + * If end_found is FALSE, it means the normal end of FCode + * wasn't seen. That is an "Unexpected" end-of-file. + * + **************************************************************************** */ + +static void throw_eof(bool premature) { - inbyte=*pc; - pc++; + char yoo = 'U'; + char eee = 'E'; + if ( premature) + { + printf("Premature "); + yoo = 'u'; + eee = 'e'; + } + if ( ! end_found ) + { + printf("%cnexpected ",yoo); + eee = 'e'; + } + printf("%cnd of file.\n",eee); + longjmp(eof_exception, -1); +} - if (pc>max) { - printf ("\nUnexpected end of file.\n"); - return 0; +/* ************************************************************************** + * + * Function name: get_bytes + * Synopsis: Return the next string of bytes, as requested, from + * the FCode input-stream. Detect end-of-file + * + * Inputs: + * Parameters: + * nbytes The number of bytes requested + * Global/Static Variables: + * pc Pointer to "where we are" in the FCode + * max Pointer to just after end of input file data. + * + * Outputs: + * Returned Value: + * Pointer to the requested bytes in the FCode input-stream. + * Global/Static Variables: + * pc Incremented by the number of bytes requested + * + * Exception: + * When end-of-file is reached, or is about to be exceeded, + * throw an end-of-file exception. + * + * Process Explanation: + * End-of-file is not exactly an error, so its detection is more + * a part of normal processing. + * If we entered this routine with PC pointing exactly at MAX, + * we are probably at the end the way we expect to be, so we + * call our EOF-handling routine with a "non-premature" flag. + * If the requested number of bytes puts us just even with MAX, + * we have neither reached nor over-run the input stream, so + * there's no call to our EOF-handling routine needed at all. + * Only if the requested number of bytes puts us past MAX have we + * over-run our input stream with a "premature" condition. + * + * Extraneous Remarks: + * This is another one where it was easier to write the code + * than the explanation ... ;-} + * + **************************************************************************** */ + +static u8 *get_bytes(int nbytes) +{ + u8 *retval = pc; + if ( pc == max ) + { + throw_eof(FALSE); + } + if ( pc + nbytes > max ) + { + throw_eof(TRUE); + } + pc += nbytes; + return( retval); }
- return 1; + +/* ************************************************************************** + * + * Function name: more_to_go + * Synopsis: Return FALSE when the last byte has been + * read from the input-stream. + * + **************************************************************************** */ + +bool more_to_go(void) +{ + bool retval; + retval = INVERSE( pc == max ); + return( retval); }
-u16 get_token(void) + +/* ************************************************************************** + * + * Function name: next_token + * Synopsis: Retrieve the next FCode-token from the input-stream. + * + * Inputs: + * Parameters: NONE + * + * Outputs: + * Returned Value: The next FCode-token + * Global/Static Variables: + * fcode The FCode-token last read. + * token_streampos Streampos() of token just gotten + * + **************************************************************************** */ + +u16 next_token(void) { u16 tok; - get_byte(); - tok=inbyte; - if (tok != 0x00 && tok < 0x10) { - get_byte(); + token_streampos = get_streampos(); + tok = *(get_bytes(1)); + if ( tok != 0x00 && tok < 0x10) + { tok<<=8; - tok|=inbyte; + tok |= *(get_bytes(1)); } fcode=tok; - return tok; + return(tok); }
u32 get_num32(void) { - u32 ret; + u32 retval; + u8 *num_str;
- get_byte(); - ret=inbyte<<24; - get_byte(); - ret|=(inbyte<<16); - get_byte(); - ret|=(inbyte<<8); - get_byte(); - ret|=inbyte; + num_str = get_bytes(4); + retval = BIG_ENDIAN_LONG_FETCH(num_str);
- return ret; + return ( retval); }
u16 get_num16(void) { - u16 ret; + u16 retval; + u8 *num_str;
- get_byte(); - ret=inbyte<<8; - get_byte(); - ret|=inbyte; + num_str = get_bytes(2); + retval = BIG_ENDIAN_WORD_FETCH(num_str);
- return ret; + return ( retval); }
u8 get_num8(void) { - get_byte(); + u8 inbyte; + + inbyte = *(get_bytes(1)); return(inbyte); }
-u16 get_offset(void) +s16 get_offset(void) { + s16 retval; if (offs16) - return (get_num16()); + { + retval = (s16)get_num16(); + }else{ + retval = (s16)get_num8(); + /* Make sure it's sign-extended */ + retval |= ( retval & 0x80 ) ? 0xff00 : 0 ; + }
- return (get_num8()); + return (retval); }
+/* ************************************************************************** + * + * Function name: get_string + * Synopsis: Return a pointer to a Forth-Style string within the + * input stream. Note: this cannot be used to create + * a new token-name; use get_name() for that. + * + * Inputs: + * Parameters: + * *len Pointer to where the length will go + * + * Outputs: + * Returned Value: + * Pointer to the string within the input stream. + * Supplied Pointers: + * *len Length of the string + * + * Process Explanation: + * Get one byte representing the length of the FORTH-style string. + * Get as many bytes as the length indicates. + * That's the string. The pointer returned by get_bytes() is + * our return value. + * + **************************************************************************** */
-int scnt=0; -u8 *get_string(void) +u8 *get_string(u8 *len) { - u8 *data; - u8 size; - unsigned int i; + char *retval; + + *len = get_num8(); + retval = get_bytes((int)*len);
- get_byte(); - size=inbyte; + return (retval); +}
- scnt++;
- data=malloc(size+2); - if (!data) printf ("No more memory.\n"); - data[0]=size; +/* ************************************************************************** + * + * Function name: get_name + * Synopsis: Retrieve a copy of the next string in the input-stream + * when it is expected to be a new function-name. + * + * Inputs: + * Parameters: + * *len Pointer to where the length will go + * Global/Static Variables: + * pc "Where we are" in the file-stream + * + * Outputs: + * Returned Value: + * Pointer to allocated memory containing a copy of the string + * Supplied Pointers: + * *len Length of the name + * Memory Allocated + * Memory for the copy of the string is allocated by strdup() + * When Freed? + * Never. Retained for duration of the program. + * + * Process Explanation: + * Get the FORTH-style string. + * At this point, PC points to the byte that follows the string; + * we are going to save that byte and replace it with a zero, + * thus creating a C-style string. + * We will pass that C-style string as an argument to strdup() , + * which will give us our return value. + * Then, of course, we restore the byte we so rudely zeroed, and + * proceed merrily on our way. + * + **************************************************************************** */ + +char *get_name(u8 *len) +{ + char *str_start; + char *retval; + u8 sav_byt;
- for (i=1; i<size+1; i++) { - get_byte(); - data[i]=inbyte; + str_start = get_string( len ); + + sav_byt = *pc; + *pc = 0; + + retval = strdup(str_start); + *pc = sav_byt; + + return (retval); } - data[i]=0; - return data;
+/* ************************************************************************** + * + * Function name: calc_checksum + * Synopsis: Calculate the checksum. + * Leave the input position unchanged. + * + * Inputs: + * Parameters: NONE + * Global/Static Variables: + * pc Pointer to "where we are" in the file-stream + * + * Outputs: + * Returned Value: Calculated checksum. + * Global/Static Variables: + * pc Reset to value upon entry + * + * Process Explanation: + * When this routine is entered, the PC is presumed to be pointing + * just after the stored checksum, and just before the length + * field in the FCode header. This is the point at which we + * will preserve the PC + * Extract the length from the FCode header. It includes the eight + * bytes of the FCode header, so we will need to adjust for that. + * The first byte after the FCode header is where the checksum + * calculation begins. + * + **************************************************************************** */ + +u16 calc_checksum(void) +{ + u16 retval = 0; + u8 *cksmptr; + u8 *save_pc; + u32 fc_blk_len; + int indx; + + save_pc = pc; + + fc_blk_len = get_num32(); /* Read len */ + cksmptr = get_bytes(fc_blk_len-8); /* Make sure we have all our data */ + + for ( indx = 8; indx < fc_blk_len; indx++) + { + retval += *cksmptr++; }
+ pc = save_pc; + return( retval); +} + + +/* ************************************************************************** + * + * Function name: adjust_for_pci_header + * Synopsis: Skip the PCI Header. Adjust the pointer to + * the start of FCode in the file-stream, + * and our pointer to "where we are" in the FCode, + * by the size of the PCI header. + * + * Inputs: + * Parameters: NONE + * Global/Static Variables: (Pointer to:) + * pc "where we are" in the file-stream + * fc_start start of FCode in the file-stream + * + * Outputs: + * Returned Value: NONE + * Global/Static Variables: + * pc Advanced past PCI header + * fc_start Likewise. + * pci_image_found Set or cleared as appropriate. + * last_defined_token Re-initialized + * + * Process Explanation: + * Call handle_pci_header to get the size of the PCI header, + * if any, and increment pc and fc_start by the number + * of bytes it returns; also, set pci_image_found based + * on whether the "size of the PCI header" was non-zero. + * (Re-)Initialize overlap detection here. Images with multiple + * PCI blocks can safely re-cycle FCode numbers; this is + * not necessarily true of multiple FCode blocks within + * the same PCI block... + * + **************************************************************************** */ + +void adjust_for_pci_header(void) +{ + int pci_header_size; + + pci_header_size = handle_pci_header(pc); + pci_image_found = pci_header_size > 0 ? TRUE : FALSE; + pc += pci_header_size; + fc_start += pci_header_size; + last_defined_token = 0; +} + +/* ************************************************************************** + * + * Function name: adjust_for_pci_filler + * Synopsis: Dispatch call to pci-filler-handler + * + * Inputs: + * Parameters: NONE + * Global/Static Variables: + * pci_image_found Whether to proceed... + * pci_image_end Pointer to just after the end of + * the current PCI image + * + * Outputs: + * Returned Value: NONE + * Global/Static Variables: + * pci_image_found Reset to FALSE + * + * Error Detection: + * Confirm that the data-stream has the complete filler, + * via a call to get_bytes() + * + **************************************************************************** */ + +void adjust_for_pci_filler(void) +{ + if ( pci_image_found ) + { + int pci_filler_len; + u8 *pci_filler_ptr; + + pci_filler_len = pci_image_end - pc; + pci_filler_ptr = get_bytes(pci_filler_len); + handle_pci_filler( pci_filler_ptr ); + pci_image_found = FALSE; + } +}
Modified: fcode-utils/detok/stream.h =================================================================== --- fcode-utils/detok/stream.h 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/detok/stream.h 2006-08-18 12:47:12 UTC (rev 76) @@ -1,3 +1,6 @@ +#ifndef _UTILS_DETOK_STREAM_H +#define _UTILS_DETOK_STREAM_H + /* * OpenBIOS - free your system! * ( detokenizer ) @@ -24,16 +27,42 @@ * */
+/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + +#include "types.h" + +/* Prototypes for functions exported from stream.c */ + + int init_stream(char *name); -int close_stream(void); +void close_stream(void); +bool more_to_go(void);
+void adjust_for_pci_header(void); +void adjust_for_pci_filler(void); +void init_fcode_block(void); + int get_streampos(void); -void set_streampos(long pos); +void set_streampos(int pos);
-u16 get_token(void); +u16 next_token(void); u8 get_num8(void); u16 get_num16(void); u32 get_num32(void); -u16 get_offset(void); -u8 *get_string(void); +s16 get_offset(void); +u8 *get_string(u8 *len); +char *get_name(u8 *len); +u16 calc_checksum(void);
+/* External declarations for variables defined in stream.c */ + +extern unsigned int stream_max; +extern u8 *indata; +extern u8 *pc; +extern u8 *max; + +#endif /* _UTILS_DETOK_STREAM_H */
Modified: fcode-utils/romheaders/Makefile =================================================================== --- fcode-utils/romheaders/Makefile 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/romheaders/Makefile 2006-08-18 12:47:12 UTC (rev 76) @@ -21,20 +21,21 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA #
- CC = gcc -CFLAGS= -O2 -Wall -W -ansi +CFLAGS= -O2 -Wall -W -ansi -I../shared
-.SUFFIXES: .c .o +SOURCES = romheaders.c ../shared/classcodes.c
+.SUFFIXES: .c + all: romheaders
-romheaders: romheaders.o - $(CC) $(CFLAGS) romheaders.o -o romheaders +romheaders: $(SOURCES) + $(CC) $(CFLAGS) $(SOURCES) -o $@ strip romheaders clean: - rm -f *.o + rm -f *~
distclean: clean rm -f romheaders
Modified: fcode-utils/romheaders/romheaders.c =================================================================== --- fcode-utils/romheaders/romheaders.c 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/romheaders/romheaders.c 2006-08-18 12:47:12 UTC (rev 76) @@ -23,6 +23,11 @@ * */
+/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */
#include <stdio.h> #include <stdlib.h> @@ -30,60 +35,32 @@ #include <sys/stat.h> #include <unistd.h>
-#define u8 unsigned char -#define u16 unsigned short -#define u32 unsigned int +#include "pcihdr.h"
-#define PCI_DATA_HDR (u32) ( ('R' << 24) | ('I' << 16) | ('C' << 8) | 'P' ) - -typedef struct { - u16 signature; - u8 reserved[0x16]; - u16 dptr; -} rom_header_t; - -typedef struct { - u32 signature; - u16 vendor; - u16 device; - u16 reserved_1; - u16 dlen; - u8 drevision; - u8 class_hi; - u16 class_lo; - u16 ilen; - u16 irevision; - u8 type; - u8 indicator; - u16 reserved_2; -} pci_data_t; - char *rom=NULL; size_t romlen=0;
-/* make this endian safe without fancy system headers */ -static u16 little_word(u16 val) -{ - u8 *ptr=(u8 *)&val; - return (ptr[0]|(ptr[1]<<8)); -} +/* Prototypes for functions exported from shared/classcodes.c */
-static u16 little_dword(u16 val) -{ - u8 *ptr=(u8 *)&val; - return (ptr[0]|(ptr[1]<<8)|(ptr[2]<<16)|(ptr[3]<<24)); -} +char *pci_device_class_name(u32 code); +char *pci_code_type_name(unsigned char code);
-/* dump the rom headers */ +/* Functions local to this file: + int dump_rom_header(rom_header_t *data); + int dump_pci_data(pci_data_t *data); + void dump_platform_extensions(u8 type, rom_header_t *data); + */ + static int dump_rom_header(rom_header_t *data) -{ - u16 sig=little_word(data->signature); +{ /* Return TRUE for "no problem" */ + const u16 pci_header_signature = 0x55aa; + u16 sig=BIG_ENDIAN_WORD_FETCH(data->signature); int i; printf ("PCI Expansion ROM Header:\n"); - printf (" Signature: 0x%02x%02x (%s)\n", - sig&0xff,sig>>8,sig==0xaa55?"Ok":"Not Ok"); + printf (" Signature: 0x%04x (%s)\n", + sig, sig == pci_header_signature ? "Ok":"Not Ok"); printf (" CPU unique data:"); for (i=0;i<16;i++) { @@ -92,97 +69,41 @@ } printf ("\n Pointer to PCI Data Structure: 0x%04x\n\n", - little_word(data->dptr)); + LITTLE_ENDIAN_WORD_FETCH(data->data_ptr));
- return (sig==0xaa55); + return (sig == pci_header_signature); }
static int dump_pci_data(pci_data_t *data) -{ - u32 sig=little_dword(data->signature); - u32 classcode=(data->class_hi<<16)|(little_word(data->class_lo)); +{ /* Return TRUE for "no problem" */ + const u32 pci_data_hdr = PCI_DATA_HDR ; + + u32 sig = BIG_ENDIAN_LONG_FETCH(data->signature); + u32 classcode= CLASS_CODE_FETCH(data->class_code); + u32 dlen = (u32)LITTLE_ENDIAN_WORD_FETCH(data->dlen); + u32 ilen = (u32)LITTLE_ENDIAN_WORD_FETCH(data->ilen); printf("PCI Data Structure:\n"); - printf(" Signature: '%c%c%c%c' (%s)\n", sig&0xff,(sig>>8)&0xff, - (sig>>16)&0xff, sig>>24, sig==PCI_DATA_HDR?"Ok":"Not Ok"); - printf(" Vendor ID: 0x%04x\n", little_word(data->vendor)); - printf(" Device ID: 0x%04x\n", little_word(data->device)); - printf(" Reserved: 0x%04x\n", little_word(data->reserved_1)); - printf(" PCI Data Structure Length: 0x%04x (%d bytes)\n", - little_word(data->dlen), little_word(data->dlen)); + printf(" Signature: 0x%04x '%c%c%c%c' ", sig, + sig>>24,(sig>>16)&0xff, (sig>>8)&0xff, sig&0xff); + printf("(%s)\n", sig == pci_data_hdr ?"Ok":"Not Ok"); + + printf(" Vendor ID: 0x%04x\n", LITTLE_ENDIAN_WORD_FETCH(data->vendor)); + printf(" Device ID: 0x%04x\n", LITTLE_ENDIAN_WORD_FETCH(data->device)); + printf(" Vital Product Data: 0x%04x\n", + LITTLE_ENDIAN_WORD_FETCH(data->vpd)); + printf(" PCI Data Structure Length: 0x%04x (%d bytes)\n", dlen, dlen); printf(" PCI Data Structure Revision: 0x%02x\n", data->drevision); - printf(" Class Code: 0x%06x (",classcode); - switch (classcode) { - case 0x0100: - printf("SCSI Storage"); - break; - case 0x0101: - printf("IDE Storage"); - break; - case 0x0103: - printf("IPI Storage"); - break; - case 0x0104: - printf("RAID Storage"); - break; - case 0x0180: - printf("Storage"); - break; - - case 0x0200: - printf("Ethernet"); - break; - case 0x0201: - printf("Token Ring"); - break; - case 0x0202: - printf("FDDI"); - break; - case 0x0203: - printf("ATM"); - break; - case 0x0280: - printf("Network"); - - case 0x0300: - printf("VGA Display"); - break; - case 0x0301: - printf("XGA Display"); - break; - case 0x0302: - printf("3D Display"); - break; - case 0x0380: - printf("Display"); - break; - - default: - printf("unkown"); - } - printf(")\n Image Length: 0x%04x blocks (%d bytes)\n", - little_word(data->ilen), little_word(data->ilen)*512); + printf(" Class Code: 0x%06x (%s)\n",classcode, + pci_device_class_name(classcode)); + printf(" Image Length: 0x%04x blocks (%d bytes)\n", ilen, ilen*512); printf(" Revision Level of Code/Data: 0x%04x\n", - little_word(data->irevision)); - printf(" Code Type: 0x%02x (", data->type); - switch (data->type) { - case 0: - printf("Intel x86"); - break; - case 1: - printf("Open Firmware"); - break; - case 2: - printf("HP PA Risc"); - break; - case 3: - printf("Intel EFI (unofficial)"); - break; - default: - printf("unknown as of PCI specs 2.2"); - } - printf(")\n Indicator: 0x%02x %s\n", data->indicator, - data->indicator&0x80?"(last image in rom)":""); + (u32)LITTLE_ENDIAN_WORD_FETCH(data->irevision)); + printf(" Code Type: 0x%02x (%s)\n", data->code_type, + pci_code_type_name(data->code_type) ); + printf(" Last-Image Flag: 0x%02x (%slast image in rom)\n", + data->last_image_flag, + data->last_image_flag&0x80?"":"not "); printf(" Reserved: 0x%04x\n\n", little_word(data->reserved_2));
return (sig==PCI_DATA_HDR); @@ -225,7 +146,7 @@ printf( " Entry point for INIT function:" " 0x%x\n\n",entry); } else - printf( " Unable to determin entry point for INIT" + printf( " Unable to determine entry point for INIT" " function. Please report.\n\n"); break; @@ -252,9 +173,9 @@
if (argc!=2) { printf ("\nUsage: %s <romimage.img>\n",argv[0]); - printf ("\nromheaders dumps pci option rom headers " + printf ("\n romheaders dumps pci option rom headers " "according to PCI \n" - "specs 2.2 in human readable form\n\n"); + " specs 2.2 in human readable form\n\n"); return -1; } @@ -290,23 +211,25 @@ do { printf("\nImage %d:\n",i); if (!dump_rom_header(rom_header)) { - printf("Error occured. Bailing out.\n"); + printf("Rom Header error occured. Bailing out.\n"); break; } - pci_data=(pci_data_t *)(rom+little_word(rom_header->dptr)); + pci_data = (pci_data_t *)((char *)rom_header + + LITTLE_ENDIAN_WORD_FETCH(rom_header->data_ptr)); if (!dump_pci_data(pci_data)) { - printf("Error occured. Bailing out.\n"); + printf("PCI Data error occured. Bailing out.\n"); break; } - dump_platform_extensions(pci_data->type, rom_header); + dump_platform_extensions(pci_data->code_type, rom_header); - rom_header+=little_word(pci_data->ilen)*512; + rom_header = (rom_header_t *)((char *)rom_header + + LITTLE_ENDIAN_WORD_FETCH(pci_data->ilen)*512); i++; - } while ((pci_data->indicator&0x80)!=0x80 && - romlen<(unsigned long)rom_header-(unsigned long)romlen); + } while ((pci_data->last_image_flag&0x80)!=0x80 && + (char *)rom_header < rom+(int)romlen );
return 0; }
Modified: fcode-utils/toke/Makefile =================================================================== --- fcode-utils/toke/Makefile 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/Makefile 2006-08-18 12:47:12 UTC (rev 76) @@ -1,11 +1,12 @@ # -# OpenBIOS - free your system! -# ( FCode tokenizer ) -# -# This program is part of a free implementation of the IEEE 1275-1994 +# OpenBIOS - free your system! +# ( Utilities ) +# +# This program is part of a free implementation of the IEEE 1275-1994 # Standard for Boot (Initialization Configuration) Firmware. # -# Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org +# Copyright (C) 2001-2006 Stefan Reinauer stepan@openbios.org +# Copyright (C) 2006 coresystems GmbH info@coresystems.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,52 +22,39 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA #
-ARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/x86_64/amd64/) -TOPDIR := $(shell /bin/pwd) -BUILDDIR ?= $(TOPDIR)/obj-$(ARCH) -VPATH := $(BUILDDIR) +PROGRAM = toke
-include $(TOPDIR)/Rules.make +CC = gcc +STRIP = strip +INCLUDES = -I../shared +#CFLAGS = -O2 -g -Wall +CFLAGS = -Os -Wall -Wno-pointer-sign -DSYS_IS_GNU_Linux +LDFLAGS =
-CC = gcc -CFLAGS = -O2 -Wall -W -ansi -pedantic -# CFLAGS = -O -g -Wall -ansi -pedantic +OBJS = clflags.o conditl.o devnode.o dictionary.o emit.o errhandler.o \ + flowcontrol.o macros.o nextfcode.o parselocals.o scanner.o stack.o \ + stream.o strsubvocab.o ticvocab.o toke.o tokzesc.o tracesyms.o \ + usersymbols.o ../shared/classcodes.o
-# CFLAGS := $(CFLAGS) -DDEBUG_SCANNER -# CFLAGS := $(CFLAGS) -DDEBUG_DSTACK +all: .dependencies $(PROGRAM)
-OBJECTS= toke.o stack.o stream.o dictionary.o macros.o scanner.o emit.o +$(PROGRAM): $(OBJS) + $(CC) -o $(PROGRAM) $(OBJS) $(LDFLAGS) + $(STRIP) -s $(PROGRAM)
-.SUFFIXES: .c .o +clean: + rm -f $(OBJS) *~
-all: main toke - @cd $(BUILDDIR) && strip toke - @echo -e "\nOpenBIOS tokenizer toke build finished\n" +distclean: clean + rm -f $(PROGRAM) .dependencies + +.dependencies: *.c + @$(CC) $(CFLAGS) $(INCLUDES) -MM *.c > .dependencies
-# main should go to rules.make -main: - @echo -e "\nWelcome to toke, the OpenBIOS fcode tokenizer.." - @test -r $(BUILDDIR) || ( mkdir -p $(BUILDDIR); \ - echo -e "\nCreating build directory $(BUILDDIR)" ) +.PHONY: all clean distclean
-toke: $(OBJECTS) - @echo -n " linking tokenizer executable... " - @cd $(BUILDDIR) && $(CC) $(CFLAGS) -o $@ $^ - @echo -e "\tok" - -clean: - @test ! -d $(BUILDDIR) && \ - echo "Architecture $(ARCH) is already clean." || \ - ( \ - echo "Cleaning up architecture $(ARCH)"; \ - rm -rf $(BUILDDIR) \ - rm forth.dict.core \ - ) +-include .dependencies
-toke.o: toke.c toke.h stack.h stream.h emit.h -dictionary.o: dictionary.c toke.h dictionary.h -emit.o: emit.c toke.h stack.h -macros.o: macros.c toke.h -scanner.o: scanner.c toke.h stack.h stream.h dictionary.h -stack.o: stack.c toke.h stack.h -stream.o: stream.c toke.h +.c.o: + $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@ +
Deleted: fcode-utils/toke/Rules.make =================================================================== --- fcode-utils/toke/Rules.make 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/Rules.make 2006-08-18 12:47:12 UTC (rev 76) @@ -1,17 +0,0 @@ -# tag: Makefile rules - -VPATH := $(VPATH):. - -.S.o: - echo -n " assembling $<... " - $(CC) -c -nostdlib $(INCLUDES) $(CFLAGS) $< -o $(BUILDDIR)/$@ && \ - echo -e " \t\tok" || \ - echo -e " \t\tfailed" - -.c.o: - @echo -n " compiling $<... " - @$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $(BUILDDIR)/$@ && \ - echo -e " \t\tok" || \ - echo -e " \t\failed" - -
Added: fcode-utils/toke/clflags.c =================================================================== --- fcode-utils/toke/clflags.c (rev 0) +++ fcode-utils/toke/clflags.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,729 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Command-Line Flags are used to control certain non-Standard + * variant behaviors of the Tokenizer. + * Support Functions for setting, clearing, displaying, etc. + * Call them "Special-Feature Flags" in messages to the User + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * For a given CLFlag name, the user may enter either: + * + * -f CLFlagName + * or + * -f noCLFlagName + * + * to either enable or disable the associated function + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Functions Exported: + * set_cl_flag Set (or clear) a CL Flag Variable + * show_all_cl_flag_settings Show CL Flags' settings unconditionally. + * list_cl_flag_settings Display CL Flags' settings if changed. + * list_cl_flag_names Display just the names of the CL Flags. + * cl_flags_help Help Message for CL Flags + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Revision History: + * Updated Mon, 08 Aug 2005 by David L. Paktor + * They're not just for setting from the Command-Line anymore, + * but let's still keep these names for internal use.... + * + **************************************************************************** */ + +/* ************************************************************************** + * + * The CL_FLAGS data structure has a field for the CLFlagName, + * one for a text explanation of the function it controls, and + * one for the address of the boolean variable ("flag") + * + **************************************************************************** */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "clflags.h" +#include "errhandler.h" + + +/* ************************************************************************** + * + * Global Variables Exported + * (The "flags" controlled by this means) + * + **************************************************************************** */ + +bool ibm_locals = FALSE ; +bool ibm_locals_legacy_separator = TRUE ; +bool ibm_legacy_separator_message = TRUE ; +bool enable_abort_quote = TRUE ; +bool sun_style_abort_quote = TRUE ; +bool abort_quote_throw = TRUE ; +bool string_remark_escape = TRUE ; +bool hex_remark_escape = TRUE ; +bool c_style_string_escape = TRUE ; +bool always_headers = FALSE ; +bool always_external = FALSE ; +bool verbose_dup_warning = TRUE ; +bool obso_fcode_warning = TRUE ; +bool trace_conditionals = FALSE ; +bool big_end_pci_image_rev = FALSE ; + +/* And one to trigger a "help" message */ +bool clflag_help = FALSE; + +/* ************************************************************************** + * + * The addition of the "upper/lower-case-tokens" flags introduces + * some complications. These are the variables we will actually + * be exporting: + * + **************************************************************************** */ + +bool force_tokens_case = FALSE ; +bool force_lower_case_tokens = FALSE ; + +/* ************************************************************************** + * + * but we will be entering two static variables into the table, + * and keep two more to detect when a change is made... + * + **************************************************************************** */ +static bool upper_case_tokens = FALSE ; +static bool lower_case_tokens = FALSE ; +static bool was_upper_case_tk = FALSE ; +static bool was_lower_case_tk = FALSE ; + +/* ************************************************************************** + * + * Internal Static Variables + * cl_flag_change A change was made to any of the CL Flags + * Internal Static Constants + * cl_flags_list List of CL Flags and their data. + * + **************************************************************************** */ + +static bool cl_flag_change = FALSE; + +static const cl_flag_t cl_flags_list[] = { + /* The clflag_tabs field takes at least one tab. + * If the name has fewer than 16 characters, + * stick in an extra tab, and yet another tab + * if the name is shorter than 8 characters + * to make the formatting of the "explanation" + * come out prettier. + */ + { "Local-Values", + &ibm_locals, + "\t\t", + "Support IBM-style Local Values ("LV"s)" } , + + { "LV-Legacy-Separator", + &ibm_locals_legacy_separator, + "\t", + "Allow Semicolon for Local Values Separator ("Legacy")" } , + + { "LV-Legacy-Message", + &ibm_legacy_separator_message, + "\t", + "Display a Message when Semicolon is used as the " + "Local Values Separator" } , + + { "ABORT-Quote", + &enable_abort_quote, + "\t\t", + "Allow ABORT" macro" } , + + { "Sun-ABORT-Quote", + &sun_style_abort_quote, + "\t\t", + "ABORT" with implicit IF ... THEN" } , + + { "ABORT-Quote-Throw", + &abort_quote_throw, + "\t", + "Use -2 THROW in an Abort" phrase, rather than ABORT" } , + + { "String-remark-escape", + &string_remark_escape, + "\t", + "Allow "\ (Quote-Backslash) to interrupt string parsing" } , + + { "Hex-remark-escape", + &hex_remark_escape, + "\t", + "Allow \ (Backslash) to interrupt " + "hex-sequence parsing within a string" } , + + { "C-Style-string-escape", + &c_style_string_escape , + "\t", + "Allow \n \t and \xx\ for special chars in string parsing" } , + + { "Always-Headers", + &always_headers , + "\t\t", + "Override "headerless" and force to "headers"" } , + + { "Always-External", + &always_external , + "\t\t", + "Override "headerless" and "headers" and " + "force to "external"" } , + + { "Warn-if-Duplicate", + &verbose_dup_warning , + "\t", + "Display a WARNING message when a duplicate definition is made" } , + + { "Obsolete-FCode-Warning", + &obso_fcode_warning , + "\t", + "Display a WARNING message when an "obsolete" " + "(per the Standard) FCode is used" } , + + { "Trace-Conditionals", + &trace_conditionals, + "\t", + "Display ADVISORY messages about the state of " + "Conditional Tokenization" } , + + { "Upper-Case-Token-Names", + &upper_case_tokens, + "\t", + "Convert Token-Names to UPPER-Case" } , + + + { "Lower-Case-Token-Names", + &lower_case_tokens, + "\t", + "Convert Token-Names to lower-Case" } , + + + { "Big-End-PCI-Rev-Level", + &big_end_pci_image_rev, + "\t", + "Save the Vendor's Rev Level field of the PCI Header" + " in Big-Endian format" } , + + + /* Keep the "help" pseudo-flag last in the list */ + { "help", + &clflag_help, + /* Two extra tabs if the name is shorter than 8 chars */ + "\t\t\t", + "Print this "Help" message for the Special-Feature Flags" } + +}; + +static const int number_of_cl_flags = + sizeof(cl_flags_list)/sizeof(cl_flag_t); + + +/* ************************************************************************** + * + * CL Flags whose settings are changed in the source file should + * not stay in effect for the duration of the entire batch of + * tokenizations (i.e., if multiple input files are named on + * the command line) the way command-line settings should. + * To accomplish this we will collect the state of the flags into + * a bit-mapped variable after the command line has been parsed + * and restore them to their collected saved state before an + * input file is processed. + * + **************************************************************************** */ + +static long int cl_flags_bit_map; +/* If the number of CL Flags ever exceeds the number of bits in a long + * (presently 32), we will need to change both this variable and + * the routines that use it. Of course, if the number of CL Flags + * ever gets that high, it will be *seriously* unwieldy... ;-} + */ + +/* ************************************************************************** + * + * Function name: adjust_case_flags + * Synopsis: If the last CL Flag Variable setting changed one of + * the "upper/lower-case-tokens" flags, make the + * appropriate adjustments. + * + * Inputs: + * Parameters: NONE + * Local Static Variables: + * was_upper_case_tk State of "upper-case-tokens" flag before + * last CL Flag Variable was processed + * was_lower_case_tk State of "lower-case-tokens" flag, before + * upper_case_tokens State of "upper-case-tokens" flag after + * last CL Flag V'ble was processed + * lower_case_tokens State of "lower-case-tokens" flag, after + * Global Variables: + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * force_tokens_case TRUE if "upper/lower-case-tokens" + * flag is in effect + * force_lower_case_tokens If force_tokens_case is TRUE, then + * this switches between "upper" + * or "lower" case + * + * Process Explanation: + * We cannot come out of this with both upper_case_tokens and + * lower_case_tokens being TRUE, though they may both be FALSE. + * If neither has changed state, we need not do anything here. + * If one has gone to TRUE, we must force the other to FALSE and + * we will set force_tokens_case to TRUE. + * If one has gone to FALSE, turn force_tokens_case to FALSE. + * If force_tokens_case is TRUE after all this, we must adjust + * force_lower_case_tokens according to lower_case_tokens + * + **************************************************************************** */ + +static void adjust_case_flags( void) +{ + static bool *case_tokens[2] = { &upper_case_tokens, &lower_case_tokens }; + static bool *was_case_tk[2] = { &was_upper_case_tk, &was_lower_case_tk }; + int the_one = 0; + int the_other = 1; + + for ( ; the_one < 2 ; the_one++ , the_other-- ) + { + /* If one has changed state */ + if ( *(case_tokens[the_one]) != *(was_case_tk[the_one]) ) + { + if ( *(case_tokens[the_one]) ) + { + /* If it has gone to TRUE, force the other to FALSE. */ + *(case_tokens[the_other]) = FALSE; + /* and set force_tokens_case to TRUE */ + force_tokens_case = TRUE; + }else{ + /* If it has gone to FALSE turn force_tokens_case FALSE */ + force_tokens_case = FALSE; + } + if ( force_tokens_case ) + { + force_lower_case_tokens = lower_case_tokens; + } + break; /* Only one can have changed state. */ + } + } +} + + + + +/* ************************************************************************** + * + * Function name: set_cl_flag + * Synopsis: Set (or clear) the named CL Flag Variable + * + * Inputs: + * Parameters: + * flag_name The name as supplied by the user + * from_src TRUE if called from source-input file + * Static Constants: + * cl_flags_list + * number_of_cl_flags + * + * Outputs: + * Returned Value: TRUE if supplied name is not valid + * Global Variables: + * The CL Flag Variable associated with the supplied name will + * be set or cleared according to the leading "no" + * Local Static Variables: + * cl_flag_change TRUE if associated variable has changed + * Printout: + * If from_src is TRUE, print "En" or "Dis" abling: + * followed by the explanation + * + * Error Detection: + * If the supplied name is not a valid CL Flag name, or if + * it's too short to be a valid CL Flag name, return TRUE. + * Print a message; either a simple print if this function was + * called from a command-line argument, or an ERROR if it + * was called from a line in the from source-input file. + * + * Process Explanation: + * Save the current state of the "upper/lower-case-tokens" flags + * If the given name has a leading "no", make note of that fact + * and remove the leading "no" from the comparison. + * Compare with the list of valid CL Flag names. + * If no match was found, Error. See under Error Detection. + * If a match: + * Change the associated variable according to the leading "no" + * Set cl_flag_change to TRUE unless the variable is the one + * associated with the "help" flag; this permits the + * "Default" vs "Setting" part of cl_flags_help() to + * work properly... + * Do the conditional Printout (see above) + * Adjust the "upper/lower-case-tokens" flags if one has changed. + * + **************************************************************************** */ +static bool first_err_msg = TRUE; /* Need extra carr-ret for first err msg */ +bool set_cl_flag(char *flag_name, bool from_src) +{ + bool retval = TRUE; + + was_upper_case_tk = upper_case_tokens; + was_lower_case_tk = lower_case_tokens; + + if ( strlen(flag_name) > 3 ) + { + int indx; + bool flagval = TRUE; + char *compar = flag_name; + + if ( strncasecmp( flag_name, "no", 2) == 0 ) + { + flagval = FALSE; + compar += 2; + } + for ( indx = 0 ; indx < number_of_cl_flags ; indx++ ) + { + if ( strcasecmp( compar, cl_flags_list[indx].clflag_name ) == 0 ) + { + retval = FALSE; + *(cl_flags_list[indx].flag_var) = flagval; + + /* The "help" flag is the last one in the list */ + if ( indx != number_of_cl_flags - 1 ) + { + cl_flag_change = TRUE; + } + if ( from_src ) + { + tokenization_error(INFO, + "%sabling: %s\n", + flagval ? "En" : "Dis", cl_flags_list[indx].clflag_expln); + } + break; + } + } + } + + if ( retval ) + { + const char* msg_txt = "Unknown Special-Feature Flag: %s\n" ; + if ( from_src ) + { + tokenization_error( TKERROR, (char *)msg_txt, flag_name); + }else{ + if ( first_err_msg ) + { + printf( "\n"); + first_err_msg = FALSE; + } + printf( msg_txt, flag_name); + } + } + + adjust_case_flags(); + + return ( retval ); +} + +/* ************************************************************************** + * + * Function name: show_all_cl_flag_settings + * Synopsis: Display the settings of the CL Flags, (except "help") + * regardless of whether they have been changed. + * + * Associated Tokenizer directive(s): [FLAGS] + * #FLAGS + * [#FLAGS] + * SHOW-FLAGS + * This routine may also be invoked by a combination of + * options on the command-line. + * + * Inputs: + * Parameters: + * from_src TRUE if called from source-input file + * Macro: + * ERRMSG_DESTINATION Error message destination; + * (Development-time switch) + * Static Constants: + * cl_flags_list + * number_of_cl_flags + * + * Outputs: + * Returned Value: NONE + * Printout: Directed to stdout or to stderr + * (see definition of ERRMSG_DESTINATION) + * A header line, followed by the names of the CL Flags, + * with "No" preceding name if value is FALSE, one to a line. + * + * Process Explanation: + * If from_src is TRUE, print the header line as a Message, and + * then direct output to ERRMSG_DESTINATION . + * Don't print the "help" trigger (the last flag in the array). + * + **************************************************************************** */ + +void show_all_cl_flag_settings(bool from_src) +{ + const char* hdr_txt = "Special-Feature Flag settings:" ; + int indx; + + if ( from_src ) + { + tokenization_error(MESSAGE, (char *)hdr_txt); + }else{ + printf("\n%s\n", hdr_txt); + } + + for ( indx = 0 ; indx < (number_of_cl_flags - 1) ; indx++ ) + { + fprintf( from_src ? ERRMSG_DESTINATION : stdout , + "\t%s%s\n", + *(cl_flags_list[indx].flag_var) ? " " : "No" , + cl_flags_list[indx].clflag_name ); + } + if ( from_src ) fprintf( ERRMSG_DESTINATION, "\n"); +} + +/* ************************************************************************** + * + * Function name: list_cl_flag_settings + * Synopsis: Display the settings of the CL Flags, (except "help") + * if any of them have been changed + * + * Inputs: + * Parameters: NONE + * Local Static Variables: + * cl_flag_change TRUE if a Flag setting has been changed. + * + * Outputs: + * Returned Value: NONE + * Printout: + * Settings of the CL Flags. See show_all_cl_flag_settings() + * + * Process Explanation: + * Don't print anything if cl_flag_change is not TRUE + * + **************************************************************************** */ + +void list_cl_flag_settings(void) +{ + + if ( cl_flag_change ) + { + show_all_cl_flag_settings( FALSE); + } +} + + +/* ************************************************************************** + * + * Function name: list_cl_flag_names + * Synopsis: Display just the names of the CL Flags + * for the Usage message + * + * Inputs: + * Parameters: NONE + * Static Constants: + * cl_flags_list + * number_of_cl_flags + * + * Outputs: + * Returned Value: NONE + * Printout: + * A header line, followed by the names of the CL Flags, + * + **************************************************************************** */ + +void list_cl_flag_names(void) +{ + int indx; + + printf("Valid Special-Feature Flags are:\n"); + for ( indx = 0 ; indx < number_of_cl_flags ; indx++ ) + { + printf("\t%s\n", cl_flags_list[indx].clflag_name ); + } +} + +/* ************************************************************************** + * + * Function name: cl_flags_help + * Synopsis: Display Usage of the CL Flags and their defaults + * + * + * Inputs: + * Parameters:: NONE + * Static Constants: + * cl_flags_list + * number_of_cl_flags + * Local Static Variables: + * cl_flag_change TRUE if setting has been changed. + * + * Outputs: + * Returned Value: NONE + * Printout: + * A few lines of header, followed by the default, the name + * and the "explanation" of each of the CL Flags, one to a line. + * + * Extraneous Remarks: + * We take advantage of the facts that this routine is called + * (1) only from the command-line, before any settings + * have been changed, and (2) via changing the flag for + * "help" to TRUE. (Technically, I suppose, the default + * for the "help" feature is "no", but showing will, I + * think be more confusing than enlightening to the user.) + * Also, I suppose a perverse user could change setting(s) on + * the same command-line with a "-f help" request; we cannot + * stop users from aiming at their boot and pulling the + * trigger. As my buddies in Customer Support would say: + * "KMAC YOYO" (Approximately, "You're On Your Own, Clown")... + * + * Revision History: + * Oh, all right. If the user changed setting(s), we can do + * them the minor courtesy of printing "Setting" instead + * of "Default". + * + * + **************************************************************************** */ + +void cl_flags_help(void ) +{ + int indx; + + printf("\n" + "Special-Feature Flags usage:\n" + " -f FlagName to enable the feature associated with FlagName,\n" + "or\n" + " -f noFlagName to disable the feature.\n\n" + "%s Flag-Name\t\t Feature:\n\n", + cl_flag_change ? "Setting" : "Default" ); + + for ( indx = 0 ; indx < number_of_cl_flags ; indx++ ) + { + printf(" %s %s%s%s\n", + *(cl_flags_list[indx].flag_var) ? " " : "no" , + cl_flags_list[indx].clflag_name, + cl_flags_list[indx].clflag_tabs, + cl_flags_list[indx].clflag_expln); + } + +} + + + +/* ************************************************************************** + * + * Function name: save_cl_flags + * Synopsis: Collect the state of the CL Flags + * + * Inputs: + * Parameters: NONE + * Local Static Variables: + * cl_flags_list + * Static Constants: + * number_of_cl_flags + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * cl_flags_bit_map Will be set to reflect the state + * of the CL Flags in the list. + * + * Process Explanation: + * The correspondence of bits to the list is that the first item + * in the list corresponds to the low-order bit, and so on + * moving toward the high-order with each successive item. + * Do not save the "help" flag (last item on the list). + * This routine is called after the command line has been parsed. + * + **************************************************************************** */ + +void save_cl_flags(void) +{ + int indx; + long int moving_bit = 1; + + cl_flags_bit_map = 0; + for ( indx = 0 ; indx < (number_of_cl_flags - 1) ; indx++ ) + { + if ( *(cl_flags_list[indx].flag_var) ) + { + cl_flags_bit_map |= moving_bit; /* The moving finger writes, */ + } + moving_bit <<= 1; /* and having writ, moves on. */ + } +} + +/* ************************************************************************** + * + * Function name: reset_cl_flags + * Synopsis: Restore the CL Flags to the state that was saved. + * + * Inputs: + * Parameters: NONE + * Local Static Variables: + * cl_flags_bit_map Reflects the state of the CL Flags + * Static Constants: + * number_of_cl_flags + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * cl_flags_list + * Global Variables: + * The CL Flag Variables will be set or cleared + * to their saved state + * + * Process Explanation: + * This routine is called before starting a new input file. + * Any changes made in the source file will not stay + * in effect for the next tokenization. + * + **************************************************************************** */ + +void reset_cl_flags(void) +{ + int indx; + long int moving_bit = 1; + + for ( indx = 0 ; indx < (number_of_cl_flags - 1) ; indx++ ) + { + *(cl_flags_list[indx].flag_var) = + BOOLVAL( cl_flags_bit_map & moving_bit) ; + moving_bit <<= 1; + } +}
Added: fcode-utils/toke/clflags.h =================================================================== --- fcode-utils/toke/clflags.h (rev 0) +++ fcode-utils/toke/clflags.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,144 @@ +#ifndef _TOKE_CLFLAGS_H +#define _TOKE_CLFLAGS_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Function Prototypes and External declarations + * for Command-Line Flags Support + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Structure-Types: + * cl_flag_t Data for recognizing and setting Command-Line + * Flags, and for displaying the help message + * + * Function Prototypes / Functions Exported: + * set_cl_flag + * list_cl_flag_settings + * list_cl_flag_names Display just the names of the CL Flags + * cl_flags_help + * + * Global Variables Exported + * (These flags, which are set by the set_cl_flag() routine, + * are used throughout the Tokenizer to control certain + * non-Standard variant behaviors.) + * ibm_locals + * ibm_locals_legacy_separator + * ibm_legacy_separator_message + * enable_abort_quote + * sun_style_abort_quote + * string_remark_escape + * hex_remark_escape + * c_style_string_escape + * always_headers + * always_external + * verbose_dup_warning + * obso_fcode_warning + * trace_conditionals + * force_tokens_case + * force_lower_case_tokens + * big_end_pci_image_rev + * clflag_help + * + **************************************************************************** */ + +/* ************************************************************************** + * Structure-Type Name: cl_flag_t + * Data for recognizing and setting Command-Line Flags, + * and for displaying the help message + * + * Fields: + * clflag_name *char CL Flag name, as entered by the user + * flag_var *bool Address of boolean ("flag") variable + * clflag_tabs *char Tabs to align the explanations, in + * the help message display + * clflag_expln *char Explanation, used in help message + * + * Since this structure will be initialized by the program, and will not + * be added-to, we can structure it as purely an array, and have no + * need to treat it as a linked list, hence no link-field. + * + **************************************************************************** */ + +#include "types.h" + +typedef struct cl_flag + { + char *clflag_name; + bool *flag_var; + char *clflag_tabs; + char *clflag_expln; + } cl_flag_t ; + + +/* ************************************************************************** + * + * Exported Global Variables + * + **************************************************************************** */ + +extern bool ibm_locals; +extern bool ibm_locals_legacy_separator; +extern bool ibm_legacy_separator_message; +extern bool enable_abort_quote; +extern bool sun_style_abort_quote; +extern bool abort_quote_throw; +extern bool string_remark_escape; +extern bool hex_remark_escape; +extern bool c_style_string_escape; +extern bool always_headers; +extern bool always_external; +extern bool verbose_dup_warning; +extern bool obso_fcode_warning; +extern bool trace_conditionals; +extern bool big_end_pci_image_rev; + +extern bool force_tokens_case; +extern bool force_lower_case_tokens; + +extern bool clflag_help; + +/* ************************************************************************** + * + * Exported Functions + * + **************************************************************************** */ + +bool set_cl_flag(char *flag_name, bool print_message); +void cl_flags_help(void); +void list_cl_flag_names(void); +void show_all_cl_flag_settings(bool from_src); +void list_cl_flag_settings(void); +void save_cl_flags(void); +void reset_cl_flags(void); + +#endif /* _TOKE_CLFLAGS_H */
Added: fcode-utils/toke/conditl.c =================================================================== --- fcode-utils/toke/conditl.c (rev 0) +++ fcode-utils/toke/conditl.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,772 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Conditional-Compilation support for Tokenizer + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Functions Exported: + * init_conditionals_vocab Initialize the "Conditionals" Vocabulary. + * handle_conditional Confirm whether a given name is a valid + * Conditional, and, if so, perform its + * function and return an indication. + * create_conditional_alias Add an alias to "Conditionals" vocab + * reset_conditionals Reset the "Conditionals" Vocabulary + * to its "Built-In" position. + * + **************************************************************************** */ + +#include <stdio.h> +#include <stdlib.h> + +#include <string.h> +#include <errno.h> + +#include "scanner.h" +#include "errhandler.h" +#include "ticvocab.h" +#include "conditl.h" +#include "stack.h" +#include "dictionary.h" +#include "vocabfuncts.h" +#include "usersymbols.h" +#include "stream.h" +#include "clflags.h" + +/* ************************************************************************** + * + * Global Variables Imported + * statbuf Start of input-source buffer + * pc Input-source Scanning pointer + * iname Current Input File name + * lineno Current Line Number in Input File + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Local Static Variables + * already_ignoring Location from which to pass a parameter, + * called "alr_ign" to the main routine. Each + * "Conditional" will have an associated routine + * that takes the pointer to this as its argument. + * The pointer to this will satisfy the "param-field" + * requirement of a TIC_HDR-style "Vocabulary"-list. + * conditionals_tbl TIC_HDR-style "Vocabulary"-list table, initialized + * as an array. + * conditionals Pointer to "tail" of Conditionals Vocabulary-list + * + **************************************************************************** */ + +/* ************************************************************************** + * + * The lists of synonymous forms of the #ELSE and #THEN operators + * are incorporated into the "Shared Words" Vocabulary. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Function name: is_a_then / is_an_else + * Synopsis: Indicate whether the given name is one of the + * [then] / [else] synonyms + * + * Inputs: + * Parameters: + * a_word Word to test + * + * Outputs: + * Returned Value: TRUE if the given name is one of the synonyms + * + * Process Explanation: + * The functions are twins, hence bundling them like this... + * + **************************************************************************** */ + + +/* ************************************************************************** + * + * Support function: is_a_type + * Synopsis: Indicate whether the given name is a "shared word" + * whose FWord Token matches the one given + * + * Inputs: + * Parameters: + * tname Target name to look for + * fw_type The FWord Token type to match + * + * Outputs: + * Returned Value: TRUE if it matches + * + **************************************************************************** */ + + +static bool is_a_type( char *tname, fwtoken fw_type) +{ + bool retval = FALSE; + tic_fwt_hdr_t *found = (tic_fwt_hdr_t *)lookup_shared_f_exec_word( tname ); + if ( found != NULL ) + { + if ( found->pfield.fw_token == fw_type ) retval = TRUE; + } + return ( retval ); +} + +static bool is_a_then( char *a_word) +{ + bool retval = is_a_type( a_word, CONDL_ENDER); + return ( retval ); +} + +static bool is_an_else( char *a_word) +{ + bool retval = is_a_type( a_word, CONDL_ELSE); + return ( retval ); +} + +/* ************************************************************************** + * + * This is a somewhat roundabout way of passing an "already ignoring" + * parameter to the various Conditional Operators. Each operator's + * Parameter-Field Pointer points to this. The calling routine + * must set it (or rely on the default); the routine that handles + * nesting of Conditionals must save and restore a local copy. + * + **************************************************************************** */ + +static bool already_ignoring = FALSE; + +/* ************************************************************************** + * + * Further down, will define and initialize a word-list table with + * all the functions that implement the Conditional Operators, + * and we'll link it in with the "Global Vocabulary" pointer. + * + * We'll call the word-list the "Conditionals Vocabulary Table", + * and refer to its entries as the "Conditionals Vocabulary", + * even though it isn't really a separate vocabulary... + * + **************************************************************************** */ + + +/* ************************************************************************** + * + * We also need a few common routines to pass as "Ignoring" functions + * for a few occasional words that take another word or two from + * the input stream as their arguments. For example, if the user + * were to write: alias [otherwise] [else] and that were to + * occur within a segment already being ignored, we need to make + * sure that this doesn't get processed as an occurrence of [else] + * Similarly with macro-definitions. + * + * Since we are using the term "ignore a word" to mean "look it up and + * process it in Ignoring-state", we need a different term to name + * this class of routine; let's use the term "skip a word" where + * the "word" is strictly an input token, delimited by whitespace. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Function name: skip_a_word + * Synopsis: Consume one input-token ("word") from the + * Input Stream, with no processing + * + * Inputs: + * Parameters: + * pfield "Parameter field" pointer, to satisfy + * the calling convention, but not used + * + * Outputs: + * Returned Value: NONE + * + **************************************************************************** */ + +void skip_a_word( tic_bool_param_t pfield ) +{ + /* signed long wlen = */ get_word(); +} + +/* ************************************************************************** + * + * Function name: skip_a_word_in_line + * Synopsis: Consume one input-token ("word") on the same line + * as the current line of input, from the Input + * Stream, with no processing. + * + * Inputs: + * Parameters: + * pfield "Parameter field" pointer, to satisfy + * the calling convention, but not used + * Global Variables: + * statbuf The word being processed, which expects + * another word on the same line; used + * for the Error message. + * + * Outputs: + * Returned Value: NONE + * + * Error Detection: + * get_word_in_line() will check and report if no word on same line. + * + **************************************************************************** */ +void skip_a_word_in_line( tic_bool_param_t pfield ) +{ + /* bool isokay = */ get_word_in_line( statbuf); +} + +/* ************************************************************************** + * + * Function name: skip_two_words_in_line + * Synopsis: Consume two input-tokens ("words") on the same line + * as the current line of input, from the Input + * Stream, with no processing. + * + * Inputs: + * Parameters: + * pfield "Parameter field" pointer, to satisfy + * the calling convention, but not used + * Global Variables: + * statbuf The word being processed, which expects + * two words on the same line; used for + * the Error message. + * + * Outputs: + * Returned Value: NONE + * Memory Allocated + * Copy of statbuf for Error message. + * When Freed? + * End of this routine + * + * Error Detection: + * get_word_in_line() will check and report + * + **************************************************************************** */ + +void skip_two_words_in_line( tic_bool_param_t pfield ) +{ + char *func_cpy = strupr( strdup( statbuf)); + if ( get_word_in_line( func_cpy) ) + { + /* bool isokay = */ get_word_in_line( func_cpy); + } + free( func_cpy); +} + + +/* ************************************************************************** + * + * Function name: ignore_one_word + * Synopsis: Handle a word that needs processing while "ignoring" + * Ignore the rest. + * + * Inputs: + * Parameters: + * tname Target name to test + * Local Static Variables: + * already_ignoring The "Already Ignoring" flag + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * tic_found Set to the TIC-entry that has just been + * found, in case it's a Macro. + * Local Static Variables: + * already_ignoring Intermediately set to TRUE, then + * returned to former state. + * + * Process Explanation: + * When we are ignoring source input, we still need to be + * sensitive to the nesting of Conditional Operators, to + * consume comments and user -message text-bodies, and to + * expand Macros, among other things. + * Rather than create special cases here for each one, we have + * added an "ign_funct" pointer to those words where this + * is relevant, including Conditional Operators. + * Save the state of already_ignoring and set it to TRUE + * Execute the "Ignoring" Function associated with the entry + * Restore already_ignoring to its previous state. + * This is necessary if the word is a Conditional Operator and + * is harmless otherwise. + * + **************************************************************************** */ + +static void ignore_one_word( char *tname) +{ + tic_bool_hdr_t *found = (tic_bool_hdr_t *)lookup_word( tname, NULL, NULL); + if ( found != NULL ) + { + if ( found->ign_func != NULL ) + { + bool save_already_ignoring = already_ignoring; + already_ignoring = TRUE ; + tic_found = (tic_hdr_t *)found; + + found->ign_func( found->pfield); + + already_ignoring = save_already_ignoring; + } + } +} + +/* ************************************************************************** + * + * Function name: conditionally_tokenize + * Synopsis: Conduct tokenization while a Conditional-Tokenization + * operator is in effect. This is the core of the + * implementation of Conditional-Tokenization. + * + * Inputs: + * Parameters: + * cond The state of the Condition-Flag that the + * immediate Conditional Operator acquired. + * TRUE means "do not ignore". Its sense + * is reversed when [ELSE] is encountered. + * alr_ign TRUE means we are Already Ignoring source input, + * except for Conditional Operators... + * Global Variables: + * statbuf The symbol (word) just retrieved from input stream. + * iname Current Input File name (for Error Messages) + * lineno Current Line Number in Input File (ditto) + * trace_conditionals Whether to issue ADVISORY messages about + * the state of Conditional Tokenization. + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * statbuf Will be advanced to the balancing [THEN] op'r. + * already_ignoring Set to TRUE if nested Conditional encountered; + * restored to previous state when done. + * Memory Allocated + * Duplicate of Input File name, for Error Messages + * When Freed? + * Just prior to exit from routine. + * Printout: + * ADVISORY messages, if "Trace-Conditionals" flag was selected. + * + * Global Behavior: + * Tokenization happens, or inputs are ignored, as necessary. + * + * Error Detection: + * End-of-file encountered on reading a word + * ERROR. Conditional Operators must be balanced within a file + * More than one [ELSE] encountered: ERROR if processing segment; + * if ignoring, WARNING. + * + * Process Explanation: + * Read a word at a time. Allow Macros to "pop" transparently, + * but not source files. + * If the word is a [THEN], we are done. + * If the word is an [ELSE], then, if we are not Already Ignoring, + * invert the sense of whether we are ignoring source input. + * If this is not the only [ELSE] in the block, report an Error + * and disregard it. + * If we are ignoring source input, for whatever reason, we still + * need to be sensitive to the nesting of Conditional Operators: + * If the word is a Conditional Operator, activate it with the + * "Already Ignoring" parameter set to TRUE; doing so will + * result in a nested call to this routine. + * Otherwise, i.e., if the word is not a Conditional Operator, + * we may still need to process it in "ignoring" mode: + * we need, for instance, to consume strings, comments + * and the text-bodies of user-messages in their entirety, + * in case there is a reference to an [ELSE] or suchlike. + * The words that need processing while "ignoring" will + * have a valid function-pointer in their ign_func field. + * If we are not ignoring source input, pass the word along to the + * tokenize_one_word routine and process it. If the word is + * a Conditional Operator, it will be handled in the context + * of normal (i.e., non-ignored) tokenization, and, again, a + * nested call to this routine will result... + * + * Revision History: + * Updated Thu, 23 Feb 2006 by David L. Paktor + * Conditional Blocks may begin with a Conditional Operator in + * a Macro definition and do not need to be concluded in + * the body of the Macro. + * Updated Fri, 10 Mar 2006 by David L. Paktor + * Recognize aliased string, comment and user-message delimiters + * in a segment that is being ignored; Conditional Operators + * within the text body of any of these are always consumed + * and never unintentionally processed. Macros are always + * processed; Conditional Operators inside a Macro body are + * recognized, so the Macro continues to function as intended. + * + **************************************************************************** */ + +static void conditionally_tokenize( bool cond, bool alr_ign ) +{ + + signed long wlen; + + /* Note: The following variables *must* remain within + * the scope of this routine; a distinct instance + * is needed each time this routine is re-entered + * (aka "a nested call"). + */ + bool ignoring; + bool first_else = TRUE; /* The "else" we see is the first. */ + bool not_done = TRUE; + unsigned int cond_strt_lineno = lineno; + char *cond_strt_ifile_nam = strdup( iname); + + ignoring = BOOLVAL( ( cond == FALSE ) || ( alr_ign != FALSE ) ); + + if ( trace_conditionals ) + { + char *cond_val = cond ? "True" : "False" ; + char *cond_junct = alr_ign ? ", but Already " : "; "; + char *processg = ignoring ? "Ignoring" : "Processing" ; + tokenization_error( INFO, + "Tokenization-Condition is %s%s%s.\n", + cond_val, cond_junct, processg); + } + + while ( not_done ) + { + wlen = get_word(); + if ( wlen == 0 ) + { + continue; + } + + if ( wlen < 0 ) + { + tokenization_error( TKERROR, + "Conditional without conclusion; started"); + just_where_started( cond_strt_ifile_nam, cond_strt_lineno); + not_done = FALSE ; + continue; + } + + if ( is_a_then ( statbuf ) ) + { + if ( trace_conditionals ) + { + tokenization_error( INFO, + "Concluding Conditional"); + just_started_at( cond_strt_ifile_nam, cond_strt_lineno); + } + not_done = FALSE ; + continue; + } + + if ( is_an_else( statbuf ) ) + { + if ( ! alr_ign ) + { + if ( first_else ) + { + ignoring = INVERSE( ignoring); + } + } + + if ( ! first_else ) + { + int severity = ignoring ? WARNING : TKERROR ; + char *the_scop = ignoring ? "(ignored)" : "the" ; + tokenization_error( severity, "Multiple %s directives " + "within %s scope of the Conditional", + strupr(statbuf), the_scop); + just_started_at( cond_strt_ifile_nam, cond_strt_lineno); + }else{ + first_else = FALSE; + if ( trace_conditionals ) + { + char *when_enc = alr_ign ? "While already" : "Now" ; + char *processg = alr_ign ? "ignoring" : + ignoring ? "Ignoring" : "Processing" ; + char *enc = alr_ign ? ", e" : ". E" ; + + tokenization_error( INFO, + "%s %s%sncountered %s belonging to Conditional", + when_enc, processg, enc, strupr(statbuf) ); + just_started_at( cond_strt_ifile_nam, cond_strt_lineno); + } + } + + continue; + } + + /* If we are ignoring source input, for whatever reason, we still + * need to be sensitive to the nesting of Conditional Operators + * and some other commands and directives, as indicated... + */ + if ( ignoring ) + { + ignore_one_word( statbuf ); + }else{ + /* And if we're not ignoring source input, process it! */ + tokenize_one_word ( wlen ); + } + } +} + +/* ************************************************************************** + * + * We will now define a series of fairly simple functions that + * will be performed by the various Conditional Operators in + * the "Conditionals Vocabulary". + * + * Each one takes, as an argument, the "parameter field" pointer, + * which, in all cases, points to the local already_ignoring + * flag, passed as an int to satisfy C's strong-typing. The + * routine will internally recast it as a bool . + * + * If it is TRUE, the routine will bypass the test for its particular + * type of condition, and go directly to conditionally_tokenize + * In most cases, testing for the condition would be harmless, + * but in the case where the test is for an item on the stack, + * it would be harmful because the sequence that put the item + * on the stack was also being ignored... + * + * We'll give these functions short prologs. Synonyms will simply + * have separate entries in the Vocabulary Table, associated + * with the same function. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * But first, a support routine... + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Function name: conditional_word_in_line + * Synopsis: Common code for the types of conditionals that + * require a word on the same line. + * + * Inputs: + * Parameters: + * alr_ign TRUE if we are already ignoring + * exist_test TRUE if the test is for "existence" of the word + * exist_funct Name of the function to call for the test + * Global Variables: + * stat_word Word for which to test + * + * Outputs: + * Returned Value: NONE + * + * Error Detection: + * The word in question must appear on the same line as the directive; + * the call to get_word_in_line() checks for that and reports. + * If the word did not appear on the same line, then the directive + * will be disregarded and processing will proceed as though it + * were absent. This may lead to a cascade of errors... + * + * Process Explanation: + * The supplied exist_funct() will test for the existence of + * the word, now read into statbuf , in the appropriate + * venue. + * We only call the exist_funct() if we are not already ignoring. + * + **************************************************************************** */ + +static void conditional_word_in_line( bool alr_ign, + bool exist_test, + bool (*exist_funct)() ) +{ + if ( get_word_in_line( statbuf) ) + { + bool cond = FALSE; + if ( INVERSE( alr_ign) ) + { + bool exists = exist_funct( statbuf); + cond = BOOLVAL( exists == exist_test); + } + conditionally_tokenize( cond, alr_ign ); + } +} + + +/* ************************************************************************** + * + * Function name: if_exists + * Synopsis: Test for existence of a given word, in the dictionary. + * + * Associated Tokenizer directives: [ifexist] + * #ifexist + * [#ifexist] + * [ifexists] + * #ifexists + * [#ifexists] + * (Note variants with and without final 's' + * + **************************************************************************** */ + +static void if_exists( tic_param_t pfield ) +{ + bool alr_ign = *pfield.bool_ptr; + conditional_word_in_line( alr_ign, TRUE, exists_in_current ); +} + +/* ************************************************************************** + * + * Function name: if_not_exist + * Synopsis: Test for Non-existence, in the appropriate dictionary,) + * of the given word. + * + * Associated Tokenizer directives: [ifnexist] + * #ifnexist + * [#ifnexist] + * (Note: Variants with final 's' didn't make sense here.) + * + * Explanatory Notes: + * This is the exact inverse of if_exists + * + **************************************************************************** */ + +static void if_not_exist( tic_bool_param_t pfield ) +{ + bool alr_ign = *pfield.bool_ptr; + conditional_word_in_line( alr_ign, FALSE, exists_in_current ); +} + +/* ************************************************************************** + * + * Function name: if_defined + * Synopsis: Test for existence of a user-defined symbol + * + * Associated Tokenizer directives: [ifdef] + * #ifdef + * [#ifdef] + * + **************************************************************************** */ + +static void if_defined( tic_bool_param_t pfield ) +{ + bool alr_ign = *pfield.bool_ptr; + conditional_word_in_line( alr_ign, TRUE, exists_as_user_symbol ); +} + +/* ************************************************************************** + * + * Function name: if_not_defined + * Synopsis: Test for NON-existence of a user-defined symbol + * + * Associated Tokenizer directives: [ifndef] + * #ifndef + * [#ifndef] + * + **************************************************************************** */ + +static void if_not_defined( tic_bool_param_t pfield ) +{ + bool alr_ign = *pfield.bool_ptr; + conditional_word_in_line( alr_ign, FALSE, exists_as_user_symbol ); +} + + +/* ************************************************************************** + * + * Function name: if_from_stack + * Synopsis: Test the number on top of the run-time stack + * + * Associated Tokenizer directive: [if] + * + * Process Explanation: + * When we are ignoring source input, and we still need to be + * sensitive to the nesting of Conditional Operators, we + * will not consume the number on the stack; this function + * is after all, being ignored and should not perform any + * action other than making sure the [else]s and [then]s + * get properly counted. + * + **************************************************************************** */ + +static void if_from_stack( tic_bool_param_t pfield ) +{ + bool alr_ign = *pfield.bool_ptr; + bool cond = FALSE; + + if ( ! alr_ign ) + { + long num = dpop(); + if (num != 0) + { + cond = TRUE; + } + } + conditionally_tokenize( cond, alr_ign ); +} + +/* For future functions, use conditl.BlankTemplate.c */ + +/* ************************************************************************** + * + * Here, at long last, we define and initialize the structure containing + * all the functions we support for Conditional Operators. + * + **************************************************************************** */ + +#define ADD_CONDL(str, func ) BUILTIN_BOOL_TIC(str, func, already_ignoring ) + +static tic_bool_hdr_t conditionals_vocab_tbl[] = { + ADD_CONDL ("[ifexist]" , if_exists ) , + ADD_CONDL ("[ifexists]" , if_exists ) , + ADD_CONDL ("#ifexist" , if_exists ) , + ADD_CONDL ("#ifexists" , if_exists ) , + ADD_CONDL ("[#ifexist]" , if_exists ) , + ADD_CONDL ("[#ifexists]" , if_exists ) , + ADD_CONDL ("[ifnexist]" , if_not_exist ) , + ADD_CONDL ("#ifnexist" , if_not_exist ) , + ADD_CONDL ("[#ifnexist]" , if_not_exist ) , + ADD_CONDL ("[ifdef]" , if_defined ) , + ADD_CONDL ("#ifdef" , if_defined ) , + ADD_CONDL ("[#ifdef]" , if_defined ) , + ADD_CONDL ("[ifndef]" , if_not_defined ) , + ADD_CONDL ("#ifndef" , if_not_defined ) , + ADD_CONDL ("[#ifndef]" , if_not_defined ) , + ADD_CONDL ("[if]" , if_from_stack ) +}; + + +/* ************************************************************************** + * + * Function name: init_conditionals_vocab + * Synopsis: Initialize the "Conditionals Vocabulary Table" + * link-pointers dynamically, and link it in + * with the given ("Global") Vocabulary pointer. + * + **************************************************************************** */ + +void init_conditionals_vocab( tic_hdr_t **tic_vocab_ptr ) +{ + static const int conditionals_vocab_max_indx = + sizeof(conditionals_vocab_tbl)/sizeof(tic_bool_hdr_t); + + init_tic_vocab( (tic_hdr_t *)conditionals_vocab_tbl, + conditionals_vocab_max_indx, + tic_vocab_ptr ); +} +
Added: fcode-utils/toke/conditl.h =================================================================== --- fcode-utils/toke/conditl.h (rev 0) +++ fcode-utils/toke/conditl.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,46 @@ +#ifndef _TOKE_CONDITL_H +#define _TOKE_CONDITL_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Function Prototypes for Conditional-Compilation support for Tokenizer + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +#include "types.h" +#include "ticvocab.h" + +void init_conditionals_vocab( tic_hdr_t **tic_vocab_ptr ); + +void skip_a_word( tic_bool_param_t pfield ); +void skip_a_word_in_line( tic_bool_param_t pfield ); +void skip_two_words_in_line( tic_bool_param_t pfield ); + +#endif /* _TOKE_CONDITL_H */
Added: fcode-utils/toke/devnode.c =================================================================== --- fcode-utils/toke/devnode.c (rev 0) +++ fcode-utils/toke/devnode.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,595 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Support routines for managing device-node vocabularies + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * The vocabulary that is created for a device-node must not remain + * available outside of that node. Also, nodes may be nested, + * child within parent. + * An attempt within a child-node to access directly a method defined + * in the parent must be flagged as an error. (Consider what would + * happen if the method in the parent-node used instance data, and + * the child-node has an instance of its own.) + * The correct way is to invoke the method via "$call-parent" or the like. + * + * We will, however, allow the user to specify a group of exceptions, + * words whose scope will be "global" within the tokenization. + * When "global" scope is initiated, definitions will be made to + * the "core" vocabulary until "device" scope is resumed. + * That will (mostly) all be handled in dictionary.c + * + **************************************************************************** */ + + +/* ************************************************************************** + * + * Functions Exported: + * new_device_vocab Create the new device-node's data-structure + * delete_device_vocab Remove device-node's data-structure + * finish_device_vocab Remove struct and give messages when + * device is "finish"ed. + * exists_in_ancestor Issue a Message if the given word exists + * in an ancestor of the current dev-node. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Still to be done: + * Add a pair of fields to the data-structure for the Input File and + * Line Number where "finish-device" occurred. When a device-node + * is "finish"ed, do not delete it, but instead fill in those + * fields and the move the node to a separate linked-list. + * When looking whether a word exists in an ancestor-node, also + * check whether it was in a device-node that was finished and + * print both where it was started and where it was finished. + * + **************************************************************************** */ + + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "devnode.h" +#include "errhandler.h" +#include "scanner.h" +#include "vocabfuncts.h" +#include "flowcontrol.h" +#include "stream.h" +#include "ticvocab.h" + + +/* ************************************************************************** + * + * Tokenization starts with an implicit "new-device" in effect. + * The top-level device-node is never removed. + * + * Initialize it here + * + **************************************************************************** */ +char default_top_dev_ifile_name[] = "Start of tokenization"; + +static device_node_t top_level_dev_node = { + NULL , /* parent_node */ + default_top_dev_ifile_name , /* ifile_name. + * Something to show, Just In Case + */ + 0 , /* line_no */ + NULL , /* tokens_vocab */ +}; + +/* ************************************************************************** + * + * Global Variables Exported. + * Pointers to: + * current_device_node data-structure of current device-node + * current_definitions vocab into which to add def'ns. + * + **************************************************************************** */ + +device_node_t *current_device_node = &top_level_dev_node; +tic_hdr_t **current_definitions = &(top_level_dev_node.tokens_vocab); + + +/* ************************************************************************** + * + * Internal Static Variables + * These are used to support the routines in_what_node() + * and show_node_start() , which are used to facilitate + * certain kinds of Messaging, as described later. + * + * in_what_buffr Buffer for the in_what_node() string + * show_where TRUE if the string needs to be followed-up + * show_which TRUE if follow-up should be just_where_started() + * rather than just_started_at() + * in_what_line Line Number to use in the follow-up + * in_what_file File Name to use in the follow-up + * + **************************************************************************** */ + +static char in_what_buffr[50]; /* Ought to be more than enough. */ +static bool show_where = FALSE; +static bool show_which; +static int in_what_line; +static char *in_what_file; + + +/* ************************************************************************** + * + * Function name: dev_vocab_control_struct_check + * Synopsis: Issue Warnings for unresolved flow-control constructs + * at start or end of a device-node. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * statbuf The command being processed. + * + * Outputs: + * Returned Value: NONE + * Printout: + * Handled by announce_control_structs() routine + * + * Error Detection: + * Handled by announce_control_structs() routine + * + * Process Explanation: + * Set up a buffer with the error message, based on statbuf + * and pass it to announce_control_structs() + * Release it when done. + * + **************************************************************************** */ + +static void dev_vocab_control_struct_check( void) +{ + char *ccs_messg; + + ccs_messg = safe_malloc(strlen(statbuf) + 32, + "Device-Node control-structure check"); + + strcpy( ccs_messg, statbuf ); + strupr( ccs_messg); + strcat( ccs_messg, " encountered"); + announce_control_structs( WARNING, ccs_messg, 0 ); + free( ccs_messg); +} + + + +/* ************************************************************************** + * + * Function name: new_device_vocab + * Synopsis: Create and initialize the data-structure for a + * new device-node when a "new-device" is created, + * with messages as appropriate. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * statbuf The word that was just read. + * iname Current Input-File Name + * lineno Current line-number + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * current_device_node Will point to the new data-structure + * Memory Allocated + * Space for the new device_node_t data-structure + * Space for a copy of the current input file name + * When Freed? + * By delete_device_vocab(), when the device-node is "finish"ed. + * Printout: + * Advisory message. + * + * Error Detection: + * In immediate-execution mode, Control Structures that have not + * been completed are questionable; Issue WARNINGS via the + * dev_vocab_control_struct_check() routine. + * + * Process Explanation: + * This routine is called when "new-device" is invoked, but only + * if we are in immediate-execution mode. + * Later on, in ERROR- or INFOrmative messages, we will want to + * be able to refer to the file and line-number in which this + * was encountered, so we include them in the structure. + * + **************************************************************************** */ + +void new_device_vocab( void ) +{ + device_node_t *new_node_data; + + dev_vocab_control_struct_check(); + + /* Advisory message will mention previous device-node + * if there was one. Either way starts out the same: + */ +#define NEW_DEV_MSG_START "Encountered %s. Starting new device-node." + + if ( current_device_node == &top_level_dev_node ) + { + tokenization_error(INFO, NEW_DEV_MSG_START "\n", statbuf ); + }else{ + tokenization_error(INFO, NEW_DEV_MSG_START + " Suspending definitions of parent-device node", statbuf ); + started_at( current_device_node->ifile_name, + current_device_node->line_no ); + } + + /* Now to business... */ + new_node_data = safe_malloc( sizeof(device_node_t), + "creating new-device vocab data" ); + new_node_data->parent_node = current_device_node; + new_node_data->ifile_name = strdup(iname); + new_node_data->line_no = lineno; + new_node_data->tokens_vocab = NULL; + + current_device_node = new_node_data; + + current_definitions = &(current_device_node->tokens_vocab); +} + + +/* ************************************************************************** + * + * Function name: delete_device_vocab + * Synopsis: Remove the vocabularies of the current device-node, + * along with its data-structure, when the device + * is "finish"ed; do not print messages. + * Do not remove the top-level device-node data-struct. + * + * Associated FORTH words: FINISH_DEVICE (interpretive state) + * END0 END1 + * Associated Tokenizer directives: RESET-SYMBOLS (in "Normal" mode) + * FCODE-END + * + * Inputs: + * Parameters: NONE + * Global Variables: + * current_device_node Points to current device's struct + * Leads to chain of dev-node structs + * + * Outputs: + * Returned Value: + * Global Variables: + * current_device_node Parent-device's struct becomes current + * Memory Freed + * All that was allocated for the tokens and the definers + * vocabs in the current device-node + * The copy of the input file name, except the top-level + * The current_device_node data-structure, except the top-level + * + **************************************************************************** */ + +void delete_device_vocab( void ) +{ + reset_tic_vocab( current_definitions, NULL ); + + if ( current_device_node != &top_level_dev_node ) + { + device_node_t *temp_node = current_device_node; + current_device_node = current_device_node->parent_node; + free( temp_node->ifile_name ); + free(temp_node); + } + + current_definitions = &(current_device_node->tokens_vocab); +} + +/* ************************************************************************** + * + * Function name: finish_device_vocab + * Synopsis: Remove the device-node data-structure and all its + * vocabularies when the device is "finish"ed, + * with appropriate messages. + * Do not remove the top-level device node data-struct. + * + * Associated FORTH word: FINISH_DEVICE + * + * Inputs: + * Parameters: NONE + * Global Variables: + * current_device_node Current device's struct pointer + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * current_device_node Parent-device's struct becomes current + * Printout: + * Advisory message. + * + * Error Detection: + * If current_device_node is already pointing at the top-level + * device node, it means there was no corresponding NEW-DEVICE + * Issue an ERROR. + * In immediate-execution mode, Control Structures that have not + * been completed are questionable; Issue WARNINGS via the + * dev_vocab_control_struct_check() routine. + * + * Process Explanation: + * This routine is called when "finish-device" is invoked, but only + * if we are in immediate-execution mode. + * + **************************************************************************** */ + +void finish_device_vocab( void ) +{ + bool at_top_level; + + dev_vocab_control_struct_check(); + + /* We never remove the top-level device-node vocabulary, + * so we need to test whether we're about to. + */ + + at_top_level = BOOLVAL( current_device_node == &top_level_dev_node ); + if ( at_top_level ) + { + tokenization_error( TKERROR, + "Encountered %s without corresponding NEW-DEVICE. " + "Resetting definitions since start of tokenization.\n", + statbuf ); + }else{ + tokenization_error(INFO, + "Encountered %s. Resetting definitions of device node", + statbuf ); + started_at( current_device_node->ifile_name, + current_device_node->line_no ); + } + + /* Now to business... */ + delete_device_vocab(); + + /* Did we just get to the top-level device-node vocabulary + * when we weren't before? + */ + if ( INVERSE(at_top_level) ) + { + if ( current_device_node == &top_level_dev_node ) + { + tokenization_error(INFO, + "Resuming definitions since start of tokenization.\n" ); + }else{ + tokenization_error(INFO, + "Resuming definitions of parent device-node" ); + started_at( current_device_node->ifile_name, + current_device_node->line_no ); + } + } +} + + +/* ************************************************************************** + * + * Function name: in_what_node + * Synopsis: Format a string for use in a Message that might + * identify the start of the given device-node. + * + * Inputs: + * Parameters: + * the_node The device-node vocabulary about which + * to construct the identifying phrase. + * Local Static Variables: + * in_what_buffr Buffer in which to format the string. + * Global Variables: + * current_definitions Device-node vocabulary currently + * in effect. + * + * Outputs: + * Returned Value: Pointer to buffer w/ formatted string + * Local Static Variables: + * in_what_buffr Will contain the formatted string. + * show_where TRUE if the string needs to be followed-up + * (i.e., did not contain a terminating + * new-line) by just_where_started() + * or by just_started_at() + * show_which TRUE if the follow-up call should be + * to just_where_started() rather + * than to just_started_at() + * in_what_line Copy of line_no field from the_node + * in_what_file Copy of ifile_name field from the_node + * + * Process Explanation: + * Calling routine must ascertain that Global-scope is not in effect. + * The returned phrase can be used as a string argument in a Message. + * Set show_where TRUE if the_node->line_no is non-zero. + * Set show_which TRUE if the_node is either the Current or the + * Top-Level device-node + * If the originating line-number in the given Node structure is zero, + * the returned phrase will contain a terminating new-line. + * (This only happens if the given Node is the top-level Node, + * and it's the Current Node, and the "official" starting-point + * hasn't yet been established by an "FCode-Starter" such as + * FCODE-VERSION2 . Once that command has been given, even + * definitions that were made prior to it belong to the Node + * that started there.) + * Otherwise, show_where is returned TRUE, and show_which becomes + * relevant. If the given node is the Current or the Top-Level + * node, text about the originating file-name and line-number + * merely describes a node that is already uniquely identified, + * so the message appended to the buffer will have the phrase + * "which began" (which introduces what is known in grammar as + * an Appositive Subordinate Clause) and show_which will be + * returned TRUE. If the given node is not uniquely identifiable + * without the file- and line- phrase, then the Subordinate Clause + * is Indicative, and should be introduced with "that" (and no + * comma); in that case, we will return show_which as FALSE. + * After the calling routine displays the message in which the + * returned phrase is used, it must call show_node_start() + * to display the followe-up message, if any. + * + **************************************************************************** */ + +char *in_what_node(device_node_t *the_node) +{ + bool top_node = BOOLVAL( the_node == &top_level_dev_node); + bool curr_node = BOOLVAL( the_node == current_device_node); + bool known_node = BOOLVAL( top_node || curr_node ); + bool no_line = BOOLVAL( the_node->line_no == 0); + + show_where = INVERSE( no_line ); + show_which = known_node; + in_what_line = the_node->line_no; + in_what_file = the_node->ifile_name; + + sprintf( in_what_buffr, "in the%s device-node%s", + INVERSE( known_node ) ? "" + : top_node ? " top-level" : " current" , + + no_line ? ".\n" + : known_node ? ", which began" : "" ); + + + return( in_what_buffr); +} + + +/* ************************************************************************** + * + * Function name: show_node_start + * Synopsis: Follow-up to the in_what_node() call. Print out, + * if applicable, the text about the originating + * file-name and line-number + * + * Inputs: + * Parameters: NONE + * Local Static Variables: + * show_where Nothing to do if not TRUE + * show_which TRUE if should call just_where_started() + * rather than just_started_at() + * in_what_line Line Number to use in the follow-up + * in_what_file File Name to use in the follow-up + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * show_where Force to FALSE + * Printout: + * Follow-up to the in_what_node() call. Applicable text + * about the originating file-name and line-number. + * + * Process Explanation: + * By forcing show_where to FALSE after this is called, we + * can safely allow routines that might or might not have + * called in_what_node() to call this routine, without + * needing any additional "bookkeeping". + * + **************************************************************************** */ + +void show_node_start( void) +{ + if ( show_where) + { + if ( show_which ) + { + just_where_started( in_what_file, in_what_line); + }else{ + just_started_at( in_what_file, in_what_line); + } + show_where = FALSE; + } +} + + + +/* ************************************************************************** + * + * Function name: exists_in_ancestor + * Synopsis: Issue a Message and return an indication if + * the given word exists in an ancestor of + * the current device-node. + * Used for additional error-message information. + * + * + * Inputs: + * Parameters: + * m_name "Method" name + * Global Variables: + * current_device_node Leads to chain of dev-node data-structs + * scope_is_global TRUE if "global" scope is in effect + * + * Outputs: + * Returned Value: TRUE if word found + * Printout: + * If m_name exists in an ancestor-node, print an ADVISORY + * giving the location where the ancestor originated. + * + * Error Detection: + * None here. Calling routine detected error; see below. + * + * Process Explanation: + * This routine was called as the result of detecting an error: + * viz., m_name was not found in either the current node + * or the base vocabulary. (Except: If "global" scope is + * in effect, we didn't search the current device-node). + * + **************************************************************************** */ + +bool exists_in_ancestor( char *m_name) +{ + tic_hdr_t *found; + bool retval = FALSE; + if ( current_device_node != NULL ) + { + device_node_t *grandpa = current_device_node->parent_node; + + if ( scope_is_global ) grandpa = current_device_node; + + for ( ; grandpa != NULL; grandpa = grandpa->parent_node ) + { + found = lookup_tic_entry( m_name, grandpa->tokens_vocab); + if ( found != NULL ) + { + retval = TRUE; + break; + } + } + if ( grandpa != NULL ) + { + char as_what_buf[32] = ""; + if ( as_a_what( found->fword_defr, as_what_buf) ) + { + strcat( as_what_buf, " "); + } + tokenization_error(INFO, "%s is defined %s%s", m_name, + as_what_buf, in_what_node( grandpa) ); + show_node_start(); + } + } + + return(retval ); +}
Added: fcode-utils/toke/devnode.h =================================================================== --- fcode-utils/toke/devnode.h (rev 0) +++ fcode-utils/toke/devnode.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,86 @@ +#ifndef _TOKE_DEVNODE_H +#define _TOKE_DEVNODE_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * External/Prototype/Structure definitions for device-node management + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +#include <stdio.h> +#include <stdlib.h> + +#include "types.h" +#include "ticvocab.h" + +/* ************************************************************************** + * Structure Name: device_node_t + * Data for managing a device node; pointers + * to vocabs, data for messaging. + * + * Fields: + * parent_node Pointer to similar data for parent node + * line_no Copy of Line Number where "new-device" was invoked + * ifile_name Name of Input File where "new-device" was invoked + * tokens_vocab Pointer to vocab for this device's tokens + * + **************************************************************************** */ + +typedef struct device_node { + struct device_node *parent_node ; + char *ifile_name ; + unsigned int line_no ; + tic_hdr_t *tokens_vocab ; +} device_node_t; + + +/* ************************************************************************** * + * + * Global Variables Exported + * + **************************************************************************** */ + +extern char default_top_dev_ifile_name[]; +extern device_node_t *current_device_node; +extern tic_hdr_t **current_definitions; + +/* ************************************************************************** * + * + * Function Prototypes / Functions Exported: + * + **************************************************************************** */ +void new_device_vocab( void ); +void delete_device_vocab( void ); +void finish_device_vocab( void ); +char *in_what_node(device_node_t *the_node); +void show_node_start( void); +bool exists_in_ancestor( char *m_name); + +#endif /* _TOKE_DEVNODE_H */
Modified: fcode-utils/toke/dictionary.c =================================================================== --- fcode-utils/toke/dictionary.c 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/dictionary.c 2006-08-18 12:47:12 UTC (rev 76) @@ -24,6 +24,12 @@ * */
+/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + #include <stdio.h> #include <stdlib.h> #if defined(__linux__) && ! defined(__USE_BSD) @@ -32,543 +38,2008 @@ #include <string.h> #include <errno.h>
-#include "toke.h" +#include "emit.h" +#include "macros.h" +#include "scanner.h" +#include "ticvocab.h" #include "dictionary.h" +#include "vocabfuncts.h" +#include "devnode.h" +#include "clflags.h" +#include "parselocals.h" +#include "errhandler.h" +#include "tokzesc.h" +#include "conditl.h"
-typedef struct token { - u8 *name; - u16 fcode; - struct token *next; -} token_t; +/* ************************************************************************** + * + * Revision History: + * Updated Fri, 29 Jul 2005 by David L. Paktor + * Retrofit to handle "Current Device" as a separate vocabulary; + * if one is in effect, searches through it occur first, as + * do definitions to it, ahead of the general vocabulary. This + * is to support managing device-node vocabularies correctly. + * Updated Mon, 12 Dec 2005 by David L. Paktor + * Allow the user to specify a group of exceptions, words whose + * scope will be "global" within the tokenization. Under "global" + * scope, definitions will be made to the "core" vocabulary. + * + * Wed, 14 Dec 2005 by David L. Paktor + * Found a problem with the current approach. Need to be able to + * temporarily suspend meaning of "instance". Define: (1) an + * alias for INSTANCE called GENERIC_INSTANCE (2) a macro + * called INSTANCE that effectively no-ops it out; and, when + * it is time to restore "INSTANCE" to normal functionality, + * (3) an alias for GENERIC_INSTANCE called INSTANCE . + * Problem is that macros are treated as a separate vocabulary + * from FWords (and their aliases) and searching one before the + * other (either way) renders the second one searched unable to + * supercede the first one: If macros are searched first, (2) + * will be found ahead of the built-in FWord (which is what we + * want) but later, when we search for (3) among the FWords, it + * will not be found ahead of (2). If, on the other hand, we + * search FWords first, the macro defined in (2) will never be + * found. + * We need a way to define both (all?) types of definitions in a + * single vocabulary that will honor the LIFO order of def'ns. + * + * Mon, 19 Dec 2005 by David L. Paktor + * Begin development of implementation of a way to define both (all?) + * types of definitions in a single tic_hdr_t type vocabulary. + * + **************************************************************************** */
-static token_t *dictionary=NULL; -static token_t *forthwords=NULL;
-static u16 lookup_token_dict(char *name, token_t *dict) + +/* ************************************************************************** + * + * We will be creating several different lists of initial built-in + * definitions; together, they constitute the Global Vocabulary. + * (We will avoid the term "dictionary", since, in classical + * Forth terminology, it refers to the complete collection of + * vocabularies in an application.) The usage of the pointer + * to the Global Vocabulary is central to the operation of this + * program and the maintenance programmer needs to understand it. + * We may also refer to the Global Vocabulary as the "core" vocab. + * + * Each initial list will be created as an array of TIC-header entries. + * Because the global vocabulary is expandable by the user, + * we will not be searching the lists as arrays but rather as + * linked-lists; the run-time initialization routine will fill + * in their link-fields and also will link the various lists + * together, so we can group their initial declarations according + * to our convenience. + * + * A single pointer, called the "Global Vocabulary Dictionary Pointer" + * (okay, so classical Forth terminology isn't completely rigorous...) + * and abbreviated GV_DP, will point to the "tail" of the "thread". + * Similar vocabularies will be created for the device-nodes; look + * in the file devnode.fth for a more detailed discussion of those. + * + * The "FC-Tokens" list contains the names and FCode numeric tokens + * of the straightforward FORTH words that simply write a token + * directly to the tokenized output. We need to access these + * without being confused by aliases or other distractions, so + * we will keep a pointer to them especially for that purpose. + * Therefore it is IMPORTANT: that the "FC-Tokens" list MUST be the + * first table linked by the initialization routine, so that its + * last-searched entry's link-field is NULL. + * + * The "FWords" list contains FORTH words that require additional + * special action at tokenization-time. Their numeric values + * are derived from the fword_token enumeration declaration, + * and are used as the control-expression for a SWITCH statement + * with a large number of CASE labels in the handle_internal() + * function. + * + * The "Shared Words" list contains FORTH words that can be executed + * similarly both during "Tokenizer Escape" mode (i.e., the scope + * of the special brackets: tokenizer[ ... ]tokenizer ) and + * also within "Normal Tokenization" mode. Their numeric values + * are derived and used the same way as the "FWords". Since we + * will be needing to do a separate search through them at times, + * we will also need a lower-bracket pointer for them. (An upper + * bracket is irrelevant for these, because aliases can be added. + * This is not the case for the "FC-Tokens" list, because searches + * through those will be conducted from within this program.) + * + * The "definer" field in the TIC-header structure is primarily used to + * detect attempts to apply the TO directive to an inappropriate + * target. Its numeric values are a subset of the "FWord tokens". + * Certain "FC-Token" names are specified to be valid TO targets; + * their entries' "definer" fields will be initialized accordingly. + * Entries in FWord Token lists that are "shared" between "Normal + * Tokenization" and "Tokenizer Escape" modes will have their + * "definer" fields initialized to COMMON_FWORD . All other + * entries' "definer" fields will be initialized to UNSPECIFIED . + * + * Other files maintain and support additional lists with the same + * structure, which need to be linked together with the lists + * declared here. We prefer to keep the GV_DP private to this + * file, so it will be passed as a parameter where needed. (I'm + * not pleased to note, however, that it can't be kept completely + * private; it's needed for add_user_macro() and possibly other + * functions outside this file.) + * + * The words that can only be used during "Tokenizer Escape" mode and + * the IBM-style "Locals", as well as the device-node vocabularies, + * will need to be separate and will not be linked together with + * the Global Vocabulary. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * We'll be initializing the lists later, but will be referencing + * the pointers sooner, so we need to declare the pointers here. + * + * We will keep all of these pointers private to this file. + * + **************************************************************************** */ + +static tic_hdr_t *global_voc_dict_ptr = NULL; /* The Global Vocabulary */ +static tic_hdr_t *fc_tokens_list_ender = NULL; /* Tokens search ends here */ +static tic_hdr_t *fc_tokens_list_start = NULL; /* Start the search here */ +static tic_hdr_t *shared_fwords_ender = NULL; /* Shared FWords search end */ +static tic_hdr_t *global_voc_reset_ptr = NULL; /* Reset-point for G.V. */ + + +/* ************************************************************************** + * + * Function name: lookup_core_word + * Synopsis: Return a pointer to the data-structure of the named + * word in the "Global" Vocabulary + * + * Inputs: + * Parameters: + * tname The name to look up + * Local Static Variables: + * global_voc_dict_ptr "Tail" of Global Vocabulary + * + * Outputs: + * Returned Value: Pointer to the data-structure, or + * NULL if not found. + * + **************************************************************************** */ + +tic_hdr_t *lookup_core_word( char *tname) { - token_t *curr; - - for (curr=dict; curr!=NULL; curr=curr->next) - if (!strcasecmp(name,(char *)curr->name)) - break; + tic_hdr_t *found ;
- if (curr) - return curr->fcode; -#ifdef DEBUG_TOKE - printf("warning: token '%s' does not exist.\n", name); -#endif - return 0xffff; + found = lookup_tic_entry( tname, global_voc_dict_ptr); + return ( found ) ; }
-u16 lookup_token(char *name) +/* ************************************************************************** + * + * Function name: exists_in_core + * Synopsis: Confirm whether the given name exists in the + * Global (aka "core") Vocabulary. Search the + * Global Vocabulary exclusively. + * + * Inputs: + * Parameters: + * name The name for which to look + * Local Static Variables: + * global_voc_dict_ptr "Tail" of Global Vocabulary + * + * Outputs: + * Returned Value: TRUE if name is found. + * + **************************************************************************** */ + +bool exists_in_core( char *name) { - return lookup_token_dict(name, dictionary); + return exists_in_tic_vocab( name, global_voc_dict_ptr ); }
-u16 lookup_fword(char *name) +/* ************************************************************************** + * + * Function name: handle_core_word + * Synopsis: Perform a function in the "Global" Vocabulary and + * indicate whether the name is valid. + * + * Inputs: + * Parameters: + * tname The name to handle + * Local Static Variables: + * global_voc_dict_ptr "Tail" of Global Vocabulary + * + * Outputs: + * Returned Value: TRUE if the given name is valid in Global Vocab + * + * Error Detection: + * If the name is not in the "Global" Vocabulary, let the calling + * routine determine whether to print an error message or to + * try it out as a number. + * + **************************************************************************** */ + +bool handle_core_word( char *tname ) { - return lookup_token_dict(name, forthwords); + bool retval; + + retval = handle_tic_vocab( tname, global_voc_dict_ptr ); + + return ( retval ) ; }
-static int add_token_dict(u16 number, char *name, token_t **dict) + +/* ************************************************************************** + * + * Function name: create_core_alias + * Synopsis: Create, in the "Global" ("core") Vocabulary, an entry + * for NEW_NAME that behaves the same as the latest + * definition of OLD_NAME, and whose behavior will + * not change even if a new definition of OLD_NAME + * is overlaid. Indicate if successful. + * + * Inputs: + * Parameters: + * new_name The name for the new alias to be created + * old_name The name of the old function to be duplicated + * Local Static Variables: + * global_voc_dict_ptr "Tail" of Global Vocabulary + * + * Outputs: + * Returned Value: TRUE if OLD_NAME was found. + * Local Static Variables: + * global_voc_dict_ptr Updated with the new entry + * Memory Allocated + * By support routine. + * + * Process Explanation: + * Both the "old" and "new" names are presumed to already point to + * stable, freshly allocated memory-spaces. + * + **************************************************************************** */ + +bool create_core_alias( char *new_name, char *old_name) { - token_t *curr; + bool retval = create_tic_alias( new_name, old_name, &global_voc_dict_ptr); + return ( retval ); +}
- curr=malloc(sizeof(token_t)); - if(!curr) { - printf("Out of memory while adding token.\n"); - exit(-ENOMEM); +/* ************************************************************************** + * + * The functions that go into the various lists' FUNCT field may be + * defined below, or might be defined externally. + * + * Often, we will need a function that merely recasts the type of the + * parameter field before passing it to the function that does + * the actual work. + * + * Prologs will be brief or even non-existent. + * + * Initialization macro definitions will accompany the functions. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * For the "FCode-Tokens" list, simply generate the token directly. + * We need this layer for param type conversion. + * In case we're ever able to eliminate it, (or just on General + * Principles) we'll invoke it via a macro... + * + **************************************************************************** */ + +static void emit_fc_token( tic_param_t pfield) +{ + u16 fc_tok = (u16)pfield.deflt_elem; + emit_fcode( fc_tok); +} + +#define FC_TOKEN_FUNC emit_fc_token + +#define BUILTIN_FCODE( tok, nam) \ + VALPARAM_TIC(nam, FC_TOKEN_FUNC, tok , UNSPECIFIED ) + +/* Built-in FCodes with known definers: */ +#define BI_FCODE_VALUE( tok, nam) \ + VALPARAM_TIC(nam, FC_TOKEN_FUNC, tok , VALUE ) + +#define BI_FCODE_VRBLE( tok, nam) \ + VALPARAM_TIC(nam, FC_TOKEN_FUNC, tok , VARIABLE ) + +#define BI_FCODE_DEFER( tok, nam) \ + VALPARAM_TIC(nam, FC_TOKEN_FUNC, tok , DEFER ) + +#define BI_FCODE_CONST( tok, nam) \ + VALPARAM_TIC(nam, FC_TOKEN_FUNC, tok , CONST ) + +/* ************************************************************************** + * + * The "FCode-Tokens" list includes tokens that are identified + * in the Standard as Obsolete. We will define a function + * that issues a WARNING before generating the token, and + * assign it to those elements of the list. + * + * Control the message via a command-line flag. + * + **************************************************************************** */ + +static void obsolete_warning( void) +{ + if ( obso_fcode_warning ) + { + tokenization_error( WARNING, "%s is an Obsolete FCode.\n", + strupr(statbuf) ); + } +} + +static void obsolete_fc_token( tic_param_t pfield) +{ + obsolete_warning(); + emit_fc_token( pfield); +} + +#define OBSO_FC_FUNC obsolete_fc_token + +#define OBSOLETE_FCODE( tok, nam) \ + VALPARAM_TIC(nam, OBSO_FC_FUNC, tok , UNSPECIFIED ) + +#define OBSOLETE_VALUE( tok, nam) \ + VALPARAM_TIC(nam, OBSO_FC_FUNC, tok , VALUE ) + + +/* ************************************************************************** + * + * The function for most of the "FWords" list, handle_internal() , + * is defined externally, but not exported in a .h file, + * because we want to keep it as private as possible. + * We will declare its prototype here. + * + * Initialization macros for both "Normal Mode"-only and + * "Shared" entries are also defined here. + * + * Arguments: + * fwt (fword_token) Value of the FWord Token (from Enum list) + * nam (string) Name of the entry as seen in the source + * + **************************************************************************** */ + +void handle_internal( tic_param_t pfield); +/* "Skip-a-string when Ignoring" function. Same args and limited-proto ... */ +void skip_string( tic_param_t pfield); + +#define FWORD_EXEC_FUNC handle_internal + +#define BUILTIN_FWORD( fwt, nam) \ + FWORD_TKN_TIC(nam, FWORD_EXEC_FUNC, fwt, BI_FWRD_DEFN ) + +#define SHARED_FWORD( fwt, nam) \ + FWORD_TKN_TIC(nam, FWORD_EXEC_FUNC, fwt, COMMON_FWORD ) + +/* Variants: When Ignoring, SKip One Word */ +#define SHR_FWD_SKOW( fwt, nam) \ + DUALFUNC_FWT_TIC(nam, FWORD_EXEC_FUNC, fwt, skip_a_word, COMMON_FWORD ) + +/* Variants: When Ignoring, SKip one Word in line */ +#define SH_FW_SK_WIL( fwt, nam) \ + DUALFUNC_FWT_TIC(nam, FWORD_EXEC_FUNC, fwt, \ + skip_a_word_in_line, COMMON_FWORD ) + +/* When Ignoring, SKip Two Words in line */ +#define SH_FW_SK2WIL( fwt, nam) \ + DUALFUNC_FWT_TIC(nam, FWORD_EXEC_FUNC, fwt, \ + skip_two_words_in_line, COMMON_FWORD ) + +/* ************************************************************************** + * + * Some of the entries in the "FWords" list -- both "Normal" (Built-in) + * and "Shared" also act as an "Ignore-handler". + * + * Arguments: + * nam (string) Name of the entry as seen in the source + * afunc (routine-name) Name of internal "active" function + * pval (integer) The "param field" item + * ifunc (routine-name) Name of "ignore-handling" function + * + **************************************************************************** */ + +#define SHARED_IG_HDLR(nam, afunc, pval, ifunc) \ + DUFNC_FWT_PARM(nam, afunc, pval, ifunc, COMMON_FWORD ) + +/* A "Shared" entry that uses the same routine for both of its functions */ +#define SHR_SAMIG_FWRD( fwt, nam) \ + DUFNC_FWT_PARM(nam, FWORD_EXEC_FUNC, fwt, FWORD_EXEC_FUNC, COMMON_FWORD ) + +/* ************************************************************************** + * + * But the "Normal" (Built-in) FWord Ignore-handler uses the same + * routine as the BUILTIN_FWORD for both of its functions. + * + * Arguments: + * fwt (fword_token) Value of the FWord Token (from Enum list) + * nam (string) Name of the entry as seen in the source + * + **************************************************************************** */ +#define BI_IG_FW_HDLR( fwt, nam) \ + DUALFUNC_FWT_TIC(nam, FWORD_EXEC_FUNC, fwt, FWORD_EXEC_FUNC, BI_FWRD_DEFN ) + +/* A variant: A "Built-In FWorD that SKiPs One Word", when Ignoring */ +#define BI_FWD_SKP_OW( fwt, nam) \ + DUALFUNC_FWT_TIC(nam, FWORD_EXEC_FUNC, fwt, skip_a_word, BI_FWRD_DEFN ) + +/* Another variant: A "Built-In FWorD String". skip_string when Ignoring */ +#define BI_FWD_STRING( fwt, nam) \ + DUALFUNC_FWT_TIC(nam, FWORD_EXEC_FUNC, fwt, skip_string, BI_FWRD_DEFN ) + +/* ************************************************************************** + * + * In order to protect device-nodes' methods from being accessed + * by other device-nodes (with the attendant potential for + * disastrous consequences), we must establish a few rules: + * + * Each device-node has a separate vocabulary for its methods. + * New definitions are made to the "current" device's vocabulary. + * Searches for names go through the "current" device-node's + * vocabulary first, then through the core dictionary. + * + * A new-device (in interpretation-mode) creates a new device-node + * vocabulary. The node that had been current (presumably its + * parent) remains in memory but inactive. + * + * A finish-device (again, only in interpretation-mode) removes the + * current device-node's vocabulary from memory; its presumed + * parent once again becomes current. + * + * Tokenization starts with an implicit "new-device" in effect. + * The top-level device-node is never removed. + * + * The Global Variable current_definitions points to the vocabulary + * to which we will add and through which we will search first. + * + * If "global" scope is in effect, then current_definitions will + * point to the "Global" (also called "core") vocabulary. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Support for operations in "current" -- i.e., "global" vis-a-vis + * "device" -- scope. + * "Global" scope will not recognize words defined in "device" scope, + * but "device" scope will recognize "global" words. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Functions to enter "global" scope and resume "device" scope. + * + **************************************************************************** */ + +static tic_hdr_t **save_device_definitions; +/* Export the indication that "global" scope is in effect */ +bool scope_is_global = FALSE; + + +void enter_global_scope( void ) +{ + if ( scope_is_global ) +{ + tokenization_error( WARNING, + "%s -- Global Scope already in effect; ignoring.\n", + strupr(statbuf) ); + }else{ + tokenization_error( INFO, + "Initiating Global Scope definitions.\n" ); + scope_is_global = TRUE; + save_device_definitions = current_definitions; + current_definitions = &global_voc_dict_ptr; + } +} + +void resume_device_scope( void ) +{ + if ( scope_is_global ) + { + tokenization_error( INFO, + "Terminating Global Scope definitions; " + "resuming Device-node definitions.\n" ); + current_definitions = save_device_definitions; + scope_is_global = FALSE; + }else{ + tokenization_error( WARNING, + "%s -- Device-node Scope already in effect; ignoring.\n", + strupr(statbuf) ); + } + +} + +/* ************************************************************************** + * + * Function name: lookup_current + * Synopsis: Return a pointer to the data-structure of the named + * word, either in the Current Device-Node vocab, + * or in the Global ("core") Vocabulary. + * + * Inputs: + * Parameters: + * tname The name to look for + * Global Variables: + * current_definitions Current vocabulary: Device-Node, or + * "core" if "global" scope in effect. + * scope_is_global TRUE if "global" scope is in effect + * Local Static Variables: + * global_voc_dict_ptr "Tail" of Global Vocabulary + * + * Outputs: + * Returned Value: Pointer to the data-structure, or + * NULL if not found. + * + * Process Explanation: + * If a current Device-Node Vocabulary in effect, search through it. + * If the given name was not found, and "global" scope is not in + * effect (i.e., "core" was not already searched), make a + * separate search through the Global ("core") Vocabulary + * + * Extraneous Remarks: + * This is the central routine for doing general word-searches that + * make use of the "normal"-mode search-list. + * + **************************************************************************** */ + +tic_hdr_t *lookup_current( char *tname) +{ + /* Search Current Device Vocabulary ahead of global (core) vocabulary */ + tic_hdr_t *retval; + retval = lookup_tic_entry( tname, *current_definitions); + if ( (retval == NULL) && INVERSE(scope_is_global) ) +{ + retval = lookup_core_word( tname); + } + return ( retval ); +} + +/* ************************************************************************** + * + * Function name: exists_in_current + * Synopsis: Confirm whether the given name exists either + * in the Current Device-Node vocab, + * or in the Global ("core") Vocabulary, + * or in Tokenizer Escape Mode, if that's current. + * + * Inputs: + * Parameters: + * tname The name to look for + * + * Outputs: + * Returned Value: TRUE if name is found + * + **************************************************************************** */ + +bool exists_in_current( char *tname) +{ + tic_hdr_t *found = lookup_word( tname, NULL, NULL); + bool retval = BOOLVAL ( found != NULL); + return( retval); }
- curr->next=*dict; - curr->fcode=number; - curr->name=(u8 *)name;
- *dict=curr; - return 0; +/* ************************************************************************** + * + * Function name: handle_current + * Synopsis: Perform a function in the current device-node vocab, + * if one is in effect, or in the "Global" Vocabulary. + * Indicate whether the name is valid. + * + * Inputs: + * Parameters: + * tname The name to handle + * Global Variables: + * current_definitions Device-Node (or Global) Vocabulary + * currently in effect. + * scope_is_global TRUE if "global" scope is in effect + * Local Static Variables: + * + * Outputs: + * Returned Value: TRUE if the given name is valid + * + **************************************************************************** */ + +bool handle_current( char *tname ) +{ + bool retval = handle_tic_vocab( tname, *current_definitions ); + + if ( INVERSE(retval) && INVERSE(scope_is_global) ) + { + retval = handle_core_word( tname ); + } + return ( retval ); + }
-int add_token(u16 number, char *name) + +/* ************************************************************************** + * + * Function name: lookup_in_dev_node + * Synopsis: Return a pointer to the data-structure of the + * named word in the Current device node, if + * in "Device" scope. Used for error-reporting. + * + * Inputs: + * Parameters: + * tname The name to look for + * Global Variables: + * current_definitions Device-Node (or Global) Vocabulary + * currently in effect. + * scope_is_global FALSE if "Device" scope is in effect + * + * Outputs: + * Returned Value: Pointer to the data-structure, or + * NULL if not found. + * + **************************************************************************** */ + +tic_hdr_t *lookup_in_dev_node( char *tname) { - return add_token_dict(number, name, &dictionary); + tic_hdr_t *retval = NULL; + + if ( INVERSE(scope_is_global) ) +{ + retval = lookup_tic_entry( tname, *current_definitions); } + return ( retval ); +}
-static int add_special(u16 number, char *name) + +/* ************************************************************************** + * + * In order to avoid unintentional "recursive"-ness, we need a way + * to render a newly created colon-definition non-findable + * until it's completed. + * + * We will accomplish this by saving and reverting the pointer to + * the newest entry, when we call the hide_last_colon() , and + * by restoring the pointer when we call reveal_last_colon() + * + * We need, therefore, to save the pointer to the last entry before + * we create the new entry. + * + **************************************************************************** */ + +/* Update this each time a new definition is entered */ +static tic_hdr_t *save_current = NULL; + +/* ************************************************************************** + * + * Function name: add_to_current + * Synopsis: Add a new entry to the "current" scope of definitions, + * which may be either the Global Vocabulary or the + * current Device-Node Vocabulary. + * + * Inputs: + * Parameters: + * name The name of the new entry + * fc_token The new entry's assigned FCode-number + * fw_definer The new entry's definer + * define_token If FALSE, suppress adding the entry, + * but preserve the side-effect of + * setting save_current + * Global Variables: + * current_definitions Pointer to pointer to "tail" of the + * Vocabulary currently in effect; + * either Device-node or Global. + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * *current_definitions Updated with the new entry + * Local Static Variables: + * save_current Pointer to previous entry + * Memory Allocated + * For the new entry's copy of the name. + * When Freed? + * When the Device-Node is "finish"ed or the Global Vocabulary + * is reset, or when the program exits. + * + * Process Explanation: + * Because current_definitions points to the Global Vocabulary + * pointer during "global" scope, this routine is extremely + * straightforward. + * All user-defined words have the same action, i.e., emitting + * the assigned FCode-number. The new entry's "parameter + * field" size is, of course, zero; the "ignore-function" + * is NULL. + * + * Extraneous Remarks: + * The define_token parameter is a late addition, necessitated + * by the decision to continue processing after an erroneous + * attempt to create a definition inside a control-structure, + * in order to catch other errors. + * + * + **************************************************************************** */ + +void add_to_current( char *name, + TIC_P_DEFLT_TYPE fc_token, + fwtoken definer, + bool define_token) { - return add_token_dict(number, name, &forthwords); + save_current = *current_definitions; + if ( define_token ) +{ + char *nu_name = strdup( name); + add_tic_entry( nu_name, FC_TOKEN_FUNC, fc_token, + definer, 0 , NULL, current_definitions ); + } }
-void init_dictionary(void) + +void hide_last_colon ( void ) { - add_token( 0x000, "end0" ); - add_token( 0x010, "b(lit)" ); - add_token( 0x011, "b(')" ); - add_token( 0x012, "b(")" ); - add_token( 0x013, "bbranch" ); - add_token( 0x014, "b?branch" ); - add_token( 0x015, "b(loop)" ); - add_token( 0x016, "b(+loop)" ); - add_token( 0x017, "b(do)" ); - add_token( 0x018, "b(?do)" ); - add_token( 0x019, "i" ); - add_token( 0x01a, "j" ); - add_token( 0x01b, "b(leave)" ); - add_token( 0x01c, "b(of)" ); - add_token( 0x01d, "execute" ); - add_token( 0x01e, "+" ); - add_token( 0x01f, "-" ); - add_token( 0x020, "*" ); - add_token( 0x021, "/" ); - add_token( 0x022, "mod" ); - add_token( 0x023, "and" ); - add_token( 0x024, "or" ); - add_token( 0x025, "xor" ); - add_token( 0x026, "invert" ); - add_token( 0x027, "lshift" ); - add_token( 0x028, "rshift" ); - add_token( 0x029, ">>a" ); - add_token( 0x02a, "/mod" ); - add_token( 0x02b, "u/mod" ); - add_token( 0x02c, "negate" ); - add_token( 0x02d, "abs" ); - add_token( 0x02e, "min" ); - add_token( 0x02f, "max" ); - add_token( 0x030, ">r" ); - add_token( 0x031, "r>" ); - add_token( 0x032, "r@" ); - add_token( 0x033, "exit" ); - add_token( 0x034, "0=" ); - add_token( 0x035, "0<>" ); - add_token( 0x036, "0<" ); - add_token( 0x037, "0<=" ); - add_token( 0x038, "0>" ); - add_token( 0x039, "0>=" ); - add_token( 0x03a, "<" ); - add_token( 0x03b, ">" ); - add_token( 0x03c, "=" ); - add_token( 0x03d, "<>" ); - add_token( 0x03e, "u>" ); - add_token( 0x03f, "u<=" ); - add_token( 0x040, "u<" ); - add_token( 0x041, "u>=" ); - add_token( 0x042, ">=" ); - add_token( 0x043, "<=" ); - add_token( 0x044, "between" ); - add_token( 0x045, "within" ); - add_token( 0x046, "drop" ); - add_token( 0x047, "dup" ); - add_token( 0x048, "over" ); - add_token( 0x049, "swap" ); - add_token( 0x04A, "rot" ); - add_token( 0x04b, "-rot" ); - add_token( 0x04c, "tuck" ); - add_token( 0x04d, "nip" ); - add_token( 0x04e, "pick" ); - add_token( 0x04f, "roll" ); - add_token( 0x050, "?dup" ); - add_token( 0x051, "depth" ); - add_token( 0x052, "2drop" ); - add_token( 0x053, "2dup" ); - add_token( 0x054, "2over" ); - add_token( 0x055, "2swap" ); - add_token( 0x056, "2rot" ); - add_token( 0x057, "2/" ); - add_token( 0x058, "u2/" ); - add_token( 0x059, "2*" ); - add_token( 0x05a, "/c" ); - add_token( 0x05b, "/w" ); - add_token( 0x05c, "/l" ); - add_token( 0x05d, "/n" ); - add_token( 0x05e, "ca+" ); - add_token( 0x05f, "wa+" ); - add_token( 0x060, "la+" ); - add_token( 0x061, "na+" ); - add_token( 0x062, "char+" ); - add_token( 0x063, "wa1+" ); - add_token( 0x064, "la1+" ); - add_token( 0x065, "cell+" ); - add_token( 0x066, "chars" ); - add_token( 0x067, "/w*" ); - add_token( 0x068, "/l*" ); - add_token( 0x069, "cells" ); - add_token( 0x06a, "on" ); - add_token( 0x06b, "off" ); - add_token( 0x06c, "+!" ); - add_token( 0x06d, "@" ); - add_token( 0x06e, "l@" ); - add_token( 0x06f, "w@" ); - add_token( 0x070, "<w@" ); - add_token( 0x071, "c@" ); - add_token( 0x072, "!" ); - add_token( 0x073, "l!" ); - add_token( 0x074, "w!" ); - add_token( 0x075, "c!" ); - add_token( 0x076, "2@" ); - add_token( 0x077, "2!" ); - add_token( 0x078, "move" ); - add_token( 0x079, "fill" ); - add_token( 0x07a, "comp" ); - add_token( 0x07b, "noop" ); - add_token( 0x07c, "lwsplit" ); - add_token( 0x07d, "wljoin" ); - add_token( 0x07e, "lbsplit" ); - add_token( 0x07f, "bljoin" ); - add_token( 0x080, "wbflip" ); - add_token( 0x081, "upc" ); - add_token( 0x082, "lcc" ); - add_token( 0x083, "pack" ); - add_token( 0x084, "count" ); - add_token( 0x085, "body>" ); - add_token( 0x086, ">body" ); - add_token( 0x087, "fcode-revision" ); - add_token( 0x088, "span" ); - add_token( 0x089, "unloop" ); - add_token( 0x08a, "expect" ); - add_token( 0x08b, "alloc-mem" ); - add_token( 0x08c, "free-mem" ); - add_token( 0x08d, "key?" ); - add_token( 0x08e, "key" ); - add_token( 0x08f, "emit" ); - add_token( 0x090, "type" ); - add_token( 0x091, "(cr" ); - add_token( 0x092, "cr" ); - add_token( 0x093, "#out" ); - add_token( 0x094, "#line" ); - add_token( 0x095, "hold" ); - add_token( 0x096, "<#" ); - add_token( 0x097, "u#>" ); - add_token( 0x098, "sign" ); - add_token( 0x099, "u#" ); - add_token( 0x09a, "u#s" ); - add_token( 0x09b, "u." ); - add_token( 0x09c, "u.r" ); - add_token( 0x09d, "." ); - add_token( 0x09e, ".r" ); - add_token( 0x09f, ".s" ); - add_token( 0x0a0, "base" ); - add_token( 0x0a1, "convert" ); - add_token( 0x0a2, "$number" ); - add_token( 0x0a3, "digit" ); - add_token( 0x0a4, "-1" ); - add_token( 0x0a5, "0" ); - add_token( 0x0a6, "1" ); - add_token( 0x0a7, "2" ); - add_token( 0x0a8, "3" ); - add_token( 0x0a9, "bl" ); - add_token( 0x0aa, "bs" ); - add_token( 0x0ab, "bell" ); - add_token( 0x0ac, "bounds" ); - add_token( 0x0ad, "here" ); - add_token( 0x0ae, "aligned" ); - add_token( 0x0af, "wbsplit" ); - add_token( 0x0b0, "bwjoin" ); - add_token( 0x0b1, "b(<mark)" ); - add_token( 0x0b2, "b(>resolve)" ); - add_token( 0x0b3, "set-token-table" ); - add_token( 0x0b4, "set-table" ); - add_token( 0x0b5, "new-token" ); - add_token( 0x0b6, "named-token" ); - add_token( 0x0b7, "b(:)" ); - add_token( 0x0b8, "b(value)" ); - add_token( 0x0b9, "b(variable)" ); - add_token( 0x0ba, "b(constant)" ); - add_token( 0x0bb, "b(create)" ); - add_token( 0x0bc, "b(defer)" ); - add_token( 0x0bd, "b(buffer:)" ); - add_token( 0x0be, "b(field)" ); - add_token( 0x0bf, "b(code)" ); - add_token( 0x0c0, "instance" ); - add_token( 0x0c2, "b(;)" ); - add_token( 0x0c3, "b(to)" ); - add_token( 0x0c4, "b(case)" ); - add_token( 0x0c5, "b(endcase)" ); - add_token( 0x0c6, "b(endof)" ); - add_token( 0x0c7, "#" ); - add_token( 0x0c8, "#s" ); - add_token( 0x0c9, "#>" ); - add_token( 0x0ca, "external-token" ); - add_token( 0x0cb, "$find" ); - add_token( 0x0cc, "offset16" ); - add_token( 0x0cd, "evaluate" ); - add_token( 0x0d0, "c," ); - add_token( 0x0d1, "w," ); - add_token( 0x0d2, "l," ); - add_token( 0x0d3, "," ); - add_token( 0x0d4, "um*" ); - add_token( 0x0d5, "um/mod" ); - add_token( 0x0d8, "d+" ); - add_token( 0x0d9, "d-" ); - add_token( 0x0da, "get-token" ); - add_token( 0x0db, "set-token" ); - add_token( 0x0dc, "state" ); - add_token( 0x0dd, "compile" ); - add_token( 0x0de, "behavior" ); - add_token( 0x0f0, "start0" ); - add_token( 0x0f1, "start1" ); - add_token( 0x0f2, "start2" ); - add_token( 0x0f3, "start4" ); - add_token( 0x0fc, "ferror" ); - add_token( 0x0fd, "version1" ); - add_token( 0x0fe, "4-byte-id" ); - add_token( 0x0ff, "end1" ); - add_token( 0x101, "dma-alloc" ); - add_token( 0x102, "my-address" ); - add_token( 0x103, "my-space" ); - add_token( 0x104, "memmap" ); - add_token( 0x105, "free-virtual" ); - add_token( 0x106, ">physical" ); - add_token( 0x10f, "my-params" ); - add_token( 0x110, "property" ); - add_token( 0x111, "encode-int" ); - add_token( 0x112, "encode+" ); - add_token( 0x113, "encode-phys" ); - add_token( 0x114, "encode-string" ); - add_token( 0x115, "encode-bytes" ); - add_token( 0x116, "reg" ); - add_token( 0x117, "intr" ); - add_token( 0x118, "driver" ); - add_token( 0x119, "model" ); - add_token( 0x11a, "device-type" ); - add_token( 0x11b, "parse-2int" ); - add_token( 0x11c, "is-install" ); - add_token( 0x11d, "is-remove" ); - add_token( 0x11e, "is-selftest" ); - add_token( 0x11f, "new-device" ); - add_token( 0x120, "diagnostic-mode?" ); - add_token( 0x121, "display-status" ); - add_token( 0x122, "memory-test-issue" ); - add_token( 0x123, "group-code" ); - add_token( 0x124, "mask" ); - add_token( 0x125, "get-msecs" ); - add_token( 0x126, "ms" ); - add_token( 0x127, "finish-device" ); - add_token( 0x128, "decode-phys" ); - add_token( 0x12b, "interpose" ); - add_token( 0x130, "map-low" ); - add_token( 0x131, "sbus-intr>cpu" ); - add_token( 0x150, "#lines" ); - add_token( 0x151, "#columns" ); - add_token( 0x152, "line#" ); - add_token( 0x153, "column#" ); - add_token( 0x154, "inverse?" ); - add_token( 0x155, "inverse-screen?" ); - add_token( 0x156, "frame-buffer-busy?" ); - add_token( 0x157, "draw-character" ); - add_token( 0x158, "reset-screen" ); - add_token( 0x159, "toggle-cursor" ); - add_token( 0x15a, "erase-screen" ); - add_token( 0x15b, "blink-screen" ); - add_token( 0x15c, "invert-screen" ); - add_token( 0x15d, "insert-characters" ); - add_token( 0x15e, "delete-characters" ); - add_token( 0x15f, "insert-lines" ); - add_token( 0x160, "delete-lines" ); - add_token( 0x161, "draw-logo" ); - add_token( 0x162, "frame-buffer-adr" ); - add_token( 0x163, "screen-height" ); - add_token( 0x164, "screen-width" ); - add_token( 0x165, "window-top" ); - add_token( 0x166, "window-left" ); - add_token( 0x16a, "default-font" ); - add_token( 0x16b, "set-font" ); - add_token( 0x16c, "char-height" ); - add_token( 0x16d, "char-width" ); - add_token( 0x16e, ">font" ); - add_token( 0x16f, "fontbytes" ); - add_token( 0x170, "fb1-draw-character" ); - add_token( 0x171, "fb1-reset-screen" ); - add_token( 0x172, "fb1-toggle-cursor" ); - add_token( 0x173, "fb1-erase-screen" ); - add_token( 0x174, "fb1-blink-screen" ); - add_token( 0x175, "fb1-invert-screen" ); - add_token( 0x176, "fb1-insert-characters" ); - add_token( 0x177, "fb1-delete-characters" ); - add_token( 0x178, "fb1-insert-lines" ); - add_token( 0x179, "fb1-delete-lines" ); - add_token( 0x17a, "fb1-draw-logo" ); - add_token( 0x17b, "fb1-install" ); - add_token( 0x17c, "fb1-slide-up" ); - add_token( 0x180, "fb8-draw-character" ); - add_token( 0x181, "fb8-reset-screen" ); - add_token( 0x182, "fb8-toggle-cursor" ); - add_token( 0x183, "fb8-erase-screen" ); - add_token( 0x184, "fb8-blink-screen" ); - add_token( 0x185, "fb8-invert-screen" ); - add_token( 0x186, "fb8-insert-characters" ); - add_token( 0x187, "fb8-delete-characters" ); - add_token( 0x188, "fb8-insert-lines" ); - add_token( 0x189, "fb8-delete-lines" ); - add_token( 0x18a, "fb8-draw-logo" ); - add_token( 0x18b, "fb8-install" ); - add_token( 0x1a0, "return-buffer" ); - add_token( 0x1a1, "xmit-packet" ); - add_token( 0x1a2, "poll-packet" ); - add_token( 0x1a4, "mac-address" ); - add_token( 0x201, "device-name" ); - add_token( 0x202, "my-args" ); - add_token( 0x203, "my-self" ); - add_token( 0x204, "find-package" ); - add_token( 0x205, "open-package" ); - add_token( 0x206, "close-package" ); - add_token( 0x207, "find-method" ); - add_token( 0x208, "call-package" ); - add_token( 0x209, "$call-parent" ); - add_token( 0x20a, "my-package" ); - add_token( 0x20b, "ihandle>phandle" ); - add_token( 0x20d, "my-unit" ); - add_token( 0x20e, "$call-method" ); - add_token( 0x20f, "$open-package" ); - add_token( 0x210, "processor-type" ); - add_token( 0x211, "firmware-version" ); - add_token( 0x212, "fcode-version" ); - add_token( 0x213, "alarm" ); - add_token( 0x214, "(is-user-word)" ); - add_token( 0x215, "suspend-fcode" ); - add_token( 0x216, "abort" ); - add_token( 0x217, "catch" ); - add_token( 0x218, "throw" ); - add_token( 0x219, "user-abort" ); - add_token( 0x21a, "get-my-property" ); - add_token( 0x21b, "decode-int" ); - add_token( 0x21c, "decode-string" ); - add_token( 0x21d, "get-inherited-property" ); - add_token( 0x21e, "delete-property" ); - add_token( 0x21f, "get-package-property" ); - add_token( 0x220, "cpeek" ); - add_token( 0x221, "wpeek" ); - add_token( 0x222, "lpeek" ); - add_token( 0x223, "cpoke" ); - add_token( 0x224, "wpoke" ); - add_token( 0x225, "lpoke" ); - add_token( 0x226, "lwflip" ); - add_token( 0x227, "lbflip" ); - add_token( 0x228, "lbflips" ); - add_token( 0x229, "adr-mask" ); - add_token( 0x230, "rb@" ); - add_token( 0x231, "rb!" ); - add_token( 0x232, "rw@" ); - add_token( 0x233, "rw!" ); - add_token( 0x234, "rl@" ); - add_token( 0x235, "rl!" ); - add_token( 0x236, "wbflips" ); - add_token( 0x237, "lwflips" ); - add_token( 0x238, "probe" ); - add_token( 0x239, "probe-virtual" ); - add_token( 0x23b, "child" ); - add_token( 0x23c, "peer" ); - add_token( 0x23d, "next-property" ); - add_token( 0x23e, "byte-load" ); - add_token( 0x23f, "set-args" ); - add_token( 0x240, "left-parse-string" ); + tic_hdr_t *temp_vocab;
+ /* The add_to_current() function will have been called before this + * one when a new colon-definition is created, so save_current + * will have been set to point to the entry that had been made + * just before the newest one, which we are hiding here. + */ + + temp_vocab = save_current ; + save_current = *current_definitions; + *current_definitions = temp_vocab; + +} + +void reveal_last_colon ( void ) +{ + /* We call this function either when the colon-definition is + * completed, or when "recursive"-ness is intentional. + */ + *current_definitions = save_current ; +} + + +/* ************************************************************************** + * + * Function name: create_current_alias + * Synopsis: Create an alias for OLD_NAME, called NEW_NAME, in + * the "current" scope of definitions, which may + * be either the Global ("core") Vocabulary or the + * current Device-Node Vocabulary. Indicate if + * successful (i.e., OLD_NAME was valid). + * This is actually a little trickier than it may at + * first appear; read the Rules in the Process + * Explanation for full details... + * + * Inputs: + * Parameters: + * new_name The name for the new alias to be created + * old_name The name of the old function to be duplicated + * Global Variables: + * current_definitions Device-node vocabulary currently + * in effect. + * scope_is_global TRUE if "global" scope is in effect + * Local Static Variables: + * global_voc_dict_ptr "Tail" of Global Vocabulary + * + * Outputs: + * Returned Value: TRUE if OLD_NAME was found. + * Global Variables: + * *current_definitions Updated with the new entry + * Memory Allocated + * By support routine. + * When Freed? + * When RESET-SYMBOLS is issued (if "global" scope is in effect) + * or when the device-node is "finish"ed. + * Printout: + * Advisory message if Rule 3 (see below) is invoked. + * + * Process Explanation: + * Both the "old" and "new" names are presumed to already point to + * stable, freshly allocated memory-spaces. + * Rules: + * (1) + * If "global" scope is in effect, and the "old" name is found in + * the Global Vocabulary, then the "new" name will be created + * in the Global Vocabulary. + * (2) + * Similarly, if "device" scope is in effect, and the "old" name is + * found in the current device-node's vocabulary, the "new" name + * will be created in the current device-node's vocabulary. + * (3) + * BUT!: If "device" scope is in effect, and the "old" name is found + * in the Global Vocabulary, then the "new" name will be created + * in the current device-node's vocabulary. It will only be + * recognized in the scope of that device-node, and will be + * removed from memory when the device-node is "finish"ed. + * And, yes, it *is* supposed to work that way... ;-) + * + * Again, because current_definitions points to the Global Vocab + * pointer during "global" scope, the first two rules of this + * routine are extremely straightforward; it's Rule 3 that you + * have to watch out for... ;-) + * + * And one other thing: + * We will always make the alias's pfld_size zero. See the + * prolog for create_tic_alias() in ticvocab.c for details... + * + * Extraneous Remarks: + * I will stretch the rules of well-structured code here, too. + * + **************************************************************************** */ + +bool create_current_alias( char *new_name, char *old_name ) +{ + bool retval = FALSE; + + if ( create_tic_alias( new_name, old_name, current_definitions) ) + { + return ( TRUE ); + } + + if ( INVERSE(scope_is_global) ) + { + tic_hdr_t *found = lookup_core_word( old_name ); + if ( found != NULL ) + { + add_tic_entry( new_name, found->funct, + found->pfield.deflt_elem, + found->fword_defr, + 0, found->ign_func, + current_definitions ); + retval = TRUE; + { + tokenization_error( INFO, + "%s is a Global definition, but its alias, %s, " + "will only be defined %s", + strupr( old_name), new_name, + in_what_node( current_device_node) ); + show_node_start(); + } + } + } + + return ( retval ); +} + +/* ************************************************************************** + * + * Support functions specific to the lists will be defined + * after the lists are created. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Create the initial list (or "Table") of FCode-Tokens. + * + * Most Standard FCode tokens are not specified as to their definition + * type, but a few have a definer specified as either a VALUE, a + * VARIABLE or a DEFER; we will enter them with the appropriate macro. + * + **************************************************************************** */ + +static tic_hdr_t tokens_table[] = +{ + BUILTIN_FCODE( 0x000, "end0" ) , + BUILTIN_FCODE( 0x010, "b(lit)" ) , + BUILTIN_FCODE( 0x011, "b(')" ) , + BUILTIN_FCODE( 0x012, "b(")" ) , + BUILTIN_FCODE( 0x013, "bbranch" ) , + BUILTIN_FCODE( 0x014, "b?branch" ) , + BUILTIN_FCODE( 0x015, "b(loop)" ) , + BUILTIN_FCODE( 0x016, "b(+loop)" ) , + BUILTIN_FCODE( 0x017, "b(do)" ) , + BUILTIN_FCODE( 0x018, "b(?do)" ) , + BUILTIN_FCODE( 0x019, "i" ) , + BUILTIN_FCODE( 0x01a, "j" ) , + BUILTIN_FCODE( 0x01b, "b(leave)" ) , + BUILTIN_FCODE( 0x01c, "b(of)" ) , + BUILTIN_FCODE( 0x01d, "execute" ) , + BUILTIN_FCODE( 0x01e, "+" ) , + BUILTIN_FCODE( 0x01f, "-" ) , + BUILTIN_FCODE( 0x020, "*" ) , + BUILTIN_FCODE( 0x021, "/" ) , + BUILTIN_FCODE( 0x022, "mod" ) , + BUILTIN_FCODE( 0x023, "and" ) , + BUILTIN_FCODE( 0x024, "or" ) , + BUILTIN_FCODE( 0x025, "xor" ) , + BUILTIN_FCODE( 0x026, "invert" ) , + BUILTIN_FCODE( 0x026, "not" ) , /* Synonym for "invert" */ + BUILTIN_FCODE( 0x027, "lshift" ) , + BUILTIN_FCODE( 0x027, "<<" ) , /* Synonym for "lshift" */ + BUILTIN_FCODE( 0x028, "rshift" ) , + BUILTIN_FCODE( 0x028, ">>" ) , /* Synonym for "rshift" */ + BUILTIN_FCODE( 0x029, ">>a" ) , + BUILTIN_FCODE( 0x02a, "/mod" ) , + BUILTIN_FCODE( 0x02b, "u/mod" ) , + BUILTIN_FCODE( 0x02c, "negate" ) , + BUILTIN_FCODE( 0x02d, "abs" ) , + BUILTIN_FCODE( 0x02e, "min" ) , + BUILTIN_FCODE( 0x02f, "max" ) , + BUILTIN_FCODE( 0x030, ">r" ) , + BUILTIN_FCODE( 0x031, "r>" ) , + BUILTIN_FCODE( 0x032, "r@" ) , + BUILTIN_FCODE( 0x033, "exit" ) , + BUILTIN_FCODE( 0x034, "0=" ) , + BUILTIN_FCODE( 0x035, "0<>" ) , + BUILTIN_FCODE( 0x036, "0<" ) , + BUILTIN_FCODE( 0x037, "0<=" ) , + BUILTIN_FCODE( 0x038, "0>" ) , + BUILTIN_FCODE( 0x039, "0>=" ) , + BUILTIN_FCODE( 0x03a, "<" ) , + BUILTIN_FCODE( 0x03b, ">" ) , + BUILTIN_FCODE( 0x03c, "=" ) , + BUILTIN_FCODE( 0x03d, "<>" ) , + BUILTIN_FCODE( 0x03e, "u>" ) , + BUILTIN_FCODE( 0x03f, "u<=" ) , + BUILTIN_FCODE( 0x040, "u<" ) , + BUILTIN_FCODE( 0x041, "u>=" ) , + BUILTIN_FCODE( 0x042, ">=" ) , + BUILTIN_FCODE( 0x043, "<=" ) , + BUILTIN_FCODE( 0x044, "between" ) , + BUILTIN_FCODE( 0x045, "within" ) , + BUILTIN_FCODE( 0x046, "drop" ) , + BUILTIN_FCODE( 0x047, "dup" ) , + BUILTIN_FCODE( 0x048, "over" ) , + BUILTIN_FCODE( 0x049, "swap" ) , + BUILTIN_FCODE( 0x04A, "rot" ) , + BUILTIN_FCODE( 0x04b, "-rot" ) , + BUILTIN_FCODE( 0x04c, "tuck" ) , + BUILTIN_FCODE( 0x04d, "nip" ) , + BUILTIN_FCODE( 0x04e, "pick" ) , + BUILTIN_FCODE( 0x04f, "roll" ) , + BUILTIN_FCODE( 0x050, "?dup" ) , + BUILTIN_FCODE( 0x051, "depth" ) , + BUILTIN_FCODE( 0x052, "2drop" ) , + BUILTIN_FCODE( 0x053, "2dup" ) , + BUILTIN_FCODE( 0x054, "2over" ) , + BUILTIN_FCODE( 0x055, "2swap" ) , + BUILTIN_FCODE( 0x056, "2rot" ) , + BUILTIN_FCODE( 0x057, "2/" ) , + BUILTIN_FCODE( 0x058, "u2/" ) , + BUILTIN_FCODE( 0x059, "2*" ) , + BUILTIN_FCODE( 0x05a, "/c" ) , + BUILTIN_FCODE( 0x05b, "/w" ) , + BUILTIN_FCODE( 0x05c, "/l" ) , + BUILTIN_FCODE( 0x05d, "/n" ) , + BUILTIN_FCODE( 0x05e, "ca+" ) , + BUILTIN_FCODE( 0x05f, "wa+" ) , + BUILTIN_FCODE( 0x060, "la+" ) , + BUILTIN_FCODE( 0x061, "na+" ) , + BUILTIN_FCODE( 0x062, "char+" ) , + BUILTIN_FCODE( 0x062, "ca1+" ) , /* Synonym for char+" */ + BUILTIN_FCODE( 0x063, "wa1+" ) , + BUILTIN_FCODE( 0x064, "la1+" ) , + BUILTIN_FCODE( 0x065, "cell+" ) , + BUILTIN_FCODE( 0x065, "na1+" ) , /* Synonym for "cell+" */ + BUILTIN_FCODE( 0x066, "chars" ) , + BUILTIN_FCODE( 0x066, "/c*" ) , /* Synonym for "chars" */ + BUILTIN_FCODE( 0x067, "/w*" ) , + BUILTIN_FCODE( 0x068, "/l*" ) , + BUILTIN_FCODE( 0x069, "cells" ) , + BUILTIN_FCODE( 0x069, "/n*" ) , /* Synonym for "cells" */ + BUILTIN_FCODE( 0x06a, "on" ) , + BUILTIN_FCODE( 0x06b, "off" ) , + BUILTIN_FCODE( 0x06c, "+!" ) , + BUILTIN_FCODE( 0x06d, "@" ) , + BUILTIN_FCODE( 0x06e, "l@" ) , + BUILTIN_FCODE( 0x06f, "w@" ) , + BUILTIN_FCODE( 0x070, "<w@" ) , + BUILTIN_FCODE( 0x071, "c@" ) , + BUILTIN_FCODE( 0x072, "!" ) , + BUILTIN_FCODE( 0x073, "l!" ) , + BUILTIN_FCODE( 0x074, "w!" ) , + BUILTIN_FCODE( 0x075, "c!" ) , + BUILTIN_FCODE( 0x076, "2@" ) , + BUILTIN_FCODE( 0x077, "2!" ) , + BUILTIN_FCODE( 0x078, "move" ) , + BUILTIN_FCODE( 0x079, "fill" ) , + BUILTIN_FCODE( 0x07a, "comp" ) , + BUILTIN_FCODE( 0x07b, "noop" ) , + BUILTIN_FCODE( 0x07c, "lwsplit" ) , + BUILTIN_FCODE( 0x07d, "wljoin" ) , + BUILTIN_FCODE( 0x07e, "lbsplit" ) , + BUILTIN_FCODE( 0x07f, "bljoin" ) , + BUILTIN_FCODE( 0x080, "wbflip" ) , + BUILTIN_FCODE( 0x080, "flip" ) , /* Synonym for "wbflip" */ + BUILTIN_FCODE( 0x081, "upc" ) , + BUILTIN_FCODE( 0x082, "lcc" ) , + BUILTIN_FCODE( 0x083, "pack" ) , + BUILTIN_FCODE( 0x084, "count" ) , + BUILTIN_FCODE( 0x085, "body>" ) , + BUILTIN_FCODE( 0x086, ">body" ) , + BUILTIN_FCODE( 0x087, "fcode-revision" ) , + BUILTIN_FCODE( 0x087, "version" ) , /* Synonym for "fcode-revision" */ + BI_FCODE_VRBLE( 0x088, "span" ) , + BUILTIN_FCODE( 0x089, "unloop" ) , + BUILTIN_FCODE( 0x08a, "expect" ) , + BUILTIN_FCODE( 0x08b, "alloc-mem" ) , + BUILTIN_FCODE( 0x08c, "free-mem" ) , + BUILTIN_FCODE( 0x08d, "key?" ) , + BUILTIN_FCODE( 0x08e, "key" ) , + BUILTIN_FCODE( 0x08f, "emit" ) , + BUILTIN_FCODE( 0x090, "type" ) , + BUILTIN_FCODE( 0x091, "(cr" ) , + BUILTIN_FCODE( 0x092, "cr" ) , + BI_FCODE_VRBLE( 0x093, "#out" ) , + BI_FCODE_VRBLE( 0x094, "#line" ) , + BUILTIN_FCODE( 0x095, "hold" ) , + BUILTIN_FCODE( 0x096, "<#" ) , + BUILTIN_FCODE( 0x097, "u#>" ) , + BUILTIN_FCODE( 0x098, "sign" ) , + BUILTIN_FCODE( 0x099, "u#" ) , + BUILTIN_FCODE( 0x09a, "u#s" ) , + BUILTIN_FCODE( 0x09b, "u." ) , + BUILTIN_FCODE( 0x09c, "u.r" ) , + BUILTIN_FCODE( 0x09d, "." ) , + BUILTIN_FCODE( 0x09e, ".r" ) , + BUILTIN_FCODE( 0x09f, ".s" ) , + BI_FCODE_VRBLE( 0x0a0, "base" ) , + OBSOLETE_FCODE( 0x0a1, "convert" ) , + BUILTIN_FCODE( 0x0a2, "$number" ) , + BUILTIN_FCODE( 0x0a3, "digit" ) , + BI_FCODE_CONST( 0x0a4, "-1" ) , + BI_FCODE_CONST( 0x0a4, "true" ) , /* Synonym for "-1" */ + BI_FCODE_CONST( 0x0a5, "0" ) , + BI_FCODE_CONST( 0x0a5, "false" ) , /* Synonym for "0" */ + BI_FCODE_CONST( 0x0a5, "struct" ) , /* Synonym for "0" */ + BI_FCODE_CONST( 0x0a6, "1" ) , + BI_FCODE_CONST( 0x0a7, "2" ) , + BI_FCODE_CONST( 0x0a8, "3" ) , + BI_FCODE_CONST( 0x0a9, "bl" ) , + BI_FCODE_CONST( 0x0aa, "bs" ) , + BI_FCODE_CONST( 0x0ab, "bell" ) , + BUILTIN_FCODE( 0x0ac, "bounds" ) , + BUILTIN_FCODE( 0x0ad, "here" ) , + BUILTIN_FCODE( 0x0ae, "aligned" ) , + BUILTIN_FCODE( 0x0af, "wbsplit" ) , + BUILTIN_FCODE( 0x0b0, "bwjoin" ) , + BUILTIN_FCODE( 0x0b1, "b(<mark)" ) , + BUILTIN_FCODE( 0x0b2, "b(>resolve)" ) , + OBSOLETE_FCODE( 0x0b3, "set-token-table" ) , + OBSOLETE_FCODE( 0x0b4, "set-table" ) , + BUILTIN_FCODE( 0x0b5, "new-token" ) , + BUILTIN_FCODE( 0x0b6, "named-token" ) , + BUILTIN_FCODE( 0x0b7, "b(:)" ) , + BUILTIN_FCODE( 0x0b8, "b(value)" ) , + BUILTIN_FCODE( 0x0b9, "b(variable)" ) , + BUILTIN_FCODE( 0x0ba, "b(constant)" ) , + BUILTIN_FCODE( 0x0bb, "b(create)" ) , + BUILTIN_FCODE( 0x0bc, "b(defer)" ) , + BUILTIN_FCODE( 0x0bd, "b(buffer:)" ) , + BUILTIN_FCODE( 0x0be, "b(field)" ) , + OBSOLETE_FCODE( 0x0bf, "b(code)" ) , + BUILTIN_FCODE( 0x0c0, "instance" ) , + BUILTIN_FCODE( 0x0c2, "b(;)" ) , + BUILTIN_FCODE( 0x0c3, "b(to)" ) , + BUILTIN_FCODE( 0x0c4, "b(case)" ) , + BUILTIN_FCODE( 0x0c5, "b(endcase)" ) , + BUILTIN_FCODE( 0x0c6, "b(endof)" ) , + BUILTIN_FCODE( 0x0c7, "#" ) , + BUILTIN_FCODE( 0x0c8, "#s" ) , + BUILTIN_FCODE( 0x0c9, "#>" ) , + BUILTIN_FCODE( 0x0ca, "external-token" ) , + BUILTIN_FCODE( 0x0cb, "$find" ) , + BUILTIN_FCODE( 0x0cc, "offset16" ) , + BUILTIN_FCODE( 0x0cd, "evaluate" ) , + BUILTIN_FCODE( 0x0cd, "eval" ) , /* Synonym for "evaluate" */ + BUILTIN_FCODE( 0x0d0, "c," ) , + BUILTIN_FCODE( 0x0d1, "w," ) , + BUILTIN_FCODE( 0x0d2, "l," ) , + BUILTIN_FCODE( 0x0d3, "," ) , + BUILTIN_FCODE( 0x0d4, "um*" ) , + BUILTIN_FCODE( 0x0d4, "u*x" ) , /* Synonym for "um*" */ + BUILTIN_FCODE( 0x0d5, "um/mod" ) , + BUILTIN_FCODE( 0x0d5, "xu/mod" ) , /* Synonym for "um/mod" */ + BUILTIN_FCODE( 0x0d8, "d+" ) , + BUILTIN_FCODE( 0x0d8, "x+" ) , /* Synonym for "d+" */ + BUILTIN_FCODE( 0x0d9, "d-" ) , + BUILTIN_FCODE( 0x0d9, "x-" ) , /* Synonym for "d-" */ + BUILTIN_FCODE( 0x0da, "get-token" ) , + BUILTIN_FCODE( 0x0db, "set-token" ) , + BI_FCODE_VRBLE( 0x0dc, "state" ) , + BUILTIN_FCODE( 0x0dd, "compile" ) , + BUILTIN_FCODE( 0x0de, "behavior" ) , + BUILTIN_FCODE( 0x0f0, "start0" ) , + BUILTIN_FCODE( 0x0f1, "start1" ) , + BUILTIN_FCODE( 0x0f2, "start2" ) , + BUILTIN_FCODE( 0x0f3, "start4" ) , + BUILTIN_FCODE( 0x0fc, "ferror" ) , + BUILTIN_FCODE( 0x0fd, "version1" ) , + OBSOLETE_FCODE( 0x0fe, "4-byte-id" ) , + BUILTIN_FCODE( 0x0ff, "end1" ) , + OBSOLETE_FCODE( 0x101, "dma-alloc" ) , + BUILTIN_FCODE( 0x102, "my-address" ) , + BUILTIN_FCODE( 0x103, "my-space" ) , + OBSOLETE_FCODE( 0x104, "memmap" ) , + BUILTIN_FCODE( 0x105, "free-virtual" ) , + OBSOLETE_FCODE( 0x106, ">physical" ) , + OBSOLETE_FCODE( 0x10f, "my-params" ) , + BUILTIN_FCODE( 0x110, "property" ) , + BUILTIN_FCODE( 0x110, "attribute" ) , /* Synonym for "property" */ + BUILTIN_FCODE( 0x111, "encode-int" ) , + BUILTIN_FCODE( 0x111, "xdrint" ) , /* Synonym for "encode-int" */ + BUILTIN_FCODE( 0x112, "encode+" ) , + BUILTIN_FCODE( 0x112, "xdr+" ) , /* Synonym for "encode+" */ + BUILTIN_FCODE( 0x113, "encode-phys" ) , + BUILTIN_FCODE( 0x113, "xdrphys" ) , /* Synonym for "encode-phys" */ + BUILTIN_FCODE( 0x114, "encode-string" ) , + BUILTIN_FCODE( 0x114, "xdrstring" ) , /* Synonym for "encode-string" */ + BUILTIN_FCODE( 0x115, "encode-bytes" ) , + BUILTIN_FCODE( 0x115, "xdrbytes" ) , /* Synonym for "encode-bytes" */ + BUILTIN_FCODE( 0x116, "reg" ) , + OBSOLETE_FCODE( 0x117, "intr" ) , + OBSOLETE_FCODE( 0x118, "driver" ) , + BUILTIN_FCODE( 0x119, "model" ) , + BUILTIN_FCODE( 0x11a, "device-type" ) , + BUILTIN_FCODE( 0x11b, "parse-2int" ) , + BUILTIN_FCODE( 0x11b, "decode-2int" ) , /* Synonym for "parse-2int" */ + BUILTIN_FCODE( 0x11c, "is-install" ) , + BUILTIN_FCODE( 0x11d, "is-remove" ) , + BUILTIN_FCODE( 0x11e, "is-selftest" ) , + BUILTIN_FCODE( 0x11f, "new-device" ) , + BUILTIN_FCODE( 0x120, "diagnostic-mode?" ) , + BUILTIN_FCODE( 0x121, "display-status" ) , + BUILTIN_FCODE( 0x122, "memory-test-issue" ) , + OBSOLETE_FCODE( 0x123, "group-code" ) , + BI_FCODE_VRBLE( 0x124, "mask" ) , + BUILTIN_FCODE( 0x125, "get-msecs" ) , + BUILTIN_FCODE( 0x126, "ms" ) , + BUILTIN_FCODE( 0x127, "finish-device" ) , + BUILTIN_FCODE( 0x128, "decode-phys" ) , + BUILTIN_FCODE( 0x12b, "interpose" ) , + BUILTIN_FCODE( 0x130, "map-low" ) , + BUILTIN_FCODE( 0x130, "map-sbus" ) , /* Synonym for "map-low" */ + BUILTIN_FCODE( 0x131, "sbus-intr>cpu" ) , + BI_FCODE_VALUE( 0x150, "#lines" ) , + BI_FCODE_VALUE( 0x151, "#columns" ) , + BI_FCODE_VALUE( 0x152, "line#" ) , + BI_FCODE_VALUE( 0x153, "column#" ) , + BI_FCODE_VALUE( 0x154, "inverse?" ) , + BI_FCODE_VALUE( 0x155, "inverse-screen?" ) , + OBSOLETE_VALUE( 0x156, "frame-buffer-busy?" ) , + BI_FCODE_DEFER( 0x157, "draw-character" ) , + BI_FCODE_DEFER( 0x158, "reset-screen" ) , + BI_FCODE_DEFER( 0x159, "toggle-cursor" ) , + BI_FCODE_DEFER( 0x15a, "erase-screen" ) , + BI_FCODE_DEFER( 0x15b, "blink-screen" ) , + BI_FCODE_DEFER( 0x15c, "invert-screen" ) , + BI_FCODE_DEFER( 0x15d, "insert-characters" ) , + BI_FCODE_DEFER( 0x15e, "delete-characters" ) , + BI_FCODE_DEFER( 0x15f, "insert-lines" ) , + BI_FCODE_DEFER( 0x160, "delete-lines" ) , + BI_FCODE_DEFER( 0x161, "draw-logo" ) , + BI_FCODE_VALUE( 0x162, "frame-buffer-adr" ) , + BI_FCODE_VALUE( 0x163, "screen-height" ) , + BI_FCODE_VALUE( 0x164, "screen-width" ) , + BI_FCODE_VALUE( 0x165, "window-top" ) , + BI_FCODE_VALUE( 0x166, "window-left" ) , + BUILTIN_FCODE( 0x16a, "default-font" ) , + BUILTIN_FCODE( 0x16b, "set-font" ) , + BI_FCODE_VALUE( 0x16c, "char-height" ) , + BI_FCODE_VALUE( 0x16d, "char-width" ) , + BUILTIN_FCODE( 0x16e, ">font" ) , + BI_FCODE_VALUE( 0x16f, "fontbytes" ) , + OBSOLETE_FCODE( 0x170, "fb1-draw-character" ) , + OBSOLETE_FCODE( 0x171, "fb1-reset-screen" ) , + OBSOLETE_FCODE( 0x172, "fb1-toggle-cursor" ) , + OBSOLETE_FCODE( 0x173, "fb1-erase-screen" ) , + OBSOLETE_FCODE( 0x174, "fb1-blink-screen" ) , + OBSOLETE_FCODE( 0x175, "fb1-invert-screen" ) , + OBSOLETE_FCODE( 0x176, "fb1-insert-characters" ) , + OBSOLETE_FCODE( 0x177, "fb1-delete-characters" ) , + OBSOLETE_FCODE( 0x178, "fb1-insert-lines" ) , + OBSOLETE_FCODE( 0x179, "fb1-delete-lines" ) , + OBSOLETE_FCODE( 0x17a, "fb1-draw-logo" ) , + OBSOLETE_FCODE( 0x17b, "fb1-install" ) , + OBSOLETE_FCODE( 0x17c, "fb1-slide-up" ) , + BUILTIN_FCODE( 0x180, "fb8-draw-character" ) , + BUILTIN_FCODE( 0x181, "fb8-reset-screen" ) , + BUILTIN_FCODE( 0x182, "fb8-toggle-cursor" ) , + BUILTIN_FCODE( 0x183, "fb8-erase-screen" ) , + BUILTIN_FCODE( 0x184, "fb8-blink-screen" ) , + BUILTIN_FCODE( 0x185, "fb8-invert-screen" ) , + BUILTIN_FCODE( 0x186, "fb8-insert-characters" ) , + BUILTIN_FCODE( 0x187, "fb8-delete-characters" ) , + BUILTIN_FCODE( 0x188, "fb8-insert-lines" ) , + BUILTIN_FCODE( 0x189, "fb8-delete-lines" ) , + BUILTIN_FCODE( 0x18a, "fb8-draw-logo" ) , + BUILTIN_FCODE( 0x18b, "fb8-install" ) , + OBSOLETE_FCODE( 0x1a0, "return-buffer" ) , + OBSOLETE_FCODE( 0x1a1, "xmit-packet" ) , + OBSOLETE_FCODE( 0x1a2, "poll-packet" ) , + BUILTIN_FCODE( 0x1a4, "mac-address" ) , + BUILTIN_FCODE( 0x201, "device-name" ) , + BUILTIN_FCODE( 0x201, "name" ) , /* Synonym for "device-name" */ + BUILTIN_FCODE( 0x202, "my-args" ) , + BI_FCODE_VALUE( 0x203, "my-self" ) , + BUILTIN_FCODE( 0x204, "find-package" ) , + BUILTIN_FCODE( 0x205, "open-package" ) , + BUILTIN_FCODE( 0x206, "close-package" ) , + BUILTIN_FCODE( 0x207, "find-method" ) , + BUILTIN_FCODE( 0x208, "call-package" ) , + BUILTIN_FCODE( 0x209, "$call-parent" ) , + BUILTIN_FCODE( 0x20a, "my-parent" ) , + BUILTIN_FCODE( 0x20b, "ihandle>phandle" ) , + BUILTIN_FCODE( 0x20d, "my-unit" ) , + BUILTIN_FCODE( 0x20e, "$call-method" ) , + BUILTIN_FCODE( 0x20f, "$open-package" ) , + OBSOLETE_FCODE( 0x210, "processor-type" ) , + OBSOLETE_FCODE( 0x211, "firmware-version" ) , + OBSOLETE_FCODE( 0x212, "fcode-version" ) , + BUILTIN_FCODE( 0x213, "alarm" ) , + BUILTIN_FCODE( 0x214, "(is-user-word)" ) , + BUILTIN_FCODE( 0x215, "suspend-fcode" ) , + BUILTIN_FCODE( 0x216, "abort" ) , + BUILTIN_FCODE( 0x217, "catch" ) , + BUILTIN_FCODE( 0x218, "throw" ) , + BUILTIN_FCODE( 0x219, "user-abort" ) , + BUILTIN_FCODE( 0x21a, "get-my-property" ) , + BUILTIN_FCODE( 0x21a, "get-my-attribute" ) , /* Synonym for "get-my-property" */ + BUILTIN_FCODE( 0x21b, "decode-int" ) , + BUILTIN_FCODE( 0x21b, "xdrtoint" ) , /* Synonym for "decode-int" */ + BUILTIN_FCODE( 0x21c, "decode-string" ) , + BUILTIN_FCODE( 0x21c, "xdrtostring" ), /* Synonym for "decode-string" */ + BUILTIN_FCODE( 0x21d, "get-inherited-property" ) , + BUILTIN_FCODE( 0x21d, "get-inherited-attribute" ) , /* Synonym for "get-inherited-property" */ + BUILTIN_FCODE( 0x21e, "delete-property" ) , + BUILTIN_FCODE( 0x21e, "delete-attribute" ) , /* Synonym for "delete-property" */ + BUILTIN_FCODE( 0x21f, "get-package-property" ) , + BUILTIN_FCODE( 0x21f, "get-package-attribute" ) , /* Synonym for "get-package-property" */ + BUILTIN_FCODE( 0x220, "cpeek" ) , + BUILTIN_FCODE( 0x221, "wpeek" ) , + BUILTIN_FCODE( 0x222, "lpeek" ) , + BUILTIN_FCODE( 0x223, "cpoke" ) , + BUILTIN_FCODE( 0x224, "wpoke" ) , + BUILTIN_FCODE( 0x225, "lpoke" ) , + BUILTIN_FCODE( 0x226, "lwflip" ) , + BUILTIN_FCODE( 0x227, "lbflip" ) , + BUILTIN_FCODE( 0x228, "lbflips" ) , + OBSOLETE_FCODE( 0x229, "adr-mask" ) , + BUILTIN_FCODE( 0x230, "rb@" ) , + BUILTIN_FCODE( 0x231, "rb!" ) , + BUILTIN_FCODE( 0x232, "rw@" ) , + BUILTIN_FCODE( 0x233, "rw!" ) , + BUILTIN_FCODE( 0x234, "rl@" ) , + BUILTIN_FCODE( 0x235, "rl!" ) , + BUILTIN_FCODE( 0x236, "wbflips" ) , + BUILTIN_FCODE( 0x236, "wflips" ) , /* Synonym for "wbflips" */ + BUILTIN_FCODE( 0x237, "lwflips" ) , + BUILTIN_FCODE( 0x237, "lflips" ) , /* Synonym for "lwflips" */ + OBSOLETE_FCODE( 0x238, "probe" ) , + OBSOLETE_FCODE( 0x239, "probe-virtual" ) , + BUILTIN_FCODE( 0x23b, "child" ) , + BUILTIN_FCODE( 0x23c, "peer" ) , + BUILTIN_FCODE( 0x23d, "next-property" ) , + BUILTIN_FCODE( 0x23e, "byte-load" ) , + BUILTIN_FCODE( 0x23f, "set-args" ) , + BUILTIN_FCODE( 0x240, "left-parse-string" ) , + /* FCodes from 64bit extension addendum */ - add_token( 0x22e, "rx@" ); - add_token( 0x22f, "rx!" ); - add_token( 0x241, "bxjoin" ); - add_token( 0x242, "<l@" ); - add_token( 0x243, "lxjoin" ); - add_token( 0x244, "wxjoin" ); - add_token( 0x245, "x," ); - add_token( 0x246, "x@" ); - add_token( 0x247, "x!" ); - add_token( 0x248, "/x" ); - add_token( 0x249, "/x*" ); - add_token( 0x24a, "xa+" ); - add_token( 0x24b, "xa1+" ); - add_token( 0x24c, "xbflip" ); - add_token( 0x24d, "xbflips" ); - add_token( 0x24e, "xbsplit" ); - add_token( 0x24f, "xlflip" ); - add_token( 0x250, "xlflips" ); - add_token( 0x251, "xlsplit" ); - add_token( 0x252, "xwflip" ); - add_token( 0x253, "xwflips" ); - add_token( 0x254, "xwsplit" ); + BUILTIN_FCODE( 0x22e, "rx@" ) , + BUILTIN_FCODE( 0x22f, "rx!" ) , + BUILTIN_FCODE( 0x241, "bxjoin" ) , + BUILTIN_FCODE( 0x242, "<l@" ) , + BUILTIN_FCODE( 0x243, "lxjoin" ) , + BUILTIN_FCODE( 0x244, "wxjoin" ) , + BUILTIN_FCODE( 0x245, "x," ) , + BUILTIN_FCODE( 0x246, "x@" ) , + BUILTIN_FCODE( 0x247, "x!" ) , + BUILTIN_FCODE( 0x248, "/x" ) , + BUILTIN_FCODE( 0x249, "/x*" ) , + BUILTIN_FCODE( 0x24a, "xa+" ) , + BUILTIN_FCODE( 0x24b, "xa1+" ) , + BUILTIN_FCODE( 0x24c, "xbflip" ) , + BUILTIN_FCODE( 0x24d, "xbflips" ) , + BUILTIN_FCODE( 0x24e, "xbsplit" ) , + BUILTIN_FCODE( 0x24f, "xlflip" ) , + BUILTIN_FCODE( 0x250, "xlflips" ) , + BUILTIN_FCODE( 0x251, "xlsplit" ) , + BUILTIN_FCODE( 0x252, "xwflip" ) , + BUILTIN_FCODE( 0x253, "xwflips" ) , + BUILTIN_FCODE( 0x254, "xwsplit" ) +};
- add_special(COLON, ":"); - add_special(SEMICOLON, ";"); - add_special(TOKENIZE, "'"); - add_special(AGAIN, "again"); - add_special(ALIAS, "alias"); - add_special(GETTOKEN, "[']"); - add_special(ASCII, "ascii"); - add_special(BEGIN, "begin"); - add_special(BUFFER, "buffer:"); - add_special(CASE, "case"); - add_special(CONST, "constant"); - add_special(CONTROL, "control"); - add_special(CREATE, "create"); - add_special(DECIMAL, "decimal"); - add_special(DEFER, "defer"); - add_special(CDO, "?do"); - add_special(DO, "do"); - add_special(ELSE, "else"); - add_special(ENDCASE, "endcase"); - add_special(ENDOF, "endof"); - add_special(EXTERNAL, "external"); - add_special(FIELD, "field"); - add_special(HEADERLESS, "headerless"); - add_special(HEADERS, "headers"); - add_special(HEX, "hex"); - add_special(IF, "if"); - add_special(CLEAVE, "?leave"); - add_special(LEAVE, "leave"); - add_special(CLOOP, "+loop"); - add_special(LOOP, "loop"); - add_special(OCTAL, "octal"); - add_special(OF, "of"); - add_special(REPEAT, "repeat"); - add_special(THEN, "then"); - add_special(TO, "to"); - add_special(UNTIL, "until"); - add_special(VALUE, "value"); - add_special(VARIABLE, "variable"); - add_special(WHILE, "while"); - add_special(OFFSET16, "offset16"); - add_special(BEGINTOK, "tokenizer["); - add_special(EMITBYTE, "emit-byte"); - add_special(ENDTOK, "]tokenizer"); - add_special(FLOAD, "fload"); - add_special(STRING, """); - add_special(PSTRING, ".""); - add_special(PBSTRING, ".("); - add_special(SSTRING, "s""); - add_special(RECURSIVE, "recursive"); - add_special(NEXTFCODE, "next-fcode"); +static const int number_of_builtin_tokens = + sizeof(tokens_table)/sizeof(tic_hdr_t); + +/* ************************************************************************** + * + * Support functions specific to the FCode-Tokens list. + * + **************************************************************************** */ + + +/* ************************************************************************** + * + * Function name: emit_token + * Synopsis: Emit the FCode token for the given FCode name. + * + * Inputs: + * Parameters: + * fc_name The name of the FCode + * Local Static Variables: + * fc_tokens_list_start "Tail" of the "FC-Tokens" list + * + * Outputs: + * Returned Value: NONE + * + * Error Detection: + * This routine should only be called with hard-coded names from + * within the program. If the given name is not found in + * the Built-in Tokens Table, that is a FATAL error. + * + * Process Explanation: + * Because the "FCode-Tokens" table was linked first, and the + * pointer kept for this purpose, the "FC-Tokens" list can + * be a subset of the "core" list, yet, when necessary, can + * be searched with the same routines. + * + * Extraneous Remarks: + * I will bend the strict rules of well-structured code; + * the exception case should never occur. + * + **************************************************************************** */ + +void emit_token( const char *fc_name) +{ + + if ( handle_tic_vocab( (char *)fc_name, fc_tokens_list_start) ) + { + return; + } + + tokenization_error( FATAL, "Did not recognize FCode name %s", fc_name); +} + + +/* ************************************************************************** + * + * Function name: lookup_token + * Synopsis: Return a pointer to the data-structure of the named + * word in the "FC-Tokens" list + * + * Inputs: + * Parameters: + * tname The name to look up + * Local Static Variables: + * fc_tokens_list_start "Tail" of the "FC-Tokens" list + * + * Outputs: + * Returned Value: Pointer to the data-structure, or + * NULL if not found. + * + **************************************************************************** */ + +tic_hdr_t *lookup_token( char *tname) +{ + tic_hdr_t *found ; + + found = lookup_tic_entry( tname, fc_tokens_list_start); + return ( found ) ; +} + +/* ************************************************************************** + * + * Function name: entry_is_token + * Synopsis: Indicate whether the supplied pointer to a tic_hdr_t + * data-structure is one for which a single-token FCode + * number is assigned. + * + * Inputs: + * Parameters: + * test_entry The entry to test; may be NULL + * Local macros: + * FC_TOKEN_FUNC The function associated with + * most single-token entries. + * OBSO_FC_FUNC The function associated with + * "obsolete" FCode tokens. + * + * Outputs: + * Returned Value: TRUE if the data-structure is + * a single-token entry. + * + * Process Explanation: + * We cannot rely on the "definer" field to indicate whether + * it is a single-token entry; instead, we will look at + * the associated function. + * Keep this routine here to avoid needing to export the names + * of the permitted functions or their synonymous macros. + * If we ever need to change it, we can do so at a single + * point of maintenance. + * Because the entry might have been found in the initial list + * of entries to the "FCode-Tokens" list, we need to check + * whether the associated function is either the general + * single-token emitting function, FC_TOKEN_FUNC , or the + * function OBSO_FC_FUNC , which presents a message before + * emitting, but is still a valid single-token function. + * + **************************************************************************** */ + +bool entry_is_token( tic_hdr_t *test_entry ) +{ + bool retval = FALSE; + if ( test_entry != NULL ) + { + if ( ( test_entry->funct == FC_TOKEN_FUNC ) || + ( test_entry->funct == OBSO_FC_FUNC ) ) + { + retval = TRUE; + } + } + return ( retval ); +} + +/* ************************************************************************** + * + * Function name: token_entry_warning + * Synopsis: Issue whatever warnings the given token_entry + * requires. F['] needs this. + * Inputs: + * Parameters: + * test_entry The entry to test; may be NULL + * Local macro: + * OBSO_FC_FUNC The function associated with + * "obsolete" entries. + * Outputs: + * Returned Value: NONE + * + * Error Detection: + * Warnings required by the given token_entry. + * + * Extraneous Remarks: + * At present, it's only the "Obsolete" warning. + * But this is the place to add others, + * should they become necessary. + * + **************************************************************************** */ + +void token_entry_warning( tic_hdr_t *t_entry) +{ + if ( t_entry->funct == OBSO_FC_FUNC ) + { + obsolete_warning(); + } +} + + +/* ************************************************************************** + * + * Create the initial "FWords" list. + * + **************************************************************************** */ + +static tic_fwt_hdr_t fwords_list[] = { + + BI_FWD_SKP_OW(COLON, ":") , + BUILTIN_FWORD(SEMICOLON, ";") , + BI_FWD_SKP_OW(TICK, "'") , + BUILTIN_FWORD(AGAIN, "again") , + BI_FWD_SKP_OW(BRACK_TICK, "[']") , + BI_FWD_SKP_OW(ASCII, "ascii") , + BUILTIN_FWORD(BEGIN, "begin") , + BI_FWD_SKP_OW(BUFFER, "buffer:") , + BUILTIN_FWORD(CASE, "case") , + BI_FWD_SKP_OW(CONST, "constant") , + BI_FWD_SKP_OW(CONTROL, "control") , + BI_FWD_SKP_OW(CREATE, "create") , + + BI_FWD_SKP_OW(DEFER, "defer") , + BUILTIN_FWORD(CDO, "?do") , + BUILTIN_FWORD(DO, "do") , + BUILTIN_FWORD(ELSE, "else") , + BUILTIN_FWORD(ENDCASE, "endcase") , + BUILTIN_FWORD(ENDOF, "endof") , + BUILTIN_FWORD(EXTERNAL, "external") , + BI_FWD_SKP_OW(FIELD, "field") , + BUILTIN_FWORD(FINISH_DEVICE, "finish-device" ) , + BUILTIN_FWORD(HEADERLESS, "headerless") , + BUILTIN_FWORD(HEADERS, "headers") , + + BUILTIN_FWORD(INSTANCE , "instance") , + + BUILTIN_FWORD(IF, "if") , + BUILTIN_FWORD(UNLOOP, "unloop") , + BUILTIN_FWORD(LEAVE, "leave") , + BUILTIN_FWORD(PLUS_LOOP, "+loop") , + BUILTIN_FWORD(LOOP, "loop") , + + BUILTIN_FWORD(OF, "of") , + BUILTIN_FWORD(REPEAT, "repeat") , + BUILTIN_FWORD(THEN, "then") , + BI_FWD_SKP_OW(TO, "to") , + BI_FWD_SKP_OW(IS, "is") , /* Deprecated synonym to TO */ + BUILTIN_FWORD(UNTIL, "until") , + BI_FWD_SKP_OW(VALUE, "value") , + BI_FWD_SKP_OW(VARIABLE, "variable") , + BUILTIN_FWORD(WHILE, "while") , + BUILTIN_FWORD(OFFSET16, "offset16") , + + BI_FWD_STRING(STRING, """) , /* XXXXX */ + BI_FWD_STRING(PSTRING, "."") , /* XXXXX */ + BI_FWD_STRING(PBSTRING, ".(") , /* XXXXX */ + BI_FWD_STRING(SSTRING, "s"") , /* XXXXX */ + BUILTIN_FWORD(IFILE_NAME, "[input-file-name]"), + BUILTIN_FWORD(ILINE_NUM, "[line-number]"), + BUILTIN_FWORD(RECURSE, "recurse") , + BUILTIN_FWORD(RECURSIVE, "recursive") , + BUILTIN_FWORD(RET_STK_FETCH, "r@") , + BUILTIN_FWORD(RET_STK_FROM, "r>") , + BUILTIN_FWORD(RET_STK_TO, ">r") , + BUILTIN_FWORD(THEN, "endif" ) , /* Synonym for "then" */ + BUILTIN_FWORD(NEW_DEVICE, "new-device" ) , + BUILTIN_FWORD(LOOP_I, "i") , + BUILTIN_FWORD(LOOP_J, "j") , /* version1 is also an fcode word, but it * needs to trigger some tokenizer internals */ - add_special(VERSION1, "version1"); - add_special(START0, "start0"); - add_special(START1, "start1"); - add_special(START2, "start2"); - add_special(START4, "start4"); - add_special(END0, "end0"); - add_special(END1, "end1"); - add_special(FCODE_V1, "fcode-version1"); - add_special(FCODE_V2, "fcode-version2"); - add_special(FCODE_V3, "fcode-version3"); - add_special(FCODE_END, "fcode-end"); - add_special(FCODE_DATE, "fcode-date"); - add_special(FCODE_TIME, "fcode-time"); - - add_special(HEXVAL, "h#"); - add_special(DECVAL, "d#"); - add_special(OCTVAL, "o#"); - add_special(CHAR, "char"); - add_special(CCHAR, "[char]"); - add_special(ABORTTXT, "abort""); + BUILTIN_FWORD(VERSION1, "version1") , + BUILTIN_FWORD(START0, "start0") , + BUILTIN_FWORD(START1, "start1") , + BUILTIN_FWORD(START2, "start2") , + BUILTIN_FWORD(START4, "start4") , + BUILTIN_FWORD(END0, "end0") , + BUILTIN_FWORD(END1, "end1") , + BUILTIN_FWORD(FCODE_V1, "fcode-version1") , + BUILTIN_FWORD(FCODE_V2, "fcode-version2") , + BUILTIN_FWORD(FCODE_V3, "fcode-version3") , + BUILTIN_FWORD(FCODE_END, "fcode-end") ,
- add_special(ENCODEFILE, "encode-file"); + /* Support for IBM-style Locals */ + BI_FWD_STRING(CURLY_BRACE, "{") , + BI_FWD_STRING(DASH_ARROW, "->") , + BUILTIN_FWORD(EXIT, "exit") ,
+ + BUILTIN_FWORD(CHAR, "char") , + BUILTIN_FWORD(CCHAR, "[char]") , + BI_FWD_STRING(ABORTTXT, "abort"") , + + BUILTIN_FWORD(ENCODEFILE, "encode-file") , + + BI_IG_FW_HDLR(ESCAPETOK, "tokenizer[") , + BI_IG_FW_HDLR(ESCAPETOK, "f[") , /* An IBM-ish synonym */ +}; + +static const int number_of_builtin_fwords = + sizeof(fwords_list)/sizeof(tic_hdr_t); + +/* ************************************************************************** + * + * Create the initial list of "Shared_Words" (words that can + * be executed similarly both during normal tokenization, + * and also within "Tokenizer Escape Mode"). + * + **************************************************************************** */ + +static tic_fwt_hdr_t shared_words_list[] = { + SHARED_FWORD(FLOAD, "fload") , + /* As does the "Allow Multi-Line" directive */ + SHR_SAMIG_FWRD(ALLOW_MULTI_LINE, "multi-line") , + + SHR_FWD_SKOW( F_BRACK_TICK, "f[']") , + + SH_FW_SK2WIL(ALIAS, "alias") , + SHARED_FWORD(DECIMAL, "decimal") , + SHARED_FWORD(HEX, "hex") , + SHARED_FWORD(OCTAL, "octal") , + SH_FW_SK_WIL(HEXVAL, "h#") , + SH_FW_SK_WIL(DECVAL, "d#") , + SH_FW_SK_WIL(OCTVAL, "o#") , + + SH_FW_SK_WIL(ASC_NUM, "a#") , + SH_FW_SK_WIL(ASC_LEFT_NUM, "al#") , + + /* IBM-style extension. Might be generalizable... */ + SHARED_FWORD(FLITERAL, "fliteral") , + + /* Directives to extract the value of a Command-Line symbol */ + SH_FW_SK_WIL(DEFINED, "[defined]") , + SH_FW_SK_WIL(DEFINED, "#defined") , + SH_FW_SK_WIL(DEFINED, "[#defined]") , + + /* Present the current date or time, either as an */ + /* in-line string or as a user-generated message. */ + SHARED_FWORD(FCODE_DATE, "[fcode-date]") , + SHARED_FWORD(FCODE_TIME, "[fcode-time]") , + + /* Current definition under construction, similarly */ + SHARED_FWORD(FUNC_NAME, "[function-name]"), + + /* Synonymous forms of the #ELSE and #THEN operators, + * associated with Conditional-Compilation, + * allowing for various syntax-styles, and for + * expansion by alias. + */ + + /* #ELSE operators */ + SHARED_FWORD(CONDL_ELSE, "#else") , + SHARED_FWORD(CONDL_ELSE, "[else]") , + SHARED_FWORD(CONDL_ELSE, "[#else]") , + + /* #THEN operators */ + SHARED_FWORD(CONDL_ENDER, "#then") , + SHARED_FWORD(CONDL_ENDER, "[then]") , + SHARED_FWORD(CONDL_ENDER, "[#then]") , + /* #ENDIF variants for users who favor C-style notation */ + SHARED_FWORD(CONDL_ENDER, "#endif") , + SHARED_FWORD(CONDL_ENDER, "[endif]") , + SHARED_FWORD(CONDL_ENDER, "[#endif]") , + + + SHARED_FWORD(OVERLOAD, "overload" ) , + + SHARED_FWORD(GLOB_SCOPE , "global-definitions" ) , + SHARED_FWORD(DEV_SCOPE , "device-definitions" ) , + + /* Directives to change a command-line flag value from source */ + SH_FW_SK_WIL(CL_FLAG, "[FLAG]") , + SH_FW_SK_WIL(CL_FLAG, "#FLAG") , + SH_FW_SK_WIL(CL_FLAG, "[#FLAG]") , + + /* Directives to force display of a command-line flags' values */ + SHARED_FWORD(SHOW_CL_FLAGS, "[FLAGS]") , + SHARED_FWORD(SHOW_CL_FLAGS, "#FLAGS") , + SHARED_FWORD(SHOW_CL_FLAGS, "[#FLAGS]") , + SHARED_FWORD(SHOW_CL_FLAGS, "SHOW-FLAGS") , + + /* Directives to save and retrieve the FCode Assignment number */ + SHARED_FWORD(PUSH_FCODE, "FCODE-PUSH") , + SHARED_FWORD(POP_FCODE, "FCODE-POP") , + + /* Directive to reset the FCode Assignment number and + * re-initialize FCode Range overlap checking. + */ + SHARED_FWORD(RESET_FCODE, "FCODE-RESET") , + /* pci header generation is done differently * across the available tokenizers. We try to * be compatible to all of them */ - add_special(PCIHDR, "pci-header"); - add_special(PCIEND, "pci-end"); /* SUN syntax */ - add_special(PCIEND, "pci-header-end"); /* Firmworks syntax */ - add_special(PCIREV, "pci-revision"); /* SUN syntax */ - add_special(PCIREV, "pci-code-revision"); /* SUN syntax */ - add_special(PCIREV, "set-rev-level"); /* Firmworks syntax */ - add_special(NOTLAST, "not-last-image"); + SHARED_FWORD(PCIHDR, "pci-header") , + SHARED_FWORD(PCIEND, "pci-end") , /* SUN syntax */ + SHARED_FWORD(PCIEND, "pci-header-end") , /* Firmworks syntax */ + SHARED_FWORD(PCIREV, "pci-revision") , /* SUN syntax */ + SHARED_FWORD(PCIREV, "pci-code-revision") , /* SUN syntax */ + SHARED_FWORD(PCIREV, "set-rev-level") , /* Firmworks syntax */ + SHARED_FWORD(NOTLAST, "not-last-image") , + SHARED_FWORD(NOTLAST, "not-last-img") , /* Shorthand form */ + SHARED_FWORD(ISLAST, "last-image") , + SHARED_FWORD(ISLAST, "last-img") , /* Shorthand form */ + SHARED_FWORD(SETLAST, "set-last-image") , + SHARED_FWORD(SETLAST, "set-last-img") , /* Shorthand form */ + + SH_FW_SK_WIL(SAVEIMG, "save-image") , + SH_FW_SK_WIL(SAVEIMG, "save-img") , /* Shorthand form */ + + SHARED_FWORD(RESETSYMBS, "reset-symbols") , + + /* User-Macro definers */ + SHARED_IG_HDLR("[MACRO]", add_user_macro, 0 , skip_user_macro) , + + /* Comments and Remarks */ + SHARED_IG_HDLR("\", process_remark, '\n', process_remark) , + SHARED_IG_HDLR("(", process_remark, ')', process_remark) , + + /* Directives to print or discard a user-generated message */ + SHARED_IG_HDLR("[MESSAGE]", user_message, '\n', skip_user_message) , + SHARED_IG_HDLR("#MESSAGE", user_message, '\n', skip_user_message) , + SHARED_IG_HDLR("[#MESSAGE]", user_message, '\n', skip_user_message) , + SHARED_IG_HDLR("#MESSAGE"", user_message, '"' , skip_user_message) , +}; + +static const int number_of_shared_words = + sizeof(shared_words_list)/sizeof(tic_hdr_t); + +/* ************************************************************************** + * + * Function name: lookup_shared_word + * Synopsis: Return a pointer to the data-structure of the named + * word, only if it is a "Shared Word" + * + * Inputs: + * Parameters: + * tname The name to look for + * Local Static Variables: + * global_voc_dict_ptr "Tail" of Global Vocabulary + * + * Outputs: + * Returned Value: Pointer to the data-structure, or + * NULL if not found. + * + * Process Explanation: + * The "Shared Words" are scattered among the Global Vocabulary; + * the user is allowed to create aliases, which may be in the + * Current-Device. We will search through the "current" scope + * and decide whether the name we found is a "Shared Word" by + * looking for COMMON_FWORD in the "definer" field. + * + * Extraneous Remarks: + * This is the only place where an additional check of the + * "definer" field is required to identify a desired entry. + * Should another "definer"-type be required, I recommend + * defining a general-purpose function in ticvocab.c and + * applying it here and in the other place(s). + * + **************************************************************************** */ + +tic_hdr_t *lookup_shared_word( char *tname) +{ + tic_hdr_t *found ; + tic_hdr_t *retval = NULL ; + + found = lookup_current( tname ); + if ( found != NULL ) + { + if ( found->fword_defr == COMMON_FWORD ) + { + retval = found ; + } + } + + return ( retval ); + } + +/* ************************************************************************** + * + * Function name: handle_shared_word + * Synopsis: Perform the function associated with the given name + * only if it is a "Shared Word". Indicate if it was. + * + * Inputs: + * Parameters: + * tname The "target" name for which to look + * + * Outputs: + * Returned Value: TRUE if the name is a valid "Shared Word" + * + * Extraneous Remarks: + * This is very similar to a call to handle_tic_vocab() except + * for the additional filtering for a "Shared Word" definer. + * + **************************************************************************** */ + +bool handle_shared_word( char *tname ) +{ + tic_hdr_t *found ; + bool retval = FALSE; + + found = lookup_shared_word( tname ); + if ( found != NULL ) + { + found->funct(found->pfield); + retval = TRUE; + } + + return ( retval ) ; +} + + +/* ************************************************************************** + * + * Function name: lookup_shared_f_exec_word + * Synopsis: Return a pointer to the data-structure of the named + * word, only if it is a "Shared F-Exec Word" + * + * Inputs: + * Parameters: + * tname The name to look for + * Local Static Variables: + * global_voc_dict_ptr "Tail" of Global Vocabulary + * Macro Definitions: + * FWORD_EXEC_FUNC The "Active" function of the + * sub-class of "Shared Word"s + * that is the object of this + * routine's search + * + * Outputs: + * Returned Value: Pointer to the data-structure, or + * NULL if not found. + * + * Process Explanation: + * The "Shared F-Exec Words" are the subset of "Shared Words" that + * have the FWORD_EXEC_FUNC as their "Active" function. + * + * Extraneous Remarks: + * This is the only routine that requires a check of two fields; + * it seems unlikely that there will be any need to generalize + * the core of this routine... + * + **************************************************************************** */ + +tic_hdr_t *lookup_shared_f_exec_word( char *tname) +{ + tic_hdr_t *found ; + tic_hdr_t *retval = NULL ; + + found = lookup_shared_word( tname ); + if ( found != NULL ) + { + if ( found->funct == FWORD_EXEC_FUNC ) + { + retval = found ; + } + } + + return ( retval ); + +} + +/* ************************************************************************** + * + * Function name: init_dictionary + * Synopsis: Initialize all the vocabularies. For the Global + * Vocabulary, fill in the link fields in each of the + * otherwise pre-initialized built-in lists, link the + * lists together, and set the relevant pointers. For + * other lists, call their initialization routines. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * Local Static Variables: + * tokens_table Base of the "FC-Tokens" list + * number_of_builtin_tokens Number of "FC-Token" entries + * fwords_list Base of the "FWords" list + * number_of_builtin_fwords Number of "FWord" entries + * shared_words_list Base of the "Shared Words" list + * number_of_shared_words Number of "Shared Words" entries + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * global_voc_dict_ptr "Tail" of Global Vocabulary + * fc_tokens_list_start "Tail" of "FC-Tokens" list + * fc_tokens_list_ender End of "FC-Tokens" search + * shared_fwords_ender End of Shared Words" search + * global_voc_reset_ptr Reset-point for Global Vocab + * + * Process Explanation: + * The first linked will be the last searched. + * Link the "FC-Tokens" first, and mark their limits + * Link the "FWords" next, + * Mark the end-limit of the "Shared Words", and link them + * The "Conditionals", defined in another file, are also "Shared"; + * link them next. + * Then link the Built-In Macros, also defined in another file. + * These constitute the Global Vocabulary. + * Mark the reset-point for the Global Vocabulary. + * The "Tokenizer Escape" mode vocabulary is not linked to the Global + * Vocabulary; call its initialization routine. + * + * Extraneous Remarks: + * I only wish I had done this sooner... + * + **************************************************************************** */ + +void init_dictionary( void ) +{ + + global_voc_dict_ptr = NULL; /* Belt-and-suspenders... */ + + /* The "FC-Tokens" list must be linked first. */ + fc_tokens_list_ender = global_voc_dict_ptr; + init_tic_vocab( tokens_table, + number_of_builtin_tokens, + &global_voc_dict_ptr ) ; + fc_tokens_list_start = global_voc_dict_ptr; + + /* Link the "FWords" next */ + init_tic_vocab( (tic_hdr_t *)fwords_list, + number_of_builtin_fwords, + &global_voc_dict_ptr ) ; + + /* Mark the end-limit of the "Shared Words", and link them. */ + shared_fwords_ender = global_voc_dict_ptr; + init_tic_vocab( (tic_hdr_t *)shared_words_list, + number_of_shared_words, + &global_voc_dict_ptr ) ; + + /* Link the "Conditionals" to the Global Vocabulary. */ + init_conditionals_vocab( &global_voc_dict_ptr ) ; + + /* Link the Built-In Macros */ + init_macros( &global_voc_dict_ptr ) ; + + /* Mark the reset-point for the Global Vocabulary. */ + global_voc_reset_ptr = global_voc_dict_ptr; + + /* Initialize the "Tokenizer Escape" mode vocabulary */ + init_tokz_esc_vocab(); + + /* Locals and Device-Node vocabularies are initially empty */ + +} + +/* ************************************************************************** + * + * Function name: reset_normal_vocabs + * Synopsis: Reset the vocabularies that were created in "Normal" + * (as distinguished from "Tokenizer Escape") mode + * to the proper state for a fresh tokenization. + * + * Associated FORTH words: END0 END1 + * Associated Tokenizer directives: RESET-SYMBOLS (in "Normal" mode) + * FCODE-END + * + * Inputs: + * Parameters: NONE + * Global Variables: + * global_voc_reset_ptr Position to which to reset + * the "Global" Vocabulary + * current_device_node Vocab struct of current dev-node + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * global_voc_dict_ptr Reset to "Built-In" position + * current_device_node Reset to point at "root" dev-node + * Memory Freed + * All memory allocated by user-definitions in "normal" mode + * -- Macros, Conditionals and Device-node Vocabularies -- are + * reset via function call. + * + * Error Detection: + * Presence of extra device-node data structure(s) indicates that + * there were more "new-device" calls than "finish-device"; + * report each as an ERROR + * + * Process Explanation: + * Vocabularies created in other files, that have different + * data-structures, will have "reset" routines of their + * own associated with them in the files in which they + * are created. Those routines will be called from here. + * Definitions in the "Tokenizer Escape Vocabulary", i.e., + * the one in effect in "Tokenizer Escape" mode, are + * specifically not touched by this routine. + * + **************************************************************************** */ + +void reset_normal_vocabs( void ) +{ + reset_tic_vocab( &global_voc_dict_ptr, global_voc_reset_ptr ); + + /* Delete the top-level device-node vocab. + * If there are extra device-nodes, + * delete their data structures and show errors + */ + do + { + if ( current_device_node->parent_node != NULL ) + { + tokenization_error( TKERROR, + "Missing FINISH-DEVICE for new device"); + started_at( current_device_node->ifile_name, + current_device_node->line_no ); + } + delete_device_vocab(); + } while ( current_device_node->parent_node != NULL ); + +} + + +/* ************************************************************************** + * + * Function name: reset_vocabs + * Synopsis: Reset all the vocabularies to the proper state + * for beginning a fresh tokenization, particularly + * when multiple files are named on the command-line + * + * Inputs: + * Parameters: NONE + * + * Outputs: + * Returned Value: NONE + * Memory Freed + * All memory allocated by user-definitions will be freed + * + * Process Explanation: + * Call the reset_normal_vocabs() routine to get the vocabularies + * that apply to "Normal" mode, then call the "reset" routine + * for the "Tokenizer Escape Vocabulary", which is supposed + * to persist across device-nodes but not across input-files + * named on the command-line. + * + **************************************************************************** */ + +void reset_vocabs( void ) +{ + reset_normal_vocabs(); + reset_tokz_esc(); +}
Modified: fcode-utils/toke/dictionary.h =================================================================== --- fcode-utils/toke/dictionary.h 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/dictionary.h 2006-08-18 12:47:12 UTC (rev 76) @@ -1,3 +1,6 @@ +#ifndef _TOKE_DICTIONARY_H +#define _TOKE_DICTIONARY_H + /* * OpenBIOS - free your system! * ( FCode tokenizer ) @@ -24,81 +27,152 @@ * */
-#define COLON 0x01 -#define SEMICOLON 0x02 -#define TOKENIZE 0x03 -#define AGAIN 0x04 -#define ALIAS 0x05 -#define GETTOKEN 0x06 -#define ASCII 0x07 -#define BEGIN 0x08 -#define BUFFER 0x09 -#define CASE 0x0a -#define CONST 0x0b -#define CONTROL 0x0c -#define CREATE 0x0d -#define DECIMAL 0x0e -#define DEFER 0x0f -#define CDO 0x10 -#define DO 0x11 -#define ELSE 0x12 -#define ENDCASE 0x13 -#define ENDOF 0x14 -#define EXTERNAL 0x15 -#define FIELD 0x16 -#define HEADERLESS 0x17 -#define HEADERS 0x18 -#define HEX 0x19 -#define IF 0x1a -#define CLEAVE 0x1b -#define LEAVE 0x1c -#define CLOOP 0x1d -#define LOOP 0x1e -#define OCTAL 0x1f -#define OF 0x20 -#define REPEAT 0x21 -#define THEN 0x22 -#define TO 0x23 -#define UNTIL 0x24 -#define VALUE 0x25 -#define VARIABLE 0x26 -#define WHILE 0x27 -#define OFFSET16 0x28 -#define BEGINTOK 0x29 -#define EMITBYTE 0x2a -#define ENDTOK 0x2b -#define FLOAD 0x2c -#define STRING 0x2d -#define PSTRING 0x2e -#define PBSTRING 0x2f -#define SSTRING 0x30 -#define RECURSIVE 0x31 -#define HEXVAL 0x32 -#define DECVAL 0x33 -#define OCTVAL 0x34 +/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */
-#define END0 0xdb -#define END1 0xdc -#define CHAR 0xdd -#define CCHAR 0xde -#define ABORTTXT 0xdf +/* ************************************************************************** + * + * Numeric values for FWord-type vocabulary entries. Used by the + * big "switch" statement in handle_internal(); a subset are + * also used as "definer-type" values associated with various + * types of definitions. + * + **************************************************************************** */
-#define NEXTFCODE 0xef +typedef enum fword_token { + UNSPECIFIED = 0xBAADD00D , /* Default (absence-of) "definer" */ + COMMON_FWORD = 0xC0EDC0DE , /* Definer indicating a "shared" FWord */ + BI_FWRD_DEFN = 0xB1F4409D , /* Definer indicating a "built-in FWord" */ + COLON = 1 , + SEMICOLON , + TICK , + AGAIN , + ALIAS , + BRACK_TICK , + F_BRACK_TICK , + ASCII , + BEGIN , + BUFFER , + CASE , + CONST , + CONTROL , + CREATE , + DECIMAL , + DEFER , + DEFINED , + CDO , + DO , + ELSE , + ENDCASE , + ENDOF , + EXTERNAL , + INSTANCE , + FIELD , + NEW_DEVICE , + FINISH_DEVICE , + FLITERAL , + HEADERLESS , + HEADERS , + HEX , + IF , + UNLOOP , + LEAVE , + LOOP_I , + LOOP_J , + LOOP , + PLUS_LOOP , + OCTAL , + OF , + REPEAT , + THEN , + TO , + IS , + UNTIL , + VALUE , + VARIABLE , + WHILE , + OFFSET16 , + ESCAPETOK , + EMITBYTE , + FLOAD , + STRING , + PSTRING , + PBSTRING , + SSTRING , + RECURSIVE , + RECURSE , + RET_STK_FETCH , + RET_STK_FROM , + RET_STK_TO , + HEXVAL , + DECVAL , + OCTVAL ,
-#define ENCODEFILE 0xf0 + ret_stk_from , + ASC_NUM , /* Convert char seq to number */ + ASC_LEFT_NUM , /* same, only left-justified. */
-#define FCODE_V1 0xf1 -#define FCODE_V3 0xf2 -#define NOTLAST 0xf3 -#define PCIREV 0xf4 -#define PCIHDR 0xf5 -#define PCIEND 0xf6 -#define START0 0xf7 -#define START1 0xf8 -#define START2 0xf9 -#define START4 0xfa -#define VERSION1 0xfb -#define FCODE_TIME 0xfc -#define FCODE_DATE 0xfd -#define FCODE_V2 0xfe -#define FCODE_END 0xff + CONDL_ENDER , /* Conditional "[THEN] / [ENDIF]" variants */ + CONDL_ELSE , /* Conditional "[ELSE]" directive variants */ + + PUSH_FCODE , /* Save the FCode Assignment number */ + POP_FCODE , /* Retrieve the FCode Assignment number */ + RESET_FCODE , /* Reset FCode Ass't nr and overlap checking */ + + CURLY_BRACE , /* Support for IBM-style Locals */ + DASH_ARROW , + LOCAL_VAL , + EXIT , + + FUNC_NAME , + IFILE_NAME , + ILINE_NUM , + + CL_FLAG , + SHOW_CL_FLAGS , + + OVERLOAD , + ALLOW_MULTI_LINE , + MACRO_DEF , + GLOB_SCOPE , + DEV_SCOPE , + + /* This value has to be adjusted + * so that FCODE_END comes + * out to be 0xff + */ + END0 = 0xd7 , /* 0xd7 */ + END1 , /* 0xd8 */ + CHAR , /* 0xd9 */ + CCHAR , /* 0xda */ + ABORTTXT , /* 0xdb */ + + NEXTFCODE , /* 0xdc */ + + ENCODEFILE , /* 0xdd */ + + FCODE_V1 , /* 0xde */ + FCODE_V3 , /* 0xdf */ + NOTLAST , /* 0xef */ + ISLAST , /* 0xf0 */ + SETLAST , /* 0xf1 */ + PCIREV , /* 0xf2 */ + PCIHDR , /* 0xf3 */ + PCIEND , /* 0xf4 */ + RESETSYMBS , /* 0xf5 */ + SAVEIMG , /* 0xf6 */ + START0 , /* 0xf7 */ + START1 , /* 0xf8 */ + START2 , /* 0xf9 */ + START4 , /* 0xfa */ + VERSION1 , /* 0xfb */ + FCODE_TIME , /* 0xfc */ + FCODE_DATE , /* 0xfd */ + FCODE_V2 , /* 0xfe */ + FCODE_END = 0xff /* 0xff */ +} fwtoken ; + +#endif /* _TOKE_DICTIONARY_H */
Modified: fcode-utils/toke/emit.c =================================================================== --- fcode-utils/toke/emit.c 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/emit.c 2006-08-18 12:47:12 UTC (rev 76) @@ -24,283 +24,548 @@ * */
+/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> + +#include "pcihdr.h" + #include "toke.h" +#include "vocabfuncts.h" #include "stack.h" +#include "scanner.h" #include "emit.h" +#include "clflags.h" +#include "errhandler.h" +#include "stream.h" +#include "nextfcode.h"
-extern bool offs16; -extern int verbose; -extern u8 *ostart, *opc, *oend; +/* ************************************************************************** + * + * Global Variables Imported + * verbose Enable optional messages, set by "-v" switch + * noerrors "Ignore Errors" flag, set by "-i" switch + * + **************************************************************************** */
-/* PCI data */ -extern u16 pci_vpd, pci_revision; -extern bool pci_is_last_image;
-/* header pointers */ -extern u8 *fcode_hdr; -extern u8 *pci_hdr; +/* ************************************************************************** + * + * Macro to zero-fill a field of the size of the given structure + * into the Output Buffer using the emit_byte() routine. + * + **************************************************************************** */
-extern bool haveend; +#define EMIT_STRUCT(x) {int j; for (j=0; j < sizeof(x) ; j++ ) emit_byte(0); }
-u16 lookup_token(char *name);
-static bool little_endian(void) +/* ************************************************************************** + * + * Local Static Variables, offsets into Output Buffer of ...: + * fcode_start_ob_off First FCode-Start byte + * fcode_hdr_ob_off FCode Header (Format byte) + * fcode_body_ob_off First functional FCode after FCode Header. + * pci_hdr_ob_off Start of PCI ROM Header Block structure + * pci_data_blk_ob_off Start of PCI Data Header Block structure + * + * For all of these, -1 means "Not initialized" + * + *************************************************************************** */ + +static int fcode_start_ob_off = -1; +static int fcode_hdr_ob_off = -1; +static int fcode_body_ob_off = -1; +static int pci_hdr_ob_off = -1; +static int pci_data_blk_ob_off = -1; + +/* ************************************************************************** + * + * These are to detect a particular error: If FCode has + * been written, before an Fcode-start<n> or before + * a PCI-header + * + **************************************************************************** */ + +static bool fcode_written = FALSE; + +/* ************************************************************************** + * + * Variables and Functions Imported, with + * Exposure as Limited as possible: + * ostart + * olen + * increase_output_buffer + * + **************************************************************************** */ + +extern u8 *ostart; +extern int olen; +extern void increase_output_buffer( void); + + +/* ************************************************************************** + * + * Function name: init_emit + * Synopsis: Initialize Local Static Variables before starting + * Output. + * Exposure as Limited as possible. + * + **************************************************************************** */ +void init_emit( void); /* Prototype. Limit Exposure. */ +void init_emit( void) { - static short one=1; - return *(char *)&one==1; + fcode_start_ob_off = -1; + fcode_hdr_ob_off = -1; + fcode_body_ob_off = -1; + pci_hdr_ob_off = -1; + pci_data_blk_ob_off = -1; + fcode_written = FALSE; + haveend = FALSE; /* Get this one too... */ }
-int emit_byte(u8 data) -{ - u8 *newout; - int newsize;
- if(opc==oend) { - /* need more output space */ - newsize = (oend - ostart) * 2; - printf("Increasing output buffer to %d bytes.\n", newsize); - if ((newout=realloc(ostart, newsize)) == NULL) { - printf("toke: could not allocate %d bytes for output buffer\n", newsize); - exit(-1); - } +/* ************************************************************************** + * + * Function name: emit_byte + * Synopsis: Fundamental routine for placing a byte + * into the Output Buffer. Also, check + * whether the buffer needs to be expanded. + * For internal use only. + * + **************************************************************************** */
- /* move pointers */ - opc=newout+(opc-ostart); - ostart=newout; - oend=ostart+newsize; +static void emit_byte(u8 data) +{ + if ( opc == olen) + { + increase_output_buffer(); } - *opc=data; + + *(ostart+opc) = data ; opc++; - - return 0; }
-int emit_fcode(u16 tok) +void emit_fcode(u16 tok) { if ((tok>>8)) emit_byte(tok>>8);
emit_byte(tok&0xff); - - return 0; + fcode_written = TRUE; }
-int emit_token(const char *name) +static void emit_num32(u32 num) { - return emit_fcode(lookup_token((char *)name)); -} - -int emit_num32(u32 num) -{ emit_byte(num>>24); emit_byte((num>>16)&0xff); emit_byte((num>>8)&0xff); emit_byte(num&0xff);
- return 0; }
-int emit_num16(u16 num) +/* ************************************************************************** + * + * Function name: user_emit_byte + * Synopsis: Action of user-mandated call to emit-byte. + * Covers the corner-case where this is the + * first command issued in the source input. + * + **************************************************************************** */ + +void user_emit_byte(u8 data) { - emit_byte(num>>8); - emit_byte(num&0xff); - - return 0; + emit_byte( data); + fcode_written = TRUE; }
-int emit_offset(s16 offs) +void emit_offset(s16 offs) { + /* Calling routine will test for out-of-range FCode-Offset */ if (offs16) - emit_num16(offs); - else - emit_byte(offs); - - return 0; + emit_byte(offs>>8); + emit_byte(offs&0xff); }
-s16 receive_offset(void) +void emit_literal(u32 num) { - s16 offs=0; - - if (offs16) { - offs=((*opc)<<8)|(*(opc+1)); - } else - offs=(*opc); - - return offs; + emit_token("b(lit)"); + emit_num32(num); }
-int emit_string(u8 *string, unsigned int cnt) +void emit_string(u8 *string, signed int cnt) { - unsigned int i=0; + signed int i=0; + signed int cnt_cpy = cnt; - if (cnt>255) { - printf("string too long."); - exit(1); + if ( cnt_cpy > STRING_LEN_MAX ) + { + tokenization_error( TKERROR, + "String too long: %d characters. Truncating.\n",cnt); + cnt_cpy = STRING_LEN_MAX ; } - emit_byte(cnt); - for (i=0; i<cnt; i++) + emit_byte(cnt_cpy); + for (i=0; i<cnt_cpy; i++) emit_byte(string[i]); - - return 0; }
-int emit_fcodehdr(void) +void emit_fcodehdr(const char *starter_name) { - /* We comply with IEEE 1275-1994 */ - emit_byte(0x08); - /* checksum */ - emit_num16(0); + /* Check for error conditions */ + if ( fcode_written ) + { + tokenization_error( TKERROR , + "Cannot create FCode header after FCode output has begun.\n"); + if ( ! noerrors ) return ; + }
- /* len */ - emit_num32(0); + fcode_header_t *fcode_hdr;
- return 0; + fcode_start_ob_off = opc; + emit_token( starter_name ); + + fcode_hdr_ob_off = opc; + fcode_hdr = (fcode_header_t *)(ostart+fcode_hdr_ob_off); + + EMIT_STRUCT(fcode_header_t); + + fcode_body_ob_off = opc; + + /* Format = 8 means we comply with IEEE 1275-1994 */ + fcode_hdr->format = 0x08; + }
-int finish_fcodehdr(void) +/* ************************************************************************** + * + * Function name: finish_fcodehdr + * Fill in the FCode header's checksum and length fields, and + * reset the FCode-header pointer for the next image. + * + * If haveend is true then the end0 has already been written + * and fcode_ender() has been called. + * + * Print a WARNING message if the end-of-file was encountered + * without an end0 or an fcode-end + * + * Print an informative message to standard-output giving the + * checksum. Call list_fcode_ranges() to print the + * value of the last FCode-token that was assigned or + * the Ranges of assigned FCode-token values if so be... + * The final FCode-binary file-length will be printed + * when the binary file is being closed. + * + **************************************************************************** */ + +void finish_fcodehdr(void) { - u16 checksum=0; - u32 len,i;
- if(!fcode_hdr) + if( fcode_hdr_ob_off == -1 ) { - printf("warning: trying to fix up unknown fcode header\n"); - return -1; + tokenization_error( TKERROR, + "Missing FCode header.\n"); + return ; }
- /* If the program does not do this, we do */ + /* If the program did not end cleanly, we'll handle it */ if (!haveend) + { + tokenization_error ( WARNING, + "End-of-file encountered without END0 or FCODE-END. " + "Supplying END0\n"); emit_token("end0"); + fcode_ender(); + }
- len=(unsigned long)opc-(unsigned long)(fcode_hdr-1); + /* Calculate and place checksum and length, if haven't already */ + if ( fcode_start_ob_off != -1 ) + { + u16 checksum; + int length; + + u8 *fcode_body = ostart+fcode_body_ob_off; + u8 *ob_end = ostart+opc; + fcode_header_t *fcode_hdr = + (fcode_header_t *)(ostart+fcode_hdr_ob_off); - for (i=8;i<len;i++) - checksum+=fcode_hdr[i-1]; + length = opc - fcode_start_ob_off;
- dpush((unsigned long)opc); - opc=fcode_hdr+1; - emit_num16(checksum); - emit_num32(len); - opc=(u8 *)dpop(); + for ( checksum = 0; + fcode_body < ob_end ; + checksum += *(fcode_body++) ) ; + + BIG_ENDIAN_WORD_STORE(fcode_hdr->checksum , checksum); + BIG_ENDIAN_LONG_STORE(fcode_hdr->length , length); + if (verbose) - printf("toke: checksum is 0x%04x (%d bytes)\n", - checksum, len); + { + printf( "toke: checksum is 0x%04x (%d bytes). ", + checksum, length); + list_fcode_ranges( TRUE); + } + }
- fcode_hdr=NULL; + /* Reset things for the next image... */ + fcode_start_ob_off = -1; + fcode_hdr_ob_off = -1; + fcode_body_ob_off = -1; + fcode_written = FALSE; haveend=FALSE; - return 0; }
-int emit_pcihdr(u16 vid, u16 did, u32 classid) +/* ************************************************************************** + * + * Function name: emit_pci_rom_hdr + * Synopsis: Write the PCI ROM Header Block into the Output Buffer + * + * Inputs: + * Parameters: NONE + * Global Variables: + * opc Output Buffer Position Counter + * ostart Start of Output Buffer + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * pci_hdr_ob_off PCI ROM Header Block Position + * (Offset) in Output Buffer + * FCode Output buffer: + * Write the part of the PCI ROM Header Block we know: + * Fill in the signature and the field reserved for + * "processor architecture unique data". + * Fill in the "Pointer to PCI Data Structure" with the + * size of the data structure, because the first PCI + * Data Structure will follow immediately. + * + * Error Detection: (Handled by calling routine) + * + **************************************************************************** */ + +static void emit_pci_rom_hdr(void) { - int i; + rom_header_t *pci_hdr; + pci_hdr_ob_off = opc; + pci_hdr = (rom_header_t *)(ostart + pci_hdr_ob_off); + + EMIT_STRUCT(rom_header_t); /* PCI start signature */ - emit_byte(0x55); emit_byte(0xaa); + LITTLE_ENDIAN_WORD_STORE(pci_hdr->signature,0xaa55); /* Processor architecture */ - emit_byte(0x34); emit_byte(0x00); + /* Note: + * The legacy code used to read: + * + * pci_hdr->reserved[0] = 0x34; + * + * I don't know what significance the literal 34 had, but + * by what might just be an odd coincidence, it is equal + * to the combined lengths of the PCI-ROM- and PCI-Data- + * headers. + * + * I suspect that it is more than merely an odd coincidence, + * and that the following would be preferable: + */
- /* 20 bytes of padding */ - for (i=0; i<20; i++) emit_byte(0x00); + LITTLE_ENDIAN_WORD_STORE( pci_hdr->reserved , + (sizeof(rom_header_t) + sizeof(pci_data_t)) ) ;
+ /* already handled padding */ + /* pointer to start of PCI data structure */ - emit_byte(0x1c); emit_byte(0x00); + LITTLE_ENDIAN_WORD_STORE(pci_hdr->data_ptr, sizeof(rom_header_t) );
- /* 2 bytes of zero padding */ - emit_byte(0x00); emit_byte(0x00); +} - /* PCI Data structure */ - emit_byte('P'); emit_byte('C'); emit_byte('I'); emit_byte('R'); - /* vendor id */ - emit_byte(vid&0xff); emit_byte(vid>>8); - /* device id */ - emit_byte(did&0xff); emit_byte(did>>8); - /* vital product data */ - emit_byte(0x00); emit_byte(0x00); - /* length of pci data structure */ - emit_byte(0x18); emit_byte(0x00); - /* PCI data structure revision */ - emit_byte(0x00); - - if (little_endian()) { - /* reg level programming */ - emit_byte(classid & 0xff); - /* class code */ - emit_byte((classid>>8)&0xff); - emit_byte((classid>>16)&0xff); - } else { - /* class code */ - emit_byte((classid>>8)&0xff); - emit_byte((classid>>16)&0xff); - /* reg level programming */ - emit_byte(classid & 0xff); +/* ************************************************************************** + * + * Function name: emit_pci_data_block + * Synopsis: Write the PCI Data Block into the Output Buffer + * + * Inputs: + * Parameters: NONE + * Global Variables: + * opc Output Buffer Position Counter + * Data-Stack Items: + * Top: Class Code + * Next: Device ID + * 3rd: Vendor ID + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * pci_data_blk_ob_off PCI Data Header Block Position + * (Offset) in Output Buffer + * Data-Stack, # of Items Popped: 3 + * FCode Output buffer: + * Write the PCI Data Header Block: Fill in the signature, + * Vendor ID, Device ID and Class Code, and everything + * else whose value we know. (Size and Checksum will + * have to wait until we finish the image...) + * Printout: + * Advisory of Vendor, Device and Class + * + * Error Detection: (Handled by calling routine) + * + **************************************************************************** */ + +static void emit_pci_data_block(void) +{ + pci_data_t *pci_data_blk; + u32 class_id = dpop(); + u16 dev_id = dpop(); + u16 vend_id = dpop(); + + pci_data_blk_ob_off = opc; + pci_data_blk = (pci_data_t *)(ostart + pci_data_blk_ob_off); + + EMIT_STRUCT(pci_data_t); + + BIG_ENDIAN_LONG_STORE(pci_data_blk->signature , PCI_DATA_HDR ); + + LITTLE_ENDIAN_WORD_STORE(pci_data_blk->vendor , vend_id ); + LITTLE_ENDIAN_WORD_STORE(pci_data_blk->device , dev_id ); + LITTLE_ENDIAN_TRIPLET_STORE(pci_data_blk->class_code , class_id ); + + LITTLE_ENDIAN_WORD_STORE(pci_data_blk->dlen , sizeof(pci_data_t) ); + + pci_data_blk->drevision = PCI_DATA_STRUCT_REV ; + + /* code type = open firmware = 1 */ + pci_data_blk->code_type = 1; + + /* last image flag */ + pci_data_blk->last_image_flag = pci_is_last_image ? 0x80 : 0 ; + + tokenization_error(INFO , + "PCI header vendor id=0x%04x, " + "device id=0x%04x, class=%06x\n", + vend_id, dev_id, class_id ); + +} + +/* ************************************************************************** + * + * Function name: emit_pcihdr + * Synopsis: Supervise the writing of PCI Header information + * into the Output Buffer, when the PCI-HEADER + * tokenizer directive has been encountered. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * fcode_start_ob_off Initted if FCode output has begun + * noerrors The "Ignore Errors" flag + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * FCode Output buffer: + * + * Error Detection: + * An attempt to write a PCI Header after FCode output -- either an + * Fcode-start<n> or ordinary FCode -- has begun is an ERROR. + * Report it; do nothing further, unless "Ignore Errors" is set. + * + **************************************************************************** */ + +void emit_pcihdr(void) +{ + + /* Check for error conditions */ + if ( + /* FCODE-START<n> has already been issued */ + ( fcode_start_ob_off != -1 ) + /* Other FCode has been written */ + || fcode_written + ) + { + tokenization_error( TKERROR , + "Cannot create PCI header after FCode output has begun.\n"); + if ( ! noerrors ) return ; }
- /* size of image - to be filled later */ - emit_byte(0x00); emit_byte(0x00); - /* revision level */ - emit_byte(0x00); emit_byte(0x00); - /* code type = open firmware */ - emit_byte(0x01); - emit_byte(0x80); - /* 2 bytes of padding */ - emit_byte(0x00); emit_byte(0x00); + emit_pci_rom_hdr();
- return 0; + emit_pci_data_block(); }
+/* ************************************************************************** + * + * Function name: finish_pcihdr + * Synopsis: Fill-in the fields of the PCI Header that could + * not be determined until the end of the PCI-block. + * + *************************************************************************** */
-int finish_pcihdr(void) +void finish_pcihdr(void) { - u8 *tpc; - u32 imgsize=opc-ostart, imgblocks; + + u32 imagesize ; + u32 imageblocks; int padding; - if(!pci_hdr) + rom_header_t *pci_hdr; + pci_data_t *pci_data_blk; + + if( pci_data_blk_ob_off == -1 ) { - printf("error: trying to fix up unknown pci header\n"); - return -1; + tokenization_error( TKERROR, + "%s without PCI-HEADER\n", strupr(statbuf) ); + return ; }
+ pci_hdr = (rom_header_t *)(ostart + pci_hdr_ob_off); + pci_data_blk = (pci_data_t *)(ostart + pci_data_blk_ob_off); + /* fix up vpd */ - tpc=opc; - opc=pci_hdr+36; - emit_byte(pci_vpd&0xff); emit_byte(pci_vpd>>8); + LITTLE_ENDIAN_WORD_STORE(pci_data_blk->vpd, pci_vpd);
- /* fix up image size */ - opc=pci_hdr+44; - imgblocks=(imgsize+511)>>9; /* size is in 512byte blocks */ - emit_byte(imgblocks&0xff); emit_byte(imgblocks>>8); + /* Calculate image size and padding */ + imagesize = opc - pci_hdr_ob_off; /* Padding includes PCI hdr */ + imageblocks = (imagesize + 511) >> 9; /* Size in 512-byte blocks */ + padding = (imageblocks << 9) - imagesize; + + /* fix up image size. */ + LITTLE_ENDIAN_WORD_STORE(pci_data_blk->ilen, imageblocks); /* fix up revision */ - emit_byte(pci_revision&0xff); emit_byte(pci_revision>>8); + if ( big_end_pci_image_rev ) + { + BIG_ENDIAN_WORD_STORE(pci_data_blk->irevision, pci_image_rev); + }else{ + LITTLE_ENDIAN_WORD_STORE(pci_data_blk->irevision, pci_image_rev); + } /* fix up last image flag */ - opc++; - emit_byte(pci_is_last_image?0x80:0x00); - opc=tpc; + pci_data_blk->last_image_flag = pci_is_last_image ? 0x80 : 0 ; /* align to 512bytes */ - padding=((imgsize+511)&0xfffffe00)-imgsize; + printf("Adding %d bytes of zero padding to PCI image.\n",padding); while (padding--) emit_byte(0); + if ( ! pci_is_last_image ) + { + printf("Note: PCI header is not last image.\n"); + } + printf("\n"); - pci_hdr=NULL; - return 0; + pci_hdr_ob_off = -1; + pci_data_blk_ob_off = -1; }
void finish_headers(void) { - if (fcode_hdr) finish_fcodehdr(); - if (pci_hdr) finish_pcihdr(); + if (fcode_hdr_ob_off != -1) finish_fcodehdr(); + if (pci_hdr_ob_off != -1) finish_pcihdr(); }
Modified: fcode-utils/toke/emit.h =================================================================== --- fcode-utils/toke/emit.h 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/emit.h 2006-08-18 12:47:12 UTC (rev 76) @@ -1,3 +1,6 @@ +#ifndef _TOKE_EMIT_H +#define _TOKE_EMIT_H + /* * OpenBIOS - free your system! * ( FCode tokenizer ) @@ -24,21 +27,90 @@ * */
-#ifndef _H_EMIT -#define _H_EMIT +/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + +#include "types.h"
-int emit_byte(u8 data); -int emit_fcode(u16 tok); -int emit_token(const char *name); -int emit_num32(u32 num); -int emit_num16(u16 num); -int emit_offset(s16 offs); -s16 receive_offset(void); -int emit_string(u8 *string, unsigned int cnt); -int emit_fcodehdr(void); -int finish_fcodehdr(void); -int emit_pcihdr(u16 vid, u16 did, u32 classid); -int finish_pcihdr(void); +/* ************************************************************************** + * Structure Name: fcode_header_t + * Synopsis: FCode Header within the Output Buffer + * + * Fields: + * format, checksum and length All as prescribed in P1275, Sec 5.2.2.5 + * + * Note that the Checksum and Length fields are stated as byte-arrays + * rather than as integers. This is intended to guarantee that + * their endian-ness will remain independent of the endian-ness + * of the host-platform on which this Tokenizer is running. + * Note also that, as integers, both are BIG-Endian. + * + **************************************************************************** */ + +typedef struct { + u8 format; + u8 checksum[2]; /* [0] = Hi byte, [1] = Lo */ + u8 length[4]; /* [0] = Hi, [1] = Hi-mid, [2] = Lo-mid, [3] = Lo */ +} fcode_header_t; + + +/* ************************************************************************** + * Macro Name: STRING_LEN_MAX + * Max number of bytes allowable in an output string + * + * Arguments: NONE + * + * This value must remail hard-coded and immutable. It represents the + * maximum number allowed in a FORTH counted-string's count-byte + * (which is, of course, the maximum number that can be expressed + * in an unsigned byte). + * It should not be used for anything else (e.g., buffer sizes), and + * most especially not for anything that might be changed! + * + **************************************************************************** */ + +#define STRING_LEN_MAX 255 + + +/* ************************************************************************** + * Macro Name: GET_BUF_MAX + * Size alloted to input-string buffer + * + * Arguments: NONE + * + * This is a generous allotment for the buffer into which + * input strings are gathered. Overflow calculations are + * also based on it. It may be changed safely. + * We like to keep it a nice power-of-two to make the memory- + * allocation routine run efficiently and happily (Okay, so + * that's anthropormism: It's efficient and *we*'re happy. + * Better? I thought so... ;-) + * + **************************************************************************** */ + +#define GET_BUF_MAX 1024 + + +/* ************************************************************************** * + * + * Function Prototypes / Functions Exported: + * + **************************************************************************** */ + +void emit_fcode(u16 tok); +void user_emit_byte(u8 data); + +void emit_offset(s16 offs); +void emit_string(u8 *string, signed int cnt); +void emit_fcodehdr(const char *starter_name); +void finish_fcodehdr(void); +void emit_pcihdr(void); +void finish_pcihdr(void); void finish_headers(void); +void emit_end0(void); +void emit_literal(u32 num);
-#endif /* _H_EMIT */ +#endif /* _TOKE_EMIT_H */
Added: fcode-utils/toke/errhandler.c =================================================================== --- fcode-utils/toke/errhandler.c (rev 0) +++ fcode-utils/toke/errhandler.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,956 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Error-Handler for Tokenizer + * + * Controls printing of various classes of errors + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Functions Exported: + * init_error_handler Initialize the error-counts, + * announce the file names. + * tokenization_error Handle an error of the given class, + * print the given message in the + * standard format. + * started_at Supplemental message, giving a back-reference + * to the "starting" point of a compound + * error, including last-colon identification. + * just_started_at Supplemental back-reference to "starting" point + * of compound error, but without last-colon + * identification. + * where_started Supplemental message, giving a more terse back- + * -reference to "start" of compound-error. + * just_where_started Supplemental message, more terse back-reference, + * without last-colon identification. + * in_last_colon Supplemental back-reference message, + * identifying last Colon-definition. + * safe_malloc malloc with built-in failure test. + * error_summary Summarize final error-message status + * before completing tokenization. + * + **************************************************************************** */ + + +/* ************************************************************************** + * + * We will define a set of bit-valued error-types and a + * global bit-mask. Each error-message will be associated + * with one of the bit-valued error-types. The bit-mask, + * which will be set by a combination of defaults and user + * inputs (mainly command-line arguments), will control + * whether an error-message of any given type is printed. + * + * Another bit-mask variable will accumulate the error- + * types that occur within any given run; at the end of + * the run, it will be examined to determine if the run + * failed, i.e., if the output should be suppressed. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Error-types fall into the following broad categories: + * FATAL Cause to immediately stop activity + * TKERROR Sufficient to make the run a failure, + * but not to stop activity. + * WARNING Not necessarily an error, but something + * to avoid. E.g., it might rely on + * assumptions that are not necessarily + * what the user/programmer wants. Or: + * It's a deprecated feature, or one + * that might be incompatible with + * other standard tokenizers. + * INFO Nothing is changed in processing, but + * an advisory is still in order. + * MESSAGE Message generated by the user. (Complete; + * new-line will be added by display routine.) + * P_MESSAGE Partial Message -- Instigated by user, but + * pre-formatted and not complete. New-line + * will be added by follow-up routine. + * + **************************************************************************** */ + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "types.h" +#include "toke.h" +#include "stream.h" +#include "errhandler.h" +#include "scanner.h" + +/* ************************************************************************** + * + * Global Variables Imported + * iname Name of file currently being processed + * lineno Current line-number being processed + * noerrors "Ignore Errors" flag, set by "-i" switch + * opc FCode Output Buffer Position Counter + * verbose If true, enable Advisory Messages + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Internal Static Variables + * print_msg Whether beginning of a message was printed; + * therefore, whether to print the rest. + * errs_to_print Error Verbosity Mask. Bits set correspond + * to message-types that will be printed + * May be altered by Command-Line switches. + * err_types_found Accumulated Error-types. Bits + * set correspond to error-types + * that have occurred. + * message_dest Message Dest'n. Usually ERRMSG_DESTINATION + * (stdout) except when we need to switch. + * err_count Count of Error Messages + * warn_count Count of Warning Messages + * info_count Count of "Advisory" Messages + * user_msg_count Count of User-generated Messages + * fatal_err_exit Exit code to be used for "Fatal" error. + * This is a special accommodation + * for the safe_malloc routine. + * + **************************************************************************** */ + +static bool print_msg ; +static int errs_to_print = ( FATAL | TKERROR | WARNING | + MESSAGE | P_MESSAGE | FORCE_MSG ) ; +static int err_types_found = 0 ; +static int err_count = 0 ; +static int warn_count = 0 ; +static int info_count = 0 ; +static int user_msg_count = 0 ; +static int fatal_err_exit = -1 ; +static FILE *message_dest; /* Would like to init to ERRMSG_DESTINATION + * here, but the compiler complains... + */ + +/* ************************************************************************** + * + * Internal Static Constant Structure + * err_category Correlate each error-type code with its + * Counter-variable and the printable + * form of its name. + * num_categories Number of entries in the err_category table + * + **************************************************************************** */ + +typedef struct { + int type_bit ; /* Error-type single-bit code */ + char *category_name ; /* Printable-name base */ + char *single ; /* Suffix to print singular of name */ + char *plural ; /* Suffix to print plural of name */ + int *counter ; /* Associated Counter-variable */ + bool new_line ; /* Whether to print new-line at end */ +} err_category ; + +static const err_category error_categories[] = { + /* FATAL must be the first entry in the table. */ + /* No plural is needed; only one is allowed.... */ + { FATAL, "Fatal Error", "", "", &err_count , TRUE }, + + { TKERROR, "Error" , "", "s", &err_count , FALSE }, + { WARNING, "Warning" , "", "s", &warn_count , FALSE }, + { INFO, "Advisor" , "y", "ies", &info_count , FALSE }, + { MESSAGE , "Message" , "", "s", &user_msg_count , TRUE }, + { P_MESSAGE , "Message" , "", "s", &user_msg_count , FALSE } +}; + +static const int num_categories = + ( sizeof(error_categories) / sizeof(err_category) ); + + +#ifdef NEEDS_STRUPR + +/* ************************************************************************** + * + * Function name: toup + * Synopsis: Support function for strupper + * Converts one character + * + * Inputs: + * Parameters: + * chr_ptr Pointer to the character + * + * Outputs: + * Returned Value: None + * Supplied Pointers: + * The character pointed to is changed + * + * Process Explanation: + * Because this fills in a lack in the host system, we cannot + * rely on the functions islower or toupper , which are + * usually built-in but might be similarly missing. + * + **************************************************************************** */ + +static void toup( char *chr_ptr) +{ + const unsigned char upcas_diff = ( 'a' - 'A' ); + if ( ( *chr_ptr >= 'a' ) && ( *chr_ptr <= 'z' ) ) + { + *chr_ptr -= upcas_diff ; + } +} + +/* ************************************************************************** + * + * Function name: strupper + * Synopsis: Replacement for strupr on systems that don't + * seem to have it. A necessary hack. + * + * Inputs: + * Parameters: + * strung Pointer to the string to be changed + * + * Outputs: + * Returned Value: Same pointer that was passed in + * Supplied Pointers: + * The string pointed to will be converted to upper case + * + * Process Explanation: + * Because it fills in a lack in the host system, this routine + * does not rely on the functions islower or toupper + * which are usually built-in but might be missing. + * + **************************************************************************** */ + +char *strupper( char *strung) +{ + char *strindx; + for (strindx = strung; *strindx != 0; strindx++) + { + toup( strindx); + } + return strung; +} + +/* ************************************************************************** + * + * If strupr is missing, it's a good bet that so is strlwr + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Function name: tolow + * Synopsis: Support function for strlower + * Converts one character + * + * Inputs: + * Parameters: + * chr_ptr Pointer to the character + * + * Outputs: + * Returned Value: None + * Supplied Pointers: + * The character pointed to is changed + * + * Process Explanation: + * Because this fills in a lack in the host system, we cannot + * rely on the functions isupper or tolower , which are + * usually built-in but might be similarly missing. + * + **************************************************************************** */ + +static void tolow( char *chr_ptr) +{ + const unsigned char lowcas_diff = ( 'A' - 'a' ); + if ( ( *chr_ptr >= 'A' ) && ( *chr_ptr <= 'Z' ) ) + { + *chr_ptr -= lowcas_diff ; + } +} + +/* ************************************************************************** + * + * Function name: strlower + * Synopsis: Replacement for strlwr on systems that don't + * seem to have it. A necessary hack. + * + * Inputs: + * Parameters: + * strung Pointer to the string to be changed + * + * Outputs: + * Returned Value: Same pointer that was passed in + * Supplied Pointers: + * The string pointed to will be converted to lower case + * + * Process Explanation: + * Because it fills in a lack in the host system, this routine + * does not rely on the functions isupper or tolower + * which are usually built-in but might be missing. + * + **************************************************************************** */ + +char *strlower( char *strung) +{ + char *strindx; + for (strindx = strung; *strindx != 0; strindx++) + { + tolow( strindx); + } + return strung; +} + + +#endif /* NEEDS_STRUPR */ + +/* ************************************************************************** + * + * Function name: init_error_handler + * Synopsis: Initialize the error-handler before starting a + * new tokenization; both the aspects that will + * persist across the entire run and those that + * need to be reset, such as error-counts. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * verbose Set by "-v" switch + * Macro: + * ERRMSG_DESTINATION Error message destination; + * (Set by development-time switch) + * FFLUSH_STDOUT Flush STDOUT if err-msg-dest is STDERR + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * errs_to_print Add the INFO bit if verbose is set + * Local Static Variables: + * message_dest Point it at ERRMSG_DESTINATION (stderr) + * Reset the following to zero: + * err_types_found Accumulated Error-types. + * err_count Count of Error Messages + * warn_count Count of Warning Messages + * info_count Count of "Advisory" Messages + * user_msg_count Count of User-generated Messages + * Other Exotic Effects: + * Flush stdout if Error message destination is not stdout, to + * avoid collisions with stderr once Error Messaging begins. + * + * Extraneous Remarks: + * This needs to be done before attempting to read the input file, + * so that any Messages that occur there can be properly counted. + * + **************************************************************************** */ + +void init_error_handler( void) +{ + message_dest = ERRMSG_DESTINATION; + if ( verbose ) errs_to_print |= INFO ; + err_types_found = 0 ; + err_count = 0 ; + warn_count = 0 ; + info_count = 0 ; + user_msg_count = 0 ; + FFLUSH_STDOUT +} + +/* ************************************************************************** + * + * Function name: tokenization_error + * Synopsis: Handle an error of the given class, + * print the given message in the standard format. + * + * Inputs: + * Parameters: + * err_type int One of the bit-valued error-types + * The remaining parameters are a format string and corresponding + * data objects such as would be sent to printf() + * Global Variables: + * errs_to_print Error Verbosity Mask. + * iname Name of file currently being processed + * lineno Current line-number being processed + * fatal_err_exit Exit code for "Fatal" error, if applicable. + * Macro: + * ERRMSG_DESTINATION Error message destination; + * (Development-time switch) + * Note: Whether this routine will or will not supply a new-line + * at the end of the printout depends on the category of the + * message. The new-line is included for a FATAL or a User- + * Generated Message, and excluded for the rest. For those, + * the calling routine must be responsible for including a + * new-line at the end of the format string or for otherwise + * finishing the line, as by calling started_at() + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * err_types_found Accumulated Error-types. + * print_msg Whether this message was printed; + * may be used by started_at() + * One of the following Category Counters + * will be incremented, as applicable: + * err_count + * warn_count + * info_count + * user_msg_count + * Printout: Directed to stdout or stderr + * (see definition of ERRMSG_DESTINATION) + * + * Error Detection: + * Err_type not in list + * Print special message; treat cause as an Error. + * Force printout. + * + * Process Explanation: + * Accumulated the Error-type into err_types_found + * Identify the Error-Category: + * Check the Error-Type against the bit-code. + * The Error-type may have more than one bit set, + * but if it matches the Category bit-code, it's it. + * If it doesn't match any Error-Category bit-code, print + * a special message and treat it as an ERROR code. + * Check the Error-Type against the Error Verbosity Mask; + * If it has a bit set, print the Error-Category, together + * with the source-file name and line number, and + * the rest of the message as supplied. + * The table that translates the Error-type into a printable + * Error-Category string also identifies the applicable + * Category Counter; increment it. + * Of course, there's no return from a FATAL error; it exits. + * + **************************************************************************** */ + +void tokenization_error( int err_type, char* msg, ... ) +{ + int indx ; + + /* Initial settings: treat as an Error. */ + char *catgy_name = "Error"; + char *catgy_suffx = ""; + int *catgy_counter = &err_count; + bool print_new_line = FALSE; + + /* Accumulated the Error-type into err_types_found */ + err_types_found |= err_type; + + /* Identify the Error-Category. */ + for ( indx = 0 ; indx < num_categories ; indx ++ ) + { + if ( ( error_categories[indx].type_bit & err_type ) != 0 ) + { + catgy_name = error_categories[indx].category_name; + catgy_suffx = error_categories[indx].single; + catgy_counter = error_categories[indx].counter; + print_new_line = error_categories[indx].new_line; + break; + } + } + + /* Special message if err_type not in list; treat as an Error. */ + if ( catgy_name == NULL ) + { + fprintf(ERRMSG_DESTINATION, + "Program error: Unknown Error-Type, 0x%08x. " + " Will treat as Error.\n", err_type) ; + err_types_found |= TKERROR; + print_msg = TRUE ; + } else { + /* Check the Error-Type against the Error Verbosity Mask */ + print_msg = BOOLVAL( ( errs_to_print & err_type ) != 0 ); + } + + if ( print_msg ) + { + va_list argp; + + if ( iname != NULL ) + { + fprintf(ERRMSG_DESTINATION, "%s%s: File %s, Line %d. ", + catgy_name, catgy_suffx, iname, lineno); + }else{ + /* Don't print iname or lineno if no file opened. */ + fprintf(ERRMSG_DESTINATION, "%s%s: ", + catgy_name, catgy_suffx); + } + + va_start(argp, msg); + vfprintf(ERRMSG_DESTINATION, msg, argp); + va_end(argp); + if ( print_new_line ) fprintf(ERRMSG_DESTINATION, "\n"); + + /* Increment the category-counter. */ + *catgy_counter += 1; + } + if ( err_type == FATAL ) + { + fprintf(ERRMSG_DESTINATION, "Tokenization terminating.\n"); + error_summary(); + exit ( fatal_err_exit ); + } +} + +/* ************************************************************************** + * + * Function name: print_where_started + * Synopsis: Supplemental message, following a tokenization_error, + * giving a back-reference to the "start" point of + * the compound-error being reported. + * This is a retro-fit; it does the heavy lifting for + * the routines started_at() , just_started_at() , + * where_started() , just_where_started() and + * in_last_colon() . + * + * Inputs: + * Parameters: + * show_started Whether to print a phrase about "started" + * show_that_st Whether to print "that started" as opposed + * to " , which started" + * saved_ifile File-name saved for "back-reference" + * saved_lineno Line-number saved for "back-reference" + * may_show_incolon Whether to allow a call to in_last_colon() + * Needed to prevent infinite recursion... + * Global Variables: + * iname Name of file currently being processed + * lineno Current line-number being processed + * Local Static Variables: + * print_msg Whether the beginning part of the message + * was printed by tokenization_error() + * message_dest Message Destination. Is ERRMSG_DESTINATION + * (stdout) usually, except sometimes... + * + * Outputs: + * Returned Value: None + * Printout: + * The remainder of a message: the location of a back-reference. + * The phrase "that started" is switchable. This routine + * will supply the leading space and a new-line; the routines + * that call this can be used to finish the line. + * + * Process Explanation: + * This routine is called immediately after tokenization_error() + * If tokenization_error() didn't print, neither will we. + * The residual state of print_msg will tell us that. + * If the preceding message ended with something general about a + * "Colon Definition" or "Device-Node" or the like, we want + * the message to read: "that started on line ... [in file ...]" + * If the end of the preceding message was something more specific, + * we just want the message to read: "on line ... [in file ...]" + * If the saved input file name doesn't match our current input + * file name, we will print it and the saved line-number. + * If the file name hasn't changed, we will print only the saved + * line-number. + * If neither is changed, there's no point in printing any of the + * above-mentioned text. + * If a Colon-definition is in progress, show its name and the + * line on which it started. Protect against infinite loop! + * End the line. + * + * Extraneous Remarks: + * This is a retrofit. Earlier, it was just started_at() . Later, + * I generated more specific messages, and needed a way to leave + * out the "that started". I could, theoretically, have added + * the extra parameter to started_at() , but by now there are + * so many of calls to it that I'd rather leave them as is, and + * just change the name of the routine in the few places that + * need the terser form of the message. + * + **************************************************************************** */ + +static void print_where_started( bool show_started, + bool show_that_st, + char * saved_ifile, + unsigned int saved_lineno, + bool may_show_incolon) +{ + if ( print_msg ) + { + bool fil_is_diff; + bool lin_is_diff; + + /* File names are case-sensitive */ + fil_is_diff = BOOLVAL(strcmp(saved_ifile, iname) != 0 ); + lin_is_diff = BOOLVAL(saved_lineno != lineno ); + if ( fil_is_diff || lin_is_diff ) + { + if ( show_started ) + { + if ( show_that_st ) + { + fprintf(message_dest, " that"); + }else{ + fprintf(message_dest, " , which"); + } + fprintf(message_dest, " started"); + } + fprintf(message_dest, " on line %d", saved_lineno); + if ( fil_is_diff ) + { + fprintf(message_dest, " of file %s", saved_ifile); + } + } + + if ( may_show_incolon ) + { + in_last_colon(); + }else{ + fprintf(message_dest, "\n"); + } + } +} + +/* ************************************************************************** + * + * Function name: started_at + * Synopsis: Supplemental back-reference message, + * with the "that started" phrase, + * and with last-colon identification. + * + * Inputs: + * Parameters: + * saved_ifile File-name saved for "back-reference" + * saved_lineno Line-number saved for "back-reference" + * + * Outputs: + * Returned Value: None + * Global Variables: + * Printout: + * The "...started at..." remainder of a message, giving a back- + * -reference to the "start" point supplied in the params, + * and the start of the current Colon-definition if one is + * in effect. + * Will supply a new-line and can be used to finish the line. + * + **************************************************************************** */ + +void started_at( char * saved_ifile, unsigned int saved_lineno) +{ + print_where_started( TRUE, TRUE, saved_ifile, saved_lineno, TRUE); +} + + +/* ************************************************************************** + * + * Function name: print_started_at + * Synopsis: Same as started_at() except output will be directed + * to stdout instead of to ERRMSG_DESTINATION + * + * Extraneous Remarks: + * A retrofit. Can you tell? + * + **************************************************************************** */ + +void print_started_at( char * saved_ifile, unsigned int saved_lineno) +{ + message_dest = stdout; + started_at( saved_ifile, saved_lineno); + message_dest = ERRMSG_DESTINATION; +} + + +/* ************************************************************************** + * + * Function name: just_started_at + * Synopsis: Supplemental back-reference message, + * with the "that started" phrase, + * but without last-colon identification. + * + * Inputs: + * Parameters: + * saved_ifile File-name saved for "back-reference" + * saved_lineno Line-number saved for "back-reference" + * + * Outputs: + * Returned Value: None + * Global Variables: + * Printout: + * The "...started at..." remainder of a message, giving a back- + * -reference to the "start" point supplied in the params, + * and no more. + * Will supply a new-line and can be used to finish the line. + * + **************************************************************************** */ + +void just_started_at( char * saved_ifile, unsigned int saved_lineno) +{ + print_where_started( TRUE, TRUE, saved_ifile, saved_lineno, FALSE); +} + +/* ************************************************************************** + * + * Function name: where_started + * Synopsis: Supplemental back-reference message, + * without the "that started" phrase, + * but with last-colon identification. + * + * Inputs: + * Parameters: + * saved_ifile File-name saved for "back-reference" + * saved_lineno Line-number saved for "back-reference" + * + * Outputs: + * Returned Value: None + * Global Variables: + * Printout: + * The remainder of a message, giving a back-reference to the + * "start" point supplied in the parameters, and the start + * of the current Colon-definition if one is in effect. + * Will supply a new-line and can be used to finish the line. + * + **************************************************************************** */ + +void where_started( char * saved_ifile, unsigned int saved_lineno) +{ + print_where_started( FALSE, FALSE, saved_ifile, saved_lineno, TRUE); +} + +/* ************************************************************************** + * + * Function name: just_where_started + * Synopsis: Supplemental back-reference message, + * without the "that started" phrase, + * and without last-colon identification. + * + * Inputs: + * Parameters: + * saved_ifile File-name saved for "back-reference" + * saved_lineno Line-number saved for "back-reference" + * + * Outputs: + * Returned Value: None + * Global Variables: + * Printout: + * The remainder of a message, giving a back-reference to the + * "start" point supplied in the parameters, and no more. + * Will supply a new-line and can be used to finish the line. + * + **************************************************************************** */ + +void just_where_started( char * saved_ifile, unsigned int saved_lineno) +{ + print_where_started( FALSE, FALSE, saved_ifile, saved_lineno, FALSE); +} + +/* ************************************************************************** + * + * Function name: in_last_colon + * Synopsis: Supplemental back-reference message, identifying + * last Colon-definition if one is in effect. + * Can be used to finish the line in either case. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * incolon TRUE if Colon-definition is in progress + * last_colon_defname Name of last colon-definition + * last_colon_filename File where last colon-def'n made + * last_colon_lineno Line number of last colon-def'n + * Local Static Variables: + * print_msg Whether the beginning part of the message + * was printed by tokenization_error() + * message_dest Message Destination. Is ERRMSG_DESTINATION + * (stdout) usually, except sometimes... + * + * Outputs: + * Returned Value: NONE + * Printout: + * Remainder of a message: + * "in definition of ... , which started ..." + * + * Process Explanation: + * Because this routine does some of its own printing, it needs + * to check the residual state of print_msg first. + * The calling routine does not need to test incolon ; it can + * call this to end the line in either case. + * + **************************************************************************** */ + +void in_last_colon( void ) +{ + if ( print_msg ) + { + if ( incolon ) + { + fprintf( message_dest, " in definition of %s ", + strupr( last_colon_defname) ); + print_where_started( TRUE, FALSE, + last_colon_filename, last_colon_lineno, FALSE); + }else{ + fprintf(message_dest, "\n"); + } + } +} + + +/* ************************************************************************** + * + * Function name: safe_malloc + * Synopsis: malloc with built-in failure test. + * + * Inputs: + * Parameters: + * size size_t Size of memory-chunk to allocate + * phrase char * Phrase to print after "... while " + * in case of failure. + * + * Outputs: + * Returned Value: Pointer to allocated memory + * Global Variables: + * fatal_err_exit On memory allocation failure, change + * to a special system-defined value + * + * Error Detection: + * On memory allocation failure, declare a FATAL error. Set up + * for a special system-defined EXIT value that indicates + * insufficient memory. + * + * Process Explanation: + * It is the responsibility of the calling routine to be sure + * the "phrase" is unique within the program. It is intended + * as a debugging aid, to help localize the point of failure. + * + **************************************************************************** */ + +_PTR safe_malloc( size_t size, char *phrase) +{ + _PTR retval ; + retval = malloc (size); + if ( !retval ) + { + fatal_err_exit = -ENOMEM ; + tokenization_error( FATAL, "Out of memory while %s.", phrase); + } + return ( retval ); +} + +/* ************************************************************************** + * + * Function name: error_summary + * Synopsis: Summarize final error-message status + * before completing tokenization. + * Indicate if OK to produce output. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * noerrors "Ignore Errors" flag, set by "-i" switch + * err_types_found Accumulated Error-types. + * error_categories Table of Error-types, Message-Counters + * and their printable names. + * opc FCode Output Buffer Position Counter + * (zero means there was no output). + * + * Outputs: + * Returned Value: True = OK to produce output (But caller + * must still verify non-zero opc) + * Printout: + * Various messages. + * + * Process Explanation: + * The first entry in the error_categories table is FATAL + * We won't need to print a tally of that... + * + **************************************************************************** */ + +bool error_summary( void ) +{ + /* Bit-mask of error-types that require suppressing output */ + static const int suppress_mask = ( FATAL | TKERROR ); + bool retval = TRUE; + bool suppressing = FALSE; + + /* There's no escaping a FATAL error */ + if ( ( err_types_found & FATAL ) != 0 ) + { + /* FATAL error. Don't even bother with the tally. */ + suppressing = TRUE; + } else { + + if ( opc == 0 ) + { + printf ( "Nothing Tokenized"); + }else{ + printf ( "Tokenization Completed"); + } + + if ( err_types_found != 0 ) + { + int indx; + bool tally_started = FALSE ; + printf (". "); + /* + * Print a tally of the error-types; + * handle plurals and punctuation appropriately. + */ + /* Start at indx = 1 to skip examining FATALs */ + for ( indx = 1; indx < num_categories ; indx ++ ) + { + if ( *(error_categories[indx].counter) > 0 ) + { + printf ("%s %d %s%s", + tally_started ? "," : "" , + *(error_categories[indx].counter), + error_categories[indx].category_name, + *(error_categories[indx].counter) > 1 ? + error_categories[indx].plural : + error_categories[indx].single ); + /* Zero out the counter, to prevent displaying the + * number of Messages twice, since it's shared + * by the "Messages" and "P_Messages" categories. + */ + *(error_categories[indx].counter) = 0; + tally_started = TRUE; + } + } + } + printf (".\n"); + + if ( ( err_types_found & suppress_mask ) != 0 ) + { /* Errors found. Not OK to produce output */ + /* Unless "Ignore Errors" flag set... */ + if ( INVERSE(noerrors) ) + { + suppressing = TRUE; + }else{ + if ( opc > 0 ) + { + printf ("Error-detection over-ridden; " + "producing binary output.\n"); + } + } + } + } + if ( suppressing ) + { + retval = FALSE ; + printf ("Suppressing binary output.\n"); + } + return ( retval ); +} +
Added: fcode-utils/toke/errhandler.h =================================================================== --- fcode-utils/toke/errhandler.h (rev 0) +++ fcode-utils/toke/errhandler.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,119 @@ +#ifndef _TOKE_ERRHANDLER_H +#define _TOKE_ERRHANDLER_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Function Prototypes for Tokenizer Error-Handler + * + * Defines symbols for the various classes of errors + * for the Error-Handler and for all its users + * + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +#include "types.h" + +#define FATAL 0x80000000 +#define TKERROR 0x04000000 +#define WARNING 0x00200000 +#define INFO 0x00010000 +#define MESSAGE 0x00000800 +#define P_MESSAGE 0x00000040 +#define FORCE_MSG 0x00000001 + +void init_error_handler( void); +void tokenization_error( int err_type, char* msg, ... ); +void started_at( char * saved_ifile, unsigned int saved_lineno); +void print_started_at( char * saved_ifile, unsigned int saved_lineno); +void just_started_at( char * saved_ifile, unsigned int saved_lineno); +void where_started( char * saved_ifile, unsigned int saved_lineno); +void just_where_started( char * saved_ifile, unsigned int saved_lineno); +void in_last_colon( void ); +_PTR safe_malloc( size_t size, char *phrase); +bool error_summary( void ); /* Return TRUE if OK to produce output. */ + + +/* ************************************************************************** + * + * Macros: + * ERRMSG_DESTINATION During development, I used this to switch + * error message destination between STDOUT and STDERR, until I + * settled on which is preferable. Recently, I have proven to + * my satisfaction that STDERR is preferable: error-messages + * produced by a sub-shell will be correctly synchronized with + * the error-messages we produce. When I tested using STDOUT + * for error-messages, that error-case looked garbled. + * FFLUSH_STDOUT fflush( stdout) if error message destination + * is STDERR, No-op if it's STDOUT. A few of these, judiciously + * placed, kept our own regular and error messages nicely in sync. + * + **************************************************************************** */ + +#define ERRMSG_DESTINATION stderr +#define FFLUSH_STDOUT fflush( stdout); + +/* We're no longer switching the above. + * The below is left here to show what had been done formerly. + */ +#if -1 /* Switchable error-message destination */ +#else /* Switchable error-message destination */ +#define ERRMSG_DESTINATION stdout +#define FFLUSH_STDOUT /* Don't need to do anything here */ +#endif /* Switchable error-message destination */ + +/* Some systems don't seem to have strupr */ +#ifdef SYS_IS_GNU_Linux +#define NEEDS_STRUPR +#endif /* SYS_IS_GNU_Linux */ +#ifdef SYS_IS_AIX +#define NEEDS_STRUPR +#endif /* SYS_IS_AIX */ +/* ??? Should this instead be tuned to Proc'r is PPC ??? Why? */ + +#ifdef NEEDS_STRUPR + +/* ************************************************************************** + * + * A necessary hack for systems that don't seem + * to have strupr and strlwr + * Let's avoid a naming conflict, just in case... + * + **************************************************************************** */ + +extern char *strupper( char *strung); +#define strupr strupper + +extern char *strlower( char *strung); +#define strlwr strlower + + +#endif /* NEEDS_STRUPR */ + +#endif /* _TOKE_ERRHANDLER_H */
Added: fcode-utils/toke/flowcontrol.c =================================================================== --- fcode-utils/toke/flowcontrol.c (rev 0) +++ fcode-utils/toke/flowcontrol.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,2080 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Support Functions for tokenizing FORTH Flow-Control structures. + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Functions Exported: + * These first two do their work after the calling routine + * has written the token for the required variant: + * + * mark_do Mark branches for "do" variants + * resolve_loop Resolve "loop" variants' branches + * + * The remaining routines' descriptions are all similar: + * Write the token(s), handle the outputs, mark + * or resolve the branches, and verify correct + * control-structure matching, for tokenizing + * the ........................ statement in FORTH + * emit_if IF + * emit_else ELSE + * emit_then THEN + * emit_begin BEGIN + * emit_again AGAIN + * emit_until UNTIL + * emit_while WHILE + * emit_repeat REPEAT + * emit_case CASE + * emit_of OF + * emit_endof ENDOF + * emit_endcase ENDCASE + * + * Three additional routines deal with matters of overall balance + * of the Control-Structures, and identify the start of any that + * were not balanced. The first just displays Messages: + * + * announce_control_structs + * + * The other two clear and re-balance them: + * + * clear_control_structs_to_limit + * clear_control_structs + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Still to be done: + * Correct analysis of Return-Stack usage around Flow-Control + * constructs, including within Do-Loops or before Loop + * Elements like I and J or UNLOOP or LEAVE. + * Similarly, Return-Stack usage around IF ... ELSE ... THEN + * statements needs analysis. For instance, the following: + * + * blablabla >R yadayada IF R> gubble ELSE flubble R> THEN + * + * is, in fact, correct, while something like: + * + * blablabla >R yadayada IF R> gubble THEN + * + * is an error. + * + * Implementing an analysis that would be sufficiently accurate + * to justify reporting an ERROR with certainty (rather than + * a mere WARNING speculatively) would probably require full + * coordination with management of Flow-Control constructs, + * and so is noted here. + * + **************************************************************************** */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "types.h" +#include "toke.h" +#include "emit.h" +#include "vocabfuncts.h" +#include "scanner.h" +#include "stack.h" +#include "errhandler.h" +#include "flowcontrol.h" +#include "stream.h" + +/* ************************************************************************** + * + * Global Variables Imported + * opc FCode Output Buffer Position Counter + * noerrors "Ignore Errors" flag, set by "-i" switch + * do_loop_depth How deep we are inside DO ... LOOP variants + * incolon State of tokenization; TRUE if inside COLON + * statbuf The word just read from the input stream + * iname Name of input file currently being processed + * lineno Current line-number being processed + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Global Variables Exported + * control_stack_depth Number of items on "Control-Stack" + * + **************************************************************************** */ + +int control_stack_depth = 0; + + +/* ************************************************************************** + * + * Internal Static Functions: + * push_cstag Push an item onto the Control-Stack + * pop_cstag Pop one item from the Control-Stack + * control_stack_size_test Test C-S depth; report if error + * control_structure_mismatch Print error-message + * offset_too_large Print error-message + * matchup_control_structure Error-check Control-Stack + * matchup_two_control_structures Error-check two Control-Stack entries + * emit_fc_offset Error-check and output FCode-Offset + * control_structure_swap Swap control-struct branch-markers + * mark_backward_target Mark target of backward-branch + * resolve_backward Resolve backward-target for branch + * mark_forward_branch Mark forward-branch + * resolve_forward Resolve forward-branch at target + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Internal Named Constants + * Note: These control-structure identifier tags -- a.k.a. cstags -- + * are used to identify the matching components of particular + * control-structures. They are passed as parameters, and either + * "Pushed" onto the "Control-Stack", or compared with what is on + * "Top" of the "Control-Stack", as an error-check. + * + * name used by forth words: + * BEGIN_CSTAG BEGIN AGAIN UNTIL REPEAT + * IF_CSTAG IF ELSE THEN + * WHILE_CSTAG WHILE REPEAT THEN + * DO_CSTAG DO ?DO LOOP +LOOP + * CASE_CSTAG CASE OF ENDCASE + * OF_CSTAG OF ENDOF + * ENDOF_CSTAG ENDOF ENDCASE + * + * The numbers assigned are arbitrary; they were selected for a + * high unlikelihood of being encountered in normal usage, + * and constructed with a hint of mnemonic value in mind. + * + **************************************************************************** */ + /* Mnemonic: */ +#define BEGIN_CSTAG 0xC57be916 /* CST BEGIN */ +#define IF_CSTAG 0xC57A901f /* CSTAG (0) IF */ +#define WHILE_CSTAG 0xC573412e /* CST WHILE */ +#define DO_CSTAG 0xC57A90d0 /* CSTAG (0) DO */ +#define CASE_CSTAG 0xC57Aca5e /* CSTA CASE */ +#define OF_CSTAG 0xC57A90f0 /* CSTAG OF (0) */ +#define ENDOF_CSTAG 0xC57e6d0f /* CST ENDOF */ + + +/* ************************************************************************** + * + * Control-Structure identification, matching, completion and error + * messaging will be supported by a data structure, which we + * will call a CSTAG-Group + * + * It consists of one "Data-item" and several "Marker" items, thus: + * + * The Data-item in most cases will be a value of OPC (the Output + * Buffer Position Counter) which will be used in calculating + * an offset or placing an offset or both, as the case may be, + * for the control structure in question. The one exception + * is for a CSTAG-Group generated by a CASE statement; its + * Data-item will be an integer count of the number of "OF"s + * to be resolved when the ENDCASE statement is reached. + * + * The CSTAG for the FORTH word, as described above + * The name of the input file in which the word was encountered + * (actually, a pointer to a mem-alloc'ed copy of the filename) + * The line number, within the input file, of the word's invocation + * The Absolute Token Number in all Source Input of the word + * The FORTH word that started the structure, (used in error messages) + * A flag to indicate when two CSTAG-Groups are created together, + * which will be used to prevent duplicate error messages when, + * for instance, a DO is mismatched with a REPEAT . + * + **************************************************************************** */ + +/* ************************************************************************** + * + * "Control-Stack" Diagram Notation + * + * The CSTAG-Groups will be kept in an order resembling a data-stack, + * (even though it won't be the data-stack itself). We will refer + * to this list of structures as the "Control Stack", and in our + * comments we will show their arrangement in a format resembling + * stack-diagram remarks. + * + * In these "Control-Stack Diagrams", we will use the notation: + * <Stmt>_{FOR|BACK}w_<TAGNAM> + * to represent a CSTAG-Group generated by a <Stmt> -type of + * statement, with a "FORw"ard or "BACKw"ard branch-marker and + * a CSTAG of the <TAGNAM> type. + * + * A CASE-CSTAG-Group will have a different notation: + * N_OFs...CASE_CSTAG + * + * In all cases, a CSTAG-Group will be manipulated as a unit. + * + * The notation for Control-Stack Diagram remarks will largely resemble + * the classic form used in FORTH, i.e., enclosed in parentheses, + * lowest item to the left, top item on the right, with a double- + * hyphen to indicate "before" or "after". + * + * Enclosure in {curly-braces} followed by a subscript-range indicates + * that the Stack-item or Group is repeated. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * We are not keeping the "Control Stack" structures on the regular + * data stack because a sneaky combination of user-inputs could + * throw things into chaos were we to use that scheme. Consider + * what would happen if a number were put on the stack, say, in + * tokenizer-escape mode, in between elements of a flow-control + * structure... Theoretically, there is no reason to prohibit + * that, but it would be unexpectedly problematical for most + * FORTH-based tokenizers. + * + * Maintaining the "Control Stack" structures in a linked-list would + * be a more nearly bullet-proof approach. The theory of operation + * would be the same, broadly speaking, and there would be no need + * to check for NOT_CSTAG and no risk of getting the elements of + * the control-structures out of sync. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Structure Name: cstag_group_t + * Synopsis: Control-Structure Tag Group + * + * Fields: + * cs_tag Control-structure identifier tag + * cs_inp_fil Name of input file where C-S was started + * cs_line_num Line-number in Current Source when C-S was started + * cs_abs_token_num "Absolute" Token Number when C-S was started + * cs_word The FORTH word that started the C-S + * cs_not_dup FALSE if second "Control Stack" entry for same word + * cs_datum Data-Item of the Group + * prev Pointer to previous CSTAG-Group in linked-list + * + * All data using this structure will remain private to this file, + * so we declare it here rather than in the .h file + * + **************************************************************************** */ + +typedef struct cstag_group { + unsigned long cs_tag; + char *cs_inp_fil; + unsigned int cs_line_num; + unsigned int cs_abs_token_num; + char *cs_word; + bool cs_not_dup; + unsigned long cs_datum; + struct cstag_group *prev; +} cstag_group_t; + +/* ************************************************************************** + * + * Internal Static Variables + * control_stack "Thread" Pointer to the linked-list of + * "Control Stack" structure entries + * not_cs_underflow Flag used to prevent duplicate messages + * not_consuming_two Flag used to prevent loss of messages + * didnt_print_otl Flag used to prevent duplicate messages + * + **************************************************************************** */ + +static cstag_group_t *control_stack = NULL; /* "Top" of the "Stack" */ + +/* ************************************************************************** + * + * not_cs_underflow is used only by routines that make two calls to + * resolve a marker. It is set TRUE before the first call; if + * that call had a control-stack underflow, the error-message + * routine resets it to FALSE. The calling routine can then + * test it as the condition for the second call. + * Routines that make only one call to resolve a marker can ignore it. + * + **************************************************************************** */ + +static bool not_cs_underflow; /* No need to initialize. */ + +/* ************************************************************************** + * + * not_consuming_two is also used only by routines that make two calls + * to resolve a marker, but for this case, those routines only need + * to reset it to FALSE and not to test it; that will be done by + * the control_structure_mismatch() routine when it looks at + * the cs_not_dup field. If the mismatch occurred because of + * a combination of control-structures that consume one each, + * the message will be printed even for the second "Control Stack" + * entry. The routine that changed it will have to set it back to + * TRUE when it's done with it. + * + * didnt_print_otl is used similarly, but only for the offset-too-large + * error in the DO ... LOOP type of control-structures. + * + **************************************************************************** */ + +static bool not_consuming_two = TRUE; +static bool didnt_print_otl = TRUE; + + +/* ************************************************************************** + * + * Function name: push_cstag + * Synopsis: Push a new CSTAG-Group onto the front ("Top") + * of the (notional) Control-Stack. + * + * Inputs: + * Parameters: + * cstag ID Tag for Control-Structure to "Push" + * datum The Data-Item for the new CSTAG-Group + * Global Variables: + * iname Name of input file currently being processed + * lineno Current-Source line-number being processed + * abs_tokenno "Absolute"Token Number of word being processed + * statbuf The word just read, which started the C-S + * Local Static Variables: + * control_stack Will become the new entry's "prev" + * + * Outputs: + * Returned Value: None + * Global Variables: + * control_stack_depth Incremented + * Local Static Variables: + * control_stack Will become the "previous" entry in the list + * Items Pushed onto Control-Stack: + * Top: A new CSTAG-Group, params as given + * Memory Allocated + * New CSTAG-Group structure + * Duplicate of name of current input file + * Duplicate of word just read + * When Freed? + * When Removing a CSTAG-Group, in pop_cstag() + * + **************************************************************************** */ + +static void push_cstag( unsigned long cstag, unsigned long datum) +{ + cstag_group_t *cs_temp; + + cs_temp = control_stack; + control_stack = safe_malloc( sizeof(cstag_group_t), "pushing CSTag"); + + control_stack->cs_tag = cstag; + control_stack->cs_inp_fil = strdup(iname); + control_stack->cs_line_num = lineno; + control_stack->cs_abs_token_num = abs_token_no; + control_stack->cs_word = strdup(statbuf); + control_stack->cs_not_dup = TRUE; + control_stack->cs_datum = datum; + control_stack->prev = cs_temp; + + control_stack_depth++; + +} + +/* ************************************************************************** + * + * Function name: pop_cstag + * Synopsis: Remove a CSTAG-Group from the front ("Top") of the + * (notional) Control-Stack. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * Local Static Variables: + * control_stack CSTAG-Group on "Top" + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * control_stack_depth Decremented + * Local Static Variables: + * control_stack "Previous" entry will become current + * Memory Freed + * mem-alloc'ed copy of input filename + * mem-alloc'ed copy of Control-structure FORTH word + * CSTAG-Group structure + * Control-Stack, # of Items Popped: 1 + * + * Process Explanation: + * The calling routine might not check for empty Control-Stack, + * so we have to be sure and check it here. + * + **************************************************************************** */ + +static void pop_cstag( void) +{ + + if ( control_stack != NULL ) + { + cstag_group_t *cs_temp; + + cs_temp = control_stack->prev; + free( control_stack->cs_word ); + free( control_stack->cs_inp_fil ); + free( control_stack ); + control_stack = cs_temp; + + control_stack_depth--; + } +} + +/* ************************************************************************** + * + * Function name: control_stack_size_test + * Synopsis: Detect Control Stack underflow; report if an ERROR. + * + * Inputs: + * Parameters: + * min_depth Minimum depth needed + * Global Variables: + * control_stack_depth Current depth of Control Stack + * statbuf Word to name in error message + * + * Outputs: + * Returned Value: TRUE if adequate depth + * Local Static Variables: + * not_cs_underflow Reset to FALSE if underflow detected. + * Printout: + * Error message is printed. + * Identify the colon definition if inside one. + * + * Process Explanation: + * Some statements need more than one item on the Control Stack; + * they will do their own control_stack_depth testing and + * make a separate call to this routine. + * + **************************************************************************** */ + +static bool control_stack_size_test( int min_depth ) +{ + bool retval = TRUE; + + if ( control_stack_depth < min_depth ) + { + retval = FALSE; + tokenization_error ( TKERROR, + "Control-Stack underflow at %s", strupr(statbuf) ); + in_last_colon(); + + not_cs_underflow = FALSE; /* See expl'n early on in this file */ + } + + return( retval ); +} + +/* ************************************************************************** + * + * Function name: control_structure_mismatch + * Synopsis: Report an ERROR after a Control Structure mismatch + * was detected. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * statbuf Word encountered, to name in error message + * Local Static Variables: + * control_stack "Pushed" Control-Structure Tag Group + * not_consuming_two See explanation early on in this file + * Control-Stack Items: + * Top: "Current" Control-Structure Tag Group + * Some of its "Marker" information + * will be used in the error message + * + * Outputs: + * Returned Value: NONE + * Printout: + * Error message is printed + * + * Process Explanation: + * This routine is called after a mismatch is detected, and + * before the CSTAG-Group is "Popped" from the notional + * Control-Stack. + * If the control_stack pointer is NULL, print a different + * Error message + * Don't print if the "Control Stack" entry is a duplicate and + * we're processing a statement that consumes two entries. + * + **************************************************************************** */ + +static void control_structure_mismatch( void ) +{ + if ( control_stack->cs_not_dup || not_consuming_two ) + { + tokenization_error ( TKERROR, + "The %s is mismatched with the %s" , + strupr(statbuf), strupr(control_stack->cs_word)); + where_started( control_stack->cs_inp_fil, control_stack->cs_line_num ); + } +} + + +/* ************************************************************************** + * + * Function name: offset_too_large + * Synopsis: Report an ERROR after a too-large fcode-offset + * was detected. + * + * Inputs: + * Parameters: + * too_large_for_16 TRUE if the offset is too large to be + * expressed as a 16-bit signed number. + * Global Variables: + * statbuf Word encountered, to name in error message + * offs16 Whether we are using 16-bit offsets + * Local Static Variables: + * control_stack "Pushed" Control-Structure Tag Group + * didnt_print_otl Switch to prevent duplicate message + * Control-Stack Items: + * Top: "Current" Control-Structure Tag Group + * Some of its "Marker" information + * will be used in the error message + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * didnt_print_otl Will be reset to FALSE + * + * Printout: + * Error message: + * Branch offset too large between <here> and <there> + * Advisory message, if we are using 8-bit offsets, will + * indicate whether switching to 16-bit offsets would help + * + * Process Explanation: + * Two branches are involved in a DO ... LOOP structure: an "outer" + * forward-branch and a slightly smaller "inner" backward-branch. + * In the majority of cases, if one offset exceeds the limit, + * both will. There is, however, a very small but distinct + * possibility that the offset for the smaller branch will not + * exceed the limit while the larger one does. To prevent two + * messages from being printed in the routine instance, but still + * assure that one will be printed in the rare eventuality, we + * utilize the flag called didnt_print_otl in conjunction + * with the cs_not_dup field. + * + **************************************************************************** */ + +static void offset_too_large( bool too_large_for_16 ) +{ + if ( control_stack->cs_not_dup || didnt_print_otl ) + { + tokenization_error( TKERROR, + "Branch offset is too large between %s and the %s" , + strupr(statbuf), strupr(control_stack->cs_word)); + where_started( control_stack->cs_inp_fil, control_stack->cs_line_num ); + if ( INVERSE( offs16 ) ) + { + if ( too_large_for_16 ) + { + tokenization_error ( INFO, + "Offset would be too large even if 16-bit offsets " + "were in effect.\n"); + }else{ + tokenization_error ( INFO, + "Offset might fit if 16-bit offsets " + "(e.g., fcode-version2) were used.\n" ); + } + } + } + didnt_print_otl = FALSE; +} + +/* ************************************************************************** + * + * Function name: emit_fc_offset + * Synopsis: Test whether the given FCode-Offset is out-of-range; + * before placing it into the FCode Output Buffer. + * + * Inputs: + * Parameters: + * fc_offset The given FCode-Offset + * Global Variables: + * offs16 Whether we are using 16-bit offsets + * noerrors "Ignore Errors" flag + * + * Outputs: + * Returned Value: NONE + * + * Error Detection: + * Error if the given FCode-Offset exceeds the range that can + * be expressed by the size (i.e., 8- or 16- -bits) of the + * offsets we are using. Call offset_too_large() to print + * the Error message; also, if noerrors is in effect, issue + * a Warning showing the actual offset and how it will be coded. + * + * Process Explanation: + * For forward-branches, the OPC will have to be adjusted to + * indicate the location that was reserved for the offset + * to be written, rather than the current location. That + * will all be handled by the calling routine. + * We will rely on "C"'s type-conversion (type-casting) facilities. + * Look at the offset value both as an 8-bit and as a 16-bit offset, + * then determine the relevant course of action. + * + **************************************************************************** */ + +static void emit_fc_offset( int fc_offset) +{ + int fc_offs_s16 = (s16)fc_offset; + int fc_offs_s8 = (s8)fc_offset; + bool too_large_for_8 = BOOLVAL( fc_offset != fc_offs_s8 ); + bool too_large_for_16 = BOOLVAL( fc_offset != fc_offs_s16); + + if ( too_large_for_16 || ( INVERSE(offs16) && too_large_for_8 ) ) + { + offset_too_large( too_large_for_16 ); + if ( noerrors ) + { + int coded_as = offs16 ? (int)fc_offs_s16 : (int)fc_offs_s8 ; + tokenization_error( WARNING, + "Actual offset is 0x%x (=dec %d), " + "but it will be coded as 0x%x (=dec %d).\n", + fc_offset, fc_offset, coded_as, coded_as ); + } + } + + emit_offset( fc_offs_s16 ); +} + + +/* ************************************************************************** + * + * Function name: matchup_control_structure + * Synopsis: Error-check. Compare the given control-structure + * identifier tag with the one in the CSTAG-Group + * on "Top" of the "Control Stack". + * If they don't match, report an error, and, if not + * "Ignoring Errors", return Error indication. + * If no error, pass the Data-item back to the caller. + * Do not consume the CSTAG-Group; that will be the + * responsibility of the calling routine. + * + * Inputs: + * Parameters: + * cstag Control-struc ID Tag expected by calling function + * Global Variables: + * noerrors "Ignore Errors" flag + * Local Static Variables: + * control_stack "Pushed" (current) Control-Structure Tag Group + * Control-Stack Items: + * Top: Current CSTAG-Group + * + * Outputs: + * Returned Value: TRUE = Successful match, no error. + * + * Error Detection: + * Control Stack underflow or cstag mismatch. See below for details. + * + * Process Explanation: + * If the expected cstag does not match the cs_tag from the CSTAG + * Group on "Top" of the "Control Stack", print an ERROR message, + * and, unless the "Ignore Errors" flag is in effect, prepare + * to return FALSE. + * However, if we've "underflowed" the "Control Stack", we dare not + * ignore errors; that could lead to things like attempting to + * write a forward-branch FCode-offset to offset ZERO, over the + * FCODE- or PCI- -header block. We don't want that... + * So, if the control_stack pointer is NULL, we will print an + * ERROR message and immediately return FALSE. + * Since we will not consume the CSTAG-Group, the calling routine + * can access the Data-Item and any "Marker" information it may + * still require via the local control_stack pointer. The caller + * will be responsible for removing the CSTAG-Group. + * + * Special Exception to "Ignore Errors": + * At the last usage of the CASE_CSTAG , for the ENDCASE statement, + * this routine will be called to control freeing-up memory, etc. + * For the OF statement, it will be called to control incrementing + * the OF-count datum. + * Processing an ENDCASE statement with the datum from any other + * CSTAG-Group can lead to a huge loop. + * Processing any other "resolver" with the datum from an ENDCASE + * CSTAG-Group can lead to mistaking a very low number for an + * offset into the Output Buffer and attempting to write to it. + * Incrementing the datum from any other CSTAG-Group can lead to + * a variety of unacceptable errors, too many to guess. + * So, if either the given cstag or the cs_tag field of the "Top" + * CSTAG-Group is a CASE_CSTAG , we will not ignore errors. + * + **************************************************************************** */ + +static bool matchup_control_structure( unsigned long cstag ) +{ + bool retval = FALSE; + + if ( control_stack_size_test( 1) ) + { + retval = TRUE; + + if ( control_stack->cs_tag != cstag ) + { + control_structure_mismatch(); + + if ( ( INVERSE(noerrors) ) + || ( cstag == CASE_CSTAG ) + || ( control_stack->cs_tag == CASE_CSTAG ) + ) + { + retval = FALSE; + } + } + + } + return ( retval ); +} + +/* ************************************************************************** + * + * Function name: control_structure_swap + * Synopsis: Swap control-structure branch-marker Groups + * + * Inputs: + * Parameters: NONE + * Local Static Variables: + * control_stack Pointer to "Control Stack" linked-list + * Control-Stack Items: + * Top: CSTAG-Group_0 + * Next: CSTAG-Group_1 + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * control_stack Points to former "previous" and vice-versa + * Items on Control-Stack: + * Top: CSTAG-Group_1 + * Next: CSTAG-Group_0 + * + * Error Detection: + * If control-stack depth is not at least 2, CS underflow ERROR. + * This might trigger other routines' error detections also... + * + * Extraneous Remarks: + * Before control-structure identification was implemented, offsets + * were kept on the data-stack, and this was a single SWAP. + * When CSTAGs were added, the "Group" was only a pair kept on the + * data-stack -- the CSTAG and the Data-item -- and this + * became a TWO_SWAP() + * For a while, when I tried keeping the CSTAG-Group on the stack, + * this became a FOUR_SWAP() + * That turned out to be unacceptably brittle; this way is much + * more robust. + * I am so glad I called this functionality out into a separate + * routine, early on in the development process. + * + * This is the function called 1 CSROLL in section A.3.2.3.2 + * of the ANSI Forth spec, which likewise corresponds to the + * modifier that Wil Baden, in his characteristically elegant + * nomenclature, dubbed: BUT + * + **************************************************************************** */ + +static void control_structure_swap( void ) +{ + if ( control_stack_size_test( 2) ) + { + cstag_group_t *cs_temp; + + cs_temp = control_stack->prev; + + control_stack->prev = cs_temp->prev; + cs_temp->prev = control_stack; + control_stack = cs_temp; + } +} + +/* ************************************************************************** + * + * Function name: matchup_two_control_structures + * Synopsis: For functions that resolve two CSTAG-Groups, both + * matchup both "Top of Control Stack" entries + * before processing them... + * + * Inputs: + * Parameters: + * top_cstag Control-struc ID Tag expected on "Top" CS entry + * next_cstag Control-struc ID Tag expected on "Next" CS entry + * Local Static Variables: + * not_cs_underflow Used for underflow detection. + * Control-Stack Items: + * Top: Current CSTAG-Group + * Next: Next CSTAG-Group + * + * Outputs: + * Returned Value: TRUE = Successful matches, no error. + * Global Variables: + * noerrors "Ignore Errors" flag; cleared, then restored + * Local Static Variables: + * not_consuming_two Cleared, then restored + * Control-Stack, # of Items Popped: 2 (if matches unsuccessful) + * + * Error Detection: + * Control Stack underflow detected by control_structure_swap() + * Control Structure mismatch detected by control_structure_mismatch() + * + * Process Explanation: + * We will use matchup_control_structure() to do the "heavy lifting". + * We will not be ignoring errors in these cases. + * Save the results of a match of top_cstag + * Swap the top two CS entries. + * If an underflow was detected, there's no more matching to be done. + * Otherwise: + * Save the results of a match of next_cstag + * Swap the top two CS entries again, to their original order. + * The result is TRUE if both matches were successful. + * If the matches were not successful, consume the top two entries + * (unless there's only one, in which case consume it). + * + **************************************************************************** */ + +static bool matchup_two_control_structures( unsigned long top_cstag, + unsigned long next_cstag) +{ + bool retval; + bool topmatch; + bool nextmatch = FALSE; + bool sav_noerrors = noerrors; + noerrors = FALSE; + not_consuming_two = FALSE; + + not_cs_underflow = TRUE; + topmatch = matchup_control_structure( top_cstag); + if ( not_cs_underflow ) + { + control_structure_swap(); + if ( not_cs_underflow ) + { + nextmatch = matchup_control_structure( next_cstag); + control_structure_swap(); + } + } + + retval = BOOLVAL( topmatch && nextmatch); + + if ( INVERSE( retval) ) + { + pop_cstag(); + pop_cstag(); + } + + not_consuming_two = TRUE; + noerrors = sav_noerrors; + return ( retval ); +} + +/* ************************************************************************** + * + * Function name: mark_backward_target + * Synopsis: Mark the target of an expected backward-branch + * + * Associated FORTH words: BEGIN DO ?DO + * + * Inputs: + * Parameters: + * cstag Control-structure ID tag for calling function + * Global Variables: + * opc Output Buffer Position Counter + * + * Outputs: + * Returned Value: NONE + * Items Pushed onto Control-Stack: + * Top: <Stmt>_BACKw_<TAGNAM> + * + * Process Explanation: + * Just before this function is called, the token that begins the + * control-structure was written to the FCode Output buffer. + * OPC, the FCode Output Buffer Position Counter, is at the + * destination to which the backward-branch will be targeted. + * Create a CSTAG-Group with the given C-S Tag, and OPC as its datum; + * push it onto the Control-Stack. + * Later, when the backward-branch is installed, the FCode-offset + * will be calculated as the difference between the OPC at + * that time and the target-OPC we saved here. + * + **************************************************************************** */ + +static void mark_backward_target(unsigned long cstag ) +{ + push_cstag( cstag, (unsigned long)opc); +} + +/* ************************************************************************** + * + * Function name: mark_forward_branch + * Synopsis: Mark the location of, and reserve space for, the + * FCode-offset associated with a forward branch. + * + * Associated FORTH words: IF WHILE ELSE + * + * Inputs: + * Parameters: + * cstag Control-structure ID tag for calling function + * + * Outputs: + * Returned Value: NONE + * Items Pushed onto Control-Stack: + * Top: <Stmt>_FORw_<TAGNAM> + * FCode Output buffer: + * Place-holder FCode-offset of zero. + * + * Process Explanation: + * Just before this function is called, the forward-branch token + * that begins the control-structure was written to the FCode + * Output buffer. + * It will need an FCode-offset to the destination to which it will + * be targeted, once that destination is known. + * Create a CSTAG-Group with the given C-S Tag, and OPC as its datum; + * push it onto the Control-Stack. (This is the same action as + * for marking a backward-target.) + * Then write a place-holder FCode-offset of zero to the FCode + * Output buffer. + * Later, when the destination is known, the FCode-offset will be + * calculated as the difference between the OPC at that time + * and the FCode-offset location we're saving now. That offset + * will be over-written onto the place-holder offset of zero at + * the location in the Output buffer that we saved on the + * Control-Stack in this routine. + * + **************************************************************************** */ + +static void mark_forward_branch(unsigned long cstag ) +{ + mark_backward_target(cstag ); + emit_offset(0); +} + +/* ************************************************************************** + * + * Function name: resolve_backward + * Synopsis: Resolve backward-target when a backward branch + * is reached. Write FCode-offset to reach saved + * target from current location. + * + * Associated FORTH words: AGAIN UNTIL REPEAT + * LOOP +LOOP + * + * Inputs: + * Parameters: + * cstag Control-structure ID tag for calling function + * Global Variables: + * opc Output Buffer Position Counter + * Control-Stack Items: + * Top: <Stmt>_BACKw_<TAGNAM> + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * opc Incremented by size of an FCode-offset + * Control-Stack, # of Items Popped: 1 + * FCode Output buffer: + * FCode-offset to reach backward-target + * + * Error Detection: + * Test for Control-structure ID tag match. + * + * Process Explanation: + * Just before this function is called, the backward-branch token + * that ends the control-structure was written to the FCode + * Output buffer. + * The current OPC is at the point from which the FCode-offset + * is to be calculated, and at which it is to be written. + * The top of the Control-Stack should have the CSTAG-Group from + * the statement that prepared the backward-branch target that + * we expect to resolve. Its datum is the OPC of the target + * of the backward branch. + * If the supplied Control-structure ID tag does not match the one + * on top of the Control-Stack, announce an error. We will + * still write an FCode-offset, but it will be a place-holder + * of zero. + * Otherwise, the FCode-offset we will write will be the difference + * between the target-OPC and our current OPC. + * + **************************************************************************** */ + +static void resolve_backward( unsigned long cstag) +{ + unsigned long targ_opc; + int fc_offset = 0; + + if ( matchup_control_structure( cstag) ) + { + targ_opc = control_stack->cs_datum; + fc_offset = targ_opc - opc; + } + + emit_fc_offset( fc_offset ); + pop_cstag(); +} + +/* ************************************************************************** + * + * Function name: resolve_forward + * Synopsis: Resolve a forward-branch when its target has been + * reached. Write the FCode-offset into the space + * that was reserved. + * + * Associated FORTH words: ELSE THEN REPEAT + * LOOP +LOOP + * + * Inputs: + * Parameters: + * cstag Control-structure ID tag for calling function + * Global Variables: + * opc Output Buffer Position Counter + * Control-Stack Items: + * Top: <Stmt>_FORw_<TAGNAM> + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * opc Changed, then restored. + * Control-Stack, # of Items Popped: 1 + * FCode Output buffer: + * FCode-offset is written to location where space was reserved + * when the forward-branch was marked. + * + * Error Detection: + * Test for Control-structure ID tag match. + * + * Process Explanation: + * Just before this function is called, the last token -- and + * possibly, FCode-offset -- that is within the scope of + * what the branch might skip was written to the FCode + * Output buffer. + * The current OPC is at the point from which the FCode-offset + * is to be calculated, but not at which it is to be written. + * The top of the Control-Stack should have the CSTAG-Group from + * the statement that prepared the forward-branch we expect + * to resolve, and for which our current OPC is the target. + * Its datum is the OPC of the space that was reserved for + * the forward-branch whose target we have just reached. + * If the supplied Control-structure ID tag does not match the one + * on top of the Control-Stack, announce an error and we're done. + * Otherwise, the datum is used both as part of the calculation of + * the FCode-offset we are about to write, and as the location + * to which we will write it. + * The FCode-offset is calculated as the difference between our + * current OPC and the reserved OPC location. + * We will not be ignoring errors in these cases, because we would + * be over-writing something that might not be a place-holder + * for a forward-branch at an earlier location in the FCode + * Output buffer. + * + **************************************************************************** */ + +static void resolve_forward( unsigned long cstag) +{ + unsigned long resvd_opc; + bool sav_noerrors = noerrors; + bool cs_match_result; + noerrors = FALSE; + /* Restore the "ignore-errors" flag before we act on our match result + * because we want it to remain in effect for emit_fc_offset() + */ + cs_match_result = matchup_control_structure( cstag); + noerrors = sav_noerrors; + + if ( cs_match_result ) + { + int saved_opc; + int fc_offset; + + resvd_opc = control_stack->cs_datum; + fc_offset = opc - resvd_opc; + + saved_opc = opc; + opc = resvd_opc; + + + emit_fc_offset( fc_offset ); + opc = saved_opc; + } + pop_cstag(); +} + + +/* ************************************************************************** + * + * The functions that follow are the exported routines that + * utilize the preceding support-routines to effect their + * associated FORTH words. + * + * The routines they call will take care of most of the Error + * Detection via stack-depth checking and Control-structure + * ID tag matching, so those will not be called-out in the + * prologues. + * + **************************************************************************** */ + + +/* ************************************************************************** + * + * Function name: emit_if + * Synopsis: All the actions when IF is encountered + * + * Associated FORTH word: IF + * + * Inputs: + * Parameters: NONE + * + * Outputs: + * Returned Value: NONE + * Items Pushed onto Control-Stack: + * Top: If_FORw_IF + * FCode Output buffer: + * Token for conditional branch -- b?branch -- followed by + * place-holder of zero for FCode-offset + * + * + **************************************************************************** */ + +void emit_if( void ) +{ + emit_token("b?branch"); + mark_forward_branch( IF_CSTAG ); +} + +/* ************************************************************************** + * + * Function name: emit_then + * Synopsis: All the actions when THEN is encountered; also + * part of another forward-branch resolver's action. + * + * Associated FORTH words: THEN ELSE + * + * Inputs: + * Parameters: NONE + * Local Static Variables: + * control_stack Points to "Top" Control-Structure Tag Group + * Control-Stack Items: + * Top: If_FORw_IF | While_FORw_WHILE + * + * Outputs: + * Returned Value: NONE + * Control-Stack, # of Items Popped: 1 + * FCode Output buffer: + * Token for forward-resolve -- b(>resolve) -- then the space + * reserved for the forward-branch FCode-offset is filled + * in so that it reaches the token after the b(>resolve) . + * + * Process Explanation: + * The THEN statement or the ELSE statement must be able to resolve + * a WHILE statement, in order to implement the extended flow- + * -control structures as described in sec. A.3.2.3.2 of the + * ANSI Forth Spec. + * But we must prevent the sequence IF ... BEGIN ... REPEAT from + * compiling as though it were: IF ... BEGIN ... AGAIN THEN + * We do this by having a separate CSTAG for WHILE and allowing + * it here but not allowing the IF_CSTAG when processing REPEAT. + * + **************************************************************************** */ + +void emit_then( void ) +{ + emit_token("b(>resolve)"); + if ( control_stack != NULL ) + { + if ( control_stack->cs_tag == WHILE_CSTAG ) + { + control_stack->cs_tag = IF_CSTAG; + } + } + resolve_forward( IF_CSTAG ); +} + + +/* ************************************************************************** + * + * Function name: emit_else + * Synopsis: All the actions when ELSE is encountered + * + * Associated FORTH word: ELSE + * + * Inputs: + * Parameters: NONE + * Global Variables: + * control_stack_depth Current depth of Control Stack + * Local Static Variables: + * not_cs_underflow If this is FALSE after the c-s swap, it + * means an underflow resulted; skip + * the call to resolve the first marker. + * Control-Stack Items: + * Top: {If_FORw_IF}1 + * (Datum is OPC of earlier forward-branch; must be resolved.) + * + * Outputs: + * Returned Value: NONE + * Control-Stack, # of Items Popped: 1 + * Items Pushed onto Control-Stack: + * Top: {If_FORw_IF}2 + * (Datum is current OPC, after forward-branch is placed.) + * FCode Output buffer: + * Token for unconditional branch -- bbranch-- followed by + * place-holder of zero for FCode-offset. Then, token + * for forward-resolve -- b(>resolve) -- and the space + * reserved earlier for the conditional forward-branch + * FCode-offset is filled in to reach the token after + * the b(>resolve) . + * + * Error Detection: + * If the "Control-Stack" is empty, bypass the forward branch + * and let the call to control_structure_swap() report + * the underflow error. Then use not_cs_underflow to + * control whether to resolve the forward-branch. + * + * Process Explanation: + * The final item needed within the scope of what the earlier + * conditional branch might skip is an unconditional branch + * over the "else"-clause to follow. After that, the earlier + * conditional branch needs to be resolved. This last step + * is identical to the action of THEN . + * + **************************************************************************** */ + +void emit_else( void ) +{ + if ( control_stack_depth > 0 ) + { + emit_token("bbranch"); + mark_forward_branch( IF_CSTAG ); + } + not_cs_underflow = TRUE; + control_structure_swap(); + if ( not_cs_underflow ) + { + emit_then(); + } +} + + +/* ************************************************************************** + * + * Function name: emit_begin + * Synopsis: All the actions when BEGIN is encountered + * + * Associated FORTH word: BEGIN + * + * Inputs: + * Parameters: NONE + * + * Outputs: + * Returned Value: NONE + * Items Pushed onto Control-Stack: + * Top: Begin_BACKw_BEGIN + * (Datum is current OPC, target of future backward-branch) + * FCode Output buffer: + * Token for target of backward branch -- b(<mark) + * + **************************************************************************** */ + +void emit_begin( void ) +{ + emit_token("b(<mark)"); + mark_backward_target( BEGIN_CSTAG ); +} + + +/* ************************************************************************** + * + * Function name: emit_again + * Synopsis: All the actions when AGAIN is encountered + * + * Associated FORTH words: AGAIN REPEAT + * + * Inputs: + * Parameters: NONE + * Control-Stack Items: + * Top: Begin_BACKw_BEGIN + * (Datum is OPC of backward-branch target at BEGIN) + * + * Outputs: + * Returned Value: NONE + * Control-Stack, # of Items Popped: 1 + * FCode Output buffer: + * Token for unconditional branch -- bbranch -- followed by + * FCode-offset that reaches just after the b(<mark) + * token at the corresponding BEGIN statement. + * + * Process Explanation: + * The FCode-offset is calculated as the difference between our + * current OPC and the target-OPC saved on the Control-Stack. + * + **************************************************************************** */ + +void emit_again( void ) +{ + emit_token("bbranch"); + resolve_backward( BEGIN_CSTAG ); +} + +/* ************************************************************************** + * + * Function name: emit_until + * Synopsis: All the actions when UNTIL is encountered + * + * Associated FORTH word: UNTIL + * + * Process Explanation: + * Same as AGAIN except token is conditional branch -- b?branch -- + * instead of unconditional. + * + **************************************************************************** */ + +void emit_until( void ) +{ + emit_token("b?branch"); + resolve_backward( BEGIN_CSTAG ); +} + +/* ************************************************************************** + * + * Function name: emit_while + * Synopsis: All the actions when WHILE is encountered + * + * Associated FORTH word: WHILE + * + * Inputs: + * Parameters: NONE + * Global Variables: + * control_stack_depth Number of items on "Control-Stack" + * Control-Stack Items: + * Top: Begin_BACKw_BEGIN + * (Datum is OPC of backward-branch target) + * + * Outputs: + * Returned Value: NONE + * Control-Stack: 1 item added below top item. + * Items on Control-Stack: + * Top: Begin_BACKw_BEGIN + * Next: While_FORw_WHILE + * FCode Output buffer: + * Token for conditional branch -- b?branch -- followed by + * place-holder of zero for FCode-offset + * + * Error Detection: + * If the "Control-Stack" is empty, bypass creating the branch + * and let the call to control_structure_swap() report + * the underflow error. + * + * Process Explanation: + * Output a conditional forward-branch sequence, similar to IF + * (except with a WHILE CSTAG), but be sure to leave the + * control-structure branch-marker that was created by the + * preceding BEGIN on top of the one just generated: + * the BEGIN needs to be resolved first in any case, and + * doing this here is the key to implementing the extended + * control-flow structures as described in sec. A.3.2.3.2 + * of the ANSI Forth Spec. + * + * Extraneous Remarks: + * It was for the use of this function that Wil Baden coined the + * name BUT for the control-structure swap routine. The idea + * was that the implementation of WHILE could be boiled down + * to: IF BUT (couldn't quite fit an AND in there...;-} ) + * Naturally, this implementation is a smidgeon more complicated... + * + **************************************************************************** */ + +void emit_while( void ) +{ + if ( control_stack_depth > 0 ) + { + emit_token("b?branch"); + mark_forward_branch( WHILE_CSTAG ); + } + control_structure_swap(); +} + +/* ************************************************************************** + * + * Function name: emit_repeat + * Synopsis: All the actions when REPEAT is encountered + * + * Associated FORTH word: REPEAT + * + * Inputs: + * Parameters: NONE + * Local Static Variables: + * not_cs_underflow If FALSE after first call to resolve marker, + * an underflow resulted; skip second call. + * Control-Stack Items: + * Top: Begin_BACKw_BEGIN + * (Datum is OPC of backward-branch target at BEGIN) + * Next: If_FORw_IF + * (Datum is OPC of FCode-offset place-holder) + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * not_consuming_two Cleared, then restored + * Control-Stack, # of Items Popped: 2 + * FCode Output buffer: + * Token for unconditional branch -- bbranch -- followed by + * FCode-offset that reaches just after the b(<mark) + * token at the corresponding BEGIN statement. Then + * the token for forward-resolve -- b(>resolve) -- and + * the space reserved for the conditional forward-branch + * FCode-offset is filled in so that it reaches the token + * after the b(>resolve) . + * + * Process Explanation: + * The action is identical to that taken for AGAIN followed + * by the action for THEN. + * The Local Static Variable not_consuming_two gets cleared + * and restored by this routine. + * + **************************************************************************** */ + +void emit_repeat( void ) +{ + if ( matchup_two_control_structures( BEGIN_CSTAG, WHILE_CSTAG ) ) + { + not_cs_underflow = TRUE; + not_consuming_two = FALSE; + emit_again(); + if ( not_cs_underflow ) + { + emit_token("b(>resolve)"); + resolve_forward( WHILE_CSTAG ); + } + not_consuming_two = TRUE; + } +} + +/* ************************************************************************** + * + * Function name: mark_do + * Synopsis: Common routine for marking the branches for + * the "do" variants + * + * Associated FORTH words: DO ?DO + * + * Inputs: + * Parameters: NONE + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * do_loop_depth Incremented + * Items Pushed onto Control-Stack: + * Top: Do_FORw_DO + * Next: Do_BACKw_DO + * FCode Output buffer: + * Place-holder of zero for FCode-offset + * + * Error Detection: + * The do_loop_depth counter will be used by other routines + * to detect misplaced "LEAVE", "UNLOOP", "I" and suchlike. + * (Imbalanced "LOOP" statements are detected by the CSTag + * matching mechanism.) + * + * Process Explanation: + * Just before this function is called, the forward-branching token + * for the "DO" variant that begins the control-structure was + * written to the FCode Output buffer. + * It needs an FCode-offset for a forward-branch to just after + * its corresponding "LOOP" variant and the FCode-offset + * associated therewith. + * That "LOOP" variant's associated FCode-offset is targeted + * to the token that follows the one for this "DO" variant + * and its FCode-offset. + * Mark the forward-branch with the C-S Tag for DO and write a + * place-holder FCode-offset of zero to FCode Output. + * Indicate that the mark that will be processed second (but which + * was made first) is a duplicate of the one that will be + * processed first. + * Then mark the backward-branch target, also with the DO C-S Tag. + * Finally, increment the do_loop_depth counter. + * + * Extraneous Remarks: + * This is more complicated to describe than to code... ;-) + * + **************************************************************************** */ + +void mark_do( void ) +{ + mark_forward_branch( DO_CSTAG); + control_stack->cs_not_dup = FALSE; + mark_backward_target( DO_CSTAG); + do_loop_depth++; +} + + +/* ************************************************************************** + * + * Function name: resolve_loop + * Synopsis: Common routine for resolving the branches for + * the "loop" variants. + * + * Associated FORTH words: LOOP +LOOP + * + * Inputs: + * Parameters: NONE + * Global Variables: + * statbuf Word read from input stream (either "loop" + * or "+loop"), used for Error Message. + * Local Static Variables: + * not_cs_underflow If FALSE after first call to resolve marker, + * an underflow resulted; skip second call. + * Control-Stack Items: + * Top: Do_FORw_DO + * Next: Do_BACKw_DO + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * do_loop_depth Decremented + * Local Static Variables: + * not_consuming_two Cleared, then restored + * didnt_print_otl Set, then set again at end. + * Control-Stack, # of Items Popped: 2 + * FCode Output buffer: + * FCode-offset that reaches just after the token of the + * corresponding "DO" variant. Then the space reserved + * for the FCode-offset of the forward-branch associated + * with the "DO" variant is filled in so that it reaches + * the token just after the "DO" variant's FCode-offset. + * + * Error Detection: + * A value of zero in do_loop_depth before it's decremented + * indicates a DO ... LOOP imbalance, which is an ERROR, + * but our other error-reporting mechanisms will catch it, + * so we don't check or report it here. + * + * Process Explanation: + * Just before this function is called, the backward-branching + * token for the "LOOP" variant that ends the control-structure + * was written to the FCode Output buffer. + * It needs an FCode-offset for a backward-branch targeted just + * after its corresponding "DO" variant and the FCode-offset + * associated therewith. + * That "DO" variant's associated FCode-offset is targeted to + * the token that follows the one for this "LOOP" variant + * and its FCode-offset. + * Make sure there are two DO C-S Tag entries on the Control Stack. + * Resolve the backward-branch, matching your target to the first + * C-S Tag for DO + * Then resolve the forward-branch, targeting to your new OPC + * position, and also making sure you match the DO C-S Tag. + * We keep track of do_loop_depth for other error-detection + * by decrementing it; make sure it doesn't go below zero. + * Don't bother resolving the forward-branch if we underflowed + * the "Control Stack" trying to resolve the backward-branch. + * If the two top C-S Tag entries are not for a DO statement, the + * matchup_two_control_structures() routine will consume both + * or up to two of them, and we will place a dummy offset of + * zero to follow-up the backward-branching token that has + * already been written. + * + * Extraneous Remarks: + * This is only a little more complicated to describe + * than to code... ;-) + * + **************************************************************************** */ + +void resolve_loop( void ) +{ + if ( INVERSE( matchup_two_control_structures( DO_CSTAG, DO_CSTAG) ) ) + { + emit_offset( 0 ); + }else{ + not_cs_underflow = TRUE; + didnt_print_otl = TRUE; + not_consuming_two = FALSE; + resolve_backward( DO_CSTAG); + if ( not_cs_underflow ) + { + resolve_forward( DO_CSTAG); + } + if ( do_loop_depth > 0 ) do_loop_depth--; + not_consuming_two = TRUE; + didnt_print_otl = TRUE; /* Might have gotten cleared */ + } +} + +/* ************************************************************************** + * + * Function name: emit_case + * Synopsis: All the actions when CASE is encountered + * + * Associated FORTH word: CASE + * + * Inputs: + * Parameters: NONE + * + * Outputs: + * Returned Value: NONE + * Items Pushed onto Control-Stack: + * Top: N_OFs=0...CASE_CSTAG + * (Datum is 0 , Initial count of OF .. ENDOF pairs) + * FCode Output buffer: + * Token for start of a CASE structure -- b(case) + * Does not require an FCode-offset. + * + **************************************************************************** */ + +void emit_case( void ) +{ + push_cstag( CASE_CSTAG, 0); + emit_token("b(case)"); +} + + +/* ************************************************************************** + * + * Function name: emit_of + * Synopsis: All the actions when OF is encountered + * + * Associated FORTH word: OF + * + * Inputs: + * Parameters: NONE + * Control-Stack Items: + * Top: N_OFs...CASE_CSTAG + * (Datum is OF-count, number of OF .. ENDOF pairs) + * {Next and beyond}: {Endof_FORw_ENDOF}1..n_ofs + * { Repeat for OF-count number of times } + * + * Outputs: + * Returned Value: NONE + * Control-Stack, 1 Item Pushed, 1 modified: + * Top: Of_FORw_OF + * Next: N_OFs+1...CASE_CSTAG + * (Datum has been incremented) + * {3rd and beyond}: {Endof_FORw_ENDOF}1..n_ofs + * { Repeat for 1 through the un-incremented OF-count } + * (Same as Next etcetera at input-time.) + * FCode Output buffer: + * Token for OF statement -- b(of) -- followed by + * place-holder FCode-offset of zero + * + * Error Detection: + * Matchup CASE-cstag before incrementing OF-count + * + * Process Explanation: + * Main difference between this implementation and that outlined + * in "the book" (see below) is that we do not directly use + * the routine for the IF statement's flow-control; we will + * use a different CSTAG for better mismatch detection. + * + * Extraneous Remarks: + * This is a "by the book" (ANSI Forth spec, section A.3.2.3.2) + * implementation (mostly). Incrementing the OF-count here, + * after we've matched up the CSTAG, gives us (and the user) + * just a little bit more protection... + * + **************************************************************************** */ + +void emit_of( void ) +{ + + if ( matchup_control_structure( CASE_CSTAG ) ) + { + emit_token("b(of)"); + + /* + * See comment-block about "Control-Stack" Diagram Notation + * early on in this file. + * + */ + + /* ( {Endof_FORw_ENDOF}1..n_ofs N_OFs...CASE_CSTAG -- ) */ + + /* Increment the OF-count . */ + (control_stack->cs_datum)++; + + /* ( {Endof_FORw_ENDOF}1..n_ofs N_OFs+1...CASE_CSTAG -- ) */ + + mark_forward_branch( OF_CSTAG ); + /* ( -- {Endof_FORw_ENDOF}1..n_ofs N_OFs+1...CASE_CSTAG Of_FORw_OF ) + */ + } + /* Leave the CSTAG-Group on the "Control-Stack" . */ +} + + +/* ************************************************************************** + * + * Function name: emit_endof + * Synopsis: All the actions when ENDOF is encountered + * + * Associated FORTH word: ENDOF + * + * Inputs: + * Parameters: NONE + * Control-Stack Items: + * Top: Of_FORw_OF + * Next: N_OFs+1...CASE_CSTAG + * (Datum has been incremented) + * {3rd and beyond}: {Endof_FORw_ENDOF}1..n_ofs + * { Repeat for 1 through the un-incremented OF-count ) + * + * Outputs: + * Returned Value: NONE + * Control-Stack, 1 Item Popped, 1 new Item Pushed. + * Top: N_OFs...CASE_CSTAG + * (The count itself is unchanged from input-time, but + * the number of {Endof_FORw_ENDOF} CSTAG-Groups + * has caught up with this number, so it is + * no longer notated as " + 1 "). + * {Next and beyond}: {Endof_FORw_ENDOF}1..n_ofs + * { Repeat for 1 through the updated OF-count ) + * FCode Output buffer: + * Token for ENDOF statement -- b(endof) -- followed by + * place-holder FCode-offset of zero. Then the space reserved + * for the FCode-offset of the forward-branch associated + * with the "OF" statement is filled in so that it reaches + * the token just after the "ENDOF" statement's FCode-offset. + * + * Error Detection: + * If control-stack depth is not at least 2, CS underflow ERROR + * and no further action. + * Routine that resolves the forward-branch checks for matchup error. + * + **************************************************************************** */ + +void emit_endof( void ) +{ + if ( control_stack_size_test( 2) ) + { + emit_token("b(endof)"); + + /* See "Control-Stack" Diagram Notation comment-block */ + + /* Stack-diagrams might need to be split across lines. */ + + /* ( {Endof_FORw_ENDOF}1..n_ofs N_OFs+1...CASE_CSTAG ... + * ... Of_FORw_OF -- ) + */ + mark_forward_branch(ENDOF_CSTAG); + /* ( -- {Endof_FORw_ENDOF}1..n_ofs N_OFs+1...CASE_CSTAG ... + * ... Of_FORw_OF {Endof_FORw_ENDOF}n_ofs+1 ) + */ + + control_structure_swap(); + /* ( -- {Endof_FORw_ENDOF}1..n_ofs N_OFs+1...CASE_CSTAG ... + * ... {Endof_FORw_ENDOF}n_ofs+1 Of_FORw_OF ) + */ + + resolve_forward( OF_CSTAG ); + /* ( -- {Endof_FORw_ENDOF}1..n_ofs N_OFs+1...CASE_CSTAG ... + * ... {Endof_FORw_ENDOF}n_ofs+1 ) + */ + + control_structure_swap(); + /* ( -- {Endof_FORw_ENDOF}1..n_ofs ... + * ... {Endof_FORw_ENDOF}n_ofs+1 ... + * ... N_OFs+1...CASE_CSTAG ) + */ + + /* The number of ENDOF-tagged Forward-Marker pairs has now + * caught up with the incremented OF-count; therefore, + * we can notate the above as: + * + * ( {Endof_FORw_ENDOF}1..n_ofs N_OFs CASE_CSTAG ) + * + * and we are ready for another OF ... ENDOF pair, + * or for the ENDCASE statement. + */ + } + +} + +/* ************************************************************************** + * + * Function name: emit_endcase + * Synopsis: All the actions when ENDCASE is encountered + * + * Associated FORTH word: ENDCASE + * + * Inputs: + * Parameters: NONE + * Control-Stack Items: + * Top: N_OFs...CASE_CSTAG + * (Datum is OF-count, number of OF .. ENDOF pairs) + * {Next and beyond}: {Endof_FORw_ENDOF}1..n_ofs + * { Repeat for OF-count number of times } + * + * Outputs: + * Returned Value: NONE + * Control-Stack, # of Items Popped: OF-count + 1 + * FCode Output buffer: + * Token for ENDCASE statement -- b(endcase) + * Then the spaces reserved for the FCode-offsets of all the + * forward-branches associated with the OF-count number + * of ENDOF statements are filled in so that they reach + * the token just after this "ENDCASE" statement. + * + * Error Detection: + * Routine that resolves the forward-branch checks for matchup error + * for each forward-branch filled in, plus the matchup routine + * checks before the OF-count is retrieved. + * + * Process Explanation: + * Retrieve the OF-count and resolve that number of ENDOF statements + * + * Extraneous Remarks: + * The setup makes coding this routine appear fairly simple... ;-} + * + **************************************************************************** */ + +void emit_endcase( void ) +{ + unsigned long n_endofs ; + if ( matchup_control_structure( CASE_CSTAG) ) + { + int indx; + + emit_token("b(endcase)"); + n_endofs = control_stack->cs_datum; + for ( indx = 0 ; indx < n_endofs ; indx++ ) + { + /* Because matchup_control_structure doesn't pop the + * control-stack, we have the N_OFs...CASE_CSTAG + * item on top of the Endof_FORw_ENDOF item we + * want to resolve. We need to keep it there so + * the POP is valid for the other path as well + * as at the end of this one. + * So we SWAP to get at the Endof_FORw_ENDOF item. + */ + control_structure_swap(); + resolve_forward( ENDOF_CSTAG); + } + } + pop_cstag(); +} + + +/* ************************************************************************** + * + * Function name: control_struct_incomplete + * Synopsis: Print a Message of given severity with origin info for + * a control-structure that has not been completed. + * + * Inputs: + * Parameters: + * c_s_entry Control-structure about which to display + * severity Severity of the messages to display. + * call_cond String identifying Calling Condition; + * used in the message. + * + * Outputs: + * Returned Value: NONE + * + * Printout: + * Message of given severity... + * + * Process Explanation: + * The calling routine will be responsible for all filtering of + * duplicate structures and the like. This routine will + * simply display a message. + * + **************************************************************************** */ + +static void control_struct_incomplete( + int severity, + char *call_cond, + cstag_group_t *c_s_entry) +{ + tokenization_error ( severity, + "%s before completion of %s" , + call_cond, strupr(c_s_entry->cs_word)); + where_started( c_s_entry->cs_inp_fil, c_s_entry->cs_line_num ); +} + +/* ************************************************************************** + * + * Function name: announce_control_structs + * Synopsis: Print a series of Messages (of severity as specified) + * announcing that the calling event is occurring + * in the context of Control-Flow structure(s), + * back to the given limit. Leave the control + * structures in effect. + * + * Inputs: + * Parameters: + * severity Severity of the messages to display. + * call_cond String identifying Calling Condition; + * used in the message. + * abs_token_limit Limit, in terms of abs_token_no + * Local Static Variables: + * control_stack Pointer to "Top" of "Control-Stack" + * + * Outputs: + * Returned Value: NONE + * Printout: + * A Message for each unresolved Control-Flow structure. + * + **************************************************************************** */ + +void announce_control_structs( int severity, char *call_cond, + unsigned int abs_token_limit) +{ + cstag_group_t *cs_temp = control_stack; + while ( cs_temp != NULL ) + { + if ( cs_temp->cs_abs_token_num < abs_token_limit ) + { + break; + } + if ( cs_temp->cs_not_dup ) + { + control_struct_incomplete( severity, call_cond, cs_temp ); + } + cs_temp = cs_temp->prev; + } +} + +/* ************************************************************************** + * + * Function name: clear_control_structs_to_limit + * Synopsis: Clear items from the "Control-Stack" back to the given + * limit. Print error-messages with origin info for + * control-structures that have not been completed. + * + * Inputs: + * Parameters: + * call_cond String identifying Calling Condition; + * used in the Error message. + * abs_token_limit Limit, in terms of abs_token_no + * Global Variables: + * control_stack_depth Number of items on "Control-Stack" + * control_stack Pointer to "Top" of "Control-Stack" + * Control-Stack Items: + * The cs_inp_fil and cs_line_num tags of any item cleared + * from the "Control-Stack" are used in error-messages. + * + * Outputs: + * Returned Value: + * Global Variables: + * do_loop_depth Decremented when "DO" item cleared. + * control_stack_depth Decremented by called routine. + * Control-Stack, # of Items Popped: As many as go back to given limit + * Memory Freed + * By called routine. + * + * Error Detection: + * Any item on the "Control-Stack" represents a Control-Structure + * that was not completed when the Calling Condition was + * encountered. Error; identify the origin of the structure. + * No special actions if noerrors is set. + * + * Process Explanation: + * The given limit corresponds to the value of abs_token_no at + * the time the colon-definition (or whatever...) was created. + * Any kind of Control-Structure imbalance at the end of the + * colon-definition is an error and the entries must be cleared, + * but the colon-definition may have been created inside nested + * interpretation-time Control-Structures, and those must be + * preserved. + * + * Of course, if this routine is called with a given limit of zero, + * that would mean all the entries are to be cleared. That will + * be the way clear_control_structs() is implemented. + * We control the loop by the cs_abs_token_num field, but also + * make sure we haven't underflowed control_stack_depth + * We skip messages and other processing for items that are duplicates + * of others, based on the cs_not_dup field. + * If the cs_tag field is DO_CSTAG we decrement do_loop_depth + * The pop_cstag() routine takes care of the rest. + * + * Extraneous Remarks: + * This is a retrofit; necessary because we now permit definitions + * to occur inside interpretation-time Control-Structures. Calls + * to clear_control_structs() are already scattered around... + * + **************************************************************************** */ + +void clear_control_structs_to_limit( char *call_cond, + unsigned int abs_token_limit) +{ + while ( control_stack_depth > 0 ) + { + if ( control_stack->cs_abs_token_num < abs_token_limit ) + { + break; + } + if ( control_stack->cs_not_dup ) + { + control_struct_incomplete( TKERROR, call_cond, control_stack ); + if ( control_stack->cs_tag == DO_CSTAG) do_loop_depth--; + } + pop_cstag(); + } +} + +/* ************************************************************************** + * + * Function name: clear_control_structs + * Synopsis: Make sure the "Control-Stack" is cleared, and print + * error-messages (giving origin information) for + * control-structures that have not been completed. + * + * Inputs: + * Parameters: + * call_cond String identifying Calling Condition; + * used in the Error message. + * Global Variables: + * control_stack_depth Number of items on "Control-Stack" + * control_stack Pointer to "Top" of "Control-Stack" + * Control-Stack Items: + * The cs_inp_fil and cs_line_num tags of any item found on + * the "Control-Stack" are used in error-messages. + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * control_stack_depth Reset to zero. + * do_loop_depth Reset to zero. + * Control-Stack, # of Items Popped: All of them + * + * Error Detection: + * Any item on the "Control-Stack" represents a Control-Structure + * that was not completed when the Calling Condition was + * encountered. Error; identify the origin of the structure. + * No special actions if noerrors is set. + * + * Process Explanation: + * Filter the duplicate messages caused by structures (e.g., DO) + * that place two entries on the "Control-Stack" by testing + * the cs_not_dup field of the "Top" "Control-Stack" item, + * which would indicate double-entry... + * + * Extraneous Remarks: + * This is called before a definition of any kind, and after a + * colon-definition. Flow-control constructs should *never* + * be allowed to cross over between immediate-execution mode + * and compilation mode. Likewise, not between device-nodes. + * Also, at the end of tokenization, there should not be any + * unresolved flow-control constructs. + * + **************************************************************************** */ + +void clear_control_structs( char *call_cond) +{ + clear_control_structs_to_limit( call_cond, 0); +}
Added: fcode-utils/toke/flowcontrol.h =================================================================== --- fcode-utils/toke/flowcontrol.h (rev 0) +++ fcode-utils/toke/flowcontrol.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,74 @@ +#ifndef _TOKE_FLOWCONTROL_H +#define _TOKE_FLOWCONTROL_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * External Variables and Function Prototypes for Support Functions + * used in tokenizing FORTH Flow-Control structures. + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + + +/* ************************************************************************** * + * + * Global Variables Exported + * + **************************************************************************** */ + +extern int control_stack_depth; + +/* ************************************************************************** * + * + * Function Prototypes / Functions Exported: + * + **************************************************************************** */ + +void emit_if( void ); +void emit_then( void ); +void emit_else( void ); +void emit_begin( void ); +void emit_again( void ); +void emit_until( void ); +void emit_while( void ); +void emit_repeat( void ); +void mark_do( void ); +void resolve_loop( void ); +void emit_case( void ); +void emit_of( void ); +void emit_endof( void ); +void emit_endcase( void ); + +void announce_control_structs( int severity, char *call_cond, + unsigned int abs_token_limit); +void clear_control_structs_to_limit( char *call_cond, + unsigned int abs_token_limit); +void clear_control_structs( char *call_cond); + +#endif /* _TOKE_FLOWCONTROL_H */
Modified: fcode-utils/toke/macros.c =================================================================== --- fcode-utils/toke/macros.c 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/macros.c 2006-08-18 12:47:12 UTC (rev 76) @@ -24,6 +24,31 @@ * */
+/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + +/* ************************************************************************** + * + * Support functions for the MACROS vocabulary, implemented + * as a TIC-Headerlist type of data structure, and linked in + * to the Global Vocabulary. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Functions Exported: + * init_macros Initialize the link-pointers in the + * initial "Built-In" portion of + * the macros vocabulary + * add_user_macro Add an entry to the macros vocabulary + * skip_user_macro Consume a Macro definition if Ignoring + * + **************************************************************************** */ + #include <stdio.h> #include <stdlib.h> #if defined(__linux__) && ! defined(__USE_BSD) @@ -32,107 +57,489 @@ #include <string.h> #include <errno.h>
-#include "toke.h" +#include "errhandler.h" +#include "ticvocab.h" +#include "stream.h" +#include "scanner.h" +#include "dictionary.h" +#include "devnode.h" +#include "macros.h"
-typedef struct macro { - u8 *name; - u8 *alias; - struct macro *next; -} macro_t; +/* ************************************************************************** + * + * Internal Static Variables + * macros_tbl Initial array of "Built-In" Macros + * number_of_builtin_macros Number of "Built-In" Macro entries. + * + **************************************************************************** */
-static macro_t *macros=NULL; +/* ************************************************************************** + * + * Revision History: + * Thu, 27 Oct 2005 by David L. Paktor + * Identify the macros that resolve to a single word. + * Remove them from here and enter them as synonymous entries + * in the Tokens, Specials or Shared-words vocabularies. + * Wed, 30 Nov 2005 by David L. Paktor + * Allow user-definition of macros. + * Fri, 06 Jan 2006 by David L. Paktor + * Re-define the Macros as a TIC-Headerlist, and make them + * part of the Global Vocabulary + * + **************************************************************************** */
-char *lookup_macro(char *name) + + +/* ************************************************************************** + * + * Function name: macro_recursion_error + * Synopsis: Function that will go temporarily into the FUNCT + * field of a Macro's TIC-entry, to protect against + * recursive macro invocations. + * + * Inputs: + * Parameters: + * pfield Param field of the TIC-entry; unused. + * Global Variables: + * statbuf The name being invoked erroneously. + * + * Outputs: + * Returned Value: NONE + * Printout: + * Error Message. + * + * Error Detection: + * If this function is called, it is an ERROR + * + * Extraneous Remarks: + * This Tokenizer does not have the early-binding characterisitics + * of FORTH; its Macros are strings, evaluated when invoked + * rather than when they are defined. A reference to a name + * that matches the macro would cause recursion, possibly + * infinite. We will not allow that. + * + **************************************************************************** */ + +static void macro_recursion_error( tic_param_t pfield) { - macro_t *curr; - - for (curr=macros; curr!=NULL; curr=curr->next) - if (!strcasecmp(name,(char *)curr->name)) - break; + tokenization_error( TKERROR, + "Recursive invocation of macro named %s\n", statbuf); +}
- return curr?(char *)curr->alias:NULL; + +/* ************************************************************************** + * + * Function name: eval_mac_string + * Synopsis: Function that goes into FUNCT field of a TIC-entry + * in the Macros list. Protect against recursion. + * + * Inputs: + * Parameters: + * pfield Param field of the TIC-entry + * Global Variables: + * tic_found The TIC-entry that has just been found; + * it's the entry for this Macro. + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * report_multiline Cleared to FALSE + * Global Behavior: + * The Macro will be evaluated as string input. + * + * Error Detection: + * An attempt at recursion will be detected because the FUNCT field + * of the Macro entry will have been temporarily be replaced by + * macro_recursion_error() + * + * Process Explanation: + * Save the address of the routine that is in the FUNCT field + * of the entry for this Macro. (Hey! It's this routine...) + * Replace the FUNCT field of the Macro entry with the Macro + * Recursion Error Detection routine + * Pass the address of the "resumption" routine and its argument + * (the entry for this Macro), to push_source() + * Recast the type of the parameter field to a string + * Make it the new Input Source Buffer. + * Suspend multi-line warning; see comment in body of add_user_macro() + * The multi-line warning flag is kept by push_source() + * + * Still to be done: + * If an error is encountered during Macro evaluation, display + * supplemental information giving the name of the Macro + * being run, and the file and line number in which it was + * defined. + * This will require changes to the way user Macros are added + * and retained, and to the way error messages are displayed. + * + * Revision History: + * Updated Thu, 23 Feb 2006 by David L. Paktor + * Do not process Macros (or, for that matter, User-defined + * Symbols or FLOADed files) with a routine that calls + * its own instance of tokenize(), because the Macro + * (etc.) might contain a phrase (such as the start of + * a conditional) that must be terminated within the + * body of a file, thus causing an undeserved Error. + * Instead, they need to be handled in a more sophis- + * ticated way, tied in with the operation of get_word() + * perhaps, that will make a smooth transition between + * the body of the Macro and the resumption of processing + * the source file. The end-of-file will only be seen + * at the end of an actual input file or when getting + * a delimited string. + * Updated Fri, 24 Feb 2006 by David L. Paktor + * Re-integrate Recursion Error Detection with the above. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * In order to integrate Recursion Error Detection with the smooth + * transition to resumption of processing the source file, we + * need to create a "resumption" routine that will restore the + * normal behavior of the macro after it's completed, by re- + * instating the address of the normal Macro-invocation routine; + * that routine, of course, is the one that passes the address + * of the "resumption" routine to push_source(). In order to + * get around this chicken-and-egg dilemma, we will create a + * local static variable into which the address of the normal + * Macro-invocation routine will be stored. We actually only + * need it once, but we'd rather avoid the overhead of checking, + * every time, whether it has already been set; since it's always + * the same, there's no harm in storing it every time. + * + **************************************************************************** */ + +typedef void (*vfunct)(); /* Pointer to function returning void */ +static vfunct sav_mac_funct ; + + +/* ************************************************************************** + * + * This "resumption" routine will be called by pop_source() + * The parameter is the Macro dictionary-entry whose behavior + * is to be restored. + * + **************************************************************************** */ + +static void mac_string_recovery( tic_hdr_t *macro_entry) +{ + (*macro_entry).funct = sav_mac_funct; + (*macro_entry).ign_func = sav_mac_funct; }
-int add_macro(char *name, char *alias) +/* ************************************************************************** + * + * The normal Macro-invocation routine, at last... + * + **************************************************************************** */ +static void eval_mac_string( tic_param_t pfield) { - macro_t *curr; + int mac_str_len = strlen(pfield.chr_ptr); + /* We can't use (*tic_found).pfld_size for the string length + * because, if this is an alias for a macro, it will be zero... + */ + /* We can change that by de-coupling the decision to free the + * param-field from whether pfld_size is non-zero (by intro- + * ducing yet another field into the tic_param_t struct), + * but we're not doing that today... + */
- curr=malloc(sizeof(macro_t)); - if(!curr) { - printf("Out of memory while adding macro.\n"); - exit(-ENOMEM); - } + sav_mac_funct = *tic_found->funct; + (*tic_found).funct = macro_recursion_error; + (*tic_found).ign_func = macro_recursion_error; + push_source( mac_string_recovery, tic_found, FALSE); + report_multiline = FALSE; /* Must be done AFTER call to push_source() + * because report_multiline is part of + * the state that push_source() saves. + */ + init_inbuf( pfield.chr_ptr, mac_str_len); +}
- curr->next=macros; - curr->name=(u8 *)name; - curr->alias=(u8 *)alias; +/* ************************************************************************** + * + * Builtin Macros do not need Recursion Error Detection. + * Intermediate routine to convert parameter type. + * + **************************************************************************** */ +static void eval_builtin_mac( tic_param_t pfield) +{ + eval_string( pfield.chr_ptr); +} +/* ************************************************************************** + * + * Make a macro, because we might eliminate this layer later on. + * + **************************************************************************** */ +#define EVAL_MAC_FUNC eval_mac_string +#define BUILTIN_MAC_FUNC eval_builtin_mac
- macros=curr; - return 0; +/* ************************************************************************** + * + * Initialization macro definition + * + **************************************************************************** */ + +#define BUILTIN_MACRO(nam, alias) BUILTIN_MAC_TIC(nam, BUILTIN_MAC_FUNC, alias ) + +static tic_mac_hdr_t macros_tbl[] = { + BUILTIN_MACRO( "(.)", "dup abs <# u#s swap sign u#>") , + + + BUILTIN_MACRO( "?", "@ .") , + BUILTIN_MACRO( "1+", "1 +") , + BUILTIN_MACRO( "1-", "1 -") , + BUILTIN_MACRO( "2+", "2 +") , + BUILTIN_MACRO( "2-", "2 -") , + + BUILTIN_MACRO( "accept", "span @ -rot expect span @ swap span !") , + BUILTIN_MACRO( "allot", "0 max 0 ?do 0 c, loop") , + BUILTIN_MACRO( "blank", "bl fill") , + BUILTIN_MACRO( "carret", "h# d") , + BUILTIN_MACRO( ".d", "base @ swap h# a base ! . base !") , + BUILTIN_MACRO( "decode-bytes", ">r over r@ + swap r@ - rot r>") , + BUILTIN_MACRO( "3drop", "drop 2drop") , + BUILTIN_MACRO( "3dup", "2 pick 2 pick 2 pick") , + BUILTIN_MACRO( "erase", "0 fill") , + BUILTIN_MACRO( ".h", "base @ swap h# 10 base ! . base !") , + BUILTIN_MACRO( "linefeed", "h# a") , + + BUILTIN_MACRO( "s.", "(.) type space") , + BUILTIN_MACRO( "space", "bl emit") , + BUILTIN_MACRO( "spaces", "0 max 0 ?do space loop") , + BUILTIN_MACRO( "(u.)", "<# u#s u#>") , + BUILTIN_MACRO( "?leave", "if leave then"), +}; + +static const int number_of_builtin_macros = + sizeof(macros_tbl)/sizeof(tic_mac_hdr_t); + +/* ************************************************************************** + * + * Function name: init_macros + * Synopsis: Initialize the link-pointers in the "Built-In" + * portion of the macros vocabulary, dynamically. + * + * Inputs: + * Parameters: + * tic_vocab_ptr Pointer to Global Vocab Pointer + * Global Variables: + * macros_tbl Initial "Built-In" Macros array + * number_of_builtin_macros Number of "Built-In" Macro entries + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * The link-fields of the initial "Built-In" Macros array entries + * will be filled in. + * Supplied Pointers: + * *tic_vocab_ptr Updated to "tail" of Macros array + * + **************************************************************************** */ + +void init_macros( tic_hdr_t **tic_vocab_ptr ) +{ + init_tic_vocab( (tic_hdr_t *)macros_tbl, + number_of_builtin_macros, + tic_vocab_ptr ); }
-void init_macros(void) + +/* ************************************************************************** + * + * Function name: print_if_mac_err + * Synopsis: Report a user-macro definition error, if so be. + * + * Inputs: + * Parameters: + * failure TRUE if error was detected + * func_cpy STRDUP() of function name, for error message + * + * Outputs: + * Returned Value: NONE + * Memory Freed + * Contents of func_cpy, error or not. + * Printout: + * Error message, if failure is TRUE. + * + **************************************************************************** */ +static void print_if_mac_err( bool failure, char *func_cpy) { - add_macro( "eval", "evaluate"); - add_macro( "(.)", "dup abs <# u#s swap sign u#>"); - add_macro( "<<", "lshift"); - add_macro( ">>", "rshift"); - add_macro( "?", "@ ."); - add_macro( "1+", "1 +"); - add_macro( "1-", "1 -"); - add_macro( "2+", "2 +"); - add_macro( "2-", "2 -"); - /* add_macro( "abort"", "-2 throw"); */ - add_macro( "accept", "span @ -rot expect span @ swap span !"); - add_macro( "allot", "0 max 0 ?do 0 c, loop"); - add_macro( "blank", "bl fill"); - add_macro( "/c*", "chars"); - add_macro( "ca1+", "char+"); - add_macro( "carret", "h# d"); - add_macro( ".d", "base @ swap h# a base ! . base !"); - add_macro( "decode-bytes", ">r over r@ + swap r@ - rot r>"); - add_macro( "3drop", "drop 2drop"); - add_macro( "3dup", "2 pick 2 pick 2 pick"); - add_macro( "erase", "0 fill"); - add_macro( "false", "0"); - add_macro( ".h", "base @ swap h# 10 base ! . base !"); - add_macro( "linefeed", "h# a"); - add_macro( "/n*", "cells"); - add_macro( "na1+", "cell+"); - add_macro( "not", "invert"); - add_macro( "s.", "(.) type space"); - add_macro( "space", "bl emit"); - add_macro( "spaces", "0 max 0 ?do space loop"); - add_macro( "struct", "0"); - add_macro( "true", "-1"); - add_macro( "(u.)", "<# u#s u#>"); + if ( failure ) + { + tokenization_error( TKERROR, + "%s directive expects name and definition on the same line\n", + strupr(func_cpy)); + } + free( func_cpy); +}
- /* H.7 FCode name changes */ - add_macro( "decode-2int", "parse-2int"); - add_macro( "delete-attribute", "delete-property"); - add_macro( "get-inherited-attribute", "get-inherited-property"); - add_macro( "get-my-attribute", "get-my-property"); - add_macro( "get-package-attribute", "get-package-property"); - add_macro( "attribute", "property"); - add_macro( "flip", "wbflip"); - add_macro( "is", "to"); - add_macro( "lflips", "lwflips"); - add_macro( "map-sbus", "map-low"); - add_macro( "u*x", "um*"); - add_macro( "version", "fcode-revision"); - add_macro( "wflips", "wbflips"); - add_macro( "x+", "d+"); - add_macro( "x-", "d-"); - add_macro( "xdr+", "encode+"); - add_macro( "xdrbytes", "encode-bytes"); - add_macro( "xdrint", "encode-int"); - add_macro( "xdrphys", "encode-phys"); - add_macro( "xdrstring", "encode-string"); - add_macro( "xdrtoint", "decode-int"); - add_macro( "xdrtostring", "decode-string"); - add_macro( "xu/mod", "um/mod"); + +/* ************************************************************************** + * + * Function name: add_user_macro + * Synopsis: Parse input and add a user-defined Macro. + * + * Associated Tokenizer directive: [MACRO] + * + * Inputs: + * Parameters: NONE + * Global Variables: + * pc Input-source Scanning pointer + * statbuf Symbol retrieved from input stream. + * in_tokz_esc TRUE if in "Tokenizer-Escape" mode + * current_definitions Pointer to Current Vocabulary pointer, + * either Global or Current Device-Node + * tokz_esc_vocab "Tokenizer Escape" Vocab pointer + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * *current_definitions { One of these will point } + * tokz_esc_vocab { to the new entry } + * Memory Allocated: + * Copy of directive, for error message + * Copy of Macro name + * Copy of Macro body + * Memory for the new entry will be allocated by support routine. + * When Freed? + * Copy of directive: When error might be reported. + * Macro name, body and entry: Upon end of tokenization, or when + * RESET-SYMBOLS is issued in the same mode and Scope as when + * the Macro was defined. + * + * Error Detection: + * At least two words in the input stream are expected to be on + * the same line as the directive. The get_word_in_line() + * and get_rest_of_line() routines will check for that; + * we will issue the Error Message for either condition. + * Check if the Macro name is a duplicate; warn_if_duplicate() + * routine will issue message. + * + * Process Explanation: + * We start just after the directive has been recognized. + * Get one word in line -- this is the macro name + * Get input to end of line. This is the "body" of the macro. + * Add the Macro to the Current vocab, using support routine. + * Set the definer field to MACRO_DEF and the Function to the + * same one that's used for the built-in macros. + * User-defined Macros may need to be processed while ignoring + * (because they might include conditional-operators, etc.) + * We will set the ign_func the same as the active function. + * + * To be considered: + * Do we want to do further filtration? + * Remove comments? + * Compress whitespace? + * Allow backslash at end of line to continue to next line? + * + * Extraneous Remarks: + * The scope of User-Macro definitions will follow the same rules + * as all other definition types: if Device-Definitions are + * in effect, the scope of the new Macro definition will be + * confined to the current Device-Node; if Global-Definitions + * are in effect when it is defined, its scope will be Global; + * if it was declared when we were in "Tokenizer Escape" mode, + * then its scope will be limited to "Tokenizer Escape" mode. + * + **************************************************************************** */ + +/* This pointer is exported to this file only */ +extern tic_hdr_t *tokz_esc_vocab ; + +void add_user_macro( void) +{ + char *macroname; + char *macrobody; + bool failure = TRUE; + + /* Copy of function name, for error message */ + char *func_cpy = strdup( statbuf); + + if ( get_word_in_line( NULL ) ) + { + /* This is the Macro name */ + macroname = strdup( statbuf); + + if ( INVERSE(get_rest_of_line() ) ) + { + /* No body on line */ + free( macroname); - /* non standard but often used macros */ - add_macro( "name", "device-name"); - add_macro( "endif", "then"); + }else{ + /* We have valid Macro body on line */ + int mac_body_len = 0; + + tic_hdr_t **target_vocab = current_definitions; + if ( in_tokz_esc ) target_vocab = &tokz_esc_vocab ; + + warn_if_duplicate( macroname); + trace_creation( MACRO_DEF, macroname); + + /* Tack on a new-line, so that a remark will appear + * to be properly terminated. This might trigger + * an undeserved multi-line warning if the Macro + * is an improperly terminated quote; we will work + * around that problem by temporarily suspending + * multi-line warnings during macro processing. + */ + strcat( statbuf, "\n"); + macrobody = strdup( statbuf); + mac_body_len = strlen(macrobody); + + add_tic_entry( macroname, EVAL_MAC_FUNC, + (TIC_P_DEFLT_TYPE)macrobody, + MACRO_DEF, mac_body_len, + EVAL_MAC_FUNC, target_vocab ); + failure = FALSE; + } + } + + print_if_mac_err( failure, func_cpy); } + +/* ************************************************************************** + * + * Function name: skip_user_macro + * Synopsis: Consume the text of a user-defined Macro from the + * Input Stream, with no processing. (Called when + * a user-Macro definer occurs in a segment that + * is being Ignored.) + * + * Inputs: + * Parameters: + * pfield "Parameter field" pointer, to satisfy + * the calling convention, but not used + * Global Variables: + * statbuf Word currently being processed. + * + * Outputs: + * Returned Value: NONE + * + * Error Detection: + * At least two words in the input stream are expected to be on + * the same line as the user-Macro definer, same as when the + * directives occurs in a segment that is not being Ignored. + * The get_word_in_line() and get_rest_of_line() routines + * will check for condition., we will issue the Error Message. + * + * Process Explanation: + * We need to protect against the case of a macro-definition that + * invokes a directive that alters Conditional processing... + * + **************************************************************************** */ +void skip_user_macro( tic_bool_param_t pfield ) +{ + bool failure = TRUE; + char *func_cpy = strdup( statbuf); + if ( get_word_in_line( NULL ) ) + { + if ( get_rest_of_line() ) + { + failure = FALSE; + } + } + + print_if_mac_err( failure, func_cpy); + +}
Added: fcode-utils/toke/macros.h =================================================================== --- fcode-utils/toke/macros.h (rev 0) +++ fcode-utils/toke/macros.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,58 @@ +#ifndef _TOKE_MACROS_H +#define _TOKE_MACROS_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Prototypes for functions that operate on the MACROS vocabulary, + * which is implemented as a String-Substitution-type vocab. + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + + +#include "types.h" +#include "ticvocab.h" + +/* ************************************************************************** * + * + * Function Prototypes / Functions Exported: + * + **************************************************************************** */ + +void init_macros( tic_hdr_t **tic_vocab_ptr ); +void add_user_macro( void); +void skip_user_macro( tic_bool_param_t pfield ); +#if 0 /* What's this doing here? */ +char *lookup_macro(char *name); +bool exists_as_macro(char *name); +bool create_macro_alias( char *new_name, char *old_name ); +void reset_macros_vocab( void ); +#endif /* What's this doing here? */ + +#endif /* _TOKE_MACROS_H */
Added: fcode-utils/toke/nextfcode.c =================================================================== --- fcode-utils/toke/nextfcode.c (rev 0) +++ fcode-utils/toke/nextfcode.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,708 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Functions for Managing FCode Assignment Pointer and for + * Detection of Overlapping-FCode Error in Tokenizer + * + * (C) Copyright 2006 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * The fact that the user is able to specify, at any time, the + * next FCode number to be assigned introduces the risk that + * a symbol might inadvertently be assigned an FCode that is + * still in use by another symbol, which could lead to bizarre + * and hard-to-trace failures at run-time. + * + * This module will support a means whereby to detect and report, + * as an Error, overlapping FCode assignments. + * + * The task is further complicated by the fact that, under some + * circumstances, "recycling" a range of FCodes can be done + * safely, and the programmer may do so intentionally. + * + * We will define a way for the programmer to specify that FCode + * assignments are being intentionally "recycled", and that + * overlaps with previously-assigned FCodes are not to be + * treated as Errors. We will not attempt to analyze whether + * it is, indeed, safe to do so; the programmer who does this + * is presumed to be sufficiently responsible. + * + **************************************************************************** */ + + +/* ************************************************************************** + * + * Functions Exported: + * reset_fcode_ranges (Re-)Initialize the range of assignable + * FCode numbers and clear the records + * of prevously-assigned ranges of FCodes + * list_fcode_ranges Display a final report of assigned FCode + * ranges at end of tokenization or when + * the reset_fcodes() routine is called. + * set_next_fcode Set the start of a new Range of FCode + * numbers to be assigned. + * assigning_fcode The next FCode number is about to be assigned; + * test for out-of-bounds, overlap, etc. + * errors. + * bump_fcode Increment the next FCode number prior to the + * next assignment. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Revision History: + * 06 Jun 06 -- Need became apparent after verification test + * against existing device-drivers. + * + * + **************************************************************************** */ + + +/* ************************************************************************** + * + * Still to be done: + * Detect and report when the Current Range stops overlapping + * one particular Range and starts overlapping another. + * + * Detect and report when the Current Range overlaps more than + * one Range at a time (e.g., if other Ranges themselves + * overlap, and the Current Range is stepping through them) + * but, again, only display one message per overlapped Range. + * + **************************************************************************** */ + + + +/* ************************************************************************** + * + * Global Variables Imported + * iname Name of current input file + * lineno Line Number within current input file + * + **************************************************************************** */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#include "toke.h" +#include "nextfcode.h" +#include "errhandler.h" +#include "stream.h" +#include "scanner.h" + + +/* ************************************************************************** + * + * Global Variables Exported + * nextfcode The next FCode-number to be assigned + * + **************************************************************************** */ + +u16 nextfcode; /* The next FCode-number to be assigned */ + +/* ************************************************************************** + * + * Internal (Static) Structure: + * fcode_range_t The record of a Range of assigned FCodes + * + * Fields: + * fcr_start FCode number at the start of a this Range + * fcr_end Last FCode number in this Range that has + * actually been assigned. 0 if none made yet. + * fcr_infile File name of where this Range was started + * fcr_linenum Line number where this Range was started + * fcr_not_lapped TRUE if an overlap error has not been reported + * against this Range. Use this to prevent + * issuing an Error message every time an + * overlapping FCode is assigned; once per + * Range is sufficient. + * fcr_next Pointer to following entry in linked-list. + * + * We will keep the list of assigned FCode Ranges as a forward-linked, + * rather than the more usual backward-linked, list for convenience + * at listing-time. Otherwise, it doesn't make much difference. + * + **************************************************************************** */ + +typedef struct fcode_range + { + u16 fcr_start; + u16 fcr_end ; + char *fcr_infile; + int fcr_linenum; + bool fcr_not_lapped; + struct fcode_range *fcr_next; + } fcode_range_t ; + + +/* ************************************************************************** + * + * Internal Static Variables + * ranges_exist TRUE if FCode Ranges have been created; + * Prevents unnecessary overlap checking. + * changes_listed TRUE if no changes to any of the Ranges + * have taken place since the last time + * a Listing was displayed. Prevents + * unnecessary repetions (e.g., if a + * reset_fcode_ranges() was called + * right after an operation that causes + * a Listing + * + * These four apply if no FCode Ranges have been created: + * + * range_start First FCode in the current first (only) range. + * range_end Last FCode in current first (only) range that + * has actually been assigned. 0 if none yet. + * first_fcr_infile File name of where first (only) range started. + * first_fcr_linenum Line number where first (only) range started. + * + * These two apply after FCode Ranges have been created: + * + * first_fc_range Pointer to the first entry in the linked + * list of FCode Ranges. + * current_fc_range Pointer to the entry in the linked list of + * Ranges that contains the Current Range. + * + **************************************************************************** */ + +static bool ranges_exist = FALSE; +static bool changes_listed = FALSE; + +static u16 range_start = FCODE_START; +static u16 range_end = 0; +static char *first_fcr_infile = NULL; +static int first_fcr_linenum = 0; + +static fcode_range_t *first_fc_range = NULL; +static fcode_range_t *current_fc_range = NULL; + +/* ************************************************************************** + * + * Function name: reset_fcode_ranges + * Synopsis: (Re-)Initialize the range of assignable FCode numbers + * and clear the records of prevously-assigned Ranges + * + * Inputs: + * Parameters: NONE + * Global Variables: + * iname Name of current input file + * lineno Line Number within current input file + * Local Static Variables: + * ranges_exist TRUE if FCode Ranges have been created + * first_fc_range Pointer to First FCode Range + * current_fc_range Pointer to the current Range + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * nextfcode Initialized to Standard start value + * for user-assigned FCodes + * Local Static Variables: + * ranges_exist Cleared to FALSE + * changes_listed Reset to FALSE + * range_start Reset to Standard start value + * range_end Reset to 0 + * first_fcr_infile Copy of iname + * first_fcr_linenum Copy of lineno + * first_fc_range Reset to NULL + * current_fc_range Reset to NULL + * Memory Allocated + * For first_fcr_infile , which will have a copy of iname + * When Freed? + * The next time this routine is called. + * Memory Freed + * Any FCode Ranges that were in effect will be freed, and the + * memory for their fcr_infile fields will be freed. + * If iname has changed, memory for first_fcr_infile will + * be freed before the new copy is made. + * + * Process Explanation: + * This will be called either as part of normal initialization + * or in response to a User-issued directive. + * In the former case, it may be called twice: once before any + * Source is examined, and once again in response to the first + * (and only to the first) invocation of an FCode-Starter, at + * which time the input file name and line number will be updated. + * In the latter case, the calling routine will be responsible for + * displaying any Advisory Messages and listings of previously + * assigned FCode Ranges. + * + **************************************************************************** */ + +void reset_fcode_ranges( void) +{ + if ( ranges_exist ) + { + while ( current_fc_range != NULL ) + { + current_fc_range = first_fc_range->fcr_next; + free( first_fc_range->fcr_infile); + free( first_fc_range); + first_fc_range = current_fc_range; + } + ranges_exist = FALSE; + }else{ + if ( first_fcr_infile != NULL ) + { + if ( strcmp( first_fcr_infile, iname) != 0 ) + { + free( first_fcr_infile); + first_fcr_infile = NULL; + } + } + } + + changes_listed = FALSE; + range_start = FCODE_START; + range_end = 0; + + if ( first_fcr_infile == NULL ) + { + first_fcr_infile = strdup( iname); + } + first_fcr_linenum = lineno; + nextfcode = FCODE_START; +} + +/* ************************************************************************** + * + * Function name: list_fcode_ranges + * Synopsis: Display an Advisory of assigned FCode ranges at + * end of tokenization or upon reset_fcodes() + * + * Inputs: + * Parameters: + * final_tally TRUE if printing a final tally at + * end of tokenization. + * Global Variables: + * verbose Do not print anything if not set. + * nextfcode FCode next after last-assigned + * Local Static Variables: + * changes_listed If TRUE, only print new-line. + * ranges_exist TRUE if more than one Range exists. + * range_start FCode at start of only range + * range_end Last FCode in only range; 0 if none. + * first_fc_range Ptr to start of FCode Ranges list + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * changes_listed Set to TRUE. + * Printout: + * Printed to Standard Out on final tally, or to STDERR otherwise. + * One of three formats: + * 1 No FCodes assigned. + * 2 Last assigned FCode = 0xXXX + * 3 FCodes assigned: + * [ No FCodes assigned in the range that started ... ] + * [ From 0xXXX to 0xYYY ** in the range that started ... ] + * (** = Indicator if the Range has an Overlap Error.) + * + * Process Explanation: + * This is called to complete an Advisory or Standard-Out Message + * that doesn't end in a new-line. + * + * Extraneous Remarks: + * If we ever decide not to keep entries for Ranges in which no + * assignments were made, let's not remove the code that lists + * them. It's harmless to keep it around, and we remain ready... + * + **************************************************************************** */ + +void list_fcode_ranges( bool final_tally) +{ + if ( verbose ) + { + FILE *message_dest = ( final_tally ? stdout : ERRMSG_DESTINATION ); + if ( changes_listed ) + { + fprintf(message_dest, "\n"); + }else{ + changes_listed = TRUE; + + if ( INVERSE(ranges_exist) ) + { /* List the first and only range */ + if ( range_end == 0 ) + { + fprintf(message_dest, "No FCodes assigned.\n"); + }else{ + if ( range_start == FCODE_START ) + { + fprintf(message_dest, + "Last assigned FCode = 0x%x\n", range_end); + }else{ + fprintf(message_dest, + "FCodes assigned: 0x%x to 0x%x\n", + range_start, range_end); + } + } + /* We are done listing the first and only range */ + }else{ /* List the collection of Ranges */ + + /* Pionter to function returning void */ + typedef void (*vfunct)(); + + /* Function for the started_at() part of the message */ + vfunct start_at_funct = + ( final_tally ? print_started_at : started_at ); + + + fcode_range_t *next_range = first_fc_range; + + fprintf(message_dest, "FCodes assigned:\n"); + + while ( next_range != NULL ) + { + if ( next_range->fcr_end == 0 ) + { + fprintf(message_dest, " None assigned"); + }else{ + fprintf(message_dest, " From 0x%x to 0x%x", + next_range->fcr_start, next_range->fcr_end ); + if ( INVERSE( next_range->fcr_not_lapped) ) + { + fprintf(message_dest, " ***Overlap***" ); + } + } + fprintf(message_dest, " in the range"); + (*start_at_funct)( + next_range->fcr_infile, next_range->fcr_linenum ); + + next_range = next_range->fcr_next; + } + } + } + } +} + + +/* ************************************************************************** + * + * Function name: set_next_fcode + * Synopsis: Set the start of a new Range of FCode numbers + * + * Inputs: + * Parameters: + * new_fcode Start of the new range of FCodes + * Global Variables: + * nextfcode The next FCode-number to be assigned + * iname Name of current input file + * lineno Line Number within current input file + * Local Static Variables: + * ranges_exist TRUE if FCode Ranges have been created + * range_start First FCode in the current (first + * and only) range + * range_end Last FCode in only range; 0 if none. + * current_fc_range Pointer to the current Range if there + * are more than one. + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * nextfcode Set to the start of the new range + * Local Static Variables: + * ranges_exist May be set to TRUE + * first_fc_range May be initialized + * current_fc_range May be initialized or moved + * first_fcr_infile May be updated, may be made NULL + * first_fcr_linenum May be updated, may be made irrelevant + * range_start May be set to start of the new range + * or rendered irrelevant + * range_end Reset to 0 (by reset_fcode_ranges() ) + * changes_listed Reset to FALSE + * Memory Allocated + * For new Range data structure; for copy of iname + * When Freed? + * By reset_fcode_ranges() + * + * Error Detection: + * Not here. + * The calling routine will detect and report attempts to set an + * illegal new range. + * Overlap with earlier Ranges will be detected and reported when + * the FCode is actually Assigned. + * + * Process Explanation: + * The calling routine will not call this routine with a new starting + * FCode that is not legal per the Standard. + * It may call with a new starting FCode that is equal to nextfcode + * If no Ranges exist yet, and the new starting FCode is equal to + * the current value of nextfcode , this is a continuation of + * the first and only range; do not change the file name or line + * number; just go away. + * If no Ranges exist yet, and no FCode assignments have been made + * in the current range, then this is a new start for the first + * and only range; detect the latter condition by range_end == 0 + * Call the reset_fcode_ranges() routine to update the file name + * and line number, then update the remaining variables for the + * current (first and only) range, and you are done here. + * If no Ranges exist yet, and if FCode assignments _have_ been made + * in the current (first and only) range, create a data structure + * for the first (and now no longer only) Range and point both + * the first_fc_range and current_fc_range pointers at it. + * Set the ranges_exist flag to TRUE. + * If Ranges exist, whether from being newly-created, above, or from + * earlier, create a data structure for the new Current Range + * and move the current_fc_range pointer to point at it. If + * the new starting FCode is equal to nextfcode we still want + * to create a new Range that will be listed separately. + * If no assignments were made within the Current Range, we will not + * overwrite or delete it; it will be listed at the appropriate + * time, and will be harmless in the overlap test. + * + * Extraneous Remarks: + * We will trade off the strict rules of structured code here, + * in exchange for ease of coding. + * + **************************************************************************** */ + +void set_next_fcode( u16 new_fcode) +{ + if ( INVERSE( ranges_exist) ) + { /* The current range is the first and only. */ + + if ( new_fcode == nextfcode ) + { + /* Do nothing here */ + return; + } + + if ( range_end == 0 ) + { /* No FCode assignments have been made in the current range */ + /* This is still the first and only range. */ + + reset_fcode_ranges(); /* Update file name and line number */ + range_start = new_fcode; + nextfcode = new_fcode; + + /* We are done here */ + return; + + }else{ /* Create the data structure for the first Range */ + first_fc_range = safe_malloc( sizeof( fcode_range_t), + "creating first FCode Range" ); + first_fc_range->fcr_start = range_start; + first_fc_range->fcr_end = range_end; + first_fc_range->fcr_infile = first_fcr_infile; + first_fc_range->fcr_linenum = first_fcr_linenum; + first_fc_range->fcr_not_lapped = TRUE; + first_fc_range->fcr_next = NULL; + + first_fcr_infile = NULL; + first_fcr_linenum = 0; + range_start = FCODE_START; + range_end = 0; + + current_fc_range = first_fc_range; + + ranges_exist = TRUE; + } + } + + /* Previous Ranges exist now for sure! */ + current_fc_range->fcr_next = safe_malloc( sizeof( fcode_range_t), + "creating new FCode Range" ); + current_fc_range = current_fc_range->fcr_next; + + nextfcode = new_fcode; + current_fc_range->fcr_start = nextfcode; + current_fc_range->fcr_end = 0; + /* Will be filled in by first assignment */ + current_fc_range->fcr_infile = strdup( iname); + current_fc_range->fcr_linenum = lineno; + current_fc_range->fcr_not_lapped = TRUE; + current_fc_range->fcr_next = NULL; + + changes_listed = FALSE; +} + + +/* ************************************************************************** + * + * Function name: find_overlap + * Synopsis: Compare the FCode under test against existing + * FCode Ranges and return a pointer to the + * Range against which it overlaps, if any. + * + * Inputs: + * Parameters: + * test_fcode FCode to be tested + * Global Variables: + * + * Local Static Variables: + * ranges_exist If not TRUE, no need to test + * first_fc_range Start of Ranges to test + * current_fc_range Do not test Current Range + * + * Outputs: + * Returned Value: Pointer to FCode Range in which an + * overlap exists, or NULL if none. + * + * Error Detection: + * The calling routine will treat any findings as it deems appropriate. + * + * Process Explanation: + * A Range within which no assignments were made will never "hit" + * the overlap test because its fcr_end field will be zero + * and its fcr_start field will be non-zero; there's no + * number that will be "between" them! + * + **************************************************************************** */ + +static fcode_range_t *find_overlap( u16 test_fcode) +{ + fcode_range_t *retval = NULL; + if ( ranges_exist ) + { + fcode_range_t *test_range = first_fc_range; + while ( test_range != current_fc_range ) + { + if ( ( test_fcode <= test_range->fcr_end ) && + ( test_fcode >= test_range->fcr_start ) ) + { + retval = test_range; + break; + } + test_range = test_range->fcr_next; + } + } + + return( retval); +} + + +/* ************************************************************************** + * + * Function name: assigning_fcode + * Synopsis: Commit the next FCode number to be assigned; + * test for out-of-bounds, overlap, etc. errors. + * + * Inputs: + * Parameters: + * + * Global Variables: + * nextfcode + * Local Static Variables: + * ranges_exist TRUE if FCode Ranges have been created + * first_fc_range First entry in linked list of Ranges. + * current_fc_range List entry for Current Range. + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * Local Static Variables: + * changes_listed Reset to FALSE + * One of these two will be set to nextfcode + * range_end ... if ranges_exist is FALSE + * current_fc_range->fcr_end ... if ranges_exist is TRUE + * + * Error Detection: + * FATAL if the value of nextfcode is larger than the legal + * maximum for an FCode + * ERROR if the value of nextfcode falls within one of the + * existing Ranges (other than the current one, of course) + * + **************************************************************************** */ + +void assigning_fcode( void) +{ + if ( nextfcode > FCODE_LIMIT ) + { + /* Let's give a last summarization before we crap out */ + tokenization_error( INFO, ""); + list_fcode_ranges( FALSE); + + tokenization_error( FATAL, + "Too many definitions. " + "Assigned FCode exceeds limit " + "specified by IEEE-1275."); + /* + * No need to return() from here. + * FATAL error exits program. + */ + } + + changes_listed = FALSE; + + if ( INVERSE(ranges_exist) ) + { /* No Overlap Error checking needed here. */ + range_end = nextfcode; + }else{ + current_fc_range->fcr_end = nextfcode; + + /* Detect and report Overlap Error only once per Range */ + if ( current_fc_range->fcr_not_lapped ) + { + fcode_range_t *found_lap = find_overlap( nextfcode); + if ( found_lap != NULL ) + { + tokenization_error( TKERROR, + "Assigning FCode of 0x%x, " + "which overlaps the range", nextfcode); + started_at( found_lap->fcr_infile, found_lap->fcr_linenum); + + current_fc_range->fcr_not_lapped = FALSE; + } + } + } + +} + + +/* ************************************************************************** + * + * Function name: bump_fcode + * Synopsis: Increment the next assignable FCode number + * prior to the next assignment. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * nextfcode The next FCode-number to be assigned + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * nextfcode Incremented + * + * Extraneous Remarks: + * This looks like a no-brainer now, but if we ever need this + * function to perform any more sophisticated background + * activity, we can limit the scope of our modifications + * to this routine. + * + **************************************************************************** */ + +void bump_fcode( void) +{ + nextfcode++; +}
Added: fcode-utils/toke/nextfcode.h =================================================================== --- fcode-utils/toke/nextfcode.h (rev 0) +++ fcode-utils/toke/nextfcode.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,80 @@ +#ifndef _TOKE_NEXTFCODE_H +#define _TOKE_NEXTFCODE_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Function Prototypes for Managing FCode Assignment Pointer + * and for Detection of Overlapping-FCode Error in Tokenizer + * + * (C) Copyright 2006 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +#include "types.h" + + +/* ************************************************************************** * + * + * Global Variables Exported + * + **************************************************************************** */ + +extern u16 nextfcode; /* The next FCode-number to be assigned */ + + +/* ************************************************************************** * + * + * Function Prototypes / Functions Exported: + * + **************************************************************************** */ + +void reset_fcode_ranges( void); +void list_fcode_ranges( bool final_tally); +void set_next_fcode( u16 new_fcode); +void assigning_fcode( void); +void bump_fcode( void); + +/* ************************************************************************** + * + * Macros: + * + * FCODE_START Standard-specified starting number for + * user-generated FCodes. + * + * FCODE_LIMIT Standard-specified maximum number for + * FCodes of any origin. + * + * I know these are not likely to change, but I still feel better + * making them named symbols, just on General Principles... + * + **************************************************************************** */ + +#define FCODE_START 0x0800 +#define FCODE_LIMIT 0x0fff + +#endif /* _TOKE_NEXTFCODE_H */
Added: fcode-utils/toke/parselocals.c =================================================================== --- fcode-utils/toke/parselocals.c (rev 0) +++ fcode-utils/toke/parselocals.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,944 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Parsing functions for IBM-style Local Values + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Functions Exported: + * declare_locals Pick up the Locals' names after the { + * handle_local Insert the code to access a Local + * exists_as_local Confirm whether a name is in the Locals vocab + * assign_local Process the "Assign to a Local" operator ( -> ) + * finish_locals Insert the code for exiting a routine + * that uses locals + * forget_locals Remove the locals' names from the search + * + **************************************************************************** */ + +/* ************************************************************************** + * + * These are the names of the three routines that will be invoked + * when Locals are used. Their definitions exist in a separate + * Local Values Support FCode source-file that must be FLOADed + * into the user's tokenization source. + * + **************************************************************************** */ + +/* Note that the enclosing curly-braces are part of the name */ +static const char* push_locals = "{push-locals}"; /* ( #ilocals #ulocals -- ) */ +static const char* pop_locals = "{pop-locals}"; /* ( #locals -- ) */ +static const char* local_addr = "_{local}"; /* ( local# -- addr ) */ + +/* Switchable Fetch or Store operator to apply to local_addr. */ +static const char* local_op = "@"; /* Initially Fetch */ + + +/* ************************************************************************** + * + * Revision History: + * Updated Wed, 13 Jul 2005 by David L. Paktor + * Command-line control for: + * Support for Locals in general + * Whether to accept the "legacy" separator (semicolon) + * Whether to issue a message for the "legacy" separator + * Updated Tue, 10 Jan 2006 by David L. Paktor + * Convert to tic_hdr_t type vocabulary. + * + **************************************************************************** */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "ticvocab.h" +#include "dictionary.h" +#include "scanner.h" +#include "parselocals.h" +#include "errhandler.h" +#include "clflags.h" +#include "stream.h" +#include "devnode.h" +#include "flowcontrol.h" + +/* ************************************************************************** + * + * Global Variables Imported + * statbuf + * pc + * opc + * incolon + * lastcolon + * ibm_locals_legacy_separator Accept ; as the "legacy" separator + * ibm_legacy_separator_message Issue a message for "legacy" sep'r + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Internal Static Variables + * local_names Vocabulary for new local-names + * num_ilocals Number of initialized local variables + * num_ulocals Number of uninitialized local variables + * localno Running Local-Number to be assigned + * eval_buf Internally-generated string to be parsed + * l_d_lineno Locals Declaration Line Number + * + **************************************************************************** */ + +static tic_hdr_t *local_names = NULL; +static int num_ilocals = 0; +static int num_ulocals = 0; +static int localno = 0; +static char eval_buf[64]; +static unsigned int l_d_lineno; /* For Error Messages */ + +/* ************************************************************************** + * + * The local_names vocabulary follows the same tic_hdr_t structure + * as the dictionaries of tokens, special-functions, etcetera. Its + * "parameter field" is an integer, used to store the Local's number, + * an its "function" is invoke_local(), defined further below. + * + * The vocabulary is initially empty, so there's no need for an "init" + * or a "reset" routine. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Function name: int_to_str + * Synopsis: Convert an integer into a compilable string. + * Suport routine for invoke_local(). + * + * Inputs: + * Parameters: + * num The number to convert + * bufr The buffer into which to place it. + * Needn't be very long: + * five at least, ten is enough + * + * Outputs: + * Returned Value: Pointer to bufr + * bufr Contents are changed. + * + * Process Explanation: + * Convert into decimal. If the number is greater than 8, + * prepend a d# in front of it. If less, don't. + * We specifically want to avoid a d# in front of + * the numbers 0 1 2 and 3, which are also named constants; + * there's no need to treat 'em as literals. + * The calling routine will be responsible for allocating + * and freeing the buffer. + * + * Extraneous Remarks: + * Too bad atoi() isn't a Standard C function; I could convert + * using the current base, and be guaranteed that it would be + * interpreted in the same base. + * Instead, I have to fiddle-faddle around with d# ... + * + **************************************************************************** */ + +static char *int_to_str( int num, char *bufr) +{ + char* prefix = "d# "; + if ( num < 8 ) prefix = ""; + sprintf(bufr,"%s%d",prefix, num); + return (bufr); +} + + + +/* ************************************************************************** + * + * Function name: invoke_local + * Synopsis: Compile-in the code to access the Local whose + * assigned Number is given. This function is + * entered into the Local-Names Vocabulary entry. + * + * Inputs: + * Parameters: + * pfield The Vocabulary entry's Param field, taken + * from the Assigned Number of the Local. + * Local Static Variables: + * local_addr Name of _{local} routine, invoked + * when a Local is used + * local_op Fetch or Store operator to apply. + * + * Outputs: + * Returned Value: None + * Local Static Variables: + * eval_buf Phrase constructed here; will become new + * Source Input Buffer, temporarily + * + * Error Detection: + * If the Local Values Support FCode source-file was not + * FLOADed into the user's tokenization source, then + * the function _{local} will be an "unknown name". + * + * Process Explanation: + * We are going to generate a string of the form: + * " #local _{local} OP" + * and pass it to the Parser for evaluation. + * The call to _{local} is preceded by its parameter, which is + * its Assigned Local-Number, and followed by the appropriate + * OPerator, which will be "Fetch" if the Local's name was + * invoked by itself, or "Store" if its invocation was made + * in conjuction with the -> operator. + * The string-buffer may be local, but it must be stable. + * + * Revision History: + * Updated Thu, 24 Mar 2005 by David L. Paktor + * Factored-out to permit lookup_local() to be a "pure" + * function that can be used for duplicate-name detection. + * Updated Tue, 10 Jan 2006 by David L. Paktor + * Accommodate conversion to tic_hdr_t type vocabulary. + * + **************************************************************************** */ + +static void invoke_local( tic_param_t pfield ) +{ + char local_num_buf[10]; + int loc_num = (int)pfield.deflt_elem; + + int_to_str(loc_num, local_num_buf); + sprintf( eval_buf, "%s %s %s", local_num_buf, local_addr, local_op ); + eval_string( eval_buf); + +} + + +/* ************************************************************************** + * + * Function name: locals_separator + * Synopsis: Test whether the given character is the separator + * between initted and uninitted Local Names. + * Optionally, allow Semi-Colon as a separator and issue + * an optional Advisory. + * + * Inputs: + * Parameters: + * subj One-character "subject" of the test + * Global Variables: + * ibm_locals_legacy_separator Allow Semi-Colon as a separator? + * ibm_legacy_separator_message Issue an Advisory message? + * + * Outputs: + * Returned Value: TRUE if the character is the separator + * + * Error Detection: + * If the separator is Semi-Colon, and ibm_locals_legacy_separator + * is TRUE, then if ibm_legacy_separator_message is TRUE, + * issue an Advisory message. + * If the flag to allow Semi-Colon is FALSE, then simply do not + * acknowledge a valid separator. Other routines will report + * an erroneous attempt to use an already-defined symbol. + * + * Revision History: + * Updated Wed, 13 Jul 2005 by David L. Paktor + * Bring the questions of whether to accept semicolon as a separator + * -- and whether to issue a message for it -- under the control + * of external flags (eventually set by command-line switches), + * rather than being hard-compiled. + * + * Extraneous Remarks: + * In the interest of avoiding too deeply nested "IF"s, I will + * not be adhering strictly to the rules of structure. + * + **************************************************************************** */ + +static bool locals_separator( char subj ) +{ + bool retval = FALSE; + /* Is it the preferred (i.e., non-legacy) separator? */ + if ( subj == '|' ) + { + retval = TRUE; + return ( retval ); + } + + if ( ibm_locals_legacy_separator ) + { + if ( subj == ';' ) + { + retval = TRUE; + if ( ibm_legacy_separator_message ) + { + tokenization_error ( WARNING , "Semicolon as separator in " + "Locals declaration is deprecated in favor of '|'\n"); + } + } + } + return ( retval ); +} + +/* ************************************************************************** + * + * Function name: add_local + * Synopsis: Given a pointer to a name and a number, enter + * them into the vocabulary for new Local names. + * + * Inputs: + * Parameters: + * lnum The assigned number + * lname Pointer to the name + * Local Static Variables: + * local_names The vocabulary for new Local names + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * local_names Enter the new Local's name and number. + * Memory Allocated: + * A place into which the name will be copied + * When Freed? + * When forget_locals() routine frees up all memory + * allocations in the "Local Names" Vocabulary. + * + * Process Explanation: + * Allocate a stable place in memory for the name, via strdup(). + * The entry's "action" will be the invoke_local() function, + * defined above. The "parameter field" size is zero. + * + **************************************************************************** */ + +static void add_local( TIC_P_DEFLT_TYPE lnum, char *lname) +{ + char *lnamecopy ; + + lnamecopy = strdup( lname); + add_tic_entry( lnamecopy, invoke_local, lnum, + LOCAL_VAL, 0, NULL, &local_names ); + trace_creation( LOCAL_VAL, lname); +} + + +/* ************************************************************************** + * + * Function name: gather_locals + * Synopsis: Collect Local names, for both initted and uninitted + * Return an indication as to whether to continue + * gathering Locals' names + * + * Inputs: + * Parameters: + * initted TRUE if we are gathering initted Local names. + * counter Pointer to variable that's counting names. + * Global Variables: + * statbuf The symbol just retrieved from the input stream. + * Local Static Variables: + * localno Running Local-Number to be assigned + * l_d_lineno Line # of Locals Declar'n start (for err mssg) + * + * Outputs: + * Returned Value: TRUE = Ended with initted/uninitted separator + * Local Static Variables: + * localno Incremented for each Local name declared + * local_names Enter the new locals' names into the Vocabulary. + * Numeric field is assigned local number. + * + * Error Detection: + * A Local-name that duplicates an existing name is an ERROR. + * Especially if that name is <Semicolon> and the flag + * called ibm_locals_legacy_separator was not set. + * Issue an Error if close-curly-brace terminator is not found, + * or if imbedded comment is not terminated, before end of file. + * If the Separator is found a second-or-more time, issue an Error + * and continue collecting uninitted Local names. + * + * Revision History: + * Updated Thu, 24 Mar 2005 by David L. Paktor + * Allow comments to be interspersed among the declarations. + * Error-check duplicate Local-name. + * Updated Wed, 30 Mar 2005 by David L. Paktor + * Warning when name length exceeds ANSI-specified max (31 chars). + * Updated Thu, 07 Jul 2005 by David L. Paktor + * Protect against PC pointer-overrun due to unterminated + * comment or declaration. + * Error-check for numbers. + * No name-length check; doesn't go into FCode anyway. + * + **************************************************************************** */ + +static bool gather_locals( bool initted, int *counter ) +{ + signed long wlen; + bool retval = FALSE; + + while ( TRUE ) + { + wlen = get_word(); + + if ( wlen <= 0 ) + { + warn_unterm( TKERROR, "Local-Values Declaration", l_d_lineno); + break; + } + + /* Allow comments to be interspersed among the declarations. */ + if ( filter_comments( statbuf) ) + { + /* Unterminated and Multi-line checking already handled */ + continue; + } + /* Is this the terminator or the separator? */ + if ( wlen == 1 ) /* Maybe */ + { + /* Check for separator */ + if (locals_separator( statbuf[0] ) ) + { + /* If gathering initted Local names, separator is legit */ + if ( initted ) + { + retval = TRUE; + break; + }else{ + tokenization_error ( TKERROR, + "Excess separator -- %s -- found " + "in Local-Values declaration", statbuf); + in_last_colon(); + continue; + } + } + /* Haven't found the separator. Check for the terminator */ + if ( statbuf[0] == '}' ) + { + break; + } + } + /* It was not the terminator or the separator */ + { + long tmp; + char *where_pt1; char *where_pt2; + /* Error-check for duplicated names */ + if ( word_exists ( statbuf, &where_pt1, &where_pt2 ) ) + { + tokenization_error ( TKERROR, "Cannot declare %s " + "as a Local-Name; it's already defined %s%s", + statbuf, where_pt1, where_pt2 ); + show_node_start(); + continue; + } + /* Error-check for numbers. */ + if ( get_number(&tmp) ) + { + tokenization_error ( TKERROR, "Cannot declare %s " + "as a Local-Name; it's a number.\n", statbuf ); + continue; + } + + /* We've got a valid new local-name */ + /* Don't need to check name length; it won't go into the FCode */ + + /* Increment our counting-v'ble */ + *counter += 1; + + /* Define our new local-name in the Locals' vocabulary */ + add_local( localno, statbuf ); + + /* Bump the running Local-Number */ + localno++; + + } + } + return ( retval ); +} + + +/* ************************************************************************** + * + * Function name: activate_locals + * Synopsis: Compile-in the call to {push-locals} that + * the new definition under construction will need, + * now that the Locals have been declared. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * num_ilocals First argument to {push-locals} + * num_ulocals Second argument to {push-locals} + * push_locals Name of {push-locals} routine. + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * eval_buf Phrase constructed here; will become + * new Source Input Buffer, temporarily + * + * Error Detection: + * If the Local Values Support FCode source-file was not + * FLOADed into the user's tokenization source, then + * the function {push-locals} will be an "unknown name". + * + * Process Explanation: + * We are going to generate a string of the form: + * " #ilocals #ulocals {push-locals}" + * and pass it to the Parser for evaluation. + * The string-buffer may be local, but it must be stable. + * + * Question under consideration.: + * Do we want to check if {push-locals} is an unknown name, + * and give the user a hint of what's needed? And, if so, + * do we do it only once, or every time? + * + **************************************************************************** */ + +static void activate_locals( void ) +{ + char ilocals_buf[10]; + char ulocals_buf[10]; + + int_to_str(num_ilocals, ilocals_buf ); + int_to_str(num_ulocals, ulocals_buf ); + sprintf( eval_buf,"%s %s %s",ilocals_buf, ulocals_buf, push_locals); + eval_string( eval_buf); +} + +/* ************************************************************************** + * + * Function name: error_check_locals + * Synopsis: Indicate whether Locals declaration is erronious + * + * Inputs: + * Parameters: NONE + * Global Variables: + * incolon TRUE if colon def'n is in effect. + * opc FCode Output buffer Position Counter + * lastcolon Value of opc when Colon def'n was started + * + * Outputs: + * Returned Value: TRUE if found errors severe enough to + * preclude further processing of Decl'n + * + * Errors Detected: + * Colon definition not in effect. ERROR and return TRUE. + * Locals declaration inside body of colon-definition (i.e., after + * something has been compiled-in to it) is potentially risky, + * but may be valid, and is a part of legacy practice. It + * will not be treated as an outright ERROR, but it will + * generate a WARNING... + * Multiple locals declarations inside a single colon-definition + * are completely disallowed. ERROR and return TRUE. + * Locals declaration inside a control-structure is prohibited. + * Generate an ERROR, but return FALSE to allow processing + * of the declaration to continue. + * + **************************************************************************** */ + +/* The value of lastcolon when Locals Declaration is made. + * If it's the same, that detects multiple locals declaration attempt. + */ +static int last_local_colon = 0; + +static bool error_check_locals ( void ) +{ + bool retval = FALSE; + + if ( ! incolon ) + { + tokenization_error ( TKERROR, + "Can only declare Locals inside of a Colon-definition.\n"); + retval = TRUE; + } else { + if ( last_local_colon == lastcolon ) + { + tokenization_error ( TKERROR, "Excess Locals Declaration"); + in_last_colon(); + retval = TRUE; + }else{ + last_local_colon = lastcolon; + if ( opc > lastcolon ) + { + tokenization_error ( WARNING, + "Declaring Locals after the body of a Colon-definition " + "has begun is not recommended.\n"); + } + announce_control_structs( TKERROR, + "Local-Values Declaration encountered", + last_colon_abs_token_no); + } + } + return ( retval ); +} + +/* ************************************************************************** + * + * Function name: declare_locals + * Synopsis: Process (or Ignore) the Declaration of Locals, + * upon encountering Curly-brace ( { ) + * + * Inputs: + * Parameters: + * ignoring TRUE if "Ignoring" + * Global Variables: + * statbuf Next symbol to process. + * lineno Current Line Number in Input File + * report_multiline FALSE to suspend multiline warning + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * statbuf Advanced to end of Locals Declaration. + * pc Bumped past the close-curly-brace + * Local Static Variables: + * localno Init'd, then updated by gather_locals() + * l_d_lineno Line Number of start of Locals Declaration + * + * Error Detection: + * See error_check_locals() + * After Error messages, will bypass further processing until the + * terminating close-curly-brace of a Locals Declaration. + * If the terminating close-curly-brace missing under those + * circumstances, issue an Error + * If terminating close-curly-brace is missing when the Locals + * Declaration is otherwise valid, gather_locals() will + * detect and report the Error. + * Warning if multiline declaration. Because embedded comments + * may also supppress the multiline warning, we need to save + * and restore the state of the report_multiline switch... + * + **************************************************************************** */ + +void declare_locals ( bool ignoring) +{ + num_ilocals = 0; + num_ulocals = 0; + localno = 0; + + l_d_lineno = lineno; + bool sav_rep_mul_lin = report_multiline; + report_multiline = TRUE; + + if ( ignoring || error_check_locals() ) + { + if ( skip_until ( '}' ) ) + { + warn_unterm(TKERROR, + "misplaced Local-Values Declaration", l_d_lineno); + }else{ + pc++ ; /* Get past the close-curly-brace */ + } + }else{ + if (gather_locals( TRUE, &num_ilocals ) ) + { + gather_locals( FALSE, &num_ulocals ); + } + } + + /* If PC has reached the END, gather_locals() will + * have already issued an "unterminated" Error; + * a "multiline" warning would be redundant + * repetitive, unnecessary, excessive, unaesthetic + * and -- did I already mention? -- redundant. + */ + if ( pc < end ) + { + report_multiline = sav_rep_mul_lin; + warn_if_multiline( "Local-Values declaration", l_d_lineno); + } + + /* Don't do anything if no Locals were declared */ + /* This could happen if the { } field is empty */ + if ( localno != 0 ) + { + activate_locals(); + } +} + +/* ************************************************************************** + * + * Function name: handle_local + * Synopsis: Process the given name as a Local Name; + * indicate if it was a valid Local Name. + * + * Inputs: + * Parameters: + * lname The "Local" name for which to look + * Local Static Variables: + * local_names The vocabulary for Local names + * + * Outputs: + * Returned Value: TRUE if the name is a valid "Local Name" + * + **************************************************************************** */ + +static bool handle_local( char *lname) +{ + bool retval = handle_tic_vocab( lname, local_names ); + return ( retval ) ; +} + +/* ************************************************************************** + * + * Function name: lookup_local + * Synopsis: Return a pointer to the data-structure of the named + * word, only if it was a valid Local Name. + * + * Inputs: + * Parameters: + * lname The "Local" name for which to look + * Local Static Variables: + * local_names The vocabulary for Local names + * + * Outputs: + * Returned Value: Pointer to the data-structure, or + * NULL if not found. + * + **************************************************************************** */ + +tic_hdr_t *lookup_local( char *lname) +{ + tic_hdr_t *retval = lookup_tic_entry( lname, local_names ); + return ( retval ) ; +} + + +/* ************************************************************************** + * + * Function name: create_local_alias + * Synopsis: Create an alias in the "Local Names" Vocabulary + * + * Associated FORTH word: ALIAS + * + * Inputs: + * Parameters: + * old_name Name of existing entry + * new_name New name for which to create an entry + * + * Outputs: + * Returned Value: TRUE if old_name found in "Locals" vocab + * Global Variables: + * local_names Will point to the new entry + * Memory Allocated: + * Memory for the new entry, by the support routine + * When Freed? + * When forget_locals() routine frees up all memory + * allocations in the "Local Names" Vocabulary. + * + **************************************************************************** */ + +bool create_local_alias(char *new_name, char *old_name) +{ + bool retval = create_tic_alias( new_name, old_name, &local_names ); + return ( retval ); +} + +/* ************************************************************************** + * + * Function name: exists_as_local + * Synopsis: Simply confirm whether a given name exists + * within the Locals vocabulary. + * + * Inputs: + * Parameters: + * stat_name Name to look up + * + * Outputs: + * Returned Value: TRUE if stat_name was a Local + * + **************************************************************************** */ + +bool exists_as_local( char *stat_name ) +{ + bool retval = exists_in_tic_vocab(stat_name, local_names ); + return ( retval ); +} + + +/* ************************************************************************** + * + * Function name: assign_local + * Synopsis: Process the "Assign to a Local" operator ( -> ) + * + * Inputs: + * Parameters: NONE + * Global Variables: + * statbuf Next symbol to process + * pc Input-source Scanning pointer + * lineno Input-source Line Number. Used for Err Mssg. + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * statbuf Advanced to next symbol + * pc Advanced; may be unchanged if error. + * lineno Advanced; may be unchanged if error + * local_op Will be set to Store and then reset to Fetch. + * Global Behavior: + * Construct a phrase and pass it to the Tokenizer. + * + * Error Detection: + * If next symbol is not a Local name, print ERROR message + * and restore pc so that the next symbol will be + * processed by ordinary means. + * In the extremely unlikely case that -> is last symbol in + * the source-file, report an ERROR. + * + * Process Explanation: + * Save the PC. + * Get the next symbol; check for end-of-file. + * Set Local Operator ( local_op ) to "Store", to prepare to apply it. + * Pass the next symbol to handle_local() . + * If handle_local() failed to find the name, you have + * detected an error; restore pc . + * Otherwise, you have invoked the local and applied "Store" to it. + * At the end, reset local_op to "Fetch". + * + **************************************************************************** */ + +void assign_local ( void ) +{ + signed long wlen; + bool is_okay; + u8 *savd_pc = pc; + unsigned int savd_lineno = lineno; + + wlen = get_word(); + + if ( wlen <= 0 ) + { + warn_unterm(TKERROR, "Locals Assignment", lineno); + return; + } + + local_op = "!"; /* Set to Store */ + + is_okay = handle_local( statbuf); + if( INVERSE(is_okay) ) + { + tokenization_error ( TKERROR, + "Cannot apply -> to %s, only to a declared Local.\n", statbuf ); + pc = savd_pc; + lineno = savd_lineno; + } + local_op = "@"; /* Reset to Fetch */ +} + +/* ************************************************************************** + * + * Function name: finish_locals + * Synopsis: Compile-in the call to {pop-locals} that the + * new definition under construction will need + * when it's about to complete execution, i.e., + * before an EXIT or a SemiColon. But only if the + * current definition under construction is using Locals. + * + * Inputs: + * Parameters: NONE + * + * Local Static Variables: + * localno Total # of Locals. + * Both a param to {pop-locals} + * and an indicator that Locals are in use. + * pop_locals Name of {pop-locals} routine. + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * eval_buf Phrase constructed here; will become new + * Source Input Buffer, temporarily + * + * Error Detection: + * If the Local Values Support FCode source-file was not + * FLOADed into the user's tokenization source, then + * the function {pop-locals} will be an "unknown name". + * + * Revision History: + * Updated Fri, 24 Feb 2006 by David L. Paktor + * The eval_string() routine no longer calls its own + * instance of tokenize() . In order to make a + * smooth transition between the processing the + * internally-generated string and the resumption + * of processing the source file, it simply sets + * up the string to be processed next. + * In this case, however, we need to have the string + * processed right away, as the calling routine + * emits a token that must follow those generated + * by this. + * Fortunately, we know the exact contents of the string. + * Two calls to tokenize_one_word() will satisfy the + * requirement. + * + **************************************************************************** */ + +void finish_locals ( void ) +{ + /* Don't do anything if Locals are not in use */ + if ( localno > 0 ) + { + char nlocals_buf[10]; + + int_to_str(localno, nlocals_buf ); + sprintf( eval_buf,"%s %s",nlocals_buf, pop_locals); + eval_string( eval_buf); + tokenize_one_word( get_word() ); + tokenize_one_word( get_word() ); + } +} + +/* ************************************************************************** + * + * Function name: forget_locals + * Synopsis: Remove the Locals' names from the special Vocabulary + * free-up their allocated memory, and reset the Locals' + * counters (which are also the indication that Locals + * are in use). This is done at the time a SemiColon + * is processed. But only if the current definition + * under construction is using Locals. + * + * Inputs: + * Parameters: NONE + * Local Static Variables: + * local_names The vocabulary for new Local names + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * local_names Emptied and pointing at NULL. + * num_ilocals Reset to zero + * num_ulocals ditto + * localno ditto + * Memory Freed + * All memory allocations in the "Local Names" Vocabulary. + * + **************************************************************************** */ + +void forget_locals ( void ) +{ + /* Don't do anything if Locals are not in use */ + if ( localno != 0 ) + { + reset_tic_vocab( &local_names, NULL ) ; + + num_ilocals = 0; + num_ulocals = 0; + localno = 0; + } +}
Added: fcode-utils/toke/parselocals.h =================================================================== --- fcode-utils/toke/parselocals.h (rev 0) +++ fcode-utils/toke/parselocals.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,48 @@ +#ifndef _TOKE_LOCALX_H +#define _TOKE_LOCALX_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Function Prototypes / External definitions for Parsing + * functions for IBM-style Local Values in Tokenizer + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +#include "ticvocab.h" + +void declare_locals ( bool ignoring); +tic_hdr_t *lookup_local( char *lname); +bool exists_as_local( char *stat_name ); +bool create_local_alias(char *new_name, char *old_name); +void assign_local ( void ); +void finish_locals ( void ); +void forget_locals ( void ); + +#endif /* _TOKE_LOCALX_H */
Modified: fcode-utils/toke/scanner.c =================================================================== --- fcode-utils/toke/scanner.c 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/scanner.c 2006-08-18 12:47:12 UTC (rev 76) @@ -24,6 +24,12 @@ * */
+/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -34,74 +40,596 @@ #include <time.h> #include <ctype.h>
-#include "toke.h" +#include "macros.h" #include "stack.h" #include "stream.h" #include "emit.h" +#include "toke.h" #include "dictionary.h" +#include "vocabfuncts.h" +#include "scanner.h" +#include "errhandler.h" +#include "tokzesc.h" +#include "conditl.h" +#include "flowcontrol.h" +#include "usersymbols.h" +#include "clflags.h" +#include "devnode.h" +#include "tracesyms.h" +#include "nextfcode.h"
-#define ERROR do { if (!noerrors) exit(-1); } while (0) +#include "parselocals.h"
-extern u8 *start, *pc, *end, *opc, *ostart; -extern int verbose, noerrors; +/* ************************************************************************** + * + * Some VERY IMPORTANT global variables follow + * + **************************************************************************** */
-u8 *statbuf=NULL; -u16 nextfcode; -u8 base=0x0a; +u8 *statbuf=NULL; /* The word just read from the input stream */ +u8 base=0x0a; /* The numeric-interpretation base */
-/* header pointers */ -u8 *fcode_hdr=NULL; -u8 *pci_hdr=NULL; - /* pci data */ bool pci_is_last_image=TRUE; -bool pci_want_header=FALSE; -u16 pci_revision=0x0001; +u16 pci_image_rev=0x0001; /* Vendor's Image, NOT PCI Data Structure Rev */ u16 pci_vpd=0x0000;
-bool offs16=TRUE; -static bool intok=FALSE, incolon=FALSE; -bool haveend=FALSE;
-static u8 *skipws(u8 *str) +/* Having to do with the state of the tokenization */ +bool offs16 = TRUE; /* We are using 16-bit branch- (etc) -offsets */ +bool in_tokz_esc = FALSE; /* TRUE if in "Tokenizer Escape" mode */ +bool incolon = FALSE; /* TRUE if inside a colon definition */ +bool haveend = FALSE; /* TRUE if the "end" code was read. */ +int do_loop_depth = 0; /* How deep we are inside DO ... LOOP variants */ + +/* Used for error-checking of IBM-style Locals */ +int lastcolon; /* Location in output stream of latest colon-definition. */ + +/* Used for error reporting */ +char *last_colon_defname = NULL; /* Name of last colon-definition */ +char *last_colon_filename = NULL; /* File where last colon-def'n made */ +unsigned int last_colon_lineno; /* Line number of last colon-def'n */ +bool report_multiline = TRUE; /* False to suspend multiline warning */ +unsigned int last_colon_abs_token_no; + +/* ************************************************************************** + * Local variables + **************************************************************************** */ +static u16 last_colon_fcode; /* FCode-number assigned to last colon-def'n */ + /* Used for RECURSE */ + +static bool do_not_overload = TRUE ; /* False to suspend dup-name-test */ +static bool got_until_eof = FALSE ; /* TRUE to signal "unterminated" */ + +static unsigned int last_colon_do_depth = 0; + +/* State of headered-ness for name-creation */ +typedef enum headeredness_t { + FLAG_HEADERLESS , + FLAG_EXTERNAL , + FLAG_HEADERS } headeredness ; +static headeredness hdr_flag = FLAG_HEADERLESS ; /* Init'l default state */ + +/* Local variables having to do with: */ +/* ... the state of the tokenization */ +static bool is_instance = FALSE; /* Is "instance" is in effect? */ +static char *instance_filename = NULL; /* File where "instance" invoked */ +static unsigned int instance_lineno; /* Line number of "instance" */ +static bool fcode_started = FALSE ; /* Only 1 fcode_starter per block. */ +static bool first_fc_starter = TRUE; /* Only once per tokenization... */ + +/* ... with the state of the input stream, */ +static bool need_to_pop_source; + +/* ... with the use of the return stack, */ +static int ret_stk_depth = 0; /* Return-Stack-Usage-Depth counter */ + +/* ... and with control of error-messaging. */ + /* Should a warning about a dangling "instance" + * be issued at the next device-node change? + */ +static bool dev_change_instance_warning = TRUE; + + /* Has a gap developed between "instance" and its application? */ +static bool instance_definer_gap = FALSE; + + /* Shared phrases */ +static char *in_tkz_esc_mode = "in Tokenizer-Escape mode.\n"; + + +/* ************************************************************************** + * + * Function name: skip_ws + * Synopsis: Advance the PC past all whitespace. + * Protect against pointer over-runs + * + * Inputs: + * Parameters: NONE + * Global Variables: + * pc Input-source Scanning pointer + * end End of input-source buffer + * + * Outputs: + * Returned Value: TRUE if PC reached END before non-blank char + * Global Variables: + * pc Advanced to first non-blank char, or to END + * lineno Incremented if encountered new-line along the way + * + * Error Detection: + * Return a TRUE if End of input-source buffer reached before + * non-blank character. Not necessarily an error; allow + * calling routine to decide... + * + **************************************************************************** */ + +static bool skip_ws(void) { - while (str && (*str=='\t' || *str==' ' || *str=='\n' )) { - if (*str=='\n') - lineno++; - str++; + bool retval = TRUE; + char ch_tmp; + + for ( ; pc < end; pc++ ) +{ + ch_tmp = *pc; + if ( (ch_tmp != '\t') && (ch_tmp != ' ') && (ch_tmp != '\n' ) ) + { + retval = FALSE; + break; } + if ( ch_tmp == '\n') lineno++; + } + return ( retval ); +} + +/* ************************************************************************** + * + * Function name: skip_until + * Synopsis: Advance the PC to the given character. + * Do not copy anything into statbuf. + * Protect against pointer over-runs + * + * Inputs: + * Parameters: + * lim_ch Limiting Character + * Global Variables: + * pc Input-source Scanning pointer + * end End of input-source buffer + * + * Outputs: + * Returned Value: TRUE if PC reached END before finding LIM_CH + * Global Variables: + * pc Advanced to first occurrence of LIM_CH, or to END + * lineno Incremented if encountered new-line along the way + * + * Error Detection: + * Return a TRUE if End of input-source buffer reached before + * desired character. Not necessarily an error; allow calling + * routine to decide... + * + **************************************************************************** */ + +bool skip_until( char lim_ch) +{ + bool retval = TRUE; + char ch_tmp; + + for ( ; pc < end; pc++ ) + { + ch_tmp = *pc; + if ( ch_tmp == lim_ch ) + { + retval = FALSE; + break; + } + if ( ch_tmp == '\n') lineno++; + } + return ( retval ); +} + + +/* ************************************************************************** + * + * Function name: get_until + * Synopsis: Return, in statbuf, the string from PC to the first + * occurrence of the given delimiter-character.. + * + * Inputs: + * Parameters: + * needle The given delimiter-character + * Global Variables: + * pc Input-source Scanning Pointer + * + * Outputs: + * Returned Value: Length of the string obtained + * Global Variables: + * statbuf The string obtained from the input stream; + * does not include the delimiter-character. + * pc Bumped past the delimiter-character, unless + * it's a new-line, in which case leave it + * to be handled by get_word() + * Local Static Variables: + * got_until_eof Pass this as a signal that the end of the + * buffer was reached before the delimiter; + * Testing whether PC has reached END is + * not a sufficient indication. + * + * Error Detection: + * If string overflows statbuf allocation, ERROR, and + * return "no string" (i.e., length = 0). + * Otherwise, if delimiter not found before eof, keep string. + * Protection against PC pointer-over-run past END is + * provided by skip_until() . Reaching END will be + * handled by calling routine; pass indication along + * via Local Static Variable. + * + * Process Explanation: + * Skip the delimiter-character from further input, unless it's a + * new-line which will be skipped anyway. Let skip_until() + * and get_word() handle incrementing line-number counters. + * If skip_until() indicated reaching end-of-file, don't bump PC + * + * Revision History: + * Updated Thu, 14 Jul 2005 by David L. Paktor + * More robust testing for when PC exceeds END + * Involved replacing firstchar() + * + **************************************************************************** */ - return str; +static signed long get_until(char needle) +{ + u8 *safe; + unsigned long len = 0; + + safe=pc; + + got_until_eof = skip_until(needle); + + len = pc - safe; + if (len >= GET_BUF_MAX ) + { + tokenization_error( TKERROR, + "get_until buffer overflow. Max is %d.\n", GET_BUF_MAX-1 ); + len = GET_BUF_MAX-1; }
-static u8 *firstchar(u8 needle, u8 *str) + memcpy(statbuf, safe, len); + statbuf[len]=0; + + if ( INVERSE(got_until_eof) ) { - while (str && *str!=needle) { - if (*str=='\n') - lineno++; - str++; + if ( needle != '\n' ) pc++; } + return len; +}
- return str; + +/* ************************************************************************** + * + * We are going to use a fairly sophisticated mechanism to + * make a smooth transition between processing the body + * of a Macro, a User-defined Symbol or an FLOADed file + * and the resumption of processing the source file, so + * that the end-of-file will only be seen at the end of + * the primary input file (the one from the command-line). + * This mechanism will be tied in with the get_word() routine + * + * We are going to define a private data-structure in which + * we will save the state of the current source file, + * and from which, of course, we will recover it. Its + * fields will be: + * A pointer to the next structure in the list. + * The saved values of START END and PC + * The saved values of INAME and LINENO + * A flag indicating that get-word should "pause" + * before popping the source-stream because + * the input file will be changing. + * A place from which to save and recover the state of + * whether we're testing for "Multi-line" strings; + * to prevent undeserved "Multi-line" warnings + * during Macro processing. + * A pointer to a "resumption" routine, to call + * when resuming processing the source file; + * the routine takes a pointer parameter + * and has no return value. The pointer + * may be NULL if no routine is needed. + * The pointer to pass as the parameter to the + * resumption routine. + * + **************************************************************************** */ + +typedef struct source_state + { + struct source_state *next; + u8 *old_start; + u8 *old_pc; + u8 *old_end; + char *old_iname; + unsigned int old_lineno; + bool pause_before_pop; + bool sav_rep_multlin; + void (*resump_func)(); + _PTR resump_param; + } source_state_t ; + +static source_state_t *saved_source = NULL; + + +/* ************************************************************************** + * + * Function name: push_source + * Synopsis: Save the state of the current source file, in the + * source_state data-structure LIFO linked-list. + * + * Inputs: + * Parameters: + * res_func Pointer to routine to call when resuming + * processing the saved source file. + * res_param Parameter to pass to res_func. + * Either or both pointers may be NULL. + * file_chg TRUE if input file is going to change. + * Global Variables: + * start Points to current input buffer + * end Points to end of current input buffer + * pc Input point in current buffer + * iname Name of current source file + * lineno Line number in current source file + * report_multiline Whether we're testing for "Multi-line" + * Local Static Variables: + * saved_source Pointer to the source_state data-structure + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * saved_source Points to new source_state entry + * Memory Allocated + * for the new source_state entry + * When Freed? + * When resuming processing the source file, by drop_source(). + * + * Process Explanation: + * The calling routine will establish the new input buffer via + * a call to init_inbuf() or the like. + * + **************************************************************************** */ + +void push_source( void (*res_func)(), _PTR res_parm, bool file_chg ) +{ + source_state_t *new_sav_src; + + new_sav_src = safe_malloc( sizeof(source_state_t), "pushing Source state"); + + new_sav_src->next = saved_source; + new_sav_src->old_start = start; + new_sav_src->old_pc = pc; + new_sav_src->old_end = end; + new_sav_src->old_iname = iname; + new_sav_src->old_lineno = lineno; + new_sav_src->pause_before_pop = file_chg; + new_sav_src->sav_rep_multlin = report_multiline; + new_sav_src->resump_func = res_func; + new_sav_src->resump_param = res_parm; + + saved_source = new_sav_src; }
-static unsigned long get_word(void) +/* ************************************************************************** + * + * Function name: drop_source + * Synopsis: Remove last saved state of source processing + * from the source_state LIFO linked-list, + * without (or after) restoring. + * + * Inputs: + * Parameters: NONE + * Local Static Variables: + * saved_source Pointer to the source_state data-structure + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * saved_source Points to previous source_state entry + * Memory Freed + * Saved source_state entry that was just "dropped" + * + * Error Detection: + * None. Called only when linked-list is known not to be at end. + * + **************************************************************************** */ + +static void drop_source( void) { + source_state_t *former_sav_src = saved_source; + + saved_source = saved_source->next ; + free( former_sav_src); +} + +/* ************************************************************************** + * + * Function name: pop_source + * Synopsis: Restore the state of source processing as it was + * last saved in the source_state linked-list. + * + * Inputs: + * Parameters: NONE + * Local Static Variables: + * saved_source Pointer to the source_state data-structure + * need_to_pop_source If TRUE, don't check before popping. + * + * Outputs: + * Returned Value: TRUE if reached end of linked-list + * Global Variables: + * start Points to restored input buffer + * end Points to end of restored input buffer + * pc Input point in restored buffer + * iname Name of restored source file + * lineno Line number in restored source file + * report_multiline Restored to saved value. + * Local Static Variables: + * saved_source Points to previous source_state entry + * need_to_pop_source TRUE if postponed popping till next time + * Memory Freed + * Saved source-state entry that was just "popped" + * + * Process Explanation: + * First check the need_to_pop_source flag. + * If it is set, we will clear it and go ahead and pop. + * If it is not set, we will check the pause_before_pop field + * of the top entry in the source_state linked-list. + * If the pause_before_pop field is set, we will set the + * need_to_pop_source flag and return. + * If it is not, we will go ahead and pop. + * If we are going to go ahead and pop, we will call the + * "Resume-Processing" routine (if it's not NULL) before + * we restore the saved source state. + * + **************************************************************************** */ + +static bool pop_source( void ) +{ + bool retval = TRUE; + + if ( saved_source != NULL ) + { + retval = FALSE; + if ( need_to_pop_source ) + { + need_to_pop_source = FALSE; + }else{ + if ( saved_source->pause_before_pop ) + { + need_to_pop_source = TRUE; + return( retval); + } + } + + if ( saved_source->resump_func != NULL ) + { + saved_source->resump_func( saved_source->resump_param); + } + report_multiline = saved_source->sav_rep_multlin; + lineno = saved_source->old_lineno ; + iname = saved_source->old_iname ; + end = saved_source->old_end ; + pc = saved_source->old_pc ; + start = saved_source->old_start ; + + drop_source(); + } + return( retval); +} + + +/* ************************************************************************** + * + * Function name: get_word + * Synopsis: Gather the next "word" (aka Forth Token) from the + * input stream. + * A Forth Token is, of course, a string of characters + * delimited by white-space (blank, tab or new-line). + * Do not increment line-number counters here; leave + * the delimiter after the word unconsumed. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * pc Input-stream Scanning Pointer + * Local Static Variables: + * need_to_pop_source If TRUE, pop_source() as first step + * + * Outputs: + * Returned Value: Length of "word" gotten; + * 0 if reached end of file. + * -1 if reached end of primary input + * (I.e., end of all source) + * Global Variables: + * statbuf Copy of "gotten" word + * pc Advanced to end of "gotten" word, + * (i.e., the next word is "consumed") + * unless returning zero. + * abs_token_no Incremented, if valid "word" (token) + * was gotten. + * + * Process Explanation: + * Skip whitespace to the start of the token, + * then skip printable characters to the end of the token. + * That part's easy, but what about when skipping whitespace + * brings you to the end of the input stream? + * First, look at the need_to_pop_source flag. If it's set, + * we came to the end of the input stream the last time + * through. Now we need to pop_source() first. + * Next, we start skipping whitespace; this detects when we've + * reached the end of the input stream. If we have, + * then we need to pop_source() again. + * If pop_source() returned a TRUE, we've reached the end + * of the primary input file. Return -1. + * If pop_source() turned the need_to_pop_source flag + * to TRUE again, then we need to "pause" until the + * next time through; return zero. + * Otherwise, we proceed with collecting the token as described. + * + * Revision History: + * Updated Thu, 23 Feb 2006 by David L. Paktor + * Tied this routine in with a more sophisticated mechanism that + * makes a smooth transition between processing the body of + * a Macro, a User-defined Symbol or an FLOADed file, and + * the resumption of processing the source file, so that the + * end-of-file will only be seen at the end of the primary + * input file (the one that came from the command-line) + * Updated Fri, 24 Feb 2006 by David L. Paktor + * This is trickier than I thought. Added a global indicator + * of whether a file-boundary was crossed while getting + * the word; previously, that was indicated by a return + * value of zero, which now means something else... + * The flag, closed_stream , will be cleared every time this + * routine is entered, and set whenever close_stream() is + * entered. + * Updated Tue, 28 Feb 2006 at 10:13 PST by David L. Paktor + * Trickier still. On crossing a file-boundary, must not + * consume the first word in the resumed file, for one + * call; instead, return zero. Consume it on the next + * call. The closed_stream flag is now irrelevant and + * has gone away. + * + **************************************************************************** */ + +signed long get_word( void) +{ size_t len; u8 *str; + bool keep_skipping; + bool pop_result;
- pc=skipws(pc); - if (pc>=end) + if ( need_to_pop_source ) + { + pop_result = pop_source(); + } + + do { + keep_skipping = skip_ws(); + if ( keep_skipping ) + { + pop_result = pop_source(); + if ( pop_result || need_to_pop_source ) + { + statbuf[0] = 0; + if ( pop_result ) + { + return -1; + } return 0; + } + } + } while ( keep_skipping );
str=pc; - while (str && *str && *str!='\n' && *str!='\t' && *str!=' ') + while ( (str < end) && *str && *str!='\n' && *str!='\t' && *str!=' ') str++;
len=(size_t)(str-pc); - if (len>1023) { - printf("%s:%d: error: buffer overflow.\n", iname, lineno); - ERROR; + if (len >= GET_BUF_MAX ) + { + tokenization_error ( FATAL, + "get_word buffer overflow. Max is %d.", GET_BUF_MAX-1 ); }
memcpy(statbuf, pc, len); @@ -112,39 +640,297 @@ iname, lineno, statbuf, len); #endif pc+=len; + abs_token_no++; return len; }
-static unsigned long get_until(char needle) + +/* ************************************************************************** + * + * Function name: get_word_in_line + * Synopsis: Get the next word on the same line as the current + * line of input. If the end of line was reached + * before a word was found, print an error message + * and return an indication. + * + * Inputs: + * Parameters: + * func_nam Name of the function expecting the same-line + * input; for use in the Error Message. + * If NULL, do not issue Error Message + * Global Variables: + * pc Input character pointer. Saved for comparison + * lineno Current input line number. Saved for comparison + * + * Outputs: + * Returned Value: TRUE = success. Word was acquired on same line. + * Global Variables: + * statbuf Advanced to the next word in the input stream. + * pc Advanced if no error; restored otherwise. + * + * Error Detection: + * If no next word is gotten (i.e., we're at end-of-file), or if + * one is gotten but not on the same line, the routine will + * return FALSE; if func_nam is not NULL, an ERROR Message + * will be issued. + * Also, the values of PC LINENO and ABS_TOKEN_NO will be reset + * to the positions they had when this routine was entered. + * + **************************************************************************** */ + +bool get_word_in_line( char *func_nam) { - u8 *safe; - unsigned long len; + signed long wlen; + bool retval = TRUE; + u8 *save_pc = pc; + unsigned int save_lineno = lineno; + unsigned int save_abs_token_no = abs_token_no;
- safe=pc; - pc=firstchar(needle,safe); - if (pc>=end) - return 0; + /* Copy of function name, for error message */ + char func_cpy[FUNC_CPY_BUF_SIZE+1];
- len=(unsigned long)pc-(unsigned long)safe; - if (len>1023) { - printf("%s:%d: error: buffer overflow\n", iname, lineno); - ERROR; + /* Do this first, in the likely event that func_nam was statbuf */ + if ( func_nam != NULL ) + { + strncpy( func_cpy, func_nam, FUNC_CPY_BUF_SIZE); + func_cpy[FUNC_CPY_BUF_SIZE] = 0; /* Guarantee a null terminator */ + } + + wlen = get_word(); + if ( ( lineno != save_lineno ) || ( wlen <= 0 ) ) + { + abs_token_no = save_abs_token_no; + lineno = save_lineno; + pc = save_pc; + retval = FALSE; + if ( func_nam != NULL ) + { + tokenization_error ( TKERROR, + "Operator %s expects its target on the same line\n", + strupr(func_cpy)); } + } + return ( retval ); +} + + +/* ************************************************************************** + * + * Function name: get_rest_of_line + * Synopsis: Get all the remaining text on the same line as + * the current line of input. If there is no text + * (not counting whitespace) before the end of line, + * return an indication. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * pc Input character pointer. Saved for restoration + * lineno Current input line number. Saved for comparison + * + * Outputs: + * Returned Value: TRUE = success. Text was acquired on same line. + * Global Variables: + * statbuf Contains the text found in the input stream. + * pc Advanced to end of line or of whitespace, if + * no error; restored otherwise. + * lineno Preserved if no error; otherwise, restored. + * abs_token_no Restored if error; otherwise, advanced as normal. + * + * Error Detection: + * Routine will return FALSE if no text is gotten on the same line. + * + **************************************************************************** */ + +bool get_rest_of_line( void) +{ + bool retval = FALSE; + u8 *save_pc = pc; + unsigned int save_lineno = lineno; + unsigned int save_abs_token_no = abs_token_no; + + if ( INVERSE( skip_ws() ) ) + { + if ( lineno == save_lineno ) + { + signed long wlen = get_until('\n'); + if ( wlen > 0 ) retval = TRUE; + }else{ + abs_token_no = save_abs_token_no; + lineno = save_lineno; + pc = save_pc; + } + } + return( retval); +} + + +/* ************************************************************************** + * + * Function name: warn_unterm + * Synopsis: Message for "Unterminated ..." something + * Show saved line-number, where the "something" started, + * and the definition, if any, in which it occurred. + * + * Inputs: + * Parameters: + * severity Type of error/warning message to display + * usually either WARNING or TKERROR + * something String to print after "Unterminated" + * saved_lineno Line-Number where the "something" started + * Global Variables: + * lineno Saved, then restored. + * last_colon_defname Used only if unterm_is_colon is TRUE; + * Local Static Variables: + * unterm_is_colon See 07 Mar 2006 entry under Rev'n History + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * lineno Saved, then restored. + * Local Static Variables: + * unterm_is_colon Reset to FALSE + * Printout: + * Warning or Error message + * + * Revision History: + * Updated Mon, 06 Mar 2006 by David L. Paktor + * Added call to in_last_colon() + * Updated Tue, 07 Mar 2006 by David L. Paktor + * Call to in_last_colon() works okay in most cases except for + * when the "something" is a Colon Definition; there, it + * results in the phrase: ... Definition in definition of ... + * which is awkward. To eliminate that, I am introducing + * a Local Static Variable flag called unterm_is_colon + * which will be set only in the appropriate place and + * re-cleared here. It's a retro-fit, of course; it could + * have been a parameter had the need for it occurred when + * this routine was first constructed... + * + **************************************************************************** */ + +static bool unterm_is_colon = FALSE; +void warn_unterm( int severity, char *something, unsigned int saved_lineno) +{ + unsigned int tmp = lineno; + lineno = saved_lineno; + if ( unterm_is_colon ) + { + tokenization_error( severity, "Unterminated %s of %s\n", + something, strupr( last_colon_defname) ); + unterm_is_colon = FALSE; + }else{ + tokenization_error( severity, "Unterminated %s", something); + in_last_colon(); + } + lineno = tmp; +} + +/* ************************************************************************** + * + * Function name: warn_if_multiline + * Synopsis: Test for "Multi-line ..." something and issue WARNING + * Show saved line-number, where the "something" started + * + * Inputs: + * Parameters: + * something String to print after "Unterminated" + * start_lineno Line-Number where the "something" started + * Global Variables: + * lineno Line-Number where we are now + * iname Input file name, to satisfy ...where_started() + * (Not crossing any actual file boundary.) + * report_multiline TRUE = go ahead with the message + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * report_multiline Restored to TRUE. + * + * Error Detection: + * Only issue message if the current lineno doesn't equal + * the start_lineno + * + * Process Explanation: + * The directive "multi-line" allows the user to specify that + * the next "Multi-line ..." something is intentional, and + * will cause its warning to be suppressed. It remains in + * effect until it's "used"; afterwards, it's reset. + * + **************************************************************************** */ + +void warn_if_multiline( char *something, unsigned int start_lineno ) +{ + if ( report_multiline && ( start_lineno != lineno ) ) + { + tokenization_error( WARNING, "Multi-line %s, started", something); + where_started( iname, start_lineno); + } + report_multiline = TRUE; +} + + +/* ************************************************************************** + * + * Function name: string_remark + * Synopsis: Suspend string parsing past end of line and + * whitespace at start of the new line. + * + * Inputs: + * Parameters: + * errmsg_txt Text to be used for error-message. + * Global Variables: + * pc Input-source Scanning pointer + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * pc Will point to first non-blank in new line + * + * Error Detection: + * The return value of the skip_until() or skip_ws() routine + * will indicate if PC goes past END. Issue a WARNING. + * The calling routine will handle things from there. + * + **************************************************************************** */ + +static void string_remark(char *errmsg_txt) +{ + unsigned int sav_lineno = lineno; + bool eof = skip_until('\n'); + if ( ! eof ) + { + eof = skip_ws(); + } + if ( eof ) + { + warn_unterm(WARNING, errmsg_txt, sav_lineno); + } - memcpy(statbuf, safe, len); - statbuf[len]=0; - return len; }
+ +/* Convert the given string to a number in the supplied base */ +/* Allow -- and ignore -- embedded periods. */ +/* The endptr param represents a pointer that will be updated + * with the address of the first non-numeric character encountered, + * (unless it is a NULL, in which case it is ignored). + */ +/* There is no test for a completely invalid string; + * the calling routine is responsible for ascertaining + * the validity of the string being passed. + */ static long parse_number(u8 *start, u8 **endptr, int lbase) { long val = 0; - int negative = 0, curr; + bool negative = FALSE ; + int curr; u8 *nptr=start;
curr = *nptr; - if (curr == '-') { - negative=1; + if (curr == '-') + { + negative = TRUE ; nptr++; } @@ -177,265 +963,3486 @@ *endptr=nptr;
if (negative) - return -val; + { + val = -val; + } return val; }
-static u8 *get_sequence(u8 *walk) +/* ************************************************************************** + * + * Function name: add_byte_to_string + * Synopsis: Add the given byte (or character) to the string + * being accumulated in statbuf, but protect + * against a buffer overflow. + * + * Inputs: + * Parameters: + * nu_byte The given character to be added + * walk Pointer to pointer to the position + * in statbuf where the character + * is to be placed + * Global Variables: + * statbuf Buffer where the string is accumulated + * Macros: + * GET_BUF_MAX Size of the buffer + * + * Outputs: + * Returned Value: NONE + * Supplied Pointers: + * **walk Given character is placed here + * *walk Incremented in any case + * + * Error Detection: + * If walk has reached end of string buffer, do not place + * the character, but continue to increment walk . + * Calling routine will detect overflow. + * + **************************************************************************** */ + +static void add_byte_to_string( u8 nu_byte, u8 **walk ) { - u8 val, pval[3]; + if ( *walk - statbuf < GET_BUF_MAX ) + { + **walk = nu_byte; + } + (*walk)++; +} + +/* ************************************************************************** + * + * Function name: c_string_escape + * Synopsis: Process C-style escape syntax in strings + * + * Inputs: + * Parameters: + * walk Pointer to pointer to area into + * which to put acquired values + * Global Variables: + * pc Input-source Scanning pointer + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * pc Point to last character processed. + * Supplied Pointers: + * *walk Advanced by number of bytes acquired + * + * Error Detection: + * WARNING conditions. See under "Process Explanation" below. + * + * Process Explanation: + * Start with PC pointing to the first character to process + * i.e., after the backslash. + * We recognize newline, tab and numbers + * A digit-string in the current base can be converted to a number. + * The first non-numeric character ends the numeric sequence + * and gets swallowed up. + * If the number exceeds the size of a byte, use the truncated + * value and issue a WARNING. + * If the first character in the "digit"-string was non-numeric, + * use the character literally and issue a WARNING. + * If the character that ended the numeric sequence is a quote, + * it might be the end of the string, or the start of a + * special-character or even of an "( ... ) hex-sequence, + * so don't swallow it up. + * + * Still to be done: + * Better protection against PC pointer-over-run past END. + * Currently, this works, but it's held together by threads: + * Because init_stream forces a null-byte at the end of + * the input buffer, parse_number() exits immediately upon + * encountering it. This situation could be covered more + * robustly... + * + **************************************************************************** */ + +static void c_string_escape( u8 **walk) +{ + char c = *pc; + u8 val; + /* We will come out of this "switch" statement + * with a value for val and a decision + * as to whether to write it. + */ + bool write_val = TRUE; - pc++; /* skip the ( */ + switch (c) + { + case 'n': + /* newline */ + val = '\n'; + break; + case 't': + /* tab */ + val = '\t'; + break; + default: + + /* Digit-string? Convert it to a number, using the current base. + * The first non-numeric character ends the numeric sequence + * and gets swallowed up. + * If the number exceeds the size of a byte, use the truncated + * value and issue a WARNING. + * If the first character in the "digit"-string was non-numeric, + * use the character literally and issue a WARNING. + */ + + /* + * If the sequence ender is a quote, it might be the end of + * the string, or the start of a special-character or even + * of an "( ... ) hex-sequence, so don't swallow it up. + */ + { + long lval; + u8 *sav_pc = pc; + lval=parse_number(pc, &pc, base); + val = (u8)lval; #ifdef DEBUG_SCANNER - printf("%s:%d: debug: hex field:", iname, lineno); + if (verbose) + printf( "%s:%d: debug: escape code " + "0x%x\n",iname, lineno, val); #endif - pval[1]=0; pval[2]=0; + if ( lval > 0x0ff ) + { + tokenization_error ( WARNING, + "Numeric String after \ overflows byte. " + "Using 0x%02x.\n", val); + }
- for(;;) { - while (!isxdigit(*pc) && (*pc) != ')') - pc++; + if ( pc == sav_pc ) + { + /* NOTE: Here, PC hasn't been advanced past its + * saved value, so we can count on C remaining + * unchanged since the start of the routine. + */ + /* Don't use the null-byte at the end of the buffer */ + if ( ( pc >= end ) + /* or a sequence-ending quote. */ + || ( c == '"' ) ) + { + write_val = FALSE; + }else{ + /* In the WARNING message, print the character + * if it's printable or show it in hex + * if it's not. + */ + if ( (c > 0x20 ) && ( c <= 0x7e) ) + { + tokenization_error ( WARNING, + "Unrecognized character, %c, " + "after \ in string. " + "Using it literally.\n", c); + }else{ + tokenization_error ( WARNING, + "Unrecognized character, 0x%02x, " + "after \ in string. " + "Using it literally.\n", c); + } + val = c; + } + } + /* NOTE: Here, however, PC may have been advanced... */ + /* Don't swallow the sequence-ender if it's a quote. */ + if ( *pc == '"' ) + { + pc--; + }
- pval[0]=*pc; - if (pval[0]==')') - break; + } /* End of the "default" clause */ + } /* End of the "switch" statement */
- pc++; /* this cannot be a \n */ + if ( write_val ) add_byte_to_string( val, walk );
- pval[1]=*pc; - if ( *pc!=')' && *pc++=='\n' ) - lineno++; - - val=parse_number(pval, NULL, 16); - *(walk++)=val; +} + +/* ************************************************************************** + * + * Function name: get_sequence + * Synopsis: Process the Hex-Number option in strings + * Protect against PC pointer-over-run past END. + * + * Inputs: + * Parameters: + * **walk Pointer to pointer to area into which + * to put acquired values + * Global Variables: + * pc Input-source Scanning pointer + * end End of input-source buffer + * + * Outputs: + * Returned Value: TRUE = "Normal Completion" (I.e., not EOF) + * Global Variables: + * pc Points at terminating close-paren, or END + * lineno Input File Line-Number Counter, may be incr'd + * Supplied Pointers: + * *walk Advanced by number of values acquired + * + * Error Detection: + * End-of-file encountered before end of hex-sequence: + * Issue a Warning, conclude processing, return FALSE. + * + * Process Explanation: + * SETUP and RULES: + * Start with PC pointing to the first character + * after the '(' (Open-Paren) + * Bytes are gathered from digits in pairs, except + * when separated they are treated singly. + * Allow a backslash in the middle of the sequence + * to skip to the end of the line and past the + * whitespace at the start of the next line, + * i.e., it acts as a comment-escape. + * + * INITIALIZE: + * PV_indx = 0 + * Set return-indicator to "Abnormal Completion" + * Ready_to_Parse = FALSE + * Stuff NULL into PVAL[2] + * WHILE PC is less than END + * Pick up character at PC into Next_Ch + * IF Next_Ch is close-paren : + * Set return-indicator to "Normal Completion". + * Done! Break out of loop. + * ENDIF + * IF comment-escape behavior (controlled by means of a + * command-line switch) is allowed + * IF Next_Ch is backslash : + * Skip to end-of line, skip whitespace. + * If that makes PC reach END : WARNING message. + * (Don't need to break out of loop; + * normal test will terminate.) + * CONTINUE Loop. + * (Don't increment PC; PC is already at right place). + * ENDIF + * ENDIF + * IF Next_Ch is a valid Hex-Digit character : + * Stuff it into PVAL[PV_indx] + * IF (PV_indx is 0) : + * Increment PV_indx + * ELSE + * Set Ready_to_Parse to TRUE + * ENDIF + * ELSE + * IF Next_Ch is a New-Line, increment Line Number counter + * IF (PV_indx is 1) : + * Stuff NULL into PVAL[1] + * Set Ready_to_Parse to TRUE + * ENDIF + * ENDIF + * IF Ready_to_Parse + * Parse PVAL + * Stuff into WALK + * Reset PV_indx to zero + * Reset Ready_to_Parse to FALSE + * ENDIF + * Increment PC + * REPEAT + * Return with Normal/Abnormal completion indicator + * + **************************************************************************** */ + +static bool get_sequence(u8 **walk) +{ + int pv_indx = 0; + bool retval = FALSE; /* "Abnormal Completion" indicator */ + bool ready_to_parse = FALSE; + char next_ch; + char pval[3]; + #ifdef DEBUG_SCANNER + printf("%s:%d: debug: hex field:", iname, lineno); +#endif + pval[2]=0; + + while ( pc < end ) + { + next_ch = *pc; + if ( next_ch == ')' ) + { + retval = TRUE; + break; + } + if ( hex_remark_escape ) + { + if ( next_ch == '\' ) + { + string_remark("string hex-sequence remark"); + continue; + } + } + if ( isxdigit(next_ch) ) + { + pval[pv_indx] = next_ch; + if ( pv_indx == 0 ) + { + pv_indx++; + }else{ + ready_to_parse = TRUE; + } + }else{ + if ( next_ch == '\n' ) lineno++ ; + if ( pv_indx != 0 ) + { + pval[1] = 0; + ready_to_parse = TRUE; + } + } + if ( ready_to_parse ) + { + u8 val = parse_number(pval, NULL, 16); + *((*walk)++)=val; +#ifdef DEBUG_SCANNER printf(" %02x",val); #endif + pv_indx = 0; + ready_to_parse = FALSE; } + pc++; + } #ifdef DEBUG_SCANNER printf("\n"); #endif - - return walk; + return ( retval ); }
-static unsigned long get_string(void) +/* ************************************************************************** + * + * Return the length of the string. + * Pack the string, without the terminating '"' (Quote), into statbuf + * Protect against PC pointer-over-run past END. + * Enable Quote-Backslash as a String-Remark Escape. + * Allowability of Quote-Backslash as a String-Remark is under control + * of a command-line switch (string_remark_escape ). + * Allowability of C-style escape characters is under control + * of a command-line switch ( c_style_string_escape ). + * + * Truncate string to size of Forth Packed-String (i.e., uses leading + * count-byte, so limited to 255, number that one byte can express) + * unless the string is being gathered for a Message or is being + * consumed for purposes of ignoring it, in either of which case + * that limit need not be enforced. Parameter "pack_str" controls + * this: TRUE if limit needs to be enforced. + * + * Issue WARNING if string length gets truncated. + * Issue WARNING if string crosses line. + * The issuance of the Multi-line WARNING is under control of a + * one-shot directive similar to OVERLOAD , called MULTI-LINE + * + * Still to be decided: + * Do we want to bring the allowability of strings crossing + * lines under control of a command-line switch? + * + ************************************************************************** */ + +static signed long get_string( bool pack_str) { u8 *walk; unsigned long len; - bool run=1; - u8 c, val; + char c; + bool run = TRUE; + unsigned long start_lineno = lineno; /* For warning message */ + /* + * Bump past the single whitespace character that delimits + * the command -- e.g., ." or " or suchlike -- that + * starts the string. Allow new-line to be a command- + * -delimiting whitespace character. Regard any sub- + * sequent whitespace characters as part of the string + */ + if (*pc++=='\n') lineno++; + + got_until_eof = TRUE ; + walk=statbuf; while (run) { - switch ((c=*pc)) { - case '\': - switch ((c=*(++pc))) { - case 'n': - /* newline */ - *(walk++)='\n'; + switch ((c=*pc)) + { + /* Standard use of '"' (Quote) for special-char escape */ + case '"': + /* Skip the '"' (Quote) */ + pc++; + /* End of the buffer also ends the string cleanly */ + if ( pc >= end ) + { + run = FALSE; + got_until_eof = FALSE ; break; - case 't': - /* tab */ - *(walk++)='\t'; + } + /* Pick up the next char after the '"' (Quote) */ + c=*pc; + switch (c) + { + case '(': + pc++; /* skip the '(' */ + run = get_sequence(&walk); break; - default: - val=parse_number(pc, &pc, base); -#ifdef DEBUG_SCANNER - if (verbose) - printf( "%s:%d: debug: escape code " - "0x%x\n",iname, lineno, val); -#endif - *(walk++)=val; - } - break; - case '"': - pc++; /* skip the " */
- /* printf("switching: %c\n",*pc); */ - switch(*pc) { - case '(': - walk=get_sequence(walk); - break; - case '"': - *(walk++)='"'; - pc++; - break; case 'n': - *(walk++)='\n'; - pc++; + add_byte_to_string( '\n', &walk); break; case 'r': - *(walk++)='\r'; - pc++; + add_byte_to_string( '\r', &walk); break; case 't': - *(walk++)='\t'; - pc++; + add_byte_to_string( '\t', &walk); break; case 'f': - *(walk++)='\f'; - pc++; + add_byte_to_string( '\f', &walk); break; case 'l': - *(walk++)='\n'; - pc++; + add_byte_to_string( '\n', &walk); break; case 'b': - *(walk++)=0x08; - pc++; + add_byte_to_string( 0x08, &walk); break; case '!': - *(walk++)=0x07; - pc++; + add_byte_to_string( 0x07, &walk); break; case '^': - pc++; - c=toupper(*(pc++)); - *(walk++)=c-'A'; + pc++; /* Skip the up-arrow (Caret) */ + add_byte_to_string( *pc & 0x1f , &walk); break; - case '\n': - lineno++; + /* We're done after any of the whitespace + * characters follows a quote. + */ case ' ': case '\t': - run=0; + /* Advance past the terminating whitespace + * character, except newline. + * Let get_word() handle that. + */ + pc++; + case '\n': + run=FALSE; + got_until_eof = FALSE ; break; default: - *(walk++)=*(pc++); + /* Control allowability of Quote-Backslash + * as a String-Remark by means of a + * command-line switch. + */ + if ( string_remark_escape ) + { + if ( c == '\' ) + { + string_remark("string-escape remark"); + /* The first non-blank in the new line + * has not been processed yet. + * Back up to allow it to be. + */ + pc--; break; } + } + add_byte_to_string( c, &walk); + } break; + case '\n': + /* Allow strings to cross lines. Include the + * newline in the string. Account for it. + */ + lineno++; default: - *(walk++)=c; + /* Control allowability of C-style escape-character + * syntax by means of a command-line switch. + */ + if ( c_style_string_escape ) + { + if ( c == '\' ) + { + pc++; + c_string_escape(&walk ); + break; + } + } + add_byte_to_string( c, &walk); } - if (*pc++=='\n') lineno++; + /* Advance past the char processed, unless we're done. */ + if ( run ) pc++; + /* Done if we hit end of file before string was concluded */ + if ( pc >= end ) + { + run = FALSE; + if ( got_until_eof ) + { + warn_unterm( WARNING, "string", start_lineno); + /* Prevent multiple messages for one error */ + got_until_eof = FALSE; + } + } } - *(walk++)=0; - - if (pc>=end) - return 0; - - len=(unsigned long)walk-(unsigned long)statbuf; - if (len>1023) { - printf("%s:%d: error: buffer overflow\n", iname, lineno); - ERROR; + warn_if_multiline( "string", start_lineno); + + len = walk - statbuf; + if (len >= GET_BUF_MAX ) + { + tokenization_error ( TKERROR, + "get_string buffer overflow. Max is %d\n.", GET_BUF_MAX-1 ); + len = GET_BUF_MAX-1; } #ifdef DEBUG_SCANNER if (verbose) printf("%s:%d: debug: scanned string: '%s'\n", iname, lineno, statbuf); #endif + if ( pack_str && (len > STRING_LEN_MAX) ) + { + tokenization_error ( WARNING, + "String length being truncated to %d.\n", STRING_LEN_MAX ); + len = STRING_LEN_MAX; + } + statbuf[len] = 0;
- return len>255?255:len; + return len ; }
-static int get_number(long *result) + +/* ************************************************************************** + * + * Function name: handle_user_message + * Synopsis: Collect a user-generated tokenization-time message; + * either print it or discard it. Shared code + * for user_message() and skip_user_message() + * + * Inputs: + * Parameters: + * delim End-of-string delimiter character. + * If it's a double-quote ("), we will use + * the get-string() routine, with all + * its options, to collect the message. + * Otherwise, we'll capture plain text from + * the input stream. + * print_it TRUE if we should print the message + * Local Static Variables: + * got_until_eof TRUE if reached end of buffer before delim. + * Global Variables: + * lineno Save, then restore. + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * statbuf The string will be collected in here + * + * Printout (if print_it is TRUE): + * The string, with new-line tacked on, will be printed from + * the tokenization_error() routine as a MESSAGE. + * The line-number will be shown as of the origin of the message + * + * Error Detection: + * Error-reports will be printed regardless of print_it param. + * If delimiter was not found, show "Unterminated" warning message. + * If delimiter was " (double-quote), the get_string() routine + * already checked for a multi-line construct; if delimiter is + * a new-line, then a multi-line construct is impossible. + * otherwise, we will do the multi-line check here. + * + **************************************************************************** */ + +static void handle_user_message( char delim, bool print_it ) { - u8 lbase, *until; - long val; + signed long wlen; + unsigned int start_lineno = lineno; + unsigned int multiline_start = lineno; /* For warning message */ + bool check_multiline = FALSE; + const char *ug_msg = "user-generated message";
- lbase=intok?0x10:base; - val=parse_number(statbuf,&until, lbase); + if ( delim == '"' ) + { + wlen = get_string( FALSE); + }else{ + /* + * When the message-delimiter is a new-line, and the + * command-delimiter was a new-line, it means the + * string length is zero; we won't bump the PC. + * Otherwise, we will honor the convention we extend + * to .( whereby, if the command is delimited + * by a new-line, we allow the string to begin + * on the next line. + */ + if ( delim == '\n' ) + { + if ( *pc != '\n') pc++; + }else{ + if (*pc++=='\n') lineno++; + multiline_start = lineno; + check_multiline = TRUE; + } + wlen = get_until( delim ); + } + + if ( print_it ) + { + unsigned int tmp_lineno = lineno; + lineno = start_lineno; + /* Don't add a new-line to body of the message. + * Routine already takes care of that. + * Besides, buffer might be full... + */ + tokenization_error( MESSAGE, statbuf); + lineno = tmp_lineno; + } + + if ( got_until_eof ) /* Crude but effective retrofit... */ + { + warn_unterm(WARNING, (char *)ug_msg, start_lineno); + }else{ + if ( check_multiline ) + { + warn_if_multiline( (char *)ug_msg, multiline_start); + } + } +} + +/* ************************************************************************** + * + * Function name: user_message + * Synopsis: Collect a user-generated message and + * print it at tokenization-time. + * + * Tokenizer directive (either mode): + * Synonyms String Delimiter + * [MESSAGE] #MESSAGE [#MESSAGE] end-of-line + * #MESSAGE" " + * "Tokenizer-Escape" mode directive String Delimiter + * .( ) + * ." " + * + * Inputs: + * Parameter is the "parameter field" of the TIC entry, which + * was initialized to the end-of-string delimiter character. + * + * Outputs: + * Returned Value: NONE + * Printout: User-message, parsed from input. + * + * Extraneous Remarks: + * We would have preferred to simply use the "character value" + * aspect of the union, but we found portability issues + * between big- and little- -endian processors, so we still + * have to recast its type here. + * + **************************************************************************** */ + +void user_message( tic_param_t pfield ) +{ + char delim = (char)pfield.deflt_elem ; + handle_user_message( delim, TRUE); +} + +/* ************************************************************************** + * + * Function name: skip_user_message + * Synopsis: Collect a user-generated message and discard it. + * Used when ignoring a Conditional section. + * + * Tokenizer directive (either mode): + * Synonyms String Delimiter + * [MESSAGE] #MESSAGE [#MESSAGE] end-of-line + * #MESSAGE" " + * "Tokenizer-Escape" mode directive String Delimiter + * .( ) + * ." " + * + * Inputs: + * Parameters: + * pfield "Parameter field" of the TIC entry, which + * was initialized to the delimiter. + * + * Outputs: + * Returned Value: NONE + * Printout: NONE + * + **************************************************************************** */ + +void skip_user_message( tic_param_t pfield ) +{ + char delim = (char)pfield.deflt_elem ; + handle_user_message( delim, FALSE); +} + + + +/* ************************************************************************** + * + * Function name: get_number + * Synopsis: If the word retrieved from the input stream is a + * valid number (under the current base) convert it. + * Return an indication if it was not. + * + * Inputs: + * Parameters: + * *result Pointer to place to return the number + * Global Variables: + * statbuf The word just read that is to be converted. + * base The current numeric-interpretation base. + * + * Outputs: + * Returned Value: TRUE = Input was a valid number + * Supplied Pointers: + * *result The converted number, if valid + * otherwise undefined + * + * Revision History: + * Updated Mon, 28 Mar 2005 by David L. Paktor + * Always use the current base. + * Reversed sense of return-flag. + * + **************************************************************************** */ + +bool get_number( long *result) +{ + u8 *until; + long val; + bool retval = FALSE ; + + val = parse_number(statbuf, &until, base); #ifdef DEBUG_SCANNER - printf("%s:%d: debug: parsing number: base 0x%x, val 0x%lx, " - "processed %ld of %ld bytes\n", iname, lineno, - lbase, val,(size_t)(until-statbuf), strlen((char *)statbuf)); + printf("%s:%d: debug: parsing number: base 0x%x, val 0x%lx, " + "processed %ld of %ld bytes\n", iname, lineno, + base, val,(size_t)(until-statbuf), strlen((char *)statbuf)); #endif
- if (until==(statbuf+strlen((char *)statbuf))) { - *result=val; - return 0; - } - - return -1; + /* If number-parsing ended before the end of the input word, + * then the input word was not a valid number. + */ + if (until==(statbuf+strlen((char *)statbuf))) + { + *result=val; + retval = TRUE; + } + + return ( retval ); }
+/* ************************************************************************** + * + * Function name: deliver_number + * Synopsis: Deliver the supplied number according to the + * state of the tokenizer: + * In normal tokenization mode, emit it as an + * FCode literal. + * In "Tokenizer-Escape" mode, push it onto + * the Data Stack. + * + * Inputs: + * Parameters: + * numval The number, verified to be valid. + * Global Variables: + * in_tokz_esc TRUE if tokenizer is in "Tokenizer Escape" mode. + * + * Outputs: + * Returned Value: NONE + * Items Pushed onto Data-Stack: + * Top: The number, if in_tokz_esc was TRUE + * FCode Output buffer: + * If in_tokz_esc was FALSE, a b(lit) token will be written, + * followed by the number. + * + **************************************************************************** */ + +static void deliver_number( long numval) +{ + if ( in_tokz_esc ) + { + dpush( numval ); + } else { + emit_literal(numval); + } +} +/* ************************************************************************** + * + * Function name: handle_number + * Synopsis: Convert the word just retrieved from the input stream + * to a number. + * Indicate whether the string was a valid number and + * deliver it, as appropriate. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * statbuf The word that was just read, and to be converted. + * + * Outputs: + * Returned Value: TRUE = Input string was a valid number + * If input string was a valid number, the converted number will + * be delivered, as appropriate, by deliver_number(). + * + **************************************************************************** */ + +static bool handle_number( void ) +{ + bool retval ; + long numval; + + retval = get_number( &numval ); + if ( retval ) + { + deliver_number( numval ); + } + + return ( retval ); +} + +/* ************************************************************************** + * + * Function name: ascii_right_number + * Synopsis: Convert a character sequence to a number, justified + * toward the right (i.e., the low-order bytes) and + * deliver it, as appropriate. + * + * Inputs: + * Parameters: + * in_str The input string + * + * Outputs: + * Returned Value: NONE + * The converted number will be delivered by deliver_number(). + * + * Process Explanation: + * The last four characters in the sequence will become the number. + * If there are fewer than four, they will fill the low-order part + * of the number. + * Example: PCIR is converted to h# 50434952 + * CPU is converted to h# 00435055 + * and + * LotsOfStuff is equivalent to a# tuff + * and is converted to h# 74756666 + * + **************************************************************************** */ + +static void ascii_right_number( char *in_str) +{ + u8 nxt_ch; + char *str_ptr = in_str; + long numval = 0; + + for ( nxt_ch = (u8)*str_ptr ; + ( nxt_ch = (u8)*str_ptr ) != 0 ; + str_ptr++ ) + { + numval = ( numval << 8 ) + nxt_ch ; + } + deliver_number( numval ); +} + + +/* ************************************************************************** + * + * Function name: ascii_left_number + * Synopsis: Similar to ascii_right_number() except justified + * toward the left (i.e., the high-order bytes). + * + * + * Inputs: + * Parameters: + * in_str The input string + * + * Outputs: + * Returned Value: NONE + * The converted number will be delivered by deliver_number(). + * + * Process Explanation: + * If there are fewer than four characters in the sequence, they + * will fill the high-order part of the number. + * CPU is converted to h# 43505500 + * In all other respects, similar to ascii_right_number() + * + **************************************************************************** */ + +static void ascii_left_number( char *in_str) +{ + u8 nxt_ch; + char *str_ptr = in_str; + long numval = 0; + int shift_amt = 24; + bool shift_over = FALSE ; + + for ( nxt_ch = (u8)*str_ptr ; + ( nxt_ch = (u8)*str_ptr ) != 0 ; + str_ptr++ ) + { + if ( shift_over ) numval <<= 8; + if ( shift_amt == 0 ) shift_over = TRUE ; + numval += ( nxt_ch << shift_amt ); + if ( shift_amt > 0 ) shift_amt -= 8; + } + deliver_number( numval ); + +} + +/* ************************************************************************** + * + * Function name: init_scanner + * Synopsis: Allocate memory the Scanner will need. + * Only need to call once per program run. + * + **************************************************************************** */ + void init_scanner(void) { - statbuf=malloc(1024); - if (!statbuf) { - printf ("no memory.\n"); - exit(-1); - } + statbuf=safe_malloc(GET_BUF_MAX, "initting scanner"); }
+/* ************************************************************************** + * + * Function name: exit_scanner + * Synopsis: Free up memory the Scanner used + * + **************************************************************************** */ + void exit_scanner(void) { free(statbuf); }
-#define FLAG_EXTERNAL 0x01 -#define FLAG_HEADERS 0x02 -char *name, *alias; -int flags=0; +/* ************************************************************************** + * + * Function name: set_hdr_flag + * Synopsis: Set the state of the "headered-ness" flag to the + * value given, unless over-ridden by one or both + * of the "always-..." Command-Line Flags + * + * Inputs: + * Parameters: + * new_flag New setting + * Global Variables: + * always_headers Override HEADERLESS and make HEADERS + * always_external Override HEADERLESS and HEADERS; + * make EXTERNAL + * + * Outputs: + * Returned Value: None + * Local Static Variables: + * hdr_flag Adjusted to new setting + * + * Process Explanation: + * If always_headers is TRUE, and new_flag is not FLAG_EXTERNAL + * then set to FLAG_HEADERS + * If always_external is TRUE, set to FLAG_EXTERNAL, regardless. + * (Note: always_external over-rides always_headers). + * Otherwise, set to new_flag + * + **************************************************************************** */
-static int create_word(void) +static void set_hdr_flag( headeredness new_flag) { - unsigned long wlen; + headeredness new_state = new_flag; + switch ( new_flag) + { + case FLAG_HEADERLESS: + { + if ( always_headers ) + { new_state = FLAG_HEADERS; + } + /* No break. Intentional... */ + } + case FLAG_HEADERS: + { + if ( always_external ) + { new_state = FLAG_EXTERNAL; + } + /* No break. Intentional... */ + } + case FLAG_EXTERNAL: + break; /* Satisfy compiler's error-checking... */ + /* No default needed here... */ + }
- if (incolon) { - printf("%s:%d: error: creating words not allowed " - "in colon definition.\n", iname, lineno); - ERROR; + hdr_flag = new_state; + +} + + +/* ************************************************************************** + * + * Function name: init_scan_state + * Synopsis: Initialize various state variables for each time + * a new tokenization scan is started. + * + * Inputs: + * Parameters: NONE + * + * Outputs: + * Returned Value: NONE + * Global Variables: Initialized to: + * base 0x0a (I.e., base = "decimal") + * nextfcode By reset_fcode_ranges() + * pci_is_last_image TRUE + * incolon FALSE + * Local Static Variables: + * hdr_flag FLAG_HEADERLESS (unless over-ridden) + * is_instance FALSE + * last_colon_filename NULL + * instance_filename NULL + * dev_change_instance_warning TRUE + * instance_definer_gap FALSE + * need_to_pop_source FALSE + * first_fc_starter TRUE + * ret_stk_depth 0 + * Memory Freed + * Copies of input-file name in last_colon_filename and + * instance_filename , if allocated. + * + **************************************************************************** */ + +void init_scan_state( void) +{ + base = 0x0a; + pci_is_last_image = TRUE; + incolon = FALSE; + is_instance = FALSE; + set_hdr_flag( FLAG_HEADERLESS); + reset_fcode_ranges(); + first_fc_starter = TRUE; + if ( last_colon_filename != NULL ) free( last_colon_filename); + if ( instance_filename != NULL ) free( instance_filename); + last_colon_filename = NULL; + instance_filename = NULL; + dev_change_instance_warning = TRUE; + instance_definer_gap = FALSE; + need_to_pop_source = FALSE; + ret_stk_depth = 0; +} + + +/* ************************************************************************** + * + * Function name: collect_input_filename + * Synopsis: Save a copy of the current input file name in the + * given variable, for error-reporting purposes + * + * Inputs: + * Parameters: + * saved_nam Pointer to pointer for copy of name + * Global Variables: + * iname Current input file name + * Local Static Variables: + * + * Outputs: + * Returned Value: NONE + * Supplied Pointers: + * *saved_nam Copy of name + * Memory Allocated + * For copy of input file name + * When Freed? + * Subsequent call to this routine with same pointer + * (Last copy made will be freed if starting a new tokenization, + * otherwise, will persist until end of program.) + * Memory Freed + * Previous copy in same pointer. + * + * Process Explanation: + * If there is a previous copy, and it still matches the current + * input-file name, we don't need to free or re-allocate. + * + **************************************************************************** */ + +static void collect_input_filename( char **saved_nam) +{ + bool update_lcfn = TRUE; /* Need to re-allocate? */ + if ( *saved_nam != NULL ) + { + if ( strcmp( *saved_nam, iname) == 0 ) + { + /* Last collected filename unchanged from iname */ + update_lcfn = FALSE; + }else{ + free( *saved_nam); } - - if(nextfcode > 0xfff) { - printf("%s:%d: error: maximum number of fcode words " - "reached.\n", iname, lineno); - ERROR; + } + if ( update_lcfn ) + { + *saved_nam = strdup(iname); + } +} + +/* ************************************************************************** + * + * Function name: test_in_colon + * Synopsis: Error-check whether a word is being used in the + * correct state, relative to being inside a colon + * definition; issue a message if it's not. + * + * Inputs: + * Parameters: + * wname The name of the word in question + * sb_in_colon TRUE if the name should be used inside + * a colon-definition only; FALSE if + * it may only be used outside of a + * colon-definition. + * severity Type of error/warning message to call. + * usually either WARNING or TKERROR + * use_instead Word the error-message should suggest be + * used "instead". This may be a NULL, + * in which case the "suggestion" part + * of the message will simply be omitted. + * Global Variables: + * incolon State of the tokenization; TRUE if inside + * a colon definition + * + * Outputs: + * Returned Value: TRUE if no error. + * Printout: Error messages as indicated. + * + * Error Detection: + * If the state, relative to being inside a colon-definition, + * is not what the parameter says it should be, issue a + * message of the indicated severity, and return FALSE. + * + **************************************************************************** */ + +static bool test_in_colon ( char *wname, + bool sb_in_colon, /* "Should Be IN colon" */ + int severity, + char *use_instead) +{ + bool is_wrong; + bool retval = TRUE ; + + is_wrong = BOOLVAL(( sb_in_colon != FALSE ) != ( incolon != FALSE )) ; + if ( is_wrong ) + { + char *ui_pt1 = ""; + char *ui_pt2 = ""; + char *ui_pt3 = ""; + retval = FALSE; + if ( use_instead != NULL ) + { + ui_pt1 = " Use "; + ui_pt2 = use_instead; + ui_pt3 = " instead."; } + tokenization_error ( severity, "The word %s should not be used " + "%sside of a colon definition.%s%s%s\n", strupr(wname), + sb_in_colon ? "out" : "in", ui_pt1, ui_pt2, ui_pt3 ); + } + return ( retval ); +} + +/* ************************************************************************** + * + * Function name: must_be_deep_in_do + * Synopsis: Check that the statement in question is called + * from inside the given depth of structures + * of the DO ... LOOP -type (i.e., any combination + * of DO or ?DO and LOOP or +LOOP ). + * Show an error if it is not. + * + **************************************************************************** */ + +static void must_be_deep_in_do( int how_deep ) +{ + int functional_depth = do_loop_depth; + if ( incolon ) + { + functional_depth -= last_colon_do_depth; + } + if ( functional_depth < how_deep ) + { + char deep_do[64] = ""; + int indx; + bool prefix = FALSE; + + for ( indx = 0; indx < how_deep ; indx ++ ) + { + strcat( deep_do, "DO ... "); + } + for ( indx = 0; indx < how_deep ; indx ++ ) + { + if ( prefix ) + { + strcat( deep_do, " ... "); + } + strcat( deep_do, "LOOP"); + prefix = TRUE; + } + + tokenization_error( TKERROR, + "%s outside of %s structure", strupr(statbuf), deep_do); + in_last_colon(); + } + +} + +/* ************************************************************************** + * + * Function name: bump_ret_stk_depth + * Synopsis: Increment or decrement the Return-Stack-Usage-Depth + * counter. + * + * Inputs: + * Parameters: + * bump Amount by which to increment; + * negative number to decrement. + * Local Static Variables: + * ret_stk_depth The Return-Stack-Usage-Depth counter + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * ret_stk_depth Incremented or decremented + * + * Process Explanation: + * This simple-seeming function is actually a place-holder + * for future expansion. Proper error-detection of + * Return-Stack usage is considerably more complex than + * what we are implementing here, and is deferred for a + * later revision. + * + * Still to be done: + * Full detection of whether the Return-Stack has been cleared + * when required, including analysis of Return-Stack usage + * within Flow-Control constructs, and before Loop elements... + * + * Extraneous Remarks: + * Some FORTHs use a Loop-Control stack separate from the Return- + * -Stack, but others use the Return-Stack to keep LOOP-control + * elements. An FCode program must be portable between different + * environments, and so must adhere to the restrictions listed + * in the ANSI Spec: + * + * 3.2.3.3 Return stack + * . . . . . . + * A program may use the return stack for temporary storage during the + * execution of a definition subject to the following restrictions: + * A program shall not access values on the return stack (using R@, + * R>, 2R@ or 2R>) that it did not place there using >R or 2>R; + * A program shall not access from within a do-loop values placed + * on the return stack before the loop was entered; + * All values placed on the return stack within a do-loop shall + * be removed before I, J, LOOP, +LOOP, UNLOOP, or LEAVE is + * executed; + * All values placed on the return stack within a definition + * shall be removed before the definition is terminated + * or before EXIT is executed. + * + **************************************************************************** */ + +static void bump_ret_stk_depth( int bump) +{ + ret_stk_depth += bump; +} + + +/* ************************************************************************** + * + * Function name: ret_stk_balance_rpt + * Synopsis: Display a Message if usage of the Return-Stack + * appears to be out of balance. + * + * Inputs: + * Parameters: + * before_what Phrase to use in Message; + * if NULL, use statbuf... + * clear_it TRUE if this call should also clear the + * Return-Stack-Usage-Depth counter + * Global Variables: + * statbuf Word currently being processed + * Local Static Variables: + * ret_stk_depth The Return-Stack-Usage-Depth counter + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * ret_stk_depth May be cleared + * + * Error Detection: + * Based simply on whether the Return-Stack-Usage-Depth counter + * is zero. This is a weak and uncertain implementation; + * therefore, the Message will be a WARNING phrased with + * some equivocation. + * + * Process Explanation: + * Proper detection of Return-Stack usage errors is considerably + * more complex, and is deferred for a future revision. + * + * Still to be done: + * Correct analysis of Return-Stack usage around Flow-Control + * constructs. Consider, for instance, the following: + * + * blablabla >R yadayada IF R> gubble ELSE flubble R> THEN + * + * It is, in fact, correct, but the present scheme would + * tag it as a possible error. Conversely, something like: + * + * blablabla >R yadayada IF R> gubble THEN + * + * would not get tagged, even though it is actually an error. + * + * The current simple scheme also does not cover Return-Stack + * usage within Do-Loops or before Loop elements like I and + * J or UNLOOP or LEAVE. Implementing something like that + * would probably need to be integrated in with Flow-Control + * constructs, and will be noted in flowcontrol.c + * + **************************************************************************** */ + +static void ret_stk_balance_rpt( char *before_what, bool clear_it) +{ + if ( ret_stk_depth != 0 ) + { + char *what_flow = ret_stk_depth < 0 ? "deficit" : "excess" ; + char *what_phr = before_what != NULL ? before_what : strupr(statbuf); + + tokenization_error( WARNING, + "Possible Return-Stack %s before %s", what_flow, what_phr); + in_last_colon(); + + if ( clear_it ) + { + ret_stk_depth = 0; + } + } +} + + +/* ************************************************************************** + * + * Function name: ret_stk_access_rpt + * Synopsis: Display a Message if an attempt to access a value + * on the Return-Stack appears to occur before + * one was placed there. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * statbuf Word currently being processed + * Local Static Variables: + * ret_stk_depth The Return-Stack-Usage-Depth counter + * + * Outputs: + * Returned Value: NONE + * + * Error Detection: + * Equivocal WARNING, based simply on whether the Return-Stack- + * -Usage-Depth counter not positive. + * + * Process Explanation: + * Proper detection is deferred... + * + * Still to be done: + * Correct analysis of Return-Stack usage... + * + **************************************************************************** */ + +static void ret_stk_access_rpt( void) +{ + if ( ret_stk_depth <= 0 ) + { + tokenization_error( WARNING, + "Possible Return-Stack access attempt by %s " + "without value having been placed there", + strupr(statbuf) ); + in_last_colon(); + } +} + + + +/* ************************************************************************** + * + * Function name: encode_file + * Synopsis: Input a (presumably binary) file and encode it + * as a series of strings which will be accumulated + * and encoded in a manner appropriate for a property. + * + * Associated Tokenizer directive: encode-file + * + * Error Detection: + * Handled by support routines. + * + **************************************************************************** */ + +static void encode_file( const char *filename ) +{ + FILE *f; + size_t s; + int num_encoded=0; - wlen=get_word(); - name=strdup((char *)statbuf); + tokenization_error( INFO, "ENCODing File %s\n", filename );
+ f = open_expanded_file( filename, "rb", "encoding"); + if( f != NULL ) + { + while( (s=fread(statbuf, 1, STRING_LEN_MAX, f)) ) + { + emit_token("b(")"); + emit_string(statbuf, s); + emit_token("encode-bytes"); + if( num_encoded ) + emit_token("encode+"); + num_encoded += s; + } + fclose( f ); + tokenization_error ( INFO, "ENCODed %d bytes.\n", num_encoded); + } +} + +/* ************************************************************************** + * + * Function name: check_name_length + * Synopsis: If the length of a user-defined name exceeds the + * ANSI-specified maximum of 31 characters, issue + * a message. This is a hard-coded limit. + * Although our Tokenizer can handle longer names, + * they will cause big problems when encountered + * by an FCode interpreter. + * If the name is going to be included in the binary + * output, the message severity must be an ERROR. + * Otherwise, if the name is HEADERLESS, the severity + * can be reduced to a Warning; if the name is only + * defined in "Tokenizer Escape" mode the message + * severity can be further reduced to an Advisory. + * + * Inputs: + * Parameters: + * wlen Length of the newly-created word + * Global Variables: + * in_tokz_esc TRUE if in "Tokenizer Escape" mode. + * Local Static Variables: + * hdr_flag State of headered-ness for name-creation + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * Printout: ERROR message if applicable. + * + * Error Detection: + * The whole point of this routine. + * + * Revision History: + * Updated Wed, 20 Jul 2005 by David L. Paktor + * Escalated from merely an informative warning to a TKERROR + * Updated Fri, 21 Oct 2005 by David L. Paktor + * Adjust severity if name doesn't go into the FCode anyway... + * + **************************************************************************** */ + +void check_name_length( signed long wlen ) +{ + if ( wlen > 31 ) + { + int severity = TKERROR; + if ( in_tokz_esc ) + { severity = INFO; + }else{ + if (hdr_flag == FLAG_HEADERLESS) + { severity = WARNING; + } + } + tokenization_error( severity, + "ANSI Forth does not permit definition of names " + "longer than 31 characters.\n" ); + } + +} + + +/* ************************************************************************** + * + * Function name: definer_name + * Synopsis: Given a defining-word internal token, return + * a printable string for the definer, for use + * in an error-message. + * + * Inputs: + * Parameters: + * definer Internal token for the defining-word + * reslt_ptr Pointer to string-pointer that takes + * the result, if successful + * + * Outputs: + * Returned Value: TRUE if definer was recognized + * Supplied Pointers: + * *reslt_ptr If successful, points to printable string; + * otherwise, left unchanged. + * + * + **************************************************************************** */ + +static bool definer_name(fwtoken definer, char **reslt_ptr) +{ + bool retval = TRUE; + switch (definer) + { + case VARIABLE: + *reslt_ptr = "VARIABLE"; + break; + case DEFER: + *reslt_ptr = "DEFER"; + break; + case VALUE: + *reslt_ptr = "VALUE"; + break; + case BUFFER: + *reslt_ptr = "BUFFER"; + break; + case CONST: + *reslt_ptr = "CONSTANT"; + break; + case COLON: + *reslt_ptr = "COLON"; + break; + case CREATE: + *reslt_ptr = "CREATE"; + break; + case FIELD: + *reslt_ptr = "FIELD"; + break; + case MACRO_DEF: + *reslt_ptr = "MACRO"; + break; + case ALIAS: + *reslt_ptr = "ALIAS"; + break; + case LOCAL_VAL: + *reslt_ptr = "Local Value name"; + break; + default: + retval = FALSE; + } + + return ( retval); +} + + +/* ************************************************************************** + * + * Function name: as_a_what + * Synopsis: Add the phrase "as a[n] <DEF'N_TYPE>" for the given + * definition-type to the given string buffer. + * + * Inputs: + * Parameters: + * definer Internal token for the defining-word + * as_what The string buffer to which to add. + * + * Outputs: + * Returned Value: TRUE if an assigned name was found + * for the given definer and text + * was added to the buffer. + * Supplied Pointers: + * *as_what Text is added to this buffer. + * + * Process Explanation: + * The calling routine is responsible to make sure the size of + * the buffer is adequate. Allow 25 for this routine. + * The added text will not have spaces before or after; if any + * are needed, they, too, are the responsibility of the + * calling routine. The return value gives a helpful clue. + * + **************************************************************************** */ + +bool as_a_what( fwtoken definer, char *as_what) +{ + char *defn_type_name; + bool retval = definer_name(definer, &defn_type_name); + if ( retval ) + { + strcat( as_what, "as a"); + /* Handle article preceding definer name + * that starts with a vowel. + */ + /* HACK: Only one definer name -- ALIAS -- + * begins with a vowel. Take advantage + * of that... + * Otherwise, we'd need to do something involving + * strchr( "AEIOU", defn_type_name[0] ) + */ + if ( definer == ALIAS ) strcat( as_what, "n" ); + + strcat( as_what, " "); + strcat( as_what, defn_type_name); + } + return( retval); +} + + +/* ************************************************************************** + * + * Function name: lookup_word + * Synopsis: Find the TIC-entry for the given word in the Current + * mode -- relative to "Tokenizer-Escape" -- and + * Scope into which definitions are being entered. + * Optionally, prepare text for various Message types. + * + * Inputs: + * Parameters: + * stat_name Word to look up + * where_pt1 Pointer to result-display string, part 1 + * NULL if not preparing text + * where_pt2 Pointer to result-display string, part 2 + * NULL if not preparing text + * Global Variables: + * in_tokz_esc TRUE if in "Tokenizer Escape" mode. + * scope_is_global TRUE if "global" scope is in effect + * current_device_node Current dev-node data-struct + * ibm_locals TRUE if IBM-style Locals are enabled + * + * Outputs: + * Returned Value: Pointer to TIC-entry; NULL if not found + * Supplied Pointers: + * *where_pt1 Result display string, part 1 of 2 + * *where_pt2 Result display string, part 2 of 2 + * + * Process Explanation: + * We will set the two-part result-display string in this routine + * because only here do we know in which vocabulary the word + * was found. + * Pre-load the two parts of the result-display string. + * If we are in "Tokenizer Escape" mode, look up the word: first, + * in the "Tokenizer Escape" Vocabulary, or, if not found, + * among the "Shared" words. + * Otherwise, we're in Normal" mode. Look it up: first, among the + * Locals, if IBM-style Locals are enabled (it can possibly be + * one if "Tokenizer Escape" mode was entered during a colon- + * -definition); then, if it was not found and if "Device" + * scope is in effect, look in the current device-node; then, + * if not found, in the "core" vocabulary. + * Load the second part of the result-display string with the + * appropriate phrase for whereever it was found. + * Then adjust the first part of the result-display string with + * the definer, if known. + * + * The two strings will be formatted to be printed adjacently, + * without any additional spaces in the printf() format. + * The first part of the result-display string will not start with + * a space, but will have an intermediate space if necessary. + * The second part of the result-display string will not start + * with a space, and will contain the terminating new-line + * if appropriate. It might or might not have been built + * with a call to in_what_node(). + * + * If the calling routine displays the result-display strings, + * it should follow-up with a call to show_node_start() + * This will be harmless if in_what_node() was not used + * in the construction of the result-display string. + * If the calling routine is NOT going to display the result strings, + * it should pass NULLs for the string-pointer pointers. + * + * The second part of the string consists of pre-coded phrases; + * therefore, we can directly assign the pointer. + * The first part of the string, however, has developed into + * something constructed "on the fly". Earlier, it, too, + * had been a directly-assignable pointer; all the callers + * to this routine expect that. Rather than change all the + * callers, we will assign a local buffer for it. + * + * Extraneous Remarks: + * We had to add the rule allowing where_pt1 or where_pt2 to be + * NULL after we introduced the in_what_node() function. + * We had cases where residue from a lookup for processing + * showed up later in an unrelated Message. The NULL rule + * should prevent that. + * + **************************************************************************** */ + +static char lookup_where_pt1_buf[32]; + +tic_hdr_t *lookup_word( char *stat_name, char **where_pt1, char **where_pt2 ) +{ + tic_hdr_t *found = NULL; + bool trail_space = TRUE; + bool doing_lookup = BOOLVAL( ( where_pt1 != NULL ) + && ( where_pt2 != NULL ) ); + char *temp_where_pt2 = "in the core vocabulary.\n"; + + lookup_where_pt1_buf[0] = 0; /* Init'lz part-1 buffer */ + + /* "Core vocab" refers both to shared fwords and built-in tokens. */ + + /* Distinguish between "Normal" and "Tokenizer Escape" mode */ + if ( in_tokz_esc ) + { /* "Tokenizer Escape" mode. */ + found = lookup_tokz_esc( stat_name); + if ( found != NULL ) + { + temp_where_pt2 = in_tkz_esc_mode; + }else{ + /* "Core vocabulary". */ + found = lookup_shared_word( stat_name); + } + }else{ + /* "Normal" tokenization mode */ + if ( ibm_locals ) + { + found = lookup_local( stat_name); + if ( doing_lookup && ( found != NULL ) ) + { + trail_space = FALSE; + temp_where_pt2 = ".\n"; + } + } + + if ( found == NULL ) + { + found = lookup_in_dev_node( stat_name); + if ( found != NULL ) + { + if ( doing_lookup ) + { + temp_where_pt2 = in_what_node( current_device_node); + } + }else{ + /* "Core vocabulary". */ + found = lookup_core_word( stat_name); + } + } + } + + if ( ( doing_lookup ) && ( found != NULL ) ) + { + if ( as_a_what( found->fword_defr, lookup_where_pt1_buf) ) + { + if ( trail_space ) + { + strcat(lookup_where_pt1_buf, " "); + } + } + *where_pt1 = lookup_where_pt1_buf; + *where_pt2 = temp_where_pt2; + } + return( found); +} + +/* ************************************************************************** + * + * Function name: word_exists + * Synopsis: Check whether a given word is already defined in the + * Current mode -- relative to "Tokenizer-Escape" -- + * and Scope into which definitions are being entered. + * Used for error-reporting. + * + * Inputs: + * Parameters: + * stat_name Word to look up + * where_pt1 Pointer to string, part 1 of 2, + * to display in result + * where_pt2 Pointer to string, part 2 of 2, + * to display in result + * + * Outputs: + * Returned Value: TRUE if the name exists. + * Supplied Pointers: + * *where_pt1 Result display string, part 1 of 2 + * *where_pt2 Result display string, part 2 of 2 + * + * Process Explanation: + * If the calling routine displays the result-display strings, + * it should follow-up with a call to show_node_start() + * + * Extraneous Remarks: + * This used to be a much heftier routine; now it's just + * a wrapper around lookup_word() . + * + **************************************************************************** */ + +bool word_exists( char *stat_name, char **where_pt1, char **where_pt2 ) +{ + bool retval = FALSE; + tic_hdr_t *found = lookup_word( stat_name, where_pt1, where_pt2 ); + + if ( found != NULL ) + { + retval = TRUE; + } + + return( retval); +} + +/* ************************************************************************** + * + * Function name: warn_if_duplicate + * Synopsis: Check whether a given word is already defined in + * the current mode and issue a warning if it is. + * + * Inputs: + * Parameters: + * stat_name Word to check + * Global Variables: + * verbose_dup_warning Whether to run the check at all. + * Local Static Variables: + * do_not_overload FALSE if OVERLOAD is in effect. + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * do_not_overload Restored to TRUE + * Printout: + * Warning message if a duplicate. + * + * Error Detection: + * None. This is merely an informative warning. + * + * Process Explanation: + * "Current mode" -- meaning, whether the tokenizer is operating + * in "Tokenizer Escape" mode or in normal tokenization mode -- + * will be recognized by the word_exists() function. + * + * Extraneous Remarks: + * The OVERLOAD directive is our best shot at creating a more + * fine-grained way to temporarily bypass this test when + * deliberately overloading a name. It would be nice to have + * a mechanism, comparable to the classic + * WARNING @ WARNING OFF ..... WARNING ! + * that could be applied to a range of definitions, but: + * (1) That would require more of a true FORTH infrastructure; + * hence, more effort than I am willing to invest, at + * this juncture, for such a small return, + * and + * (2) Most intentional-overloading ranges only cover a + * single definition anyway. + * + **************************************************************************** */ + +void warn_if_duplicate( char *stat_name) +{ + if ( verbose_dup_warning && do_not_overload ) + { + char *where_pt1; + char *where_pt2; + if ( word_exists( stat_name, &where_pt1, &where_pt2) ) + { + tokenization_error( WARNING, + "Duplicate definition: %s already exists %s%s", + stat_name, where_pt1, where_pt2 ); + show_node_start(); + } + } + do_not_overload = TRUE; +} + + +/* ************************************************************************** + * + * Function name: glob_not_allowed + * Synopsis: Print a Message that "XXX is not allowed." + * because Global Scope is in effect. + * Used from several places... + * + * Inputs: + * Parameters: + * severity Severity of the Message + * not_ignoring FALSE = "Ignoring", for the part of the + * message about "How It's being Handled" + * Global Variables: + * statbuf Disallowed word currently being processed + * + * Outputs: + * Returned Value: NONE + * Printout: Message of given severity. + * + **************************************************************************** */ + +static void glob_not_allowed( int severity, bool not_ignoring) +{ + tokenization_error( severity, "Global Scope is in effect; " + "%s not allowed. %s.\n", + strupr(statbuf), + not_ignoring ? + "Attempting to compensate.." : + "Ignoring" ); +} + + +/* ************************************************************************** + * + * Function name: not_in_dict + * Synopsis: Print the message "XXX is not in dictionary." + * Used from several places... + * + * Inputs: + * Parameters: + * stat_name Word that could not be processed + * + * Outputs: + * Returned Value: NONE + * Printout: Error message. + * + **************************************************************************** */ + +static void not_in_dict( char *stat_name) +{ + tokenization_error ( TKERROR, + "Word %s is not in dictionary.\n", stat_name); +} + +/* ************************************************************************** + * + * Function name: tokenized_word_error + * Synopsis: Report an error when a word could not be processed + * by the tokenizer. Messages will vary... + * + * Inputs: + * Parameters: + * stat_name Word that could not be processed + * Global Variables: + * in_tokz_esc TRUE if tokenizer is in "Tokenizer Escape" mode. + * + * Outputs: + * Returned Value: NONE + * Printout: Error message. Possible Advisory about + * + * Error Detection: + * Error was detected by the calling routine... + * + * Process Explanation: + * If the tokenizer is in "Tokenizer Escape" mode, the word might + * be one that can be used in normal tokenization mode; + * Conversely, if the tokenizer is in normal-tokenization mode, + * the word might be one that can be used in the "Escape" mode. + * Or, the word is completely unknown. + * Recognizing the current mode is handled by word_exists() + * However, we need to test for the *converse* of the current mode, + * so before we call word_exists() we are going to save and + * invert the setting of in_tokz_esc (and afterwards, of + * course, restore it...) + * + **************************************************************************** */ + +static void tokenized_word_error( char *stat_name) +{ + char *where_pt1; + char *where_pt2; + bool found_somewhere; + + bool sav_in_tokz_esc = in_tokz_esc; + in_tokz_esc = INVERSE(sav_in_tokz_esc); + + found_somewhere = word_exists( stat_name, &where_pt1, &where_pt2); + if ( found_somewhere ) + { + tokenization_error ( TKERROR, "The word %s is %s recognized " + "in tokenizer-escape mode.\n", + stat_name, sav_in_tokz_esc ? "not" : "only" ); + } else { + not_in_dict( stat_name); + } + + if ( INVERSE(exists_in_ancestor( stat_name)) ) + { + if ( found_somewhere && sav_in_tokz_esc ) + { + tokenization_error(INFO, + "%s is defined %s%s", stat_name, where_pt1, where_pt2 ); + show_node_start(); + } + } + + in_tokz_esc = sav_in_tokz_esc; +} + + +/* ************************************************************************** + * + * Function name: unresolved_instance + * Synopsis: Print the "unresolved instance" message + * + * Inputs: + * Parameters: + * severity Severity of the Message + * Local Static Variables: + * instance_filename File where "instance" invoked + * instance_lineno Line number where "instance" invoked + * + * Outputs: + * Returned Value: NONE + * Printout: Message. + * + * Error Detection: + * Error was detected by the calling routine... + * + **************************************************************************** */ + +static void unresolved_instance( int severity) +{ + tokenization_error( severity, "Unresolved "INSTANCE"" ); + just_where_started( instance_filename, instance_lineno ); +} + + +/* ************************************************************************** + * + * Function name: modified_by_instance + * Synopsis: Print the "[not] modified by instance" message + * + * Inputs: + * Parameters: + * definer Internal token for the defining-word + * was_modded FALSE if "not modified..." + * Local Static Variables: + * instance_filename File where "instance" invoked + * instance_lineno Line number where "instance" invoked + * + * Outputs: + * Returned Value: NONE + * Printout: WARNING message. + * + * Error Detection: + * Error was detected by the calling routine... + * + **************************************************************************** */ + +static void modified_by_instance( fwtoken definer, bool was_modded) +{ + char *was_not = was_modded ? "was" : "not" ; + char *defn_type_name; + + /* No need to check the return value */ + definer_name(definer, &defn_type_name); + + tokenization_error ( WARNING, + "%s definition %s modified by "INSTANCE"", + defn_type_name, was_not ); + just_where_started( instance_filename, instance_lineno ); + } + +/* ************************************************************************** + * + * Function name: validate_instance + * Synopsis: If "instance" is in effect, check whether it is + * appropriate to the defining-word being called. + * + * Inputs: + * Parameters: + * definer Internal token for the defining-word + * Local Static Variables: + * is_instance TRUE if "instance" is in effect. + * instance_definer_gap TRUE if invalid definer(s) invoked + * since "instance" went into effect. + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * is_instance Reset to FALSE if definer was valid. + * instance_definer_gap TRUE if definer was not valid; + * FALSE if definer was valid. + * + * Error Detection: + * If "instance" is in effect, the only defining-words that are + * valid are: value variable defer or buffer: Attempts + * to use any other defining-word will be reported with a + * WARNING, but "instance" will remain in effect. + * If an invalid defining-word was invoked since "instance" went + * into effect, then, when it is finally applied to a valid + * definer, issue a WARNING. + * + * Process Explanation: + * Implicit in the Standard is the notion that, once INSTANCE has + * been executed, it remains in effect until a valid defining- + * word is encountered. We will do the same. + * + **************************************************************************** */ + +static void validate_instance(fwtoken definer) +{ + if ( is_instance ) + { + bool is_error = TRUE ; + + switch ( definer) + { + case VALUE: + case VARIABLE: + case DEFER: + case BUFFER: + is_error = FALSE; + /* No default needed, likewise, no breaks; */ + /* but some compilers get upset without 'em... */ + default: + break; + } + + if( is_error ) + { + modified_by_instance(definer, FALSE ); + instance_definer_gap = TRUE; + }else{ + if ( instance_definer_gap ) + { + modified_by_instance(definer, TRUE ); + } + is_instance = FALSE; + instance_definer_gap = FALSE; + } + } +} + + +/* ************************************************************************** + * + * Function name: trace_creation + * Synopsis: If the word being created is on the Trace List, + * display the appropriate message + * + * Inputs: + * Parameters: + * definer Internal token for the defining-word + * nu_name The word being created + * Global Variables: + * verbose No point in doing all this if we're + * not showing the message anyway... + * in_tokz_esc TRUE if we are in Tokenizer-Escape mode + * scope_is_global TRUE if "global" scope is in effect + * current_device_node Current dev-node data-struct + * + * Outputs: + * Returned Value: NONE + * Printout: + * Advisory Message, if the word is on the Trace List. + * + * Process Explanation: + * The order of scope-checking is important: + * A Local has no scope beyond the definition in which it occurs. + * Tokenizer-Escape mode supercedes "Normal" mode, and renders + * moot the differences between Global and Device scope. + * Global scope is mutually exclusive with Device scope. + * Device scope needs to identify where the Current device-node + * began. + * + **************************************************************************** */ + +void trace_creation( fwtoken definer, char *nu_name) +{ + if ( verbose ) + { + if ( is_on_trace_list( nu_name) ) + { + char as_what[96] = ""; + bool show_last_colon = BOOLVAL( definer == LOCAL_VAL); + + as_a_what( definer, as_what); /* No need to check return value. */ + + /* Scope-checking starts here, unless show_last_colon is TRUE. + * Come out of this with as_what[] filled up and + * terminated with a new-line, if appropriate, + */ + while ( ! show_last_colon ) + { + strcat( as_what, " "); + + if ( in_tokz_esc ) + { + strcat( as_what, in_tkz_esc_mode); + break; + } + + if ( scope_is_global ) + { + strcat( as_what, "with Global scope.\n"); + }else{ + /* In Device scope. Show the Current node. */ + strcat( as_what, in_what_node( current_device_node)); + } + break; + + } /* Destination of BREAKs ... */ + + tokenization_error(INFO, "Creating %s %s", nu_name, as_what); + + if ( show_last_colon ) + { + in_last_colon(); + }else{ + show_node_start(); + } + + } + } +} + +/* ************************************************************************** + * + * Function name: create_word + * Synopsis: + * + * Inputs: + * Parameters: + * definer Internal token for the defining-word + * Global Variables: + * control_stack_depth Number of "Control Stack" entries in effect + * nextfcode FCode-number to be assigned to the new name + * statbuf Symbol last read from the input stream + * pc Input-source Scanning pointer + * hdr_flag State of headered-ness for name-creation + * force_tokens_case If TRUE, force token-names' case in FCode + * force_lower_case_tokens + * If force_tokens_case is TRUE, this + * determines which case to force + * iname Input-source file name; for error-reporting + * lineno Input-source Line number; also for err-rep't + * + * Outputs: + * Returned Value: TRUE if successful + * Global Variables: + * nextfcode Incremented (by bump_fcode() ) + * statbuf Advanced to next symbol; must be re-read + * pc Advanced, then restored to previous value + * Memory Allocated + * Copy of the name being defined, by support routine. + * Copy of input-source file name, for error-reporting + * When Freed? + * Copy of name being defined is freed when Current Device Vocab + * is "finished", or at end of tokenization. + * Copy of input-source file name is freed at end of this routine. + * + * Error Detection: + * ERROR if already inside a colon-definition. Discontinue + * processing and return FALSE. + * ERROR if inside a control-structure. Continue processing, + * though, to catch other errors, and even return TRUE; + * except: leave the new token undefined. + * Warning on duplicate name (subject to command-line control) + * Message if name is excessively long; Warning if headerless. + * FATAL if the value of nextfcode is larger than the legal + * maximum for an FCode, (0x0fff). + * + * Revision History: + * Updated Thu, 24 Mar 2005 by David L. Paktor + * Optional warning when name about to be created is a + * duplicate of an existing name. + * Updated Wed, 30 Mar 2005 by David L. Paktor + * Warning when name length exceeds ANSI-specified max (31 chars). + * Updated Tue, 05 Apr 2005 by David L. Paktor + * Add "definer" parameter and call to add_definer() . Part + * of the mechanism to forbid attempts to use the TO + * directive to change values of CONSTANTs in particular + * and of inappropriate targets in general. + * Updated Fri, 06 May 2005 by David L. Paktor + * Error-detection of DO ... LOOP and BEGIN ... imbalance + * Error-detection of nextfcode exceeding legal maximum (0x0fff). + * Updated Wed, 20 Jul 2005 by David L. Paktor + * Put Duplicate-Name-Test under command-line control... + * Updated Wed, 24 Aug 2005 by David L. Paktor + * Error-detection via clear_control_structs() routine. + * Updated Tue, 10 Jan 2006 by David L. Paktor + * Convert to tic_hdr_t type vocabulary. + * Updated Thu, 20 Apr 2006 by David L. Paktor + * Allow creation of new definition within body of a flow-control + * structure. (Remove error-detection via clear_control_structs) + * Updated Tue, 13 Jun 2006 by David L. Paktor + * Move detection of out-of-bounds nextfcode to assigning_fcode() + * routine, which also detects Overlapping Ranges error. + * Updated Thu, 27 Jun 2006 by David L. Paktor + * Report Error for attempt to create def'n inside control structure. + * + * Extraneous Remarks: + * We must not set incolon to TRUE (if we are creating a colon + * definition) until *AFTER* this routine has been called, due + * to the initial error-checking. If we need to detect whether + * we are creating a colon definition, we can do so by testing + * whether the parameter, DEFINER, equals COLON . + * + **************************************************************************** */ + +static bool create_word(fwtoken definer) +{ + signed long wlen; + bool retval = FALSE; + char *defn_type_name; + + /* If already inside a colon, ERROR and discontinueprocessing */ + /* If an alias to a definer is used, show the name of the alias */ + if ( test_in_colon(statbuf, FALSE, TKERROR, NULL) ) + { + char defn_type_buffr[32] = ""; + unsigned int old_lineno = lineno; /* For error message */ + bool define_token = TRUE; + + { /* Set up definition-type text for error-message */ + + /* No need to check the return value */ + definer_name(definer, &defn_type_name); + + strcat( defn_type_buffr, defn_type_name); + strcat( defn_type_buffr, " definition"); + } + /* If in a control-structure, ERROR but continue processing */ + if ( control_stack_depth != 0 ) + { + announce_control_structs( TKERROR, defn_type_buffr, 0); + /* Leave the new token undefined. */ + define_token = FALSE; + } + + /* Get the name of the new token */ + wlen = get_word(); + #ifdef DEBUG_SCANNER printf("%s:%d: debug: defined new word %s, fcode no 0x%x\n", iname, lineno, name, nextfcode); #endif - add_token(nextfcode, name); - if (flags) { - if (flags&FLAG_EXTERNAL) - emit_token("external-token"); - else - emit_token("named-token"); - emit_string((u8 *)name, wlen); - } else - emit_token("new-token"); + if ( wlen <= 0 ) + { + warn_unterm( TKERROR, defn_type_buffr, old_lineno); + }else{ + bool emit_token_name = TRUE; + + /* Handle Tracing of new definitions */ + trace_creation( definer, statbuf); + + /* Other Error or Warnings as applicable */ + validate_instance( definer); + warn_if_duplicate( statbuf); + check_name_length( wlen); + + /* Bump FCode; error-check as applicable */ + assigning_fcode(); + + /* Define the new token, unless disallowed */ + add_to_current( statbuf, nextfcode, definer, define_token); + + /* Emit appropriate FCodes: Type of def'n, */ + switch ( hdr_flag ) + { + case FLAG_HEADERS: + emit_token("named-token"); + break; + + case FLAG_EXTERNAL: + emit_token("external-token"); + break; + + default: /* FLAG_HEADERLESS */ + emit_token("new-token"); + emit_token_name = FALSE; + } + + /* Emit name of token, if applicable */ + if ( emit_token_name ) + { + if ( force_tokens_case ) + { + if ( force_lower_case_tokens ) + { + strlwr( statbuf); + }else{ + strupr( statbuf); + } + } + emit_string((u8 *)statbuf, wlen); + } + + /* Emit the new token's FCode */ + emit_fcode(nextfcode); + + /* Prepare FCode Assignment Counter for next definition */ + bump_fcode(); + + /* Declare victory */ + retval = TRUE; + } + } + return( retval); +} + + +/* ************************************************************************** + * + * Function name: cannot_apply + * Synopsis: Print error message of the form: + * "Cannot apply <func> to <targ>, which is a <def'n>" + * + * Inputs: + * Parameters: + * func_nam The name of the function + * targ_nam The name of the target + * defr The numeric-code of the definer-type + * + * Outputs: + * Returned Value: NONE + * Printout: + * The error message is the entire printout of this routine + * + * Error Detection: + * Error was detected by calling routine + * + * Process Explanation: + * The calling routine already looked up the definer for its + * own purposes, so we don't need to do that again here. + * + * Still to be done: + * If the definer-name is not found, we might still look up + * the target name in the various vocabularies and use + * a phrase for those. E.g., if it is a valid token, + * we could say it's defined as a "primitive". (I'm + * not sure what we'd say about an FWord...) + * + **************************************************************************** */ + +static void cannot_apply( char *func_nam, char *targ_nam, fwtoken defr) +{ + char *defr_name = "" ; + const char *defr_phrase = ", which is defined as a " ; + + if ( ! definer_name(defr, &defr_name) ) + { + defr_phrase = ""; + } + + tokenization_error ( TKERROR , + "Cannot apply %s to %s %s%s.\n", + func_nam, targ_nam, defr_phrase, defr_name ); + +} + + +/* ************************************************************************** + * + * Function name: lookup_with_definer + * Synopsis: Return pointer to data-structure of named word, + * if it's valid in Current context, and supply its + * definer. If it's not valid in Current context, + * see if it might be a Local, and supply that definer. + * + * Inputs: + * Parameters: + * stat_name Name to look up + * *definr Pointer to place to put the definer. + * + * Outputs: + * Returned Value: Pointer to data-structure, or + * NULL if not in Current context. + * Supplied Pointers: + * *definr Definer; possibly LOCAL_VAL + * + * Process Explanation: + * If the name is not found in the Current context, and does not + * exist as a Local, *definr will remain unchanged. + * + * Extraneous Remarks: + * This is an odd duck^H^H^H^H^H^H^H^H^H^H^H^H a highly-specialized + * routine created to meet some corner-case needs engendered by + * the conversion to tic_hdr_t vocabularies all around, combined + * with an obsessive urge to preserve a high level of detail in + * our error-messages. + * + **************************************************************************** */ + +static tic_hdr_t *lookup_with_definer( char *stat_name, fwtoken *definr ) +{ + tic_hdr_t *retval = lookup_current( stat_name); + if ( retval != NULL ) + { + *definr = retval->fword_defr; + }else{ + if ( exists_as_local( stat_name) ) *definr = LOCAL_VAL; + } + return ( retval ); +} + +/* ************************************************************************** + * + * Function name: validate_to_target + * Synopsis: Print a message if the intended target + * of the TO directive is not valid + * + * Inputs: + * Parameters: NONE + * Global Variables: + * statbuf Next symbol to be read from the input stream + * pc Input-source Scanning pointer + * + * Outputs: + * Returned Value: TRUE = Allow b(to) token to be output. + * Global Variables: + * statbuf Advanced to next symbol; must be re-read + * pc Advanced, then restored to previous value + * + * Error Detection: + * If next symbol is not a valid target of TO , issue ERROR + * message. Restored pc will cause the next symbol to + * be processed by ordinary means. + * Allow b(to) token to be output in selected cases. Even if + * user has set the "Ignore Errors" flag, certain targets are + * still too risky to be allowed to follow a b(to) token; + * if "Ignore Errors" is not set, output won't get created + * anyway. + * Issue ERROR in the extremely unlikely case that "to" is the + * last word in the Source. + * + * Process Explanation: + * Valid targets for a TO directive are words defined by: + * DEFER, VALUE and arguably VARIABLE. We will also allow + * CONSTANT, but will still issue an Error message. + * After the check, restore pc ; this was only a look-ahead. + * Also restore lineno and abs_token_no + * + * Extraneous Remarks: + * Main part of the mechanism to detect attempts to use the TO + * directive to change the values of CONSTANTs in particular + * and of inappropriate targets in general. + * + **************************************************************************** */ + +static bool validate_to_target( void ) +{ + signed long wlen; + tic_hdr_t *test_entry; + u8 *saved_pc = pc; + char *cmd_cpy = strupr( strdup( statbuf)); /* For error message */ + unsigned int saved_lineno = lineno; + unsigned int saved_abs_token_no = abs_token_no; + fwtoken defr = UNSPECIFIED ; + bool targ_err = TRUE ; + bool retval = FALSE ; + + wlen = get_word(); + if ( wlen <= 0 ) + { + warn_unterm( TKERROR, cmd_cpy, saved_lineno); + }else{ + + test_entry = lookup_with_definer( statbuf, &defr); + if ( test_entry != NULL ) + { + switch (defr) + { + case VARIABLE: + tokenization_error( WARNING, + "Applying %s to a VARIABLE (%s) is " + "not recommended; use ! instead.\n", + cmd_cpy, statbuf); + case DEFER: + case VALUE: + targ_err = FALSE ; + case CONST: + retval = TRUE ; + /* No default needed, likewise, no breaks; */ + /* but some compilers get upset without 'em... */ + default: + break; + } + } + + if ( targ_err ) + { + cannot_apply(cmd_cpy, strupr(statbuf), defr ); + } + + pc = saved_pc; + lineno = saved_lineno; + abs_token_no = saved_abs_token_no; + } + free( cmd_cpy); + return( retval); +} + + +/* ************************************************************************** + * + * Function name: you_are_here + * Synopsis: Display a generic Advisory of the Source command + * or directive encountered and being processed + * + * Inputs: + * Parameters: NONE + * Global Variables: + * statbuf The command being processed + * + * Outputs: + * Returned Value: NONE + * Printout: + * Advisory message + * + **************************************************************************** */ + +static void you_are_here( void) +{ + tokenization_error( INFO, + "%s encountered; processing...\n", + strupr(statbuf) ); +} + + +/* ************************************************************************** + * + * Function name: fcode_starter + * Synopsis: Respond to one of the "FCode Starter" words + * + * Inputs: + * Parameters: + * token_name The FCode-token for this "Starter" word + * spread The separation between tokens. + * is_offs16 Whether we are using a 16-bit number + * for branch- (and suchlike) -offsets, + * or the older-style 8-bit offset numbers. + * Global Variables: + * iname Input-File name, used to set ifile_name + * field of current_device_node + * lineno Current Input line number, used to set + * line_no field of current_device_node + * Local Static Variables: + * fcode_started If this is TRUE, we have an Error. + * first_fc_starter Control calling reset_fcode_ranges() ; + * only on the first fcode_starter of + * a tokenization. + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * offs16 Global "16-bit-offsets" flag + * current_device_node The ifile_name and line_no fields will be + * loaded with the current input file name + * and line number. This node will be the + * top-level device-node. + * FCode Ranges will be reset the first time per tokenization + * that this routine is entered. + * A new FCode Range will be started every time after that. + * Local Static Variables: + * fcode_started Set to TRUE. We invoke the starter only + * once per image-block. + * first_fc_starter Reset to FALSE if not already + * Memory Allocated + * Duplicate of Input-File name + * When Freed? + * In fcode_ender() + * + * Error Detection: + * Spread of other than 1 -- Warning message. + * "FCode Starter" previously encountered -- Warning and ignore. + * + * Question under consideration: + * Do we want directives -- such as definitions of constants -- + * supplied before the "FCode Starter", to be considered as + * taking place in "Tokenizer Escape" mode? That would mean + * the "Starter" functions must be recognized in "Tokenizer + * Escape" mode. Many ramifications to be thought through... + * I think I'm coming down strongly on the side of "No". The user + * who wants to do that can very well invoke "Tokenizer Escape" + * mode explicitly. + * + **************************************************************************** */ + +static void fcode_starter( const char *token_name, int spread, bool is_offs16) +{ + you_are_here(); + if ( spread != 1 ) + { + tokenization_error( WARNING, "spread of %d not supported.\n", spread); + } + if ( fcode_started ) + { + tokenization_error( WARNING, + "Only one "FCode Starter" permitted per tokenization. " + "Ignoring...\n"); + } else { + + emit_fcodehdr(token_name); + offs16 = is_offs16; + fcode_started = TRUE; + + current_device_node->ifile_name = strdup(iname); + current_device_node->line_no = lineno; + + if ( first_fc_starter ) + { + reset_fcode_ranges(); + first_fc_starter = FALSE; + }else{ + set_next_fcode( nextfcode); + } + } +} + +/* ************************************************************************** + * + * Function name: fcode_end_err_check + * Synopsis: Do error-checking at end of tokenization, + * whether due to FCODE-END or end-of-file, + * and reset the indicators we check. + * + * Inputs: + * Parameters: NONE + * Global Variables: + * Data-Stack depth Is anything left on the stack? + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * Data-Stack Reset to empty + * + * Error Detection: + * Unresolved control structures detected by clear_control_structs() + * If anything is left on the stack, it indicates some incomplete + * condition; we will treat it as a Warning. + * + **************************************************************************** */ + +static void fcode_end_err_check( void) +{ + bool stack_imbal = BOOLVAL( stackdepth() != 0 ); + + if ( stack_imbal ) + { + tokenization_error( WARNING, + "Stack imbalance before end of tokenization.\n"); + } + clear_stack(); + clear_control_structs("End of tokenization"); +} + +/* ************************************************************************** + * + * Function name: fcode_ender + * Synopsis: Respond to one of the "FCode Ender" words: + * The FCode-token for "End0" or "End1" + * has already been written to the + * FCode Output buffer. + * Finish the FCode header: fill in its + * checksum and length. + * Reset the token names defined in "normal" mode + * (Does not reset the FCode-token number) + * + * Associated FORTH words: END0, END1 + * Associated Tokenizer directive: FCODE-END + * + * Inputs: + * Parameters: NONE + * Global Variables: + * incolon If TRUE, a colon def'n has not been completed + * last_colon_filename For error message. + * last_colon_lineno For error message. + * scope_is_global For error detection + * is_instance For error detection + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * haveend Set to TRUE + * fcode_started Reset to FALSE. Be ready to start anew. + * FCode-defined tokens, aliases and macros -- i.e., those + * *NOT* defined in tokenizer-escape mode -- are reset. + * (Also, command-line-defined symbols are preserved). + * Vocabularies will be reset + * Device-node data structures will be deleted + * Top-level device-node ifile_name and line_no fields + * will be reset. + * Memory Freed + * Duplicate of Input-File name, in top-level device-node. + * Printout: + * Advisory message giving current value of nextfcode + * (the "FCode-token Assignment Counter") + * + * Error Detection: + * ERROR if a Colon definition has not been completed. + * ERROR if "instance" is still in effect + * WARNING if Global-Scope has not been terminated; compensate. + * + * Extraneous Remarks: + * In order to accommodate odd cases, such as multiple FCode blocks + * within a single PCI header, this routine does not automatically + * reset nextfcode to h# 0800 + * + **************************************************************************** */ + +void fcode_ender(void) +{ + if ( incolon ) + { + char *tmp_iname = iname; + iname = last_colon_filename; + unterm_is_colon = TRUE; + warn_unterm( TKERROR, "Colon Definition", last_colon_lineno); + iname = tmp_iname; + } + + haveend = TRUE; + + if ( is_instance ) + { + unresolved_instance( TKERROR); + } + + if ( scope_is_global ) + { + tokenization_error( WARNING , + "No DEVICE-DEFINITIONS directive encountered before end. " + "Compensating...\n"); + resume_device_scope(); + } + fcode_end_err_check(); + reset_normal_vocabs(); + finish_fcodehdr(); + fcode_started = FALSE; + + if ( current_device_node->ifile_name != default_top_dev_ifile_name ) + { + free( current_device_node->ifile_name ); + current_device_node->ifile_name = default_top_dev_ifile_name; + current_device_node->line_no = 0; + } +} + +/* ************************************************************************** + * + * Function name: get_token + * Synopsis: Read the next word in the input stream and retrieve + * its FCode-token number. If it's not a symbol to + * which a single token is assigned (e.g., if it's + * a macro), report an error. + * + * Associated FORTH words: ['] ' + * Associated Tokenizer directive: F['] + * + * Inputs: + * Parameters: + * *tok_entry Place to put the pointer to token entry + * Global Variables: + * statbuf The command being processed + * pc Input stream character pointer + * + * Outputs: + * Returned Value: TRUE if successful (i.e., no error) + * Supplied Pointers: + * *tok_entry The token entry, if no error + * Global Variables: + * statbuf The next word in the input stream + * pc Restored to previous value if error + * + * Error Detection: + * The next word in the input stream is expected to be on the + * same line as the directive. The get_word_in_line() + * routine will check for that. + * If the next word in the input stream is not a symbol + * for which a single-token FCode number is assigned, + * report an ERROR and restore PC to its previous value. + * + **************************************************************************** */ + +static bool get_token(tic_hdr_t **tok_entry) +{ + bool retval = FALSE; + u8 *save_pc; + + /* Copy of command being processed, for error message */ + char cmnd_cpy[FUNC_CPY_BUF_SIZE+1]; + strncpy( cmnd_cpy, statbuf, FUNC_CPY_BUF_SIZE); + cmnd_cpy[FUNC_CPY_BUF_SIZE] = 0; /* Guarantee null terminator. */ + + save_pc = pc; + + if ( get_word_in_line( statbuf) ) + { + fwtoken defr = UNSPECIFIED; + + /* We need to scan the newest definitions first; they + * might supercede standard ones. We need, though, + * to bypass built-in FWords that need to trigger + * some tokenizer internals before emitting their + * synonymous FCode Tokens, (e.g., version1 , end0 , + * and start{0-4}); if we find one of those, we will + * need to search again, specifically within the list + * of FCode Tokens. + */ + *tok_entry = lookup_with_definer( statbuf, &defr); + if ( *tok_entry != NULL ) + { + /* Built-in FWords can be uniquely identified by their + * definer, BI_FWRD_DEFN . The definer for "shared" + * FWords is COMMON_FWORD but there are none of + * those that might be synonymous with legitimate + * FCode Tokens, nor are any likely ever to be... + */ + if ( defr == BI_FWRD_DEFN ) + { + *tok_entry = lookup_token( statbuf); + retval = BOOLVAL( *tok_entry != NULL ); + }else{ + retval = entry_is_token( *tok_entry); + } + } + + if ( INVERSE( retval) ) + { + cannot_apply( cmnd_cpy, strupr(statbuf), defr ); + pc = save_pc; + } + } + + return ( retval ); +} + + +static void base_change ( int new_base ) +{ + if ( incolon && ( INVERSE( in_tokz_esc) ) ) + { + emit_literal(new_base ); + emit_token("base"); + emit_token("!"); + } else { + base = new_base; + } +} + +static void base_val (int new_base) +{ + u8 *old_pc; + + char base_cmnd[FUNC_CPY_BUF_SIZE+1]; + strncpy( base_cmnd, statbuf, FUNC_CPY_BUF_SIZE); + base_cmnd[FUNC_CPY_BUF_SIZE] = 0; /* Guarantee NULL terminator */ + + old_pc=pc; + if ( get_word_in_line( statbuf) ) + { + u8 basecpy=base; + + base = new_base; + if ( ! handle_number() ) + { + /* We did get a word on the line, but it's not a valid number */ + tokenization_error( WARNING , + "Applying %s to non-numeric value. Ignoring.\n", + strupr(base_cmnd) ); + pc = old_pc; + } + base=basecpy; + } +} + + +/* ************************************************************************** + * + * Function name: eval_string + * Synopsis: Prepare to tokenize a string, artificially generated + * by this program or created as a user-defined + * Macro. When done, resume at existing source. + * Keep the file-name and line-number unchanged. + * + * Inputs: + * Parameters: + * inp_bufr String (or buffer) to evaluate + * + * Outputs: + * Returned Value: NONE + * Global Variables, changed by call to init_inbuf(): + * start Points to given string + * pc ditto + * end Points to end of given string + * + * Revision History: + * Updated Thu, 23 Feb 2006 by David L. Paktor + * This routine no longer calls its own instance of tokenize() + * It has become the gateway to the mechanism that makes a + * smooth transition between the body of the Macro, User- + * defined Symbol or internally-generated string and the + * resumption of processing the source file. + * A similar (but more complicated) transition when processing + * an FLOADed file will be handled elsewhere. + * Updated Fri, 24 Feb 2006 by David L. Paktor + * In order to support Macro-recursion protection, this routine + * is no longer the gateway for Macros; they will have to + * call push_source() directly. + * + **************************************************************************** */ + +void eval_string( char *inp_bufr) +{ + push_source( NULL, NULL, FALSE); + init_inbuf( inp_bufr, strlen(inp_bufr)); +} + + +/* ************************************************************************** + * + * Function name: finish_or_new_device + * Synopsis: Handle the shared logic for the NEW-DEVICE and + * FINISH-DEVICE commands. + * + * Inputs: + * Parameters: + * finishing_device TRUE for FINISH-DEVICE, + * FALSE for NEW-DEVICE + * Global Variables: + * incolon TRUE if inside a colon definition + * noerrors TRUE if ignoring errors + * scope_is_global TRUE if "global scope" in effect + * Local Static Variables: + * is_instance TRUE if "instance" is in effect + * dev_change_instance_warning TRUE if warning hasn't been issued + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * dev_change_instance_warning FALSE if warning is issued + * instance_definer_gap TRUE if "instance" is in effect + * + * Error Detection: + * NEW-DEVICE and FINISH-DEVICE should not be used outside of + * a colon-definition if global-scope is in effect. Error + * message; no further action unless we are ignoring errors. + * Issue a WARNING if INSTANCE wasn't resolved before the current + * device-node is changed. Try not to be too repetitive... + * + * Process Explanation: + * The words NEW-DEVICE and FINISH-DEVICE may be incorporated into + * a colon-definition, whether the word is defined in global- + * or device- -scope. Such an incorporation does not effect + * a change in the device-node vocabulary; simply emit the token. + * If we are in interpretation mode, though, we need to check for + * errors before changing the device-node vocabulary: + * If global-scope is in effect, we need to check whether we are + * ignoring errors; if so, we will compensate by switching to + * device-scope. + * If "instance" is in effect, it's "dangling". It will remain + * in effect through a device-node change, but this is very + * bad style and deserves a WARNING, but only one for each + * occurrence. It would be unaesthetic, to say the least, + * to have multiple messages for the same dangling "instance" + * in a "finish-device new-device" sequence. + * We must be careful about the order we do things, because of + * the messages printed as a side-effect of the node change... + * + * Extraneous Remarks: + * I will violate strict structure here. + * + **************************************************************************** */ + +static void finish_or_new_device( bool finishing_device ) +{ + if ( INVERSE( incolon ) ) + { + if ( INVERSE( is_instance) ) + { + /* Arm warning for next time: */ + dev_change_instance_warning = TRUE; + }else{ + /* Dangling "instance" */ + instance_definer_gap = TRUE; + /* Warn only once. */ + if ( dev_change_instance_warning ) + { + unresolved_instance( WARNING); + dev_change_instance_warning = FALSE; + } + } + + /* Note: "Instance" cannot be in effect during "global" scope */ + if ( scope_is_global ) + { + glob_not_allowed( TKERROR, noerrors ); + if ( noerrors ) + { + resume_device_scope(); + }else{ + return; + } + } + + if ( finishing_device ) + { + finish_device_vocab(); + }else{ + new_device_vocab(); + } + } + emit_token( finishing_device ? "finish-device" : "new-device" ); + } - emit_fcode(nextfcode); - nextfcode++; + +/* ************************************************************************** + * + * Function name: abort_quote + * Synopsis: Optionally implement the ABORT" function as + * though it were a macro. Control whether to allow + * it, and which style to support, via switches set + * on the command-line at run-time. + * + * Inputs: + * Parameters: + * tok Numeric-code associated with the + * FORTH word that was just read. + * Global Variables: + * enable_abort_quote Whether to allow ABORT" + * sun_style_abort_quote SUN-style versus Apple-style + * abort_quote_throw Whether to use -2 THROW vs ABORT + * + * Outputs: + * Returned Value: TRUE if it was handled + * Global Variables: + * report_multiline Reset to FALSE. + * Printout: + * ADVISORY: ABORT" in fcode is not defined by IEEE 1275-1994 + * + * Error Detection: + * Performed by other routines. If user selected not to + * allow ABORT" , it will simply be treated as an + * unknown word. + * The string following it, however, will still be consumed. + * + * Process Explanation: + * If the supplied tok was not ABORTTXT , then return FALSE. + * If the enable_abort_quote flag is FALSE, consume the + * string following the Abort" token, but be careful to + * leave the Abort" token in statbuf, as it will be used + * for the error message. + * Otherwise, create and prepare for processing the appropriate Macro: + * For Apple Style, we push the specified string onto the stack + * and do -2 THROW (and hope the stack unwinds correctly). + * For Sun Style, we test the condition on top of the stack, + * and if it's true, print the specified string before we + * do the -2 THROW. + * We perform the underlying operations directly: placing an "IF" + * (if Sun Style), then placing the string. This bypasses + * any issues of double-parsing, as well as of doubly checking + * for a multi-line string. + * Finally, we perform the operational equivalents of the remainder + * of the command sequence. + * + * Extraneous Remarks: + * I would have preferred not to have to directly perform the under- + * lying operations, and instead simply prepare the entire command + * sequence in a buffer, but I needed to handle the case where + * quote-escaped quotes are included in the string: If the string + * were simply to be reproduced into the buffer, the quote-escaped + * quotes would appear as plain quote-marks and terminate the + * string parsing prematurely, leaving the rest of the string + * to be treated as code instead of text... + * Also, the introduction of the variability of whether to do the + * -2 THROW or to compile-in the token for ABORT makes the + * buffer-interpretation scheme somewhat too messy for my tastes. + * + **************************************************************************** */ + +static bool abort_quote( fwtoken tok) +{ + bool retval = FALSE; + if ( tok == ABORTTXT ) + { + if ( ! enable_abort_quote ) + { + /* ABORT" is not enabled; we'd better consume the string */ + char *save_statbuf; + signed long wlen; + save_statbuf = strdup( (char *)statbuf); + wlen = get_string( FALSE); + strcpy( statbuf, save_statbuf); + free( save_statbuf); + }else{ + /* ABORT" is not to be used in FCODE drivers + * but Apple drivers do use it. Therefore we + * allow it. We push the specified string to + * the stack, do -2 THROW and hope that THROW + * will correctly unwind the stack. + * Presumably, Apple Source supplies its own + * IF ... THEN + */ + char *abort_string; + signed long wlen;
- return 0; + retval = TRUE; + tokenization_error (INFO, "ABORT" in fcode not " + "defined by IEEE 1275-1994\n"); + test_in_colon("ABORT"", TRUE, TKERROR, NULL); + wlen=get_string( TRUE); + + if ( sun_style_abort_quote ) emit_if(); + + emit_token("b(")"); + emit_string(statbuf, wlen); + + if ( sun_style_abort_quote ) emit_token("type"); + + if ( abort_quote_throw ) + { + emit_literal( -2); + emit_token("throw"); + }else{ + emit_token("abort"); + } + + if ( sun_style_abort_quote ) emit_then(); + /* Sun Style */ + abort_string = " type -2 THROW THEN:" ; } + } + return( retval ); +}
-static void encode_file( const char *filename ) + +/* ************************************************************************** + * + * Function name: create_alias + * Synopsis: Create an alias, as specified by the user + * + * Associated FORTH word: ALIAS + * + * Inputs: + * Parameters: NONE + * Global Variables: + * incolon Colon-def'n-in-progress indicator + * in_tokz_esc "Tokenizer Escape" mode indicator + * Input Stream + * Two words will be read. + * + * Outputs: + * Returned Value: TRUE if succeeded. + * Global Variables: + * statbuf New name will be copied back into here. + * Memory Allocated + * The two words will be copied into freshly-allocated memory + * that will be passed to the create_..._alias() routine. + * When Freed? + * When Current Device Vocabulary is "finished", or at end + * of tokenization, or upon termination of program. + * If not able to create alias, the copies will be freed here. + * + * Error Detection: + * If the ALIAS command was given during colon-definition, that + * can be handled by this tokenizer, but it is not supported + * by IEEE 1275-1994. Issue a WARNING. + * If the new name is a copy of an existing word-name, issue a warning. + * If the word to which an alias is to be created does not exist + * in the appropriate mode -- relative to "Tokenizer-Escape" -- + * that is an ERROR. + * If "instance" is in effect, the ALIAS command is an ERROR. + * + * Process Explanation: + * Get two words -- the new name and the "old" word -- from the + * same line of input as the ALIAS command. + * Copy the new name back into statbuf for use in trace_creation. + * Determine whether or not we are in "Tokenizer-Escape" mode. + * Subsequent searches will take place in that same mode. + * If the "new" name already exists, issue a warning. + * In each vocabulary applicable to the current mode -- i.e., + * "Tokenizer-Escape" or "Normal" -- (except: cannot + * make aliases to "Locals"): + * Try using the create_..._alias() routine. + * If it succeeds, we are done. + * IMPORTANT: The order in which we try the vocabularies MUST + * match the order in which tokenize_one_word() searches them. + * If all the attempts failed, the "old" word does not exist; + * declare an ERROR and free up the memory that was allocated. + * + * Extraneous Remarks: + * With the separation of the tokenizer[ state, this + * function has become too complicated to keep as a + * simple CASE in the big SWITCH statement anymore... + * + * I had earlier thought that it was sufficient to create a + * macro linking the "new" name to the "old" word. There + * were too many cases, though, where that didn't work. + * This is cleaner. + * + * I will not be adhering to the strict rules of structure in + * this routine, as it would get me nested too deeply... + * + * Revision History: + * Updated Tue, 10 Jan 2006 by David L. Paktor + * Convert to tic_hdr_t type vocabularies. + * + **************************************************************************** */ + +static bool create_alias( void ) { - FILE *f; - size_t s; - int i=0; + char *new_alias ; + + validate_instance(ALIAS); + if ( incolon ) + { + tokenization_error ( WARNING, + "ALIAS during colon-definition " + "is not supported by IEEE 1275-1994\n"); +} + if ( get_word_in_line( "ALIAS") ) + { + + new_alias = strdup((char *)statbuf); + + if (get_word_in_line( "ALIAS") ) +{ + char *old_name = strdup((char *)statbuf) ; + + /* Copy the "new" alias name back into statbuf. + * This is a HACK ^H^H^H^H awkward way to retrofit + * support for the trace_creation() function. + */ + strcpy( statbuf, new_alias); + + /* We don't call trace_creation() here because we don't + * know if the creation succeeded. However, we want + * to issue a "Duplicate" warning based on the attempt, + * even if it doesn't succeed. + * We would prefer to have the "Trace" message precede the + * "Duplicate" warning, but we don't think it's worth + * the effort. When it becomes worthwhile, the way to + * do it would be to factor out the block that handles + * normal-tokenization versus "Tokenizer-Escape" mode; + * condition the "Trace" message on its success-return, + * show the "Duplicate" warning in any case, then show + * the error-message and do the cleanup conditioned on + * a failure-return. + * That will also obviate the need for a return value from + * this routine and for the copy-back into statbuf. + */ + warn_if_duplicate(new_alias); + + /* + * Here is where we begin trying the create_..._alias() + * routines for the vocabularies. + */ + + /* + * Distinguish between "Normal" tokenization mode + * and "Tokenizer Escape" mode + */ + if ( in_tokz_esc ) + { + if ( create_tokz_esc_alias( new_alias, old_name) ) + return(TRUE); - if( !(f=fopen(filename,"rb")) ) { - printf("%s:%d: opening '%s':\n", iname, lineno, filename ); - ERROR; - return; + /* + * Handle the classes of operatives that are common between + * "Tokenizer Escape" mode and "Normal" tokenization mode. + * Those classes include selected non-fcode forth constructs + * and Conditional-Compilation Operators. + */ + { + tic_hdr_t *found = lookup_shared_word( old_name); + if ( found != NULL ) + { + if ( create_core_alias( new_alias, old_name) ) + return(TRUE); + } } - while( (s=fread(statbuf, 1, 255, f)) ) { - emit_token("b(")"); - emit_string(statbuf, s); - emit_token("encode-bytes"); - if( i++ ) - emit_token("encode+"); + }else{ + /* "Normal" tokenization mode */ + + /* Can create aliases for "Locals", why not? */ + if ( create_local_alias( new_alias, old_name) ) + return(TRUE); + + /* + * All other classes of operatives -- non-fcode forth + * constructs, Standard and user-defined fcode + * tokens, Macros, and Conditional-Compilation + * Operators, -- are included in the "currently + * active" vocabulary. + */ + + if ( create_current_alias( new_alias, old_name) ) + return(TRUE); + + } /* End of separate handling for normal-tokenization mode + * versus "Tokenizer-Escape" mode + */ + + /* It's not a word, a macro or any of that other stuff. */ + tokenized_word_error(old_name); + free(old_name); } - fclose( f ); + free (new_alias); + } + return(FALSE); }
+ +/* ************************************************************************** + * + * Function name: string_err_check + * Synopsis: Error-check after processing or Ignoring + * simple strings + * + * Inputs: + * Parameters: + * is_paren TRUE if string is Dot-Paren .( + * FALSE if Ess-Quote ( s" ) + * sav_lineno Saved Line Number, for Unterminated Error + * strt_lineno Start Line Number, for Multiline Warning + * Global Variables: + * noerrors TRUE if ignoring errors + * Local Static Variables: + * got_until_eof TRUE if reached end of buffer before delim. + * + * Outputs: + * Returned Value: TRUE if did not reach end of buffer, or, + * if ignoring errors, TRUE anyway. + * + * Error Detection: + * Multi-line warning, "Unterminated" Error messages, as apppropriate + * + **************************************************************************** */
-static void handle_internal(u16 tok) +static bool string_err_check( bool is_paren, + unsigned int sav_lineno, + unsigned int strt_lineno ) { - unsigned long wlen; - long offs1,offs2; - u16 itok; + bool retval = noerrors ; + char *item_typ = is_paren ? + "Dot-Paren" : "Ess-Quote" ; + if ( got_until_eof ) /* Crude retrofit... */ + { + warn_unterm( TKERROR, item_typ, sav_lineno ); + }else{ + retval = TRUE; + warn_if_multiline( item_typ, strt_lineno ); + } + return( retval); +} + + +/* ************************************************************************** + * + * Function name: handle_internal + * Synopsis: Perform the functions associated with FORTH words + * that do not map directly to a single token. This + * is the functions that will go into the FUNCT field + * of entries in the "FWords" and "Shared Words" lists. + * + * Inputs: + * Parameters: + * pfield Param-field of the tic_hdr_t -type entry + * associated with the FORTH-Word (FWord) + * just read that is being "handled". + * Global Variables: + * statbuf The word that was just read. + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * statbuf More words may be read. + * + * Error Detection: + * Too numerous to list here... + * + * Process Explanation: + * Recast the type of the param-field of a tic_hdr_t -type + * entry and rename it "tok". + * The "tok" will be used as the control-expression for a + * SWITCH statement with a large number of CASE labels. + * Both "FWords" and "shared_words" list entries will + * be processed by this routine. + * + * Revision History: + * Updated Wed, 20 Jul 2005 by David L. Paktor + * Put handling of ABORT" under control of a run-time + * command-line switch. + * Put decision to support IBM-style Locals under control + * of a run-time command-line switch. + * Updated Tue, 17 Jan 2006 by David L. Paktor + * Convert to handler for tic_hdr_t type vocab entries. + * + * Extraneous Remarks: + * We would prefer to keep this function private, so we will + * declare its prototype here and in the one other file + * where we need it, namely, dictionary.c, rather than + * exporting it widely in a .h file. + * + **************************************************************************** */ + +void handle_internal( tic_param_t pfield); +void handle_internal( tic_param_t pfield) +{ + fwtoken tok = pfield.fw_token; + + signed long wlen; + unsigned int sav_lineno = lineno; /* For error message */ + + bool handy_toggle = TRUE ; /* Various uses... */ #ifdef DEBUG_SCANNER printf("%s:%d: debug: tokenizing control word '%s'\n", @@ -443,727 +4450,1087 @@ #endif switch (tok) { case BEGIN: - emit_token("b(<mark)"); - dpush((unsigned long)opc); + emit_begin(); break;
case BUFFER: - create_word(); + if ( create_word(tok) ) + { emit_token("b(buffer:)"); + } break;
case CONST: - create_word(); + if ( create_word(tok) ) + { emit_token("b(constant)"); + } break;
case COLON: - create_word(); + { + /* Collect error- -detection or -reporting items, + * but don't commit until we're sure the + * creation was a success. + */ + u16 maybe_last_colon_fcode = nextfcode ; + unsigned int maybe_last_colon_lineno = lineno; + unsigned int maybe_last_colon_abs_token_no = abs_token_no; + unsigned int maybe_last_colon_do_depth = do_loop_depth; + /* last_colon_defname + * has to wait until after call to create_word() + */ + + if ( create_word(tok) ) + { + last_colon_fcode = maybe_last_colon_fcode; + last_colon_lineno = maybe_last_colon_lineno; + last_colon_abs_token_no = maybe_last_colon_abs_token_no; + last_colon_do_depth = maybe_last_colon_do_depth; + collect_input_filename( &last_colon_filename); + /* Now we can get last_colon_defname */ + if ( last_colon_defname != NULL ) + { + free( last_colon_defname); + } + last_colon_defname = strdup(statbuf); + emit_token("b(:)"); incolon=TRUE; + hide_last_colon(); + lastcolon = opc; + } + } break; case SEMICOLON: + if ( test_in_colon("SEMICOLON", TRUE, TKERROR, NULL) ) + { + ret_stk_balance_rpt( "termination,", TRUE); + /* Clear Control Structures just back to where + * the current Colon-definition began. + */ + clear_control_structs_to_limit( + "End of colon-definition", last_colon_abs_token_no); + + if ( ibm_locals ) + { + finish_locals(); + forget_locals(); + } + emit_token("b(;)"); incolon=FALSE; + reveal_last_colon(); + } break;
case CREATE: - create_word(); + if ( create_word(tok) ) + { emit_token("b(create)"); + } break;
case DEFER: - create_word(); + if ( create_word(tok) ) + { emit_token("b(defer)"); + } break;
+ case ALLOW_MULTI_LINE: + report_multiline = FALSE; + break; + + case OVERLOAD: + if ( test_in_colon(statbuf, FALSE, WARNING, NULL) ) + { + do_not_overload = FALSE; + } + break; + + case DEFINED: + if (get_word_in_line( statbuf) ) + { + eval_user_symbol(statbuf); + } + break; + + case CL_FLAG: + if (get_word_in_line( statbuf) ) + { + set_cl_flag( statbuf, TRUE); + } + break; + + case SHOW_CL_FLAGS: + show_all_cl_flag_settings( TRUE); + break; + case FIELD: - create_word(); + if ( create_word(tok) ) + { emit_token("b(field)"); + } break;
case VALUE: - create_word(); + if ( create_word(tok) ) + { emit_token("b(value)"); + } break; case VARIABLE: - create_word(); + if ( create_word(tok) ) + { emit_token("b(variable)"); + } break;
- case EXTERNAL: - flags=FLAG_EXTERNAL; - break; - - case TOKENIZE: - emit_token("b(')"); - break; - case AGAIN: - emit_token("bbranch"); - offs1=dpop()-(unsigned long)opc; - emit_offset(offs1); + emit_again(); break;
case ALIAS: - wlen=get_word(); - name=strdup((char *)statbuf); - wlen=get_word(); - alias=strdup((char *)statbuf); - if(lookup_macro(name)) - printf("%s:%d: warning: duplicate alias\n", - iname, lineno); - add_macro(name,alias); + if ( create_alias() ) + { + trace_creation( ALIAS, statbuf); + } break;
case CONTROL: - wlen=get_word(); - emit_token("b(lit)"); - emit_num32(statbuf[0]&0x1f); + if ( get_word_in_line( statbuf) ) + { + emit_literal(statbuf[0]&0x1f); + } break;
case DO: emit_token("b(do)"); - dpush((unsigned long)opc); - emit_offset(0); - dpush((unsigned long)opc); + mark_do(); break;
case CDO: emit_token("b(?do)"); - dpush((unsigned long)opc); - emit_offset(0); - dpush((unsigned long)opc); + mark_do(); break;
case ELSE: - offs2=dpop(); - emit_token("bbranch"); - dpush((unsigned long)opc); - emit_offset(0); - emit_token("b(>resolve)"); - offs1=(unsigned long)opc; - opc=(u8 *)offs2; - offs2=offs1-(unsigned long)opc; - emit_offset(offs2); - opc=(u8 *)offs1; + emit_else(); break;
case CASE: - emit_token("b(case)"); - dpush(0); + emit_case(); break;
case ENDCASE: - /* first emit endcase, then calculate offsets. */ - emit_token("b(endcase)"); - - offs1=(unsigned long)opc; - - offs2=dpop(); - while (offs2) { - u16 tmp; - - opc=(u8 *)(ostart+offs2); + emit_endcase(); + break;
- /* we're using an fcode offset to temporarily - * store our linked list. At this point we take - * the signed fcode offset as unsigned as we know - * that the offset will always be >0. This code - * is still broken for any case statement that - * occurs after the fcode bytecode grows larger - * than 64kB - */ - tmp=receive_offset(); + case NEW_DEVICE: + handy_toggle = FALSE; + case FINISH_DEVICE: + finish_or_new_device( handy_toggle ); + break;
- offs2=(unsigned long)offs1-(unsigned long)opc; - -#if defined(DEBUG_SCANNER) - printf ("%s:%d: debug: endcase offset 0x%lx\n", - iname,lineno, (unsigned long)offs2); -#endif - emit_offset(offs2); - offs2=tmp; + case FLITERAL: + { + u32 val; + val = dpop(); + emit_literal(val); } - opc=(u8 *)offs1; break;
case OF: - emit_token("b(of)"); - dpush((unsigned long)(opc-ostart)); - emit_offset(0); + emit_of(); break;
case ENDOF: - offs1=dpop(); - emit_token("b(endof)"); + emit_endof(); + break; - offs2=dpop(); - dpush((unsigned long)(opc-ostart)); - emit_offset(offs2); - - offs2=(unsigned long)(opc-ostart); - opc=(u8 *)(ostart+offs1); - offs1=offs2-offs1; - emit_offset(offs1); - - opc=(u8 *)(ostart+offs2); + case EXTERNAL: + set_hdr_flag( FLAG_EXTERNAL ); break; case HEADERLESS: - flags=0; + set_hdr_flag( FLAG_HEADERLESS ); break; case HEADERS: - flags=FLAG_HEADERS; + set_hdr_flag( FLAG_HEADERS ); break;
case DECIMAL: /* in a definition this is expanded as macro "10 base !" */ - if (incolon) { - emit_token("b(lit)"); - emit_num32(0x0a); - emit_token("base"); - emit_token("!"); - } else - base=10; + base_change ( 0x0a ); break; case HEX: - if (incolon) { - emit_token("b(lit)"); - emit_num32(0x10); - emit_token("base"); - emit_token("!"); - } else - base=16; + base_change ( 0x10 ); break;
case OCTAL: - if (incolon) { - emit_token("b(lit)"); - emit_num32(0x08); - emit_token("base"); - emit_token("!"); - } else - base=8; + base_change ( 0x08 ); break;
case OFFSET16: if (!offs16) - printf("%s:%d: switching to " - "16bit offsets.\n", iname, lineno); + { + tokenization_error(INFO, "Switching to 16-bit offsets.\n"); + }else{ + tokenization_error(WARNING, + "Call of OFFSET16 is redundant.\n"); + } emit_token("offset16"); offs16=TRUE; break;
case IF: - emit_token("b?branch"); - dpush((unsigned long)opc); - emit_offset(0); + emit_if(); break;
- case CLEAVE: +/* ************************************************************************** + * + * Still to be done: + * Correct analysis of Return-Stack usage within Do-Loops + * or before Loop Elements like I and J or UNLOOP or LEAVE. + * + **************************************************************************** */ + case UNLOOP: + emit_token("unloop"); + must_be_deep_in_do(1); + break; + case LEAVE: emit_token("b(leave)"); + must_be_deep_in_do(1); break; + + case LOOP_I: + emit_token("i"); + must_be_deep_in_do(1); + break; + + case LOOP_J: + emit_token("j"); + must_be_deep_in_do(2); + break; case LOOP: emit_token("b(loop)"); - offs1=dpop(); - offs2=offs1-(unsigned long)opc; - emit_offset(offs2); - offs1=(unsigned long)opc; - opc=(u8 *)dpop(); - offs2=offs1-(unsigned long)opc; - emit_offset(offs2); - opc=(u8 *)offs1; + resolve_loop(); break; - case CLOOP: + case PLUS_LOOP: emit_token("b(+loop)"); - offs1=dpop(); - offs2=offs1-(unsigned long)opc; - emit_offset(offs2); - offs1=(unsigned long)opc; - opc=(u8 *)dpop(); - offs2=offs1-(unsigned long)opc; - emit_offset(offs2); - opc=(u8 *)offs1; + resolve_loop(); break;
- case GETTOKEN: - emit_token("b(')"); - wlen=get_word(); - itok=lookup_token((char *)statbuf); - if (itok==0xffff) { - printf("%s:%d: error: no such word '%s' in [']\n", - iname, lineno, statbuf); - ERROR; + + case INSTANCE: + { + bool set_instance_state = FALSE; + bool emit_instance = TRUE; + /* We will treat "instance" in a colon-definition as + * an error, but allow it to be emitted if we're + * ignoring errors; if we're not ignoring errors, + * there's no output anyway... + */ + if ( test_in_colon(statbuf, FALSE, TKERROR, NULL) ) + { /* We are in interpretation (not colon) state. */ + /* "Instance" not allowed during "global" scope */ + if ( scope_is_global ) + { + glob_not_allowed( WARNING, FALSE ); + emit_instance = FALSE; + }else{ + set_instance_state = TRUE; + } + } + if ( emit_instance ) + { + if ( set_instance_state ) + { + /* "Instance" isn't cumulative.... */ + if ( is_instance ) + { + unresolved_instance( WARNING); + } + collect_input_filename( &instance_filename); + instance_lineno = lineno; + is_instance = TRUE; + dev_change_instance_warning = TRUE; + } + emit_token("instance"); + } } - /* FIXME check size, u16 or token */ - emit_fcode(itok); break; - case ASCII: - wlen=get_word(); - emit_token("b(lit)"); - emit_num32(statbuf[0]); + case GLOB_SCOPE: + if ( test_in_colon(statbuf, FALSE, TKERROR, NULL) ) + { + if ( INVERSE( is_instance) ) + { + enter_global_scope(); + }else{ + tokenization_error( TKERROR, + "Global Scope not allowed. " + ""Instance" is in effect; issued" ); + just_where_started( instance_filename, + instance_lineno ); + } + } break;
- case CHAR: - if (incolon) - printf("%s:%d: warning: CHAR cannot be used inside " - "of a colon definition.\n", iname, lineno); - wlen=get_word(); - emit_token("b(lit)"); - emit_num32(statbuf[0]); + case DEV_SCOPE: + if ( test_in_colon(statbuf, FALSE, TKERROR, NULL) ) + { + resume_device_scope(); + } break;
+ case TICK: /* ' */ + test_in_colon(statbuf, FALSE, WARNING, "[']"); + case BRACK_TICK: /* ['] */ + { + tic_hdr_t *token_entry; + if ( get_token( &token_entry) ) + { + emit_token("b(')"); + /* Emit the token; warning or whatever comes gratis */ + token_entry->funct( token_entry->pfield); + } + } + break; + + case F_BRACK_TICK: /* F['] <name> + * emits the token-number for <name> + * Mainly useful to compute the argument + * to get-token or set-token + */ + { + tic_hdr_t *token_entry; + if ( get_token( &token_entry) ) + { + /* "Obsolete" warning doesn't come gratis here... */ + token_entry_warning( token_entry); + /* In Tokenizer-Escape mode, push the token */ + if ( in_tokz_esc ) + { + dpush( token_entry->pfield.deflt_elem); + }else{ + emit_literal( token_entry->pfield.deflt_elem); + } + } + } + break; + + case CHAR: + handy_toggle = FALSE; case CCHAR: - wlen=get_word(); - emit_token("b(lit)"); - emit_num32(statbuf[0]); + test_in_colon(statbuf, handy_toggle, WARNING, + handy_toggle ? "CHAR" : "[CHAR]" ); + case ASCII: + if ( get_word_in_line( statbuf) ) + { + emit_literal(statbuf[0]); + } break; case UNTIL: - emit_token("b?branch"); - emit_offset(dpop()-(unsigned long)opc); + emit_until(); break;
case WHILE: - emit_token("b?branch"); - dpush((unsigned long)opc); - emit_offset(0); + emit_while(); break; case REPEAT: - emit_token("bbranch"); - offs2=dpop(); - offs1=dpop(); - offs1-=(unsigned long)opc; - emit_offset(offs1); - - emit_token("b(>resolve)"); - offs1=(unsigned long)opc; - opc=(u8 *)offs2; - emit_offset(offs1-offs2); - opc=(u8 *)offs1; + emit_repeat(); break; case THEN: - emit_token("b(>resolve)"); - offs1=(unsigned long)opc; - opc=(u8 *)dpop(); - offs2=offs1-(unsigned long)opc; - emit_offset(offs2); - opc=(u8 *)offs1; + emit_then(); break;
+ case IS: + tokenization_error ( INFO, + "Substituting TO for deprecated IS\n"); case TO: + if ( validate_to_target() ) + { emit_token("b(to)"); + } break;
case FLOAD: + if ( get_word_in_line( statbuf) ) { - u8 *oldstart, *oldpc, *oldend; - char *oldiname; - int oldlineno; - - wlen=get_word(); + bool stream_ok ; - oldstart=start; oldpc=pc; oldend=end; - oldiname=iname; oldlineno=lineno; + push_source( close_stream, NULL, TRUE) ; - init_stream((char *)statbuf); - tokenize(); - close_stream(); + tokenization_error( INFO, "FLOADing %s\n", statbuf ); - iname=oldiname; lineno=oldlineno; - end=oldend; pc=oldpc; start=oldstart; + stream_ok = init_stream( statbuf ); + if ( INVERSE( stream_ok) ) + { + drop_source(); + } } break;
- case STRING: - if (*pc++=='\n') lineno++; - wlen=get_string(); + case STRING: /* Double-Quote ( " ) string */ + handy_toggle = FALSE; + case PSTRING: /* Dot-Quote ( ." ) string */ + wlen=get_string( TRUE); emit_token("b(")"); - emit_string(statbuf,wlen-1); + emit_string(statbuf, wlen); + if ( handy_toggle ) + { + emit_token("type"); + } break;
- case PSTRING: + case SSTRING: /* Ess-Quote ( s" ) string */ + handy_toggle = FALSE; + case PBSTRING: /* Dot-Paren .( string */ if (*pc++=='\n') lineno++; - wlen=get_string(); + { + unsigned int strt_lineno = lineno; + wlen = get_until( handy_toggle ? ')' : '"' ); + if ( string_err_check( handy_toggle, + sav_lineno, strt_lineno) ) + { emit_token("b(")"); - emit_string(statbuf,wlen-1); + emit_string(statbuf, wlen); + if ( handy_toggle ) + { emit_token("type"); + } + } + } break;
- case PBSTRING: - if (*pc++=='\n') lineno++; - get_until(')'); + case FUNC_NAME: + if ( test_in_colon( statbuf, TRUE, TKERROR, NULL) ) + { + if ( in_tokz_esc ) + { + tokenization_error( P_MESSAGE, "Currently" ); + in_last_colon(); + }else{ emit_token("b(")"); - emit_string(statbuf,strlen((char *)statbuf)-1); - emit_token("type"); + emit_string( last_colon_defname, + strlen( last_colon_defname) ); + /* if ( hdr_flag == FLAG_HEADERLESS ) { WARNING } */ + } + } break;
- case SSTRING: - if (*pc++=='\n') lineno++; - get_until('"'); + case IFILE_NAME: emit_token("b(")"); - emit_string(statbuf,strlen((char *)statbuf)-1); - pc++; /* skip " */ + emit_string( iname, strlen( iname) ); break;
+ case ILINE_NUM: + emit_literal( lineno); + break; + case HEXVAL: - { - u8 basecpy=base; - long val; - - base=0x10; - wlen=get_word(); - if (!get_number(&val)) { - emit_token("b(lit)"); - emit_num32(val); - } else { - printf("%s:%d: warning: illegal value in h#" - " ignored\n", iname, lineno); - } - base=basecpy; - } + base_val (0x10); break; case DECVAL: - { - u8 basecpy=base; - long val; - - base=0x0a; - wlen=get_word(); - if (!get_number(&val)) { - emit_token("b(lit)"); - emit_num32(val); - } else { - printf("%s:%d: warning: illegal value in d#" - " ignored\n", iname, lineno); - } - - base=basecpy; - } + base_val (0x0a); break; case OCTVAL: + base_val (8); + break; + + case ASC_LEFT_NUM: + handy_toggle = FALSE; + case ASC_NUM: + if (get_word_in_line( statbuf) ) { - u8 basecpy=base; - long val; - - base=0x08; - wlen=get_word(); - if (!get_number(&val)) { - emit_token("b(lit)"); - emit_num32(val); + if ( handy_toggle ) + { + ascii_right_number( statbuf); } else { - printf("%s:%d: warning: illegal value in o#" - " ignored\n", iname, lineno); + ascii_left_number( statbuf); } - - base=basecpy; } break; - case BEGINTOK: - intok=TRUE; + + case CONDL_ENDER: /* Conditional directives out of context */ + case CONDL_ELSE: + tokenization_error ( TKERROR, + "No conditional preceding %s directive\n", + strupr(statbuf) ); break;
- case EMITBYTE: - if (intok) - emit_byte(dpop()); - else - printf ("%s:%d: warning: emit-byte outside tokenizer" - " scope\n", iname, lineno); + case PUSH_FCODE: + tokenization_error( INFO, + "FCode-token Assignment Counter of 0x%x " + "has been saved on stack.\n", nextfcode ); + dpush( (long)nextfcode ); break;
- case NEXTFCODE: - if (intok) - nextfcode=dpop(); - else - printf("%s:%d: warning: next-fcode outside tokenizer" - " scope\n", iname, lineno); + case POP_FCODE: + pop_next_fcode(); break; + + case RESET_FCODE: + tokenization_error( INFO, + "Encountered %s. Resetting FCode-token " + "Assignment Counter. ", strupr(statbuf) ); + list_fcode_ranges( FALSE); + reset_fcode_ranges(); + break; - case ENDTOK: - intok=FALSE; + case EXIT: + if ( test_in_colon( statbuf, TRUE, TKERROR, NULL) + || noerrors ) + { + ret_stk_balance_rpt( NULL, FALSE); + if ( ibm_locals ) + { + finish_locals (); + } + emit_token("exit"); + } break; + + case ESCAPETOK: + enter_tokz_esc(); + break; case VERSION1: case FCODE_V1: - printf("%s:%d: using version1 header\n", iname, lineno); - emit_token("version1"); - fcode_hdr=opc; - emit_fcodehdr(); - offs16=FALSE; + tokenization_error( INFO, "Using version1 header " + "(8-bit offsets).\n"); + fcode_starter( "version1", 1, FALSE) ; break; case START1: case FCODE_V2: case FCODE_V3: /* Full IEEE 1275 */ - emit_token("start1"); - fcode_hdr=opc; - emit_fcodehdr(); - offs16=TRUE; + fcode_starter( "start1", 1, TRUE); break; case START0: - printf ("%s:%d: warning: spread of 0 not supported.", - iname, lineno); - emit_token("start0"); - fcode_hdr=opc; - emit_fcodehdr(); - offs16=TRUE; + fcode_starter( "start0", 0, TRUE); break; case START2: - printf ("%s:%d: warning: spread of 2 not supported.", - iname, lineno); - emit_token("start2"); - fcode_hdr=opc; - emit_fcodehdr(); - offs16=TRUE; + fcode_starter( "start2", 2, TRUE); break; case START4: - printf ("%s:%d: warning: spread of 4 not supported.", - iname, lineno); - emit_token("start4"); - fcode_hdr=opc; - emit_fcodehdr(); - offs16=TRUE; + fcode_starter( "start4", 4, TRUE); break; + case END1: + tokenization_error( WARNING, + "Appearance of END1 in FCode source code " + "is not intended by IEEE 1275-1994\n"); + handy_toggle = FALSE; case END0: case FCODE_END: - haveend=TRUE; - emit_token("end0"); + if ( handy_toggle ) + { + you_are_here(); + } + emit_token( handy_toggle ? "end0" : "end1" ); + fcode_ender(); + FFLUSH_STDOUT break;
- case END1: - haveend=TRUE; - emit_token("end1"); + case RECURSE: + if ( test_in_colon(statbuf, TRUE, TKERROR, NULL ) ) + { + emit_fcode(last_colon_fcode); + } break; + case RECURSIVE: + if ( test_in_colon(statbuf, TRUE, TKERROR, NULL ) ) + { + reveal_last_colon(); + } break;
+ case RET_STK_FETCH: + ret_stk_access_rpt(); + emit_token( "r@"); + break; + + case RET_STK_FROM: + ret_stk_access_rpt(); + bump_ret_stk_depth( -1); + emit_token( "r>"); + break; + + case RET_STK_TO: + bump_ret_stk_depth( 1); + emit_token( ">r"); + break; + case PCIHDR: - { - u32 classid=dpop(); - u16 did=dpop(); - u16 vid=dpop(); - - pci_hdr=opc; - emit_pcihdr(vid, did, classid); - - printf("%s:%d: PCI header vendor id=0x%04x, " - "device id=0x%04x, class=%06x\n", - iname, lineno, vid, did, classid); - } + emit_pcihdr(); break; case PCIEND: - if (!pci_hdr) { - printf("%s:%d: error: pci-header-end/pci-end " - "without pci-header\n", iname, lineno); - ERROR; - } finish_pcihdr(); + reset_fcode_ranges(); + FFLUSH_STDOUT break;
case PCIREV: - pci_revision=dpop(); - printf("%s:%d: PCI header revision=0x%04x\n", - iname, lineno, pci_revision); + pci_image_rev = dpop(); + tokenization_error( INFO, + "PCI header revision=0x%04x%s\n", pci_image_rev, + big_end_pci_image_rev ? + ". Will be saved in Big-Endian format." + : "" ); break;
case NOTLAST: - pci_is_last_image=FALSE; - printf("%s:%d: PCI header not last image!\n", - iname, lineno); + handy_toggle = FALSE; + case ISLAST: + dpush(handy_toggle); + case SETLAST: + { + u32 val = dpop(); + bool new_pili = BOOLVAL( (val != 0) ); + if ( pci_is_last_image != new_pili ) + { + tokenization_error( INFO, + new_pili ? + "Last image for PCI header.\n" : + "PCI header not last image.\n" ); + pci_is_last_image = new_pili; + } + } break; - case ABORTTXT: - /* ABORT" is not to be used in FCODE drivers - * but Apple drivers do use it. Therefore we - * allow it. We push the specified string to - * the stack, do -2 THROW and hope that THROW - * will correctly unwind the stack. - */ - - printf("%s:%d: warning: ABORT" in fcode not defined by " - "IEEE 1275-1994.\n", iname, lineno); - if (*pc++=='\n') lineno++; - wlen=get_string(); - -#ifdef BREAK_COMPLIANCE - /* IF */ - emit_token("b?branch"); - - dpush((unsigned long)opc); - emit_offset(0); -#endif - emit_token("b(")"); - emit_string(statbuf,wlen-1); -#ifdef BREAK_COMPLIANCE - emit_token("type"); -#endif - emit_token("-2"); - emit_token("throw"); -#ifdef BREAK_COMPLIANCE - /* THEN */ - emit_token("b(>resolve)"); - offs1=(unsigned long)opc; - opc=(u8 *)dpop(); - offs2=offs1-(unsigned long)opc; - emit_offset(offs2); - opc=(u8 *)offs1; -#endif + case SAVEIMG: + if (get_word_in_line( statbuf) ) + { + free(oname); + oname = strdup( statbuf ); + tokenization_error( INFO, + "Output is redirected to file: %s\n", oname); + } break;
- case FCODE_DATE: + case RESETSYMBS: + tokenization_error( INFO, + "Resetting symbols defined in %s mode.\n", + in_tokz_esc ? "tokenizer-escape" : ""normal""); + if ( in_tokz_esc ) { - time_t tt; - char fcode_date[11]; - - tt=time(NULL); - strftime(fcode_date, 11, "%m/%d.%Y", - localtime(&tt)); - emit_token("b(")"); - emit_string((u8 *)fcode_date,10); + reset_tokz_esc(); + }else{ + reset_normal_vocabs(); } break;
+ case FCODE_DATE: + handy_toggle = FALSE; case FCODE_TIME: { time_t tt; - char fcode_time[9]; + char temp_buffr[32]; tt=time(NULL); - strftime(fcode_time, 9, "%H:%M:%S", - localtime(&tt)); + if ( handy_toggle ) + { + strftime(temp_buffr, 32, "%T %Z", localtime(&tt)); + }else{ + strftime(temp_buffr, 32, "%m/%d/%Y", localtime(&tt)); + } + if ( in_tokz_esc ) + { + tokenization_error( MESSAGE, temp_buffr); + }else{ emit_token("b(")"); - emit_string((u8 *)fcode_time,8); + emit_string((u8 *)temp_buffr, strlen(temp_buffr) ); + } } break;
case ENCODEFILE: - wlen=get_word(); + if (get_word_in_line( statbuf) ) + { encode_file( (char*)statbuf ); + } break;
default: - printf("%s:%d: error: Unimplemented control word '%s'\n", - iname, lineno, statbuf); - ERROR; + /* IBM-style Locals, under control of a switch */ + if ( ibm_locals ) + { + bool found_it = TRUE; + switch (tok) { + case CURLY_BRACE: + declare_locals( FALSE); + break; + case DASH_ARROW: + assign_local(); + break; + default: + found_it = FALSE; } + if ( found_it ) break; }
-void tokenize(void) + /* Down here, we have our last chance to recognize a token. + * If abort_quote is disallowed, we will still consume + * the string. In case the string spans more than one + * line, we want to make sure the line number displayed + * in the error-message is the one on which the disallowed + * abort_quote token appeared, not the one where the + * string ended; therefore, we might need to be able to + * "fake-out" the line number... + */ { - unsigned long wlen; - u16 tok; - u8 *mac; - long val; + bool fake_out_lineno = FALSE; + unsigned int save_lineno = lineno; + unsigned int true_lineno; + if ( abort_quote( tok) ) + { break; + }else{ + if ( tok == ABORTTXT ) fake_out_lineno = TRUE; + } + true_lineno = lineno; + + if ( fake_out_lineno ) lineno = save_lineno; + tokenization_error ( TKERROR, + "Unimplemented control word '%s'\n", strupr(statbuf) ); + if ( fake_out_lineno ) lineno = true_lineno; + } + } +} - while ((wlen=get_word())!=0) { +/* ************************************************************************** + * + * Function name: skip_string + * Synopsis: When Ignoring, skip various kinds of strings. Maps + * to string-handlers in handle_internal()... + * + * Associated FORTH words: Double-Quote ( " ) string + * Dot-Quote ( ." ) string + * Ess-Quote ( s" ) string + * Dot-Paren .( string + * ABORT" (even if not enabled) + * { (Local-Values declaration) and -> (Local-Values assignment) + * are also handled if ibm_locals is enabled. + * + * Inputs: + * Parameters: + * pfield Param-field of the entry associated with + * the FWord that is being Ignored. + * Global Variables: + * statbuf The word that was just read. + * pc Input-stream pointer + * lineno Line-number, used for errors and warnings + * ibm_locals TRUE if IBM-style Locals are enabled + * + * Outputs: + * Returned Value: NONE + * + * Error Detection: + * Multi-line warnings, "Unterminated" Errors + * handled by called routines + * + * Extraneous Remarks: + * We would prefer to keep this function private, too, so we + * will declare its prototype here and in the one other + * file where we need it, namely, dictionary.c, rather + * than exporting it widely in a .h file. + * + **************************************************************************** */
- /* Filter comments */ - switch (statbuf[0]) { - case '\': - pc-=wlen; - get_until('\n'); - continue; +void skip_string( tic_param_t pfield); +void skip_string( tic_param_t pfield) +{ + fwtoken tok = pfield.fw_token; + unsigned int sav_lineno = lineno; + bool handy_toggle = TRUE ; /* Various uses... */ - case '(': - /* only a ws encapsulated '(' is a stack comment */ - if (statbuf[1]) + switch (tok) { + case STRING: /* Double-Quote ( " ) string */ + case PSTRING: /* Dot-Quote ( ." ) string */ + case ABORTTXT: /* ABORT", even if not enabled */ + get_string( FALSE); /* Don't truncate; ignoring anyway */ + /* Will handle multi-line warnings, etc. */ break; - pc-=wlen; - get_until(')'); + case SSTRING: /* Ess-Quote ( s" ) string */ + handy_toggle = FALSE; + case PBSTRING: /* Dot-Paren .( string */ if (*pc++=='\n') lineno++; + { + unsigned int strt_lineno = lineno; + get_until( handy_toggle ? ')' : '"' ); + string_err_check( handy_toggle, sav_lineno, strt_lineno ); + } + break; + + default: + /* IBM-style Locals, under control of a switch */ + if ( ibm_locals ) + { + bool found_it = TRUE; + switch (tok) { + case CURLY_BRACE: + declare_locals( TRUE); + break; + case DASH_ARROW: + get_word(); + break; + default: + found_it = FALSE; + } + if ( found_it ) break; + } + + tokenization_error ( FATAL, "Program Error. " + "Unimplemented skip-string word '%s'\n", strupr(statbuf) ); + } +} + +/* ************************************************************************** + * + * Function name: process_remark + * Synopsis: The active function for remarks (backslash-space) + * and comments (enclosed within parens) + * + * Associated FORTH word(s): \ ( + * + * Inputs: + * Parameters: + * TIC entry "parameter field", init'd to delimiter character. + * + * Outputs: + * Returned Value: NONE + * + * Error Detection: + * Warning if end-of-file encountered before delimiter. + * Warning if multi-line parentheses-delimited comment. + * + * Process Explanation: + * Skip until the delimiter. + * If end-of-file was encountered, issue Warning. + * Otherwise, and if delimiter was not new-line, + * check for multi-line with Warning. + * + **************************************************************************** */ + +void process_remark( tic_param_t pfield ) +{ + char until_char = (char)pfield.deflt_elem ; + unsigned int start_lineno = lineno; + #ifdef DEBUG_SCANNER + + get_until(until_char); printf ("%s:%d: debug: stack diagram: %s)\n", iname, lineno, statbuf); -#endif - continue; - } +#else
- /* Check whether a macro with given name exists */ + if ( skip_until( until_char) ) + { + if ( until_char == '\n' ) + { + /* Don't need any saved line number here ... */ + tokenization_error ( WARNING, + "Unterminated remark.\n"); + }else{ + warn_unterm( WARNING, "comment", start_lineno); + } + }else{ + if ( until_char != '\n' ) + { + pc++; + warn_if_multiline( "comment", start_lineno); + } + } +#endif /* DEBUG_SCANNER */ +} - mac=(u8 *)lookup_macro((char *)statbuf); - if(mac) { - u8 *oldstart, *oldpc, *oldend; -#ifdef DEBUG_SCANNER - printf("%s:%d: debug: macro %s folds out to sequence" - " '%s'\n", iname, lineno, statbuf, mac); -#endif - oldstart=start; oldpc=pc; oldend=end; - start=pc=end=mac; - end+=strlen((char *)mac); - tokenize(); +/* ************************************************************************** + * + * Function name: filter_comments + * Synopsis: Process remarks and comments in special conditions + * + * Inputs: + * Parameters: + * inword Current word just parsed + * + * Outputs: + * Returned Value: TRUE if Current word is a Comment-starter. + * Comment will be processed + * + * Process Explanation: + * We want to be able to recognize any alias the user may have + * defined to a comment-delimiter, in whatever applicable + * vocabulary it might be. + * The active-function of any such alias will, of necessity, be + * the process_remark() routine, defined just above. + * We will search for the TIC-entry of the given word; if we don't + * find it, it's not a comment-delimiter. If we do find it, + * and it is one, we invoke its active-function and return TRUE. + * We also want to permit the "allow-multiline-comments" directive + * to be processed in the context that calls this routine, so + * we will check for that condition, too. + * + **************************************************************************** */
- end=oldend; pc=oldpc; start=oldstart; +bool filter_comments( u8 *inword) +{ + bool retval = FALSE; + tic_hdr_t *found = lookup_word( inword, NULL, NULL ); - continue; + if ( found != NULL ) + { + if ( found->funct == process_remark ) + { + found->funct( found->pfield); + retval = TRUE; + }else{ + /* Permit the "allow-multiline-comments" directive */ + if ( found->funct == handle_internal ) + { + if ( found->pfield.fw_token == ALLOW_MULTI_LINE ) + { + /* Make sure any intended side-effects occur... */ + found->funct( found->pfield); + retval = TRUE; } + } + } + } + return ( retval ); + }
- /* Check whether it's a non-fcode forth construct */ - tok=lookup_fword((char *)statbuf); - if (tok!=0xffff) { -#ifdef DEBUG_SCANNER - printf("%s:%d: debug: matched internal opcode 0x%04x\n", - iname, lineno, tok); -#endif - handle_internal(tok); -#ifdef DEBUG_SCANNER - if (verbose) - printf("%s:%d: debug: '%s' done.\n", - iname,lineno,statbuf); -#endif - continue; - } +/* ************************************************************************** + * + * Function name: tokenize_one_word + * Synopsis: Tokenize the currently-obtained word + * along with whatever it consumes. + * + * Inputs: + * Parameters: + * wlen Length of symbol just retrieved from the input stream + * This is not really used here any more; it's + * left over from an earlier implementation. + * Global Variables: + * statbuf The symbol (word) just retrieved from input stream. + * in_tokz_esc TRUE if "Tokenizer-Escape" mode is in effect; a + * different set of vocabularies from "Normal" + * mode will be checked (along with those that + * are common to both modes). + * ibm_locals Controls whether to check for IBM-style Locals; + * set by means of a command-line switch. + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * statbuf May be incremented + * in_tokz_esc May be set if the word just retrieved is + * the tokenizer[ directive. + * tic_found + * + * Error Detection: + * If the word could neither be identified nor processed as a number, + * that is an ERROR; pass it to tokenized_word_error for a + * message. + * + * Process Explanation: + * Look for the word in each of the various lists and vocabularies + * in which it might be found, as appropriate to the current + * state of activity. + * If found, process it accordingly. + * If not found, try to process it as a number. + * If cannot process it as a number, declare an error. + * + * Revision History: + * Updated Tue, 10 Jan 2006 by David L. Paktor + * Convert to tic_hdr_t type vocabularies. + * Updated Mon, 03 Apr 2006 by David L. Paktor + * Replaced bulky "Normal"-vs-"Escape" block with a call + * to lookup_word . Attend to a small but important + * side-effect of the "handle_<vocab>" routines that + * feeds directly into the protection against self- + * -recursion in a user-defined Macro: Set the global + * variable tic_found to the entry, just before we + * execute it, and we're good to go... + * + * Extraneous Remarks: + * We trade off the strict rules of structure for simplicity + * of coding. + * + **************************************************************************** */ - /* Check whether it's one of the defined fcode words */ +void tokenize_one_word( signed long wlen ) +{ - tok=lookup_token((char *)statbuf); - if (tok!=0xffff) { -#ifdef DEBUG_SCANNER - printf("%s:%d: debug: matched fcode no 0x%04x\n", - iname, lineno, tok); -#endif - emit_fcode(tok); - continue; - } + /* The shared lookup routine now handles everything. */ + tic_hdr_t *found = lookup_word( statbuf, NULL, NULL ); - /* It's not a word or macro - is it a number? */ + if ( found != NULL ) + { + tic_found = found; + found->funct( found->pfield); + return ; + } - if (!get_number(&val)) { - if (intok) - dpush(val); - else { - emit_fcode(lookup_token("b(lit)")); - emit_num32(val); + /* It's not a word in any of our current contexts. + * Is it a number? + */ + if ( handle_number() ) + { + return ; } - continue; + + /* Could not identify - give a shout. */ + tokenized_word_error( statbuf ); }
- /* could not identify - bail out. */ +/* ************************************************************************** + * + * Function name: tokenize + * Synopsis: Tokenize the current input stream. + * May be called recursively for macros and such. + * + * Revision History: + * Updated Thu, 24 Mar 2005 by David L. Paktor + * Factor-out comment-filtration; apply to gather_locals + * Factor-out tokenizing a single word (for conditionals) + * Separate actions of "Tokenizer-Escape" mode. + * + **************************************************************************** */ + +void tokenize(void) +{ + signed long wlen = 0; - printf("%s:%d: error: word '%s' is not in dictionary.\n", - iname, lineno, statbuf); - ERROR; + while ( wlen >= 0 ) + { + wlen = get_word(); + if ( wlen > 0 ) + { + tokenize_one_word( wlen ); } + } }
Added: fcode-utils/toke/scanner.h =================================================================== --- fcode-utils/toke/scanner.h (rev 0) +++ fcode-utils/toke/scanner.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,123 @@ +#ifndef _TOKE_SCANNER_H +#define _TOKE_SCANNER_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * External/Prototype definitions for Scanning functions in Tokenizer + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + + +#include "types.h" +#include "ticvocab.h" + +/* ************************************************************************** * + * + * Global Variables Exported + * + **************************************************************************** */ + +extern u8 *statbuf; /* The word just read from the input stream */ +extern u8 base; /* The numeric-interpretation base */ + + +/* pci data */ +extern bool pci_is_last_image; +extern u16 pci_image_rev; /* Vendor's Image, NOT PCI Data Struct Rev */ +extern u16 pci_vpd; + + +/* Having to do with the state of the tokenization */ +extern bool offs16; /* Using 16-bit branch- (etc) -offsets */ +extern bool in_tokz_esc; /* TRUE if in "Tokenizer Escape" mode */ +extern bool incolon; /* TRUE if inside a colon definition */ +extern bool haveend; /* TRUE if the "end" code was read. */ +extern int do_loop_depth; /* How deep we are inside DO ... LOOP variants */ + +/* For special-case error detection or reporting */ +extern int lastcolon; /* Loc'n in output stream of latest colon-def'n. */ + /* Used for error-checking of IBM-style Locals */ +extern char *last_colon_defname; /* Name of last colon-definition */ +extern char *last_colon_filename; /* File where last colon-def'n made */ +extern unsigned int last_colon_lineno; /* Line number of last colon-def'n */ +extern bool report_multiline; /* False to suspend multiline warning */ +extern unsigned int last_colon_abs_token_no; + +/* ************************************************************************** * + * + * Function Prototypes / Functions Exported: + * + **************************************************************************** */ + +void init_scanner( void ); +void exit_scanner( void ); +void init_scan_state( void ); +void fcode_ender( void ); + +bool skip_until( char lim_ch); +void push_source( void (*res_func)(), _PTR res_parm, bool is_f_chg ); +signed long get_word( void); +bool get_word_in_line( char *func_nam); +bool get_rest_of_line( void); +void warn_unterm( int severity, + char *something, + unsigned int saved_lineno); +void warn_if_multiline( char *something, unsigned int start_lineno ); +void user_message( tic_param_t pfield ); +void skip_user_message( tic_param_t pfield ); +bool get_number( long *result); +void eval_string( char *inp_bufr); + +void process_remark( tic_param_t pfield ); +bool filter_comments( u8 *inword); +bool as_a_what( fwtoken definer, char *as_what); +tic_hdr_t *lookup_word( char *stat_name, char **where_pt1, char **where_pt2 ); +bool word_exists( char *stat_name, char **where_pt1, char **where_pt2 ); +void warn_if_duplicate ( char *stat_name); +void trace_creation( fwtoken definer, char *nu_name); +void tokenize_one_word( signed long wlen ); +void check_name_length( signed long wlen ); + +void tokenize( void ); + +/* ************************************************************************** + * + * Macro Name: FUNC_CPY_BUF_SIZE + * Size of a temporary buffer to retain a copy of + * a function name taken from statbuf, when statbuf + * will be used to return a value, but the function + * name might still be needed for an error message. + * + **************************************************************************** */ + +#define FUNC_CPY_BUF_SIZE 40 + + +#endif /* _TOKE_SCANNER_H */
Modified: fcode-utils/toke/stack.c =================================================================== --- fcode-utils/toke/stack.c 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/stack.c 2006-08-18 12:47:12 UTC (rev 76) @@ -24,93 +24,203 @@ * */
+/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + #include <stdlib.h> #include <stdio.h> #include <string.h>
-#include "toke.h" #include "stack.h" +#include "scanner.h" +#include "errhandler.h"
+/* ************************************************************************** + * + * Global Variables Imported + * statbuf The word just read from the input stream + * + **************************************************************************** */
-#define GUARD_STACK -#define EXIT_STACKERR
-#ifdef GLOBALSTACK -#define STATIC static -#else -#define STATIC -#endif -STATIC long *dstack,*startdstack,*enddstack; -#undef STATIC +/* ************************************************************************** + * + * Global Variables Exported + * dstack Pointer to current item on top of Data Stack + * + **************************************************************************** */
+long *dstack; + +/* ************************************************************************** + * + * Local/Static Pointers ..... to ... -> Points to ... + * startdstack Start of data-stack area -> last possible item + * enddstack End of data-stack area -> past first item + * + *************************************************************************** */ + +static long *startdstack; +static long *enddstack; + +void clear_stack(void) +{ + dstack = enddstack; +} + /* internal stack functions */
-int init_stack(void) +void init_stack(void) { - startdstack=enddstack=malloc(MAX_ELEMENTS*sizeof(long)); - enddstack+=MAX_ELEMENTS; + startdstack = safe_malloc(MAX_ELEMENTS*sizeof(long), "initting stack"); + enddstack = startdstack + MAX_ELEMENTS; dstack=enddstack; - return 0; }
-#ifdef GLOBALSTACK +/* Input Param: stat TRUE = Underflow, FALSE = Overflow */ +static void stackerror(bool stat) +{ + /* + * Because all of our stack operations are protected and + * we have no risk of the dstack pointer going into + * invalid territory, this error needs not be FATAL. + */ + tokenization_error ( TKERROR , "stack %sflow at or near %s \n", + (stat)?"under":"over" , statbuf ); +}
-#ifdef GUARD_STACK -static void stackerror(int stat) +/* + * Return TRUE if the stack depth is equal to or greater than + * the supplied minimum requirement. If not, print an error. + */ +bool min_stack_depth(int mindep) { - printf ("FATAL: stack %sflow\n", - (stat)?"under":"over" ); -#ifdef EXIT_STACKERR - exit(-1); -#endif + bool retval = TRUE ; + long *stack_result; + + stack_result = dstack + mindep; + /* + * The above appears counter-intuitive. However, C compensates + * for the size of the object of a pointer when it handles + * address arithmetic. A more explicit expression that would + * yield the same result, might look something like this: + * + * (long *)((int)dstack + (mindep * sizeof(long))) + * + * I doubt that that form would yield tighter code, or otherwise + * represent any material advantage... + */ + + if ( stack_result > enddstack ) + { + retval = FALSE; + stackerror(TRUE); + } + + return ( retval ); } -#endif
+/* + * Return TRUE if the stack has room for the supplied # of items + */ +static bool room_on_stack_for(int newdep) +{ + bool retval = TRUE ; + long *stack_result; + + stack_result = dstack - newdep; + /* See above note about "counter-intuitive" pointer address arithmetic */ + + if ( stack_result < startdstack ) + { + retval = FALSE; + stackerror(FALSE); + } + + return ( retval ); +} + void dpush(long data) { #ifdef DEBUG_DSTACK printf("dpush: sp=%p, data=0x%lx, ", dstack, data); #endif - *(--dstack)=data; -#ifdef GUARD_STACK - if (dstack<startdstack) stackerror(0); -#endif + if ( room_on_stack_for(1) ) + { + --dstack; + *(dstack)=data; + } }
long dpop(void) { - long val; + long val = 0; #ifdef DEBUG_DSTACK printf("dpop: sp=%p, data=0x%lx, ",dstack, *dstack); #endif - val=*(dstack++); -#ifdef GUARD_STACK - if (dstack>enddstack) stackerror(1); -#endif + if ( min_stack_depth(1) ) + { + val=*(dstack); + dstack++; + } return val; }
long dget(void) { - return *(dstack); + long val = 0; + if ( min_stack_depth(1) ) + { + val = *(dstack); + } + return val; } -#endif
-/* Stack helper functions */ - -u8 *get_stackstring(void) +long stackdepth(void) { - long size; - u8 *fstring, *retstring; + long depth;
- size=dpop(); - fstring=(u8 *)dpop(); + depth = enddstack - dstack; + /* + * Again, C's address arithmetic compensation comes into play. + * See the note at min_stack_depth() + * + * A more explicit equivalent expression might look like this: + * + * (((long int)enddstack - (long int)dstack) / sizeof(long)) + * + * I doubt any material advantage with that one either... + */
- retstring=malloc(size+1); - strncpy((char *)retstring, (const char *)fstring, size); - retstring[size]=0; + return (depth); +}
- return retstring; +void swap(void) +{ + long nos_temp; /* Next-On-Stack temp */ + if ( min_stack_depth(2) ) + { + nos_temp = dstack[1]; + dstack[1]= dstack[0]; + dstack[0]= nos_temp; + } }
+void two_swap(void) +{ + long two_deep, three_deep; + if ( min_stack_depth(4) ) + { + two_deep = dstack[2]; + three_deep = dstack[3]; + dstack[2] = dstack[0]; + dstack[3] = dstack[1]; + dstack[1] = three_deep; + dstack[0] = two_deep; + } +}
+
Modified: fcode-utils/toke/stack.h =================================================================== --- fcode-utils/toke/stack.h 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/stack.h 2006-08-18 12:47:12 UTC (rev 76) @@ -1,3 +1,6 @@ +#ifndef _TOKE_STACK_H +#define _TOKE_STACK_H + /* * OpenBIOS - free your system! * ( FCode tokenizer ) @@ -24,23 +27,47 @@ * */
-#ifdef ANSI_ONLY -#define GLOBALSTACK -#endif +/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */
+#include "types.h" + +/* ************************************************************************** * + * + * Macros: + * MAX_ELEMENTS Size of stack area, in "elements" + * + **************************************************************************** */ + #define MAX_ELEMENTS 1024
-#ifdef GLOBALSTACK +/* ************************************************************************** * + * + * Global Variables Exported + * + **************************************************************************** */ + +extern long *dstack; + +/* ************************************************************************** * + * + * Function Prototypes / Functions Exported: + * + **************************************************************************** */ + void dpush(long data); long dpop(void); long dget(void); -#else -extern long *dstack,*startdstack; -static inline void dpush(long data) { *(--dstack)=data; } -static inline long dpop(void) { return (long)*(dstack++); } -static inline long dget(void) { return *(dstack); } -#endif
-int init_stack(void); -u8 *get_stackstring(void); +void clear_stack(void); +void init_stack(void);
+bool min_stack_depth(int mindep); /* TRUE if no error */ +long stackdepth(void); +void swap(void); +void two_swap(void); + +#endif /* _TOKE_STACK_H */
Modified: fcode-utils/toke/stream.c =================================================================== --- fcode-utils/toke/stream.c 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/stream.c 2006-08-18 12:47:12 UTC (rev 76) @@ -24,6 +24,12 @@ * */
+/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + #include <stdio.h> #include <stdlib.h> #ifdef __GLIBC__ @@ -32,134 +38,1577 @@ #include <string.h> #include <sys/stat.h>
+#include "emit.h" +#include "stream.h" +#include "errhandler.h" #include "toke.h" -#include "stream.h"
-#define OUTPUT_SIZE 131072 +/* ************************************************************************** + * + * Revision History: + * Updated Tue, 31 Jan 2006 by David L. Paktor + * Add support for embedded Environment-Variables in path name + * Updated Thu, 16 Feb 2006 David L. Paktor + * Collect missing (inaccessible) filenames + * Updated Thu, 16 Mar 2006 David L. Paktor + * Add support for Include-Lists + * + **************************************************************************** */
-extern bool offs16; -extern u16 nextfcode; +/* ************************************************************************** + * + * Global Variables Exported + * start Start of input-source buffer + * end End of input-source buffer + * pc Input-source Scanning pointer + * iname Current Input File name + * lineno Current Line Number in Input File + * ostart Start of Output Buffer + * opc FCode Output Buffer Position Counter + * oname Output File name + * + **************************************************************************** */
-u8 *start, *pc, *end; -char *iname;
+/* Input pointers, Position Counters and Length counters */ +u8 *start = NULL; +u8 *pc; +u8 *end; +char *iname = NULL; +unsigned int lineno = 0; +unsigned int abs_token_no = 0; /* Absolute Token Number in all Source Input + * Will be used to identify position + * where colon-definition begins and + * to limit clearing of control-structs. + */ +static unsigned int ilen; /* Length of Input Buffer */ + /* output pointers */ -u8 *ostart, *opc, *oend, *oname; -static unsigned int ilen; +u8 *ostart; +char *oname = NULL; +unsigned int opc; /* Output Position Counter */
-unsigned int lineno; +/* We want to limit exposure of this v'ble, so don't put it in .h file */ +unsigned int olen; /* Length of Output Buffer */ +/* We want to limit exposure of this Imported Function, likewise. */ +void init_emit( void);
-int init_stream( const char *name) +/* ************************************************************************** + * + * Internal Static Variables + * load_list_name Name of the Load List File + * load_list_file (Pointer to) File-Structure for the Load List File + * depncy_list_name Name of the Dependency List File + * depncy_file (Pointer to) File-Structure for the Dependency List File + * missing_list_name Name of the Missing-Files-List File + * missing_list_file (Pointer to) File-Structure for Missing-List File + * no_files_missing TRUE if able to load all files + * + **************************************************************************** */ + +static char *load_list_name; +static FILE *load_list_file; +static char *depncy_list_name; +static FILE *depncy_file; +static char *missing_list_name; +static FILE *missing_list_file; +static bool no_files_missing = TRUE; + +/* ************************************************************************** + * + * Private data-structure for Include-List support + * + * Components are simply a string-pointer and a link pointer + * + **************************************************************************** */ + +typedef struct incl_list { - FILE *infile; - unsigned int i; + char *dir_path; + struct incl_list *next; + } incl_list_t; + +/* ************************************************************************** + * + * Internal Static Variables associated with Include-List support + * include_list_start Start of the Include-List + * include_list_next Next entry in Include-List to add or read + * max_dir_path_len Size of longest entry in the Include-List + * include_list_full_path Full-Path (i.e., expanded File-name with + * Include-List Entry) that was last opened. + * + **************************************************************************** */ +static incl_list_t *include_list_start = NULL; +static incl_list_t *include_list_next = NULL; +static unsigned int max_dir_path_len = 0; +static char *include_list_full_path = NULL; + + +/* ************************************************************************** + * + * Function name: add_to_include_list + * Synopsis: Add an entry to the Include-List + * + * Inputs: + * Parameters: + * dir_compt Directory Component to add to Inc-List + * Local Static Variables: + * include_list_start First entry in the Include-List + * include_list_next Next entry in Include-List to add + * max_dir_path_len Previous max Dir-Component Length + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * include_list_start Assigned a value, first time through + * include_list_next "Next" field updated with new entry, + * then pointer updated to new entry. + * max_dir_path_len Maximum Length + * Memory Allocated + * For the list-entry, and for the directory/path name to be added + * When Freed? + * Remains in effect through the life of the program. + * + * Process Explanation: + * Unlike most of our linked-lists, this one will be linked forward, + * i.e., in the order elements are added, and will be searched + * in a forward order. + * This means extra code to handle the first entry. + * Allocate and initialize the New Include-List Entry. + * If this is the first entry, point the List-Starter at it. + * Otherwise, the Last-Entry-on-the-List pointer is already valid; + * point its "next" field at the New Entry. + * Point the Last-Entry-on-the-List pointer at the New Entry. + * + **************************************************************************** */ + +void add_to_include_list( char *dir_compt) +{ + unsigned int new_path_len = strlen( dir_compt); + incl_list_t *new_i_l_e = safe_malloc( sizeof( incl_list_t), + "adding to include-list" ); + + new_i_l_e->dir_path = strdup( dir_compt); + new_i_l_e->next = NULL; + + if ( include_list_start == NULL ) + { + include_list_start = new_i_l_e; + }else{ + include_list_next->next = new_i_l_e; + } + + include_list_next = new_i_l_e; + if ( new_path_len > max_dir_path_len ) max_dir_path_len = new_path_len; +} + +#define DISPLAY_WIDTH 80 +/* ************************************************************************** + * + * Function name: display_include_list + * Synopsis: Display the Include-List, once it's completed, + * if "verbose" mode is in effect. + * + * Inputs: + * Parameters: NONE + * Local Static Variables: + * include_list_start First entry in the Include-List + * include_list_next Next entry, as we step through. + * Macro: + * DISPLAY_WIDTH Width limit of the display + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * include_list_next NULL, when reaches end of Incl-List + * Printout: + * The elements of the Include-List, separated by a space, on + * a line up to the DISPLAY_WIDTH, or on a line by itself + * if the element is wider. + * + * Process Explanation: + * The calling routine will check for the verbose flag. + * Nothing to be done here if Include-List is NULL. + * Print a header, then the list. + * + **************************************************************************** */ + +void display_include_list( void) +{ + if ( include_list_start != NULL ) + { + int curr_wid = DISPLAY_WIDTH; /* Current width; force new line */ + printf("\nInclude-List:"); + include_list_next = include_list_start ; + while ( include_list_next != NULL ) + { + int this_wid = strlen( include_list_next->dir_path) + 1; + char *separator = " "; + if ( curr_wid + this_wid > DISPLAY_WIDTH ) + { + separator = "\n\t"; + curr_wid = 7; /* Allow 1 for the theoretical space */ + } + printf("%s%s", separator, include_list_next->dir_path); + curr_wid += this_wid; + include_list_next = include_list_next->next ; + } + printf("\n"); + } +} + + + +/* ************************************************************************** + * + * We cannot accommodate the structures of the different + * routines that open files with a single function, so + * we will have to divide the action up into pieces: + * one routine to initialize the include-list search, a + * second to return successive candidates. The calling + * routine will do the operation (stat or fopen) until + * it succeeds or the list is exhausted. Then it will + * call a final routine to clean up and display messages. + * + * I'm sure I don't need to mention that, when no include-list + * is defined, these functions will still support correct + * operation... + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Function name: init_incl_list_scan + * Synopsis: Initialize the search through the Include-List + * + * Inputs: + * Parameters: + * base_name Expanded user-supplied file-name + * Local Static Variables: + * include_list_start First entry in the Include-List + * max_dir_path_len Maximum Directory Component Length + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * include_list_next Next entry in Include-List to read + * include_list_full_path Full-Path Buffer pointer + * Memory Allocated + * Full-Path Buffer (If Include-List was defined) + * When Freed? + * In finish_incl_list_scan() + * + * Process Explanation: + * The base_name passed to the routine is expected to have + * any embedded Environment-Variables already expanded. + * The Full-Path Buffer is presumed to be unallocated, and + * its pointer to be NULL. + * The Next-Entry-to-read pointer is also presumed to be NULL. + * If an Include-List has been defined, we will allocate memory + * for the Full-Path Buffer and point the Next-Entry pointer + * at the Start of the List. If not, no need to do anything. + * + **************************************************************************** */ + +static void init_incl_list_scan( char *base_name) +{ + if ( include_list_start != NULL ) + { + /* Allocate memory for the file-name buffer. + * maximum path-element length plus base-name length + * plus one for the slash plus one for the ending NULL + */ + unsigned int new_path_len = max_dir_path_len + strlen( base_name) + 2; + include_list_full_path = safe_malloc( new_path_len, + "scanning include-list" ); + include_list_next = include_list_start; + } +} + +/* ************************************************************************** + * + * Function name: scan_incl_list + * Synopsis: Prepare the next candidate in the include-list search + * Indicate when the end has been reached. + * + * Inputs: + * Parameters: + * base_name Expanded user-supplied file-name + * Local Static Variables: + * include_list_full_path Full-Path Buffer pointer + * include_list_next Next entry in Include-List to read + * + * Outputs: + * Returned Value: TRUE if valid candidate; FALSE when done + * Local Static Variables: + * include_list_full_path Next Full file-name Path to use + * include_list_next Updated to next entry in the List + * + * Process Explanation: + * Include-List Components are presumed not to require any expansion; + * the Shell is expected to resolve any Environment-Variables + * supplied in command-line arguments before they are passed + * to the (this) application-program. + * We will, therefore, not attempt to expand any Components of + * the Include-List. + * If the Full-Path Buffer pointer is NULL, it indicates that no + * entries have been made to the Include-List and this is our + * first time through this routine in this search; we will + * use the base-name as supplied, presumably relative to the + * current directory. Point the buffer-pointer at the base- + * -name and return "Not Done". + * Otherwise, we will look at the Next-Entry pointer: + * If it is NULL, we have come to the end of the Include-List; + * whether because no Include-List was defined or because + * we have reached the end, we will return "Done". + * Otherwise, we will load the Full-Path Buffer with the entry + * currently indicated by the Next-Entry pointer, advance + * it to the next entry in the List and return "Not Done". + * We will supply a slash as the directory-element separator in + * between the Include-List entry and the base_name + * + * Extraneous Remarks: + * The slash as directory-element separator works in UNIX-related + * environments, but is not guaranteed in others. I would + * have preferred to specify that Include-List Components are + * required to end with the appropriate separator, but that + * was neither acceptable nor compatible with existing practice + * in other utilities, and the effort to programmatically + * determine the separator used by the Host O/S was too much + * for such a small return. And besides, we already have so + * many other UNIX-centric assumptions hard-coded into the + * routines in this file (dollar-sign to signify Environment + * Variables, period for file-name-extension separator, etc.) + * that it's just too much of an uphill battle anymore... + * + **************************************************************************** */ + +static bool scan_incl_list( char *base_name) +{ + bool retval = FALSE; /* default to "Done" */ + if ( include_list_full_path == NULL ) + { + include_list_full_path = base_name; + retval = TRUE; + }else{ + if ( include_list_next != NULL ) + { + + /* Special case: If the next Directory Component is + * an empty string, do not prepend a slash; that + * would either become a root-based absolute path, + * or, if the base-name is itself an absolute path, + * it would be a path that begins with two slashes, + * and *some* Host Operating Systems ***REALLY*** + * DO NOT LIKE that! + */ + if ( strlen( include_list_next->dir_path) == 0 ) + { + sprintf( include_list_full_path, "%s", base_name); + }else{ + sprintf( include_list_full_path, "%s/%s", + include_list_next->dir_path, base_name); + } + include_list_next = include_list_next->next; + retval = TRUE; + } + } + + return( retval); +} + +/* ************************************************************************** + * + * Function name: finish_incl_list_scan + * Synopsis: Clean up after a search through the Include-List + * Display appropriate messages. + * + * Inputs: + * Parameters: + * op_succeeded TRUE if intended operation was ok. + * + * Local Static Variables: + * include_list_start Non-NULL if Include-List was defined + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * include_list_full_path Reset to NULL + * include_list_next Reset to NULL + * Memory Freed + * Full-Path Buffer (If Include-List was defined) + * Printout: + * If file was found in Include-List, Advisory showing where. + * + **************************************************************************** */ + +static void finish_incl_list_scan( bool op_succeeded) +{ + if ( include_list_start != NULL ) + { + if ( op_succeeded ) + { + tokenization_error( INFO, + "File was found in %s\n" ,include_list_full_path ); + } + free( include_list_full_path); + } + include_list_full_path = NULL; + include_list_next = NULL; +} + +/* ************************************************************************** + * + * Function name: open_incl_list_file + * Synopsis: Look in the Include-List, if one is defined, for + * the file whose name is given and open it. + * + * Inputs: + * Parameters: + * base_name Expanded user-supplied file-name + * mode Mode-string to use; usually "r" or "rb" + * Local Static Variables: + * include_list_full_path Full Path to use in fopen atttempt + * + * Outputs: + * Returned Value: File structure pointer; NULL if failed + * Local Static Variables: + * include_list_full_path Full Path used, if succeeded + * + * Error Detection: + * Calling routine will detect and report Errors. + * + * Process Explanation: + * This routine will initialize and step through Include-List. + * Calling routine will be responsible for "finishing" the + * Include-List search, as well as any Advisory messages. + * + **************************************************************************** */ + +static FILE *open_incl_list_file( char *base_name, char *mode) +{ + FILE *retval = NULL; + + init_incl_list_scan( base_name); + while ( scan_incl_list( base_name) ) + { + retval = fopen( include_list_full_path, mode); + if ( retval != NULL ) + { + break; + } + } + + return (retval); +} + +/* ************************************************************************** + * + * Function name: stat_incl_list_file + * Synopsis: Look in the Include-List, if defined, for given file, + * and collect its statistics. + * + * + * Inputs: + * Parameters: + * base_name Expanded user-supplied file-name + * file_info Pointer to STAT structure + * Local Static Variables: + * include_list_full_path Full Path to use in file-status atttempt + * + * Outputs: + * Returned Value: TRUE if succeeded. + * Local Static Variables: + * include_list_full_path Full Path used, if succeeded + * Supplied Pointers: + * *file_info File-statistics structure from STAT call + * + * Error Detection: + * Calling routine will detect and report Errors. + * + * Process Explanation: + * This routine will initialize and step through Include-List. + * Calling routine will be responsible for "finishing" the + * Include-List search, as well as any Advisory messages. + * + **************************************************************************** */ + +static bool stat_incl_list_file( char *base_name, struct stat *file_info) +{ + bool retval = FALSE; + int stat_reslt = -1; /* Success = 0 */ + + init_incl_list_scan( base_name); + while ( scan_incl_list( base_name) ) + { + stat_reslt = stat( include_list_full_path, file_info); + if ( stat_reslt == 0 ) + { + retval = TRUE; + break; + } + } + + return (retval); +} + +/* ************************************************************************** + * + * Function name: init_inbuf + * Synopsis: Set the given buffer as the current input source + * + * Inputs: + * Parameters: + * inbuf Pointer to start of new input buffer + * buflen Length of new input buffer + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * start Points to given buffer + * end Points to end of new input buffer + * pc Re-initialized + * + **************************************************************************** */ + +void init_inbuf(char *inbuf, unsigned int buflen) +{ + start = inbuf; + pc = start; + end = pc + buflen; +} + +/* ************************************************************************** + * + * Function name: could_not_open + * Synopsis: Report the "Could not open" Message for various Files. + * + * Inputs: + * Parameters: + * severity Severity of message, WARNING or ERROR + * fle_nam Name of file + * for_what Phrase after "... for " + * + * Outputs: + * Returned Value: NONE + * Printout: + * Message of indicated severity. + * + * Error Detection: + * Error already detected; reported here. + * + **************************************************************************** */ + +static void could_not_open(int severity, char *fle_nam, char *for_what) +{ + tokenization_error( severity, "Could not open file %s for %s.\n", + fle_nam, for_what); + +} + +/* ************************************************************************** + * + * Function name: file_is_missing + * Synopsis: Add the given File to the Missing-Files-List. + * + * Inputs: + * Parameters: + * fle_nam Name of file + * Local Static Variables: + * missing_list_file Missing-Files-List File Structure + * May be NULL if none was opened + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * no_files_missing Set FALSE + * File Output: + * Write File name to Missing-Files-List (if one was opened) + * + * Error Detection: + * Error already detected; reported here. + * + **************************************************************************** */ + +static void file_is_missing( char *fle_nam) +{ + if ( missing_list_file != NULL ) + { + fprintf( missing_list_file, "%s\n", fle_nam); + no_files_missing = FALSE; + } +} + +/* ************************************************************************** + * + * Function name: add_to_load_lists + * Synopsis: Add the given input file-name to the Load-List File, + * and the Full File path to the Dependency-List File. + * + * Inputs: + * Parameters: + * in_name Name of given input Source File + * Local Static Variables: + * load_list_file Load List File Structure pointer + * depncy_file Dependency-List File Structure ptr + * Either may be NULL if the file was not opened. + * include_list_full_path Full Path to where the file was found. + * + * Outputs: + * Returned Value: NONE + * File Output: + * Write given file-name to Load-List file (if one was opened) + * Write File Path to Dependency-List file (if one was opened) + * + * Process Explanation: + * Write into the Load-List file the input Source Filename in the + * same form -- i.e., unexpanded -- as was supplied by the User. + * Write into the Dependency-List file the full expanded path, as + * supplied by the program to the Host Operating System. + * + **************************************************************************** */ + +static void add_to_load_lists( const char *in_name) +{ + if ( load_list_file != NULL ) + { + fprintf( load_list_file, "%s\n", in_name); + } + if ( depncy_file != NULL ) + { + fprintf( depncy_file, "%s\n", include_list_full_path); + } +} + + +/* ************************************************************************** + * + * In the functions that support accessing files whose path-names + * contain embedded Environment-Variables, the commentaries + * will refer to this process, or to inputs that require it, + * using variants of the term "expand". + * + * We will also keep some of the relevant information as Local + * Static Variables. + * + **************************************************************************** */ + +static char expansion_buffer[ 2*GET_BUF_MAX]; +static bool was_expanded; +static int expansion_msg_severity = INFO; + +/* ************************************************************************** + * + * Function name: expanded_name + * Synopsis: Advisory message to display filename expansion. + * + * Inputs: + * Parameters: + * Local Static Variables: + * was_expanded TRUE if expansion happened + * expansion_buffer Buffer with result of expansion + * expansion_msg_severity Whether it's an ordinary Advisory + * or we force a message. + * + * Outputs: + * Returned Value: NONE + * + * Printout: + * Advisory message showing expansion, if expansion happened + * Otherwise, nothing. + * + **************************************************************************** */ + +static void expanded_name( void ) +{ + if ( was_expanded ) + { + tokenization_error( expansion_msg_severity, + "File name expanded to: %s\n", expansion_buffer); + } +} + + +/* ************************************************************************** + * + * Function name: expansion_error + * Synopsis: Supplemental message to display filename expansion. + * Called after an expanded-filename failure was reported. + * + * Inputs: + * Parameters: + * Global Variables: + * verbose Set by "-v" switch + * + * Outputs: + * Returned Value: NONE + * Printout: + * Advisory message showing expansion, if applicable + * and if wasn't already shown. + * + * Error Detection: + * Called after Error was reported. + * + * Process Explanation: + * Presumptions are that: + * An Error message, showing the user-supplied form of the + * pathname is also being displayed + * An advisory message showing the pathname expansion may + * have been displayed during the expansion process, + * if verbose was TRUE. + * The purpose of this routine is to display the expansion if + * it had not already just been displayed, i.e., if verbose + * is not set to TRUE: Temporarily force the display of an + * Advisory message. + * + * Extraneous Remarks: + * If this routine is called before the Error message is displayed, + * the verbose and non-verbose versions of the Log-File will + * match up nicely... + * + **************************************************************************** */ + +static void expansion_error( void ) +{ + if ( INVERSE( verbose) ) + { + expansion_msg_severity |= FORCE_MSG; + expanded_name(); + expansion_msg_severity ^= FORCE_MSG; + } +} + + +/* ************************************************************************** + * + * Function name: expand_pathname + * Synopsis: Perform the expansion of a path-name that may contain + * embedded Environment-Variables + * + * Inputs: + * Parameters: + * input_pathname The user-supplied filename + * Global/Static MACRO: + * GET_BUF_MAX Size of expansion buffer is twice this. + * + * Outputs: + * Returned Value: Pointer to expanded name, or to + * input if no expansion needed. + * NULL if error. + * Local Static Variables: + * was_expanded TRUE if expansion needed and succeeded + * expansion_buffer Result of expansion + * Printout: + * Advisory message showing expansion + * Presumption is that an Advisory giving the user-supplied + * pathname was already printed. + * + * Error Detection: + * Syntax error. System might print something; it might not be + * captured, even to a log-file. System failure return might + * be the only program-detectable indication. Display ERROR + * message and return NULL pointer. Calling routine will + * display the user-supplied pathname in its Error message + * indicating failure to open the file. + * + * Process Explanation: + * Generally speaking, we will let the Shell expand the Environment + * Variables embedded in the user-supplied pathname. + * First, though, we will see if the expansion is necessary: Look + * for the telltale character, '$', in the input string. If + * it's not there, there are no Env't-V'bles, and no expansion + * is necessary. Return the pointer to the input string and + * we're done. Otherwise..... + * Acquire a temporary file-name. Construct a string of the form: + * echo input_string > temp_file_name + * and then issue that string as a command to the Shell. + * If that string generates a system-call failure, report an ERROR. + * Open the temporary file and read its contents. That will be + * the expansion of the input string. If its length exceeds + * the capacity of the expansion buffer, it's another ERROR. + * (Of course, don't forget to delete the temporary file.) + * Place the null-byte marker at the end of the expanded name, + * trimming off the terminating new-line. + * Success. Display the expanded name (as an Advisory message) + * Return the pointer to the expansion buffer and set the flag. + * (Did I mention don't forget to delete the temporary file?) + * + * Extraneous Remarks: + * This implementation approach turned out to be the simplest and + * cleanest way to accomplish our purpose. It also boasts the + * HUGE advantage of not requiring re-invention of a well-used + * (proverbial) wheel. Plus, any variations allowed by the + * shell (e.g.,: $PWD:h ) are automatically converted, too, + * depending on the System shell (e.g., not for Bourne shell). + * In order to spare you, the maintenance programmer, unnecessary + * agony, I will list a few other approaches I tested, with a + * brief note about the results of each: + * (1) + * I actually tried parsing the input line and passing each component + * V'ble to the getenv() function, accumulating the results into + * a conversion buffer. I needed to check for every possible + * delimiter, and handle curly-brace enclosures. The resultant + * code was *UGLY* ... you'd be appalled! The only good spot was + * that I was able to compensate for an open-curly-brace without + * a corresponding close-curly-brace (if close-c-b wasn't found, + * resume the search for other delimiters...) which, apparently, + * the System does not or will not do. It was, however, too + * small a compensation for all the awfulness entailed overall. + * + * I tried various approaches to using the Environment-Variables to + * convert and retrieve the input string: + * (2) + * Create a command-string that would set an Env't V'ble to the + * input-string, and pass the command-string to the system() call, + * then retrieve the Env't V'ble thus set via getenv(). No dice; + * the system() call operated in a separate sub-shell and could + * not export its Env't upwards. + * (3) + * Use the setenv() command to set an Env't V'ble to the input-string + * and retrieve it via getenv(). The returned string matched the + * input-string without converting it. + * (4) + * Use the setenv() command to set an Env't V'ble to a string like: + * `echo input_string` + * Again, the string retrieved via getenv() exactly matched the + * unconverted command-string, back-quotes and all. + * + * Of course, the equivalents of (2), (3) and (4) worked as desired + * when tested as direct commands to the Shell. UNIX can be + * funny that way... + * + * Oh! Also: we will slightly stretch the rules of well-structured + * code. + * + **************************************************************************** */ + +static char *expand_pathname( const char *input_pathname) +{ + static const int buffer_max = GET_BUF_MAX * 2; + + char *retval = (char *)input_pathname; + was_expanded = FALSE; + + /* If no '$' is found, expansion is unnecessary. */ + if ( strchr( input_pathname, '$') != NULL ) + { + FILE *temp_file; + int syst_stat; + const char *temp_file_name = tmpnam( NULL); + + /* Use the expansion buffer for our temporary command string */ + sprintf( expansion_buffer, + "echo %s>%s\n", input_pathname, temp_file_name); + syst_stat = system( expansion_buffer); + if ( syst_stat != 0 ) + { + tokenization_error( TKERROR, + "Expansion Syntax.\n"); + /* The "File-Opening" error message will show the input string */ + return( NULL); + } + + temp_file = fopen( temp_file_name, "r"); /* Cannot fail. */ + syst_stat = fread( expansion_buffer, 1, buffer_max, temp_file); + /* Error test. Length of what we read is not a good indicator; + * it's limited anyway by buffer_max. + * Valid test is if last character read was the new-line. + */ + if ( expansion_buffer[syst_stat-1] != '\n' ) + { + tokenization_error( TKERROR, + "Expansion buffer overflow. Max length is %d.\n", + buffer_max); + retval = NULL; + }else{ + expansion_buffer[syst_stat-1] =0; + was_expanded = TRUE; + retval = expansion_buffer; + expanded_name(); + } + + fclose( temp_file); + remove( temp_file_name); + } + + return( retval); +} + +/* ************************************************************************** + * + * Function name: open_expanded_file + * Synopsis: Open a file, expanding Environment-Variables that + * may be embedded in the given path-name. + * + * Inputs: + * Parameters: + * path_name The user-supplied path-name + * mode Mode-string to use; usually "r" or "rb" + * for_what Phrase to use in Messages + * + * Outputs: + * Returned Value: Pointer to FILE structure; NULL if failed + * Local Static Variables: + * was_expanded TRUE if expansion happened + * expansion_buffer Result of expansion + * Printout: + * Advisory message showing expansion + * + * Error Detection: + * If expansion or system-call for file-open failed, + * report Error and return NULL. + * + **************************************************************************** */ + +FILE *open_expanded_file( const char *path_name, char *mode, char *for_what) +{ + + FILE *retval = NULL; + + char *infile_name = expand_pathname( path_name); + if ( infile_name != NULL ) + { + retval = open_incl_list_file( infile_name, mode); + } + + if ( retval == NULL ) + { + expansion_error(); + tokenization_error ( TKERROR, + "Failed to open file %s for %s\n", path_name, for_what ); + } + + finish_incl_list_scan( BOOLVAL( retval != NULL) ); + + return( retval); +} + +/* ************************************************************************** + * + * Function name: init_stream + * Synopsis: Open a file and make it the current source. + * This is called, not only at the start of tokenization, + * but also when a subsidiary file is FLOADed. + * + * Inputs: + * Parameters: + * name Name of the new Input File to open + * May be path-name containing + * embedded Environment-Variables. + * Global Variables: + * oname NULL if opening Primary Input File + * Local Static Variables: + * include_list_full_path Full Path to where the file was found + * + * Outputs: + * Returned Value: TRUE = opened and read file successfully + * Global Variables (Only changed if successful): + * iname Set to new Input File name + * lineno Re-initialized to 1 + * Local Static Variables: + * no_files_missing Set FALSE if couldn't read input file + * include_list_full_path Retains full-path if file opened was + * the Primary Input File (as contrasted with an FLoaded + * Source file), in which case a call to init_output() + * is expected; the Full-Path Buffer will be freed there. + * Memory Allocated + * Duplicate of Input File name (becomes iname ) + * A fresh input buffer; input file is copied to it. + * Becomes start by action of call to init_inbuf(). + * When Freed? + * By close_stream() + * File Output: + * Write new Input File name to Load-List file. + * Writing to Missing-Files-List File if failure, + * or Full File path to Dependency-List File, + * is handled by called routine. + * Other Exotic Effects: + * Force a flush of stdout before printing ERROR messages + * + * Error Detection: + * Failure to open or read Input file: ERROR; suppress output; + * write Input File name to Missing-Files-List File. + * + * Process Explanation: + * Free local buffer on failure. + * Caller should only invoke close_stream() if this call succeeded. + * Some filesystems use zeros for new-line; we need to convert + * those zeros to line-feeds. + * Similarly for files that have carr-ret/line-feed; the carr-ret + * will cause havoc; replace it w/ a space. + * + * Revision History: + * Updated Thu, 07 Apr 2005 by David L. Paktor + * Restructured. If opened file, close it, even if can't read it. + * Return TRUE on success. + * Caller examines return value. + * Updated Wed, 13 Jul 2005 by David L. Paktor + * Replace carr-rets with spaces. + * Updated Sun, 27 Nov 2005 by David L. Paktor + * Write new Input File name to Load-List file. + * Updated Tue, 31 Jan 2006 by David L. Paktor + * Add support for embedded Environment-Variables in path name + * Updated Thu, 16 Feb 2006 David L. Paktor + * Collect missing (inaccessible) filenames + * Updated Fri, 17 Mar 2006 David L. O'Paktor + * Add support for Include-List search + * + * Still to be done: + * Set a flag when carr-ret has been replaced by space; + * when a string crosses a line, if this flag is set, + * issue a warning that an extra space has been inserted. + * + **************************************************************************** */ + +bool init_stream( const char *name) +{ + FILE *infile; + u8 *newbuf; struct stat finfo; + bool stat_succ = FALSE; + bool tried_stat = FALSE; + bool retval = FALSE; + bool inp_fil_acc_err = FALSE; + bool inp_fil_open_err = FALSE; + bool inp_fil_read_err = FALSE; + + char *infile_name = expand_pathname( name); + + if ( (infile_name != NULL) ) + { + tried_stat = TRUE; + stat_succ = stat_incl_list_file( infile_name, &finfo); + } + + if ( INVERSE( stat_succ) ) + { + inp_fil_acc_err = TRUE; + }else{ - if (stat(name,&finfo)) - return -1; + infile = fopen( include_list_full_path, "r"); + if ( infile == NULL ) + { + inp_fil_open_err = TRUE; + }else{ ilen=finfo.st_size; - start=malloc(ilen+1); - if (!start) - return -1; + newbuf = safe_malloc(ilen+1, "initting stream");
- infile=fopen(name,"r"); - if (!infile) - return -1; + if ( fread( newbuf, ilen, 1, infile) != 1 ) + { + inp_fil_read_err = TRUE; + free( newbuf ); + } else { + unsigned int i;
- if (fread(start, ilen, 1, infile)!=1) { - free(start); - return -1; + retval = TRUE ; + /* Replace zeroes in the file with LineFeeds. */ + /* Replace carr-rets with spaces. */ + for (i=0; i<ilen; i++) + { + char test_c = newbuf[i]; + if ( test_c == 0 ) newbuf[i] = 0x0a; + if ( test_c == 0x0d ) newbuf[i] = ' '; } + newbuf[ilen]=0;
+ init_inbuf(newbuf, ilen); + + /* If the -l option was specified, write the name of the + * new input-file to the Load-List file... UNLESS + * this is the first time through and we haven't yet + * opened the Load-List file, in which case we'll + * just open it here and wait until we create the + * output-file name (since the Load-List file name + * depends on the output-file name anyway) before + * we write the initial input-file name to it. + */ + /* Looking for the option-flag _and_ for a non-NULL value + * of the file-structure pointer is redundandundant: + * The non-NULL pointer is sufficient, once the List + * File has been created... + */ + /* Same thing applies if the -P option was specified, + * for the Dependency-List file, except there we'll + * write the full path to where the file was found. + */ + /* We have a routine to do both of those. */ + add_to_load_lists( name); + /* + * And... there's one slight complication: If this is + * the first time through, (i.e., we're opening the + * Primary Input File) then we haven't yet opened the + * Dependency-List file, and we need to preserve the + * Full file-name Buffer until the call to init_output() + * where the include-list scan will be "finish"ed. + * Actually, we want to postpone "finish"ing the inc-l scan + * for several reasons beyond the Dependency-List file, + * such as completing the File Name Announcement first. + * A NULL output-name buffer is our indicator. + */ + if ( oname == NULL ) + { + /* Quick way to suppress "finish"ing the i-l scan */ + tried_stat = FALSE; + } + } fclose(infile); + } + } - /* no zeroes within the file. */ - for (i=0; i<ilen; i++) { - /* start[i]=start[i]?start[i]:0x0a; */ - start[i] |= (((signed char)start[i] - 1) >> 7) & 0x0a; + FFLUSH_STDOUT /* Do this first */ + /* Now we can deliver our postponed error and advisory messages */ + if ( INVERSE( retval) ) + { + file_is_missing( (char *)name); + if ( inp_fil_acc_err ) + { + expansion_error(); + tokenization_error( TKERROR, + "Could not access input file %s\n", name); + }else{ + if ( inp_fil_open_err ) + { + expansion_error(); + could_not_open( TKERROR, (char *)name, "input"); + }else{ + if ( inp_fil_read_err ) + { + expansion_error(); + tokenization_error( TKERROR, + "Could not read input file %s\n", name); + } + } } - start[ilen]=0; + } - pc=start; - end=pc+ilen; + if ( tried_stat ) + { + finish_incl_list_scan( stat_succ); + }
+ /* Don't change the input file name and line-number until after + * the Advisory showing where the file was found. + */ + if ( retval ) + { iname=strdup(name); - lineno=1; + } - return 0; + return ( retval ); }
-int init_output( const char *in_name, const char *out_name ) +/* ************************************************************************** + * + * Function name: extend_filename + * Synopsis: Change the filename to the given extension + * + * Inputs: + * Parameters: + * base_name Name of the Input Base File + * new_ext New ext'n (with leading period) + * + * Outputs: + * Returned Value: Result filename + * Memory Allocated + * Buffer for result filename + * When Freed? + * At end of Tokenization, by close_output(). + * + * Process Explanation: + * If the Input Base File Name has an extension, it will be replaced + * with the given new extension. If not, the new extension will + * simply be appended. + * If the Input Base File Name has an extension that matches the + * new extension, a duplicate of the extension will be appended. + * + * Extraneous Remarks: + * I only recently added protection against the situation where the + * Input Base File Name has no extension, but the Directory Path + * leading to it has a period in one of the directory names. + * Granted, this is a rare case, but not altogether impossible; + * I would have done it earlier except for the fact that the + * separator between directories may vary with different Host + * Operating Systems. + * However, at this point we have UNIX-centric assumptions hard- + * -coded in to so many other places that we might as well + * go with the slash here too. + * + **************************************************************************** */ + +static char *extend_filename( const char *base_name, const char *new_ext) { - const char *ext; + char *retval; + char *ext; unsigned int len; /* should this be size_t? */ + const char *root;
+ root = strrchr(base_name, '/'); + if ( root == NULL ) root = base_name; + + ext = strrchr(root, '.'); + if ( ext != NULL ) + { + if ( strcasecmp(ext, new_ext) == 0 ) + { + ext = NULL; + } + } + + len = ext ? (ext - base_name) : (unsigned int)strlen(base_name) ; + retval = safe_malloc(len+strlen(new_ext)+1, "extending file-name"); + memcpy( retval, base_name, len); + retval[len] = 0; + strcat(retval, new_ext); + + return( retval); +} + +/* ************************************************************************** + * + * Function name: init_output + * Synopsis: After the Input Source File has been opened, assign + * the name for the Binary Output File; initialize + * the FCode Output Buffer; assign names for the + * FLoad List, Dependency-List, and Missing-Files + * List files; open them and write their first + * entries to them. + * Announce the Input and various output file names. + * + * Inputs: + * Parameters: + * in_name Name of the Input Source File + * out_name Name of the Binary Output File, if + * specified on the Command Line, + * or NULL if not. + * Global Variables: + * fload_list Whether to create an FLoad-List file + * dependency_list Whether to create a Dependency-List file + * Local Static Variables: + * include_list_full_path Full Path to the Input Source File; + * should still be valid from opening + * of Primary Source Input file, for + * first entry to Dependency-List file. + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * oname Binary Output File Name + * ostart Start of FCode Output Buffer + * opc FCode Output Buffer Position Counter + * abs_token_no Initialized to 1 + * Local Static Variables: + * load_list_name Name of the Load List File + * load_list_file FLoad List File Structure pointer + * depncy_list_name Name of the Dependency List File ptr + * depncy_file Dependency List File Structure + * missing_list_name Name of the Missing-Files-List File + * missing_list_file Missing-Files-List File Structure + * no_files_missing Initialized to TRUE + * Memory Allocated + * Binary Output File Name Buffer + * FCode Output Buffer + * FLoad List File Name Buffer + * Dependency List File Name Buffer + * + * When Freed? + * In close_output() + * File Output: + * FLoad List or Dependency List files are opened (if specified). + * Primary Source Input file name and path, respectively, + * are written as the first entry to each. + * Printout: + * (Announcement of input file name has already been made) + * Announce binary output, fload- and dependency- -list file names + * + * Error Detection: + * Failure to open FLoad List or Dependency List file: ERROR; + * suppress binary output. Further attempts to write to + * FLoad List or Dependency List files are prevented by + * the respective FILE_structure pointers being NULL. + * Failure to open Missing-Files-List file: WARNING + * + * Process Explanation: + * If no Output File Name was specified on the Command Line, the + * name of the Binary (FCode) Output File will be derived + * from the name of the Input File by replacing its extension + * with .fc , or, if the Input File had no extension, by + * merely appending the extension .fc + * In the odd case where the Input File name has an extension + * of .fc, we will merely append another .fc extension. + * If fload_list is TRUE (i.e., the "-l" option was specified on + * the command-line, the FLoad List File name will be derived + * from the name of the Output File by the same rules, only with + * an extension of .fl Open the FLoad List File. Write the + * name of the initial input file to the FLoad List File. + * Similarly if the "-P" command-line option was specified, the name + * of the Dependency List File will be derived with an extension + * of .P Open it and write the Full Path for the initial input + * file to it. NOTE: To do that, we need to have preserved the + * Full Path-name Buffer from the call to init_stream() We + * will "finish" it here, after we've used it. + * The Missing-Files-List File will be created if either option was + * specified. Its name will be derived similarly, with an + * extension of .fl.missing + * + **************************************************************************** */ + +void init_output( const char *in_name, const char *out_name ) +{ /* preparing output */
- if( out_name ) - oname = (u8 *)strdup( out_name ); - else { - ext=strrchr(in_name, '.'); - len=ext ? (unsigned int)(ext-in_name) : (unsigned int)strlen(in_name) ; - oname=malloc(len+4); - memcpy(oname, in_name, len); - oname[len] = 0; - strcat((char *)oname, ".fc"); + if( out_name != NULL ) + { + oname = strdup( out_name ); + }else{ + oname = extend_filename( in_name, ".fc"); } /* output buffer size. this is 128k per default now, but we * could reallocate if we run out. KISS for now. */ - ostart=malloc(OUTPUT_SIZE); - if (!ostart) { - free(oname); - free(start); - return -1; + olen = OUTPUT_SIZE; + ostart=safe_malloc(olen, "initting output buffer"); + + opc = 0; + init_emit(); /* Init'l'zns needed by our companion file, emit.c */ + + printf("Binary output to %s ", oname); + if ( fload_list ) + { + load_list_name = extend_filename( oname, ".fl"); + load_list_file = fopen( load_list_name,"w"); + printf(" FLoad-list to %s ", load_list_name); } + if ( dependency_list ) + { + depncy_list_name = extend_filename( oname, ".P"); + depncy_file = fopen( depncy_list_name,"w"); + printf(" Dependency-list to %s ", depncy_list_name); + } + printf("\n");
- opc=oend=ostart; - oend+=OUTPUT_SIZE; + add_to_load_lists( in_name); - /* We're beginning a new output file, so we have to - * start our own fcode numbers at 0x800 again. - */ - nextfcode=0x800; + /* Let's avoid collisions between stdout and stderr */ + FFLUSH_STDOUT + + /* Now we can deliver our advisory and error messages */ - return 0; + { + /* Suspend showing filename in advisory and error messages. */ + char *temp_iname = iname; + iname = NULL; + + finish_incl_list_scan( TRUE); + + if ( fload_list && (load_list_file == NULL) ) + { + could_not_open( TKERROR, load_list_name, "Load-List"); + free( load_list_name); + } + if ( dependency_list && (depncy_file == NULL) ) + { + could_not_open( TKERROR, depncy_list_name, + "Dependency-List"); + free( depncy_list_name); }
-int close_stream(void) + if ( fload_list || dependency_list ) + { + missing_list_name = extend_filename( oname, ".fl.missing"); + missing_list_file = fopen( missing_list_name,"w"); + no_files_missing = TRUE; + + if ( missing_list_file == NULL ) + { + could_not_open( WARNING, missing_list_name, + "Missing-Files List" ); + free( missing_list_name); + } + } + iname = temp_iname; + } + abs_token_no = 1; +} + +/* ************************************************************************** + * + * Function name: increase_output_buffer + * Synopsis: Reallocate the Output Buffer to double its prior size + * + * Inputs: + * Parameters: NONE + * Global Variables: + * ostart Start-address of current Output Buffer + * olen Current size of the Output Buffer + * Local Static Variables: + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * olen Doubled from value at input + * ostart Start-address of new Output Buffer + * Memory Allocated + * A new FCode Output Buffer, using the realloc() facility. + * When Freed? + * In close_output() + * Memory Freed + * Former FCode Output Buffer, also by means of realloc() + * + * Printout: + * Advisory message that this is taking place. + * + * Error Detection: + * FATAL if realloc() fails. + * FATAL if output buffer has been expanded to a size beyond + * what an INT can express. Unlikely? maybe; impossible? no... + * + * Process Explanation: + * Because we are allowing the Output Buffer to be relocated, we + * must take care to limit the exposure to external routines + * of its actual address. All references to locations within + * the Output Buffer should be made in terms of an _offset_. + * + * Extraneous Remarks: + * Unfortunately, it is not feasible to completely isolate the + * actual address of the Output Buffer, but we will keep the + * exposure limited to the routines in emit.c + * Similarly, it wasn't feasible to keep this routine isolated, + * nor the variable olen , but we will limit their exposure. + * + **************************************************************************** */ +void increase_output_buffer( void ); /* Keep the prototype local */ +void increase_output_buffer( void ) { + u8 *newout; + + if ( olen == 0 ) + { + tokenization_error( FATAL, + "Output Buffer reallocation overflow."); + }else{ + unsigned int rea_len; + olen = olen * 2; + rea_len = olen; + if ( rea_len == 0 ) rea_len = (unsigned int)-1; + tokenization_error( INFO, + "Output Buffer overflow. " + "Relocating and increasing to %d bytes.\n", rea_len); + + newout = realloc(ostart, rea_len); + if ( newout == NULL) + { + tokenization_error( FATAL, + "Could not reallocate %d bytes for Output Buffer", rea_len); + } + + ostart = newout; + } +} + + +/* ************************************************************************** + * + * Function name: close_stream + * Synopsis: Free-up the memory used for the current input file + * whenever it is closed. Reset pointers and + * line-counter. Close files as necessary. + * + * The dummy parameter is there to accommodate Macro-recursion protection. + * It's a long story; don't get me started... + * + **************************************************************************** */ + +void close_stream( _PTR dummy) +{ free(start); free(iname); - return 0; + start = NULL; + iname = NULL; + lineno = 0; }
-int close_output(void) +/* ************************************************************************** + * + * Function name: close_output + * Synopsis: Write the Binary Output file, if appropriate. + * Return a "Failure" flag. + * + **************************************************************************** */ + + +bool close_output(void) { + bool retval = TRUE; /* "Failure" */ + if ( error_summary() ) + { + if ( opc == 0 ) +{ + retval = FALSE; /* "Not a problem" */ + }else{ FILE *outfile; - unsigned int len;
- len=(unsigned long)opc-(unsigned long)ostart; + outfile=fopen( oname,"w"); + if (!outfile) + { + /* Don't do this as a tokenization_error( TKERROR + * because those are all counted, among other reasons... + */ + printf( "Could not open file %s for output.\n", oname); + }else{ - outfile=fopen((char *)oname,"w"); - if (!outfile) { - printf("toke: error opening output file.\n"); - return -1; + if ( fwrite(ostart, opc, 1, outfile) != 1 ) + { + tokenization_error( FATAL, "While writing output."); } - if(fwrite(ostart, len, 1, outfile)!=1) - printf ("toke: error while writing output.\n"); - fclose(outfile);
- printf("toke: wrote %d bytes to bytecode file '%s'\n", len, oname); + printf("toke: wrote %d bytes to bytecode file '%s'\n", + opc, oname); + retval = FALSE; /* "No problem" */ + } + } + } free(oname); - return 0; + free(ostart); + oname = NULL; + ostart = NULL; + opc = 0; + olen = OUTPUT_SIZE; + + if ( load_list_file != NULL ) + { + fclose(load_list_file); + free(load_list_name); + } + if ( depncy_file != NULL ) + { + fclose(depncy_file); + free(depncy_list_name); + } + if ( missing_list_file != NULL ) + { + fclose( missing_list_file); + if ( no_files_missing ) + { + remove( missing_list_name); + } + free( missing_list_name); + } + + load_list_file = NULL; + load_list_name = NULL; + missing_list_file = NULL; + missing_list_name = NULL; + depncy_file = NULL; + depncy_list_name = NULL; + + return ( retval ); }
Modified: fcode-utils/toke/stream.h =================================================================== --- fcode-utils/toke/stream.h 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/stream.h 2006-08-18 12:47:12 UTC (rev 76) @@ -1,3 +1,6 @@ +#ifndef _H_STREAM +#define _H_STREAM + /* * OpenBIOS - free your system! * ( FCode tokenizer ) @@ -24,15 +27,68 @@ * */
-#ifndef _H_STREAM -#define _H_STREAM +/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */
-int init_stream( const char *name ); -int close_stream(void); -int init_output( const char *inname, const char *outname ); -int close_output(void); +#include "types.h"
-extern unsigned int lineno; +/* ************************************************************************** + * + * Exported Global Variables + * + **************************************************************************** */ + +/* input pointers */ +extern u8 *start; +extern u8 *pc; +extern u8 *end; extern char *iname; +extern unsigned int lineno; /* Line Number within current input file */ +extern unsigned int abs_token_no; /* Absolute Token Number in Source Input */
+/* output pointers */ +extern char *oname; /* output file name */ + +extern unsigned int opc; /* output buffer position counter */ + +/* ************************************************************************** + * + * Note that the variables ostart and olen , as well as the routine + * increase_output_buffer are not listed here. + * + * We would have preferred to isolate them completely, but we would have + * to disrupt the organization of emit.c (which we'd rather not); + * in order to avoid exporting them any more widely than necessary, + * we will declare them extern only in the file where they are + * unavoidably needed. + * + **************************************************************************** */ + +/* ************************************************************************** + * Macro Name: OUTPUT_SIZE + * Initial size of the Output Buffer + * + **************************************************************************** */ + +#define OUTPUT_SIZE 131072 + + +/* ************************************************************************** + * + * Exported Functions + * + **************************************************************************** */ + +void add_to_include_list( char *dir_compt); +void display_include_list( void); +FILE *open_expanded_file( const char *path_name, char *mode, char *for_what); +bool init_stream( const char *name ); +void close_stream( _PTR dummy); +void init_output( const char *inname, const char *outname ); +bool close_output(void); +void init_inbuf(char *inbuf, unsigned int buflen); + #endif /* _H_STREAM */
Added: fcode-utils/toke/strsubvocab.c =================================================================== --- fcode-utils/toke/strsubvocab.c (rev 0) +++ fcode-utils/toke/strsubvocab.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,337 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * General-purpose support functions for + * String-Substitution-type vocabularies + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * A String-Substitution vocabulary, as the name implies, is one in + * in which each an entry consists of two strings; one that is + * sought, and one that is returned as a substitute. Macros and + * aliases are implemented this way, as are also user-supplied + * command-line symbol definitions. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Functions Exported: + * init_str_sub_vocab Initialize a String-Substitution vocab + * add_str_sub_entry Add an entry to a Str-Subst vocab + * lookup_str_sub Look for a name in a String-Substitution + * vocab, return the substitution string. + * exists_in_str_sub Confirm whether a given name exists in a + * String-Substitution vocabulary + * create_str_sub_alias Duplicate the behavior of one name with + * another name. Return a "success" flag. + * reset_str_sub_vocab Reset a given Str-Subst vocab to its initial + * "Built-In" position. + * + * + **************************************************************************** */ + +#include <stdio.h> +#include <stdlib.h> +#if defined(__linux__) && ! defined(__USE_BSD) +#define __USE_BSD +#endif +#include <string.h> + +#include "errhandler.h" +#include "strsubvocab.h" + + +/* ************************************************************************** + * + * Function name: init_str_sub_vocab + * Synopsis: Dynamically initialize the link-pointers + * of the.given String-Substitution vocabulary + * + * Inputs: + * Parameters: + * str_sub_vocab_tbl Pointer to the initial Str-Subst vocab array + * max_indx Maximum Index of the initial array. + * + * Outputs: + * Returned Value: None + * Global Variables: + * The link-fields of the initial Str-Subs vocab array entries + * will be filled in. + * + **************************************************************************** */ + +void init_str_sub_vocab( str_sub_vocab_t *str_sub_vocab_tbl, int max_indx) +{ + int indx; + for ( indx = 1 ; indx < max_indx ; indx++ ) + { + str_sub_vocab_tbl[indx].next = &str_sub_vocab_tbl[indx-1]; + } +} + +/* ************************************************************************** + * + * Function name: add_str_sub_entry + * Synopsis: Add an entry to the given Str-Subst vocab + * + * Inputs: + * Parameters: Pointer to: + * ename space containing the name of the entry + * subst_str space containing the substitution string + * *str_sub_vocab the "tail" of the Str-Subst vocab-list + * + * Outputs: + * Returned Value: NONE + * Supplied Pointers: + * *str_sub_vocab Will point to new entry + * Memory Allocated: + * Memory for the new entry will be allocated. + * When Freed? + * When reset_str_sub_vocab() is applied to the same vocab-list. + * In some instances, the new entry will be freed upon end + * of tokenization; in others, only on termination of program. + * + * Error Detection: + * Failure to allocate memory is a Fatal Error. + * + * Process Explanation: + * The name and substitution-string pointers are presumed to already + * point to stable memory-spaces. Memory will be allocated + * for the entry itself; its pointers will be entered and the + * given pointer-to-the-tail-of-the-vocabulary will be updated. + * + * Extraneous Remarks: + * This might have been where we would have checked for re-aliasing, + * but the introduction of the approach to aliasing embodied in + * the various create_..._alias() routines neatly bypasses it. + * + **************************************************************************** */ + +void add_str_sub_entry( char *ename, + char *subst_str, + str_sub_vocab_t **str_sub_vocab ) +{ + str_sub_vocab_t *new_entry; + + new_entry = safe_malloc(sizeof(str_sub_vocab_t), "adding str_sub_entry"); + new_entry->name = ename; + new_entry->alias = subst_str; + new_entry->next = *str_sub_vocab; + + *str_sub_vocab = new_entry; + +} + + +/* ************************************************************************** + * + * Function name: lookup_str_sub + * Synopsis: Look for a name in the given Str-Subst vocabulary + * + * Inputs: + * Parameters: + * tname The "target" name for which to look + * str_sub_vocab The Str-Subst vocab-list + * + * Outputs: + * Returned Value: Pointer to the substitution string, or + * NULL pointer if name not found. + * May be NULL if subst'n string is NULL. + * + **************************************************************************** */ + +char *lookup_str_sub( char *tname, str_sub_vocab_t *str_sub_vocab ) +{ + str_sub_vocab_t *curr; + char *retval = NULL; + + for (curr = str_sub_vocab ; curr != NULL ; curr=curr->next) + { + if ( strcasecmp(tname, curr->name) == 0 ) + { + retval = curr->alias; + break; + } + } + return ( retval ) ; +} + +/* ************************************************************************** + * + * Function name: exists_in_str_sub + * Synopsis: Confirm whether a given name exists in a given + * String-Substitution vocabulary + * + * Inputs: + * Parameters: + * tname The "target" name for which to look + * str_sub_vocab Pointer to the Str-Subst vocab-list + * + * Outputs: + * Returned Value: TRUE if the name is found + * + * Extraneous Remarks: + * Because the Returned Value of lookup_str_sub() may be NULL for + * other reasons than that the name was not found, we cannot + * rely on that routine, and must replicate the outer-shell + * of its structure. + * + **************************************************************************** */ + +bool exists_in_str_sub( char *tname, str_sub_vocab_t *str_sub_vocab ) +{ + str_sub_vocab_t *curr; + bool retval = FALSE; + + for (curr = str_sub_vocab ; curr != NULL ; curr=curr->next) + { + if ( strcasecmp(tname, curr->name) == 0 ) + { + retval = TRUE; + break; + } + } + return ( retval ); + +} + +/* ************************************************************************** + * + * Function name: create_str_sub_alias + * Synopsis: Create an Alias in a String-Substitution vocabulary + * Return a "success" flag. + * + * Associated FORTH word: ALIAS + * + * Inputs: + * Parameters: + * old_name Name of existing entry + * new_name New name for which to create an entry + * *str_sub_vocab Pointer to "tail" of Str-Subst vocab-list + * + * Outputs: + * Returned Value: TRUE if old_name found in str_sub_vocab + * Supplied Pointers: + * *str_sub_vocab Will be updated to point to the new entry + * Memory Allocated: + * A copy of the "old" name's substitution string. + * When Freed? + * When reset_str_sub_vocab() is applied to the same vocab-list. + * In some instances, the new entry will be freed when the + * device-node in which it was created is "finish"ed; in + * others, only on termination of the program. + * + * Process Explanation: + * The "new" name is presumed to point to a stable memory-space. + * If the given "old" name exists in the given Str-Subst vocab-list, + * duplicate the substitution string into newly-allocated memory + * and pass the duplicated string and the "new" name along to + * the add_str_sub_entry() routine and return TRUE. + * If the given "old" name does not exist in the given vocab-list, + * return FALSE. + * + * Extraneous Remarks: + * This neatly bypasses the question of re-aliasing... ;-) + * + * We can rely on testing for a returned NULL from lookup_str_sub() + * because we won't be applying this routine to any vocabulary + * that permits a NULL in its substitution string. + * + **************************************************************************** */ + +bool create_str_sub_alias(char *new_name, + char *old_name, + str_sub_vocab_t **str_sub_vocab ) +{ + bool retval = FALSE; + char *old_subst_str = lookup_str_sub( old_name, *str_sub_vocab ); + if ( old_subst_str != NULL ) + { + char *new_subst_str = strdup(old_subst_str ); + add_str_sub_entry(new_name, new_subst_str, str_sub_vocab ); + retval = TRUE ; + } + + return ( retval ); +} + + +/* ************************************************************************** + * + * Function name: reset_str_sub_vocab + * Synopsis: Reset a given Str-Subst vocab to its initial + * "Built-In" position. + * + * Inputs: + * Parameters: + * *str_sub_vocab Pointer to the Str-Subst vocab-list + * reset_position Position to which to reset the list + * + * Outputs: + * Returned Value: NONE + * Supplied Pointers: + * *str_sub_vocab Reset to given "Built-In" position. + * Memory Freed + * All memory allocated by user-definitions will be freed + * + * Process Explanation: + * The "stable memory-spaces" to which the name and substitution + * string pointers point are presumed to have been acquired + * by allocation of memory, which is reasonable for entries + * created by the user as opposed to the built-in entries, + * which we are, in any case, not releasing. + * The substitution-string pointer may be null; watch out when + * we free() it; not all C implementations forgive that. + * + **************************************************************************** */ + +void reset_str_sub_vocab( + str_sub_vocab_t **str_sub_vocab , + str_sub_vocab_t *reset_position ) +{ + str_sub_vocab_t *next_t; + + next_t = *str_sub_vocab; + while ( next_t != reset_position ) + { + next_t = (*str_sub_vocab)->next ; + + free( (*str_sub_vocab)->name ); + if ( !(*str_sub_vocab)->alias ) + { + free( (*str_sub_vocab)->alias ); + } + free( *str_sub_vocab ); + *str_sub_vocab = next_t ; + } +} +
Added: fcode-utils/toke/strsubvocab.h =================================================================== --- fcode-utils/toke/strsubvocab.h (rev 0) +++ fcode-utils/toke/strsubvocab.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,85 @@ +#ifndef _TOKE_STRSUBVOCAB_H +#define _TOKE_STRSUBVOCAB_H + + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Headers, general-purpose support structures, function prototypes + * and macros for String-Substitution-type vocabularies. + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Structures: + * str_sub_vocab_t Entry in a String-Substitution-type vocab + * + * Macros: + * BUILTIN_STR_SUB Add an entry to the initial Str-Sub vocab. + * + **************************************************************************** */ + +#include "types.h" + + +typedef struct str_sub_vocab { + u8 *name; + u8 *alias; + struct str_sub_vocab *next; +} str_sub_vocab_t; + +#if 0 /* On the way out */ +/* + * BUILTIN_STR_SUB Add an entry to the initial Str-Sub vocab. + * + * Arguments: (Both are strings) + * princ Principal name by which the string is known + * subst Substitution-string that replaces the Principal. + */ +#define BUILTIN_STR_SUB(princ, subst) \ + { princ , subst , (str_sub_vocab_t *)NULL } +#endif /* On the way out */ + + +void init_str_sub_vocab( str_sub_vocab_t *str_sub_vocab_tbl, + int max_indx); +void add_str_sub_entry( char *ename, + char *subst_str, + str_sub_vocab_t **str_sub_vocab ); +char *lookup_str_sub( char *tname, str_sub_vocab_t *str_sub_vocab ); +bool create_str_sub_alias(char *new_name, + char *old_name, + str_sub_vocab_t **str_sub_vocab ); +bool exists_in_str_sub( char *tname, str_sub_vocab_t *str_sub_vocab ); +void reset_str_sub_vocab( str_sub_vocab_t **str_sub_vocab , + str_sub_vocab_t *reset_position ); + + +#endif /* _TOKE_STRSUBVOCAB_H */
Added: fcode-utils/toke/ticvocab.c =================================================================== --- fcode-utils/toke/ticvocab.c (rev 0) +++ fcode-utils/toke/ticvocab.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,426 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * General-purpose support functions for + * Threaded Interpretive Code (T. I. C.)-type vocabularies + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * We are going to implement a strategy that takes better advantage + * of the concept of Threaded Interpretive Code (well, okay, + * it won't really be interpretive ... ) We will use it to + * implement a small (but expandable) subset of FORTH-like + * commands in Tokenizer-Escape mode, as well as a few other + * things, such as conditional-tokenization. + * + * The Threaded Interpretive Code Header data structure is described + * in detail in the accompanying ticvocab.h header-file. + * + * In most cases, the contents of a beginning portion of the vocabulary + * are known at compile-time, and later parts are added by the + * user at run-time. (The linked-list structure is needed to allow + * for that.) We can initialize the known start of the vocabulary + * easily, except for the link-pointers, as an array. + * We can either explicitly state an index for each entry's link-pointer + * to the previous entry (which can become a problem to maintain) or + * have a function to initialize the links dynamically, at run-time. + * I think I will (regretfully, resignedly) choose the latter. + * + * We will define a few general-purpose functions for dealing with + * T. I. C. -type vocabularies. Eventually, it might be a good + * idea to convert all the vocabularies to this structure... + * + **************************************************************************** */ + +/* ************************************************************************** + * + * + * Revision History: + * Mon, 19 Dec 2005 by David L. Paktor + * Begin converting most, if not all, of the vocabularies to + * T. I. C. -type structure. + * + **************************************************************************** */ + + +/* ************************************************************************** + * + * Functions Exported: + * init_tic_vocab Initialize a TIC_HDR -type vocabulary + * add_tic_entry Add an entry to a TIC_HDR -type vocabulary + * lookup_tic_entry Look for a name in a TIC_HDR -type vocabulary + * handle_tic_vocab Perform a function in a TIC_HDR -type vocab + * exists_in_tic_vocab Confirm whether a given name exists in a + * TIC_HDR -type vocabulary + * create_tic_alias Duplicate the behavior of one name with + * another name. Return a "success" flag. + * reset_tic_vocab Reset a given TIC_HDR -type vocabulary to + * its "Built-In" position. + * + **************************************************************************** */ + + +/* ************************************************************************** + * + * Global Variables Exported + * tic_found The entry, in a TIC_HDR -type vocabulary, + * that has just been found and is being + * "handled". Needed for protection against + * recursion in a User-defined Macro (which + * should occur only rarely). + * + **************************************************************************** */ + + +#include <stdlib.h> +#include <string.h> +#include "ticvocab.h" +#include "errhandler.h" + +tic_hdr_t *tic_found; + +/* ************************************************************************** + * + * Function name: init_tic_vocab + * Synopsis: Dynamically initialize the link-pointers + * of the.given TIC_HDR -type vocabulary + * + * Inputs: + * Parameters: + * tic_vocab_tbl Pointer to the initial TIC_HDR vocab array + * max_indx Maximum Index of the initial array. + * tic_vocab_ptr Pointer to the vocab "tail" + * + * Outputs: + * Returned Value: None + * Global Variables: + * The link-fields of the initial TIC_HDR vocab array entries + * will be filled in. + * Supplied Pointers: + * *tic_vocab_ptr Points to the last element in the array + * + * Process Explanation: + * The value that tic_vocab_ptr has upon entry to the routine + * (which may point to the end of another array which is to + * precede this one in the voacbulary) gets entered into + * the link-pointer field of the first element of the array. + * For this reason, it is important that all TIC_HDR vocabulary + * pointers that will be pased to this routine have their + * initial values explicitly declared NULL. + * + **************************************************************************** */ + +void init_tic_vocab( tic_hdr_t *tic_vocab_tbl, + int max_indx, + tic_hdr_t **tic_vocab_ptr) +{ + int indx; + for ( indx = 0 ; indx < max_indx ; indx++ ) + { + tic_vocab_tbl[indx].next = *tic_vocab_ptr; + *tic_vocab_ptr = &tic_vocab_tbl[indx]; + } +} + + +/* ************************************************************************** + * + * Function name: add_tic_entry + * Synopsis: Add an entry to the given TIC_HDR -type vocabulary + * + * Inputs: + * Parameters: + * tname Pointer to space containing the name of the entry + * tfunct Pointer to the routine the new entry will call + * tparam The "parameter field" value (may be a pointer) + * fw_defr FWord Token of the entry's Definer + * pfldsiz Size of "param field" (if a pointer to alloc'd mem) + * ign_fnc Pointer to "ignoring" routine for new entry + * tic_vocab Pointer to ptr to "tail" of T.I.C.-type vocab-list + * + * Outputs: + * Returned Value: NONE + * Supplied Pointers: + * *tic_vocab Will point to new entry + * Memory Allocated: + * For the new entry. + * When Freed? + * When reset_tic_vocab() is applied to the same vocab-list. + * + * Error Detection: + * Failure to allocate memory is a Fatal Error. + * + * Process Explanation: + * The name pointer is presumed to already point to a stable, + * newly-allocated memory-space. If the parameter field is + * actually a pointer, it, too, is presumed to already have + * been allocated. + * Memory will be allocated for the entry itself; its pointers + * will be entered and the given pointer-to-the-tail-of-the- + * -vocabulary will be updated to point to the new entry. + * + **************************************************************************** */ + +void add_tic_entry( char *tname, + void (*tfunct)(), + TIC_P_DEFLT_TYPE tparam, + fwtoken fw_defr, + int pfldsiz, + void (*ign_fnc)(), + tic_hdr_t **tic_vocab ) +{ + tic_hdr_t *new_entry; + + new_entry = safe_malloc(sizeof(tic_hdr_t), "adding tic_entry"); + new_entry->name = tname; + new_entry->next = *tic_vocab; + new_entry->funct = tfunct; + new_entry->pfield.deflt_elem = tparam; + new_entry->fword_defr = fw_defr; + new_entry->ign_func = ign_fnc; + new_entry->pfld_size = pfldsiz; + + *tic_vocab = new_entry; + +} + +/* ************************************************************************** + * + * Function name: lookup_tic_entry + * Synopsis: Look for a name in the given TIC_HDR -type vocabulary + * + * Inputs: + * Parameters: + * tname The "target" name for which to look + * tic_vocab Pointer to the T. I. C. -type vocabulary + * + * Outputs: + * Returned Value: Pointer to the relevant entry, or + * NULL if name not found. + * + * Extraneous Remarks: + * We don't set the global tic_found here because this routine + * is not always called when the found function is going to + * be executed; sometimes it is called for error-detection, + * for instance... + * + **************************************************************************** */ + +tic_hdr_t *lookup_tic_entry( char *tname, tic_hdr_t *tic_vocab ) +{ + tic_hdr_t *curr ; + + for (curr = tic_vocab ; curr != NULL ; curr=curr->next) + { + if ( strcasecmp(tname, curr->name) == 0 ) + { + break; + } + } + + return ( curr ) ; +} + +/* ************************************************************************** + * + * Function name: exists_in_tic_vocab + * Synopsis: Confirm whether the given name exists in the + * given TIC_HDR -type vocabulary + * + * Inputs: + * Parameters: + * tname The name for which to look + * tic_vocab Pointer to the T. I. C. -type vocabulary + * + * Outputs: + * Returned Value: TRUE if name is found, + * + **************************************************************************** */ + +bool exists_in_tic_vocab( char *tname, tic_hdr_t *tic_vocab ) +{ + tic_hdr_t *found ; + bool retval = FALSE; + + found = lookup_tic_entry( tname, tic_vocab ); + if ( found != NULL ) + { + retval = TRUE; + } + + return ( retval ); +} + + +/* ************************************************************************** + * + * Function name: create_tic_alias + * Synopsis: Create an Alias in a TIC_HDR -type vocabulary + * Return a "success" flag. + * + * Associated FORTH word: ALIAS + * + * Inputs: + * Parameters: + * old_name Name of existing entry + * new_name New name for which to create an entry + * *tic_vocab Pointer to the "tail" of the + * T. I. C. -type vocab-list + * + * Outputs: + * Returned Value: TRUE if old_name found in given vocab + * Supplied Pointers: + * *tic_vocab Will be updated to point to the new entry + * Memory Allocated: + * For the new entry, by the support routine. + * When Freed? + * When reset_tic_vocab() is applied to the same vocab-list. + * + * Process Explanation: + * Both the "old" and "new" names are presumed to already point to + * stable, freshly allocated memory-spaces. + * Even if the "old" entry's pfld_size is not zero, meaning its + * param-field is a pointer to allocated memory, we still do + * not need to copy it into a freshly allocated memory-space, + * as long as we make the new alias-entry's pfld_size zero: + * the reference to the old space will work, and the old + * entry's param-field memory space will not be freed with + * the alias-entry but only with the "old" entry. + * + **************************************************************************** */ + +bool create_tic_alias( char *new_name, char *old_name, tic_hdr_t **tic_vocab ) +{ + tic_hdr_t *found ; + bool retval = FALSE; + + found = lookup_tic_entry( old_name, *tic_vocab ); + if ( found != NULL ) + { + add_tic_entry( new_name, found->funct, + found->pfield.deflt_elem, + found->fword_defr, + 0, found->ign_func, tic_vocab ); + retval = TRUE; + } + + return ( retval ); +} + + +/* ************************************************************************** + * + * Function name: handle_tic_vocab + * Synopsis: Perform the function associated with the given name + * in the given TIC_HDR -type vocabulary + * + * Inputs: + * Parameters: + * tname The "target" name for which to look + * tic_vocab Pointer to the T. I. C. -type vocabulary + * + * Outputs: + * Returned Value: TRUE if the given name is valid in the given vocab + * Global Variables: + * tic_found Points to the TIC entry of the "target" + * name, if it was found; else, NULL. + * Global Behavior: + * Whatever the associated function does... + * + * Process Explanation: + * Find the name and execute its associated function. + * If the name is not in the given vocabulary, return + * an indication; leave it to the calling routine + * to decide how to proceed. + * + **************************************************************************** */ + +bool handle_tic_vocab( char *tname, tic_hdr_t *tic_vocab ) +{ + bool retval = FALSE; + + tic_found = lookup_tic_entry( tname, tic_vocab ); + if ( tic_found != NULL ) + { + tic_found->funct( tic_found->pfield); + retval = TRUE; + } + + return ( retval ) ; +} + +/* ************************************************************************** + * + * Function name: reset_tic_vocab + * Synopsis: Reset a given TIC_HDR -type vocabulary to + * its given "Built-In" position. + * + * Inputs: + * Parameters: + * *tic_vocab Pointer to the T. I. C.-type vocab-list + * reset_position Position to which to reset the list + * + * Outputs: + * Returned Value: NONE + * Supplied Pointers: + * *tic_vocab Reset to given "Built-In" position. + * Memory Freed + * All memory allocated by user-definitions will be freed + * + * Process Explanation: + * The "stable memory-spaces" to which the name and parameter + * field pointers point are presumed to have been acquired + * by allocation of memory, which is reasonable for entries + * created by the user as opposed to the built-in entries, + * which we are, in any case, not releasing. + * The parameter-field size field tells us whether we need to + * free() the parameter-field pointer. + * + **************************************************************************** */ + +void reset_tic_vocab( tic_hdr_t **tic_vocab, tic_hdr_t *reset_position ) +{ + tic_hdr_t *next_t; + + next_t = *tic_vocab; + while ( next_t != reset_position ) + { + next_t = (*tic_vocab)->next ; + + free( (*tic_vocab)->name ); + if ( (*tic_vocab)->pfld_size != 0 ) + { + free( (*tic_vocab)->pfield.chr_ptr ); + } + free( *tic_vocab ); + *tic_vocab = next_t ; + } +}
Added: fcode-utils/toke/ticvocab.h =================================================================== --- fcode-utils/toke/ticvocab.h (rev 0) +++ fcode-utils/toke/ticvocab.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,478 @@ +#ifndef _TOKE_TICVOCAB_H +#define _TOKE_TICVOCAB_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * General-purpose support structures and function prototypes for + * Threaded Interpretive Code (T. I. C.)-type vocabularies. + * See ticvocab.c + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Structures: + * + * The Threaded Interpretive Code Header data structure consists of: + * (1) A pointer to the function name as seen in the source + * (2) A link to the next (well, preceding) element + * (3) A Pointer to the routine to run as the function's behavior + * during active processing. It takes the "parameter field" + * item as its argument and has no return-value. + * (4) The "parameter field" item, which will be passed as an + * argument to the function. It may be an FCode- or FWord- + * -token, or an item of another type, or a pointer to data. + * The function may re-cast it as needed. + * (5) The "Definer" of the entry; a member of the subset of FWord- + * -tokens that may be Definers. + * (6) A Pointer to a routine to be run when the word is encountered + * in a Conditional Compilation section that is being ignored. + * Certain functions still need to be recognized in that state, + * and will require special behaviors; those that can be simply + * ignored will have a NULL pointer in this field. The function + * in this field, also, takes the "parameter field" item as its + * argument and has no return-value. + * (7) The size of the data pointed to by the "parameter field" item, + * if it is a pointer to allocated data; used to allocate space + * for a copy of the p.f. when making an alias, and to indicate + * whether the space needs to be freed. Automatic procedures + * are too often fooled, so we don't leave things to chance... + * To accommodate C's insistence on strong-typing, we might need + * to define different "parameter field" structure-types; see + * description of "Parameter Field as a union", below. + * + * It's not an exact name, but we'll still call it a T. I. C. Header + * + * We will use this structure for most of our vocabularies... + * + **************************************************************************** + * + * The "Parameter Field" is a union of several alternative types, + * for convenience, to avert excessive type-casting. It may + * either be the Parameter Data itself (if it is small enough) + * or a pointer to Parameter Data. + * In the case where the Parameter Field is the data itself, or is a + * pointer to hard-coded (non-allocated) data, the "size" field + * will be zero, to indicate that no space allocation is required. + * The types are (starting with the default for initialization) + * A long integer (including an FCode Token) + * An FWord Token + * A pointer to a boolean variable + * A pointer to a character or a character string + * If the parameter field value is intended to be a single character, + * it must be recast as a long integer, in order to preserve + * portability across big- and little- -endian platforms. + * + **************************************************************************** */ + +/* ************************************************************************** * + * + * Macros: + * NO_PARAM_TIC Create an entry in the initial "Built-In" + * portion of a TIC-type vocabulary with + * an empty "param field". + * NO_PARAM_IGN Create an entry with an empty "param field" + * whose action- and "Ignore"- -functions + * are the same. + * VALPARAM_TIC " ... with a literal value for the "param field" + * DUALFUNC_TIC " ... with a literal "param" and both an action- + * and an "Ignore"- -function. + * DUFNC_FWT_PARM A tic_fwt_hdr_t -type entry with a literal + * "param" and both an action-function and an + * "Ignore"-function. + * FWORD_TKN_TIC " ... with an FWord Token for the "param field" + * DUALFUNC_FWT_TIC " " ... and both action- and "Ignore"- -function + * BUILTIN_MAC_TIC A tic_mac_hdr_t -type entry with a Macro- + * -Substitution-String "param" + * BUILTIN_BOOL_TIC A tic_bool_hdr_t -type entry with a boolean- + * -variable-pointer "param" + * + **************************************************************************** */ + +#include "types.h" +#include "dictionary.h" + +/* ************************************************************************** + * + * In order to work around C's limitations regarding data-typing + * during initialization, we need to create some alternative + * data-structures that exactly match the layout of tic_hdr_t + * as defined above, but have a different default-type for + * the parameter field. + * I apologize in advance for any maintenance awkwardnesses this + * might engender; I would have come up with a more convenient + * way to do this if I could. At least, the pieces that need + * to be co-ordinated are in close proximity to each other... + * + **************************************************************************** */ + +/* ************************************************************************** + * + * The differences are all centered in the "parameter field" of + * the TIC header structure. In order to make sure all the + * alternative types map smoothly into each other, we will + * create a series of "union" types, differing only in what + * their default type is. We will keep the "parameter field" + * item the size of a Long Integer. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * This form is the default type. + * + **************************************************************************** */ + +#define TIC_P_DEFLT_TYPE long +typedef union tic_param + { + TIC_P_DEFLT_TYPE deflt_elem ; /* The "default element" aspect. */ + long long_val ; /* Explicitly specifying "long" */ + fwtoken fw_token ; /* FWord Token */ + bool *bool_ptr ; /* Pointer to a boolean variable */ + char *chr_ptr ; /* Pointer to a character string */ + + /* The "character value" aspect behaves differently on big- + * versus little- -endian platforms (for initialization, + * anyway), so we cannot actually use it. + * Keep this commented-out, as a reminder. + */ + /* char char_val ; */ + /* We will recast "character value" as an integer. */ + + } tic_param_t ; + +typedef struct tic_hdr + { + char *name; + struct tic_hdr *next; + void (*funct)(); /* Function for active processing */ + tic_param_t pfield; + fwtoken fword_defr; /* FWord Token of entry's Definer */ + void (*ign_func)(); /* Function in "Ignored" segment */ + int pfld_size; + } tic_hdr_t ; + +/* ************************************************************************** + * + * This form is for initialization of an FWord Token list. + * + **************************************************************************** */ + +#define TIC_FWT_P_DEFLT_TYPE fwtoken +typedef union tic_fwt_param + { + TIC_FWT_P_DEFLT_TYPE deflt_elem ; /* "Default element" aspect. */ + long long_val ; /* Long integer */ + fwtoken fw_token ; /* Explicit FWord Token */ + bool *bool_ptr ; /* Pointer to a boolean variable */ + char *chr_ptr ; /* Pointer to a character string */ + } tic_fwt_param_t ; + +typedef struct tic_fwt_hdr + { + char *name; + struct tic_fwt_hdr *next; + void (*funct)(); /* Function for active processing */ + tic_fwt_param_t pfield; + fwtoken fword_defr; /* FWord Token of entry's Definer */ + void (*ign_func)(); /* Function in "Ignored" segment */ + int pfld_size; + } tic_fwt_hdr_t ; + + +/* ************************************************************************** + * + * The third form is for initialization of Built-in Macros. Its + * default parameter field type is a pointer to a compiled-in + * (i.e., constant) character string. Its pfld_size can be + * left as zero, because no allocated-memory copies of the + * string will be needed, even for aliases. (User-created + * macros, however, will need to allocate strings; we will + * deal with that elsewhere...) + * + **************************************************************************** */ + +#define TIC_MAC_P_DEFLT_TYPE char * +typedef union tic_mac_param + { + TIC_MAC_P_DEFLT_TYPE deflt_elem ; /* "Default element" aspect. */ + long long_val ; /* Long integer */ + fwtoken fw_token ; /* FWord Token */ + bool *bool_ptr ; /* Pointer to a boolean variable */ + char *chr_ptr ; /* Explicit Pointer to char str. */ + } tic_mac_param_t ; + +typedef struct tic_mac_hdr + { + char *name; + struct tic_mac_hdr *next; + void (*funct)(); + tic_mac_param_t pfield; + fwtoken fword_defr; + void (*ign_func)(); + int pfld_size; + } tic_mac_hdr_t ; + +/* ************************************************************************** + * + * The next form is for initialization of Condtionals. Its default + * parameter field type is a pointer to a boolean variable. + * + **************************************************************************** */ + +#define TIC_BOOL_P_DEFLT_TYPE bool * +typedef union tic_bool_param + { + TIC_BOOL_P_DEFLT_TYPE deflt_elem ; /* "Default element" aspect. */ + long long_val ; /* Long integer */ + fwtoken fw_token ; /* FWord Token */ + bool *bool_ptr ; /* Explicit Ptr to boolean v'ble */ + char *chr_ptr ; /* Pointer to a character string */ + } tic_bool_param_t ; + +typedef struct tic_bool_hdr + { + char *name; + struct tic_bool_hdr *next; + void (*funct)(); + tic_bool_param_t pfield; + fwtoken fword_defr; + void (*ign_func)(); + int pfld_size; + } tic_bool_hdr_t ; + + + +/* ************************************************************************** + * + * Various macros to create an entry in the initial "Built-In" portion + * of a vocabulary-list, specified as an array of one of the + * matching forms of a T. I. C. Header; each macro adjusts type + * casting as needed. + * In all cases, the "size" field will be set to zero, indicating that + * the "param field" item is either the complete data or a pointer + * to a hard-coded (non-allocated) data item. + * + **************************************************************************** */ + +/* ************************************************************************** + * Macro Name: NO_PARAM_TIC + * Create an entry in the initial "Built-In" portion + * of a TIC_HDR -type vocabulary with an empty + * "param field" + * + * Arguments: + * nam (string) Name of the entry as seen in the source + * func (routine-name) Name of internal function to call + * + **************************************************************************** */ +#define NO_PARAM_TIC(nam, func ) \ + { nam , (tic_hdr_t *)NULL , func , { 0 }, UNSPECIFIED , NULL , 0 } + + +/* ************************************************************************** + * Macro Name: NO_PARAM_IGN + * Create an entry with an empty "param field" + * whose action-function and "Ignore"-function + * are the same. + * + * Arguments: + * nam (string) Name of the entry as seen in the source + * func (routine-name) Name of internal function to call for both + * + * + **************************************************************************** */ +#define NO_PARAM_IGN(nam, func ) \ + { nam , (tic_hdr_t *)NULL , func , { 0 }, UNSPECIFIED , func , 0 } + + +/* ************************************************************************** + * + * Variations on the above, to compensate for Type-Casting complications + * + **************************************************************************** */ + +/* ************************************************************************** + * Macro Name: VALPARAM_TIC + * Create an entry in the initial "Built-In" portion + * of a TIC_HDR -type vocabulary with a literal + * value for the "param field" and a specifiable + * "definer". + * Arguments: + * nam (string) Name of the entry as seen in the source + * func (routine-name) Name of internal function to call + * pval (integer) The "param field" item + * definr (fword_token) "Definer" of the entry + * + * The "param field" item will be recast to the required default type. + * + **************************************************************************** */ + +#define VALPARAM_TIC(nam, func, pval, definr ) \ + { nam , (tic_hdr_t *)NULL , func , \ + { (TIC_P_DEFLT_TYPE)(pval) }, definr , NULL , 0 } + + +/* ************************************************************************** + * Macro Name: DUALFUNC_TIC + * Create an entry in the initial "Built-In" portion + * of a TIC_HDR -type vocabulary with both an + * "active" and an "ignoring" function, a literal + * value for the "param field" and a specifiable + * "definer". + * + * Arguments: + * nam (string) Name of the entry as seen in the source + * afunc (routine-name) Name of internal "active" function + * pval (integer) The "param field" item + * ifunc (routine-name) Name of "ignoring" function + * definr (fword_token) "Definer" of the entry + * + * The "param field" item will be recast to the required default type. + * + **************************************************************************** */ +#define DUALFUNC_TIC(nam, afunc, pval, ifunc, definr ) \ + { nam , (tic_hdr_t *)NULL , afunc , \ + { (TIC_P_DEFLT_TYPE)(pval) }, definr , ifunc , 0 } + +/* Similar but a tic_fwt_hdr_t type structure */ +#define DUFNC_FWT_PARM(nam, afunc, pval, ifunc, definr ) \ + { nam , (tic_fwt_hdr_t *)NULL , afunc , \ + { (TIC_FWT_P_DEFLT_TYPE)(pval) }, definr , ifunc , 0 } + + +/* ************************************************************************** + * Macro Name: FWORD_TKN_TIC + * Create an entry in the initial "Built-In" portion + * of an FWord Token list of tic_fwt_hdr_t type. + * + * Arguments: + * nam (string) Name of the entry as seen in the source + * func (routine-name) Name of internal function to call + * fw_tokval (fword_token) Value of the FWord Token + * definr (fword_token) "Definer" of the entry + * + * The "param field" item should not need be recast. + * + **************************************************************************** */ + +#define FWORD_TKN_TIC(nam, func, fw_tokval, definr ) \ + { nam , (tic_fwt_hdr_t *)NULL , func , { fw_tokval }, definr , NULL , 0 } + +/* ************************************************************************** + * Macro Name: DUALFUNC_FWT_TIC + * Create an entry in the initial "Built-In" portion + * of an FWord Token list of tic_fwt_hdr_t type + * with both an action- and an "Ignore"- -function. + * + * Arguments: + * nam (string) Name of the entry as seen in the source + * afunc (routine-name) Name of internal "Action" function + * fw_tokval (fword_token) Value of the FWord Token + * ifunc (routine-name) Name of "ignoring" function + * definr (fword_token) "Definer" of the entry + * + * The "param field" item should not need be recast. + * + **************************************************************************** */ +#define DUALFUNC_FWT_TIC(nam, afunc, fw_tokval, ifunc, definr ) \ + { nam , (tic_fwt_hdr_t *)NULL , afunc , { fw_tokval }, definr , ifunc , 0 } + +/* ************************************************************************** + * Macro Name: BUILTIN_MAC_TIC + * Create an entry in the initial "Built-In" portion + * of a Macros vocabulary of tic_mac_hdr_t type. + * + * Arguments: + * nam (string) Name of the entry as seen in the source + * func (routine-name) Name of internal function to call + * alias (string) Macro-Substitution string + * + * The "param field" item should not need be recast. + * The "definer" will be MACRO_DEF + * Builtin Macros do not need to be expanded while Ignoring, so + * the ign_func will be NULL + * + **************************************************************************** */ + +#define BUILTIN_MAC_TIC(nam, func, alias ) \ + { nam , (tic_mac_hdr_t *)NULL , func , { alias }, MACRO_DEF , NULL , 0 } + + +/* ************************************************************************** + * Macro Name: BUILTIN_BOOL_TIC + * Create an entry in the initial "Built-In" portion + * of a Condtionals list of tic_bool_hdr_t type. + * + * Arguments: + * nam (string) Name of the entry as seen in the source + * func (routine-name) Name of internal function to call + * bool_vbl (boolean v'ble) Name of the boolean variable. + * + * The "param field" item should not need be recast. + * For all of the Condtionals, the "Ignoring" function is the same + * as the "Active" function. + * The "definer" will be COMMON_FWORD + * + **************************************************************************** */ + +#define BUILTIN_BOOL_TIC(nam, func, bool_vbl ) \ + { nam , (tic_bool_hdr_t *)NULL , func , { &bool_vbl }, \ + COMMON_FWORD , func , 0 } + + +/* ************************************************************************** + * + * Exported Variables and Function Prototypes the rest of the way... + * + **************************************************************************** */ + +extern tic_hdr_t *tic_found; + +void init_tic_vocab( tic_hdr_t *tic_vocab_tbl, + int max_indx, + tic_hdr_t **tic_vocab_ptr); +void add_tic_entry( char *tname, + void (*tfunct)(), + TIC_P_DEFLT_TYPE tparam, + fwtoken fw_defr, + int pfldsiz, + void (*ign_fnc)(), + tic_hdr_t **tic_vocab ); +tic_hdr_t *lookup_tic_entry( char *tname, tic_hdr_t *tic_vocab ); +bool exists_in_tic_vocab( char *tname, tic_hdr_t *tic_vocab ); +bool handle_tic_vocab( char *tname, tic_hdr_t *tic_vocab ); +bool create_tic_alias( char *new_name, + char *old_name, + tic_hdr_t **tic_vocab ); +void reset_tic_vocab( tic_hdr_t **tic_vocab, tic_hdr_t *reset_position ); + +#endif /* _TOKE_TICVOCAB_H */
Modified: fcode-utils/toke/toke.c =================================================================== --- fcode-utils/toke/toke.c 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/toke.c 2006-08-18 12:47:12 UTC (rev 76) @@ -7,7 +7,7 @@ * This program is part of a free implementation of the IEEE 1275-1994 * Standard for Boot (Initialization Configuration) Firmware. * - * Copyright (C) 2001-2005 by Stefan Reinauer stepan@openbios.org + * Copyright (C) 2001-2006 by Stefan Reinauer stepan@openbios.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +24,12 @@ * */
+/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */ + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -34,47 +40,214 @@ #include <getopt.h> #endif
+#include "types.h" #include "toke.h" #include "stream.h" #include "stack.h" #include "emit.h"
-#define TOKE_VERSION "0.6.10" +#define TOKE_VERSION "1.0.0"
-int verbose=0; -int noerrors=0; +#include "vocabfuncts.h" +#include "scanner.h" +#include "errhandler.h" +#include "usersymbols.h" +#include "clflags.h" +#include "tracesyms.h"
+#define CORE_COPYR "(C) Copyright 2001-2006 Stefan Reinauer.\n" \ + "(C) Copyright 2006 coresystems GmbH info@coresystems.de" +#define IBM_COPYR "(C) Copyright 2005 IBM Corporation. All Rights Reserved." + +/* Temporary hack during development... See DATE_STAMP line below... */ +#ifdef DEVEL +#include "date_stamp.h" +#endif /* DEVEL */ + +/* ************************************************************************** + * + * Global Variables Exported: + * verbose If true, enable optional messages. + * noerrors If true, create binary even if error(s) encountered. + * fload_list If true, create an "FLoad-List" file + * dependency_list If true, create a "Dependencies-List" file + * + **************************************************************************** */ + +bool verbose = FALSE; +bool noerrors = FALSE; +bool fload_list = FALSE; +bool dependency_list = FALSE; + +/* ************************************************************************** + * + * Internal Static Variables + * outputname Name of output file supplied on command-line + * with the optional -o switch. + * Internal System Variable + * optind Index into argv vector of first param after options, + * from which input file names will be taken. + * + **************************************************************************** */ + +static char *outputname = NULL; + +/* ************************************************************************** + * + * Print the copyright message. + * + **************************************************************************** */ static void print_copyright(void) { - printf( "Welcome to toke - OpenBIOS tokenizer v%s\nCopyright (c)" - " 2001-2005 by Stefan Reinauer stepan@openbios.org\n" + printf( "Welcome to toke - OpenBIOS tokenizer v" TOKE_VERSION "\n" + CORE_COPYR "\n" IBM_COPYR "\n" "This program is free software; you may redistribute it " "under the terms of\nthe GNU General Public License. This " - "program has absolutely no warranty.\n\n", TOKE_VERSION); + "program has absolutely no warranty.\n\n"); +#ifdef DEVEL + /* Temporary hack during development... */ + printf( "\tTokenizer Compiled " DATE_STAMP "\n" ); +#endif /* DEVEL */ + }
+/* ************************************************************************** + * + * Function name: usage + * Synopsis: Print convenient usage-help message + * + **************************************************************************** */ + static void usage(char *name) { - printf("usage: %s [-v] [-i] [-o target] <forth-file>\n\n",name); - printf(" -v|--verbose print debug messages\n"); - printf(" -i|--ignore-errors don't bail out after an error\n"); + printf("usage: %s [-v] [-i] [-l] [-P] [-o target] <[-d name[=value]]> " + "<[-f [no]flagname]> <[-I dir-path]> " + "<[-T symbol]> <forth-file>\n\n",name); + printf(" -v|--verbose print Advisory messages\n"); + printf(" -i|--ignore-errors don't suppress output after errors\n"); + printf(" -l|--load-list create list of FLoaded file names\n"); + printf(" -P|--dependencies create dePendency-list file\n"); + printf(" -o|--output-name send output to filename given\n"); + printf(" -d|--define create user-defined symbol\n"); + printf(" -f|--flag set (or clear) Special-Feature flag\n"); + printf(" -I|--Include add a directory to the Include-List\n"); + printf(" -T|--Trace add a symbol to the Trace List\n"); printf(" -h|--help print this help message\n\n"); - + printf(" -f|--flag help Help for Special-Feature flags\n"); }
-int main(int argc, char **argv) +/* ************************************************************************** + * + * Function name: get_args + * Synopsis: Parse the Command-Line option switches + * + * Inputs: + * Parameters: NONE + * Global Variables: + * argc Counter of command-line arguments + * argv Vector pointing to command-line arguments + * Command-Line Items: The entire command-line will be parsed + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * verbose set by "-v" switch + * noerrors set by "-i" switch + * fload_list set by "-l" switch + * dependency_list set by "-P" switch + * Internal Static Variables + * outputname set by "-o" switch + * Internal System Variable + * optind Index into argv vector of the position + * from which to take input file names. + * Printout: + * (Copyright was already printed by the main body as a + * matter of course, rather than here depending on + * the Verbose flag, because getopt() prints its + * own error messages and we want to be sure to show + * the Copyright notice before any error messages.) + * Rules for Usage and Flags-list or Flags-help display: + * Usage message on Help-Request or error. + * Ask for usage help, get Usage plus list of Flag Names. + * Ask for Flags-help alone, get Flags-help (names plus + * explanations) + * Ask for usage help and for Flags-help, get Usage plus + * Flags-help, without redundant list of Flag Names. + * Any help-request, exit Zero + * Error in Option switches, or missing input-file name, + * get error-description plus Usage + * Error in Flag Names, get list of Flag Names. + * Any error, exit One. + * Behavior: + * Exit (non-failure) after printing "Help" message + * + * Error Detection: Exit with failure status on: + * Unknown Option switches or Flag Names + * Missing input file name + * + * Process Explanation: + * The following switches are recognized: + * v + * h + * ? + * i + * I + * l + * P + * o + * d + * f + * T + * The conditions they set remain in effect through + * the entire program run. + * + * Revision History: + * Updated Fri, 15 Jul 2005 by David L. Paktor + * Don't bail on first invalid option. + * Flags to control special features + * Usage messages for "special-feature" flags + * Updated Mon, 18 Jul 2005 by David L. Paktor + * Fine-tune Usage and Flags-list or Flags-help display. + * Updated Sun, 27 Nov 2005 by David L. Paktor + * Add FLoad-List flag + * Updated Wed, 29 Nov 2005 by David L. Paktor + * Make getopt() case-insensitive + * Updated Fri, 17 Mar 2006 by David L. O'Paktor + * Make getopt() case-sensitive again, + * add include-list support and dePendency-list switch + * + * Extraneous Remarks: + * We were originally thinking about defining various classes + * of "Warning" Messages and (somehow) controlling their + * display, but now that we have "special-feature" flags + * that control the generation of specific messages, that + * step has become unnecessary... + * + **************************************************************************** */ + +static void get_args( int argc, char **argv ) { - const char *optstring="vhio:?"; - char *outputname = NULL; + const char *optstring="vhilPo:d:f:I:T:?"; int c; + int argindx = 0; + bool inval_opt = FALSE; + bool help_mssg = FALSE; + bool cl_flag_error = FALSE;
while (1) { #ifdef __GLIBC__ int option_index = 0; static struct option long_options[] = { { "verbose", 0, 0, 'v' }, + { "help", 0, 0, 'h' }, { "ignore-errors", 0, 0, 'i' }, - { "help", 0, 0, 'h' }, + { "load-list", 0, 0, 'l' }, + { "dependencies", 0, 0, 'P' }, + { "output-name", 1, 0, 'o' }, + { "define", 1, 0, 'd' }, + { "flag", 1, 0, 'f' }, + { "Include", 1, 0, 'I' }, + { "Trace", 1, 0, 'T' }, { 0, 0, 0, 0 } };
@@ -86,63 +259,169 @@ if (c == -1) break;
+ argindx++; switch (c) { case 'v': - verbose=1; + verbose=TRUE; break; case 'o': outputname = optarg; break; case 'i': - noerrors=1; + noerrors = TRUE; break; + case 'l': + fload_list = TRUE; + break; + case 'P': + dependency_list = TRUE; + break; + case 'd': + { + char *user_symb = optarg; + add_user_symbol(user_symb); + } + break; + case 'f': + cl_flag_error = set_cl_flag(optarg, FALSE) ; + break; + case 'I': + { + char *incl_list_elem = optarg; + add_to_include_list(incl_list_elem); + } + break; + case 'T': + add_to_trace_list(optarg); + break; + case '?': + /* Distinguish between a '?' from the user + * and one getopt() returned + */ + if ( argv[argindx][1] != '?' ) + { + inval_opt = TRUE; + break; + } case 'h': - case '?': - print_copyright(); - usage(argv[0]); - return 0; + case 'H': + help_mssg = TRUE; + break; default: - print_copyright(); + /* This is never executed + * because getopt() prints the + * "unknown option -- X" + * message and returns a '?' + */ printf ("%s: unknown options.\n",argv[0]); usage(argv[0]); - return 1; + exit( 1 ); } }
- if (verbose) - print_copyright(); + if ( help_mssg ) + { + usage(argv[0]); + if ( ! clflag_help ) + { + list_cl_flag_names(); + } + } + if ( clflag_help ) cl_flags_help(); + if ( help_mssg || clflag_help ) + { + exit( 0 ); + }
- if (optind >= argc) { - print_copyright(); - printf ("%s: filename missing.\n",argv[0]); + if ( inval_opt ) printf ("unknown options.\n"); + if (optind >= argc) printf ("Input file name missing.\n"); + if ( inval_opt || (optind >= argc) ) + { usage(argv[0]); - return 1; } + if ( cl_flag_error ) list_cl_flag_names();
+ if ( inval_opt || (optind >= argc) || cl_flag_error ) + { + exit( 1); + } + + if (verbose) + { + list_user_symbols(); + list_cl_flag_settings(); + display_include_list(); + } + save_cl_flags(); +} + +/* ************************************************************************** + * + * Main body of program. Return 0 for success, 1 for failure. + * + * Still to be done: + * Devise a syntax to allow the command-line to specify multiple + * input files together with an output file name for each. + * Currently, the syntax allows only one output file name to be + * specified; when multiple input file names are specified, + * the specification of an output file name is disallowed, + * and only the default output file names are permitted. + * While this works around the immediate problem, a more + * elegant solution could be devised... + * + **************************************************************************** */ + +int main(int argc, char **argv) +{ + int retval = 0; + + print_copyright(); + get_args( argc, argv ); + init_stack(); init_dictionary(); - init_macros(); + init_scanner(); - while (optind < argc) { - if (init_stream(argv[optind])) { - printf ("%s: warning: could not open file "%s"\n", - argv[0], argv[optind]); - optind++; - continue; + if ( outputname != NULL ) + { + if ( argc > optind + 1 ) + { + /* Multiple input file names w/ single output file name */ + /* Work-around */ + printf( "Cannot specify single output file name " + "with multiple input file names.\n" + "Please either remove output-file-name specification,\n" + "or use multiple commands.\n"); + exit ( -2 ); + } } + + for ( ; optind < argc ; optind++ ) + { + bool stream_ok ; + + printf("\nTokenizing %s ", argv[optind]); + init_error_handler(); + stream_ok = init_stream( argv[optind]); + if ( stream_ok ) + { init_output(argv[optind], outputname);
+ init_scan_state(); + + reset_vocabs(); + reset_cl_flags(); + tokenize(); finish_headers(); - close_output(); - close_stream(); - - optind++; + close_stream( NULL); + if ( close_output() ) retval = 1; + } } exit_scanner(); - return 0; + return retval; }
Modified: fcode-utils/toke/toke.h =================================================================== --- fcode-utils/toke/toke.h 2006-08-18 09:45:11 UTC (rev 75) +++ fcode-utils/toke/toke.h 2006-08-18 12:47:12 UTC (rev 76) @@ -1,3 +1,6 @@ +#ifndef _TOKE_TOKE_H +#define _TOKE_TOKE_H + /* * OpenBIOS - free your system! * ( FCode tokenizer ) @@ -24,30 +27,25 @@ * */
-#ifndef _H_TOKE -#define _H_TOKE +/* ************************************************************************** + * Modifications made in 2005 by IBM Corporation + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Modifications Author: David L. Paktor dlpaktor@us.ibm.com + **************************************************************************** */
-#define u8 unsigned char -#define u16 unsigned short -#define u32 unsigned int -#define s16 short -#define bool int -#define TRUE (-1) -#define FALSE (0) -#define ANSI_ONLY
-extern void init_scanner( void ); -extern void exit_scanner( void ); +#include "types.h"
-extern void init_dictionary( void ); -extern void init_macros( void ); -extern void tokenize( void );
-extern u16 lookup_token(char *name); -extern u16 lookup_fword(char *name); -extern char *lookup_macro(char *name); -extern int add_token(u16 number, char *name); +/* ************************************************************************** * + * + * Global Variables Exported + * + **************************************************************************** */
-extern int add_macro(char *name, char *alias); +extern bool verbose; +extern bool noerrors; +extern bool fload_list; +extern bool dependency_list;
-#endif /* _H_TOKE */ +#endif /* _TOKE_TOKE_H */
Added: fcode-utils/toke/tokzesc.c =================================================================== --- fcode-utils/toke/tokzesc.c (rev 0) +++ fcode-utils/toke/tokzesc.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,771 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Process activity inside "Tokenizer Escape" mode. + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Functions Exported: + * init_tokz_esc_vocab Initialize the relevant vocabulary. + * enter_tokz_esc Enter "Tokenizer Escape" mode + * handle_tokz_esc Perform a function in the + * "Tokenizer Escape" Vocabulary + * exists_in_tokz_esc Confirm whether a given name exists in + * the "Tokz_Esc_Vocabulary" + * create_tokz_esc_alias Add an alias to "Tokenizer Escape" space + * reset_tokz_esc Reset the "Tokenizer Escape" Vocabulary + * to its "Built-In" position. + * + **************************************************************************** */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include "ticvocab.h" +#include "tokzesc.h" +#include "stack.h" +#include "emit.h" +#include "stream.h" +#include "scanner.h" +#include "errhandler.h" +#include "strsubvocab.h" +#include "nextfcode.h" + +#undef TOKZTEST /* Define for testing only; else undef */ +#ifdef TOKZTEST /* For testing only */ + #include "vocabfuncts.h" + #include "date_stamp.h" +#endif /* For testing only */ + +/* ************************************************************************** + * + * Global Variables Imported + * in_tokz_esc State of the tokenization operation. + * Value is FALSE if it's operating normally + * or TRUE if it's in "Tokenizer Escape" mode. + * nextfcode + * statbuf + * dstack Pointer to current item on top of Data Stack. + * base Current tokenizer numeric conversion radix + * + **************************************************************************** */ + +/* ************************************************************************** + * + * We are going to implement a mini-forth using a strategy based + * on the concept of Threaded Interpretive Code (well, okay, + * it won't really be interpretive ... ) + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Internal Static Variables -- (well, almost) + * tokz_esc_vocab Pointer to "tail" of "Tokenizer Escape" Vocab + * + * While we would prefer to keep tokz_esc_vocab private to this file, + * we find we need it in one other place, namely, macros.c + * We will declare it "extern" within that file, rather than + * exporting it widely by including it in a .h file + * + **************************************************************************** */ + +/* ************************************************************************** + * + * We will define and initialize a structure consisting of all the + * functions we initially support for "Tokenizer Escape" mode, + * called tokz_esc_vocab_tbl for "Tokenizer Escape Vocab Table". + * I expect we can initialize its body, but I don't think there's a + * convenient way in "C" to initialize its links; we'll have to + * do that dynamically, at run-time. Oh, well... + * + * We'll call the pointer to it the "Tokenizer Escape" Vocabulary. + * We have to declare it here, because we need to refer to it in + * a function that will be entered into the Table. + * + * We would like to pre-initialize it; to do so, we would have to + * declare it extern here, then later create its instance and + * assign its initial value. That would be all well and good, + * except that some linkers don't handle that very well, so, to + * accommodate those, we have to include its initialization in + * the same routine where we initialize the Table's links. + * + * Revision History: + * Updated Wed, 04 Jan 2006 by David L. Paktor + * Initialization of tokz_esc_vocab is now included with + * the call to init_tic_vocab() + * + **************************************************************************** */ + +tic_hdr_t *tokz_esc_vocab = NULL ; + +/* ************************************************************************** + * + * We'll give short prologs to the simpler functions that will be + * used in the "Tokenizer Escape" Vocabulary. + * + * All these take, as an argument, the "parameter field" pointer. + * To satisfy C's strong-typing, it will always be declared + * of a consistent type. The routine itself can internally + * recast -- or ignore -- it, as needed. + * Many of these will refer to the Global Variable statbuf . It + * all such cases, it is used for Error reporting. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Function name: enter_tokz_esc + * Synopsis: When you start "Tokenizer Escape" mode. + * + * Associated Tokenizer directive: TOKENIZER[ + * + * Process Explanation: + * Enter "Tokenizer Escape" mode ... Save the current tokenizer + * numeric conversion radix, and set the radix to sixteen + * (hexadecimal) + * + **************************************************************************** */ + +static int saved_base ; /* Place to save the numeric conversion radix */ + +void enter_tokz_esc( void ) +{ + saved_base = base ; + base = 16; + in_tokz_esc = TRUE; +} + +/* ************************************************************************** + * + * Function name: end_tokz_esc + * Synopsis: When you've reached the end of "Tokenizer Escape" mode. + * + * Associated Tokenizer directive: ]TOKENIZER + * + * Process Explanation: + * Exit "Tokenizer Escape" mode, resume "Normal"-mode behavior. + * Restore the tokenizer numeric conversion radix to the value + * saved by tokenizer[ and exit "Tokenizer Escape" mode . . . + * + **************************************************************************** */ + +static void end_tokz_esc( tic_param_t pfield ) +{ + in_tokz_esc = FALSE; + base = saved_base ; +} + +/* ************************************************************************** + * + * Function name: tokz_esc_emit_byte + * Synopsis: Emit the byte found on the data-stack + * + * Associated Tokenizer directive: EMIT-BYTE + * + * Error Detection: + * If number on stack is larger than a byte: Truncate and Warn + * + **************************************************************************** */ + +static void tokz_esc_emit_byte ( tic_param_t pfield ) +{ + long num_on_stk = dpop(); + u8 byt_to_emit = (u8)num_on_stk; + if ( byt_to_emit != num_on_stk ) + { + tokenization_error( WARNING, + "Value on stack for %s command is 0x%0x. " + "Truncating to 0x%02x.\n", + strupr(statbuf), num_on_stk, byt_to_emit); + } + user_emit_byte(byt_to_emit); +} + +/* ************************************************************************** + * + * Function name: get_fcode_from_stack + * Synopsis: Retrieve an FCode value from the data-stack. + * Indicate if erroneous + * + * Inputs: + * Parameters: + * the_num Pointer to where to put the number + * the_action Phrase to be used in ERROR message + * Data-Stack Items: + * Top: Value to be retrieved + * + * Outputs: + * Returned Value: TRUE if number is within valid FCode range + * Supplied Pointers: + * *the_num Value retrieved from the data-stack + * + * Error Detection: + * If the number on the stack is larger than 16 bits, truncate + * it, with a WARNING message. + * If the (possibly truncated) number from the stack is larger + * than the legal maximum for an FCode (0x0fff), or + * less than the legal minimum (0x0800), issue an ERROR, + * leave the_num unchanged and return FALSE. + * + **************************************************************************** */ + +static bool get_fcode_from_stack( u16 *the_num, char *the_action) +{ + bool retval = FALSE; + long num_on_stk = dpop(); + u16 test_fcode = (u16)num_on_stk; + if ( test_fcode != num_on_stk ) + { + tokenization_error( WARNING, + "Value on stack for %s command is 0x%0x. " + "Truncating to 0x%03x.\n", + strupr(statbuf), num_on_stk, test_fcode); + } + if ( ( test_fcode >= 0x800 ) && ( test_fcode <= 0xfff ) ) + { + retval = TRUE; + *the_num = test_fcode; + }else{ tokenization_error( TKERROR, "Attempt to %s " + "0x%x, which violates limit specified by IEEE-1275. " + "Disallowing.\n", the_action, test_fcode ); + } + return( retval ); +} + + +/* ************************************************************************** + * + * Function name: tokz_esc_next_fcode + * Synopsis: Set the next-fcode to the value on the data-stack + * + * Associated Tokenizer Directive: next-fcode + * + * Error Detection: + * If the number on the stack is not legal for an FCode, as + * detected by get_fcode_from_stack(), issue an ERROR + * message and don't change nextfcode. + * + * Printout: + * Advisory showing change in FCode token Assignment Counter + * + **************************************************************************** */ + +static void tokz_esc_next_fcode( tic_param_t pfield ) +{ + u16 test_fcode; + + if ( get_fcode_from_stack( &test_fcode, "set next fcode to") ) + { + if ( test_fcode == nextfcode ) + { + tokenization_error( INFO, "FCode-token Assignment Counter " + "is unchanged from 0x%x.\n", + nextfcode); + }else{ + tokenization_error( INFO, "FCode-token Assignment Counter " + "was 0x%x; has been %s to 0x%x.\n", + nextfcode, + test_fcode > nextfcode ? "advanced" : "reset", + test_fcode ); + set_next_fcode( test_fcode); + } + } +} + +/* ************************************************************************** + * + * Function name: tokz_emit_fcode + * Synopsis: Emit the value on the data-stack as an FCode token + * + * Associated Tokenizer Directive: emit-fcode + * + * Error Detection: + * If the number on the stack is not legal for an FCode, as + * detected by get_fcode_from_stack(), issue an ERROR + * message and don't emit anything. + * + * Printout: + * Advisory showing FCode being emitted. + * + **************************************************************************** */ + +static void tokz_emit_fcode( tic_param_t pfield ) +{ + u16 test_fcode; + + if ( get_fcode_from_stack( &test_fcode, "Emit FCode value of") ) + { + tokenization_error( INFO, + "Emitting FCode value of 0x%x\n", test_fcode); + emit_fcode( test_fcode); + } +} + + +/* ************************************************************************** + * + * Function name: zero_equals + * Synopsis: Boolean-inversion of item on top of stack. + * If zero, make it minus-one; if non-zero, make it zero. + * + * Associated FORTH word-name: 0= + * + **************************************************************************** */ + +static void zero_equals ( tic_param_t pfield ) +{ + *dstack = (*dstack == 0) ? -1 : 0 ; +} + +/* ************************************************************************** + * + * Function name: tokz_esc_swap + * Synopsis: "Tokenizer Escape" mode-time data-stack SWAP operation + * + * Associated FORTH word-name: swap + * + **************************************************************************** */ + +static void tokz_esc_swap ( tic_param_t pfield ) +{ + swap(); +} + +/* ************************************************************************** + * + * Function name: tokz_esc_two_swap + * Synopsis: "Tokenizer Escape" mode-time data-stack 2SWAP operation + * + * Associated FORTH word-name: 2swap + * + **************************************************************************** */ + +static void tokz_esc_two_swap ( tic_param_t pfield ) +{ + two_swap(); +} + +/* ************************************************************************** + * + * Function name: tokz_esc_noop + * Synopsis: "Tokenizer Escape" mode-time non-operation + * + * Associated FORTH word-name: noop + * + **************************************************************************** */ + +static void tokz_esc_noop ( tic_param_t pfield ) +{ + return; +} + +#ifdef TOKZTEST /* For testing only */ + + static void tokz_esc_emit_string( tic_param_t pfield ) + { + int lenny ; + lenny = strlen ( pfield.chr_ptr ); + emit_token("b(")"); + emit_string(pfield.chr_ptr, lenny); + } + +#endif /* For testing only */ + +/* ************************************************************************** + * + * Function name: do_constant + * Synopsis: The function to perform when a named constant + * that was defined in "Tokenizer Escape" mode + * is invoked in "Tokenizer Escape" mode + * + * Associated FORTH word: A user-defined constant + * + * Inputs: + * Parameters: + * The param-field of the table-entry contains + * the value of the constant + * + * Outputs: + * Returned Value: NONE + * Items Pushed onto Data-Stack: + * Top: The table-entry's param-field's value + * + * Error Detection: + * An attempt, while operating in normal tokenization mode, to invoke + * a named constant that was defined in "Tokenizer Escape" mode + * will be detected by the main scanning loop, and need not + * concern us here. + * + **************************************************************************** */ + +static void do_constant ( tic_param_t pfield ) +{ + dpush( pfield.long_val ); +} + +/* ************************************************************************** + * + * Function name: create_constant + * Synopsis: Create a user-defined constant that will be + * recognized in "Tokenizer Escape" mode + * + * Associated FORTH word-name: CONSTANT (when issued + * in "Tokenizer Escape" mode) + * + * Inputs: + * Parameters: NONE + * Global Variables: + * statbuf The constant's name will be taken from the + * next word in the input stream. + * do_constant The function assigned to the definition + * tokz_esc_vocab The "Tokenizer Escape" Vocabulary pointer + * Data-Stack Items: + * Top: The constant's value is popped from the stack + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * statbuf Advanced to the next word in the input stream. + * tokz_esc_vocab Updated to point to new vocab entry. + * Memory Allocated: + * for the name and for the new entry. + * When Freed? + * When RESET-SYMBOLS is issued in "Tokenizer Escape" mode, + * or upon end of tokenization. + * Data-Stack, # of Items Popped: 1 + * + * Error Detection: + * Failure to allocate memory is a Fatal Error. + * Warning on excessively long name + * Warning on duplicate name + * Name to be defined not in same file, ERROR + * + * Process Explanation: + * Get the next word, STRDUP it (which implicitly allocates memory). + * Get the number popped off the stack. + * Pass the pointer and the value to the add_tic_entry() routine. + * + **************************************************************************** */ + +static void create_constant( tic_param_t pfield ) +{ + char *c_name_space ; /* Space for copy of the name */ + long valu ; /* Value, popped off the stack */ + signed long wlen; + + /* Get the name that is to be defined */ + wlen = get_word(); + if ( wlen <= 0 ) + { + warn_unterm( TKERROR, "Constant definition", lineno); + return; + } + + valu = dpop(); + + /* If ever we implement more than just this one + * defining-word in "Tokenizer Escape" mode, + * the lines from here to the end of the + * routine should be re-factored... + */ + trace_creation( CONST, statbuf); + + warn_if_duplicate( statbuf ); + check_name_length( wlen ); + + c_name_space = strdup( statbuf ); + + add_tic_entry( + c_name_space, + do_constant, + (TIC_P_DEFLT_TYPE)valu, + CONST , + 0 , NULL, + &tokz_esc_vocab ); + +} + +/* ************************************************************************** + * + * Let's create usable named constants for "Tokenizer Escape" mode. + * It's useful, it's easy and ... well, you get the idea. + * + **************************************************************************** */ +/* I don't think we need to any more +static const int zero = 0 ; +static const int minus_one = -1 ; +static const char double_quote = '"' ; +static const char close_paren = ')' ; + * Except for this next one, of course... */ +#ifdef TOKZTEST /* For testing only */ + static const char date_me[] = DATE_STAMP; +#endif /* For testing only */ + +/* ************************************************************************** + * + * Here, at long last, we define and initialize the structure containing + * all the functions we support in "Tokenizer Escape" mode. + * Let's call it the "Tokenizer Escape Vocabulary Table" and the + * pointer to it, the "Tokenizer Escape" Vocabulary. + * We can initialize the start of the "Tokenizer Escape" Vocabulary + * easily, except for the link-pointers, as an array. + * + **************************************************************************** */ + +#define TKZESC_CONST(nam, pval) \ + VALPARAM_TIC(nam, do_constant, pval, CONST ) +#define TKZ_ESC_FUNC(nam, afunc, pval, ifunc) \ + DUALFUNC_TIC(nam, afunc, pval, ifunc, UNSPECIFIED) + +static tic_hdr_t tokz_esc_vocab_tbl[] = { + NO_PARAM_IGN( "]tokenizer" , end_tokz_esc ) , + + /* An IBM-ish synonym. */ + NO_PARAM_IGN( "f]" , end_tokz_esc ) , + /* An alternate synonym. */ + NO_PARAM_IGN( "]f" , end_tokz_esc ) , + + NO_PARAM_TIC( "emit-byte" , tokz_esc_emit_byte ) , + NO_PARAM_TIC( "next-fcode" , tokz_esc_next_fcode ) , + NO_PARAM_TIC( "emit-fcode" , tokz_emit_fcode ) , + NO_PARAM_TIC( "constant" , create_constant ) , + NO_PARAM_TIC( "0=" , zero_equals ) , + NO_PARAM_TIC( "swap" , tokz_esc_swap ) , + NO_PARAM_TIC( "2swap" , tokz_esc_two_swap ) , + NO_PARAM_TIC( "noop" , tokz_esc_noop ) , + TKZESC_CONST( "false" , 0 ) , + TKZESC_CONST( "true" , -1 ) , + TKZ_ESC_FUNC( ".(" , user_message, ')', skip_user_message ) , + TKZ_ESC_FUNC( "."" , user_message, '"', skip_user_message ) , +#ifdef TOKZTEST /* For testing only */ + /* Data is a pointer to a constant string in the compiler; */ + /* no need to copy, hence data_size can remain zero. */ + /* We could almost use the Macro macro, except for the type. */ + TKZ_ESC_FUNC( "emit-date" , tokz_esc_emit_string, date_me , NULL ) , +#endif /* For testing only */ +}; + +/* ************************************************************************** + * + * Also, keep a pointer to the "Built-In" position of + * the "Tokenizer Escape" Vocabulary + * + **************************************************************************** */ + +static const tic_hdr_t *built_in_tokz_esc = + &tokz_esc_vocab_tbl[(sizeof(tokz_esc_vocab_tbl)/sizeof(tic_hdr_t))-1]; + +/* ************************************************************************** + * + * Function name: init_tokz_esc_vocab + * Synopsis: Initialize the "Tokenizer Escape" Vocabulary + * link-pointers dynamically. + * + **************************************************************************** */ + +void init_tokz_esc_vocab ( void ) +{ + static const int tokz_esc_vocab_max_indx = + sizeof(tokz_esc_vocab_tbl)/sizeof(tic_hdr_t) ; + + tokz_esc_vocab = NULL ; /* Belt-and-suspenders... */ + init_tic_vocab(tokz_esc_vocab_tbl, + tokz_esc_vocab_max_indx, + &tokz_esc_vocab ); +} + +/* ************************************************************************** + * + * Function name: handle_tokz_esc + * Synopsis: Perform a function in the "Tokenizer Escape" Vocabulary + * Indicate whether the name is valid in this vocabulary. + * Handle "Tokenizer Escape" aliases implicitly. + * + * Inputs: + * Parameters: + * tname The name to handle + * Global Variables: + * tokz_esc_vocab Pointer to "Tokenizer Escape" Vocabulary + * + * Outputs: + * Returned Value: TRUE if the given name is valid in tokz_esc + * + * Process Explanation: + * Find the name and execute its associated function. + * If the name is not in the "Tokenizer Escape" Vocabulary, + * let the calling routine determine whether to try it + * out as a number or to print an error message. + * + **************************************************************************** */ + +bool handle_tokz_esc( char *tname ) +{ + bool retval = handle_tic_vocab( tname, tokz_esc_vocab ); + return ( retval ) ; +} + + +/* ************************************************************************** + * + * Function name: lookup_tokz_esc + * Synopsis: Return a pointer to the data-structure of the named + * word in the"Tokenizer Escape" Vocabulary + * + * Inputs: + * Parameters: + * name The given name for which to look + * Local Static Variables: + * tokz_esc_vocab Pointer to "Tokenizer Escape" Vocabulary + * + * Outputs: + * Returned Value: TRUE if name is found, + * + **************************************************************************** */ + +tic_hdr_t *lookup_tokz_esc(char *name) +{ + tic_hdr_t *retval = lookup_tic_entry( name, tokz_esc_vocab ); + return ( retval ); +} + + +/* ************************************************************************** + * + * Function name: exists_in_tokz_esc + * Synopsis: Confirm whether a given name exists in the + * "Tokenizer Escape" Vocabulary + * + * Inputs: + * Parameters: + * name The given name to confirm + * Global Variables: + * tokz_esc_vocab Pointer to "Tokenizer Escape" Vocabulary + * + * Outputs: + * Returned Value: TRUE if name is found, + * + **************************************************************************** */ + +bool exists_in_tokz_esc(char *name) +{ + bool retval = exists_in_tic_vocab( name, tokz_esc_vocab ); + return ( retval ); +} + + +/* ************************************************************************** + * + * Function name: create_tokz_esc_alias + * Synopsis: Create an alias in the "Tokenizer Escape" Vocabulary + * + * Associated FORTH word: ALIAS (in "Tokenizer Escape" mode) + * + * Inputs: + * Parameters: + * old_name Name of existing entry + * new_name New name for which to create an entry + * + * Outputs: + * Returned Value: TRUE if old_name found in "Tok Esc" vocab + * Global Variables: + * tokz_esc_vocab Will point to the new entry + * Memory Allocated: + * Memory for the new entry will be allocated + * by the support routine + * When Freed? + * When RESET-SYMBOLS is issued in "Tokenizer Escape" mode, + * or upon end of tokenization. + * + **************************************************************************** */ + +bool create_tokz_esc_alias(char *new_name, char *old_name) +{ + bool retval = create_tic_alias( new_name, old_name, &tokz_esc_vocab ); + return ( retval ); +} + + +/* ************************************************************************** + * + * Function name: reset_tokz_esc + * Synopsis: Reset the "Tokenizer Escape" Vocabulary to + * its "Built-In" position. + * + * Associated Tokenizer directive: RESET-SYMBOLS (when issued + * in "Tokenizer Escape" mode) + * + * Inputs: + * Parameters: NONE + * Global Variables: + * tokz_esc_vocab Pointer to "Tokenizer Escape" Vocabulary + * built_in_tokz_esc Pointer to "Built-In" position + * + * Outputs: + * Returned Value: NONE + * Global Variables: + * tokz_esc_vocab Reset to "Built-In" position + * Memory Freed + * Memory will be freed by the support routine + * + **************************************************************************** */ + +void reset_tokz_esc( void ) +{ + reset_tic_vocab( &tokz_esc_vocab, (tic_hdr_t *)built_in_tokz_esc); +} + +/* ************************************************************************** + * + * Function name: pop_next_fcode + * Synopsis: Vector off to the tokz_esc_next_fcode function, + * but without the pseudo-param. A retro-fit... + * + * Associated Tokenizer directive: FCODE-POP (issued in either mode) + * + * Inputs: + * Parameters: NONE + * Data-Stack Items: + * Top: Next FCode value, presumably saved + * by an FCODE-PUSH issued earlier. + * + * Outputs: + * Returned Value: + * Global Variables: + * nextfcode FCode token Assignment Counter + * + **************************************************************************** */ + +void pop_next_fcode( void) +{ + tic_param_t dummy_param; + tokz_esc_next_fcode( dummy_param); +}
Added: fcode-utils/toke/tokzesc.h =================================================================== --- fcode-utils/toke/tokzesc.h (rev 0) +++ fcode-utils/toke/tokzesc.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,50 @@ +#ifndef _TOKE_TOKZESC_H +#define _TOKE_TOKZESC_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * External and Prototype definitions for functions that process + * activity in "Tokenizer Escape" mode + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +#include "types.h" +#include "ticvocab.h" + +void init_tokz_esc_vocab( void ); +bool create_tokz_esc_alias(char *new_name, char *old_name); +void enter_tokz_esc( void ); +bool handle_tokz_esc( char *tname ); +tic_hdr_t *lookup_tokz_esc(char *name); +bool exists_in_tokz_esc(char *name); +void reset_tokz_esc( void ); +void pop_next_fcode( void); + +#endif /* _TOKE_TOKZESC_H */
Added: fcode-utils/toke/tracesyms.c =================================================================== --- fcode-utils/toke/tracesyms.c (rev 0) +++ fcode-utils/toke/tracesyms.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,172 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Support routines for "Trace-Symbols" debugging feature + * + * (C) Copyright 2006 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Functions Exported: + * add_to_trace_list Add the given name to the Trace List + * show_initial_traces Show pre-defined names the user + * asked to Trace (if any) + * is_on_trace_list Indicate whether the given name is + * on the Trace List + * + **************************************************************************** */ + +#include <string.h> + +#include "tracesyms.h" +#include "errhandler.h" + + +/* ************************************************************************** + * + * Internal Static Variables + * trace_list Pointer to last entry in the Trace List linked-list + * data structure + * + * + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Internal (Static) Structures: + * trace_entry_t Linked-list of entries in the Trace List + * + * Fields: + * tracee Name of the symbol to be traced + * prev Pointer to previous entry in the linked-list + * + **************************************************************************** */ + +typedef struct trace_entry { + char *tracee; + struct trace_entry *prev; +} trace_entry_t; + +static trace_entry_t *trace_list = NULL; + + + +/* ************************************************************************** + * + * Function name: add_to_trace_list + * Synopsis: Add the given name to the Trace List + * + * + * Inputs: + * Parameters: + * trace_symb Name of the symbol to be added + * Local Static Variables: + * trace_list Pointer to the Trace List + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * trace_list Points to new entry in Trace List + * Memory Allocated + * For Trace List entry + * For copy of Symbol Name + * When Freed? + * Never. Well, only on termination of the program. Trace-list + * endures for the entire batch of tokenizations. + * + * Error Detection: + * Memory allocation failure is a FATAL error. + * + **************************************************************************** */ + +void add_to_trace_list( char *trace_symb) +{ + trace_entry_t *new_t_l_entry = safe_malloc( sizeof( trace_entry_t), + "adding to trace-list"); + new_t_l_entry->tracee = strdup( trace_symb); + new_t_l_entry->prev = trace_list; + + trace_list = new_t_l_entry; +} + + +/* ************************************************************************** + * + * Function name: is_on_trace_list + * Synopsis: Indicate whether the given name is on the Trace List + * + * Inputs: + * Parameters: + * symb_name Symbol-name to test + * Local Static Variables: + * trace_list Pointer to the Trace List + * + * Outputs: + * Returned Value: TRUE if Symbol-name is on the Trace List + * + **************************************************************************** */ + +bool is_on_trace_list( char *symb_name) +{ + bool retval = FALSE; + trace_entry_t *test_entry = trace_list; + while ( test_entry != NULL ) + { + if ( strcasecmp( symb_name, test_entry->tracee) == 0 ) + { + retval = TRUE; + break; + } + test_entry = test_entry->prev; + } + return ( retval ); +} + + +/* ************************************************************************** + * + * Still to be done: + * Implement a function -- name it show_initial_traces -- + * that will show any pre-defined names the user asked + * to Trace. That is, if any of the names the user asked + * to Trace belongs to a pre-defined function, macro or + * directive, then, at the beginning of the output, issue + * Advisory Messages identifying the scope of those names. + * + * E.g, if the user had -T 3DUP -T SWAP the function would + * issue Messages like: + * 3DUP is pre-defined as a Macro with Global scope + * SWAP is pre-defined with Global scope + * SWAP is pre-defined in Tokenizer-Escape mode + * + * The names would, of course, remain on the Trace List and + * any re-definitions of them would be reported. + * + **************************************************************************** */
Added: fcode-utils/toke/tracesyms.h =================================================================== --- fcode-utils/toke/tracesyms.h (rev 0) +++ fcode-utils/toke/tracesyms.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,48 @@ +#ifndef _TOKE_TRACESYMS_H +#define _TOKE_TRACESYMS_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * External/Prototype/Structure definitions for "Trace-Symbols" feature + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +#include "types.h" + +/* ************************************************************************** * + * + * Function Prototypes / Functions Exported: + * + **************************************************************************** */ + +void add_to_trace_list( char *trace_symb); +bool is_on_trace_list( char *symb_name); + +#endif /* _TOKE_TRACESYMS_H */
Added: fcode-utils/toke/usersymbols.c =================================================================== --- fcode-utils/toke/usersymbols.c (rev 0) +++ fcode-utils/toke/usersymbols.c 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,363 @@ +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * General-purpose support functions for + * User-defined command-line compilation-control symbols + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +/* ************************************************************************** + * + * The syntax for user-defined command-line compilation-control symbols + * is <NAME>[=<VALUE>] + * + * The name is always required; the equal-sign and value is optional. + * If you wish the "value" to contain spaces or quotes, you can + * accomplish that using the shell escape conventions. + * + * The operations that can be performed upon these symbols will be + * described by the operators that use them as operands, but, + * broadly speaking, the tests will either be to simply verify + * the existence of a symbol, or to evaluate the defined value. + * + * Once a symbol is defined on the command-line, it stays in effect + * for the duration of the entire batch of tokenizations (i.e., + * if there are multiple input files named on the command line). + * Also, there are no symbols defined at the outset. Therefore, + * there is no need for either an "init" or a "reset" routine. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * User-defined command-line compilation-control symbols are + * implemented as a String-Substitution-type vocabulary. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Functions Exported: + * add_user_symbol Add a user-defined symbol to the list + * lookup_user_symbol Look for a user-defined symbol, return + * the assigned value. + * exists_as_user_symbol Confirm whether a given name exists + * as a user-defined symbol. + * eval_user_symbol Tokenize the value assigned to a user + * symbol. + * list_user_symbols Print the list of user-defined symbols + * for the Logfile. + * + **************************************************************************** */ + +/* ************************************************************************** + * + * Still to be done: + * Convert the handling of user-defined symbols to the T.I.C. + * data-structure and its support routines. This should + * eliminate any further need of String-Substitution-type + * vocabularies. User-defined symbols will, however, still + * need to be a separate vocabulary from the Global, because + * they are required to stay in effect for the duration of + * the entire batch of tokenizations... + * (Afterthought: This is only true for user-defined symbols that + * were created on the command-line; if we ever allow symbols + * to be defined in the Source file, they should be as volatile + * as anything else that comes from a source file... + * Putting source-file-derived user-defined symbols into the Global + * Vocabulary could be a quasi-simple way to accomplish this.) + * + * Enable the definition of user-symbols from the Source file, using + * a syntax like: [define] symbol or [define] symbol=<value> + * (How to allow spaces into the <value>? Maybe make the syntax + * [define] symbol = <value components to end of line> + * delimited in a manner similar to Macro definitions. + * There might be a need to be able to [undefine] a user-symbol + * that would entail defining an unlink_tic_entry function. + * Not difficult; just keeping this around as a reminder... + * + **************************************************************************** */ + + + +#include <stdio.h> +#include <stdlib.h> +#if defined(__linux__) && ! defined(__USE_BSD) +#define __USE_BSD +#endif +#include <string.h> + +#include "errhandler.h" +#include "strsubvocab.h" +#include "usersymbols.h" +#include "scanner.h" + + +/* ************************************************************************** + * + * Internal Static Variables + * user_symbol_list Pointer to the "tail" of the list of + * user-defined symbols. + * user_symbol_count Count of how many are defined + * + **************************************************************************** */ + +static str_sub_vocab_t *user_symbol_list = NULL; +static int user_symbol_count = 0; + +/* ************************************************************************** + * + * Function name: add_user_symbol + * Synopsis: Add a user-defined symbol to the list + * + * Inputs: + * Parameters: + * raw_symb The string as supplied on the command-line. + * Local Static Variables: + * user_symbol_list Pointer to the list of user-defined symbols. + * + * Outputs: + * Returned Value: NONE + * Local Static Variables: + * user_symbol_list Will be updated. + * user_symbol_count Will be incremented + * Memory Allocated: + * for the string(s) and the new entry + * When Freed? + * Never. Well, only on termination of the program. User-defined + * symbols endure for the entire batch of tokenizations. + * + * Process Explanation: + * The string in raw_symb may or may not include the optional + * equal-sign and value pair. If the equal-sign is present, + * the remainder of the string will become the "value" that + * will be returned by the "lookup" routine. + * Memory for the name string and for the value, if there is one, + * will be allocated here, in one step. Memory for the data + * structure itself will be allocated by the support routine. + * + **************************************************************************** */ + +void add_user_symbol(char *raw_symb) +{ + char *symb_nam; + char *symb_valu; + + symb_nam = strdup(raw_symb); + symb_valu = strchr(symb_nam,'='); + if ( symb_valu != NULL ) + { + *symb_valu = 0; + symb_valu++; + } + add_str_sub_entry(symb_nam, symb_valu, &user_symbol_list ); + user_symbol_count++; +} + + +/* ************************************************************************** + * + * Function name: lookup_user_symbol + * Synopsis: Look for the given name as user-defined symbol, return + * the assigned value. + * + * Inputs: + * Parameters: + * symb_nam The name for which to look. + * Local Static Variables: + * user_symbol_list Pointer to the list of user-defined symbols. + * + * Outputs: + * Returned Value: Pointer to the "value" string, or NULL + * pointer if the name was not found. + * May also be NULL if "value" is NULL. + * + **************************************************************************** */ + +char *lookup_user_symbol(char *symb_nam) +{ + char *symb_valu; + + symb_valu = lookup_str_sub(symb_nam, user_symbol_list ); + return (symb_valu); +} + +/* ************************************************************************** + * + * Function name: exists_as_user_symbol + * Synopsis: Confirm whether a given name exists + * as a user-defined symbol. + * + * Inputs: + * Parameters: + * symb_nam The name for which to look. + * Local Static Variables: + * user_symbol_list Pointer to the list of user-defined symbols. + * + * Outputs: + * Returned Value: TRUE if the name is found + * + **************************************************************************** */ + +bool exists_as_user_symbol(char *symb_nam) +{ + bool retval; + + retval = exists_in_str_sub(symb_nam, user_symbol_list ); + return (retval); +} + +/* ************************************************************************** + * + * Function name: eval_user_symbol + * Synopsis: Tokenize the value assigned to a user-symbol. + * + * Associated Tokenizer directive (synonyms): [DEFINED] + * #DEFINED + * [#DEFINED] + * + * Syntax Notes: + * (1) The User-Defined-Symbol must appear + * on the same line as the directive. + * (2) This is not (yet) implemented in contexts that + * directly read input from the stream, e.g., + * after ['] or after H# etc. + * + * Inputs: + * Parameters: + * symbol The User-Defined-Symbol to evaluate + * Local Static Variables: + * user_symbol_list Pointer to the list of user-defined symbols. + * + * Outputs: + * Returned Value: NONE + * The assigned value will be tokenized. + * + * Error Detection: + * Calling routine is responsible for verifying that the user-symbol + * is on the same line as the directive. + * WARNING if the symbol is not found or has no assigned value. + * + * Process Explanation: + * Look up the parameter in the User Symbol List, and retrieve + * its associated value. + * If it is not found, or if it has no associated value, issue + * a WARNING and do nothing further. Otherwise... + * Interpret the associated value as though it were source. + * + * Still to be done: + * Hook-in this routine to the processing of: ['] F['] H# FLOAD + * etc., and wherever else it might be needed or useful. + * + **************************************************************************** */ + +void eval_user_symbol(char *symbol ) +{ + char *symb_valu; + symb_valu = lookup_user_symbol(symbol ); + if ( symb_valu == NULL ) + { + tokenization_error ( WARNING, + "No value assigned to command-line symbol %s\n", symbol ); + }else{ + eval_string( symb_valu ); + } + +} +/* ************************************************************************** + * + * Function name: list_user_symbols + * Synopsis: Print the list of user symbols for the Logfile. + * + * Inputs: + * Parameters: NONE + * Local Static Variables: + * user_symbol_list Pointer to the list of user-defined symbols. + * user_symbol_count Count of user-defined symbols. + * + * Outputs: + * Returned Value: NONE + * Printout: List of user symbols and their definitions; + * nothing if user_symbol_list is NULL. + * + * Process Explanation: + * We want to display the symbols in the same order they were created. + * We will: + * Allocate a temporary array of pointers. + * Step backwards through the linked-list of symbols, and + * enter their pointers into the array. + * Collect the maximum length of the symbol names. + * Step through the array in the reverse order, printing + * as we go. + * Use the max name length to space the equal-signs evenly + * Free the temporary array. + * + **************************************************************************** */ + +void list_user_symbols(void ) +{ + str_sub_vocab_t *curr; + + if ( user_symbol_list != NULL ) + { + /* Collect the pointers and max length */ + str_sub_vocab_t **symb_ptr; + int indx = 0; + int maxlen = 0; + + symb_ptr = (str_sub_vocab_t **)safe_malloc( + (sizeof(str_sub_vocab_t *) * user_symbol_count), + "collecting user-symbol pointers" ); + + for (curr = user_symbol_list ; curr != NULL ; curr=curr->next) + { + symb_ptr[indx] = curr; + indx++; + if ( strlen(curr->name) > maxlen ) maxlen = strlen(curr->name); + } + + /* Now print 'em out */ + printf("\nUser-Defined Symbols:\n"); + while ( indx > 0 ) + { + indx--; + curr = symb_ptr[indx]; + printf("\t%s",curr->name); + if ( curr->alias != NULL ) + { + int strindx; + for ( strindx = strlen(curr->name) ; + strindx < maxlen ; strindx++ ) printf(" "); + printf(" = %s",curr->alias); + } + printf("\n"); + } + free(symb_ptr); + } +}
Added: fcode-utils/toke/usersymbols.h =================================================================== --- fcode-utils/toke/usersymbols.h (rev 0) +++ fcode-utils/toke/usersymbols.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,46 @@ +#ifndef _TOKE_USERSYMBOLS_H +#define _TOKE_USERSYMBOLS_H + + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * Prototype/External Declarations for general-purpose functions + * for support of User-defined command-line compilation-control + * symbols, as defined in usersymbols.c + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + +void add_user_symbol(char *raw_symb); +char *lookup_user_symbol(char *symb_nam); +bool exists_as_user_symbol(char *symb_nam); +void eval_user_symbol(char *symbol ); +void list_user_symbols(void ); + +#endif /* _TOKE_USERSYMBOLS_H */
Added: fcode-utils/toke/vocabfuncts.h =================================================================== --- fcode-utils/toke/vocabfuncts.h (rev 0) +++ fcode-utils/toke/vocabfuncts.h 2006-08-18 12:47:12 UTC (rev 76) @@ -0,0 +1,92 @@ +#ifndef _TOKE_VOCABFUNCTS_H +#define _TOKE_VOCABFUNCTS_H + +/* + * OpenBIOS - free your system! + * ( FCode tokenizer ) + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 2001-2005 Stefan Reinauer, stepan@openbios.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +/* ************************************************************************** + * + * External/Prototype definitions for Vocabulary functions + * in dictionary.c for Tokenizer + * + * (C) Copyright 2005 IBM Corporation. All Rights Reserved. + * Module Author: David L. Paktor dlpaktor@us.ibm.com + * + **************************************************************************** */ + + +#include "types.h" +#include "ticvocab.h" + + +/* ************************************************************************** * + * + * Global Variables Exported + * + **************************************************************************** */ + +extern bool scope_is_global; + +/* ************************************************************************** * + * + * Function Prototypes / Functions Exported: + * + **************************************************************************** */ + + +tic_hdr_t *lookup_core_word( char *tname); +bool exists_in_core( char *name); +bool handle_core_word( char *tname ); +bool create_core_alias( char *new_name, char *old_name); + +void enter_global_scope( void ); +void resume_device_scope( void ); + +tic_hdr_t *lookup_current( char *name); +bool exists_in_current( char *tname); +bool handle_current( char *tname ); +tic_hdr_t *lookup_in_dev_node( char *tname); +void add_to_current( char *name, + TIC_P_DEFLT_TYPE fc_token, + fwtoken definer, + bool define_token); +void hide_last_colon ( void ); +void reveal_last_colon ( void ); +bool create_current_alias( char *new_name, char *old_name ); + +void emit_token( const char *fc_name); +tic_hdr_t *lookup_token( char *tname); +bool entry_is_token( tic_hdr_t *test_entry ); +void token_entry_warning( tic_hdr_t *t_entry); + +tic_hdr_t *lookup_shared_word( char *tname); +bool handle_shared_word( char *tname ); +tic_hdr_t *lookup_shared_f_exec_word( char *tname); + +void init_dictionary( void ); +void reset_normal_vocabs( void ); +void reset_vocabs( void ); + + +#endif /* _TOKE_VOCABFUNCTS_H */