mirror of
https://github.com/lcn2/calc.git
synced 2025-08-16 01:03:29 +03:00
Release calc version 2.10.2t30
This commit is contained in:
513
symbol.c
Normal file
513
symbol.c
Normal file
@@ -0,0 +1,513 @@
|
||||
/*
|
||||
* Copyright (c) 1996 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.
|
||||
*/
|
||||
|
||||
#include "calc.h"
|
||||
#include "token.h"
|
||||
#include "symbol.h"
|
||||
#include "string.h"
|
||||
#include "opcodes.h"
|
||||
#include "func.h"
|
||||
|
||||
#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(NUMBER *num, long digits, long width);
|
||||
static void unscope(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.
|
||||
*/
|
||||
void
|
||||
initglobals(void)
|
||||
{
|
||||
int i; /* index counter */
|
||||
|
||||
for (i = 0; i < HASHSIZE; i++)
|
||||
globalhash[i] = NULL;
|
||||
initstr(&globalnames);
|
||||
filescope = SCOPE_STATIC;
|
||||
funcscope = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* given:
|
||||
* name name of global variable
|
||||
* isstatic TRUE if symbol is static
|
||||
*/
|
||||
GLOBAL *
|
||||
addglobal(char *name, BOOL isstatic)
|
||||
{
|
||||
GLOBAL *sp; /* current symbol pointer */
|
||||
GLOBAL **hp; /* hash table head address */
|
||||
int len; /* length of string */
|
||||
int newfilescope; /* file scope being looked for */
|
||||
int newfuncscope; /* function scope being looked for */
|
||||
|
||||
newfilescope = SCOPE_GLOBAL;
|
||||
newfuncscope = 0;
|
||||
if (isstatic) {
|
||||
newfilescope = filescope;
|
||||
newfuncscope = funcscope;
|
||||
}
|
||||
len = (int)strlen(name);
|
||||
if (len <= 0)
|
||||
return NULL;
|
||||
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))
|
||||
return sp;
|
||||
}
|
||||
sp = (GLOBAL *) malloc(sizeof(GLOBAL));
|
||||
if (sp == NULL)
|
||||
return sp;
|
||||
sp->g_name = addstr(&globalnames, name);
|
||||
sp->g_len = len;
|
||||
sp->g_filescope = newfilescope;
|
||||
sp->g_funcscope = newfuncscope;
|
||||
sp->g_value.v_num = qlink(&_qzero_);
|
||||
sp->g_value.v_type = V_NUM;
|
||||
sp->g_next = *hp;
|
||||
*hp = sp;
|
||||
return sp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
* was not found.
|
||||
*
|
||||
* given:
|
||||
* name name of global variable
|
||||
*/
|
||||
GLOBAL *
|
||||
findglobal(char *name)
|
||||
{
|
||||
GLOBAL *sp; /* current symbol pointer */
|
||||
GLOBAL *bestsp; /* found symbol with highest scope */
|
||||
long len; /* length of string */
|
||||
|
||||
bestsp = NULL;
|
||||
len = (long)strlen(name);
|
||||
for (sp = globalhash[HASHSYM(name, len)]; sp; sp = sp->g_next) {
|
||||
if ((sp->g_len != len) || strcmp(sp->g_name, name))
|
||||
continue;
|
||||
if (sp->g_filescope == SCOPE_GLOBAL) {
|
||||
if (bestsp == NULL)
|
||||
bestsp = sp;
|
||||
continue;
|
||||
}
|
||||
if (sp->g_filescope != filescope)
|
||||
continue;
|
||||
if ((bestsp == NULL) || (sp->g_funcscope > bestsp->g_funcscope))
|
||||
bestsp = sp;
|
||||
}
|
||||
return bestsp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the name of a global variable given its address.
|
||||
*
|
||||
* given:
|
||||
* sp address of global pointer
|
||||
*/
|
||||
char *
|
||||
globalname(GLOBAL *sp)
|
||||
{
|
||||
if (sp)
|
||||
return sp->g_name;
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Show the value of all global variables, typing only the head and
|
||||
* tail of very large numbers. Only truly global symbols are shown.
|
||||
*/
|
||||
void
|
||||
showglobals(void)
|
||||
{
|
||||
GLOBAL **hp; /* hash table head address */
|
||||
register GLOBAL *sp; /* current global symbol pointer */
|
||||
long count; /* number of global variables shown */
|
||||
NUMBER *num, *den;
|
||||
long digits;
|
||||
|
||||
count = 0;
|
||||
for (hp = &globalhash[HASHSIZE-1]; hp >= globalhash; hp--) {
|
||||
for (sp = *hp; sp; sp = sp->g_next) {
|
||||
if (sp->g_value.v_type != V_NUM)
|
||||
continue;
|
||||
if (sp->g_filescope != SCOPE_GLOBAL)
|
||||
continue;
|
||||
if (count++ == 0) {
|
||||
printf("\nName Digits Value\n");
|
||||
printf( "---- ------ -----\n");
|
||||
}
|
||||
printf("%-8s ", sp->g_name);
|
||||
num = qnum(sp->g_value.v_num);
|
||||
digits = qdigits(num);
|
||||
printf("%-7ld ", digits);
|
||||
fitprint(num, digits, 60L);
|
||||
qfree(num);
|
||||
if (!qisint(sp->g_value.v_num)) {
|
||||
den = qden(sp->g_value.v_num);
|
||||
digits = qdigits(den);
|
||||
printf("\n %-6ld /", digits);
|
||||
fitprint(den, digits, 60L);
|
||||
qfree(den);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
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.
|
||||
*/
|
||||
static void
|
||||
fitprint(NUMBER *num, long digits, long width)
|
||||
{
|
||||
long show, used;
|
||||
NUMBER *p, *t, *div, *val;
|
||||
|
||||
if (digits <= width) {
|
||||
qprintf("%r", num);
|
||||
return;
|
||||
}
|
||||
show = (width / 2) - 2;
|
||||
t = itoq(10L);
|
||||
p = itoq((long) (digits - show));
|
||||
div = qpowi(t, p);
|
||||
val = qquo(num, div, 0);
|
||||
qprintf("%r", val);
|
||||
printf("...");
|
||||
qfree(p);
|
||||
qfree(div);
|
||||
qfree(val);
|
||||
p = itoq(show);
|
||||
div = qpowi(t, p);
|
||||
val = qmod(num, div, 0);
|
||||
used = qdigits(val);
|
||||
while (used++ < show) printf("0");
|
||||
qprintf("%r", val);
|
||||
qfree(p);
|
||||
qfree(div);
|
||||
qfree(val);
|
||||
qfree(t);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write all normal global variables to an output file.
|
||||
* Note: Currently only simple types are saved.
|
||||
* Returns nonzero on error.
|
||||
*/
|
||||
int
|
||||
writeglobals(char *name)
|
||||
{
|
||||
FILE *fp;
|
||||
GLOBAL **hp; /* hash table head address */
|
||||
register GLOBAL *sp; /* current global symbol pointer */
|
||||
int savemode; /* saved output mode */
|
||||
|
||||
fp = f_open(name, "w");
|
||||
if (fp == NULL)
|
||||
return 1;
|
||||
math_setfp(fp);
|
||||
for (hp = &globalhash[HASHSIZE-1]; hp >= globalhash; hp--) {
|
||||
for (sp = *hp; sp; sp = sp->g_next) {
|
||||
switch (sp->g_value.v_type) {
|
||||
case V_NUM:
|
||||
case V_COM:
|
||||
case V_STR:
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
math_fmt("%s = ", sp->g_name);
|
||||
savemode = math_setmode(MODE_HEX);
|
||||
printvalue(&sp->g_value, PRINT_UNAMBIG);
|
||||
math_setmode(savemode);
|
||||
math_str(";\n");
|
||||
}
|
||||
}
|
||||
math_setfp(stdout);
|
||||
if (fclose(fp))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
* defined.
|
||||
*/
|
||||
void
|
||||
resetscopes(void)
|
||||
{
|
||||
filescope = SCOPE_STATIC;
|
||||
funcscope = 0;
|
||||
unscope();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
void
|
||||
enterfilescope(void)
|
||||
{
|
||||
filescope++;
|
||||
funcscope = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
void
|
||||
exitfilescope(void)
|
||||
{
|
||||
if (filescope > SCOPE_STATIC)
|
||||
filescope--;
|
||||
funcscope = 0;
|
||||
unscope();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
void
|
||||
enterfuncscope(void)
|
||||
{
|
||||
funcscope++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
* accessible again.
|
||||
*/
|
||||
void
|
||||
exitfuncscope(void)
|
||||
{
|
||||
if (funcscope > 0)
|
||||
funcscope--;
|
||||
unscope();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
static void
|
||||
unscope(void)
|
||||
{
|
||||
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--) {
|
||||
prevsp = NULL;
|
||||
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)))
|
||||
{
|
||||
prevsp = sp;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* This symbol needs removing.
|
||||
*/
|
||||
if (prevsp)
|
||||
prevsp->g_next = sp->g_next;
|
||||
else
|
||||
*hp = sp->g_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize the local and parameter symbol table information.
|
||||
*/
|
||||
void
|
||||
initlocals(void)
|
||||
{
|
||||
initstr(&localnames);
|
||||
initstr(¶mnames);
|
||||
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.
|
||||
*
|
||||
* given:
|
||||
* name name of local variable
|
||||
*/
|
||||
long
|
||||
addlocal(char *name)
|
||||
{
|
||||
long index; /* current symbol index */
|
||||
|
||||
index = findstr(&localnames, name);
|
||||
if (index >= 0)
|
||||
return index;
|
||||
index = localnames.h_count;
|
||||
(void) addstr(&localnames, name);
|
||||
curfunc->f_localcount++;
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find a local variable name and return its index.
|
||||
* Returns minus one if the variable name is not defined.
|
||||
*
|
||||
* given:
|
||||
* name name of local variable
|
||||
*/
|
||||
long
|
||||
findlocal(char *name)
|
||||
{
|
||||
return findstr(&localnames, name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the name of a local variable.
|
||||
*/
|
||||
char *
|
||||
localname(long n)
|
||||
{
|
||||
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.
|
||||
*
|
||||
* given:
|
||||
* name name of parameter variable
|
||||
*/
|
||||
long
|
||||
addparam(char *name)
|
||||
{
|
||||
long index; /* current symbol index */
|
||||
|
||||
index = findstr(¶mnames, name);
|
||||
if (index >= 0)
|
||||
return index;
|
||||
index = paramnames.h_count;
|
||||
(void) addstr(¶mnames, name);
|
||||
curfunc->f_paramcount++;
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find a parameter variable name and return its index.
|
||||
* Returns minus one if the variable name is not defined.
|
||||
*
|
||||
* given:
|
||||
* name name of parameter variable
|
||||
*/
|
||||
long
|
||||
findparam(char *name)
|
||||
{
|
||||
return findstr(¶mnames, name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the name of a parameter variable.
|
||||
*/
|
||||
char *
|
||||
paramname(long n)
|
||||
{
|
||||
return namestr(¶mnames, n);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the type of a variable name.
|
||||
* This is either local, parameter, global, static, or undefined.
|
||||
*
|
||||
* given:
|
||||
* name variable name to find
|
||||
*/
|
||||
int
|
||||
symboltype(char *name)
|
||||
{
|
||||
GLOBAL *sp;
|
||||
|
||||
if (findlocal(name) >= 0)
|
||||
return SYM_LOCAL;
|
||||
if (findparam(name) >= 0)
|
||||
return SYM_PARAM;
|
||||
sp = findglobal(name);
|
||||
if (sp) {
|
||||
if (sp->g_filescope == SCOPE_GLOBAL)
|
||||
return SYM_GLOBAL;
|
||||
return SYM_STATIC;
|
||||
}
|
||||
return SYM_UNDEFINED;
|
||||
}
|
||||
|
||||
/* END CODE */
|
Reference in New Issue
Block a user