home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 40 / IOPROG_40.ISO / SOFT / NETFrameworkSDK.exe / comsdk.cab / samples1.exe / smc / parser.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  240.0 KB  |  8,776 lines

  1. /*****************************************************************************/
  2.  
  3. #include "smcPCH.h"
  4. #pragma hdrstop
  5.  
  6. /*****************************************************************************/
  7.  
  8. #include "hash.h"
  9. #include "error.h"
  10. #include "scan.h"
  11. #include "parser.h"
  12.  
  13. /*****************************************************************************/
  14.  
  15. #ifdef  DEBUG
  16. static  unsigned    totalLinesCompiled;
  17. #endif
  18.  
  19. /*****************************************************************************/
  20.  
  21. int                 parser::parserInit(Compiler comp)
  22. {
  23.     /* Remember which compiler we belong to */
  24.  
  25.     parseComp = comp;
  26.  
  27.     /* Initialize our private allocator */
  28.  
  29.     if  (parseAllocPriv.nraInit(comp))
  30.         return  1;
  31.  
  32.     /* The following is hokey, fix when symbol table design is more stable */
  33.  
  34. //  parseAllocTemp   = &comp->cmpAllocTemp;
  35.     parseAllocPerm   = &comp->cmpAllocPerm;
  36.  
  37.     /* We're not parsing a text section right now */
  38.  
  39.     parseReadingText = false;
  40.  
  41. #ifdef  DEBUG
  42.     parseReadingTcnt = 0;
  43. #endif
  44.  
  45.     /* We've had no pragma pushes yet */
  46.  
  47.     parseAlignStack  = 0;
  48.     parseAlignStLvl  = 0;
  49.  
  50.     /* All went OK, we're done initializing */
  51.  
  52.     return 0;
  53. }
  54.  
  55. void                parser::parserDone()
  56. {
  57.     assert(parseReadingTcnt == 0);
  58.  
  59. #ifdef  DEBUG
  60. //  if  (totalLinesCompiled) printf("A total of %u lines compiled.\n", totalLinesCompiled);
  61. #endif
  62.  
  63. }
  64.  
  65. /*****************************************************************************
  66.  *
  67.  *  The following routines check for a particular token and error if not found.
  68.  */
  69.  
  70. void                parser::chkCurTok(int tok, int err)
  71. {
  72.     if  (parseScan->scanTok.tok != tok)
  73.         parseComp->cmpError(err);
  74.     else
  75.         parseScan->scan();
  76. }
  77.  
  78. void                parser::chkNxtTok(int tok, int err)
  79. {
  80.     if  (parseScan->scan() != tok)
  81.         parseComp->cmpError(err);
  82.     else
  83.         parseScan->scan();
  84. }
  85.  
  86. /*****************************************************************************
  87.  *
  88.  *  Saves and restores current "using" state.
  89.  */
  90.  
  91. void                parser::parseUsingScpBeg(  OUT usingState REF state, SymDef owner)
  92. {
  93.     /* Save the current "using" state */
  94.  
  95.     state.usUseList = parseCurUseList;
  96.     state.usUseDesc = parseCurUseDesc;
  97.  
  98.     /* Create a new "desc" entry for local refs to use */
  99.  
  100. #if MGDDATA
  101.     parseCurUseDesc = new UseList;
  102. #else
  103.     parseCurUseDesc =    (UseList)parseAllocPerm->nraAlloc(sizeof(*parseCurUseDesc));
  104. #endif
  105.  
  106.     parseCurUseList = NULL;
  107.  
  108.     parseCurUseDesc->ul.ulSym = owner;
  109.     parseCurUseDesc->ulAnchor = true;
  110.     parseCurUseDesc->ulBound  = false;
  111.     parseCurUseDesc->ulNext   = NULL;
  112. }
  113.  
  114. void                parser::parseUsingScpEnd(IN usingState REF state)
  115. {
  116.     UseList         uses;
  117.  
  118.     assert(parseCurUseDesc);
  119.     assert(parseCurUseDesc->ulAnchor);
  120.  
  121.     /* Connect the two lists */
  122.  
  123.     if  (parseCurUseList)
  124.     {
  125.         parseCurUseDesc->ulNext = uses = parseCurUseList;
  126.  
  127.         while (uses->ulNext != NULL)
  128.             uses = uses->ulNext;
  129.  
  130.         uses           ->ulNext = state.usUseDesc;
  131.     }
  132.     else
  133.         parseCurUseDesc->ulNext = state.usUseDesc;
  134.  
  135.     /* Now restore the saved state */
  136.  
  137.     parseCurUseList = state.usUseList;
  138.     parseCurUseDesc = state.usUseDesc;
  139. }
  140.  
  141. /*****************************************************************************
  142.  *
  143.  *  Initialize the "using" logic.
  144.  */
  145.  
  146. void                parser::parseUsingInit()
  147. {
  148.     UseList         uses;
  149.  
  150.     parseCurUseList = NULL;
  151.     parseCurUseDesc = NULL;
  152.  
  153.     assert(parseComp->cmpNmSpcSystem);
  154.  
  155.     parseUsingScpBeg(parseInitialUse, parseComp->cmpGlobalNS);
  156.  
  157. #if MGDDATA
  158.     uses = new UseList;
  159. #else
  160.     uses =    (UseList)parseAllocPerm->nraAlloc(sizeof(*uses));
  161. #endif
  162.  
  163.     uses->ulAll    = true;
  164.     uses->ulAnchor = false;
  165.     uses->ulBound  = true;
  166.     uses->ul.ulSym = parseComp->cmpNmSpcSystem;
  167.     uses->ulNext   = parseCurUseList;
  168.                      parseCurUseList = uses;
  169. }
  170.  
  171. /*****************************************************************************
  172.  *
  173.  *  Finalize the "using" logic.
  174.  */
  175.  
  176. void                parser::parseUsingDone()
  177. {
  178.     if  (parseCurUseDesc)
  179.         parseUsingScpEnd(parseInitialUse);
  180. }
  181.  
  182. /*****************************************************************************
  183.  *
  184.  *  The main entry point into the parser to process all top-level declarations
  185.  *  in the given source text.
  186.  */
  187.  
  188. SymDef              parser::parsePrepSrc(stringBuff         filename,
  189.                                          QueuedFile         fileBuff,
  190.                                          const  char      * srcText,
  191.                                          SymTab             symtab)
  192. {
  193.     nraMarkDsc      allocMark;
  194.  
  195.     SymDef          compUnit = NULL;
  196.     Compiler        ourComp  = parseComp;
  197.  
  198.     parseScan = ourComp->cmpScanner;
  199.  
  200. #ifdef  __SMC__
  201. //  printf("Prepare '%s'\n", filename);
  202. #endif
  203.  
  204.     /*
  205.         Make sure we capture any errors, so that we can release any
  206.         allocated memory and unref any import entries we might ref.
  207.     */
  208.  
  209.     parseAllocPriv.nraMark(&allocMark);
  210.  
  211.     /* Set a trap for any errors */
  212.  
  213.     setErrorTrap(ourComp);
  214.     begErrorTrap
  215.     {
  216.         usingState      useState;
  217.         accessLevels    defAccess;
  218.  
  219.         Scanner         ourScanner = parseScan;
  220.  
  221.         /* Remember which hash/symbol table we'll be using */
  222.  
  223.         parseStab = symtab;
  224.         parseHash = symtab->stHash;
  225.  
  226.         /* Make sure the error logic knows the file we're parsing */
  227.  
  228.         ourComp->cmpErrorSrcf  = filename;
  229.  
  230.         /* Create a comp-unit symbol */
  231.  
  232.         parseCurCmp =
  233.         compUnit    = symtab->stDeclareSym(parseHash->hashString(filename),
  234.                                            SYM_COMPUNIT,
  235.                                            NS_HIDE,
  236.                                            ourComp->cmpGlobalNS);
  237.  
  238.         /* We don't have any local scopes */
  239.  
  240.         parseCurScope = NULL;
  241.  
  242.         /* Save the current "using" state */
  243.  
  244.         parseUsingScpBeg(useState, ourComp->cmpGlobalNS);
  245.  
  246.         /* Declaring types is normally OK */
  247.  
  248.         parseNoTypeDecl = false;
  249.  
  250.         /* Save the source file name */
  251.  
  252.         compUnit->sdComp.sdcSrcFile = compUnit->sdSpelling();
  253.  
  254.         /* Reset the compile-phase value */
  255.  
  256.         ourComp->cmpConfig.ccCurPhase = CPH_START;
  257.  
  258.         /* Get hold of the scanner we're supposed to use */
  259.  
  260.         ourScanner = parseScan;
  261.  
  262.         /* Tell the scanner which parser to refer to */
  263.  
  264.         ourScanner->scanSetp(this);
  265.  
  266.         /* Get the scanner started on our source */
  267.  
  268.         ourScanner->scanStart(compUnit,
  269.                               filename,
  270.                               fileBuff,
  271.                               srcText,
  272.                               symtab->stHash,
  273.                               symtab->stAllocPerm);
  274.         ourScanner->scan();
  275.  
  276.         /* We've processed initial whitespace, set compile-phase value */
  277.  
  278.         ourComp->cmpConfig.ccCurPhase = CPH_PARSING;
  279.  
  280.         /* Find all the namespace and class declarations */
  281.  
  282.         for (;;)
  283.         {
  284. //          unsigned        filepos = ourScanner->scanGetFilePos();
  285.  
  286.             genericBuff     defFpos;
  287.             unsigned        defLine;
  288.  
  289.             bool            saveStyle;
  290.  
  291.             /* Get hold of the default style/alignment we're supposed to use */
  292.  
  293.             parseOldStyle  = ourComp->cmpConfig.ccOldStyle;
  294.             parseAlignment = ourComp->cmpConfig.ccAlignVal;
  295.  
  296.             /* Figure out the default access level */
  297.  
  298.             defAccess      = parseOldStyle ? ACL_PUBLIC
  299.                                            : ACL_DEFAULT;
  300.  
  301.             /* Record the source position of the next declaration */
  302.  
  303.             defFpos = ourScanner->scanGetTokenPos(&defLine);
  304.  
  305.             /* See what kind of a declaration we've got */
  306.  
  307.             switch (ourScanner->scanTok.tok)
  308.             {
  309.                 declMods        mods;
  310.                 declMods        clrm;
  311.  
  312.             case tkCONST:
  313.             case tkVOLATILE:
  314.  
  315.             case tkPUBLIC:
  316.             case tkPRIVATE:
  317.             case tkPROTECTED:
  318.  
  319.             case tkSEALED:
  320.             case tkABSTRACT:
  321.  
  322.             case tkMANAGED:
  323.             case tkUNMANAGED:
  324.  
  325.             case tkMULTICAST:
  326.  
  327.             case tkTRANSIENT:
  328.             case tkSERIALIZABLE:
  329.  
  330.                 parseDeclMods(defAccess, &mods);
  331.  
  332.             DONE_MODS:
  333.  
  334.                 switch (ourScanner->scanTok.tok)
  335.                 {
  336.                 case tkENUM:
  337.                 case tkCLASS:
  338.                 case tkUNION:
  339.                 case tkSTRUCT:
  340.                 case tkINTERFACE:
  341.                 case tkDELEGATE:
  342.                 case tkNAMESPACE:
  343.  
  344.                     parsePrepSym(ourComp->cmpGlobalNS,
  345.                                  mods,
  346.                                  ourScanner->scanTok.tok,
  347.                                  defFpos,
  348.                                  defLine);
  349.                     break;
  350.  
  351.                 default:
  352.  
  353.                     /* This is presumably a generic global declaration */
  354.  
  355.                     if  (ourComp->cmpConfig.ccPedantic)
  356.                         ourComp->cmpError(ERRnoDecl);
  357.  
  358.                     saveStyle = parseOldStyle; parseOldStyle = true;
  359.  
  360.                     parseMeasureSymDef(parseComp->cmpGlobalNS, mods, defFpos,
  361.                                                                      defLine);
  362.  
  363.                     parseOldStyle = saveStyle;
  364.                     break;
  365.                 }
  366.                 break;
  367.  
  368.                 /* The following swallows any leading attributes */
  369.  
  370.             case tkLBrack:
  371.             case tkAtComment:
  372.             case tkCAPABILITY:
  373.             case tkPERMISSION:
  374.             case tkATTRIBUTE:
  375.  
  376.                 for (;;)
  377.                 {
  378.                     switch (ourScanner->scanTok.tok)
  379.                     {
  380.                         AtComment       atcList;
  381.  
  382.                     case tkLBrack:
  383.                         parseBrackAttr(false, ATTR_MASK_SYS_IMPORT|ATTR_MASK_SYS_STRUCT|ATTR_MASK_GUID);
  384.                         continue;
  385.  
  386.                     case tkAtComment:
  387.  
  388.                         for (atcList = ourScanner->scanTok.atComm.tokAtcList;
  389.                              atcList;
  390.                              atcList = atcList->atcNext)
  391.                         {
  392.                             switch (atcList->atcFlavor)
  393.                             {
  394.                             case AC_COM_INTF:
  395.                             case AC_COM_CLASS:
  396.                             case AC_COM_REGISTER:
  397.                                 break;
  398.  
  399.                             case AC_DLL_STRUCT:
  400.                             case AC_DLL_IMPORT:
  401.                                 break;
  402.  
  403.                             case AC_DEPRECATED:
  404.                                 break;
  405.  
  406.                             default:
  407.                                 parseComp->cmpError(ERRbadAtCmPlc);
  408.                                 break;
  409.                             }
  410.                         }
  411.                         ourScanner->scan();
  412.                         break;
  413.  
  414.                     case tkCAPABILITY:
  415.                         parseCapability();
  416.                         break;
  417.  
  418.                     case tkPERMISSION:
  419.                         parsePermission();
  420.                         break;
  421.  
  422.                     case tkATTRIBUTE:
  423.                         unsigned    tossMask;
  424.                         genericBuff tossAddr;
  425.                         size_t      tossSize;
  426.                         parseAttribute(0, tossMask, tossAddr, tossSize);
  427.                         break;
  428.  
  429.                     default:
  430.                         parseDeclMods(defAccess, &mods); mods.dmMod |= DM_XMODS;
  431.                         goto DONE_MODS;
  432.                     }
  433.                 }
  434.  
  435.             case tkENUM:
  436.             case tkCLASS:
  437.             case tkUNION:
  438.             case tkSTRUCT:
  439.             case tkINTERFACE:
  440.             case tkDELEGATE:
  441.             case tkNAMESPACE:
  442.  
  443.                 initDeclMods(&clrm, defAccess);
  444.  
  445.                 parsePrepSym(ourComp->cmpGlobalNS,
  446.                              clrm,
  447.                              ourScanner->scanTok.tok,
  448.                              defFpos,
  449.                              defLine);
  450.                 break;
  451.  
  452.             case tkSColon:
  453.                 ourScanner->scan();
  454.                 break;
  455.  
  456.             case tkEOF:
  457.                 goto DONE_SRCF;
  458.  
  459.             case tkUSING:
  460.                 parseUsingDecl();
  461.  
  462.                 break;
  463.  
  464.             case tkEXTERN:
  465.  
  466.                 if  (ourScanner->scanLookAhead() == tkStrCon)
  467.                 {
  468.                     UNIMPL("process C++ style linkage thang");
  469.                     parseOldStyle = true;
  470.                 }
  471.  
  472.                 // Fall through ....
  473.  
  474.             default:
  475.  
  476.                 /* Don't allow global declarations when pedantic */
  477.  
  478. //              if  (ourComp->cmpConfig.ccPedantic)
  479. //                  ourComp->cmpWarn(WRNglobDecl);
  480.  
  481.                 /* Simply assume that this is a global declaration */
  482.  
  483.                 clrm.dmAcc = defAccess;
  484.                 clrm.dmMod = DM_CLEARED;
  485.  
  486.                 saveStyle = parseOldStyle; parseOldStyle = true;
  487.  
  488.                 parseMeasureSymDef(parseComp->cmpGlobalNS,
  489.                                    clrm,
  490.                                    defFpos,
  491.                                    defLine);
  492.  
  493.                 parseOldStyle = saveStyle;
  494.                 break;
  495.             }
  496.         }
  497.  
  498.     DONE_SRCF:
  499.  
  500. #ifdef DEBUG
  501.         unsigned    lineNo;
  502.         ourScanner->scanGetTokenPos(&lineNo);
  503.         totalLinesCompiled += (lineNo - 1);
  504. #endif
  505.  
  506.         parseUsingScpEnd(useState);
  507.  
  508.         ourScanner->scanClose();
  509.  
  510.         /* End of the error trap's "normal" block */
  511.  
  512.         endErrorTrap(ourComp);
  513.     }
  514.     chkErrorTrap(fltErrorTrap(ourComp, _exception_code(), NULL)) // _exception_info()))
  515.     {
  516.         /* Begin the error trap's cleanup block */
  517.  
  518.         hndErrorTrap(ourComp);
  519.  
  520.         /* Tell the caller that things are hopeless */
  521.  
  522.         compUnit = NULL;
  523.     }
  524.  
  525.     /* Release any memory blocks we may have acquired */
  526.  
  527.     parseAllocPriv.nraRlsm(&allocMark);
  528.  
  529.     /* We're no longer parsing a source file */
  530.  
  531.     ourComp->cmpErrorSrcf = NULL;
  532.  
  533.     return  compUnit;
  534. }
  535.  
  536. /*****************************************************************************
  537.  *
  538.  *  Record source text information about a namespace/class/enum/etc symbol.
  539.  */
  540.  
  541. SymDef              parser::parsePrepSym(SymDef     parent,
  542.                                          declMods   mods,
  543.                                          tokens     defTok, scanPosTP dclFpos,
  544.                                                             unsigned  dclLine)
  545. {
  546.     symbolKinds     defKind;
  547.     symbolKinds     symKind;
  548.     genericBuff     defFpos;
  549.     bool            prefix;
  550.     SymDef          newSym = NULL;
  551.  
  552.     str_flavors     flavor;
  553.     bool            valueTp;
  554.     bool            hasBase;
  555.     bool            managOK;
  556.  
  557.     unsigned        ctxFlag;
  558.  
  559.     bool            mgdSave;
  560.  
  561.     bool            asynch;
  562.  
  563.     SymDef          owner      = parent;
  564.  
  565.     Compiler        ourComp    = parseComp;
  566.     SymTab          ourSymTab  = parseStab;
  567.     Scanner         ourScanner = parseScan;
  568.  
  569.     /* Figure out the management mode (save it first so that it can be restored) */
  570.  
  571.     mgdSave = ourComp->cmpManagedMode;
  572.  
  573.     if  (mods.dmMod & (DM_MANAGED|DM_UNMANAGED))
  574.     {
  575.         ourComp->cmpManagedMode = ((mods.dmMod & DM_MANAGED) != 0);
  576.     }
  577.     else
  578.     {
  579.         /* Is this a declaration at a file/namespace scope level? */
  580.  
  581.         if  (parent == ourComp->cmpGlobalNS || parent->sdSymKind == SYM_NAMESPACE)
  582.         {
  583.             ourComp->cmpManagedMode = !ourComp->cmpConfig.ccOldStyle;
  584.         }
  585.         else
  586.             ourComp->cmpManagedMode = parent->sdIsManaged;
  587.     }
  588.  
  589.     /* Make sure the caller didn't mess up */
  590.  
  591.     assert(parent);
  592.     assert(parent->sdSymKind == SYM_NAMESPACE || parent->sdSymKind == SYM_CLASS);
  593.  
  594.     defTok = ourScanner->scanTok.tok;
  595.  
  596.     /* Are we processing a typedef? */
  597.  
  598.     if  (defTok == tkTYPEDEF || (mods.dmMod & DM_TYPEDEF))
  599.     {
  600.         TypDef          type;
  601.         Ident           name;
  602.  
  603.         unsigned        defLine;
  604.  
  605.         DefList         symDef;
  606.  
  607.         /* Swallow the "typedef" token */
  608.  
  609.         if  (defTok == tkTYPEDEF)
  610.             ourScanner->scan();
  611.  
  612.         switch (ourScanner->scanTok.tok)
  613.         {
  614.             SymDef          tagSym;
  615.  
  616.         case tkSTRUCT:
  617.         case tkUNION:
  618.         case tkENUM:
  619.  
  620.             /* Looks like we have "typedef struct [tag] { ... } name;" */
  621.  
  622.             defFpos = ourScanner->scanGetTokenPos(&defLine);
  623.  
  624.             /* Prevent recursive death */
  625.  
  626.             mods.dmMod &= ~DM_TYPEDEF;
  627.  
  628.             /* Process the underlying type definition */
  629.  
  630.             tagSym = parsePrepSym(parent,
  631.                                   mods,
  632.                                   ourScanner->scanTok.tok,
  633.                                   defFpos,
  634.                                   defLine);
  635.  
  636.             if  (ourScanner->scanTok.tok != tkID)
  637.             {
  638.                 ourComp->cmpError(ERRnoIdent);
  639.             }
  640.             else
  641.             {
  642.                 Ident           name = ourScanner->scanTok.id.tokIdent;
  643.  
  644.                 /* For now we only allow the same name for both tag and typedef */
  645.  
  646.                 if  (tagSym && tagSym->sdName != name)
  647.                     ourComp->cmpGenError(ERRtypedefNm, name->idSpelling(), tagSym->sdSpelling());
  648.  
  649.                 if  (ourScanner->scan() != tkSColon)
  650.                     ourComp->cmpError(ERRnoSemic);
  651.             }
  652.  
  653.             goto EXIT;
  654.         }
  655.  
  656.         defTok  = tkTYPEDEF;
  657.         symKind = SYM_TYPEDEF;
  658.  
  659.         /* Jump to this label for delegates as well */
  660.  
  661.     TDF_DLG:
  662.  
  663.         /* Parse the type specification */
  664.  
  665.         type = parseTypeSpec(&mods, false);
  666.  
  667.         /* Parse the declarator */
  668.  
  669.         name = parseDeclarator(&mods, type, DN_REQUIRED, NULL, NULL, false);
  670.         if  (!name)
  671.             goto EXIT;
  672.  
  673.         /* Look for an existing symbol with a matching name */
  674.  
  675.         if  (parent->sdSymKind == SYM_CLASS)
  676.             newSym = ourSymTab->stLookupScpSym(name,          parent);
  677.         else
  678.             newSym = ourSymTab->stLookupNspSym(name, NS_NORM, parent);
  679.  
  680.         if  (newSym)
  681.         {
  682.             /* Symbol already exists, is it an import? */
  683.  
  684.             if  (newSym->sdIsImport == false    ||
  685.                  newSym->sdSymKind != SYM_CLASS ||
  686.                  newSym->sdClass.sdcFlavor != STF_DELEGATE)
  687.             {
  688.                 parseComp->cmpError(ERRredefName, newSym);
  689.                 goto EXIT;
  690.             }
  691.  
  692.             newSym->sdIsImport            = false;
  693.             newSym->sdClass.sdcMDtypedef  = 0;
  694.             newSym->sdClass.sdcMemDefList = NULL;
  695.             newSym->sdClass.sdcMemDefLast = NULL;
  696.         }
  697.         else
  698.         {
  699.             /* Symbol not known yet, so declare it */
  700.  
  701.             newSym = ourSymTab->stDeclareSym(name, symKind, NS_NORM, parent);
  702.  
  703.             if  (symKind == SYM_CLASS)
  704.             {
  705.                 /* This is a delegate, mark it as such */
  706.  
  707.                 newSym->sdIsManaged       = true;
  708.                 newSym->sdClass.sdcFlavor = STF_DELEGATE;
  709.  
  710.                 /* Mark the delegate as "multicast" if appropriate */
  711.  
  712.                 if  (mods.dmMod & DM_MULTICAST)
  713.                     newSym->sdClass.sdcMultiCast = true;
  714.  
  715.                 /* Create the class type */
  716.  
  717.                 newSym->sdTypeGet();
  718.             }
  719.         }
  720.  
  721.         if  (defTok == tkDELEGATE)
  722.             newSym->sdClass.sdcAsyncDlg = asynch;
  723.  
  724.         /* Remember the access level of the symbol */
  725.  
  726.         newSym->sdAccessLevel = (accessLevels)mods.dmAcc;
  727.  
  728.         /* Allocate a definition descriptor and add it to the symbol's list */
  729.  
  730.         ourScanner->scanGetTokenPos(&defLine);
  731.  
  732.         if  (parent->sdSymKind == SYM_CLASS)
  733.         {
  734.             ExtList         memDef;
  735.  
  736.             symDef =
  737.             memDef = ourSymTab->stRecordMemSrcDef(name,
  738.                                                   NULL,
  739.                                                   parseCurCmp,
  740.                                                   parseCurUseDesc,
  741.                                                   dclFpos,
  742. //                                                ourScanner->scanGetFilePos(),
  743.                                                   defLine);
  744.  
  745.             /* Record the delegate symbol in the entry */
  746.  
  747.             memDef->mlSym  = newSym;
  748.  
  749.             /* Add the delegate to the member list of the class */
  750.  
  751.             ourComp->cmpRecordMemDef(parent, memDef);
  752.         }
  753.         else
  754.         {
  755.             symDef = ourSymTab->stRecordSymSrcDef(newSym,
  756.                                                   parseCurCmp,
  757.                                                   parseCurUseDesc,
  758.                                                   dclFpos,
  759. //                                                ourScanner->scanGetFilePos(),
  760.                                                   defLine);
  761.         }
  762.  
  763.         symDef->dlHasDef = true;
  764.         goto EXIT;
  765.     }
  766.  
  767.     /* We must have a namespace/class/enum definition here */
  768.  
  769.     assert(defTok == tkENUM      ||
  770.            defTok == tkCLASS     ||
  771.            defTok == tkUNION     ||
  772.            defTok == tkSTRUCT    ||
  773.            defTok == tkDELEGATE  ||
  774.            defTok == tkINTERFACE ||
  775.            defTok == tkNAMESPACE);
  776.  
  777.     switch (defTok)
  778.     {
  779.     case tkENUM:
  780.         defKind = SYM_ENUM;
  781.         break;
  782.  
  783.     case tkCLASS:
  784.         ctxFlag = 0;
  785.         flavor  = STF_CLASS;
  786.         defKind = SYM_CLASS;
  787.         valueTp = false;
  788.         managOK = true;
  789.         break;
  790.  
  791.     case tkUNION:
  792.         flavor  = STF_UNION;
  793.         defKind = SYM_CLASS;
  794.         valueTp = true;
  795.         managOK = false;
  796.         break;
  797.  
  798.     case tkSTRUCT:
  799.         flavor  = STF_STRUCT;
  800.         defKind = SYM_CLASS;
  801.         valueTp = true;
  802.         managOK = true;
  803.         break;
  804.  
  805.     case tkINTERFACE:
  806.  
  807. #if 0
  808.  
  809.         /* Disallow interfaces at file scope */
  810.  
  811.         if  (parent == parseComp->cmpGlobalNS)
  812.             parseComp->cmpError(ERRbadGlobInt);
  813.  
  814. #endif
  815.  
  816.         /* Interfaces are never unmanaged */
  817.  
  818.         if  (mods.dmMod & DM_UNMANAGED)
  819.         {
  820.             parseComp->cmpError(ERRbadUnmInt);
  821.             mods.dmMod &= ~DM_UNMANAGED;
  822.         }
  823.  
  824.         flavor  = STF_INTF;
  825.         defKind = SYM_CLASS;
  826.         valueTp = false;
  827.         managOK = true;
  828.         break;
  829.  
  830.     case tkNAMESPACE:
  831.         defKind = SYM_NAMESPACE;
  832.         break;
  833.  
  834.     case tkDELEGATE:
  835.         dclFpos = ourScanner->scanGetFilePos();
  836.         asynch  = false;
  837.         if  (ourScanner->scan() == tkASYNCH)
  838.         {
  839.             asynch = true;
  840.             ourScanner->scan();
  841.         }
  842.         symKind = SYM_CLASS;
  843.         goto TDF_DLG;
  844.  
  845.     default:
  846.         NO_WAY(!"what the?");
  847.     }
  848.  
  849.     hasBase = false;
  850.  
  851. FIND_LC:
  852.  
  853.     /* Process the name of the namespace/class/intf/enum */
  854.  
  855.     switch (ourScanner->scan())
  856.     {
  857.     case tkLCurly:
  858.  
  859.         /* Anonymous type - invent a name for it */
  860.  
  861.         if  (defTok == tkINTERFACE ||
  862.              defTok == tkNAMESPACE || parseComp->cmpConfig.ccPedantic)
  863.         {
  864.             parseComp->cmpError(ERRnoIdent);
  865.         }
  866.  
  867.         newSym = ourSymTab->stDeclareSym(parseComp->cmpNewAnonymousName(),
  868.                                          defKind,
  869.                                          NS_HIDE,
  870.                                          parent);
  871.  
  872.         newSym->sdAccessLevel = (accessLevels)mods.dmAcc;
  873.  
  874.         if  (defKind == SYM_CLASS)
  875.             newSym->sdClass.sdcAnonUnion = true;
  876.  
  877.         break;
  878.  
  879.     case tkLParen:
  880.  
  881.         /* This might a tagged anonymous union */
  882.  
  883.         if  (defTok == tkUNION && parent->sdSymKind == SYM_CLASS)
  884.         {
  885.             if  (ourScanner->scan() != tkID)
  886.             {
  887.                 ourComp->cmpError(ERRnoIdent);
  888.                 UNIMPL(!"recover from error");
  889.             }
  890.  
  891.             if  (ourScanner->scan() != tkRParen)
  892.             {
  893.                 ourComp->cmpError(ERRnoRparen);
  894.                 UNIMPL(!"recover from error");
  895.             }
  896.  
  897.             if  (ourScanner->scan() != tkLCurly)
  898.             {
  899.                 ourComp->cmpError(ERRnoLcurly);
  900.                 UNIMPL(!"recover from error");
  901.             }
  902.  
  903.             /* Declare the anonymous union symbol */
  904.  
  905.             newSym = ourSymTab->stDeclareSym(parseComp->cmpNewAnonymousName(),
  906.                                              SYM_CLASS,
  907.                                              NS_HIDE,
  908.                                              parent);
  909.  
  910.             newSym->sdAccessLevel        = (accessLevels)mods.dmAcc;
  911.             newSym->sdClass.sdcAnonUnion = true;
  912.             newSym->sdClass.sdcTagdUnion = true;
  913.             parent->sdClass.sdcNestTypes = true;
  914.  
  915.             break;
  916.         }
  917.  
  918.         // Fall through ...
  919.  
  920.     default:
  921.  
  922.         for (symKind = SYM_NAMESPACE, prefix = true;;)
  923.         {
  924.             tokens          nextTok;
  925.             Ident           symName;
  926.  
  927.             /* The next token better be a name */
  928.  
  929.             if  (ourScanner->scanTok.tok != tkID)
  930.             {
  931.                 ourComp->cmpError(ERRnoIdent);
  932.                 assert(!"need to skip to semicolon or an outer '{', right?");
  933.             }
  934.             else
  935.             {
  936.                 symName = ourScanner->scanTok.id.tokIdent;
  937.  
  938.                 /* Is this a namespace prefix or the actual name of the symbol? */
  939.  
  940.                 defFpos = ourScanner->scanGetFilePos();
  941.                 nextTok = ourScanner->scanLookAhead();
  942.  
  943.                 if  (nextTok != tkDot && nextTok != tkColon2)
  944.                 {
  945.                     prefix  = false;
  946.                     symKind = defKind;
  947.                 }
  948.                 else
  949.                 {
  950.                     /* Qualified names are only allowed at the outermost level */
  951.  
  952.                     if  (owner != ourComp->cmpGlobalNS)
  953.                     {
  954.                         ourComp->cmpError(ERRbadQualid);
  955.                         UNIMPL("now what?");
  956.                     }
  957.                 }
  958.             }
  959.  
  960.             /* Look for an existing symbol with a matching name */
  961.  
  962.             if  (parent->sdSymKind == SYM_CLASS)
  963.                 newSym = ourSymTab->stLookupScpSym(symName,          parent);
  964.             else
  965.                 newSym = ourSymTab->stLookupNspSym(symName, NS_NORM, parent);
  966.  
  967.             if  (newSym)
  968.             {
  969.                 /* Symbol already exists, make sure it's the right kind */
  970.  
  971.                 if  (newSym->sdSymKindGet() != symKind)
  972.                 {
  973.                     /* This is not legal, issue an error message */
  974.  
  975.                     ourComp->cmpError(ERRredefName, newSym);
  976.  
  977.                     /* Declare a hidden symbol anyway to prevent further blow-ups */
  978.  
  979.                     newSym = ourSymTab->stDeclareSym(symName, symKind, NS_HIDE, parent);
  980.                     goto NEW_SYM;
  981.                 }
  982.                 else
  983.                 {
  984.                     /* Make sure various other attributes agree */
  985.  
  986. #ifdef  DEBUG
  987.                     if  (newSym->sdAccessLevel != (accessLevels)mods.dmAcc && symKind != SYM_NAMESPACE)
  988.                     {
  989.                         printf("Access level changed for '%s', weirdness in metadata?\n", newSym->sdSpelling());
  990.                     }
  991. #endif
  992.  
  993.                     switch (symKind)
  994.                     {
  995.                     case SYM_CLASS:
  996.  
  997.                         /* Make sure the flavor agrees with previous declaration */
  998.  
  999.                         if  (newSym->sdClass.sdcFlavor != (unsigned)flavor)
  1000.                         {
  1001.                             /* Special case: "Delegate" is defined as a class */
  1002.  
  1003.                             if  (flavor == STF_CLASS && newSym->sdClass.sdcFlavor == STF_DELEGATE
  1004.                                                      && newSym->sdClass.sdcBuiltin)
  1005.                             {
  1006.                                 flavor = STF_DELEGATE;
  1007.                                 break;
  1008.                             }
  1009.  
  1010.                             ourComp->cmpGenError(ERRchgClsFlv,
  1011.                                                  newSym->sdSpelling(),
  1012.                                                  symTab::stClsFlavorStr(newSym->sdClass.sdcFlavor));
  1013.                         }
  1014.  
  1015.                         // Fall through, the rest is shared with enum's
  1016.  
  1017.                     case SYM_ENUM:
  1018.  
  1019.                         /* Was there an explicit management specifier? */
  1020.  
  1021.                         if  (mods.dmMod & (DM_MANAGED|DM_UNMANAGED))
  1022.                         {
  1023.                             if  (mods.dmMod & DM_MANAGED)
  1024.                             {
  1025.                                 if  (newSym->sdIsManaged == false)
  1026.                                     ourComp->cmpError(ERRchgMgmt, newSym, parseHash->tokenToIdent(tkUNMANAGED));
  1027.                             }
  1028.                             else
  1029.                             {
  1030.                                 if  (newSym->sdIsManaged != false)
  1031.                                     ourComp->cmpError(ERRchgMgmt, newSym, parseHash->tokenToIdent(tkMANAGED));
  1032.                             }
  1033.                         }
  1034.                         else
  1035.                         {
  1036.                             /* The class/enum will inherit management */
  1037.  
  1038.                             mods.dmMod |= newSym->sdIsManaged ? DM_MANAGED
  1039.                                                               : DM_UNMANAGED;
  1040.                         }
  1041.                         break;
  1042.  
  1043.                     case SYM_NAMESPACE:
  1044.                         break;
  1045.  
  1046.                     default:
  1047.                         NO_WAY(!"unexpected symbol");
  1048.                     }
  1049.                 }
  1050.             }
  1051.             else
  1052.             {
  1053.                 /* Symbol not known yet, declare it */
  1054.  
  1055.                 newSym = ourSymTab->stDeclareSym(symName, symKind, NS_NORM, parent);
  1056.  
  1057.             NEW_SYM:
  1058.  
  1059.                 newSym->sdAccessLevel = (accessLevels)mods.dmAcc;
  1060.  
  1061.                 switch (symKind)
  1062.                 {
  1063.                     bool            manage;
  1064.  
  1065.                 case SYM_NAMESPACE:
  1066.  
  1067.                     newSym->sdNS.sdnSymtab = ourSymTab;
  1068.                     break;
  1069.  
  1070.                 case SYM_CLASS:
  1071.  
  1072.                     if  (mods.dmMod & DM_TRANSIENT)
  1073.                         parseComp->cmpGenWarn(WRNobsolete, "'transient' on a class");
  1074.  
  1075.                     newSym->sdClass.sdcUnsafe   = ((mods.dmMod & DM_UNSAFE   ) != 0);
  1076.                     newSym->sdClass.sdcSrlzable = ((mods.dmMod & DM_SERLZABLE) != 0);
  1077.                     newSym->sdIsAbstract        = ((mods.dmMod & DM_ABSTRACT ) != 0);
  1078.                     newSym->sdIsSealed          = ((mods.dmMod & DM_SEALED   ) != 0);
  1079.  
  1080.                     if  (parent->sdSymKind == SYM_CLASS)
  1081.                          parent->sdClass.sdcNestTypes = true;
  1082.  
  1083.                     break;
  1084.  
  1085.                 case SYM_ENUM:
  1086.  
  1087.                     /* Has explicit management been specified ? */
  1088.  
  1089.                     if  (mods.dmMod & (DM_MANAGED|DM_UNMANAGED))
  1090.                     {
  1091.                         manage = ((mods.dmMod & DM_MANAGED) != 0);
  1092.                     }
  1093.                     else
  1094.                     {
  1095.                         /* By default we inherit management from our parents */
  1096.  
  1097.                         manage = parent->sdIsManaged;
  1098.  
  1099.                         if  (parent->sdSymKind != SYM_CLASS)
  1100.                         {
  1101.                             /* Generally enums in namespaces are managed by default */
  1102.  
  1103.                             manage = true;
  1104.  
  1105.                             /* In global scope choose based on the "old-style" toggle */
  1106.  
  1107.                             if  (parent == parseComp->cmpGlobalNS)
  1108.                             {
  1109.                                 manage = !parseOldStyle;
  1110.                             }
  1111.                         }
  1112.                     }
  1113.  
  1114.                     newSym->sdIsManaged = manage;
  1115.                     break;
  1116.                 }
  1117.             }
  1118.  
  1119.             /* Consume the identifier */
  1120.  
  1121.             ourScanner->scan();
  1122.  
  1123.             /* We're done if we've found the actual symbol name */
  1124.  
  1125.             if  (!prefix)
  1126.                 break;
  1127.  
  1128.             /* The current symbol becomes the new context */
  1129.  
  1130.             parent = newSym;
  1131.  
  1132.             /* Consume the delimiter */
  1133.  
  1134.             ourScanner->scan();
  1135.         }
  1136.  
  1137.         if  (newSym->sdIsImport && newSym->sdSymKind != SYM_NAMESPACE)
  1138.         {
  1139.             assert(newSym->sdCompileState <= CS_DECLARED);  // ISSUE: well, what if?
  1140.             assert(newSym->sdSymKind == SYM_CLASS);
  1141.  
  1142.             newSym->sdIsImport            = false;
  1143.             newSym->sdClass.sdcMDtypedef  = 0;
  1144.             newSym->sdClass.sdcMemDefList = NULL;
  1145.             newSym->sdClass.sdcMemDefLast = NULL;
  1146.         }
  1147.  
  1148.         break;
  1149.  
  1150.     case tkATTRIBUTE:
  1151.  
  1152.         hasBase = true;
  1153.  
  1154.         if  (ourScanner->scanLookAhead() == tkLParen)
  1155.         {
  1156.             ourScanner->scan(); assert(ourScanner->scanTok.tok == tkLParen);
  1157.  
  1158. //          parseComp->cmpGenWarn(WRNobsolete, "class __attribute(AttributeTargets.xxxxx) foo { ... } thingie");
  1159.  
  1160.             if  (ourScanner->scan() != tkRParen)
  1161.             {
  1162.                 parseExprComma();
  1163.                 if  (ourScanner->scanTok.tok != tkRParen)
  1164.                     parseComp->cmpError(ERRnoRparen);
  1165.             }
  1166.             else
  1167.             {
  1168.                 parseComp->cmpError(ERRnoCnsExpr);
  1169.             }
  1170.         }
  1171.         else
  1172.             parseComp->cmpGenWarn(WRNobsolete, "Please switch to the '__attribute(const-expr)' style soon!!!!");
  1173.  
  1174.         goto FIND_LC;
  1175.  
  1176.     case tkAPPDOMAIN:
  1177.  
  1178.         if  (ctxFlag || defTok != tkCLASS)
  1179.             parseComp->cmpError(ERRdupModifier);
  1180.  
  1181.         ctxFlag = 1;
  1182.         hasBase = true;
  1183.         goto FIND_LC;
  1184.  
  1185.     case tkCONTEXTFUL:
  1186.  
  1187.         if  (ctxFlag || defTok != tkCLASS)
  1188.             parseComp->cmpError(ERRdupModifier);
  1189.  
  1190.         ctxFlag = 2;
  1191.         hasBase = true;
  1192.         goto FIND_LC;
  1193.     }
  1194.  
  1195.     /* Figure out and record the source extent of the definition */
  1196.  
  1197.     switch (defKind)
  1198.     {
  1199.         DefList         defRec;
  1200.         TypDef          clsTyp;
  1201.         bool            manage;
  1202.         declMods        memMods;
  1203.  
  1204.     case SYM_CLASS:
  1205.  
  1206.         /* Figure out whether the class is to be managed or unmanaged */
  1207.  
  1208.         if  (mods.dmMod & (DM_MANAGED|DM_UNMANAGED))
  1209.         {
  1210.             if  (mods.dmMod & DM_MANAGED)
  1211.             {
  1212.                 if  (!managOK)
  1213.                     parseComp->cmpWarn(WRNbadMgdStr);
  1214.  
  1215.                 manage = true;
  1216.             }
  1217.             else
  1218.             {
  1219.                 assert(mods.dmMod & DM_UNMANAGED);
  1220.  
  1221.                 manage = false;
  1222.             }
  1223.         }
  1224.         else
  1225.         {
  1226.             /* No explicit management specifier, use default */
  1227.  
  1228.             switch (flavor)
  1229.             {
  1230.             case STF_CLASS:
  1231.             case STF_UNION:
  1232.             case STF_STRUCT:
  1233.  
  1234.                 if  (parent == parseComp->cmpGlobalNS)
  1235.                 {
  1236.                     {
  1237.                         manage = !parseOldStyle;
  1238.                         break;
  1239.                     }
  1240.                 }
  1241.  
  1242.                 if  (parent->sdSymKind == SYM_CLASS)
  1243.                     manage = parent->sdIsManaged;
  1244.                 else
  1245.                     manage = true;
  1246.  
  1247.                 break;
  1248.  
  1249.             case STF_INTF:
  1250.             case STF_DELEGATE:
  1251.                 manage = true;
  1252.                 break;
  1253.  
  1254.             default:
  1255.                 NO_WAY(!"weird flavor");
  1256.             }
  1257.         }
  1258.  
  1259.         /* Remember the management status of the class */
  1260.  
  1261.         newSym->sdIsManaged       =
  1262.         ourComp->cmpManagedMode   = manage;
  1263.  
  1264.         /* Remember the "flavor" of the symbol */
  1265.  
  1266.         newSym->sdClass.sdcFlavor = flavor;
  1267.  
  1268.         /* Create the class type and record whether it's a ref or value type */
  1269.  
  1270.         clsTyp = newSym->sdTypeGet(); assert(clsTyp && clsTyp->tdClass.tdcSymbol == newSym);
  1271.  
  1272.         clsTyp->tdClass.tdcValueType = valueTp;
  1273.  
  1274.         /* Check for a "known" class name */
  1275.  
  1276.         if  (hashTab::getIdentFlags(newSym->sdName) & IDF_PREDEF)
  1277.         {
  1278.             if  (parent == parseComp->cmpNmSpcSystem)
  1279.                 parseComp->cmpMarkStdType(newSym);
  1280.         }
  1281.  
  1282.         /* Is this a generic class declaration? */
  1283.  
  1284.         if  (ourScanner->scanTok.tok == tkLT)
  1285.         {
  1286.             /* This better be a managed class/interface */
  1287.  
  1288.             if  ((newSym->sdClass.sdcFlavor != STF_CLASS &&
  1289.                   newSym->sdClass.sdcFlavor != STF_INTF) || !newSym->sdIsManaged)
  1290.             {
  1291.                 ourComp->cmpError(ERRumgGenCls);
  1292.             }
  1293.  
  1294.             /* This better not be a nested class */
  1295.  
  1296.             if  (parent->sdSymKind != SYM_NAMESPACE)
  1297.                 ourComp->cmpError(ERRgenNested);
  1298.  
  1299.             /* Parse and record the formal parameter list */
  1300.  
  1301.             newSym->sdClass.sdcGeneric = true;
  1302.             newSym->sdClass.sdcArgLst  = parseGenFormals();
  1303.         }
  1304.  
  1305.         /* Does this class implement any interfaces? */
  1306.  
  1307.         if  (ourScanner->scanTok.tok == tkINCLUDES ||
  1308.              ourScanner->scanTok.tok == tkIMPLEMENTS)
  1309.         {
  1310.             clearDeclMods(&memMods);
  1311.  
  1312.             hasBase = true;
  1313.  
  1314.             for (;;)
  1315.             {
  1316.                 ourScanner->scan();
  1317.  
  1318.                 parseTypeSpec(&memMods, false);
  1319.  
  1320.                 if  (ourScanner->scanTok.tok != tkComma)
  1321.                     break;
  1322.             }
  1323.  
  1324.             goto DONE_BASE;
  1325.         }
  1326.  
  1327.         // Fall through ...
  1328.  
  1329.     case SYM_ENUM:
  1330.  
  1331.         if  (ourScanner->scanTok.tok == tkColon)
  1332.         {
  1333.             /* Carefully skip the ": base" part */
  1334.  
  1335.             for (;;)
  1336.             {
  1337.                 switch (ourScanner->scan())
  1338.                 {
  1339.                 case tkPUBLIC:
  1340.                     if  (defKind == SYM_CLASS)
  1341.                     {
  1342.                         ourScanner->scan();
  1343.                         break;
  1344.                     }
  1345.  
  1346.                 case tkPRIVATE:
  1347.                 case tkPROTECTED:
  1348.                     parseComp->cmpError(ERRbadAccSpec);
  1349.                     ourScanner->scan();
  1350.                     break;
  1351.                 }
  1352.  
  1353.                 parseTypeSpec(&memMods, false);
  1354.  
  1355.                 if  (ourScanner->scanTok.tok != tkComma)
  1356.                     break;
  1357.                 if  (defKind != SYM_CLASS || flavor != STF_INTF)
  1358.                     break;
  1359.             }
  1360.  
  1361.             if  ((ourScanner->scanTok.tok == tkINCLUDES ||
  1362.                   ourScanner->scanTok.tok == tkIMPLEMENTS) && defKind == SYM_CLASS)
  1363.             {
  1364.                 if  (hasBase)
  1365.                     parseComp->cmpError(ERRdupIntfc);
  1366.  
  1367.                 for (;;)
  1368.                 {
  1369.                     ourScanner->scan();
  1370.  
  1371.                     parseTypeSpec(&memMods, false);
  1372.  
  1373.                     if  (ourScanner->scanTok.tok != tkComma)
  1374.                         break;
  1375.                 }
  1376.             }
  1377.  
  1378.             hasBase = true;
  1379.         }
  1380.  
  1381.     DONE_BASE:
  1382.  
  1383.         clearDeclMods(&memMods);
  1384.  
  1385.         /* If the name was qualified we may need to insert some "using" entries */
  1386.  
  1387.         if  (newSym->sdParent != owner)
  1388.         {
  1389.             usingState  state;
  1390.  
  1391.             parseInsertUses(state, newSym->sdParent, owner);
  1392.             defRec = parseMeasureSymDef(newSym, memMods, dclFpos, dclLine);
  1393.             parseRemoveUses(state);
  1394.         }
  1395.         else
  1396.         {
  1397.             defRec = parseMeasureSymDef(newSym, memMods, dclFpos, dclLine);
  1398.         }
  1399.  
  1400.         if  (!defRec)
  1401.             goto EXIT;
  1402.  
  1403.         defRec->dlEarlyDecl = (defKind == SYM_ENUM);
  1404.  
  1405.         /* Remember whether we need to re-process the part before the "{" */
  1406.  
  1407.         if  (hasBase || (mods.dmMod & DM_XMODS) || (newSym->sdSymKind == SYM_CLASS &&
  1408.                                                     newSym->sdClass.sdcGeneric))
  1409.         {
  1410.             defRec->dlHasBase = true;
  1411.         }
  1412.         else if (newSym->sdSymKind == SYM_CLASS)
  1413.         {
  1414.             if      (newSym->sdClass.sdcTagdUnion)
  1415.             {
  1416.                 defRec->dlHasBase = true;
  1417.  
  1418.                 if  (ourScanner->scanTok.tok != tkSColon)
  1419.                     ourComp->cmpError(ERRnoSemic);
  1420.             }
  1421.             else if (newSym->sdClass.sdcAnonUnion)
  1422.             {
  1423.                 defRec->dlHasBase   =
  1424.                 defRec->dlAnonUnion = true;
  1425.             }
  1426.         }
  1427.  
  1428.         break;
  1429.  
  1430.     case SYM_NAMESPACE:
  1431.  
  1432.         clearDeclMods(&memMods);
  1433.  
  1434.         newSym->sdIsManaged = ourComp->cmpManagedMode;
  1435.  
  1436.         parseMeasureSymDef(newSym, memMods, dclFpos, dclLine);
  1437.  
  1438.         break;
  1439.  
  1440.     default:
  1441.         NO_WAY(!"what the?");
  1442.     }
  1443.  
  1444. EXIT:
  1445.  
  1446.     /* Restore previous management mode */
  1447.  
  1448.     ourComp->cmpManagedMode = mgdSave;
  1449.  
  1450.     return  newSym;
  1451. }
  1452.  
  1453. /*****************************************************************************
  1454.  *
  1455.  *  A recursive routine that parses qualified names.
  1456.  */
  1457.  
  1458. QualName            parser::parseQualNRec(unsigned depth, Ident name1, bool allOK)
  1459. {
  1460.     Scanner         ourScanner = parseScan;
  1461.  
  1462.     bool            isAll = false;
  1463.  
  1464.     QualName        qual;
  1465.     Ident           name;
  1466.  
  1467.     /* Remember the name */
  1468.  
  1469.     if  (name1)
  1470.     {
  1471.         /* The name was already consumed by the caller */
  1472.  
  1473.         name = name1;
  1474.     }
  1475.     else
  1476.     {
  1477.         /* Remember and consume the name */
  1478.  
  1479.         assert(ourScanner->scanTok.tok == tkID);
  1480.         name = ourScanner->scanTok.id.tokIdent;
  1481.         ourScanner->scan();
  1482.     }
  1483.  
  1484.     /* Is this the end or is there more? */
  1485.  
  1486.     switch(ourScanner->scanTok.tok)
  1487.     {
  1488.     case tkDot:
  1489.     case tkColon2:
  1490.  
  1491.         /* Make sure the right thing follows */
  1492.  
  1493.         switch (ourScanner->scan())
  1494.         {
  1495.         case tkID:
  1496.  
  1497.             /* Recursively process the rest of the name */
  1498.  
  1499.             qual = parseQualNRec(depth+1, NULL, allOK);
  1500.  
  1501.             if  (qual)
  1502.             {
  1503.                 /* Insert our name in the table and return */
  1504.  
  1505.                 assert(depth < qual->qnCount); qual->qnTable[depth] = name;
  1506.             }
  1507.  
  1508.             return  qual;
  1509.  
  1510.         case tkMul:
  1511.             if  (allOK)
  1512.             {
  1513.                 ourScanner->scan();
  1514.                 isAll = true;
  1515.                 break;
  1516.             }
  1517.  
  1518.         default:
  1519.             parseComp->cmpError(ERRnoIdent);
  1520.             return  NULL;
  1521.         }
  1522.     }
  1523.  
  1524.     /* This is the end of the name; allocate the descriptor */
  1525.  
  1526. #if MGDDATA
  1527.     qual = new QualName; qual->qnTable = new Ident[depth+1];
  1528. #else
  1529.     qual =    (QualName)parseAllocPerm->nraAlloc(sizeof(*qual) + (depth+1)*sizeof(Ident));
  1530. #endif
  1531.  
  1532.     qual->qnCount        = depth+1;
  1533.     qual->qnEndAll       = isAll;
  1534.     qual->qnTable[depth] = name;
  1535.  
  1536.     return  qual;
  1537. }
  1538.  
  1539. /*****************************************************************************
  1540.  *
  1541.  *  Process a using declaration.
  1542.  */
  1543.  
  1544. void                parser::parseUsingDecl()
  1545. {
  1546.     QualName        name;
  1547.     UseList         uses;
  1548.     bool            full;
  1549.  
  1550.     assert(parseScan->scanTok.tok == tkUSING);
  1551.  
  1552.     /* Is this "using namespace foo" ? */
  1553.  
  1554.     full = false;
  1555.  
  1556.     if  (parseScan->scan() == tkNAMESPACE)
  1557.     {
  1558.         full = true;
  1559.         parseScan->scan();
  1560.     }
  1561.  
  1562.     /* Make sure the expected identifier is present */
  1563.  
  1564.     if  (parseScan->scanTok.tok != tkID)
  1565.     {
  1566.         parseComp->cmpError(ERRnoIdent);
  1567.         parseScan->scanSkipText(tkNone, tkNone);
  1568.         return;
  1569.     }
  1570.  
  1571.     /* Parse the (possibly qualified) name */
  1572.  
  1573.     name = parseQualName(true);
  1574.  
  1575.     /* Create a "using" entry */
  1576.  
  1577. #if MGDDATA
  1578.     uses = new UseList;
  1579. #else
  1580.     uses =    (UseList)parseAllocPerm->nraAlloc(sizeof(*uses));
  1581. #endif
  1582.  
  1583.     uses->ulAll     = full | name->qnEndAll;
  1584.     uses->ulAnchor  = false;
  1585.     uses->ulBound   = false;
  1586.     uses->ul.ulName = name;
  1587.     uses->ulNext    = parseCurUseList;
  1588.                       parseCurUseList = uses;
  1589.  
  1590.     /* There better be a ";" following the directive */
  1591.  
  1592.     if  (parseScan->scanTok.tok != tkSColon)
  1593.         parseComp->cmpError(ERRnoSemic);
  1594. }
  1595.  
  1596. /*****************************************************************************
  1597.  *
  1598.  *  Save the current "using" state and insert entries for all namespaces that
  1599.  *  lie between the given symbols.
  1600.  */
  1601.  
  1602. void                parser::parseInsertUses(INOUT usingState REF state,
  1603.                                                   SymDef         inner,
  1604.                                                   SymDef         outer)
  1605. {
  1606.     /* Save the current "using" state */
  1607.  
  1608.     state.usUseList = parseCurUseList;
  1609.     state.usUseDesc = parseCurUseDesc;
  1610.  
  1611.     /* Recursively insert all the necessary "using" entries */
  1612.  
  1613.     if  (inner != outer)
  1614.         parseInsertUsesR(inner, outer);
  1615.  
  1616.     parseCurUseList = NULL;
  1617. }
  1618.  
  1619. /*****************************************************************************
  1620.  *
  1621.  *  Add entries for all namespaces up to "inner" to the given use list.
  1622.  */
  1623.  
  1624. UseList             parser::parseInsertUses(UseList useList, SymDef inner)
  1625. {
  1626.     UseList         newList;
  1627.  
  1628.     assert(inner != parseComp->cmpGlobalNS);
  1629.     assert(parseCurUseDesc == NULL);
  1630.  
  1631.     parseCurUseDesc = useList;
  1632.  
  1633.     parseInsertUsesR(inner, parseComp->cmpGlobalNS);
  1634.  
  1635.     newList = parseCurUseDesc;
  1636.               parseCurUseDesc = NULL;
  1637.  
  1638.     return  newList;
  1639. }
  1640.  
  1641. /*****************************************************************************
  1642.  *
  1643.  *  Recursive helper to insert "using" entries between the two namespaces.
  1644.  */
  1645.  
  1646. void                parser::parseInsertUsesR(SymDef inner, SymDef outer)
  1647. {
  1648.     UseList         uses;
  1649.  
  1650.     assert(inner && inner->sdSymKind == SYM_NAMESPACE);
  1651.  
  1652.     if  (inner->sdParent != outer)
  1653.         parseInsertUsesR(inner->sdParent, outer);
  1654.  
  1655.     /* Create a "using" entry */
  1656.  
  1657. #if MGDDATA
  1658.     uses = new UseList;
  1659. #else
  1660.     uses =    (UseList)parseAllocPerm->nraAlloc(sizeof(*uses));
  1661. #endif
  1662.  
  1663.     uses->ulAnchor  = true;
  1664.     uses->ulBound   = true;
  1665.     uses->ul.ulSym  = inner;
  1666.     uses->ulNext    = parseCurUseDesc;
  1667.                       parseCurUseDesc = uses;
  1668. }
  1669.  
  1670. /*****************************************************************************
  1671.  *
  1672.  *  Restore previous "using" state.
  1673.  */
  1674.  
  1675. void                parser::parseRemoveUses(IN usingState REF state)
  1676. {
  1677.     parseCurUseList = state.usUseList;
  1678.     parseCurUseDesc = state.usUseDesc;
  1679. }
  1680.  
  1681. /*****************************************************************************
  1682.  *
  1683.  *  Swallow the definition of the specified symbol (checking for any nested
  1684.  *  members in the process). We record the source text extent of the symbol's
  1685.  *  definition and return after consuming its final token.
  1686.  */
  1687.  
  1688. DefList             parser::parseMeasureSymDef(SymDef sym, declMods  mods,
  1689.                                                            scanPosTP dclFpos,
  1690.                                                            unsigned  dclLine)
  1691. {
  1692.     Compiler        ourComp    = parseComp;
  1693.     SymTab          ourSymTab  = parseStab;
  1694.     Scanner         ourScanner = parseScan;
  1695.  
  1696.     bool            hasBody    = true;
  1697.     bool            isCtor     = false;
  1698.  
  1699.     bool            prefMods   = false;
  1700.  
  1701.     bool            addUses    = false;
  1702.     usingState      useState;
  1703.  
  1704.     declMods        memMod;
  1705.     scanPosTP       memFpos;
  1706.  
  1707.     bool            fileScope;
  1708.  
  1709.     scanPosTP       defEpos;
  1710.  
  1711.     unsigned        defLine;
  1712.  
  1713.     DefList         defRec;
  1714.  
  1715.     accessLevels    acc;
  1716.  
  1717.     /* Remember which symbol we're processing and whether we're at file scope */
  1718.  
  1719.     parseCurSym = sym;
  1720.     fileScope   = (sym == parseComp->cmpGlobalNS);
  1721.  
  1722.     if  (parseOldStyle && fileScope && !(mods.dmMod & (DM_MANAGED|DM_UNMANAGED)))
  1723.     {
  1724.         acc       = ACL_PUBLIC;
  1725.         memMod    = mods;
  1726.         memFpos   = dclFpos;
  1727.         defLine   = dclLine;
  1728. //      defCol    = dclCol;
  1729.  
  1730.         /* Have we already parsed the modifiers? */
  1731.  
  1732.         if  (!(mods.dmMod & DM_CLEARED))
  1733.             goto PARSE_MEM;
  1734.  
  1735.         /* Check for an import declaration */
  1736.  
  1737.         switch (ourScanner->scanTok.tok)
  1738.         {
  1739.         case tkID:
  1740.  
  1741.             /* Check for a ctor */
  1742.  
  1743.             switch (ourScanner->scanLookAhead())
  1744.             {
  1745.             case tkDot:
  1746.             case tkColon2:
  1747.                 if  (parseIsCtorDecl(NULL))
  1748.                 {
  1749.                     isCtor = true;
  1750.                     goto IS_CTOR;
  1751.                 }
  1752.                 break;
  1753.             }
  1754.             break;
  1755.  
  1756.         case tkEXTERN:
  1757.  
  1758.             switch (ourScanner->scanLookAhead())
  1759.             {
  1760.             case tkLParen:
  1761.                 parseBrackAttr(false, 0, &memMod);
  1762.                 prefMods = true;
  1763.                 goto PARSE_MEM;
  1764.  
  1765.             case tkStrCon:
  1766.  
  1767.                 ourComp->cmpWarn(WRNignoreLnk);
  1768.  
  1769.                 ourScanner->scan();
  1770.                 ourScanner->scanTok.tok = tkEXTERN;
  1771.                 break;
  1772.             }
  1773.             break;
  1774.  
  1775.         case tkLBrack:
  1776.             parseBrackAttr(false, ATTR_MASK_SYS_IMPORT|ATTR_MASK_SYS_STRUCT);
  1777.             goto PARSE_MOD;
  1778.  
  1779.         case tkMULTICAST:
  1780.             ourScanner->scan();
  1781.             parseDeclMods(acc, &memMod); memMod.dmMod |= DM_MULTICAST;
  1782.             goto NEST_DEF;
  1783.         }
  1784.  
  1785.         goto PARSE_MOD;
  1786.     }
  1787.  
  1788.     /* Remember where the whole thing starts */
  1789.  
  1790.     ourScanner->scanGetTokenPos(&dclLine);
  1791.  
  1792.     /* Make sure the expected "{" is actually present */
  1793.  
  1794.     if  (ourScanner->scanTok.tok != tkLCurly)
  1795.     {
  1796.         /* Is this a file-scope forward declaration? */
  1797.  
  1798.         if  (ourScanner->scanTok.tok == tkSColon &&
  1799.              sym->sdParent == parseComp->cmpGlobalNS)
  1800.         {
  1801.             hasBody = false;
  1802.             goto DONE_DEF;
  1803.         }
  1804.  
  1805.         /* Well, what the heck is this? */
  1806.  
  1807.         ourComp->cmpError(ERRnoLcurly);
  1808.  
  1809.         if  (ourScanner->scanTok.tok != tkSColon)
  1810.             ourScanner->scanSkipText(tkNone, tkNone);
  1811.  
  1812.         return  NULL;
  1813.     }
  1814.  
  1815.     /* If we're in a namespace, open a new "using" scope */
  1816.  
  1817.     if  (sym->sdSymKind == SYM_NAMESPACE)
  1818.     {
  1819.         addUses = true; parseUsingScpBeg(useState, sym);
  1820.     }
  1821.  
  1822. //  if  (!strcmp(sym->sdSpelling(), "<name>")) forceDebugBreak();
  1823.  
  1824.     /* Now consume the rest of the definition */
  1825.  
  1826.     switch (sym->sdSymKind)
  1827.     {
  1828.     case SYM_ENUM:
  1829.  
  1830.         /* Can't allow two definitions for the same symbol */
  1831.  
  1832.         if  (sym->sdIsDefined)
  1833.             ourComp->cmpError(ERRredefEnum, sym);
  1834.  
  1835.         sym->sdIsDefined = true;
  1836.  
  1837.         /* Simply swallow everything up to the "}" or ";" */
  1838.  
  1839.         ourScanner->scanSkipText(tkLCurly, tkRCurly);
  1840.         break;
  1841.  
  1842.     case SYM_CLASS:
  1843.  
  1844.         /* Can't allow two definitions for the same symbol */
  1845.  
  1846.         if  (sym->sdIsDefined)
  1847.             ourComp->cmpError(ERRredefClass, sym);
  1848.  
  1849.         sym->sdIsDefined = true;
  1850.  
  1851.         /* Record the current default alignment value */
  1852.  
  1853.         sym->sdClass.sdcDefAlign = compiler::cmpEncodeAlign(parseAlignment);
  1854.  
  1855.         /* Make sure the value was recorded correctly */
  1856.  
  1857.         assert(compiler::cmpDecodeAlign(sym->sdClass.sdcDefAlign) == parseAlignment);
  1858.  
  1859.     case SYM_NAMESPACE:
  1860.  
  1861.         /* Swallow the "{" */
  1862.  
  1863.         assert(ourScanner->scanTok.tok == tkLCurly); ourScanner->scan();
  1864.  
  1865.         /* Figure out the default access level */
  1866.  
  1867.         acc = ACL_DEFAULT;
  1868.  
  1869.         if  (parseOldStyle)
  1870.         {
  1871.             acc = ACL_PUBLIC;
  1872.         }
  1873.         else if (sym->sdSymKind == SYM_CLASS &&
  1874.                  sym->sdClass.sdcFlavor == STF_INTF)
  1875.         {
  1876.             acc = ACL_PUBLIC;
  1877.         }
  1878.  
  1879.         /* Process the contents of the class/namespace */
  1880.  
  1881.         while (ourScanner->scanTok.tok != tkEOF &&
  1882.                ourScanner->scanTok.tok != tkRCurly)
  1883.         {
  1884.             tokens          defTok;
  1885.  
  1886.             /* Remember the source position of the member */
  1887.  
  1888.             memFpos = ourScanner->scanGetTokenPos(&defLine);
  1889.  
  1890.             /* See what kind of a member do we have */
  1891.  
  1892.             switch (ourScanner->scanTok.tok)
  1893.             {
  1894.                 TypDef          type;
  1895.                 Ident           name;
  1896.                 QualName        qual;
  1897.                 dclrtrName      nmod;
  1898.  
  1899.                 bool            noMore;
  1900.  
  1901.                 ExtList         memDef;
  1902.  
  1903.                 unsigned        memBlin;
  1904.                 scanPosTP       memBpos;
  1905.                 unsigned        memSlin;
  1906.                 scanPosTP       memSpos;
  1907.  
  1908.             case tkEXTERN:
  1909.  
  1910.                 switch (ourScanner->scanLookAhead())
  1911.                 {
  1912.                 case tkLParen:
  1913.                     parseBrackAttr(false, 0, &memMod);
  1914.                     prefMods = true;
  1915.                     goto PARSE_MEM;
  1916.  
  1917.                 case tkStrCon:
  1918.  
  1919.                     ourComp->cmpWarn(WRNignoreLnk);
  1920.  
  1921.                     ourScanner->scan();
  1922.                     ourScanner->scanTok.tok = tkEXTERN;
  1923.                     break;
  1924.                 }
  1925.  
  1926.                 // Fall through ...
  1927.  
  1928.             default:
  1929.  
  1930.                 /* Must be a "normal" member */
  1931.  
  1932.             PARSE_MOD:
  1933.  
  1934.                 parseDeclMods(acc, &memMod);
  1935.  
  1936.             PARSE_MEM:
  1937.  
  1938. //              static int x; if (++x == 0) forceDebugBreak();
  1939.  
  1940.                 if  (memMod.dmMod & DM_TYPEDEF)
  1941.                 {
  1942.                     defTok = tkTYPEDEF;
  1943.                     goto NEST_DEF;
  1944.                 }
  1945.  
  1946.                 /* Members are only allowed within classes */
  1947.  
  1948.                 if  (sym->sdSymKind == SYM_CLASS)
  1949.                 {
  1950.                     isCtor = false;
  1951.  
  1952.                     if  (sym->sdType->tdClass.tdcFlavor != STF_INTF)
  1953.                     {
  1954.                         isCtor = parseIsCtorDecl(sym);
  1955.  
  1956.                         if  (isCtor)
  1957.                         {
  1958.                             /* Pretend we've parsed a type spec already */
  1959.  
  1960.                         IS_CTOR:
  1961.  
  1962.                             type = sym->sdType;
  1963.                             goto GET_DCL;
  1964.                         }
  1965.  
  1966.                     }
  1967.                 }
  1968.                 else
  1969.                 {
  1970.                     /* We also allow declarations at file scope */
  1971.  
  1972.                     if  (!fileScope)
  1973.                     {
  1974.                         ourComp->cmpError(ERRbadNSmem);
  1975.                         ourScanner->scanSkipText(tkNone, tkNone);
  1976.                         break;
  1977.                     }
  1978.                 }
  1979.  
  1980.                 /* Parse the type specification */
  1981.  
  1982.                 type = parseTypeSpec(&memMod, false);
  1983.  
  1984.             GET_DCL:
  1985.  
  1986.                 /* We have the type, now parse any declarators that follow */
  1987.  
  1988.                 nmod = (dclrtrName)(DN_REQUIRED|DN_QUALOK);
  1989.                 if  (!fileScope)
  1990.                 {
  1991.                     /* We allow interface method implementations to be qualified */
  1992.  
  1993.                     if  (sym->sdSymKind != SYM_CLASS || !sym->sdIsManaged)
  1994.                         nmod = DN_REQUIRED;
  1995.                 }
  1996.  
  1997.                 /*
  1998.                     This is trickier than it may seem at first glance. We need
  1999.                     to be able to process each member / variable individually
  2000.                     later on, but one declaration can declare more than one
  2001.                     member / variable with a single type specifier, like so:
  2002.  
  2003.                         int foo, bar;
  2004.  
  2005.                     What we do is remember where the type specifier ends, and
  2006.                     for each declarator we record how much of the source needs
  2007.                     to be skipped to reach its beginning. This is a bit tricky
  2008.                     because the distance can be arbitrarily large (really) and
  2009.                     we need to be clever about recording it in little space.
  2010.                  */
  2011.  
  2012.                 memBpos = ourScanner->scanGetTokenPos();
  2013.                 memBlin = ourScanner->scanGetTokenLno();
  2014.  
  2015.                 for (;;)
  2016.                 {
  2017.                     bool            memDefd;
  2018.                     bool            memInit;
  2019.  
  2020.                     scanPosTP       memEpos;
  2021.                     scanDifTP       dclDist;
  2022.  
  2023.                     /* Remember where the declarator starts */
  2024.  
  2025.                     memSpos = ourScanner->scanGetTokenPos();
  2026.                     memSlin = ourScanner->scanGetTokenLno();
  2027.  
  2028.                     // UNDONE: Make sure the declaration doesn't span a conditional compilation boundary!
  2029.  
  2030.                     noMore = false;
  2031.  
  2032.                     /* Is this an unnamed bitfield? */
  2033.  
  2034.                     if  (ourScanner->scanTok.tok == tkColon)
  2035.                     {
  2036.                         name = NULL;
  2037.                         qual = NULL;
  2038.                     }
  2039.                     else
  2040.                     {
  2041.                         /* Parse the next declarator */
  2042.  
  2043.                         name = parseDeclarator(&memMod,
  2044.                                                type,
  2045.                                                nmod,
  2046.                                                NULL,
  2047.                                                &qual,
  2048.                                                false);
  2049.  
  2050.                         if  (prefMods)
  2051.                             memMod.dmMod |= DM_XMODS;
  2052.                     }
  2053.  
  2054.                     memEpos = ourScanner->scanGetFilePos();
  2055.  
  2056.                     /* Is there an initializer or method body? */
  2057.  
  2058.                     memDefd = memInit = false;
  2059.  
  2060.                     switch (ourScanner->scanTok.tok)
  2061.                     {
  2062.                     case tkAsg:
  2063.  
  2064.                         /* Skip over the initializer */
  2065.  
  2066.                         ourScanner->scanSkipText(tkLParen, tkRParen, tkComma);
  2067.                         memInit =
  2068.                         memDefd = true;
  2069.                         memEpos = ourScanner->scanGetFilePos();
  2070.                         break;
  2071.  
  2072.                     case tkColon:
  2073.  
  2074.                         /* This could be a base class initializer or a bitfield */
  2075.  
  2076.                         if  (!isCtor)
  2077.                         {
  2078.                             /* Swallow the bitfield specification */
  2079.  
  2080.                             ourScanner->scan();
  2081.                             parseExprComma();
  2082.  
  2083.                             memEpos = ourScanner->scanGetFilePos();
  2084.                             break;
  2085.                         }
  2086.  
  2087.                         /* Presumably we have "ctor(...) : base(...) */
  2088.  
  2089.                         ourScanner->scanSkipText(tkNone, tkNone, tkLCurly);
  2090.  
  2091.                         if  (ourScanner->scanTok.tok != tkLCurly)
  2092.                         {
  2093.                             ourComp->cmpError(ERRnoLcurly);
  2094.                             break;
  2095.                         }
  2096.  
  2097.                         // Fall through ...
  2098.  
  2099.                     case tkLCurly:
  2100.  
  2101.                         parseComp->cmpFncCntSeen++;
  2102.  
  2103.                         /* Skip over the function/property body */
  2104.  
  2105.                         ourScanner->scanSkipText(tkLCurly, tkRCurly);
  2106.                         noMore  = true;
  2107.  
  2108.                         memDefd = true;
  2109.                         memEpos = ourScanner->scanGetFilePos();
  2110.  
  2111.                         if  (ourScanner->scanTok.tok == tkRCurly)
  2112.                             ourScanner->scan();
  2113.  
  2114.                         break;
  2115.                     }
  2116.  
  2117.                     /* Ignore the member if there were really bad errors */
  2118.  
  2119.                     if  (name == NULL && qual == NULL)
  2120.                     {
  2121.                         goto BAD_MEM;
  2122.                     }
  2123.  
  2124.                     /* Add a definition descriptor for the member */
  2125.  
  2126.                     memDef = ourSymTab->stRecordMemSrcDef(name,
  2127.                                                           qual,
  2128.                                                           parseCurCmp,
  2129.                                                           parseCurUseDesc,
  2130.                                                           memFpos,
  2131. //                                                        memEpos,
  2132.                                                           defLine);
  2133.  
  2134. //                  printf("[%08X..%08X-%08X..%08X] Member '%s'\n", memFpos, memBpos, memSpos, memEpos, name->idSpelling());
  2135.  
  2136.                     memDef->dlHasDef     = memDefd;
  2137.                     memDef->dlPrefixMods = ((memMod.dmMod & DM_XMODS) != 0);
  2138.                     memDef->dlIsCtor     = isCtor;
  2139.                     memDef->dlDefAcc     = memMod.dmAcc;
  2140.  
  2141.                     /* Figure out the "distance" to the declarator */
  2142.  
  2143.                     dclDist = ourScanner->scanGetPosDiff(memBpos, memSpos);
  2144.  
  2145.                     if  (dclDist || memBlin != memSlin)
  2146.                     {
  2147.                         NumPair         dist;
  2148.  
  2149.                         /* Try to pack the distance in the descriptor */
  2150.  
  2151.                         if  (memSlin == memBlin && dclDist < dlSkipBig)
  2152.                         {
  2153.                             memDef->dlDeclSkip = dclDist;
  2154.  
  2155.                             /* Make sure the stored value fit in the bitfield */
  2156.  
  2157.                             assert(memDef->dlDeclSkip == dclDist);
  2158.  
  2159.                             goto DONE_SKIP;
  2160.                         }
  2161.  
  2162.                         /* The distance is too far, go to plan B */
  2163.  
  2164. #if MGDDATA
  2165.                         dist = new NumPair;
  2166. #else
  2167.                         dist =    (NumPair)parseAllocPerm->nraAlloc(sizeof(*dist));
  2168. #endif
  2169.                         dist->npNum1 = dclDist;
  2170.                         dist->npNum2 = memSlin - memBlin;
  2171.  
  2172.                         /* Add the number pair to the generic vector */
  2173.  
  2174.                         dclDist = parseComp->cmpAddVecEntry(dist, VEC_TOKEN_DIST) | dlSkipBig;
  2175.  
  2176.                         /* Store the vector index with the "big" bit added */
  2177.  
  2178.                         memDef->dlDeclSkip = dclDist;
  2179.  
  2180.                         /* Make sure the stored value fit in the bitfield */
  2181.  
  2182.                         assert(memDef->dlDeclSkip == dclDist);
  2183.                     }
  2184.  
  2185.                 DONE_SKIP:
  2186.  
  2187.                     /* Mark global constants as such */
  2188.  
  2189.                     if  ((memMod.dmMod & DM_CONST) && !qual && memInit)
  2190.                         memDef->dlEarlyDecl = true;
  2191.  
  2192.                     /* Record the member if we're in the right place */
  2193.  
  2194.                     if  (sym->sdSymKind == SYM_CLASS)
  2195.                     {
  2196.                         assert(sym->sdIsImport == false);
  2197.  
  2198.                         /* Add it to the member list of the class */
  2199.  
  2200.                         ourComp->cmpRecordMemDef(sym, memDef);
  2201.                     }
  2202.                     else
  2203.                     {
  2204.                         assert(sym->sdSymKind == SYM_NAMESPACE);
  2205.  
  2206.                         /* This is a file scope / namespace declaration */
  2207.  
  2208.                         memDef->dlNext = sym->sdNS.sdnDeclList;
  2209.                                          sym->sdNS.sdnDeclList = memDef;
  2210.                     }
  2211.  
  2212.                 BAD_MEM:
  2213.  
  2214.                     /* Are there any more declarators? */
  2215.  
  2216.                     if  (ourScanner->scanTok.tok != tkComma || noMore
  2217.                                                             || prefMods)
  2218.                     {
  2219.                         if  (fileScope)
  2220.                             goto EXIT;
  2221.  
  2222.                         /* Check for - and consume - the terminating ";" */
  2223.  
  2224.                         if  (ourScanner->scanTok.tok == tkSColon)
  2225.                             ourScanner->scan();
  2226.  
  2227.                         break;
  2228.                     }
  2229.  
  2230.                     /* Swallow the "," and go get the next declarator */
  2231.  
  2232.                     ourScanner->scan();
  2233.                 }
  2234.  
  2235.                 break;
  2236.  
  2237.             case tkRCurly:
  2238.                 goto DONE_DEF;
  2239.  
  2240.             case tkSColon:
  2241.                 ourScanner->scan();
  2242.                 break;
  2243.  
  2244.             case tkUSING:
  2245.                 parseUsingDecl();
  2246.                 break;
  2247.  
  2248.             case tkDEFAULT:
  2249.  
  2250.                 if  (ourScanner->scanLookAhead() == tkPROPERTY)
  2251.                     goto PARSE_MOD;
  2252.  
  2253.                 // Fall through ...
  2254.  
  2255.             case tkCASE:
  2256.  
  2257.                 if  (sym->sdSymKind != SYM_CLASS || !sym->sdClass.sdcTagdUnion)
  2258.                     ourComp->cmpError(ERRbadStrCase);
  2259.  
  2260.                 /* Record the name for the 'fake' member we will add */
  2261.  
  2262.                 name = parseHash->tokenToIdent(ourScanner->scanTok.tok);
  2263.  
  2264.                 if  (ourScanner->scanTok.tok == tkCASE)
  2265.                 {
  2266.                     /* Skip over the 'case' and the expression that should follow */
  2267.  
  2268.                     ourScanner->scan();
  2269.                     parseExprComma();
  2270.  
  2271.                     /* Both "case val:" and "case(val)" are OK */
  2272.  
  2273.                     if  (ourScanner->scanTok.tok == tkColon)
  2274.                         ourScanner->scan();
  2275.                 }
  2276.                 else
  2277.                 {
  2278.                     /* Both "default:" and just plain "default" are OK for now */
  2279.  
  2280.                     if  (ourScanner->scan() == tkColon)
  2281.                         ourScanner->scan();
  2282.                 }
  2283.  
  2284.                 if  (sym->sdSymKind == SYM_CLASS && sym->sdClass.sdcTagdUnion)
  2285.                 {
  2286.                     /* Create a definition descriptor for the case label */
  2287.  
  2288.                     memDef = ourSymTab->stRecordMemSrcDef(name,
  2289.                                                           NULL,
  2290.                                                           parseCurCmp,
  2291.                                                           parseCurUseDesc,
  2292.                                                           memFpos,
  2293. //                                                        ourScanner->scanGetFilePos(),
  2294.                                                           defLine);
  2295.  
  2296.                     assert(sym->sdSymKind == SYM_CLASS);
  2297.                     assert(sym->sdIsImport == false);
  2298.  
  2299.                     /* Add the case to the member list of the class */
  2300.  
  2301.                     ourComp->cmpRecordMemDef(sym, memDef);
  2302.                 }
  2303.                 break;
  2304.  
  2305.             case tkENUM:
  2306.             case tkCLASS:
  2307.             case tkUNION:
  2308.             case tkSTRUCT:
  2309.             case tkTYPEDEF:
  2310.             case tkDELEGATE:
  2311.             case tkINTERFACE:
  2312.             case tkNAMESPACE:
  2313.  
  2314.                 defTok  = ourScanner->scanTok.tok;
  2315.                 memFpos = ourScanner->scanGetFilePos();
  2316.  
  2317.                 initDeclMods(&memMod, acc);
  2318.  
  2319.             NEST_DEF:
  2320.  
  2321.                 /* Make sure this is allowed here */
  2322.  
  2323.                 if  (sym->sdSymKind != SYM_NAMESPACE)
  2324.                 {
  2325.                     switch (defTok)
  2326.                     {
  2327.                     case tkCLASS:
  2328.                     case tkUNION:
  2329.                     case tkSTRUCT:
  2330.                     case tkDELEGATE:
  2331.                     case tkINTERFACE:
  2332.  
  2333.                         // ISSUE: should we allow enum's/typedef's within classes?
  2334.  
  2335.                         break;
  2336.  
  2337.                     default:
  2338.                         ourComp->cmpError(ERRnoRcurly);
  2339.                         goto DONE;
  2340.                     }
  2341.                 }
  2342.  
  2343.                 if  (prefMods)
  2344.                     memMod.dmMod |= DM_XMODS;
  2345.  
  2346.                 /* Process the nested member recursively */
  2347.  
  2348.                 parsePrepSym(sym, memMod, defTok, memFpos, dclLine);
  2349.  
  2350.                 if  (ourScanner->scanTok.tok == tkComma)
  2351.                 {
  2352.                     if  (defTok != tkTYPEDEF)
  2353.                         break;
  2354.  
  2355.                     UNIMPL("Sorry: you can only typedef one name at a time for now");
  2356.                 }
  2357.  
  2358.                 /* We're back to processing our symbol */
  2359.  
  2360.                 parseCurSym = sym;
  2361.                 break;
  2362.  
  2363.             case tkPUBLIC:
  2364.             case tkPRIVATE:
  2365.             case tkPROTECTED:
  2366.  
  2367.                 switch (ourScanner->scanLookAhead())
  2368.                 {
  2369.                 case tkColon:
  2370.  
  2371.                     /* This is an access specifier */
  2372.  
  2373.                     switch (ourScanner->scanTok.tok)
  2374.                     {
  2375.                     case tkPUBLIC:    acc = ACL_PUBLIC   ; break;
  2376.                     case tkPRIVATE:   acc = ACL_PRIVATE  ; break;
  2377.                     case tkPROTECTED: acc = ACL_PROTECTED; break;
  2378.                     }
  2379.  
  2380.                     /* Consume the "access:" and continue */
  2381.  
  2382.                     ourScanner->scan();
  2383.                     ourScanner->scan();
  2384.                     continue;
  2385.                 }
  2386.  
  2387.             case tkCONST:
  2388.             case tkVOLATILE:
  2389.  
  2390.             case tkINLINE:
  2391.             case tkSTATIC:
  2392.             case tkSEALED:
  2393.             case tkVIRTUAL:
  2394.             case tkABSTRACT:
  2395.             case tkOVERRIDE:
  2396.             case tkOVERLOAD:
  2397.  
  2398.             case tkMANAGED:
  2399.             case tkUNMANAGED:
  2400.  
  2401.             case tkTRANSIENT:
  2402.             case tkSERIALIZABLE:
  2403.  
  2404.                 /* Here we have some member modifiers */
  2405.  
  2406.                 parseDeclMods(acc, &memMod);
  2407.  
  2408.             CHK_NST:
  2409.  
  2410.                 /* Check for a non-data/function member */
  2411.  
  2412.                 switch (ourScanner->scanTok.tok)
  2413.                 {
  2414.                 case tkENUM:
  2415.                 case tkCLASS:
  2416.                 case tkUNION:
  2417.                 case tkSTRUCT:
  2418.                 case tkTYPEDEF:
  2419.                 case tkDELEGATE:
  2420.                 case tkINTERFACE:
  2421.                 case tkNAMESPACE:
  2422.                     defTok = ourScanner->scanTok.tok;
  2423.                     goto NEST_DEF;
  2424.                 }
  2425.  
  2426.                 goto PARSE_MEM;
  2427.  
  2428.             case tkLBrack:
  2429.             case tkAtComment:
  2430.             case tkCAPABILITY:
  2431.             case tkPERMISSION:
  2432.             case tkATTRIBUTE:
  2433.  
  2434.                 /* These guys can be basically repeated ad nauseaum */
  2435.  
  2436.                 for (;;)
  2437.                 {
  2438.                     switch (ourScanner->scanTok.tok)
  2439.                     {
  2440.                     case tkLBrack:
  2441.                         parseBrackAttr(false, (sym->sdSymKind == SYM_NAMESPACE)
  2442.                                                     ? ATTR_MASK_SYS_IMPORT
  2443.                                                     : ATTR_MASK_SYS_IMPORT|ATTR_MASK_NATIVE_TYPE);
  2444.                         continue;
  2445.  
  2446.                     case tkAtComment:
  2447.                         ourScanner->scan();
  2448.                         break;
  2449.  
  2450.                     case tkCAPABILITY:
  2451.                         parseCapability();
  2452.                         break;
  2453.  
  2454.                     case tkPERMISSION:
  2455.                         parsePermission();
  2456.                         break;
  2457.  
  2458.                     case tkATTRIBUTE:
  2459.  
  2460.                         /* At this stage we just swallow the initializer list */
  2461.  
  2462.                         unsigned    tossMask;
  2463.                         genericBuff tossAddr;
  2464.                         size_t      tossSize;
  2465.  
  2466.                         parseAttribute(0, tossMask, tossAddr, tossSize);
  2467.                         break;
  2468.  
  2469.                     default:
  2470.                         parseDeclMods(acc, &memMod); memMod.dmMod |= DM_XMODS;
  2471.                         goto CHK_NST;
  2472.                     }
  2473.                 }
  2474.  
  2475.                 break;  // unreached, BTW
  2476.  
  2477.             case tkMULTICAST:
  2478.                 ourScanner->scan();
  2479.                 parseDeclMods(acc, &memMod); memMod.dmMod |= DM_MULTICAST;
  2480.                 goto NEST_DEF;
  2481.             }
  2482.         }
  2483.  
  2484.         /* Unless we're in global scope or in an old-style namespace, require "}" */
  2485.  
  2486.         if  (ourScanner->scanTok.tok != tkRCurly && sym != parseComp->cmpGlobalNS)
  2487.         {
  2488.             if  (sym->sdSymKind != SYM_NAMESPACE)
  2489.                 parseComp->cmpError(ERRnoRcurly);
  2490.         }
  2491.  
  2492.         break;
  2493.  
  2494.     default:
  2495.         NO_WAY(!"what?");
  2496.     }
  2497.  
  2498. DONE_DEF:
  2499.  
  2500.     /* Get the position of the end of the definition */
  2501.  
  2502.     defEpos = ourScanner->scanGetFilePos();
  2503.  
  2504.     /* Consume the closing "}" if present */
  2505.  
  2506.     if  (ourScanner->scanTok.tok == tkRCurly)
  2507.         ourScanner->scan();
  2508.  
  2509. DONE:
  2510.  
  2511.     /* Are we processing a tagged/anonymous union? */
  2512.  
  2513.     if  (sym->sdSymKind == SYM_CLASS && sym->sdClass.sdcAnonUnion)
  2514.     {
  2515.         ExtList         memDef;
  2516.         Ident           memName;
  2517.  
  2518.         SymDef          owner = sym->sdParent;
  2519.  
  2520.         assert(owner->sdSymKind == SYM_CLASS);
  2521.  
  2522.         /* Is there a member name? */
  2523.  
  2524.         if  (ourScanner->scanTok.tok == tkID)
  2525.         {
  2526.             memName = ourScanner->scanTok.id.tokIdent;
  2527.             ourScanner->scan();
  2528.         }
  2529.         else
  2530.         {
  2531.             memName = parseComp->cmpNewAnonymousName();
  2532.         }
  2533.  
  2534.         if  (ourScanner->scanTok.tok != tkSColon)
  2535.             ourComp->cmpError(ERRnoSemic);
  2536.  
  2537.         /* Record the extent of the member's definition */
  2538.  
  2539.         memDef = ourSymTab->stRecordMemSrcDef(memName,
  2540.                                               NULL,
  2541.                                               parseCurCmp,
  2542.                                               parseCurUseDesc,
  2543.                                               dclFpos,
  2544. //                                            defEpos,
  2545.                                               dclLine);
  2546.  
  2547.         memDef->dlHasDef    = true;
  2548.         memDef->dlAnonUnion = true;
  2549.         memDef->mlSym       = sym;
  2550.  
  2551.         /* Add the member to the owning class' list */
  2552.  
  2553.         ourComp->cmpRecordMemDef(owner, memDef);
  2554.     }
  2555.  
  2556.     /* Allocate a definition descriptor and add it to the symbol's list */
  2557.  
  2558.     defRec = ourSymTab->stRecordSymSrcDef(sym,
  2559.                                           parseCurCmp,
  2560.                                           parseCurUseDesc,
  2561.                                           dclFpos,
  2562. //                                        defEpos,
  2563.                                           dclLine);
  2564.  
  2565.     defRec->dlHasDef   = hasBody;
  2566.     defRec->dlOldStyle = parseOldStyle;
  2567.  
  2568. EXIT:
  2569.  
  2570.     /* Restore the "using" state we had on entry if we've changed it */
  2571.  
  2572.     if  (addUses)
  2573.         parseUsingScpEnd(useState);
  2574.  
  2575.     parseCurSym = NULL;
  2576.  
  2577.     return  defRec;
  2578. }
  2579.  
  2580. /*****************************************************************************
  2581.  *
  2582.  *  Keep track of default alignment (pragma pack).
  2583.  */
  2584.  
  2585. void            parser::parseAlignSet(unsigned align)
  2586. {
  2587.     parseAlignment  = align;
  2588. }
  2589.  
  2590. void            parser::parseAlignPush()
  2591. {
  2592. //  printf("Push align: %08X <- %u / %u\n", parseAlignStack, parseAlignment, compiler::cmpEncodeAlign(parseAlignment));
  2593.     parseAlignStack = parseAlignStack << 4 | compiler::cmpEncodeAlign(parseAlignment);
  2594.     parseAlignStLvl++;
  2595. }
  2596.  
  2597. void            parser::parseAlignPop()
  2598. {
  2599.     if  (parseAlignStLvl)
  2600.     {
  2601. //      printf("Pop  align: %08X -> %u / %u\n", parseAlignStack, parseAlignStack & 0xF, compiler::cmpDecodeAlign(parseAlignStack & 0xF));
  2602.         parseAlignment  = compiler::cmpDecodeAlign(parseAlignStack & 0x0F);
  2603.         parseAlignStack = parseAlignStack >> 4;
  2604.         parseAlignStLvl--;
  2605.     }
  2606.     else
  2607.     {
  2608. //      printf("Pop  align: ******** -> %u\n", parseComp->cmpConfig.ccAlignVal);
  2609.         parseAlignment  = parseComp->cmpConfig.ccAlignVal;
  2610.     }
  2611. }
  2612.  
  2613. /*****************************************************************************
  2614.  *
  2615.  *  Parse and return any member modifiers, such as "public" or "abstract".
  2616.  */
  2617.  
  2618. void                parser::parseDeclMods(accessLevels defAccess, DeclMod modPtr)
  2619. {
  2620.     Scanner         ourScanner = parseScan;
  2621.  
  2622.     declMods        mods; clearDeclMods(&mods);
  2623.  
  2624.     for (;;)
  2625.     {
  2626.         switch (ourScanner->scanTok.tok)
  2627.         {
  2628.             unsigned        modf;
  2629.  
  2630.         case tkID:
  2631.  
  2632.         DONE:
  2633.  
  2634.             if  (mods.dmAcc == ACL_DEFAULT)
  2635.                  mods.dmAcc = defAccess;
  2636.  
  2637.             *modPtr = mods;
  2638.             return;
  2639.  
  2640.         default:
  2641.  
  2642.             modf = hashTab::tokenIsMod(ourScanner->scanTok.tok);
  2643.             if  (modf)
  2644.             {
  2645.                 switch (ourScanner->scanTok.tok)
  2646.                 {
  2647.                 case tkMANAGED:
  2648.                     if  (mods.dmMod & (DM_MANAGED|DM_UNMANAGED))
  2649.                         parseComp->cmpError(ERRdupModifier);
  2650.                     break;
  2651.  
  2652.                 case tkUNMANAGED:
  2653.                     if  (mods.dmMod & (DM_MANAGED|DM_UNMANAGED))
  2654.                         parseComp->cmpError(ERRdupModifier);
  2655.                     break;
  2656.  
  2657.                 default:
  2658.                     if  (mods.dmMod & modf)
  2659.                         parseComp->cmpError(ERRdupModifier);
  2660.                     break;
  2661.                 }
  2662.  
  2663.                 mods.dmMod |= modf;
  2664.                 break;
  2665.             }
  2666.  
  2667.             goto DONE;
  2668.  
  2669.         case tkPUBLIC:
  2670.             if  (mods.dmAcc != ACL_DEFAULT)
  2671.                 parseComp->cmpError(ERRdupModifier);
  2672.             mods.dmAcc = ACL_PUBLIC;
  2673.             break;
  2674.  
  2675.         case tkPRIVATE:
  2676.             if  (mods.dmAcc != ACL_DEFAULT)
  2677.                 parseComp->cmpError(ERRdupModifier);
  2678.             mods.dmAcc = ACL_PRIVATE;
  2679.             break;
  2680.  
  2681.         case tkPROTECTED:
  2682.             if  (mods.dmAcc != ACL_DEFAULT)
  2683.                 parseComp->cmpError(ERRdupModifier);
  2684.             mods.dmAcc = ACL_PROTECTED;
  2685.             break;
  2686.         }
  2687.  
  2688.         ourScanner->scan();
  2689.     }
  2690. }
  2691.  
  2692. /*****************************************************************************
  2693.  *
  2694.  *  Parse a type specification.
  2695.  */
  2696.  
  2697. TypDef              parser::parseTypeSpec(DeclMod mods, bool forReal)
  2698. {
  2699.     Scanner         ourScanner  = parseScan;
  2700.  
  2701.     bool            hadUnsigned = false;
  2702.     bool            hadSigned   = false;
  2703.  
  2704.     bool            hadShort    = false;
  2705.     bool            hadLong     = false;
  2706.  
  2707.     var_types       baseType    = TYP_UNDEF;
  2708.  
  2709.     bool            isManaged   = parseComp->cmpManagedMode;
  2710.  
  2711.     TypDef          type;
  2712.  
  2713. //  static int x; if (++x == 0) forceDebugBreak();
  2714.  
  2715.     for (;;)
  2716.     {
  2717.         switch (ourScanner->scanTok.tok)
  2718.         {
  2719.         case tkCONST:
  2720.             if  (mods->dmMod & DM_CONST)
  2721.                 parseComp->cmpError(ERRdupModifier);
  2722.             mods->dmMod |= DM_CONST;
  2723.             break;
  2724.  
  2725.         case tkVOLATILE:
  2726.             if  (mods->dmMod & DM_VOLATILE)
  2727.                 parseComp->cmpError(ERRdupModifier);
  2728.             mods->dmMod |= DM_VOLATILE;
  2729.             break;
  2730.  
  2731.         default:
  2732.             goto DONE_CV;
  2733.         }
  2734.  
  2735.         ourScanner->scan();
  2736.     }
  2737.  
  2738. DONE_CV:
  2739.  
  2740. #ifdef  __SMC__
  2741. //printf("Token = %d '%s'\n", ourScanner->scanTok.tok, tokenNames[ourScanner->scanTok.tok]); fflush(stdout);
  2742. #endif
  2743.  
  2744.     /* Grab the type specifier (along with any prefixes) */
  2745.  
  2746.     switch (ourScanner->scanTok.tok)
  2747.     {
  2748.         SymDef          tsym;
  2749.         bool            qual;
  2750.  
  2751.     case tkID:
  2752.  
  2753.         /* Must be a type name */
  2754.  
  2755.         if  (forReal)
  2756.         {
  2757.             /* Parse the (possibly qualified) name */
  2758.  
  2759.             switch (ourScanner->scanLookAhead())
  2760.             {
  2761.                 Ident           name;
  2762.  
  2763.             case tkDot:
  2764.             case tkColon2:
  2765.  
  2766.             QUALID:
  2767.  
  2768.                 tsym = parseNameUse(true, false);
  2769.                 if  (!tsym)
  2770.                     goto NO_TPID;
  2771.  
  2772.                 qual = true;
  2773.                 goto NMTP;
  2774.  
  2775.             default:
  2776.  
  2777.                 /* Simple name - look it up in the current context */
  2778.  
  2779.                 name = ourScanner->scanTok.id.tokIdent;
  2780.  
  2781.                 /* Can't be in scanner lookahead state for lookup [ISSUE?] */
  2782.  
  2783.                 ourScanner->scan();
  2784.  
  2785. #if 0
  2786.                 if  (parseLookupSym(name))
  2787.                 {
  2788.                     parseComp->cmpError(ERRidNotType, name);
  2789.                     return  parseStab->stNewErrType(name);
  2790.                 }
  2791. #endif
  2792.  
  2793.                 tsym = parseStab->stLookupSym(name, NS_TYPE);
  2794.  
  2795.                 if  (tsym)
  2796.                 {
  2797.                     qual = false;
  2798.  
  2799.                     /* Make sure the symbol we've found is a type */
  2800.  
  2801.                 NMTP:
  2802.  
  2803.                     switch (tsym->sdSymKind)
  2804.                     {
  2805.                     case SYM_CLASS:
  2806.  
  2807.                         if  (ourScanner->scanTok.tok == tkLT && tsym->sdClass.sdcGeneric)
  2808.                         {
  2809.                             if  (forReal)
  2810.                             {
  2811.                                 tsym = parseSpecificType(tsym);
  2812.                                 if  (!tsym)
  2813.                                     return  parseStab->stNewErrType(NULL);
  2814.  
  2815.                                 assert(tsym->sdSymKind == SYM_CLASS);
  2816.                                 assert(tsym->sdClass.sdcGeneric  == false);
  2817.                                 assert(tsym->sdClass.sdcSpecific != false);
  2818.                             }
  2819.                             else
  2820.                             {
  2821.                                 ourScanner->scanNestedGT(+1);
  2822.                                 ourScanner->scanSkipText(tkLT, tkGT);
  2823.                                 if  (ourScanner->scanTok.tok == tkGT)
  2824.                                     ourScanner->scan();
  2825.                                 ourScanner->scanNestedGT(-1);
  2826.                             }
  2827.                         }
  2828.  
  2829.                         // Fall through ...
  2830.  
  2831.                     case SYM_ENUM:
  2832.  
  2833.                     CLSNM:
  2834.  
  2835.                         type = tsym->sdTypeGet();
  2836.                         break;
  2837.  
  2838.                     case SYM_TYPEDEF:
  2839.                         if  (forReal && !parseNoTypeDecl)
  2840.                             parseComp->cmpDeclSym(tsym);
  2841.                         type = tsym->sdTypeGet();
  2842.                         break;
  2843.  
  2844.                     case SYM_FNC:
  2845.  
  2846.                         /* A constructor name sort of hides the class name */
  2847.  
  2848.                         if  (tsym->sdFnc.sdfCtor)
  2849.                         {
  2850.                             tsym = tsym->sdParent;
  2851.                             goto CLSNM;
  2852.                         }
  2853.  
  2854.                         // Fall through ...
  2855.  
  2856.                     default:
  2857.                         if  (qual)
  2858.                             parseComp->cmpError(ERRidNotType, tsym);
  2859.                         else
  2860.                             parseComp->cmpError(ERRidNotType, name);
  2861.  
  2862.                         // Fall through ...
  2863.  
  2864.                     case SYM_ERR:
  2865.                         type = parseStab->stIntrinsicType(TYP_UNDEF);
  2866.                         break;
  2867.                     }
  2868.  
  2869.                     /* Make sure we are allowed to access the type */
  2870.  
  2871.                     parseComp->cmpCheckAccess(tsym);
  2872.                 }
  2873.                 else
  2874.                 {
  2875.                     parseComp->cmpError(ERRundefName, name);
  2876.                     type = parseStab->stNewErrType(name);
  2877.                 }
  2878.  
  2879.                 break;
  2880.             }
  2881.  
  2882.             assert(type);
  2883.  
  2884.             /* For managed non-value classes switch to a reference */
  2885.  
  2886.             if  (type->tdTypeKind == TYP_CLASS &&  type->tdIsManaged
  2887.                                                && !type->tdClass.tdcValueType)
  2888.             {
  2889.                 type = type->tdClass.tdcRefTyp;
  2890.             }
  2891.  
  2892.             goto CHK_MGD_ARR;
  2893.         }
  2894.         else
  2895.         {
  2896.             if  (ourScanner->scanTok.tok == tkColon2)
  2897.                 ourScanner->scan();
  2898.  
  2899.             for (;;)
  2900.             {
  2901.                 if  (ourScanner->scan() != tkDot)
  2902.                 {
  2903.                     if  (ourScanner->scanTok.tok != tkColon2)
  2904.                     {
  2905.                         if  (ourScanner->scanTok.tok == tkLT)
  2906.                         {
  2907.                             ourScanner->scanSkipText(tkLT, tkGT);
  2908.                             if  (ourScanner->scanTok.tok == tkGT)
  2909.                                 ourScanner->scan();
  2910.                         }
  2911.  
  2912.                         goto DONE_TPSP;
  2913.                     }
  2914.                 }
  2915.  
  2916.                 if  (ourScanner->scan() != tkID)
  2917.                     goto DONE_TPSP;
  2918.             }
  2919.         }
  2920.  
  2921.     case tkColon2:
  2922.         goto QUALID;
  2923.  
  2924.     case tkQUALID:
  2925. //      qual = false;
  2926.         tsym = ourScanner->scanTok.qualid.tokQualSym;
  2927.         ourScanner->scan();
  2928.         goto NMTP;
  2929.     }
  2930.  
  2931. NO_TPID:
  2932.  
  2933.     /* Must be a type declared via keywords */
  2934.  
  2935.     for (;;)
  2936.     {
  2937.         if  (parseHash->tokenIsType(ourScanner->scanTok.tok))
  2938.         {
  2939.             switch (ourScanner->scanTok.tok)
  2940.             {
  2941.             case tkINT:
  2942.                 ourScanner->scan();
  2943.                 goto COMP_TPSP;
  2944.  
  2945.             case tkVOID:       baseType = TYP_VOID   ; goto TYP1;
  2946.             case tkBOOL:       baseType = TYP_BOOL   ; goto TYP1;
  2947.             case tkBYTE:       baseType = TYP_UCHAR  ; goto TYP1;
  2948.             case tkWCHAR:      baseType = TYP_WCHAR  ; goto TYP1;
  2949.             case tkUINT:       baseType = TYP_UINT   ; goto TYP1;
  2950.             case tkUSHORT:     baseType = TYP_USHORT ; goto TYP1;
  2951.             case tkNATURALINT: baseType = TYP_NATINT ; goto TYP1;
  2952.             case tkNATURALUINT:baseType = TYP_NATUINT; goto TYP1;
  2953.             case tkFLOAT:      baseType = TYP_FLOAT  ; goto TYP1;
  2954. //          case tkREFANY:     baseType = TYP_REFANY ; goto TYP1;
  2955.  
  2956.             TYP1:
  2957.  
  2958.                 /* No size/sign modifiers allowed */
  2959.  
  2960.                 if  (hadUnsigned || hadSigned || hadShort || hadLong)
  2961.                     parseComp->cmpError(ERRbadModifier);
  2962.  
  2963.                 ourScanner->scan();
  2964.                 goto DONE_TPSP;
  2965.  
  2966.             case tkCHAR:
  2967.  
  2968.                 /* Only "unsigned" allowed as a modifier */
  2969.  
  2970.                 if  (hadShort || hadLong)
  2971.                     parseComp->cmpError(ERRbadModifier);
  2972.  
  2973.                 if  (hadUnsigned)
  2974.                     baseType = TYP_UCHAR;
  2975.                 else if (hadSigned)
  2976.                     baseType = TYP_CHAR;
  2977.                 else
  2978.                     baseType = TYP_CHAR;    // same as "signed" for now ....
  2979.                 ourScanner->scan();
  2980.                 goto DONE_TPSP;
  2981.  
  2982.             case tkINT8:
  2983.                 if  (hadShort || hadLong)
  2984.                     parseComp->cmpError(ERRbadModifier);
  2985.                 baseType = hadUnsigned ? TYP_UCHAR
  2986.                                        : TYP_CHAR;
  2987.  
  2988.                 ourScanner->scan();
  2989.                 goto DONE_TPSP;
  2990.  
  2991.             case tkINT16:
  2992.                 if  (hadShort || hadLong)
  2993.                     parseComp->cmpError(ERRbadModifier);
  2994.                 baseType = hadUnsigned ? TYP_USHORT
  2995.                                        : TYP_SHORT;
  2996.  
  2997.                 ourScanner->scan();
  2998.                 goto DONE_TPSP;
  2999.  
  3000.             case tkINT32:
  3001.                 if  (hadShort || hadLong)
  3002.                     parseComp->cmpError(ERRbadModifier);
  3003.                 baseType = hadUnsigned ? TYP_UINT
  3004.                                        : TYP_INT;
  3005.  
  3006.                 ourScanner->scan();
  3007.                 goto DONE_TPSP;
  3008.  
  3009.             case tkINT64:
  3010.                 if  (hadShort || hadLong)
  3011.                     parseComp->cmpError(ERRbadModifier);
  3012.                 baseType = hadUnsigned ? TYP_ULONG
  3013.                                        : TYP_LONG;
  3014.  
  3015.                 ourScanner->scan();
  3016.                 goto DONE_TPSP;
  3017.  
  3018.             case tkUINT8:
  3019.                 if  (hadShort || hadLong || hadUnsigned)
  3020.                     parseComp->cmpError(ERRbadModifier);
  3021.                 baseType = TYP_UCHAR;
  3022.                 ourScanner->scan();
  3023.                 goto DONE_TPSP;
  3024.  
  3025.             case tkUINT16:
  3026.                 if  (hadShort || hadLong || hadUnsigned)
  3027.                     parseComp->cmpError(ERRbadModifier);
  3028.                 baseType = TYP_USHORT;
  3029.                 ourScanner->scan();
  3030.                 goto DONE_TPSP;
  3031.  
  3032.             case tkUINT32:
  3033.                 if  (hadShort || hadLong || hadUnsigned)
  3034.                     parseComp->cmpError(ERRbadModifier);
  3035.                 baseType = TYP_UINT;
  3036.                 ourScanner->scan();
  3037.                 goto DONE_TPSP;
  3038.  
  3039.             case tkUINT64:
  3040.                 if  (hadShort || hadLong || hadUnsigned)
  3041.                     parseComp->cmpError(ERRbadModifier);
  3042.                 baseType = TYP_ULONG;
  3043.                 ourScanner->scan();
  3044.                 goto DONE_TPSP;
  3045.  
  3046.             case tkLONGINT:
  3047.                 if  (hadShort || hadLong || hadUnsigned)
  3048.                     parseComp->cmpError(ERRbadModifier);
  3049.                 baseType = TYP_LONG;
  3050.                 ourScanner->scan();
  3051.                 goto DONE_TPSP;
  3052.  
  3053.             case tkULONGINT:
  3054.                 if  (hadShort || hadLong || hadUnsigned)
  3055.                     parseComp->cmpError(ERRbadModifier);
  3056.                 baseType = TYP_ULONG;
  3057.                 ourScanner->scan();
  3058.                 goto DONE_TPSP;
  3059.  
  3060.             case tkSHORT:
  3061.                 if  (hadShort || hadLong)
  3062.                     parseComp->cmpError(ERRdupModifier);
  3063.                 hadShort = true;
  3064.                 break;
  3065.  
  3066.             case tkDOUBLE:
  3067.                 if  (hadUnsigned || hadSigned || hadShort)
  3068.                     parseComp->cmpError(ERRbadModifier);
  3069.  
  3070.                 baseType = hadLong ? TYP_LONGDBL
  3071.                                    : TYP_DOUBLE;
  3072.                 ourScanner->scan();
  3073.                 goto DONE_TPSP;
  3074.  
  3075.             case tkSIGNED:
  3076.                 if  (hadUnsigned || hadSigned)
  3077.                     parseComp->cmpError(ERRdupModifier);
  3078.                 hadSigned = true;
  3079.                 break;
  3080.  
  3081.             case tkUNSIGNED:
  3082.                 if  (hadUnsigned || hadSigned)
  3083.                     parseComp->cmpError(ERRdupModifier);
  3084.                 hadUnsigned = true;
  3085.                 break;
  3086.  
  3087.             default:
  3088.                 NO_WAY(!"token marked as type but not handled");
  3089.             }
  3090.         }
  3091.         else
  3092.         {
  3093.             /* Make sure we've found something, anything */
  3094.  
  3095.             if  (!hadUnsigned && !hadSigned && !hadShort && !hadLong)
  3096.             {
  3097.                 parseComp->cmpError(ERRnoType);
  3098.  
  3099.                 if  (!forReal)
  3100.                     return  NULL;
  3101.             }
  3102.  
  3103.             goto COMP_TPSP;
  3104.         }
  3105.  
  3106.         ourScanner->scan();
  3107.     }
  3108.  
  3109. COMP_TPSP:
  3110.  
  3111.     if      (hadLong)
  3112.     {
  3113.         baseType = hadUnsigned ? TYP_ULONG
  3114.                                : TYP_LONG;
  3115.     }
  3116.     else if (hadShort)
  3117.     {
  3118.         baseType = hadUnsigned ? TYP_USHORT
  3119.                                : TYP_SHORT;
  3120.     }
  3121.     else
  3122.     {
  3123.         baseType = hadUnsigned ? TYP_UINT
  3124.                                : TYP_INT;
  3125.     }
  3126.  
  3127. DONE_TPSP:
  3128.  
  3129.     type = parseStab->stIntrinsicType(baseType);
  3130.  
  3131.     /* Look for any trailing const/volatile modifiers */
  3132.  
  3133.     switch (ourScanner->scanTok.tok)
  3134.     {
  3135.     case tkCONST:
  3136.         if  (mods->dmMod & DM_CONST)
  3137.             parseComp->cmpError(ERRdupModifier);
  3138.         mods->dmMod |= DM_CONST;
  3139.         ourScanner->scan();
  3140.         goto DONE_TPSP;
  3141.  
  3142.     case tkVOLATILE:
  3143.         if  (mods->dmMod & DM_VOLATILE)
  3144.             parseComp->cmpError(ERRdupModifier);
  3145.         mods->dmMod |= DM_VOLATILE;
  3146.         ourScanner->scan();
  3147.         goto DONE_TPSP;
  3148.  
  3149.     default:
  3150.         break;
  3151.     }
  3152.  
  3153. CHK_MGD_ARR:
  3154.  
  3155.     /* Is this an intrinsic type "in disguise" ? */
  3156.  
  3157.     if  (type->tdTypeKind == TYP_CLASS)
  3158.     {
  3159.         var_types       vtyp = (var_types)type->tdClass.tdcIntrType;
  3160.  
  3161.         if  (vtyp != TYP_UNDEF)
  3162.             type = parseStab->stIntrinsicType(vtyp);
  3163.     }
  3164.  
  3165.     for (;;)
  3166.     {
  3167.         switch (ourScanner->scanTok.tok)
  3168.         {
  3169.         case tkMANAGED:
  3170.  
  3171.             if  (ourScanner->scan() != tkLBrack)
  3172.             {
  3173.                 parseComp->cmpError(ERRbadMgdTyp);
  3174.                 continue;
  3175.             }
  3176.  
  3177.             isManaged = true;
  3178.  
  3179.             // Fall through ...
  3180.  
  3181.         case tkLBrack:
  3182.  
  3183.             if  (!isManaged)
  3184.                 break;
  3185.  
  3186.             if  (forReal)
  3187.             {
  3188.                 DimDef          dims;
  3189.  
  3190.                 /* If we're just checking for a type, only allow "[]" for now */
  3191.  
  3192.                 if  (parseNoTypeDecl && ourScanner->scanLookAhead() != tkRBrack)
  3193.                     return  type;
  3194.  
  3195.                 /* Parse the dimensions */
  3196.  
  3197.                 dims = parseDimList(true);
  3198.  
  3199.                 /* Create the array type */
  3200.  
  3201.                 type = parseStab->stNewArrType(dims, true, type);
  3202.             }
  3203.             else
  3204.             {
  3205.                 ourScanner->scanSkipText(tkLBrack, tkRBrack);
  3206.                 if  (ourScanner->scanTok.tok != tkRBrack)
  3207.                     break;
  3208.                 ourScanner->scan();
  3209.             }
  3210.  
  3211.             continue;
  3212.         }
  3213.  
  3214.         return  type;
  3215.     }
  3216. }
  3217.  
  3218. /*****************************************************************************
  3219.  *
  3220.  *  Parse the "guts" of a declarator.
  3221.  */
  3222.  
  3223. TypDef              parser::parseDclrtrTerm(dclrtrName  nameMode,
  3224.                                             bool        forReal,
  3225.                                             DeclMod     modsPtr,
  3226.                                             TypDef      baseType,
  3227.                                             TypDef  * * baseRef,
  3228.                                             Ident     * nameRet,
  3229.                                             QualName  * qualRet)
  3230. {
  3231.     Compiler        ourComp    = parseComp;
  3232.     Scanner         ourScanner = parseScan;
  3233.     SymTab          ourSymTab  = parseStab;
  3234.  
  3235.     Ident           name       = NULL;
  3236.     QualName        qual       = NULL;
  3237.  
  3238.     bool            isManaged  = ourComp->cmpManagedMode;
  3239.  
  3240.     TypDef          innerTyp   = NULL;
  3241.     TypDef      *   innerRef   = NULL;
  3242.  
  3243.     TypDef          outerTyp;
  3244.     TypDef      *   outerRef;
  3245.  
  3246.     /* Check for pointer/array prefixes, parentheses, and the name itself */
  3247.  
  3248.     for (;;)
  3249.     {
  3250.         switch (ourScanner->scanTok.tok)
  3251.         {
  3252.             TypDef      tempType;
  3253.             var_types   refKind;
  3254.  
  3255.         case tkUNMANAGED:
  3256.  
  3257.             if  (ourScanner->scan() != tkLBrack)
  3258.             {
  3259.                 ourComp->cmpError(ERRbadUnmTyp);
  3260.                 continue;
  3261.             }
  3262.  
  3263.             isManaged = false;
  3264.             goto DONE_PREF;
  3265.  
  3266.         case tkAnd:
  3267.  
  3268.             /* This is a reference declarator */
  3269.  
  3270.             refKind = TYP_REF;
  3271.             goto REF_PREF;
  3272.  
  3273.         case tkMul:
  3274.  
  3275.             /* This is a pointer declarator */
  3276.  
  3277.             refKind = TYP_PTR;
  3278.  
  3279.         REF_PREF:
  3280.  
  3281.             if  (forReal)
  3282.             {
  3283.                 if  (baseType)
  3284.                 {
  3285.                     baseType =
  3286.                     innerTyp = parseStab->stNewRefType(refKind, baseType);
  3287.                     innerRef = NULL;
  3288.                 }
  3289.                 else
  3290.                 {
  3291.                     tempType = parseStab->stNewRefType(refKind, innerTyp);
  3292.  
  3293.                     if  (!innerTyp)
  3294.                         innerRef = &tempType->tdRef.tdrBase;
  3295.  
  3296.                     innerTyp = tempType;
  3297.                 }
  3298.             }
  3299.  
  3300.             if  (modsPtr->dmMod &   (DM_CONST|DM_VOLATILE))
  3301.             {
  3302.                 // ISSUE: May need to save const/volatile modifiers on ptr/ref!
  3303.  
  3304.                  modsPtr->dmMod &= ~(DM_CONST|DM_VOLATILE);
  3305.             }
  3306.  
  3307.             ourScanner->scan();
  3308.             continue;
  3309.         }
  3310.         break;
  3311.     }
  3312.  
  3313. DONE_PREF:
  3314.  
  3315.     /* Next we expect the name being declared */
  3316.  
  3317.     switch (ourScanner->scanTok.tok)
  3318.     {
  3319.     case tkID:
  3320.  
  3321.         /* We've got the name */
  3322.  
  3323.         if  ((nameMode & DN_MASK) == DN_NONE)
  3324.             parseComp->cmpError(ERRbadIdent);
  3325.  
  3326.         /* Record the name and consume it */
  3327.  
  3328.         name = ourScanner->scanTok.id.tokIdent;
  3329.  
  3330.     GOT_ID:
  3331.  
  3332.         ourScanner->scan();
  3333.  
  3334.         /* We don't have any outer specifiers */
  3335.  
  3336.         outerTyp = NULL;
  3337.  
  3338.         /* Is the name qualified? */
  3339.  
  3340.         qual = NULL;
  3341.  
  3342.         if  (ourScanner->scanTok.tok == tkDot ||
  3343.              ourScanner->scanTok.tok == tkColon2)
  3344.         {
  3345.             if  (!(nameMode & DN_QUALOK))
  3346.                 parseComp->cmpError(ERRbadQualid);
  3347.  
  3348.             qual = parseQualName(name, false);
  3349.             name = NULL;
  3350.         }
  3351.  
  3352.         break;
  3353.  
  3354.     case tkLParen:
  3355.  
  3356.         /* Consume the "(" */
  3357.  
  3358.         ourScanner->scan();
  3359.  
  3360.         /* Parse the inner declarator term */
  3361.  
  3362.         outerTyp = parseDclrtrTerm(nameMode,
  3363.                                    forReal,
  3364.                                    modsPtr,
  3365.                                    NULL,
  3366.                                    &outerRef,
  3367.                                    &name,
  3368.                                    &qual);
  3369.  
  3370.         /* Make sure we have a closing ")" */
  3371.  
  3372.         if  (ourScanner->scanTok.tok != tkRParen)
  3373.             parseComp->cmpError(ERRnoRparen);
  3374.         else
  3375.             ourScanner->scan();
  3376.  
  3377.         break;
  3378.  
  3379.     case tkOPERATOR:
  3380.  
  3381.         /* Make sure the operator name looks OK */
  3382.  
  3383.         switch (ourScanner->scan())
  3384.         {
  3385.         case tkIMPLICIT:
  3386.         case tkEXPLICIT:
  3387.             break;
  3388.  
  3389.         case tkID:
  3390.  
  3391.             if  (!strcmp(ourScanner->scanTok.id.tokIdent->idSpelling(), "equals"))
  3392.             {
  3393.                 ourScanner->scanTok.tok = tkEQUALS;
  3394.                 break;
  3395.             }
  3396.  
  3397.             if  (!strcmp(ourScanner->scanTok.id.tokIdent->idSpelling(), "compare"))
  3398.             {
  3399.                 ourScanner->scanTok.tok = tkCOMPARE;
  3400.                 break;
  3401.             }
  3402.  
  3403.             goto OPR_ERR;
  3404.  
  3405.         default:
  3406.             if  (hashTab::tokenOvlOper(ourScanner->scanTok.tok))
  3407.                 break;
  3408.  
  3409.         OPR_ERR:
  3410.  
  3411.             parseComp->cmpError(ERRbadOperNm);
  3412.             UNIMPL("how do we recover from this?");
  3413.         }
  3414.  
  3415.         name = parseHash->tokenToIdent(ourScanner->scanTok.tok);
  3416.  
  3417.         goto GOT_ID;
  3418.  
  3419.     default:
  3420.  
  3421.         /* Looks like there is no name, is that OK with the caller? */
  3422.  
  3423.         if  ((nameMode & DN_MASK) == DN_REQUIRED)
  3424.         {
  3425.             parseComp->cmpError(ERRnoIdent);
  3426.  
  3427.             /* Need to guarantee progress to avoid endless looping */
  3428.  
  3429.             if  (ourScanner->scanTok.tok == tkLCurly)
  3430.                 ourScanner->scanSkipText(tkLCurly, tkRCurly);
  3431.             ourScanner->scan();
  3432.         }
  3433.  
  3434.         outerTyp = NULL;
  3435.  
  3436.         name     = NULL;
  3437.         qual     = NULL;
  3438.         break;
  3439.     }
  3440.  
  3441. #ifdef  __SMC__
  3442. //printf("Token = %d '%s'\n", ourScanner->scanTok.tok, tokenNames[ourScanner->scanTok.tok]); fflush(stdout);
  3443. #endif
  3444.  
  3445.     /* Check for any suffixes (array and function declaration) */
  3446.  
  3447.     isManaged = parseComp->cmpManagedMode;
  3448.  
  3449.     for (;;)
  3450.     {
  3451.         switch (ourScanner->scanTok.tok)
  3452.         {
  3453.         case tkLParen:
  3454.  
  3455.             if  (forReal)
  3456.             {
  3457.                 TypDef          funcTyp;
  3458.                 ArgDscRec       args;
  3459.  
  3460.                 /* Parse the argument list */
  3461.  
  3462.                 parseArgList(args);
  3463.  
  3464.                 /* Create the fnc type and try to combine it with the element type */
  3465.  
  3466.                 if  (outerTyp)
  3467.                 {
  3468.                     /* Create the function type (we don't know the return type yet) */
  3469.  
  3470.                     *outerRef = funcTyp = ourSymTab->stNewFncType(args, NULL);
  3471.  
  3472.                     /* Update the "outer" types */
  3473.  
  3474.                      outerRef = &funcTyp->tdFnc.tdfRett;
  3475.                 }
  3476.                 else
  3477.                 {
  3478.                     funcTyp = ourSymTab->stNewFncType(args, innerTyp);
  3479.  
  3480.                     if  (!innerTyp)
  3481.                         innerRef = &funcTyp->tdFnc.tdfRett;
  3482.  
  3483.                     innerTyp = funcTyp;
  3484.                 }
  3485.             }
  3486.             else
  3487.             {
  3488.                 ourScanner->scanSkipText(tkLParen, tkRParen);
  3489.                 if  (ourScanner->scanTok.tok != tkRParen)
  3490.                     goto DONE;
  3491.                 ourScanner->scan();
  3492.             }
  3493.  
  3494.             continue;
  3495.  
  3496.         case tkLBrack:
  3497.  
  3498.             isManaged = false;
  3499.  
  3500.             if  (forReal)
  3501.             {
  3502.                 TypDef          arrayTyp;
  3503.  
  3504.                 DimDef          dims;
  3505.  
  3506.                 /* Parse the dimensions */
  3507.  
  3508.                 dims = parseDimList(isManaged);
  3509.  
  3510.                 /* Create the array type and try to combine it with the element type */
  3511.  
  3512.                 if  (outerTyp)
  3513.                 {
  3514.                     /* Create the array type (we don't know the element type yet) */
  3515.  
  3516.                     *outerRef = arrayTyp = ourSymTab->stNewArrType(dims, isManaged, NULL);
  3517.  
  3518.                     /* Update the "outer" types */
  3519.  
  3520.                      outerRef = &arrayTyp->tdArr.tdaElem;
  3521.                 }
  3522.                 else if (isManaged)
  3523.                 {
  3524.                     assert(baseType != NULL);
  3525.                     assert(innerTyp == NULL || innerTyp == baseType);
  3526.                     assert(innerRef == NULL);
  3527.  
  3528.                     baseType = innerTyp = ourSymTab->stNewArrType(dims, isManaged, baseType);
  3529.                 }
  3530.                 else
  3531.                 {
  3532.                     /* Create the array type (we don't know the element type yet) */
  3533.  
  3534.                     outerTyp = arrayTyp = ourSymTab->stNewArrType(dims, isManaged, NULL);
  3535.  
  3536.                     /* Update the "outer" types */
  3537.  
  3538.                     outerRef = &arrayTyp->tdArr.tdaElem;
  3539.                 }
  3540.             }
  3541.             else
  3542.             {
  3543.                 ourScanner->scanSkipText(tkLBrack, tkRBrack);
  3544.                 if  (ourScanner->scanTok.tok != tkRBrack)
  3545.                     goto DONE;
  3546.                 ourScanner->scan();
  3547.             }
  3548.             continue;
  3549.  
  3550.         case tkUNMANAGED:
  3551.  
  3552.             if  (ourScanner->scan() != tkLBrack)
  3553.             {
  3554.                 ourComp->cmpError(ERRbadUnmTyp);
  3555.                 continue;
  3556.             }
  3557.  
  3558.             isManaged = false;
  3559.             continue;
  3560.  
  3561.         default:
  3562.             break;
  3563.         }
  3564.  
  3565.         break;
  3566.     }
  3567.  
  3568. DONE:
  3569.  
  3570.     /* Return the type(s) and name(s) to the caller */
  3571.  
  3572.     if  (qualRet)
  3573.         *qualRet = qual;
  3574.  
  3575.     assert(nameRet); *nameRet = name;
  3576.  
  3577.     /* Combine inner and outer types if necessary */
  3578.  
  3579.     assert(baseRef);
  3580.  
  3581.     if  (outerTyp)
  3582.     {
  3583.         if  (innerTyp)
  3584.         {
  3585.             *outerRef = innerTyp;
  3586.              outerRef = innerRef;
  3587.         }
  3588.  
  3589.         *baseRef = outerRef;
  3590.         return     outerTyp;
  3591.     }
  3592.     else
  3593.     {
  3594.         *baseRef = innerRef;
  3595.         return     innerTyp;
  3596.     }
  3597. }
  3598.  
  3599. /*****************************************************************************
  3600.  *
  3601.  *  Parse a declarator.
  3602.  */
  3603.  
  3604. Ident               parser::parseDeclarator(DeclMod     mods,
  3605.                                             TypDef      baseType,
  3606.                                             dclrtrName  nameMode,
  3607.                                             TypDef    * typeRet,
  3608.                                             QualName  * qualRet,
  3609.                                             bool        forReal)
  3610. {
  3611.     Ident           name;
  3612.     TypDef          type;
  3613.     TypDef      *   tref;
  3614.  
  3615.     /* Now we look for the name being declared */
  3616.  
  3617.     type = parseDclrtrTerm(nameMode, forReal, mods, baseType, &tref, &name, qualRet);
  3618.  
  3619.     /* Special case "const type *" -- the const doesn't belong to the top level */
  3620.  
  3621.     if  (mods->dmMod & (DM_CONST|DM_VOLATILE))
  3622.     {
  3623.         /*
  3624.             HACK:   Remove const/volatile if it should have applied
  3625.                     to a sub-type and not the 'topmost' type.
  3626.          */
  3627.  
  3628.         if  (type && type->tdTypeKind == TYP_PTR)
  3629.             mods->dmMod &= ~(DM_CONST|DM_VOLATILE);
  3630.     }
  3631.  
  3632.     /* Return the type to the caller if he's interested */
  3633.  
  3634.     if  (typeRet)
  3635.     {
  3636.         /* Make sure we connect the base type */
  3637.  
  3638.         if  (type)
  3639.         {
  3640.             if  (tref)
  3641.                 *tref = baseType;
  3642.         }
  3643.         else
  3644.              type = baseType;
  3645.  
  3646.         assert(forReal);
  3647.         *typeRet = type;
  3648.     }
  3649.  
  3650.     return  name;
  3651. }
  3652.  
  3653. /*****************************************************************************
  3654.  *
  3655.  *  Parse a complete type reference (e.g. "const char *") and return the type.
  3656.  */
  3657.  
  3658. TypDef              parser::parseType()
  3659. {
  3660.     declMods        mods;
  3661.     TypDef          type;
  3662.  
  3663.     /* Parse any leading modifiers */
  3664.  
  3665.     parseDeclMods(ACL_DEFAULT, &mods);
  3666.  
  3667.     /* Parse the type specification */
  3668.  
  3669.     type = parseTypeSpec(&mods, true);
  3670.  
  3671.     /* Parse the declarator */
  3672.  
  3673.     parseDeclarator(&mods, type, DN_OPTIONAL, &type, NULL, true);
  3674.  
  3675.     return  type;
  3676. }
  3677.  
  3678. /*****************************************************************************
  3679.  *
  3680.  *  Returns true if what follows in the source file looks like a constructor
  3681.  *  declaration.
  3682.  */
  3683.  
  3684. bool                parser::parseIsCtorDecl(SymDef clsSym)
  3685. {
  3686.     Token           tsav;
  3687.     unsigned        line;
  3688.  
  3689.     bool            result = false;
  3690.     Scanner         ourScanner = parseScan;
  3691.  
  3692.     if  (ourScanner->scanTok.tok == tkID && clsSym == NULL ||
  3693.          ourScanner->scanTok.id.tokIdent == clsSym->sdName)
  3694.     {
  3695.         scanPosTP       tokenPos;
  3696.  
  3697.         /* Start recording tokens so that we can back up later */
  3698.  
  3699.         if  (clsSym)
  3700.         {
  3701.             tokenPos = ourScanner->scanTokMarkPos(tsav, line);
  3702.  
  3703.             /* Swallow the identifier */
  3704.  
  3705.             ourScanner->scan();
  3706.         }
  3707.         else
  3708.         {
  3709.             QualName            qual;
  3710.  
  3711.             tokenPos = ourScanner->scanTokMarkPLA(tsav, line);
  3712.  
  3713.             qual = parseQualName(false);
  3714.  
  3715.             if  (qual && qual->qnCount >= 2)
  3716.             {
  3717.                 unsigned        qcnt = qual->qnCount;
  3718.  
  3719.                 if  (qual->qnTable[qcnt - 1] != qual->qnTable[qcnt - 2])
  3720.                     goto DONE;
  3721.             }
  3722.         }
  3723.  
  3724.         /* Does "()" or "(typespec ......)" follow? */
  3725.  
  3726.         if  (ourScanner->scanTok.tok == tkLParen)
  3727.         {
  3728.             switch (ourScanner->scan())
  3729.             {
  3730.             default:
  3731.                 if  (!parseIsTypeSpec(true))
  3732.                     break;
  3733.  
  3734.                 // Fall through ...
  3735.  
  3736.             case tkIN:
  3737.             case tkOUT:
  3738.             case tkINOUT:
  3739.             case tkRParen:
  3740.                 result = true;
  3741.                 goto DONE;
  3742.             }
  3743.         }
  3744.  
  3745.         /* Not a constructor, we'll return "false" */
  3746.  
  3747.     DONE:
  3748.  
  3749.         ourScanner->scanTokRewind(tokenPos, line, &tsav);
  3750.     }
  3751.  
  3752.     return  result;
  3753. }
  3754.  
  3755. /*****************************************************************************
  3756.  *
  3757.  *  Prepare the specified text section for parsing.
  3758.  */
  3759.  
  3760. void                parser::parsePrepText(DefSrc                def,
  3761.                                           SymDef                compUnit,
  3762.                                           OUT parserState REF   save)
  3763. {
  3764.     save.psSaved = parseReadingText;
  3765.  
  3766.     if  (parseReadingText)
  3767.     {
  3768.         parseScan->scanSuspend(save.psScanSt);
  3769.         save.psCurComp = parseComp->cmpErrorComp;
  3770.     }
  3771.  
  3772.     parseReadingText = true;
  3773.  
  3774. #ifdef  DEBUG
  3775.     parseReadingTcnt++;
  3776. #endif
  3777.  
  3778.     assert(compUnit && compUnit->sdSymKind == SYM_COMPUNIT);
  3779.  
  3780.     parseComp->cmpErrorComp = compUnit;
  3781.     parseComp->cmpErrorTree = NULL;
  3782.  
  3783.     parseScan->scanRestart(compUnit,
  3784.                            compUnit->sdComp.sdcSrcFile,
  3785.                            def->dsdBegPos,
  3786. //                         def->dsdEndPos,
  3787.                            def->dsdSrcLno,
  3788. //                         def->dsdSrcCol,
  3789.                            parseAllocPerm);
  3790. }
  3791.  
  3792. /*****************************************************************************
  3793.  *
  3794.  *  We're finished parsing a section of source code, restore previous state
  3795.  *  if there was any.
  3796.  */
  3797.  
  3798. void                parser::parseDoneText(IN parserState REF save)
  3799. {
  3800.     parseReadingText = save.psSaved;
  3801.  
  3802. #ifdef  DEBUG
  3803.     assert(parseReadingTcnt); parseReadingTcnt--;
  3804. #endif
  3805.  
  3806.     if  (parseReadingText)
  3807.     {
  3808.         parseScan->scanResume(save.psScanSt);
  3809.         parseComp->cmpErrorComp = save.psCurComp;
  3810.     }
  3811. }
  3812.  
  3813. /*****************************************************************************
  3814.  *
  3815.  *  Set the error information to the specified text section.
  3816.  */
  3817.  
  3818. void                parser::parseSetErrPos(DefSrc def, SymDef compUnit)
  3819. {
  3820.     assert(parseReadingText == 0);
  3821.  
  3822.     assert(compUnit && compUnit->sdSymKind == SYM_COMPUNIT);
  3823.  
  3824.     parseComp->cmpErrorComp = compUnit;
  3825.     parseComp->cmpErrorTree = NULL;
  3826.  
  3827.     parseScan->scanSetCpos(compUnit->sdComp.sdcSrcFile, def->dsdSrcLno);
  3828. }
  3829.  
  3830. /*****************************************************************************
  3831.  *
  3832.  *  Parse a (possibly empty) list of array dimensions.
  3833.  */
  3834.  
  3835. DimDef              parser::parseDimList(bool isManaged)
  3836. {
  3837.     Compiler        ourComp    = parseComp;
  3838.     SymTab          ourSymTab  = parseStab;
  3839.     Scanner         ourScanner = parseScan;
  3840.  
  3841.     DimDef          dimList    = NULL;
  3842.     DimDef          dimLast    = NULL;
  3843.  
  3844.     assert(ourScanner->scanTok.tok == tkLBrack);
  3845.  
  3846.     switch (ourScanner->scan())
  3847.     {
  3848.     case tkRBrack:
  3849.  
  3850.         /* This is "[]", an array without a dimension */
  3851.  
  3852. #if MGDDATA
  3853.         dimList = new DimDef;
  3854. #else
  3855.         dimList =    (DimDef)parseAllocPerm->nraAlloc(sizeof(*dimList));
  3856. #endif
  3857.  
  3858.         dimList->ddNoDim   = true;
  3859.         dimList->ddIsConst = false;
  3860.         dimList->ddNext    = NULL;
  3861.  
  3862.         ourScanner->scan();
  3863.         break;
  3864.  
  3865.     case tkQMark:
  3866.  
  3867.         /* If this is a totally generic array, just return NULL */
  3868.  
  3869.         if  (isManaged && ourScanner->scanLookAhead() == tkRBrack)
  3870.         {
  3871.             ourScanner->scan(); assert(ourScanner->scanTok.tok == tkRBrack);
  3872.             ourScanner->scan();
  3873.  
  3874.             break;
  3875.         }
  3876.  
  3877.         // Fall through ....
  3878.  
  3879.     default:
  3880.  
  3881.         /* Presumably we have one or more dimensions here */
  3882.  
  3883.         for (;;)
  3884.         {
  3885.             DimDef          dimThis;
  3886.  
  3887.             /* Allocate a dimension entry and add it to the list */
  3888.  
  3889. #if MGDDATA
  3890.             dimThis = new DimDef;
  3891. #else
  3892.             dimThis =    (DimDef)parseAllocPerm->nraAlloc(sizeof(*dimThis));
  3893. #endif
  3894.  
  3895.             dimThis->ddNoDim    = false;
  3896.             dimThis->ddIsConst  = false;
  3897. #ifdef  DEBUG
  3898.             dimThis->ddDimBound = false;
  3899. #endif
  3900.  
  3901.             dimThis->ddNext     = NULL;
  3902.  
  3903.             if  (dimLast)
  3904.                 dimLast->ddNext = dimThis;
  3905.             else
  3906.                 dimList         = dimThis;
  3907.             dimLast = dimThis;
  3908.  
  3909.             /* Check for any weird dimension cases */
  3910.  
  3911.             switch (ourScanner->scanTok.tok)
  3912.             {
  3913.                 tokens          nextTok;
  3914.  
  3915.             case tkMul:
  3916.  
  3917.                 if  (isManaged)
  3918.                 {
  3919.                     /* Is the dimension a simple "*" ? */
  3920.  
  3921.                     nextTok = ourScanner->scanLookAhead();
  3922.                     if  (nextTok == tkComma || nextTok == tkRBrack)
  3923.                     {
  3924.                         ourScanner->scan();
  3925.                         dimThis->ddNoDim = true;
  3926.                         break;
  3927.                     }
  3928.                 }
  3929.  
  3930.                 // Fall through ...
  3931.  
  3932.             default:
  3933.  
  3934.                 /* Parse the dimension expression and save it */
  3935.  
  3936.                 dimThis->ddLoTree  = parseExprComma();
  3937.  
  3938.                 /* Is there an upper bound as well? */
  3939.  
  3940.                 if  (ourScanner->scanTok.tok == tkDot2)
  3941.                 {
  3942.                     ourScanner->scan();
  3943.                     dimThis->ddHiTree = parseExprComma();
  3944.                 }
  3945.                 else
  3946.                 {
  3947.                     dimThis->ddHiTree = NULL;
  3948.                 }
  3949.  
  3950.                 break;
  3951.  
  3952.             case tkComma:
  3953.             case tkRBrack:
  3954.  
  3955.                 if  (!isManaged)
  3956.                     parseComp->cmpError(ERRnoDimDcl);
  3957.  
  3958.                 dimThis->ddNoDim = true;
  3959.                 break;
  3960.             }
  3961.  
  3962.             if  (ourScanner->scanTok.tok != tkComma)
  3963.                 break;
  3964.  
  3965.             if  (!isManaged)
  3966.                 parseComp->cmpError(ERRua2manyDims);
  3967.  
  3968.             ourScanner->scan();
  3969.         }
  3970.  
  3971.         chkCurTok(tkRBrack, ERRnoRbrack);
  3972.     }
  3973.  
  3974.     return  dimList;
  3975. }
  3976.  
  3977. /*****************************************************************************
  3978.  *
  3979.  *  Given a list of argument types, create an argument list descriptor. The
  3980.  *  caller supplies the count so that can we check that a NULL terminates
  3981.  *  the list.
  3982.  */
  3983.  
  3984. void    _cdecl      parser::parseArgListNew(ArgDscRec & argDsc,
  3985.                                             unsigned    argCnt,
  3986.                                             bool        argNames, ...)
  3987. {
  3988.     va_list         args;
  3989.  
  3990.     ArgDef          list = NULL;
  3991.     ArgDef          last = NULL;
  3992.     ArgDef          desc;
  3993.  
  3994.     va_start(args, argNames);
  3995.  
  3996.     /* Clear the arglist descriptor */
  3997.  
  3998. #if MGDDATA
  3999.     argDsc = new ArgDscRec;
  4000. #else
  4001.     memset(&argDsc, 0, sizeof(argDsc));
  4002. #endif
  4003.  
  4004.     /* Save the argument count */
  4005.  
  4006.     argDsc.adCount = argCnt;
  4007.  
  4008.     while (argCnt--)
  4009.     {
  4010.         TypDef          argType;
  4011.         Ident           argName = NULL;
  4012.  
  4013.         argType = va_arg(args, TypDef); assert(argType);
  4014.  
  4015.         if  (argNames)
  4016.         {
  4017.             const   char *  argNstr;
  4018.  
  4019.             argNstr = (const char *)(va_arg(args, int)); assert(argNstr);
  4020.             argName = parseHash->hashString(argNstr);
  4021.         }
  4022.  
  4023.         /* Create an argument entry */
  4024.  
  4025. #if MGDDATA
  4026.         desc = new ArgDef;
  4027. #else
  4028.         desc =    (ArgDef)parseAllocPerm->nraAlloc(sizeof(*desc));
  4029. #endif
  4030.  
  4031.         desc->adType  = argType;
  4032.         desc->adName  = argName;
  4033.  
  4034. #ifdef  DEBUG
  4035.         desc->adIsExt = false;
  4036. #endif
  4037.  
  4038.         /* Append the argument to the end of the list */
  4039.  
  4040.         if  (list)
  4041.             last->adNext = desc;
  4042.         else
  4043.             list         = desc;
  4044.  
  4045.         last = desc;
  4046.     }
  4047.  
  4048.     if  (last)
  4049.         last->adNext = NULL;
  4050.  
  4051.     argDsc.adArgs = list;
  4052.  
  4053.     /* Make sure the list terminates with a NULL where we expect it */
  4054.  
  4055. #if defined(__IL__) && defined(_MSC_VER)
  4056.     assert(va_arg(args,    int) ==    0);
  4057. #else
  4058.     assert(va_arg(args, void *) == NULL);
  4059. #endif
  4060.  
  4061.     va_end(args);
  4062. }
  4063.  
  4064. /*****************************************************************************
  4065.  *
  4066.  *  Parse a function parameter list declaration.
  4067.  */
  4068.  
  4069. void                parser::parseArgList(OUT ArgDscRec REF argDsc)
  4070. {
  4071.     Compiler        ourComp    = parseComp;
  4072. //  SymTab          ourSymTab  = parseStab;
  4073.     Scanner         ourScanner = parseScan;
  4074.  
  4075.     assert(ourScanner->scanTok.tok == tkLParen);
  4076.  
  4077.     /* Clear the arglist descriptor */
  4078.  
  4079. #if MGDDATA
  4080.     argDsc = new ArgDscRec;
  4081. #else
  4082.     memset(&argDsc, 0, sizeof(argDsc));
  4083. #endif
  4084.  
  4085.     /* Are there any arguments at all? */
  4086.  
  4087.     if  (ourScanner->scan() == tkRParen)
  4088.     {
  4089.         /* Empty argument list */
  4090.  
  4091.         argDsc.adArgs    = NULL;
  4092.  
  4093.         /* Swallow the closing ")" */
  4094.  
  4095.         ourScanner->scan();
  4096.     }
  4097.     else
  4098.     {
  4099.         /* Recursively parse the argument list */
  4100.  
  4101.         argDsc.adArgs = parseArgListRec(argDsc);
  4102.     }
  4103. }
  4104.  
  4105. /*****************************************************************************
  4106.  *
  4107.  *  Recursive helper that parses a function parameter list.
  4108.  */
  4109.  
  4110. ArgDef              parser::parseArgListRec(ArgDscRec &argDsc)
  4111. {
  4112.     declMods        mods;
  4113.     TypDef          type;
  4114.     Ident           name;
  4115.     ArgDef          next;
  4116.     ArgDef          arec;
  4117.     SymXinfo        attr;
  4118.  
  4119.     Compiler        ourComp    = parseComp;
  4120. //  SymTab          ourSymTab  = parseStab;
  4121.     Scanner         ourScanner = parseScan;
  4122.  
  4123.     unsigned        argFlags   = 0;
  4124.     constVal        argDef;
  4125.  
  4126.     /* Check for a parameter mode and ellipsis */
  4127.  
  4128. MODE:
  4129.  
  4130.     switch (ourScanner->scanTok.tok)
  4131.     {
  4132.         unsigned        attrMask;
  4133.         genericBuff     attrAddr;
  4134.         size_t          attrSize;
  4135.         SymDef          attrCtor;
  4136.  
  4137.     case tkIN:
  4138.         ourScanner->scan();
  4139.         break;
  4140.  
  4141.     case tkBYREF:
  4142.         argFlags |= ARGF_MODE_REF;
  4143.         goto EXT_ARG;
  4144.  
  4145.     case tkOUT:
  4146.         argFlags |= ARGF_MODE_OUT;
  4147.         goto EXT_ARG;
  4148.  
  4149.     case tkINOUT:
  4150.         argFlags |= ARGF_MODE_INOUT;
  4151.  
  4152.     EXT_ARG:
  4153.  
  4154.         /* We know we will need a "big" argument record */
  4155.  
  4156.         argDsc.adExtRec = true;
  4157.  
  4158.         ourScanner->scan();
  4159.         break;
  4160.  
  4161.     case tkEllipsis:
  4162.  
  4163.         if  (ourScanner->scan() == tkRParen)
  4164.             ourScanner->scan();
  4165.         else
  4166.             parseComp->cmpError(ERRnoRparen);
  4167.  
  4168.         argDsc.adVarArgs = true;
  4169.  
  4170.         return  NULL;
  4171.  
  4172.     case tkATTRIBUTE:
  4173.  
  4174.         attrCtor = parseAttribute(ATGT_Parameters, attrMask,
  4175.                                                    attrAddr,
  4176.                                                    attrSize);
  4177.  
  4178.         if  (attrSize)
  4179.             attr = parseComp->cmpAddXtraInfo(attr, attrCtor, attrMask, attrSize, attrAddr);
  4180.         else
  4181.             attr = NULL;    
  4182.  
  4183.         goto GOT_ATTR;
  4184.  
  4185.     case tkLBrack:
  4186.  
  4187.         attr = parseBrackAttr(true, ATTR_MASK_NATIVE_TYPE);
  4188.  
  4189.     GOT_ATTR:
  4190.  
  4191.         if  (attr)
  4192.         {
  4193.             argDsc.adExtRec = true;
  4194.             argDsc.adAttrs  = true;
  4195.  
  4196.             argFlags |= ARGF_MARSH_ATTR;
  4197.         }
  4198.  
  4199.         if  (ourScanner->scanTok.tok == tkIN   ) goto MODE;
  4200.         if  (ourScanner->scanTok.tok == tkOUT  ) goto MODE;
  4201.         if  (ourScanner->scanTok.tok == tkINOUT) goto MODE;
  4202.         break;
  4203.     }
  4204.  
  4205.     /* Parse any leading modifiers */
  4206.  
  4207.     parseDeclMods(ACL_DEFAULT, &mods);
  4208.  
  4209.     /* Parse the type specification */
  4210.  
  4211.     type = parseTypeSpec(&mods, true);
  4212.  
  4213.     /* Parse the declarator */
  4214.  
  4215. //  static int x; if (++x == 0) forceDebugBreak();
  4216.  
  4217.     name = parseDeclarator(&mods, type, DN_OPTIONAL, &type, NULL, true);
  4218.  
  4219.     if  (!name && ourComp->cmpConfig.ccPedantic)
  4220.         ourComp->cmpWarn(WRNnoArgName);
  4221.  
  4222.     /* Is the argument a reference or an unmanaged array? */
  4223.  
  4224.     switch (type->tdTypeKind)
  4225.     {
  4226.     case TYP_REF:
  4227.  
  4228.         /* Is this the implicit reference to a managed class? */
  4229.  
  4230.         if  (type->tdIsImplicit)
  4231.         {
  4232.             assert(type->tdRef.tdrBase->tdClass.tdcRefTyp == type);
  4233.             break;
  4234.         }
  4235.  
  4236.         /* Strip the reference and check for "void &" */
  4237.  
  4238.         type = type->tdRef.tdrBase;
  4239.  
  4240.         if  (type->tdTypeKind == TYP_VOID)
  4241.         {
  4242.             if  (argFlags & (ARGF_MODE_OUT|ARGF_MODE_INOUT))
  4243.                 parseComp->cmpError(ERRbyref2refany);
  4244.  
  4245.             type = parseStab->stIntrinsicType(TYP_REFANY);
  4246.             break;
  4247.         }
  4248.  
  4249.         /* Record the argument mode */
  4250.  
  4251.         argFlags |= ARGF_MODE_REF;
  4252.  
  4253.         /* We know we will need a "big" argument record */
  4254.  
  4255.         argDsc.adExtRec = true;
  4256.  
  4257.         break;
  4258.  
  4259.     case TYP_VOID:
  4260.  
  4261.         /* Special case: "(void)" */
  4262.  
  4263.         if  (argDsc.adCount == 0 && ourScanner->scanTok.tok == tkRParen)
  4264.         {
  4265.             parseComp->cmpWarn(WRNvoidFnc);
  4266.             ourScanner->scan();
  4267.             return  NULL;
  4268.         }
  4269.  
  4270.         parseComp->cmpError(ERRbadVoid);
  4271.         break;
  4272.  
  4273.     case TYP_FNC:
  4274.  
  4275.         /* Function types implicitly become pointers */
  4276.  
  4277.         type = parseStab->stNewRefType(TYP_PTR, type);
  4278.         break;
  4279.  
  4280.     case TYP_ARRAY:
  4281.  
  4282.         if  (!type->tdIsManaged)
  4283.         {
  4284.             /* Change the type to a pointer to the element */
  4285.  
  4286.             type = parseStab->stNewRefType(TYP_PTR, type->tdArr.tdaElem);
  4287.         }
  4288.  
  4289.         break;
  4290.     }
  4291.  
  4292.     /* Check the inside of the type */
  4293.  
  4294.     if  (type->tdTypeKind > TYP_lastIntrins)
  4295.         ourComp->cmpBindType(type, false, false);
  4296.  
  4297.     /* Is there a default argument value? */
  4298.  
  4299.     if  (ourScanner->scanTok.tok == tkAsg)
  4300.     {
  4301.         /* Swallow the "=" and parse the default value */
  4302.  
  4303.         ourScanner->scan();
  4304.  
  4305.         parseConstExpr(argDef, NULL, type);
  4306.  
  4307.         /* Flag the fact that we have a default value */
  4308.  
  4309.         argFlags |= ARGF_DEFVAL;
  4310.  
  4311.         /* We'll need a "big" argument record */
  4312.  
  4313.         argDsc.adDefs   = true;
  4314.         argDsc.adExtRec = true;
  4315.     }
  4316.  
  4317.     /* Is there another argument? */
  4318.  
  4319.     next = NULL;
  4320.  
  4321.     if  (ourScanner->scanTok.tok == tkComma)
  4322.     {
  4323.         ourScanner->scan();
  4324.  
  4325.         next = parseArgListRec(argDsc);
  4326.     }
  4327.     else
  4328.     {
  4329.         if      (ourScanner->scanTok.tok == tkRParen)
  4330.         {
  4331.             ourScanner->scan();
  4332.         }
  4333.         else
  4334.             parseComp->cmpError(ERRnoRparen);
  4335.     }
  4336.  
  4337.     /* Check for duplicate names */
  4338.  
  4339.     if  (name)
  4340.     {
  4341.         for (arec = next; arec; arec = arec->adNext)
  4342.         {
  4343.             if  (arec->adName == name)
  4344.             {
  4345.                 parseComp->cmpError(ERRdupArg, name);
  4346.                 break;
  4347.             }
  4348.         }
  4349.     }
  4350.  
  4351.     /* Allocate the argument descriptor */
  4352.  
  4353.     if  (argDsc.adExtRec)
  4354.     {
  4355.         ArgExt          xrec;
  4356.  
  4357. #if MGDDATA
  4358.         xrec = new ArgExt;
  4359. #else
  4360.         xrec =    (ArgExt)parseAllocPerm->nraAlloc(sizeof(*xrec));
  4361. #endif
  4362.  
  4363.         xrec->adFlags  = argFlags;
  4364.         xrec->adDefVal = argDef;
  4365.         xrec->adAttrs  = attr;
  4366.  
  4367.         arec = xrec;
  4368.     }
  4369.     else
  4370.     {
  4371. #if MGDDATA
  4372.         arec = new ArgDef;
  4373. #else
  4374.         arec =    (ArgDef)parseAllocPerm->nraAlloc(sizeof(*arec));
  4375. #endif
  4376.     }
  4377.  
  4378.     arec->adNext  = next;
  4379.     arec->adType  = type;
  4380.     arec->adName  = name;
  4381.  
  4382. #ifdef  DEBUG
  4383.     arec->adIsExt = argDsc.adExtRec;
  4384. #endif
  4385.  
  4386.     /* Increment the total argument count and return */
  4387.  
  4388.     argDsc.adCount++;
  4389.  
  4390.     return  arec;
  4391. }
  4392.  
  4393. /*****************************************************************************
  4394.  *
  4395.  *  Swallow source text until one of the specified tokens is reached.
  4396.  */
  4397.  
  4398. void                parser::parseResync(tokens delim1, tokens delim2)
  4399. {
  4400.     Scanner         ourScanner = parseScan;
  4401.  
  4402.     while (ourScanner->scan() != tkEOF)
  4403.     {
  4404.         if  (ourScanner->scanTok.tok == delim1)
  4405.             return;
  4406.         if  (ourScanner->scanTok.tok == delim2)
  4407.             return;
  4408.  
  4409.         if  (ourScanner->scanTok.tok == tkLCurly)
  4410.             return;
  4411.         if  (ourScanner->scanTok.tok == tkRCurly)
  4412.             return;
  4413.     }
  4414. }
  4415.  
  4416. /*****************************************************************************
  4417.  *
  4418.  *  Add a new entry to a list of tree nodes.
  4419.  */
  4420.  
  4421. Tree                parser::parseAddToNodeList(      Tree       nodeList,
  4422.                                                INOUT Tree   REF nodeLast,
  4423.                                                      Tree       nodeAdd)
  4424. {
  4425.     Tree            nodeTemp;
  4426.  
  4427.     /* Create a new tree list node and append it at the end */
  4428.  
  4429.     nodeTemp = parseCreateOperNode(TN_LIST, nodeAdd, NULL);
  4430.  
  4431.     if  (nodeList)
  4432.     {
  4433.         assert(nodeLast);
  4434.  
  4435.         nodeLast->tnOp.tnOp2 = nodeTemp;
  4436.  
  4437.         nodeLast = nodeTemp;
  4438.  
  4439.         return  nodeList;
  4440.     }
  4441.     else
  4442.     {
  4443.         nodeLast = nodeTemp;
  4444.         return  nodeTemp;
  4445.     }
  4446. }
  4447.  
  4448. /*****************************************************************************
  4449.  *
  4450.  *  See if we have an abstract type spec + declarator followed by the given
  4451.  *  token. When 'isCast' is non-zero we also check if whatever follows the
  4452.  *  next token (which must be tkRParen) is an operand or operator. If the
  4453.  *  type is found, its type descriptor is returned and the current token
  4454.  *  will be the 'nxtTok' that follows the type.
  4455.  */
  4456.  
  4457. TypDef              parser::parseCheck4type(tokens nxtTok, bool isCast)
  4458. {
  4459.     Scanner         ourScanner = parseScan;
  4460.  
  4461.     unsigned        ecnt;
  4462.     declMods        mods;
  4463.     TypDef          type;
  4464.     scanPosTP       tpos;
  4465.  
  4466.     Token           tsav;
  4467.     unsigned        line;
  4468.  
  4469.     /* Can the current token possibly start a type? */
  4470.  
  4471.     if  (!parseHash->tokenBegsTyp(ourScanner->scanTok.tok))
  4472.         return  NULL;
  4473.  
  4474.     /* Start recording tokens so that we can back up later */
  4475.  
  4476.     tpos = ourScanner->scanTokMarkPos(tsav, line);
  4477.  
  4478.     /*
  4479.         See if have a type - note that we can't allow types to be declared
  4480.         right now, since we're recording tokens. We also don't want any
  4481.         errors to be reported - if the type doesn't look right we'll tell
  4482.         the caller without issuing any error messages.
  4483.       */
  4484.  
  4485.     ecnt = parseComp->cmpStopErrorMessages();
  4486.  
  4487.     assert(parseNoTypeDecl == false);
  4488.     parseNoTypeDecl = true;
  4489.  
  4490.            parseDeclMods(ACL_DEFAULT, &mods);
  4491.     type = parseTypeSpec(&mods, true);
  4492.  
  4493.     parseNoTypeDecl = false;
  4494.  
  4495.     /* Does it still look like we could have a type? */
  4496.  
  4497.     if  (!parseComp->cmpRestErrorMessages(ecnt) && type)
  4498.     {
  4499.         ecnt = parseComp->cmpStopErrorMessages();
  4500.  
  4501.         /* Parse the declarator */
  4502.  
  4503.         parseDeclarator(&mods, type, DN_NONE, NULL, NULL, false);
  4504.  
  4505.         /* Did the above call try to issue any errors? */
  4506.  
  4507.         if  (!parseComp->cmpRestErrorMessages(ecnt))
  4508.         {
  4509.             /* No - it still looks like a type, is it followed by 'nxtTok' ? */
  4510.  
  4511.             if  (ourScanner->scanTok.tok == nxtTok)
  4512.             {
  4513.                 unsigned        prec;
  4514.                 treeOps         oper;
  4515.  
  4516.                 /* Do we require a cast check? */
  4517.  
  4518.                 if  (!isCast)
  4519.                     goto ITS_TYPE;
  4520.  
  4521.                 /* Is the "(type)" sequence followed by an operator or terminator? */
  4522.  
  4523.                 parseScan->scan();
  4524.  
  4525.                 if  (parseHash->tokenIsUnop (parseScan->scanTok.tok, &prec, &oper) && oper != TN_NONE)
  4526.                     goto ITS_TYPE;
  4527.  
  4528.                 if  (parseHash->tokenIsBinop(parseScan->scanTok.tok, &prec, &oper) && oper != TN_NONE)
  4529.                     goto RST_NTYP;
  4530.  
  4531.                 switch (ourScanner->scanTok.tok)
  4532.                 {
  4533.                 case tkID:
  4534.                 case tkTHIS:
  4535.                 case tkBASECLASS:
  4536.  
  4537.                 case tkNEW:
  4538.                 case tkTHROW:
  4539.                 case tkREFADDR:
  4540.  
  4541.                 case tkColon2:
  4542.                 case tkLParen:
  4543.  
  4544.                 case tkNULL:
  4545.                 case tkTRUE:
  4546.                 case tkFALSE:
  4547.                 case tkIntCon:
  4548.                 case tkLngCon:
  4549.                 case tkFltCon:
  4550.                 case tkDblCon:
  4551.                 case tkStrCon:
  4552.  
  4553.                 case tkAnd:
  4554.                 case tkAdd:
  4555.                 case tkSub:
  4556.                 case tkMul:
  4557.                 case tkBang:
  4558.                 case tkTilde:
  4559.  
  4560.                     goto ITS_TYPE;
  4561.                 }
  4562.             }
  4563.         }
  4564.     }
  4565.  
  4566.     /* Looks like it's not a cast after all, backtrack and parse "(expr)" */
  4567.  
  4568. RST_NTYP:
  4569.  
  4570.     ourScanner->scanTokRewind(tpos, line, &tsav);
  4571.  
  4572.     return  NULL;
  4573.  
  4574. ITS_TYPE:
  4575.  
  4576.     /* We can't allow types to be declared right now since we're replaying tokens */
  4577.  
  4578.     assert(parseNoTypeDecl == false); parseNoTypeDecl = true;
  4579.  
  4580.     /* It looks like a type; backtrack and parse it as such */
  4581.  
  4582.     ourScanner->scanTokRewind(tpos, line, &tsav);
  4583.  
  4584. #ifdef  DEBUG
  4585.     unsigned        errs = parseComp->cmpErrorCount;
  4586. #endif
  4587.  
  4588.     /* Parse (optional) modifiers and the base type spec */
  4589.  
  4590.            parseDeclMods(ACL_DEFAULT, &mods);
  4591.     type = parseTypeSpec(&mods, true);
  4592.  
  4593.     /* Parse the declarator */
  4594.  
  4595.     parseDeclarator(&mods, type, DN_NONE, &type, NULL, true);
  4596.  
  4597.     /* Allow types to be declared once again */
  4598.  
  4599.     parseNoTypeDecl = false;
  4600.  
  4601.     /* We should not have received any errors, right? */
  4602.  
  4603.     assert(errs == parseComp->cmpErrorCount);
  4604.  
  4605.     /* Make sure we find the token we expect to follow */
  4606.  
  4607.     assert(ourScanner->scanTok.tok == nxtTok);
  4608.  
  4609.     return  type;
  4610. }
  4611.  
  4612. /*****************************************************************************
  4613.  *
  4614.  *  Parse either "(type)expr" or "(expr)", it's actually pretty hard to tell
  4615.  *  these apart.
  4616.  */
  4617.  
  4618. Tree                parser::parseCastOrExpr()
  4619. {
  4620.     Scanner         ourScanner = parseScan;
  4621.  
  4622.     TypDef          type;
  4623.     Tree            tree;
  4624.  
  4625. //  static int x; if (++x == 0) forceDebugBreak();
  4626.  
  4627.     assert(ourScanner->scanTok.tok == tkLParen); ourScanner->scan();
  4628.  
  4629.     /* Can the token after the opening "(" possibly start a type? */
  4630.  
  4631.     if  (parseHash->tokenBegsTyp(ourScanner->scanTok.tok))
  4632.     {
  4633.         type = parseCheck4type(tkRParen, true);
  4634.         if  (type)
  4635.         {
  4636.             /* Consume the ")" that we know follows the type */
  4637.  
  4638.             assert(ourScanner->scanTok.tok == tkRParen); ourScanner->scan();
  4639.  
  4640.             /* Create the cast node and parse the operand */
  4641.  
  4642.             tree = parseCreateOperNode(TN_CAST, parseExpr(99, NULL), NULL);
  4643.             tree->tnFlags |= TNF_EXP_CAST;
  4644.  
  4645.             /* Store the target type in the cast node and we're done */
  4646.  
  4647.             tree->tnType = type;
  4648.  
  4649.             return  tree;
  4650.         }
  4651.     }
  4652.  
  4653.     /* This cannot be a cast, process as parenthesised expression */
  4654.  
  4655.     tree = parseExpr(0, NULL);
  4656.     tree->tnFlags |= TNF_PAREN;
  4657.  
  4658.     chkCurTok(tkRParen, ERRnoRparen);
  4659.  
  4660.     return  tree;
  4661. }
  4662.  
  4663. /*****************************************************************************
  4664.  *
  4665.  *  Swallow an expression without analyzing it at all.
  4666.  */
  4667.  
  4668. void                parser::parseExprSkip()
  4669. {
  4670.     unsigned        parens = 0;
  4671.  
  4672.     Scanner         ourScanner = parseScan;
  4673.  
  4674.     for (;;)
  4675.     {
  4676.         switch (ourScanner->scan())
  4677.         {
  4678.         case tkSColon:
  4679.         case tkLCurly:
  4680.         case tkRCurly:
  4681.             return;
  4682.  
  4683.         case tkLParen:
  4684.             parens++;
  4685.             break;
  4686.  
  4687.         case tkRParen:
  4688.             if  (!parens)
  4689.                 return;
  4690.             parens--;
  4691.             break;
  4692.  
  4693.         case tkComma:
  4694.             if  (!parens)
  4695.                 return;
  4696.             break;
  4697.         }
  4698.     }
  4699. }
  4700.  
  4701. /*****************************************************************************
  4702.  *
  4703.  *  Parse a list of expressions.
  4704.  */
  4705.  
  4706. Tree                parser::parseExprList(tokens endTok)
  4707. {
  4708.     Tree            argList = NULL;
  4709.     Tree            argLast = NULL;
  4710.  
  4711.     Scanner         ourScanner = parseScan;
  4712.  
  4713. //  static int x; if (++x == 0) forceDebugBreak();
  4714.  
  4715.     /* Make sure things look kosher */
  4716.  
  4717.     assert((ourScanner->scanTok.tok == tkLParen && endTok == tkRParen) ||
  4718.            (ourScanner->scanTok.tok == tkLBrack && endTok == tkRBrack));
  4719.  
  4720.     /* Special case: check for an empty list */
  4721.  
  4722.     if  (ourScanner->scan() == endTok)
  4723.     {
  4724.         ourScanner->scan();
  4725.         return  NULL;
  4726.     }
  4727.  
  4728.     for (;;)
  4729.     {
  4730.         Tree            argTree;
  4731.  
  4732.         /* Parse the next value */
  4733.  
  4734.         argTree = parseExprComma();
  4735.  
  4736.         /* Add the expression to the list */
  4737.  
  4738.         argList = parseAddToNodeList(argList, argLast, argTree);
  4739.  
  4740.         /* Are there more arguments? */
  4741.  
  4742.         if  (ourScanner->scanTok.tok != tkComma)
  4743.             break;
  4744.  
  4745.         ourScanner->scan();
  4746.     }
  4747.  
  4748.     /* Issue an error if the ")" or "]" is not there */
  4749.  
  4750.     if  (ourScanner->scanTok.tok != endTok)
  4751.     {
  4752.         parseComp->cmpError((endTok == tkRParen) ? ERRnoRparen
  4753.                                                  : ERRnoRbrack);
  4754.     }
  4755.     else
  4756.     {
  4757.         /* Consume the ")" or "]" */
  4758.  
  4759.         ourScanner->scan();
  4760.     }
  4761.  
  4762.     return  argList;
  4763. }
  4764.  
  4765. /*****************************************************************************
  4766.  *
  4767.  *  Parse an XML class ctor argument list.
  4768.  */
  4769.  
  4770. /*****************************************************************************
  4771.  *
  4772.  *  Parse an expression term (e.g. a constant, variable, 'this').
  4773.  */
  4774.  
  4775. Tree                parser::parseTerm(Tree tree)
  4776. {
  4777.     Scanner         ourScanner = parseScan;
  4778.  
  4779.     if  (tree == NULL)
  4780.     {
  4781.         /*
  4782.             Note:   if you add any new tokens below that can start
  4783.                     an expression, don't forget to add them to the
  4784.                     parseCastOrExpr() function as well.
  4785.          */
  4786.  
  4787. //      static int x; if (++x == 0) forceDebugBreak();
  4788.  
  4789.         switch  (ourScanner->scanTok.tok)
  4790.         {
  4791.         case tkID:
  4792.  
  4793. #if 0
  4794.  
  4795.             /* Check for the "typename(expr)" style of cast */
  4796.  
  4797.             if  (parseIsTypeSpec(false))
  4798.                 goto NEW_CAST;
  4799.  
  4800. #endif
  4801.  
  4802.             /* The identifier may be or have been a qualified name */
  4803.  
  4804.             if  (ourScanner->scanTok.tok == tkID)
  4805.             {
  4806.                 tokens          nxtTok = ourScanner->scanLookAhead();
  4807.                 Ident           name   = ourScanner->scanTok.id.tokIdent;
  4808.  
  4809.                 if  (nxtTok == tkDot || nxtTok == tkColon2)
  4810.                 {
  4811.                     parseNameUse(false, true, true);
  4812.  
  4813.                     if  (ourScanner->scanTok.tok != tkID)
  4814.                         goto QUALID;
  4815.                 }
  4816.  
  4817.                 ourScanner->scan();
  4818.  
  4819.                 tree = parseCreateNameNode(name);
  4820.                 break;
  4821.             }
  4822.  
  4823.         QUALID:
  4824.  
  4825.             if  (ourScanner->scanTok.tok != tkQUALID)
  4826.             {
  4827.                 if  (ourScanner->scanTok.tok == tkHACKID)
  4828.                 {
  4829.                     tree = parseCreateUSymNode(ourScanner->scanTok.hackid.tokHackSym);
  4830.                     tree = parseCreateOperNode(TN_TYPEOF, tree, NULL);
  4831.                     ourScanner->scan();
  4832.                     break;
  4833.                 }
  4834.                 else
  4835.                 {
  4836.                     /* This should only happen after errors */
  4837.  
  4838.                     assert(parseComp->cmpErrorCount ||
  4839.                            parseComp->cmpErrorMssgDisabled);
  4840.  
  4841.                     return  parseCreateErrNode();
  4842.                 }
  4843.             }
  4844.  
  4845.             tree = parseCreateUSymNode(ourScanner->scanTok.qualid.tokQualSym,
  4846.                                        ourScanner->scanTok.qualid.tokQualScp);
  4847.  
  4848.             ourScanner->scan();
  4849.             break;
  4850.  
  4851.         case tkQUALID:
  4852.  
  4853.             /* Check for the "typename(expr)" style of cast */
  4854.  
  4855.             if  (parseIsTypeSpec(false))
  4856.                 goto NEW_CAST;
  4857.  
  4858.             tree = parseCreateUSymNode(ourScanner->scanTok.qualid.tokQualSym,
  4859.                                        ourScanner->scanTok.qualid.tokQualScp);
  4860.             ourScanner->scan();
  4861.             break;
  4862.  
  4863.         case tkIntCon:
  4864.             tree = parseCreateIconNode(ourScanner->scanTok.intCon.tokIntVal,
  4865.                                        ourScanner->scanTok.intCon.tokIntTyp);
  4866.             ourScanner->scan();
  4867.             break;
  4868.  
  4869.         case tkLngCon:
  4870.             tree = parseCreateLconNode(ourScanner->scanTok.lngCon.tokLngVal,
  4871.                                        ourScanner->scanTok.lngCon.tokLngTyp);
  4872.             ourScanner->scan();
  4873.             break;
  4874.  
  4875.         case tkFltCon:
  4876.             tree = parseCreateFconNode(ourScanner->scanTok.fltCon.tokFltVal);
  4877.             ourScanner->scan();
  4878.             break;
  4879.  
  4880.         case tkDblCon:
  4881.             tree = parseCreateDconNode(ourScanner->scanTok.dblCon.tokDblVal);
  4882.             ourScanner->scan();
  4883.             break;
  4884.  
  4885.         case tkStrCon:
  4886.             tree = parseCreateSconNode(ourScanner->scanTok.strCon.tokStrVal,
  4887.                                        ourScanner->scanTok.strCon.tokStrLen,
  4888.                                        ourScanner->scanTok.strCon.tokStrType,
  4889.                                        ourScanner->scanTok.strCon.tokStrWide);
  4890.  
  4891.             while (ourScanner->scan() == tkStrCon)
  4892.             {
  4893.                 tree = parseCreateSconNode(ourScanner->scanTok.strCon.tokStrVal,
  4894.                                            ourScanner->scanTok.strCon.tokStrLen,
  4895.                                            ourScanner->scanTok.strCon.tokStrType,
  4896.                                            ourScanner->scanTok.strCon.tokStrWide,
  4897.                                            tree);
  4898.             }
  4899.             break;
  4900.  
  4901.         case tkTHIS:
  4902.             tree = parseCreateOperNode(TN_THIS, NULL, NULL);
  4903.             if  (ourScanner->scan() == tkLParen)
  4904.             {
  4905.                 parseBaseCTcall = true;
  4906.                 parseThisCTcall = true;
  4907.             }
  4908.             break;
  4909.  
  4910.         case tkBASECLASS:
  4911.             tree = parseCreateOperNode(TN_BASE, NULL, NULL);
  4912.             if  (ourScanner->scan() == tkLParen)
  4913.                 parseBaseCTcall = true;
  4914.             break;
  4915.  
  4916.         case tkNULL:
  4917.             tree = parseCreateOperNode(TN_NULL, NULL, NULL);
  4918.             ourScanner->scan();
  4919.             break;
  4920.  
  4921.         case tkLParen:       // "(" expr ")"
  4922.             tree = parseCastOrExpr();
  4923.             break;
  4924.  
  4925.         case tkTRUE:
  4926.             ourScanner->scan();
  4927.             tree = parseCreateBconNode(1);
  4928.             break;
  4929.  
  4930.         case tkFALSE:
  4931.             ourScanner->scan();
  4932.             tree = parseCreateBconNode(0);
  4933.             break;
  4934.  
  4935.         case tkNEW:
  4936.             tree = parseNewExpr();
  4937.             break;
  4938.  
  4939.         case tkDELETE:
  4940.             ourScanner->scan();
  4941.             tree = parseCreateOperNode(TN_DELETE , parseExpr(), NULL);
  4942.             break;
  4943.  
  4944.         case tkARRAYLEN:
  4945.             chkNxtTok(tkLParen, ERRnoLparen);
  4946.             tree = parseCreateOperNode(TN_ARR_LEN, parseExpr(), NULL);
  4947.             chkCurTok(tkRParen, ERRnoRparen);
  4948.             break;
  4949.  
  4950.         case tkREFADDR:
  4951.             chkNxtTok(tkLParen, ERRnoLparen);
  4952.             tree = parseCreateOperNode(TN_REFADDR, parseExprComma(), NULL);
  4953.             if  (ourScanner->scanTok.tok == tkComma)
  4954.             {
  4955.                 Tree            typx;
  4956.  
  4957.                 ourScanner->scan();
  4958.  
  4959.                 typx = tree->tnOp.tnOp2 = parseCreateOperNode(TN_NONE, NULL, NULL);
  4960.                 typx->tnType = parseType();
  4961.             }
  4962.             else
  4963.                 parseComp->cmpError(ERRnoComma);
  4964.             chkCurTok(tkRParen, ERRnoRparen);
  4965.             break;
  4966.  
  4967.         default:
  4968.  
  4969.             if  (parseIsTypeSpec(false))
  4970.             {
  4971.                 declMods        mods;
  4972.                 TypDef          type;
  4973.  
  4974.             NEW_CAST:
  4975.  
  4976.                 /* What we expect here is "type(expr)" */
  4977.  
  4978.                 parseDeclMods(ACL_DEFAULT, &mods);
  4979.  
  4980.                 type = parseTypeSpec(&mods, true);
  4981.                 if  (!type)
  4982.                     return  parseCreateErrNode();
  4983.  
  4984.                 /* Make sure the expected "(" is present */
  4985.  
  4986.                 if  (ourScanner->scanTok.tok != tkLParen)
  4987.                 {
  4988.  
  4989.                     parseDeclarator(&mods, type, DN_OPTIONAL, &type, NULL, true);
  4990.  
  4991.                     /* We'll let the compiler decide what to do with this thing */
  4992.  
  4993.                     tree = parseCreateOperNode(TN_TYPE, NULL, NULL);
  4994.                     tree->tnType = type;
  4995.  
  4996.                     return  tree;
  4997.                 }
  4998.                 ourScanner->scan();
  4999.  
  5000.                 /* Create the cast node and parse the operand */
  5001.  
  5002.                 tree = parseCreateOperNode(TN_CAST, parseExpr(0, NULL), NULL);
  5003.                 tree->tnFlags |= TNF_EXP_CAST;
  5004.  
  5005.                 chkCurTok(tkRParen, ERRnoRparen);
  5006.  
  5007.                 /* Store the target type in the cast node and we're done */
  5008.  
  5009.                 tree->tnType = type;
  5010.                 break;
  5011.             }
  5012.  
  5013.             tree = parseCreateErrNode(ERRsyntax);
  5014.             parseResync(tkNone, tkNone);
  5015.             break;
  5016.         }
  5017.     }
  5018.  
  5019.     /* Check for any post-fix operators */
  5020.  
  5021.     for (;;)
  5022.     {
  5023.         switch  (ourScanner->scanTok.tok)
  5024.         {
  5025.             Tree            index;
  5026.  
  5027.         case tkDot:
  5028.             if  (ourScanner->scan() == tkID)
  5029.             {
  5030.                 tree = parseCreateOperNode(TN_DOT,
  5031.                                            tree,
  5032.                                            parseCreateNameNode(ourScanner->scanTok.id.tokIdent));
  5033.                 ourScanner->scan();
  5034.                 break;
  5035.             }
  5036.             return parseCreateErrNode(ERRnoIdent);
  5037.  
  5038.         case tkArrow:
  5039.             if  (ourScanner->scan() == tkID)
  5040.             {
  5041.                 tree = parseCreateOperNode(TN_ARROW,
  5042.                                            tree,
  5043.                                            parseCreateNameNode(ourScanner->scanTok.id.tokIdent));
  5044.                 ourScanner->scan();
  5045.                 break;
  5046.             }
  5047.             return parseCreateErrNode(ERRnoIdent);
  5048.  
  5049.         case tkLParen:
  5050.  
  5051.             /* Special case: va_arg takes a type as its second argument */
  5052.  
  5053.             if  (tree->tnOper == TN_NAME && tree->tnName.tnNameId == parseComp->cmpIdentVAget)
  5054.             {
  5055.                 Tree            arg1;
  5056.                 Tree            arg2;
  5057.  
  5058.                 ourScanner->scan();
  5059.  
  5060.                 /* va_arg expects an expression followed by a type */
  5061.  
  5062.                 arg1 = parseExprComma();
  5063.  
  5064.                 /* Do we have a second argument ? */
  5065.  
  5066.                 if  (ourScanner->scanTok.tok == tkComma)
  5067.                 {
  5068.                     TypDef          type;
  5069.  
  5070.                     ourScanner->scan();
  5071.  
  5072.                     /* We should have a type followed by ")" */
  5073.  
  5074.                     type = parseType();
  5075.                     if  (type)
  5076.                     {
  5077.                         if  (ourScanner->scanTok.tok == tkRParen)
  5078.                         {
  5079.                             /* Everything looks OK, consume the ")" */
  5080.  
  5081.                             ourScanner->scan();
  5082.  
  5083.                             /* Create a call with the two arguments */
  5084.  
  5085.                             arg2 = parseCreateOperNode(TN_TYPE, NULL, NULL);
  5086.                             arg2->tnType = type;
  5087.                             arg2 = parseCreateOperNode(TN_LIST, arg2, NULL);
  5088.                             arg1 = parseCreateOperNode(TN_LIST, arg1, arg2);
  5089.                             tree = parseCreateOperNode(TN_CALL, tree, arg1);
  5090.  
  5091.                             break;
  5092.                         }
  5093.  
  5094.                         parseComp->cmpError(ERRnoRparen);
  5095.                     }
  5096.                 }
  5097.                 else
  5098.                 {
  5099.                     parseComp->cmpError(ERRbadVAarg);
  5100.                 }
  5101.  
  5102.                 /* Something went wrong, we should perform error recovery */
  5103.  
  5104.                 return parseCreateErrNode();
  5105.             }
  5106.  
  5107.             tree = parseCreateOperNode(TN_CALL , tree, parseExprList(tkRParen));
  5108.             break;
  5109.  
  5110.         case tkLBrack:
  5111.  
  5112.             index = parseExprList(tkRBrack);
  5113.  
  5114.             if  (index)
  5115.             {
  5116.                 assert(index->tnOper == TN_LIST);
  5117.                 if  (index->tnOp.tnOp2 == NULL)
  5118.                     index = index->tnOp.tnOp1;
  5119.  
  5120.                 tree = parseCreateOperNode(TN_INDEX, tree, index);
  5121.                 break;
  5122.             }
  5123.  
  5124.             return parseCreateErrNode(ERRnoDim);
  5125.  
  5126.         case tkInc:
  5127.             tree = parseCreateOperNode(TN_INC_POST, tree, NULL);
  5128.             ourScanner->scan();
  5129.             break;
  5130.  
  5131.         case tkDec:
  5132.             tree = parseCreateOperNode(TN_DEC_POST, tree, NULL);
  5133.             ourScanner->scan();
  5134.             break;
  5135.  
  5136.         default:
  5137.             return tree;
  5138.         }
  5139.     }
  5140. }
  5141.  
  5142. /*****************************************************************************
  5143.  *
  5144.  *  Parse a sub-expression at the specified precedence level. If 'tree' is
  5145.  *  non-zero, we've already parsed the initial operand (and 'tree' is that
  5146.  *  operand).
  5147.  */
  5148.  
  5149. Tree                parser::parseExpr(unsigned minPrec, Tree tree)
  5150. {
  5151.     Scanner         ourScanner = parseScan;
  5152.  
  5153.     unsigned        prec;
  5154.     treeOps         oper;
  5155.  
  5156.     /* Should we check for a unary operator? */
  5157.  
  5158.     if  (tree == NULL)
  5159.     {
  5160.         /* Is the current token a unary operator? */
  5161.  
  5162.         if  (!parseHash->tokenIsUnop(ourScanner->scanTok.tok, &prec, &oper) ||
  5163.              oper == TN_NONE)
  5164.         {
  5165.             /* There is no unary operator */
  5166.  
  5167.             tree = parseTerm();
  5168.         }
  5169.         else
  5170.         {
  5171.             /* Swallow the unary operator and check for some special cases */
  5172.  
  5173.             ourScanner->scan();
  5174.  
  5175.             switch (oper)
  5176.             {
  5177.                 TypDef          type;
  5178.  
  5179.             default:
  5180.  
  5181.                 /* This is the "normal" unary operator case */
  5182.  
  5183.                 tree = parseCreateOperNode(oper, parseExpr(prec, NULL), NULL);
  5184.                 break;
  5185.  
  5186.             case TN_SIZEOF:
  5187.  
  5188.                 chkCurTok(tkLParen, ERRnoLparen);
  5189.  
  5190.                 /* Do we have a type or an expression? */
  5191.  
  5192.                 type = parseCheck4type(tkRParen);
  5193.                 if  (type)
  5194.                 {
  5195.                     /* "sizeof" is not allowed on some types */
  5196.  
  5197.                     switch(type->tdTypeKind)
  5198.                     {
  5199.                     case TYP_UNDEF:
  5200.                         tree = parseCreateErrNode();
  5201.                         break;
  5202.  
  5203.                     case TYP_VOID:
  5204.                     case TYP_FNC:
  5205.                         tree = parseCreateErrNode(ERRbadSizeof);
  5206.                         break;
  5207.  
  5208.                     default:
  5209.                         tree = parseCreateOperNode(oper, NULL, NULL);
  5210.                         tree->tnType = type;
  5211.                         break;
  5212.                     }
  5213.                 }
  5214.                 else
  5215.                 {
  5216.                     /* Presumably we have "sizeof(expr)" */
  5217.  
  5218.                     tree = parseCreateOperNode(oper, parseExpr(), NULL);
  5219.                 }
  5220.  
  5221.                 /* Make sure we have the closing ")" */
  5222.  
  5223.                 chkCurTok(tkRParen, ERRnoRparen);
  5224.  
  5225.                 tree = parseTerm(tree);
  5226.                 break;
  5227.  
  5228.             case TN_TYPEOF:
  5229.  
  5230.                 chkCurTok(tkLParen, ERRnoLparen);
  5231.  
  5232.                 /* Do we have a type or an expression? */
  5233.  
  5234.                 type = parseCheck4type(tkRParen);
  5235.                 if  (type)
  5236.                 {
  5237.                     TypDef          btyp = type;
  5238.                     var_types       bvtp = btyp->tdTypeKindGet();
  5239.  
  5240.                     switch (bvtp)
  5241.                     {
  5242.                     case TYP_CLASS:
  5243.                         break;
  5244.  
  5245.                     case TYP_REF:
  5246.                     case TYP_PTR:
  5247.                         btyp = btyp->tdRef.tdrBase;
  5248.                         bvtp = btyp->tdTypeKindGet();
  5249.                         break;
  5250.                     }
  5251.  
  5252.                     if  (!btyp->tdIsManaged)
  5253.                     {
  5254.                         if  (bvtp > TYP_lastIntrins)
  5255.                         {
  5256.                             parseComp->cmpError(ERRtypeidOp, type);
  5257.                             return parseCreateErrNode();
  5258.                         }
  5259.  
  5260.                         type = parseComp->cmpFindStdValType(bvtp);
  5261.                     }
  5262.  
  5263.                     tree = parseCreateOperNode(oper, NULL, NULL);
  5264.                     tree->tnType = type;
  5265.                 }
  5266.                 else
  5267.                 {
  5268.                     /* This looks like "typeid(expr)" */
  5269.  
  5270.                     tree = parseCreateOperNode(oper, parseExpr(), NULL);
  5271.                 }
  5272.  
  5273.                 /* Make sure we have the closing ")" */
  5274.  
  5275.                 chkCurTok(tkRParen, ERRnoRparen);
  5276.  
  5277.                 tree = parseTerm(tree);
  5278.                 break;
  5279.  
  5280.             case TN_DEFINED:
  5281.  
  5282.                 tree = parseCreateIconNode(ourScanner->scanChkDefined(), TYP_INT);
  5283.  
  5284.                 /* Make sure we have the closing ")" */
  5285.  
  5286.                 chkNxtTok(tkRParen, ERRnoRparen);
  5287.                 break;
  5288.             }
  5289.         }
  5290.     }
  5291.  
  5292.     /* Process a sequence of operators and operands */
  5293.  
  5294.     for (;;)
  5295.     {
  5296.         Tree            qc;
  5297.  
  5298.         /* Is the current token an operator? */
  5299.  
  5300.         if  (!parseHash->tokenIsBinop(ourScanner->scanTok.tok, &prec, &oper))
  5301.             break;
  5302.  
  5303.         if  (oper == TN_NONE)
  5304.             break;
  5305.  
  5306.         assert(prec);
  5307.  
  5308.         if  (prec < minPrec)
  5309.             break;
  5310.  
  5311.         /* Special case: equal precedence */
  5312.  
  5313.         if  (prec == minPrec)
  5314.         {
  5315.             /* Assignment operators are right-associative */
  5316.  
  5317.             if  (!(TreeNode::tnOperKind(oper) & TNK_ASGOP))
  5318.                 break;
  5319.         }
  5320.  
  5321.         /* Precedence is high enough -- we'll take the operator */
  5322.  
  5323.         tree = parseCreateOperNode(oper, tree, NULL);
  5324.  
  5325.         /* Consume the operator token */
  5326.  
  5327.         ourScanner->scan();
  5328.  
  5329.         /* Check for some special cases */
  5330.  
  5331.         switch (oper)
  5332.         {
  5333.             Tree            op1;
  5334.             Tree            op2;
  5335.  
  5336.         default:
  5337.  
  5338.             /* Parse the operand and store it in the operator node */
  5339.  
  5340.             tree->tnOp.tnOp2 = parseExpr(prec, NULL);
  5341.             break;
  5342.  
  5343.         case TN_ISTYPE:
  5344.  
  5345.             /* Parse the type and store it in the operator node */
  5346.  
  5347.             tree->tnType = parseTypeSpec(NULL, true);
  5348.             break;
  5349.  
  5350.         case TN_QMARK:
  5351.  
  5352.             /* Parse the first ":" branch */
  5353.  
  5354.             qc = parseExpr(prec - 1, NULL);
  5355.  
  5356.             /* We must have ":" at this point */
  5357.  
  5358.             chkCurTok(tkColon, ERRnoColon);
  5359.  
  5360.             /* Parse the second expression and insert the ":" node */
  5361.  
  5362.             tree->tnOp.tnOp2 = parseCreateOperNode(TN_COLON, qc, parseExpr(2, NULL));
  5363.             break;
  5364.  
  5365.         case TN_OR:
  5366.         case TN_AND:
  5367.         case TN_XOR:
  5368.  
  5369.             op2 = tree->tnOp.tnOp2 = parseExpr(prec, NULL);
  5370.             op1 = tree->tnOp.tnOp1;
  5371.  
  5372.             /* Check for the commnon mistake of saying "x & y == z" */
  5373.  
  5374.             if  ((op1->tnOperKind() & TNK_RELOP) && !(op1->tnFlags & TNF_PAREN) ||
  5375.                  (op2->tnOperKind() & TNK_RELOP) && !(op2->tnFlags & TNF_PAREN))
  5376.             {
  5377.                 parseComp->cmpWarn(WRNoperPrec);
  5378.             }
  5379.  
  5380.             break;
  5381.         }
  5382.     }
  5383.  
  5384.     return  tree;
  5385. }
  5386.  
  5387. /*****************************************************************************
  5388.  *
  5389.  *  Parse and evaluate a compile-time constant expression. If the caller knows
  5390.  *  the type the expression is supposed to evaluate to, it can be passed in as
  5391.  *  'dstt', but this argument can also be NULL to indicate that any type is OK.
  5392.  *  If the 'nonCnsPtr' argument is non-zero, it is OK for the expression to be
  5393.  *  non-constant, and if a non-constant expression is encountered the value at
  5394.  *  '*nonCnsPtr' will be set to the non-constant bound expression tree.
  5395.  */
  5396.  
  5397. bool                parser::parseConstExpr(OUT constVal REF valRef,
  5398.                                                Tree         tree,
  5399.                                                TypDef       dstt,
  5400.                                                Tree     *   nonCnsPtr)
  5401. {
  5402.     unsigned        curLno;
  5403.  
  5404.     Compiler        ourComp    = parseComp;
  5405.     Scanner         ourScanner = parseScan;
  5406.  
  5407.     /* Assume that we won't have a string */
  5408.  
  5409.     valRef.cvIsStr = false;
  5410.     valRef.cvHasLC = false;
  5411.  
  5412.     /* Parse the expression if the caller hasn't supplied a tree */
  5413.  
  5414.     if  (!tree)
  5415.         tree = parseExprComma();
  5416.  
  5417.     ourScanner->scanGetTokenPos(&curLno);
  5418.     tree = parseComp->cmpBindExpr(tree);
  5419.     ourScanner->scanSetTokenPos( curLno);
  5420.  
  5421.     if  (dstt)
  5422.         tree = parseComp->cmpCoerceExpr(tree, dstt, false);
  5423.  
  5424.     tree = parseComp->cmpFoldExpression(tree);
  5425.  
  5426.     switch (tree->tnOper)
  5427.     {
  5428.         ConstStr        cnss;
  5429.  
  5430.     case TN_CNS_INT:
  5431.         valRef.cvValue.cvIval = tree->tnIntCon.tnIconVal;
  5432.         break;
  5433.  
  5434.     case TN_CNS_LNG:
  5435.         valRef.cvValue.cvLval = tree->tnLngCon.tnLconVal;
  5436.         break;
  5437.  
  5438.     case TN_CNS_FLT:
  5439.         valRef.cvValue.cvFval = tree->tnFltCon.tnFconVal;
  5440.         break;
  5441.  
  5442.     case TN_CNS_DBL:
  5443.         valRef.cvValue.cvDval = tree->tnDblCon.tnDconVal;
  5444.         break;
  5445.  
  5446.     case TN_CNS_STR:
  5447.  
  5448. #if MGDDATA
  5449.         cnss = new ConstStr;
  5450. #else
  5451.         cnss =    (ConstStr)parseAllocPriv.nraAlloc(sizeof(*cnss));
  5452. #endif
  5453.  
  5454.         valRef.cvValue.cvSval = cnss;
  5455.         valRef.cvIsStr        = true;
  5456.         valRef.cvHasLC        = tree->tnStrCon.tnSconLCH;
  5457.  
  5458.         cnss->csStr = tree->tnStrCon.tnSconVal;
  5459.         cnss->csLen = tree->tnStrCon.tnSconLen;
  5460.  
  5461.         break;
  5462.  
  5463.     case TN_NULL:
  5464.         valRef.cvValue.cvIval = 0;
  5465.         break;
  5466.  
  5467.     default:
  5468.  
  5469.         if  (nonCnsPtr)
  5470.         {
  5471.             *nonCnsPtr = tree;
  5472.             return  false;
  5473.         }
  5474.  
  5475.         parseComp->cmpError(ERRnoCnsExpr);
  5476.  
  5477.         // Fall through ...
  5478.  
  5479.     case TN_ERROR:
  5480.  
  5481.         valRef.cvVtyp         = TYP_UNDEF;
  5482.         valRef.cvType         = parseStab->stIntrinsicType(TYP_UNDEF);
  5483.  
  5484.         return  false;
  5485.     }
  5486.  
  5487.     valRef.cvType = tree->tnType;
  5488.     valRef.cvVtyp = tree->tnVtypGet();
  5489.  
  5490.     parseComp->cmpErrorTree = NULL;
  5491.  
  5492.     return  true;
  5493. }
  5494.  
  5495. /*****************************************************************************
  5496.  *
  5497.  *  Parse a (possibly qualified) name reference and return the corresponding
  5498.  *  symbol (or NULL in case of an error).
  5499.  */
  5500.  
  5501. SymDef              parser::parseNameUse(bool typeName,
  5502.                                          bool keepName, bool chkOnly)
  5503. {
  5504.     name_space      nameSP = (name_space)(NS_TYPE|NS_NORM);
  5505.     Ident           name;
  5506.     SymDef          scp;
  5507.     SymDef          sym;
  5508.  
  5509.     Scanner         ourScanner = parseScan;
  5510.     SymTab          ourSymTab  = parseStab;
  5511.  
  5512.     scp = NULL;
  5513.  
  5514.     if  (ourScanner->scanTok.tok == tkColon2)
  5515.     {
  5516.         sym = parseComp->cmpGlobalNS;
  5517.         goto NXTID;
  5518.     }
  5519.  
  5520.     assert(ourScanner->scanTok.tok == tkID);
  5521.  
  5522.     /* Lookup the initial name */
  5523.  
  5524.     name = ourScanner->scanTok.id.tokIdent;
  5525.  
  5526.     if  (parseLookupSym(name))
  5527.         return  NULL;
  5528.  
  5529. //  static int x; if (++x == 0) forceDebugBreak();
  5530.  
  5531.     switch (ourScanner->scanLookAhead())
  5532.     {
  5533.     case tkDot:
  5534.     case tkColon2:
  5535.         if  (typeName)
  5536.         {
  5537.             sym = ourSymTab->stLookupSym(name, NS_CONT);
  5538.             if  (sym)
  5539.                 break;
  5540.         }
  5541.         sym = ourSymTab->stLookupSym(name, (name_space)(NS_NORM|NS_TYPE));
  5542.         break;
  5543.  
  5544.     default:
  5545.         sym = ourSymTab->stLookupSym(name, nameSP);
  5546.         break;
  5547.     }
  5548.  
  5549.     if  (!sym)
  5550.     {
  5551.         if  (chkOnly)
  5552.             return  NULL;
  5553.  
  5554.         parseComp->cmpError(ERRundefName, name);
  5555.  
  5556.         /* Swallow the rest of the name */
  5557.  
  5558.     ERR:
  5559.  
  5560.         for (;;)
  5561.         {
  5562.             // UNDONE: The following doesn't always work, need to pay attention to 'chkOnly'
  5563.  
  5564.             switch (ourScanner->scan())
  5565.             {
  5566.             case tkID:
  5567.             case tkDot:
  5568.             case tkColon2:
  5569.                 continue;
  5570.  
  5571.             default:
  5572.                 return  ourSymTab->stErrSymbol;
  5573.             }
  5574.         }
  5575.     }
  5576.  
  5577.     /* Make sure we have access to the symbol */
  5578.  
  5579.     if  (sym->sdSymKind != SYM_FNC)
  5580.         parseComp->cmpCheckAccess(sym);
  5581.  
  5582.     /* Process any further names */
  5583.  
  5584.     for (;;)
  5585.     {
  5586.         SymDef          tmp;
  5587.  
  5588.         switch (ourScanner->scanLookAhead())
  5589.         {
  5590.         case tkDot:
  5591.         case tkColon2:
  5592.  
  5593.             /* Have we gone far enough already? */
  5594.  
  5595.             if  (sym->sdHasScope())
  5596.                 break;
  5597.  
  5598.             // Fall through ....
  5599.  
  5600.         default:
  5601.  
  5602.             if  (keepName)
  5603.                 ourScanner->scanSetQualID(NULL, sym, scp);
  5604.             else
  5605.                 ourScanner->scan();
  5606.  
  5607.             return sym;
  5608.         }
  5609.  
  5610.         ourScanner->scan();
  5611.  
  5612.     NXTID:
  5613.  
  5614.         /* The "." or "::" better be followed by an identifier */
  5615.  
  5616.         if  (ourScanner->scan() != tkID)
  5617.         {
  5618.  
  5619.             parseComp->cmpError(ERRnoIdent);
  5620.             goto ERR;
  5621.         }
  5622.  
  5623.         name = ourScanner->scanTok.id.tokIdent;
  5624.  
  5625.         /* Make sure the current scope is appropriate, and lookup the name in it */
  5626.  
  5627.         switch (sym->sdSymKind)
  5628.         {
  5629.         case SYM_NAMESPACE:
  5630.             tmp = ourSymTab->stLookupNspSym(name, nameSP, sym);
  5631.             if  (tmp)
  5632.                 break;
  5633.             if  (sym == parseComp->cmpGlobalNS)
  5634.                 parseComp->cmpError(ERRnoGlobNm,      name);
  5635.             else
  5636.                 parseComp->cmpError(ERRnoNspMem, sym, name);
  5637.             goto ERR;
  5638.  
  5639.         case SYM_CLASS:
  5640.             tmp = ourSymTab->stLookupAllCls(name, sym, nameSP, CS_DECLSOON);
  5641.             if  (tmp)
  5642.                 break;
  5643.             parseComp->cmpError(ERRnoClsMem, sym, name);
  5644.             goto ERR;
  5645.  
  5646.         case SYM_ENUM:
  5647.             tmp = ourSymTab->stLookupScpSym(name, sym);
  5648.             if  (tmp)
  5649.                 break;
  5650.             parseComp->cmpError(ERRnoClsMem, sym, name);
  5651.             goto ERR;
  5652.  
  5653.         default:
  5654.             parseComp->cmpError(ERRnoTPmems, sym);
  5655.             goto ERR;
  5656.         }
  5657.  
  5658.         /* Switch to the new symbol and continue */
  5659.  
  5660.         scp = sym;
  5661.         sym = tmp;
  5662.     }
  5663. }
  5664.  
  5665. /*****************************************************************************
  5666.  *
  5667.  *  Create a declaration node for the given local variable / argument.
  5668.  */
  5669.  
  5670. Tree                parser::parseLclDclMake(Ident name, TypDef   type,
  5671.                                                         Tree     init,
  5672.                                                         unsigned mods,
  5673.                                                         bool     arg)
  5674. {
  5675.     Tree            decl;
  5676.     Tree            info;
  5677.  
  5678.     /* Create an entry for this declaration */
  5679.  
  5680.     decl = parseCreateNode(TN_VAR_DECL);
  5681.  
  5682.     /* Combine the name with the optional initializer */
  5683.  
  5684.     info = parseCreateNameNode(name);
  5685.  
  5686.     if  (init)
  5687.     {
  5688.         decl->tnFlags |= TNF_VAR_INIT;
  5689.         info = parseCreateOperNode(TN_LIST, info, init);
  5690.     }
  5691.  
  5692.     decl->tnDcl.tnDclInfo = info;
  5693.     decl->tnDcl.tnDclSym  = NULL;
  5694.     decl->tnDcl.tnDclNext = NULL;
  5695.  
  5696.     /* Set any flags that need setting */
  5697.  
  5698.     if  (arg)
  5699.         decl->tnFlags |= TNF_VAR_ARG;
  5700.  
  5701.     if  (mods & DM_STATIC)
  5702.         decl->tnFlags |= TNF_VAR_STATIC;
  5703.     if  (mods & DM_CONST)
  5704.         decl->tnFlags |= TNF_VAR_CONST;
  5705.     if  (mods & DM_SEALED)
  5706.         decl->tnFlags |= TNF_VAR_SEALED;
  5707.  
  5708.     /* Store the declared type in the declaration node */
  5709.  
  5710.     decl->tnType = type;
  5711.  
  5712.     return  decl;
  5713. }
  5714.  
  5715. /*****************************************************************************
  5716.  *
  5717.  *  Add the given declaration node to the current declaration list.
  5718.  */
  5719.  
  5720. void                parser::parseLclDclDecl(Tree decl)
  5721. {
  5722.     /* Insert the declaration in the current scope */
  5723.  
  5724.     if  (parseLastDecl)
  5725.     {
  5726.         /* Not the first declaration, append to the list */
  5727.  
  5728.         assert(parseLastDecl->tnOper          == TN_VAR_DECL);
  5729.         assert(parseLastDecl->tnDcl.tnDclNext == NULL);
  5730.  
  5731.         parseLastDecl->tnDcl.tnDclNext = decl;
  5732.     }
  5733.     else
  5734.     {
  5735.         Tree            curBlk = parseCurScope;
  5736.  
  5737.         /* It's the first declaration, start the decl list */
  5738.  
  5739.         assert(curBlk && curBlk->tnOper == TN_BLOCK);
  5740.  
  5741.         curBlk->tnBlock.tnBlkDecl = decl;
  5742.     }
  5743.  
  5744.     parseLastDecl = decl;
  5745.  
  5746.     /* Keep track of how many non-static/non-const/real locals we've declared */
  5747.  
  5748.     if  (!(decl->tnFlags & (TNF_VAR_STATIC|TNF_VAR_CONST|TNF_VAR_UNREAL)))
  5749.         parseLclVarCnt++;
  5750. }
  5751.  
  5752. /*****************************************************************************
  5753.  *
  5754.  *  Look for the given name in the current local scopes.
  5755.  */
  5756.  
  5757. Tree                parser::parseLookupSym(Ident name)
  5758. {
  5759.     Tree            scope;
  5760.  
  5761.     for (scope = parseCurScope;
  5762.          scope;
  5763.          scope = scope->tnBlock.tnBlkParent)
  5764.     {
  5765.         Tree            decl;
  5766.  
  5767.         assert(scope->tnOper == TN_BLOCK);
  5768.  
  5769.         for (decl = scope->tnBlock.tnBlkDecl;
  5770.              decl;
  5771.              decl = decl->tnDcl.tnDclNext)
  5772.         {
  5773.             Tree            vnam;
  5774.  
  5775.             assert(decl->tnOper == TN_VAR_DECL);
  5776.  
  5777.             vnam = decl->tnDcl.tnDclInfo;
  5778.             if  (decl->tnFlags & TNF_VAR_INIT)
  5779.             {
  5780.                 assert(vnam->tnOper == TN_LIST);
  5781.  
  5782.                 vnam = vnam->tnOp.tnOp1;
  5783.             }
  5784.  
  5785.             assert(vnam->tnOper == TN_NAME);
  5786.  
  5787.             if  (vnam->tnName.tnNameId == name)
  5788.                 return  decl;
  5789.         }
  5790.     }
  5791.  
  5792.     return  NULL;
  5793. }
  5794.  
  5795. /*****************************************************************************
  5796.  *
  5797.  *  Parse an initializer - this could be a simple expression or a "{}"-style
  5798.  *  array/class initializer.
  5799.  */
  5800.  
  5801. Tree                parser::parseInitExpr()
  5802. {
  5803.     Scanner         ourScanner = parseScan;
  5804.  
  5805.     scanPosTP       iniFpos;
  5806.     unsigned        iniLine;
  5807.  
  5808.     Tree            init;
  5809.  
  5810.     iniFpos = ourScanner->scanGetTokenPos(&iniLine);
  5811.  
  5812.     if  (ourScanner->scanTok.tok == tkLCurly)
  5813.     {
  5814.         ourScanner->scanSkipText(tkLCurly, tkRCurly);
  5815.         if  (ourScanner->scanTok.tok == tkRCurly)
  5816.             ourScanner->scan();
  5817.     }
  5818.     else
  5819.     {
  5820.         ourScanner->scanSkipText(tkNone, tkNone, tkComma);
  5821.     }
  5822.  
  5823.     init = parseCreateNode(TN_SLV_INIT);
  5824.     init->tnInit.tniSrcPos.dsdBegPos = iniFpos;
  5825.     init->tnInit.tniSrcPos.dsdSrcLno = iniLine;
  5826. //  init->tnInit.tniSrcPos.dsdSrcCol = iniCol;
  5827. //  init->tnInit.tniSrcPos.dsdEndPos = ourScanner->scanGetFilePos();
  5828.     init->tnInit.tniCompUnit         = ourScanner->scanGetCompUnit();
  5829.  
  5830.     return  init;
  5831. }
  5832.  
  5833. /*****************************************************************************
  5834.  *
  5835.  *  Parse a try/catch/except/finally statement.
  5836.  */
  5837.  
  5838. Tree                parser::parseTryStmt()
  5839. {
  5840.     Tree            tryStmt;
  5841.     Tree            hndList = NULL;
  5842.     Tree            hndLast = NULL;
  5843.  
  5844.     Scanner         ourScanner = parseScan;
  5845.  
  5846.     assert(ourScanner->scanTok.tok == tkTRY);
  5847.  
  5848.     if  (ourScanner->scan() != tkLCurly)
  5849.         parseComp->cmpError(ERRtryNoBlk);
  5850.  
  5851.     tryStmt = parseCreateOperNode(TN_TRY, parseFuncStmt(), NULL);
  5852.  
  5853.     /* The next thing must be except or catch/finally */
  5854.  
  5855.     switch (ourScanner->scanTok.tok)
  5856.     {
  5857.         Tree            hndThis;
  5858.  
  5859.     case tkEXCEPT:
  5860.  
  5861.         chkNxtTok(tkLParen, ERRnoLparen);
  5862.         hndList = parseCreateOperNode(TN_EXCEPT, parseExpr(), NULL);
  5863.         chkCurTok(tkRParen, ERRnoRparen);
  5864.  
  5865.         if  (ourScanner->scanTok.tok != tkLCurly)
  5866.             parseComp->cmpError(ERRnoLcurly);
  5867.  
  5868.         hndList->tnOp.tnOp2 = parseFuncStmt();
  5869.         break;
  5870.  
  5871.     case tkCATCH:
  5872.  
  5873.         /* Parse a series of catches, optionally followed by "finally" */
  5874.  
  5875.         do
  5876.         {
  5877.             declMods        mods;
  5878.             TypDef          type;
  5879.             Ident           name;
  5880.             Tree            decl;
  5881.             Tree            body;
  5882.  
  5883.             assert(ourScanner->scanTok.tok == tkCATCH);
  5884.  
  5885.             /* Process the initial "catch(type name)" */
  5886.  
  5887.             chkNxtTok(tkLParen, ERRnoLparen);
  5888.  
  5889.             /* Parse any leading modifiers */
  5890.  
  5891.             parseDeclMods(ACL_DEFAULT, &mods);
  5892.  
  5893.             /* Make sure no modifiers are present */
  5894.  
  5895.             if  (mods.dmMod)
  5896.                 parseComp->cmpModifierError(ERRlvModifier, mods.dmMod);
  5897.  
  5898.             /* Parse the type specification */
  5899.  
  5900.             type = parseTypeSpec(&mods, true);
  5901.  
  5902.             /* Parse the declarator */
  5903.  
  5904.             name = parseDeclarator(&mods, type, DN_OPTIONAL, &type, NULL, true);
  5905.  
  5906.             /* Make sure the expected ")" is present */
  5907.  
  5908.             chkCurTok(tkRParen, ERRnoRparen);
  5909.  
  5910.             /* Create a declaration node and pass it indirectly to parseBlock() */
  5911.  
  5912.             decl = parseTryDecl = parseLclDclMake(name, type, NULL, 0, false);
  5913.  
  5914.             /* Parse the body of the catch block and create a "catch" node */
  5915.  
  5916.             if  (ourScanner->scanTok.tok == tkLCurly)
  5917.             {
  5918.                 body = parseFuncBlock(parseComp->cmpGlobalNS);
  5919.             }
  5920.             else
  5921.             {
  5922.                 body = parseCreateErrNode(ERRnoLcurly);
  5923.  
  5924.                 parseFuncStmt();
  5925.             }
  5926.  
  5927.             hndThis = parseCreateOperNode(TN_CATCH, decl, body);
  5928.  
  5929.             /* Add the handler to the list and check for more */
  5930.  
  5931.             hndList = parseAddToNodeList(hndList, hndLast, hndThis);
  5932.         }
  5933.         while (ourScanner->scanTok.tok == tkCATCH);
  5934.  
  5935.         /* Is there a finally at the end? */
  5936.  
  5937.         if  (ourScanner->scanTok.tok != tkFINALLY)
  5938.             break;
  5939.  
  5940.         // Fall through ....
  5941.  
  5942.     case tkFINALLY:
  5943.  
  5944.         if  (ourScanner->scan() != tkLCurly)
  5945.             parseComp->cmpError(ERRnoLcurly);
  5946.  
  5947.         tryStmt->tnFlags |= TNF_BLK_HASFIN;
  5948.  
  5949.         hndThis = parseCreateOperNode(TN_FINALLY, parseFuncStmt(), NULL);
  5950.  
  5951.         if  (hndList)
  5952.             hndList = parseAddToNodeList(hndList, hndLast, hndThis);
  5953.         else
  5954.             hndList = hndThis;
  5955.  
  5956.         break;
  5957.  
  5958.     default:
  5959.         parseComp->cmpError(ERRnoHandler);
  5960.         break;
  5961.     }
  5962.  
  5963.     tryStmt->tnOp.tnOp2 = hndList;
  5964.  
  5965.     return  tryStmt;
  5966. }
  5967.  
  5968. /*****************************************************************************
  5969.  *
  5970.  *  Parse a single statement.
  5971.  */
  5972.  
  5973. Tree                parser::parseFuncStmt(bool stmtOpt)
  5974. {
  5975.     Scanner         ourScanner = parseScan;
  5976.  
  5977.     Tree            tree;
  5978.  
  5979. //  static int x; if (++x == 0) forceDebugBreak();
  5980.  
  5981.     /* See what sort of a statement we have here */
  5982.  
  5983.     switch (ourScanner->scanTok.tok)
  5984.     {
  5985.         bool            isLabel;
  5986.         bool            isDecl;
  5987.  
  5988.         Tree            cond;
  5989.         Tree            save;
  5990.         Tree            svld;
  5991.  
  5992.     case tkID:
  5993.  
  5994.         /*
  5995.             This is a difficult case - both declarations of local
  5996.             variables as well as statement expressions can start
  5997.             with an identifier. In C++ the ambiguity is resolved
  5998.             by lookahead - if the thing can possibly be a variable
  5999.             declaration, it is; otherwise it's an expression. The
  6000.             problem is that (unlimited) token lookahead is very
  6001.             expensive, and even people have a hard time figuring
  6002.             out what is what. Thus, we use a simple rule: if the
  6003.             thing is a declaration that starts with a name, that
  6004.             name must be known to be a type name.
  6005.          */
  6006.  
  6007.         isLabel = false;
  6008.         isDecl  = parseIsTypeSpec(false, &isLabel);
  6009.  
  6010.         if  (isLabel)
  6011.         {
  6012.             Tree            label;
  6013.             Ident           name;
  6014.  
  6015.             assert(ourScanner->scanTok.tok == tkID);
  6016.             name = ourScanner->scanTok.id.tokIdent;
  6017.  
  6018.             /* Allocate a label entry and add it to the list */
  6019.  
  6020.             label = parseCreateOperNode(TN_LABEL, parseCreateNameNode(name),
  6021.                                                   parseLabelList);
  6022.             parseLabelList = label;
  6023.  
  6024.             assert(ourScanner->scanTok.tok == tkID);
  6025.                    ourScanner->scan();
  6026.             assert(ourScanner->scanTok.tok == tkColon);
  6027.                    ourScanner->scan();
  6028.  
  6029.             /* Do we have (or require) a "real" statement here? */
  6030.  
  6031.             if  (!stmtOpt || (ourScanner->scanTok.tok != tkRCurly &&
  6032.                               ourScanner->scanTok.tok != tkSColon))
  6033.             {
  6034.                 tree = parseFuncStmt();
  6035.  
  6036.                 if  (tree)
  6037.                 {
  6038.                     label->tnOp.tnOp2 = parseCreateOperNode(TN_LIST,
  6039.                                                             tree,
  6040.                                                             label->tnOp.tnOp2);
  6041.                 }
  6042.             }
  6043.  
  6044.             return  label;
  6045.         }
  6046.  
  6047.         if  (isDecl)
  6048.             goto DECL;
  6049.         else
  6050.             goto EXPR;
  6051.  
  6052.     default:
  6053.  
  6054.         /* Is this a declaration? */
  6055.  
  6056.         if  (parseHash->tokenBegsTyp(ourScanner->scanTok.tok))
  6057.         {
  6058.             unsigned        mbad;
  6059.             declMods        mods;
  6060.             TypDef          btyp;
  6061.             Tree            last;
  6062.  
  6063.         DECL:
  6064.  
  6065.             /* Here we have a local declaration */
  6066.  
  6067.             tree = last = NULL;
  6068.  
  6069.             /* Parse any leading modifiers */
  6070.  
  6071.             parseDeclMods(ACL_DEFAULT, &mods);
  6072.  
  6073.             /* Make sure no weird modifiers are present */
  6074.  
  6075.             mbad = (mods.dmMod & ~(DM_STATIC|DM_CONST));
  6076.             if  (mbad)
  6077.                 parseComp->cmpModifierError(ERRlvModifier, mbad);
  6078.  
  6079.             if  (mods.dmAcc != ACL_DEFAULT)
  6080.                 parseComp->cmpError(ERRlvAccess);
  6081.  
  6082.             /* Parse the type specification */
  6083.  
  6084.             btyp = parseTypeSpec(&mods, true);
  6085.  
  6086.             /* Parse the declarator list */
  6087.  
  6088.             for (;;)
  6089.             {
  6090.                 Ident           name;
  6091.                 Tree            init;
  6092.                 Tree            decl;
  6093.                 TypDef          type;
  6094.  
  6095.                 /* Parse the next declarator */
  6096.  
  6097.                 name = parseDeclarator(&mods, btyp, DN_REQUIRED, &type, NULL, true);
  6098.  
  6099.                 /* Make sure we have a non-NULL type */
  6100.  
  6101.                 if  (type && name)
  6102.                 {
  6103.                     Tree            prev;
  6104.  
  6105.                     /* Check for a redeclaration */
  6106.  
  6107.                     if  (parseComp->cmpConfig.ccPedantic)
  6108.                     {
  6109.                         /* Check all the local scopes */
  6110.  
  6111.                         prev = parseLookupSym(name);
  6112.                     }
  6113.                     else
  6114.                     {
  6115.                         Tree            save;
  6116.  
  6117.                         /* Check only the current local scope */
  6118.  
  6119.                         save = parseCurScope->tnBlock.tnBlkParent;
  6120.                                parseCurScope->tnBlock.tnBlkParent = NULL;
  6121.                         prev = parseLookupSym(name);
  6122.                                parseCurScope->tnBlock.tnBlkParent = save;
  6123.                     }
  6124.  
  6125.                     if  (prev)
  6126.                     {
  6127.                         parseComp->cmpError(ERRredefLcl, name);
  6128.                         name = NULL;
  6129.                     }
  6130.                 }
  6131.                 else
  6132.                 {
  6133.                     name = NULL;
  6134.                     type = parseStab->stIntrinsicType(TYP_UNDEF);
  6135.                 }
  6136.  
  6137.                 /* Is there an initializer? */
  6138.  
  6139.                 init = NULL;
  6140.  
  6141.                 if  (ourScanner->scanTok.tok == tkAsg)
  6142.                 {
  6143.                     /* Is the variable static or auto? */
  6144.  
  6145.                     if  (mods.dmMod & DM_STATIC)
  6146.                     {
  6147.                         /* This could be a "{}"-style initializer */
  6148.  
  6149.                         ourScanner->scan();
  6150.  
  6151.                         init = parseInitExpr();
  6152.                     }
  6153.                     else
  6154.                     {
  6155.                         /* Swallow the "=" and parse the initializer expression */
  6156.  
  6157.                         if  (ourScanner->scan() == tkLCurly)
  6158.                         {
  6159.                             init = parseInitExpr();
  6160.                         }
  6161.                         else
  6162.                             init = parseExprComma();
  6163.                     }
  6164.                 }
  6165.  
  6166.                 /* Add the declaration to the list */
  6167.  
  6168.                 decl = parseLclDclMake(name, type, init, mods.dmMod, false);
  6169.                        parseLclDclDecl(decl);
  6170.                 tree = parseAddToNodeList(tree, last, decl);
  6171.  
  6172.                 /* Are there any more declarations? */
  6173.  
  6174.                 if  (ourScanner->scanTok.tok != tkComma)
  6175.                     break;
  6176.  
  6177.                 ourScanner->scan();
  6178.             }
  6179.  
  6180.             break;
  6181.         }
  6182.  
  6183.         /* We have an expression statement */
  6184.  
  6185.     EXPR:
  6186.  
  6187.         tree = parseExpr();
  6188.         break;
  6189.  
  6190.     case tkLCurly:
  6191.         return  parseFuncBlock();
  6192.  
  6193.     case tkIF:
  6194.  
  6195.         tree = parseCreateOperNode(TN_IF, NULL, NULL);
  6196.  
  6197.         chkNxtTok(tkLParen, ERRnoLparen);
  6198.         tree->tnOp.tnOp1 = parseExpr();
  6199.         chkCurTok(tkRParen, ERRnoRparen);
  6200.         tree->tnOp.tnOp2 = parseFuncStmt();
  6201.  
  6202.         /*
  6203.             Check for the presence of an "else" clause. Note that we want
  6204.             to end up with the following tree for 'if' without 'else':
  6205.  
  6206.                 IF(cond,stmt)
  6207.  
  6208.             If the 'else' clause is present, we want to create this tree
  6209.             instead:
  6210.  
  6211.                 IF(cond,LIST(true_stmt,false_stmt))
  6212.  
  6213.             We also set 'TNF_IF_HASELSE' to indicate that the 'else' part
  6214.             is present.
  6215.          */
  6216.  
  6217.         if  (ourScanner->scanTok.tok == tkELSE)
  6218.         {
  6219.             ourScanner->scan();
  6220.  
  6221.             tree->tnOp.tnOp2 = parseCreateOperNode(TN_LIST, tree->tnOp.tnOp2,
  6222.                                                             parseFuncStmt());
  6223.  
  6224.             tree->tnFlags |= TNF_IF_HASELSE;
  6225.         }
  6226.  
  6227.         return  tree;
  6228.  
  6229.     case tkRETURN:
  6230.  
  6231.         tree = (ourScanner->scan() == tkSColon) ? NULL
  6232.                                                 : parseExpr();
  6233.  
  6234.         tree = parseCreateOperNode(TN_RETURN, tree, NULL);
  6235.         break;
  6236.  
  6237.     case tkTHROW:
  6238.  
  6239.         tree = parseCreateOperNode(TN_THROW, NULL, NULL);
  6240.  
  6241.         if  (ourScanner->scan() != tkSColon)
  6242.             tree->tnOp.tnOp1 = parseExpr();
  6243.  
  6244.         break;
  6245.  
  6246.     case tkWHILE:
  6247.  
  6248.         chkNxtTok(tkLParen, ERRnoLparen);
  6249.         cond = parseExpr();
  6250.         chkCurTok(tkRParen, ERRnoRparen);
  6251.  
  6252.         return  parseCreateOperNode(TN_WHILE, cond, parseFuncStmt());
  6253.  
  6254.     case tkDO:
  6255.  
  6256.         ourScanner->scan();
  6257.  
  6258.         tree = parseCreateOperNode(TN_DO, parseFuncStmt(), NULL);
  6259.  
  6260.         if  (ourScanner->scanTok.tok == tkWHILE)
  6261.         {
  6262.             chkNxtTok(tkLParen, ERRnoLparen);
  6263.             tree->tnOp.tnOp2 = parseExpr();
  6264.             chkCurTok(tkRParen, ERRnoRparen);
  6265.         }
  6266.         else
  6267.         {
  6268.             parseComp->cmpError(ERRnoWhile);
  6269.         }
  6270.         return  tree;
  6271.  
  6272.     case tkSWITCH:
  6273.  
  6274.         chkNxtTok(tkLParen, ERRnoLparen);
  6275.         cond = parseExpr();
  6276.         chkCurTok(tkRParen, ERRnoRparen);
  6277.  
  6278.         /* Save the current switch, insert ours and parse the body */
  6279.  
  6280.         save = parseCurSwitch;
  6281.         tree = parseCurSwitch = parseCreateOperNode(TN_SWITCH, NULL, NULL);
  6282.  
  6283.         tree->tnSwitch.tnsValue    = cond;
  6284.         tree->tnSwitch.tnsCaseList =
  6285.         tree->tnSwitch.tnsCaseLast = NULL;
  6286.         tree->tnSwitch.tnsStmt     = parseFuncStmt();
  6287.  
  6288.         /* Restore the previous switch context and return */
  6289.  
  6290.         parseCurSwitch = save;
  6291.  
  6292.         return  tree;
  6293.  
  6294.     case tkCASE:
  6295.  
  6296.         if  (!parseCurSwitch)
  6297.             parseComp->cmpError(ERRbadCase);
  6298.  
  6299.         ourScanner->scan();
  6300.  
  6301.         cond = parseExpr();
  6302.  
  6303.     ADD_CASE:
  6304.  
  6305.         tree = parseCreateOperNode(TN_CASE, NULL, NULL);
  6306.  
  6307.         chkCurTok(tkColon, ERRnoColon);
  6308.  
  6309.         tree->tnCase.tncValue = cond;
  6310.         tree->tnCase.tncLabel = NULL;
  6311.         tree->tnCase.tncNext  = NULL;
  6312.  
  6313.         if  (parseCurSwitch)
  6314.         {
  6315.             if  (parseCurSwitch->tnSwitch.tnsCaseList)
  6316.                 parseCurSwitch->tnSwitch.tnsCaseLast->tnCase.tncNext = tree;
  6317.             else
  6318.                 parseCurSwitch->tnSwitch.tnsCaseList                 = tree;
  6319.  
  6320.             parseCurSwitch->tnSwitch.tnsCaseLast = tree;
  6321.         }
  6322.  
  6323.         return  tree;
  6324.  
  6325.     case tkDEFAULT:
  6326.  
  6327.         if  (!parseCurSwitch)
  6328.             parseComp->cmpError(ERRbadDefl);
  6329.  
  6330.         ourScanner->scan();
  6331.  
  6332.         cond = NULL;
  6333.  
  6334.         goto ADD_CASE;
  6335.  
  6336.     case tkFOR:
  6337.  
  6338.         save = NULL;
  6339.  
  6340.         if  (ourScanner->scan() == tkLParen)
  6341.         {
  6342.             Tree            init = NULL;
  6343.             Tree            incr = NULL;
  6344.             Tree            body = NULL;
  6345.             Tree            forx = parseCreateOperNode(TN_FOR, NULL, NULL);
  6346.  
  6347.             /* The "init-expr/decl" is optional */
  6348.  
  6349.             if  (ourScanner->scan() != tkSColon)
  6350.             {
  6351.                 /* Is there a declaration? */
  6352.  
  6353.                 if  (parseHash->tokenBegsTyp(ourScanner->scanTok.tok))
  6354.                 {
  6355.                     declMods        mods;
  6356.                     TypDef          btyp;
  6357.                     TypDef          type;
  6358.                     Ident           name;
  6359.  
  6360.                     /* If we have an identifier, it's a bit tricker */
  6361.  
  6362.                     if  (ourScanner->scanTok.tok == tkID)
  6363.                     {
  6364.                         if  (!parseIsTypeSpec(false))
  6365.                             goto FOR_EXPR;
  6366.                     }
  6367.  
  6368.                     /* Preserve the current declaration list value(s) */
  6369.  
  6370.                     svld = parseLastDecl; parseLastDecl = NULL;
  6371.  
  6372.                     /* Add a new block entry to the current scope list */
  6373.  
  6374.                     save = parseCreateNode(TN_BLOCK);
  6375.  
  6376.                     save->tnFlags            |= TNF_BLK_FOR;
  6377.                     save->tnBlock.tnBlkStmt   = NULL;
  6378.                     save->tnBlock.tnBlkDecl   = NULL;
  6379.                     save->tnBlock.tnBlkParent = parseCurScope;
  6380.                                                 parseCurScope = save;
  6381.  
  6382.                     /* Parse any leading modifiers */
  6383.  
  6384.                     clearDeclMods(&mods);
  6385.                     parseDeclMods(ACL_DEFAULT, &mods);
  6386.  
  6387.                     /* Parse the type specification */
  6388.  
  6389.                     btyp = parseTypeSpec(&mods, true);
  6390.  
  6391.                     /* Parse a series of declarators */
  6392.  
  6393.                     for (;;)
  6394.                     {
  6395.                         Tree            decl;
  6396.                         Tree            init;
  6397.  
  6398.                         /* Get the next declarator */
  6399.  
  6400.                         name = parseDeclarator(&mods, btyp, DN_REQUIRED, &type, NULL, true);
  6401.  
  6402.                         /* Is there an initializer? */
  6403.  
  6404.                         if  (ourScanner->scanTok.tok == tkAsg)
  6405.                         {
  6406.                             ourScanner->scan();
  6407.  
  6408.                             init = parseExprComma();
  6409.                         }
  6410.                         else
  6411.                             init = NULL;
  6412.  
  6413.                         /* Add the declaration to the list */
  6414.  
  6415.                         decl = parseLclDclMake(name, type, init, mods.dmMod, false);
  6416.                                parseLclDclDecl(decl);
  6417.  
  6418.                         /* Are there more declarators? */
  6419.  
  6420.                         if  (ourScanner->scanTok.tok != tkComma)
  6421.                             break;
  6422.  
  6423.                         ourScanner->scan();
  6424.                     }
  6425.  
  6426.                     init = save;
  6427.                 }
  6428.                 else
  6429.                 {
  6430.                     /* Here the initializer is a simple expression */
  6431.  
  6432.                 FOR_EXPR:
  6433.  
  6434.                     init = parseExpr(); assert(init->tnOper != TN_LIST);
  6435.                 }
  6436.  
  6437.                 /* There better be a semicolon here */
  6438.  
  6439.                 if  (ourScanner->scanTok.tok != tkSColon)
  6440.                 {
  6441.                     parseComp->cmpError(ERRnoSemic);
  6442.  
  6443.                     /* Maybe they just forgot the other expressions? */
  6444.  
  6445.                     if  (ourScanner->scanTok.tok == tkRParen)
  6446.                         goto FOR_BODY;
  6447.                     else
  6448.                         goto BAD_FOR;
  6449.                 }
  6450.             }
  6451.  
  6452.             assert(ourScanner->scanTok.tok == tkSColon);
  6453.  
  6454.             /* The "cond-expr" is optional */
  6455.  
  6456.             cond = NULL;
  6457.  
  6458.             if  (ourScanner->scan() != tkSColon)
  6459.             {
  6460.                 cond = parseExpr();
  6461.  
  6462.                 /* There better be a semicolon here */
  6463.  
  6464.                 if  (ourScanner->scanTok.tok != tkSColon)
  6465.                 {
  6466.                     parseComp->cmpError(ERRnoSemic);
  6467.  
  6468.                     /* Maybe they just forgot the other expressions? */
  6469.  
  6470.                     if  (ourScanner->scanTok.tok == tkRParen)
  6471.                         goto FOR_BODY;
  6472.                     else
  6473.                         goto BAD_FOR;
  6474.                 }
  6475.             }
  6476.  
  6477.             assert(ourScanner->scanTok.tok == tkSColon);
  6478.  
  6479.             /* The "incr-expr" is optional */
  6480.  
  6481.             if  (ourScanner->scan() != tkRParen)
  6482.             {
  6483.                 incr = parseExpr();
  6484.  
  6485.                 /* There better be a ")" here */
  6486.  
  6487.                 if  (ourScanner->scanTok.tok != tkRParen)
  6488.                 {
  6489.                     parseComp->cmpError(ERRnoRparen);
  6490.                     goto BAD_FOR;
  6491.                 }
  6492.             }
  6493.  
  6494.         FOR_BODY:
  6495.  
  6496.             assert(ourScanner->scanTok.tok == tkRParen); ourScanner->scan();
  6497.  
  6498.             body = parseFuncBlock();
  6499.  
  6500.             /* Fill in the "for" node to hold all the components */
  6501.  
  6502.             forx->tnOp.tnOp1 = parseCreateOperNode(TN_LIST, init, cond);
  6503.             forx->tnOp.tnOp2 = parseCreateOperNode(TN_LIST, incr, body);
  6504.  
  6505.             /* Pop the block scope if we created one */
  6506.  
  6507.             if  (save)
  6508.             {
  6509.                 assert(save->tnOper == TN_BLOCK && save == init);
  6510.  
  6511.                 /* Figure out where the scope of the declaration ended */
  6512.  
  6513.                 if  (body && body->tnOper == TN_BLOCK)
  6514.                     save->tnBlock.tnBlkSrcEnd = body->tnBlock.tnBlkSrcEnd;
  6515.                 else
  6516.                     save->tnBlock.tnBlkSrcEnd = ourScanner->scanGetTokenLno();
  6517.  
  6518.                 parseCurScope = save->tnBlock.tnBlkParent;
  6519.                 parseLastDecl = svld;
  6520.             }
  6521.  
  6522.             return  forx;
  6523.         }
  6524.         else
  6525.         {
  6526.             parseComp->cmpError(ERRnoLparen);
  6527.  
  6528.         BAD_FOR:
  6529.  
  6530.             parseResync(tkNone, tkNone);
  6531.  
  6532.             /* Pop the block scope if we created one */
  6533.  
  6534.             if  (save)
  6535.             {
  6536.                 parseCurScope = save->tnBlock.tnBlkParent;
  6537.                 parseLastDecl = svld;
  6538.             }
  6539.  
  6540.             tree = parseCreateErrNode();
  6541.         }
  6542.         break;
  6543.  
  6544.     case tkASSERT:
  6545.  
  6546.         if  (ourScanner->scan() != tkLParen)
  6547.         {
  6548.             tree = parseCreateErrNode(ERRnoLparen);
  6549.             break;
  6550.         }
  6551.  
  6552.         if  (parseComp->cmpConfig.ccAsserts)
  6553.         {
  6554.             ourScanner->scan();
  6555.             cond = parseExpr();
  6556.         }
  6557.         else
  6558.         {
  6559.             ourScanner->scanSkipText(tkLParen, tkRParen);
  6560.             cond = NULL;
  6561.         }
  6562.  
  6563.         chkCurTok(tkRParen, ERRnoRparen);
  6564.  
  6565.         tree = parseCreateOperNode(TN_ASSERT, cond, NULL);
  6566.         break;
  6567.  
  6568.     case tkBREAK:
  6569.         tree = parseCreateOperNode(TN_BREAK   , NULL, NULL);
  6570.         if  (ourScanner->scan() == tkID)
  6571.         {
  6572.             tree->tnOp.tnOp1 = parseCreateNameNode(ourScanner->scanTok.id.tokIdent);
  6573.             ourScanner->scan();
  6574.         }
  6575.         break;
  6576.  
  6577.     case tkCONTINUE:
  6578.         tree = parseCreateOperNode(TN_CONTINUE, NULL, NULL);
  6579.         if  (ourScanner->scan() == tkID)
  6580.         {
  6581.             tree->tnOp.tnOp1 = parseCreateNameNode(ourScanner->scanTok.id.tokIdent);
  6582.             ourScanner->scan();
  6583.         }
  6584.         break;
  6585.  
  6586.     case tkELSE:
  6587.         parseComp->cmpError(ERRbadElse);
  6588.         ourScanner->scan();
  6589.         return  parseFuncStmt();
  6590.  
  6591.     case tkGOTO:
  6592.         parseHadGoto = true;
  6593.         if  (ourScanner->scan() == tkID)
  6594.         {
  6595.             tree = parseCreateNameNode(parseScan->scanTok.id.tokIdent);
  6596.             ourScanner->scan();
  6597.             tree = parseCreateOperNode(TN_GOTO, tree, NULL);
  6598.         }
  6599.         else
  6600.         {
  6601.             tree = parseCreateErrNode(ERRnoIdent);
  6602.         }
  6603.         break;
  6604.  
  6605.     case tkTRY:
  6606.         return  parseTryStmt();
  6607.  
  6608.     case tkEXCLUSIVE:
  6609.  
  6610.         chkNxtTok(tkLParen, ERRnoLparen);
  6611.         cond = parseExpr();
  6612.         chkCurTok(tkRParen, ERRnoRparen);
  6613.  
  6614.         return  parseCreateOperNode(TN_EXCLUDE, cond, parseFuncStmt());
  6615.  
  6616.     case tkSColon:
  6617.         tree = NULL;
  6618.         break;
  6619.     }
  6620.  
  6621.     if  (ourScanner->scanTok.tok == tkSColon)
  6622.     {
  6623.         ourScanner->scan();
  6624.     }
  6625.     else
  6626.     {
  6627.         if  (tree == NULL || tree->tnOper != TN_ERROR)
  6628.         {
  6629.             tree = parseCreateErrNode(ERRnoSemic);
  6630.             ourScanner->scanSkipText(tkNone, tkNone);
  6631.         }
  6632.     }
  6633.  
  6634.     return  tree;
  6635. }
  6636.  
  6637. /*****************************************************************************
  6638.  *
  6639.  *  Parse a statement block (the current token is assumed to be "{", except
  6640.  *  when this is the body of a loop statement).
  6641.  */
  6642.  
  6643. Tree                parser::parseFuncBlock(SymDef fsym)
  6644. {
  6645.     Scanner         ourScanner = parseScan;
  6646.  
  6647.     Tree            stmtBlock;
  6648.     Tree            stmtList = NULL;
  6649.     Tree            stmtLast = NULL;
  6650.  
  6651.     Tree            saveLastDecl;
  6652.  
  6653.     /* Preserve the current declaration list value(s) */
  6654.  
  6655.     saveLastDecl = parseLastDecl; parseLastDecl = NULL;
  6656.  
  6657.     /* Add a new block entry to the current scope list */
  6658.  
  6659.     stmtBlock = parseCreateNode(TN_BLOCK);
  6660.  
  6661.     stmtBlock->tnBlock.tnBlkStmt   = NULL;
  6662.     stmtBlock->tnBlock.tnBlkDecl   = NULL;
  6663.     stmtBlock->tnBlock.tnBlkParent = parseCurScope;
  6664.                                      parseCurScope = stmtBlock;
  6665.  
  6666.     /* Is this the outermost function scope? */
  6667.  
  6668.     if  (fsym)
  6669.     {
  6670.         TypDef          ftyp;
  6671.         ArgDef          args;
  6672.  
  6673.         /* Special case: injected local variable declaration */
  6674.  
  6675.         if  (fsym == parseComp->cmpGlobalNS)
  6676.         {
  6677.             stmtBlock->tnFlags |= TNF_BLK_CATCH;
  6678.  
  6679.             parseLclDclDecl(parseTryDecl);
  6680.  
  6681.             stmtBlock->tnBlock.tnBlkStmt = parseAddToNodeList(stmtBlock->tnBlock.tnBlkStmt,
  6682.                                                               stmtLast,
  6683.                                                               parseTryDecl);
  6684.             goto BODY;
  6685.         }
  6686.  
  6687.         /* Add declarations for all the arguments */
  6688.  
  6689.         ftyp = fsym->sdType; assert(ftyp && ftyp->tdTypeKind == TYP_FNC);
  6690.  
  6691.         for (args = ftyp->tdFnc.tdfArgs.adArgs; args; args = args->adNext)
  6692.         {
  6693.             Tree            decl;
  6694.  
  6695.             /* Create a declaration node for the argument */
  6696.  
  6697.             decl = parseLclDclMake(args->adName, args->adType, NULL, 0, true);
  6698.                    parseLclDclDecl(decl);
  6699.  
  6700.             /* Add the declaration to the list */
  6701.  
  6702.             stmtBlock->tnBlock.tnBlkStmt = parseAddToNodeList(stmtBlock->tnBlock.tnBlkStmt,
  6703.                                                               stmtLast,
  6704.                                                               decl);
  6705.         }
  6706.  
  6707.         /* Reset the local variable count, we don't want to count args */
  6708.  
  6709.         parseLclVarCnt = 0;
  6710.     }
  6711.     else
  6712.     {
  6713.         if  (ourScanner->scanTok.tok != tkLCurly)
  6714.         {
  6715.             Tree            body = parseFuncStmt(true);
  6716.  
  6717.             if  (body)
  6718.                 stmtBlock->tnBlock.tnBlkStmt = parseCreateOperNode(TN_LIST, body, NULL);
  6719.  
  6720.             stmtBlock->tnBlock.tnBlkSrcEnd = ourScanner->scanGetTokenLno();
  6721.             goto DONE;
  6722.         }
  6723.     }
  6724.  
  6725. BODY:
  6726.  
  6727.     /* Parse the contents of the block */
  6728.  
  6729.     assert(ourScanner->scanTok.tok == tkLCurly); ourScanner->scan();
  6730.  
  6731.     while (ourScanner->scanTok.tok != tkRCurly)
  6732.     {
  6733.         if  (ourScanner->scanTok.tok == tkSColon)
  6734.         {
  6735.             ourScanner->scan();
  6736.         }
  6737.         else
  6738.         {
  6739.             Tree            stmtNext;
  6740.  
  6741.             /* Parse the next statement and add it to the list */
  6742.  
  6743.             stmtNext = parseFuncStmt(true);
  6744.  
  6745.             if  (stmtNext)
  6746.             {
  6747.                 stmtBlock->tnBlock.tnBlkStmt = parseAddToNodeList(stmtBlock->tnBlock.tnBlkStmt,
  6748.                                                                   stmtLast,
  6749.                                                                   stmtNext);
  6750.             }
  6751.         }
  6752.  
  6753.         /* See if have any more statements */
  6754.  
  6755.         if  (ourScanner->scanTok.tok == tkEOF)
  6756.             goto DONE;
  6757.     }
  6758.  
  6759.     /* We should be sitting at the closing "}" now, remember its position */
  6760.  
  6761.     assert(ourScanner->scanTok.tok == tkRCurly);
  6762.     stmtBlock->tnBlock.tnBlkSrcEnd = ourScanner->scanGetTokenLno();
  6763.     ourScanner->scan();
  6764.  
  6765. DONE:
  6766.  
  6767.     /* Pop the block scope */
  6768.  
  6769.     parseCurScope = stmtBlock->tnBlock.tnBlkParent;
  6770.  
  6771.     /* Restore the saved declaration list value(s) */
  6772.  
  6773.     parseLastDecl = saveLastDecl;
  6774.  
  6775.     return  stmtBlock;
  6776. }
  6777.  
  6778. /*****************************************************************************
  6779.  *
  6780.  *  Parse a function body.
  6781.  */
  6782.  
  6783. Tree                parser::parseFuncBody(SymDef fsym, Tree     *labels,
  6784.                                                        unsigned *locals,
  6785.                                                        bool     *hadGoto,
  6786.                                                        bool     *baseCT,
  6787.                                                        bool     *thisCT)
  6788. {
  6789.     Tree            block;
  6790.  
  6791.     /* We haven't seen any local declarations/labels/switches/etc. yet */
  6792.  
  6793.     parseLastDecl   = NULL;
  6794.     parseLabelList  = NULL;
  6795.     parseCurSwitch  = NULL;
  6796.     parseLclVarCnt  = 0;
  6797.     parseHadGoto    = false;
  6798.  
  6799.     /* We haven't see a call to a base/this constructor */
  6800.  
  6801.     parseBaseCTcall = false;
  6802.     parseThisCTcall = false;
  6803.  
  6804.     /* Parse the outermost function statement block */
  6805.  
  6806.     setErrorTrap(parseComp);
  6807.     begErrorTrap
  6808.     {
  6809.         assert(parseCurScope == NULL);
  6810.  
  6811.         /* Do we have a base class ctor call ? */
  6812.  
  6813.         if  (parseScan->scanTok.tok == tkColon)
  6814.         {
  6815.             Scanner         ourScanner = parseScan;
  6816.  
  6817.             SymDef          clsSym;
  6818.             Tree            baseCT;
  6819.             TypDef          baseTyp;
  6820.  
  6821.             /* We should find a call to the base class ctor */
  6822.  
  6823.             parseBaseCTcall = true;
  6824.  
  6825.             /* Make sure we have a base class */
  6826.  
  6827.             clsSym = fsym->sdParent;
  6828.  
  6829.             if  (!clsSym || clsSym->sdSymKind != SYM_CLASS)
  6830.             {
  6831.             BCT_BAD:
  6832.                 parseComp->cmpError(ERRnoBaseInit);
  6833.                 goto BCT_ERR;
  6834.             }
  6835.  
  6836.             baseTyp = clsSym->sdType->tdClass.tdcBase;
  6837.             if  (!baseTyp)
  6838.                 goto BCT_BAD;
  6839.  
  6840.             switch (ourScanner->scan())
  6841.             {
  6842.             case tkID:
  6843.  
  6844.                 /* The name better match the base class */
  6845.  
  6846.                 if  (ourScanner->scanTok.id.tokIdent != baseTyp->tdClass.tdcSymbol->sdName)
  6847.                     goto BCT_BAD;
  6848.                 break;
  6849.  
  6850.             case tkBASECLASS:
  6851.                 break;
  6852.  
  6853.             default:
  6854.                 parseComp->cmpError(ERRnoBaseInit);
  6855.                 goto BCT_ERR;
  6856.             }
  6857.  
  6858.             /* Parse the base ctor argument list */
  6859.  
  6860.             if  (parseScan->scan() != tkLParen)
  6861.                 goto BCT_BAD;
  6862.  
  6863.             baseCT = parseCreateOperNode(TN_CALL, parseCreateOperNode(TN_BASE, NULL, NULL),
  6864.                                                   parseExprList(tkRParen));
  6865.  
  6866.             /* The body of the ctor better follow */
  6867.  
  6868.             if  (ourScanner->scanTok.tok != tkLCurly)
  6869.             {
  6870.                 parseComp->cmpError(ERRnoLcurly);
  6871.  
  6872.             BCT_ERR:
  6873.  
  6874.                 /* Try to find the "{" of the body */
  6875.  
  6876.                 UNIMPL(!"skip to '{' of the ctor body");
  6877.             }
  6878.             else
  6879.             {
  6880.                 /* Process the body of the ctor */
  6881.  
  6882.                 block = parseFuncBlock(fsym);
  6883.  
  6884.                 /* Insert the base ctor call into the ctor body */
  6885.  
  6886.                 if  (block)
  6887.                 {
  6888.                     Tree            body = block->tnBlock.tnBlkStmt;
  6889.  
  6890.                     assert(block->tnOper == TN_BLOCK);
  6891.                     assert(body == NULL || body->tnOper == TN_LIST);
  6892.  
  6893.                     block->tnBlock.tnBlkStmt = parseCreateOperNode(TN_LIST,
  6894.                                                                    baseCT,
  6895.                                                                    body);
  6896.                 }
  6897.             }
  6898.         }
  6899.         else
  6900.             block = parseFuncBlock(fsym);
  6901.  
  6902.         assert(parseCurScope == NULL);
  6903.  
  6904.         /* End of the error trap's "normal" block */
  6905.  
  6906.         endErrorTrap(parseComp);
  6907.     }
  6908.     chkErrorTrap(fltErrorTrap(parseComp, _exception_code(), NULL)) // _exception_info()))
  6909.     {
  6910.         /* Begin the error trap's cleanup block */
  6911.  
  6912.         hndErrorTrap(parseComp);
  6913.  
  6914.         block         = NULL;
  6915.         parseCurScope = NULL;
  6916.     }
  6917.  
  6918.     *labels  = parseLabelList;
  6919.     *locals  = parseLclVarCnt;
  6920.     *baseCT  = parseBaseCTcall;
  6921.     *thisCT  = parseThisCTcall;
  6922.     *hadGoto = parseHadGoto;
  6923.  
  6924.     return  block;
  6925. }
  6926.  
  6927. /*****************************************************************************
  6928.  *
  6929.  *  Return true if the current thing in the source file looks like a type.
  6930.  */
  6931.  
  6932. bool                parser::parseIsTypeSpec(bool noLookup, bool *labChkPtr)
  6933. {
  6934.     SymDef          tsym;
  6935.     tokens          nextTok;
  6936.  
  6937.     /* If it's clearly not a type specifier, we're done */
  6938.  
  6939.     if  (!parseHash->tokenBegsTyp(parseScan->scanTok.tok))
  6940.         return  false;
  6941.  
  6942.     /* Is there a leading scope operator? */
  6943.  
  6944.     if  (parseScan->scanTok.tok == tkColon2)
  6945.         goto QUALID;
  6946.  
  6947.     /* Do we have a qualified symbol? */
  6948.  
  6949.     if  (parseScan->scanTok.tok == tkQUALID)
  6950.     {
  6951.         tsym = parseScan->scanTok.qualid.tokQualSym;
  6952.         goto CHKSYM;
  6953.     }
  6954.  
  6955.     /* If it's an identifier, we have more checking to do */
  6956.  
  6957.     if  (parseScan->scanTok.tok != tkID)
  6958.         return  true;
  6959.  
  6960.     /* We have an identifier, see if it's a type or not */
  6961.  
  6962.     nextTok = parseScan->scanLookAhead();
  6963.  
  6964.     switch (nextTok)
  6965.     {
  6966.         Ident           name;
  6967.  
  6968.     case tkDot:
  6969.     case tkColon2:
  6970.  
  6971.         if  (noLookup)
  6972.             goto QUALCHK;
  6973.  
  6974.     QUALID:
  6975.  
  6976.         /* Here we have a qualified name, find the symbol it denotes */
  6977.  
  6978.         tsym = parseNameUse(true, true, true);
  6979.         if  (!tsym || parseScan->scanTok.tok != tkQUALID)
  6980.             return  false;
  6981.  
  6982.         break;
  6983.  
  6984.     case tkColon:
  6985.  
  6986.         if  (labChkPtr)
  6987.         {
  6988.             *labChkPtr = true;
  6989.             return  false;
  6990.         }
  6991.  
  6992.         return false;
  6993.  
  6994.     case tkLParen:
  6995.  
  6996.         // HACK: for now always assume that this is a function call
  6997.  
  6998.     case tkAsg:
  6999.     case tkAsgAdd:
  7000.     case tkAsgSub:
  7001.     case tkAsgMul:
  7002.     case tkAsgDiv:
  7003.     case tkAsgMod:
  7004.     case tkAsgAnd:
  7005.     case tkAsgXor:
  7006.     case tkAsgOr:
  7007.     case tkAsgLsh:
  7008.     case tkAsgRsh:
  7009.     case tkAsgCnc:
  7010.  
  7011.     case tkArrow:
  7012.  
  7013.     case tkIntCon:
  7014.     case tkLngCon:
  7015.     case tkFltCon:
  7016.     case tkDblCon:
  7017.     case tkStrCon:
  7018.  
  7019.         /* Just a short-cut to give up quicker ... */
  7020.  
  7021.         return  false;
  7022.  
  7023.     default:
  7024.  
  7025.         /* We have a simple identifier, see whether it's defined */
  7026.  
  7027.         name = parseScan->scanTok.id.tokIdent;
  7028.  
  7029.         if  (noLookup)
  7030.         {
  7031.             /* We can't really do lookups, so use heuristics */
  7032.  
  7033.         QUALCHK:
  7034.  
  7035.             for (;;)
  7036.             {
  7037.                 switch (parseScan->scan())
  7038.                 {
  7039.                 case tkID:
  7040.                 case tkAnd:
  7041.                 case tkMul:
  7042.                 case tkLBrack:
  7043.                     // UNDONE: add more things that start a type
  7044.                     return  true;
  7045.  
  7046.                 case tkLParen:
  7047.                     // ISSUE: what's the right thing to do here?
  7048.                     return  true;
  7049.  
  7050.                 case tkColon2:
  7051.                 case tkDot:
  7052.  
  7053.                     if  (parseScan->scan() != tkID)
  7054.                         return  false;
  7055.  
  7056.                     continue;
  7057.  
  7058.                 default:
  7059.                     return  false;
  7060.                 }
  7061.             }
  7062.         }
  7063.  
  7064.         if  (nextTok == tkID)
  7065.         {
  7066.             /* Sure looks like a type, don't it? */
  7067.  
  7068.             tsym = parseStab->stLookupSym(name, NS_TYPE);
  7069.             if  (tsym)
  7070.                 break;
  7071.         }
  7072.  
  7073.         /* If it's a local name, it can't be a type */
  7074.  
  7075.         if  (parseLookupSym(name))
  7076.             return  false;
  7077.  
  7078.         /* Look for a non-local name */
  7079.  
  7080.         tsym = parseStab->stLookupSym(name, (name_space)(NS_NORM|NS_TYPE));
  7081.         break;
  7082.     }
  7083.  
  7084. CHKSYM:
  7085.  
  7086.     /* We might have found a symbol, see if it represents a type */
  7087.  
  7088.     if  (tsym)
  7089.     {
  7090.         switch (tsym->sdSymKind)
  7091.         {
  7092.         case SYM_ENUM:
  7093.         case SYM_CLASS:
  7094.         case SYM_TYPEDEF:
  7095.         case SYM_NAMESPACE: // HACK!HACK!HACK!HACK!HACK!HACK!HACK!HACK!HACK!HACK!HACK!HACK!HACK!
  7096.             return  true;
  7097.         }
  7098.     }
  7099.  
  7100.     return  false;
  7101. }
  7102.  
  7103. /*****************************************************************************
  7104.  *
  7105.  *  Return non-zero if the given operator may throw an exception.
  7106.  */
  7107.  
  7108. bool                TreeNode::tnOperMayThrow()
  7109. {
  7110.     // ISSUE: Are we missing any operations that could cause an exception?
  7111.  
  7112.     switch (tnOper)
  7113.     {
  7114.     case TN_DIV:
  7115.     case TN_MOD:
  7116.         return  varTypeIsIntegral(tnVtypGet());
  7117.  
  7118.     case TN_NEW:
  7119.     case TN_CALL:
  7120.     case TN_INDEX:
  7121.         return  true;
  7122.     }
  7123.  
  7124.     return  false;
  7125. }
  7126.  
  7127. /*****************************************************************************
  7128.  *
  7129.  *  Parse a "new" expression - this usually allocates a class or an array.
  7130.  */
  7131.  
  7132. Tree                parser::parseNewExpr()
  7133. {
  7134.     declMods        mods;
  7135.     TypDef          type;
  7136.  
  7137.     bool            mgdSave;
  7138.  
  7139.     Tree             newExpr;
  7140.     Tree            initExpr = NULL;
  7141.  
  7142.     Scanner         ourScanner = parseScan;
  7143.  
  7144. //  static int x; if (++x == 0) forceDebugBreak();
  7145.  
  7146.     /* Swallow the "new" token and check for management */
  7147.  
  7148.     assert(ourScanner->scanTok.tok == tkNEW);
  7149.  
  7150.     mgdSave = parseComp->cmpManagedMode;
  7151.  
  7152.     switch (ourScanner->scan())
  7153.     {
  7154.     case tkMANAGED:
  7155.         parseComp->cmpManagedMode = true;
  7156.         ourScanner->scan();
  7157.         break;
  7158.  
  7159.     case tkUNMANAGED:
  7160.         parseComp->cmpManagedMode = false;
  7161.         ourScanner->scan();
  7162.         break;
  7163.     }
  7164.  
  7165.     /* Check for any modifiers */
  7166.  
  7167.     parseDeclMods(ACL_DEFAULT, &mods);
  7168.  
  7169.     /* Make sure the modifiers are reasonable */
  7170.  
  7171.     if  (mods.dmMod & (DM_ALL & ~(DM_MANAGED|DM_UNMANAGED)))
  7172.     {
  7173.         UNIMPL(!"report bad new mod");
  7174.     }
  7175.  
  7176.     /* Parse the type specification */
  7177.  
  7178.     type = parseTypeSpec(&mods, true);
  7179.     if  (!type)
  7180.     {
  7181.         // ISSUE: probably should resync and return err node
  7182.  
  7183.     ERR:
  7184.  
  7185.         parseComp->cmpManagedMode = mgdSave;
  7186.         return  NULL;
  7187.     }
  7188.  
  7189.     /* Check for the special case of "classname(args)" */
  7190.  
  7191.     if  (ourScanner->scanTok.tok == tkLParen)
  7192.     {
  7193.         switch (type->tdTypeKind)
  7194.         {
  7195.         case TYP_CLASS:
  7196.             assert(type->tdClass.tdcValueType || !type->tdIsManaged);
  7197.             break;
  7198.  
  7199.         case TYP_REF:
  7200.             type = type->tdRef.tdrBase;
  7201.             assert(type->tdTypeKind == TYP_CLASS);
  7202.             assert(type->tdIsManaged);
  7203.             assert(type->tdClass.tdcValueType == false);
  7204.             break;
  7205.  
  7206.         case TYP_ENUM:
  7207.  
  7208.             if  (type->tdIsManaged)
  7209.                 break;
  7210.  
  7211.             // Fall through ...
  7212.  
  7213.         default:
  7214.  
  7215.             if  (type->tdTypeKind > TYP_lastIntrins)
  7216.                 goto NON_CLS;
  7217.  
  7218.             type = parseComp->cmpFindStdValType(type->tdTypeKindGet());
  7219.             break;
  7220.  
  7221.         case TYP_UNDEF:
  7222.             return  parseCreateErrNode();
  7223.         }
  7224.  
  7225.         /* Parse the ctor argument list */
  7226.  
  7227.         initExpr = parseExprList(tkRParen);
  7228.     }
  7229.     else
  7230.     {
  7231.         /* Parse the declarator */
  7232.  
  7233. NON_CLS:
  7234.  
  7235.         // ISSUE: Can't tell whether "char[size]" s/b a managed array or not!
  7236.  
  7237.         parseDeclarator(&mods, type, DN_NONE, &type, NULL, true);
  7238.         if  (!type)
  7239.             goto ERR;
  7240.  
  7241.         type = parseComp->cmpDirectType(type);
  7242.  
  7243.         /* What kind of a type is being allocated? */
  7244.  
  7245.         switch (type->tdTypeKind)
  7246.         {
  7247.         case TYP_REF:
  7248.  
  7249.             type = type->tdRef.tdrBase;
  7250.             assert(type->tdTypeKind == TYP_CLASS);
  7251.  
  7252.             // Fall through ...
  7253.  
  7254.         case TYP_CLASS:
  7255.  
  7256.             if  (ourScanner->scanTok.tok == tkLParen)
  7257.                 initExpr = parseExprList(tkRParen);
  7258.  
  7259.             break;
  7260.  
  7261.         case TYP_ARRAY:
  7262.  
  7263.             if  (ourScanner->scanTok.tok == tkLCurly)
  7264.                 initExpr = parseInitExpr();
  7265.  
  7266.             break;
  7267.  
  7268.         default:
  7269.  
  7270.             /* Presumably an unmanaged allocation */
  7271.  
  7272.             type = parseStab->stNewRefType(TYP_PTR, type);
  7273.             break;
  7274.         }
  7275.     }
  7276.  
  7277.     newExpr = parseCreateOperNode(TN_NEW, initExpr, NULL);
  7278.     newExpr->tnType = type;
  7279.  
  7280.     parseComp->cmpManagedMode = mgdSave;
  7281.  
  7282.     return  newExpr;
  7283. }
  7284.  
  7285. /*****************************************************************************
  7286.  *
  7287.  *  Swallow a security 'action' specifier.
  7288.  */
  7289.  
  7290. struct  capDesc
  7291. {
  7292.     const   char *      cdName;
  7293.     CorDeclSecurity     cdSpec;
  7294. };
  7295.  
  7296. CorDeclSecurity     parser::parseSecAction()
  7297. {
  7298.     const   char *  name;
  7299.     CorDeclSecurity spec;
  7300.  
  7301.     capDesc      *  capp;
  7302.  
  7303.     static
  7304.     capDesc         caps[] =
  7305.     {
  7306.         { "request",      dclRequest          },
  7307.         { "demand",       dclDemand           },
  7308. //      { "assert",       dclAssert           },
  7309.         { "deny",         dclDeny             },
  7310.         { "permitonly",   dclPermitOnly       },
  7311.         { "linkcheck",    dclLinktimeCheck    },
  7312.         { "inheritcheck", dclInheritanceCheck },
  7313.  
  7314.         {     NULL      , dclActionNil        }
  7315.     };
  7316.  
  7317.     if  (parseScan->scanTok.tok != tkID)
  7318.     {
  7319.         if  (parseScan->scanTok.tok == tkASSERT)
  7320.         {
  7321.             parseScan->scan();
  7322.             return  dclAssert;
  7323.         }
  7324.  
  7325.         UNIMPL("weird security spec, what to do?");
  7326.     }
  7327.  
  7328.     name = parseScan->scanTok.id.tokIdent->idSpelling();
  7329.  
  7330.     for (capp = caps; ; capp++)
  7331.     {
  7332.         if  (!capp->cdName)
  7333.         {
  7334.             parseComp->cmpGenError(ERRbadSecActn, name);
  7335.             spec = capp->cdSpec;
  7336.             break;
  7337.         }
  7338.  
  7339.         if  (!strcmp(name, capp->cdName))
  7340.         {
  7341.             spec = capp->cdSpec;
  7342.             break;
  7343.         }
  7344.     }
  7345.  
  7346.     parseScan->scan();
  7347.  
  7348.     return  spec;
  7349. }
  7350.  
  7351. /*****************************************************************************
  7352.  *
  7353.  *  Parse a capability specifier.
  7354.  */
  7355.  
  7356. SecurityInfo        parser::parseCapability(bool forReal)
  7357. {
  7358.     Scanner         ourScanner = parseScan;
  7359.  
  7360.     CorDeclSecurity spec;
  7361.     SecurityInfo    info = NULL;
  7362.  
  7363.     assert(ourScanner->scanTok.tok == tkCAPABILITY); ourScanner->scan();
  7364.  
  7365.     /* The security action comes first */
  7366.  
  7367.     spec = parseSecAction();
  7368.  
  7369.     /* Next comes the expression that yields the GUID/url */
  7370.  
  7371.     if  (forReal)
  7372.     {
  7373.         constVal        cval;
  7374.  
  7375.         if  (parseConstExpr(cval, NULL, parseComp->cmpStringRef(), NULL))
  7376.         {
  7377.             assert(cval.cvIsStr);
  7378.  
  7379.             /* Allocate and fill in a security descriptor */
  7380.  
  7381. #if MGDDATA
  7382.             info = new SecurityInfo;
  7383. #else
  7384.             info =    (SecurityInfo)parseAllocPerm->nraAlloc(sizeof(*info));
  7385. #endif
  7386.  
  7387.             info->sdSpec    = spec;
  7388.             info->sdIsPerm  = false;
  7389.             info->sdCapbStr = cval.cvValue.cvSval;
  7390.         }
  7391.     }
  7392.     else
  7393.     {
  7394.         parseComp->cmpErrorMssgDisabled++;
  7395.         parseExprComma();
  7396.         parseComp->cmpErrorMssgDisabled--;
  7397.     }
  7398.  
  7399.     return  info;
  7400. }
  7401.  
  7402. /*****************************************************************************
  7403.  *
  7404.  *  Parse a permission specifier.
  7405.  */
  7406.  
  7407. SecurityInfo        parser::parsePermission(bool forReal)
  7408. {
  7409.     Scanner         ourScanner = parseScan;
  7410.  
  7411.     CorDeclSecurity spec;
  7412.     SecurityInfo    info = NULL;
  7413.  
  7414.     SymDef          clss = NULL;
  7415.  
  7416.     PairList        list = NULL;
  7417.     PairList        last = NULL;
  7418.  
  7419. //  __permission deny   UIPermission(unrestricted=true) void f(){}
  7420. //  __permission demand UIPermission(unrestricted=true) void g(){}
  7421.  
  7422.     assert(ourScanner->scanTok.tok == tkPERMISSION); ourScanner->scan();
  7423.  
  7424.     /* The security action comes first */
  7425.  
  7426.     spec = parseSecAction();
  7427.  
  7428.     /* Next comes a reference to a class name */
  7429.  
  7430.     if  (forReal)
  7431.     {
  7432.         clss = parseNameUse(true, false, false);
  7433.  
  7434.         if  (clss && clss->sdSymKind != SYM_CLASS)
  7435.             parseComp->cmpError(ERRnoClassName);
  7436.     }
  7437.     else
  7438.         parseQualName(false);
  7439.  
  7440.     /* Now we expect a parenthesised list of [name=value] pairs */
  7441.  
  7442.     if  (ourScanner->scanTok.tok != tkLParen)
  7443.     {
  7444.         parseComp->cmpError(ERRnoLparen);
  7445.         // ISSUE: error recovery?
  7446.         return  NULL;
  7447.     }
  7448.  
  7449.     for (;;)
  7450.     {
  7451.         Ident           name;
  7452.  
  7453.         /* First we must have an identifier */
  7454.  
  7455.         if  (ourScanner->scan() != tkID)
  7456.         {
  7457.             parseComp->cmpError(ERRnoIdent);
  7458.             UNIMPL(!"error recovery");
  7459.         }
  7460.  
  7461.         name = ourScanner->scanTok.id.tokIdent;
  7462.  
  7463.         /* Next comes the "= value" part */
  7464.  
  7465.         if  (ourScanner->scan() != tkAsg)
  7466.         {
  7467.             parseComp->cmpError(ERRnoEqual);
  7468.             UNIMPL(!"error recovery");
  7469.         }
  7470.  
  7471.         ourScanner->scan();
  7472.  
  7473.         if  (forReal)
  7474.         {
  7475.             PairList        next;
  7476.  
  7477.             /* Allocate and fill in a pair entry and append it to the list */
  7478.  
  7479. #if MGDDATA
  7480.             next = new PairList;
  7481. #else
  7482.             next =    (PairList)parseAllocPerm->nraAlloc(sizeof(*next));
  7483. #endif
  7484.  
  7485.             next->plName  = name;
  7486.             next->plNext  = NULL;
  7487.  
  7488.             if  (last)
  7489.                 last->plNext = next;
  7490.             else
  7491.                 list         = next;
  7492.             last = next;
  7493.  
  7494.             /* Fill in the value */
  7495.  
  7496.             switch (ourScanner->scanTok.tok)
  7497.             {
  7498.             case tkFALSE:
  7499.                 next->plValue = false;
  7500.                 ourScanner->scan();
  7501.                 break;
  7502.  
  7503.             case tkTRUE:
  7504.                 next->plValue = true;
  7505.                 ourScanner->scan();
  7506.                 break;
  7507.  
  7508.             default:
  7509.                 UNIMPL(!"sorry, only true/false supported for now");
  7510.             }
  7511.         }
  7512.         else
  7513.         {
  7514.             parseExprComma();
  7515.         }
  7516.  
  7517.         /* Do we have any more values? */
  7518.  
  7519.         if  (ourScanner->scanTok.tok != tkComma)
  7520.             break;
  7521.     }
  7522.  
  7523.     chkCurTok(tkRParen, ERRnoRparen);
  7524.  
  7525.     if  (forReal)
  7526.     {
  7527.         /* Allocate and fill in a security descriptor */
  7528.  
  7529. #if MGDDATA
  7530.         info = new SecurityInfo;
  7531. #else
  7532.         info =    (SecurityInfo)parseAllocPerm->nraAlloc(sizeof(*info));
  7533. #endif
  7534.  
  7535.         info->sdSpec           = spec;
  7536.         info->sdIsPerm         = true;
  7537.         info->sdPerm.sdPermCls = clss;
  7538.         info->sdPerm.sdPermVal = list;
  7539.     }
  7540.  
  7541.     return  info;
  7542. }
  7543.  
  7544. /*****************************************************************************
  7545.  *
  7546.  *  Parse a formal paremeter list for a generic class.
  7547.  */
  7548.  
  7549. GenArgDscF          parser::parseGenFormals()
  7550. {
  7551.     Scanner         ourScanner = parseScan;
  7552.  
  7553.     GenArgDscF      paramList;
  7554.     GenArgDscF      paramLast;
  7555.     GenArgDscF      paramNext;
  7556.  
  7557.     assert(ourScanner->scanTok.tok == tkLT);
  7558.  
  7559.     for (paramList = paramLast = NULL;;)
  7560.     {
  7561.         /* We should have "class foo" here */
  7562.  
  7563.         if  (ourScanner->scan() != tkCLASS)
  7564.         {
  7565.             parseComp->cmpError(ERRnoClsGt);
  7566.  
  7567.         ERR:
  7568.  
  7569.             parseScan->scanSkipText(tkNone, tkNone, tkGT);
  7570.  
  7571.             if  (ourScanner->scanTok.tok == tkGT)
  7572.                 ourScanner->scan();
  7573.  
  7574.             return  NULL;
  7575.         }
  7576.  
  7577.         if  (ourScanner->scan() != tkID)
  7578.         {
  7579.             parseComp->cmpError(ERRnoIdent);
  7580.             goto ERR;
  7581.         }
  7582.  
  7583.         /* Add a new entry to the parameter list */
  7584.  
  7585. #if MGDDATA
  7586.         paramNext = new GenArgRecF;
  7587. #else
  7588.         paramNext =    (GenArgRecF*)parseAllocPerm->nraAlloc(sizeof(*paramNext));
  7589. #endif
  7590.  
  7591.         paramNext->gaName = ourScanner->scanTok.id.tokIdent;
  7592. #ifdef  DEBUG
  7593.         paramNext->gaBound = false;
  7594. #endif
  7595.         paramNext->gaNext  = NULL;
  7596.  
  7597.         if  (paramLast)
  7598.              paramLast->gaNext = paramNext;
  7599.         else
  7600.              paramList         = paramNext;
  7601.  
  7602.         paramLast = paramNext;
  7603.  
  7604.         /* Check for (optional) base class and/or interfaces */
  7605.  
  7606.         if  (ourScanner->scan() == tkColon)
  7607.         {
  7608.             UNIMPL(!"generic arg - skip base spec");
  7609.         }
  7610.  
  7611.         if  (ourScanner->scanTok.tok == tkIMPLEMENTS)
  7612.         {
  7613.             UNIMPL(!"generic arg - skip intf spec");
  7614.         }
  7615.  
  7616.         if  (ourScanner->scanTok.tok == tkINCLUDES)
  7617.         {
  7618.             UNIMPL(!"generic arg - skip incl spec");
  7619.         }
  7620.  
  7621.         /* Are there any more arguments? */
  7622.  
  7623.         if  (ourScanner->scanTok.tok == tkGT)
  7624.             break;
  7625.  
  7626.         if  (ourScanner->scanTok.tok == tkComma)
  7627.             continue;
  7628.  
  7629.         parseComp->cmpError(ERRnoCmGt);
  7630.         goto ERR;
  7631.     }
  7632.  
  7633.     assert(ourScanner->scanTok.tok == tkGT); ourScanner->scan();
  7634.  
  7635.     return  paramList;
  7636. }
  7637.  
  7638. /*****************************************************************************
  7639.  *
  7640.  *  Parse a generic class actual paremeter list, i.e. "cls<arg,arg,..>". As a
  7641.  *  special case, the caller may pass in an optional second argument and in
  7642.  *  that case we pretend that the type was the single argument given for the
  7643.  *  specific type.
  7644.  */
  7645.  
  7646. SymDef              parser::parseSpecificType(SymDef clsSym, TypDef elemTp)
  7647. {
  7648.     Scanner         ourScanner = parseScan;
  7649.     Compiler        ourComp    = parseComp;
  7650.  
  7651.     GenArgDscF      formals;
  7652.  
  7653.     GenArgDscA      argList;
  7654.     GenArgDscA      argLast;
  7655.     GenArgDscA      argNext;
  7656.  
  7657.     SymList         instList;
  7658.  
  7659.     SymDef          instSym;
  7660.  
  7661.     assert(clsSym);
  7662.     assert(clsSym->sdSymKind == SYM_CLASS);
  7663.     assert(clsSym->sdClass.sdcGeneric  != false);
  7664.     assert(clsSym->sdClass.sdcSpecific == false);
  7665.  
  7666.     /* Before we do anything, make sure the generic class is declared */
  7667.  
  7668.     if  (clsSym->sdCompileState < CS_DECLARED)
  7669.         ourComp->cmpDeclSym(clsSym);
  7670.  
  7671.     /* Special case: caller-supplied single argument */
  7672.  
  7673.     if  (elemTp)
  7674.     {
  7675.         /* Create an actual argument list with a single entry */
  7676.  
  7677.         if  (ourComp->cmpGenArgAfree)
  7678.         {
  7679.             argNext = ourComp->cmpGenArgAfree;
  7680.                       ourComp->cmpGenArgAfree = (GenArgDscA)argNext->gaNext;
  7681.  
  7682.             assert(argNext->gaBound == true);
  7683.         }
  7684.         else
  7685.         {
  7686. #if MGDDATA
  7687.             argNext = new GenArgRecA;
  7688. #else
  7689.             argNext =    (GenArgRecA*)parseAllocPerm->nraAlloc(sizeof(*argNext));
  7690. #endif
  7691.         }
  7692.  
  7693.         argNext->gaType  = elemTp;
  7694. #ifdef  DEBUG
  7695.         argNext->gaBound = true;
  7696. #endif
  7697.         argNext->gaNext  = NULL;
  7698.  
  7699.         argList =
  7700.         argLast = argNext;
  7701.  
  7702.         goto GOT_ARGS;
  7703.     }
  7704.  
  7705.     /* Process the list of the actual arguments */
  7706.  
  7707.     argList = argLast = NULL;
  7708.  
  7709.     /* We should be sitting at the opening "<" of the argument list */
  7710.  
  7711.     assert(ourScanner->scanTok.tok == tkLT);
  7712.  
  7713.     ourScanner->scanNestedGT(+1);
  7714.  
  7715.     for (formals = (GenArgDscF)clsSym->sdClass.sdcArgLst;
  7716.          formals;
  7717.          formals = (GenArgDscF)formals->gaNext)
  7718.     {
  7719.         TypDef          argType;
  7720.  
  7721.         assert(formals->gaBound == false);
  7722.  
  7723.         /* Make sure there is another argument */
  7724.  
  7725.         if  (ourScanner->scan() == tkGT)
  7726.         {
  7727.             ourComp->cmpError(ERRmisgGenArg, formals->gaName);
  7728.  
  7729.             UNIMPL(!"need to flag the instance type as bogus, right?");
  7730.             break;
  7731.         }
  7732.  
  7733.         /* Parse the actual type */
  7734.  
  7735.         argType = parseType();
  7736.  
  7737.         /* The type better be a managed class/interface */
  7738.  
  7739.         if  (argType->tdTypeKind != TYP_REF)
  7740.         {
  7741.         ARG_ERR:
  7742.             ourComp->cmpGenError(ERRgenArg, formals->gaName->idSpelling());
  7743.             argType = NULL;
  7744.         }
  7745.         else
  7746.         {
  7747.             argType = argType->tdRef.tdrBase;
  7748.  
  7749.             if  (argType->tdTypeKind != TYP_CLASS || !argType->tdIsManaged)
  7750.                 goto ARG_ERR;
  7751.  
  7752.             /* Verify that the actual type satisfies all requirements */
  7753.  
  7754.             if  (formals->gaBase)
  7755.             {
  7756.                 if  (!ourComp->cmpIsBaseClass(formals->gaBase, argType))
  7757.                 {
  7758.                     ourComp->cmpGenError(ERRgenArgBase, formals->gaName->idSpelling(),
  7759.                                                         formals->gaBase->tdClass.tdcSymbol->sdSpelling());
  7760.                 }
  7761.             }
  7762.  
  7763.             if  (formals->gaIntf)
  7764.             {
  7765.                 UNIMPL(!"check intf");
  7766.             }
  7767.         }
  7768.  
  7769.         /* Add an entry to the actual argument list */
  7770.  
  7771.         if  (ourComp->cmpGenArgAfree)
  7772.         {
  7773.             argNext = ourComp->cmpGenArgAfree;
  7774.                       ourComp->cmpGenArgAfree = (GenArgDscA)argNext->gaNext;
  7775.  
  7776.             assert(argNext->gaBound == true);
  7777.         }
  7778.         else
  7779.         {
  7780. #if MGDDATA
  7781.             argNext = new GenArgRecA;
  7782. #else
  7783.             argNext =    (GenArgRecA*)parseAllocPerm->nraAlloc(sizeof(*argNext));
  7784. #endif
  7785.         }
  7786.  
  7787.         argNext->gaType  = argType;
  7788.  
  7789. #ifdef  DEBUG
  7790.         argNext->gaBound = true;
  7791. #endif
  7792.  
  7793.         argNext->gaNext  = NULL;
  7794.  
  7795.         if  (argLast)
  7796.              argLast->gaNext = argNext;
  7797.         else
  7798.              argList         = argNext;
  7799.  
  7800.         argLast = argNext;
  7801.  
  7802.         if  (ourScanner->scanTok.tok == tkComma)
  7803.             continue;
  7804.  
  7805.         if  (formals->gaNext)
  7806.         {
  7807.             if  (ourScanner->scanTok.tok == tkGT)
  7808.                 ourComp->cmpError(ERRmisgGenArg, formals->gaName);
  7809.             else
  7810.                 ourComp->cmpError(ERRnoComma);
  7811.  
  7812.             UNIMPL(!"need to flag the instance type as bogus, right?");
  7813.         }
  7814.  
  7815.         break;
  7816.     }
  7817.  
  7818.     if  (ourScanner->scanTok.tok != tkGT)
  7819.     {
  7820.         ourComp->cmpError(ERRnoGt);
  7821.  
  7822.         if  (ourScanner->scanTok.tok == tkComma)
  7823.         {
  7824.             /* Presumably we have excess arguments, so skip them */
  7825.  
  7826.             UNIMPL(!"swallow excess args, skip to closing '>'");
  7827.         }
  7828.     }
  7829.     else
  7830.         ourScanner->scan();
  7831.  
  7832.     ourScanner->scanNestedGT(-1);
  7833.  
  7834. GOT_ARGS:
  7835.  
  7836.     /* Look for an existing instance that matches ours */
  7837.  
  7838.     for (instList = clsSym->sdClass.sdcInstances;
  7839.          instList;
  7840.          instList = instList->slNext)
  7841.     {
  7842.         GenArgDscA      arg1;
  7843.         GenArgDscA      arg2;
  7844.  
  7845.         assert(instList->slSym->sdSymKind == SYM_CLASS);
  7846.         assert(instList->slSym->sdClass.sdcGeneric  == false);
  7847.         assert(instList->slSym->sdClass.sdcSpecific != false);
  7848.  
  7849.         /* Compare the argument types */
  7850.  
  7851.         arg1 = argList;
  7852.         arg2 = (GenArgDscA)instList->slSym->sdClass.sdcArgLst;
  7853.  
  7854.         do
  7855.         {
  7856.             TypDef          typ1 = arg1->gaType;
  7857.             TypDef          typ2 = arg2->gaType;
  7858.  
  7859.             assert(arg1 && arg1->gaBound);
  7860.             assert(arg2 && arg2->gaBound);
  7861.  
  7862.             /* If this argument doesn't match, give up on this instance */
  7863.  
  7864.             if  (!symTab::stMatchTypes(typ1, typ2))
  7865.                 goto CHK_NXT;
  7866.  
  7867.             arg1 = (GenArgDscA)arg1->gaNext;
  7868.             arg2 = (GenArgDscA)arg2->gaNext;
  7869.         }
  7870.         while (arg1);
  7871.  
  7872.         /* Looks like we've got ourselves a match! */
  7873.  
  7874.         assert(arg2 == NULL);
  7875.  
  7876.         /* Move the argument list we've created to the free list */
  7877.  
  7878.         argLast->gaNext = ourComp->cmpGenArgAfree;
  7879.                           ourComp->cmpGenArgAfree = argList;
  7880.  
  7881.         /* Return the existing instance symbol */
  7882.  
  7883.         return  instList->slSym;
  7884.  
  7885.     CHK_NXT:;
  7886.  
  7887.     }
  7888.  
  7889.     /* Declare a new instance symbol + type */
  7890.  
  7891.     instSym = parseStab->stDeclareSym(clsSym->sdName,
  7892.                                       SYM_CLASS,
  7893.                                       NS_HIDE,
  7894.                                       clsSym->sdParent);
  7895.  
  7896.     instSym->sdAccessLevel        = clsSym->sdAccessLevel;
  7897.     instSym->sdIsManaged          = clsSym->sdIsManaged;
  7898.     instSym->sdClass.sdcFlavor    = clsSym->sdClass.sdcFlavor;
  7899.     instSym->sdCompileState       = CS_KNOWN;
  7900.  
  7901.     instSym->sdClass.sdcSpecific  = true;
  7902.     instSym->sdClass.sdcArgLst    = argList;
  7903.     instSym->sdClass.sdcGenClass  = clsSym;
  7904.     instSym->sdClass.sdcHasBodies = clsSym->sdClass.sdcHasBodies;
  7905.  
  7906.     /* Set the base class of the instance equal to the generic type */
  7907.  
  7908.     instSym->sdTypeGet()->tdClass.tdcBase = clsSym->sdType;
  7909.  
  7910.     /* Add the class to the list of instances of the generic class */
  7911.  
  7912. #if MGDDATA
  7913.     instList = new SymList;
  7914. #else
  7915.     instList =    (SymList)parseAllocPerm->nraAlloc(sizeof(*instList));
  7916. #endif
  7917.  
  7918.     instList->slSym  = instSym;
  7919.     instList->slNext = clsSym->sdClass.sdcInstances;
  7920.                        clsSym->sdClass.sdcInstances = instList;
  7921.  
  7922.     return  instSym;
  7923. }
  7924.  
  7925. /*****************************************************************************/
  7926. /*****************************************************************************
  7927.  *
  7928.  *  Parse a custom attribute thingie. When parsing "for real" (i.e. when the
  7929.  *  value of "tgtMask" is non-zero), we actually create the serialized blob
  7930.  *  value and return the constructor that is to be called.
  7931.  */
  7932.  
  7933. SymDef              parser::parseAttribute(unsigned         tgtMask,
  7934.                                        OUT unsigned     REF useMask,
  7935.                                        OUT genericBuff  REF blobAddr,
  7936.                                        OUT size_t       REF blobSize)
  7937. {
  7938.     SymDef          clsSym;
  7939.     Tree            args;
  7940.  
  7941.     Scanner         ourScanner = parseScan;
  7942.  
  7943.     assert(ourScanner->scanTok.tok == tkATTRIBUTE);
  7944.  
  7945.     if  (!tgtMask)
  7946.     {
  7947.         /* First skip the class name that's supposed to follow */
  7948.  
  7949.         do
  7950.         {
  7951.             if  (ourScanner->scan() != tkID)
  7952.             {
  7953.                 parseComp->cmpError(ERRnoIdent);
  7954.                 return  NULL;
  7955.             }
  7956.  
  7957.             ourScanner->scan();
  7958.         }
  7959.         while (ourScanner->scanTok.tok == tkDot ||
  7960.                ourScanner->scanTok.tok == tkColon2);
  7961.  
  7962.         if  (ourScanner->scanTok.tok != tkLParen)
  7963.         {
  7964.             parseComp->cmpError(ERRnoRparen);
  7965.             return  NULL;
  7966.         }
  7967.  
  7968.         ourScanner->scanSkipText(tkLParen, tkRParen);
  7969.         chkCurTok(tkRParen, ERRnoRparen);
  7970.  
  7971.         return  NULL;
  7972.     }
  7973.  
  7974.     /* The first thing better be a class marked as "attribute" */
  7975.  
  7976.     ourScanner->scan();
  7977.  
  7978.     clsSym = parseNameUse(true, false, false);
  7979.  
  7980.     if  (clsSym)
  7981.     {
  7982.         if  (clsSym->sdSymKind == SYM_CLASS) // && clsSym->sdClass.sdcAttribute)
  7983.         {
  7984. //          ctrSym = parseStab->stLookupOperND(OVOP_CTOR_INST, clsSym);
  7985.         }
  7986.         else
  7987.         {
  7988.             if  (clsSym->sdSymKind != SYM_ERR)
  7989.                 parseComp->cmpErrorQnm(ERRnotAclass, clsSym);
  7990.  
  7991.             clsSym = NULL;
  7992.         }
  7993.     }
  7994.  
  7995.     /* Now parse the ctor argument list */
  7996.  
  7997.     args = parseExprList(tkRParen);
  7998.  
  7999.     /* If we had no errors, go process the ctor call */
  8000.  
  8001.     if  (clsSym)
  8002.     {
  8003.         SymDef          ctrSym;
  8004.  
  8005.         /* Let the compiler take care of binding the sucker */
  8006.  
  8007.         ctrSym = parseComp->cmpBindAttribute(clsSym, args, tgtMask,
  8008.                                                            useMask, blobAddr,
  8009.                                                                     blobSize);
  8010.         if  (ctrSym)
  8011.             return  ctrSym;
  8012.     }
  8013.  
  8014.     /* Something went wrong, return an empty blob / NULL ctor */
  8015.  
  8016.     blobAddr = NULL;
  8017.     blobSize = 0;
  8018.  
  8019.     return  NULL;
  8020. }
  8021.  
  8022. /*****************************************************************************
  8023.  *
  8024.  *  Parse an [attribute] thing or a linkage specifier: extern("linkname").
  8025.  */
  8026.  
  8027. #ifndef __SMC__
  8028. extern  const char    *     attrNames[];    // in macros.*
  8029. #endif
  8030.  
  8031. SymXinfo            parser::parseBrackAttr(bool     forReal,
  8032.                                            unsigned OKmask,
  8033.                                            DeclMod  modsPtr)
  8034. {
  8035.     Scanner         ourScanner = parseScan;
  8036.  
  8037.     char    *       DLLname;
  8038.     char    *       SYMname;
  8039.     callingConvs    callCnv;
  8040.     unsigned        strVal;
  8041.     bool            lstErr;
  8042.  
  8043.     constVal        cval;
  8044.     const   char *  name;
  8045.     unsigned        attr;
  8046.  
  8047.     if  (ourScanner->scanTok.tok == tkEXTERN)
  8048.     {
  8049.         SymXinfoLnk     entry;
  8050.  
  8051.         assert(modsPtr);
  8052.  
  8053.         /* The caller has already checked that "(" follows */
  8054.  
  8055.         ourScanner->scan(); assert(ourScanner->scanTok.tok == tkLParen);
  8056.  
  8057.         /* The next thing should be the linkage name */
  8058.  
  8059.         if  (ourScanner->scan() != tkStrCon)
  8060.         {
  8061.         NO_STR:
  8062.             parseComp->cmpError(ERRnoLinkStr);
  8063.             parseResync(tkLParen, tkRParen);
  8064.             return  NULL;
  8065.         }
  8066.  
  8067.         /* Are we just skipping the thing for now ? */
  8068.  
  8069.         if  (!forReal)
  8070.         {
  8071.             if  (ourScanner->scanLookAhead() == tkComma)
  8072.             {
  8073.                 ourScanner->scan();
  8074.  
  8075.                 if  (ourScanner->scan() != tkStrCon)
  8076.                     goto NO_STR;
  8077.             }
  8078.  
  8079.             chkNxtTok(tkRParen, ERRnoRparen);
  8080.  
  8081.             parseDeclMods(ACL_DEFAULT, modsPtr); modsPtr->dmMod |= DM_EXTERN;
  8082.  
  8083.             return  NULL;
  8084.         }
  8085.  
  8086.         DLLname = NULL;
  8087.         SYMname = NULL;
  8088.         strVal  = 0;
  8089.         lstErr  = false;
  8090.  
  8091.         /* Is there a separate string for the entry point ? */
  8092.  
  8093.         if  (ourScanner->scanLookAhead() == tkComma)
  8094.         {
  8095.             size_t          strLen;
  8096.  
  8097.             /* Save the DLL name string */
  8098.  
  8099.             strLen  = ourScanner->scanTok.strCon.tokStrLen;
  8100.             DLLname = (char*)parseAllocPerm->nraAlloc(roundUp(strLen+1));
  8101.             memcpy(DLLname, ourScanner->scanTok.strCon.tokStrVal, strLen+1);
  8102.  
  8103.             /* We should have a comma followed by another string */
  8104.  
  8105.             ourScanner->scan();
  8106.  
  8107.             if  (ourScanner->scan() != tkStrCon)
  8108.                 goto NO_STR;
  8109.  
  8110.             /* Save the entry point name string */
  8111.  
  8112.             strLen  = ourScanner->scanTok.strCon.tokStrLen;
  8113.             SYMname = (char*)parseAllocPerm->nraAlloc(roundUp(strLen+1));
  8114.             memcpy(SYMname, ourScanner->scanTok.strCon.tokStrVal, strLen+1);
  8115.         }
  8116.         else
  8117.         {
  8118.             const   char *  str = ourScanner->scanTok.strCon.tokStrVal;
  8119.             size_t          len = ourScanner->scanTok.strCon.tokStrLen;
  8120.  
  8121.             const   char *  col;
  8122.  
  8123.             /* The string should have the format "DLLname:entrypoint" */
  8124.  
  8125.             col = strchr(str, ':');
  8126.  
  8127.             if  (col && col > str && col < str + len - 1)
  8128.             {
  8129.                 size_t          DLLnlen;
  8130.                 size_t          SYMnlen;
  8131.  
  8132.                 DLLnlen = col - str;
  8133.                 SYMnlen = str + len - col;
  8134.  
  8135. #if MGDDATA
  8136.                 UNIMPL(!"save nane strings");
  8137. #else
  8138.                 DLLname = (char*)parseAllocPerm->nraAlloc(roundUp(DLLnlen+1));
  8139.                 SYMname = (char*)parseAllocPerm->nraAlloc(roundUp(SYMnlen+1));
  8140.  
  8141.                 memcpy(DLLname, str  , DLLnlen); DLLname[DLLnlen] = 0;
  8142.                 memcpy(SYMname, col+1, SYMnlen); SYMname[SYMnlen] = 0;
  8143. #endif
  8144.  
  8145.             }
  8146.             else
  8147.             {
  8148.                 parseComp->cmpError(ERRbadLinkStr);
  8149.             }
  8150.         }
  8151.  
  8152.         chkNxtTok(tkRParen, ERRnoRparen);
  8153.  
  8154.         /* Temp hack: default to "cdecl" for extern-style imports */
  8155.  
  8156.         callCnv = CCNV_CDECL;
  8157.  
  8158.     SAVE_LINK:
  8159.  
  8160. //      printf("DLL name: '%s'\n", DLLname);
  8161. //      printf("SYM name: '%s'\n", SYMname);
  8162.  
  8163.         /* Allocate a linkage descriptor and save the info */
  8164.  
  8165. #if MGDDATA
  8166.         entry = new SymXinfoLnk;
  8167. #else
  8168.         entry =    (SymXinfoLnk)parseAllocPerm->nraAlloc(sizeof(*entry));
  8169. #endif
  8170.  
  8171.         entry->xiKind = XI_LINKAGE;
  8172.         entry->xiNext = NULL;
  8173.  
  8174.         entry->xiLink.ldDLLname = DLLname;
  8175.         entry->xiLink.ldSYMname = SYMname;
  8176.         entry->xiLink.ldStrings = strVal;
  8177.         entry->xiLink.ldLastErr = lstErr;
  8178.         entry->xiLink.ldCallCnv = callCnv;
  8179.  
  8180.         /* Grab any further modifiers that might be present */
  8181.  
  8182.         if  (modsPtr)
  8183.         {
  8184.             parseDeclMods(ACL_DEFAULT, modsPtr);
  8185.                                        modsPtr->dmMod |= DM_EXTERN;
  8186.         }
  8187.  
  8188.         return  entry;
  8189.     }
  8190.  
  8191.     /* Here we must have a bracketed attribute deal */
  8192.  
  8193.     assert(ourScanner->scanTok.tok == tkLBrack);
  8194.  
  8195.     /* Skip the "[" and make sure an attribute name follows */
  8196.  
  8197.     if  (ourScanner->scan() == tkID)
  8198.     {
  8199.         name = ourScanner->scanTok.id.tokIdent->idSpelling();
  8200.     }
  8201.     else
  8202.     {
  8203.         if  (ourScanner->scanTok.tok > tkKwdLast)
  8204.         {
  8205.         ATTR_ERR:
  8206.             parseComp->cmpError(ERRbadAttr);
  8207.  
  8208.         ATTR_SKIP:
  8209.             parseResync(tkRBrack, tkNone);
  8210.             if  (ourScanner->scanTok.tok == tkRBrack)
  8211.                 ourScanner->scan();
  8212.             return  NULL;
  8213.         }
  8214.  
  8215.         name = parseHash->tokenToIdent(ourScanner->scanTok.tok)->idSpelling();
  8216.     }
  8217.  
  8218.     /* Check for a recognized attribute name [linear search via strcmp - hmm ...] */
  8219.  
  8220.     for (attr = 0; attr < ATTR_COUNT; attr++)
  8221.     {
  8222.         if  (!strcmp(name, attrNames[attr]))
  8223.         {
  8224.             /* Match - make sure the attribute is acceptable here */
  8225.  
  8226.             if  (!(OKmask & (1 << attr)) && OKmask)
  8227.             {
  8228.                 parseComp->cmpError(ERRplcAttr);
  8229.                 goto ATTR_SKIP;
  8230.             }
  8231.  
  8232.             switch (attr)
  8233.             {
  8234.             case ATTR_SYS_IMPORT:
  8235.                 goto LINK;
  8236.  
  8237.             case ATTR_GUID:
  8238.  
  8239.                 // [guid(string)]
  8240.  
  8241.                 if  (ourScanner->scan() == tkLParen)
  8242.                 {
  8243.                     SymXinfoAtc     entry;
  8244.  
  8245.                     if  (ourScanner->scan() == tkRParen)
  8246.                         goto ATTR_ERR;
  8247.  
  8248.                     if  (forReal)
  8249.                     {
  8250.                         if  (parseConstExpr(cval, NULL, parseComp->cmpStringRef(), NULL))
  8251.                         {
  8252.                             AtComment       adesc;
  8253.                             GUID            GUID;
  8254.  
  8255.                             assert(cval.cvIsStr);
  8256.  
  8257.                             /* Make sure the string is valid */
  8258.  
  8259.                             if  (parseGUID(cval.cvValue.cvSval->csStr, &GUID, false))
  8260.                                 goto ATTR_ERR;
  8261.  
  8262.                             /* Temp hack: create an @comment thing */
  8263.  
  8264. #if MGDDATA
  8265.                             adesc = new AtComment;
  8266. #else
  8267.                             adesc =    (AtComment)parseAllocPerm->nraAlloc(sizeof(*adesc));
  8268. #endif
  8269.  
  8270.                             adesc->atcFlavor              = AC_COM_REGISTER;
  8271.                             adesc->atcNext                = NULL;
  8272.                             adesc->atcInfo.atcReg.atcGUID = cval.cvValue.cvSval;
  8273.                             adesc->atcInfo.atcReg.atcDual = false;
  8274.  
  8275. #if MGDDATA
  8276.                             entry = new SymXinfoAtc;
  8277. #else
  8278.                             entry =    (SymXinfoAtc)parseAllocPerm->nraAlloc(sizeof(*entry));
  8279. #endif
  8280.  
  8281.                             entry->xiKind    = XI_ATCOMMENT;
  8282.                             entry->xiNext    = NULL;
  8283.                             entry->xiAtcInfo = adesc;
  8284.                         }
  8285.                     }
  8286.                     else
  8287.                     {
  8288.                         parseExprSkip(); entry = NULL;
  8289.                     }
  8290.  
  8291.                     if  (ourScanner->scanTok.tok != tkRParen)
  8292.                         goto ATTR_ERR;
  8293.  
  8294.                     if  (ourScanner->scan()      != tkRBrack)
  8295.                         goto ATTR_ERR;
  8296.  
  8297.                     ourScanner->scan();
  8298.  
  8299.                     return  entry;
  8300.                 }
  8301.                 goto ATTR_ERR;
  8302.  
  8303.             case ATTR_SYS_STRUCT:
  8304.  
  8305.                 // [sysstruct(charset=CharacterSet::Unicode,pack=4)]
  8306.  
  8307.                 if  (ourScanner->scan() == tkLParen)
  8308.                 {
  8309.                     AtComment       adesc;
  8310.                     SymXinfoAtc     entry;
  8311.  
  8312.                     int             cset = 0;
  8313.                     unsigned        pack = 0;
  8314.  
  8315.                     if  (ourScanner->scan() == tkRParen)
  8316.                         goto END_SS;
  8317.  
  8318.                     for (;;)
  8319.                     {
  8320.                         if  (ourScanner->scanTok.tok != tkID)
  8321.                             goto ATTR_ERR;
  8322.  
  8323.                         name = ourScanner->scanTok.id.tokIdent->idSpelling();
  8324.  
  8325.                         if  (ourScanner->scan() != tkAsg)
  8326.                             goto ATTR_ERR;
  8327.  
  8328.                         ourScanner->scan();
  8329.  
  8330.                         if      (!strcmp(name, "pack"))
  8331.                         {
  8332.                             if  (forReal)
  8333.                             {
  8334.                                 if  (parseConstExpr(cval, NULL, parseComp->cmpTypeUint, NULL))
  8335.                                 {
  8336.                                     pack = cval.cvValue.cvIval;
  8337.  
  8338.                                     if  (pack !=  1 &&
  8339.                                          pack !=  2 &&
  8340.                                          pack !=  4 &&
  8341.                                          pack !=  8 &&
  8342.                                          pack != 16)
  8343.                                     {
  8344.                                         goto ATTR_ERR;
  8345.                                     }
  8346.                                 }
  8347.                             }
  8348.                             else
  8349.                             {
  8350.                                 if  (pack)
  8351.                                     goto ATTR_ERR;
  8352.  
  8353.                                 parseExprSkip(); pack = 1;
  8354.                             }
  8355.                         }
  8356.                         else if (!strcmp(name, "charset"))
  8357.                         {
  8358.                             if  (forReal)
  8359.                             {
  8360.                                 if  (parseConstExpr(cval, NULL, parseComp->cmpCharSetGet()->sdType, NULL))
  8361.                                     cset = cval.cvValue.cvIval;
  8362.                             }
  8363.                             else
  8364.                             {
  8365.                                 if  (cset)
  8366.                                     goto ATTR_ERR;
  8367.  
  8368.                                 parseExprSkip(); cset = 1;
  8369.                             }
  8370.                         }
  8371.                         else
  8372.                             goto ATTR_ERR;
  8373.  
  8374.                         if  (ourScanner->scanTok.tok != tkComma)
  8375.                             break;
  8376.  
  8377.                         ourScanner->scan();
  8378.                     }
  8379.  
  8380.                     if  (ourScanner->scanTok.tok != tkRParen)
  8381.                         goto ATTR_ERR;
  8382.  
  8383.                 END_SS:
  8384.  
  8385.                     if  (ourScanner->scan() != tkRBrack)
  8386.                         goto ATTR_ERR;
  8387.  
  8388.                     ourScanner->scan();
  8389.  
  8390.                     if  (!forReal)
  8391.                         return  NULL;
  8392.  
  8393.                     /* Temp hack: create an @comment thing */
  8394.  
  8395. #if MGDDATA
  8396.                     adesc = new AtComment;
  8397. #else
  8398.                     adesc =    (AtComment)parseAllocPerm->nraAlloc(sizeof(*adesc));
  8399. #endif
  8400.  
  8401.                     adesc->atcFlavor                    = AC_DLL_STRUCT;
  8402.                     adesc->atcNext                      = NULL;
  8403.                     adesc->atcInfo.atcStruct.atcStrings = cset;
  8404.                     adesc->atcInfo.atcStruct.atcPack    = pack;
  8405.  
  8406. #if MGDDATA
  8407.                     entry = new SymXinfoAtc;
  8408. #else
  8409.                     entry =    (SymXinfoAtc)parseAllocPerm->nraAlloc(sizeof(*entry));
  8410. #endif
  8411.  
  8412.                     entry->xiKind    = XI_ATCOMMENT;
  8413.                     entry->xiNext    = NULL;
  8414.                     entry->xiAtcInfo = adesc;
  8415.  
  8416.                     return  entry;
  8417.                 }
  8418.                 goto ATTR_ERR;
  8419.  
  8420.             case ATTR_NATIVE_TYPE:
  8421.  
  8422.                 // nativetype(NativeType.xxxx,size=123)
  8423.  
  8424.                 if  (ourScanner->scan() == tkLParen)
  8425.                 {
  8426.                     SymXinfoCOM     entry = NULL;
  8427.                     MarshalInfo     adesc;
  8428.  
  8429.                     int             type  = -1;
  8430.                     int             sbtp  = -1;
  8431.                     int             size  = -1;
  8432.  
  8433.                     const   char *  custG = NULL;
  8434.                     const   char *  custC = NULL;
  8435.                     SymDef          custT = NULL;
  8436.  
  8437.                     int             amIn  = 0;
  8438.                     int             amOut = 0;
  8439.  
  8440.                     /* The first thing must be the type itself */
  8441.  
  8442.                     ourScanner->scan();
  8443.  
  8444.                     if  (forReal)
  8445.                     {
  8446.                         if  (parseConstExpr(cval, NULL, parseComp->cmpNatTypeGet()->sdType, NULL))
  8447.                             type = cval.cvValue.cvIval;
  8448.                     }
  8449.                     else
  8450.                         parseExprSkip();
  8451.  
  8452.                     /* Is there more stuff ? */
  8453.  
  8454.                     while (ourScanner->scanTok.tok == tkComma)
  8455.                     {
  8456.                         /* Check for "size=" and the others */
  8457.  
  8458.                         if  (ourScanner->scan() != tkID)
  8459.                         {
  8460.                             if      (ourScanner->scanTok.tok == tkIN)
  8461.                                 amIn  = true;
  8462.                             else if (ourScanner->scanTok.tok == tkOUT)
  8463.                                 amOut = true;
  8464.                             else
  8465.                                 goto ATTR_ERR;
  8466.  
  8467.                             ourScanner->scan();
  8468.                             continue;
  8469.                         }
  8470.  
  8471.                         name = ourScanner->scanTok.id.tokIdent->idSpelling();
  8472.  
  8473.                         if  (ourScanner->scan() != tkAsg)
  8474.                             goto ATTR_ERR;
  8475.  
  8476.                         ourScanner->scan();
  8477.  
  8478.                         if      (!strcmp(name, "size"))
  8479.                         {
  8480.                             if  (forReal)
  8481.                             {
  8482.                                 if  (parseConstExpr(cval, NULL, parseComp->cmpTypeUint, NULL))
  8483.                                     size = cval.cvValue.cvIval;
  8484.                             }
  8485.                             else
  8486.                             {
  8487.                                 if  (type != NATIVE_TYPE_FIXEDSYSSTRING &&
  8488.                                      type != NATIVE_TYPE_FIXEDARRAY     && type != -1)
  8489.                                 {
  8490.                                     goto ATTR_ERR;
  8491.                                 }
  8492.  
  8493.                                 parseExprSkip();
  8494.                             }
  8495.                         }
  8496.                         else if (!strcmp(name, "subtype"))
  8497.                         {
  8498.                             if  (forReal)
  8499.                             {
  8500.                                 if  (parseConstExpr(cval, NULL, parseComp->cmpNatTypeGet()->sdType, NULL))
  8501.                                     sbtp = cval.cvValue.cvIval;
  8502.                             }
  8503.                             else
  8504.                             {
  8505.                                 if  (type != NATIVE_TYPE_ARRAY     &&
  8506.                                      type != NATIVE_TYPE_SAFEARRAY && type != -1)
  8507.                                 {
  8508.                                     goto ATTR_ERR;
  8509.                                 }
  8510.  
  8511.                                 parseExprSkip();
  8512.                             }
  8513.                         }
  8514.                         else if (!strcmp(name, "marshalcomtype"))
  8515.                         {
  8516.                             if  (forReal)
  8517.                             {
  8518.                                 if  (parseConstExpr(cval, NULL, parseComp->cmpStringRef(), NULL))
  8519.                                 {
  8520.                                     assert(cval.cvIsStr);
  8521.  
  8522.                                     custG = cval.cvValue.cvSval->csStr;
  8523.                                 }
  8524.                             }
  8525.                             else
  8526.                             {
  8527.                                 if  (type != NATIVE_TYPE_CUSTOMMARSHALER)
  8528.                                     goto ATTR_ERR;
  8529.  
  8530.                                 parseExprSkip();
  8531.                             }
  8532.                         }
  8533.                         else if (!strcmp(name, "marshalclass"))
  8534.                         {
  8535.                             if  (forReal)
  8536.                             {
  8537.                                 if  (ourScanner->scanTok.tok != tkID)
  8538.                                 {
  8539.                                     parseComp->cmpError(ERRnoClassName);
  8540.                                     parseExprSkip();
  8541.                                 }
  8542.                                 else
  8543.                                 {
  8544.                                     SymDef          tsym;
  8545.  
  8546.                                     tsym = parseNameUse(true, false);
  8547.                                     if  (tsym)
  8548.                                     {
  8549.                                         if  (tsym->sdSymKind == SYM_CLASS)
  8550.                                             custT = tsym;
  8551.                                         else
  8552.                                             parseComp->cmpError(ERRnoClassName);
  8553.                                     }
  8554.                                 }
  8555.                             }
  8556.                             else
  8557.                             {
  8558.                                 if  (type != NATIVE_TYPE_CUSTOMMARSHALER)
  8559.                                     goto ATTR_ERR;
  8560.  
  8561.                                 parseExprSkip();
  8562.                             }
  8563.                         }
  8564.                         else if (!strcmp(name, "marshalcookie"))
  8565.                         {
  8566.                             if  (forReal)
  8567.                             {
  8568.                                 if  (parseConstExpr(cval, NULL, parseComp->cmpStringRef(), NULL))
  8569.                                 {
  8570.                                     assert(cval.cvIsStr);
  8571.  
  8572.                                     custC = cval.cvValue.cvSval->csStr;
  8573.                                 }
  8574.                             }
  8575.                             else
  8576.                             {
  8577.                                 if  (type != NATIVE_TYPE_CUSTOMMARSHALER)
  8578.                                     goto ATTR_ERR;
  8579.  
  8580.                                 parseExprSkip();
  8581.                             }
  8582.                         }
  8583.                         else
  8584.                             goto ATTR_ERR;
  8585.                     }
  8586.  
  8587.                     if  (ourScanner->scanTok.tok != tkRParen)
  8588.                         goto ATTR_ERR;
  8589.                     if  (ourScanner->scan()      != tkRBrack)
  8590.                         goto ATTR_ERR;
  8591.  
  8592.                     ourScanner->scan();
  8593.  
  8594.                     if  (forReal)
  8595.                     {
  8596.                         if  (type == NATIVE_TYPE_CUSTOMMARSHALER)
  8597.                         {
  8598.                             marshalExt *    bdesc;
  8599.  
  8600.                             bdesc = (marshalExt*)parseAllocPerm->nraAlloc(sizeof(*bdesc));
  8601.  
  8602.                             if  (custG == NULL)
  8603.                                 parseComp->cmpGenWarn(WRNgeneric, "no custom marshalling GUID specified, this may not work - should this be an error?");
  8604.                             if  (custT == NULL)
  8605.                                 parseComp->cmpGenWarn(WRNgeneric, "no custom marshalling type specified, this may not work - should this be an error?");
  8606.  
  8607.                             bdesc->marshCustG = custG;
  8608.                             bdesc->marshCustC = custC;
  8609.                             bdesc->marshCustT = custT;
  8610.  
  8611.                             adesc = bdesc;
  8612.                         }
  8613.                         else
  8614.                         {
  8615.                             adesc = (MarshalInfo)parseAllocPerm->nraAlloc(sizeof(*adesc));
  8616.                         }
  8617.  
  8618.                         adesc->marshType    = type;
  8619.                         adesc->marshSubTp   = sbtp;
  8620.                         adesc->marshSize    = size;
  8621.  
  8622.                         adesc->marshModeIn  = amIn;
  8623.                         adesc->marshModeOut = amOut;
  8624.  
  8625. #if MGDDATA
  8626.                         entry = new SymXinfoCOM;
  8627. #else
  8628.                         entry =    (SymXinfoCOM)parseAllocPerm->nraAlloc(sizeof(*entry));
  8629. #endif
  8630.                         entry->xiKind       = XI_MARSHAL;
  8631.                         entry->xiCOMinfo    = adesc;
  8632.                         entry->xiNext       = NULL;
  8633.                     }
  8634.  
  8635.                     return  entry;
  8636.                 }
  8637.                 goto ATTR_ERR;
  8638.  
  8639.             default:
  8640.                 NO_WAY(!"unexpected attribute");
  8641.                 return  NULL;
  8642.             }
  8643.         }
  8644.     }
  8645.  
  8646.     /* Don't know this attribute, issue a warning and skip over it */
  8647.  
  8648.     if  (!forReal)
  8649.         parseComp->cmpGenWarn(WRNunkAttr, name);
  8650.  
  8651.     goto ATTR_SKIP;
  8652.  
  8653. LINK:
  8654.  
  8655.     // [sysimport(dll="kernel32", name="VirtualAlloc",charset=)]
  8656.  
  8657.     DLLname = NULL;
  8658.     SYMname = NULL;
  8659.     strVal  = 0;
  8660.     lstErr  = false;
  8661.  
  8662.     if  (ourScanner->scan() != tkLParen)
  8663.         goto ATTR_ERR;
  8664.  
  8665.     do
  8666.     {
  8667.         unsigned        kind;
  8668.  
  8669.         static
  8670.         const char *    names[] =
  8671.         {
  8672.             "dll", "name", "charset", "setLastError"
  8673.         };
  8674.  
  8675.         /* We expect the attribute name to be next */
  8676.  
  8677.         if  (ourScanner->scan() != tkID)
  8678.             goto ATTR_ERR;
  8679.  
  8680.         name = ourScanner->scanTok.id.tokIdent->idSpelling();
  8681.  
  8682.         for (kind = 0; kind < arraylen(names); kind++)
  8683.         {
  8684.             if  (!strcmp(name, names[kind]))
  8685.                 goto LINK_GOTN;
  8686.         }
  8687.  
  8688.         goto ATTR_ERR;
  8689.  
  8690.     LINK_GOTN:
  8691.  
  8692.         if  (ourScanner->scan() != tkAsg)
  8693.             goto ATTR_ERR;
  8694.  
  8695.         ourScanner->scan();
  8696.  
  8697.         if  (!forReal)
  8698.         {
  8699.             parseExprSkip();
  8700.             continue;
  8701.         }
  8702.  
  8703.         switch (kind)
  8704.         {
  8705.         case 0:
  8706.         case 1:
  8707.  
  8708.             if  (parseConstExpr(cval, NULL, parseComp->cmpStringRef(), NULL))
  8709.             {
  8710.                 char    *       saveNm;
  8711.                 size_t          saveLn;
  8712.  
  8713.                 assert(cval.cvIsStr);
  8714.  
  8715.                 /* Save the DLL/entry string */
  8716.  
  8717.                 saveLn = cval.cvValue.cvSval->csLen;
  8718. #if MGDDATA
  8719.                 UNIMPL(!"save name string on managed heap");
  8720. #else
  8721.                 saveNm = (char*)parseAllocPerm->nraAlloc(roundUp(saveLn+1));
  8722.                 memcpy(saveNm, cval.cvValue.cvSval->csStr, saveLn);
  8723. #endif
  8724.                 saveNm[saveLn] = 0;
  8725.  
  8726.                 if  (kind)
  8727.                     SYMname = saveNm;
  8728.                 else
  8729.                     DLLname = saveNm;
  8730.             }
  8731.             break;
  8732.  
  8733.         case 2:
  8734.  
  8735.             if  (parseConstExpr(cval, NULL, parseComp->cmpCharSetGet()->sdType, NULL))
  8736.                 strVal = cval.cvValue.cvIval;
  8737.  
  8738.             break;
  8739.  
  8740.         case 3:
  8741.  
  8742.             if  (parseConstExpr(cval, NULL, parseComp->cmpTypeBool, NULL))
  8743.                 lstErr = cval.cvValue.cvIval != 0;
  8744.  
  8745.             break;
  8746.  
  8747.         default:
  8748.             goto ATTR_ERR;
  8749.         }
  8750.     }
  8751.     while (ourScanner->scanTok.tok == tkComma);
  8752.  
  8753.     /* Temp hack: default to "winapi" for sysimport-style imports */
  8754.  
  8755.     callCnv = CCNV_WINAPI;
  8756.  
  8757.     /* Make the closing ")]" is present */
  8758.  
  8759.     if  (ourScanner->scanTok.tok != tkRParen)
  8760.         goto ATTR_ERR;
  8761.     if  (ourScanner->scan()      != tkRBrack)
  8762.         goto ATTR_ERR;
  8763.  
  8764.     ourScanner->scan();
  8765.  
  8766.     /* All went OK, create the linkage descriptor if appropriate */
  8767.  
  8768.     if  (forReal)
  8769.         goto SAVE_LINK;
  8770.  
  8771.     return  NULL;
  8772. }
  8773.  
  8774. /*****************************************************************************/
  8775. /*****************************************************************************/
  8776.