Main Page | Data Structures | File List | Data Fields | Globals

devnode.c

Go to the documentation of this file.
00001 /*
00002  *                     OpenBIOS - free your system!
00003  *                         ( FCode tokenizer )
00004  *
00005  *  This program is part of a free implementation of the IEEE 1275-1994
00006  *  Standard for Boot (Initialization Configuration) Firmware.
00007  *
00008  *  Copyright (C) 2001-2005 Stefan Reinauer, <stepan@openbios.org>
00009  *
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; version 2 of the License.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with this program; if not, write to the Free Software
00021  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
00022  *
00023  */
00024 
00025 /* **************************************************************************
00026  *
00027  *      Support routines for managing device-node vocabularies
00028  *
00029  *      (C) Copyright 2005 IBM Corporation.  All Rights Reserved.
00030  *      Module Author:  David L. Paktor    dlpaktor@us.ibm.com
00031  *
00032  **************************************************************************** */
00033 
00034 /* **************************************************************************
00035  *
00036  *      The vocabulary that is created for a device-node must not remain
00037  *          available outside of that node.  Also, nodes may be nested,
00038  *          child within parent.
00039  *      An attempt within a child-node to access directly a method defined
00040  *          in the parent must be flagged as an error.  (Consider what would
00041  *          happen if the method in the parent-node used instance data, and
00042  *          the child-node has an instance of its own.)
00043  *      The correct way is to invoke the method via "$call-parent" or the like.
00044  *
00045  *      We will, however, allow the user to specify a group of exceptions,
00046  *          words whose scope will be "global" within the tokenization.
00047  *          When "global" scope is initiated, definitions will be made to
00048  *          the "core" vocabulary until "device" scope is resumed.
00049  *          That will (mostly) all be handled in  dictionary.c 
00050  *
00051  **************************************************************************** */
00052 
00053 
00054 /* **************************************************************************
00055  *
00056  *      Functions Exported:
00057  *          new_device_vocab        Create the new device-node's data-structure
00058  *          delete_device_vocab     Remove device-node's data-structure
00059  *          finish_device_vocab     Remove struct and give messages when
00060  *                                      device is "finish"ed.
00061  *          exists_in_ancestor      Issue a Message if the given word exists
00062  *                                      in an ancestor of the current dev-node.
00063  *
00064  **************************************************************************** */
00065 
00066 /* **************************************************************************
00067  *
00068  *      Still to be done:
00069  *          Add a pair of fields to the data-structure for the Input File and
00070  *              Line Number where "finish-device" occurred.  When a device-node
00071  *              is "finish"ed, do not delete it, but instead fill in those
00072  *              fields and the move the node to a separate linked-list.
00073  *          When looking whether a word exists in an ancestor-node, also
00074  *              check whether it was in a device-node that was finished and
00075  *              print both where it was started and where it was finished.
00076  *
00077  **************************************************************************** */
00078 
00079 
00080 
00081 #include <stdio.h>
00082 #include <stdlib.h>
00083 #include <string.h>
00084 #include <errno.h>
00085 
00086 #include "devnode.h"
00087 #include "errhandler.h"
00088 #include "scanner.h"
00089 #include "vocabfuncts.h"
00090 #include "flowcontrol.h"
00091 #include "stream.h"
00092 #include "ticvocab.h"
00093 
00094 
00095 /* **************************************************************************
00096  *
00097  *      Tokenization starts with an implicit "new-device" in effect.
00098  *          The top-level device-node is never removed.
00099  *
00100  *      Initialize it here
00101  *
00102  **************************************************************************** */
00103 char default_top_dev_ifile_name[] = "Start of tokenization";
00104 
00105 static device_node_t top_level_dev_node = {
00106         NULL ,                          /*  parent_node    */
00107         default_top_dev_ifile_name ,    /*  ifile_name.
00108                                          *     Something to show, Just In Case
00109                                          */
00110         0 ,                             /*  line_no        */
00111         NULL ,                          /*  tokens_vocab   */
00112 };
00113 
00114 /* **************************************************************************
00115  *
00116  *          Global Variables Exported.
00117  *                                  Pointers to:
00118  *     current_device_node      data-structure of current device-node
00119  *     current_definitions      vocab into which to add def'ns.
00120  *
00121  **************************************************************************** */
00122 
00123 device_node_t *current_device_node = &top_level_dev_node;
00124 tic_hdr_t **current_definitions = &(top_level_dev_node.tokens_vocab);
00125 
00126 
00127 /* **************************************************************************
00128  *
00129  *          Internal Static Variables
00130  *               These are used to support the routines  in_what_node() 
00131  *                   and  show_node_start() , which are used to facilitate
00132  *                   certain kinds of Messaging, as described later.
00133  *
00134  *     in_what_buffr       Buffer for the  in_what_node()  string
00135  *     show_where          TRUE if the string needs to be followed-up
00136  *     show_which          TRUE if follow-up should be  just_where_started()
00137  *                             rather than  just_started_at()
00138  *     in_what_line        Line Number to use in the follow-up
00139  *     in_what_file        File Name to use in the follow-up
00140  *
00141  **************************************************************************** */
00142 
00143 static char in_what_buffr[50];   /*  Ought to be more than enough.  */
00144 static bool show_where = FALSE;
00145 static bool show_which;
00146 static int in_what_line;
00147 static char *in_what_file;
00148 
00149 
00150 /* **************************************************************************
00151  *
00152  *      Function name:  dev_vocab_control_struct_check
00153  *      Synopsis:       Issue Warnings for unresolved flow-control constructs
00154  *                          at start or end of a device-node.
00155  *
00156  *      Inputs:
00157  *         Parameters:                     NONE
00158  *         Global Variables:
00159  *             statbuf                     The command being processed.
00160  *
00161  *      Outputs:
00162  *         Returned Value:                 NONE
00163  *         Printout:
00164  *             Handled by  announce_control_structs() routine
00165  *
00166  *      Error Detection:
00167  *          Handled by  announce_control_structs()  routine
00168  *
00169  *      Process Explanation:
00170  *          Set up a buffer with the error message, based on  statbuf
00171  *              and pass it to  announce_control_structs()
00172  *          Release it when done.
00173  *
00174  **************************************************************************** */
00175 
00176 static void dev_vocab_control_struct_check( void)
00177 {
00178     char *ccs_messg;
00179 
00180     ccs_messg = safe_malloc(strlen(statbuf) + 32,
00181         "Device-Node control-structure check");
00182     
00183     strcpy( ccs_messg, statbuf );
00184     strupr( ccs_messg);
00185     strcat( ccs_messg, " encountered");
00186     announce_control_structs( WARNING, ccs_messg, 0 );
00187     free( ccs_messg);
00188 }
00189 
00190 
00191 
00192 /* **************************************************************************
00193  *
00194  *      Function name:  new_device_vocab
00195  *      Synopsis:       Create and initialize the data-structure for a
00196  *                      new device-node when a "new-device" is created,
00197  *                      with messages as appropriate.
00198  *
00199  *      Inputs:
00200  *         Parameters:                     NONE
00201  *         Global Variables:
00202  *             statbuf                     The word that was just read.
00203  *             iname                       Current Input-File Name
00204  *             lineno                      Current line-number
00205  *
00206  *      Outputs:
00207  *         Returned Value:                 NONE
00208  *         Global Variables:
00209  *             current_device_node         Will point to the new data-structure
00210  *         Memory Allocated
00211  *             Space for the new  device_node_t  data-structure
00212  *             Space for a copy of the current input file name
00213  *         When Freed?
00214  *             By delete_device_vocab(), when the device-node is "finish"ed.
00215  *         Printout:
00216  *             Advisory message.
00217  *
00218  *      Error Detection:
00219  *          In immediate-execution mode, Control Structures that have not
00220  *              been completed are questionable;  Issue WARNINGS via the
00221  *               dev_vocab_control_struct_check()  routine.
00222  *
00223  *      Process Explanation:
00224  *          This routine is called when "new-device" is invoked, but only
00225  *              if we are in immediate-execution mode.
00226  *          Later on, in ERROR- or INFOrmative messages, we will want to
00227  *              be able to refer to the file and line-number in which this
00228  *              was encountered, so we include them in the structure.
00229  *
00230  **************************************************************************** */
00231 
00232 void new_device_vocab( void )
00233 {
00234     device_node_t *new_node_data;
00235 
00236     dev_vocab_control_struct_check();
00237 
00238     /*  Advisory message will mention previous device-node
00239      *      if there was one.  Either way starts out the same:
00240      */
00241 #define NEW_DEV_MSG_START  "Encountered %s.  Starting new device-node."
00242 
00243     if ( current_device_node == &top_level_dev_node )
00244     {
00245         tokenization_error(INFO, NEW_DEV_MSG_START "\n", statbuf );
00246     }else{
00247         tokenization_error(INFO, NEW_DEV_MSG_START
00248             "  Suspending definitions of parent-device node", statbuf );
00249         started_at( current_device_node->ifile_name,
00250              current_device_node->line_no );
00251     }
00252 
00253     /*  Now to business...   */
00254     new_node_data = safe_malloc( sizeof(device_node_t),
00255         "creating new-device vocab data" );
00256     new_node_data->parent_node = current_device_node;
00257     new_node_data->ifile_name = strdup(iname);
00258     new_node_data->line_no = lineno;
00259     new_node_data->tokens_vocab = NULL;
00260 
00261     current_device_node = new_node_data;
00262     
00263     current_definitions = &(current_device_node->tokens_vocab);
00264 }
00265 
00266 
00267 /* **************************************************************************
00268  *
00269  *      Function name:  delete_device_vocab
00270  *      Synopsis:       Remove the vocabularies of the current device-node,
00271  *                          along with its data-structure, when the device
00272  *                          is "finish"ed; do not print messages.
00273  *                      Do not remove the top-level device-node data-struct.
00274  *
00275  *      Associated FORTH words:              FINISH_DEVICE  (interpretive state)
00276  *                                           END0  END1
00277  *      Associated Tokenizer directives:     RESET-SYMBOLS  (in "Normal" mode)
00278  *                                           FCODE-END
00279  *
00280  *      Inputs:
00281  *         Parameters:                    NONE
00282  *         Global Variables:
00283  *             current_device_node        Points to current device's struct
00284  *                                            Leads to chain of dev-node structs
00285  *
00286  *      Outputs:
00287  *         Returned Value: 
00288  *         Global Variables:
00289  *             current_device_node        Parent-device's struct becomes current
00290  *         Memory Freed
00291  *             All that was allocated for the tokens and the definers
00292  *                 vocabs in the current device-node
00293  *             The copy of the input file name, except the top-level
00294  *             The current_device_node data-structure, except the top-level
00295  *
00296  **************************************************************************** */
00297 
00298 void delete_device_vocab( void )
00299 {
00300     reset_tic_vocab( current_definitions, NULL );
00301 
00302     if ( current_device_node != &top_level_dev_node )
00303     {
00304         device_node_t *temp_node = current_device_node;
00305         current_device_node = current_device_node->parent_node;
00306         free( temp_node->ifile_name );
00307         free(temp_node);
00308     }
00309 
00310     current_definitions = &(current_device_node->tokens_vocab);
00311 }
00312 
00313 /* **************************************************************************
00314  *
00315  *      Function name:  finish_device_vocab
00316  *      Synopsis:       Remove the device-node data-structure and all its
00317  *                          vocabularies when the device is "finish"ed,
00318  *                          with appropriate messages.
00319  *                      Do not remove the top-level device node data-struct.
00320  *
00321  *      Associated FORTH word:                 FINISH_DEVICE
00322  *
00323  *      Inputs:
00324  *         Parameters:                    NONE
00325  *         Global Variables:
00326  *             current_device_node        Current device's struct pointer
00327  *
00328  *      Outputs:
00329  *         Returned Value:                NONE
00330  *         Global Variables:
00331  *             current_device_node        Parent-device's struct becomes current
00332  *         Printout:
00333  *             Advisory message.
00334  *
00335  *      Error Detection:
00336  *          If current_device_node is already pointing at the top-level
00337  *              device node, it means there was no corresponding NEW-DEVICE
00338  *              Issue an ERROR.
00339  *          In immediate-execution mode, Control Structures that have not
00340  *              been completed are questionable;  Issue WARNINGS via the
00341  *               dev_vocab_control_struct_check()  routine.
00342  *
00343  *      Process Explanation:
00344  *          This routine is called when "finish-device" is invoked, but only
00345  *              if we are in immediate-execution mode.
00346  *
00347  **************************************************************************** */
00348 
00349 void finish_device_vocab( void )
00350 {
00351     bool at_top_level;
00352 
00353     dev_vocab_control_struct_check();
00354 
00355     /*   We never remove the top-level device-node vocabulary,
00356      *       so we need to test whether we're about to.
00357      */
00358 
00359     at_top_level = BOOLVAL( current_device_node == &top_level_dev_node );
00360     if ( at_top_level )
00361     {
00362         tokenization_error( TKERROR,
00363             "Encountered %s without corresponding NEW-DEVICE.  "
00364             "Resetting definitions since start of tokenization.\n",
00365                 statbuf );
00366     }else{    
00367         tokenization_error(INFO,
00368             "Encountered %s.  Resetting definitions of device node",
00369                 statbuf );
00370         started_at( current_device_node->ifile_name,
00371              current_device_node->line_no );
00372     }
00373 
00374     /*  Now to business...   */
00375     delete_device_vocab();
00376 
00377     /*   Did we just get to the top-level device-node vocabulary
00378      *       when we weren't before?
00379      */
00380     if ( INVERSE(at_top_level) )
00381     {
00382         if ( current_device_node == &top_level_dev_node )
00383         {
00384             tokenization_error(INFO,
00385                 "Resuming definitions since start of tokenization.\n" );
00386         }else{
00387             tokenization_error(INFO,
00388                 "Resuming definitions of parent device-node" );
00389             started_at( current_device_node->ifile_name,
00390                  current_device_node->line_no );
00391         }
00392     }
00393 }
00394 
00395 
00396 /* **************************************************************************
00397  *
00398  *      Function name:  in_what_node
00399  *      Synopsis:       Format a string for use in a Message that might
00400  *                          identify the start of the given device-node.
00401  *
00402  *      Inputs:
00403  *         Parameters:
00404  *             the_node               The device-node vocabulary about which
00405  *                                        to construct the identifying phrase.
00406  *         Local Static Variables:
00407  *             in_what_buffr          Buffer in which to format the string.
00408  *         Global Variables:
00409  *             current_definitions    Device-node vocabulary currently
00410  *                                        in effect.
00411  *
00412  *      Outputs:
00413  *         Returned Value:           Pointer to buffer w/ formatted string
00414  *         Local Static Variables:
00415  *             in_what_buffr         Will contain the formatted string.
00416  *             show_where            TRUE if the string needs to be followed-up
00417  *                                        (i.e., did not contain a terminating
00418  *                                        new-line) by  just_where_started()
00419  *                                        or by  just_started_at()
00420  *             show_which            TRUE if the follow-up call should be
00421  *                                       to  just_where_started()  rather 
00422  *                                       than to  just_started_at() 
00423  *             in_what_line          Copy of line_no field from the_node
00424  *             in_what_file          Copy of ifile_name field from the_node
00425  *
00426  *      Process Explanation:
00427  *          Calling routine must ascertain that Global-scope is not in effect.
00428  *          The returned phrase can be used as a string argument in a Message.
00429  *          Set  show_where  TRUE if the_node->line_no is non-zero.
00430  *          Set  show_which  TRUE if the_node is either the Current or the
00431  *              Top-Level device-node
00432  *          If the originating line-number in the given Node structure is zero,
00433  *              the returned phrase will contain a terminating new-line.
00434  *              (This only happens if the given Node is the top-level Node,
00435  *              and it's the Current Node, and the "official" starting-point
00436  *              hasn't yet been established by an "FCode-Starter" such as 
00437  *               FCODE-VERSION2 .  Once that command has been given, even
00438  *              definitions that were made prior to it belong to the Node
00439  *              that started there.)
00440  *          Otherwise,  show_where  is returned TRUE, and  show_which  becomes
00441  *              relevant.  If the given node is the Current or the Top-Level
00442  *              node, text about the originating file-name and line-number
00443  *              merely describes a node that is already uniquely identified,
00444  *              so the message appended to the buffer will have the phrase
00445  *              "which began" (which introduces what is known in grammar as
00446  *              an Appositive Subordinate Clause) and  show_which  will be
00447  *              returned TRUE.  If the given node is not uniquely identifiable
00448  *              without the file- and line- phrase, then the Subordinate Clause
00449  *              is Indicative, and should be introduced with "that" (and no
00450  *              comma); in that case, we will return  show_which  as FALSE.
00451  *          After the calling routine displays the message in which the
00452  *              returned phrase is used, it must call  show_node_start()
00453  *              to display the followe-up message, if any.
00454  *
00455  **************************************************************************** */
00456 
00457 char *in_what_node(device_node_t *the_node)
00458 {
00459     bool top_node    = BOOLVAL( the_node == &top_level_dev_node);
00460     bool curr_node   = BOOLVAL( the_node == current_device_node);
00461     bool known_node  = BOOLVAL( top_node || curr_node );
00462     bool no_line     = BOOLVAL( the_node->line_no == 0);
00463 
00464     show_where   = INVERSE( no_line  );
00465     show_which   = known_node;
00466     in_what_line = the_node->line_no;
00467     in_what_file = the_node->ifile_name;
00468 
00469     sprintf( in_what_buffr, "in the%s device-node%s",
00470         INVERSE( known_node )  ? ""
00471                 :  top_node    ?    " top-level"   :  " current" ,
00472         
00473         no_line                ?  ".\n"
00474                 :  known_node  ?  ", which began"  :   ""         );
00475 
00476     
00477     return( in_what_buffr);
00478 }
00479 
00480 
00481 /* **************************************************************************
00482  *
00483  *      Function name:  show_node_start
00484  *      Synopsis:       Follow-up to the  in_what_node()  call.  Print out,
00485  *                          if applicable, the text about the originating
00486  *                          file-name and line-number
00487  *
00488  *      Inputs:
00489  *         Parameters:             NONE
00490  *         Local Static Variables:
00491  *             show_where          Nothing to do if not TRUE
00492  *             show_which          TRUE if should call  just_where_started()
00493  *                                     rather than  just_started_at()
00494  *             in_what_line        Line Number to use in the follow-up
00495  *             in_what_file        File Name to use in the follow-up
00496  *
00497  *      Outputs:
00498  *         Returned Value:         NONE
00499  *         Local Static Variables:
00500  *             show_where          Force to FALSE
00501  *         Printout:
00502  *             Follow-up to  the in_what_node() call.  Applicable text
00503  *                 about the originating file-name and line-number.
00504  *
00505  *      Process Explanation:
00506  *          By forcing  show_where  to FALSE after this is called, we
00507  *              can safely allow routines that might or might not have
00508  *              called  in_what_node()  to call this routine, without
00509  *              needing any additional "bookkeeping".
00510  *
00511  **************************************************************************** */
00512 
00513 void show_node_start( void)
00514 {
00515     if ( show_where)
00516     {
00517         if ( show_which )
00518         {
00519             just_where_started( in_what_file, in_what_line);
00520         }else{
00521             just_started_at( in_what_file, in_what_line);
00522         }
00523         show_where = FALSE;
00524     }
00525 }
00526 
00527 
00528 
00529 /* **************************************************************************
00530  *
00531  *      Function name:  exists_in_ancestor
00532  *      Synopsis:       Issue a Message and return an indication if
00533  *                          the given word exists in an ancestor of
00534  *                          the current device-node.
00535  *                      Used for additional error-message information.
00536  *                      
00537  *
00538  *      Inputs:
00539  *         Parameters:
00540  *             m_name                   "Method" name
00541  *         Global Variables:
00542  *             current_device_node      Leads to chain of dev-node data-structs
00543  *             scope_is_global          TRUE if "global" scope is in effect
00544  *
00545  *      Outputs:
00546  *         Returned Value:              TRUE if word found
00547  *         Printout:
00548  *             If  m_name  exists in an ancestor-node, print an ADVISORY
00549  *                 giving the location where the ancestor originated.
00550  *
00551  *      Error Detection:
00552  *          None here.  Calling routine detected error; see below.
00553  *
00554  *      Process Explanation:
00555  *          This routine was called as the result of detecting an error:
00556  *              viz.,  m_name  was not found in either the current node
00557  *              or the base vocabulary.  (Except:  If "global" scope is
00558  *              in effect, we didn't search the current device-node).
00559  *
00560  **************************************************************************** */
00561 
00562 bool exists_in_ancestor( char *m_name)
00563 {
00564     tic_hdr_t *found;
00565     bool retval = FALSE;
00566     if ( current_device_node != NULL )
00567     {
00568         device_node_t *grandpa = current_device_node->parent_node;
00569 
00570         if ( scope_is_global )    grandpa = current_device_node;
00571 
00572         for ( ; grandpa != NULL; grandpa = grandpa->parent_node )
00573         {
00574             found = lookup_tic_entry( m_name, grandpa->tokens_vocab);
00575             if ( found != NULL )
00576             {
00577                 retval = TRUE;
00578                 break;
00579             }
00580         }
00581         if ( grandpa != NULL )
00582         {
00583             char as_what_buf[32] = "";
00584             if ( as_a_what( found->fword_defr, as_what_buf) )
00585             {
00586                 strcat( as_what_buf, " ");
00587             }
00588             tokenization_error(INFO, "%s is defined %s%s", m_name,
00589                 as_what_buf, in_what_node( grandpa) );
00590             show_node_start();
00591         }
00592     }
00593 
00594     return(retval );
00595 }

Generated on Fri Aug 18 14:03:38 2006 for Toke1.0 by  doxygen 1.4.4