varmgrc.c
上传用户:xiaoan1112
上传日期:2013-04-11
资源大小:19621k
文件大小:63k
源码类别:

操作系统开发

开发平台:

Visual C++

  1. /*** 
  2. *varmgrc.c - Variable Manager for the BASIC 5.0 Interpreter
  3. *
  4. *  Copyright <C> 1985, Microsoft Corporation
  5. *
  6. *Purpose:
  7. *  Includes code for:
  8. *     - creating and searching for variables
  9. *     - creating and searching for user-defined types
  10. *  Includes a description of namespaces in BASIC.
  11. *
  12. **************************************************************************/
  13. /*
  14. The matrix given below is a representation of the namespaces in BASIC.
  15. Each class of names is listed on both the vertical and horizontal axis';
  16. X's in a square indicate that the two classes share a namespace (and
  17. could thus have name conflicts), while blanks in a square indicates that
  18. the two classes have separate namespaces.
  19. An astrisk ('*') (shown on vertical axis only) indicates that
  20. a type character included at the end of the name counts as
  21. part of the name for determining uniqueness.
  22. NOTE: This is a copy of the identical table in basic40.doc. If there's
  23.       any conflict between this table and that one, the one in basic40.doc
  24.       takes precedence.
  25.            COM  LAB  DEF  SUB  FUNC Type Elem Sclr typd Arry typd Const
  26.            Blk        Fn                           Sclr      Arry
  27.           |    |    |    |    |    |    |    |    |    |    |    |    |
  28.         ---------------------------------------------------------------
  29. COMMON Blk| XX |    |    |    |    |    |    |    |    |    |    |    |
  30.           | XX |    |    |    |    |    |    |    |    |    |    |    |
  31.         ---------------------------------------------------------------
  32. Label     |    | XX |    |    |    |    |    |    |    |    |    |    |
  33.           |    | XX |    |    |    |    |    |    |    |    |    |    |
  34.         ---------------------------------------------------------------
  35. DEF Fn*   |    |    | XX | XX | XX |    |    | XX | XX | XX | XX | XX |
  36.           |    |    | XX | XX | XX |    |    | XX | XX | XX | XX | XX |
  37.         ---------------------------------------------------------------
  38. SUB       |    |    | XX | XX | XX |    |    | XX | XX | XX | XX | XX |
  39.           |    |    | XX | XX | XX |    |    | XX | XX | XX | XX | XX |
  40.         ---------------------------------------------------------------
  41. FUNCTION  |    |    | XX | XX | XX |    |    | XX | XX | XX | XX | XX |
  42.           |    |    | XX | XX | XX |    |    | XX | XX | XX | XX | XX |
  43.         ---------------------------------------------------------------
  44. Type      |    |    |    |    |    | XX |    |    |    |    |    |    |
  45.           |    |    |    |    |    | XX |    |    |    |    |    |    |
  46.         ---------------------------------------------------------------
  47. Element   |    |    |    |    |    |    | XX |    |    |    |    |    |
  48.           |    |    |    |    |    |    | XX |    |    |    |    |    |
  49.         ---------------------------------------------------------------
  50. Scaler*   |    |    | XX | XX | XX |    |    | XX | XX |    |    | XX |
  51.           |    |    | XX | XX | XX |    |    | XX | XX |    |    | XX |
  52.         ---------------------------------------------------------------
  53. typed     |    |    | XX | XX | XX |    |    | XX | XX |    |    | XX |
  54.   Scaler  |    |    | XX | XX | XX |    |    | XX | XX |    |    | XX |
  55.         ---------------------------------------------------------------
  56. Array*    |    |    | XX | XX | XX |    |    |    |    | XX | XX |    |
  57.           |    |    | XX | XX | XX |    |    |    |    | XX | XX |    |
  58.         ---------------------------------------------------------------
  59. typed     |    |    | XX | XX | XX |    |    |    |    | XX | XX |    |
  60.   Array   |    |    | XX | XX | XX |    |    |    |    | XX | XX |    |
  61.         ---------------------------------------------------------------
  62. Const     |    |    | XX | XX | XX |    |    | XX | XX |    |    | XX |
  63.           |    |    | XX | XX | XX |    |    | XX | XX |    |    | XX |
  64.         ---------------------------------------------------------------
  65. */
  66. #include "version.h"
  67. #if !HEAP_H
  68. #include "heap.h"
  69. #endif
  70. #if !CONINT_H
  71. #include "conint.h"
  72. #endif
  73. #if !CONTEXT_H
  74. #include "context.h"
  75. #endif
  76. #if !VARIABLE_H
  77. #include "variable.h"
  78. #endif
  79. #if !QBIMSGS_H
  80. #include "qbimsgs.h"
  81. #endif
  82. #if !NAMES_H
  83. #include "names.h"
  84. #endif
  85. #if !UTIL_H
  86. #include "util.h"
  87. #endif
  88. #if !EXECUTOR_H
  89. #include "executor.h"
  90. #endif
  91. #if !PARSER_H
  92. #include "parser.h"
  93. #endif
  94. #if !TXTMGR_H
  95. #include "txtmgr.h"
  96. #endif
  97. #if !SCANNER_H
  98. #include "scanner.h"
  99. #endif
  100. /* forward reference of functions used only locally */
  101. ushort   NEAR     CreateVar(ushort, ushort);
  102. boolean  FAR      ModSharedChk(VOID);
  103. void     NEAR     ReDirect(VOID);
  104. ushort   NEAR     StdSearch(VOID);
  105. STATICF(VOID) AdjustStatChain(var *, ushort, ushort);
  106. STATICF(ushort) GrowBdVar(ushort);
  107. ushort NEAR FuncSearch(void);
  108. ushort NEAR GetDefaultType(char);
  109. extern   ushort oNamOfPrsCur;    /* set in ssrude.asm                         */
  110. VOID     FAR      B_ISdUpd(sd *, ushort);
  111.                                  /* runtime entry point to update moving sd's */
  112. VOID     FAR      B_IAdUpd(ad *, ushort);
  113.                                  /* runtime entry point to update moving ad's */
  114. /* varmgr-specific data */
  115. ushort  vm_oVarCur;                 /* offset to current variable table entry */
  116. var *vm_pVarCur;                    /* only guaranteed to be setup immediately
  117.                                        after a search or variable creation    */
  118. ushort vm_oVarTmp;                  /* temporary var entry offset             */
  119. boolean vm_fVarFound;               /* return value from var search routines.
  120.                                        note that, if vm_fVarFound is TRUE, the 
  121.                                        offset to the found var will be in 
  122.                                        vm_oVarCur (a static, also used in 
  123.                                        variable creation).                    */
  124. ushort vm_fPVCur;                   /* currently searching tPV if TRUE        */
  125. STATICV uchar nm_mask;              /* mask to apply to tNam flag for variable*/
  126. STATICV ushort errVal;              /* error return - used for those cases
  127.                                        which must return some other value
  128.                                        (such as routines invoked via
  129.                                         ForEachPrsInMrs ...)                  */
  130. STATICV boolean fConvtdToFun;       /* used by FuncSearch to communicate the
  131.                                        fact that it converted an existing
  132.                                        entry to be a FUNCTION entry.          */
  133. /*##############################################################################
  134. #                                                                              #
  135. #                        Variable Storage Scheme                               #
  136. #                                                                              #
  137. ##############################################################################*/
  138. /* 
  139. Variables are stored as follows:
  140.       There is one physical variable table per module, and one logical table
  141.       per procedure and module. This is accomplished by having one hash table
  142.       per logical table, all inter-woven in the physical table.
  143.       Each hash table is initialized to zeros, and contains a fixed number
  144.       of fields, each of which is an offset into the physical table to the
  145.       first variable in a chain of variables that hash to the same hash table
  146.       entry.  The hashing function is based on the name table offset (oNam)
  147.       for the variable.   Note that module hash tables are larger than proc.
  148.       hash tables, in anticipation of more variables per module than per
  149.       procedure (i.e., to help give us reasonable search speed for module
  150.       variables).  As of this writing (Aug. '87), there are 16 hash chains 
  151.       per module hash table, and 8 per procedure hash table.
  152.       The links in each hash chain are (physical) variable table offsets to
  153.       the next variable entry in the chain.  The end-of-chain marker is
  154.       EITHER a 0 or a 1 - - - this is because we also store a flag in the
  155.       low bit of the hash link (we use every bit we can get ...).
  156.       Since variables cannot be dynamically removed and/or reused (i.e.,
  157.       one can unlink an entry, but then that space is dead), variable
  158.       entries and hash tables go into the physical table in whatever order 
  159.       they are encountered.
  160. Variable Entries:
  161.       A variable entry looks like one of the below:
  162.                   If oTyp is User-              If oTyp is I2, I4,
  163.                   Defined or a Fixed            R4, R8, or Sd. oTyp
  164.                   Length String                 is stored in low 3
  165.                                                 bits of flags field
  166.                   +----------------+      
  167.   |   oTyp/cbFS    |
  168.                   +----------------+            +----------------+
  169.                   |      oNam      |            |      oNam      |
  170.                   +----------------+            +----------------+ 
  171.                   |   oHashLink    |            |   oHashLink    |
  172.                   +----------------+            +----------------+
  173.                   |     flags      |            |     flags      |
  174.                   +----------------+            +----------------+
  175.           pVar--->+     value      |    pVar--->|     value      |
  176.                   |                |            |                |
  177.                   +----------------+            +----------------+
  178.       The value field is of variable length, depending on what the variable
  179.       represents. The flag bits allow determination of size and use of the
  180.       value field for any given variable.
  181.       All variable entries are of even size, and must fall on even byte
  182.       boundaries, for 2 reasons:
  183.          (1) The runtime requires SD's to fall on even byte boundaries
  184.          (2) We store a flag bit in the low byte of the oHashLink field,
  185.                so each oVar must be even.
  186.                                                                               */
  187. /*##############################################################################
  188. #                                                                              #
  189. #                        Variable Creation                                     #
  190. #                                                                              #
  191. ##############################################################################*/
  192. /***
  193. *GrowBdVar(cbGrowVar) - grow variable table
  194. *Purpose:
  195. *  Given an amount by which we wish to grow the active variable table,
  196. *  grow it if possible, returning FALSE if successful or an error code if not.
  197. *
  198. *  In the event that grs.otxCONT != UNDEFINED, don't call BdGrowVar; instead,
  199. *  succeed if sufficient space exists between cbLogical and cbPhysical, fail
  200. *  otherwise, returning ER_CN.
  201. *Entry:
  202. *  cbGrowVar - number of bytes we wish to grow mrsCur.bdVar by.
  203. *Exit:
  204. *  FALSE if successful, in which case mrsCur.bdVar.cbLogical is increased by
  205. *     cbGrowVar
  206. *  Otherwise, returns an error code for use by CreateVar, below.
  207. *******************************************************************************/
  208. STATICF(ushort) GrowBdVar(cbGrowVar)
  209. ushort cbGrowVar;
  210.    {
  211.    /* [13] ensure that oVar < 0x8000       */
  212.    if ((mrsCur.bdVar.cbLogical + VAR_STRUCT_SIZE + 2) > 0x7FFF) /* [13]       */
  213.       return (PRS_ER_RE | ER_OM);    /* [13] out of memory      */
  214.    if (grs.otxCONT == UNDEFINED) {                 /* user can't CONTinue     */
  215.       if (!BdGrowVar(&mrsCur.bdVar, cbGrowVar))
  216.          return (PRS_ER_RE | ER_OM);               /* out of memory           */
  217.       }
  218.    else {            
  219.       /* user is able to CONTinue; fail unless space already exists in table  */
  220.       REG1 ushort temp = mrsCur.bdVar.cbLogical + cbGrowVar;
  221.       if (temp > mrsCur.bdVar.cbPhysical) {    /* would have to actually  */
  222.    /* grow table       */
  223.          DbAssert(!(mkVar.flags2 & MV_fTrashTable))
  224.          return (0x8000 | ER_CN);
  225.          }
  226.       else 
  227.          mrsCur.bdVar.cbLogical = temp;            /* success.                */
  228.       }
  229.    return(FALSE); 
  230.    }
  231. /***
  232. *CreateVar(oPVHash, varFlags) - create a new variable
  233. *Purpose:
  234. *  Create a new variable in the mrsCur.bdVar. If 'oPVHASH' is UNDEFINED, 
  235. *  create it in the tMV, else, use the offset to the tPV hash table.
  236. *  
  237. *Entry:
  238. *  oPVHash - UNDEFINED if we're to create var in the tMV, or an offset
  239. *              into mrsCur.bdVar to the hash table for the tPV.
  240. *  varFlags  - Initial settings for the flags word in the new var entry.
  241. *              FVFNNAME, FVFUN, FVCOMMON, FVFORMAL, FVDECLDVAR, FVSHARED, 
  242. *              FVCONST, and FVSTATIC are to be set correctly; FVARRAY & 
  243. *              FVINDEXED will frequently be correct, but may be changed 
  244. *              based on other flags settings; FVVALUESTORED is to
  245. *              be pathologically set to TRUE on input, while 
  246. *              FVEVEREXPLICIT, and FVREDIRECT are to be set FALSE.
  247. *  mkVar - global structure containing MakeVariable inputs for oNam,
  248. *              oTyp, and a(nother) flags word.
  249. *
  250. *  NOTE: All variables are created on even-byte boundaries. This
  251. *        guarantees, in turn, that the value fields of all variables will
  252. *        start on even byte boundaries. We ensure this primarily by the
  253. *        structure definitions in variable.h/.inc.  The primary reason for
  254. *        this is that the shared runtime assumes (and requires) that all
  255. *        string descriptors be on even byte boundaries.
  256. *
  257. *Exit:
  258. *  return value is an error code; either zero is returned (no error),
  259. *  or the same error code as is used by MakeVariable is returned (see
  260. *  MakeVariable, below).
  261. *
  262. *  Also sets module static vm_oVarCur to the offset into mrsCur.bdVar
  263. *  to the new entry, and vm_pVarCur to point to the entry.
  264. *
  265. *Exceptions:
  266. *  none.
  267. *
  268. *******************************************************************************/
  269. ushort NEAR CreateVar(oPVHash, varFlags)
  270. ushort oPVHash;
  271. ushort varFlags;
  272.    {
  273.    var *pVar;
  274.    ushort inFlags = mkVar.flags;      /* put MakeVariable callers flags
  275. word in a register       */
  276.    ushort cbValue = 0;
  277.    ushort cbOTyp;
  278.    ushort *pHash;
  279.    uchar  nmsp_type;
  280.    ushort temp;
  281.    ushort entryFlags;      /* [11] use this to build up
  282. [11] the flags word for entry */
  283.    ushort oPrsRef;      /* [11] 0 or oPrs for function
  284. [11] ref       */
  285.    /* if caller to MakeVariable really wanted just a search without modifying
  286.       the variable table, return Internal Error code to indicate that the
  287.       search failed                                                           */
  288.    if (mkVar.flags2 & MV_fDontCreate)
  289.       return (PRS_ER_RP | ER_IER);
  290.    /* The following assertion is made because (if for no other reason ...)
  291.       we assume that the user can still CONTinue if he asks to add a variable
  292.       but we return ER_CN and he backs out of the edit                        */
  293.    DbAssertIf(mkVar.flags & !(FVCOMMON | FVFNNAME | FVFUNCTION), 
  294.                                           !(mkVar.flags2 & MV_fTrashTable))
  295.    if ((mkVar.oTyp == UNDEFINED) && !(mkVar.flags & FVASCLAUSE))
  296.                                     /* reference to a record prior to ...AS...*/
  297.       return (PRS_ER_RP | MSG_BadElemRef); /* [9] */
  298.    /* The following assertion is based on the fact that we're using
  299.       grs.oRsCur in the case that we CAN continue to see if there's an active
  300.       frame on the stack for the active procedure - if so, we return ER_CN    */
  301.    DbAssertIf(oPVHash != UNDEFINED, 
  302.                ((grs.oRsCur & 0x8000) && (prsCur.oVarHash == oPVHash)))
  303.    if ((oPVHash != UNDEFINED) && 
  304.        (grs.otxCONT != UNDEFINED) && 
  305.        !(varFlags & (FVSTATIC | FVSHARED | FVCONST)))
  306.       if (FindORsFrame())           /* TRUE if this proc has an active frame  */
  307.  return (0x8000 | ER_CN);   /* allow the user to back out of edit     */
  308.    oPrsRef = 0;      /* [11] initialize       */
  309.    entryFlags = varFlags & ~0x07;
  310.    if (inFlags & (FVFORCEARRAY | FVINDEXED))
  311.       if (varFlags & FVFUN)
  312.  entryFlags |= FVINDEXED;
  313.       else {
  314.  entryFlags |= (FVARRAY | FVINDEXED);
  315.          /* set the dimension count; if input of zero, assume 1 - - - will end
  316.             up giving Rude Edit later if this turns out to have been wrong    */
  317.          if ((mkVar.cDimensions == 0) && !(inFlags & FVCOMMON))
  318.             cbValue = sizeof(dm);
  319.             /* NOTE: we if a dimension count wasn't specified on a COMMON
  320.                      statement for an array, the execute scanner depends on
  321.                      the cDims field in the variable entry being 0;
  322.                      we depend on that for STATIC arrays, in StdSearch        */
  323.          if ((inFlags & FVSTATIC) && (mkVar.cDimensions > 8))
  324.             return (PRS_ER_RE | MSG_SubCnt); /* 'Wrong number of subscripts'  */
  325.          }
  326.    
  327.    if (!(inFlags & FVIMPLICIT))           /* if pathological input was wrong  */
  328.       entryFlags |= FVEVEREXPLICIT;
  329.                                                       
  330.    inFlags = entryFlags;      /* now use flags as passed BY MakeVariable      */
  331.    /* initialize cbValue for static variable case, to save code later on      */
  332.    cbValue += (inFlags & FVARRAY) ? (sizeof(aStat) + - sizeof(oneChar) +
  333.      sizeof(dm) * mkVar.cDimensions) :
  334.     (mkVar.oTyp == ET_FS ? mkVar.fsLength :
  335.      CbTyp(mkVar.oTyp));
  336.    nmsp_type = NMSP_Variable; /* assume we're not creating a FUNCTION, or 
  337.                                  DEF FN entry                                 */
  338.    if (inFlags & 
  339.       (FVFORMAL | FVCOMMON | FVSTATIC | FVFUNCTION | FVSHARED | FVCONST)) {
  340.       if (inFlags & (FVFORMAL | FVCOMMON | FVFUNCTION)) {
  341.          if (inFlags & FVCOMMON) {
  342.     entryFlags &= ~FVVALUESTORED;    /* set that bit to FALSE   */
  343.     cbValue = (inFlags & FVARRAY ? sizeof(aCom) : sizeof(comRef));
  344.             if (inFlags & FVSHARED)
  345.                nm_mask |= NM_fShared;
  346.             }
  347.          else {                                    /* not COMMON -            */
  348.     cbValue = sizeof(ushort);
  349.             if (inFlags & FVFUNCTION) {
  350.                nmsp_type = 0;                      /* don't set any name table
  351.                                                       bits                    */
  352.                if ((oPVHash == UNDEFINED) && (mkVar.flags & FVFUNCTION))
  353.                   nm_mask |= NM_fShared;           /* set tNam entry flag  */
  354.                if (mkVar.flags & FVLVAL)           /* retval                  */
  355.   entryFlags &= ~FVVALUESTORED;    /* set to FALSE for retval */
  356.        else {
  357.   if ((oPrsRef =
  358.                      PrsRef(mkVar.oNam,
  359.                             (uchar)((mkVar.flags & FVFUNCTION) ? 
  360.                                        PT_FUNCTION : PT_DEFFN),
  361.     mkVar.oTyp)) & 0x8000) /* [16] function not found */
  362.                      return (PRS_ER_RP | ER_UF);   /* 'Undefined Function'    */
  363.                   }
  364.                }
  365.             else {   /* FVFORMAL */
  366.        entryFlags &= ~FVVALUESTORED;    /* set that bit to FALSE   */
  367.                if (inFlags & FVARRAY)
  368.   cbValue = sizeof(aFormal);
  369.                }  
  370.             }  /* else - not COMMON */
  371.          }  /* if FORMAL, COMMON, DEF FN, or FUNCTION */
  372.       else                                         /* STATIC,SHARED, or CONST */
  373.          if (inFlags & FVSHARED) {
  374.             if (oPVHash == UNDEFINED)              /* entry going in the tMV  */
  375.                nm_mask |= NM_fShared;
  376.             else {   /* entry going in tPV */
  377.        entryFlags &= ~FVVALUESTORED;    /* set to FALSE */
  378.        cbValue = sizeof(ushort);
  379.                }
  380.             }  /* if SHARED */
  381.          else if (inFlags & FVCONST) {
  382.             if (oPVHash == UNDEFINED)              /* entry going in the tMV  */
  383.                nm_mask = NM_fShared;               /* Always set fShared bit
  384.                                                       so constants are found  */
  385.             }
  386.       }  /* if special case flag is set */
  387.    else {
  388.       if ((grs.oPrsCur != UNDEFINED) && (prsCur.procType == PT_DEFFN))
  389.          oPVHash = UNDEFINED;    /* var ref. belongs in the tMV for DEF's     */
  390.       if ((oPVHash != UNDEFINED) && (!(prsCur.flags & FP_STATIC))) {
  391.  entryFlags &= ~FVVALUESTORED;   /* actual value not stored in entry */
  392.          if (inFlags & FVARRAY)
  393.     cbValue = sizeof(aFrame);
  394.          else
  395.     cbValue = sizeof(ushort);    /* size of a frame offset  */
  396.          }
  397.       }  /* no special case flag was set */
  398.    cbValue = ((++cbValue) >> 1) << 1;              /* round up cbValue, to 
  399.                                                       ensure even-byte vars. 
  400.                                                       Note that this MUST be
  401.                                                       done in case of odd-sized
  402.                                                       user-defined types or 
  403.       fixed-length strings.   */
  404.    cbOTyp = ((mkVar.oTyp > ET_MAX) || (mkVar.oTyp == ET_FS)) ?
  405.   sizeof(ushort) : 0;
  406.    vm_oVarCur = mrsCur.bdVar.cbLogical + cbOTyp + VAR_STRUCT_SIZE;    /* [11] */
  407.    /* [11] see if namespace ER_DD error BEFORE we try to grow the var table,
  408.       [11] so we don't ask user if he wants to continue and THEN give error   */
  409.    if (nmsp_type)    /* don't set anything if
  410.                                                       creating a DEF or FUN
  411.                                                       entry (txtmgr does it)  */
  412.       if (CheckONamSpace(mkVar.oNam, nmsp_type))
  413.  return (PRS_ER_RE | ER_DD);    /* duplicate definition    */
  414.    temp = cbValue + cbOTyp + VAR_STRUCT_SIZE;
  415.    if (temp < cbValue) /* [12] 64k wrap occurred       */
  416.       return (PRS_ER_RE | ER_OM); /* [12] out of memory       */
  417.    if (temp = GrowBdVar(temp))
  418.       return (temp);
  419.    pVar = (var *)(mrsCur.bdVar.pb + vm_oVarCur); /* in case table moved    */
  420.    ZeroFill((char *)pVar, cbValue);
  421.    if (cbOTyp) {       /* oTyp > ET_MAX */
  422.       if (mkVar.oTyp == ET_FS) {
  423.   *((ushort *)((char *)pVar + VAR_cbFixed)) = mkVar.fsLength;
  424.   entryFlags |= mkVar.oTyp;
  425.       }
  426.       else
  427.   *((ushort *)((char *)pVar + VAR_oTyp)) = mkVar.oTyp;
  428.       }
  429.    else
  430.       entryFlags |= mkVar.oTyp;
  431.    
  432.    ONamOf(pVar) = mkVar.oNam;    /* [11]       */
  433.    FlagsOf(pVar) = entryFlags;    /* [11] set entry flags    */
  434.    ValueOf(pVar, oPrs) = oPrsRef;    /* [11] oPrs or zero       */
  435.    if (nmsp_type) {                                /* don't set anything if
  436.                                                       creating a DEF or FUN
  437.                                                       entry (txtmgr does it)  */
  438.       if (SetONamSpace(mkVar.oNam, nmsp_type))
  439.  ;    /* [11] CheckONamSpace will
  440.       [11] already have caught
  441.       [11] error, if any      */
  442.       }
  443.    mrsCur.oPastLastVar = mrsCur.bdVar.cbLogical;   /* can always trim table 
  444.                                                       back to oPastLastVar and
  445.                                                       lose no variables       */
  446.    vm_pVarCur = pVar;                              /* an exit value           */
  447.    /* initialize the dim count if:
  448. the entry is an array AND it's NOT (shared AND in a procedure).
  449. (If an array is shared and in a procedure it doesn't have a cDims
  450. field in the var table entry.  The entry is a near pointer to the
  451. array descriptor defining the array.) */
  452.    if ((FlagsOf(pVar) & FVARRAY) &&
  453.       !((FlagsOf(pVar) & FVSHARED) && (oPVHash != UNDEFINED))) //[17]
  454.       ValueOf(pVar, aryStat.cDims) = mkVar.cDimensions;
  455.                                                    /* this actually sets
  456.                                                       cDims for all arrays    */
  457.    /* now just have to link the new entry in */
  458.    pHash = (ushort *)(mrsCur.bdVar.pb +
  459.                         ((oPVHash == UNDEFINED) ? 
  460.                               (mkVar.oNam & HASH_MV_NAMMASK) : 
  461.                               (oPVHash + (mkVar.oNam & HASH_PV_NAMMASK))));
  462.    if ((*pHash == 0) || (FlagsOf(pVar) & FVDECLDVAR)) {  
  463.       /* link this entry into start of chain */
  464.       OHashLinkOf(pVar) = *pHash;         /* old start of chain in new entry  */
  465.       *pHash = vm_oVarCur;                /* save offset to new entry         */
  466.       }
  467.    else {   /* link this entry into end of chain */
  468.       OHashLinkOf(pVar) = 0;              /* 0 (or 1) indicates end of chain;
  469.                                              UNDEFINED doesn't do it because
  470.                                              we store a flag in the low bit   */
  471.    pVar = (var *)(mrsCur.bdVar.pb + *pHash);    /* point to start of chain */
  472.    while (OHashLinkOf(pVar) > 1)    /* while not end of hash chain    */
  473.       pVar = (var *)(mrsCur.bdVar.pb + (OHashLinkOf(pVar) & 0xFFFE));
  474.       OHashLinkOf(pVar) |= vm_oVarCur;    /* OR this in rather than assign it
  475.                                              to preserve existing flag value  */
  476.       DbAssert(!(vm_oVarCur & 1))         /* we depend on oVars being on even
  477.                                              byte boundaries for this hashlink
  478.                                              bit flag use, and for SD's       */
  479.       }
  480.    return (vm_fVarFound = FALSE);                  /* var created, not found;
  481.                                                       retval says 'no errors' */
  482.    }  /* CreateVar */
  483. /*##############################################################################
  484. #                                                                              #
  485. #                        Variable Searching                                    #
  486. #                                                                              #
  487. ##############################################################################*/
  488. /***
  489. *ReDirect() - unlink entry @ vm_oVarCur, set FVREDIRECT, put vm_oVarTmp in value
  490. *Purpose:
  491. *  'ReDirect' a variable entry, i.e., unlink it from its hash chain, set
  492. *  the FVREDIRECT flag in the entry, and put the offset to the 'real'
  493. *  entry (in vm_oVarTmp) into the value field.
  494. *
  495. *  Redirection is performed whenever an existing entry is made invalid
  496. *  by some new instance of a matching variable, for example, what looked
  497. *  like an array at first encounter might be found to be a FUNCTION at
  498. *  a later encounter - - - all such array entries (in tMV and all tPV's)
  499. *  are redirected to this newly created FUNCTION entry. The scanner
  500. *  can then go through and fix up the pcode for each redirected entry,
  501. *  since we'll put the oVar for the new entry in the redirected entry.
  502. *Entry:
  503. *  vm_fPVCur - module static flag, TRUE if hash table is in tPV, FALSE if tMV.
  504. *  mrsCur.bdVar assumed set up, and if vm_fPVCur is TRUE, prsCur is assumed
  505. *     to be set up, and the oVarHash field to contain an offset into
  506. *     mrsCur.bdVar to the tPV hash table.
  507. *  vm_oVarCur is an offset into mrsCur.bdVar to the entry to be redirected.
  508. *  vm_oVarTmp is an offset into mrsCur.bdVar to the entry it is to be
  509. *     redirected to.
  510. *Exit:
  511. *  none.
  512. *Exceptions:
  513. *  none.
  514. *******************************************************************************/
  515. VOID NEAR ReDirect()
  516.    {
  517.    REG1 var *pVar;                     
  518.    REG2 char *pVarBase = mrsCur.bdVar.pb;
  519.    REG3 ushort *pHash;
  520.    REG4 var *pVarPrev;
  521.    REG5 ushort oHashTmp;
  522.    /*--------------------------------------------------------------------------
  523.    | calculate pointer into hash table to offset to the first entry in the    |
  524.    |  chain; this is just:                                                    |
  525.    |     (base of physical table) + (offset to start of hash table) +         |
  526.    |     (offset into hash table)                                             |
  527.    --------------------------------------------------------------------------*/
  528.    DbAssertIf(vm_fPVCur, prsCur.oVarHash != UNDEFINED)
  529.    pHash = (ushort *)(mrsCur.bdVar.pb +
  530.                      (vm_fPVCur ? 
  531.                            (prsCur.oVarHash + (mkVar.oNam & HASH_PV_NAMMASK)) :
  532.                            (0 + (mkVar.oNam & HASH_MV_NAMMASK))));
  533.    pVar = (var *)(pVarBase + *pHash);           /* point to first entry       */
  534.    if (*pHash == vm_oVarCur)                    /* entry is @ start of chain  */
  535.       *pHash = OHashLinkOf(pVar) & 0xFFFE;      /* unlink first entry         */
  536.    else {
  537.       while ((oHashTmp = OHashLinkOf(pVar) & 0xFFFE) != vm_oVarCur) {
  538.          DbAssert(oHashTmp != 0)                /* better not be end of chain */
  539.          pVar = (var *)(pVarBase + oHashTmp);
  540.          }
  541.       pVarPrev = pVar;                          /* point to entry prior to one
  542.                                                    we wish to unlink          */
  543.       pVar = (var *)(pVarBase + oHashTmp);
  544.       OHashLinkOf(pVarPrev) = OHashLinkOf(pVar);/* unlink the entry           */
  545.       }
  546.    
  547.    /* at this point, pVar points to the entry being redirected                */
  548.    FlagsOf(pVar) |= FVREDIRECT;
  549.    ValueOf(pVar, oMV) = vm_oVarTmp;
  550.    }  /* ReDirect */
  551. /***
  552. *FuncSearch() - search the appropriate hash table for FUNCTION case
  553. *Purpose:
  554. *  Search the appropriate table (tPV or tMV) in the case where we've
  555. *  encountered [DECLARE] FUNCTION.
  556. *Entry:
  557. *  vm_fPVCur - module static flag, TRUE if we're to search tPV, FALSE if tMV.
  558. *  mrsCur.bdVar assumed set up, and if vm_fPVCur is TRUE, prsCur is assumed
  559. *     to be set up, and the oVarHash field is either UNDEFINED (in which
  560. *     case we just return), or contains an offset into mrsCur.bdVar to the 
  561. *     tPV hash table.
  562. *
  563. *  mkVar set up as per MakeVariable (below).
  564. *Exit:
  565. *  FALSE = no error
  566. *  otherwise, the same error code is returned as described for MakeVariable,
  567. *     below.
  568. *  If no error is returned, then the static vm_fVarFound indicates success or
  569. *     failure. 
  570. *  If vm_fVarFound == TRUE, vm_oVarCur is set to the offset into mrsCur.bdVar to
  571. *     the found variable entry, and vm_pVarCur points to the entry.
  572. *  If an existing entry has been converted to a FUNCTION entry by the search,
  573. *     the static flag fConvtdToFun will be set TRUE.
  574. *Exceptions:
  575. *  none.
  576. *******************************************************************************/
  577. ushort NEAR FuncSearch()
  578.    {
  579.    REG1 var *pVar;                     
  580.    REG2 char *pVarBase = mrsCur.bdVar.pb;
  581.    /*--------------------------------------------------------------------------
  582.    | calculate offset into mrsCur.bdVar to first entry in appropriate hash    |
  583.    |  chain; this is the contents of:                                         |
  584.    |     (base of physical table) + (offset to start of hash table) +         |
  585.    |     (offset into hash table)                                             |
  586.    --------------------------------------------------------------------------*/
  587.    REG3 ushort oVar = *(ushort *)(mrsCur.bdVar.pb +
  588.                      (vm_fPVCur ? 
  589.                            (prsCur.oVarHash + (mkVar.oNam & HASH_PV_NAMMASK)) :
  590.                            (0 + (mkVar.oNam & HASH_MV_NAMMASK))));
  591.    fConvtdToFun = vm_fVarFound = FALSE;      /* initialize                    */
  592.    if ((oVar == 0) || (vm_fPVCur && (prsCur.oVarHash == UNDEFINED)))
  593.       return(FALSE);                         /* empty hash chain - not found  */
  594.    for (pVar = (var *)(pVarBase + oVar);     /* loop init.                    */
  595.         pVar != (var *)pVarBase;             /* oVar = 0 ==> end of chain     */
  596.         pVar = (var *)(pVarBase + (OHashLinkOf(pVar) & 0xFFFE))) {   
  597.                                              /* loop re-init   */
  598.       if (mkVar.oNam != ONamOf(pVar))
  599.          continue;
  600.       if (!(FlagsOf(pVar) & FVFUN)) {
  601.          if (FlagsOf(pVar) & (FVFORMAL | FVCOMMON | FVSTATIC | FVCONST |
  602.                                                       FVSHARED | FVDECLDVAR))
  603.             return (PRS_ER_RE | ER_DD);
  604.          if (OTypOf(pVar) != mkVar.oTyp)
  605.             if (FlagsOf(pVar) & FVEVEREXPLICIT)
  606.                return (PRS_ER_RE | ER_DD);
  607.             else {
  608.                DbAssert(mkVar.oTyp <= ET_MAX)
  609.                FlagsOf(pVar) = (FlagsOf(pVar) & ~ 0x07 | mkVar.oTyp);
  610.                }
  611.          fConvtdToFun = TRUE;                /* set flag if converting to FUN */
  612.          ValueOf(pVar, oPrs) = PrsRef(mkVar.oNam, PT_FUNCTION, mkVar.oTyp);
  613.                                              /* set value field               */
  614.          DbAssert(ValueOf(pVar, oPrs) != UNDEFINED)
  615.                                              /* error if prs not found        */
  616.          FlagsOf(pVar) |= (FVFUN | FVDECLDVAR | FVEVEREXPLICIT);
  617.          FlagsOf(pVar) &= ~FVARRAY;
  618.          }  /* if entry flag FVFUN is FALSE */
  619.       if (vm_fVarFound)                      /* is this a second match in the */
  620.          return(PRS_ER_RE | ER_DD);          /*    same chain? If so error    */
  621.       /* now, note that we've found a match and save this oVar, but keep
  622.          looking, in case there's another matching name, which would trigger
  623.          the above error ...                                                  */
  624.       vm_fVarFound = TRUE;
  625.       vm_oVarCur = (char *)pVar - mrsCur.bdVar.pb;
  626.       vm_pVarCur = pVar;
  627.       }  /* while not at end of hash chain */
  628.    return (FALSE);                           /* no errors                     */
  629.    }  /* FuncSearch */
  630. /***
  631. *ModSharedChk() - check tPV for matches to a new module SHARED variable
  632. *Purpose:
  633. *  Check the tPV (of prsCur) for a match to a given (new) module SHARED
  634. *  variable. If a match is found, redirect it, i.e., unlink the tPV entry
  635. *  from its hash chain, set the FVREDIRECT flag in it, and place
  636. *  the offset to the new module SHARED variable in its value field.
  637. *
  638. *  Note: This is now optimized based on the knowledge that it's ONLY used
  639. *        used for FUNCTION declarations or definitions.
  640. *  
  641. *Entry:
  642. *  vm_oVarTmp = offset into mrsCur.bdVar to a new module SHARED variable.
  643. *  vm_fPVCur assumed to be TRUE
  644. *  other inputs set up as for FuncSearch (above)
  645. *Exit:
  646. *  TRUE - no error.
  647. *  FALSE - some error from FuncSearch, assumed to be a rude edit case
  648. *           (so we can count on mrsCur.bdVar being tossed out).
  649. *           In this event, the static variable 'errVal' will be contain the 
  650. *           error return, and (non-RELEASE only) the mkVar.flags2 bit
  651. *           MV_fTrashTable will be set.
  652. *Exceptions:
  653. *  none.
  654. *******************************************************************************/
  655. boolean ModSharedChk()
  656.    {
  657.    if (errVal = FuncSearch()) {
  658.       return(FALSE);                /* some error found - quit looking        */
  659.       }
  660.    if (vm_fVarFound)
  661.       ReDirect();
  662.    return (TRUE);
  663.    }  /* ModSharedChk */
  664. /***
  665. *GetDefaultType - given the logical 1st char of a var name,  get default oTyp
  666. *Purpose:
  667. *  Given the logical first char of a name, return the default oTyp of that name.
  668. *  Note that 'logical first char' implies the third char of a name which starts
  669. *  with 'FN' and the first char of any other name.
  670. *Entry:
  671. *  namChar
  672. *Exit:
  673. *  oTyp
  674. *Exceptions:
  675. *  none.
  676. *
  677. *******************************************************************************/
  678. ushort NEAR GetDefaultType(namChar)
  679. char namChar;
  680.    {
  681.    namChar &= 0xDF;   /* convert to upper case */
  682.    DbAssert ((namChar == ('.' & 0xDF)) ||
  683.              ((namChar >= 'A') && (namChar <= 'Z')));
  684.    return(namChar == ('.' & 0xDF)) ? ET_R4 : (ushort)ps.tEtCur[(namChar) - 'A'];
  685.    } /* GetDefaultType */
  686. /***
  687. *MakeVariable - Search for var, create if req'd, return offset to it
  688. *Purpose:
  689. *  Given a variable encountered by the parser or scanner, search for the
  690. *  variable; if not found (and no error conditions detected), create the
  691. *  variable in the tMV or the appropriate tPV and return an offset into
  692. *  mrsCur.bdVar ('oVar') to the value field in the variable entry; this offset 
  693. *  goes in the pcode stream.
  694. *
  695. *Entry:
  696. *  mrsCur set up; it is assumed that bdVar is a heap owner.
  697. *  prsCur either set up, or grs.oPrsCur is UNDEFINED if no procedure is
  698. *     currently active
  699. *  mkVar.oNam - global name table offset for the name of the input variable
  700. *  mkVar.oTyp - global type table offset for the (perhaps assumed) type of the
  701. *              input variable. In the case of an implicitly typed variable,
  702. *              ET_IMP should be passed; in this instance, MakeVariable will 
  703. *              determine the appropriate default type, based on the oNam.
  704. *              In the case of a reference to a record element, the oTyp of the
  705. *              record variable cannot be set by the caller; in this special 
  706. *              case, mkVar.oTyp must be set to UNDEFINED by the caller.
  707. *  mkVar.flags - global 2-bytes of bit flags used to describe the variable
  708. *              encountered. One byte contains flags which are set in 
  709. *              atypical situations, the other contains flags to be tested
  710. *              in common situations.
  711. *              Note that the FVIMPLICIT and FVFNNAME flags are not inputs,
  712. *              however - - - these can be set or reset on input: MakeVariable
  713. *              (now) sets these based on the oTyp and oNam fields (respectively)
  714. *  mkVar.cDimensions - number of dimensions in an array variable; required
  715. *              for correctly allocating the array descriptor, and setting
  716. *              the dimension count for array variables. Only meaningful
  717. *              when FVINDEXED is set, and FVFUNCTION is not (and the variable
  718. *              name does not start with 'FN') (Note that FVINDEXED is 
  719. *              considered to be set whenever FVFORCEARRAY is set).
  720. *  mkVar.flags2 & MV_fONamInOTyp - set when the oType field is either ET_FS or
  721. *        ET_FT and the fsLength field is the oNam of a CONSTant
  722. *        which gives the length of the fixed length string/text.
  723. *  mkVar.flags2 & MV_fDontCreate - set when MakeVariable is called JUST to 
  724. *              search for an existing variable. Does not create a new variable 
  725. *              if one is not found with this flag set. Non-RELEASE code checks 
  726. *              that no other modification of the variable table takes place 
  727. *              when this is TRUE.
  728. *
  729. *Exit:
  730. *  The return value is an oVar if the high bit (bit 15) is clear, and
  731. *  it's an error code if the high bit is set. 
  732. *
  733. *  If the high bit is not set (and retval is an oVar), if the input mkVar.oTyp 
  734. *  was incorrectly assumed by the caller (i.e., implicitly typed), mkVar.oTyp
  735. *  will contain the correct oTyp on exit. 
  736. *
  737. *  If the high bit is not set, if a CONSTant var entry was found, mkVar.flags2 
  738. *  will have the MV_fConstFound bit set (always reset on exit otherwise).
  739. *
  740. *  If the high bit is set, the LSB is a scanner error code and the MSB
  741. *  minus bit 15 is a parser action code.  The scanner error code is an
  742. *  error which the user will see, whereas the parser action code is an
  743. *  indication to the parser of what action it should take. The codes are 
  744. *  listed below:
  745. *
  746. *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  747. *  |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
  748. *  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
  749. *  | E| P| P| P| P| P| P| P| S| S| S| S| S| S| S| S|
  750. *  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  751. *
  752. *  E - Error indicator (error if set)
  753. *  P - Parser action code - bits set for different codes (includes bit 15 set):
  754. *        PRS_ER_RE - Module Rude Edit
  755. *        PRS_ER_RP - opReParse placed before statement
  756. *  S - Scanner error code - decimal number in LSB (see basicmsg.doc)
  757. *
  758. *  If the return value is an error code, and the mkVar.flags2 MV_fTrashTable
  759. *  bit is set, then the caller MUST take action to 'throw away' mrsCur.bdVar; 
  760. *  this flag set on error return indicates that the table has been modified
  761. *  somehow and cannot be used dependably. 
  762. *  Note that this is a non-RELEASE flag; assertion code is used to ensure
  763. *  that a rude edit error is returned whenever this flag is TRUE.
  764. *
  765. *  Note that ER_IER ('Internal Error') is used to signal the case where
  766. *  the caller had the mkVar.flags2 MV_fDontCreate bit set on input and a 
  767. *  matching entry was not found.
  768. *
  769. *  Note that an oVar (pVar) is not an offset (pointer) to the start (low word)
  770. *  of the appropriate variable entry, rather it's an offset (pointer) to the
  771. *  value field in the entry. Other fields are referenced from a pVar via 
  772. *  negative offsets.
  773. *  
  774. *  On exit, the following input flag bits are reset to FALSE in mkVar.flags:
  775. *     FVASCLAUSE, FVFNNAME, FVFORCEARRAY, FVFUNCTION, FVIMPLICIT,
  776. *     FVINDEXED, FVLVAL, FVCONST 
  777. *  On exit, the MV_fONamInOTyp and MV_fDontCreate bits are always reset in
  778. *     in mkVar.flags2.
  779. *Exceptions:
  780. *  none.
  781. *
  782. *******************************************************************************/
  783. ushort NEAR MakeVariable()
  784.    {
  785.    REG1 ushort flags;
  786.    REG2 var *pVar;
  787.    REG3 ushort retval;
  788.    REG4 ushort createMask;
  789.    REG5 ushort oHashCreate;
  790.    REG6 ushort oNamPrs;
  791.    REG7 ushort namChar;
  792.    REG8 boolean fCreate;                     /* used to signal that we don't
  793.                                                 want to create input variable */
  794.    REG9 ushort inputFlags = mkVar.flags;     /* save input mkVar.flags in case
  795.                                                 we must change them locally   */
  796.    ushort mkVarONam;
  797.    ushort mkVarOTyp;
  798.    uchar mkVarCDims;
  799.    boolean fTemp;
  800.    DbAssert(grs.oMrsCur != UNDEFINED)
  801.    DbChkGrs()                    /* sanity check on grs, mrsCur, and prsCur   */
  802.    if (mkVar.flags2 & MV_fONamInOTyp) {
  803.       mkVarONam = mkVar.oNam;
  804.       mkVarOTyp = mkVar.oTyp;
  805.       mkVarCDims = mkVar.cDimensions;
  806.       /* mkVar.fsLength is really an oNam for a CONSTant. We must search local
  807.          var table for this constant (tMV too if we're at proc level) and
  808.          use it's value to set the input oTyp to the appropriate fixed length 
  809.          string constant                                                      */
  810.       DbChkoNam(mkVar.fsLength)
  811.       mkVar.flags2 &= ~MV_fConstFound;
  812.       mkVar.oNam = mkVar.fsLength;
  813.       mkVar.flags = FVIMPLICIT;
  814.       mkVar.oTyp = ET_I2;                    /* CONSTant MUST be an I2     */
  815.       vm_fPVCur = (grs.oPrsCur != UNDEFINED);
  816.       retval = StdSearch();
  817.       if (!vm_fVarFound && !retval && !(vm_fPVCur = !vm_fPVCur))
  818.          /* if we searched tPV and didn't find it, better be in tMV        */
  819.          retval = StdSearch();
  820.       /* restore input values of mkVar struct (must do this here so mkVar.flags
  821.          is correct in case of error)                                         */
  822.       mkVar.oNam = mkVarONam;
  823.       mkVar.oTyp = mkVarOTyp;
  824.       mkVar.flags = inputFlags;
  825.       mkVar.cDimensions = mkVarCDims;
  826.       if (retval || !vm_fVarFound || !(mkVar.flags2 & MV_fConstFound) ||
  827.   (OTypOf(vm_pVarCur) != ET_I2) || (ValueOf(vm_pVarCur, I2) <= 0)) {
  828.                retval = PRS_ER_RP | MSG_InvConst;
  829.                goto RetValExit;
  830.                }
  831.       mkVar.fsLength = ValueOf(vm_pVarCur, I2);
  832.       }
  833.    mkVar.flags &= ~(FVFNNAME | FVIMPLICIT);  /* Initialize the flags to FALSE */
  834.    DbAssertIf(mkVar.flags & FVCONST, 
  835.        (mkVar.oTyp != ET_IMP))
  836.    if ((mkVar.oTyp == ET_IMP) || 
  837.          ((mkVar.oTyp == UNDEFINED) && !(mkVar.flags & FVASCLAUSE)))
  838.       mkVar.flags |= FVIMPLICIT;             /* note that an 'UNDEFINED' oTyp
  839.                                                 could really be a fixed-length
  840.                                                 string of maximal (32K) length.
  841.                                                 The FVASCLAUSE bit removes this
  842.                                                 ambiguity                     */
  843.    if ((namChar = GetVarNamChar(mkVar.oNam)) & 0xff00)
  844.       mkVar.flags |= FVFNNAME;               /* get first logical char of name
  845.                                                 in low byte, & fFNnam in high */
  846.    if (vm_fPVCur = (grs.oPrsCur != UNDEFINED)) {
  847.       DbAssert(prsCur.oVarHash != UNDEFINED)
  848.       DbAssert(prsCur.oVarHash < mrsCur.bdVar.cbLogical)
  849.       if (mkVar.flags & FVCOMMON) {
  850.          retval = PRS_ER_RP | MSG_InvProc;
  851.          goto RetValExit;
  852.          }
  853.       oHashCreate = prsCur.oVarHash;
  854.       /* The below is a speed optimization. oNamOfPrsCur is set by the rude 
  855.          scanner to prevent searching the name table for the proc name for
  856.          each variable reference in the procedure.  When we're called by the
  857.          parser, oNamOfPrsCur will be UNDEFINED and we must do it here.       */
  858.       if ((oNamPrs = oNamOfPrsCur) == UNDEFINED)
  859.          oNamPrs = ONamOfOgNam(prsCur.ogNam);/* [4]                           */
  860.       DbAssert(oNamPrs != 0)                 /* [4] ONamOfOgNam CAN'T ret. OM */
  861.       }
  862.    else {                                    /* no prs active                 */
  863.       if (mkVar.flags & FVSTATIC) {
  864.          retval = PRS_ER_RP | MSG_InvModLev;
  865.          goto RetValExit;
  866.          }
  867.       oHashCreate = 
  868.       oNamPrs = UNDEFINED;
  869.       }
  870.    flags = mkVar.flags;          /* put flags word in a register              */
  871.    if ((flags & FVIMPLICIT) && (mkVar.oTyp != UNDEFINED)) 
  872.          mkVar.oTyp = GetDefaultType((char)namChar);  /* set default type     */
  873.    DbMkVarInp()                  /* special validation code for global inputs */
  874.    /*======================================================================
  875.       'createMask' is a mask used to pass to CreateVar - - - the code below
  876.       depends on the fact that most of the variable entry flags correspond
  877.       in position to the MakeVariable input flags ...                
  878.    =======================================================================*/
  879.    createMask = FVVALUESTORED |
  880.                 (flags & ~(FVREDIRECT | FVEVEREXPLICIT | FVDIM | FV_STATICSET));
  881.    
  882.    nm_mask = 0;                              /* initialize                    */
  883.    vm_oVarCur = UNDEFINED;                   /* initialize                    */
  884.    mkVar.flags2 &= ~MV_fConstFound;          /* initialize                    */
  885.    if (!(flags & (FVFORMAL | FVCOMMON | FVSTATIC | FVSHARED | FVFNNAME |
  886.                   FVFUNCTION | FVCONST))) {
  887.       /*==== SEARCHING FOR VARIABLE IN THE TYPICAL CASE ====*/
  888.       if (retval = StdSearch())
  889.          goto RetValExit;                    /* return error code             */
  890.       if (vm_fPVCur) {                       /* a procedure is active         */
  891.          /*====================================================================
  892.          Even though a procedure is active, we must search the tMV as well
  893.          in one of three possible cases:
  894.          1. A match was not found, and the name table entry indicates that
  895.             there is a module shared variable of this oNam.
  896.          2. A match was not found, and the current prs is for a DEF FN.
  897.          3. We've found a retval in the currently active FUNCTION, but input
  898.             FVLVAL is not set, i.e., we've got a case of self-recursion,
  899.             and thus want to find the tMV FUNCTION reference rather than the
  900.             tPV retval. Note that in this case, we KNOW we'll find a match
  901.             in the tMV, as the reference is to the FUNCTION in prsCur.
  902.          ====================================================================*/
  903.          if ((!vm_fVarFound && 
  904.               ((FlagOfONam(mkVar.oNam) & NM_fShared) ||
  905.                (prsCur.procType == PT_DEFFN))) ||
  906.              (vm_fVarFound && !(flags & FVLVAL) && 
  907.               (FlagsOf(vm_pVarCur) & FVFUN) &&
  908.               (mkVar.oNam == oNamPrs) && (prsCur.procType == PT_FUNCTION))) {
  909.             vm_fPVCur = FALSE;               /* search the tMV                */
  910.             if (retval = StdSearch())
  911.                goto RetValExit;              /* return error code             */
  912.             vm_fPVCur = TRUE;                /* reset                         */
  913.             if (vm_fVarFound) {
  914.        pVar = vm_pVarCur;
  915.        /* [10] set temp boolean TRUE if there exists a module-level
  916.   [10] var of this name (not necessarily the var just found!  */
  917.        fTemp = FlagOfONam(mkVar.oNam) & NM_fShared; /* [10]       */
  918.        if (fTemp && !(FlagsOf(pVar) & (FVFUN | FVCONST))) {   /* [10] */
  919.   if (!(FlagsOf(pVar) & FVSHARED))       /* [10] */
  920.       vm_fVarFound = FALSE;  /* [10] not SHARED, so not found */
  921.   }       /* [10] */
  922.        else if (!fTemp && (prsCur.procType != PT_DEFFN))      /* [10] */
  923.       vm_fVarFound = FALSE;  /* if not SHARED, then not found */
  924.                else if ((FlagsOf(pVar) & FVFUN) && (flags & FVLVAL))
  925.                   if ((mkVar.oNam == oNamPrs) && 
  926.                       (prsCur.procType == PT_FUNCTION)) { 
  927.                      /* not found after all - really want to create a retval  */
  928.                      createMask |= (FVFUN | FVDECLDVAR | FVEVEREXPLICIT);
  929.                      vm_fVarFound = FALSE;
  930.                      }
  931.                   else goto RE_DD_Exit;      /* attempt to assign to a Function
  932.                                                 outside of the Function       */
  933.                }  /* if vm_fVarFound */
  934.             }  /* if !vm_fVarFound && tNam entry fShared bit set */
  935.          else if (vm_fVarFound && (FlagsOf(vm_pVarCur) & FVSHARED))
  936.             vm_oVarCur = ValueOf(vm_pVarCur, oMV); 
  937.                                              /* caller doesn't want oVar for 
  938.                                                 the SHARED entry in the tPV,
  939.                                                 he wants the actual tMV entry */
  940.          }
  941.       else                                   /* no procedure is active        */
  942.          if ((flags & FVLVAL) && vm_fVarFound && (FlagsOf(vm_pVarCur) & FVFUN))
  943.             goto RE_DD_Exit;                 /* attempt to assign to a Function
  944.                                                 outside of the Function       */
  945.       if (!vm_fVarFound)
  946.          if (retval = CreateVar(oHashCreate, createMask))
  947.             goto RetValExit;                 /* return error code             */
  948.       }  /* typical case - no special flags set */
  949.    else {
  950.       /*==== SEARCHING FOR SOME SPECIAL VAR (i.e., COMMON, STATIC, etc.) =====*/
  951.       if (flags & (FVFUNCTION | FVFNNAME)) {
  952.          if (flags & FVFUNCTION) {
  953.             DbAssert(vm_fPVCur == FALSE)     /* [DECLARE] FUNCTION only legal
  954.                                                 at module level               */
  955.             if (retval = FuncSearch())
  956.                goto RetValExit;
  957.             pVar = vm_pVarCur;
  958.             if ((!vm_fVarFound) || (fConvtdToFun)) {
  959.                if (!fConvtdToFun)         /* function entry doesn't exist yet */
  960.                   if (retval = CreateVar(UNDEFINED, 
  961.                         createMask | FVDECLDVAR | FVEVEREXPLICIT | FVSHARED))
  962.                      goto RetValExit;     /* return error code */
  963.                if ((NMSP_MASK & FlagOfONam(mkVar.oNam)) == NMSP_Variable) {
  964.                   /* there exists at some non-FUNCTION variable(s) of this 
  965.                      oNam somewhere in mrsCur.bdVar                           */
  966.                   /* now set up inputs for each invocation of ModSharedChk    */
  967.                   vm_fPVCur = TRUE; 
  968.                   vm_oVarTmp = vm_oVarCur;
  969.                   
  970.                   errVal = 0;
  971.                   ForEachPrsInMrs(ModSharedChk);
  972.                
  973.                   /* reset static variables */
  974.                   vm_oVarCur = vm_oVarTmp;
  975.                   vm_fPVCur = FALSE;
  976.                   retval = errVal;
  977.                   FlagsOf(vm_pVarCur) |= FVSHARED;
  978.                   /* remember that an entry of this oNam is module shared: */
  979.                   nm_mask |= NM_fShared;
  980.    
  981.                   if (retval)
  982.                      goto RetValExit;  
  983.                   ResetONamMaskTmp(mkVar.oNam,NMSP_Variable);
  984.                                           /* txtmgr depends on us resetting 
  985.                                              this bit in this case            */
  986.                   }
  987.                }
  988.             }  /* if FVFUNCTION */
  989.          else {                  /* must be FVFNNAME */
  990.             if ((!vm_fPVCur) || (mkVar.oNam != oNamPrs))
  991.                if (mkVar.flags & FVLVAL)
  992.                   goto RE_DD_Exit;          
  993.             if (retval = StdSearch())
  994.                goto RetValExit;              /* return error code             */
  995.             if (!vm_fVarFound) {
  996.                if ((vm_fPVCur) && !(mkVar.flags & FVLVAL)) {
  997.                   vm_fPVCur = FALSE;         /* search the tMV                */
  998.                   if (retval = StdSearch())
  999.                      goto RetValExit;        /* return error code             */
  1000.                   vm_fPVCur = TRUE;          /* reset                         */
  1001.                   }
  1002.                if (!vm_fVarFound)
  1003.                   if (retval = CreateVar(oHashCreate, createMask | FVFUN))
  1004.                      goto RetValExit;        /* return error code             */
  1005.                }
  1006.             }  /* if FVFNNAME */
  1007.          }  /* if FVFUNCTION, of FVFNNAME */
  1008.       else {                                 /* must be FORMAL, STATIC, 
  1009.                                                 COMMON, SHARED, or CONST      */
  1010.          if (retval = StdSearch())
  1011.             goto RetValExit;                 /* return error code             */
  1012.          if (flags & (FVFORMAL | FVSTATIC | FVCONST)) {
  1013.             if (vm_fVarFound)
  1014.                goto RE_DD_Exit;              /* existing var matches formal,
  1015.                                                 static, or const              */
  1016.             if (retval = CreateVar(oHashCreate, createMask))
  1017.                goto RetValExit;              /* return error code             */
  1018.             
  1019.             if ((flags & FVCONST) && !vm_fPVCur) {
  1020.                DbAssert(txdCur.scanState == SS_RUDE)  /* ensure no owners     */
  1021.                FlagsOf(vm_pVarCur) |= FVSHARED;
  1022.                /* remember that an entry of this oNam is module shared: */
  1023.                nm_mask |= NM_fShared;
  1024.                }
  1025.             }  /* if FVFORMAL, FVSTATIC, or FVCONST */
  1026.          else if (flags & FVCOMMON) {
  1027.             fCreate = TRUE;                  /* assume we want to create the
  1028.                                                 variable if not found         */
  1029.             if (vm_fVarFound) {
  1030.                pVar = vm_pVarCur;
  1031.                if (FlagsOf(pVar) & FVARRAY) {
  1032.                   DbAssert(txdCur.scanState == SS_RUDE)  /* ensure no owners  */
  1033.                   FlagsOf(pVar) |= FVCOMMON; /* convert entry to be a COMMON  */
  1034.                   FlagsOf(pVar) &= ~FVVALUESTORED;
  1035.                   fCreate = FALSE;           /* don't want to create too ...  */
  1036.                   }
  1037.        else      /* not an array       */
  1038.   goto RE_DD_Exit;      /* [14]       */
  1039.                }  /* if found */
  1040.             
  1041.             if (fCreate)   
  1042.                if (retval = CreateVar(UNDEFINED, createMask))
  1043.                   goto RetValExit;     /* return error code */
  1044.             if (flags & FVSHARED) {
  1045.                DbAssert(txdCur.scanState == SS_RUDE)  /* ensure no owners     */
  1046.                FlagsOf(vm_pVarCur) |= FVSHARED;
  1047.                /* remember that an entry of this oNam is module shared: */
  1048.                nm_mask |= NM_fShared;
  1049.                }
  1050.             }  /* if FVCOMMON */
  1051.          else {                              /* must be FVSHARED              */
  1052.             DbAssert(flags & FVSHARED)
  1053.             /* NOTE: this case MUST be tested AFTER we check for FVCOMMON     */
  1054.             if (vm_fPVCur) {                 /* active procedure              */
  1055.                if (vm_fVarFound)
  1056.   goto RE_DD_Exit;      /* [14] in case found entry
  1057. [14] contains an owner       */
  1058.                else {                        /* var not found in the tPV      */
  1059.                   vm_fPVCur = FALSE;
  1060.                   if (retval = StdSearch())  /* search tMV                    */
  1061.                      goto RetValExit;
  1062.                   vm_fPVCur = TRUE;          /* reset                         */
  1063.                   if (!vm_fVarFound) {
  1064.                      if (retval = CreateVar(UNDEFINED, createMask & ~FVSHARED))
  1065.                         goto RetValExit;     /* create var a module level     */
  1066.                      }
  1067.                   FlagsOf(vm_pVarCur) |= FVSHARED; /* scanner needs this bit
  1068.                                                       set in module entry.
  1069.                                                       Namespace bit keeps
  1070.                                                       this case straight.     */
  1071.                   vm_oVarTmp = vm_oVarCur;   /* save offset to tMV entry      */
  1072.                   if (retval = CreateVar(prsCur.oVarHash, createMask))
  1073.                      goto RetValExit;        /* return error code             */
  1074.                   pVar = vm_pVarCur;
  1075.                   ValueOf(pVar, oMV) = 
  1076.                   vm_oVarCur = vm_oVarTmp;
  1077.                   }
  1078.                }
  1079.             else {                           /* no proc active - DIM SHARED   */
  1080.                if (!vm_fVarFound)
  1081.                   if (retval = CreateVar(UNDEFINED, createMask))
  1082.                      goto RetValExit;        /* return error code             */
  1083.                /* NOTE: the parser CAN call us here when we're not in SS_RUDE,
  1084.                   NOTE: but the txtmgr guarantees us that if a user enters
  1085.                   NOTE: or modifies a DIM SHARED statement, it will be a rude
  1086.                   NOTE: edit. I.e., we don't need to worry about any proc-level
  1087.                   NOTE: variables here, since the rude scanner scans the
  1088.                   NOTE: module before any of the procedures in the module     */
  1089.                FlagsOf(vm_pVarCur) |= FVSHARED;
  1090.                /* remember that an entry of this oNam is module shared: */
  1091.                nm_mask |= NM_fShared;
  1092.                }
  1093.             }  /* if FVSHARED */
  1094.          }  /* COMMON, SHARED */
  1095.       }  /* some special-case flag(s) is/are set */
  1096.    /* var was either explicitly or implicitly typed; set flag accordingly:    */
  1097.    if (!(flags & FVIMPLICIT))
  1098.       FlagsOf((var *)(mrsCur.bdVar.pb + vm_oVarCur)) |= FVEVEREXPLICIT;
  1099.    if (nm_mask != 0)
  1100.       SetONamMask(mkVar.oNam, nm_mask);      /* don't set name table flag bits
  1101.                                                 until no chance of error      */
  1102.    DbChkoVar(vm_oVarCur)
  1103.    DbChkoTyp(mkVar.oTyp)
  1104.    DbMkVarExit(vm_oVarCur,vm_fVarFound,vm_fPVCur)
  1105.    /* Reset most of the input flags to their default values (FALSE) - - leave
  1106.       the rest as they were on entry                                          */
  1107.    mkVar.exitFlags = mkVar.flags;            /* NOTE: can remove exitFlags
  1108.                                                       when MakeVariable is
  1109.                                                       rewritten in native code*/
  1110.    mkVar.flags = inputFlags & ~(FVFNNAME | FVASCLAUSE | FVIMPLICIT | FVLVAL | 
  1111.      FVFORCEARRAY | FVINDEXED | FVFUNCTION | FVCONST);
  1112.    mkVar.flags2 &= ~(MV_fONamInOTyp | MV_fDontCreate);
  1113.    return(vm_oVarCur);
  1114. RE_DD_Exit:
  1115.    retval = PRS_ER_RE | ER_DD;
  1116. RetValExit:
  1117.    DbMkVarExit(retval,vm_fVarFound,vm_fPVCur)
  1118.    /* Reset most of the input flags to their default values (FALSE) - - leave
  1119.       the rest as they were on entry                                          */
  1120.    mkVar.exitFlags = mkVar.flags;            /* NOTE: can remove exitFlags
  1121.                                                       when MakeVariable is
  1122.                                                       rewritten in native code*/
  1123.    mkVar.flags = inputFlags & ~(FVFNNAME | FVASCLAUSE | FVIMPLICIT | FVLVAL | 
  1124.      FVFORCEARRAY | FVINDEXED | FVFUNCTION | FVCONST);
  1125.    mkVar.flags2 &= ~(MV_fONamInOTyp | MV_fDontCreate);
  1126.    return(retval);
  1127.    }  /* MakeVariable */
  1128. /*##############################################################################
  1129. #                                                                              #
  1130. #                 Call-back code, for when a variable table moves              #
  1131. #                                                                              #
  1132. ##############################################################################*/
  1133. /***
  1134. *AdjustStatChain(pVarTable, oVar, cbAdjust)
  1135. *Purpose:
  1136. *  Adjust the back pointers to AD's and SD's in all static variables in
  1137. *  the current hash chain by cbAdjust bytes.
  1138. *  Note that this code is shared by AdjustMrsVarTable and AdjustPrsVarTable.
  1139. *
  1140. *Entry:
  1141. *  pVarTable is the base pointer for the variable table.
  1142. *  oVar is an offset into a variable table to the first var in a chain.
  1143. *  cbAdjust is an adjustment factor to be added to appropriate backpointers.
  1144. *
  1145. *Exit:
  1146. *  none.
  1147. *
  1148. *Exceptions:
  1149. *  none.
  1150. *
  1151. *******************************************************************************/
  1152. STATICF(VOID) AdjustStatChain(pVarTable, oVar, cbAdjust)
  1153. var *pVarTable;
  1154. REG2 ushort oVar;
  1155. ushort cbAdjust;
  1156.    {
  1157.    REG1 var *pVar;
  1158.    REG3 ushort flags;
  1159.    while (oVar != 0) {
  1160.       pVar = (var *)((char *)pVarTable + oVar);
  1161.       flags = FlagsOf(pVar);
  1162.       oVar = (OHashLinkOf(pVar) & 0xFFFE);
  1163.       if ((flags & FVFUN) || !(flags & FVVALUESTORED))
  1164.          continue;
  1165.       if (flags & FVARRAY) {
  1166.          if ((ValueOf(pVar, aryStat.aryDsc.fFeatures & FADF_SD)) &&
  1167.              (ValueOf(pVar, aryStat.aryDsc.pNext) != NOT_OWNER))
  1168.                   B_IAdUpd(&(ValueOf(pVar, aryStat.aryDsc)), cbAdjust);
  1169.          }
  1170.       else if ((OTypOf(pVar) == ET_SD) && (ValueOf(pVar,sdStr.pb) != NULL)) {
  1171.          B_ISdUpd(&(ValueOf(pVar, sdStr)), cbAdjust);
  1172.          }
  1173.       }  /* while */
  1174.    }  /* AdjustStatChain */
  1175. /***
  1176. *AdjustMrsVarTable(pVarTable, cbAdjust)
  1177. *
  1178. *Purpose:
  1179. *  Adjust the back pointers to AD's and SD's in all static variables in
  1180. *  the tMV by cbAdjust bytes.
  1181. *
  1182. *Entry:
  1183. *  pVarTable is the base pointer for the variable table.
  1184. *  cbAdjust is an adjustment factor to be added to appropriate backpointers.
  1185. *
  1186. *Exit:
  1187. *  none.
  1188. *
  1189. *Exceptions:
  1190. *  none.
  1191. *
  1192. *******************************************************************************/
  1193. VOID NEAR AdjustMrsVarTable(pVarTable, cbAdjust)
  1194. var *pVarTable;
  1195. ushort cbAdjust;
  1196.    {
  1197.    REG1 ushort iHash;
  1198.    REG2 ushort *pHash = (ushort *)pVarTable; /* tMV hash tbl @ start    */
  1199.    for (iHash = 0; iHash < CBINITMVHASH/2; iHash++)
  1200.       AdjustStatChain(pVarTable, *pHash++, cbAdjust);
  1201.    }  /* AdjustMrsVarTable */
  1202. /***
  1203. *AdjustPrsVarTable(pVarTable, oVarHash, cbAdjust)
  1204. *
  1205. *Purpose:
  1206. *  Adjust the back pointers to AD's and SD's in all static variables in
  1207. *  the given tPV by cbAdjust bytes.
  1208. *
  1209. *Entry:
  1210. *  pVarTable is the base pointer for the variable table.
  1211. *  oVarHash is the offset in the variable table to the tPV hash table.
  1212. *  cbAdjust is an adjustment factor to be added to appropriate backpointers.
  1213. *
  1214. *Exit:
  1215. *  none.
  1216. *
  1217. *Exceptions:
  1218. *  none.
  1219. *
  1220. *******************************************************************************/
  1221. VOID NEAR AdjustPrsVarTable(pVarTable, oVarHash, cbAdjust)
  1222. var *pVarTable;
  1223. ushort oVarHash;
  1224. ushort cbAdjust;
  1225.    {
  1226.    REG1 ushort iHash;
  1227.    REG2 ushort *pHash = (ushort *)((char *)pVarTable + oVarHash);
  1228.    
  1229.    if (oVarHash != UNDEFINED)
  1230.       for (iHash = 0; iHash < CBINITPVHASH/2; iHash++)
  1231.          AdjustStatChain(pVarTable, *pHash++, cbAdjust);
  1232.    }  /* AdjustPrsVarTable */