1 : /*
2 : * OpenBIOS - free your system!
3 : * ( FCode tokenizer )
4 : *
5 : * scanner.c - simple scanner for forth files.
6 : *
7 : * This program is part of a free implementation of the IEEE 1275-1994
8 : * Standard for Boot (Initialization Configuration) Firmware.
9 : *
10 : * Copyright (C) 2001-2005 by Stefan Reinauer <stepan@openbios.org>
11 : *
12 : * This program is free software; you can redistribute it and/or modify
13 : * it under the terms of the GNU General Public License as published by
14 : * the Free Software Foundation; version 2 of the License.
15 : *
16 : * This program is distributed in the hope that it will be useful,
17 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : * GNU General Public License for more details.
20 : *
21 : * You should have received a copy of the GNU General Public License
22 : * along with this program; if not, write to the Free Software
23 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
24 : *
25 : */
26 :
27 : /* **************************************************************************
28 : * Modifications made in 2005 by IBM Corporation
29 : * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
30 : * Modifications Author: David L. Paktor dlpaktor@us.ibm.com
31 : **************************************************************************** */
32 :
33 : #include <stdio.h>
34 : #include <stdlib.h>
35 : #include <unistd.h>
36 : #ifdef __GLIBC__
37 : #define __USE_XOPEN_EXTENDED
38 : #endif
39 : #include <string.h>
40 : #include <time.h>
41 : #include <ctype.h>
42 :
43 : #include "macros.h"
44 : #include "stack.h"
45 : #include "stream.h"
46 : #include "emit.h"
47 : #include "toke.h"
48 : #include "dictionary.h"
49 : #include "vocabfuncts.h"
50 : #include "scanner.h"
51 : #include "errhandler.h"
52 : #include "tokzesc.h"
53 : #include "conditl.h"
54 : #include "flowcontrol.h"
55 : #include "usersymbols.h"
56 : #include "clflags.h"
57 : #include "devnode.h"
58 : #include "tracesyms.h"
59 : #include "nextfcode.h"
60 :
61 : #include "parselocals.h"
62 :
63 : /* **************************************************************************
64 : *
65 : * Some VERY IMPORTANT global variables follow
66 : *
67 : **************************************************************************** */
68 :
69 : u8 *statbuf=NULL; /* The word just read from the input stream */
70 : u8 base=0x0a; /* The numeric-interpretation base */
71 :
72 : /* pci data */
73 : bool pci_is_last_image=TRUE;
74 : u16 pci_image_rev=0x0001; /* Vendor's Image, NOT PCI Data Structure Rev */
75 : u16 pci_vpd=0x0000;
76 :
77 :
78 : /* Having to do with the state of the tokenization */
79 : bool offs16 = TRUE; /* We are using 16-bit branch- (etc) -offsets */
80 : bool in_tokz_esc = FALSE; /* TRUE if in "Tokenizer Escape" mode */
81 : bool incolon = FALSE; /* TRUE if inside a colon definition */
82 : bool haveend = FALSE; /* TRUE if the "end" code was read. */
83 : int do_loop_depth = 0; /* How deep we are inside DO ... LOOP variants */
84 :
85 : /* Used for error-checking of IBM-style Locals */
86 : int lastcolon; /* Location in output stream of latest colon-definition. */
87 :
88 : /* Used for error reporting */
89 : char *last_colon_defname = NULL; /* Name of last colon-definition */
90 : char *last_colon_filename = NULL; /* File where last colon-def'n made */
91 : unsigned int last_colon_lineno; /* Line number of last colon-def'n */
92 : bool report_multiline = TRUE; /* False to suspend multiline warning */
93 : unsigned int last_colon_abs_token_no;
94 :
95 : /* **************************************************************************
96 : * Local variables
97 : **************************************************************************** */
98 : static u16 last_colon_fcode; /* FCode-number assigned to last colon-def'n */
99 : /* Used for RECURSE */
100 :
101 : static bool do_not_overload = TRUE ; /* False to suspend dup-name-test */
102 : static bool got_until_eof = FALSE ; /* TRUE to signal "unterminated" */
103 :
104 : static unsigned int last_colon_do_depth = 0;
105 :
106 : /* State of headered-ness for name-creation */
107 : typedef enum headeredness_t {
108 : FLAG_HEADERLESS ,
109 : FLAG_EXTERNAL ,
110 : FLAG_HEADERS } headeredness ;
111 : static headeredness hdr_flag = FLAG_HEADERLESS ; /* Init'l default state */
112 :
113 : /* Local variables having to do with: */
114 : /* ... the state of the tokenization */
115 : static bool is_instance = FALSE; /* Is "instance" is in effect? */
116 : static char *instance_filename = NULL; /* File where "instance" invoked */
117 : static unsigned int instance_lineno; /* Line number of "instance" */
118 : static bool fcode_started = FALSE ; /* Only 1 fcode_starter per block. */
119 : static bool first_fc_starter = TRUE; /* Only once per tokenization... */
120 :
121 : /* ... with the state of the input stream, */
122 : static bool need_to_pop_source;
123 :
124 : /* ... with the use of the return stack, */
125 : static int ret_stk_depth = 0; /* Return-Stack-Usage-Depth counter */
126 :
127 : /* ... and with control of error-messaging. */
128 : /* Should a warning about a dangling "instance"
129 : * be issued at the next device-node change?
130 : */
131 : static bool dev_change_instance_warning = TRUE;
132 :
133 : /* Has a gap developed between "instance" and its application? */
134 : static bool instance_definer_gap = FALSE;
135 :
136 : /* Shared phrases */
137 : static char *in_tkz_esc_mode = "in Tokenizer-Escape mode.\n";
138 :
139 :
140 : /* **************************************************************************
141 : *
142 : * Function name: skip_ws
143 : * Synopsis: Advance the PC past all whitespace.
144 : * Protect against pointer over-runs
145 : *
146 : * Inputs:
147 : * Parameters: NONE
148 : * Global Variables:
149 : * pc Input-source Scanning pointer
150 : * end End of input-source buffer
151 : *
152 : * Outputs:
153 : * Returned Value: TRUE if PC reached END before non-blank char
154 : * Global Variables:
155 : * pc Advanced to first non-blank char, or to END
156 : * lineno Incremented if encountered new-line along the way
157 : *
158 : * Error Detection:
159 : * Return a TRUE if End of input-source buffer reached before
160 : * non-blank character. Not necessarily an error; allow
161 : * calling routine to decide...
162 : *
163 : **************************************************************************** */
164 :
165 : static bool skip_ws(void)
166 126801 : {
167 126801 : bool retval = TRUE;
168 : char ch_tmp;
169 :
170 269989 : for ( ; pc < end; pc++ )
171 : {
172 268373 : ch_tmp = *pc;
173 268373 : if ( (ch_tmp != '\t') && (ch_tmp != ' ') && (ch_tmp != '\n' ) )
174 : {
175 125185 : retval = FALSE;
176 125185 : break;
177 : }
178 143188 : if ( ch_tmp == '\n') lineno++;
179 : }
180 126801 : return ( retval );
181 : }
182 :
183 : /* **************************************************************************
184 : *
185 : * Function name: skip_until
186 : * Synopsis: Advance the PC to the given character.
187 : * Do not copy anything into statbuf.
188 : * Protect against pointer over-runs
189 : *
190 : * Inputs:
191 : * Parameters:
192 : * lim_ch Limiting Character
193 : * Global Variables:
194 : * pc Input-source Scanning pointer
195 : * end End of input-source buffer
196 : *
197 : * Outputs:
198 : * Returned Value: TRUE if PC reached END before finding LIM_CH
199 : * Global Variables:
200 : * pc Advanced to first occurrence of LIM_CH, or to END
201 : * lineno Incremented if encountered new-line along the way
202 : *
203 : * Error Detection:
204 : * Return a TRUE if End of input-source buffer reached before
205 : * desired character. Not necessarily an error; allow calling
206 : * routine to decide...
207 : *
208 : **************************************************************************** */
209 :
210 : bool skip_until( char lim_ch)
211 4661 : {
212 4661 : bool retval = TRUE;
213 : char ch_tmp;
214 :
215 205731 : for ( ; pc < end; pc++ )
216 : {
217 205723 : ch_tmp = *pc;
218 205723 : if ( ch_tmp == lim_ch )
219 : {
220 4653 : retval = FALSE;
221 4653 : break;
222 : }
223 201070 : if ( ch_tmp == '\n') lineno++;
224 : }
225 4661 : return ( retval );
226 : }
227 :
228 :
229 : /* **************************************************************************
230 : *
231 : * Function name: get_until
232 : * Synopsis: Return, in statbuf, the string from PC to the first
233 : * occurrence of the given delimiter-character..
234 : *
235 : * Inputs:
236 : * Parameters:
237 : * needle The given delimiter-character
238 : * Global Variables:
239 : * pc Input-source Scanning Pointer
240 : *
241 : * Outputs:
242 : * Returned Value: Length of the string obtained
243 : * Global Variables:
244 : * statbuf The string obtained from the input stream;
245 : * does not include the delimiter-character.
246 : * pc Bumped past the delimiter-character, unless
247 : * it's a new-line, in which case leave it
248 : * to be handled by get_word()
249 : * Local Static Variables:
250 : * got_until_eof Pass this as a signal that the end of the
251 : * buffer was reached before the delimiter;
252 : * Testing whether PC has reached END is
253 : * not a sufficient indication.
254 : *
255 : * Error Detection:
256 : * If string overflows statbuf allocation, ERROR, and
257 : * return "no string" (i.e., length = 0).
258 : * Otherwise, if delimiter not found before eof, keep string.
259 : * Protection against PC pointer-over-run past END is
260 : * provided by skip_until() . Reaching END will be
261 : * handled by calling routine; pass indication along
262 : * via Local Static Variable.
263 : *
264 : * Process Explanation:
265 : * Skip the delimiter-character from further input, unless it's a
266 : * new-line which will be skipped anyway. Let skip_until()
267 : * and get_word() handle incrementing line-number counters.
268 : * If skip_until() indicated reaching end-of-file, don't bump PC
269 : *
270 : * Revision History:
271 : * Updated Thu, 14 Jul 2005 by David L. Paktor
272 : * More robust testing for when PC exceeds END
273 : * Involved replacing firstchar()
274 : *
275 : **************************************************************************** */
276 :
277 : static signed long get_until(char needle)
278 518 : {
279 : u8 *safe;
280 518 : unsigned long len = 0;
281 :
282 518 : safe=pc;
283 :
284 518 : got_until_eof = skip_until(needle);
285 :
286 518 : len = pc - safe;
287 518 : if (len >= GET_BUF_MAX )
288 : {
289 2 : tokenization_error( TKERROR,
290 : "get_until buffer overflow. Max is %d.\n", GET_BUF_MAX-1 );
291 2 : len = GET_BUF_MAX-1;
292 : }
293 :
294 518 : memcpy(statbuf, safe, len);
295 518 : statbuf[len]=0;
296 :
297 518 : if ( INVERSE(got_until_eof) )
298 : {
299 514 : if ( needle != '\n' ) pc++;
300 : }
301 518 : return len;
302 : }
303 :
304 :
305 : /* **************************************************************************
306 : *
307 : * We are going to use a fairly sophisticated mechanism to
308 : * make a smooth transition between processing the body
309 : * of a Macro, a User-defined Symbol or an FLOADed file
310 : * and the resumption of processing the source file, so
311 : * that the end-of-file will only be seen at the end of
312 : * the primary input file (the one from the command-line).
313 : * This mechanism will be tied in with the get_word() routine
314 : *
315 : * We are going to define a private data-structure in which
316 : * we will save the state of the current source file,
317 : * and from which, of course, we will recover it. Its
318 : * fields will be:
319 : * A pointer to the next structure in the list.
320 : * The saved values of START END and PC
321 : * The saved values of INAME and LINENO
322 : * A flag indicating that get-word should "pause"
323 : * before popping the source-stream because
324 : * the input file will be changing.
325 : * A place from which to save and recover the state of
326 : * whether we're testing for "Multi-line" strings;
327 : * to prevent undeserved "Multi-line" warnings
328 : * during Macro processing.
329 : * A pointer to a "resumption" routine, to call
330 : * when resuming processing the source file;
331 : * the routine takes a pointer parameter
332 : * and has no return value. The pointer
333 : * may be NULL if no routine is needed.
334 : * The pointer to pass as the parameter to the
335 : * resumption routine.
336 : *
337 : **************************************************************************** */
338 :
339 : typedef struct source_state
340 : {
341 : struct source_state *next;
342 : u8 *old_start;
343 : u8 *old_pc;
344 : u8 *old_end;
345 : char *old_iname;
346 : unsigned int old_lineno;
347 : bool pause_before_pop;
348 : bool sav_rep_multlin;
349 : void (*resump_func)();
350 : _PTR resump_param;
351 : } source_state_t ;
352 :
353 : static source_state_t *saved_source = NULL;
354 :
355 :
356 : /* **************************************************************************
357 : *
358 : * Function name: push_source
359 : * Synopsis: Save the state of the current source file, in the
360 : * source_state data-structure LIFO linked-list.
361 : *
362 : * Inputs:
363 : * Parameters:
364 : * res_func Pointer to routine to call when resuming
365 : * processing the saved source file.
366 : * res_param Parameter to pass to res_func.
367 : * Either or both pointers may be NULL.
368 : * file_chg TRUE if input file is going to change.
369 : * Global Variables:
370 : * start Points to current input buffer
371 : * end Points to end of current input buffer
372 : * pc Input point in current buffer
373 : * iname Name of current source file
374 : * lineno Line number in current source file
375 : * report_multiline Whether we're testing for "Multi-line"
376 : * Local Static Variables:
377 : * saved_source Pointer to the source_state data-structure
378 : *
379 : * Outputs:
380 : * Returned Value: NONE
381 : * Local Static Variables:
382 : * saved_source Points to new source_state entry
383 : * Memory Allocated
384 : * for the new source_state entry
385 : * When Freed?
386 : * When resuming processing the source file, by drop_source().
387 : *
388 : * Process Explanation:
389 : * The calling routine will establish the new input buffer via
390 : * a call to init_inbuf() or the like.
391 : *
392 : **************************************************************************** */
393 :
394 : void push_source( void (*res_func)(), _PTR res_parm, bool file_chg )
395 1458 : {
396 : source_state_t *new_sav_src;
397 :
398 1458 : new_sav_src = safe_malloc( sizeof(source_state_t), "pushing Source state");
399 :
400 1458 : new_sav_src->next = saved_source;
401 1458 : new_sav_src->old_start = start;
402 1458 : new_sav_src->old_pc = pc;
403 1458 : new_sav_src->old_end = end;
404 1458 : new_sav_src->old_iname = iname;
405 1458 : new_sav_src->old_lineno = lineno;
406 1458 : new_sav_src->pause_before_pop = file_chg;
407 1458 : new_sav_src->sav_rep_multlin = report_multiline;
408 1458 : new_sav_src->resump_func = res_func;
409 1458 : new_sav_src->resump_param = res_parm;
410 :
411 1458 : saved_source = new_sav_src;
412 1458 : }
413 :
414 : /* **************************************************************************
415 : *
416 : * Function name: drop_source
417 : * Synopsis: Remove last saved state of source processing
418 : * from the source_state LIFO linked-list,
419 : * without (or after) restoring.
420 : *
421 : * Inputs:
422 : * Parameters: NONE
423 : * Local Static Variables:
424 : * saved_source Pointer to the source_state data-structure
425 : *
426 : * Outputs:
427 : * Returned Value: NONE
428 : * Local Static Variables:
429 : * saved_source Points to previous source_state entry
430 : * Memory Freed
431 : * Saved source_state entry that was just "dropped"
432 : *
433 : * Error Detection:
434 : * None. Called only when linked-list is known not to be at end.
435 : *
436 : **************************************************************************** */
437 :
438 : static void drop_source( void)
439 1458 : {
440 1458 : source_state_t *former_sav_src = saved_source;
441 :
442 1458 : saved_source = saved_source->next ;
443 1458 : free( former_sav_src);
444 1458 : }
445 :
446 : /* **************************************************************************
447 : *
448 : * Function name: pop_source
449 : * Synopsis: Restore the state of source processing as it was
450 : * last saved in the source_state linked-list.
451 : *
452 : * Inputs:
453 : * Parameters: NONE
454 : * Local Static Variables:
455 : * saved_source Pointer to the source_state data-structure
456 : * need_to_pop_source If TRUE, don't check before popping.
457 : *
458 : * Outputs:
459 : * Returned Value: TRUE if reached end of linked-list
460 : * Global Variables:
461 : * start Points to restored input buffer
462 : * end Points to end of restored input buffer
463 : * pc Input point in restored buffer
464 : * iname Name of restored source file
465 : * lineno Line number in restored source file
466 : * report_multiline Restored to saved value.
467 : * Local Static Variables:
468 : * saved_source Points to previous source_state entry
469 : * need_to_pop_source TRUE if postponed popping till next time
470 : * Memory Freed
471 : * Saved source-state entry that was just "popped"
472 : *
473 : * Process Explanation:
474 : * First check the need_to_pop_source flag.
475 : * If it is set, we will clear it and go ahead and pop.
476 : * If it is not set, we will check the pause_before_pop field
477 : * of the top entry in the source_state linked-list.
478 : * If the pause_before_pop field is set, we will set the
479 : * need_to_pop_source flag and return.
480 : * If it is not, we will go ahead and pop.
481 : * If we are going to go ahead and pop, we will call the
482 : * "Resume-Processing" routine (if it's not NULL) before
483 : * we restore the saved source state.
484 : *
485 : **************************************************************************** */
486 :
487 : static bool pop_source( void )
488 1859 : {
489 1859 : bool retval = TRUE;
490 :
491 1859 : if ( saved_source != NULL )
492 : {
493 1688 : retval = FALSE;
494 1688 : if ( need_to_pop_source )
495 : {
496 244 : need_to_pop_source = FALSE;
497 : }else{
498 1444 : if ( saved_source->pause_before_pop )
499 : {
500 244 : need_to_pop_source = TRUE;
501 244 : return( retval);
502 : }
503 : }
504 :
505 1444 : if ( saved_source->resump_func != NULL )
506 : {
507 610 : saved_source->resump_func( saved_source->resump_param);
508 : }
509 1444 : report_multiline = saved_source->sav_rep_multlin;
510 1444 : lineno = saved_source->old_lineno ;
511 1444 : iname = saved_source->old_iname ;
512 1444 : end = saved_source->old_end ;
513 1444 : pc = saved_source->old_pc ;
514 1444 : start = saved_source->old_start ;
515 :
516 1444 : drop_source();
517 : }
518 1615 : return( retval);
519 : }
520 :
521 :
522 : /* **************************************************************************
523 : *
524 : * Function name: get_word
525 : * Synopsis: Gather the next "word" (aka Forth Token) from the
526 : * input stream.
527 : * A Forth Token is, of course, a string of characters
528 : * delimited by white-space (blank, tab or new-line).
529 : * Do not increment line-number counters here; leave
530 : * the delimiter after the word unconsumed.
531 : *
532 : * Inputs:
533 : * Parameters: NONE
534 : * Global Variables:
535 : * pc Input-stream Scanning Pointer
536 : * Local Static Variables:
537 : * need_to_pop_source If TRUE, pop_source() as first step
538 : *
539 : * Outputs:
540 : * Returned Value: Length of "word" gotten;
541 : * 0 if reached end of file.
542 : * -1 if reached end of primary input
543 : * (I.e., end of all source)
544 : * Global Variables:
545 : * statbuf Copy of "gotten" word
546 : * pc Advanced to end of "gotten" word,
547 : * (i.e., the next word is "consumed")
548 : * unless returning zero.
549 : * abs_token_no Incremented, if valid "word" (token)
550 : * was gotten.
551 : *
552 : * Process Explanation:
553 : * Skip whitespace to the start of the token,
554 : * then skip printable characters to the end of the token.
555 : * That part's easy, but what about when skipping whitespace
556 : * brings you to the end of the input stream?
557 : * First, look at the need_to_pop_source flag. If it's set,
558 : * we came to the end of the input stream the last time
559 : * through. Now we need to pop_source() first.
560 : * Next, we start skipping whitespace; this detects when we've
561 : * reached the end of the input stream. If we have,
562 : * then we need to pop_source() again.
563 : * If pop_source() returned a TRUE, we've reached the end
564 : * of the primary input file. Return -1.
565 : * If pop_source() turned the need_to_pop_source flag
566 : * to TRUE again, then we need to "pause" until the
567 : * next time through; return zero.
568 : * Otherwise, we proceed with collecting the token as described.
569 : *
570 : * Revision History:
571 : * Updated Thu, 23 Feb 2006 by David L. Paktor
572 : * Tied this routine in with a more sophisticated mechanism that
573 : * makes a smooth transition between processing the body of
574 : * a Macro, a User-defined Symbol or an FLOADed file, and
575 : * the resumption of processing the source file, so that the
576 : * end-of-file will only be seen at the end of the primary
577 : * input file (the one that came from the command-line)
578 : * Updated Fri, 24 Feb 2006 by David L. Paktor
579 : * This is trickier than I thought. Added a global indicator
580 : * of whether a file-boundary was crossed while getting
581 : * the word; previously, that was indicated by a return
582 : * value of zero, which now means something else...
583 : * The flag, closed_stream , will be cleared every time this
584 : * routine is entered, and set whenever close_stream() is
585 : * entered.
586 : * Updated Tue, 28 Feb 2006 at 10:13 PST by David L. Paktor
587 : * Trickier still. On crossing a file-boundary, must not
588 : * consume the first word in the resumed file, for one
589 : * call; instead, return zero. Consume it on the next
590 : * call. The closed_stream flag is now irrelevant and
591 : * has gone away.
592 : *
593 : **************************************************************************** */
594 :
595 : signed long get_word( void)
596 125435 : {
597 : size_t len;
598 : u8 *str;
599 : bool keep_skipping;
600 : bool pop_result;
601 :
602 125435 : if ( need_to_pop_source )
603 : {
604 244 : pop_result = pop_source();
605 : }
606 :
607 : do {
608 126635 : keep_skipping = skip_ws();
609 126635 : if ( keep_skipping )
610 : {
611 1615 : pop_result = pop_source();
612 1615 : if ( pop_result || need_to_pop_source )
613 : {
614 415 : statbuf[0] = 0;
615 415 : if ( pop_result )
616 : {
617 171 : return -1;
618 : }
619 244 : return 0;
620 : }
621 : }
622 126220 : } while ( keep_skipping );
623 :
624 125020 : str=pc;
625 733184 : while ( (str < end) && *str && *str!='\n' && *str!='\t' && *str!=' ')
626 483144 : str++;
627 :
628 125020 : len=(size_t)(str-pc);
629 125020 : if (len >= GET_BUF_MAX )
630 : {
631 0 : tokenization_error ( FATAL,
632 : "get_word buffer overflow. Max is %d.", GET_BUF_MAX-1 );
633 : }
634 :
635 125020 : memcpy(statbuf, pc, len);
636 125020 : statbuf[len]=0;
637 :
638 : #ifdef DEBUG_SCANNER
639 : printf("%s:%d: debug: read token '%s', length=%ld\n",
640 : iname, lineno, statbuf, len);
641 : #endif
642 125020 : pc+=len;
643 125020 : abs_token_no++;
644 125020 : return len;
645 : }
646 :
647 :
648 : /* **************************************************************************
649 : *
650 : * Function name: get_word_in_line
651 : * Synopsis: Get the next word on the same line as the current
652 : * line of input. If the end of line was reached
653 : * before a word was found, print an error message
654 : * and return an indication.
655 : *
656 : * Inputs:
657 : * Parameters:
658 : * func_nam Name of the function expecting the same-line
659 : * input; for use in the Error Message.
660 : * If NULL, do not issue Error Message
661 : * Global Variables:
662 : * pc Input character pointer. Saved for comparison
663 : * lineno Current input line number. Saved for comparison
664 : *
665 : * Outputs:
666 : * Returned Value: TRUE = success. Word was acquired on same line.
667 : * Global Variables:
668 : * statbuf Advanced to the next word in the input stream.
669 : * pc Advanced if no error; restored otherwise.
670 : *
671 : * Error Detection:
672 : * If no next word is gotten (i.e., we're at end-of-file), or if
673 : * one is gotten but not on the same line, the routine will
674 : * return FALSE; if func_nam is not NULL, an ERROR Message
675 : * will be issued.
676 : * Also, the values of PC LINENO and ABS_TOKEN_NO will be reset
677 : * to the positions they had when this routine was entered.
678 : *
679 : **************************************************************************** */
680 :
681 : bool get_word_in_line( char *func_nam)
682 1733 : {
683 : signed long wlen;
684 1733 : bool retval = TRUE;
685 1733 : u8 *save_pc = pc;
686 1733 : unsigned int save_lineno = lineno;
687 1733 : unsigned int save_abs_token_no = abs_token_no;
688 :
689 : /* Copy of function name, for error message */
690 : char func_cpy[FUNC_CPY_BUF_SIZE+1];
691 :
692 : /* Do this first, in the likely event that func_nam was statbuf */
693 1733 : if ( func_nam != NULL )
694 : {
695 1620 : strncpy( func_cpy, func_nam, FUNC_CPY_BUF_SIZE);
696 1620 : func_cpy[FUNC_CPY_BUF_SIZE] = 0; /* Guarantee a null terminator */
697 : }
698 :
699 1733 : wlen = get_word();
700 1733 : if ( ( lineno != save_lineno ) || ( wlen <= 0 ) )
701 : {
702 16 : abs_token_no = save_abs_token_no;
703 16 : lineno = save_lineno;
704 16 : pc = save_pc;
705 16 : retval = FALSE;
706 16 : if ( func_nam != NULL )
707 : {
708 15 : tokenization_error ( TKERROR,
709 : "Operator %s expects its target on the same line\n",
710 : strupr(func_cpy));
711 : }
712 : }
713 1733 : return ( retval );
714 : }
715 :
716 :
717 : /* **************************************************************************
718 : *
719 : * Function name: get_rest_of_line
720 : * Synopsis: Get all the remaining text on the same line as
721 : * the current line of input. If there is no text
722 : * (not counting whitespace) before the end of line,
723 : * return an indication.
724 : *
725 : * Inputs:
726 : * Parameters: NONE
727 : * Global Variables:
728 : * pc Input character pointer. Saved for restoration
729 : * lineno Current input line number. Saved for comparison
730 : *
731 : * Outputs:
732 : * Returned Value: TRUE = success. Text was acquired on same line.
733 : * Global Variables:
734 : * statbuf Contains the text found in the input stream.
735 : * pc Advanced to end of line or of whitespace, if
736 : * no error; restored otherwise.
737 : * lineno Preserved if no error; otherwise, restored.
738 : * abs_token_no Restored if error; otherwise, advanced as normal.
739 : *
740 : * Error Detection:
741 : * Routine will return FALSE if no text is gotten on the same line.
742 : *
743 : **************************************************************************** */
744 :
745 : bool get_rest_of_line( void)
746 112 : {
747 112 : bool retval = FALSE;
748 112 : u8 *save_pc = pc;
749 112 : unsigned int save_lineno = lineno;
750 112 : unsigned int save_abs_token_no = abs_token_no;
751 :
752 112 : if ( INVERSE( skip_ws() ) )
753 : {
754 112 : if ( lineno == save_lineno )
755 : {
756 111 : signed long wlen = get_until('\n');
757 111 : if ( wlen > 0 ) retval = TRUE;
758 : }else{
759 1 : abs_token_no = save_abs_token_no;
760 1 : lineno = save_lineno;
761 1 : pc = save_pc;
762 : }
763 : }
764 112 : return( retval);
765 : }
766 :
767 :
768 : /* **************************************************************************
769 : *
770 : * Function name: warn_unterm
771 : * Synopsis: Message for "Unterminated ..." something
772 : * Show saved line-number, where the "something" started,
773 : * and the definition, if any, in which it occurred.
774 : *
775 : * Inputs:
776 : * Parameters:
777 : * severity Type of error/warning message to display
778 : * usually either WARNING or TKERROR
779 : * something String to print after "Unterminated"
780 : * saved_lineno Line-Number where the "something" started
781 : * Global Variables:
782 : * lineno Saved, then restored.
783 : * last_colon_defname Used only if unterm_is_colon is TRUE;
784 : * Local Static Variables:
785 : * unterm_is_colon See 07 Mar 2006 entry under Rev'n History
786 : *
787 : * Outputs:
788 : * Returned Value: NONE
789 : * Global Variables:
790 : * lineno Saved, then restored.
791 : * Local Static Variables:
792 : * unterm_is_colon Reset to FALSE
793 : * Printout:
794 : * Warning or Error message
795 : *
796 : * Revision History:
797 : * Updated Mon, 06 Mar 2006 by David L. Paktor
798 : * Added call to in_last_colon()
799 : * Updated Tue, 07 Mar 2006 by David L. Paktor
800 : * Call to in_last_colon() works okay in most cases except for
801 : * when the "something" is a Colon Definition; there, it
802 : * results in the phrase: ... Definition in definition of ...
803 : * which is awkward. To eliminate that, I am introducing
804 : * a Local Static Variable flag called unterm_is_colon
805 : * which will be set only in the appropriate place and
806 : * re-cleared here. It's a retro-fit, of course; it could
807 : * have been a parameter had the need for it occurred when
808 : * this routine was first constructed...
809 : *
810 : **************************************************************************** */
811 :
812 : static bool unterm_is_colon = FALSE;
813 : void warn_unterm( int severity, char *something, unsigned int saved_lineno)
814 25 : {
815 25 : unsigned int tmp = lineno;
816 25 : lineno = saved_lineno;
817 25 : if ( unterm_is_colon )
818 : {
819 3 : tokenization_error( severity, "Unterminated %s of %s\n",
820 : something, strupr( last_colon_defname) );
821 3 : unterm_is_colon = FALSE;
822 : }else{
823 22 : tokenization_error( severity, "Unterminated %s", something);
824 22 : in_last_colon();
825 : }
826 25 : lineno = tmp;
827 25 : }
828 :
829 : /* **************************************************************************
830 : *
831 : * Function name: warn_if_multiline
832 : * Synopsis: Test for "Multi-line ..." something and issue WARNING
833 : * Show saved line-number, where the "something" started
834 : *
835 : * Inputs:
836 : * Parameters:
837 : * something String to print after "Unterminated"
838 : * start_lineno Line-Number where the "something" started
839 : * Global Variables:
840 : * lineno Line-Number where we are now
841 : * iname Input file name, to satisfy ...where_started()
842 : * (Not crossing any actual file boundary.)
843 : * report_multiline TRUE = go ahead with the message
844 : *
845 : * Outputs:
846 : * Returned Value: NONE
847 : * Global Variables:
848 : * report_multiline Restored to TRUE.
849 : *
850 : * Error Detection:
851 : * Only issue message if the current lineno doesn't equal
852 : * the start_lineno
853 : *
854 : * Process Explanation:
855 : * The directive "multi-line" allows the user to specify that
856 : * the next "Multi-line ..." something is intentional, and
857 : * will cause its warning to be suppressed. It remains in
858 : * effect until it's "used"; afterwards, it's reset.
859 : *
860 : **************************************************************************** */
861 :
862 : void warn_if_multiline( char *something, unsigned int start_lineno )
863 36922 : {
864 36922 : if ( report_multiline && ( start_lineno != lineno ) )
865 : {
866 130 : tokenization_error( WARNING, "Multi-line %s, started", something);
867 130 : where_started( iname, start_lineno);
868 : }
869 36922 : report_multiline = TRUE;
870 36922 : }
871 :
872 :
873 : /* **************************************************************************
874 : *
875 : * Function name: string_remark
876 : * Synopsis: Suspend string parsing past end of line and
877 : * whitespace at start of the new line.
878 : *
879 : * Inputs:
880 : * Parameters:
881 : * errmsg_txt Text to be used for error-message.
882 : * Global Variables:
883 : * pc Input-source Scanning pointer
884 : *
885 : * Outputs:
886 : * Returned Value: NONE
887 : * Global Variables:
888 : * pc Will point to first non-blank in new line
889 : *
890 : * Error Detection:
891 : * The return value of the skip_until() or skip_ws() routine
892 : * will indicate if PC goes past END. Issue a WARNING.
893 : * The calling routine will handle things from there.
894 : *
895 : **************************************************************************** */
896 :
897 : static void string_remark(char *errmsg_txt)
898 54 : {
899 54 : unsigned int sav_lineno = lineno;
900 54 : bool eof = skip_until('\n');
901 54 : if ( ! eof )
902 : {
903 54 : eof = skip_ws();
904 : }
905 54 : if ( eof )
906 : {
907 1 : warn_unterm(WARNING, errmsg_txt, sav_lineno);
908 : }
909 :
910 54 : }
911 :
912 :
913 : /* Convert the given string to a number in the supplied base */
914 : /* Allow -- and ignore -- embedded periods. */
915 : /* The endptr param represents a pointer that will be updated
916 : * with the address of the first non-numeric character encountered,
917 : * (unless it is a NULL, in which case it is ignored).
918 : */
919 : /* There is no test for a completely invalid string;
920 : * the calling routine is responsible for ascertaining
921 : * the validity of the string being passed.
922 : */
923 : static long parse_number(u8 *start, u8 **endptr, int lbase)
924 11827 : {
925 11827 : long val = 0;
926 11827 : bool negative = FALSE ;
927 : int curr;
928 11827 : u8 *nptr=start;
929 :
930 11827 : curr = *nptr;
931 11827 : if (curr == '-')
932 : {
933 0 : negative = TRUE ;
934 0 : nptr++;
935 : }
936 :
937 37570 : for (curr = *nptr; (curr = *nptr); nptr++) {
938 26467 : if ( curr == '.' )
939 8 : continue;
940 26459 : if ( curr >= '0' && curr <= '9')
941 24765 : curr -= '0';
942 1694 : else if (curr >= 'a' && curr <= 'f')
943 1023 : curr += 10 - 'a';
944 671 : else if (curr >= 'A' && curr <= 'F')
945 2 : curr += 10 - 'A';
946 : else
947 669 : break;
948 :
949 25790 : if (curr >= lbase)
950 55 : break;
951 :
952 25735 : val *= lbase;
953 25735 : val += curr;
954 : }
955 :
956 : #ifdef DEBUG_SCANNER
957 : if (curr)
958 : printf( "%s:%d: warning: couldn't parse number '%s' (%d/%d)\n",
959 : iname, lineno, start,curr,lbase);
960 : #endif
961 :
962 11827 : if (endptr)
963 11548 : *endptr=nptr;
964 :
965 11827 : if (negative)
966 : {
967 0 : val = -val;
968 : }
969 11827 : return val;
970 : }
971 :
972 : /* **************************************************************************
973 : *
974 : * Function name: add_byte_to_string
975 : * Synopsis: Add the given byte (or character) to the string
976 : * being accumulated in statbuf, but protect
977 : * against a buffer overflow.
978 : *
979 : * Inputs:
980 : * Parameters:
981 : * nu_byte The given character to be added
982 : * walk Pointer to pointer to the position
983 : * in statbuf where the character
984 : * is to be placed
985 : * Global Variables:
986 : * statbuf Buffer where the string is accumulated
987 : * Macros:
988 : * GET_BUF_MAX Size of the buffer
989 : *
990 : * Outputs:
991 : * Returned Value: NONE
992 : * Supplied Pointers:
993 : * **walk Given character is placed here
994 : * *walk Incremented in any case
995 : *
996 : * Error Detection:
997 : * If walk has reached end of string buffer, do not place
998 : * the character, but continue to increment walk .
999 : * Calling routine will detect overflow.
1000 : *
1001 : **************************************************************************** */
1002 :
1003 : static void add_byte_to_string( u8 nu_byte, u8 **walk )
1004 1478035 : {
1005 1478035 : if ( *walk - statbuf < GET_BUF_MAX )
1006 : {
1007 1475587 : **walk = nu_byte;
1008 : }
1009 1478035 : (*walk)++;
1010 1478035 : }
1011 :
1012 : /* **************************************************************************
1013 : *
1014 : * Function name: c_string_escape
1015 : * Synopsis: Process C-style escape syntax in strings
1016 : *
1017 : * Inputs:
1018 : * Parameters:
1019 : * walk Pointer to pointer to area into
1020 : * which to put acquired values
1021 : * Global Variables:
1022 : * pc Input-source Scanning pointer
1023 : *
1024 : * Outputs:
1025 : * Returned Value: NONE
1026 : * Global Variables:
1027 : * pc Point to last character processed.
1028 : * Supplied Pointers:
1029 : * *walk Advanced by number of bytes acquired
1030 : *
1031 : * Error Detection:
1032 : * WARNING conditions. See under "Process Explanation" below.
1033 : *
1034 : * Process Explanation:
1035 : * Start with PC pointing to the first character to process
1036 : * i.e., after the backslash.
1037 : * We recognize newline, tab and numbers
1038 : * A digit-string in the current base can be converted to a number.
1039 : * The first non-numeric character ends the numeric sequence
1040 : * and gets swallowed up.
1041 : * If the number exceeds the size of a byte, use the truncated
1042 : * value and issue a WARNING.
1043 : * If the first character in the "digit"-string was non-numeric,
1044 : * use the character literally and issue a WARNING.
1045 : * If the character that ended the numeric sequence is a quote,
1046 : * it might be the end of the string, or the start of a
1047 : * special-character or even of an "( ... ) hex-sequence,
1048 : * so don't swallow it up.
1049 : *
1050 : * Still to be done:
1051 : * Better protection against PC pointer-over-run past END.
1052 : * Currently, this works, but it's held together by threads:
1053 : * Because init_stream forces a null-byte at the end of
1054 : * the input buffer, parse_number() exits immediately upon
1055 : * encountering it. This situation could be covered more
1056 : * robustly...
1057 : *
1058 : **************************************************************************** */
1059 :
1060 : static void c_string_escape( u8 **walk)
1061 159 : {
1062 159 : char c = *pc;
1063 : u8 val;
1064 : /* We will come out of this "switch" statement
1065 : * with a value for val and a decision
1066 : * as to whether to write it.
1067 : */
1068 159 : bool write_val = TRUE;
1069 :
1070 159 : switch (c)
1071 : {
1072 : case 'n':
1073 : /* newline */
1074 17 : val = '\n';
1075 17 : break;
1076 : case 't':
1077 : /* tab */
1078 27 : val = '\t';
1079 27 : break;
1080 : default:
1081 :
1082 : /* Digit-string? Convert it to a number, using the current base.
1083 : * The first non-numeric character ends the numeric sequence
1084 : * and gets swallowed up.
1085 : * If the number exceeds the size of a byte, use the truncated
1086 : * value and issue a WARNING.
1087 : * If the first character in the "digit"-string was non-numeric,
1088 : * use the character literally and issue a WARNING.
1089 : */
1090 :
1091 : /*
1092 : * If the sequence ender is a quote, it might be the end of
1093 : * the string, or the start of a special-character or even
1094 : * of an "( ... ) hex-sequence, so don't swallow it up.
1095 : */
1096 : {
1097 : long lval;
1098 115 : u8 *sav_pc = pc;
1099 115 : lval=parse_number(pc, &pc, base);
1100 115 : val = (u8)lval;
1101 : #ifdef DEBUG_SCANNER
1102 : if (verbose)
1103 : printf( "%s:%d: debug: escape code "
1104 : "0x%x\n",iname, lineno, val);
1105 : #endif
1106 115 : if ( lval > 0x0ff )
1107 : {
1108 14 : tokenization_error ( WARNING,
1109 : "Numeric String after \\ overflows byte. "
1110 : "Using 0x%02x.\n", val);
1111 : }
1112 :
1113 115 : if ( pc == sav_pc )
1114 : {
1115 : /* NOTE: Here, PC hasn't been advanced past its
1116 : * saved value, so we can count on C remaining
1117 : * unchanged since the start of the routine.
1118 : */
1119 : /* Don't use the null-byte at the end of the buffer */
1120 40 : if ( ( pc >= end )
1121 : /* or a sequence-ending quote. */
1122 : || ( c == '"' ) )
1123 : {
1124 2 : write_val = FALSE;
1125 : }else{
1126 : /* In the WARNING message, print the character
1127 : * if it's printable or show it in hex
1128 : * if it's not.
1129 : */
1130 38 : if ( (c > 0x20 ) && ( c <= 0x7e) )
1131 : {
1132 20 : tokenization_error ( WARNING,
1133 : "Unrecognized character, %c, "
1134 : "after \\ in string. "
1135 : "Using it literally.\n", c);
1136 : }else{
1137 18 : tokenization_error ( WARNING,
1138 : "Unrecognized character, 0x%02x, "
1139 : "after \\ in string. "
1140 : "Using it literally.\n", c);
1141 : }
1142 38 : val = c;
1143 : }
1144 : }
1145 : /* NOTE: Here, however, PC may have been advanced... */
1146 : /* Don't swallow the sequence-ender if it's a quote. */
1147 115 : if ( *pc == '"' )
1148 : {
1149 16 : pc--;
1150 : }
1151 :
1152 : } /* End of the "default" clause */
1153 : } /* End of the "switch" statement */
1154 :
1155 159 : if ( write_val ) add_byte_to_string( val, walk );
1156 :
1157 159 : }
1158 :
1159 : /* **************************************************************************
1160 : *
1161 : * Function name: get_sequence
1162 : * Synopsis: Process the Hex-Number option in strings
1163 : * Protect against PC pointer-over-run past END.
1164 : *
1165 : * Inputs:
1166 : * Parameters:
1167 : * **walk Pointer to pointer to area into which
1168 : * to put acquired values
1169 : * Global Variables:
1170 : * pc Input-source Scanning pointer
1171 : * end End of input-source buffer
1172 : *
1173 : * Outputs:
1174 : * Returned Value: TRUE = "Normal Completion" (I.e., not EOF)
1175 : * Global Variables:
1176 : * pc Points at terminating close-paren, or END
1177 : * lineno Input File Line-Number Counter, may be incr'd
1178 : * Supplied Pointers:
1179 : * *walk Advanced by number of values acquired
1180 : *
1181 : * Error Detection:
1182 : * End-of-file encountered before end of hex-sequence:
1183 : * Issue a Warning, conclude processing, return FALSE.
1184 : *
1185 : * Process Explanation:
1186 : * SETUP and RULES:
1187 : * Start with PC pointing to the first character
1188 : * after the '(' (Open-Paren)
1189 : * Bytes are gathered from digits in pairs, except
1190 : * when separated they are treated singly.
1191 : * Allow a backslash in the middle of the sequence
1192 : * to skip to the end of the line and past the
1193 : * whitespace at the start of the next line,
1194 : * i.e., it acts as a comment-escape.
1195 : *
1196 : * INITIALIZE:
1197 : * PV_indx = 0
1198 : * Set return-indicator to "Abnormal Completion"
1199 : * Ready_to_Parse = FALSE
1200 : * Stuff NULL into PVAL[2]
1201 : * WHILE PC is less than END
1202 : * Pick up character at PC into Next_Ch
1203 : * IF Next_Ch is close-paren :
1204 : * Set return-indicator to "Normal Completion".
1205 : * Done! Break out of loop.
1206 : * ENDIF
1207 : * IF comment-escape behavior (controlled by means of a
1208 : * command-line switch) is allowed
1209 : * IF Next_Ch is backslash :
1210 : * Skip to end-of line, skip whitespace.
1211 : * If that makes PC reach END : WARNING message.
1212 : * (Don't need to break out of loop;
1213 : * normal test will terminate.)
1214 : * CONTINUE Loop.
1215 : * (Don't increment PC; PC is already at right place).
1216 : * ENDIF
1217 : * ENDIF
1218 : * IF Next_Ch is a valid Hex-Digit character :
1219 : * Stuff it into PVAL[PV_indx]
1220 : * IF (PV_indx is 0) :
1221 : * Increment PV_indx
1222 : * ELSE
1223 : * Set Ready_to_Parse to TRUE
1224 : * ENDIF
1225 : * ELSE
1226 : * IF Next_Ch is a New-Line, increment Line Number counter
1227 : * IF (PV_indx is 1) :
1228 : * Stuff NULL into PVAL[1]
1229 : * Set Ready_to_Parse to TRUE
1230 : * ENDIF
1231 : * ENDIF
1232 : * IF Ready_to_Parse
1233 : * Parse PVAL
1234 : * Stuff into WALK
1235 : * Reset PV_indx to zero
1236 : * Reset Ready_to_Parse to FALSE
1237 : * ENDIF
1238 : * Increment PC
1239 : * REPEAT
1240 : * Return with Normal/Abnormal completion indicator
1241 : *
1242 : **************************************************************************** */
1243 :
1244 : static bool get_sequence(u8 **walk)
1245 33 : {
1246 33 : int pv_indx = 0;
1247 33 : bool retval = FALSE; /* "Abnormal Completion" indicator */
1248 33 : bool ready_to_parse = FALSE;
1249 : char next_ch;
1250 : char pval[3];
1251 :
1252 : #ifdef DEBUG_SCANNER
1253 : printf("%s:%d: debug: hex field:", iname, lineno);
1254 : #endif
1255 33 : pval[2]=0;
1256 :
1257 888 : while ( pc < end )
1258 : {
1259 854 : next_ch = *pc;
1260 854 : if ( next_ch == ')' )
1261 : {
1262 32 : retval = TRUE;
1263 32 : break;
1264 : }
1265 822 : if ( hex_remark_escape )
1266 : {
1267 685 : if ( next_ch == '\\' )
1268 : {
1269 34 : string_remark("string hex-sequence remark");
1270 34 : continue;
1271 : }
1272 : }
1273 788 : if ( isxdigit(next_ch) )
1274 : {
1275 469 : pval[pv_indx] = next_ch;
1276 469 : if ( pv_indx == 0 )
1277 : {
1278 279 : pv_indx++;
1279 : }else{
1280 190 : ready_to_parse = TRUE;
1281 : }
1282 : }else{
1283 319 : if ( next_ch == '\n' ) lineno++ ;
1284 319 : if ( pv_indx != 0 )
1285 : {
1286 89 : pval[1] = 0;
1287 89 : ready_to_parse = TRUE;
1288 : }
1289 : }
1290 788 : if ( ready_to_parse )
1291 : {
1292 279 : u8 val = parse_number(pval, NULL, 16);
1293 279 : *((*walk)++)=val;
1294 : #ifdef DEBUG_SCANNER
1295 : printf(" %02x",val);
1296 : #endif
1297 279 : pv_indx = 0;
1298 279 : ready_to_parse = FALSE;
1299 : }
1300 788 : pc++;
1301 : }
1302 : #ifdef DEBUG_SCANNER
1303 : printf("\n");
1304 : #endif
1305 33 : return ( retval );
1306 : }
1307 :
1308 : /* **************************************************************************
1309 : *
1310 : * Return the length of the string.
1311 : * Pack the string, without the terminating '"' (Quote), into statbuf
1312 : * Protect against PC pointer-over-run past END.
1313 : * Enable Quote-Backslash as a String-Remark Escape.
1314 : * Allowability of Quote-Backslash as a String-Remark is under control
1315 : * of a command-line switch (string_remark_escape ).
1316 : * Allowability of C-style escape characters is under control
1317 : * of a command-line switch ( c_style_string_escape ).
1318 : *
1319 : * Truncate string to size of Forth Packed-String (i.e., uses leading
1320 : * count-byte, so limited to 255, number that one byte can express)
1321 : * unless the string is being gathered for a Message or is being
1322 : * consumed for purposes of ignoring it, in either of which case
1323 : * that limit need not be enforced. Parameter "pack_str" controls
1324 : * this: TRUE if limit needs to be enforced.
1325 : *
1326 : * Issue WARNING if string length gets truncated.
1327 : * Issue WARNING if string crosses line.
1328 : * The issuance of the Multi-line WARNING is under control of a
1329 : * one-shot directive similar to OVERLOAD , called MULTI-LINE
1330 : *
1331 : * Still to be decided:
1332 : * Do we want to bring the allowability of strings crossing
1333 : * lines under control of a command-line switch?
1334 : *
1335 : ************************************************************************** */
1336 :
1337 : static signed long get_string( bool pack_str)
1338 36080 : {
1339 : u8 *walk;
1340 : unsigned long len;
1341 : char c;
1342 36080 : bool run = TRUE;
1343 36080 : unsigned long start_lineno = lineno; /* For warning message */
1344 :
1345 : /*
1346 : * Bump past the single whitespace character that delimits
1347 : * the command -- e.g., ." or " or suchlike -- that
1348 : * starts the string. Allow new-line to be a command-
1349 : * -delimiting whitespace character. Regard any sub-
1350 : * sequent whitespace characters as part of the string
1351 : */
1352 36080 : if (*pc++=='\n') lineno++;
1353 :
1354 36080 : got_until_eof = TRUE ;
1355 :
1356 36080 : walk=statbuf;
1357 1586321 : while (run) {
1358 1514161 : switch ((c=*pc))
1359 : {
1360 : /* Standard use of '"' (Quote) for special-char escape */
1361 : case '\"':
1362 : /* Skip the '"' (Quote) */
1363 36376 : pc++;
1364 : /* End of the buffer also ends the string cleanly */
1365 36376 : if ( pc >= end )
1366 : {
1367 0 : run = FALSE;
1368 0 : got_until_eof = FALSE ;
1369 0 : break;
1370 : }
1371 : /* Pick up the next char after the '"' (Quote) */
1372 36376 : c=*pc;
1373 36376 : switch (c)
1374 : {
1375 : case '(':
1376 33 : pc++; /* skip the '(' */
1377 33 : run = get_sequence(&walk);
1378 33 : break;
1379 :
1380 : case 'n':
1381 41 : add_byte_to_string( '\n', &walk);
1382 41 : break;
1383 : case 'r':
1384 7 : add_byte_to_string( '\r', &walk);
1385 7 : break;
1386 : case 't':
1387 35 : add_byte_to_string( '\t', &walk);
1388 35 : break;
1389 : case 'f':
1390 7 : add_byte_to_string( '\f', &walk);
1391 7 : break;
1392 : case 'l':
1393 6 : add_byte_to_string( '\n', &walk);
1394 6 : break;
1395 : case 'b':
1396 13 : add_byte_to_string( 0x08, &walk);
1397 13 : break;
1398 : case '!':
1399 14 : add_byte_to_string( 0x07, &walk);
1400 14 : break;
1401 : case '^':
1402 20 : pc++; /* Skip the up-arrow (Caret) */
1403 20 : add_byte_to_string( *pc & 0x1f , &walk);
1404 20 : break;
1405 : /* We're done after any of the whitespace
1406 : * characters follows a quote.
1407 : */
1408 : case ' ':
1409 : case '\t':
1410 : /* Advance past the terminating whitespace
1411 : * character, except newline.
1412 : * Let get_word() handle that.
1413 : */
1414 34785 : pc++;
1415 : case '\n':
1416 36071 : run=FALSE;
1417 36071 : got_until_eof = FALSE ;
1418 36071 : break;
1419 : default:
1420 : /* Control allowability of Quote-Backslash
1421 : * as a String-Remark by means of a
1422 : * command-line switch.
1423 : */
1424 129 : if ( string_remark_escape )
1425 : {
1426 121 : if ( c == '\\' )
1427 : {
1428 20 : string_remark("string-escape remark");
1429 : /* The first non-blank in the new line
1430 : * has not been processed yet.
1431 : * Back up to allow it to be.
1432 : */
1433 20 : pc--;
1434 20 : break;
1435 : }
1436 : }
1437 109 : add_byte_to_string( c, &walk);
1438 : }
1439 : break;
1440 : case '\n':
1441 : /* Allow strings to cross lines. Include the
1442 : * newline in the string. Account for it.
1443 : */
1444 218 : lineno++;
1445 : default:
1446 : /* Control allowability of C-style escape-character
1447 : * syntax by means of a command-line switch.
1448 : */
1449 1477785 : if ( c_style_string_escape )
1450 : {
1451 1477446 : if ( c == '\\' )
1452 : {
1453 159 : pc++;
1454 159 : c_string_escape(&walk );
1455 159 : break;
1456 : }
1457 : }
1458 1477626 : add_byte_to_string( c, &walk);
1459 : }
1460 : /* Advance past the char processed, unless we're done. */
1461 1514161 : if ( run ) pc++;
1462 : /* Done if we hit end of file before string was concluded */
1463 1514161 : if ( pc >= end )
1464 : {
1465 9 : run = FALSE;
1466 9 : if ( got_until_eof )
1467 : {
1468 9 : warn_unterm( WARNING, "string", start_lineno);
1469 : /* Prevent multiple messages for one error */
1470 9 : got_until_eof = FALSE;
1471 : }
1472 : }
1473 : }
1474 :
1475 36080 : warn_if_multiline( "string", start_lineno);
1476 :
1477 36080 : len = walk - statbuf;
1478 36080 : if (len >= GET_BUF_MAX )
1479 : {
1480 4 : tokenization_error ( TKERROR,
1481 : "get_string buffer overflow. Max is %d\n.", GET_BUF_MAX-1 );
1482 4 : len = GET_BUF_MAX-1;
1483 : }
1484 : #ifdef DEBUG_SCANNER
1485 : if (verbose)
1486 : printf("%s:%d: debug: scanned string: '%s'\n",
1487 : iname, lineno, statbuf);
1488 : #endif
1489 36080 : if ( pack_str && (len > STRING_LEN_MAX) )
1490 : {
1491 2 : tokenization_error ( WARNING,
1492 : "String length being truncated to %d.\n", STRING_LEN_MAX );
1493 2 : len = STRING_LEN_MAX;
1494 : }
1495 36080 : statbuf[len] = 0;
1496 :
1497 36080 : return len ;
1498 : }
1499 :
1500 :
1501 : /* **************************************************************************
1502 : *
1503 : * Function name: handle_user_message
1504 : * Synopsis: Collect a user-generated tokenization-time message;
1505 : * either print it or discard it. Shared code
1506 : * for user_message() and skip_user_message()
1507 : *
1508 : * Inputs:
1509 : * Parameters:
1510 : * delim End-of-string delimiter character.
1511 : * If it's a double-quote ("), we will use
1512 : * the get-string() routine, with all
1513 : * its options, to collect the message.
1514 : * Otherwise, we'll capture plain text from
1515 : * the input stream.
1516 : * print_it TRUE if we should print the message
1517 : * Local Static Variables:
1518 : * got_until_eof TRUE if reached end of buffer before delim.
1519 : * Global Variables:
1520 : * lineno Save, then restore.
1521 : *
1522 : * Outputs:
1523 : * Returned Value: NONE
1524 : * Global Variables:
1525 : * statbuf The string will be collected in here
1526 : *
1527 : * Printout (if print_it is TRUE):
1528 : * The string, with new-line tacked on, will be printed from
1529 : * the tokenization_error() routine as a MESSAGE.
1530 : * The line-number will be shown as of the origin of the message
1531 : *
1532 : * Error Detection:
1533 : * Error-reports will be printed regardless of print_it param.
1534 : * If delimiter was not found, show "Unterminated" warning message.
1535 : * If delimiter was " (double-quote), the get_string() routine
1536 : * already checked for a multi-line construct; if delimiter is
1537 : * a new-line, then a multi-line construct is impossible.
1538 : * otherwise, we will do the multi-line check here.
1539 : *
1540 : **************************************************************************** */
1541 :
1542 : static void handle_user_message( char delim, bool print_it )
1543 822 : {
1544 : signed long wlen;
1545 822 : unsigned int start_lineno = lineno;
1546 822 : unsigned int multiline_start = lineno; /* For warning message */
1547 822 : bool check_multiline = FALSE;
1548 822 : const char *ug_msg = "user-generated message";
1549 :
1550 822 : if ( delim == '"' )
1551 : {
1552 452 : wlen = get_string( FALSE);
1553 : }else{
1554 : /*
1555 : * When the message-delimiter is a new-line, and the
1556 : * command-delimiter was a new-line, it means the
1557 : * string length is zero; we won't bump the PC.
1558 : * Otherwise, we will honor the convention we extend
1559 : * to .( whereby, if the command is delimited
1560 : * by a new-line, we allow the string to begin
1561 : * on the next line.
1562 : */
1563 370 : if ( delim == '\n' )
1564 : {
1565 324 : if ( *pc != '\n') pc++;
1566 : }else{
1567 46 : if (*pc++=='\n') lineno++;
1568 46 : multiline_start = lineno;
1569 46 : check_multiline = TRUE;
1570 : }
1571 370 : wlen = get_until( delim );
1572 : }
1573 :
1574 822 : if ( print_it )
1575 : {
1576 582 : unsigned int tmp_lineno = lineno;
1577 582 : lineno = start_lineno;
1578 : /* Don't add a new-line to body of the message.
1579 : * Routine already takes care of that.
1580 : * Besides, buffer might be full...
1581 : */
1582 582 : tokenization_error( MESSAGE, statbuf);
1583 582 : lineno = tmp_lineno;
1584 : }
1585 :
1586 822 : if ( got_until_eof ) /* Crude but effective retrofit... */
1587 : {
1588 2 : warn_unterm(WARNING, (char *)ug_msg, start_lineno);
1589 : }else{
1590 820 : if ( check_multiline )
1591 : {
1592 44 : warn_if_multiline( (char *)ug_msg, multiline_start);
1593 : }
1594 : }
1595 822 : }
1596 :
1597 : /* **************************************************************************
1598 : *
1599 : * Function name: user_message
1600 : * Synopsis: Collect a user-generated message and
1601 : * print it at tokenization-time.
1602 : *
1603 : * Tokenizer directive (either mode):
1604 : * Synonyms String Delimiter
1605 : * [MESSAGE] #MESSAGE [#MESSAGE] end-of-line
1606 : * #MESSAGE" "
1607 : * "Tokenizer-Escape" mode directive String Delimiter
1608 : * .( )
1609 : * ." "
1610 : *
1611 : * Inputs:
1612 : * Parameter is the "parameter field" of the TIC entry, which
1613 : * was initialized to the end-of-string delimiter character.
1614 : *
1615 : * Outputs:
1616 : * Returned Value: NONE
1617 : * Printout: User-message, parsed from input.
1618 : *
1619 : * Extraneous Remarks:
1620 : * We would have preferred to simply use the "character value"
1621 : * aspect of the union, but we found portability issues
1622 : * between big- and little- -endian processors, so we still
1623 : * have to recast its type here.
1624 : *
1625 : **************************************************************************** */
1626 :
1627 : void user_message( tic_param_t pfield )
1628 582 : {
1629 582 : char delim = (char)pfield.deflt_elem ;
1630 582 : handle_user_message( delim, TRUE);
1631 582 : }
1632 :
1633 : /* **************************************************************************
1634 : *
1635 : * Function name: skip_user_message
1636 : * Synopsis: Collect a user-generated message and discard it.
1637 : * Used when ignoring a Conditional section.
1638 : *
1639 : * Tokenizer directive (either mode):
1640 : * Synonyms String Delimiter
1641 : * [MESSAGE] #MESSAGE [#MESSAGE] end-of-line
1642 : * #MESSAGE" "
1643 : * "Tokenizer-Escape" mode directive String Delimiter
1644 : * .( )
1645 : * ." "
1646 : *
1647 : * Inputs:
1648 : * Parameters:
1649 : * pfield "Parameter field" of the TIC entry, which
1650 : * was initialized to the delimiter.
1651 : *
1652 : * Outputs:
1653 : * Returned Value: NONE
1654 : * Printout: NONE
1655 : *
1656 : **************************************************************************** */
1657 :
1658 : void skip_user_message( tic_param_t pfield )
1659 240 : {
1660 240 : char delim = (char)pfield.deflt_elem ;
1661 240 : handle_user_message( delim, FALSE);
1662 240 : }
1663 :
1664 :
1665 :
1666 : /* **************************************************************************
1667 : *
1668 : * Function name: get_number
1669 : * Synopsis: If the word retrieved from the input stream is a
1670 : * valid number (under the current base) convert it.
1671 : * Return an indication if it was not.
1672 : *
1673 : * Inputs:
1674 : * Parameters:
1675 : * *result Pointer to place to return the number
1676 : * Global Variables:
1677 : * statbuf The word just read that is to be converted.
1678 : * base The current numeric-interpretation base.
1679 : *
1680 : * Outputs:
1681 : * Returned Value: TRUE = Input was a valid number
1682 : * Supplied Pointers:
1683 : * *result The converted number, if valid
1684 : * otherwise undefined
1685 : *
1686 : * Revision History:
1687 : * Updated Mon, 28 Mar 2005 by David L. Paktor
1688 : * Always use the current base.
1689 : * Reversed sense of return-flag.
1690 : *
1691 : **************************************************************************** */
1692 :
1693 : bool get_number( long *result)
1694 11433 : {
1695 : u8 *until;
1696 : long val;
1697 11433 : bool retval = FALSE ;
1698 :
1699 11433 : val = parse_number(statbuf, &until, base);
1700 :
1701 : #ifdef DEBUG_SCANNER
1702 : printf("%s:%d: debug: parsing number: base 0x%x, val 0x%lx, "
1703 : "processed %ld of %ld bytes\n", iname, lineno,
1704 : base, val,(size_t)(until-statbuf), strlen((char *)statbuf));
1705 : #endif
1706 :
1707 : /* If number-parsing ended before the end of the input word,
1708 : * then the input word was not a valid number.
1709 : */
1710 11433 : if (until==(statbuf+strlen((char *)statbuf)))
1711 : {
1712 10823 : *result=val;
1713 10823 : retval = TRUE;
1714 : }
1715 :
1716 11433 : return ( retval );
1717 : }
1718 :
1719 : /* **************************************************************************
1720 : *
1721 : * Function name: deliver_number
1722 : * Synopsis: Deliver the supplied number according to the
1723 : * state of the tokenizer:
1724 : * In normal tokenization mode, emit it as an
1725 : * FCode literal.
1726 : * In "Tokenizer-Escape" mode, push it onto
1727 : * the Data Stack.
1728 : *
1729 : * Inputs:
1730 : * Parameters:
1731 : * numval The number, verified to be valid.
1732 : * Global Variables:
1733 : * in_tokz_esc TRUE if tokenizer is in "Tokenizer Escape" mode.
1734 : *
1735 : * Outputs:
1736 : * Returned Value: NONE
1737 : * Items Pushed onto Data-Stack:
1738 : * Top: The number, if in_tokz_esc was TRUE
1739 : * FCode Output buffer:
1740 : * If in_tokz_esc was FALSE, a b(lit) token will be written,
1741 : * followed by the number.
1742 : *
1743 : **************************************************************************** */
1744 :
1745 : static void deliver_number( long numval)
1746 10845 : {
1747 10845 : if ( in_tokz_esc )
1748 : {
1749 231 : dpush( numval );
1750 : } else {
1751 10614 : emit_literal(numval);
1752 : }
1753 10845 : }
1754 : /* **************************************************************************
1755 : *
1756 : * Function name: handle_number
1757 : * Synopsis: Convert the word just retrieved from the input stream
1758 : * to a number.
1759 : * Indicate whether the string was a valid number and
1760 : * deliver it, as appropriate.
1761 : *
1762 : * Inputs:
1763 : * Parameters: NONE
1764 : * Global Variables:
1765 : * statbuf The word that was just read, and to be converted.
1766 : *
1767 : * Outputs:
1768 : * Returned Value: TRUE = Input string was a valid number
1769 : * If input string was a valid number, the converted number will
1770 : * be delivered, as appropriate, by deliver_number().
1771 : *
1772 : **************************************************************************** */
1773 :
1774 : static bool handle_number( void )
1775 11128 : {
1776 : bool retval ;
1777 : long numval;
1778 :
1779 11128 : retval = get_number( &numval );
1780 11128 : if ( retval )
1781 : {
1782 10820 : deliver_number( numval );
1783 : }
1784 :
1785 11128 : return ( retval );
1786 : }
1787 :
1788 : /* **************************************************************************
1789 : *
1790 : * Function name: ascii_right_number
1791 : * Synopsis: Convert a character sequence to a number, justified
1792 : * toward the right (i.e., the low-order bytes) and
1793 : * deliver it, as appropriate.
1794 : *
1795 : * Inputs:
1796 : * Parameters:
1797 : * in_str The input string
1798 : *
1799 : * Outputs:
1800 : * Returned Value: NONE
1801 : * The converted number will be delivered by deliver_number().
1802 : *
1803 : * Process Explanation:
1804 : * The last four characters in the sequence will become the number.
1805 : * If there are fewer than four, they will fill the low-order part
1806 : * of the number.
1807 : * Example: PCIR is converted to h# 50434952
1808 : * CPU is converted to h# 00435055
1809 : * and
1810 : * LotsOfStuff is equivalent to a# tuff
1811 : * and is converted to h# 74756666
1812 : *
1813 : **************************************************************************** */
1814 :
1815 : static void ascii_right_number( char *in_str)
1816 13 : {
1817 : u8 nxt_ch;
1818 13 : char *str_ptr = in_str;
1819 13 : long numval = 0;
1820 :
1821 13 : for ( nxt_ch = (u8)*str_ptr ;
1822 98 : ( nxt_ch = (u8)*str_ptr ) != 0 ;
1823 72 : str_ptr++ )
1824 : {
1825 72 : numval = ( numval << 8 ) + nxt_ch ;
1826 : }
1827 13 : deliver_number( numval );
1828 13 : }
1829 :
1830 :
1831 : /* **************************************************************************
1832 : *
1833 : * Function name: ascii_left_number
1834 : * Synopsis: Similar to ascii_right_number() except justified
1835 : * toward the left (i.e., the high-order bytes).
1836 : *
1837 : *
1838 : * Inputs:
1839 : * Parameters:
1840 : * in_str The input string
1841 : *
1842 : * Outputs:
1843 : * Returned Value: NONE
1844 : * The converted number will be delivered by deliver_number().
1845 : *
1846 : * Process Explanation:
1847 : * If there are fewer than four characters in the sequence, they
1848 : * will fill the high-order part of the number.
1849 : * CPU is converted to h# 43505500
1850 : * In all other respects, similar to ascii_right_number()
1851 : *
1852 : **************************************************************************** */
1853 :
1854 : static void ascii_left_number( char *in_str)
1855 12 : {
1856 : u8 nxt_ch;
1857 12 : char *str_ptr = in_str;
1858 12 : long numval = 0;
1859 12 : int shift_amt = 24;
1860 12 : bool shift_over = FALSE ;
1861 :
1862 12 : for ( nxt_ch = (u8)*str_ptr ;
1863 92 : ( nxt_ch = (u8)*str_ptr ) != 0 ;
1864 68 : str_ptr++ )
1865 : {
1866 68 : if ( shift_over ) numval <<= 8;
1867 68 : if ( shift_amt == 0 ) shift_over = TRUE ;
1868 68 : numval += ( nxt_ch << shift_amt );
1869 68 : if ( shift_amt > 0 ) shift_amt -= 8;
1870 : }
1871 12 : deliver_number( numval );
1872 :
1873 12 : }
1874 :
1875 : /* **************************************************************************
1876 : *
1877 : * Function name: init_scanner
1878 : * Synopsis: Allocate memory the Scanner will need.
1879 : * Only need to call once per program run.
1880 : *
1881 : **************************************************************************** */
1882 :
1883 : void init_scanner(void)
1884 154 : {
1885 154 : statbuf=safe_malloc(GET_BUF_MAX, "initting scanner");
1886 154 : }
1887 :
1888 : /* **************************************************************************
1889 : *
1890 : * Function name: exit_scanner
1891 : * Synopsis: Free up memory the Scanner used
1892 : *
1893 : **************************************************************************** */
1894 :
1895 : void exit_scanner(void)
1896 153 : {
1897 153 : free(statbuf);
1898 153 : }
1899 :
1900 : /* **************************************************************************
1901 : *
1902 : * Function name: set_hdr_flag
1903 : * Synopsis: Set the state of the "headered-ness" flag to the
1904 : * value given, unless over-ridden by one or both
1905 : * of the "always-..." Command-Line Flags
1906 : *
1907 : * Inputs:
1908 : * Parameters:
1909 : * new_flag New setting
1910 : * Global Variables:
1911 : * always_headers Override HEADERLESS and make HEADERS
1912 : * always_external Override HEADERLESS and HEADERS;
1913 : * make EXTERNAL
1914 : *
1915 : * Outputs:
1916 : * Returned Value: None
1917 : * Local Static Variables:
1918 : * hdr_flag Adjusted to new setting
1919 : *
1920 : * Process Explanation:
1921 : * If always_headers is TRUE, and new_flag is not FLAG_EXTERNAL
1922 : * then set to FLAG_HEADERS
1923 : * If always_external is TRUE, set to FLAG_EXTERNAL, regardless.
1924 : * (Note: always_external over-rides always_headers).
1925 : * Otherwise, set to new_flag
1926 : *
1927 : **************************************************************************** */
1928 :
1929 : static void set_hdr_flag( headeredness new_flag)
1930 349 : {
1931 349 : headeredness new_state = new_flag;
1932 349 : switch ( new_flag)
1933 : {
1934 : case FLAG_HEADERLESS:
1935 : {
1936 171 : if ( always_headers )
1937 7 : { new_state = FLAG_HEADERS;
1938 : }
1939 : /* No break. Intentional... */
1940 : }
1941 : case FLAG_HEADERS:
1942 : {
1943 337 : if ( always_external )
1944 8 : { new_state = FLAG_EXTERNAL;
1945 : }
1946 : /* No break. Intentional... */
1947 : }
1948 : case FLAG_EXTERNAL:
1949 : break; /* Satisfy compiler's error-checking... */
1950 : /* No default needed here... */
1951 : }
1952 :
1953 349 : hdr_flag = new_state;
1954 :
1955 349 : }
1956 :
1957 :
1958 : /* **************************************************************************
1959 : *
1960 : * Function name: init_scan_state
1961 : * Synopsis: Initialize various state variables for each time
1962 : * a new tokenization scan is started.
1963 : *
1964 : * Inputs:
1965 : * Parameters: NONE
1966 : *
1967 : * Outputs:
1968 : * Returned Value: NONE
1969 : * Global Variables: Initialized to:
1970 : * base 0x0a (I.e., base = "decimal")
1971 : * nextfcode By reset_fcode_ranges()
1972 : * pci_is_last_image TRUE
1973 : * incolon FALSE
1974 : * Local Static Variables:
1975 : * hdr_flag FLAG_HEADERLESS (unless over-ridden)
1976 : * is_instance FALSE
1977 : * last_colon_filename NULL
1978 : * instance_filename NULL
1979 : * dev_change_instance_warning TRUE
1980 : * instance_definer_gap FALSE
1981 : * need_to_pop_source FALSE
1982 : * first_fc_starter TRUE
1983 : * ret_stk_depth 0
1984 : * Memory Freed
1985 : * Copies of input-file name in last_colon_filename and
1986 : * instance_filename , if allocated.
1987 : *
1988 : **************************************************************************** */
1989 :
1990 : void init_scan_state( void)
1991 165 : {
1992 165 : base = 0x0a;
1993 165 : pci_is_last_image = TRUE;
1994 165 : incolon = FALSE;
1995 165 : is_instance = FALSE;
1996 165 : set_hdr_flag( FLAG_HEADERLESS);
1997 165 : reset_fcode_ranges();
1998 165 : first_fc_starter = TRUE;
1999 165 : if ( last_colon_filename != NULL ) free( last_colon_filename);
2000 165 : if ( instance_filename != NULL ) free( instance_filename);
2001 165 : last_colon_filename = NULL;
2002 165 : instance_filename = NULL;
2003 165 : dev_change_instance_warning = TRUE;
2004 165 : instance_definer_gap = FALSE;
2005 165 : need_to_pop_source = FALSE;
2006 165 : ret_stk_depth = 0;
2007 165 : }
2008 :
2009 :
2010 : /* **************************************************************************
2011 : *
2012 : * Function name: collect_input_filename
2013 : * Synopsis: Save a copy of the current input file name in the
2014 : * given variable, for error-reporting purposes
2015 : *
2016 : * Inputs:
2017 : * Parameters:
2018 : * saved_nam Pointer to pointer for copy of name
2019 : * Global Variables:
2020 : * iname Current input file name
2021 : * Local Static Variables:
2022 : *
2023 : * Outputs:
2024 : * Returned Value: NONE
2025 : * Supplied Pointers:
2026 : * *saved_nam Copy of name
2027 : * Memory Allocated
2028 : * For copy of input file name
2029 : * When Freed?
2030 : * Subsequent call to this routine with same pointer
2031 : * (Last copy made will be freed if starting a new tokenization,
2032 : * otherwise, will persist until end of program.)
2033 : * Memory Freed
2034 : * Previous copy in same pointer.
2035 : *
2036 : * Process Explanation:
2037 : * If there is a previous copy, and it still matches the current
2038 : * input-file name, we don't need to free or re-allocate.
2039 : *
2040 : **************************************************************************** */
2041 :
2042 : static void collect_input_filename( char **saved_nam)
2043 805 : {
2044 805 : bool update_lcfn = TRUE; /* Need to re-allocate? */
2045 805 : if ( *saved_nam != NULL )
2046 : {
2047 664 : if ( strcmp( *saved_nam, iname) == 0 )
2048 : {
2049 : /* Last collected filename unchanged from iname */
2050 614 : update_lcfn = FALSE;
2051 : }else{
2052 50 : free( *saved_nam);
2053 : }
2054 : }
2055 805 : if ( update_lcfn )
2056 : {
2057 191 : *saved_nam = strdup(iname);
2058 : }
2059 805 : }
2060 :
2061 : /* **************************************************************************
2062 : *
2063 : * Function name: test_in_colon
2064 : * Synopsis: Error-check whether a word is being used in the
2065 : * correct state, relative to being inside a colon
2066 : * definition; issue a message if it's not.
2067 : *
2068 : * Inputs:
2069 : * Parameters:
2070 : * wname The name of the word in question
2071 : * sb_in_colon TRUE if the name should be used inside
2072 : * a colon-definition only; FALSE if
2073 : * it may only be used outside of a
2074 : * colon-definition.
2075 : * severity Type of error/warning message to call.
2076 : * usually either WARNING or TKERROR
2077 : * use_instead Word the error-message should suggest be
2078 : * used "instead". This may be a NULL,
2079 : * in which case the "suggestion" part
2080 : * of the message will simply be omitted.
2081 : * Global Variables:
2082 : * incolon State of the tokenization; TRUE if inside
2083 : * a colon definition
2084 : *
2085 : * Outputs:
2086 : * Returned Value: TRUE if no error.
2087 : * Printout: Error messages as indicated.
2088 : *
2089 : * Error Detection:
2090 : * If the state, relative to being inside a colon-definition,
2091 : * is not what the parameter says it should be, issue a
2092 : * message of the indicated severity, and return FALSE.
2093 : *
2094 : **************************************************************************** */
2095 :
2096 : static bool test_in_colon ( char *wname,
2097 : bool sb_in_colon, /* "Should Be IN colon" */
2098 : int severity,
2099 : char *use_instead)
2100 11120 : {
2101 : bool is_wrong;
2102 11120 : bool retval = TRUE ;
2103 :
2104 11120 : is_wrong = BOOLVAL(( sb_in_colon != FALSE ) != ( incolon != FALSE )) ;
2105 11120 : if ( is_wrong )
2106 : {
2107 23 : char *ui_pt1 = "";
2108 23 : char *ui_pt2 = "";
2109 23 : char *ui_pt3 = "";
2110 23 : retval = FALSE;
2111 23 : if ( use_instead != NULL )
2112 : {
2113 5 : ui_pt1 = " Use ";
2114 5 : ui_pt2 = use_instead;
2115 5 : ui_pt3 = " instead.";
2116 : }
2117 23 : tokenization_error ( severity, "The word %s should not be used "
2118 : "%sside of a colon definition.%s%s%s\n", strupr(wname),
2119 : sb_in_colon ? "out" : "in", ui_pt1, ui_pt2, ui_pt3 );
2120 : }
2121 11120 : return ( retval );
2122 : }
2123 :
2124 : /* **************************************************************************
2125 : *
2126 : * Function name: must_be_deep_in_do
2127 : * Synopsis: Check that the statement in question is called
2128 : * from inside the given depth of structures
2129 : * of the DO ... LOOP -type (i.e., any combination
2130 : * of DO or ?DO and LOOP or +LOOP ).
2131 : * Show an error if it is not.
2132 : *
2133 : **************************************************************************** */
2134 :
2135 : static void must_be_deep_in_do( int how_deep )
2136 82 : {
2137 82 : int functional_depth = do_loop_depth;
2138 82 : if ( incolon )
2139 : {
2140 69 : functional_depth -= last_colon_do_depth;
2141 : }
2142 82 : if ( functional_depth < how_deep )
2143 : {
2144 14 : char deep_do[64] = "";
2145 : int indx;
2146 14 : bool prefix = FALSE;
2147 :
2148 34 : for ( indx = 0; indx < how_deep ; indx ++ )
2149 : {
2150 20 : strcat( deep_do, "DO ... ");
2151 : }
2152 34 : for ( indx = 0; indx < how_deep ; indx ++ )
2153 : {
2154 20 : if ( prefix )
2155 : {
2156 6 : strcat( deep_do, " ... ");
2157 : }
2158 20 : strcat( deep_do, "LOOP");
2159 20 : prefix = TRUE;
2160 : }
2161 :
2162 14 : tokenization_error( TKERROR,
2163 : "%s outside of %s structure", strupr(statbuf), deep_do);
2164 14 : in_last_colon();
2165 : }
2166 :
2167 82 : }
2168 :
2169 : /* **************************************************************************
2170 : *
2171 : * Function name: bump_ret_stk_depth
2172 : * Synopsis: Increment or decrement the Return-Stack-Usage-Depth
2173 : * counter.
2174 : *
2175 : * Inputs:
2176 : * Parameters:
2177 : * bump Amount by which to increment;
2178 : * negative number to decrement.
2179 : * Local Static Variables:
2180 : * ret_stk_depth The Return-Stack-Usage-Depth counter
2181 : *
2182 : * Outputs:
2183 : * Returned Value: NONE
2184 : * Local Static Variables:
2185 : * ret_stk_depth Incremented or decremented
2186 : *
2187 : * Process Explanation:
2188 : * This simple-seeming function is actually a place-holder
2189 : * for future expansion. Proper error-detection of
2190 : * Return-Stack usage is considerably more complex than
2191 : * what we are implementing here, and is deferred for a
2192 : * later revision.
2193 : *
2194 : * Still to be done:
2195 : * Full detection of whether the Return-Stack has been cleared
2196 : * when required, including analysis of Return-Stack usage
2197 : * within Flow-Control constructs, and before Loop elements...
2198 : *
2199 : * Extraneous Remarks:
2200 : * Some FORTHs use a Loop-Control stack separate from the Return-
2201 : * -Stack, but others use the Return-Stack to keep LOOP-control
2202 : * elements. An FCode program must be portable between different
2203 : * environments, and so must adhere to the restrictions listed
2204 : * in the ANSI Spec:
2205 : *
2206 : * 3.2.3.3 Return stack
2207 : * . . . . . .
2208 : * A program may use the return stack for temporary storage during the
2209 : * execution of a definition subject to the following restrictions:
2210 : * A program shall not access values on the return stack (using R@,
2211 : * R>, 2R@ or 2R>) that it did not place there using >R or 2>R;
2212 : * A program shall not access from within a do-loop values placed
2213 : * on the return stack before the loop was entered;
2214 : * All values placed on the return stack within a do-loop shall
2215 : * be removed before I, J, LOOP, +LOOP, UNLOOP, or LEAVE is
2216 : * executed;
2217 : * All values placed on the return stack within a definition
2218 : * shall be removed before the definition is terminated
2219 : * or before EXIT is executed.
2220 : *
2221 : **************************************************************************** */
2222 :
2223 : static void bump_ret_stk_depth( int bump)
2224 76 : {
2225 76 : ret_stk_depth += bump;
2226 76 : }
2227 :
2228 :
2229 : /* **************************************************************************
2230 : *
2231 : * Function name: ret_stk_balance_rpt
2232 : * Synopsis: Display a Message if usage of the Return-Stack
2233 : * appears to be out of balance.
2234 : *
2235 : * Inputs:
2236 : * Parameters:
2237 : * before_what Phrase to use in Message;
2238 : * if NULL, use statbuf...
2239 : * clear_it TRUE if this call should also clear the
2240 : * Return-Stack-Usage-Depth counter
2241 : * Global Variables:
2242 : * statbuf Word currently being processed
2243 : * Local Static Variables:
2244 : * ret_stk_depth The Return-Stack-Usage-Depth counter
2245 : *
2246 : * Outputs:
2247 : * Returned Value: NONE
2248 : * Local Static Variables:
2249 : * ret_stk_depth May be cleared
2250 : *
2251 : * Error Detection:
2252 : * Based simply on whether the Return-Stack-Usage-Depth counter
2253 : * is zero. This is a weak and uncertain implementation;
2254 : * therefore, the Message will be a WARNING phrased with
2255 : * some equivocation.
2256 : *
2257 : * Process Explanation:
2258 : * Proper detection of Return-Stack usage errors is considerably
2259 : * more complex, and is deferred for a future revision.
2260 : *
2261 : * Still to be done:
2262 : * Correct analysis of Return-Stack usage around Flow-Control
2263 : * constructs. Consider, for instance, the following:
2264 : *
2265 : * blablabla >R yadayada IF R> gubble ELSE flubble R> THEN
2266 : *
2267 : * It is, in fact, correct, but the present scheme would
2268 : * tag it as a possible error. Conversely, something like:
2269 : *
2270 : * blablabla >R yadayada IF R> gubble THEN
2271 : *
2272 : * would not get tagged, even though it is actually an error.
2273 : *
2274 : * The current simple scheme also does not cover Return-Stack
2275 : * usage within Do-Loops or before Loop elements like I and
2276 : * J or UNLOOP or LEAVE. Implementing something like that
2277 : * would probably need to be integrated in with Flow-Control
2278 : * constructs, and will be noted in flowcontrol.c
2279 : *
2280 : **************************************************************************** */
2281 :
2282 : static void ret_stk_balance_rpt( char *before_what, bool clear_it)
2283 764 : {
2284 764 : if ( ret_stk_depth != 0 )
2285 : {
2286 7 : char *what_flow = ret_stk_depth < 0 ? "deficit" : "excess" ;
2287 7 : char *what_phr = before_what != NULL ? before_what : strupr(statbuf);
2288 :
2289 7 : tokenization_error( WARNING,
2290 : "Possible Return-Stack %s before %s", what_flow, what_phr);
2291 7 : in_last_colon();
2292 :
2293 7 : if ( clear_it )
2294 : {
2295 5 : ret_stk_depth = 0;
2296 : }
2297 : }
2298 764 : }
2299 :
2300 :
2301 : /* **************************************************************************
2302 : *
2303 : * Function name: ret_stk_access_rpt
2304 : * Synopsis: Display a Message if an attempt to access a value
2305 : * on the Return-Stack appears to occur before
2306 : * one was placed there.
2307 : *
2308 : * Inputs:
2309 : * Parameters: NONE
2310 : * Global Variables:
2311 : * statbuf Word currently being processed
2312 : * Local Static Variables:
2313 : * ret_stk_depth The Return-Stack-Usage-Depth counter
2314 : *
2315 : * Outputs:
2316 : * Returned Value: NONE
2317 : *
2318 : * Error Detection:
2319 : * Equivocal WARNING, based simply on whether the Return-Stack-
2320 : * -Usage-Depth counter not positive.
2321 : *
2322 : * Process Explanation:
2323 : * Proper detection is deferred...
2324 : *
2325 : * Still to be done:
2326 : * Correct analysis of Return-Stack usage...
2327 : *
2328 : **************************************************************************** */
2329 :
2330 : static void ret_stk_access_rpt( void)
2331 44 : {
2332 44 : if ( ret_stk_depth <= 0 )
2333 : {
2334 9 : tokenization_error( WARNING,
2335 : "Possible Return-Stack access attempt by %s "
2336 : "without value having been placed there",
2337 : strupr(statbuf) );
2338 9 : in_last_colon();
2339 : }
2340 44 : }
2341 :
2342 :
2343 :
2344 : /* **************************************************************************
2345 : *
2346 : * Function name: encode_file
2347 : * Synopsis: Input a (presumably binary) file and encode it
2348 : * as a series of strings which will be accumulated
2349 : * and encoded in a manner appropriate for a property.
2350 : *
2351 : * Associated Tokenizer directive: encode-file
2352 : *
2353 : * Error Detection:
2354 : * Handled by support routines.
2355 : *
2356 : **************************************************************************** */
2357 :
2358 : static void encode_file( const char *filename )
2359 18 : {
2360 : FILE *f;
2361 : size_t s;
2362 18 : int num_encoded=0;
2363 :
2364 18 : tokenization_error( INFO, "ENCODing File %s\n", filename );
2365 :
2366 18 : f = open_expanded_file( filename, "rb", "encoding");
2367 18 : if( f != NULL )
2368 : {
2369 21 : while( (s=fread(statbuf, 1, STRING_LEN_MAX, f)) )
2370 : {
2371 14 : emit_token("b(\")");
2372 14 : emit_string(statbuf, s);
2373 14 : emit_token("encode-bytes");
2374 14 : if( num_encoded )
2375 10 : emit_token("encode+");
2376 14 : num_encoded += s;
2377 : }
2378 7 : fclose( f );
2379 7 : tokenization_error ( INFO, "ENCODed %d bytes.\n", num_encoded);
2380 : }
2381 18 : }
2382 :
2383 : /* **************************************************************************
2384 : *
2385 : * Function name: check_name_length
2386 : * Synopsis: If the length of a user-defined name exceeds the
2387 : * ANSI-specified maximum of 31 characters, issue
2388 : * a message. This is a hard-coded limit.
2389 : * Although our Tokenizer can handle longer names,
2390 : * they will cause big problems when encountered
2391 : * by an FCode interpreter.
2392 : * If the name is going to be included in the binary
2393 : * output, the message severity must be an ERROR.
2394 : * Otherwise, if the name is HEADERLESS, the severity
2395 : * can be reduced to a Warning; if the name is only
2396 : * defined in "Tokenizer Escape" mode the message
2397 : * severity can be further reduced to an Advisory.
2398 : *
2399 : * Inputs:
2400 : * Parameters:
2401 : * wlen Length of the newly-created word
2402 : * Global Variables:
2403 : * in_tokz_esc TRUE if in "Tokenizer Escape" mode.
2404 : * Local Static Variables:
2405 : * hdr_flag State of headered-ness for name-creation
2406 : *
2407 : * Outputs:
2408 : * Returned Value: NONE
2409 : * Global Variables:
2410 : * Printout: ERROR message if applicable.
2411 : *
2412 : * Error Detection:
2413 : * The whole point of this routine.
2414 : *
2415 : * Revision History:
2416 : * Updated Wed, 20 Jul 2005 by David L. Paktor
2417 : * Escalated from merely an informative warning to a TKERROR
2418 : * Updated Fri, 21 Oct 2005 by David L. Paktor
2419 : * Adjust severity if name doesn't go into the FCode anyway...
2420 : *
2421 : **************************************************************************** */
2422 :
2423 : void check_name_length( signed long wlen )
2424 10077 : {
2425 10077 : if ( wlen > 31 )
2426 : {
2427 7 : int severity = TKERROR;
2428 7 : if ( in_tokz_esc )
2429 2 : { severity = INFO;
2430 : }else{
2431 5 : if (hdr_flag == FLAG_HEADERLESS)
2432 1 : { severity = WARNING;
2433 : }
2434 : }
2435 7 : tokenization_error( severity,
2436 : "ANSI Forth does not permit definition of names "
2437 : "longer than 31 characters.\n" );
2438 : }
2439 :
2440 10077 : }
2441 :
2442 :
2443 : /* **************************************************************************
2444 : *
2445 : * Function name: definer_name
2446 : * Synopsis: Given a defining-word internal token, return
2447 : * a printable string for the definer, for use
2448 : * in an error-message.
2449 : *
2450 : * Inputs:
2451 : * Parameters:
2452 : * definer Internal token for the defining-word
2453 : * reslt_ptr Pointer to string-pointer that takes
2454 : * the result, if successful
2455 : *
2456 : * Outputs:
2457 : * Returned Value: TRUE if definer was recognized
2458 : * Supplied Pointers:
2459 : * *reslt_ptr If successful, points to printable string;
2460 : * otherwise, left unchanged.
2461 : *
2462 : *
2463 : **************************************************************************** */
2464 :
2465 : static bool definer_name(fwtoken definer, char **reslt_ptr)
2466 10275 : {
2467 10275 : bool retval = TRUE;
2468 10275 : switch (definer)
2469 : {
2470 : case VARIABLE:
2471 64 : *reslt_ptr = "VARIABLE";
2472 64 : break;
2473 : case DEFER:
2474 5 : *reslt_ptr = "DEFER";
2475 5 : break;
2476 : case VALUE:
2477 72 : *reslt_ptr = "VALUE";
2478 72 : break;
2479 : case BUFFER:
2480 37 : *reslt_ptr = "BUFFER";
2481 37 : break;
2482 : case CONST:
2483 9115 : *reslt_ptr = "CONSTANT";
2484 9115 : break;
2485 : case COLON:
2486 783 : *reslt_ptr = "COLON";
2487 783 : break;
2488 : case CREATE:
2489 32 : *reslt_ptr = "CREATE";
2490 32 : break;
2491 : case FIELD:
2492 6 : *reslt_ptr = "FIELD";
2493 6 : break;
2494 : case MACRO_DEF:
2495 25 : *reslt_ptr = "MACRO";
2496 25 : break;
2497 : case ALIAS:
2498 3 : *reslt_ptr = "ALIAS";
2499 3 : break;
2500 : case LOCAL_VAL:
2501 46 : *reslt_ptr = "Local Value name";
2502 46 : break;
2503 : default:
2504 87 : retval = FALSE;
2505 : }
2506 :
2507 10275 : return ( retval);
2508 : }
2509 :
2510 :
2511 : /* **************************************************************************
2512 : *
2513 : * Function name: as_a_what
2514 : * Synopsis: Add the phrase "as a[n] <DEF'N_TYPE>" for the given
2515 : * definition-type to the given string buffer.
2516 : *
2517 : * Inputs:
2518 : * Parameters:
2519 : * definer Internal token for the defining-word
2520 : * as_what The string buffer to which to add.
2521 : *
2522 : * Outputs:
2523 : * Returned Value: TRUE if an assigned name was found
2524 : * for the given definer and text
2525 : * was added to the buffer.
2526 : * Supplied Pointers:
2527 : * *as_what Text is added to this buffer.
2528 : *
2529 : * Process Explanation:
2530 : * The calling routine is responsible to make sure the size of
2531 : * the buffer is adequate. Allow 25 for this routine.
2532 : * The added text will not have spaces before or after; if any
2533 : * are needed, they, too, are the responsibility of the
2534 : * calling routine. The return value gives a helpful clue.
2535 : *
2536 : **************************************************************************** */
2537 :
2538 : bool as_a_what( fwtoken definer, char *as_what)
2539 245 : {
2540 : char *defn_type_name;
2541 245 : bool retval = definer_name(definer, &defn_type_name);
2542 245 : if ( retval )
2543 : {
2544 171 : strcat( as_what, "as a");
2545 : /* Handle article preceding definer name
2546 : * that starts with a vowel.
2547 : */
2548 : /* HACK: Only one definer name -- ALIAS --
2549 : * begins with a vowel. Take advantage
2550 : * of that...
2551 : * Otherwise, we'd need to do something involving
2552 : * strchr( "AEIOU", defn_type_name[0] )
2553 : */
2554 171 : if ( definer == ALIAS ) strcat( as_what, "n" );
2555 :
2556 171 : strcat( as_what, " ");
2557 171 : strcat( as_what, defn_type_name);
2558 : }
2559 245 : return( retval);
2560 : }
2561 :
2562 :
2563 : /* **************************************************************************
2564 : *
2565 : * Function name: lookup_word
2566 : * Synopsis: Find the TIC-entry for the given word in the Current
2567 : * mode -- relative to "Tokenizer-Escape" -- and
2568 : * Scope into which definitions are being entered.
2569 : * Optionally, prepare text for various Message types.
2570 : *
2571 : * Inputs:
2572 : * Parameters:
2573 : * stat_name Word to look up
2574 : * where_pt1 Pointer to result-display string, part 1
2575 : * NULL if not preparing text
2576 : * where_pt2 Pointer to result-display string, part 2
2577 : * NULL if not preparing text
2578 : * Global Variables:
2579 : * in_tokz_esc TRUE if in "Tokenizer Escape" mode.
2580 : * scope_is_global TRUE if "global" scope is in effect
2581 : * current_device_node Current dev-node data-struct
2582 : * ibm_locals TRUE if IBM-style Locals are enabled
2583 : *
2584 : * Outputs:
2585 : * Returned Value: Pointer to TIC-entry; NULL if not found
2586 : * Supplied Pointers:
2587 : * *where_pt1 Result display string, part 1 of 2
2588 : * *where_pt2 Result display string, part 2 of 2
2589 : *
2590 : * Process Explanation:
2591 : * We will set the two-part result-display string in this routine
2592 : * because only here do we know in which vocabulary the word
2593 : * was found.
2594 : * Pre-load the two parts of the result-display string.
2595 : * If we are in "Tokenizer Escape" mode, look up the word: first,
2596 : * in the "Tokenizer Escape" Vocabulary, or, if not found,
2597 : * among the "Shared" words.
2598 : * Otherwise, we're in Normal" mode. Look it up: first, among the
2599 : * Locals, if IBM-style Locals are enabled (it can possibly be
2600 : * one if "Tokenizer Escape" mode was entered during a colon-
2601 : * -definition); then, if it was not found and if "Device"
2602 : * scope is in effect, look in the current device-node; then,
2603 : * if not found, in the "core" vocabulary.
2604 : * Load the second part of the result-display string with the
2605 : * appropriate phrase for whereever it was found.
2606 : * Then adjust the first part of the result-display string with
2607 : * the definer, if known.
2608 : *
2609 : * The two strings will be formatted to be printed adjacently,
2610 : * without any additional spaces in the printf() format.
2611 : * The first part of the result-display string will not start with
2612 : * a space, but will have an intermediate space if necessary.
2613 : * The second part of the result-display string will not start
2614 : * with a space, and will contain the terminating new-line
2615 : * if appropriate. It might or might not have been built
2616 : * with a call to in_what_node().
2617 : *
2618 : * If the calling routine displays the result-display strings,
2619 : * it should follow-up with a call to show_node_start()
2620 : * This will be harmless if in_what_node() was not used
2621 : * in the construction of the result-display string.
2622 : * If the calling routine is NOT going to display the result strings,
2623 : * it should pass NULLs for the string-pointer pointers.
2624 : *
2625 : * The second part of the string consists of pre-coded phrases;
2626 : * therefore, we can directly assign the pointer.
2627 : * The first part of the string, however, has developed into
2628 : * something constructed "on the fly". Earlier, it, too,
2629 : * had been a directly-assignable pointer; all the callers
2630 : * to this routine expect that. Rather than change all the
2631 : * callers, we will assign a local buffer for it.
2632 : *
2633 : * Extraneous Remarks:
2634 : * We had to add the rule allowing where_pt1 or where_pt2 to be
2635 : * NULL after we introduced the in_what_node() function.
2636 : * We had cases where residue from a lookup for processing
2637 : * showed up later in an unrelated Message. The NULL rule
2638 : * should prevent that.
2639 : *
2640 : **************************************************************************** */
2641 :
2642 : static char lookup_where_pt1_buf[32];
2643 :
2644 : tic_hdr_t *lookup_word( char *stat_name, char **where_pt1, char **where_pt2 )
2645 123068 : {
2646 123068 : tic_hdr_t *found = NULL;
2647 123068 : bool trail_space = TRUE;
2648 123068 : bool doing_lookup = BOOLVAL( ( where_pt1 != NULL )
2649 : && ( where_pt2 != NULL ) );
2650 123068 : char *temp_where_pt2 = "in the core vocabulary.\n";
2651 :
2652 123068 : lookup_where_pt1_buf[0] = 0; /* Init'lz part-1 buffer */
2653 :
2654 : /* "Core vocab" refers both to shared fwords and built-in tokens. */
2655 :
2656 : /* Distinguish between "Normal" and "Tokenizer Escape" mode */
2657 123068 : if ( in_tokz_esc )
2658 : { /* "Tokenizer Escape" mode. */
2659 2539 : found = lookup_tokz_esc( stat_name);
2660 2539 : if ( found != NULL )
2661 : {
2662 1304 : temp_where_pt2 = in_tkz_esc_mode;
2663 : }else{
2664 : /* "Core vocabulary". */
2665 1235 : found = lookup_shared_word( stat_name);
2666 : }
2667 : }else{
2668 : /* "Normal" tokenization mode */
2669 120529 : if ( ibm_locals )
2670 : {
2671 11758 : found = lookup_local( stat_name);
2672 11758 : if ( doing_lookup && ( found != NULL ) )
2673 : {
2674 44 : trail_space = FALSE;
2675 44 : temp_where_pt2 = ".\n";
2676 : }
2677 : }
2678 :
2679 120529 : if ( found == NULL )
2680 : {
2681 119983 : found = lookup_in_dev_node( stat_name);
2682 119983 : if ( found != NULL )
2683 : {
2684 1318 : if ( doing_lookup )
2685 : {
2686 19 : temp_where_pt2 = in_what_node( current_device_node);
2687 : }
2688 : }else{
2689 : /* "Core vocabulary". */
2690 118665 : found = lookup_core_word( stat_name);
2691 : }
2692 : }
2693 : }
2694 :
2695 123068 : if ( ( doing_lookup ) && ( found != NULL ) )
2696 : {
2697 174 : if ( as_a_what( found->fword_defr, lookup_where_pt1_buf) )
2698 : {
2699 109 : if ( trail_space )
2700 : {
2701 65 : strcat(lookup_where_pt1_buf, " ");
2702 : }
2703 : }
2704 174 : *where_pt1 = lookup_where_pt1_buf;
2705 174 : *where_pt2 = temp_where_pt2;
2706 : }
2707 123068 : return( found);
2708 : }
2709 :
2710 : /* **************************************************************************
2711 : *
2712 : * Function name: word_exists
2713 : * Synopsis: Check whether a given word is already defined in the
2714 : * Current mode -- relative to "Tokenizer-Escape" --
2715 : * and Scope into which definitions are being entered.
2716 : * Used for error-reporting.
2717 : *
2718 : * Inputs:
2719 : * Parameters:
2720 : * stat_name Word to look up
2721 : * where_pt1 Pointer to string, part 1 of 2,
2722 : * to display in result
2723 : * where_pt2 Pointer to string, part 2 of 2,
2724 : * to display in result
2725 : *
2726 : * Outputs:
2727 : * Returned Value: TRUE if the name exists.
2728 : * Supplied Pointers:
2729 : * *where_pt1 Result display string, part 1 of 2
2730 : * *where_pt2 Result display string, part 2 of 2
2731 : *
2732 : * Process Explanation:
2733 : * If the calling routine displays the result-display strings,
2734 : * it should follow-up with a call to show_node_start()
2735 : *
2736 : * Extraneous Remarks:
2737 : * This used to be a much heftier routine; now it's just
2738 : * a wrapper around lookup_word() .
2739 : *
2740 : **************************************************************************** */
2741 :
2742 : bool word_exists( char *stat_name, char **where_pt1, char **where_pt2 )
2743 11030 : {
2744 11030 : bool retval = FALSE;
2745 11030 : tic_hdr_t *found = lookup_word( stat_name, where_pt1, where_pt2 );
2746 :
2747 11030 : if ( found != NULL )
2748 : {
2749 174 : retval = TRUE;
2750 : }
2751 :
2752 11030 : return( retval);
2753 : }
2754 :
2755 : /* **************************************************************************
2756 : *
2757 : * Function name: warn_if_duplicate
2758 : * Synopsis: Check whether a given word is already defined in
2759 : * the current mode and issue a warning if it is.
2760 : *
2761 : * Inputs:
2762 : * Parameters:
2763 : * stat_name Word to check
2764 : * Global Variables:
2765 : * verbose_dup_warning Whether to run the check at all.
2766 : * Local Static Variables:
2767 : * do_not_overload FALSE if OVERLOAD is in effect.
2768 : *
2769 : * Outputs:
2770 : * Returned Value: NONE
2771 : * Local Static Variables:
2772 : * do_not_overload Restored to TRUE
2773 : * Printout:
2774 : * Warning message if a duplicate.
2775 : *
2776 : * Error Detection:
2777 : * None. This is merely an informative warning.
2778 : *
2779 : * Process Explanation:
2780 : * "Current mode" -- meaning, whether the tokenizer is operating
2781 : * in "Tokenizer Escape" mode or in normal tokenization mode --
2782 : * will be recognized by the word_exists() function.
2783 : *
2784 : * Extraneous Remarks:
2785 : * The OVERLOAD directive is our best shot at creating a more
2786 : * fine-grained way to temporarily bypass this test when
2787 : * deliberately overloading a name. It would be nice to have
2788 : * a mechanism, comparable to the classic
2789 : * WARNING @ WARNING OFF ..... WARNING !
2790 : * that could be applied to a range of definitions, but:
2791 : * (1) That would require more of a true FORTH infrastructure;
2792 : * hence, more effort than I am willing to invest, at
2793 : * this juncture, for such a small return,
2794 : * and
2795 : * (2) Most intentional-overloading ranges only cover a
2796 : * single definition anyway.
2797 : *
2798 : **************************************************************************** */
2799 :
2800 : void warn_if_duplicate( char *stat_name)
2801 10380 : {
2802 10380 : if ( verbose_dup_warning && do_not_overload )
2803 : {
2804 : char *where_pt1;
2805 : char *where_pt2;
2806 10319 : if ( word_exists( stat_name, &where_pt1, &where_pt2) )
2807 : {
2808 57 : tokenization_error( WARNING,
2809 : "Duplicate definition: %s already exists %s%s",
2810 : stat_name, where_pt1, where_pt2 );
2811 57 : show_node_start();
2812 : }
2813 : }
2814 10380 : do_not_overload = TRUE;
2815 10380 : }
2816 :
2817 :
2818 : /* **************************************************************************
2819 : *
2820 : * Function name: glob_not_allowed
2821 : * Synopsis: Print a Message that "XXX is not allowed."
2822 : * because Global Scope is in effect.
2823 : * Used from several places...
2824 : *
2825 : * Inputs:
2826 : * Parameters:
2827 : * severity Severity of the Message
2828 : * not_ignoring FALSE = "Ignoring", for the part of the
2829 : * message about "How It's being Handled"
2830 : * Global Variables:
2831 : * statbuf Disallowed word currently being processed
2832 : *
2833 : * Outputs:
2834 : * Returned Value: NONE
2835 : * Printout: Message of given severity.
2836 : *
2837 : **************************************************************************** */
2838 :
2839 : static void glob_not_allowed( int severity, bool not_ignoring)
2840 33 : {
2841 33 : tokenization_error( severity, "Global Scope is in effect; "
2842 : "%s not allowed. %s.\n",
2843 : strupr(statbuf),
2844 : not_ignoring ?
2845 : "Attempting to compensate.." :
2846 : "Ignoring" );
2847 33 : }
2848 :
2849 :
2850 : /* **************************************************************************
2851 : *
2852 : * Function name: not_in_dict
2853 : * Synopsis: Print the message "XXX is not in dictionary."
2854 : * Used from several places...
2855 : *
2856 : * Inputs:
2857 : * Parameters:
2858 : * stat_name Word that could not be processed
2859 : *
2860 : * Outputs:
2861 : * Returned Value: NONE
2862 : * Printout: Error message.
2863 : *
2864 : **************************************************************************** */
2865 :
2866 : static void not_in_dict( char *stat_name)
2867 289 : {
2868 289 : tokenization_error ( TKERROR,
2869 : "Word %s is not in dictionary.\n", stat_name);
2870 289 : }
2871 :
2872 : /* **************************************************************************
2873 : *
2874 : * Function name: tokenized_word_error
2875 : * Synopsis: Report an error when a word could not be processed
2876 : * by the tokenizer. Messages will vary...
2877 : *
2878 : * Inputs:
2879 : * Parameters:
2880 : * stat_name Word that could not be processed
2881 : * Global Variables:
2882 : * in_tokz_esc TRUE if tokenizer is in "Tokenizer Escape" mode.
2883 : *
2884 : * Outputs:
2885 : * Returned Value: NONE
2886 : * Printout: Error message. Possible Advisory about
2887 : *
2888 : * Error Detection:
2889 : * Error was detected by the calling routine...
2890 : *
2891 : * Process Explanation:
2892 : * If the tokenizer is in "Tokenizer Escape" mode, the word might
2893 : * be one that can be used in normal tokenization mode;
2894 : * Conversely, if the tokenizer is in normal-tokenization mode,
2895 : * the word might be one that can be used in the "Escape" mode.
2896 : * Or, the word is completely unknown.
2897 : * Recognizing the current mode is handled by word_exists()
2898 : * However, we need to test for the *converse* of the current mode,
2899 : * so before we call word_exists() we are going to save and
2900 : * invert the setting of in_tokz_esc (and afterwards, of
2901 : * course, restore it...)
2902 : *
2903 : **************************************************************************** */
2904 :
2905 : static void tokenized_word_error( char *stat_name)
2906 319 : {
2907 : char *where_pt1;
2908 : char *where_pt2;
2909 : bool found_somewhere;
2910 :
2911 319 : bool sav_in_tokz_esc = in_tokz_esc;
2912 319 : in_tokz_esc = INVERSE(sav_in_tokz_esc);
2913 :
2914 319 : found_somewhere = word_exists( stat_name, &where_pt1, &where_pt2);
2915 319 : if ( found_somewhere )
2916 : {
2917 30 : tokenization_error ( TKERROR, "The word %s is %s recognized "
2918 : "in tokenizer-escape mode.\n",
2919 : stat_name, sav_in_tokz_esc ? "not" : "only" );
2920 : } else {
2921 289 : not_in_dict( stat_name);
2922 : }
2923 :
2924 319 : if ( INVERSE(exists_in_ancestor( stat_name)) )
2925 : {
2926 261 : if ( found_somewhere && sav_in_tokz_esc )
2927 : {
2928 22 : tokenization_error(INFO,
2929 : "%s is defined %s%s", stat_name, where_pt1, where_pt2 );
2930 22 : show_node_start();
2931 : }
2932 : }
2933 :
2934 319 : in_tokz_esc = sav_in_tokz_esc;
2935 319 : }
2936 :
2937 :
2938 : /* **************************************************************************
2939 : *
2940 : * Function name: unresolved_instance
2941 : * Synopsis: Print the "unresolved instance" message
2942 : *
2943 : * Inputs:
2944 : * Parameters:
2945 : * severity Severity of the Message
2946 : * Local Static Variables:
2947 : * instance_filename File where "instance" invoked
2948 : * instance_lineno Line number where "instance" invoked
2949 : *
2950 : * Outputs:
2951 : * Returned Value: NONE
2952 : * Printout: Message.
2953 : *
2954 : * Error Detection:
2955 : * Error was detected by the calling routine...
2956 : *
2957 : **************************************************************************** */
2958 :
2959 : static void unresolved_instance( int severity)
2960 17 : {
2961 17 : tokenization_error( severity, "Unresolved \"INSTANCE\"" );
2962 17 : just_where_started( instance_filename, instance_lineno );
2963 17 : }
2964 :
2965 :
2966 : /* **************************************************************************
2967 : *
2968 : * Function name: modified_by_instance
2969 : * Synopsis: Print the "[not] modified by instance" message
2970 : *
2971 : * Inputs:
2972 : * Parameters:
2973 : * definer Internal token for the defining-word
2974 : * was_modded FALSE if "not modified..."
2975 : * Local Static Variables:
2976 : * instance_filename File where "instance" invoked
2977 : * instance_lineno Line number where "instance" invoked
2978 : *
2979 : * Outputs:
2980 : * Returned Value: NONE
2981 : * Printout: WARNING message.
2982 : *
2983 : * Error Detection:
2984 : * Error was detected by the calling routine...
2985 : *
2986 : **************************************************************************** */
2987 :
2988 : static void modified_by_instance( fwtoken definer, bool was_modded)
2989 19 : {
2990 19 : char *was_not = was_modded ? "was" : "not" ;
2991 : char *defn_type_name;
2992 :
2993 : /* No need to check the return value */
2994 19 : definer_name(definer, &defn_type_name);
2995 :
2996 19 : tokenization_error ( WARNING,
2997 : "%s definition %s modified by \"INSTANCE\"",
2998 : defn_type_name, was_not );
2999 19 : just_where_started( instance_filename, instance_lineno );
3000 19 : }
3001 :
3002 : /* **************************************************************************
3003 : *
3004 : * Function name: validate_instance
3005 : * Synopsis: If "instance" is in effect, check whether it is
3006 : * appropriate to the defining-word being called.
3007 : *
3008 : * Inputs:
3009 : * Parameters:
3010 : * definer Internal token for the defining-word
3011 : * Local Static Variables:
3012 : * is_instance TRUE if "instance" is in effect.
3013 : * instance_definer_gap TRUE if invalid definer(s) invoked
3014 : * since "instance" went into effect.
3015 : *
3016 : * Outputs:
3017 : * Returned Value: NONE
3018 : * Local Static Variables:
3019 : * is_instance Reset to FALSE if definer was valid.
3020 : * instance_definer_gap TRUE if definer was not valid;
3021 : * FALSE if definer was valid.
3022 : *
3023 : * Error Detection:
3024 : * If "instance" is in effect, the only defining-words that are
3025 : * valid are: value variable defer or buffer: Attempts
3026 : * to use any other defining-word will be reported with a
3027 : * WARNING, but "instance" will remain in effect.
3028 : * If an invalid defining-word was invoked since "instance" went
3029 : * into effect, then, when it is finally applied to a valid
3030 : * definer, issue a WARNING.
3031 : *
3032 : * Process Explanation:
3033 : * Implicit in the Standard is the notion that, once INSTANCE has
3034 : * been executed, it remains in effect until a valid defining-
3035 : * word is encountered. We will do the same.
3036 : *
3037 : **************************************************************************** */
3038 :
3039 : static void validate_instance(fwtoken definer)
3040 10193 : {
3041 10193 : if ( is_instance )
3042 : {
3043 90 : bool is_error = TRUE ;
3044 :
3045 90 : switch ( definer)
3046 : {
3047 : case VALUE:
3048 : case VARIABLE:
3049 : case DEFER:
3050 : case BUFFER:
3051 80 : is_error = FALSE;
3052 : /* No default needed, likewise, no breaks; */
3053 : /* but some compilers get upset without 'em... */
3054 : default:
3055 : break;
3056 : }
3057 :
3058 90 : if( is_error )
3059 : {
3060 10 : modified_by_instance(definer, FALSE );
3061 10 : instance_definer_gap = TRUE;
3062 : }else{
3063 80 : if ( instance_definer_gap )
3064 : {
3065 9 : modified_by_instance(definer, TRUE );
3066 : }
3067 80 : is_instance = FALSE;
3068 80 : instance_definer_gap = FALSE;
3069 : }
3070 : }
3071 10193 : }
3072 :
3073 :
3074 : /* **************************************************************************
3075 : *
3076 : * Function name: trace_creation
3077 : * Synopsis: If the word being created is on the Trace List,
3078 : * display the appropriate message
3079 : *
3080 : * Inputs:
3081 : * Parameters:
3082 : * definer Internal token for the defining-word
3083 : * nu_name The word being created
3084 : * Global Variables:
3085 : * verbose No point in doing all this if we're
3086 : * not showing the message anyway...
3087 : * in_tokz_esc TRUE if we are in Tokenizer-Escape mode
3088 : * scope_is_global TRUE if "global" scope is in effect
3089 : * current_device_node Current dev-node data-struct
3090 : *
3091 : * Outputs:
3092 : * Returned Value: NONE
3093 : * Printout:
3094 : * Advisory Message, if the word is on the Trace List.
3095 : *
3096 : * Process Explanation:
3097 : * The order of scope-checking is important:
3098 : * A Local has no scope beyond the definition in which it occurs.
3099 : * Tokenizer-Escape mode supercedes "Normal" mode, and renders
3100 : * moot the differences between Global and Device scope.
3101 : * Global scope is mutually exclusive with Device scope.
3102 : * Device scope needs to identify where the Current device-node
3103 : * began.
3104 : *
3105 : **************************************************************************** */
3106 :
3107 : void trace_creation( fwtoken definer, char *nu_name)
3108 10665 : {
3109 10665 : if ( verbose )
3110 : {
3111 10665 : if ( is_on_trace_list( nu_name) )
3112 : {
3113 13 : char as_what[96] = "";
3114 13 : bool show_last_colon = BOOLVAL( definer == LOCAL_VAL);
3115 :
3116 13 : as_a_what( definer, as_what); /* No need to check return value. */
3117 :
3118 : /* Scope-checking starts here, unless show_last_colon is TRUE.
3119 : * Come out of this with as_what[] filled up and
3120 : * terminated with a new-line, if appropriate,
3121 : */
3122 13 : while ( ! show_last_colon )
3123 : {
3124 12 : strcat( as_what, " ");
3125 :
3126 12 : if ( in_tokz_esc )
3127 : {
3128 1 : strcat( as_what, in_tkz_esc_mode);
3129 1 : break;
3130 : }
3131 :
3132 11 : if ( scope_is_global )
3133 : {
3134 1 : strcat( as_what, "with Global scope.\n");
3135 : }else{
3136 : /* In Device scope. Show the Current node. */
3137 10 : strcat( as_what, in_what_node( current_device_node));
3138 : }
3139 : break;
3140 :
3141 : } /* Destination of BREAKs ... */
3142 :
3143 13 : tokenization_error(INFO, "Creating %s %s", nu_name, as_what);
3144 :
3145 13 : if ( show_last_colon )
3146 : {
3147 1 : in_last_colon();
3148 : }else{
3149 12 : show_node_start();
3150 : }
3151 :
3152 : }
3153 : }
3154 10665 : }
3155 :
3156 : /* **************************************************************************
3157 : *
3158 : * Function name: create_word
3159 : * Synopsis:
3160 : *
3161 : * Inputs:
3162 : * Parameters:
3163 : * definer Internal token for the defining-word
3164 : * Global Variables:
3165 : * control_stack_depth Number of "Control Stack" entries in effect
3166 : * nextfcode FCode-number to be assigned to the new name
3167 : * statbuf Symbol last read from the input stream
3168 : * pc Input-source Scanning pointer
3169 : * hdr_flag State of headered-ness for name-creation
3170 : * force_tokens_case If TRUE, force token-names' case in FCode
3171 : * force_lower_case_tokens
3172 : * If force_tokens_case is TRUE, this
3173 : * determines which case to force
3174 : * iname Input-source file name; for error-reporting
3175 : * lineno Input-source Line number; also for err-rep't
3176 : *
3177 : * Outputs:
3178 : * Returned Value: TRUE if successful
3179 : * Global Variables:
3180 : * nextfcode Incremented (by bump_fcode() )
3181 : * statbuf Advanced to next symbol; must be re-read
3182 : * pc Advanced, then restored to previous value
3183 : * Memory Allocated
3184 : * Copy of the name being defined, by support routine.
3185 : * Copy of input-source file name, for error-reporting
3186 : * When Freed?
3187 : * Copy of name being defined is freed when Current Device Vocab
3188 : * is "finished", or at end of tokenization.
3189 : * Copy of input-source file name is freed at end of this routine.
3190 : *
3191 : * Error Detection:
3192 : * ERROR if already inside a colon-definition. Discontinue
3193 : * processing and return FALSE.
3194 : * ERROR if inside a control-structure. Continue processing,
3195 : * though, to catch other errors, and even return TRUE;
3196 : * except: leave the new token undefined.
3197 : * Warning on duplicate name (subject to command-line control)
3198 : * Message if name is excessively long; Warning if headerless.
3199 : * FATAL if the value of nextfcode is larger than the legal
3200 : * maximum for an FCode, (0x0fff).
3201 : *
3202 : * Revision History:
3203 : * Updated Thu, 24 Mar 2005 by David L. Paktor
3204 : * Optional warning when name about to be created is a
3205 : * duplicate of an existing name.
3206 : * Updated Wed, 30 Mar 2005 by David L. Paktor
3207 : * Warning when name length exceeds ANSI-specified max (31 chars).
3208 : * Updated Tue, 05 Apr 2005 by David L. Paktor
3209 : * Add "definer" parameter and call to add_definer() . Part
3210 : * of the mechanism to forbid attempts to use the TO
3211 : * directive to change values of CONSTANTs in particular
3212 : * and of inappropriate targets in general.
3213 : * Updated Fri, 06 May 2005 by David L. Paktor
3214 : * Error-detection of DO ... LOOP and BEGIN ... imbalance
3215 : * Error-detection of nextfcode exceeding legal maximum (0x0fff).
3216 : * Updated Wed, 20 Jul 2005 by David L. Paktor
3217 : * Put Duplicate-Name-Test under command-line control...
3218 : * Updated Wed, 24 Aug 2005 by David L. Paktor
3219 : * Error-detection via clear_control_structs() routine.
3220 : * Updated Tue, 10 Jan 2006 by David L. Paktor
3221 : * Convert to tic_hdr_t type vocabulary.
3222 : * Updated Thu, 20 Apr 2006 by David L. Paktor
3223 : * Allow creation of new definition within body of a flow-control
3224 : * structure. (Remove error-detection via clear_control_structs)
3225 : * Updated Tue, 13 Jun 2006 by David L. Paktor
3226 : * Move detection of out-of-bounds nextfcode to assigning_fcode()
3227 : * routine, which also detects Overlapping Ranges error.
3228 : * Updated Thu, 27 Jun 2006 by David L. Paktor
3229 : * Report Error for attempt to create def'n inside control structure.
3230 : *
3231 : * Extraneous Remarks:
3232 : * We must not set incolon to TRUE (if we are creating a colon
3233 : * definition) until *AFTER* this routine has been called, due
3234 : * to the initial error-checking. If we need to detect whether
3235 : * we are creating a colon definition, we can do so by testing
3236 : * whether the parameter, DEFINER, equals COLON .
3237 : *
3238 : **************************************************************************** */
3239 :
3240 : static bool create_word(fwtoken definer)
3241 9982 : {
3242 : signed long wlen;
3243 9982 : bool retval = FALSE;
3244 : char *defn_type_name;
3245 :
3246 : /* If already inside a colon, ERROR and discontinueprocessing */
3247 : /* If an alias to a definer is used, show the name of the alias */
3248 9982 : if ( test_in_colon(statbuf, FALSE, TKERROR, NULL) )
3249 : {
3250 9979 : char defn_type_buffr[32] = "";
3251 9979 : unsigned int old_lineno = lineno; /* For error message */
3252 9979 : bool define_token = TRUE;
3253 :
3254 : { /* Set up definition-type text for error-message */
3255 :
3256 : /* No need to check the return value */
3257 9979 : definer_name(definer, &defn_type_name);
3258 :
3259 9979 : strcat( defn_type_buffr, defn_type_name);
3260 9979 : strcat( defn_type_buffr, " definition");
3261 : }
3262 : /* If in a control-structure, ERROR but continue processing */
3263 9979 : if ( control_stack_depth != 0 )
3264 : {
3265 17 : announce_control_structs( TKERROR, defn_type_buffr, 0);
3266 : /* Leave the new token undefined. */
3267 17 : define_token = FALSE;
3268 : }
3269 :
3270 : /* Get the name of the new token */
3271 9979 : wlen = get_word();
3272 :
3273 : #ifdef DEBUG_SCANNER
3274 : printf("%s:%d: debug: defined new word %s, fcode no 0x%x\n",
3275 : iname, lineno, name, nextfcode);
3276 : #endif
3277 9979 : if ( wlen <= 0 )
3278 : {
3279 0 : warn_unterm( TKERROR, defn_type_buffr, old_lineno);
3280 : }else{
3281 9979 : bool emit_token_name = TRUE;
3282 :
3283 : /* Handle Tracing of new definitions */
3284 9979 : trace_creation( definer, statbuf);
3285 :
3286 : /* Other Error or Warnings as applicable */
3287 9979 : validate_instance( definer);
3288 9979 : warn_if_duplicate( statbuf);
3289 9979 : check_name_length( wlen);
3290 :
3291 : /* Bump FCode; error-check as applicable */
3292 9979 : assigning_fcode();
3293 :
3294 : /* Define the new token, unless disallowed */
3295 9978 : add_to_current( statbuf, nextfcode, definer, define_token);
3296 :
3297 : /* Emit appropriate FCodes: Type of def'n, */
3298 9978 : switch ( hdr_flag )
3299 : {
3300 : case FLAG_HEADERS:
3301 9872 : emit_token("named-token");
3302 9872 : break;
3303 :
3304 : case FLAG_EXTERNAL:
3305 19 : emit_token("external-token");
3306 19 : break;
3307 :
3308 : default: /* FLAG_HEADERLESS */
3309 87 : emit_token("new-token");
3310 87 : emit_token_name = FALSE;
3311 : }
3312 :
3313 : /* Emit name of token, if applicable */
3314 9978 : if ( emit_token_name )
3315 : {
3316 9891 : if ( force_tokens_case )
3317 : {
3318 16 : if ( force_lower_case_tokens )
3319 : {
3320 15 : strlwr( statbuf);
3321 : }else{
3322 1 : strupr( statbuf);
3323 : }
3324 : }
3325 9891 : emit_string((u8 *)statbuf, wlen);
3326 : }
3327 :
3328 : /* Emit the new token's FCode */
3329 9978 : emit_fcode(nextfcode);
3330 :
3331 : /* Prepare FCode Assignment Counter for next definition */
3332 9978 : bump_fcode();
3333 :
3334 : /* Declare victory */
3335 9978 : retval = TRUE;
3336 : }
3337 : }
3338 9981 : return( retval);
3339 : }
3340 :
3341 :
3342 : /* **************************************************************************
3343 : *
3344 : * Function name: cannot_apply
3345 : * Synopsis: Print error message of the form:
3346 : * "Cannot apply <func> to <targ>, which is a <def'n>"
3347 : *
3348 : * Inputs:
3349 : * Parameters:
3350 : * func_nam The name of the function
3351 : * targ_nam The name of the target
3352 : * defr The numeric-code of the definer-type
3353 : *
3354 : * Outputs:
3355 : * Returned Value: NONE
3356 : * Printout:
3357 : * The error message is the entire printout of this routine
3358 : *
3359 : * Error Detection:
3360 : * Error was detected by calling routine
3361 : *
3362 : * Process Explanation:
3363 : * The calling routine already looked up the definer for its
3364 : * own purposes, so we don't need to do that again here.
3365 : *
3366 : * Still to be done:
3367 : * If the definer-name is not found, we might still look up
3368 : * the target name in the various vocabularies and use
3369 : * a phrase for those. E.g., if it is a valid token,
3370 : * we could say it's defined as a "primitive". (I'm
3371 : * not sure what we'd say about an FWord...)
3372 : *
3373 : **************************************************************************** */
3374 :
3375 : static void cannot_apply( char *func_nam, char *targ_nam, fwtoken defr)
3376 32 : {
3377 32 : char *defr_name = "" ;
3378 32 : const char *defr_phrase = ", which is defined as a " ;
3379 :
3380 32 : if ( ! definer_name(defr, &defr_name) )
3381 : {
3382 13 : defr_phrase = "";
3383 : }
3384 :
3385 32 : tokenization_error ( TKERROR ,
3386 : "Cannot apply %s to %s %s%s.\n",
3387 : func_nam, targ_nam, defr_phrase, defr_name );
3388 :
3389 32 : }
3390 :
3391 :
3392 : /* **************************************************************************
3393 : *
3394 : * Function name: lookup_with_definer
3395 : * Synopsis: Return pointer to data-structure of named word,
3396 : * if it's valid in Current context, and supply its
3397 : * definer. If it's not valid in Current context,
3398 : * see if it might be a Local, and supply that definer.
3399 : *
3400 : * Inputs:
3401 : * Parameters:
3402 : * stat_name Name to look up
3403 : * *definr Pointer to place to put the definer.
3404 : *
3405 : * Outputs:
3406 : * Returned Value: Pointer to data-structure, or
3407 : * NULL if not in Current context.
3408 : * Supplied Pointers:
3409 : * *definr Definer; possibly LOCAL_VAL
3410 : *
3411 : * Process Explanation:
3412 : * If the name is not found in the Current context, and does not
3413 : * exist as a Local, *definr will remain unchanged.
3414 : *
3415 : * Extraneous Remarks:
3416 : * This is an odd duck^H^H^H^H^H^H^H^H^H^H^H^H a highly-specialized
3417 : * routine created to meet some corner-case needs engendered by
3418 : * the conversion to tic_hdr_t vocabularies all around, combined
3419 : * with an obsessive urge to preserve a high level of detail in
3420 : * our error-messages.
3421 : *
3422 : **************************************************************************** */
3423 :
3424 : static tic_hdr_t *lookup_with_definer( char *stat_name, fwtoken *definr )
3425 258 : {
3426 258 : tic_hdr_t *retval = lookup_current( stat_name);
3427 258 : if ( retval != NULL )
3428 : {
3429 251 : *definr = retval->fword_defr;
3430 : }else{
3431 7 : if ( exists_as_local( stat_name) ) *definr = LOCAL_VAL;
3432 : }
3433 258 : return ( retval );
3434 : }
3435 :
3436 : /* **************************************************************************
3437 : *
3438 : * Function name: validate_to_target
3439 : * Synopsis: Print a message if the intended target
3440 : * of the TO directive is not valid
3441 : *
3442 : * Inputs:
3443 : * Parameters: NONE
3444 : * Global Variables:
3445 : * statbuf Next symbol to be read from the input stream
3446 : * pc Input-source Scanning pointer
3447 : *
3448 : * Outputs:
3449 : * Returned Value: TRUE = Allow b(to) token to be output.
3450 : * Global Variables:
3451 : * statbuf Advanced to next symbol; must be re-read
3452 : * pc Advanced, then restored to previous value
3453 : *
3454 : * Error Detection:
3455 : * If next symbol is not a valid target of TO , issue ERROR
3456 : * message. Restored pc will cause the next symbol to
3457 : * be processed by ordinary means.
3458 : * Allow b(to) token to be output in selected cases. Even if
3459 : * user has set the "Ignore Errors" flag, certain targets are
3460 : * still too risky to be allowed to follow a b(to) token;
3461 : * if "Ignore Errors" is not set, output won't get created
3462 : * anyway.
3463 : * Issue ERROR in the extremely unlikely case that "to" is the
3464 : * last word in the Source.
3465 : *
3466 : * Process Explanation:
3467 : * Valid targets for a TO directive are words defined by:
3468 : * DEFER, VALUE and arguably VARIABLE. We will also allow
3469 : * CONSTANT, but will still issue an Error message.
3470 : * After the check, restore pc ; this was only a look-ahead.
3471 : * Also restore lineno and abs_token_no
3472 : *
3473 : * Extraneous Remarks:
3474 : * Main part of the mechanism to detect attempts to use the TO
3475 : * directive to change the values of CONSTANTs in particular
3476 : * and of inappropriate targets in general.
3477 : *
3478 : **************************************************************************** */
3479 :
3480 : static bool validate_to_target( void )
3481 202 : {
3482 : signed long wlen;
3483 : tic_hdr_t *test_entry;
3484 202 : u8 *saved_pc = pc;
3485 202 : char *cmd_cpy = strupr( strdup( statbuf)); /* For error message */
3486 202 : unsigned int saved_lineno = lineno;
3487 202 : unsigned int saved_abs_token_no = abs_token_no;
3488 202 : fwtoken defr = UNSPECIFIED ;
3489 202 : bool targ_err = TRUE ;
3490 202 : bool retval = FALSE ;
3491 :
3492 202 : wlen = get_word();
3493 202 : if ( wlen <= 0 )
3494 : {
3495 1 : warn_unterm( TKERROR, cmd_cpy, saved_lineno);
3496 : }else{
3497 :
3498 201 : test_entry = lookup_with_definer( statbuf, &defr);
3499 201 : if ( test_entry != NULL )
3500 : {
3501 197 : switch (defr)
3502 : {
3503 : case VARIABLE:
3504 7 : tokenization_error( WARNING,
3505 : "Applying %s to a VARIABLE (%s) is "
3506 : "not recommended; use ! instead.\n",
3507 : cmd_cpy, statbuf);
3508 : case DEFER:
3509 : case VALUE:
3510 177 : targ_err = FALSE ;
3511 : case CONST:
3512 179 : retval = TRUE ;
3513 : /* No default needed, likewise, no breaks; */
3514 : /* but some compilers get upset without 'em... */
3515 : default:
3516 : break;
3517 : }
3518 : }
3519 :
3520 201 : if ( targ_err )
3521 : {
3522 24 : cannot_apply(cmd_cpy, strupr(statbuf), defr );
3523 : }
3524 :
3525 201 : pc = saved_pc;
3526 201 : lineno = saved_lineno;
3527 201 : abs_token_no = saved_abs_token_no;
3528 : }
3529 202 : free( cmd_cpy);
3530 202 : return( retval);
3531 : }
3532 :
3533 :
3534 : /* **************************************************************************
3535 : *
3536 : * Function name: you_are_here
3537 : * Synopsis: Display a generic Advisory of the Source command
3538 : * or directive encountered and being processed
3539 : *
3540 : * Inputs:
3541 : * Parameters: NONE
3542 : * Global Variables:
3543 : * statbuf The command being processed
3544 : *
3545 : * Outputs:
3546 : * Returned Value: NONE
3547 : * Printout:
3548 : * Advisory message
3549 : *
3550 : **************************************************************************** */
3551 :
3552 : static void you_are_here( void)
3553 335 : {
3554 335 : tokenization_error( INFO,
3555 : "%s encountered; processing...\n",
3556 : strupr(statbuf) );
3557 335 : }
3558 :
3559 :
3560 : /* **************************************************************************
3561 : *
3562 : * Function name: fcode_starter
3563 : * Synopsis: Respond to one of the "FCode Starter" words
3564 : *
3565 : * Inputs:
3566 : * Parameters:
3567 : * token_name The FCode-token for this "Starter" word
3568 : * spread The separation between tokens.
3569 : * is_offs16 Whether we are using a 16-bit number
3570 : * for branch- (and suchlike) -offsets,
3571 : * or the older-style 8-bit offset numbers.
3572 : * Global Variables:
3573 : * iname Input-File name, used to set ifile_name
3574 : * field of current_device_node
3575 : * lineno Current Input line number, used to set
3576 : * line_no field of current_device_node
3577 : * Local Static Variables:
3578 : * fcode_started If this is TRUE, we have an Error.
3579 : * first_fc_starter Control calling reset_fcode_ranges() ;
3580 : * only on the first fcode_starter of
3581 : * a tokenization.
3582 : *
3583 : * Outputs:
3584 : * Returned Value: NONE
3585 : * Global Variables:
3586 : * offs16 Global "16-bit-offsets" flag
3587 : * current_device_node The ifile_name and line_no fields will be
3588 : * loaded with the current input file name
3589 : * and line number. This node will be the
3590 : * top-level device-node.
3591 : * FCode Ranges will be reset the first time per tokenization
3592 : * that this routine is entered.
3593 : * A new FCode Range will be started every time after that.
3594 : * Local Static Variables:
3595 : * fcode_started Set to TRUE. We invoke the starter only
3596 : * once per image-block.
3597 : * first_fc_starter Reset to FALSE if not already
3598 : * Memory Allocated
3599 : * Duplicate of Input-File name
3600 : * When Freed?
3601 : * In fcode_ender()
3602 : *
3603 : * Error Detection:
3604 : * Spread of other than 1 -- Warning message.
3605 : * "FCode Starter" previously encountered -- Warning and ignore.
3606 : *
3607 : * Question under consideration:
3608 : * Do we want directives -- such as definitions of constants --
3609 : * supplied before the "FCode Starter", to be considered as
3610 : * taking place in "Tokenizer Escape" mode? That would mean
3611 : * the "Starter" functions must be recognized in "Tokenizer
3612 : * Escape" mode. Many ramifications to be thought through...
3613 : * I think I'm coming down strongly on the side of "No". The user
3614 : * who wants to do that can very well invoke "Tokenizer Escape"
3615 : * mode explicitly.
3616 : *
3617 : **************************************************************************** */
3618 :
3619 : static void fcode_starter( const char *token_name, int spread, bool is_offs16)
3620 170 : {
3621 170 : you_are_here();
3622 170 : if ( spread != 1 )
3623 : {
3624 0 : tokenization_error( WARNING, "spread of %d not supported.\n", spread);
3625 : }
3626 170 : if ( fcode_started )
3627 : {
3628 0 : tokenization_error( WARNING,
3629 : "Only one \"FCode Starter\" permitted per tokenization. "
3630 : "Ignoring...\n");
3631 : } else {
3632 :
3633 170 : emit_fcodehdr(token_name);
3634 170 : offs16 = is_offs16;
3635 170 : fcode_started = TRUE;
3636 :
3637 170 : current_device_node->ifile_name = strdup(iname);
3638 170 : current_device_node->line_no = lineno;
3639 :
3640 170 : if ( first_fc_starter )
3641 : {
3642 141 : reset_fcode_ranges();
3643 141 : first_fc_starter = FALSE;
3644 : }else{
3645 29 : set_next_fcode( nextfcode);
3646 : }
3647 : }
3648 170 : }
3649 :
3650 : /* **************************************************************************
3651 : *
3652 : * Function name: fcode_end_err_check
3653 : * Synopsis: Do error-checking at end of tokenization,
3654 : * whether due to FCODE-END or end-of-file,
3655 : * and reset the indicators we check.
3656 : *
3657 : * Inputs:
3658 : * Parameters: NONE
3659 : * Global Variables:
3660 : * Data-Stack depth Is anything left on the stack?
3661 : *
3662 : * Outputs:
3663 : * Returned Value: NONE
3664 : * Global Variables:
3665 : * Data-Stack Reset to empty
3666 : *
3667 : * Error Detection:
3668 : * Unresolved control structures detected by clear_control_structs()
3669 : * If anything is left on the stack, it indicates some incomplete
3670 : * condition; we will treat it as a Warning.
3671 : *
3672 : **************************************************************************** */
3673 :
3674 : static void fcode_end_err_check( void)
3675 170 : {
3676 170 : bool stack_imbal = BOOLVAL( stackdepth() != 0 );
3677 :
3678 170 : if ( stack_imbal )
3679 : {
3680 13 : tokenization_error( WARNING,
3681 : "Stack imbalance before end of tokenization.\n");
3682 : }
3683 170 : clear_stack();
3684 170 : clear_control_structs("End of tokenization");
3685 170 : }
3686 :
3687 : /* **************************************************************************
3688 : *
3689 : * Function name: fcode_ender
3690 : * Synopsis: Respond to one of the "FCode Ender" words:
3691 : * The FCode-token for "End0" or "End1"
3692 : * has already been written to the
3693 : * FCode Output buffer.
3694 : * Finish the FCode header: fill in its
3695 : * checksum and length.
3696 : * Reset the token names defined in "normal" mode
3697 : * (Does not reset the FCode-token number)
3698 : *
3699 : * Associated FORTH words: END0, END1
3700 : * Associated Tokenizer directive: FCODE-END
3701 : *
3702 : * Inputs:
3703 : * Parameters: NONE
3704 : * Global Variables:
3705 : * incolon If TRUE, a colon def'n has not been completed
3706 : * last_colon_filename For error message.
3707 : * last_colon_lineno For error message.
3708 : * scope_is_global For error detection
3709 : * is_instance For error detection
3710 : *
3711 : * Outputs:
3712 : * Returned Value: NONE
3713 : * Global Variables:
3714 : * haveend Set to TRUE
3715 : * fcode_started Reset to FALSE. Be ready to start anew.
3716 : * FCode-defined tokens, aliases and macros -- i.e., those
3717 : * *NOT* defined in tokenizer-escape mode -- are reset.
3718 : * (Also, command-line-defined symbols are preserved).
3719 : * Vocabularies will be reset
3720 : * Device-node data structures will be deleted
3721 : * Top-level device-node ifile_name and line_no fields
3722 : * will be reset.
3723 : * Memory Freed
3724 : * Duplicate of Input-File name, in top-level device-node.
3725 : * Printout:
3726 : * Advisory message giving current value of nextfcode
3727 : * (the "FCode-token Assignment Counter")
3728 : *
3729 : * Error Detection:
3730 : * ERROR if a Colon definition has not been completed.
3731 : * ERROR if "instance" is still in effect
3732 : * WARNING if Global-Scope has not been terminated; compensate.
3733 : *
3734 : * Extraneous Remarks:
3735 : * In order to accommodate odd cases, such as multiple FCode blocks
3736 : * within a single PCI header, this routine does not automatically
3737 : * reset nextfcode to h# 0800
3738 : *
3739 : **************************************************************************** */
3740 :
3741 : void fcode_ender(void)
3742 170 : {
3743 170 : if ( incolon )
3744 : {
3745 3 : char *tmp_iname = iname;
3746 3 : iname = last_colon_filename;
3747 3 : unterm_is_colon = TRUE;
3748 3 : warn_unterm( TKERROR, "Colon Definition", last_colon_lineno);
3749 3 : iname = tmp_iname;
3750 : }
3751 :
3752 170 : haveend = TRUE;
3753 :
3754 170 : if ( is_instance )
3755 : {
3756 2 : unresolved_instance( TKERROR);
3757 : }
3758 :
3759 170 : if ( scope_is_global )
3760 : {
3761 6 : tokenization_error( WARNING ,
3762 : "No DEVICE-DEFINITIONS directive encountered before end. "
3763 : "Compensating...\n");
3764 6 : resume_device_scope();
3765 : }
3766 170 : fcode_end_err_check();
3767 170 : reset_normal_vocabs();
3768 170 : finish_fcodehdr();
3769 170 : fcode_started = FALSE;
3770 :
3771 170 : if ( current_device_node->ifile_name != default_top_dev_ifile_name )
3772 : {
3773 169 : free( current_device_node->ifile_name );
3774 169 : current_device_node->ifile_name = default_top_dev_ifile_name;
3775 169 : current_device_node->line_no = 0;
3776 : }
3777 170 : }
3778 :
3779 : /* **************************************************************************
3780 : *
3781 : * Function name: get_token
3782 : * Synopsis: Read the next word in the input stream and retrieve
3783 : * its FCode-token number. If it's not a symbol to
3784 : * which a single token is assigned (e.g., if it's
3785 : * a macro), report an error.
3786 : *
3787 : * Associated FORTH words: ['] '
3788 : * Associated Tokenizer directive: F[']
3789 : *
3790 : * Inputs:
3791 : * Parameters:
3792 : * *tok_entry Place to put the pointer to token entry
3793 : * Global Variables:
3794 : * statbuf The command being processed
3795 : * pc Input stream character pointer
3796 : *
3797 : * Outputs:
3798 : * Returned Value: TRUE if successful (i.e., no error)
3799 : * Supplied Pointers:
3800 : * *tok_entry The token entry, if no error
3801 : * Global Variables:
3802 : * statbuf The next word in the input stream
3803 : * pc Restored to previous value if error
3804 : *
3805 : * Error Detection:
3806 : * The next word in the input stream is expected to be on the
3807 : * same line as the directive. The get_word_in_line()
3808 : * routine will check for that.
3809 : * If the next word in the input stream is not a symbol
3810 : * for which a single-token FCode number is assigned,
3811 : * report an ERROR and restore PC to its previous value.
3812 : *
3813 : **************************************************************************** */
3814 :
3815 : static bool get_token(tic_hdr_t **tok_entry)
3816 58 : {
3817 58 : bool retval = FALSE;
3818 : u8 *save_pc;
3819 :
3820 : /* Copy of command being processed, for error message */
3821 : char cmnd_cpy[FUNC_CPY_BUF_SIZE+1];
3822 58 : strncpy( cmnd_cpy, statbuf, FUNC_CPY_BUF_SIZE);
3823 58 : cmnd_cpy[FUNC_CPY_BUF_SIZE] = 0; /* Guarantee null terminator. */
3824 :
3825 58 : save_pc = pc;
3826 :
3827 58 : if ( get_word_in_line( statbuf) )
3828 : {
3829 57 : fwtoken defr = UNSPECIFIED;
3830 :
3831 : /* We need to scan the newest definitions first; they
3832 : * might supercede standard ones. We need, though,
3833 : * to bypass built-in FWords that need to trigger
3834 : * some tokenizer internals before emitting their
3835 : * synonymous FCode Tokens, (e.g., version1 , end0 ,
3836 : * and start{0-4}); if we find one of those, we will
3837 : * need to search again, specifically within the list
3838 : * of FCode Tokens.
3839 : */
3840 57 : *tok_entry = lookup_with_definer( statbuf, &defr);
3841 57 : if ( *tok_entry != NULL )
3842 : {
3843 : /* Built-in FWords can be uniquely identified by their
3844 : * definer, BI_FWRD_DEFN . The definer for "shared"
3845 : * FWords is COMMON_FWORD but there are none of
3846 : * those that might be synonymous with legitimate
3847 : * FCode Tokens, nor are any likely ever to be...
3848 : */
3849 54 : if ( defr == BI_FWRD_DEFN )
3850 : {
3851 11 : *tok_entry = lookup_token( statbuf);
3852 11 : retval = BOOLVAL( *tok_entry != NULL );
3853 : }else{
3854 43 : retval = entry_is_token( *tok_entry);
3855 : }
3856 : }
3857 :
3858 57 : if ( INVERSE( retval) )
3859 : {
3860 8 : cannot_apply( cmnd_cpy, strupr(statbuf), defr );
3861 8 : pc = save_pc;
3862 : }
3863 : }
3864 :
3865 58 : return ( retval );
3866 : }
3867 :
3868 :
3869 : static void base_change ( int new_base )
3870 93 : {
3871 95 : if ( incolon && ( INVERSE( in_tokz_esc) ) )
3872 : {
3873 2 : emit_literal(new_base );
3874 2 : emit_token("base");
3875 2 : emit_token("!");
3876 : } else {
3877 91 : base = new_base;
3878 : }
3879 93 : }
3880 :
3881 : static void base_val (int new_base)
3882 341 : {
3883 : u8 *old_pc;
3884 :
3885 : char base_cmnd[FUNC_CPY_BUF_SIZE+1];
3886 341 : strncpy( base_cmnd, statbuf, FUNC_CPY_BUF_SIZE);
3887 341 : base_cmnd[FUNC_CPY_BUF_SIZE] = 0; /* Guarantee NULL terminator */
3888 :
3889 341 : old_pc=pc;
3890 341 : if ( get_word_in_line( statbuf) )
3891 : {
3892 341 : u8 basecpy=base;
3893 :
3894 341 : base = new_base;
3895 341 : if ( ! handle_number() )
3896 : {
3897 : /* We did get a word on the line, but it's not a valid number */
3898 6 : tokenization_error( WARNING ,
3899 : "Applying %s to non-numeric value. Ignoring.\n",
3900 : strupr(base_cmnd) );
3901 6 : pc = old_pc;
3902 : }
3903 341 : base=basecpy;
3904 : }
3905 341 : }
3906 :
3907 :
3908 : /* **************************************************************************
3909 : *
3910 : * Function name: eval_string
3911 : * Synopsis: Prepare to tokenize a string, artificially generated
3912 : * by this program or created as a user-defined
3913 : * Macro. When done, resume at existing source.
3914 : * Keep the file-name and line-number unchanged.
3915 : *
3916 : * Inputs:
3917 : * Parameters:
3918 : * inp_bufr String (or buffer) to evaluate
3919 : *
3920 : * Outputs:
3921 : * Returned Value: NONE
3922 : * Global Variables, changed by call to init_inbuf():
3923 : * start Points to given string
3924 : * pc ditto
3925 : * end Points to end of given string
3926 : *
3927 : * Revision History:
3928 : * Updated Thu, 23 Feb 2006 by David L. Paktor
3929 : * This routine no longer calls its own instance of tokenize()
3930 : * It has become the gateway to the mechanism that makes a
3931 : * smooth transition between the body of the Macro, User-
3932 : * defined Symbol or internally-generated string and the
3933 : * resumption of processing the source file.
3934 : * A similar (but more complicated) transition when processing
3935 : * an FLOADed file will be handled elsewhere.
3936 : * Updated Fri, 24 Feb 2006 by David L. Paktor
3937 : * In order to support Macro-recursion protection, this routine
3938 : * is no longer the gateway for Macros; they will have to
3939 : * call push_source() directly.
3940 : *
3941 : **************************************************************************** */
3942 :
3943 : void eval_string( char *inp_bufr)
3944 834 : {
3945 834 : push_source( NULL, NULL, FALSE);
3946 834 : init_inbuf( inp_bufr, strlen(inp_bufr));
3947 834 : }
3948 :
3949 :
3950 : /* **************************************************************************
3951 : *
3952 : * Function name: finish_or_new_device
3953 : * Synopsis: Handle the shared logic for the NEW-DEVICE and
3954 : * FINISH-DEVICE commands.
3955 : *
3956 : * Inputs:
3957 : * Parameters:
3958 : * finishing_device TRUE for FINISH-DEVICE,
3959 : * FALSE for NEW-DEVICE
3960 : * Global Variables:
3961 : * incolon TRUE if inside a colon definition
3962 : * noerrors TRUE if ignoring errors
3963 : * scope_is_global TRUE if "global scope" in effect
3964 : * Local Static Variables:
3965 : * is_instance TRUE if "instance" is in effect
3966 : * dev_change_instance_warning TRUE if warning hasn't been issued
3967 : *
3968 : * Outputs:
3969 : * Returned Value: NONE
3970 : * Local Static Variables:
3971 : * dev_change_instance_warning FALSE if warning is issued
3972 : * instance_definer_gap TRUE if "instance" is in effect
3973 : *
3974 : * Error Detection:
3975 : * NEW-DEVICE and FINISH-DEVICE should not be used outside of
3976 : * a colon-definition if global-scope is in effect. Error
3977 : * message; no further action unless we are ignoring errors.
3978 : * Issue a WARNING if INSTANCE wasn't resolved before the current
3979 : * device-node is changed. Try not to be too repetitive...
3980 : *
3981 : * Process Explanation:
3982 : * The words NEW-DEVICE and FINISH-DEVICE may be incorporated into
3983 : * a colon-definition, whether the word is defined in global-
3984 : * or device- -scope. Such an incorporation does not effect
3985 : * a change in the device-node vocabulary; simply emit the token.
3986 : * If we are in interpretation mode, though, we need to check for
3987 : * errors before changing the device-node vocabulary:
3988 : * If global-scope is in effect, we need to check whether we are
3989 : * ignoring errors; if so, we will compensate by switching to
3990 : * device-scope.
3991 : * If "instance" is in effect, it's "dangling". It will remain
3992 : * in effect through a device-node change, but this is very
3993 : * bad style and deserves a WARNING, but only one for each
3994 : * occurrence. It would be unaesthetic, to say the least,
3995 : * to have multiple messages for the same dangling "instance"
3996 : * in a "finish-device new-device" sequence.
3997 : * We must be careful about the order we do things, because of
3998 : * the messages printed as a side-effect of the node change...
3999 : *
4000 : * Extraneous Remarks:
4001 : * I will violate strict structure here.
4002 : *
4003 : **************************************************************************** */
4004 :
4005 : static void finish_or_new_device( bool finishing_device )
4006 177 : {
4007 177 : if ( INVERSE( incolon ) )
4008 : {
4009 169 : if ( INVERSE( is_instance) )
4010 : {
4011 : /* Arm warning for next time: */
4012 160 : dev_change_instance_warning = TRUE;
4013 : }else{
4014 : /* Dangling "instance" */
4015 9 : instance_definer_gap = TRUE;
4016 : /* Warn only once. */
4017 9 : if ( dev_change_instance_warning )
4018 : {
4019 9 : unresolved_instance( WARNING);
4020 9 : dev_change_instance_warning = FALSE;
4021 : }
4022 : }
4023 :
4024 : /* Note: "Instance" cannot be in effect during "global" scope */
4025 169 : if ( scope_is_global )
4026 : {
4027 11 : glob_not_allowed( TKERROR, noerrors );
4028 11 : if ( noerrors )
4029 : {
4030 8 : resume_device_scope();
4031 : }else{
4032 3 : return;
4033 : }
4034 : }
4035 :
4036 166 : if ( finishing_device )
4037 : {
4038 83 : finish_device_vocab();
4039 : }else{
4040 83 : new_device_vocab();
4041 : }
4042 : }
4043 174 : emit_token( finishing_device ? "finish-device" : "new-device" );
4044 : }
4045 :
4046 :
4047 : /* **************************************************************************
4048 : *
4049 : * Function name: abort_quote
4050 : * Synopsis: Optionally implement the ABORT" function as
4051 : * though it were a macro. Control whether to allow
4052 : * it, and which style to support, via switches set
4053 : * on the command-line at run-time.
4054 : *
4055 : * Inputs:
4056 : * Parameters:
4057 : * tok Numeric-code associated with the
4058 : * FORTH word that was just read.
4059 : * Global Variables:
4060 : * enable_abort_quote Whether to allow ABORT"
4061 : * sun_style_abort_quote SUN-style versus Apple-style
4062 : * abort_quote_throw Whether to use -2 THROW vs ABORT
4063 : *
4064 : * Outputs:
4065 : * Returned Value: TRUE if it was handled
4066 : * Global Variables:
4067 : * report_multiline Reset to FALSE.
4068 : * Printout:
4069 : * ADVISORY: ABORT" in fcode is not defined by IEEE 1275-1994
4070 : *
4071 : * Error Detection:
4072 : * Performed by other routines. If user selected not to
4073 : * allow ABORT" , it will simply be treated as an
4074 : * unknown word.
4075 : * The string following it, however, will still be consumed.
4076 : *
4077 : * Process Explanation:
4078 : * If the supplied tok was not ABORTTXT , then return FALSE.
4079 : * If the enable_abort_quote flag is FALSE, consume the
4080 : * string following the Abort" token, but be careful to
4081 : * leave the Abort" token in statbuf, as it will be used
4082 : * for the error message.
4083 : * Otherwise, create and prepare for processing the appropriate Macro:
4084 : * For Apple Style, we push the specified string onto the stack
4085 : * and do -2 THROW (and hope the stack unwinds correctly).
4086 : * For Sun Style, we test the condition on top of the stack,
4087 : * and if it's true, print the specified string before we
4088 : * do the -2 THROW.
4089 : * We perform the underlying operations directly: placing an "IF"
4090 : * (if Sun Style), then placing the string. This bypasses
4091 : * any issues of double-parsing, as well as of doubly checking
4092 : * for a multi-line string.
4093 : * Finally, we perform the operational equivalents of the remainder
4094 : * of the command sequence.
4095 : *
4096 : * Extraneous Remarks:
4097 : * I would have preferred not to have to directly perform the under-
4098 : * lying operations, and instead simply prepare the entire command
4099 : * sequence in a buffer, but I needed to handle the case where
4100 : * quote-escaped quotes are included in the string: If the string
4101 : * were simply to be reproduced into the buffer, the quote-escaped
4102 : * quotes would appear as plain quote-marks and terminate the
4103 : * string parsing prematurely, leaving the rest of the string
4104 : * to be treated as code instead of text...
4105 : * Also, the introduction of the variability of whether to do the
4106 : * -2 THROW or to compile-in the token for ABORT makes the
4107 : * buffer-interpretation scheme somewhat too messy for my tastes.
4108 : *
4109 : **************************************************************************** */
4110 :
4111 : static bool abort_quote( fwtoken tok)
4112 36 : {
4113 36 : bool retval = FALSE;
4114 36 : if ( tok == ABORTTXT )
4115 : {
4116 14 : if ( ! enable_abort_quote )
4117 : {
4118 : /* ABORT" is not enabled; we'd better consume the string */
4119 : char *save_statbuf;
4120 : signed long wlen;
4121 4 : save_statbuf = strdup( (char *)statbuf);
4122 4 : wlen = get_string( FALSE);
4123 4 : strcpy( statbuf, save_statbuf);
4124 4 : free( save_statbuf);
4125 : }else{
4126 : /* ABORT" is not to be used in FCODE drivers
4127 : * but Apple drivers do use it. Therefore we
4128 : * allow it. We push the specified string to
4129 : * the stack, do -2 THROW and hope that THROW
4130 : * will correctly unwind the stack.
4131 : * Presumably, Apple Source supplies its own
4132 : * IF ... THEN
4133 : */
4134 : char *abort_string;
4135 : signed long wlen;
4136 :
4137 10 : retval = TRUE;
4138 10 : tokenization_error (INFO, "ABORT\" in fcode not "
4139 : "defined by IEEE 1275-1994\n");
4140 10 : test_in_colon("ABORT\"", TRUE, TKERROR, NULL);
4141 10 : wlen=get_string( TRUE);
4142 :
4143 10 : if ( sun_style_abort_quote ) emit_if();
4144 :
4145 10 : emit_token("b(\")");
4146 10 : emit_string(statbuf, wlen);
4147 :
4148 10 : if ( sun_style_abort_quote ) emit_token("type");
4149 :
4150 10 : if ( abort_quote_throw )
4151 : {
4152 9 : emit_literal( -2);
4153 9 : emit_token("throw");
4154 : }else{
4155 1 : emit_token("abort");
4156 : }
4157 :
4158 10 : if ( sun_style_abort_quote ) emit_then();
4159 : /* Sun Style */
4160 10 : abort_string = " type -2 THROW THEN:" ;
4161 : }
4162 : }
4163 36 : return( retval );
4164 : }
4165 :
4166 :
4167 : /* **************************************************************************
4168 : *
4169 : * Function name: create_alias
4170 : * Synopsis: Create an alias, as specified by the user
4171 : *
4172 : * Associated FORTH word: ALIAS
4173 : *
4174 : * Inputs:
4175 : * Parameters: NONE
4176 : * Global Variables:
4177 : * incolon Colon-def'n-in-progress indicator
4178 : * in_tokz_esc "Tokenizer Escape" mode indicator
4179 : * Input Stream
4180 : * Two words will be read.
4181 : *
4182 : * Outputs:
4183 : * Returned Value: TRUE if succeeded.
4184 : * Global Variables:
4185 : * statbuf New name will be copied back into here.
4186 : * Memory Allocated
4187 : * The two words will be copied into freshly-allocated memory
4188 : * that will be passed to the create_..._alias() routine.
4189 : * When Freed?
4190 : * When Current Device Vocabulary is "finished", or at end
4191 : * of tokenization, or upon termination of program.
4192 : * If not able to create alias, the copies will be freed here.
4193 : *
4194 : * Error Detection:
4195 : * If the ALIAS command was given during colon-definition, that
4196 : * can be handled by this tokenizer, but it is not supported
4197 : * by IEEE 1275-1994. Issue a WARNING.
4198 : * If the new name is a copy of an existing word-name, issue a warning.
4199 : * If the word to which an alias is to be created does not exist
4200 : * in the appropriate mode -- relative to "Tokenizer-Escape" --
4201 : * that is an ERROR.
4202 : * If "instance" is in effect, the ALIAS command is an ERROR.
4203 : *
4204 : * Process Explanation:
4205 : * Get two words -- the new name and the "old" word -- from the
4206 : * same line of input as the ALIAS command.
4207 : * Copy the new name back into statbuf for use in trace_creation.
4208 : * Determine whether or not we are in "Tokenizer-Escape" mode.
4209 : * Subsequent searches will take place in that same mode.
4210 : * If the "new" name already exists, issue a warning.
4211 : * In each vocabulary applicable to the current mode -- i.e.,
4212 : * "Tokenizer-Escape" or "Normal" -- (except: cannot
4213 : * make aliases to "Locals"):
4214 : * Try using the create_..._alias() routine.
4215 : * If it succeeds, we are done.
4216 : * IMPORTANT: The order in which we try the vocabularies MUST
4217 : * match the order in which tokenize_one_word() searches them.
4218 : * If all the attempts failed, the "old" word does not exist;
4219 : * declare an ERROR and free up the memory that was allocated.
4220 : *
4221 : * Extraneous Remarks:
4222 : * With the separation of the tokenizer[ state, this
4223 : * function has become too complicated to keep as a
4224 : * simple CASE in the big SWITCH statement anymore...
4225 : *
4226 : * I had earlier thought that it was sufficient to create a
4227 : * macro linking the "new" name to the "old" word. There
4228 : * were too many cases, though, where that didn't work.
4229 : * This is cleaner.
4230 : *
4231 : * I will not be adhering to the strict rules of structure in
4232 : * this routine, as it would get me nested too deeply...
4233 : *
4234 : * Revision History:
4235 : * Updated Tue, 10 Jan 2006 by David L. Paktor
4236 : * Convert to tic_hdr_t type vocabularies.
4237 : *
4238 : **************************************************************************** */
4239 :
4240 : static bool create_alias( void )
4241 214 : {
4242 : char *new_alias ;
4243 :
4244 214 : validate_instance(ALIAS);
4245 214 : if ( incolon )
4246 : {
4247 20 : tokenization_error ( WARNING,
4248 : "ALIAS during colon-definition "
4249 : "is not supported by IEEE 1275-1994\n");
4250 : }
4251 214 : if ( get_word_in_line( "ALIAS") )
4252 : {
4253 :
4254 213 : new_alias = strdup((char *)statbuf);
4255 :
4256 213 : if (get_word_in_line( "ALIAS") )
4257 : {
4258 212 : char *old_name = strdup((char *)statbuf) ;
4259 :
4260 : /* Copy the "new" alias name back into statbuf.
4261 : * This is a HACK ^H^H^H^H awkward way to retrofit
4262 : * support for the trace_creation() function.
4263 : */
4264 212 : strcpy( statbuf, new_alias);
4265 :
4266 : /* We don't call trace_creation() here because we don't
4267 : * know if the creation succeeded. However, we want
4268 : * to issue a "Duplicate" warning based on the attempt,
4269 : * even if it doesn't succeed.
4270 : * We would prefer to have the "Trace" message precede the
4271 : * "Duplicate" warning, but we don't think it's worth
4272 : * the effort. When it becomes worthwhile, the way to
4273 : * do it would be to factor out the block that handles
4274 : * normal-tokenization versus "Tokenizer-Escape" mode;
4275 : * condition the "Trace" message on its success-return,
4276 : * show the "Duplicate" warning in any case, then show
4277 : * the error-message and do the cleanup conditioned on
4278 : * a failure-return.
4279 : * That will also obviate the need for a return value from
4280 : * this routine and for the copy-back into statbuf.
4281 : */
4282 212 : warn_if_duplicate(new_alias);
4283 :
4284 : /*
4285 : * Here is where we begin trying the create_..._alias()
4286 : * routines for the vocabularies.
4287 : */
4288 :
4289 : /*
4290 : * Distinguish between "Normal" tokenization mode
4291 : * and "Tokenizer Escape" mode
4292 : */
4293 212 : if ( in_tokz_esc )
4294 : {
4295 89 : if ( create_tokz_esc_alias( new_alias, old_name) )
4296 80 : return(TRUE);
4297 :
4298 : /*
4299 : * Handle the classes of operatives that are common between
4300 : * "Tokenizer Escape" mode and "Normal" tokenization mode.
4301 : * Those classes include selected non-fcode forth constructs
4302 : * and Conditional-Compilation Operators.
4303 : */
4304 : {
4305 9 : tic_hdr_t *found = lookup_shared_word( old_name);
4306 9 : if ( found != NULL )
4307 : {
4308 4 : if ( create_core_alias( new_alias, old_name) )
4309 4 : return(TRUE);
4310 : }
4311 : }
4312 : }else{
4313 : /* "Normal" tokenization mode */
4314 :
4315 : /* Can create aliases for "Locals", why not? */
4316 123 : if ( create_local_alias( new_alias, old_name) )
4317 1 : return(TRUE);
4318 :
4319 : /*
4320 : * All other classes of operatives -- non-fcode forth
4321 : * constructs, Standard and user-defined fcode
4322 : * tokens, Macros, and Conditional-Compilation
4323 : * Operators, -- are included in the "currently
4324 : * active" vocabulary.
4325 : */
4326 :
4327 122 : if ( create_current_alias( new_alias, old_name) )
4328 110 : return(TRUE);
4329 :
4330 : } /* End of separate handling for normal-tokenization mode
4331 : * versus "Tokenizer-Escape" mode
4332 : */
4333 :
4334 : /* It's not a word, a macro or any of that other stuff. */
4335 17 : tokenized_word_error(old_name);
4336 17 : free(old_name);
4337 : }
4338 18 : free (new_alias);
4339 : }
4340 19 : return(FALSE);
4341 : }
4342 :
4343 :
4344 : /* **************************************************************************
4345 : *
4346 : * Function name: string_err_check
4347 : * Synopsis: Error-check after processing or Ignoring
4348 : * simple strings
4349 : *
4350 : * Inputs:
4351 : * Parameters:
4352 : * is_paren TRUE if string is Dot-Paren .(
4353 : * FALSE if Ess-Quote ( s" )
4354 : * sav_lineno Saved Line Number, for Unterminated Error
4355 : * strt_lineno Start Line Number, for Multiline Warning
4356 : * Global Variables:
4357 : * noerrors TRUE if ignoring errors
4358 : * Local Static Variables:
4359 : * got_until_eof TRUE if reached end of buffer before delim.
4360 : *
4361 : * Outputs:
4362 : * Returned Value: TRUE if did not reach end of buffer, or,
4363 : * if ignoring errors, TRUE anyway.
4364 : *
4365 : * Error Detection:
4366 : * Multi-line warning, "Unterminated" Error messages, as apppropriate
4367 : *
4368 : **************************************************************************** */
4369 :
4370 : static bool string_err_check( bool is_paren,
4371 : unsigned int sav_lineno,
4372 : unsigned int strt_lineno )
4373 37 : {
4374 37 : bool retval = noerrors ;
4375 : char *item_typ = is_paren ?
4376 37 : "Dot-Paren" : "Ess-Quote" ;
4377 37 : if ( got_until_eof ) /* Crude retrofit... */
4378 : {
4379 2 : warn_unterm( TKERROR, item_typ, sav_lineno );
4380 : }else{
4381 35 : retval = TRUE;
4382 35 : warn_if_multiline( item_typ, strt_lineno );
4383 : }
4384 37 : return( retval);
4385 : }
4386 :
4387 :
4388 : /* **************************************************************************
4389 : *
4390 : * Function name: handle_internal
4391 : * Synopsis: Perform the functions associated with FORTH words
4392 : * that do not map directly to a single token. This
4393 : * is the functions that will go into the FUNCT field
4394 : * of entries in the "FWords" and "Shared Words" lists.
4395 : *
4396 : * Inputs:
4397 : * Parameters:
4398 : * pfield Param-field of the tic_hdr_t -type entry
4399 : * associated with the FORTH-Word (FWord)
4400 : * just read that is being "handled".
4401 : * Global Variables:
4402 : * statbuf The word that was just read.
4403 : *
4404 : * Outputs:
4405 : * Returned Value: NONE
4406 : * Global Variables:
4407 : * statbuf More words may be read.
4408 : *
4409 : * Error Detection:
4410 : * Too numerous to list here...
4411 : *
4412 : * Process Explanation:
4413 : * Recast the type of the param-field of a tic_hdr_t -type
4414 : * entry and rename it "tok".
4415 : * The "tok" will be used as the control-expression for a
4416 : * SWITCH statement with a large number of CASE labels.
4417 : * Both "FWords" and "shared_words" list entries will
4418 : * be processed by this routine.
4419 : *
4420 : * Revision History:
4421 : * Updated Wed, 20 Jul 2005 by David L. Paktor
4422 : * Put handling of ABORT" under control of a run-time
4423 : * command-line switch.
4424 : * Put decision to support IBM-style Locals under control
4425 : * of a run-time command-line switch.
4426 : * Updated Tue, 17 Jan 2006 by David L. Paktor
4427 : * Convert to handler for tic_hdr_t type vocab entries.
4428 : *
4429 : * Extraneous Remarks:
4430 : * We would prefer to keep this function private, so we will
4431 : * declare its prototype here and in the one other file
4432 : * where we need it, namely, dictionary.c, rather than
4433 : * exporting it widely in a .h file.
4434 : *
4435 : **************************************************************************** */
4436 :
4437 : void handle_internal( tic_param_t pfield);
4438 : void handle_internal( tic_param_t pfield)
4439 53162 : {
4440 53162 : fwtoken tok = pfield.fw_token;
4441 :
4442 : signed long wlen;
4443 53162 : unsigned int sav_lineno = lineno; /* For error message */
4444 :
4445 53162 : bool handy_toggle = TRUE ; /* Various uses... */
4446 :
4447 : #ifdef DEBUG_SCANNER
4448 : printf("%s:%d: debug: tokenizing control word '%s'\n",
4449 : iname, lineno, statbuf);
4450 : #endif
4451 53162 : switch (tok) {
4452 : case BEGIN:
4453 47 : emit_begin();
4454 47 : break;
4455 :
4456 : case BUFFER:
4457 34 : if ( create_word(tok) )
4458 : {
4459 34 : emit_token("b(buffer:)");
4460 : }
4461 : break;
4462 :
4463 : case CONST:
4464 9077 : if ( create_word(tok) )
4465 : {
4466 9075 : emit_token("b(constant)");
4467 : }
4468 : break;
4469 :
4470 : case COLON:
4471 : {
4472 : /* Collect error- -detection or -reporting items,
4473 : * but don't commit until we're sure the
4474 : * creation was a success.
4475 : */
4476 718 : u16 maybe_last_colon_fcode = nextfcode ;
4477 718 : unsigned int maybe_last_colon_lineno = lineno;
4478 718 : unsigned int maybe_last_colon_abs_token_no = abs_token_no;
4479 718 : unsigned int maybe_last_colon_do_depth = do_loop_depth;
4480 : /* last_colon_defname
4481 : * has to wait until after call to create_word()
4482 : */
4483 :
4484 718 : if ( create_word(tok) )
4485 : {
4486 717 : last_colon_fcode = maybe_last_colon_fcode;
4487 717 : last_colon_lineno = maybe_last_colon_lineno;
4488 717 : last_colon_abs_token_no = maybe_last_colon_abs_token_no;
4489 717 : last_colon_do_depth = maybe_last_colon_do_depth;
4490 717 : collect_input_filename( &last_colon_filename);
4491 : /* Now we can get last_colon_defname */
4492 717 : if ( last_colon_defname != NULL )
4493 : {
4494 607 : free( last_colon_defname);
4495 : }
4496 717 : last_colon_defname = strdup(statbuf);
4497 :
4498 717 : emit_token("b(:)");
4499 717 : incolon=TRUE;
4500 717 : hide_last_colon();
4501 717 : lastcolon = opc;
4502 : }
4503 : }
4504 : break;
4505 :
4506 : case SEMICOLON:
4507 718 : if ( test_in_colon("SEMICOLON", TRUE, TKERROR, NULL) )
4508 : {
4509 714 : ret_stk_balance_rpt( "termination,", TRUE);
4510 : /* Clear Control Structures just back to where
4511 : * the current Colon-definition began.
4512 : */
4513 714 : clear_control_structs_to_limit(
4514 : "End of colon-definition", last_colon_abs_token_no);
4515 :
4516 714 : if ( ibm_locals )
4517 : {
4518 402 : finish_locals();
4519 402 : forget_locals();
4520 : }
4521 :
4522 714 : emit_token("b(;)");
4523 714 : incolon=FALSE;
4524 714 : reveal_last_colon();
4525 : }
4526 : break;
4527 :
4528 : case CREATE:
4529 27 : if ( create_word(tok) )
4530 : {
4531 26 : emit_token("b(create)");
4532 : }
4533 : break;
4534 :
4535 : case DEFER:
4536 5 : if ( create_word(tok) )
4537 : {
4538 5 : emit_token("b(defer)");
4539 : }
4540 : break;
4541 :
4542 : case ALLOW_MULTI_LINE:
4543 12 : report_multiline = FALSE;
4544 12 : break;
4545 :
4546 : case OVERLOAD:
4547 43 : if ( test_in_colon(statbuf, FALSE, WARNING, NULL) )
4548 : {
4549 42 : do_not_overload = FALSE;
4550 : }
4551 : break;
4552 :
4553 : case DEFINED:
4554 26 : if (get_word_in_line( statbuf) )
4555 : {
4556 26 : eval_user_symbol(statbuf);
4557 : }
4558 : break;
4559 :
4560 : case CL_FLAG:
4561 131 : if (get_word_in_line( statbuf) )
4562 : {
4563 131 : set_cl_flag( statbuf, TRUE);
4564 : }
4565 : break;
4566 :
4567 : case SHOW_CL_FLAGS:
4568 12 : show_all_cl_flag_settings( TRUE);
4569 12 : break;
4570 :
4571 : case FIELD:
4572 5 : if ( create_word(tok) )
4573 : {
4574 5 : emit_token("b(field)");
4575 : }
4576 : break;
4577 :
4578 : case VALUE:
4579 63 : if ( create_word(tok) )
4580 : {
4581 63 : emit_token("b(value)");
4582 : }
4583 : break;
4584 :
4585 : case VARIABLE:
4586 53 : if ( create_word(tok) )
4587 : {
4588 53 : emit_token("b(variable)");
4589 : }
4590 : break;
4591 :
4592 : case AGAIN:
4593 28 : emit_again();
4594 28 : break;
4595 :
4596 : case ALIAS:
4597 214 : if ( create_alias() )
4598 : {
4599 195 : trace_creation( ALIAS, statbuf);
4600 : }
4601 : break;
4602 :
4603 : case CONTROL:
4604 17 : if ( get_word_in_line( statbuf) )
4605 : {
4606 17 : emit_literal(statbuf[0]&0x1f);
4607 : }
4608 : break;
4609 :
4610 : case DO:
4611 53 : emit_token("b(do)");
4612 53 : mark_do();
4613 53 : break;
4614 :
4615 : case CDO:
4616 44 : emit_token("b(?do)");
4617 44 : mark_do();
4618 44 : break;
4619 :
4620 : case ELSE:
4621 24 : emit_else();
4622 24 : break;
4623 :
4624 : case CASE:
4625 30 : emit_case();
4626 30 : break;
4627 :
4628 : case ENDCASE:
4629 29 : emit_endcase();
4630 29 : break;
4631 :
4632 : case NEW_DEVICE:
4633 88 : handy_toggle = FALSE;
4634 : case FINISH_DEVICE:
4635 177 : finish_or_new_device( handy_toggle );
4636 177 : break;
4637 :
4638 : case FLITERAL:
4639 : {
4640 : u32 val;
4641 19 : val = dpop();
4642 19 : emit_literal(val);
4643 : }
4644 19 : break;
4645 :
4646 : case OF:
4647 1294 : emit_of();
4648 1294 : break;
4649 :
4650 : case ENDOF:
4651 1293 : emit_endof();
4652 1293 : break;
4653 :
4654 : case EXTERNAL:
4655 12 : set_hdr_flag( FLAG_EXTERNAL );
4656 12 : break;
4657 :
4658 : case HEADERLESS:
4659 6 : set_hdr_flag( FLAG_HEADERLESS );
4660 6 : break;
4661 :
4662 : case HEADERS:
4663 166 : set_hdr_flag( FLAG_HEADERS );
4664 166 : break;
4665 :
4666 : case DECIMAL:
4667 : /* in a definition this is expanded as macro "10 base !" */
4668 32 : base_change ( 0x0a );
4669 32 : break;
4670 :
4671 : case HEX:
4672 55 : base_change ( 0x10 );
4673 55 : break;
4674 :
4675 : case OCTAL:
4676 6 : base_change ( 0x08 );
4677 6 : break;
4678 :
4679 : case OFFSET16:
4680 0 : if (!offs16)
4681 : {
4682 0 : tokenization_error(INFO, "Switching to 16-bit offsets.\n");
4683 : }else{
4684 0 : tokenization_error(WARNING,
4685 : "Call of OFFSET16 is redundant.\n");
4686 : }
4687 0 : emit_token("offset16");
4688 0 : offs16=TRUE;
4689 0 : break;
4690 :
4691 : case IF:
4692 189 : emit_if();
4693 189 : break;
4694 :
4695 : /* **************************************************************************
4696 : *
4697 : * Still to be done:
4698 : * Correct analysis of Return-Stack usage within Do-Loops
4699 : * or before Loop Elements like I and J or UNLOOP or LEAVE.
4700 : *
4701 : **************************************************************************** */
4702 : case UNLOOP:
4703 3 : emit_token("unloop");
4704 3 : must_be_deep_in_do(1);
4705 3 : break;
4706 :
4707 : case LEAVE:
4708 7 : emit_token("b(leave)");
4709 7 : must_be_deep_in_do(1);
4710 7 : break;
4711 :
4712 : case LOOP_I:
4713 60 : emit_token("i");
4714 60 : must_be_deep_in_do(1);
4715 60 : break;
4716 :
4717 : case LOOP_J:
4718 12 : emit_token("j");
4719 12 : must_be_deep_in_do(2);
4720 12 : break;
4721 :
4722 : case LOOP:
4723 85 : emit_token("b(loop)");
4724 85 : resolve_loop();
4725 85 : break;
4726 :
4727 : case PLUS_LOOP:
4728 12 : emit_token("b(+loop)");
4729 12 : resolve_loop();
4730 12 : break;
4731 :
4732 :
4733 : case INSTANCE:
4734 : {
4735 117 : bool set_instance_state = FALSE;
4736 117 : bool emit_instance = TRUE;
4737 : /* We will treat "instance" in a colon-definition as
4738 : * an error, but allow it to be emitted if we're
4739 : * ignoring errors; if we're not ignoring errors,
4740 : * there's no output anyway...
4741 : */
4742 117 : if ( test_in_colon(statbuf, FALSE, TKERROR, NULL) )
4743 : { /* We are in interpretation (not colon) state. */
4744 : /* "Instance" not allowed during "global" scope */
4745 110 : if ( scope_is_global )
4746 : {
4747 22 : glob_not_allowed( WARNING, FALSE );
4748 22 : emit_instance = FALSE;
4749 : }else{
4750 88 : set_instance_state = TRUE;
4751 : }
4752 : }
4753 117 : if ( emit_instance )
4754 : {
4755 95 : if ( set_instance_state )
4756 : {
4757 : /* "Instance" isn't cumulative.... */
4758 88 : if ( is_instance )
4759 : {
4760 6 : unresolved_instance( WARNING);
4761 : }
4762 88 : collect_input_filename( &instance_filename);
4763 88 : instance_lineno = lineno;
4764 88 : is_instance = TRUE;
4765 88 : dev_change_instance_warning = TRUE;
4766 : }
4767 95 : emit_token("instance");
4768 : }
4769 : }
4770 : break;
4771 :
4772 : case GLOB_SCOPE:
4773 65 : if ( test_in_colon(statbuf, FALSE, TKERROR, NULL) )
4774 : {
4775 65 : if ( INVERSE( is_instance) )
4776 : {
4777 63 : enter_global_scope();
4778 : }else{
4779 2 : tokenization_error( TKERROR,
4780 : "Global Scope not allowed. "
4781 : "\"Instance\" is in effect; issued" );
4782 2 : just_where_started( instance_filename,
4783 : instance_lineno );
4784 : }
4785 : }
4786 : break;
4787 :
4788 : case DEV_SCOPE:
4789 48 : if ( test_in_colon(statbuf, FALSE, TKERROR, NULL) )
4790 : {
4791 48 : resume_device_scope();
4792 : }
4793 : break;
4794 :
4795 : case TICK: /* ' */
4796 1 : test_in_colon(statbuf, FALSE, WARNING, "[']");
4797 : case BRACK_TICK: /* ['] */
4798 : {
4799 : tic_hdr_t *token_entry;
4800 40 : if ( get_token( &token_entry) )
4801 : {
4802 34 : emit_token("b(')");
4803 : /* Emit the token; warning or whatever comes gratis */
4804 34 : token_entry->funct( token_entry->pfield);
4805 : }
4806 : }
4807 : break;
4808 :
4809 : case F_BRACK_TICK: /* F['] <name>
4810 : * emits the token-number for <name>
4811 : * Mainly useful to compute the argument
4812 : * to get-token or set-token
4813 : */
4814 : {
4815 : tic_hdr_t *token_entry;
4816 18 : if ( get_token( &token_entry) )
4817 : {
4818 : /* "Obsolete" warning doesn't come gratis here... */
4819 15 : token_entry_warning( token_entry);
4820 : /* In Tokenizer-Escape mode, push the token */
4821 15 : if ( in_tokz_esc )
4822 : {
4823 0 : dpush( token_entry->pfield.deflt_elem);
4824 : }else{
4825 15 : emit_literal( token_entry->pfield.deflt_elem);
4826 : }
4827 : }
4828 : }
4829 : break;
4830 :
4831 : case CHAR:
4832 7 : handy_toggle = FALSE;
4833 : case CCHAR:
4834 16 : test_in_colon(statbuf, handy_toggle, WARNING,
4835 : handy_toggle ? "CHAR" : "[CHAR]" );
4836 : case ASCII:
4837 18 : if ( get_word_in_line( statbuf) )
4838 : {
4839 18 : emit_literal(statbuf[0]);
4840 : }
4841 : break;
4842 :
4843 : case UNTIL:
4844 4 : emit_until();
4845 4 : break;
4846 :
4847 : case WHILE:
4848 11 : emit_while();
4849 11 : break;
4850 :
4851 : case REPEAT:
4852 11 : emit_repeat();
4853 11 : break;
4854 :
4855 : case THEN:
4856 194 : emit_then();
4857 194 : break;
4858 :
4859 : case IS:
4860 42 : tokenization_error ( INFO,
4861 : "Substituting TO for deprecated IS\n");
4862 : case TO:
4863 202 : if ( validate_to_target() )
4864 : {
4865 179 : emit_token("b(to)");
4866 : }
4867 : break;
4868 :
4869 : case FLOAD:
4870 254 : if ( get_word_in_line( statbuf) )
4871 : {
4872 : bool stream_ok ;
4873 :
4874 254 : push_source( close_stream, NULL, TRUE) ;
4875 :
4876 254 : tokenization_error( INFO, "FLOADing %s\n", statbuf );
4877 :
4878 254 : stream_ok = init_stream( statbuf );
4879 254 : if ( INVERSE( stream_ok) )
4880 : {
4881 14 : drop_source();
4882 : }
4883 : }
4884 : break;
4885 :
4886 : case STRING: /* Double-Quote ( " ) string */
4887 184 : handy_toggle = FALSE;
4888 : case PSTRING: /* Dot-Quote ( ." ) string */
4889 35239 : wlen=get_string( TRUE);
4890 35239 : emit_token("b(\")");
4891 35239 : emit_string(statbuf, wlen);
4892 35239 : if ( handy_toggle )
4893 : {
4894 35055 : emit_token("type");
4895 : }
4896 : break;
4897 :
4898 : case SSTRING: /* Ess-Quote ( s" ) string */
4899 7 : handy_toggle = FALSE;
4900 : case PBSTRING: /* Dot-Paren .( string */
4901 29 : if (*pc++=='\n') lineno++;
4902 : {
4903 29 : unsigned int strt_lineno = lineno;
4904 29 : wlen = get_until( handy_toggle ? ')' : '"' );
4905 29 : if ( string_err_check( handy_toggle,
4906 : sav_lineno, strt_lineno) )
4907 : {
4908 28 : emit_token("b(\")");
4909 28 : emit_string(statbuf, wlen);
4910 28 : if ( handy_toggle )
4911 : {
4912 22 : emit_token("type");
4913 : }
4914 : }
4915 : }
4916 : break;
4917 :
4918 : case FUNC_NAME:
4919 58 : if ( test_in_colon( statbuf, TRUE, TKERROR, NULL) )
4920 : {
4921 58 : if ( in_tokz_esc )
4922 : {
4923 2 : tokenization_error( P_MESSAGE, "Currently" );
4924 2 : in_last_colon();
4925 : }else{
4926 56 : emit_token("b(\")");
4927 56 : emit_string( last_colon_defname,
4928 : strlen( last_colon_defname) );
4929 : /* if ( hdr_flag == FLAG_HEADERLESS ) { WARNING } */
4930 : }
4931 : }
4932 : break;
4933 :
4934 : case IFILE_NAME:
4935 2 : emit_token("b(\")");
4936 2 : emit_string( iname, strlen( iname) );
4937 2 : break;
4938 :
4939 : case ILINE_NUM:
4940 2 : emit_literal( lineno);
4941 2 : break;
4942 :
4943 : case HEXVAL:
4944 282 : base_val (0x10);
4945 282 : break;
4946 :
4947 : case DECVAL:
4948 47 : base_val (0x0a);
4949 47 : break;
4950 :
4951 : case OCTVAL:
4952 12 : base_val (8);
4953 12 : break;
4954 :
4955 : case ASC_LEFT_NUM:
4956 12 : handy_toggle = FALSE;
4957 : case ASC_NUM:
4958 26 : if (get_word_in_line( statbuf) )
4959 : {
4960 25 : if ( handy_toggle )
4961 : {
4962 13 : ascii_right_number( statbuf);
4963 : } else {
4964 12 : ascii_left_number( statbuf);
4965 : }
4966 : }
4967 : break;
4968 :
4969 : case CONDL_ENDER: /* Conditional directives out of context */
4970 : case CONDL_ELSE:
4971 23 : tokenization_error ( TKERROR,
4972 : "No conditional preceding %s directive\n",
4973 : strupr(statbuf) );
4974 23 : break;
4975 :
4976 : case PUSH_FCODE:
4977 153 : tokenization_error( INFO,
4978 : "FCode-token Assignment Counter of 0x%x "
4979 : "has been saved on stack.\n", nextfcode );
4980 153 : dpush( (long)nextfcode );
4981 153 : break;
4982 :
4983 : case POP_FCODE:
4984 43 : pop_next_fcode();
4985 43 : break;
4986 :
4987 : case RESET_FCODE:
4988 26 : tokenization_error( INFO,
4989 : "Encountered %s. Resetting FCode-token "
4990 : "Assignment Counter. ", strupr(statbuf) );
4991 26 : list_fcode_ranges( FALSE);
4992 26 : reset_fcode_ranges();
4993 26 : break;
4994 :
4995 : case EXIT:
4996 50 : if ( test_in_colon( statbuf, TRUE, TKERROR, NULL)
4997 : || noerrors )
4998 : {
4999 50 : ret_stk_balance_rpt( NULL, FALSE);
5000 50 : if ( ibm_locals )
5001 : {
5002 18 : finish_locals ();
5003 : }
5004 50 : emit_token("exit");
5005 : }
5006 : break;
5007 :
5008 : case ESCAPETOK:
5009 573 : enter_tokz_esc();
5010 573 : break;
5011 :
5012 : case VERSION1:
5013 : case FCODE_V1:
5014 2 : tokenization_error( INFO, "Using version1 header "
5015 : "(8-bit offsets).\n");
5016 2 : fcode_starter( "version1", 1, FALSE) ;
5017 2 : break;
5018 :
5019 : case START1:
5020 : case FCODE_V2:
5021 : case FCODE_V3: /* Full IEEE 1275 */
5022 168 : fcode_starter( "start1", 1, TRUE);
5023 168 : break;
5024 :
5025 : case START0:
5026 0 : fcode_starter( "start0", 0, TRUE);
5027 0 : break;
5028 :
5029 : case START2:
5030 0 : fcode_starter( "start2", 2, TRUE);
5031 0 : break;
5032 :
5033 : case START4:
5034 0 : fcode_starter( "start4", 4, TRUE);
5035 0 : break;
5036 :
5037 : case END1:
5038 0 : tokenization_error( WARNING,
5039 : "Appearance of END1 in FCode source code "
5040 : "is not intended by IEEE 1275-1994\n");
5041 0 : handy_toggle = FALSE;
5042 : case END0:
5043 : case FCODE_END:
5044 165 : if ( handy_toggle )
5045 : {
5046 165 : you_are_here();
5047 : }
5048 165 : emit_token( handy_toggle ? "end0" : "end1" );
5049 165 : fcode_ender();
5050 165 : FFLUSH_STDOUT
5051 165 : break;
5052 :
5053 : case RECURSE:
5054 6 : if ( test_in_colon(statbuf, TRUE, TKERROR, NULL ) )
5055 : {
5056 5 : emit_fcode(last_colon_fcode);
5057 : }
5058 : break;
5059 :
5060 :
5061 : case RECURSIVE:
5062 6 : if ( test_in_colon(statbuf, TRUE, TKERROR, NULL ) )
5063 : {
5064 5 : reveal_last_colon();
5065 : }
5066 : break;
5067 :
5068 : case RET_STK_FETCH:
5069 6 : ret_stk_access_rpt();
5070 6 : emit_token( "r@");
5071 6 : break;
5072 :
5073 : case RET_STK_FROM:
5074 38 : ret_stk_access_rpt();
5075 38 : bump_ret_stk_depth( -1);
5076 38 : emit_token( "r>");
5077 38 : break;
5078 :
5079 : case RET_STK_TO:
5080 38 : bump_ret_stk_depth( 1);
5081 38 : emit_token( ">r");
5082 38 : break;
5083 :
5084 : case PCIHDR:
5085 30 : emit_pcihdr();
5086 30 : break;
5087 :
5088 : case PCIEND:
5089 29 : finish_pcihdr();
5090 29 : reset_fcode_ranges();
5091 29 : FFLUSH_STDOUT
5092 29 : break;
5093 :
5094 : case PCIREV:
5095 26 : pci_image_rev = dpop();
5096 26 : tokenization_error( INFO,
5097 : "PCI header revision=0x%04x%s\n", pci_image_rev,
5098 : big_end_pci_image_rev ?
5099 : ". Will be saved in Big-Endian format."
5100 : : "" );
5101 26 : break;
5102 :
5103 : case NOTLAST:
5104 12 : handy_toggle = FALSE;
5105 : case ISLAST:
5106 24 : dpush(handy_toggle);
5107 : case SETLAST:
5108 : {
5109 25 : u32 val = dpop();
5110 25 : bool new_pili = BOOLVAL( (val != 0) );
5111 25 : if ( pci_is_last_image != new_pili )
5112 : {
5113 25 : tokenization_error( INFO,
5114 : new_pili ?
5115 : "Last image for PCI header.\n" :
5116 : "PCI header not last image.\n" );
5117 25 : pci_is_last_image = new_pili;
5118 : }
5119 : }
5120 : break;
5121 :
5122 : case SAVEIMG:
5123 0 : if (get_word_in_line( statbuf) )
5124 : {
5125 0 : free(oname);
5126 0 : oname = strdup( statbuf );
5127 0 : tokenization_error( INFO,
5128 : "Output is redirected to file: %s\n", oname);
5129 : }
5130 : break;
5131 :
5132 : case RESETSYMBS:
5133 14 : tokenization_error( INFO,
5134 : "Resetting symbols defined in %s mode.\n",
5135 : in_tokz_esc ? "tokenizer-escape" : "\"normal\"");
5136 14 : if ( in_tokz_esc )
5137 : {
5138 12 : reset_tokz_esc();
5139 : }else{
5140 2 : reset_normal_vocabs();
5141 : }
5142 : break;
5143 :
5144 : case FCODE_DATE:
5145 3 : handy_toggle = FALSE;
5146 : case FCODE_TIME:
5147 : {
5148 : time_t tt;
5149 : char temp_buffr[32];
5150 :
5151 6 : tt=time(NULL);
5152 6 : if ( handy_toggle )
5153 : {
5154 3 : strftime(temp_buffr, 32, "%T %Z", localtime(&tt));
5155 : }else{
5156 3 : strftime(temp_buffr, 32, "%m/%d/%Y", localtime(&tt));
5157 : }
5158 6 : if ( in_tokz_esc )
5159 : {
5160 2 : tokenization_error( MESSAGE, temp_buffr);
5161 : }else{
5162 4 : emit_token("b(\")");
5163 4 : emit_string((u8 *)temp_buffr, strlen(temp_buffr) );
5164 : }
5165 : }
5166 : break;
5167 :
5168 : case ENCODEFILE:
5169 18 : if (get_word_in_line( statbuf) )
5170 : {
5171 18 : encode_file( (char*)statbuf );
5172 : }
5173 : break;
5174 :
5175 : default:
5176 : /* IBM-style Locals, under control of a switch */
5177 200 : if ( ibm_locals )
5178 : {
5179 164 : bool found_it = TRUE;
5180 164 : switch (tok) {
5181 : case CURLY_BRACE:
5182 69 : declare_locals( FALSE);
5183 69 : break;
5184 : case DASH_ARROW:
5185 95 : assign_local();
5186 95 : break;
5187 : default:
5188 0 : found_it = FALSE;
5189 : }
5190 164 : if ( found_it ) break;
5191 : }
5192 :
5193 : /* Down here, we have our last chance to recognize a token.
5194 : * If abort_quote is disallowed, we will still consume
5195 : * the string. In case the string spans more than one
5196 : * line, we want to make sure the line number displayed
5197 : * in the error-message is the one on which the disallowed
5198 : * abort_quote token appeared, not the one where the
5199 : * string ended; therefore, we might need to be able to
5200 : * "fake-out" the line number...
5201 : */
5202 : {
5203 36 : bool fake_out_lineno = FALSE;
5204 36 : unsigned int save_lineno = lineno;
5205 : unsigned int true_lineno;
5206 36 : if ( abort_quote( tok) )
5207 10 : { break;
5208 : }else{
5209 26 : if ( tok == ABORTTXT ) fake_out_lineno = TRUE;
5210 : }
5211 26 : true_lineno = lineno;
5212 :
5213 26 : if ( fake_out_lineno ) lineno = save_lineno;
5214 26 : tokenization_error ( TKERROR,
5215 : "Unimplemented control word '%s'\n", strupr(statbuf) );
5216 26 : if ( fake_out_lineno ) lineno = true_lineno;
5217 : }
5218 : }
5219 53161 : }
5220 :
5221 : /* **************************************************************************
5222 : *
5223 : * Function name: skip_string
5224 : * Synopsis: When Ignoring, skip various kinds of strings. Maps
5225 : * to string-handlers in handle_internal()...
5226 : *
5227 : * Associated FORTH words: Double-Quote ( " ) string
5228 : * Dot-Quote ( ." ) string
5229 : * Ess-Quote ( s" ) string
5230 : * Dot-Paren .( string
5231 : * ABORT" (even if not enabled)
5232 : * { (Local-Values declaration) and -> (Local-Values assignment)
5233 : * are also handled if ibm_locals is enabled.
5234 : *
5235 : * Inputs:
5236 : * Parameters:
5237 : * pfield Param-field of the entry associated with
5238 : * the FWord that is being Ignored.
5239 : * Global Variables:
5240 : * statbuf The word that was just read.
5241 : * pc Input-stream pointer
5242 : * lineno Line-number, used for errors and warnings
5243 : * ibm_locals TRUE if IBM-style Locals are enabled
5244 : *
5245 : * Outputs:
5246 : * Returned Value: NONE
5247 : *
5248 : * Error Detection:
5249 : * Multi-line warnings, "Unterminated" Errors
5250 : * handled by called routines
5251 : *
5252 : * Extraneous Remarks:
5253 : * We would prefer to keep this function private, too, so we
5254 : * will declare its prototype here and in the one other
5255 : * file where we need it, namely, dictionary.c, rather
5256 : * than exporting it widely in a .h file.
5257 : *
5258 : **************************************************************************** */
5259 :
5260 : void skip_string( tic_param_t pfield);
5261 : void skip_string( tic_param_t pfield)
5262 403 : {
5263 403 : fwtoken tok = pfield.fw_token;
5264 403 : unsigned int sav_lineno = lineno;
5265 403 : bool handy_toggle = TRUE ; /* Various uses... */
5266 :
5267 403 : switch (tok) {
5268 : case STRING: /* Double-Quote ( " ) string */
5269 : case PSTRING: /* Dot-Quote ( ." ) string */
5270 : case ABORTTXT: /* ABORT", even if not enabled */
5271 375 : get_string( FALSE); /* Don't truncate; ignoring anyway */
5272 : /* Will handle multi-line warnings, etc. */
5273 375 : break;
5274 :
5275 : case SSTRING: /* Ess-Quote ( s" ) string */
5276 4 : handy_toggle = FALSE;
5277 : case PBSTRING: /* Dot-Paren .( string */
5278 8 : if (*pc++=='\n') lineno++;
5279 : {
5280 8 : unsigned int strt_lineno = lineno;
5281 8 : get_until( handy_toggle ? ')' : '"' );
5282 8 : string_err_check( handy_toggle, sav_lineno, strt_lineno );
5283 : }
5284 8 : break;
5285 :
5286 : default:
5287 : /* IBM-style Locals, under control of a switch */
5288 20 : if ( ibm_locals )
5289 : {
5290 20 : bool found_it = TRUE;
5291 20 : switch (tok) {
5292 : case CURLY_BRACE:
5293 10 : declare_locals( TRUE);
5294 10 : break;
5295 : case DASH_ARROW:
5296 10 : get_word();
5297 10 : break;
5298 : default:
5299 0 : found_it = FALSE;
5300 : }
5301 20 : if ( found_it ) break;
5302 : }
5303 :
5304 0 : tokenization_error ( FATAL, "Program Error. "
5305 : "Unimplemented skip-string word '%s'\n", strupr(statbuf) );
5306 : }
5307 403 : }
5308 :
5309 : /* **************************************************************************
5310 : *
5311 : * Function name: process_remark
5312 : * Synopsis: The active function for remarks (backslash-space)
5313 : * and comments (enclosed within parens)
5314 : *
5315 : * Associated FORTH word(s): \ (
5316 : *
5317 : * Inputs:
5318 : * Parameters:
5319 : * TIC entry "parameter field", init'd to delimiter character.
5320 : *
5321 : * Outputs:
5322 : * Returned Value: NONE
5323 : *
5324 : * Error Detection:
5325 : * Warning if end-of-file encountered before delimiter.
5326 : * Warning if multi-line parentheses-delimited comment.
5327 : *
5328 : * Process Explanation:
5329 : * Skip until the delimiter.
5330 : * If end-of-file was encountered, issue Warning.
5331 : * Otherwise, and if delimiter was not new-line,
5332 : * check for multi-line with Warning.
5333 : *
5334 : **************************************************************************** */
5335 :
5336 : void process_remark( tic_param_t pfield )
5337 4078 : {
5338 4078 : char until_char = (char)pfield.deflt_elem ;
5339 4078 : unsigned int start_lineno = lineno;
5340 :
5341 : #ifdef DEBUG_SCANNER
5342 :
5343 : get_until(until_char);
5344 : printf ("%s:%d: debug: stack diagram: %s)\n",
5345 : iname, lineno, statbuf);
5346 : #else
5347 :
5348 4078 : if ( skip_until( until_char) )
5349 : {
5350 4 : if ( until_char == '\n' )
5351 : {
5352 : /* Don't need any saved line number here ... */
5353 1 : tokenization_error ( WARNING,
5354 : "Unterminated remark.\n");
5355 : }else{
5356 3 : warn_unterm( WARNING, "comment", start_lineno);
5357 : }
5358 : }else{
5359 4074 : if ( until_char != '\n' )
5360 : {
5361 688 : pc++;
5362 688 : warn_if_multiline( "comment", start_lineno);
5363 : }
5364 : }
5365 : #endif /* DEBUG_SCANNER */
5366 4078 : }
5367 :
5368 :
5369 : /* **************************************************************************
5370 : *
5371 : * Function name: filter_comments
5372 : * Synopsis: Process remarks and comments in special conditions
5373 : *
5374 : * Inputs:
5375 : * Parameters:
5376 : * inword Current word just parsed
5377 : *
5378 : * Outputs:
5379 : * Returned Value: TRUE if Current word is a Comment-starter.
5380 : * Comment will be processed
5381 : *
5382 : * Process Explanation:
5383 : * We want to be able to recognize any alias the user may have
5384 : * defined to a comment-delimiter, in whatever applicable
5385 : * vocabulary it might be.
5386 : * The active-function of any such alias will, of necessity, be
5387 : * the process_remark() routine, defined just above.
5388 : * We will search for the TIC-entry of the given word; if we don't
5389 : * find it, it's not a comment-delimiter. If we do find it,
5390 : * and it is one, we invoke its active-function and return TRUE.
5391 : * We also want to permit the "allow-multiline-comments" directive
5392 : * to be processed in the context that calls this routine, so
5393 : * we will check for that condition, too.
5394 : *
5395 : **************************************************************************** */
5396 :
5397 : bool filter_comments( u8 *inword)
5398 629 : {
5399 629 : bool retval = FALSE;
5400 629 : tic_hdr_t *found = lookup_word( inword, NULL, NULL );
5401 :
5402 629 : if ( found != NULL )
5403 : {
5404 219 : if ( found->funct == process_remark )
5405 : {
5406 111 : found->funct( found->pfield);
5407 111 : retval = TRUE;
5408 : }else{
5409 : /* Permit the "allow-multiline-comments" directive */
5410 108 : if ( found->funct == handle_internal )
5411 : {
5412 40 : if ( found->pfield.fw_token == ALLOW_MULTI_LINE )
5413 : {
5414 : /* Make sure any intended side-effects occur... */
5415 4 : found->funct( found->pfield);
5416 4 : retval = TRUE;
5417 : }
5418 : }
5419 : }
5420 : }
5421 629 : return ( retval );
5422 : }
5423 :
5424 :
5425 : /* **************************************************************************
5426 : *
5427 : * Function name: tokenize_one_word
5428 : * Synopsis: Tokenize the currently-obtained word
5429 : * along with whatever it consumes.
5430 : *
5431 : * Inputs:
5432 : * Parameters:
5433 : * wlen Length of symbol just retrieved from the input stream
5434 : * This is not really used here any more; it's
5435 : * left over from an earlier implementation.
5436 : * Global Variables:
5437 : * statbuf The symbol (word) just retrieved from input stream.
5438 : * in_tokz_esc TRUE if "Tokenizer-Escape" mode is in effect; a
5439 : * different set of vocabularies from "Normal"
5440 : * mode will be checked (along with those that
5441 : * are common to both modes).
5442 : * ibm_locals Controls whether to check for IBM-style Locals;
5443 : * set by means of a command-line switch.
5444 : *
5445 : * Outputs:
5446 : * Returned Value: NONE
5447 : * Global Variables:
5448 : * statbuf May be incremented
5449 : * in_tokz_esc May be set if the word just retrieved is
5450 : * the tokenizer[ directive.
5451 : * tic_found
5452 : *
5453 : * Error Detection:
5454 : * If the word could neither be identified nor processed as a number,
5455 : * that is an ERROR; pass it to tokenized_word_error for a
5456 : * message.
5457 : *
5458 : * Process Explanation:
5459 : * Look for the word in each of the various lists and vocabularies
5460 : * in which it might be found, as appropriate to the current
5461 : * state of activity.
5462 : * If found, process it accordingly.
5463 : * If not found, try to process it as a number.
5464 : * If cannot process it as a number, declare an error.
5465 : *
5466 : * Revision History:
5467 : * Updated Tue, 10 Jan 2006 by David L. Paktor
5468 : * Convert to tic_hdr_t type vocabularies.
5469 : * Updated Mon, 03 Apr 2006 by David L. Paktor
5470 : * Replaced bulky "Normal"-vs-"Escape" block with a call
5471 : * to lookup_word . Attend to a small but important
5472 : * side-effect of the "handle_<vocab>" routines that
5473 : * feeds directly into the protection against self-
5474 : * -recursion in a user-defined Macro: Set the global
5475 : * variable tic_found to the entry, just before we
5476 : * execute it, and we're good to go...
5477 : *
5478 : * Extraneous Remarks:
5479 : * We trade off the strict rules of structure for simplicity
5480 : * of coding.
5481 : *
5482 : **************************************************************************** */
5483 :
5484 : void tokenize_one_word( signed long wlen )
5485 109599 : {
5486 :
5487 : /* The shared lookup routine now handles everything. */
5488 109599 : tic_hdr_t *found = lookup_word( statbuf, NULL, NULL );
5489 :
5490 109599 : if ( found != NULL )
5491 : {
5492 98812 : tic_found = found;
5493 98812 : found->funct( found->pfield);
5494 98810 : return ;
5495 : }
5496 :
5497 : /* It's not a word in any of our current contexts.
5498 : * Is it a number?
5499 : */
5500 10787 : if ( handle_number() )
5501 : {
5502 10485 : return ;
5503 : }
5504 :
5505 : /* Could not identify - give a shout. */
5506 302 : tokenized_word_error( statbuf );
5507 : }
5508 :
5509 : /* **************************************************************************
5510 : *
5511 : * Function name: tokenize
5512 : * Synopsis: Tokenize the current input stream.
5513 : * May be called recursively for macros and such.
5514 : *
5515 : * Revision History:
5516 : * Updated Thu, 24 Mar 2005 by David L. Paktor
5517 : * Factor-out comment-filtration; apply to gather_locals
5518 : * Factor-out tokenizing a single word (for conditionals)
5519 : * Separate actions of "Tokenizer-Escape" mode.
5520 : *
5521 : **************************************************************************** */
5522 :
5523 : void tokenize(void)
5524 165 : {
5525 165 : signed long wlen = 0;
5526 :
5527 96616 : while ( wlen >= 0 )
5528 : {
5529 96287 : wlen = get_word();
5530 96287 : if ( wlen > 0 )
5531 : {
5532 95927 : tokenize_one_word( wlen );
5533 : }
5534 : }
5535 164 : }
5536 :
|