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

macros.c

Go to the documentation of this file.
00001 /*
00002  *                     OpenBIOS - free your system!
00003  *                         ( FCode tokenizer )
00004  *
00005  *  macros.c - macro initialization and functions.
00006  *
00007  *  This program is part of a free implementation of the IEEE 1275-1994
00008  *  Standard for Boot (Initialization Configuration) Firmware.
00009  *
00010  *  Copyright (C) 2001-2005 by Stefan Reinauer <stepan@openbios.org>
00011  *
00012  *  This program is free software; you can redistribute it and/or modify
00013  *  it under the terms of the GNU General Public License as published by
00014  *  the Free Software Foundation; version 2 of the License.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public License
00022  *  along with this program; if not, write to the Free Software
00023  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
00024  *
00025  */
00026 
00027 /* **************************************************************************
00028  *         Modifications made in 2005 by IBM Corporation
00029  *      (C) Copyright 2005 IBM Corporation.  All Rights Reserved.
00030  *      Modifications Author:  David L. Paktor    dlpaktor@us.ibm.com
00031  **************************************************************************** */
00032 
00033 /* **************************************************************************
00034  *
00035  *      Support functions for the  MACROS  vocabulary, implemented
00036  *          as a TIC-Headerlist type of data structure, and linked in
00037  *          to the Global Vocabulary.
00038  *
00039  **************************************************************************** */
00040 
00041 /* **************************************************************************
00042  *
00043  *      Functions Exported:
00044  *          init_macros             Initialize the link-pointers in the
00045  *                                      initial "Built-In" portion of
00046  *                                      the  macros  vocabulary
00047  *          add_user_macro          Add an entry to the  macros  vocabulary
00048  *          skip_user_macro         Consume a Macro definition if Ignoring
00049  *
00050  **************************************************************************** */
00051 
00052 #include <stdio.h>
00053 #include <stdlib.h>
00054 #if defined(__linux__) && ! defined(__USE_BSD)
00055 #define __USE_BSD
00056 #endif
00057 #include <string.h>
00058 #include <errno.h>
00059 
00060 #include "errhandler.h"
00061 #include "ticvocab.h"
00062 #include "stream.h"
00063 #include "scanner.h"
00064 #include "dictionary.h"
00065 #include "devnode.h"
00066 #include "macros.h"
00067 
00068 /* **************************************************************************
00069  *
00070  *              Internal Static Variables
00071  *          macros_tbl                    Initial array of "Built-In" Macros
00072  *          number_of_builtin_macros      Number of "Built-In" Macro entries.
00073  *
00074  **************************************************************************** */
00075 
00076 /* **************************************************************************
00077  *
00078  *      Revision History:
00079  *          Thu, 27 Oct 2005 by David L. Paktor
00080  *              Identify the macros that resolve to a single word.
00081  *              Remove them from here and enter them as synonymous entries
00082  *                  in the Tokens, Specials or Shared-words vocabularies.
00083  *          Wed, 30 Nov 2005 by David L. Paktor
00084  *              Allow user-definition of macros.
00085  *          Fri, 06 Jan 2006 by David L. Paktor
00086  *              Re-define the Macros as a TIC-Headerlist, and make them
00087  *                  part of the Global Vocabulary
00088  *
00089  **************************************************************************** */
00090 
00091 
00092 
00093 /* **************************************************************************
00094  *
00095  *      Function name:  macro_recursion_error
00096  *      Synopsis:       Function that will go temporarily into the FUNCT
00097  *                      field of a Macro's TIC-entry, to protect against
00098  *                      recursive macro invocations.
00099  *
00100  *      Inputs:
00101  *         Parameters:
00102  *             pfield              Param field of the TIC-entry; unused.
00103  *         Global Variables:
00104  *             statbuf             The name being invoked erroneously.
00105  *
00106  *      Outputs:
00107  *         Returned Value:         NONE
00108  *         Printout:
00109  *             Error Message.
00110  *
00111  *      Error Detection:
00112  *          If this function is called, it is an ERROR
00113  *
00114  *      Extraneous Remarks:
00115  *          This Tokenizer does not have the early-binding characterisitics
00116  *              of FORTH; its Macros are strings, evaluated when invoked
00117  *              rather than when they are defined.  A reference to a name
00118  *              that matches the macro would cause recursion, possibly
00119  *              infinite.  We will not allow that.
00120  *
00121  **************************************************************************** */
00122 
00123 static void macro_recursion_error( tic_param_t pfield)
00124 {
00125     tokenization_error( TKERROR,
00126         "Recursive invocation of macro named %s\n", statbuf);
00127 }
00128 
00129 
00130 /* **************************************************************************
00131  *
00132  *      Function name:  eval_mac_string
00133  *      Synopsis:       Function that goes into FUNCT field of a TIC-entry
00134  *                      in the Macros list.  Protect against recursion.
00135  *
00136  *      Inputs:
00137  *         Parameters:
00138  *             pfield              Param field of the TIC-entry
00139  *         Global Variables:
00140  *             tic_found           The TIC-entry that has just been found;
00141  *                                     it's the entry for this Macro.
00142  *
00143  *      Outputs:
00144  *         Returned Value:         NONE
00145  *         Global Variables:
00146  *             report_multiline    Cleared to FALSE
00147  *         Global Behavior:
00148  *            The Macro will be evaluated as string input.
00149  *
00150  *      Error Detection:
00151  *          An attempt at recursion will be detected because the FUNCT field
00152  *              of the Macro entry will have been temporarily be replaced by
00153  *              macro_recursion_error()
00154  *
00155  *      Process Explanation:
00156  *          Save the address of the routine that is in the FUNCT field
00157  *               of the entry for this Macro.  (Hey!  It's this routine...)
00158  *          Replace the FUNCT field of the Macro entry with the Macro
00159  *              Recursion Error Detection routine
00160  *          Pass the address of the "resumption" routine and its argument
00161  *              (the entry for this Macro), to  push_source()
00162  *          Recast the type of the parameter field to a string
00163  *          Make it the new Input Source Buffer.
00164  *          Suspend multi-line warning; see comment in body of add_user_macro()
00165  *              The multi-line warning flag is kept by  push_source()
00166  *
00167  *      Still to be done:
00168  *          If an error is encountered during Macro evaluation, display
00169  *              supplemental information giving the name of the Macro 
00170  *              being run, and the file and line number in which it was
00171  *              defined.
00172  *          This will require changes to the way user Macros are added
00173  *              and retained, and to the way error messages are displayed.
00174  *
00175  *      Revision History:
00176  *          Updated Thu, 23 Feb 2006 by David L. Paktor
00177  *              Do not process Macros (or, for that matter, User-defined
00178  *                  Symbols or FLOADed files) with a routine that calls
00179  *                  its own instance of  tokenize(), because the Macro
00180  *                  (etc.) might contain a phrase (such as the start of
00181  *                  a conditional) that must be terminated within the
00182  *                  body of a file, thus causing an undeserved Error.
00183  *                  Instead, they need to be handled in a more sophis-
00184  *                  ticated way, tied in with the operation of get_word()
00185  *                  perhaps, that will make a smooth transition between
00186  *                  the body of the Macro and the resumption of processing
00187  *                  the source file.  The end-of-file will only be seen
00188  *                  at the end of an actual input file or when getting
00189  *                  a delimited string.
00190  *          Updated Fri, 24 Feb 2006 by David L. Paktor
00191  *              Re-integrate Recursion Error Detection with the above.
00192  *
00193  **************************************************************************** */
00194 
00195 /* **************************************************************************
00196  *
00197  *     In order to integrate Recursion Error Detection with the smooth
00198  *         transition to resumption of processing the source file, we
00199  *         need to create a "resumption" routine that will restore the
00200  *         normal behavior of the macro after it's completed, by re-
00201  *         instating the address of the normal Macro-invocation routine;
00202  *         that routine, of course, is the one that passes the address
00203  *         of the "resumption" routine to push_source().  In order to
00204  *         get around this chicken-and-egg dilemma, we will create a
00205  *         local static variable into which the address of the normal
00206  *         Macro-invocation routine will be stored.  We actually only
00207  *         need it once, but we'd rather avoid the overhead of checking,
00208  *         every time, whether it has already been set; since it's always
00209  *         the same, there's no harm in storing it every time.
00210  *
00211  **************************************************************************** */
00212 
00213 typedef void (*vfunct)();  /*  Pointer to function returning void  */
00214 static vfunct sav_mac_funct ;
00215 
00216 
00217 /* **************************************************************************
00218  *
00219  *     This "resumption" routine will be called by  pop_source()
00220  *     The parameter is the Macro dictionary-entry whose behavior
00221  *         is to be restored.
00222  *
00223  **************************************************************************** */
00224 
00225 static void mac_string_recovery( tic_hdr_t *macro_entry)
00226 {
00227     (*macro_entry).funct = sav_mac_funct;
00228     (*macro_entry).ign_func = sav_mac_funct;
00229 }
00230 
00231 /* **************************************************************************
00232  *
00233  *     The normal Macro-invocation routine, at last...
00234  *
00235  **************************************************************************** */
00236 static void eval_mac_string( tic_param_t pfield)
00237 {
00238     int mac_str_len = strlen(pfield.chr_ptr);
00239     /*  We can't use  (*tic_found).pfld_size  for the string length
00240      *      because, if this is an alias for a macro, it will be zero...
00241      */
00242     /*  We can change that by de-coupling the decision to free the
00243      *      param-field from whether pfld_size is non-zero (by intro-
00244      *      ducing yet another field into the  tic_param_t  struct),
00245      *      but we're not doing that today...
00246      */
00247 
00248     sav_mac_funct = *tic_found->funct;
00249     (*tic_found).funct = macro_recursion_error;
00250     (*tic_found).ign_func = macro_recursion_error;
00251     push_source( mac_string_recovery, tic_found, FALSE);
00252     report_multiline = FALSE;  /*  Must be done AFTER call to push_source()
00253                                 *      because  report_multiline  is part of
00254                                 *      the state that  push_source()  saves.
00255                                 */
00256     init_inbuf( pfield.chr_ptr, mac_str_len);
00257 }
00258 
00259 /* **************************************************************************
00260  *
00261  *     Builtin Macros do not need Recursion Error Detection.
00262  *     Intermediate routine to convert parameter type.
00263  *
00264  **************************************************************************** */
00265 static void eval_builtin_mac( tic_param_t pfield)
00266 {
00267     eval_string( pfield.chr_ptr);
00268 }
00269 /* **************************************************************************
00270  *
00271  *      Make a macro, because we might eliminate this layer later on.
00272  *
00273  **************************************************************************** */
00274 #define EVAL_MAC_FUNC  eval_mac_string
00275 #define BUILTIN_MAC_FUNC  eval_builtin_mac
00276 
00277 /* **************************************************************************
00278  *
00279  *      Initialization macro definition
00280  *
00281  **************************************************************************** */
00282 
00283 #define BUILTIN_MACRO(nam, alias) BUILTIN_MAC_TIC(nam, BUILTIN_MAC_FUNC, alias )
00284 
00285 static tic_mac_hdr_t macros_tbl[] = {
00286         BUILTIN_MACRO( "(.)",           "dup abs <# u#s swap sign u#>") ,
00287 
00288 
00289         BUILTIN_MACRO( "?",             "@ .") ,
00290         BUILTIN_MACRO( "1+",            "1 +") ,
00291         BUILTIN_MACRO( "1-",            "1 -") ,
00292         BUILTIN_MACRO( "2+",            "2 +") ,
00293         BUILTIN_MACRO( "2-",            "2 -") ,
00294 
00295         BUILTIN_MACRO( "accept",      "span @ -rot expect span @ swap span !") ,
00296         BUILTIN_MACRO( "allot",         "0 max 0 ?do 0 c, loop") ,
00297         BUILTIN_MACRO( "blank",         "bl fill") ,
00298         BUILTIN_MACRO( "carret",        "h# d") ,
00299         BUILTIN_MACRO( ".d",            "base @ swap h# a base ! . base !") ,
00300         BUILTIN_MACRO( "decode-bytes",  ">r over r@ + swap r@ - rot r>") ,
00301         BUILTIN_MACRO( "3drop",         "drop 2drop") ,
00302         BUILTIN_MACRO( "3dup",          "2 pick 2 pick 2 pick") ,
00303         BUILTIN_MACRO( "erase",         "0 fill") ,
00304         BUILTIN_MACRO( ".h",            "base @ swap h# 10 base ! . base !") ,
00305         BUILTIN_MACRO( "linefeed",      "h# a") ,
00306 
00307         BUILTIN_MACRO( "s.",            "(.) type space") ,
00308         BUILTIN_MACRO( "space",         "bl emit") ,
00309         BUILTIN_MACRO( "spaces",        "0 max 0 ?do space loop") ,
00310         BUILTIN_MACRO( "(u.)",          "<# u#s u#>") ,
00311         BUILTIN_MACRO( "?leave",        "if leave then"),
00312 };
00313 
00314 static const int number_of_builtin_macros =
00315          sizeof(macros_tbl)/sizeof(tic_mac_hdr_t);
00316 
00317 /* **************************************************************************
00318  *
00319  *      Function name:  init_macros
00320  *      Synopsis:       Initialize the link-pointers in the "Built-In"
00321  *                          portion of the  macros  vocabulary, dynamically.
00322  *      
00323  *      Inputs:
00324  *         Parameters:
00325  *             tic_vocab_ptr                 Pointer to Global Vocab Pointer
00326  *         Global Variables:
00327  *             macros_tbl                    Initial "Built-In" Macros array
00328  *             number_of_builtin_macros      Number of "Built-In" Macro entries
00329  *
00330  *      Outputs:
00331  *         Returned Value:          NONE
00332  *         Global Variables:    
00333  *             The link-fields of the initial "Built-In" Macros array entries
00334  *                  will be filled in.
00335  *         Supplied Pointers:
00336  *             *tic_vocab_ptr                Updated to "tail" of Macros array
00337  *
00338  **************************************************************************** */
00339 
00340 void init_macros( tic_hdr_t **tic_vocab_ptr )
00341 {
00342     init_tic_vocab( (tic_hdr_t *)macros_tbl,
00343         number_of_builtin_macros,
00344             tic_vocab_ptr );
00345 }
00346 
00347 
00348 /* **************************************************************************
00349  *
00350  *      Function name:  print_if_mac_err
00351  *      Synopsis:       Report a user-macro definition error, if so be.
00352  *
00353  *      Inputs:
00354  *         Parameters:
00355  *             failure             TRUE if error was detected
00356  *             func_cpy            STRDUP() of function name, for error message
00357  *
00358  *      Outputs:
00359  *         Returned Value:         NONE
00360  *         Memory Freed
00361  *             Contents of func_cpy, error or not.
00362  *         Printout:
00363  *             Error message, if  failure  is TRUE.
00364  *
00365  **************************************************************************** */
00366 static void print_if_mac_err( bool failure, char *func_cpy)
00367 {
00368     if ( failure )
00369     {
00370         tokenization_error( TKERROR,
00371            "%s directive expects name and definition on the same line\n",
00372                strupr(func_cpy));
00373     }
00374     free( func_cpy);
00375 }
00376 
00377 
00378 /* **************************************************************************
00379  *
00380  *      Function name:  add_user_macro
00381  *      Synopsis:       Parse input and add a user-defined Macro.
00382  *
00383  *      Associated Tokenizer directive:        [MACRO]
00384  *
00385  *      Inputs:
00386  *         Parameters:                 NONE
00387  *         Global Variables:
00388  *             pc                      Input-source Scanning pointer
00389  *             statbuf                 Symbol retrieved from input stream.
00390  *             in_tokz_esc             TRUE if in "Tokenizer-Escape" mode
00391  *             current_definitions     Pointer to Current Vocabulary pointer,
00392  *                                         either Global or Current Device-Node
00393  *             tokz_esc_vocab         "Tokenizer Escape" Vocab pointer
00394  *
00395  *      Outputs:
00396  *         Returned Value:            NONE
00397  *         Global Variables:
00398  *             *current_definitions   { One of these will point  }
00399  *             tokz_esc_vocab         {     to the new entry     }
00400  *         Memory Allocated:
00401  *             Copy of directive, for error message
00402  *             Copy of Macro name
00403  *             Copy of Macro body
00404  *             Memory for the new entry will be allocated by support routine.
00405  *         When Freed?
00406  *             Copy of directive:  When error might be reported.
00407  *             Macro name, body and entry:  Upon end of tokenization, or when
00408  *                 RESET-SYMBOLS is issued in the same mode and Scope as when
00409  *                 the Macro was defined. 
00410  *
00411  *      Error Detection:
00412  *          At least two words in the input stream are expected to be on
00413  *              the same line as the directive.  The  get_word_in_line()
00414  *              and  get_rest_of_line()  routines will check for that;
00415  *              we will issue the Error Message for either condition.
00416  *          Check if the Macro name is a duplicate; warn_if_duplicate()
00417  *              routine will issue message.
00418  *
00419  *      Process Explanation:
00420  *          We start just after the directive has been recognized.
00421  *          Get one word in line -- this is the macro name
00422  *          Get input to end of line.  This is the "body" of the macro.
00423  *          Add the Macro to the Current vocab, using support routine.
00424  *          Set the definer field to MACRO_DEF and the Function to the
00425  *              same one that's used for the built-in macros.
00426  *          User-defined Macros may need to be processed while ignoring
00427  *              (because they might include conditional-operators, etc.)
00428  *              We will set the ign_func the same as the active function.
00429  *
00430  *      To be considered:
00431  *          Do we want to do further filtration? 
00432  *              Remove comments?
00433  *              Compress whitespace?
00434  *              Allow backslash at end of line to continue to next line?
00435  *
00436  *      Extraneous Remarks:
00437  *          The scope of User-Macro definitions will follow the same rules
00438  *              as all other definition types:  if Device-Definitions are
00439  *              in effect, the scope of the new Macro definition will be
00440  *              confined to the current Device-Node; if Global-Definitions
00441  *              are in effect when it is defined, its scope will be Global;
00442  *              if it was declared when we were in "Tokenizer Escape" mode,
00443  *              then its scope will be limited to "Tokenizer Escape" mode.
00444  *
00445  **************************************************************************** */
00446 
00447 /*  This pointer is exported to this file only  */
00448 extern tic_hdr_t *tokz_esc_vocab ;
00449 
00450 void add_user_macro( void)
00451 {
00452     char *macroname;
00453     char *macrobody;
00454     bool failure = TRUE;
00455 
00456     /*  Copy of function name, for error message  */
00457     char *func_cpy = strdup( statbuf);
00458 
00459     if ( get_word_in_line( NULL ) )
00460     {
00461         /*  This is the Macro name  */
00462         macroname = strdup( statbuf);
00463 
00464         if ( INVERSE(get_rest_of_line() ) )
00465         {
00466             /*  No body on line  */
00467             free( macroname);
00468         
00469         }else{
00470             /*  We have valid Macro body on line  */
00471             int mac_body_len = 0;
00472 
00473             tic_hdr_t **target_vocab = current_definitions;
00474             if ( in_tokz_esc ) target_vocab = &tokz_esc_vocab ;
00475 
00476             warn_if_duplicate( macroname);
00477             trace_creation( MACRO_DEF, macroname);
00478 
00479             /*  Tack on a new-line, so that a remark will appear
00480              *      to be properly terminated.   This might trigger
00481              *      an undeserved multi-line warning if the Macro
00482              *      is an improperly terminated quote; we will work
00483              *      around that problem by temporarily suspending
00484              *      multi-line warnings during macro processing.
00485              */
00486             strcat( statbuf, "\n");
00487             macrobody = strdup( statbuf);
00488             mac_body_len = strlen(macrobody);
00489 
00490             add_tic_entry( macroname, EVAL_MAC_FUNC,
00491                                (TIC_P_DEFLT_TYPE)macrobody,
00492                                    MACRO_DEF, mac_body_len,
00493                                        EVAL_MAC_FUNC, target_vocab );
00494             failure = FALSE;
00495         }
00496     }
00497 
00498     print_if_mac_err( failure, func_cpy);
00499 }
00500 
00501 /* **************************************************************************
00502  *
00503  *      Function name:  skip_user_macro
00504  *      Synopsis:       Consume the text of a user-defined Macro from the
00505  *                          Input Stream, with no processing.  (Called when
00506  *                          a user-Macro definer occurs in a segment that
00507  *                          is being Ignored.)
00508  *
00509  *      Inputs:
00510  *         Parameters:
00511  *             pfield             "Parameter field" pointer, to satisfy
00512  *                                    the calling convention, but not used
00513  *         Global Variables:
00514  *             statbuf            Word currently being processed.
00515  *
00516  *      Outputs:
00517  *         Returned Value:        NONE
00518  *
00519  *      Error Detection:
00520  *          At least two words in the input stream are expected to be on
00521  *              the same line as the user-Macro definer, same as when the
00522  *              directives occurs in a segment that is not being Ignored.
00523  *              The  get_word_in_line()  and  get_rest_of_line()  routines
00524  *              will check for condition., we will issue the Error Message.
00525  *
00526  *      Process Explanation:
00527  *          We need to protect against the case of a macro-definition that
00528  *              invokes a directive that alters Conditional processing...
00529  *
00530  **************************************************************************** */
00531 void skip_user_macro( tic_bool_param_t pfield )
00532 {
00533     bool failure = TRUE;
00534     char *func_cpy = strdup( statbuf);
00535     if ( get_word_in_line( NULL ) )
00536     {
00537         if ( get_rest_of_line() )
00538         {
00539             failure = FALSE;
00540         }
00541     }
00542 
00543     print_if_mac_err( failure, func_cpy);
00544 
00545 }

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