* Copyright (c) 1994 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
* Global and local symbol routines.
#define HASHSIZE 37 /* size of hash table */
static int filescope
; /* file scope level for static variables */
static int funcscope
; /* function scope level for static variables */
static STRINGHEAD localnames
; /* list of local variable names */
static STRINGHEAD globalnames
; /* list of global variable names */
static STRINGHEAD paramnames
; /* list of parameter variable names */
static GLOBAL
*globalhash
[HASHSIZE
]; /* hash table for globals */
static void fitprint
MATH_PROTO((NUMBER
*num
, long digits
, long width
));
static void unscope
MATH_PROTO((void));
* Hash a symbol name so we can find it in the hash table.
* Args are the symbol name and the symbol name size.
#define HASHSYM(n, s) ((unsigned)((n)[0]*123 + (n)[s-1]*135 + (s)*157) % HASHSIZE)
* Initialize the global symbol table.
int i
; /* index counter */
for (i
= 0; i
< HASHSIZE
; i
++)
filescope
= SCOPE_STATIC
;
* Define a possibly new global variable which may or may not be static.
* If it did not already exist, it is created with a value of zero.
* The address of the global symbol structure is returned.
addglobal(name
, isstatic
)
char *name
; /* name of global variable */
BOOL isstatic
; /* TRUE if symbol is static */
GLOBAL
*sp
; /* current symbol pointer */
GLOBAL
**hp
; /* hash table head address */
long len
; /* length of string */
int newfilescope
; /* file scope being looked for */
int newfuncscope
; /* function scope being looked for */
newfilescope
= SCOPE_GLOBAL
;
newfilescope
= filescope
;
newfuncscope
= funcscope
;
hp
= &globalhash
[HASHSYM(name
, len
)];
for (sp
= *hp
; sp
; sp
= sp
->g_next
) {
if ((sp
->g_len
== len
) && (strcmp(sp
->g_name
, name
) == 0)
&& (sp
->g_filescope
== newfilescope
)
&& (sp
->g_funcscope
== newfuncscope
))
sp
= (GLOBAL
*) malloc(sizeof(GLOBAL
));
sp
->g_name
= addstr(&globalnames
, name
);
sp
->g_filescope
= newfilescope
;
sp
->g_funcscope
= newfuncscope
;
sp
->g_value
.v_num
= qlink(&_qzero_
);
sp
->g_value
.v_type
= V_NUM
;
* Look up the name of a global variable and return its address.
* Since the same variable may appear in different scopes, we search
* for the one with the highest function scope value within the current
* file scope level (or which is global). Returns NULL if the symbol
char *name
; /* name of global variable */
GLOBAL
*sp
; /* current symbol pointer */
GLOBAL
*bestsp
; /* found symbol with highest scope */
long len
; /* length of string */
for (sp
= globalhash
[HASHSYM(name
, len
)]; sp
; sp
= sp
->g_next
) {
if ((sp
->g_len
!= len
) || strcmp(sp
->g_name
, name
))
if (sp
->g_filescope
== SCOPE_GLOBAL
) {
if (sp
->g_filescope
!= filescope
)
if ((bestsp
== NULL
) || (sp
->g_funcscope
> bestsp
->g_funcscope
))
* Return the name of a global variable given its address.
GLOBAL
*sp
; /* address of global pointer */
* Show the value of all global variables, typing only the head and
* tail of very large numbers. Only truly global symbols are shown.
GLOBAL
**hp
; /* hash table head address */
register GLOBAL
*sp
; /* current global symbol pointer */
long count
; /* number of global variables shown */
for (hp
= &globalhash
[HASHSIZE
-1]; hp
>= globalhash
; hp
--) {
for (sp
= *hp
; sp
; sp
= sp
->g_next
) {
if (sp
->g_value
.v_type
!= V_NUM
)
if (sp
->g_filescope
!= SCOPE_GLOBAL
)
printf("\nName Digits Value\n");
printf( "---- ------ -----\n");
printf("%-8s ", sp
->g_name
);
num
= qnum(sp
->g_value
.v_num
);
printf("%-7ld ", digits
);
fitprint(num
, digits
, 60L);
if (!qisint(sp
->g_value
.v_num
)) {
den
= qden(sp
->g_value
.v_num
);
printf("\n %-6ld /", digits
);
fitprint(den
, digits
, 60L);
printf(count
? "\n" : "No global variables defined.\n");
* Print an integer which is guaranteed to fit in the specified number
* of columns, using imbedded '...' characters if it is too large.
fitprint(num
, digits
, width
)
NUMBER
*num
; /* number to print */
NUMBER
*p
, *t
, *div
, *val
;
p
= itoq((long) (digits
- show
));
while (used
++ < show
) printf("0");
* Write all normal global variables to an output file.
* Note: Currently only simple types are saved.
* Returns nonzero on error.
GLOBAL
**hp
; /* hash table head address */
register GLOBAL
*sp
; /* current global symbol pointer */
int savemode
; /* saved output mode */
for (hp
= &globalhash
[HASHSIZE
-1]; hp
>= globalhash
; hp
--) {
for (sp
= *hp
; sp
; sp
= sp
->g_next
) {
switch (sp
->g_value
.v_type
) {
math_fmt("%s = ", sp
->g_name
);
savemode
= math_setmode(MODE_HEX
);
printvalue(&sp
->g_value
, PRINT_UNAMBIG
);
* Reset the file and function scope levels back to the original values.
* This is called on errors to forget any static variables which were being
filescope
= SCOPE_STATIC
;
* Enter a new file scope level so that newly defined static variables
* will have the appropriate scope, and so that previously defined static
* variables will temporarily be unaccessible. This should only be called
* when the function scope level is zero.
* Exit from a file scope level. This deletes from the global symbol table
* all of the static variables that were defined within this file scope level.
* The function scope level is also reset to zero.
if (filescope
> SCOPE_STATIC
)
* Enter a new function scope level within the current file scope level.
* This allows newly defined static variables to override previously defined
* static variables in the same file scope level.
* Exit from a function scope level. This deletes static symbols which were
* defined within the current function scope level, and makes previously
* defined symbols with the same name within the same file scope level
* Remove all the symbols from the global symbol table which have file or
* function scopes larger than the current scope levels. Their memory
* remains allocated since their values still actually exist.
GLOBAL
**hp
; /* hash table head address */
register GLOBAL
*sp
; /* current global symbol pointer */
GLOBAL
*prevsp
; /* previous kept symbol pointer */
for (hp
= &globalhash
[HASHSIZE
-1]; hp
>= globalhash
; hp
--) {
for (sp
= *hp
; sp
; sp
= sp
->g_next
) {
if ((sp
->g_filescope
== SCOPE_GLOBAL
) ||
(sp
->g_filescope
< filescope
) ||
((sp
->g_filescope
== filescope
) &&
(sp
->g_funcscope
<= funcscope
)))
* This symbol needs removing.
prevsp
->g_next
= sp
->g_next
;
* Initialize the local and parameter symbol table information.
curfunc
->f_localcount
= 0;
curfunc
->f_paramcount
= 0;
* Add a possibly new local variable definition.
* Returns the index of the variable into the local symbol table.
* Minus one indicates the symbol could not be added.
char *name
; /* name of local variable */
long index
; /* current symbol index */
index
= findstr(&localnames
, name
);
index
= localnames
.h_count
;
(void) addstr(&localnames
, name
);
* Find a local variable name and return its index.
* Returns minus one if the variable name is not defined.
char *name
; /* name of local variable */
return findstr(&localnames
, name
);
* Return the name of a local variable.
return namestr(&localnames
, n
);
* Add a possibly new parameter variable definition.
* Returns the index of the variable into the parameter symbol table.
* Minus one indicates the symbol could not be added.
char *name
; /* name of parameter variable */
long index
; /* current symbol index */
index
= findstr(¶mnames
, name
);
index
= paramnames
.h_count
;
(void) addstr(¶mnames
, name
);
* Find a parameter variable name and return its index.
* Returns minus one if the variable name is not defined.
char *name
; /* name of parameter variable */
return findstr(¶mnames
, name
);
* Return the name of a parameter variable.
return namestr(¶mnames
, n
);
* Return the type of a variable name.
* This is either local, parameter, global, static, or undefined.
char *name
; /* variable name to find */
if (findlocal(name
) >= 0)
if (findparam(name
) >= 0)
if (sp
->g_filescope
== SCOPE_GLOBAL
)