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

conditl.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  *      Conditional-Compilation support for Tokenizer
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  *          init_conditionals_vocab    Initialize the "Conditionals" Vocabulary.
00038  *          handle_conditional         Confirm whether a given name is a valid
00039  *                                         Conditional, and, if so, perform its
00040  *                                         function and return an indication.
00041  *          create_conditional_alias   Add an alias to "Conditionals" vocab
00042  *          reset_conditionals         Reset the "Conditionals" Vocabulary
00043  *                                         to its "Built-In" position.
00044  *
00045  **************************************************************************** */
00046 
00047 #include <stdio.h>
00048 #include <stdlib.h>
00049 
00050 #include <string.h>
00051 #include <errno.h>
00052 
00053 #include "scanner.h"
00054 #include "errhandler.h"
00055 #include "ticvocab.h"
00056 #include "conditl.h"
00057 #include "stack.h"
00058 #include "dictionary.h"
00059 #include "vocabfuncts.h"
00060 #include "usersymbols.h"
00061 #include "stream.h"
00062 #include "clflags.h"
00063 
00064 /* **************************************************************************
00065  *
00066  *          Global Variables Imported
00067  *              statbuf               Start of input-source buffer
00068  *              pc                    Input-source Scanning pointer
00069  *              iname                 Current Input File name
00070  *              lineno                Current Line Number in Input File
00071  *
00072  **************************************************************************** */
00073 
00074 /* **************************************************************************
00075  *
00076  *              Local Static Variables
00077  *      already_ignoring      Location from which to pass a parameter,
00078  *                            called "alr_ign" to the main routine.  Each
00079  *                            "Conditional" will have an associated routine
00080  *                            that takes the pointer to this as its argument.
00081  *                            The pointer to this will satisfy the "param-field"
00082  *                            requirement of a TIC_HDR-style "Vocabulary"-list.
00083  *      conditionals_tbl      TIC_HDR-style "Vocabulary"-list table, initialized
00084  *                            as an array.
00085  *      conditionals          Pointer to "tail" of Conditionals Vocabulary-list
00086  *
00087  **************************************************************************** */
00088 
00089 /* **************************************************************************
00090  *
00091  *      The lists of synonymous forms of the #ELSE and #THEN operators
00092  *          are incorporated into the "Shared Words" Vocabulary.
00093  *
00094  **************************************************************************** */
00095 
00096 /* **************************************************************************
00097  *
00098  *      Function name:  is_a_then  /  is_an_else
00099  *      Synopsis:       Indicate whether the given name is one of the
00100  *                      [then] / [else]  synonyms
00101  *      
00102  *      Inputs:
00103  *         Parameters:
00104  *             a_word                        Word to test
00105  *
00106  *      Outputs:
00107  *         Returned Value:       TRUE if the given name is one of the synonyms
00108  *
00109  *      Process Explanation:
00110  *          The functions are twins, hence bundling them like this...
00111  *
00112  **************************************************************************** */
00113 
00114 
00115 /* **************************************************************************
00116  *
00117  *      Support function:  is_a_type
00118  *      Synopsis:          Indicate whether the given name is a "shared word"
00119  *                         whose FWord Token matches the one given
00120  *
00121  *      Inputs:
00122  *         Parameters:
00123  *             tname                        Target name to look for
00124  *             fw_type                      The FWord Token type to match
00125  *
00126  *      Outputs:
00127  *         Returned Value:                  TRUE if it matches
00128  *
00129  **************************************************************************** */
00130 
00131 
00132 static bool is_a_type( char *tname, fwtoken fw_type)
00133 {
00134     bool retval = FALSE;
00135     tic_fwt_hdr_t *found = (tic_fwt_hdr_t *)lookup_shared_f_exec_word( tname );
00136     if ( found != NULL )
00137     {
00138         if ( found->pfield.fw_token == fw_type )  retval = TRUE;
00139     }
00140     return ( retval );
00141 }
00142 
00143 static bool is_a_then( char *a_word)
00144 {
00145     bool retval = is_a_type( a_word, CONDL_ENDER);
00146     return ( retval );
00147 }
00148 
00149 static bool is_an_else( char *a_word)
00150 {
00151     bool retval = is_a_type( a_word, CONDL_ELSE);
00152     return ( retval );
00153 }
00154 
00155 /* **************************************************************************
00156  *
00157  *     This is a somewhat roundabout way of passing an "already ignoring"
00158  *         parameter to the various Conditional Operators.  Each operator's
00159  *         Parameter-Field Pointer points to this.  The calling routine
00160  *         must set it (or rely on the default); the routine that handles
00161  *         nesting of Conditionals must save and restore a local copy.
00162  *
00163  **************************************************************************** */
00164 
00165 static bool already_ignoring = FALSE;
00166 
00167 /* **************************************************************************
00168  *
00169  *      Further down, will define and initialize a word-list table with
00170  *          all the functions that implement the Conditional Operators,
00171  *          and we'll link it in with the "Global Vocabulary" pointer.
00172  *
00173  *      We'll call the word-list the "Conditionals Vocabulary Table",
00174  *          and refer to its entries as the "Conditionals Vocabulary",
00175  *          even though it isn't really a separate vocabulary...
00176  * 
00177  **************************************************************************** */
00178 
00179 
00180 /* **************************************************************************
00181  *
00182  *      We also need a few common routines to pass as "Ignoring" functions
00183  *          for a few occasional words that take another word or two from
00184  *          the input stream as their arguments.  For example, if the user
00185  *          were to write:   alias [otherwise] [else]   and that were to
00186  *          occur within a segment already being ignored, we need to make
00187  *          sure that this doesn't get processed as an occurrence of  [else]
00188  *          Similarly with macro-definitions.
00189  *
00190  *      Since we are using the term "ignore a word" to mean "look it up and
00191  *          process it in Ignoring-state", we need a different term to name
00192  *          this class of routine; let's use the term "skip a word" where
00193  *          the "word" is strictly an input token, delimited by whitespace.
00194  *
00195  **************************************************************************** */
00196  
00197 /* **************************************************************************
00198  *
00199  *      Function name:  skip_a_word
00200  *      Synopsis:       Consume one input-token ("word") from the
00201  *                          Input Stream, with no processing
00202  *
00203  *      Inputs:
00204  *         Parameters:
00205  *             pfield             "Parameter field" pointer, to satisfy
00206  *                                    the calling convention, but not used
00207  *
00208  *      Outputs:
00209  *         Returned Value:        NONE
00210  *
00211  **************************************************************************** */
00212 
00213 void skip_a_word( tic_bool_param_t pfield )
00214 {
00215     /* signed long wlen = */ get_word();
00216 }
00217 
00218 /* **************************************************************************
00219  *
00220  *      Function name:  skip_a_word_in_line
00221  *      Synopsis:       Consume one input-token ("word") on the same line
00222  *                          as the current line of input, from the Input
00223  *                          Stream, with no processing.
00224  *
00225  *      Inputs:
00226  *         Parameters:
00227  *             pfield             "Parameter field" pointer, to satisfy
00228  *                                    the calling convention, but not used
00229  *         Global Variables:
00230  *             statbuf            The word being processed, which expects
00231  *                                    another word on the same line; used
00232  *                                    for the Error message.
00233  *
00234  *      Outputs:
00235  *         Returned Value:        NONE
00236  *
00237  *      Error Detection:
00238  *          get_word_in_line() will check and report if no word on same line.
00239  *
00240  **************************************************************************** */
00241 void skip_a_word_in_line( tic_bool_param_t pfield )
00242 {
00243     /* bool isokay = */ get_word_in_line( statbuf);
00244 }
00245 
00246 /* **************************************************************************
00247  *
00248  *      Function name:  skip_two_words_in_line
00249  *      Synopsis:       Consume two input-tokens ("words") on the same line
00250  *                          as the current line of input, from the Input
00251  *                          Stream, with no processing.
00252  *
00253  *      Inputs:
00254  *         Parameters:
00255  *             pfield             "Parameter field" pointer, to satisfy
00256  *                                    the calling convention, but not used
00257  *         Global Variables:
00258  *             statbuf            The word being processed, which expects
00259  *                                    two words on the same line; used for
00260  *                                    the Error message.
00261  *
00262  *      Outputs:
00263  *         Returned Value:         NONE
00264  *         Memory Allocated
00265  *             Copy of  statbuf  for Error message.
00266  *         When Freed?
00267  *             End of this routine
00268  *
00269  *      Error Detection:
00270  *          get_word_in_line() will check and report
00271  *
00272  **************************************************************************** */
00273 
00274 void skip_two_words_in_line( tic_bool_param_t pfield )
00275 {
00276     char *func_cpy = strupr( strdup( statbuf));
00277     if ( get_word_in_line( func_cpy) )
00278     {
00279         /* bool isokay = */ get_word_in_line( func_cpy);
00280     }
00281     free( func_cpy);
00282 }
00283 
00284 
00285 /* **************************************************************************
00286  *
00287  *      Function name:  ignore_one_word
00288  *      Synopsis:       Handle a word that needs processing while "ignoring"
00289  *                          Ignore the rest.
00290  *
00291  *      Inputs:
00292  *         Parameters:
00293  *             tname                  Target name to test
00294  *         Local Static Variables:
00295  *             already_ignoring       The "Already Ignoring" flag
00296  *
00297  *      Outputs:
00298  *         Returned Value:            NONE
00299  *         Global Variables:
00300  *             tic_found              Set to the TIC-entry that has just been
00301  *                                        found, in case it's a Macro.
00302  *         Local Static Variables:
00303  *             already_ignoring       Intermediately set to TRUE, then
00304  *                                        returned to former state.
00305  *
00306  *      Process Explanation:
00307  *          When we are ignoring source input, we still need to be
00308  *              sensitive to the nesting of Conditional Operators, to
00309  *              consume comments and user -message text-bodies, and to
00310  *              expand Macros, among other things.
00311  *         Rather than create special cases here for each one, we have
00312  *              added an "ign_funct" pointer to those words where this
00313  *              is relevant, including Conditional Operators. 
00314  *          Save the state of  already_ignoring  and set it to TRUE
00315  *              Execute the "Ignoring" Function associated with the entry
00316  *              Restore  already_ignoring  to its previous state.
00317  *          This is necessary if the word is a Conditional Operator and
00318  *              is harmless otherwise.
00319  *
00320  **************************************************************************** */
00321 
00322 static void ignore_one_word( char *tname)
00323 {
00324     tic_bool_hdr_t *found = (tic_bool_hdr_t *)lookup_word( tname, NULL, NULL);
00325     if ( found != NULL )
00326     {
00327         if ( found->ign_func != NULL )
00328         {
00329             bool save_already_ignoring = already_ignoring;
00330             already_ignoring = TRUE ;
00331             tic_found = (tic_hdr_t *)found;
00332 
00333             found->ign_func( found->pfield);
00334 
00335             already_ignoring = save_already_ignoring;
00336         }
00337     }
00338 }
00339 
00340 /* **************************************************************************
00341  *
00342  *      Function name:  conditionally_tokenize
00343  *      Synopsis:       Conduct tokenization while a Conditional-Tokenization
00344  *                          operator is in effect.  This is the core of the
00345  *                          implementation of Conditional-Tokenization.
00346  *      
00347  *      Inputs:
00348  *         Parameters:
00349  *             cond             The state of the Condition-Flag that the
00350  *                                  immediate Conditional Operator acquired.
00351  *                                  TRUE means "do not ignore".  Its sense
00352  *                                  is reversed when [ELSE] is encountered.
00353  *             alr_ign          TRUE means we are Already Ignoring source input,
00354  *                                  except for Conditional Operators...
00355  *         Global Variables:
00356  *             statbuf       The symbol (word) just retrieved from input stream.
00357  *             iname         Current Input File name (for Error Messages)
00358  *             lineno        Current Line Number in Input File (ditto)
00359  *             trace_conditionals   Whether to issue ADVISORY messages about
00360  *                                      the state of Conditional Tokenization.
00361  *
00362  *      Outputs:
00363  *         Returned Value:       NONE
00364  *         Global Variables:
00365  *             statbuf           Will be advanced to the balancing [THEN] op'r.
00366  *             already_ignoring  Set to TRUE if nested Conditional encountered;
00367  *                                  restored to previous state when done.
00368  *         Memory Allocated
00369  *             Duplicate of Input File name, for Error Messages
00370  *         When Freed?
00371  *             Just prior to exit from routine.
00372  *         Printout:
00373  *             ADVISORY messages, if "Trace-Conditionals" flag was selected.
00374  *             
00375  *         Global Behavior:
00376  *            Tokenization happens, or inputs are ignored, as necessary.
00377  *
00378  *      Error Detection:
00379  *          End-of-file encountered on reading a word    
00380  *              ERROR.  Conditional Operators must be balanced within a file
00381  *          More than one [ELSE] encountered:  ERROR if processing segment;
00382  *              if ignoring, WARNING.
00383  *
00384  *      Process Explanation:
00385  *          Read a word at a time.   Allow Macros to "pop" transparently,
00386  *              but not source files.
00387  *          If the word is a [THEN], we are done.
00388  *          If the word is an [ELSE], then, if we are not Already Ignoring,
00389  *                  invert the sense of whether we are ignoring source input. 
00390  *              If this is not the only [ELSE] in the block, report an Error
00391  *                  and disregard it.
00392  *          If we are ignoring source input, for whatever reason, we still
00393  *              need to be sensitive to the nesting of Conditional Operators:
00394  *              If the word is a Conditional Operator, activate it with the
00395  *                  "Already Ignoring" parameter set to TRUE; doing so will
00396  *                  result in a nested call to this routine.
00397  *              Otherwise, i.e., if the word is not a Conditional Operator,
00398  *                  we may still need to process it in "ignoring" mode:
00399  *                  we need, for instance, to consume strings, comments
00400  *                  and the text-bodies of user-messages in their entirety,
00401  *                  in case there is a reference to an [ELSE] or suchlike.
00402  *                  The words that need processing while "ignoring" will
00403  *                  have a valid function-pointer in their ign_func field.
00404  *          If we are not ignoring source input, pass the word along to the
00405  *              tokenize_one_word routine and process it.  If the word is
00406  *              a Conditional Operator, it will be handled in the context
00407  *              of normal (i.e., non-ignored) tokenization, and, again, a
00408  *              nested call to this routine will result...
00409  *
00410  *      Revision History:
00411  *          Updated Thu, 23 Feb 2006 by David L. Paktor
00412  *              Conditional Blocks may begin with a Conditional Operator in
00413  *                  a Macro definition and do not need to be concluded in
00414  *                  the body of the Macro.
00415  *          Updated Fri, 10 Mar 2006 by David L. Paktor
00416  *              Recognize aliased string, comment and user-message delimiters
00417  *                  in a segment that is being ignored; Conditional Operators
00418  *                  within the text body of any of these are always consumed
00419  *                  and never unintentionally processed.  Macros are always
00420  *                  processed; Conditional Operators inside a Macro body are
00421  *                  recognized, so the Macro continues to function as intended.
00422  *
00423  **************************************************************************** */
00424 
00425 static void conditionally_tokenize( bool cond, bool alr_ign )
00426 {
00427     
00428     signed long wlen;
00429 
00430     /*  Note:  The following variables *must* remain within
00431      *      the scope of this routine; a distinct instance
00432      *      is needed each time this routine is re-entered
00433      *     (aka "a nested call").
00434      */
00435     bool ignoring;
00436     bool first_else = TRUE;  /*  The "else" we see is the first.  */
00437     bool not_done = TRUE;
00438     unsigned int cond_strt_lineno = lineno;
00439     char *cond_strt_ifile_nam = strdup( iname);
00440 
00441     ignoring = BOOLVAL( ( cond == FALSE ) || ( alr_ign != FALSE ) );
00442 
00443     if ( trace_conditionals )
00444     {
00445         char *cond_val = cond ? "True" : "False" ;
00446         char *cond_junct = alr_ign ? ", but Already " : "; ";
00447         char *processg = ignoring ? "Ignoring" : "Processing" ;
00448         tokenization_error( INFO,
00449             "Tokenization-Condition is %s%s%s.\n",
00450                 cond_val, cond_junct, processg);
00451     }
00452 
00453     while ( not_done )
00454     {
00455         wlen = get_word();
00456         if ( wlen == 0 )
00457         {
00458             continue;
00459         }
00460 
00461         if ( wlen < 0 )
00462         {
00463             tokenization_error( TKERROR,
00464                 "Conditional without conclusion; started");
00465             just_where_started( cond_strt_ifile_nam, cond_strt_lineno);
00466             not_done = FALSE ;
00467             continue;
00468         }
00469 
00470         if ( is_a_then ( statbuf ) )
00471         {
00472             if ( trace_conditionals )
00473             {
00474                 tokenization_error( INFO,
00475                     "Concluding Conditional");
00476                 just_started_at( cond_strt_ifile_nam, cond_strt_lineno);
00477             }
00478             not_done = FALSE ;
00479             continue;
00480         }
00481 
00482         if ( is_an_else( statbuf ) )
00483         {
00484             if ( ! alr_ign )
00485             {
00486                 if ( first_else )
00487                 {
00488                     ignoring = INVERSE( ignoring);
00489                 }
00490             }
00491 
00492             if ( ! first_else )
00493             {
00494                 int severity = ignoring ? WARNING : TKERROR ;
00495                 char *the_scop = ignoring ? "(ignored)" : "the" ;
00496                 tokenization_error( severity, "Multiple %s directives "
00497                     "within %s scope of the Conditional",
00498                          strupr(statbuf), the_scop);
00499                 just_started_at( cond_strt_ifile_nam, cond_strt_lineno);
00500             }else{
00501                 first_else = FALSE;
00502                 if ( trace_conditionals )
00503                 {
00504                     char *when_enc = alr_ign ? "While already" : "Now" ;
00505                     char *processg = alr_ign ? "ignoring" :
00506                                     ignoring ? "Ignoring" : "Processing" ;
00507                     char *enc       = alr_ign ? ", e" : ".  E" ;
00508 
00509                     tokenization_error( INFO,
00510                         "%s %s%sncountered %s belonging to Conditional",
00511                             when_enc, processg, enc, strupr(statbuf) );
00512                     just_started_at( cond_strt_ifile_nam, cond_strt_lineno);
00513                 }
00514             }
00515 
00516             continue;
00517         }
00518 
00519         /*  If we are ignoring source input, for whatever reason, we still
00520          *      need to be sensitive to the nesting of Conditional Operators
00521          *      and some other commands and directives, as indicated...
00522          */
00523         if ( ignoring )
00524         {
00525             ignore_one_word( statbuf );
00526         }else{
00527             /*  And if we're not ignoring source input, process it! */
00528             tokenize_one_word ( wlen );
00529         }
00530     }
00531 }
00532 
00533 /* **************************************************************************
00534  *
00535  *      We will now define a series of fairly simple functions that
00536  *          will be performed by the various Conditional Operators in
00537  *          the "Conditionals Vocabulary".
00538  *
00539  *      Each one takes, as an argument, the "parameter field" pointer,
00540  *          which, in all cases, points to the local  already_ignoring 
00541  *          flag, passed as an int to satisfy C's strong-typing.  The
00542  *          routine will internally recast it as a  bool .
00543  *
00544  *      If it is TRUE, the routine will bypass the test for its particular
00545  *          type of condition, and go directly to  conditionally_tokenize
00546  *          In most cases, testing for the condition would be harmless,
00547  *          but in the case where the test is for an item on the stack,
00548  *          it would be harmful because the sequence that put the item
00549  *          on the stack was also being ignored...
00550  *
00551  *      We'll give these functions short prologs.  Synonyms will simply
00552  *          have separate entries in the Vocabulary Table, associated
00553  *          with the same function.
00554  *
00555  **************************************************************************** */
00556 
00557 /* **************************************************************************
00558  *
00559  *      But first, a support routine...
00560  *
00561  **************************************************************************** */
00562 
00563 /* **************************************************************************
00564  *
00565  *      Function name:  conditional_word_in_line
00566  *      Synopsis:       Common code for the types of conditionals that
00567  *                          require a word on the same line.
00568  *
00569  *      Inputs:
00570  *         Parameters:
00571  *             alr_ign         TRUE if we are already ignoring
00572  *             exist_test      TRUE if the test is for "existence" of the word
00573  *             exist_funct     Name of the function to call for the test
00574  *         Global Variables:
00575  *             stat_word       Word for which to test
00576  *
00577  *      Outputs:
00578  *         Returned Value:     NONE
00579  *
00580  *      Error Detection:
00581  *          The word in question must appear on the same line as the directive;
00582  *              the call to  get_word_in_line()  checks for that and reports.
00583  *          If the word did not appear on the same line, then the directive
00584  *              will be disregarded and processing will proceed as though it
00585  *              were absent.  This may lead to a cascade of errors...
00586  *
00587  *      Process Explanation:
00588  *          The supplied  exist_funct()  will test for the existence of
00589  *              the word, now read into  statbuf , in the appropriate 
00590  *              venue.
00591  *          We only call the  exist_funct()  if we are not already ignoring.
00592  *
00593  **************************************************************************** */
00594 
00595 static void conditional_word_in_line( bool alr_ign,
00596                                           bool exist_test,
00597                                               bool (*exist_funct)() )
00598 {
00599     if ( get_word_in_line( statbuf) )
00600     {
00601         bool cond = FALSE;
00602         if ( INVERSE( alr_ign) )
00603         {
00604             bool exists = exist_funct( statbuf);
00605             cond = BOOLVAL( exists == exist_test);
00606         }
00607         conditionally_tokenize( cond, alr_ign );
00608     }
00609 }
00610 
00611 
00612 /* **************************************************************************
00613  *
00614  *      Function name:  if_exists
00615  *      Synopsis:       Test for existence of a given word, in the dictionary.
00616  *
00617  *      Associated Tokenizer directives:        [ifexist]
00618  *                                              #ifexist
00619  *                                              [#ifexist]
00620  *                                              [ifexists]
00621  *                                              #ifexists
00622  *                                              [#ifexists]
00623  *        (Note variants with and without final 's'
00624  *
00625  **************************************************************************** */
00626 
00627 static void if_exists( tic_param_t pfield )
00628 {
00629     bool alr_ign = *pfield.bool_ptr;
00630     conditional_word_in_line( alr_ign, TRUE, exists_in_current );
00631 }
00632 
00633 /* **************************************************************************
00634  *
00635  *      Function name:  if_not_exist
00636  *      Synopsis:       Test for Non-existence, in the appropriate dictionary,)
00637  *                          of the given word.
00638  *
00639  *      Associated Tokenizer directives:        [ifnexist]
00640  *                                              #ifnexist
00641  *                                              [#ifnexist]
00642  *        (Note:  Variants with final 's' didn't make sense here.)
00643  *
00644  *      Explanatory Notes:
00645  *          This is the exact inverse of  if_exists
00646  *
00647  **************************************************************************** */
00648 
00649 static void if_not_exist( tic_bool_param_t pfield )
00650 {
00651     bool alr_ign = *pfield.bool_ptr;
00652     conditional_word_in_line( alr_ign, FALSE, exists_in_current );
00653 }
00654 
00655 /* **************************************************************************
00656  *
00657  *      Function name:  if_defined
00658  *      Synopsis:       Test for existence of a user-defined symbol
00659  *
00660  *      Associated Tokenizer directives:        [ifdef]
00661  *                                              #ifdef
00662  *                                              [#ifdef]
00663  *
00664  **************************************************************************** */
00665 
00666 static void if_defined( tic_bool_param_t pfield )
00667 {
00668     bool alr_ign = *pfield.bool_ptr;
00669     conditional_word_in_line( alr_ign, TRUE, exists_as_user_symbol );
00670 }
00671 
00672 /* **************************************************************************
00673  *
00674  *      Function name:  if_not_defined
00675  *      Synopsis:       Test for NON-existence of a user-defined symbol
00676  *
00677  *      Associated Tokenizer directives:        [ifndef]
00678  *                                              #ifndef
00679  *                                              [#ifndef]
00680  *
00681  **************************************************************************** */
00682 
00683 static void if_not_defined( tic_bool_param_t pfield )
00684 {
00685     bool alr_ign = *pfield.bool_ptr;
00686     conditional_word_in_line( alr_ign, FALSE, exists_as_user_symbol );
00687 }
00688 
00689 
00690 /* **************************************************************************
00691  *
00692  *      Function name:  if_from_stack
00693  *      Synopsis:       Test the number on top of the run-time stack
00694  *
00695  *      Associated Tokenizer directive:         [if]
00696  *
00697  *      Process Explanation:
00698  *          When we are ignoring source input, and we still need to be
00699  *              sensitive to the nesting of Conditional Operators, we
00700  *              will not consume the number on the stack; this function
00701  *              is after all, being ignored and should not perform any
00702  *              action other than making sure the [else]s and [then]s
00703  *              get properly counted.
00704  *
00705  **************************************************************************** */
00706 
00707 static void if_from_stack( tic_bool_param_t pfield )
00708 {
00709     bool alr_ign = *pfield.bool_ptr;
00710     bool cond = FALSE;
00711 
00712     if ( ! alr_ign )
00713     {
00714         long num = dpop();
00715         if (num != 0)
00716         {
00717             cond = TRUE;
00718         }
00719     }
00720     conditionally_tokenize( cond, alr_ign );
00721 }
00722 
00723 /*  For future functions, use  conditl.BlankTemplate.c  */
00724 
00725 /* **************************************************************************
00726  *
00727  *      Here, at long last, we define and initialize the structure containing
00728  *          all the functions we support for Conditional Operators.
00729  *
00730  **************************************************************************** */
00731 
00732 #define ADD_CONDL(str, func )   BUILTIN_BOOL_TIC(str, func, already_ignoring )
00733 
00734 static tic_bool_hdr_t conditionals_vocab_tbl[] = {
00735     ADD_CONDL ("[ifexist]"   , if_exists      ) ,
00736     ADD_CONDL ("[ifexists]"  , if_exists      ) ,
00737     ADD_CONDL ("#ifexist"    , if_exists      ) ,
00738     ADD_CONDL ("#ifexists"   , if_exists      ) ,
00739     ADD_CONDL ("[#ifexist]"  , if_exists      ) ,
00740     ADD_CONDL ("[#ifexists]" , if_exists      ) ,
00741     ADD_CONDL ("[ifnexist]"  , if_not_exist   ) ,
00742     ADD_CONDL ("#ifnexist"   , if_not_exist   ) ,
00743     ADD_CONDL ("[#ifnexist]" , if_not_exist   ) ,
00744     ADD_CONDL ("[ifdef]"     , if_defined     ) ,
00745     ADD_CONDL ("#ifdef"      , if_defined     ) ,
00746     ADD_CONDL ("[#ifdef]"    , if_defined     ) ,
00747     ADD_CONDL ("[ifndef]"    , if_not_defined ) ,
00748     ADD_CONDL ("#ifndef"     , if_not_defined ) ,
00749     ADD_CONDL ("[#ifndef]"   , if_not_defined ) ,
00750     ADD_CONDL ("[if]"        , if_from_stack  )
00751 };
00752 
00753 
00754 /* **************************************************************************
00755  *
00756  *      Function name:  init_conditionals_vocab
00757  *      Synopsis:       Initialize the "Conditionals Vocabulary Table"
00758  *                          link-pointers dynamically, and link it in
00759  *                          with the given ("Global") Vocabulary pointer.
00760  *
00761  **************************************************************************** */
00762 
00763 void init_conditionals_vocab( tic_hdr_t **tic_vocab_ptr )
00764 {
00765     static const int conditionals_vocab_max_indx =
00766          sizeof(conditionals_vocab_tbl)/sizeof(tic_bool_hdr_t);
00767 
00768     init_tic_vocab( (tic_hdr_t *)conditionals_vocab_tbl,
00769                         conditionals_vocab_max_indx,
00770                             tic_vocab_ptr );
00771 }
00772 

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