mirror of
https://github.com/lcn2/calc.git
synced 2025-08-16 01:03:29 +03:00
Converted all ASCII tabs to ASCII spaces using a 8 character tab stop, for all files, except for all Makefiles (plus rpm.mk). The `git diff -w` reports no changes.
784 lines
22 KiB
C
784 lines
22 KiB
C
/*
|
|
* symbol - global and local symbol routines
|
|
*
|
|
* Copyright (C) 1999-2007,2021-2023 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 "errtbl.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) &&
|
|
(strncmp(sp->g_name, name, len+1) == 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 != NULL; sp = sp->g_next) {
|
|
if ((sp->g_len == len) &&
|
|
(strncmp(sp->g_name, name, len+1) == 0)) {
|
|
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;
|
|
char *errsym;
|
|
bool alloced;
|
|
|
|
type = vp->v_type;
|
|
if (type < 0) {
|
|
errsym = errnum_2_errsym(-type, &alloced);
|
|
if (errsym == NULL) {
|
|
printf("Error %d", -type);
|
|
} else {
|
|
printf("Error %s", errsym);
|
|
if (alloced == true) {
|
|
free(errsym);
|
|
}
|
|
}
|
|
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 = "subtractive 100 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 */
|
|
|
|
/*
|
|
* 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--) {
|
|
for (sp = *hp; sp; sp = sp->g_next) {
|
|
if (sp->g_value.v_type != V_NULL) {
|
|
freevalue(&sp->g_value);
|
|
}
|
|
}
|
|
}
|
|
/* 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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");
|
|
not_reached();
|
|
}
|
|
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 un-scoped 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 */
|