1 : /*
2 : * OpenBIOS - free your system!
3 : * ( FCode tokenizer )
4 : *
5 : * This program is part of a free implementation of the IEEE 1275-1994
6 : * Standard for Boot (Initialization Configuration) Firmware.
7 : *
8 : * Copyright (C) 2001-2005 Stefan Reinauer, <stepan@openbios.org>
9 : *
10 : * This program is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License as published by
12 : * the Free Software Foundation; version 2 of the License.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program; if not, write to the Free Software
21 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
22 : *
23 : */
24 :
25 : /* **************************************************************************
26 : *
27 : * Conditional-Compilation support for Tokenizer
28 : *
29 : * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
30 : * Module Author: David L. Paktor dlpaktor@us.ibm.com
31 : *
32 : **************************************************************************** */
33 :
34 : /* **************************************************************************
35 : *
36 : * Functions Exported:
37 : * init_conditionals_vocab Initialize the "Conditionals" Vocabulary.
38 : * handle_conditional Confirm whether a given name is a valid
39 : * Conditional, and, if so, perform its
40 : * function and return an indication.
41 : * create_conditional_alias Add an alias to "Conditionals" vocab
42 : * reset_conditionals Reset the "Conditionals" Vocabulary
43 : * to its "Built-In" position.
44 : *
45 : **************************************************************************** */
46 :
47 : #include <stdio.h>
48 : #include <stdlib.h>
49 :
50 : #include <string.h>
51 : #include <errno.h>
52 :
53 : #include "scanner.h"
54 : #include "errhandler.h"
55 : #include "ticvocab.h"
56 : #include "conditl.h"
57 : #include "stack.h"
58 : #include "dictionary.h"
59 : #include "vocabfuncts.h"
60 : #include "usersymbols.h"
61 : #include "stream.h"
62 : #include "clflags.h"
63 :
64 : /* **************************************************************************
65 : *
66 : * Global Variables Imported
67 : * statbuf Start of input-source buffer
68 : * pc Input-source Scanning pointer
69 : * iname Current Input File name
70 : * lineno Current Line Number in Input File
71 : *
72 : **************************************************************************** */
73 :
74 : /* **************************************************************************
75 : *
76 : * Local Static Variables
77 : * already_ignoring Location from which to pass a parameter,
78 : * called "alr_ign" to the main routine. Each
79 : * "Conditional" will have an associated routine
80 : * that takes the pointer to this as its argument.
81 : * The pointer to this will satisfy the "param-field"
82 : * requirement of a TIC_HDR-style "Vocabulary"-list.
83 : * conditionals_tbl TIC_HDR-style "Vocabulary"-list table, initialized
84 : * as an array.
85 : * conditionals Pointer to "tail" of Conditionals Vocabulary-list
86 : *
87 : **************************************************************************** */
88 :
89 : /* **************************************************************************
90 : *
91 : * The lists of synonymous forms of the #ELSE and #THEN operators
92 : * are incorporated into the "Shared Words" Vocabulary.
93 : *
94 : **************************************************************************** */
95 :
96 : /* **************************************************************************
97 : *
98 : * Function name: is_a_then / is_an_else
99 : * Synopsis: Indicate whether the given name is one of the
100 : * [then] / [else] synonyms
101 : *
102 : * Inputs:
103 : * Parameters:
104 : * a_word Word to test
105 : *
106 : * Outputs:
107 : * Returned Value: TRUE if the given name is one of the synonyms
108 : *
109 : * Process Explanation:
110 : * The functions are twins, hence bundling them like this...
111 : *
112 : **************************************************************************** */
113 :
114 :
115 : /* **************************************************************************
116 : *
117 : * Support function: is_a_type
118 : * Synopsis: Indicate whether the given name is a "shared word"
119 : * whose FWord Token matches the one given
120 : *
121 : * Inputs:
122 : * Parameters:
123 : * tname Target name to look for
124 : * fw_type The FWord Token type to match
125 : *
126 : * Outputs:
127 : * Returned Value: TRUE if it matches
128 : *
129 : **************************************************************************** */
130 :
131 :
132 : static bool is_a_type( char *tname, fwtoken fw_type)
133 31671 : {
134 31671 : bool retval = FALSE;
135 31671 : tic_fwt_hdr_t *found = (tic_fwt_hdr_t *)lookup_shared_f_exec_word( tname );
136 31671 : if ( found != NULL )
137 : {
138 1921 : if ( found->pfield.fw_token == fw_type ) retval = TRUE;
139 : }
140 31671 : return ( retval );
141 : }
142 :
143 : static bool is_a_then( char *a_word)
144 16102 : {
145 16102 : bool retval = is_a_type( a_word, CONDL_ENDER);
146 16102 : return ( retval );
147 : }
148 :
149 : static bool is_an_else( char *a_word)
150 15569 : {
151 15569 : bool retval = is_a_type( a_word, CONDL_ELSE);
152 15569 : return ( retval );
153 : }
154 :
155 : /* **************************************************************************
156 : *
157 : * This is a somewhat roundabout way of passing an "already ignoring"
158 : * parameter to the various Conditional Operators. Each operator's
159 : * Parameter-Field Pointer points to this. The calling routine
160 : * must set it (or rely on the default); the routine that handles
161 : * nesting of Conditionals must save and restore a local copy.
162 : *
163 : **************************************************************************** */
164 :
165 : static bool already_ignoring = FALSE;
166 :
167 : /* **************************************************************************
168 : *
169 : * Further down, will define and initialize a word-list table with
170 : * all the functions that implement the Conditional Operators,
171 : * and we'll link it in with the "Global Vocabulary" pointer.
172 : *
173 : * We'll call the word-list the "Conditionals Vocabulary Table",
174 : * and refer to its entries as the "Conditionals Vocabulary",
175 : * even though it isn't really a separate vocabulary...
176 : *
177 : **************************************************************************** */
178 :
179 :
180 : /* **************************************************************************
181 : *
182 : * We also need a few common routines to pass as "Ignoring" functions
183 : * for a few occasional words that take another word or two from
184 : * the input stream as their arguments. For example, if the user
185 : * were to write: alias [otherwise] [else] and that were to
186 : * occur within a segment already being ignored, we need to make
187 : * sure that this doesn't get processed as an occurrence of [else]
188 : * Similarly with macro-definitions.
189 : *
190 : * Since we are using the term "ignore a word" to mean "look it up and
191 : * process it in Ignoring-state", we need a different term to name
192 : * this class of routine; let's use the term "skip a word" where
193 : * the "word" is strictly an input token, delimited by whitespace.
194 : *
195 : **************************************************************************** */
196 :
197 : /* **************************************************************************
198 : *
199 : * Function name: skip_a_word
200 : * Synopsis: Consume one input-token ("word") from the
201 : * Input Stream, with no processing
202 : *
203 : * Inputs:
204 : * Parameters:
205 : * pfield "Parameter field" pointer, to satisfy
206 : * the calling convention, but not used
207 : *
208 : * Outputs:
209 : * Returned Value: NONE
210 : *
211 : **************************************************************************** */
212 :
213 : void skip_a_word( tic_bool_param_t pfield )
214 78 : {
215 78 : /* signed long wlen = */ get_word();
216 78 : }
217 :
218 : /* **************************************************************************
219 : *
220 : * Function name: skip_a_word_in_line
221 : * Synopsis: Consume one input-token ("word") on the same line
222 : * as the current line of input, from the Input
223 : * Stream, with no processing.
224 : *
225 : * Inputs:
226 : * Parameters:
227 : * pfield "Parameter field" pointer, to satisfy
228 : * the calling convention, but not used
229 : * Global Variables:
230 : * statbuf The word being processed, which expects
231 : * another word on the same line; used
232 : * for the Error message.
233 : *
234 : * Outputs:
235 : * Returned Value: NONE
236 : *
237 : * Error Detection:
238 : * get_word_in_line() will check and report if no word on same line.
239 : *
240 : **************************************************************************** */
241 : void skip_a_word_in_line( tic_bool_param_t pfield )
242 76 : {
243 76 : /* bool isokay = */ get_word_in_line( statbuf);
244 76 : }
245 :
246 : /* **************************************************************************
247 : *
248 : * Function name: skip_two_words_in_line
249 : * Synopsis: Consume two input-tokens ("words") on the same line
250 : * as the current line of input, from the Input
251 : * Stream, with no processing.
252 : *
253 : * Inputs:
254 : * Parameters:
255 : * pfield "Parameter field" pointer, to satisfy
256 : * the calling convention, but not used
257 : * Global Variables:
258 : * statbuf The word being processed, which expects
259 : * two words on the same line; used for
260 : * the Error message.
261 : *
262 : * Outputs:
263 : * Returned Value: NONE
264 : * Memory Allocated
265 : * Copy of statbuf for Error message.
266 : * When Freed?
267 : * End of this routine
268 : *
269 : * Error Detection:
270 : * get_word_in_line() will check and report
271 : *
272 : **************************************************************************** */
273 :
274 : void skip_two_words_in_line( tic_bool_param_t pfield )
275 0 : {
276 0 : char *func_cpy = strupr( strdup( statbuf));
277 0 : if ( get_word_in_line( func_cpy) )
278 : {
279 0 : /* bool isokay = */ get_word_in_line( func_cpy);
280 : }
281 0 : free( func_cpy);
282 0 : }
283 :
284 :
285 : /* **************************************************************************
286 : *
287 : * Function name: ignore_one_word
288 : * Synopsis: Handle a word that needs processing while "ignoring"
289 : * Ignore the rest.
290 : *
291 : * Inputs:
292 : * Parameters:
293 : * tname Target name to test
294 : * Local Static Variables:
295 : * already_ignoring The "Already Ignoring" flag
296 : *
297 : * Outputs:
298 : * Returned Value: NONE
299 : * Global Variables:
300 : * tic_found Set to the TIC-entry that has just been
301 : * found, in case it's a Macro.
302 : * Local Static Variables:
303 : * already_ignoring Intermediately set to TRUE, then
304 : * returned to former state.
305 : *
306 : * Process Explanation:
307 : * When we are ignoring source input, we still need to be
308 : * sensitive to the nesting of Conditional Operators, to
309 : * consume comments and user -message text-bodies, and to
310 : * expand Macros, among other things.
311 : * Rather than create special cases here for each one, we have
312 : * added an "ign_funct" pointer to those words where this
313 : * is relevant, including Conditional Operators.
314 : * Save the state of already_ignoring and set it to TRUE
315 : * Execute the "Ignoring" Function associated with the entry
316 : * Restore already_ignoring to its previous state.
317 : * This is necessary if the word is a Conditional Operator and
318 : * is harmless otherwise.
319 : *
320 : **************************************************************************** */
321 :
322 : static void ignore_one_word( char *tname)
323 1715 : {
324 1715 : tic_bool_hdr_t *found = (tic_bool_hdr_t *)lookup_word( tname, NULL, NULL);
325 1715 : if ( found != NULL )
326 : {
327 1608 : if ( found->ign_func != NULL )
328 : {
329 1322 : bool save_already_ignoring = already_ignoring;
330 1322 : already_ignoring = TRUE ;
331 1322 : tic_found = (tic_hdr_t *)found;
332 :
333 1322 : found->ign_func( found->pfield);
334 :
335 1322 : already_ignoring = save_already_ignoring;
336 : }
337 : }
338 1715 : }
339 :
340 : /* **************************************************************************
341 : *
342 : * Function name: conditionally_tokenize
343 : * Synopsis: Conduct tokenization while a Conditional-Tokenization
344 : * operator is in effect. This is the core of the
345 : * implementation of Conditional-Tokenization.
346 : *
347 : * Inputs:
348 : * Parameters:
349 : * cond The state of the Condition-Flag that the
350 : * immediate Conditional Operator acquired.
351 : * TRUE means "do not ignore". Its sense
352 : * is reversed when [ELSE] is encountered.
353 : * alr_ign TRUE means we are Already Ignoring source input,
354 : * except for Conditional Operators...
355 : * Global Variables:
356 : * statbuf The symbol (word) just retrieved from input stream.
357 : * iname Current Input File name (for Error Messages)
358 : * lineno Current Line Number in Input File (ditto)
359 : * trace_conditionals Whether to issue ADVISORY messages about
360 : * the state of Conditional Tokenization.
361 : *
362 : * Outputs:
363 : * Returned Value: NONE
364 : * Global Variables:
365 : * statbuf Will be advanced to the balancing [THEN] op'r.
366 : * already_ignoring Set to TRUE if nested Conditional encountered;
367 : * restored to previous state when done.
368 : * Memory Allocated
369 : * Duplicate of Input File name, for Error Messages
370 : * When Freed?
371 : * Just prior to exit from routine.
372 : * Printout:
373 : * ADVISORY messages, if "Trace-Conditionals" flag was selected.
374 : *
375 : * Global Behavior:
376 : * Tokenization happens, or inputs are ignored, as necessary.
377 : *
378 : * Error Detection:
379 : * End-of-file encountered on reading a word
380 : * ERROR. Conditional Operators must be balanced within a file
381 : * More than one [ELSE] encountered: ERROR if processing segment;
382 : * if ignoring, WARNING.
383 : *
384 : * Process Explanation:
385 : * Read a word at a time. Allow Macros to "pop" transparently,
386 : * but not source files.
387 : * If the word is a [THEN], we are done.
388 : * If the word is an [ELSE], then, if we are not Already Ignoring,
389 : * invert the sense of whether we are ignoring source input.
390 : * If this is not the only [ELSE] in the block, report an Error
391 : * and disregard it.
392 : * If we are ignoring source input, for whatever reason, we still
393 : * need to be sensitive to the nesting of Conditional Operators:
394 : * If the word is a Conditional Operator, activate it with the
395 : * "Already Ignoring" parameter set to TRUE; doing so will
396 : * result in a nested call to this routine.
397 : * Otherwise, i.e., if the word is not a Conditional Operator,
398 : * we may still need to process it in "ignoring" mode:
399 : * we need, for instance, to consume strings, comments
400 : * and the text-bodies of user-messages in their entirety,
401 : * in case there is a reference to an [ELSE] or suchlike.
402 : * The words that need processing while "ignoring" will
403 : * have a valid function-pointer in their ign_func field.
404 : * If we are not ignoring source input, pass the word along to the
405 : * tokenize_one_word routine and process it. If the word is
406 : * a Conditional Operator, it will be handled in the context
407 : * of normal (i.e., non-ignored) tokenization, and, again, a
408 : * nested call to this routine will result...
409 : *
410 : * Revision History:
411 : * Updated Thu, 23 Feb 2006 by David L. Paktor
412 : * Conditional Blocks may begin with a Conditional Operator in
413 : * a Macro definition and do not need to be concluded in
414 : * the body of the Macro.
415 : * Updated Fri, 10 Mar 2006 by David L. Paktor
416 : * Recognize aliased string, comment and user-message delimiters
417 : * in a segment that is being ignored; Conditional Operators
418 : * within the text body of any of these are always consumed
419 : * and never unintentionally processed. Macros are always
420 : * processed; Conditional Operators inside a Macro body are
421 : * recognized, so the Macro continues to function as intended.
422 : *
423 : **************************************************************************** */
424 :
425 : static void conditionally_tokenize( bool cond, bool alr_ign )
426 540 : {
427 :
428 : signed long wlen;
429 :
430 : /* Note: The following variables *must* remain within
431 : * the scope of this routine; a distinct instance
432 : * is needed each time this routine is re-entered
433 : * (aka "a nested call").
434 : */
435 : bool ignoring;
436 540 : bool first_else = TRUE; /* The "else" we see is the first. */
437 540 : bool not_done = TRUE;
438 540 : unsigned int cond_strt_lineno = lineno;
439 540 : char *cond_strt_ifile_nam = strdup( iname);
440 :
441 540 : ignoring = BOOLVAL( ( cond == FALSE ) || ( alr_ign != FALSE ) );
442 :
443 540 : if ( trace_conditionals )
444 : {
445 86 : char *cond_val = cond ? "True" : "False" ;
446 86 : char *cond_junct = alr_ign ? ", but Already " : "; ";
447 86 : char *processg = ignoring ? "Ignoring" : "Processing" ;
448 86 : tokenization_error( INFO,
449 : "Tokenization-Condition is %s%s%s.\n",
450 : cond_val, cond_junct, processg);
451 : }
452 :
453 16691 : while ( not_done )
454 : {
455 16152 : wlen = get_word();
456 16152 : if ( wlen == 0 )
457 : {
458 44 : continue;
459 : }
460 :
461 16108 : if ( wlen < 0 )
462 : {
463 6 : tokenization_error( TKERROR,
464 : "Conditional without conclusion; started");
465 6 : just_where_started( cond_strt_ifile_nam, cond_strt_lineno);
466 6 : not_done = FALSE ;
467 6 : continue;
468 : }
469 :
470 16102 : if ( is_a_then ( statbuf ) )
471 : {
472 533 : if ( trace_conditionals )
473 : {
474 85 : tokenization_error( INFO,
475 : "Concluding Conditional");
476 85 : just_started_at( cond_strt_ifile_nam, cond_strt_lineno);
477 : }
478 533 : not_done = FALSE ;
479 533 : continue;
480 : }
481 :
482 15569 : if ( is_an_else( statbuf ) )
483 : {
484 350 : if ( ! alr_ign )
485 : {
486 260 : if ( first_else )
487 : {
488 258 : ignoring = INVERSE( ignoring);
489 : }
490 : }
491 :
492 350 : if ( ! first_else )
493 : {
494 4 : int severity = ignoring ? WARNING : TKERROR ;
495 4 : char *the_scop = ignoring ? "(ignored)" : "the" ;
496 4 : tokenization_error( severity, "Multiple %s directives "
497 : "within %s scope of the Conditional",
498 : strupr(statbuf), the_scop);
499 4 : just_started_at( cond_strt_ifile_nam, cond_strt_lineno);
500 : }else{
501 346 : first_else = FALSE;
502 346 : if ( trace_conditionals )
503 : {
504 70 : char *when_enc = alr_ign ? "While already" : "Now" ;
505 : char *processg = alr_ign ? "ignoring" :
506 70 : ignoring ? "Ignoring" : "Processing" ;
507 70 : char *enc = alr_ign ? ", e" : ". E" ;
508 :
509 70 : tokenization_error( INFO,
510 : "%s %s%sncountered %s belonging to Conditional",
511 : when_enc, processg, enc, strupr(statbuf) );
512 70 : just_started_at( cond_strt_ifile_nam, cond_strt_lineno);
513 : }
514 : }
515 :
516 : continue;
517 : }
518 :
519 : /* If we are ignoring source input, for whatever reason, we still
520 : * need to be sensitive to the nesting of Conditional Operators
521 : * and some other commands and directives, as indicated...
522 : */
523 15219 : if ( ignoring )
524 : {
525 1715 : ignore_one_word( statbuf );
526 : }else{
527 : /* And if we're not ignoring source input, process it! */
528 13504 : tokenize_one_word ( wlen );
529 : }
530 : }
531 539 : }
532 :
533 : /* **************************************************************************
534 : *
535 : * We will now define a series of fairly simple functions that
536 : * will be performed by the various Conditional Operators in
537 : * the "Conditionals Vocabulary".
538 : *
539 : * Each one takes, as an argument, the "parameter field" pointer,
540 : * which, in all cases, points to the local already_ignoring
541 : * flag, passed as an int to satisfy C's strong-typing. The
542 : * routine will internally recast it as a bool .
543 : *
544 : * If it is TRUE, the routine will bypass the test for its particular
545 : * type of condition, and go directly to conditionally_tokenize
546 : * In most cases, testing for the condition would be harmless,
547 : * but in the case where the test is for an item on the stack,
548 : * it would be harmful because the sequence that put the item
549 : * on the stack was also being ignored...
550 : *
551 : * We'll give these functions short prologs. Synonyms will simply
552 : * have separate entries in the Vocabulary Table, associated
553 : * with the same function.
554 : *
555 : **************************************************************************** */
556 :
557 : /* **************************************************************************
558 : *
559 : * But first, a support routine...
560 : *
561 : **************************************************************************** */
562 :
563 : /* **************************************************************************
564 : *
565 : * Function name: conditional_word_in_line
566 : * Synopsis: Common code for the types of conditionals that
567 : * require a word on the same line.
568 : *
569 : * Inputs:
570 : * Parameters:
571 : * alr_ign TRUE if we are already ignoring
572 : * exist_test TRUE if the test is for "existence" of the word
573 : * exist_funct Name of the function to call for the test
574 : * Global Variables:
575 : * stat_word Word for which to test
576 : *
577 : * Outputs:
578 : * Returned Value: NONE
579 : *
580 : * Error Detection:
581 : * The word in question must appear on the same line as the directive;
582 : * the call to get_word_in_line() checks for that and reports.
583 : * If the word did not appear on the same line, then the directive
584 : * will be disregarded and processing will proceed as though it
585 : * were absent. This may lead to a cascade of errors...
586 : *
587 : * Process Explanation:
588 : * The supplied exist_funct() will test for the existence of
589 : * the word, now read into statbuf , in the appropriate
590 : * venue.
591 : * We only call the exist_funct() if we are not already ignoring.
592 : *
593 : **************************************************************************** */
594 :
595 : static void conditional_word_in_line( bool alr_ign,
596 : bool exist_test,
597 : bool (*exist_funct)() )
598 228 : {
599 228 : if ( get_word_in_line( statbuf) )
600 : {
601 217 : bool cond = FALSE;
602 217 : if ( INVERSE( alr_ign) )
603 : {
604 190 : bool exists = exist_funct( statbuf);
605 190 : cond = BOOLVAL( exists == exist_test);
606 : }
607 217 : conditionally_tokenize( cond, alr_ign );
608 : }
609 227 : }
610 :
611 :
612 : /* **************************************************************************
613 : *
614 : * Function name: if_exists
615 : * Synopsis: Test for existence of a given word, in the dictionary.
616 : *
617 : * Associated Tokenizer directives: [ifexist]
618 : * #ifexist
619 : * [#ifexist]
620 : * [ifexists]
621 : * #ifexists
622 : * [#ifexists]
623 : * (Note variants with and without final 's'
624 : *
625 : **************************************************************************** */
626 :
627 : static void if_exists( tic_param_t pfield )
628 58 : {
629 58 : bool alr_ign = *pfield.bool_ptr;
630 58 : conditional_word_in_line( alr_ign, TRUE, exists_in_current );
631 58 : }
632 :
633 : /* **************************************************************************
634 : *
635 : * Function name: if_not_exist
636 : * Synopsis: Test for Non-existence, in the appropriate dictionary,)
637 : * of the given word.
638 : *
639 : * Associated Tokenizer directives: [ifnexist]
640 : * #ifnexist
641 : * [#ifnexist]
642 : * (Note: Variants with final 's' didn't make sense here.)
643 : *
644 : * Explanatory Notes:
645 : * This is the exact inverse of if_exists
646 : *
647 : **************************************************************************** */
648 :
649 : static void if_not_exist( tic_bool_param_t pfield )
650 67 : {
651 67 : bool alr_ign = *pfield.bool_ptr;
652 67 : conditional_word_in_line( alr_ign, FALSE, exists_in_current );
653 67 : }
654 :
655 : /* **************************************************************************
656 : *
657 : * Function name: if_defined
658 : * Synopsis: Test for existence of a user-defined symbol
659 : *
660 : * Associated Tokenizer directives: [ifdef]
661 : * #ifdef
662 : * [#ifdef]
663 : *
664 : **************************************************************************** */
665 :
666 : static void if_defined( tic_bool_param_t pfield )
667 48 : {
668 48 : bool alr_ign = *pfield.bool_ptr;
669 48 : conditional_word_in_line( alr_ign, TRUE, exists_as_user_symbol );
670 48 : }
671 :
672 : /* **************************************************************************
673 : *
674 : * Function name: if_not_defined
675 : * Synopsis: Test for NON-existence of a user-defined symbol
676 : *
677 : * Associated Tokenizer directives: [ifndef]
678 : * #ifndef
679 : * [#ifndef]
680 : *
681 : **************************************************************************** */
682 :
683 : static void if_not_defined( tic_bool_param_t pfield )
684 55 : {
685 55 : bool alr_ign = *pfield.bool_ptr;
686 55 : conditional_word_in_line( alr_ign, FALSE, exists_as_user_symbol );
687 54 : }
688 :
689 :
690 : /* **************************************************************************
691 : *
692 : * Function name: if_from_stack
693 : * Synopsis: Test the number on top of the run-time stack
694 : *
695 : * Associated Tokenizer directive: [if]
696 : *
697 : * Process Explanation:
698 : * When we are ignoring source input, and we still need to be
699 : * sensitive to the nesting of Conditional Operators, we
700 : * will not consume the number on the stack; this function
701 : * is after all, being ignored and should not perform any
702 : * action other than making sure the [else]s and [then]s
703 : * get properly counted.
704 : *
705 : **************************************************************************** */
706 :
707 : static void if_from_stack( tic_bool_param_t pfield )
708 323 : {
709 323 : bool alr_ign = *pfield.bool_ptr;
710 323 : bool cond = FALSE;
711 :
712 323 : if ( ! alr_ign )
713 : {
714 240 : long num = dpop();
715 240 : if (num != 0)
716 : {
717 176 : cond = TRUE;
718 : }
719 : }
720 323 : conditionally_tokenize( cond, alr_ign );
721 323 : }
722 :
723 : /* For future functions, use conditl.BlankTemplate.c */
724 :
725 : /* **************************************************************************
726 : *
727 : * Here, at long last, we define and initialize the structure containing
728 : * all the functions we support for Conditional Operators.
729 : *
730 : **************************************************************************** */
731 :
732 : #define ADD_CONDL(str, func ) BUILTIN_BOOL_TIC(str, func, already_ignoring )
733 :
734 : static tic_bool_hdr_t conditionals_vocab_tbl[] = {
735 : ADD_CONDL ("[ifexist]" , if_exists ) ,
736 : ADD_CONDL ("[ifexists]" , if_exists ) ,
737 : ADD_CONDL ("#ifexist" , if_exists ) ,
738 : ADD_CONDL ("#ifexists" , if_exists ) ,
739 : ADD_CONDL ("[#ifexist]" , if_exists ) ,
740 : ADD_CONDL ("[#ifexists]" , if_exists ) ,
741 : ADD_CONDL ("[ifnexist]" , if_not_exist ) ,
742 : ADD_CONDL ("#ifnexist" , if_not_exist ) ,
743 : ADD_CONDL ("[#ifnexist]" , if_not_exist ) ,
744 : ADD_CONDL ("[ifdef]" , if_defined ) ,
745 : ADD_CONDL ("#ifdef" , if_defined ) ,
746 : ADD_CONDL ("[#ifdef]" , if_defined ) ,
747 : ADD_CONDL ("[ifndef]" , if_not_defined ) ,
748 : ADD_CONDL ("#ifndef" , if_not_defined ) ,
749 : ADD_CONDL ("[#ifndef]" , if_not_defined ) ,
750 : ADD_CONDL ("[if]" , if_from_stack )
751 : };
752 :
753 :
754 : /* **************************************************************************
755 : *
756 : * Function name: init_conditionals_vocab
757 : * Synopsis: Initialize the "Conditionals Vocabulary Table"
758 : * link-pointers dynamically, and link it in
759 : * with the given ("Global") Vocabulary pointer.
760 : *
761 : **************************************************************************** */
762 :
763 : void init_conditionals_vocab( tic_hdr_t **tic_vocab_ptr )
764 154 : {
765 : static const int conditionals_vocab_max_indx =
766 : sizeof(conditionals_vocab_tbl)/sizeof(tic_bool_hdr_t);
767 :
768 154 : init_tic_vocab( (tic_hdr_t *)conditionals_vocab_tbl,
769 : conditionals_vocab_max_indx,
770 : tic_vocab_ptr );
771 154 : }
772 :
|