📄 varmgrc.c
字号:
/***
*varmgrc.c - Variable Manager for the BASIC 5.0 Interpreter
*
* Copyright <C> 1985, Microsoft Corporation
*
*Purpose:
* Includes code for:
* - creating and searching for variables
* - creating and searching for user-defined types
* Includes a description of namespaces in BASIC.
*
**************************************************************************/
/*
The matrix given below is a representation of the namespaces in BASIC.
Each class of names is listed on both the vertical and horizontal axis';
X's in a square indicate that the two classes share a namespace (and
could thus have name conflicts), while blanks in a square indicates that
the two classes have separate namespaces.
An astrisk ('*') (shown on vertical axis only) indicates that
a type character included at the end of the name counts as
part of the name for determining uniqueness.
NOTE: This is a copy of the identical table in basic40.doc. If there's
any conflict between this table and that one, the one in basic40.doc
takes precedence.
COM LAB DEF SUB FUNC Type Elem Sclr typd Arry typd Const
Blk Fn Sclr Arry
| | | | | | | | | | | | |
---------------------------------------------------------------
COMMON Blk| XX | | | | | | | | | | | |
| XX | | | | | | | | | | | |
---------------------------------------------------------------
Label | | XX | | | | | | | | | | |
| | XX | | | | | | | | | | |
---------------------------------------------------------------
DEF Fn* | | | XX | XX | XX | | | XX | XX | XX | XX | XX |
| | | XX | XX | XX | | | XX | XX | XX | XX | XX |
---------------------------------------------------------------
SUB | | | XX | XX | XX | | | XX | XX | XX | XX | XX |
| | | XX | XX | XX | | | XX | XX | XX | XX | XX |
---------------------------------------------------------------
FUNCTION | | | XX | XX | XX | | | XX | XX | XX | XX | XX |
| | | XX | XX | XX | | | XX | XX | XX | XX | XX |
---------------------------------------------------------------
Type | | | | | | XX | | | | | | |
| | | | | | XX | | | | | | |
---------------------------------------------------------------
Element | | | | | | | XX | | | | | |
| | | | | | | XX | | | | | |
---------------------------------------------------------------
Scaler* | | | XX | XX | XX | | | XX | XX | | | XX |
| | | XX | XX | XX | | | XX | XX | | | XX |
---------------------------------------------------------------
typed | | | XX | XX | XX | | | XX | XX | | | XX |
Scaler | | | XX | XX | XX | | | XX | XX | | | XX |
---------------------------------------------------------------
Array* | | | XX | XX | XX | | | | | XX | XX | |
| | | XX | XX | XX | | | | | XX | XX | |
---------------------------------------------------------------
typed | | | XX | XX | XX | | | | | XX | XX | |
Array | | | XX | XX | XX | | | | | XX | XX | |
---------------------------------------------------------------
Const | | | XX | XX | XX | | | XX | XX | | | XX |
| | | XX | XX | XX | | | XX | XX | | | XX |
---------------------------------------------------------------
*/
#include "version.h"
#if !HEAP_H
#include "heap.h"
#endif
#if !CONINT_H
#include "conint.h"
#endif
#if !CONTEXT_H
#include "context.h"
#endif
#if !VARIABLE_H
#include "variable.h"
#endif
#if !QBIMSGS_H
#include "qbimsgs.h"
#endif
#if !NAMES_H
#include "names.h"
#endif
#if !UTIL_H
#include "util.h"
#endif
#if !EXECUTOR_H
#include "executor.h"
#endif
#if !PARSER_H
#include "parser.h"
#endif
#if !TXTMGR_H
#include "txtmgr.h"
#endif
#if !SCANNER_H
#include "scanner.h"
#endif
/* forward reference of functions used only locally */
ushort NEAR CreateVar(ushort, ushort);
boolean FAR ModSharedChk(VOID);
void NEAR ReDirect(VOID);
ushort NEAR StdSearch(VOID);
STATICF(VOID) AdjustStatChain(var *, ushort, ushort);
STATICF(ushort) GrowBdVar(ushort);
ushort NEAR FuncSearch(void);
ushort NEAR GetDefaultType(char);
extern ushort oNamOfPrsCur; /* set in ssrude.asm */
VOID FAR B_ISdUpd(sd *, ushort);
/* runtime entry point to update moving sd's */
VOID FAR B_IAdUpd(ad *, ushort);
/* runtime entry point to update moving ad's */
/* varmgr-specific data */
ushort vm_oVarCur; /* offset to current variable table entry */
var *vm_pVarCur; /* only guaranteed to be setup immediately
after a search or variable creation */
ushort vm_oVarTmp; /* temporary var entry offset */
boolean vm_fVarFound; /* return value from var search routines.
note that, if vm_fVarFound is TRUE, the
offset to the found var will be in
vm_oVarCur (a static, also used in
variable creation). */
ushort vm_fPVCur; /* currently searching tPV if TRUE */
STATICV uchar nm_mask; /* mask to apply to tNam flag for variable*/
STATICV ushort errVal; /* error return - used for those cases
which must return some other value
(such as routines invoked via
ForEachPrsInMrs ...) */
STATICV boolean fConvtdToFun; /* used by FuncSearch to communicate the
fact that it converted an existing
entry to be a FUNCTION entry. */
/*##############################################################################
# #
# Variable Storage Scheme #
# #
##############################################################################*/
/*
Variables are stored as follows:
There is one physical variable table per module, and one logical table
per procedure and module. This is accomplished by having one hash table
per logical table, all inter-woven in the physical table.
Each hash table is initialized to zeros, and contains a fixed number
of fields, each of which is an offset into the physical table to the
first variable in a chain of variables that hash to the same hash table
entry. The hashing function is based on the name table offset (oNam)
for the variable. Note that module hash tables are larger than proc.
hash tables, in anticipation of more variables per module than per
procedure (i.e., to help give us reasonable search speed for module
variables). As of this writing (Aug. '87), there are 16 hash chains
per module hash table, and 8 per procedure hash table.
The links in each hash chain are (physical) variable table offsets to
the next variable entry in the chain. The end-of-chain marker is
EITHER a 0 or a 1 - - - this is because we also store a flag in the
low bit of the hash link (we use every bit we can get ...).
Since variables cannot be dynamically removed and/or reused (i.e.,
one can unlink an entry, but then that space is dead), variable
entries and hash tables go into the physical table in whatever order
they are encountered.
Variable Entries:
A variable entry looks like one of the below:
If oTyp is User- If oTyp is I2, I4,
Defined or a Fixed R4, R8, or Sd. oTyp
Length String is stored in low 3
bits of flags field
+----------------+
| oTyp/cbFS |
+----------------+ +----------------+
| oNam | | oNam |
+----------------+ +----------------+
| oHashLink | | oHashLink |
+----------------+ +----------------+
| flags | | flags |
+----------------+ +----------------+
pVar--->+ value | pVar--->| value |
| | | |
+----------------+ +----------------+
The value field is of variable length, depending on what the variable
represents. The flag bits allow determination of size and use of the
value field for any given variable.
All variable entries are of even size, and must fall on even byte
boundaries, for 2 reasons:
(1) The runtime requires SD's to fall on even byte boundaries
(2) We store a flag bit in the low byte of the oHashLink field,
so each oVar must be even.
*/
/*##############################################################################
# #
# Variable Creation #
# #
##############################################################################*/
/***
*GrowBdVar(cbGrowVar) - grow variable table
*Purpose:
* Given an amount by which we wish to grow the active variable table,
* grow it if possible, returning FALSE if successful or an error code if not.
*
* In the event that grs.otxCONT != UNDEFINED, don't call BdGrowVar; instead,
* succeed if sufficient space exists between cbLogical and cbPhysical, fail
* otherwise, returning ER_CN.
*Entry:
* cbGrowVar - number of bytes we wish to grow mrsCur.bdVar by.
*Exit:
* FALSE if successful, in which case mrsCur.bdVar.cbLogical is increased by
* cbGrowVar
* Otherwise, returns an error code for use by CreateVar, below.
*******************************************************************************/
STATICF(ushort) GrowBdVar(cbGrowVar)
ushort cbGrowVar;
{
/* [13] ensure that oVar < 0x8000 */
if ((mrsCur.bdVar.cbLogical + VAR_STRUCT_SIZE + 2) > 0x7FFF) /* [13] */
return (PRS_ER_RE | ER_OM); /* [13] out of memory */
if (grs.otxCONT == UNDEFINED) { /* user can't CONTinue */
if (!BdGrowVar(&mrsCur.bdVar, cbGrowVar))
return (PRS_ER_RE | ER_OM); /* out of memory */
}
else {
/* user is able to CONTinue; fail unless space already exists in table */
REG1 ushort temp = mrsCur.bdVar.cbLogical + cbGrowVar;
if (temp > mrsCur.bdVar.cbPhysical) { /* would have to actually */
/* grow table */
DbAssert(!(mkVar.flags2 & MV_fTrashTable))
return (0x8000 | ER_CN);
}
else
mrsCur.bdVar.cbLogical = temp; /* success. */
}
return(FALSE);
}
/***
*CreateVar(oPVHash, varFlags) - create a new variable
*Purpose:
* Create a new variable in the mrsCur.bdVar. If 'oPVHASH' is UNDEFINED,
* create it in the tMV, else, use the offset to the tPV hash table.
*
*Entry:
* oPVHash - UNDEFINED if we're to create var in the tMV, or an offset
* into mrsCur.bdVar to the hash table for the tPV.
* varFlags - Initial settings for the flags word in the new var entry.
* FVFNNAME, FVFUN, FVCOMMON, FVFORMAL, FVDECLDVAR, FVSHARED,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -