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 * Parsing functions for IBM-style Local Values 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 * declare_locals Pick up the Locals' names after the { 00038 * handle_local Insert the code to access a Local 00039 * exists_as_local Confirm whether a name is in the Locals vocab 00040 * assign_local Process the "Assign to a Local" operator ( -> ) 00041 * finish_locals Insert the code for exiting a routine 00042 * that uses locals 00043 * forget_locals Remove the locals' names from the search 00044 * 00045 **************************************************************************** */ 00046 00047 /* ************************************************************************** 00048 * 00049 * These are the names of the three routines that will be invoked 00050 * when Locals are used. Their definitions exist in a separate 00051 * Local Values Support FCode source-file that must be FLOADed 00052 * into the user's tokenization source. 00053 * 00054 **************************************************************************** */ 00055 00056 /* Note that the enclosing curly-braces are part of the name */ 00057 static const char* push_locals = "{push-locals}"; /* ( #ilocals #ulocals -- ) */ 00058 static const char* pop_locals = "{pop-locals}"; /* ( #locals -- ) */ 00059 static const char* local_addr = "_{local}"; /* ( local# -- addr ) */ 00060 00061 /* Switchable Fetch or Store operator to apply to local_addr. */ 00062 static const char* local_op = "@"; /* Initially Fetch */ 00063 00064 00065 /* ************************************************************************** 00066 * 00067 * Revision History: 00068 * Updated Wed, 13 Jul 2005 by David L. Paktor 00069 * Command-line control for: 00070 * Support for Locals in general 00071 * Whether to accept the "legacy" separator (semicolon) 00072 * Whether to issue a message for the "legacy" separator 00073 * Updated Tue, 10 Jan 2006 by David L. Paktor 00074 * Convert to tic_hdr_t type vocabulary. 00075 * 00076 **************************************************************************** */ 00077 00078 #include <stdio.h> 00079 #include <stdlib.h> 00080 #include <string.h> 00081 #include "ticvocab.h" 00082 #include "dictionary.h" 00083 #include "scanner.h" 00084 #include "parselocals.h" 00085 #include "errhandler.h" 00086 #include "clflags.h" 00087 #include "stream.h" 00088 #include "devnode.h" 00089 #include "flowcontrol.h" 00090 00091 /* ************************************************************************** 00092 * 00093 * Global Variables Imported 00094 * statbuf 00095 * pc 00096 * opc 00097 * incolon 00098 * lastcolon 00099 * ibm_locals_legacy_separator Accept ; as the "legacy" separator 00100 * ibm_legacy_separator_message Issue a message for "legacy" sep'r 00101 * 00102 **************************************************************************** */ 00103 00104 /* ************************************************************************** 00105 * 00106 * Internal Static Variables 00107 * local_names Vocabulary for new local-names 00108 * num_ilocals Number of initialized local variables 00109 * num_ulocals Number of uninitialized local variables 00110 * localno Running Local-Number to be assigned 00111 * eval_buf Internally-generated string to be parsed 00112 * l_d_lineno Locals Declaration Line Number 00113 * 00114 **************************************************************************** */ 00115 00116 static tic_hdr_t *local_names = NULL; 00117 static int num_ilocals = 0; 00118 static int num_ulocals = 0; 00119 static int localno = 0; 00120 static char eval_buf[64]; 00121 static unsigned int l_d_lineno; /* For Error Messages */ 00122 00123 /* ************************************************************************** 00124 * 00125 * The local_names vocabulary follows the same tic_hdr_t structure 00126 * as the dictionaries of tokens, special-functions, etcetera. Its 00127 * "parameter field" is an integer, used to store the Local's number, 00128 * an its "function" is invoke_local(), defined further below. 00129 * 00130 * The vocabulary is initially empty, so there's no need for an "init" 00131 * or a "reset" routine. 00132 * 00133 **************************************************************************** */ 00134 00135 /* ************************************************************************** 00136 * 00137 * Function name: int_to_str 00138 * Synopsis: Convert an integer into a compilable string. 00139 * Suport routine for invoke_local(). 00140 * 00141 * Inputs: 00142 * Parameters: 00143 * num The number to convert 00144 * bufr The buffer into which to place it. 00145 * Needn't be very long: 00146 * five at least, ten is enough 00147 * 00148 * Outputs: 00149 * Returned Value: Pointer to bufr 00150 * bufr Contents are changed. 00151 * 00152 * Process Explanation: 00153 * Convert into decimal. If the number is greater than 8, 00154 * prepend a d# in front of it. If less, don't. 00155 * We specifically want to avoid a d# in front of 00156 * the numbers 0 1 2 and 3, which are also named constants; 00157 * there's no need to treat 'em as literals. 00158 * The calling routine will be responsible for allocating 00159 * and freeing the buffer. 00160 * 00161 * Extraneous Remarks: 00162 * Too bad atoi() isn't a Standard C function; I could convert 00163 * using the current base, and be guaranteed that it would be 00164 * interpreted in the same base. 00165 * Instead, I have to fiddle-faddle around with d# ... 00166 * 00167 **************************************************************************** */ 00168 00169 static char *int_to_str( int num, char *bufr) 00170 { 00171 char* prefix = "d# "; 00172 if ( num < 8 ) prefix = ""; 00173 sprintf(bufr,"%s%d",prefix, num); 00174 return (bufr); 00175 } 00176 00177 00178 00179 /* ************************************************************************** 00180 * 00181 * Function name: invoke_local 00182 * Synopsis: Compile-in the code to access the Local whose 00183 * assigned Number is given. This function is 00184 * entered into the Local-Names Vocabulary entry. 00185 * 00186 * Inputs: 00187 * Parameters: 00188 * pfield The Vocabulary entry's Param field, taken 00189 * from the Assigned Number of the Local. 00190 * Local Static Variables: 00191 * local_addr Name of _{local} routine, invoked 00192 * when a Local is used 00193 * local_op Fetch or Store operator to apply. 00194 * 00195 * Outputs: 00196 * Returned Value: None 00197 * Local Static Variables: 00198 * eval_buf Phrase constructed here; will become new 00199 * Source Input Buffer, temporarily 00200 * 00201 * Error Detection: 00202 * If the Local Values Support FCode source-file was not 00203 * FLOADed into the user's tokenization source, then 00204 * the function _{local} will be an "unknown name". 00205 * 00206 * Process Explanation: 00207 * We are going to generate a string of the form: 00208 * " #local _{local} OP" 00209 * and pass it to the Parser for evaluation. 00210 * The call to _{local} is preceded by its parameter, which is 00211 * its Assigned Local-Number, and followed by the appropriate 00212 * OPerator, which will be "Fetch" if the Local's name was 00213 * invoked by itself, or "Store" if its invocation was made 00214 * in conjuction with the -> operator. 00215 * The string-buffer may be local, but it must be stable. 00216 * 00217 * Revision History: 00218 * Updated Thu, 24 Mar 2005 by David L. Paktor 00219 * Factored-out to permit lookup_local() to be a "pure" 00220 * function that can be used for duplicate-name detection. 00221 * Updated Tue, 10 Jan 2006 by David L. Paktor 00222 * Accommodate conversion to tic_hdr_t type vocabulary. 00223 * 00224 **************************************************************************** */ 00225 00226 static void invoke_local( tic_param_t pfield ) 00227 { 00228 char local_num_buf[10]; 00229 int loc_num = (int)pfield.deflt_elem; 00230 00231 int_to_str(loc_num, local_num_buf); 00232 sprintf( eval_buf, "%s %s %s", local_num_buf, local_addr, local_op ); 00233 eval_string( eval_buf); 00234 00235 } 00236 00237 00238 /* ************************************************************************** 00239 * 00240 * Function name: locals_separator 00241 * Synopsis: Test whether the given character is the separator 00242 * between initted and uninitted Local Names. 00243 * Optionally, allow Semi-Colon as a separator and issue 00244 * an optional Advisory. 00245 * 00246 * Inputs: 00247 * Parameters: 00248 * subj One-character "subject" of the test 00249 * Global Variables: 00250 * ibm_locals_legacy_separator Allow Semi-Colon as a separator? 00251 * ibm_legacy_separator_message Issue an Advisory message? 00252 * 00253 * Outputs: 00254 * Returned Value: TRUE if the character is the separator 00255 * 00256 * Error Detection: 00257 * If the separator is Semi-Colon, and ibm_locals_legacy_separator 00258 * is TRUE, then if ibm_legacy_separator_message is TRUE, 00259 * issue an Advisory message. 00260 * If the flag to allow Semi-Colon is FALSE, then simply do not 00261 * acknowledge a valid separator. Other routines will report 00262 * an erroneous attempt to use an already-defined symbol. 00263 * 00264 * Revision History: 00265 * Updated Wed, 13 Jul 2005 by David L. Paktor 00266 * Bring the questions of whether to accept semicolon as a separator 00267 * -- and whether to issue a message for it -- under the control 00268 * of external flags (eventually set by command-line switches), 00269 * rather than being hard-compiled. 00270 * 00271 * Extraneous Remarks: 00272 * In the interest of avoiding too deeply nested "IF"s, I will 00273 * not be adhering strictly to the rules of structure. 00274 * 00275 **************************************************************************** */ 00276 00277 static bool locals_separator( char subj ) 00278 { 00279 bool retval = FALSE; 00280 /* Is it the preferred (i.e., non-legacy) separator? */ 00281 if ( subj == '|' ) 00282 { 00283 retval = TRUE; 00284 return ( retval ); 00285 } 00286 00287 if ( ibm_locals_legacy_separator ) 00288 { 00289 if ( subj == ';' ) 00290 { 00291 retval = TRUE; 00292 if ( ibm_legacy_separator_message ) 00293 { 00294 tokenization_error ( WARNING , "Semicolon as separator in " 00295 "Locals declaration is deprecated in favor of '|'\n"); 00296 } 00297 } 00298 } 00299 return ( retval ); 00300 } 00301 00302 /* ************************************************************************** 00303 * 00304 * Function name: add_local 00305 * Synopsis: Given a pointer to a name and a number, enter 00306 * them into the vocabulary for new Local names. 00307 * 00308 * Inputs: 00309 * Parameters: 00310 * lnum The assigned number 00311 * lname Pointer to the name 00312 * Local Static Variables: 00313 * local_names The vocabulary for new Local names 00314 * 00315 * Outputs: 00316 * Returned Value: NONE 00317 * Local Static Variables: 00318 * local_names Enter the new Local's name and number. 00319 * Memory Allocated: 00320 * A place into which the name will be copied 00321 * When Freed? 00322 * When forget_locals() routine frees up all memory 00323 * allocations in the "Local Names" Vocabulary. 00324 * 00325 * Process Explanation: 00326 * Allocate a stable place in memory for the name, via strdup(). 00327 * The entry's "action" will be the invoke_local() function, 00328 * defined above. The "parameter field" size is zero. 00329 * 00330 **************************************************************************** */ 00331 00332 static void add_local( TIC_P_DEFLT_TYPE lnum, char *lname) 00333 { 00334 char *lnamecopy ; 00335 00336 lnamecopy = strdup( lname); 00337 add_tic_entry( lnamecopy, invoke_local, lnum, 00338 LOCAL_VAL, 0, NULL, &local_names ); 00339 trace_creation( LOCAL_VAL, lname); 00340 } 00341 00342 00343 /* ************************************************************************** 00344 * 00345 * Function name: gather_locals 00346 * Synopsis: Collect Local names, for both initted and uninitted 00347 * Return an indication as to whether to continue 00348 * gathering Locals' names 00349 * 00350 * Inputs: 00351 * Parameters: 00352 * initted TRUE if we are gathering initted Local names. 00353 * counter Pointer to variable that's counting names. 00354 * Global Variables: 00355 * statbuf The symbol just retrieved from the input stream. 00356 * Local Static Variables: 00357 * localno Running Local-Number to be assigned 00358 * l_d_lineno Line # of Locals Declar'n start (for err mssg) 00359 * 00360 * Outputs: 00361 * Returned Value: TRUE = Ended with initted/uninitted separator 00362 * Local Static Variables: 00363 * localno Incremented for each Local name declared 00364 * local_names Enter the new locals' names into the Vocabulary. 00365 * Numeric field is assigned local number. 00366 * 00367 * Error Detection: 00368 * A Local-name that duplicates an existing name is an ERROR. 00369 * Especially if that name is <Semicolon> and the flag 00370 * called ibm_locals_legacy_separator was not set. 00371 * Issue an Error if close-curly-brace terminator is not found, 00372 * or if imbedded comment is not terminated, before end of file. 00373 * If the Separator is found a second-or-more time, issue an Error 00374 * and continue collecting uninitted Local names. 00375 * 00376 * Revision History: 00377 * Updated Thu, 24 Mar 2005 by David L. Paktor 00378 * Allow comments to be interspersed among the declarations. 00379 * Error-check duplicate Local-name. 00380 * Updated Wed, 30 Mar 2005 by David L. Paktor 00381 * Warning when name length exceeds ANSI-specified max (31 chars). 00382 * Updated Thu, 07 Jul 2005 by David L. Paktor 00383 * Protect against PC pointer-overrun due to unterminated 00384 * comment or declaration. 00385 * Error-check for numbers. 00386 * No name-length check; doesn't go into FCode anyway. 00387 * 00388 **************************************************************************** */ 00389 00390 static bool gather_locals( bool initted, int *counter ) 00391 { 00392 signed long wlen; 00393 bool retval = FALSE; 00394 00395 while ( TRUE ) 00396 { 00397 wlen = get_word(); 00398 00399 if ( wlen <= 0 ) 00400 { 00401 warn_unterm( TKERROR, "Local-Values Declaration", l_d_lineno); 00402 break; 00403 } 00404 00405 /* Allow comments to be interspersed among the declarations. */ 00406 if ( filter_comments( statbuf) ) 00407 { 00408 /* Unterminated and Multi-line checking already handled */ 00409 continue; 00410 } 00411 /* Is this the terminator or the separator? */ 00412 if ( wlen == 1 ) /* Maybe */ 00413 { 00414 /* Check for separator */ 00415 if (locals_separator( statbuf[0] ) ) 00416 { 00417 /* If gathering initted Local names, separator is legit */ 00418 if ( initted ) 00419 { 00420 retval = TRUE; 00421 break; 00422 }else{ 00423 tokenization_error ( TKERROR, 00424 "Excess separator -- %s -- found " 00425 "in Local-Values declaration", statbuf); 00426 in_last_colon(); 00427 continue; 00428 } 00429 } 00430 /* Haven't found the separator. Check for the terminator */ 00431 if ( statbuf[0] == '}' ) 00432 { 00433 break; 00434 } 00435 } 00436 /* It was not the terminator or the separator */ 00437 { 00438 long tmp; 00439 char *where_pt1; char *where_pt2; 00440 /* Error-check for duplicated names */ 00441 if ( word_exists ( statbuf, &where_pt1, &where_pt2 ) ) 00442 { 00443 tokenization_error ( TKERROR, "Cannot declare %s " 00444 "as a Local-Name; it's already defined %s%s", 00445 statbuf, where_pt1, where_pt2 ); 00446 show_node_start(); 00447 continue; 00448 } 00449 /* Error-check for numbers. */ 00450 if ( get_number(&tmp) ) 00451 { 00452 tokenization_error ( TKERROR, "Cannot declare %s " 00453 "as a Local-Name; it's a number.\n", statbuf ); 00454 continue; 00455 } 00456 00457 /* We've got a valid new local-name */ 00458 /* Don't need to check name length; it won't go into the FCode */ 00459 00460 /* Increment our counting-v'ble */ 00461 *counter += 1; 00462 00463 /* Define our new local-name in the Locals' vocabulary */ 00464 add_local( localno, statbuf ); 00465 00466 /* Bump the running Local-Number */ 00467 localno++; 00468 00469 } 00470 } 00471 return ( retval ); 00472 } 00473 00474 00475 /* ************************************************************************** 00476 * 00477 * Function name: activate_locals 00478 * Synopsis: Compile-in the call to {push-locals} that 00479 * the new definition under construction will need, 00480 * now that the Locals have been declared. 00481 * 00482 * Inputs: 00483 * Parameters: NONE 00484 * Global Variables: 00485 * num_ilocals First argument to {push-locals} 00486 * num_ulocals Second argument to {push-locals} 00487 * push_locals Name of {push-locals} routine. 00488 * 00489 * Outputs: 00490 * Returned Value: NONE 00491 * Local Static Variables: 00492 * eval_buf Phrase constructed here; will become 00493 * new Source Input Buffer, temporarily 00494 * 00495 * Error Detection: 00496 * If the Local Values Support FCode source-file was not 00497 * FLOADed into the user's tokenization source, then 00498 * the function {push-locals} will be an "unknown name". 00499 * 00500 * Process Explanation: 00501 * We are going to generate a string of the form: 00502 * " #ilocals #ulocals {push-locals}" 00503 * and pass it to the Parser for evaluation. 00504 * The string-buffer may be local, but it must be stable. 00505 * 00506 * Question under consideration.: 00507 * Do we want to check if {push-locals} is an unknown name, 00508 * and give the user a hint of what's needed? And, if so, 00509 * do we do it only once, or every time? 00510 * 00511 **************************************************************************** */ 00512 00513 static void activate_locals( void ) 00514 { 00515 char ilocals_buf[10]; 00516 char ulocals_buf[10]; 00517 00518 int_to_str(num_ilocals, ilocals_buf ); 00519 int_to_str(num_ulocals, ulocals_buf ); 00520 sprintf( eval_buf,"%s %s %s",ilocals_buf, ulocals_buf, push_locals); 00521 eval_string( eval_buf); 00522 } 00523 00524 /* ************************************************************************** 00525 * 00526 * Function name: error_check_locals 00527 * Synopsis: Indicate whether Locals declaration is erronious 00528 * 00529 * Inputs: 00530 * Parameters: NONE 00531 * Global Variables: 00532 * incolon TRUE if colon def'n is in effect. 00533 * opc FCode Output buffer Position Counter 00534 * lastcolon Value of opc when Colon def'n was started 00535 * 00536 * Outputs: 00537 * Returned Value: TRUE if found errors severe enough to 00538 * preclude further processing of Decl'n 00539 * 00540 * Errors Detected: 00541 * Colon definition not in effect. ERROR and return TRUE. 00542 * Locals declaration inside body of colon-definition (i.e., after 00543 * something has been compiled-in to it) is potentially risky, 00544 * but may be valid, and is a part of legacy practice. It 00545 * will not be treated as an outright ERROR, but it will 00546 * generate a WARNING... 00547 * Multiple locals declarations inside a single colon-definition 00548 * are completely disallowed. ERROR and return TRUE. 00549 * Locals declaration inside a control-structure is prohibited. 00550 * Generate an ERROR, but return FALSE to allow processing 00551 * of the declaration to continue. 00552 * 00553 **************************************************************************** */ 00554 00555 /* The value of lastcolon when Locals Declaration is made. 00556 * If it's the same, that detects multiple locals declaration attempt. 00557 */ 00558 static int last_local_colon = 0; 00559 00560 static bool error_check_locals ( void ) 00561 { 00562 bool retval = FALSE; 00563 00564 if ( ! incolon ) 00565 { 00566 tokenization_error ( TKERROR, 00567 "Can only declare Locals inside of a Colon-definition.\n"); 00568 retval = TRUE; 00569 } else { 00570 if ( last_local_colon == lastcolon ) 00571 { 00572 tokenization_error ( TKERROR, "Excess Locals Declaration"); 00573 in_last_colon(); 00574 retval = TRUE; 00575 }else{ 00576 last_local_colon = lastcolon; 00577 if ( opc > lastcolon ) 00578 { 00579 tokenization_error ( WARNING, 00580 "Declaring Locals after the body of a Colon-definition " 00581 "has begun is not recommended.\n"); 00582 } 00583 announce_control_structs( TKERROR, 00584 "Local-Values Declaration encountered", 00585 last_colon_abs_token_no); 00586 } 00587 } 00588 return ( retval ); 00589 } 00590 00591 /* ************************************************************************** 00592 * 00593 * Function name: declare_locals 00594 * Synopsis: Process (or Ignore) the Declaration of Locals, 00595 * upon encountering Curly-brace ( { ) 00596 * 00597 * Inputs: 00598 * Parameters: 00599 * ignoring TRUE if "Ignoring" 00600 * Global Variables: 00601 * statbuf Next symbol to process. 00602 * lineno Current Line Number in Input File 00603 * report_multiline FALSE to suspend multiline warning 00604 * 00605 * Outputs: 00606 * Returned Value: NONE 00607 * Global Variables: 00608 * statbuf Advanced to end of Locals Declaration. 00609 * pc Bumped past the close-curly-brace 00610 * Local Static Variables: 00611 * localno Init'd, then updated by gather_locals() 00612 * l_d_lineno Line Number of start of Locals Declaration 00613 * 00614 * Error Detection: 00615 * See error_check_locals() 00616 * After Error messages, will bypass further processing until the 00617 * terminating close-curly-brace of a Locals Declaration. 00618 * If the terminating close-curly-brace missing under those 00619 * circumstances, issue an Error 00620 * If terminating close-curly-brace is missing when the Locals 00621 * Declaration is otherwise valid, gather_locals() will 00622 * detect and report the Error. 00623 * Warning if multiline declaration. Because embedded comments 00624 * may also supppress the multiline warning, we need to save 00625 * and restore the state of the report_multiline switch... 00626 * 00627 **************************************************************************** */ 00628 00629 void declare_locals ( bool ignoring) 00630 { 00631 num_ilocals = 0; 00632 num_ulocals = 0; 00633 localno = 0; 00634 00635 l_d_lineno = lineno; 00636 bool sav_rep_mul_lin = report_multiline; 00637 report_multiline = TRUE; 00638 00639 if ( ignoring || error_check_locals() ) 00640 { 00641 if ( skip_until ( '}' ) ) 00642 { 00643 warn_unterm(TKERROR, 00644 "misplaced Local-Values Declaration", l_d_lineno); 00645 }else{ 00646 pc++ ; /* Get past the close-curly-brace */ 00647 } 00648 }else{ 00649 if (gather_locals( TRUE, &num_ilocals ) ) 00650 { 00651 gather_locals( FALSE, &num_ulocals ); 00652 } 00653 } 00654 00655 /* If PC has reached the END, gather_locals() will 00656 * have already issued an "unterminated" Error; 00657 * a "multiline" warning would be redundant 00658 * repetitive, unnecessary, excessive, unaesthetic 00659 * and -- did I already mention? -- redundant. 00660 */ 00661 if ( pc < end ) 00662 { 00663 report_multiline = sav_rep_mul_lin; 00664 warn_if_multiline( "Local-Values declaration", l_d_lineno); 00665 } 00666 00667 /* Don't do anything if no Locals were declared */ 00668 /* This could happen if the { } field is empty */ 00669 if ( localno != 0 ) 00670 { 00671 activate_locals(); 00672 } 00673 } 00674 00675 /* ************************************************************************** 00676 * 00677 * Function name: handle_local 00678 * Synopsis: Process the given name as a Local Name; 00679 * indicate if it was a valid Local Name. 00680 * 00681 * Inputs: 00682 * Parameters: 00683 * lname The "Local" name for which to look 00684 * Local Static Variables: 00685 * local_names The vocabulary for Local names 00686 * 00687 * Outputs: 00688 * Returned Value: TRUE if the name is a valid "Local Name" 00689 * 00690 **************************************************************************** */ 00691 00692 static bool handle_local( char *lname) 00693 { 00694 bool retval = handle_tic_vocab( lname, local_names ); 00695 return ( retval ) ; 00696 } 00697 00698 /* ************************************************************************** 00699 * 00700 * Function name: lookup_local 00701 * Synopsis: Return a pointer to the data-structure of the named 00702 * word, only if it was a valid Local Name. 00703 * 00704 * Inputs: 00705 * Parameters: 00706 * lname The "Local" name for which to look 00707 * Local Static Variables: 00708 * local_names The vocabulary for Local names 00709 * 00710 * Outputs: 00711 * Returned Value: Pointer to the data-structure, or 00712 * NULL if not found. 00713 * 00714 **************************************************************************** */ 00715 00716 tic_hdr_t *lookup_local( char *lname) 00717 { 00718 tic_hdr_t *retval = lookup_tic_entry( lname, local_names ); 00719 return ( retval ) ; 00720 } 00721 00722 00723 /* ************************************************************************** 00724 * 00725 * Function name: create_local_alias 00726 * Synopsis: Create an alias in the "Local Names" Vocabulary 00727 * 00728 * Associated FORTH word: ALIAS 00729 * 00730 * Inputs: 00731 * Parameters: 00732 * old_name Name of existing entry 00733 * new_name New name for which to create an entry 00734 * 00735 * Outputs: 00736 * Returned Value: TRUE if old_name found in "Locals" vocab 00737 * Global Variables: 00738 * local_names Will point to the new entry 00739 * Memory Allocated: 00740 * Memory for the new entry, by the support routine 00741 * When Freed? 00742 * When forget_locals() routine frees up all memory 00743 * allocations in the "Local Names" Vocabulary. 00744 * 00745 **************************************************************************** */ 00746 00747 bool create_local_alias(char *new_name, char *old_name) 00748 { 00749 bool retval = create_tic_alias( new_name, old_name, &local_names ); 00750 return ( retval ); 00751 } 00752 00753 /* ************************************************************************** 00754 * 00755 * Function name: exists_as_local 00756 * Synopsis: Simply confirm whether a given name exists 00757 * within the Locals vocabulary. 00758 * 00759 * Inputs: 00760 * Parameters: 00761 * stat_name Name to look up 00762 * 00763 * Outputs: 00764 * Returned Value: TRUE if stat_name was a Local 00765 * 00766 **************************************************************************** */ 00767 00768 bool exists_as_local( char *stat_name ) 00769 { 00770 bool retval = exists_in_tic_vocab(stat_name, local_names ); 00771 return ( retval ); 00772 } 00773 00774 00775 /* ************************************************************************** 00776 * 00777 * Function name: assign_local 00778 * Synopsis: Process the "Assign to a Local" operator ( -> ) 00779 * 00780 * Inputs: 00781 * Parameters: NONE 00782 * Global Variables: 00783 * statbuf Next symbol to process 00784 * pc Input-source Scanning pointer 00785 * lineno Input-source Line Number. Used for Err Mssg. 00786 * 00787 * Outputs: 00788 * Returned Value: NONE 00789 * Global Variables: 00790 * statbuf Advanced to next symbol 00791 * pc Advanced; may be unchanged if error. 00792 * lineno Advanced; may be unchanged if error 00793 * local_op Will be set to Store and then reset to Fetch. 00794 * Global Behavior: 00795 * Construct a phrase and pass it to the Tokenizer. 00796 * 00797 * Error Detection: 00798 * If next symbol is not a Local name, print ERROR message 00799 * and restore pc so that the next symbol will be 00800 * processed by ordinary means. 00801 * In the extremely unlikely case that -> is last symbol in 00802 * the source-file, report an ERROR. 00803 * 00804 * Process Explanation: 00805 * Save the PC. 00806 * Get the next symbol; check for end-of-file. 00807 * Set Local Operator ( local_op ) to "Store", to prepare to apply it. 00808 * Pass the next symbol to handle_local() . 00809 * If handle_local() failed to find the name, you have 00810 * detected an error; restore pc . 00811 * Otherwise, you have invoked the local and applied "Store" to it. 00812 * At the end, reset local_op to "Fetch". 00813 * 00814 **************************************************************************** */ 00815 00816 void assign_local ( void ) 00817 { 00818 signed long wlen; 00819 bool is_okay; 00820 u8 *savd_pc = pc; 00821 unsigned int savd_lineno = lineno; 00822 00823 wlen = get_word(); 00824 00825 if ( wlen <= 0 ) 00826 { 00827 warn_unterm(TKERROR, "Locals Assignment", lineno); 00828 return; 00829 } 00830 00831 local_op = "!"; /* Set to Store */ 00832 00833 is_okay = handle_local( statbuf); 00834 if( INVERSE(is_okay) ) 00835 { 00836 tokenization_error ( TKERROR, 00837 "Cannot apply -> to %s, only to a declared Local.\n", statbuf ); 00838 pc = savd_pc; 00839 lineno = savd_lineno; 00840 } 00841 local_op = "@"; /* Reset to Fetch */ 00842 } 00843 00844 /* ************************************************************************** 00845 * 00846 * Function name: finish_locals 00847 * Synopsis: Compile-in the call to {pop-locals} that the 00848 * new definition under construction will need 00849 * when it's about to complete execution, i.e., 00850 * before an EXIT or a SemiColon. But only if the 00851 * current definition under construction is using Locals. 00852 * 00853 * Inputs: 00854 * Parameters: NONE 00855 * 00856 * Local Static Variables: 00857 * localno Total # of Locals. 00858 * Both a param to {pop-locals} 00859 * and an indicator that Locals are in use. 00860 * pop_locals Name of {pop-locals} routine. 00861 * 00862 * Outputs: 00863 * Returned Value: NONE 00864 * Local Static Variables: 00865 * eval_buf Phrase constructed here; will become new 00866 * Source Input Buffer, temporarily 00867 * 00868 * Error Detection: 00869 * If the Local Values Support FCode source-file was not 00870 * FLOADed into the user's tokenization source, then 00871 * the function {pop-locals} will be an "unknown name". 00872 * 00873 * Revision History: 00874 * Updated Fri, 24 Feb 2006 by David L. Paktor 00875 * The eval_string() routine no longer calls its own 00876 * instance of tokenize() . In order to make a 00877 * smooth transition between the processing the 00878 * internally-generated string and the resumption 00879 * of processing the source file, it simply sets 00880 * up the string to be processed next. 00881 * In this case, however, we need to have the string 00882 * processed right away, as the calling routine 00883 * emits a token that must follow those generated 00884 * by this. 00885 * Fortunately, we know the exact contents of the string. 00886 * Two calls to tokenize_one_word() will satisfy the 00887 * requirement. 00888 * 00889 **************************************************************************** */ 00890 00891 void finish_locals ( void ) 00892 { 00893 /* Don't do anything if Locals are not in use */ 00894 if ( localno > 0 ) 00895 { 00896 char nlocals_buf[10]; 00897 00898 int_to_str(localno, nlocals_buf ); 00899 sprintf( eval_buf,"%s %s",nlocals_buf, pop_locals); 00900 eval_string( eval_buf); 00901 tokenize_one_word( get_word() ); 00902 tokenize_one_word( get_word() ); 00903 } 00904 } 00905 00906 /* ************************************************************************** 00907 * 00908 * Function name: forget_locals 00909 * Synopsis: Remove the Locals' names from the special Vocabulary 00910 * free-up their allocated memory, and reset the Locals' 00911 * counters (which are also the indication that Locals 00912 * are in use). This is done at the time a SemiColon 00913 * is processed. But only if the current definition 00914 * under construction is using Locals. 00915 * 00916 * Inputs: 00917 * Parameters: NONE 00918 * Local Static Variables: 00919 * local_names The vocabulary for new Local names 00920 * 00921 * Outputs: 00922 * Returned Value: NONE 00923 * Local Static Variables: 00924 * local_names Emptied and pointing at NULL. 00925 * num_ilocals Reset to zero 00926 * num_ulocals ditto 00927 * localno ditto 00928 * Memory Freed 00929 * All memory allocations in the "Local Names" Vocabulary. 00930 * 00931 **************************************************************************** */ 00932 00933 void forget_locals ( void ) 00934 { 00935 /* Don't do anything if Locals are not in use */ 00936 if ( localno != 0 ) 00937 { 00938 reset_tic_vocab( &local_names, NULL ) ; 00939 00940 num_ilocals = 0; 00941 num_ulocals = 0; 00942 localno = 0; 00943 } 00944 }