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