mirror of
https://github.com/lcn2/calc.git
synced 2025-08-19 01:13:27 +03:00
Added notes to help/unexpected about: display() will limit the number of digits printed after decimal point %d will format after the decimal point for non-integer numeric values %x will format as fractions for non-integer numeric values fprintf(fd, "%d\n", huge_value) may need fflush(fd) to finish Fixed Makefile dependencies for the args.h rule. Fixed Makefile cases where echo with -n is used. On some systems, /bin/sh does not use -n, so we must call /bin/echo -n instead via the ${ECHON} Makefile variable. Add missing standard tools to sub-Makefiles to make them easier to invoke directly. Sort lists of standard tool Makefile variables and remove duplicates. Declare the SHELL at the top of Makefiles. Fixed the depend rule in the custom Makefile. Improved the messages produced by the depend in the Makefiles. Changed the UNUSED define in have_unused.h to be a macro with a parameter. Changed all use of UNUSED in *.c to be UNUSED(x). Removed need for HAVE_UNUSED in building the have_unused.h file. CCBAN is given to ${CC} in order to control if banned.h is in effect. The banned.h attempts to ban the use of certain dangerous functions that, if improperly used, could compromise the computational integrity if calculations. In the case of calc, we are motivated in part by the desire for calc to correctly calculate: even during extremely long calculations. If UNBAN is NOT defined, then calling certain functions will result in a call to a non-existent function (link error). While we do NOT encourage defining UNBAN, there may be a system / compiler environment where re-defining a function may lead to a fatal compiler complication. If that happens, consider compiling as: make clobber all chk CCBAN=-DUNBAN as see if this is a work-a-round. If YOU discover a need for the -DUNBAN work-a-round, PLEASE tell us! Please send us a bug report. See the file: BUGS or the URL: http://www.isthe.com/chongo/tech/comp/calc/calc-bugrept.html for how to send us such a bug report. Added the building of have_ban_pragma.h, which will determine if "#pragma GCC poison func_name" is supported. If it is not, or of HAVE_PRAGMA_GCC_POSION=-DHAVE_NO_PRAGMA_GCC_POSION, then banned.h will have no effect. Fixed building of the have_getpgid.h file. Fixed building of the have_getprid.h file. Fixed building of the have_getsid.h file. Fixed building of the have_gettime.h file. Fixed building of the have_strdup.h file. Fixed building of the have_ustat.h file. Fixed building of the have_rusage.h file. Added HAVE_NO_STRLCPY to control if we want to test if the system has a strlcpy() function. This in turn produces the have_strlcpy.h file wherein the symbol HAVE_STRLCPY will be defined, or not depending if the system comes with a strlcpy() function. If the system does not have a strlcpy() function, we compile our own strlcpy() function. See strl.c for details. Added HAVE_NO_STRLCAT to control if we want to test if the system has a strlcat() function. This in turn produces the have_strlcat.h file wherein the symbol HAVE_STRLCAT will be defined, or not depending if the system comes with a strlcat() function. If the system does not have a strlcat() function, we compile our own strlcat() function. See strl.c for details. Fixed places were <string.h>, using #ifdef HAVE_STRING_H for legacy systems that do not have that include file. Added ${H} Makefile symbol to control the announcement of forming and having formed hsrc related files. By default H=@ (announce hsrc file formation) vs. H=@: to silence hsrc related file formation. Explicitly turn off quiet mode (set Makefile variable ${Q} to be empty) when building rpms. Improved and fixed the hsrc build process. Forming rpms is performed in verbose mode to assist debugging to the rpm build process. Compile custom code, if needed, after main code is compiled.
773 lines
16 KiB
C
773 lines
16 KiB
C
/*
|
|
* symbol - global and local symbol routines
|
|
*
|
|
* Copyright (C) 1999-2007,2021 David I. Bell and Ernest Bowen
|
|
*
|
|
* Primary author: David I. Bell
|
|
*
|
|
* Calc is open software; you can redistribute it and/or modify it under
|
|
* the terms of the version 2.1 of the GNU Lesser General Public License
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* Calc is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
|
* Public License for more details.
|
|
*
|
|
* A copy of version 2.1 of the GNU Lesser General Public License is
|
|
* distributed with calc under the filename COPYING-LGPL. You should have
|
|
* received a copy with calc; if not, write to Free Software Foundation, Inc.
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Under source code control: 1990/02/15 01:48:23
|
|
* File existed as early as: before 1990
|
|
*
|
|
* Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include "calc.h"
|
|
#include "token.h"
|
|
#include "symbol.h"
|
|
#include "str.h"
|
|
#include "opcodes.h"
|
|
#include "func.h"
|
|
|
|
|
|
#include "banned.h" /* include after system header <> includes */
|
|
|
|
|
|
#define HASHSIZE 37 /* size of hash table */
|
|
|
|
E_FUNC FILE *f_open(char *name, char *mode);
|
|
|
|
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 */
|
|
|
|
S_FUNC void printtype(VALUE *);
|
|
S_FUNC void unscope(void);
|
|
S_FUNC void addstatic(GLOBAL *);
|
|
STATIC long staticcount = 0;
|
|
STATIC long staticavail = 0;
|
|
STATIC GLOBAL **statictable;
|
|
|
|
|
|
/*
|
|
* 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 */
|
|
size_t 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 = 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_value.v_subtype = V_NOSUBTYPE;
|
|
sp->g_next = *hp;
|
|
*hp = sp;
|
|
return sp;
|
|
}
|
|
|
|
|
|
/*
|
|
* Look for the highest-scope global variable with a specified name.
|
|
* Returns the address of the variable or NULL according as the search
|
|
* succeeds or fails.
|
|
*/
|
|
GLOBAL *
|
|
findglobal(char *name)
|
|
{
|
|
GLOBAL *sp; /* current symbol pointer */
|
|
GLOBAL *bestsp; /* found symbol with highest scope */
|
|
size_t len; /* length of string */
|
|
|
|
bestsp = NULL;
|
|
len = strlen(name);
|
|
for (sp = globalhash[HASHSYM(name, len)]; sp; sp = sp->g_next) {
|
|
if ((sp->g_len == len) && !strcmp(sp->g_name, name)) {
|
|
if ((bestsp == NULL) ||
|
|
(sp->g_filescope > bestsp->g_filescope) ||
|
|
(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 real-number valued global variables, displaying
|
|
* only the head and tail of very large numerators and denominators.
|
|
* Static variables are not included.
|
|
*/
|
|
void
|
|
showglobals(void)
|
|
{
|
|
GLOBAL **hp; /* hash table head address */
|
|
register GLOBAL *sp; /* current global symbol pointer */
|
|
long count; /* number of global variables shown */
|
|
|
|
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 (count++ == 0) {
|
|
printf("\nName Digits Value\n");
|
|
printf( "---- ------ -----\n");
|
|
}
|
|
printf("%-8s", sp->g_name);
|
|
if (sp->g_filescope != SCOPE_GLOBAL)
|
|
printf(" (s)");
|
|
fitprint(sp->g_value.v_num, 50);
|
|
printf("\n");
|
|
}
|
|
}
|
|
if (count == 0) {
|
|
printf("No real-valued global variables\n");
|
|
}
|
|
putchar('\n');
|
|
}
|
|
|
|
|
|
void
|
|
showallglobals(void)
|
|
{
|
|
GLOBAL **hp; /* hash table head address */
|
|
register GLOBAL *sp; /* current global symbol pointer */
|
|
long count; /* number of global variables shown */
|
|
|
|
count = 0;
|
|
for (hp = &globalhash[HASHSIZE-1]; hp >= globalhash; hp--) {
|
|
for (sp = *hp; sp; sp = sp->g_next) {
|
|
if (count++ == 0) {
|
|
printf("\nName Level Type\n");
|
|
printf( "---- ----- -----\n");
|
|
}
|
|
printf("%-8s%4d ", sp->g_name, sp->g_filescope);
|
|
printtype(&sp->g_value);
|
|
printf("\n");
|
|
}
|
|
}
|
|
if (count > 0)
|
|
printf("\nNumber: %ld\n", count);
|
|
else
|
|
printf("No global variables\n");
|
|
}
|
|
|
|
S_FUNC void
|
|
printtype(VALUE *vp)
|
|
{
|
|
int type;
|
|
char *s;
|
|
|
|
type = vp->v_type;
|
|
if (type < 0) {
|
|
printf("Error %d", -type);
|
|
return;
|
|
}
|
|
switch (type) {
|
|
case V_NUM:
|
|
printf("real = ");
|
|
fitprint(vp->v_num, 32);
|
|
return;
|
|
case V_COM:
|
|
printf("complex = ");
|
|
fitprint(vp->v_com->real, 8);
|
|
if (!vp->v_com->imag->num.sign)
|
|
printf("+");
|
|
fitprint(vp->v_com->imag, 8);
|
|
printf("i");
|
|
return;
|
|
case V_STR:
|
|
printf("string = \"");
|
|
fitstring(vp->v_str->s_str, vp->v_str->s_len, 50);
|
|
printf("\"");
|
|
return;
|
|
case V_NULL:
|
|
s = "null";
|
|
break;
|
|
case V_MAT:
|
|
s = "matrix";
|
|
break;
|
|
case V_LIST:
|
|
s = "list";
|
|
break;
|
|
case V_ASSOC:
|
|
s = "association";
|
|
break;
|
|
case V_OBJ:
|
|
printf("%s ", objtypename(
|
|
vp->v_obj->o_actions->oa_index));
|
|
s = "object";
|
|
break;
|
|
case V_FILE:
|
|
s = "file id";
|
|
break;
|
|
case V_RAND:
|
|
s = "additive 55 random state";
|
|
break;
|
|
case V_RANDOM:
|
|
s = "Blum random state";
|
|
break;
|
|
case V_CONFIG:
|
|
s = "config state";
|
|
break;
|
|
case V_HASH:
|
|
s = "hash state";
|
|
break;
|
|
case V_BLOCK:
|
|
s = "unnamed block";
|
|
break;
|
|
case V_NBLOCK:
|
|
s = "named block";
|
|
break;
|
|
case V_VPTR:
|
|
s = "value pointer";
|
|
break;
|
|
case V_OPTR:
|
|
s = "octet pointer";
|
|
break;
|
|
case V_SPTR:
|
|
s = "string pointer";
|
|
break;
|
|
case V_NPTR:
|
|
s = "number pointer";
|
|
break;
|
|
default:
|
|
s = "???";
|
|
break;
|
|
}
|
|
printf("%s", s);
|
|
}
|
|
|
|
|
|
/*
|
|
* 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 */
|
|
E_FUNC void math_setfp(FILE *fp);
|
|
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* Free all non-null global and visible static variables
|
|
*/
|
|
void
|
|
freeglobals(void)
|
|
{
|
|
GLOBAL **hp; /* hash table head address */
|
|
GLOBAL *sp; /* current global symbol pointer */
|
|
long count; /* number of global variables freed */
|
|
|
|
/*
|
|
* We prevent the hp pointer from walking behind globalhash
|
|
* by stopping one short of the end and running the loop one
|
|
* more time.
|
|
*
|
|
* We could stop the loop with just hp >= globalhash, but stopping
|
|
* short and running the loop one last time manually helps make
|
|
* code checkers such as insure happy.
|
|
*/
|
|
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_NULL) {
|
|
freevalue(&sp->g_value);
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
/* run the loop manually one last time */
|
|
for (sp = *hp; sp; sp = sp->g_next) {
|
|
if (sp->g_value.v_type != V_NULL) {
|
|
freevalue(&sp->g_value);
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Free all invisible static variables
|
|
*/
|
|
void
|
|
freestatics(void)
|
|
{
|
|
GLOBAL **stp;
|
|
GLOBAL *sp;
|
|
long count;
|
|
|
|
stp = statictable;
|
|
count = staticcount;
|
|
while (count-- > 0) {
|
|
sp = *stp++;
|
|
freevalue(&sp->g_value);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 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();
|
|
}
|
|
|
|
|
|
/*
|
|
* To end the scope of any static variable with identifier id when
|
|
* id is being declared as global, or when id is declared as static and the
|
|
* variable is at the same file and function level.
|
|
*/
|
|
void
|
|
endscope(char *name, BOOL isglobal)
|
|
{
|
|
GLOBAL *sp;
|
|
GLOBAL *prevsp;
|
|
GLOBAL **hp;
|
|
size_t len;
|
|
|
|
len = strlen(name);
|
|
prevsp = NULL;
|
|
hp = &globalhash[HASHSYM(name, len)];
|
|
for (sp = *hp; sp; sp = sp->g_next) {
|
|
if (sp->g_len == len && !strcmp(sp->g_name, name) &&
|
|
sp->g_filescope > SCOPE_GLOBAL) {
|
|
if (isglobal || (sp->g_filescope == filescope &&
|
|
sp->g_funcscope == funcscope)) {
|
|
addstatic(sp);
|
|
if (prevsp)
|
|
prevsp->g_next = sp->g_next;
|
|
else
|
|
*hp = sp->g_next;
|
|
continue;
|
|
}
|
|
}
|
|
prevsp = sp;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* To store in a table a static variable whose scope is being ended
|
|
*/
|
|
void
|
|
addstatic(GLOBAL *sp)
|
|
{
|
|
GLOBAL **stp;
|
|
|
|
if (staticavail <= 0) {
|
|
if (staticcount <= 0)
|
|
stp = (GLOBAL **) malloc(20 * sizeof(GLOBAL *));
|
|
else
|
|
stp = (GLOBAL **) realloc(statictable,
|
|
(20 + staticcount) * sizeof(GLOBAL *));
|
|
if (stp == NULL) {
|
|
math_error("Cannot allocate static-variable table");
|
|
/*NOTREACHED*/
|
|
}
|
|
statictable = stp;
|
|
staticavail = 20;
|
|
}
|
|
statictable[staticcount++] = sp;
|
|
staticavail--;
|
|
}
|
|
|
|
/*
|
|
* To display all static variables whose scope has been ended
|
|
*/
|
|
void
|
|
showstatics(void)
|
|
{
|
|
long count;
|
|
GLOBAL **stp;
|
|
GLOBAL *sp;
|
|
|
|
for (count = 0, stp = statictable; count < staticcount; count++) {
|
|
sp = *stp++;
|
|
if (count == 0) {
|
|
printf("\nName Scopes Type\n");
|
|
printf( "---- ------ -----\n");
|
|
}
|
|
printf("%-8s", sp->g_name);
|
|
printf("%3d", sp->g_filescope);
|
|
printf("%3d ", sp->g_funcscope);
|
|
printtype(&sp->g_value);
|
|
printf("\n");
|
|
}
|
|
if (count > 0)
|
|
printf("\nNumber: %ld\n", count);
|
|
else
|
|
printf("No unscoped static variables\n");
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
S_FUNC void
|
|
unscope(void)
|
|
{
|
|
GLOBAL **hp; /* hash table head address */
|
|
register GLOBAL *sp; /* current global symbol pointer */
|
|
GLOBAL *prevsp; /* previous kept symbol pointer */
|
|
|
|
/*
|
|
* We prevent the hp pointer from walking behind globalhash
|
|
* by stopping one short of the end and running the loop one
|
|
* more time.
|
|
*
|
|
* We could stop the loop with just hp >= globalhash, but stopping
|
|
* short and running the loop one last time manually helps make
|
|
* code checkers such as insure happy.
|
|
*/
|
|
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.
|
|
*/
|
|
addstatic(sp);
|
|
if (prevsp)
|
|
prevsp->g_next = sp->g_next;
|
|
else
|
|
*hp = sp->g_next;
|
|
}
|
|
}
|
|
/* run the loop manually one last time */
|
|
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.
|
|
*/
|
|
addstatic(sp);
|
|
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 (findparam(name) >= 0)
|
|
return SYM_PARAM;
|
|
if (findlocal(name) >= 0)
|
|
return SYM_LOCAL;
|
|
sp = findglobal(name);
|
|
if (sp) {
|
|
if (sp->g_filescope == SCOPE_GLOBAL)
|
|
return SYM_GLOBAL;
|
|
return SYM_STATIC;
|
|
}
|
|
return SYM_UNDEFINED;
|
|
}
|
|
|
|
/* END CODE */
|