Edit

openbios/fcode-utils/toke/ticvocab.c

Branch :

  • Show log

    Commit

  • Author : Stefan Reinauer
    Date : 2006-10-30 09:48:28
    Hash : 60c9c198
    Message : tokenizer v 1.0.2, contribution by David Paktor <dlpaktor@netscape.net> git-svn-id: svn://coreboot.org/openbios/fcode-utils@100 f158a5a8-5612-0410-a976-696ce0be7e32

  • toke/ticvocab.c
  • /*
     *                     OpenBIOS - free your system!
     *                         ( FCode tokenizer )
     *
     *  This program is part of a free implementation of the IEEE 1275-1994
     *  Standard for Boot (Initialization Configuration) Firmware.
     *
     *  Copyright (C) 2001-2005 Stefan Reinauer, <stepan@openbios.org>
     *
     *  This program is free software; you can redistribute it and/or modify
     *  it under the terms of the GNU General Public License as published by
     *  the Free Software Foundation; version 2 of the License.
     *
     *  This program is distributed in the hope that it will be useful,
     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     *  GNU General Public License for more details.
     *
     *  You should have received a copy of the GNU General Public License
     *  along with this program; if not, write to the Free Software
     *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
     *
     */
    
    /* **************************************************************************
     *
     *      General-purpose support functions for
     *      Threaded Interpretive Code (T. I. C.)-type vocabularies
     *
     *      (C) Copyright 2005 IBM Corporation.  All Rights Reserved.
     *      Module Author:  David L. Paktor    dlpaktor@us.ibm.com
     *
     **************************************************************************** */
    
    /* **************************************************************************
     *
     *      We are going to implement a strategy that takes better advantage
     *          of the concept of Threaded Interpretive Code  (well, okay,
     *          it won't really be interpretive ... )  We will use it to
     *          implement a small (but expandable) subset of FORTH-like
     *          commands in Tokenizer-Escape mode, as well as a few other
     *          things, such as conditional-tokenization.
     *
     *      The Threaded Interpretive Code Header data structure is described
     *          in detail in the accompanying  ticvocab.h  header-file.
     *
     *      In most cases, the contents of a beginning portion of the vocabulary
     *          are known at compile-time, and later parts are added by the
     *          user at run-time.  (The linked-list structure is needed to allow
     *          for that.)  We can initialize the known start of the vocabulary
     *          easily, except for the link-pointers, as an array.
     *      We can either explicitly state an index for each entry's link-pointer
     *          to the previous entry (which can become a problem to maintain) or
     *          have a function to initialize the links dynamically, at run-time.
     *      I think I will (regretfully, resignedly) choose the latter.
     *          
     *      We will define a few general-purpose functions for dealing with
     *          T. I. C. -type vocabularies.  Eventually, it might be a good
     *          idea to convert all the vocabularies to this structure...
     *
     **************************************************************************** */
    
    /* **************************************************************************
     *
     *
     *      Revision History:
     *          Mon, 19 Dec 2005 by David L. Paktor
     *          Begin converting most, if not all, of the vocabularies to
     *              T. I. C. -type structure.
     *
     **************************************************************************** */
    
    
    /* **************************************************************************
     *
     *      Functions Exported:
     *          init_tic_vocab        Initialize a TIC_HDR -type vocabulary
     *          add_tic_entry         Add an entry to a TIC_HDR -type vocabulary
     *          lookup_tic_entry      Look for a name in a TIC_HDR -type vocabulary
     *          handle_tic_vocab      Perform a function in a TIC_HDR -type vocab
     *          exists_in_tic_vocab   Confirm whether a given name exists in a
     *                                    TIC_HDR -type vocabulary
     *          create_tic_alias      Duplicate the behavior of one name with
     *                                     another name.  Return a "success" flag.
     *          reset_tic_vocab       Reset a given TIC_HDR -type vocabulary to
     *                                    its "Built-In" position.
     *
     **************************************************************************** */
    
    
    /* **************************************************************************
     *
     *          Global Variables Exported
     *              tic_found       The entry, in a TIC_HDR -type vocabulary,
     *                                  that has just been found and is being 
     *                                  "handled".  Needed for protection against
     *                                  recursion in a User-defined Macro (which
     *                                  should occur only rarely).
     *
     **************************************************************************** */
    
    
    #include <stdlib.h>
    #include <string.h>
    
    #include "ticvocab.h"
    #include "errhandler.h"
    #include "tracesyms.h"
    #include "scanner.h"
    #include "devnode.h"
    #include "vocabfuncts.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 passed to this routine have their
     *              initial values explicitly declared NULL. 
     *          If the user has asked to Trace any built-in name, the support
     *              routine will set its  tracing  field and dispay a message.
     *
     **************************************************************************** */
    
    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];
    	trace_builtin( &tic_vocab_tbl[indx]);
        }
    }
    
    
    /* **************************************************************************
     *
     *      Function name:  make_tic_entry
     *      Synopsis:       Construct a new entry to a TIC_HDR -type vocab-list
     *                          but do not add it to a 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)
     *             is_single     TRUE if entry is a single-token FCode
     *             ign_fnc       Pointer to "ignoring" routine for new entry
     *             trace_this    TRUE if new entry is to be "Traced"
     *             tic_vocab     Address of the variable that holds the latest
     *                               pointer to the "tail" of the T.I.C.-type
     *                               vocab-list to which we are adding.
     *
     *      Outputs:
     *         Returned Value:   Pointer to the 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 and the given
     *              data will be placed into its fields.
     *
     *      Extraneous Remarks:
     *          This is a retro-fit; it's a factor of the add_tic_entry()
     *              routine, whose functionality has been expanded to include
     *              issuing the Trace-Note and Duplication Warning messages.
     *              Having it separate allows it to be called (internally) by
     *              create_split_alias(), which has special requirements for
     *              its call to trace_creation() 
     *
     **************************************************************************** */
    
    static tic_hdr_t *make_tic_entry( char *tname,
                            void (*tfunct)(),
                                 TIC_P_DEFLT_TYPE tparam,
                                     fwtoken fw_defr,
    				     int pfldsiz,
                                             bool is_single,
                                             void (*ign_fnc)(),
                                                   bool trace_this,
                                                 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->is_token          =  is_single;
        new_entry->ign_func          =  ign_fnc;
        new_entry->pfld_size         =  pfldsiz;
        new_entry->tracing           =  trace_this;
    
        return( new_entry);
    }
    
    
    /* **************************************************************************
     *
     *      Function name:  add_tic_entry
     *      Synopsis:       Add an entry to the given TIC_HDR -type vocabulary;
     *                          issue the Creation Tracing and Duplicate-Name
     *                          messages as applicable.
     *
     *      Inputs:
     *         Parameters:
     *             tname             Pointer to space containing entry's new name
     *             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 ptr to alloc'd mem)
     *             is_single         TRUE if entry is a single-token FCode
     *             ign_fnc           Pointer to "ignoring" routine for new entry
     *          NOTE:  No  trace_this  param here; it's only in make_tic_entry()
     *             tic_vocab         Address of the variable that holds the latest
     *                                   pointer to the "tail" of the T.I.C.-type
     *                                   vocab-list to which we are adding.
     *         Global Variables:
     *             scope_is_global   TRUE if "global" scope is in effect
     *                                  (passed to "Trace-Creation" message)
     *
     *      Outputs:
     *         Returned Value:       NONE
     *         Supplied Pointers:
     *             *tic_vocab        Will point to new entry
     *         Printout:
     *             "Trace-Creation" message
     *
     *      Error Detection:
     *          Warning on duplicate name (subject to command-line control)
     *
     *      Process Explanation:
     *          The entry itself will be created by the  make_tic_entry()  routine.
     *          This routine will test whether the new name is to be Traced,
     *              and will pass that datum to the  make_tic_entry()  routine.
     *          If the new name is to be Traced, issue a Creation Tracing message.
     *              (We want it to appear first).  Use the new entry.
     *          Because this routine will not be called for creating aliases, the
     *              second param to  trace_creation()  is NULL.
     *          Do the duplicate-name check _before_ linking the new entry in to
     *              the given vocabulary.  We don't want the duplicate-name test
     *              to find the name in the new entry, only in pre-existing ones...
     *          Now we're ready to update the given pointer-to-the-tail-of-the-
     *              -vocabulary to point to the new entry.
     *
     **************************************************************************** */
    
    void add_tic_entry( char *tname,
                            void (*tfunct)(),
                                 TIC_P_DEFLT_TYPE tparam,
                                     fwtoken fw_defr,
    				     int pfldsiz,
                                             bool is_single,
    					   void (*ign_fnc)(),
    					       tic_hdr_t **tic_vocab )
    {
        bool trace_this = is_on_trace_list( tname);
        tic_hdr_t *new_entry = make_tic_entry( tname,
    			       tfunct,
    			           tparam,
    				       fw_defr, pfldsiz,
    				           is_single,
    					       ign_fnc,
    						   trace_this,
    						       tic_vocab );
    
        if ( trace_this )
        {
    	trace_creation( new_entry, NULL, scope_is_global);
        }
        warn_if_duplicate( tname);
        *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
     *                                      in which to search
     *
     *      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, duplicate-name checking...
     *
     **************************************************************************** */
     
    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_split_alias
     *      Synopsis:       Create an Alias in one TIC_HDR -type vocabulary
     *                          for a word in (optionally) another vocabulary.
     *                          Return a "success" flag.
     *                          This is the work-horse for  create_tic_alias()
     *
     *      Associated FORTH word:                 ALIAS
     *
     *      Inputs:
     *         Parameters:
     *             old_name             Name of existing entry
     *             new_name             New name for which to create an entry
     *             *src_vocab           Pointer to the "tail" of the "Source"
     *                                      TIC_HDR -type vocab-list 
     *             *dest_vocab          Pointer to the "tail" of the "Destination"
     *                                      TIC_HDR -type vocab-list 
     *
     *      Outputs:
     *         Returned Value:          TRUE if  old_name  found in "Source" vocab
     *         Supplied Pointers:
     *             *dest_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 "Destination" vocab-list.
     *         Printout:
     *             "Trace-Creation" message
     *
     *      Error Detection:
     *          Warning on duplicate name (subject to command-line control)
     *
     *      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.
     *          We will do both the "Creation-Tracing" announcement and the
     *              Duplicate Name Warning here.  "Tracing" happens either if
     *              the entry for the old name has its  tracing  flag set, or
     *              if the new name is on the trace-list.  The "source" vocab
     *              and the "dest" vocab can only be different when the "old"
     *              name has defined Global scope.  We will pass that along
     *              to the  trace_creation()  routine.
     *          We're doing the "Tracing" and Duplicate-Name functions because
     *              we're applying the "Tracing" message to the "old" name's
     *              entry.  Because of this, we must call  make_tic_entry()  to
     *              bypass  add_tic_entry(), which now does its own "Tracing"
     *              and Duplicate-Name functions on the new entry.
     *
     **************************************************************************** */
    
    bool create_split_alias( char *new_name, char *old_name,
                                  tic_hdr_t **src_vocab, tic_hdr_t **dest_vocab )
    {
        tic_hdr_t *found ;
        bool retval = FALSE;
    
        found = lookup_tic_entry( old_name, *src_vocab );
        if ( found != NULL )
        {
    	bool trace_it = found->tracing;
    	if ( ! trace_it )
    	{
    	    trace_it = is_on_trace_list( new_name);
    	}
    	if ( trace_it )
    	{
    	    bool old_is_global = BOOLVAL( src_vocab != dest_vocab );
    	    trace_creation( found, new_name, old_is_global);
    	}
    	warn_if_duplicate( new_name);
    
    	*dest_vocab = make_tic_entry( new_name,
    			   found->funct,
    			   found->pfield.deflt_elem,
    				   found->fword_defr, 0,
    			               found->is_token,
    					   found->ign_func,
    					       trace_it,
    						   dest_vocab );
    	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:
     *          The given vocabulary is both the "Source" and the "Destination".
     *              Pass them both to  create_split_alias.
    
     **************************************************************************** */
    
    bool create_tic_alias( char *new_name, char *old_name, tic_hdr_t **tic_vocab )
    {
        return ( create_split_alias( new_name, old_name, tic_vocab, tic_vocab ) );
    }
    
    
    /* **************************************************************************
     *
     *      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 ;
        }
    }