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 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
/*
* OpenBIOS - free your system!
* ( FCode tokenizer )
*
* This program is part of a free implementation of the IEEE 1275-1994
* Standard for Boot (Initialization Configuration) Firmware.
*
* Copyright (C) 2001-2005 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
*
*/
/* **************************************************************************
*
* Support routines for managing device-node vocabularies
*
* (C) Copyright 2005 IBM Corporation. All Rights Reserved.
* Module Author: David L. Paktor dlpaktor@us.ibm.com
*
**************************************************************************** */
/* **************************************************************************
*
* The vocabulary that is created for a device-node must not remain
* available outside of that node. Also, nodes may be nested,
* child within parent.
* An attempt within a child-node to access directly a method defined
* in the parent must be flagged as an error. (Consider what would
* happen if the method in the parent-node used instance data, and
* the child-node has an instance of its own.)
* The correct way is to invoke the method via "$call-parent" or the like.
*
* We will, however, allow the user to specify a group of exceptions,
* words whose scope will be "global" within the tokenization.
* When "global" scope is initiated, definitions will be made to
* the "core" vocabulary until "device" scope is resumed.
* That will (mostly) all be handled in dictionary.c
*
**************************************************************************** */
/* **************************************************************************
*
* Functions Exported:
* new_device_vocab Create the new device-node's data-structure
* delete_device_vocab Remove device-node's data-structure
* finish_device_vocab Remove struct and give messages when
* device is "finish"ed.
* exists_in_ancestor Issue a Message if the given word exists
* in an ancestor of the current dev-node.
*
**************************************************************************** */
/* **************************************************************************
*
* Still to be done:
* Add a pair of fields to the data-structure for the Input File and
* Line Number where "finish-device" occurred. When a device-node
* is "finish"ed, do not delete it, but instead fill in those
* fields and the move the node to a separate linked-list.
* When looking whether a word exists in an ancestor-node, also
* check whether it was in a device-node that was finished and
* print both where it was started and where it was finished.
*
**************************************************************************** */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "devnode.h"
#include "errhandler.h"
#include "scanner.h"
#include "vocabfuncts.h"
#include "flowcontrol.h"
#include "stream.h"
#include "ticvocab.h"
/* **************************************************************************
*
* Tokenization starts with an implicit "new-device" in effect.
* The top-level device-node is never removed.
*
* Initialize it here
*
**************************************************************************** */
char default_top_dev_ifile_name[] = "Start of tokenization";
static device_node_t top_level_dev_node = {
NULL , /* parent_node */
default_top_dev_ifile_name , /* ifile_name.
* Something to show, Just In Case
*/
0 , /* line_no */
NULL , /* tokens_vocab */
};
/* **************************************************************************
*
* Global Variables Exported.
* Pointers to:
* current_device_node data-structure of current device-node
* current_definitions vocab into which to add def'ns.
*
**************************************************************************** */
device_node_t *current_device_node = &top_level_dev_node;
tic_hdr_t **current_definitions = &(top_level_dev_node.tokens_vocab);
/* **************************************************************************
*
* Internal Static Variables
* These are used to support the routines in_what_node()
* and show_node_start() , which are used to facilitate
* certain kinds of Messaging, as described later.
*
* in_what_buffr Buffer for the in_what_node() string
* show_where TRUE if the string needs to be followed-up
* show_which TRUE if follow-up should be just_where_started()
* rather than just_started_at()
* in_what_line Line Number to use in the follow-up
* in_what_file File Name to use in the follow-up
*
**************************************************************************** */
static char in_what_buffr[50]; /* Ought to be more than enough. */
static bool show_where = FALSE;
static bool show_which;
static int in_what_line;
static char *in_what_file;
/* **************************************************************************
*
* Function name: dev_vocab_control_struct_check
* Synopsis: Issue Warnings for unresolved flow-control constructs
* at start or end of a device-node.
*
* Inputs:
* Parameters: NONE
* Global Variables:
* statbuf The command being processed.
*
* Outputs:
* Returned Value: NONE
* Printout:
* Handled by announce_control_structs() routine
*
* Error Detection:
* Handled by announce_control_structs() routine
*
* Process Explanation:
* Set up a buffer with the error message, based on statbuf
* and pass it to announce_control_structs()
* Release it when done.
*
**************************************************************************** */
static void dev_vocab_control_struct_check( void)
{
char *ccs_messg;
ccs_messg = safe_malloc(strlen(statbuf) + 32,
"Device-Node control-structure check");
strcpy( ccs_messg, statbuf );
strupr( ccs_messg);
strcat( ccs_messg, " encountered");
announce_control_structs( WARNING, ccs_messg, 0 );
free( ccs_messg);
}
/* **************************************************************************
*
* Function name: new_device_vocab
* Synopsis: Create and initialize the data-structure for a
* new device-node when a "new-device" is created,
* with messages as appropriate.
*
* Inputs:
* Parameters: NONE
* Global Variables:
* statbuf The word that was just read.
* iname Current Input-File Name
* lineno Current line-number
*
* Outputs:
* Returned Value: NONE
* Global Variables:
* current_device_node Will point to the new data-structure
* Memory Allocated
* Space for the new device_node_t data-structure
* Space for a copy of the current input file name
* When Freed?
* By delete_device_vocab(), when the device-node is "finish"ed.
* Printout:
* Advisory message.
*
* Error Detection:
* In immediate-execution mode, Control Structures that have not
* been completed are questionable; Issue WARNINGS via the
* dev_vocab_control_struct_check() routine.
*
* Process Explanation:
* This routine is called when "new-device" is invoked, but only
* if we are in immediate-execution mode.
* Later on, in ERROR- or INFOrmative messages, we will want to
* be able to refer to the file and line-number in which this
* was encountered, so we include them in the structure.
*
**************************************************************************** */
void new_device_vocab( void )
{
device_node_t *new_node_data;
dev_vocab_control_struct_check();
/* Advisory message will mention previous device-node
* if there was one. Either way starts out the same:
*/
#define NEW_DEV_MSG_START "Encountered %s. Starting new device-node."
if ( current_device_node == &top_level_dev_node )
{
tokenization_error(INFO, NEW_DEV_MSG_START "\n", statbuf );
}else{
tokenization_error(INFO, NEW_DEV_MSG_START
" Suspending definitions of parent-device node", statbuf );
started_at( current_device_node->ifile_name,
current_device_node->line_no );
}
/* Now to business... */
new_node_data = safe_malloc( sizeof(device_node_t),
"creating new-device vocab data" );
new_node_data->parent_node = current_device_node;
new_node_data->ifile_name = strdup(iname);
new_node_data->line_no = lineno;
new_node_data->tokens_vocab = NULL;
current_device_node = new_node_data;
current_definitions = &(current_device_node->tokens_vocab);
}
/* **************************************************************************
*
* Function name: delete_device_vocab
* Synopsis: Remove the vocabularies of the current device-node,
* along with its data-structure, when the device
* is "finish"ed; do not print messages.
* Do not remove the top-level device-node data-struct.
*
* Associated FORTH words: FINISH_DEVICE (interpretive state)
* END0 END1
* Associated Tokenizer directives: RESET-SYMBOLS (in "Normal" mode)
* FCODE-END
*
* Inputs:
* Parameters: NONE
* Global Variables:
* current_device_node Points to current device's struct
* Leads to chain of dev-node structs
*
* Outputs:
* Returned Value:
* Global Variables:
* current_device_node Parent-device's struct becomes current
* Memory Freed
* All that was allocated for the tokens and the definers
* vocabs in the current device-node
* The copy of the input file name, except the top-level
* The current_device_node data-structure, except the top-level
*
**************************************************************************** */
void delete_device_vocab( void )
{
reset_tic_vocab( current_definitions, NULL );
if ( current_device_node != &top_level_dev_node )
{
device_node_t *temp_node = current_device_node;
current_device_node = current_device_node->parent_node;
free( temp_node->ifile_name );
free(temp_node);
}
current_definitions = &(current_device_node->tokens_vocab);
}
/* **************************************************************************
*
* Function name: finish_device_vocab
* Synopsis: Remove the device-node data-structure and all its
* vocabularies when the device is "finish"ed,
* with appropriate messages.
* Do not remove the top-level device node data-struct.
*
* Associated FORTH word: FINISH_DEVICE
*
* Inputs:
* Parameters: NONE
* Global Variables:
* current_device_node Current device's struct pointer
*
* Outputs:
* Returned Value: NONE
* Global Variables:
* current_device_node Parent-device's struct becomes current
* Printout:
* Advisory message.
*
* Error Detection:
* If current_device_node is already pointing at the top-level
* device node, it means there was no corresponding NEW-DEVICE
* Issue an ERROR.
* In immediate-execution mode, Control Structures that have not
* been completed are questionable; Issue WARNINGS via the
* dev_vocab_control_struct_check() routine.
*
* Process Explanation:
* This routine is called when "finish-device" is invoked, but only
* if we are in immediate-execution mode.
*
**************************************************************************** */
void finish_device_vocab( void )
{
bool at_top_level;
dev_vocab_control_struct_check();
/* We never remove the top-level device-node vocabulary,
* so we need to test whether we're about to.
*/
at_top_level = BOOLVAL( current_device_node == &top_level_dev_node );
if ( at_top_level )
{
tokenization_error( TKERROR,
"Encountered %s without corresponding NEW-DEVICE. "
"Resetting definitions since start of tokenization.\n",
statbuf );
}else{
tokenization_error(INFO,
"Encountered %s. Resetting definitions of device node",
statbuf );
started_at( current_device_node->ifile_name,
current_device_node->line_no );
}
/* Now to business... */
delete_device_vocab();
/* Did we just get to the top-level device-node vocabulary
* when we weren't before?
*/
if ( INVERSE(at_top_level) )
{
if ( current_device_node == &top_level_dev_node )
{
tokenization_error(INFO,
"Resuming definitions since start of tokenization.\n" );
}else{
tokenization_error(INFO,
"Resuming definitions of parent device-node" );
started_at( current_device_node->ifile_name,
current_device_node->line_no );
}
}
}
/* **************************************************************************
*
* Function name: in_what_node
* Synopsis: Format a string for use in a Message that might
* identify the start of the given device-node.
*
* Inputs:
* Parameters:
* the_node The device-node vocabulary about which
* to construct the identifying phrase.
* Local Static Variables:
* in_what_buffr Buffer in which to format the string.
* Global Variables:
* current_definitions Device-node vocabulary currently
* in effect.
*
* Outputs:
* Returned Value: Pointer to buffer w/ formatted string
* Local Static Variables:
* in_what_buffr Will contain the formatted string.
* show_where TRUE if the string needs to be followed-up
* (i.e., did not contain a terminating
* new-line) by just_where_started()
* or by just_started_at()
* show_which TRUE if the follow-up call should be
* to just_where_started() rather
* than to just_started_at()
* in_what_line Copy of line_no field from the_node
* in_what_file Copy of ifile_name field from the_node
*
* Process Explanation:
* Calling routine must ascertain that Global-scope is not in effect.
* The returned phrase can be used as a string argument in a Message.
* Set show_where TRUE if the_node->line_no is non-zero.
* Set show_which TRUE if the_node is either the Current or the
* Top-Level device-node
* If the originating line-number in the given Node structure is zero,
* the returned phrase will contain a terminating new-line.
* (This only happens if the given Node is the top-level Node,
* and it's the Current Node, and the "official" starting-point
* hasn't yet been established by an "FCode-Starter" such as
* FCODE-VERSION2 . Once that command has been given, even
* definitions that were made prior to it belong to the Node
* that started there.)
* Otherwise, show_where is returned TRUE, and show_which becomes
* relevant. If the given node is the Current or the Top-Level
* node, text about the originating file-name and line-number
* merely describes a node that is already uniquely identified,
* so the message appended to the buffer will have the phrase
* "which began" (which introduces what is known in grammar as
* an Appositive Subordinate Clause) and show_which will be
* returned TRUE. If the given node is not uniquely identifiable
* without the file- and line- phrase, then the Subordinate Clause
* is Indicative, and should be introduced with "that" (and no
* comma); in that case, we will return show_which as FALSE.
* After the calling routine displays the message in which the
* returned phrase is used, it must call show_node_start()
* to display the followe-up message, if any.
*
**************************************************************************** */
char *in_what_node(device_node_t *the_node)
{
bool top_node = BOOLVAL( the_node == &top_level_dev_node);
bool curr_node = BOOLVAL( the_node == current_device_node);
bool known_node = BOOLVAL( top_node || curr_node );
bool no_line = BOOLVAL( the_node->line_no == 0);
show_where = INVERSE( no_line );
show_which = known_node;
in_what_line = the_node->line_no;
in_what_file = the_node->ifile_name;
sprintf( in_what_buffr, "in the%s device-node%s",
INVERSE( known_node ) ? ""
: top_node ? " top-level" : " current" ,
no_line ? ".\n"
: known_node ? ", which began" : "" );
return( in_what_buffr);
}
/* **************************************************************************
*
* Function name: show_node_start
* Synopsis: Follow-up to the in_what_node() call. Print out,
* if applicable, the text about the originating
* file-name and line-number
*
* Inputs:
* Parameters: NONE
* Local Static Variables:
* show_where Nothing to do if not TRUE
* show_which TRUE if should call just_where_started()
* rather than just_started_at()
* in_what_line Line Number to use in the follow-up
* in_what_file File Name to use in the follow-up
*
* Outputs:
* Returned Value: NONE
* Local Static Variables:
* show_where Force to FALSE
* Printout:
* Follow-up to the in_what_node() call. Applicable text
* about the originating file-name and line-number.
*
* Process Explanation:
* By forcing show_where to FALSE after this is called, we
* can safely allow routines that might or might not have
* called in_what_node() to call this routine, without
* needing any additional "bookkeeping".
*
**************************************************************************** */
void show_node_start( void)
{
if ( show_where)
{
if ( show_which )
{
just_where_started( in_what_file, in_what_line);
}else{
just_started_at( in_what_file, in_what_line);
}
show_where = FALSE;
}
}
/* **************************************************************************
*
* Function name: exists_in_ancestor
* Synopsis: Issue a Message and return an indication if
* the given word exists in an ancestor of
* the current device-node.
* Used for additional error-message information.
*
*
* Inputs:
* Parameters:
* m_name "Method" name
* Global Variables:
* current_device_node Leads to chain of dev-node data-structs
* scope_is_global TRUE if "global" scope is in effect
*
* Outputs:
* Returned Value: TRUE if word found
* Printout:
* If m_name exists in an ancestor-node, print an ADVISORY
* giving the location where the ancestor originated.
*
* Error Detection:
* None here. Calling routine detected error; see below.
*
* Process Explanation:
* This routine was called as the result of detecting an error:
* viz., m_name was not found in either the current node
* or the base vocabulary. (Except: If "global" scope is
* in effect, we didn't search the current device-node).
*
**************************************************************************** */
bool exists_in_ancestor( char *m_name)
{
tic_hdr_t *found;
bool retval = FALSE;
if ( current_device_node != NULL )
{
device_node_t *grandpa = current_device_node->parent_node;
if ( scope_is_global ) grandpa = current_device_node;
for ( ; grandpa != NULL; grandpa = grandpa->parent_node )
{
found = lookup_tic_entry( m_name, grandpa->tokens_vocab);
if ( found != NULL )
{
retval = TRUE;
break;
}
}
if ( grandpa != NULL )
{
char as_what_buf[AS_WHAT_BUF_SIZE] = "";
if ( as_a_what( found->fword_defr, as_what_buf) )
{
strcat( as_what_buf, " ");
}
tokenization_error(INFO, "%s is defined %s%s", m_name,
as_what_buf, in_what_node( grandpa) );
show_node_start();
}
}
return(retval );
}