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

parselocals.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  *      Parsing functions for IBM-style Local Values
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  *      Functions Exported:
00037  *          declare_locals      Pick up the Locals' names after the {
00038  *          handle_local        Insert the code to access a Local
00039  *          exists_as_local     Confirm whether a name is in the Locals vocab
00040  *          assign_local        Process the "Assign to a Local" operator ( -> )
00041  *          finish_locals       Insert the code for exiting a routine
00042  *                                  that uses locals
00043  *          forget_locals       Remove the locals' names from the search   
00044  *
00045  **************************************************************************** */
00046 
00047 /* **************************************************************************
00048  *
00049  *          These are the names of the three routines that will be invoked
00050  *          when Locals are used.  Their definitions exist in a separate
00051  *          Local Values Support FCode source-file that must be FLOADed
00052  *          into the user's tokenization source.
00053  *
00054  **************************************************************************** */
00055 
00056 /*  Note that the enclosing curly-braces are part of the name  */
00057 static const char* push_locals = "{push-locals}"; /* ( #ilocals #ulocals -- ) */
00058 static const char* pop_locals = "{pop-locals}";   /* ( #locals -- )           */
00059 static const char* local_addr = "_{local}";       /* ( local# -- addr )       */
00060 
00061 /*  Switchable Fetch or Store operator to apply to  local_addr.   */
00062 static const char* local_op = "@";   /*  Initially Fetch  */
00063 
00064 
00065 /* **************************************************************************
00066  *
00067  *      Revision History:
00068  *          Updated Wed, 13 Jul 2005 by David L. Paktor
00069  *              Command-line control for:
00070  *                  Support for Locals in general
00071  *                  Whether to accept the "legacy" separator (semicolon)
00072  *                  Whether to issue a message for the "legacy" separator
00073  *          Updated Tue, 10 Jan 2006 by David L. Paktor
00074  *              Convert to  tic_hdr_t  type vocabulary.
00075  *
00076  **************************************************************************** */
00077 
00078 #include <stdio.h>
00079 #include <stdlib.h>
00080 #include <string.h>
00081 #include "ticvocab.h"
00082 #include "dictionary.h"
00083 #include "scanner.h"
00084 #include "parselocals.h"
00085 #include "errhandler.h"
00086 #include "clflags.h"
00087 #include "stream.h"
00088 #include "devnode.h"
00089 #include "flowcontrol.h"
00090 
00091 /* **************************************************************************
00092  *
00093  *      Global Variables Imported
00094  *          statbuf
00095  *          pc    
00096  *          opc
00097  *          incolon
00098  *          lastcolon
00099  *          ibm_locals_legacy_separator      Accept ; as the "legacy" separator
00100  *          ibm_legacy_separator_message     Issue a message for "legacy" sep'r
00101  *
00102  **************************************************************************** */
00103 
00104 /* **************************************************************************
00105  *
00106  *          Internal Static Variables
00107  *              local_names        Vocabulary for new local-names
00108  *              num_ilocals        Number of initialized local variables
00109  *              num_ulocals        Number of uninitialized local variables
00110  *              localno            Running Local-Number to be assigned
00111  *              eval_buf           Internally-generated string to be parsed
00112  *              l_d_lineno         Locals Declaration Line Number
00113  *
00114  **************************************************************************** */
00115 
00116 static tic_hdr_t *local_names = NULL;
00117 static int num_ilocals = 0;
00118 static int num_ulocals = 0;
00119 static int localno = 0;
00120 static char eval_buf[64];
00121 static unsigned int l_d_lineno;         /*  For Error Messages   */
00122 
00123 /* **************************************************************************
00124  *
00125  *     The  local_names  vocabulary follows the same  tic_hdr_t   structure
00126  *         as the dictionaries of tokens, special-functions, etcetera.   Its
00127  *         "parameter field" is an integer, used to store the Local's number,
00128  *         an its "function" is invoke_local(), defined further below.
00129  *
00130  *     The vocabulary is initially empty, so there's no need for an "init"
00131  *         or a "reset" routine.
00132  *
00133  **************************************************************************** */
00134 
00135 /* **************************************************************************
00136  *
00137  *      Function name:  int_to_str
00138  *      Synopsis:       Convert an integer into a compilable string.
00139  *                      Suport routine for invoke_local().
00140  *
00141  *      Inputs:
00142  *         Parameters:
00143  *             num             The number to convert
00144  *             bufr            The buffer into which to place it.
00145  *                                 Needn't be very long:
00146  *                                 five at least, ten is enough
00147  *
00148  *      Outputs:
00149  *         Returned Value:     Pointer to  bufr
00150  *             bufr            Contents are changed.
00151  *
00152  *      Process Explanation:
00153  *          Convert into decimal.  If the number is greater than 8,
00154  *              prepend a  d#  in front of it.  If less, don't.
00155  *              We specifically want to avoid a  d#  in front of
00156  *              the numbers 0 1 2 and 3, which are also named constants;
00157  *              there's no need to treat 'em as literals.
00158  *          The calling routine will be responsible for allocating
00159  *              and freeing the buffer.
00160  *
00161  *      Extraneous Remarks:
00162  *          Too bad  atoi()  isn't a Standard C function; I could convert
00163  *             using the current base, and be guaranteed that it would be
00164  *             interpreted in the same base.
00165  *          Instead, I have to fiddle-faddle around with  d#  ...
00166  *
00167  **************************************************************************** */
00168 
00169 static char *int_to_str( int num, char *bufr)
00170 {
00171      char* prefix = "d# ";
00172      if ( num < 8 ) prefix = "";
00173      sprintf(bufr,"%s%d",prefix, num);
00174      return (bufr);
00175 }
00176 
00177 
00178 
00179 /* **************************************************************************
00180  *
00181  *      Function name:  invoke_local
00182  *      Synopsis:       Compile-in the code to access the Local whose
00183  *                      assigned Number is given.  This function is
00184  *                      entered into the Local-Names Vocabulary entry.
00185  *      
00186  *      Inputs:
00187  *         Parameters:
00188  *             pfield              The Vocabulary entry's Param field, taken
00189  *                                     from the Assigned Number of the Local.
00190  *         Local Static Variables:
00191  *             local_addr          Name of  _{local}  routine, invoked
00192  *                                     when a Local is used 
00193  *             local_op            Fetch or Store operator to apply.
00194  *
00195  *      Outputs:
00196  *         Returned Value:         None
00197  *         Local Static Variables:
00198  *             eval_buf            Phrase constructed here; will become new
00199  *                                     Source Input Buffer, temporarily
00200  *
00201  *      Error Detection:
00202  *          If the Local Values Support FCode source-file was not
00203  *              FLOADed into the user's tokenization source, then
00204  *              the function  _{local}  will be an "unknown name".
00205  *
00206  *      Process Explanation:
00207  *          We are going to generate a string of the form:
00208  *                  " #local _{local} OP"
00209  *              and pass it to the Parser for evaluation.
00210  *          The call to  _{local}  is preceded by its parameter, which is
00211  *               its Assigned Local-Number, and followed by the appropriate
00212  *               OPerator, which will be "Fetch" if the Local's name was
00213  *               invoked by itself, or "Store" if its invocation was made
00214  *               in conjuction with the  ->  operator.
00215  *          The string-buffer may be local, but it must be stable.
00216  *
00217  *      Revision History:
00218  *      Updated Thu, 24 Mar 2005 by David L. Paktor
00219  *          Factored-out to permit  lookup_local()  to be a "pure"
00220  *          function that can be used for duplicate-name detection.
00221  *      Updated Tue, 10 Jan 2006 by David L. Paktor
00222  *          Accommodate conversion to  tic_hdr_t  type vocabulary.
00223  *
00224  **************************************************************************** */
00225 
00226 static void invoke_local( tic_param_t pfield )
00227 {
00228     char local_num_buf[10];
00229     int loc_num = (int)pfield.deflt_elem;
00230 
00231     int_to_str(loc_num, local_num_buf);
00232     sprintf( eval_buf, "%s %s %s", local_num_buf, local_addr, local_op );
00233     eval_string( eval_buf);
00234 
00235 }
00236 
00237 
00238 /* **************************************************************************
00239  *
00240  *      Function name:  locals_separator
00241  *      Synopsis:       Test whether the given character is the separator
00242  *                          between initted and uninitted Local Names.
00243  *                      Optionally, allow Semi-Colon as a separator and issue
00244  *                          an optional Advisory.
00245  *
00246  *      Inputs:
00247  *         Parameters:
00248  *             subj     One-character "subject" of the test
00249  *         Global Variables:    
00250  *             ibm_locals_legacy_separator     Allow Semi-Colon as a separator?
00251  *             ibm_legacy_separator_message    Issue an Advisory message?
00252  *
00253  *      Outputs:
00254  *         Returned Value:   TRUE if the character is the separator
00255  *
00256  *      Error Detection:
00257  *          If the separator is Semi-Colon, and  ibm_locals_legacy_separator 
00258  *              is TRUE, then if  ibm_legacy_separator_message  is TRUE,
00259  *              issue an Advisory message.
00260  *          If the flag to allow Semi-Colon is FALSE, then simply do not
00261  *              acknowledge a valid separator.  Other routines will report
00262  *              an erroneous attempt to use an already-defined symbol.
00263  *
00264  *      Revision History:
00265  *          Updated Wed, 13 Jul 2005 by David L. Paktor
00266  *          Bring the questions of whether to accept semicolon as a separator
00267  *              -- and whether to issue a message for it -- under the control 
00268  *              of external flags (eventually set by command-line switches),
00269  *              rather than being hard-compiled.
00270  *
00271  *      Extraneous Remarks:
00272  *          In the interest of avoiding too deeply nested "IF"s, I will
00273  *              not be adhering strictly to the rules of structure.
00274  *
00275  **************************************************************************** */
00276 
00277 static bool locals_separator( char subj )
00278 {
00279     bool retval = FALSE;
00280     /*  Is it the preferred (i.e., non-legacy) separator?   */
00281     if ( subj == '|' )
00282     {  
00283         retval = TRUE;
00284         return ( retval );
00285     }
00286         
00287     if ( ibm_locals_legacy_separator )
00288     {
00289         if ( subj == ';' )
00290         {
00291             retval = TRUE;
00292             if ( ibm_legacy_separator_message )
00293             {
00294                 tokenization_error ( WARNING , "Semicolon as separator in "
00295                     "Locals declaration is deprecated in favor of '|'\n");
00296             }
00297         }
00298     }
00299     return ( retval );
00300 }
00301 
00302 /* **************************************************************************
00303  *
00304  *      Function name:  add_local
00305  *      Synopsis:       Given a pointer to a name and a number, enter
00306  *                      them into the vocabulary for new Local names.
00307  *      
00308  *      Inputs:
00309  *         Parameters:
00310  *             lnum              The assigned number
00311  *             lname             Pointer to the name
00312  *         Local Static Variables:
00313  *             local_names       The vocabulary for new Local names
00314  *
00315  *      Outputs:
00316  *         Returned Value:       NONE
00317  *         Local Static Variables:
00318  *             local_names       Enter the new Local's name and number.
00319  *         Memory Allocated:
00320  *             A place into which the name will be copied
00321  *         When Freed?
00322  *             When  forget_locals()  routine frees up all memory
00323  *                 allocations in the "Local Names" Vocabulary.
00324  *
00325  *      Process Explanation:
00326  *          Allocate a stable place in memory for the name, via  strdup().
00327  *          The entry's "action" will be the  invoke_local()  function,
00328  *              defined above.  The "parameter field" size is zero.
00329  *
00330  **************************************************************************** */
00331 
00332 static void add_local( TIC_P_DEFLT_TYPE lnum, char *lname)
00333 {
00334     char *lnamecopy ;
00335 
00336     lnamecopy = strdup( lname);
00337     add_tic_entry( lnamecopy, invoke_local, lnum,
00338                        LOCAL_VAL, 0, NULL, &local_names );
00339     trace_creation( LOCAL_VAL, lname);
00340 }
00341 
00342 
00343 /* **************************************************************************
00344  *
00345  *      Function name:  gather_locals
00346  *      Synopsis:       Collect Local names, for both initted and uninitted
00347  *                      Return an indication as to whether to continue
00348  *                      gathering Locals' names
00349  *      
00350  *      Inputs:
00351  *         Parameters:
00352  *             initted        TRUE if we are gathering initted Local names.
00353  *             counter        Pointer to variable that's counting names.
00354  *         Global Variables:
00355  *             statbuf        The symbol just retrieved from the input stream.
00356  *         Local Static Variables:
00357  *             localno        Running Local-Number to be assigned
00358  *             l_d_lineno     Line # of Locals Declar'n start (for err mssg)
00359  *
00360  *      Outputs:
00361  *         Returned Value:    TRUE = Ended with initted/uninitted separator
00362  *         Local Static Variables:
00363  *             localno        Incremented for each Local name declared
00364  *             local_names    Enter the new locals' names into the Vocabulary.
00365  *                            Numeric field is assigned local number.
00366  *
00367  *      Error Detection:
00368  *          A Local-name that duplicates an existing name is an ERROR.
00369  *              Especially if that name is <Semicolon> and the flag
00370  *              called  ibm_locals_legacy_separator  was not set.
00371  *          Issue an Error if close-curly-brace terminator is not found,
00372  *              or if imbedded comment is not terminated, before end of file.
00373  *          If the Separator is found a second-or-more time, issue an Error
00374  *              and continue collecting uninitted Local names.
00375  *
00376  *      Revision History:
00377  *      Updated Thu, 24 Mar 2005 by David L. Paktor
00378  *          Allow comments to be interspersed among the declarations.
00379  *          Error-check duplicate Local-name.
00380  *      Updated Wed, 30 Mar 2005 by David L. Paktor
00381  *          Warning when name length exceeds ANSI-specified max (31 chars). 
00382  *      Updated Thu, 07 Jul 2005 by David L. Paktor
00383  *          Protect against PC pointer-overrun due to unterminated
00384  *              comment or declaration.
00385  *          Error-check for numbers.
00386  *          No name-length check; doesn't go into FCode anyway.
00387  *
00388  **************************************************************************** */
00389 
00390 static bool gather_locals( bool initted, int *counter )
00391 {
00392     signed long wlen;
00393     bool retval = FALSE;
00394 
00395     while ( TRUE )
00396     {
00397         wlen = get_word();
00398 
00399         if ( wlen <= 0 )
00400         {
00401             warn_unterm( TKERROR, "Local-Values Declaration", l_d_lineno);
00402             break;
00403         }
00404 
00405         /*  Allow comments to be interspersed among the declarations.  */
00406         if ( filter_comments( statbuf) )
00407         {
00408             /*  Unterminated and Multi-line checking already handled   */
00409             continue;
00410         }
00411         /*  Is this the terminator or the separator? */
00412         if ( wlen == 1 )    /*  Maybe   */
00413         {
00414             /*  Check for separator   */
00415             if (locals_separator( statbuf[0] ) )
00416             {
00417                 /*  If gathering initted Local names, separator is legit  */
00418                 if ( initted )
00419                 {
00420                     retval = TRUE;
00421                     break;
00422                 }else{
00423                     tokenization_error ( TKERROR,
00424                         "Excess separator -- %s -- found "
00425                             "in Local-Values declaration", statbuf);
00426                     in_last_colon();
00427                     continue;
00428                 }
00429             }
00430             /*  Haven't found the separator.  Check for the terminator  */
00431             if ( statbuf[0] == '}' )
00432             {
00433                 break;
00434             }
00435         }
00436         /*  It was not the terminator or the separator  */
00437         {
00438             long tmp;
00439             char *where_pt1;  char *where_pt2;
00440             /*  Error-check for duplicated names  */
00441             if ( word_exists ( statbuf, &where_pt1, &where_pt2 ) )
00442             {
00443                 tokenization_error ( TKERROR, "Cannot declare %s "
00444                     "as a Local-Name; it's already defined %s%s",
00445                         statbuf, where_pt1, where_pt2 );
00446                 show_node_start();
00447                 continue;
00448             }
00449             /*  Error-check for numbers.  */
00450             if ( get_number(&tmp) )
00451             {
00452                 tokenization_error ( TKERROR, "Cannot declare %s "
00453                     "as a Local-Name; it's a number.\n", statbuf );
00454                 continue;
00455             }
00456 
00457             /*  We've got a valid new local-name    */
00458             /*  Don't need to check name length; it won't go into the FCode  */
00459 
00460             /*  Increment our counting-v'ble  */
00461             *counter += 1;
00462 
00463             /*  Define our new local-name in the Locals' vocabulary  */
00464             add_local( localno, statbuf );
00465 
00466             /*  Bump the running Local-Number  */
00467             localno++;
00468 
00469         }
00470     }
00471     return ( retval );
00472 }
00473 
00474 
00475 /* **************************************************************************
00476  *
00477  *      Function name:  activate_locals
00478  *      Synopsis:       Compile-in the call to  {push-locals}  that
00479  *                      the new definition under construction will need,
00480  *                      now that the Locals have been declared.
00481  *      
00482  *      Inputs:
00483  *         Parameters:                NONE
00484  *         Global Variables:
00485  *             num_ilocals              First argument to  {push-locals}
00486  *             num_ulocals              Second argument to  {push-locals}
00487  *             push_locals              Name of  {push-locals}  routine.
00488  *
00489  *      Outputs:
00490  *         Returned Value:            NONE
00491  *         Local Static Variables:
00492  *             eval_buf               Phrase constructed here; will become
00493  *                                        new Source Input Buffer, temporarily
00494  *
00495  *      Error Detection:
00496  *          If the Local Values Support FCode source-file was not
00497  *              FLOADed into the user's tokenization source, then
00498  *              the function  {push-locals}  will be an "unknown name".
00499  *
00500  *      Process Explanation:
00501  *          We are going to generate a string of the form:
00502  *                  " #ilocals #ulocals {push-locals}"
00503  *              and pass it to the Parser for evaluation.
00504  *          The string-buffer may be local, but it must be stable.
00505  *
00506  *      Question under consideration.:
00507  *          Do we want to check if  {push-locals}  is an unknown name,
00508  *              and give the user a hint of what's needed?  And, if so,
00509  *              do we do it only once, or every time?
00510  *
00511  **************************************************************************** */
00512 
00513 static void activate_locals( void )
00514 {
00515     char ilocals_buf[10];
00516     char ulocals_buf[10];
00517      
00518     int_to_str(num_ilocals, ilocals_buf ); 
00519     int_to_str(num_ulocals, ulocals_buf );
00520     sprintf( eval_buf,"%s %s %s",ilocals_buf, ulocals_buf, push_locals);
00521     eval_string( eval_buf);
00522 }
00523 
00524 /* **************************************************************************
00525  *
00526  *      Function name:  error_check_locals
00527  *      Synopsis:       Indicate whether Locals declaration is erronious
00528  *      
00529  *      Inputs:
00530  *         Parameters:     NONE
00531  *         Global Variables:
00532  *             incolon             TRUE if colon def'n is in effect.
00533  *             opc                 FCode Output buffer Position Counter
00534  *             lastcolon           Value of opc when Colon def'n was started
00535  *
00536  *      Outputs:
00537  *         Returned Value:         TRUE if found errors severe enough to
00538  *                                     preclude further processing of Decl'n
00539  *
00540  *      Errors Detected:
00541  *           Colon definition not in effect.  ERROR and return TRUE.
00542  *           Locals declaration inside body of colon-definition (i.e., after
00543  *                something has been compiled-in to it) is potentially risky,
00544  *                but may be valid, and is a part of legacy practice.  It
00545  *                will not be treated as an outright ERROR, but it will
00546  *                generate a WARNING...
00547  *           Multiple locals declarations inside a single colon-definition
00548  *                are completely disallowed.  ERROR and return TRUE.
00549  *           Locals declaration inside a control-structure is prohibited.
00550  *                Generate an ERROR, but return FALSE to allow processing
00551  *                of the declaration to continue.
00552  *
00553  **************************************************************************** */
00554 
00555 /*  The value of  lastcolon  when Locals Declaration is made.
00556  *      If it's the same, that detects multiple locals declaration attempt.
00557  */
00558 static int last_local_colon = 0;
00559 
00560 static bool error_check_locals ( void )
00561 {
00562     bool retval = FALSE;
00563     
00564     if ( ! incolon )
00565     {
00566         tokenization_error ( TKERROR,
00567             "Can only declare Locals inside of a Colon-definition.\n");
00568         retval = TRUE;
00569     } else {
00570         if ( last_local_colon == lastcolon )
00571         {
00572             tokenization_error ( TKERROR, "Excess Locals Declaration");
00573             in_last_colon();
00574             retval = TRUE;
00575         }else{
00576             last_local_colon = lastcolon;
00577             if ( opc > lastcolon )
00578             {
00579                 tokenization_error ( WARNING,
00580                     "Declaring Locals after the body of a Colon-definition "
00581                     "has begun is not recommended.\n");
00582             }
00583             announce_control_structs( TKERROR,
00584                 "Local-Values Declaration encountered",
00585                     last_colon_abs_token_no);
00586         }
00587     }
00588     return ( retval );
00589 }
00590 
00591 /* **************************************************************************
00592  *
00593  *      Function name:  declare_locals
00594  *      Synopsis:       Process (or Ignore) the Declaration of Locals,
00595  *                          upon encountering Curly-brace ( {  )
00596  *      
00597  *      Inputs:
00598  *         Parameters:
00599  *             ignoring            TRUE if "Ignoring"
00600  *         Global Variables:
00601  *             statbuf             Next symbol to process.
00602  *             lineno              Current Line Number in Input File
00603  *             report_multiline    FALSE to suspend multiline warning
00604  *
00605  *      Outputs:
00606  *         Returned Value:         NONE
00607  *         Global Variables:
00608  *             statbuf             Advanced to end of Locals Declaration.
00609  *             pc                  Bumped past the close-curly-brace
00610  *         Local Static Variables:
00611  *             localno             Init'd, then updated by gather_locals()
00612  *             l_d_lineno          Line Number of start of Locals Declaration
00613  *
00614  *      Error Detection:
00615  *          See  error_check_locals()
00616  *              After Error messages, will bypass further processing until the
00617  *                  terminating close-curly-brace of a Locals Declaration.
00618  *                  If the terminating close-curly-brace missing under those
00619  *                  circumstances, issue an Error
00620  *              If terminating close-curly-brace is missing when the Locals
00621  *                  Declaration is otherwise valid, gather_locals() will
00622  *                  detect and report the Error.
00623  *              Warning if multiline declaration.  Because embedded comments
00624  *                  may also supppress the multiline warning, we need to save
00625  *                  and restore the state of the report_multiline switch...
00626  *
00627  **************************************************************************** */
00628 
00629 void declare_locals ( bool ignoring)
00630 {
00631     num_ilocals = 0;
00632     num_ulocals = 0;
00633     localno = 0;
00634     
00635     l_d_lineno = lineno;
00636     bool sav_rep_mul_lin = report_multiline;
00637     report_multiline = TRUE;
00638 
00639     if ( ignoring || error_check_locals() )
00640     {
00641        if ( skip_until ( '}' ) )
00642        {
00643            warn_unterm(TKERROR,
00644                "misplaced Local-Values Declaration", l_d_lineno);
00645        }else{
00646            pc++ ;  /*  Get past the close-curly-brace  */
00647        }
00648     }else{
00649        if (gather_locals( TRUE,  &num_ilocals ) )
00650        {
00651            gather_locals( FALSE, &num_ulocals );
00652        }
00653     }
00654 
00655     /*  If PC has reached the END,  gather_locals()  will
00656      *      have already issued an "unterminated" Error;
00657      *      a "multiline" warning would be redundant
00658      *      repetitive, unnecessary, excessive, unaesthetic
00659      *      and -- did I already mention? -- redundant.
00660      */
00661     if ( pc < end )
00662     {
00663         report_multiline = sav_rep_mul_lin;
00664         warn_if_multiline( "Local-Values declaration", l_d_lineno);
00665     }
00666 
00667     /*  Don't do anything if no Locals were declared    */
00668     /*  This could happen if the  {  }  field is empty  */
00669     if ( localno != 0 )
00670     {
00671         activate_locals();
00672     }
00673 }
00674 
00675 /* **************************************************************************
00676  *
00677  *      Function name:  handle_local
00678  *      Synopsis:       Process the given name as a Local Name;
00679  *                      indicate if it was a valid Local Name.
00680  *
00681  *      Inputs:
00682  *         Parameters:
00683  *             lname                The "Local" name for which to look
00684  *         Local Static Variables:  
00685  *             local_names          The vocabulary for Local names
00686  *
00687  *      Outputs:
00688  *         Returned Value:          TRUE if the name is a valid "Local Name"
00689  *
00690  **************************************************************************** */
00691 
00692 static bool handle_local( char *lname)
00693 {
00694     bool retval = handle_tic_vocab( lname, local_names );
00695     return ( retval ) ;
00696 }
00697 
00698 /* **************************************************************************
00699  *
00700  *      Function name:  lookup_local
00701  *      Synopsis:       Return a pointer to the data-structure of the named
00702  *                      word, only if it was a valid Local Name.
00703  *
00704  *      Inputs:
00705  *         Parameters:
00706  *             lname                The "Local" name for which to look
00707  *         Local Static Variables:  
00708  *             local_names          The vocabulary for Local names
00709  *
00710  *      Outputs:
00711  *         Returned Value:          Pointer to the data-structure, or
00712  *                                      NULL if not found.
00713  *
00714  **************************************************************************** */
00715 
00716 tic_hdr_t *lookup_local( char *lname)
00717 {
00718     tic_hdr_t *retval = lookup_tic_entry( lname, local_names );
00719     return ( retval ) ;
00720 }
00721 
00722 
00723 /* **************************************************************************
00724  *
00725  *      Function name:  create_local_alias
00726  *      Synopsis:       Create an alias in the "Local Names" Vocabulary
00727  *
00728  *      Associated FORTH word:              ALIAS
00729  *
00730  *      Inputs:
00731  *         Parameters:
00732  *             old_name             Name of existing entry
00733  *             new_name             New name for which to create an entry
00734  *
00735  *      Outputs:
00736  *         Returned Value:          TRUE if  old_name  found in "Locals" vocab
00737  *         Global Variables:    
00738  *             local_names          Will point to the new entry
00739  *         Memory Allocated:
00740  *             Memory for the new entry, by the support routine
00741  *         When Freed?
00742  *             When  forget_locals()  routine frees up all memory
00743  *                 allocations in the "Local Names" Vocabulary.
00744  *
00745  **************************************************************************** */
00746 
00747 bool create_local_alias(char *new_name, char *old_name)
00748 {
00749     bool retval = create_tic_alias( new_name, old_name, &local_names );
00750     return ( retval );
00751 }
00752 
00753 /* **************************************************************************
00754  *
00755  *      Function name:  exists_as_local
00756  *      Synopsis:       Simply confirm whether a given name exists
00757  *                      within the Locals vocabulary.
00758  *      
00759  *      Inputs:
00760  *         Parameters:
00761  *             stat_name          Name to look up
00762  *
00763  *      Outputs:
00764  *         Returned Value:        TRUE if stat_name was a Local
00765  *
00766  **************************************************************************** */
00767 
00768 bool exists_as_local( char *stat_name )
00769 {
00770     bool retval = exists_in_tic_vocab(stat_name, local_names );
00771     return ( retval );
00772 }
00773 
00774 
00775 /* **************************************************************************
00776  *
00777  *      Function name:  assign_local
00778  *      Synopsis:       Process the "Assign to a Local" operator ( -> )
00779  *      
00780  *      Inputs:
00781  *         Parameters:             NONE
00782  *         Global Variables:
00783  *             statbuf          Next symbol to process
00784  *             pc               Input-source Scanning pointer
00785  *             lineno           Input-source Line Number. Used for Err Mssg.
00786  *
00787  *      Outputs:
00788  *         Returned Value:         NONE
00789  *         Global Variables:
00790  *             statbuf          Advanced to next symbol
00791  *             pc               Advanced; may be unchanged if error.
00792  *             lineno           Advanced; may be unchanged if error
00793  *             local_op         Will be set to Store and then reset to Fetch.
00794  *         Global Behavior:
00795  *             Construct a phrase and pass it to the Tokenizer.
00796  *
00797  *      Error Detection:
00798  *          If next symbol is not a Local name, print ERROR message    
00799  *              and restore  pc  so that the next symbol will be    
00800  *              processed by ordinary means.
00801  *          In the extremely unlikely case that -> is last symbol in  
00802  *              the source-file, report an ERROR.
00803  *
00804  *      Process Explanation:
00805  *          Save the PC.
00806  *          Get the next symbol; check for end-of-file.
00807  *          Set Local Operator ( local_op ) to "Store", to prepare to apply it.
00808  *          Pass the next symbol to  handle_local() .
00809  *          If  handle_local()  failed to find the name, you have
00810  *              detected an error; restore  pc .
00811  *          Otherwise, you have invoked the local and applied "Store" to it.
00812  *          At the end, reset  local_op  to "Fetch".
00813  *
00814  **************************************************************************** */
00815 
00816 void assign_local ( void )
00817 {
00818     signed long wlen;
00819     bool is_okay;
00820     u8 *savd_pc = pc;
00821     unsigned int savd_lineno = lineno;
00822 
00823     wlen = get_word();
00824 
00825         if ( wlen <= 0 )
00826         {
00827             warn_unterm(TKERROR, "Locals Assignment", lineno);
00828             return;
00829         }
00830 
00831     local_op = "!";   /*  Set to Store  */
00832 
00833     is_okay = handle_local( statbuf);
00834     if( INVERSE(is_okay)  )
00835     {
00836         tokenization_error ( TKERROR,
00837             "Cannot apply -> to %s, only to a declared Local.\n", statbuf );
00838         pc = savd_pc;
00839         lineno = savd_lineno;
00840     }
00841     local_op = "@";   /*  Reset to Fetch  */
00842 }
00843 
00844 /* **************************************************************************
00845  *
00846  *      Function name:  finish_locals
00847  *      Synopsis:       Compile-in the call to  {pop-locals}  that the
00848  *                      new definition under construction will need
00849  *                      when it's about to complete execution, i.e.,
00850  *                      before an EXIT or a SemiColon.  But only if the
00851  *                      current definition under construction is using Locals.
00852  *      
00853  *      Inputs:
00854  *         Parameters:       NONE
00855  *             
00856  *         Local Static Variables:
00857  *             localno            Total # of Locals.
00858  *                                    Both a param to  {pop-locals} 
00859  *                                    and an indicator that Locals are in use.
00860  *             pop_locals         Name of  {pop-locals}  routine.
00861  *
00862  *      Outputs:
00863  *         Returned Value:        NONE
00864  *         Local Static Variables:
00865  *             eval_buf            Phrase constructed here; will become new
00866  *                                     Source Input Buffer, temporarily
00867  *
00868  *      Error Detection:
00869  *          If the Local Values Support FCode source-file was not
00870  *              FLOADed into the user's tokenization source, then
00871  *              the function  {pop-locals}  will be an "unknown name".
00872  *
00873  *      Revision History:
00874  *          Updated Fri, 24 Feb 2006 by David L. Paktor
00875  *              The eval_string() routine no longer calls its own
00876  *                  instance of  tokenize() .  In order to make a
00877  *                  smooth transition between the processing the
00878  *                  internally-generated string and the resumption
00879  *                  of processing the source file, it simply sets
00880  *                  up the string to be processed next.
00881  *              In this case, however, we need to have the string
00882  *                  processed right away, as the calling routine
00883  *                  emits a token that must follow those generated
00884  *                  by this.
00885  *              Fortunately, we know the exact contents of the string.
00886  *                  Two calls to tokenize_one_word() will satisfy the
00887  *                  requirement.
00888  *
00889  **************************************************************************** */
00890 
00891 void finish_locals ( void )
00892 {
00893      /*    Don't do anything if Locals are not in use    */
00894     if ( localno > 0 )
00895     {
00896         char nlocals_buf[10];
00897      
00898         int_to_str(localno, nlocals_buf ); 
00899         sprintf( eval_buf,"%s %s",nlocals_buf, pop_locals);
00900         eval_string( eval_buf);
00901         tokenize_one_word( get_word() );
00902         tokenize_one_word( get_word() );
00903     }
00904 }
00905 
00906 /* **************************************************************************
00907  *
00908  *      Function name:  forget_locals
00909  *      Synopsis:       Remove the Locals' names from the special Vocabulary
00910  *                      free-up their allocated memory, and reset the Locals'
00911  *                      counters (which are also the indication that Locals
00912  *                      are in use).  This is done at the time a SemiColon
00913  *                      is processed.  But only if the current definition
00914  *                      under construction is using Locals.
00915  *      
00916  *      Inputs:
00917  *         Parameters:              NONE
00918  *         Local Static Variables:
00919  *             local_names          The vocabulary for new Local names
00920  *
00921  *      Outputs:
00922  *         Returned Value:          NONE
00923  *         Local Static Variables:
00924  *             local_names          Emptied and pointing at NULL.
00925  *             num_ilocals          Reset to zero
00926  *             num_ulocals              ditto
00927  *             localno                  ditto
00928  *         Memory Freed
00929  *             All memory allocations in the "Local Names" Vocabulary.
00930  *
00931  **************************************************************************** */
00932 
00933 void forget_locals ( void )
00934 {
00935      /*    Don't do anything if Locals are not in use    */
00936     if ( localno != 0 )
00937     {
00938         reset_tic_vocab( &local_names, NULL ) ;
00939 
00940         num_ilocals = 0;
00941         num_ulocals = 0;
00942         localno = 0;
00943     }
00944 }

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