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(a)openbios.org>
+# Copyright (C) 2001-2006 Stefan Reinauer <stepan(a)openbios.org>
+# Copyright (C) 2006 coresystems GmbH <info(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)openbios.org>
+# Copyright (C) 2001-2006 Stefan Reinauer <stepan(a)openbios.org>
+# Copyright (C) 2006 coresystems GmbH <info(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)openbios.org>
+ * Copyright (C) 2001-2006 by Stefan Reinauer <stepan(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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(a)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 */