2 * symbol - global and local symbol routines
4 * Copyright (C) 1999-2007 David I. Bell and Ernest Bowen
6 * Primary author: David I. Bell
8 * Calc is open software; you can redistribute it and/or modify it under
9 * the terms of the version 2.1 of the GNU Lesser General Public License
10 * as published by the Free Software Foundation.
12 * Calc is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
15 * Public License for more details.
17 * A copy of version 2.1 of the GNU Lesser General Public License is
18 * distributed with calc under the filename COPYING-LGPL. You should have
19 * received a copy with calc; if not, write to Free Software Foundation, Inc.
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * @(#) $Revision: 30.2 $
23 * @(#) $Id: symbol.c,v 30.2 2013/08/11 08:41:38 chongo Exp $
24 * @(#) $Source: /usr/local/src/bin/calc/RCS/symbol.c,v $
26 * Under source code control: 1990/02/15 01:48:23
27 * File existed as early as: before 1990
29 * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
41 #define HASHSIZE 37 /* size of hash table */
43 E_FUNC
FILE *f_open(char *name
, char *mode
);
45 STATIC
int filescope
; /* file scope level for static variables */
46 STATIC
int funcscope
; /* function scope level for static variables */
47 STATIC STRINGHEAD localnames
; /* list of local variable names */
48 STATIC STRINGHEAD globalnames
; /* list of global variable names */
49 STATIC STRINGHEAD paramnames
; /* list of parameter variable names */
50 STATIC GLOBAL
*globalhash
[HASHSIZE
]; /* hash table for globals */
52 S_FUNC
void printtype(VALUE
*);
53 S_FUNC
void unscope(void);
54 S_FUNC
void addstatic(GLOBAL
*);
55 STATIC
long staticcount
= 0;
56 STATIC
long staticavail
= 0;
57 STATIC GLOBAL
**statictable
;
61 * Hash a symbol name so we can find it in the hash table.
62 * Args are the symbol name and the symbol name size.
64 #define HASHSYM(n, s) ((unsigned)((n)[0]*123 + (n)[s-1]*135 + (s)*157) % \
69 * Initialize the global symbol table.
74 int i
; /* index counter */
76 for (i
= 0; i
< HASHSIZE
; i
++)
78 initstr(&globalnames
);
79 filescope
= SCOPE_STATIC
;
85 * Define a possibly new global variable which may or may not be static.
86 * If it did not already exist, it is created with a value of zero.
87 * The address of the global symbol structure is returned.
90 * name name of global variable
91 * isstatic TRUE if symbol is static
94 addglobal(char *name
, BOOL isstatic
)
96 GLOBAL
*sp
; /* current symbol pointer */
97 GLOBAL
**hp
; /* hash table head address */
98 size_t len
; /* length of string */
99 int newfilescope
; /* file scope being looked for */
100 int newfuncscope
; /* function scope being looked for */
102 newfilescope
= SCOPE_GLOBAL
;
105 newfilescope
= filescope
;
106 newfuncscope
= funcscope
;
111 hp
= &globalhash
[HASHSYM(name
, len
)];
112 for (sp
= *hp
; sp
; sp
= sp
->g_next
) {
113 if ((sp
->g_len
== len
) && (strcmp(sp
->g_name
, name
) == 0)
114 && (sp
->g_filescope
== newfilescope
)
115 && (sp
->g_funcscope
== newfuncscope
))
118 sp
= (GLOBAL
*) malloc(sizeof(GLOBAL
));
121 sp
->g_name
= addstr(&globalnames
, name
);
123 sp
->g_filescope
= newfilescope
;
124 sp
->g_funcscope
= newfuncscope
;
125 sp
->g_value
.v_num
= qlink(&_qzero_
);
126 sp
->g_value
.v_type
= V_NUM
;
127 sp
->g_value
.v_subtype
= V_NOSUBTYPE
;
135 * Look for the highest-scope global variable with a specified name.
136 * Returns the address of the variable or NULL according as the search
140 findglobal(char *name
)
142 GLOBAL
*sp
; /* current symbol pointer */
143 GLOBAL
*bestsp
; /* found symbol with highest scope */
144 size_t len
; /* length of string */
148 for (sp
= globalhash
[HASHSYM(name
, len
)]; sp
; sp
= sp
->g_next
) {
149 if ((sp
->g_len
== len
) && !strcmp(sp
->g_name
, name
)) {
150 if ((bestsp
== NULL
) ||
151 (sp
->g_filescope
> bestsp
->g_filescope
) ||
152 (sp
->g_funcscope
> bestsp
->g_funcscope
))
161 * Return the name of a global variable given its address.
164 * sp address of global pointer
167 globalname(GLOBAL
*sp
)
176 * Show the value of all real-number valued global variables, displaying
177 * only the head and tail of very large numerators and denominators.
178 * Static variables are not included.
183 GLOBAL
**hp
; /* hash table head address */
184 register GLOBAL
*sp
; /* current global symbol pointer */
185 long count
; /* number of global variables shown */
188 for (hp
= &globalhash
[HASHSIZE
-1]; hp
>= globalhash
; hp
--) {
189 for (sp
= *hp
; sp
; sp
= sp
->g_next
) {
190 if (sp
->g_value
.v_type
!= V_NUM
)
193 printf("\nName Digits Value\n");
194 printf( "---- ------ -----\n");
196 printf("%-8s", sp
->g_name
);
197 if (sp
->g_filescope
!= SCOPE_GLOBAL
)
199 fitprint(sp
->g_value
.v_num
, 50);
204 printf("No real-valued global variables\n");
213 GLOBAL
**hp
; /* hash table head address */
214 register GLOBAL
*sp
; /* current global symbol pointer */
215 long count
; /* number of global variables shown */
218 for (hp
= &globalhash
[HASHSIZE
-1]; hp
>= globalhash
; hp
--) {
219 for (sp
= *hp
; sp
; sp
= sp
->g_next
) {
221 printf("\nName Level Type\n");
222 printf( "---- ----- -----\n");
224 printf("%-8s%4d ", sp
->g_name
, sp
->g_filescope
);
225 printtype(&sp
->g_value
);
230 printf("\nNumber: %ld\n", count
);
232 printf("No global variables\n");
243 printf("Error %d", -type
);
249 fitprint(vp
->v_num
, 32);
252 printf("complex = ");
253 fitprint(vp
->v_com
->real
, 8);
254 if (!vp
->v_com
->imag
->num
.sign
)
256 fitprint(vp
->v_com
->imag
, 8);
260 printf("string = \"");
261 fitstring(vp
->v_str
->s_str
, vp
->v_str
->s_len
, 50);
277 printf("%s ", objtypename(
278 vp
->v_obj
->o_actions
->oa_index
));
285 s
= "additive 55 random state";
288 s
= "Blum random state";
309 s
= "string pointer";
312 s
= "number pointer";
323 * Write all normal global variables to an output file.
324 * Note: Currently only simple types are saved.
325 * Returns nonzero on error.
328 writeglobals(char *name
)
331 GLOBAL
**hp
; /* hash table head address */
332 register GLOBAL
*sp
; /* current global symbol pointer */
333 int savemode
; /* saved output mode */
334 E_FUNC
void math_setfp(FILE *fp
);
336 fp
= f_open(name
, "w");
340 for (hp
= &globalhash
[HASHSIZE
-1]; hp
>= globalhash
; hp
--) {
341 for (sp
= *hp
; sp
; sp
= sp
->g_next
) {
342 switch (sp
->g_value
.v_type
) {
350 math_fmt("%s = ", sp
->g_name
);
351 savemode
= math_setmode(MODE_HEX
);
352 printvalue(&sp
->g_value
, PRINT_UNAMBIG
);
353 math_setmode(savemode
);
364 * Free all non-null global and visible static variables
369 GLOBAL
**hp
; /* hash table head address */
370 GLOBAL
*sp
; /* current global symbol pointer */
371 long count
; /* number of global variables freed */
374 * We prevent the hp pointer from walking behind globalhash
375 * by stopping one short of the end and running the loop one
378 * We could stop the loop with just hp >= globalhash, but stopping
379 * short and running the loop one last time manually helps make
380 * code checkers such as insure happy.
383 for (hp
= &globalhash
[HASHSIZE
-1]; hp
> globalhash
; hp
--) {
384 for (sp
= *hp
; sp
; sp
= sp
->g_next
) {
385 if (sp
->g_value
.v_type
!= V_NULL
) {
386 freevalue(&sp
->g_value
);
391 /* run the loop manually one last time */
392 for (sp
= *hp
; sp
; sp
= sp
->g_next
) {
393 if (sp
->g_value
.v_type
!= V_NULL
) {
394 freevalue(&sp
->g_value
);
401 * Free all invisible static variables
412 while (count
-- > 0) {
414 freevalue(&sp
->g_value
);
420 * Reset the file and function scope levels back to the original values.
421 * This is called on errors to forget any static variables which were being
427 filescope
= SCOPE_STATIC
;
434 * Enter a new file scope level so that newly defined static variables
435 * will have the appropriate scope, and so that previously defined static
436 * variables will temporarily be unaccessible. This should only be called
437 * when the function scope level is zero.
448 * Exit from a file scope level. This deletes from the global symbol table
449 * all of the static variables that were defined within this file scope level.
450 * The function scope level is also reset to zero.
455 if (filescope
> SCOPE_STATIC
)
463 * Enter a new function scope level within the current file scope level.
464 * This allows newly defined static variables to override previously defined
465 * static variables in the same file scope level.
475 * Exit from a function scope level. This deletes static symbols which were
476 * defined within the current function scope level, and makes previously
477 * defined symbols with the same name within the same file scope level
490 * To end the scope of any static variable with identifier id when
491 * id is being declared as global, or when id is declared as static and the
492 * variable is at the same file and function level.
495 endscope(char *name
, BOOL isglobal
)
504 hp
= &globalhash
[HASHSYM(name
, len
)];
505 for (sp
= *hp
; sp
; sp
= sp
->g_next
) {
506 if (sp
->g_len
== len
&& !strcmp(sp
->g_name
, name
) &&
507 sp
->g_filescope
> SCOPE_GLOBAL
) {
508 if (isglobal
|| (sp
->g_filescope
== filescope
&&
509 sp
->g_funcscope
== funcscope
)) {
512 prevsp
->g_next
= sp
->g_next
;
523 * To store in a table a static variable whose scope is being ended
526 addstatic(GLOBAL
*sp
)
530 if (staticavail
<= 0) {
531 if (staticcount
<= 0)
532 stp
= (GLOBAL
**) malloc(20 * sizeof(GLOBAL
*));
534 stp
= (GLOBAL
**) realloc(statictable
,
535 (20 + staticcount
) * sizeof(GLOBAL
*));
537 math_error("Cannot allocate static-variable table");
543 statictable
[staticcount
++] = sp
;
548 * To display all static variables whose scope has been ended
557 for (count
= 0, stp
= statictable
; count
< staticcount
; count
++) {
560 printf("\nName Scopes Type\n");
561 printf( "---- ------ -----\n");
563 printf("%-8s", sp
->g_name
);
564 printf("%3d", sp
->g_filescope
);
565 printf("%3d ", sp
->g_funcscope
);
566 printtype(&sp
->g_value
);
570 printf("\nNumber: %ld\n", count
);
572 printf("No unscoped static variables\n");
576 * Remove all the symbols from the global symbol table which have file or
577 * function scopes larger than the current scope levels. Their memory
578 * remains allocated since their values still actually exist.
583 GLOBAL
**hp
; /* hash table head address */
584 register GLOBAL
*sp
; /* current global symbol pointer */
585 GLOBAL
*prevsp
; /* previous kept symbol pointer */
588 * We prevent the hp pointer from walking behind globalhash
589 * by stopping one short of the end and running the loop one
592 * We could stop the loop with just hp >= globalhash, but stopping
593 * short and running the loop one last time manually helps make
594 * code checkers such as insure happy.
596 for (hp
= &globalhash
[HASHSIZE
-1]; hp
> globalhash
; hp
--) {
598 for (sp
= *hp
; sp
; sp
= sp
->g_next
) {
599 if ((sp
->g_filescope
== SCOPE_GLOBAL
) ||
600 (sp
->g_filescope
< filescope
) ||
601 ((sp
->g_filescope
== filescope
) &&
602 (sp
->g_funcscope
<= funcscope
))) {
608 * This symbol needs removing.
612 prevsp
->g_next
= sp
->g_next
;
617 /* run the loop manually one last time */
619 for (sp
= *hp
; sp
; sp
= sp
->g_next
) {
620 if ((sp
->g_filescope
== SCOPE_GLOBAL
) ||
621 (sp
->g_filescope
< filescope
) ||
622 ((sp
->g_filescope
== filescope
) &&
623 (sp
->g_funcscope
<= funcscope
))) {
629 * This symbol needs removing.
633 prevsp
->g_next
= sp
->g_next
;
641 * Initialize the local and parameter symbol table information.
646 initstr(&localnames
);
647 initstr(¶mnames
);
648 curfunc
->f_localcount
= 0;
649 curfunc
->f_paramcount
= 0;
654 * Add a possibly new local variable definition.
655 * Returns the index of the variable into the local symbol table.
656 * Minus one indicates the symbol could not be added.
659 * name name of local variable
664 long index
; /* current symbol index */
666 index
= findstr(&localnames
, name
);
669 index
= localnames
.h_count
;
670 (void) addstr(&localnames
, name
);
671 curfunc
->f_localcount
++;
677 * Find a local variable name and return its index.
678 * Returns minus one if the variable name is not defined.
681 * name name of local variable
684 findlocal(char *name
)
686 return findstr(&localnames
, name
);
691 * Return the name of a local variable.
696 return namestr(&localnames
, n
);
701 * Add a possibly new parameter variable definition.
702 * Returns the index of the variable into the parameter symbol table.
703 * Minus one indicates the symbol could not be added.
706 * name name of parameter variable
711 long index
; /* current symbol index */
713 index
= findstr(¶mnames
, name
);
716 index
= paramnames
.h_count
;
717 (void) addstr(¶mnames
, name
);
718 curfunc
->f_paramcount
++;
724 * Find a parameter variable name and return its index.
725 * Returns minus one if the variable name is not defined.
728 * name name of parameter variable
731 findparam(char *name
)
733 return findstr(¶mnames
, name
);
738 * Return the name of a parameter variable.
743 return namestr(¶mnames
, n
);
748 * Return the type of a variable name.
749 * This is either local, parameter, global, static, or undefined.
752 * name variable name to find
755 symboltype(char *name
)
759 if (findparam(name
) >= 0)
761 if (findlocal(name
) >= 0)
763 sp
= findglobal(name
);
765 if (sp
->g_filescope
== SCOPE_GLOBAL
)
769 return SYM_UNDEFINED
;