This is idents.c in view mode; [Download] [Up]
/****************************************************************************
**
*A idents.c GAP source Martin Schoenert
**
*H @(#)$Id: idents.c,v 3.6 1993/02/09 14:28:51 martin Rel $
**
*Y Copyright 1990-1992, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany
**
** This file contains the functions for mapping identifiers to variables.
**
*H $Log: idents.c,v $
*H Revision 3.6 1993/02/09 14:28:51 martin
*H changed the recognition of undefined globals
*H
*H Revision 3.5 1993/02/04 10:51:10 martin
*H changed 'T_STRING' to 'T_RECNAME'
*H
*H Revision 3.4 1992/01/20 13:21:15 martin
*H improved the identifier completion
*H
*H Revision 3.3 1991/07/17 13:40:28 martin
*H fixed 'FindRecname' from bad rehashing
*H
*H Revision 3.2 1991/04/30 16:12:23 martin
*H initial revision under RCS
*H
*H Revision 3.1 1991/01/15 12:00:00 martin
*H fixed 'x ->' yields 'warning, undefined variable'
*H
*H Revision 3.0 1990/11/30 12:00:00 martin
*H extended 'SyFgets' by identifier completion
*H
*/
#include "system.h" /* system dependent functions */
#include "gasman.h" /* dynamic storage manager */
#include "idents.h" /* declaration part of the package */
/****************************************************************************
**
*V HdIdenttab . . . . . . . . . . . . . . handle of identifier table, local
*V NrIdenttab . . . . . . . . . . . . . number of used table entries, local
**
** 'HdIdenttab' is the handle of the identifier table bag. The table is a
** list which contains all the variable bags. The entries are hashed into
** this table, i.e., for an identifier we compute a hash value and then we
** put the variable bag for that identifier bag at this position. If this
** entry is already used by another variable, a situation we call collision,
** we take the next free entry.
**
** 'NrIdenttab' is the number of entries used in this table. Note that we
** keep the size of the table at least twice as big, to reduce the number of
** collisions.
*/
TypHandle HdIdenttab;
unsigned long NrIdenttab;
/****************************************************************************
**
*V HdStack . . . . . . . . . handle of the function definition stack, local
*V TopStack . . . . . . . . . . top of the function definition stack, local
**
** 'HdStack' is the handle of the function definition stack. This is a list
** of all the functions that are currently being read organized as a stack.
** The entries of this list are the function definition bags. 'FindIdent'
** first searches this stack to look for local variables before searching
** 'HdIdenttab'.
**
** 'TopStack' is the index of the topmost entry in the stack, which grows
** upward.
*/
TypHandle HdStack;
unsigned long TopStack;
/****************************************************************************
**
*F PushFunction( <hdFun> ) . . . . . . . . add another function to the stack
**
** 'PushFunction' adds another function to the function definition stack.
** It is called from the reader when the reader starts to parse a function.
** It makes the local variables known to 'FindIdent'.
*/
void PushFunction ( hdFun )
TypHandle hdFun;
{
PTR(HdStack)[++TopStack] = hdFun;
}
/****************************************************************************
**
*F PopFunction() . . . . . . . . . . remove another function from the stack
**
** 'PopFunction' removes the most recent function from the function
** definition stack. It is called from the reader when the reader finished
** parsing a function. It makes the local variables again unknown.
*/
void PopFunction ()
{
PTR(HdStack)[TopStack--] = 0;
}
/****************************************************************************
**
*V IsUndefinedGlobal . . . . . true if a variable is an new global variable
**
** 'IsUndefinedGlobal' is set by 'FindIdent' if <name> is a new global
** variable inside a function definition. 'RdVar' tests 'IsUndefinedGlobal'
** and complains about such variables.
*/
unsigned long IsUndefinedGlobal;
/****************************************************************************
**
*F FindIdent( <name> ) . . . . . . . . . . . find variable for an identifier
**
** 'FindIdent' returns the handle of the variable bag for the variable
** with the identifier <name>. 'FindIdent' first searches the function
** definition bags made added to the stack by 'PushFunction'. If no local
** variable has this identifier, 'FindIdent' looks in the global identifier
** table. If the identifier is also not found in the global table a new
** global variable is created.
*/
TypHandle FindIdent ( name )
char name [];
{
TypHandle hd, hdIdenttab, hd2;
char * p;
unsigned long i, k, nrEntries;
/* horrible hack */
IsUndefinedGlobal = 0;
/* First search the local tables stored on the function stack. */
for ( i = TopStack; i > 0; --i ) {
hd = PTR(HdStack)[i];
nrEntries = (SIZE(hd) - 2*sizeof(short)) / SIZE_HD - 1;
for ( k = 1; k < nrEntries; ++k ) {
if ( ! SyStrcmp( name, (char*)(PTR(PTR(hd)[k])+1) ) )
return PTR(hd)[k];
}
}
/* Next look in the global identifer table, but where ? */
for ( k = 0, p = name; *p != '\0'; ++p ) k = 65599 * k + *p;
k = k % (SIZE(HdIdenttab) / SIZE_HD);
/* Look through the table, until you find a free slot or our name */
while ( PTR(HdIdenttab)[k] != 0
&& SyStrcmp( (char*)(PTR(PTR(HdIdenttab)[k])+1), name ) ) {
k = (k + 1) % (SIZE(HdIdenttab) / SIZE_HD);
}
/* If we found our identifer, very good. */
if ( PTR(HdIdenttab)[k] != 0 ) {
if ( PTR( PTR(HdIdenttab)[k] )[0] == 0 && TopStack != 0 )
IsUndefinedGlobal = 1;
return PTR(HdIdenttab)[k];
}
/* If currently reading a function, give a warning */
if ( TopStack != 0 )
IsUndefinedGlobal = 1;
/* If we find a free slot, still good. */
hd = NewBag( T_VAR, SIZE_HD+SyStrlen(name)+1 );
SyStrncat( (char*)(PTR(hd)+1), name, SyStrlen(name) );
PTR(HdIdenttab)[k] = hd;
++NrIdenttab;
/* If the identifer table isn't overcrowed simply return hd. */
if ( 3 * NrIdenttab / 2 < SIZE(HdIdenttab) / SIZE_HD )
return hd;
/* Otherwise enlarge it and rehash all entries. */
hdIdenttab = NewBag( T_LIST, SIZE(HdIdenttab) );
for ( i = 0; i < SIZE(hdIdenttab) / SIZE_HD; ++i ) {
PTR(hdIdenttab)[i] = PTR(HdIdenttab)[i];
PTR(HdIdenttab)[i] = 0;
}
Resize( HdIdenttab, 2 * SIZE(HdIdenttab) + SIZE_HD );
for ( i = 0; i < SIZE(hdIdenttab) / SIZE_HD; ++i ) {
hd2 = PTR(hdIdenttab)[i];
if ( hd2 == 0 ) continue;
for ( k = 0, p = (char*)(PTR(hd2)+1); *p != '\0'; ++p )
k = 65599 * k + *p;
k = k % (SIZE(HdIdenttab) / SIZE_HD);
while ( PTR(HdIdenttab)[k] != 0 )
k = (k + 1) % (SIZE(HdIdenttab) / SIZE_HD);
PTR(HdIdenttab)[k] = hd2;
}
return hd;
}
/****************************************************************************
**
*V HdRectab . . . . . . . . . . . . . . handle of record name table, local
*V NrRectab . . . . . . . . . . . . . . number of used table entries, local
**
** 'HdRectab' is the handle of the record name table bag. The table is a
** list which contains all the record name bags. The entries are hashed into
** this table, i.e., for a record name we compute a hash value and then we
** put the record name bag for that record name bag at this position. If
** this entry is already used by another record name, a situation we call
** collision, we take the next free entry.
**
** 'NrRectab' is the number of entries used in this table. Note that we
** keep the size of the table at least twice as big, to reduce the number of
** collisions.
*/
TypHandle HdRectab;
unsigned long NrRectab;
/****************************************************************************
**
*F FindRecname( <name> ) . . . . find the record name bag for a record name
**
** 'FindRecname' returns the record name bag for the record name <name>.
** Note that record names are always stored unique, i.e., for every string
** there is a unique record name bag for that string. This makes it easier
** to find a record element for a given record name: We do not have to
** compare strings, it is enough to compare handles.
*/
TypHandle FindRecname ( name )
char name [];
{
TypHandle hd, hdRectab, hd2;
char * p;
unsigned long i, k;
/* Look in the record name table, but where ? */
for ( k = 0, p = name; *p != '\0'; ++p ) k = 65599 * k + *p;
k = k % (SIZE(HdRectab) / SIZE_HD);
/* Look through the table, until you find a free slot or our name */
while ( PTR(HdRectab)[k] != 0
&& SyStrcmp( (char*)(PTR(PTR(HdRectab)[k])), name ) ) {
k = (k + 1) % (SIZE(HdRectab) / SIZE_HD);
}
/* If we found our record name, very good. */
if ( PTR(HdRectab)[k] != 0 ) {
return PTR(HdRectab)[k];
}
/* If we find a free slot, still good. */
hd = NewBag( T_RECNAM, (unsigned long)(SyStrlen(name)+1) );
SyStrncat( (char*)PTR(hd), name, SyStrlen(name) );
PTR(HdRectab)[k] = hd;
++NrRectab;
/* If the record name table isn't overcrowed simply return hd. */
if ( 3 * NrRectab / 2 < SIZE(HdRectab) / SIZE_HD )
return hd;
/* Otherwise enlarge it and rehash all entries. */
hdRectab = NewBag( T_LIST, SIZE(HdRectab) );
for ( i = 0; i < SIZE(hdRectab) / SIZE_HD; ++i ) {
PTR(hdRectab)[i] = PTR(HdRectab)[i];
PTR(HdRectab)[i] = 0;
}
Resize( HdRectab, 2 * SIZE(HdRectab) + SIZE_HD );
for ( i = 0; i < SIZE(hdRectab) / SIZE_HD; ++i ) {
hd2 = PTR(hdRectab)[i];
if ( hd2 == 0 ) continue;
for ( k = 0, p = (char*)PTR(hd2); *p != '\0'; ++p )
k = 65599 * k + *p;
k = k % (SIZE(HdRectab) / SIZE_HD);
while ( PTR(HdRectab)[k] != 0 )
k = (k + 1) % (SIZE(HdRectab) / SIZE_HD);
PTR(HdRectab)[k] = hd2;
}
return hd;
}
/****************************************************************************
**
*F completion( <name>, <len> ) . . . . . . . . find the completions of name
*/
unsigned long iscomplete ( name, len, rn )
char * name;
unsigned long len;
unsigned long rn;
{
char * curr;
unsigned long i, k;
TypHandle hdTab;
if ( ! rn ) hdTab = HdIdenttab;
else hdTab = HdRectab;
for ( i = 0; i < SIZE(hdTab)/SIZE_HD; i++ ) {
if ( PTR(hdTab)[i] == 0 ) continue;
if ( ! rn ) curr = (char*)(PTR(PTR(hdTab)[i])+1);
else curr = (char*)(PTR(PTR(hdTab)[i]));
for ( k = 0; name[k] != 0 && curr[k] == name[k]; k++ ) ;
if ( k == len && curr[k] == '\0' ) return 1;
}
return 0;
}
unsigned long completion ( name, len, rn )
char * name;
unsigned long len;
unsigned long rn;
{
char * curr, * next;
unsigned long i, k;
TypHandle hdTab;
if ( ! rn ) hdTab = HdIdenttab;
else hdTab = HdRectab;
next = 0;
for ( i = 0; i < SIZE(hdTab)/SIZE_HD; i++ ) {
if ( PTR(hdTab)[i] == 0 ) continue;
if ( ! rn ) curr = (char*)(PTR(PTR(hdTab)[i])+1);
else curr = (char*)(PTR(PTR(hdTab)[i]));
for ( k = 0; name[k] != 0 && curr[k] == name[k]; k++ ) ;
if ( k < len || curr[k] <= name[k] ) continue;
if ( next != 0 ) {
for ( k = 0; curr[k] != '\0' && curr[k] == next[k]; k++ ) ;
if ( k < len || next[k] < curr[k] ) continue;
}
next = curr;
}
if ( next != 0 ) {
for ( k = 0; next[k] != '\0'; k++ )
name[k] = next[k];
name[k] = '\0';
}
return next != 0;
}
/****************************************************************************
**
*F InitIdents() . . . . . . . . . . . . . . . initialize identifier package
**
** 'InitIdents' initializes the identifier package. This must be done before
** the first call to 'FindIdent' or 'FindRecname', i.e., before the
** evaluator packages are initialized.
*/
void InitIdents ()
{
HdIdenttab = NewBag( T_LIST, 997 * SIZE_HD );
HdRectab = NewBag( T_LIST, 997 * SIZE_HD );
HdStack = NewBag( T_LIST, 1024 * SIZE_HD );
}
/****************************************************************************
**
*E Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables
**
** Local Variables:
** mode: outline
** outline-regexp: "*A\\|*F\\|*V\\|*T\\|*E"
** fill-column: 73
** fill-prefix: "** "
** eval: (local-set-key "\t" 'c-indent-command)
** eval: (local-set-key ";" 'electric-c-semi )
** eval: (local-set-key "{" 'electric-c-brace)
** eval: (local-set-key "}" 'electric-c-brace)
** eval: (hide-body)
** End:
*/
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.