Hash :
60c9c198
Author :
Date :
2006-10-30T09:48:28
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
/*
* OpenBIOS - free your system!
* ( FCode tokenizer )
*
* macros.c - macro initialization and functions.
*
* This program is part of a free implementation of the IEEE 1275-1994
* Standard for Boot (Initialization Configuration) Firmware.
*
* Copyright (C) 2001-2005 by Stefan Reinauer <stepan@openbios.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
*
*/
/* **************************************************************************
* Modifications made in 2005 by IBM Corporation
* (C) Copyright 2005 IBM Corporation. All Rights Reserved.
* Modifications Author: David L. Paktor dlpaktor@us.ibm.com
**************************************************************************** */
/* **************************************************************************
*
* Support functions for the MACROS vocabulary, implemented
* as a TIC-Headerlist type of data structure, and linked in
* to the Global Vocabulary.
*
**************************************************************************** */
/* **************************************************************************
*
* Functions Exported:
* init_macros Initialize the link-pointers in the
* initial "Built-In" portion of
* the macros vocabulary
* add_user_macro Add an entry to the macros vocabulary
* skip_user_macro Consume a Macro definition if Ignoring
*
**************************************************************************** */
#include <stdio.h>
#include <stdlib.h>
#if defined(__linux__) && ! defined(__USE_BSD)
#define __USE_BSD
#endif
#include <string.h>
#include <errno.h>
#include "macros.h"
#include "errhandler.h"
#include "ticvocab.h"
#include "stream.h"
#include "scanner.h"
#include "dictionary.h"
#include "devnode.h"
/* **************************************************************************
*
* Internal Static Variables
* macros_tbl Initial array of "Built-In" Macros
* number_of_builtin_macros Number of "Built-In" Macro entries.
*
**************************************************************************** */
/* **************************************************************************
*
* Revision History:
* Thu, 27 Oct 2005 by David L. Paktor
* Identify the macros that resolve to a single word.
* Remove them from here and enter them as synonymous entries
* in the Tokens, Specials or Shared-words vocabularies.
* Wed, 30 Nov 2005 by David L. Paktor
* Allow user-definition of macros.
* Fri, 06 Jan 2006 by David L. Paktor
* Re-define the Macros as a TIC-Headerlist, and make them
* part of the Global Vocabulary
*
**************************************************************************** */
/* **************************************************************************
*
* Function name: macro_recursion_error
* Synopsis: Function that will go temporarily into the FUNCT
* field of a Macro's TIC-entry, to protect against
* recursive macro invocations.
*
* Inputs:
* Parameters:
* pfield Param field of the TIC-entry; unused.
* Global Variables:
* statbuf The name being invoked erroneously.
*
* Outputs:
* Returned Value: NONE
* Printout:
* Error Message.
*
* Error Detection:
* If this function is called, it is an ERROR
*
* Extraneous Remarks:
* This Tokenizer does not have the early-binding characterisitics
* of FORTH; its Macros are strings, evaluated when invoked
* rather than when they are defined. A reference to a name
* that matches the macro would cause recursion, possibly
* infinite. We will not allow that.
*
**************************************************************************** */
static void macro_recursion_error( tic_param_t pfield)
{
tokenization_error( TKERROR,
"Recursive invocation of macro named %s\n", statbuf);
}
/* **************************************************************************
*
* Function name: eval_mac_string
* Synopsis: Function that goes into FUNCT field of a TIC-entry
* in the Macros list. Protect against recursion.
*
* Inputs:
* Parameters:
* pfield Param field of the TIC-entry
* Global Variables:
* tic_found The TIC-entry that has just been found;
* it's the entry for this Macro.
*
* Outputs:
* Returned Value: NONE
* Global Variables:
* report_multiline Cleared to FALSE
* Global Behavior:
* The Macro will be evaluated as string input.
*
* Error Detection:
* An attempt at recursion will be detected because the FUNCT field
* of the Macro entry will have been temporarily be replaced by
* macro_recursion_error()
*
* Process Explanation:
* Save the address of the routine that is in the FUNCT field
* of the entry for this Macro. (Hey! It's this routine...)
* Replace the FUNCT field of the Macro entry with the Macro
* Recursion Error Detection routine
* Pass the address of the "resumption" routine and its argument
* (the entry for this Macro), to push_source()
* Recast the type of the parameter field to a string
* Make it the new Input Source Buffer.
* Suspend multi-line warning; see comment in body of add_user_macro()
* The multi-line warning flag is kept by push_source()
*
* Still to be done:
* If an error is encountered during Macro evaluation, display
* supplemental information giving the name of the Macro
* being run, and the file and line number in which it was
* defined.
* This will require changes to the way user Macros are added
* and retained, and to the way error messages are displayed.
*
* Revision History:
* Updated Thu, 23 Feb 2006 by David L. Paktor
* Do not process Macros (or, for that matter, User-defined
* Symbols or FLOADed files) with a routine that calls
* its own instance of tokenize(), because the Macro
* (etc.) might contain a phrase (such as the start of
* a conditional) that must be terminated within the
* body of a file, thus causing an undeserved Error.
* Instead, they need to be handled in a more sophis-
* ticated way, tied in with the operation of get_word()
* perhaps, that will make a smooth transition between
* the body of the Macro and the resumption of processing
* the source file. The end-of-file will only be seen
* at the end of an actual input file or when getting
* a delimited string.
* Updated Fri, 24 Feb 2006 by David L. Paktor
* Re-integrate Recursion Error Detection with the above.
*
**************************************************************************** */
/* **************************************************************************
*
* In order to integrate Recursion Error Detection with the smooth
* transition to resumption of processing the source file, we
* need to create a "resumption" routine that will restore the
* normal behavior of the macro after it's completed, by re-
* instating the address of the normal Macro-invocation routine;
* that routine, of course, is the one that passes the address
* of the "resumption" routine to push_source(). In order to
* get around this chicken-and-egg dilemma, we will create a
* local static variable into which the address of the normal
* Macro-invocation routine will be stored. We actually only
* need it once, but we'd rather avoid the overhead of checking,
* every time, whether it has already been set; since it's always
* the same, there's no harm in storing it every time.
*
**************************************************************************** */
typedef void (*vfunct)(); /* Pointer to function returning void */
static vfunct sav_mac_funct ;
/* **************************************************************************
*
* This "resumption" routine will be called by pop_source()
* The parameter is the Macro dictionary-entry whose behavior
* is to be restored.
*
**************************************************************************** */
static void mac_string_recovery( tic_hdr_t *macro_entry)
{
(*macro_entry).funct = sav_mac_funct;
(*macro_entry).ign_func = sav_mac_funct;
}
/* **************************************************************************
*
* The normal Macro-invocation routine, at last...
*
**************************************************************************** */
static void eval_mac_string( tic_param_t pfield)
{
int mac_str_len = strlen(pfield.chr_ptr);
/* We can't use (*tic_found).pfld_size for the string length
* because, if this is an alias for a macro, it will be zero...
*/
/* We can change that by de-coupling the decision to free the
* param-field from whether pfld_size is non-zero (by intro-
* ducing yet another field into the tic_param_t struct),
* but we're not doing that today...
*/
sav_mac_funct = *tic_found->funct;
(*tic_found).funct = macro_recursion_error;
(*tic_found).ign_func = macro_recursion_error;
push_source( mac_string_recovery, tic_found, FALSE);
report_multiline = FALSE; /* Must be done AFTER call to push_source()
* because report_multiline is part of
* the state that push_source() saves.
*/
init_inbuf( pfield.chr_ptr, mac_str_len);
}
/* **************************************************************************
*
* Builtin Macros do not need Recursion Error Detection.
* Intermediate routine to convert parameter type.
*
**************************************************************************** */
static void eval_builtin_mac( tic_param_t pfield)
{
eval_string( pfield.chr_ptr);
}
/* **************************************************************************
*
* Make a macro, because we might eliminate this layer later on.
*
**************************************************************************** */
#define EVAL_MAC_FUNC eval_mac_string
#define BUILTIN_MAC_FUNC eval_builtin_mac
/* **************************************************************************
*
* Initialization macro definition
*
**************************************************************************** */
#define BUILTIN_MACRO(nam, alias) BUILTIN_MAC_TIC(nam, BUILTIN_MAC_FUNC, alias )
static tic_mac_hdr_t macros_tbl[] = {
BUILTIN_MACRO( "(.)", "dup abs <# u#s swap sign u#>") ,
BUILTIN_MACRO( "?", "@ .") ,
BUILTIN_MACRO( "1+", "1 +") ,
BUILTIN_MACRO( "1-", "1 -") ,
BUILTIN_MACRO( "2+", "2 +") ,
BUILTIN_MACRO( "2-", "2 -") ,
BUILTIN_MACRO( "accept", "span @ -rot expect span @ swap span !") ,
BUILTIN_MACRO( "allot", "0 max 0 ?do 0 c, loop") ,
BUILTIN_MACRO( "blank", "bl fill") ,
BUILTIN_MACRO( "carret", "h# d") ,
BUILTIN_MACRO( ".d", "base @ swap h# a base ! . base !") ,
/* Note: The Standard gives: ">r over r@ + swap r@ - rot r>"
* as its example of the macro for decode-bytes
* But here's one that does the same thing without
* using return-stack operations. And it's one step
* shorter, into the bargain!
*/
BUILTIN_MACRO( "decode-bytes", "tuck - -rot 2dup + swap 2swap rot") ,
BUILTIN_MACRO( "3drop", "drop 2drop") ,
BUILTIN_MACRO( "3dup", "2 pick 2 pick 2 pick") ,
BUILTIN_MACRO( "erase", "0 fill") ,
BUILTIN_MACRO( ".h", "base @ swap h# 10 base ! . base !") ,
BUILTIN_MACRO( "linefeed", "h# a") ,
BUILTIN_MACRO( "s.", "(.) type space") ,
BUILTIN_MACRO( "space", "bl emit") ,
BUILTIN_MACRO( "spaces", "0 max 0 ?do space loop") ,
BUILTIN_MACRO( "(u.)", "<# u#s u#>") ,
BUILTIN_MACRO( "?leave", "if leave then"),
};
static const int number_of_builtin_macros =
sizeof(macros_tbl)/sizeof(tic_mac_hdr_t);
/* **************************************************************************
*
* Function name: init_macros
* Synopsis: Initialize the link-pointers in the "Built-In"
* portion of the macros vocabulary, dynamically.
*
* Inputs:
* Parameters:
* tic_vocab_ptr Pointer to Global Vocab Pointer
* Global Variables:
* macros_tbl Initial "Built-In" Macros array
* number_of_builtin_macros Number of "Built-In" Macro entries
*
* Outputs:
* Returned Value: NONE
* Global Variables:
* The link-fields of the initial "Built-In" Macros array entries
* will be filled in.
* Supplied Pointers:
* *tic_vocab_ptr Updated to "tail" of Macros array
*
**************************************************************************** */
void init_macros( tic_hdr_t **tic_vocab_ptr )
{
init_tic_vocab( (tic_hdr_t *)macros_tbl,
number_of_builtin_macros,
tic_vocab_ptr );
}
/* **************************************************************************
*
* Function name: print_if_mac_err
* Synopsis: Report a user-macro definition error, if so be.
*
* Inputs:
* Parameters:
* failure TRUE if error was detected
* func_cpy STRDUP() of function name, for error message
*
* Outputs:
* Returned Value: NONE
* Memory Freed
* Contents of func_cpy, error or not.
* Printout:
* Error message, if failure is TRUE.
*
**************************************************************************** */
static void print_if_mac_err( bool failure, char *func_cpy)
{
if ( failure )
{
tokenization_error( TKERROR,
"%s directive expects name and definition on the same line\n",
strupr(func_cpy));
}
free( func_cpy);
}
/* **************************************************************************
*
* Function name: add_user_macro
* Synopsis: Parse input and add a user-defined Macro.
*
* Associated Tokenizer directive: [MACRO]
*
* Inputs:
* Parameters: NONE
* Global Variables:
* pc Input-source Scanning pointer
* statbuf Symbol retrieved from input stream.
* in_tokz_esc TRUE if in "Tokenizer-Escape" mode
* current_definitions Pointer to Current Vocabulary pointer,
* either Global or Current Device-Node
* tokz_esc_vocab "Tokenizer Escape" Vocab pointer
*
* Outputs:
* Returned Value: NONE
* Global Variables:
* *current_definitions { One of these will point }
* tokz_esc_vocab { to the new entry }
* Memory Allocated:
* Copy of directive, for error message
* Copy of Macro name
* Copy of Macro body
* Memory for the new entry will be allocated by support routine.
* When Freed?
* Copy of directive: When error might be reported.
* Macro name, body and entry: Upon end of tokenization, or when
* RESET-SYMBOLS is issued in the same mode and Scope as when
* the Macro was defined.
*
* Error Detection:
* At least two words in the input stream are expected to be on
* the same line as the directive. The get_word_in_line()
* and get_rest_of_line() routines will check for that;
* we will issue the Error Message for either condition.
* Check if the Macro name is a duplicate; warn_if_duplicate()
* routine will issue message.
*
* Process Explanation:
* We start just after the directive has been recognized.
* Get one word in line -- this is the macro name
* Get input to end of line. This is the "body" of the macro.
* Add the Macro to the Current vocab, using support routine.
* Set the definer field to MACRO_DEF and the Function to the
* same one that's used for the built-in macros.
* User-defined Macros may need to be processed while ignoring
* (because they might include conditional-operators, etc.)
* We will set the ign_func the same as the active function.
*
* To be considered:
* Do we want to do further filtration?
* Remove comments?
* Compress whitespace?
* Allow backslash at end of line to continue to next line?
*
* Extraneous Remarks:
* The scope of User-Macro definitions will follow the same rules
* as all other definition types: if Device-Definitions are
* in effect, the scope of the new Macro definition will be
* confined to the current Device-Node; if Global-Definitions
* are in effect when it is defined, its scope will be Global;
* if it was declared when we were in "Tokenizer Escape" mode,
* then its scope will be limited to "Tokenizer Escape" mode.
*
**************************************************************************** */
/* This pointer is exported to this file only */
extern tic_hdr_t *tokz_esc_vocab ;
void add_user_macro( void)
{
char *macroname;
char *macrobody;
bool failure = TRUE;
/* Copy of function name, for error message */
char *func_cpy = strdup( statbuf);
if ( get_word_in_line( NULL ) )
{
/* This is the Macro name */
macroname = strdup( statbuf);
if ( INVERSE(get_rest_of_line() ) )
{
/* No body on line */
free( macroname);
}else{
/* We have valid Macro body on line */
int mac_body_len = 0;
tic_hdr_t **target_vocab = current_definitions;
if ( in_tokz_esc ) target_vocab = &tokz_esc_vocab ;
/* Tack on a new-line, so that a remark will appear
* to be properly terminated. This might trigger
* an undeserved multi-line warning if the Macro
* is an improperly terminated quote; we will work
* around that problem by temporarily suspending
* multi-line warnings during macro processing.
*/
strcat( statbuf, "\n");
macrobody = strdup( statbuf);
mac_body_len = strlen(macrobody);
add_tic_entry( macroname, EVAL_MAC_FUNC,
(TIC_P_DEFLT_TYPE)macrobody,
MACRO_DEF, mac_body_len, FALSE,
EVAL_MAC_FUNC, target_vocab );
failure = FALSE;
}
}
print_if_mac_err( failure, func_cpy);
}
/* **************************************************************************
*
* Function name: skip_user_macro
* Synopsis: Consume the text of a user-defined Macro from the
* Input Stream, with no processing. (Called when
* a user-Macro definer occurs in a segment that
* is being Ignored.)
*
* Inputs:
* Parameters:
* pfield "Parameter field" pointer, to satisfy
* the calling convention, but not used
* Global Variables:
* statbuf Word currently being processed.
*
* Outputs:
* Returned Value: NONE
*
* Error Detection:
* At least two words in the input stream are expected to be on
* the same line as the user-Macro definer, same as when the
* directives occurs in a segment that is not being Ignored.
* The get_word_in_line() and get_rest_of_line() routines
* will check for condition., we will issue the Error Message.
*
* Process Explanation:
* We need to protect against the case of a macro-definition that
* invokes a directive that alters Conditional processing...
*
**************************************************************************** */
void skip_user_macro( tic_bool_param_t pfield )
{
bool failure = TRUE;
char *func_cpy = strdup( statbuf);
if ( get_word_in_line( NULL ) )
{
if ( get_rest_of_line() )
{
failure = FALSE;
}
}
print_if_mac_err( failure, func_cpy);
}