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