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

  1. /*****************************************************************************/
  2.  
  3. #include "smcPCH.h"
  4. #pragma hdrstop
  5.  
  6. #include "genIL.h"
  7. #ifdef  OLD_IL
  8. #include "oldIL.h"
  9. #endif
  10.  
  11. /*****************************************************************************
  12.  *
  13.  *  Create/free a temporary local variable to be used for IL gen.
  14.  */
  15.  
  16. SymDef              compiler::cmpTempVarMake(TypDef type)
  17. {
  18.     SymDef          tsym;
  19.  
  20.     /* Declare a temp symbol with the appropriate type */
  21.  
  22.     tsym = cmpGlobalST->stDeclareLcl(NULL, SYM_VAR, NS_NORM, cmpCurScp, &cmpAllocCGen);
  23.  
  24.     tsym->sdType         = type;
  25.     tsym->sdIsImplicit   = true;
  26.     tsym->sdIsDefined    = true;
  27.     tsym->sdVar.sdvLocal = true;
  28.     tsym->sdCompileState = CS_DECLARED;
  29.     tsym->sdAccessLevel  = ACL_PUBLIC;
  30.  
  31.     /* Tell the IL generator about the temp */
  32.  
  33.     if  (type->tdTypeKind != TYP_VOID)
  34.         cmpILgen->genTempVarNew(tsym);
  35.  
  36.     return  tsym;
  37. }
  38.  
  39. void                compiler::cmpTempVarDone(SymDef tsym)
  40. {
  41.     cmpILgen->genTempVarEnd(tsym);
  42. }
  43.  
  44. /*****************************************************************************
  45.  *
  46.  *  Bind and generate code for a "try" statement.
  47.  */
  48.  
  49. void                compiler::cmpStmtTry(Tree stmt, Tree pref)
  50. {
  51.     ILblock         begPC;
  52.     ILblock         endPC;
  53.     ILblock         hndPC;
  54.  
  55.     bitset          iniVars;
  56.     bitset          endVars;
  57.  
  58.     Tree            handList;
  59.  
  60.     stmtNestRec     nestStmt;
  61.  
  62.     ILblock         labDone;
  63.     bool            endReach;
  64.  
  65.     assert(stmt->tnOper == TN_TRY);
  66.  
  67.     /* If we were given an extra statement, output it now */
  68.  
  69.     if  (pref)
  70.     {
  71.         cmpChkVarInitExpr(pref);
  72.         cmpILgen->genExpr(pref, false);
  73.     }
  74.  
  75.     /* Record the set of initialized variables at the beginning */
  76.  
  77.     if  (cmpChkVarInit)
  78.         cmpBitSetCreate(iniVars, cmpVarsDefined);
  79.  
  80.     /* Insert the appropriate entry into the statement list */
  81.  
  82.     nestStmt.snStmtExpr = stmt;
  83.     nestStmt.snStmtKind = TN_TRY;
  84.     nestStmt.snLabel    = NULL;
  85.     nestStmt.snHadCont  = false; cmpBS_bigStart(nestStmt.snDefBreak);
  86.     nestStmt.snHadBreak = false; cmpBS_bigStart(nestStmt.snDefCont );
  87.     nestStmt.snLabCont  = NULL;
  88.     nestStmt.snLabBreak = NULL;
  89.     nestStmt.snOuter    = cmpStmtNest;
  90.                           cmpStmtNest = &nestStmt;
  91.  
  92.     /* Remember where the body of the try block started */
  93.  
  94.     begPC = cmpILgen->genBwdLab();
  95.  
  96.     /* Generate the body of the try block */
  97.  
  98.     cmpInTryBlk++;
  99.     cmpStmt(stmt->tnOp.tnOp1);
  100.     cmpInTryBlk--;
  101.  
  102.     /* We're out of the try block, into handlers now */
  103.  
  104.     cmpInHndBlk++;
  105.  
  106.     nestStmt.snStmtKind = TN_CATCH;
  107.  
  108.     /* Note whether the end of the try block was reachable */
  109.  
  110.     endReach = cmpStmtReachable;
  111.  
  112.     /* Record the set of initialized variables at the end of the "try" */
  113.  
  114.     if  (cmpChkVarInit)
  115.         cmpBitSetCreate(endVars, cmpVarsDefined);
  116.  
  117.     /* Get hold of the handler list and see what kind of a handler we have */
  118.  
  119.     handList = stmt->tnOp.tnOp2;
  120.  
  121.     /* Create the label that we will jump to when the try is done */
  122.  
  123.     labDone = cmpILgen->genFwdLabGet();
  124.  
  125.     /* If the end of the try is reachable, jump past all of the handlers */
  126.  
  127.     if  (cmpStmtReachable)
  128.         cmpILgen->genLeave(labDone);
  129.  
  130.     /* Remember where the body of the try block ended */
  131.  
  132.     endPC = cmpILgen->genBwdLab();
  133.  
  134.     /* In case we had an awful syntax error */
  135.  
  136.     if  (handList == NULL)
  137.         goto FIN;
  138.  
  139.     /* Is this a "try/except" statement? */
  140.  
  141.     if  (handList->tnOper == TN_EXCEPT)
  142.     {
  143.         SymDef          tsym;
  144.  
  145.         ILblock         fltPC;
  146.  
  147.         Tree            filt = handList->tnOp.tnOp1;
  148.         TypDef          type = cmpExceptRef();
  149.  
  150.         assert((stmt->tnFlags & TNF_BLK_HASFIN) == 0);
  151.  
  152.         /* Assume all the handlers are reachable */
  153.  
  154.         cmpStmtReachable = true;
  155.  
  156.         /* Set the known initialized variables to the "try" beginning */
  157.  
  158.         if  (cmpChkVarInit)
  159.             cmpBitSetAssign(cmpVarsDefined, iniVars);
  160.  
  161.         /* Create a temp symbol to hold the exception object */
  162.  
  163.         tsym = cmpTempVarMake(type);
  164.  
  165.         /* Create a label for the filter expression */
  166.  
  167.         fltPC = cmpILgen->genBwdLab();
  168.  
  169.         /* Bind and generate the filter expression */
  170.  
  171.         cmpFilterObj = tsym;
  172.         cmpILgen->genFiltExpr(cmpCoerceExpr(cmpBindExpr(filt), cmpTypeInt, false), tsym);
  173.         cmpFilterObj = NULL;
  174.  
  175.         /* If the end of any handler is reachable, so will be the end of the whole thing */
  176.  
  177.         endReach |= cmpStmtReachable;
  178.  
  179.         /* Set the known initialized variables to the "try" beginning */
  180.  
  181.         if  (cmpChkVarInit)
  182.             cmpBitSetAssign(cmpVarsDefined, iniVars);
  183.  
  184.         /* Create a label for the handler block */
  185.  
  186.         hndPC = cmpILgen->genBwdLab();
  187.  
  188.         /* Start the except handler block */
  189.  
  190.         cmpILgen->genExcptBeg(tsym);
  191.  
  192.         /* Generate code for the handler itself */
  193.  
  194.         cmpStmt(handList->tnOp.tnOp2);
  195.  
  196.         /* Exit the catch block via "leave" */
  197.  
  198.         if  (cmpStmtReachable)
  199.             cmpILgen->genLeave(labDone);
  200.  
  201.         /* Mark the end of the handler */
  202.  
  203.         cmpILgen->genCatchEnd(cmpStmtReachable);
  204.  
  205.         /* Add an entry for the 'except' to the table */
  206.  
  207.         cmpILgen->genEHtableAdd(begPC,
  208.                                 endPC,
  209.                                 fltPC,
  210.                                 hndPC,
  211.                                 cmpILgen->genBwdLab(),
  212.                                 NULL,
  213.                                 false);
  214.  
  215.         /* Release the temp */
  216.  
  217.         cmpTempVarDone(tsym);
  218.  
  219.         /* Form an intersection with current set of initialized variables */
  220.  
  221.         if  (cmpChkVarInit && cmpStmtReachable)
  222.             cmpBitSetIntsct(endVars, cmpVarsDefined);
  223.  
  224.         goto DONE;
  225.     }
  226.  
  227.     /* Process all catch blocks, if any are present */
  228.  
  229.     if  (handList->tnOper == TN_FINALLY)
  230.         goto FIN;
  231.  
  232.     for (;;)
  233.     {
  234.         Tree            argDecl;
  235.         TypDef          argType;
  236.  
  237.         Tree            handThis;
  238.  
  239.         /* Create a label for the catch block */
  240.  
  241.         hndPC = cmpILgen->genBwdLab();
  242.  
  243.         /* Assume all the handlers are reachable */
  244.  
  245.         cmpStmtReachable = true;
  246.  
  247.         /* Set the known initialized variables to the "try" beginning */
  248.  
  249.         if  (cmpChkVarInit)
  250.             cmpBitSetAssign(cmpVarsDefined, iniVars);
  251.  
  252.         /* Get hold of the next handler */
  253.  
  254.         assert(handList->tnOper == TN_LIST);
  255.         handThis = handList->tnOp.tnOp1;
  256.  
  257.         /* There might be a finally at the end */
  258.  
  259.         if  (handThis->tnOper != TN_CATCH)
  260.         {
  261.             assert(handThis->tnOper == TN_FINALLY);
  262.             assert(handList->tnOp.tnOp2 == NULL);
  263.             handList = handThis;
  264.             break;
  265.         }
  266.  
  267.         /* Get hold of the catch symbol declaration node */
  268.  
  269.         argDecl = handThis->tnOp.tnOp1;
  270.         assert(argDecl->tnOper == TN_VAR_DECL);
  271.  
  272.         /* Get hold of the exception type */
  273.  
  274.         argType = argDecl->tnType; cmpBindType(argType, false, false);
  275.  
  276.         assert(argType->tdTypeKind == TYP_REF ||
  277.                argType->tdTypeKind == TYP_UNDEF);
  278.  
  279.         // UNDONE: check for duplicate handler types!
  280.  
  281.         /* Generate the body of the 'catch' block */
  282.  
  283.         cmpBlock(handThis->tnOp.tnOp2, false);
  284.  
  285.         /* Mark the end of the handler */
  286.  
  287.         cmpILgen->genCatchEnd(cmpStmtReachable);
  288.  
  289.         /* Exit the catch block via "leave" */
  290.  
  291.         if  (cmpStmtReachable)
  292.             cmpILgen->genLeave(labDone);
  293.  
  294.         /* Add an entry for the 'catch' to the table */
  295.  
  296.         cmpILgen->genEHtableAdd(begPC,
  297.                                 endPC,
  298.                                 NULL,
  299.                                 hndPC,
  300.                                 cmpILgen->genBwdLab(),
  301.                                 argType->tdRef.tdrBase,
  302.                                 false);
  303.  
  304.         /* If the end of any handler is reachable, so will be the end of the whole thing */
  305.  
  306.         endReach |= cmpStmtReachable;
  307.  
  308.         /* Form an intersection with current set of initialized variables */
  309.  
  310.         if  (cmpChkVarInit && cmpStmtReachable)
  311.             cmpBitSetIntsct(endVars, cmpVarsDefined);
  312.  
  313.         /* Are there any more 'catch' clauses? */
  314.  
  315.         handList = handList->tnOp.tnOp2;
  316.         if  (!handList)
  317.             break;
  318.     }
  319.  
  320. FIN:
  321.  
  322.     /* If there is a handler at this point, it must be a finally */
  323.  
  324.     if  (handList)
  325.     {
  326.         ILblock         hndPC;
  327.  
  328.         assert(handList->tnOper == TN_FINALLY);
  329.         assert(handList->tnOp.tnOp2 == NULL);
  330.  
  331.         assert((stmt->tnFlags & TNF_BLK_HASFIN) != 0);
  332.  
  333.         /* Set the known initialized variables to the "try" beginning */
  334.  
  335.         if  (cmpChkVarInit)
  336.             cmpBitSetAssign(cmpVarsDefined, iniVars);
  337.  
  338.         /* Generate the "finally" block itself */
  339.  
  340.         cmpInFinBlk++;
  341.  
  342.         hndPC = cmpILgen->genBwdLab();
  343.  
  344.         nestStmt.snStmtKind = TN_FINALLY;
  345.  
  346.         if  (pref)
  347.         {
  348.             cmpChkVarInitExpr(handList->tnOp.tnOp1);
  349.             cmpILgen->genExpr(handList->tnOp.tnOp1, false);
  350.         }
  351.         else
  352.             cmpStmt(handList->tnOp.tnOp1);
  353.  
  354.         cmpILgen->genEndFinally();
  355.  
  356.         cmpInFinBlk--;
  357.  
  358.         /* Add an entry for the "finally" to the EH tables */
  359.  
  360.         cmpILgen->genEHtableAdd(begPC,
  361.                                 hndPC,
  362.                                 NULL,
  363.                                 hndPC,
  364.                                 cmpILgen->genBwdLab(),
  365.                                 NULL,
  366.                                 true);
  367.  
  368.         /* Form an intersection with current set of initialized variables */
  369.  
  370.         if  (cmpChkVarInit && cmpStmtReachable)
  371.         {
  372.             /* Special case: compiler-added finally doesn't count */
  373.  
  374.             if  (!(handList->tnFlags & TNF_NOT_USER))
  375.                 cmpBitSetIntsct(endVars, cmpVarsDefined);
  376.         }
  377.     }
  378.     else
  379.     {
  380.         assert((stmt->tnFlags & TNF_BLK_HASFIN) == 0);
  381.     }
  382.  
  383. DONE:
  384.  
  385.     /* Define the 'done' label if necessary */
  386.  
  387.     if  (labDone)
  388.         cmpILgen->genFwdLabDef(labDone);
  389.  
  390.     if  (cmpChkVarInit)
  391.     {
  392.         /* Switch to the intersection of all the sets */
  393.  
  394.         cmpBitSetAssign(cmpVarsDefined, endVars);
  395.  
  396.         /* Toss the saved "init" and the "ending" variable sets */
  397.  
  398.         cmpBitSetDone(iniVars);
  399.         cmpBitSetDone(endVars);
  400.     }
  401.  
  402.     /* Remove our entry from the statement list */
  403.  
  404.     cmpStmtNest = nestStmt.snOuter; cmpInHndBlk--;
  405.  
  406.     /* If the end of any of the blocks was reachable, so is this point */
  407.  
  408.     cmpStmtReachable = endReach;
  409. }
  410.  
  411. /*****************************************************************************
  412.  *
  413.  *  Bind and generate code for a "do - while" loop.
  414.  */
  415.  
  416. void                compiler::cmpStmtDo(Tree stmt, SymDef lsym)
  417. {
  418.     stmtNestRec     nestStmt;
  419.  
  420.     ILblock         labLoop;
  421.     ILblock         labCont;
  422.     ILblock         labBreak;
  423.  
  424.     Tree            condExpr;
  425.     int             condVal;
  426.  
  427.     assert(stmt->tnOper == TN_DO);
  428.  
  429.     /* Create the 'loop top', 'break' and 'continue' labels */
  430.  
  431.     labLoop  = cmpILgen->genBwdLab();
  432.     labCont  = cmpILgen->genFwdLabGet();
  433.     labBreak = cmpILgen->genFwdLabGet();
  434.  
  435.     /* Insert the appropriate entry into the statement list */
  436.  
  437.     nestStmt.snStmtExpr = stmt;
  438.     nestStmt.snStmtKind = TN_DO;
  439.     nestStmt.snLabel    = lsym;
  440.     nestStmt.snHadCont  = false; cmpBS_bigStart(nestStmt.snDefBreak);
  441.     nestStmt.snHadBreak = false; cmpBS_bigStart(nestStmt.snDefCont );
  442.     nestStmt.snLabCont  = labCont;
  443.     nestStmt.snLabBreak = labBreak;
  444.     nestStmt.snOuter    = cmpStmtNest;
  445.                           cmpStmtNest = &nestStmt;
  446.  
  447.     /* Generate the body of the loop */
  448.  
  449.     cmpStmt(stmt->tnOp.tnOp1);
  450.  
  451.     /* Remove our entry from the statement list */
  452.  
  453.     cmpStmtNest = nestStmt.snOuter;
  454.  
  455.     /* Define the 'continue' label */
  456.  
  457.     cmpILgen->genFwdLabDef(labCont);
  458.  
  459.     /* Did we have "continue" and are we checking for uninitialized var use? */
  460.  
  461.     if  (cmpChkVarInit && nestStmt.snHadCont)
  462.     {
  463.         /* Compute the definition set at the condition */
  464.  
  465.         cmpBitSetIntsct(cmpVarsDefined, nestStmt.snDefCont);
  466.  
  467.         /* We can free up the "continue" bitset now */
  468.  
  469.         cmpBitSetDone(nestStmt.snDefCont);
  470.     }
  471.  
  472.     /* Test the condition and jump to the top if true */
  473.  
  474.     condExpr = cmpBindCondition(stmt->tnOp.tnOp2);
  475.     condVal  = cmpEvalCondition(condExpr);
  476.  
  477.     switch (condVal)
  478.     {
  479.     case -1:
  480.  
  481.         /* The loop will never be repeated */
  482.  
  483.         break;
  484.  
  485.     case 0:
  486.  
  487.         /* The loop may or not be repeated, we'll generate a conditional jump */
  488.  
  489.         if  (cmpChkVarInit)
  490.         {
  491.             bitset          tempBS;
  492.  
  493.             /* Check the condition and note the 'false' set */
  494.  
  495.             cmpCheckUseCond(condExpr, cmpVarsIgnore, true, tempBS, false);
  496.  
  497.             /* Generate the conditional jump */
  498.  
  499.             cmpILgen->genExprTest(condExpr, true, true, labLoop, labBreak);
  500.  
  501.             /* Use the 'false' set for the code that follows the loop */
  502.  
  503.             cmpBitSetAssign(cmpVarsDefined, tempBS);
  504.  
  505.             /* Free up the bitset now */
  506.  
  507.             cmpBitSetDone(tempBS);
  508.         }
  509.         else
  510.             cmpILgen->genExprTest(condExpr, true, true, labLoop, labBreak);
  511.  
  512.         break;
  513.  
  514.     case 1:
  515.  
  516.         /* The loop will repeat forever */
  517.  
  518.         cmpILgen->genJump(labLoop);
  519.         break;
  520.     }
  521.  
  522.     /* Define the 'break' label */
  523.  
  524.     cmpILgen->genFwdLabDef(labBreak);
  525.  
  526.     /* Code after the loop is reachable unless the condition is 'forever' */
  527.  
  528.     cmpStmtReachable = (condVal != 1);
  529.  
  530.     /* Code after the loop is also reachable if there was a break */
  531.  
  532.     if  (nestStmt.snHadBreak)
  533.     {
  534.         cmpStmtReachable = true;
  535.  
  536.         /* Are we checking for uninitialized variable use? */
  537.  
  538.         if  (cmpChkVarInit)
  539.         {
  540.             /* Intersect with the "break" definition set */
  541.  
  542.             cmpBitSetIntsct(cmpVarsDefined, nestStmt.snDefBreak);
  543.  
  544.             /* Free up the "break" bitset */
  545.  
  546.             cmpBitSetDone(nestStmt.snDefBreak);
  547.         }
  548.     }
  549. }
  550.  
  551. /*****************************************************************************
  552.  *
  553.  *  Compile a "for" statement.
  554.  */
  555.  
  556. void                compiler::cmpStmtFor(Tree stmt, SymDef lsym)
  557. {
  558.     Tree            initExpr;
  559.     Tree            condExpr;
  560.     Tree            incrExpr;
  561.     Tree            bodyExpr;
  562.  
  563.     stmtNestRec     nestStmt;
  564.  
  565.     ILblock         labLoop;
  566.     ILblock         labTest;
  567.     ILblock         labCont;
  568.     ILblock         labBreak;
  569.  
  570.     int             condVal;
  571.  
  572.     bitset          tempBS;
  573.  
  574.     SymDef          outerScp = cmpCurScp;
  575.  
  576.     assert(stmt->tnOper == TN_FOR);
  577.  
  578.     /* Get hold of the various pieces of the 'for' statement tree */
  579.  
  580.     assert(stmt->tnOp.tnOp1->tnOper == TN_LIST);
  581.     assert(stmt->tnOp.tnOp2->tnOper == TN_LIST);
  582.  
  583.     initExpr = stmt->tnOp.tnOp1->tnOp.tnOp1;
  584.     condExpr = stmt->tnOp.tnOp1->tnOp.tnOp2;
  585.     incrExpr = stmt->tnOp.tnOp2->tnOp.tnOp1;
  586.     bodyExpr = stmt->tnOp.tnOp2->tnOp.tnOp2;
  587.  
  588.     /* Get the initial tree and see if it's a statement or declaration */
  589.  
  590.     if  (initExpr)
  591.     {
  592.         if  (initExpr->tnOper == TN_BLOCK)
  593.         {
  594.             /* We have declaration(s), create a block scope */
  595.  
  596.             cmpBlockDecl(initExpr, false, true, false);
  597.         }
  598.         else
  599.         {
  600.             initExpr = cmpFoldExpression(cmpBindExpr(initExpr));
  601.             cmpChkVarInitExpr(initExpr);
  602.             cmpILgen->genExpr(initExpr, false);
  603.         }
  604.     }
  605.  
  606.     /* Create the 'cond test', 'break' and 'continue' labels */
  607.  
  608.     labTest  = cmpILgen->genFwdLabGet();
  609.     labCont  = cmpILgen->genFwdLabGet();
  610.     labBreak = cmpILgen->genFwdLabGet();
  611.  
  612.     /* Bind the loop condition */
  613.  
  614.     if  (condExpr)
  615.     {
  616.         condExpr = cmpBindCondition(condExpr);
  617.         condVal  = cmpEvalCondition(condExpr);
  618.     }
  619.     else
  620.     {
  621.         condVal  = 1;
  622.     }
  623.  
  624.     /* Jump to the 'test' label (unless the condition is initially true) */
  625.  
  626.     if  (condVal < 1)
  627.         cmpILgen->genJump(labTest);
  628.  
  629.     /* Are we checking for uninitialized variable use? */
  630.  
  631.     if  (cmpChkVarInit)
  632.     {
  633.         if  (condVal)
  634.         {
  635.             /* The condition's outcome is known, just check it */
  636.  
  637.             if  (condExpr)
  638.                 cmpChkVarInitExpr(condExpr);
  639.         }
  640.         else
  641.         {
  642.             /* Check the condition and record the 'false' set */
  643.  
  644.             cmpCheckUseCond(condExpr, cmpVarsIgnore, true, tempBS, false);
  645.         }
  646.     }
  647.  
  648.     /* Create and define the 'loop top' label */
  649.  
  650.     labLoop = cmpILgen->genBwdLab();
  651.  
  652.     /* Insert the appropriate entry into the statement list */
  653.  
  654.     nestStmt.snStmtExpr = stmt;
  655.     nestStmt.snStmtKind = TN_FOR;
  656.     nestStmt.snLabel    = lsym;
  657.     nestStmt.snHadCont  = false; cmpBS_bigStart(nestStmt.snDefBreak);
  658.     nestStmt.snHadBreak = false; cmpBS_bigStart(nestStmt.snDefCont );
  659.     nestStmt.snLabCont  = labCont;
  660.     nestStmt.snLabBreak = labBreak;
  661.     nestStmt.snOuter    = cmpStmtNest;
  662.                           cmpStmtNest = &nestStmt;
  663.  
  664.     /* The body is reachable unless the condition is 'never' */
  665.  
  666.     cmpStmtReachable = (condVal != -1);
  667.  
  668.     /* Generate the body of the loop */
  669.  
  670.     if  (bodyExpr)
  671.         cmpStmt(bodyExpr);
  672.  
  673.     /* Remove our entry from the statement list */
  674.  
  675.     cmpStmtNest = nestStmt.snOuter;
  676.  
  677.     /* Define the 'continue' label */
  678.  
  679.     cmpILgen->genFwdLabDef(labCont);
  680.  
  681.     /* Toss the "continue" set if one was computed */
  682.  
  683.     if  (cmpChkVarInit && nestStmt.snHadCont)
  684.         cmpBitSetDone(nestStmt.snDefCont);
  685.  
  686.     /* Generate the increment expression, if present */
  687.  
  688.     if  (incrExpr)
  689.     {
  690. #ifdef  OLD_IL
  691.         if  (cmpConfig.ccOILgen)
  692.             cmpOIgen->GOIrecExprPos(incrExpr);
  693.         else
  694. #endif
  695.             cmpILgen->genRecExprPos(incrExpr);
  696.  
  697.         incrExpr = cmpBindExpr(incrExpr);
  698.         cmpChkVarInitExpr(incrExpr);
  699.         cmpILgen->genExpr(incrExpr, false);
  700.     }
  701.  
  702.     /* Define the 'cond test' label */
  703.  
  704.     cmpILgen->genFwdLabDef(labTest);
  705.  
  706.     /* Test the condition and jump to the top if true */
  707.  
  708.     if  (condExpr)
  709.     {
  710. #ifdef  OLD_IL
  711.         if  (cmpConfig.ccOILgen)
  712.             cmpOIgen->GOIrecExprPos(condExpr);
  713.         else
  714. #endif
  715.             cmpILgen->genRecExprPos(condExpr);
  716.  
  717.         cmpILgen->genExprTest(condExpr, true, true, labLoop, labBreak);
  718.     }
  719.     else
  720.     {
  721.         cmpILgen->genJump(labLoop);
  722.     }
  723.  
  724.     /* Define the 'break' label */
  725.  
  726.     cmpILgen->genFwdLabDef(labBreak);
  727.  
  728.     /*
  729.         The code after the loop will be reachable if the loop condition
  730.         is not 'forever', or if 'break' was present within the loop.
  731.      */
  732.  
  733.     cmpStmtReachable = (condVal != 1 || nestStmt.snHadBreak);
  734.  
  735.     /* Are we checking for uninitialized variable use? */
  736.  
  737.     if  (cmpChkVarInit)
  738.     {
  739.         /* Intersect with the "break" definition set, if have one */
  740.  
  741.         if  (nestStmt.snHadBreak)
  742.         {
  743.             cmpBitSetIntsct(cmpVarsDefined, nestStmt.snDefBreak);
  744.             cmpBitSetDone(nestStmt.snDefBreak);
  745.         }
  746.  
  747.         /* Intersect with the "false" bit from the condition */
  748.  
  749.         if  (!condVal)
  750.         {
  751.             cmpBitSetIntsct(cmpVarsDefined, tempBS);
  752.             cmpBitSetDone(tempBS);
  753.         }
  754.     }
  755.  
  756.     /* For debug info, close a lexical scope if one was opened */
  757.  
  758.     if  (cmpConfig.ccGenDebug && cmpCurScp != outerScp
  759.                               && !cmpCurFncSym->sdIsImplicit)
  760.     {
  761.         if  (cmpSymWriter->CloseScope(0))
  762.             cmpGenFatal(ERRdebugInfo);
  763.  
  764.         cmpCurScp->sdScope.sdEndBlkAddr = cmpILgen->genBuffCurAddr();
  765.         cmpCurScp->sdScope.sdEndBlkOffs = cmpILgen->genBuffCurOffs();
  766.     }
  767.  
  768.     /* Remove the block if we created one for the loop */
  769.  
  770.     cmpCurScp = outerScp;
  771. }
  772.  
  773. /*****************************************************************************/
  774. /*****************************************************************************
  775.  *
  776.  *  Bind and generate code for an "exclusive" statement.
  777.  */
  778.  
  779. void                compiler::cmpStmtExcl(Tree stmt)
  780. {
  781.     SymDef          tsym;
  782.     TypDef          type;
  783.  
  784.     Tree            argx;
  785.     Tree            objx;
  786.     Tree            begx;
  787.     Tree            endx;
  788.     Tree            hndx;
  789.  
  790.     assert(stmt->tnOper == TN_EXCLUDE);
  791.  
  792.     /*
  793.         We implement this by transforming "exclusive(obj) { stmt }" into
  794.         the following:
  795.  
  796.             temp = obj;
  797.             CriticalSection::Enter(temp);
  798.  
  799.             try
  800.             {
  801.                 stmt;
  802.             }
  803.             finally
  804.             {
  805.                 CriticalSection::Exit(temp);
  806.             }
  807.      */
  808.  
  809.     objx = cmpBindExpr(stmt->tnOp.tnOp1);
  810.     type = objx->tnType;
  811.  
  812.     /* Make sure the type is acceptable */
  813.  
  814.     if  (type->tdTypeKind != TYP_REF && (type->tdTypeKind != TYP_ARRAY || !type->tdIsManaged))
  815.     {
  816.         if  (type->tdTypeKind != TYP_UNDEF)
  817.             cmpError(ERRnotClsVal, type);
  818.  
  819.         return;
  820.     }
  821.  
  822.     /* Create a temp symbol to hold the synchronization object */
  823.  
  824.     tsym = cmpTempVarMake(type);
  825.  
  826.     /* Create the "critsect enter/exit" expressions */
  827.  
  828.     if  (!cmpFNsymCSenter)
  829.     {
  830.         /* Make sure we have the "" class type */
  831.  
  832.         cmpMonitorRef();
  833.  
  834.         /* Locate the helper methods in the class */
  835.  
  836.         cmpFNsymCSenter = cmpGlobalST->stLookupClsSym(cmpIdentEnter, cmpClassMonitor);
  837.         assert(cmpFNsymCSenter && cmpFNsymCSenter->sdFnc.sdfNextOvl == NULL);
  838.  
  839.         cmpFNsymCSexit  = cmpGlobalST->stLookupClsSym(cmpIdentExit , cmpClassMonitor);
  840.         assert(cmpFNsymCSexit  && cmpFNsymCSexit ->sdFnc.sdfNextOvl == NULL);
  841.     }
  842.  
  843.     argx = cmpCreateVarNode (NULL, tsym);
  844.     argx = cmpCreateExprNode(NULL, TN_ASG ,        type, argx, objx);
  845.     argx = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, argx, NULL);
  846.  
  847.     begx = cmpCreateExprNode(NULL, TN_FNC_SYM, cmpTypeVoid);
  848.     begx->tnFncSym.tnFncSym  = cmpFNsymCSenter;
  849.     begx->tnFncSym.tnFncArgs = argx;
  850.     begx->tnFncSym.tnFncObj  = NULL;
  851.     begx->tnFlags           |= TNF_NOT_USER;
  852.  
  853.     argx = cmpCreateVarNode (NULL, tsym);
  854.     argx = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, argx, NULL);
  855.  
  856.     endx = cmpCreateExprNode(NULL, TN_FNC_SYM, cmpTypeVoid);
  857.     endx->tnFncSym.tnFncSym  = cmpFNsymCSexit;
  858.     endx->tnFncSym.tnFncArgs = argx;
  859.     endx->tnFncSym.tnFncObj  = NULL;
  860.     endx->tnFlags           |= TNF_NOT_USER;
  861.  
  862.     /* Create the 'try/finally' block and generate code for it */
  863.  
  864.     hndx = cmpCreateExprNode(NULL, TN_FINALLY , cmpTypeVoid, endx, NULL);
  865.     hndx->tnFlags |= TNF_NOT_USER;
  866.     hndx = cmpCreateExprNode(NULL, TN_TRY     , cmpTypeVoid, stmt->tnOp.tnOp2, hndx);
  867.     hndx->tnFlags |= TNF_BLK_HASFIN;
  868.  
  869.     cmpStmtTry(hndx, begx);
  870.  
  871.     /* Release the temp */
  872.  
  873.     cmpTempVarDone(tsym);
  874. }
  875.  
  876. /*****************************************************************************
  877.  *
  878.  *  Compile a "while" statement.
  879.  */
  880.  
  881. void                compiler::cmpStmtWhile(Tree stmt, SymDef lsym)
  882. {
  883.     ILblock         labCont;
  884.     ILblock         labBreak;
  885.     ILblock         labLoop;
  886.  
  887.     Tree            condExpr;
  888.     int             condVal;
  889.  
  890.     bitset          tempBS;
  891.  
  892.     stmtNestRec     nestStmt;
  893.  
  894.     assert(stmt->tnOper == TN_WHILE);
  895.  
  896.     /* Create the 'break' and 'continue' labels */
  897.  
  898.     labBreak = cmpILgen->genFwdLabGet();
  899.     labCont  = cmpILgen->genFwdLabGet();
  900.  
  901.     /* Can the condition be evaluated at compile time? */
  902.  
  903.     condExpr = cmpBindCondition(stmt->tnOp.tnOp1);
  904.     condVal  = cmpEvalCondition(condExpr);
  905.  
  906.     /* Could the condition ever be false? */
  907.  
  908.     if  (condVal < 1)
  909.     {
  910.         /* Jump to the 'continue' label */
  911.  
  912.         cmpILgen->genJump(labCont);
  913.     }
  914.  
  915.     /* Are we checking for uninitialized variable use? */
  916.  
  917.     if  (cmpChkVarInit)
  918.     {
  919.         if  (condVal)
  920.         {
  921.             /* The condition's outcome is known, just check it */
  922.  
  923.             cmpChkVarInitExpr(condExpr);
  924.         }
  925.         else
  926.         {
  927.             /* Check the condition and record the 'false' set */
  928.  
  929.             cmpCheckUseCond(condExpr, cmpVarsIgnore, true, tempBS, false);
  930.         }
  931.     }
  932.  
  933.     /* Create and define the 'loop top' label */
  934.  
  935.     labLoop = cmpILgen->genBwdLab();
  936.  
  937.     /* Insert our context into the context list */
  938.  
  939.     nestStmt.snStmtExpr = stmt;
  940.     nestStmt.snStmtKind = TN_WHILE;
  941.     nestStmt.snLabel    = lsym;
  942.     nestStmt.snHadCont  = false; cmpBS_bigStart(nestStmt.snDefBreak);
  943.     nestStmt.snHadBreak = false; cmpBS_bigStart(nestStmt.snDefCont );
  944.     nestStmt.snLabCont  = labCont;
  945.     nestStmt.snLabBreak = labBreak;
  946.     nestStmt.snOuter    = cmpStmtNest;
  947.                           cmpStmtNest = &nestStmt;
  948.  
  949.     /* Generate the body of the loop */
  950.  
  951.     if  (stmt->tnOp.tnOp2)
  952.         cmpStmt(stmt->tnOp.tnOp2);
  953.  
  954.     /* Remove our context from the context list */
  955.  
  956.     cmpStmtNest = nestStmt.snOuter;
  957.  
  958.     /* Define the 'continue' label */
  959.  
  960.     cmpILgen->genFwdLabDef(labCont);
  961.  
  962.     /* Toss the "continue" set if one was computed */
  963.  
  964.     if  (cmpChkVarInit && nestStmt.snHadCont)
  965.         cmpBitSetDone(nestStmt.snDefCont);
  966.  
  967.     /* Is the condition always true? */
  968.  
  969.     switch (condVal)
  970.     {
  971.     case 0:
  972.  
  973.         /* Test the condition and end the loop if false */
  974.  
  975.         cmpILgen->genExprTest(condExpr, true, true, labLoop, labBreak);
  976.  
  977.         /* Whenever the condition is false we'll skip over the loop, of course */
  978.  
  979.         cmpStmtReachable = true;
  980.         break;
  981.  
  982.     case -1:
  983.  
  984.         /* Condition never true, don't bother looping */
  985.  
  986.         cmpILgen->genSideEff(condExpr);
  987.         break;
  988.  
  989.     case 1:
  990.  
  991.         /* Condition always true, loop every time */
  992.  
  993.         cmpILgen->genJump(labLoop);
  994.         cmpStmtReachable = false;
  995.         break;
  996.     }
  997.  
  998.     /* Define the 'break' label */
  999.  
  1000.     cmpILgen->genFwdLabDef(labBreak);
  1001.  
  1002.     /* Code after the loop is also reachable if there was a break */
  1003.  
  1004.     if  (nestStmt.snHadBreak)
  1005.         cmpStmtReachable = true;
  1006.  
  1007.     /* Are we checking for uninitialized variable use? */
  1008.  
  1009.     if  (cmpChkVarInit)
  1010.     {
  1011.         /* Intersect with the "break" definition set, if have one */
  1012.  
  1013.         if  (nestStmt.snHadBreak)
  1014.         {
  1015.             cmpBitSetIntsct(cmpVarsDefined, nestStmt.snDefBreak);
  1016.             cmpBitSetDone(nestStmt.snDefBreak);
  1017.         }
  1018.  
  1019.         /* Intersect with the "false" bit from the condition */
  1020.  
  1021.         if  (!condVal)
  1022.         {
  1023.             cmpBitSetIntsct(cmpVarsDefined, tempBS);
  1024.             cmpBitSetDone(tempBS);
  1025.         }
  1026.     }
  1027. }
  1028.  
  1029. /*****************************************************************************/
  1030. #ifndef __IL__
  1031. /*****************************************************************************
  1032.  *
  1033.  *  Compare routine passed to quicksort for sorting of case label values.
  1034.  */
  1035.  
  1036. static
  1037. int __cdecl         caseSortCmp(const void *p1, const void *p2)
  1038. {
  1039.     Tree            op1 = *(Tree*)p1; assert(op1->tnOper == TN_CASE);
  1040.     Tree            op2 = *(Tree*)p2; assert(op2->tnOper == TN_CASE);
  1041.  
  1042.     Tree            cx1 = op1->tnCase.tncValue; assert(cx1 && cx1->tnOper == TN_CNS_INT);
  1043.     Tree            cx2 = op2->tnCase.tncValue; assert(cx2 && cx2->tnOper == TN_CNS_INT);
  1044.  
  1045.     return cx1->tnIntCon.tnIconVal -
  1046.            cx2->tnIntCon.tnIconVal;
  1047. }
  1048.  
  1049. /*****************************************************************************/
  1050. #else
  1051. /*****************************************************************************/
  1052.  
  1053. static
  1054. void                sortSwitchCases(vectorTree table, unsigned count)
  1055. {
  1056.     if  (count < 2)
  1057.         return;
  1058.  
  1059.     for (unsigned skip = (count+1)/2; skip >= 1; skip /= 2)
  1060.     {
  1061.         bool            swap;
  1062.  
  1063.         do
  1064.         {
  1065.             unsigned    i = 0;
  1066.             unsigned    b = count - skip;
  1067.  
  1068.             Tree    *   l = table + i;
  1069.             Tree    *   h = l + skip;
  1070.  
  1071.             swap = false;
  1072.  
  1073.             while   (i < b)
  1074.             {
  1075.                 assert(l >= table && l < h);
  1076.                 assert(h <  table + count);
  1077.  
  1078.                 Tree            op1 = *l++; assert(op1->tnOper == TN_CASE);
  1079.                 Tree            op2 = *h++; assert(op2->tnOper == TN_CASE);
  1080.  
  1081.                 Tree            cx1 = op1->tnCase.tncValue; assert(cx1 && cx1->tnOper == TN_CNS_INT);
  1082.                 Tree            cx2 = op2->tnCase.tncValue; assert(cx2 && cx2->tnOper == TN_CNS_INT);
  1083.  
  1084.                 if  (cx1->tnIntCon.tnIconVal > cx2->tnIntCon.tnIconVal)
  1085.                 {
  1086.                     l[-1] = op2;
  1087.                     h[-1] = op1;
  1088.  
  1089.                     swap  = true;
  1090.                 }
  1091.  
  1092.                 i++;
  1093.             }
  1094.         }
  1095.         while (swap);
  1096.     }
  1097. }
  1098.  
  1099. /*****************************************************************************/
  1100. #endif
  1101. /*****************************************************************************
  1102.  *
  1103.  *  Generate code for a switch statement.
  1104.  */
  1105.  
  1106. void                compiler::cmpStmtSwitch(Tree stmt, SymDef lsym)
  1107. {
  1108.     Tree            svalExpr;
  1109.     Tree            caseLab;
  1110.  
  1111.     bool            caseUns;
  1112.     unsigned        caseCnt;
  1113.  
  1114.     int             caseMin;
  1115.     int             caseMax;
  1116.     int             casePrv;
  1117.  
  1118.     bool            needSort;
  1119.     unsigned        sortNum;
  1120.  
  1121.     stmtNestRec     nestStmt;
  1122.  
  1123.     ILblock         nmLabel;
  1124.     ILblock         labBreak;
  1125.     ILblock         labDeflt;
  1126.  
  1127.     bool            hadErrs;
  1128.     bool            hadDefault;
  1129.  
  1130.     assert(stmt->tnOper == TN_SWITCH);
  1131.  
  1132.     /* Bind the switch value */
  1133.  
  1134.     svalExpr = cmpBindExpr(stmt->tnSwitch.tnsValue); cmpChkVarInitExpr(svalExpr);
  1135.  
  1136.     /* Make sure the expression has an acceptable type */
  1137.  
  1138.     if  (svalExpr->tnVtyp != TYP_UINT   &&
  1139.          svalExpr->tnVtyp != TYP_NATINT &&
  1140.          svalExpr->tnVtyp != TYP_NATUINT)
  1141.     {
  1142.         svalExpr = cmpCoerceExpr(svalExpr, cmpTypeInt, false);
  1143.     }
  1144.  
  1145.     caseUns  = varTypeIsUnsigned(svalExpr->tnVtypGet());
  1146.     caseCnt  = 0;
  1147.  
  1148.     /* Create the 'break' label */
  1149.  
  1150.     labBreak = cmpILgen->genFwdLabGet();
  1151.     labDeflt = NULL;
  1152.  
  1153.     /* Insert the appropriate entry into the statement list */
  1154.  
  1155.     nestStmt.snStmtExpr = stmt;
  1156.     nestStmt.snStmtKind = TN_SWITCH;
  1157.     nestStmt.snLabel    = lsym;
  1158.     nestStmt.snHadCont  = false; cmpBS_bigStart(nestStmt.snDefBreak);
  1159.     nestStmt.snHadBreak = false; cmpBS_bigStart(nestStmt.snDefCont );
  1160.     nestStmt.snLabCont  = NULL;
  1161.     nestStmt.snLabBreak = labBreak;
  1162.     nestStmt.snOuter    = cmpStmtNest;
  1163.                           cmpStmtNest = &nestStmt;
  1164.  
  1165.     /* Bind all the case values and check them */
  1166.  
  1167.     hadDefault = hadErrs = needSort = false;
  1168.  
  1169.     for (caseLab = stmt->tnSwitch.tnsCaseList;
  1170.          caseLab;
  1171.          caseLab = caseLab->tnCase.tncNext)
  1172.     {
  1173.         assert(caseLab->tnOper == TN_CASE);
  1174.  
  1175.         /* Create a label and assign it to the case/default */
  1176.  
  1177.         caseLab->tnCase.tncLabel = cmpILgen->genFwdLabGet();
  1178.  
  1179.         /* Is there a label value or is this "default" ? */
  1180.  
  1181.         if  (caseLab->tnCase.tncValue)
  1182.         {
  1183.             __int32         cval;
  1184.             Tree            cexp;
  1185.  
  1186.             /* Bind the value and coerce to the right type */
  1187.  
  1188.             cexp = cmpCoerceExpr(cmpBindExpr(caseLab->tnCase.tncValue),
  1189.                                  svalExpr->tnType,
  1190.                                  false);
  1191.  
  1192.             /* Make sure the value is a constant expression */
  1193.  
  1194.             if  (cexp->tnOper != TN_CNS_INT)
  1195.             {
  1196.                 if  (cexp->tnVtyp != TYP_UNDEF)
  1197.                     cmpError(ERRnoIntExpr);
  1198.  
  1199.                 cexp    = NULL;
  1200.                 hadErrs = true;
  1201.             }
  1202.             else
  1203.             {
  1204.                 /* Get the constant value for this label */
  1205.  
  1206.                 cval = cexp->tnIntCon.tnIconVal;
  1207.  
  1208.                 /* Keep track of the min. and max. value, plus total count */
  1209.  
  1210.                 caseCnt++;
  1211.  
  1212.                 if  (caseCnt == 1)
  1213.                 {
  1214.                     /* This is the very first case value */
  1215.  
  1216.                     caseMax =
  1217.                     caseMin = cval;
  1218.                 }
  1219.                 else
  1220.                 {
  1221.                     /* We've had values before - update min/max as appropriate */
  1222.  
  1223.                     if  (caseUns)
  1224.                     {
  1225.                         if  ((unsigned)caseMin >  (unsigned)cval) caseMin  = cval;
  1226.                         if  ((unsigned)caseMax <  (unsigned)cval) caseMax  = cval;
  1227.                         if  ((unsigned)casePrv >= (unsigned)cval) needSort = true;
  1228.                     }
  1229.                     else
  1230.                     {
  1231.                         if  (  (signed)caseMin >    (signed)cval) caseMin  = cval;
  1232.                         if  (  (signed)caseMax <    (signed)cval) caseMax  = cval;
  1233.                         if  (  (signed)casePrv >=   (signed)cval) needSort = true;
  1234.                     }
  1235.                 }
  1236.  
  1237.                 casePrv = cval;
  1238.             }
  1239.  
  1240.             caseLab->tnCase.tncValue = cexp;
  1241.         }
  1242.         else
  1243.         {
  1244.             /* This is a "default:" label */
  1245.  
  1246.             if  (hadDefault)
  1247.                 cmpError(ERRdupDefl);
  1248.  
  1249.             hadDefault = true;
  1250.             labDeflt   = caseLab->tnCase.tncLabel;
  1251.         }
  1252.     }
  1253.  
  1254. #if 0
  1255.  
  1256.     printf("Total case labels: %u", caseCnt);
  1257.  
  1258.     if  (caseUns)
  1259.         printf(" [min = %u, max = %u]\n", caseMin, caseMax);
  1260.     else
  1261.         printf(" [min = %d, max = %d]\n", caseMin, caseMax);
  1262.  
  1263. #endif
  1264.  
  1265.     /* Don't bother generating the opcode if we had errors */
  1266.  
  1267.     if  (hadErrs)
  1268.         goto DONE_SWT;
  1269.  
  1270.     /* Figure out where to go if no case label value matches */
  1271.  
  1272.     nmLabel = hadDefault ? labDeflt : labBreak;
  1273.  
  1274.     if  (!caseCnt)
  1275.         goto JMP_DEF;
  1276.  
  1277.     /* Collect all the case labels in a table */
  1278.  
  1279. #if MGDDATA
  1280.  
  1281.     Tree    []  sortBuff;
  1282.  
  1283.     sortBuff = new Tree[caseCnt];
  1284.  
  1285. #else
  1286.  
  1287.     Tree    *   sortBuff;
  1288.  
  1289.     sortBuff = (Tree*)cmpAllocCGen.nraAlloc(caseCnt*sizeof(*sortBuff));
  1290.  
  1291. #endif
  1292.  
  1293.     /* Add all the case labels in the table */
  1294.  
  1295.     for (caseLab = stmt->tnSwitch.tnsCaseList, sortNum = 0;
  1296.          caseLab;
  1297.          caseLab = caseLab->tnCase.tncNext)
  1298.     {
  1299.         assert(caseLab->tnOper == TN_CASE);
  1300.  
  1301.         /* Append to the table unless it's a 'default' label */
  1302.  
  1303.         if  (caseLab->tnCase.tncValue)
  1304.             sortBuff[sortNum++] = caseLab;
  1305.     }
  1306.  
  1307.     assert(sortNum == caseCnt);
  1308.  
  1309.     /* Sort the table by case label value, if necessary */
  1310.  
  1311.     if  (needSort)
  1312.     {
  1313.         unsigned    sortLast;
  1314.         Tree    *   sortAddr;
  1315.         unsigned    sortCnt;
  1316.  
  1317. #ifdef  __IL__
  1318.         sortSwitchCases(sortBuff, caseCnt);
  1319. #else
  1320.         qsort(sortBuff, caseCnt, sizeof(*sortBuff), caseSortCmp);
  1321. #endif
  1322.  
  1323.         /* Check for duplicates */
  1324.  
  1325.         sortCnt  = caseCnt;
  1326.         sortAddr = sortBuff;
  1327.         sortLast = 0;
  1328.  
  1329.         do
  1330.         {
  1331.             Tree            sortCase = *sortAddr; assert(sortCase->tnOper == TN_CASE);
  1332.             unsigned        sortNext;
  1333.  
  1334.             if  (!sortCase->tnCase.tncValue)
  1335.                 continue;
  1336.  
  1337.             assert(sortCase->tnCase.tncValue->tnOper == TN_CNS_INT);
  1338.             sortNext = sortCase->tnCase.tncValue->tnIntCon.tnIconVal;
  1339.  
  1340.             if  (sortLast == sortNext && sortAddr > sortBuff)
  1341.             {
  1342.                 char            cstr[16];
  1343.  
  1344.                 if  (caseUns)
  1345.                     sprintf(cstr, "%u", sortNext);
  1346.                 else
  1347.                     sprintf(cstr, "%d", sortNext);
  1348.  
  1349.                 cmpRecErrorPos(sortCase);
  1350.                 cmpGenError(ERRdupCaseVal, cstr); hadErrs = true;
  1351.             }
  1352.  
  1353.             sortLast = sortNext;
  1354.         }
  1355.         while (++sortAddr, --sortCnt);
  1356.  
  1357.         if  (hadErrs)
  1358.             goto DONE_SWT;
  1359.     }
  1360.  
  1361.     /* Decide whether to use the "switch" opcode or not */
  1362.  
  1363.     if  (caseCnt > 3U && (unsigned)(caseMax - caseMin) <= 2U*caseCnt)
  1364.     {
  1365.         /* Generate a "real" switch opcode */
  1366.  
  1367.         cmpChkVarInitExpr(svalExpr);
  1368.         cmpILgen->genExpr(svalExpr, true);
  1369.  
  1370.         cmpILgen->genSwitch(caseMax - caseMin + 1,
  1371.                             caseCnt,
  1372.                             caseMin,
  1373.                             sortBuff,
  1374.                             nmLabel);
  1375.     }
  1376.     else
  1377.     {
  1378.         unsigned            tempNum;
  1379.  
  1380.         /* Allocate a temp to hold the value */
  1381.  
  1382.         tempNum = cmpILgen->genTempVarGet(svalExpr->tnType);
  1383.  
  1384.         /* Store the switch value in the temporary */
  1385.  
  1386.         cmpILgen->genExpr     (svalExpr, true);
  1387.         cmpILgen->genLclVarRef( tempNum, true);
  1388.  
  1389.         /* Now generate a series of compares and jumps */
  1390.  
  1391.         for (caseLab = stmt->tnSwitch.tnsCaseList;
  1392.              caseLab;
  1393.              caseLab = caseLab->tnCase.tncNext)
  1394.         {
  1395.             __int32         cval;
  1396.             Tree            cexp;
  1397.  
  1398.             assert(caseLab->tnOper == TN_CASE);
  1399.  
  1400.             /* Is there a label value or is this "default" ? */
  1401.  
  1402.             if  (!caseLab->tnCase.tncValue)
  1403.                 continue;
  1404.  
  1405.             cexp = caseLab->tnCase.tncValue; assert(cexp->tnOper == TN_CNS_INT);
  1406.             cval = cexp->tnIntCon.tnIconVal;
  1407.  
  1408.             cmpILgen->genLclVarRef(tempNum, false);
  1409.             cmpILgen->genSwtCmpJmp(cval, caseLab->tnCase.tncLabel);
  1410.         }
  1411.  
  1412.         cmpILgen->genTempVarRls(svalExpr->tnType, tempNum);
  1413.     }
  1414.  
  1415. JMP_DEF:
  1416.  
  1417.     /* If none of the values match, jump to 'default' or skip over */
  1418.  
  1419.     cmpILgen->genJump(nmLabel);
  1420.  
  1421. DONE_SWT:
  1422.  
  1423.     /* Only case labels are reachable in a switch */
  1424.  
  1425.     cmpStmtReachable = false;
  1426.  
  1427.     /* Bind the body of the switch */
  1428.  
  1429.     assert(stmt->tnSwitch.tnsStmt->tnOper == TN_BLOCK); cmpBlock(stmt->tnSwitch.tnsStmt, false);
  1430.  
  1431.     /* Remove our entry from the statement list */
  1432.  
  1433.     cmpStmtNest = nestStmt.snOuter;
  1434.  
  1435.     /* Define the "break" label */
  1436.  
  1437.     cmpILgen->genFwdLabDef(labBreak);
  1438.  
  1439.     /* The next statement is reachable if we had a break or no default */
  1440.  
  1441.     if  (nestStmt.snHadBreak || hadDefault == 0)
  1442.         cmpStmtReachable = true;
  1443. }
  1444.  
  1445. /*****************************************************************************
  1446.  *
  1447.  *  Report an "unreachable code" diagnostic unless the given statement is
  1448.  *  one for which such a diagnostic wouldn't make sense (like a label).
  1449.  */
  1450.  
  1451. void                compiler::cmpErrorReach(Tree stmt)
  1452. {
  1453.     switch (stmt->tnOper)
  1454.     {
  1455.         StmtNest        nest;
  1456.  
  1457.     case TN_CASE:
  1458.     case TN_LABEL:
  1459.         return;
  1460.  
  1461.     case TN_BREAK:
  1462.  
  1463.         for (nest = cmpStmtNest; nest; nest = nest->snOuter)
  1464.         {
  1465.             switch (nest->snStmtKind)
  1466.             {
  1467.             case TN_SWITCH:
  1468.                 return;
  1469.  
  1470.             case TN_DO:
  1471.             case TN_FOR:
  1472.             case TN_WHILE:
  1473.                 break;
  1474.  
  1475.             default:
  1476.                 continue;
  1477.             }
  1478.  
  1479.             break;
  1480.         }
  1481.  
  1482.         break;
  1483.  
  1484.     case TN_VAR_DECL:
  1485.         if  (!(stmt->tnFlags & TNF_VAR_INIT))
  1486.             return;
  1487.     }
  1488.  
  1489.     cmpRecErrorPos(stmt);
  1490.     cmpWarn(WRNunreach);
  1491.     cmpStmtReachable = true;
  1492. }
  1493.  
  1494. /*****************************************************************************/
  1495. /*****************************************************************************
  1496.  *
  1497.  *  Generate IL for the given statement/declaration.
  1498.  */
  1499.  
  1500. void                compiler::cmpStmt(Tree stmt)
  1501. {
  1502.     /* The stack should be empty at the start of each statement */
  1503.  
  1504. #ifdef  OLD_IL
  1505.     if  (!cmpConfig.ccOILgen)
  1506. #endif
  1507.         assert(cmpILgen->genCurStkLvl == 0 || cmpErrorCount);
  1508.  
  1509. AGAIN:
  1510.  
  1511.     if  (!stmt)
  1512.         return;
  1513.  
  1514. #ifdef DEBUG
  1515.  
  1516.     if  (cmpConfig.ccVerbose >= 2)
  1517.     {
  1518.         printf("Compile statement [%u]:\n", stmt->tnLineNo);
  1519.         cmpParser->parseDispTree(stmt);
  1520.     }
  1521.  
  1522. //  if  (cmpConfig.ccDispCode)
  1523. //  {
  1524. //      if  (stmt->tnLineNo)
  1525. //          printf("; source line %x\n\n");
  1526. //  }
  1527.  
  1528.     assert(stmt->tnLineNo || (stmt->tnFlags & TNF_NOT_USER));
  1529.  
  1530.     cmpRecErrorPos(stmt);
  1531.  
  1532. #endif
  1533.  
  1534. #ifdef  OLD_IL
  1535.     if  (cmpConfig.ccOILgen)
  1536.         cmpOIgen->GOIrecExprPos(stmt);
  1537.     else
  1538. #endif
  1539.         cmpILgen->genRecExprPos(stmt);
  1540.  
  1541.     cmpCheckReach(stmt);
  1542.  
  1543.     switch (stmt->tnOper)
  1544.     {
  1545.         SymDef          lsym;
  1546.         Ident           name;
  1547.         StmtNest        nest;
  1548.         Tree            cond;
  1549.         TypDef          type;
  1550.  
  1551.         bool            exitTry;
  1552.         bool            exitHnd;
  1553.  
  1554.     case TN_CALL:
  1555.  
  1556.         /*
  1557.             If this is a "baseclass" call, we need to add any instance
  1558.             member initializers right after the call to the base class
  1559.             constructor.
  1560.          */
  1561.  
  1562.         if  (stmt->tnOp.tnOp1 && stmt->tnOp.tnOp1->tnOper == TN_BASE)
  1563.         {
  1564.             stmt = cmpBindExpr(stmt);
  1565.             cmpChkVarInitExpr(stmt);
  1566.             cmpILgen->genExpr(stmt, false);
  1567.  
  1568.             cmpAddCTinits();
  1569.             break;
  1570.         }
  1571.  
  1572.         // Fall through ...
  1573.  
  1574.     default:
  1575.  
  1576.         /* Presumably an expression statement */
  1577.  
  1578.         stmt = cmpBindExpr(stmt);
  1579.         cmpChkVarInitExpr(stmt);
  1580.  
  1581.         /* See if the expression actually does some work */
  1582.  
  1583.         switch (stmt->tnOper)
  1584.         {
  1585.         case TN_NEW:
  1586.         case TN_CALL:
  1587.         case TN_THROW:
  1588.         case TN_ERROR:
  1589.         case TN_DBGBRK:
  1590.         case TN_DELETE:
  1591.         case TN_FNC_SYM:
  1592.         case TN_INC_PRE:
  1593.         case TN_DEC_PRE:
  1594.         case TN_INC_POST:
  1595.         case TN_DEC_POST:
  1596.         case TN_INST_STUB:
  1597.         case TN_VARARG_BEG:
  1598.             break;
  1599.  
  1600.         default:
  1601.             if  (stmt->tnOperKind() & TNK_ASGOP)
  1602.                 break;
  1603.             cmpWarn(WRNstmtNoUse);
  1604.         }
  1605.  
  1606.         cmpILgen->genExpr(stmt, false);
  1607.         break;
  1608.  
  1609.     case TN_BLOCK:
  1610.  
  1611.         cmpBlock(stmt, false);
  1612.         return;
  1613.  
  1614.     case TN_VAR_DECL:
  1615.  
  1616.         /* Get hold of the local variable */
  1617.  
  1618.         lsym = stmt->tnDcl.tnDclSym;
  1619.         assert(lsym && lsym->sdSymKind == SYM_VAR);
  1620.  
  1621.         /* Mark the variable as declared/defined */
  1622.  
  1623.         lsym->sdIsDefined    = true;
  1624.         lsym->sdCompileState = CS_DECLARED;
  1625.  
  1626.         /* Check and set the type of the symbol */
  1627.  
  1628. //      printf("Declare local  [%08X] '%s'\n", lsym, cmpGlobalST->stTypeName(NULL, lsym, NULL, NULL, false));
  1629.  
  1630.         type = stmt->tnType; assert(type);
  1631.  
  1632.         /* Special case: "refany" return type */
  1633.  
  1634.         if  (type->tdTypeKind == TYP_REF && type->tdRef.tdrBase->tdTypeKind == TYP_VOID)
  1635.             stmt->tnType = type = cmpGlobalST->stIntrinsicType(TYP_REFANY);
  1636.         else
  1637.             cmpBindType(type, false, false);
  1638.  
  1639.         lsym->sdType = type;
  1640.  
  1641.         /* Local static variables may not have a managed type for now */
  1642.  
  1643.         if  (lsym->sdIsStatic && type->tdIsManaged)
  1644.         {
  1645.             lsym->sdIsManaged = true;
  1646.             cmpError(ERRmgdStatVar);
  1647.             break;
  1648.         }
  1649.  
  1650.         /* Is there an initializer? */
  1651.  
  1652.         if  (stmt->tnFlags & TNF_VAR_INIT)
  1653.         {
  1654.             parserState     save;
  1655.  
  1656.             Tree            init;
  1657.             Tree            assg;
  1658.  
  1659.             cmpRecErrorPos(stmt);
  1660.  
  1661.             /* Managed static locals can't be initialized for now */
  1662.  
  1663.             if  (lsym->sdIsManaged)
  1664.             {
  1665.                 cmpError(ERRmgdStatVar);
  1666.                 break;
  1667.             }
  1668.  
  1669.             /* Get hold of the initializer */
  1670.  
  1671.             assert(stmt->tnDcl.tnDclInfo->tnOper == TN_LIST);
  1672.             init = stmt->tnDcl.tnDclInfo->tnOp.tnOp2;
  1673.  
  1674.             /* Is the variable "static" ? */
  1675.  
  1676.             if  (lsym->sdIsStatic)
  1677.             {
  1678.                 memBuffPtr      addr = memBuffMkNull();
  1679.  
  1680.                 assert(init->tnOper == TN_SLV_INIT);
  1681.  
  1682.                 /* Start reading from the symbol's definition text */
  1683.  
  1684.                 cmpParser->parsePrepText(&init->tnInit.tniSrcPos, cmpCurComp, save);
  1685.  
  1686.                 /* Process the variable initializer */
  1687.  
  1688.                 cmpInitVarAny(addr, lsym->sdType, lsym);
  1689.                 cmpInitVarEnd(lsym);
  1690.  
  1691.                 /* We're done reading source text from the definition */
  1692.  
  1693.                 cmpParser->parseDoneText(save);
  1694.  
  1695.                 /* The variable has been fully compiled */
  1696.  
  1697.                 lsym->sdCompileState = CS_COMPILED;
  1698.             }
  1699.             else
  1700.             {
  1701.                 if  (init->tnOper == TN_SLV_INIT)
  1702.                 {
  1703.                     TypDef          type = lsym->sdType;
  1704.  
  1705.                     /* Start reading from the initializer's text */
  1706.  
  1707.                     cmpParser->parsePrepText(&init->tnInit.tniSrcPos, init->tnInit.tniCompUnit, save);
  1708.  
  1709.                     /* Make sure the type looks acceptable */
  1710.  
  1711.                     if  (type->tdTypeKind != TYP_ARRAY || !type->tdIsManaged)
  1712.                     {
  1713.                         cmpError(ERRbadBrInit, type);
  1714.                     }
  1715.                     else
  1716.                     {
  1717.                         /* Parse and bind the initializer */
  1718.  
  1719.                         init = cmpBindArrayExpr(type);
  1720.  
  1721.                         /* Create "var = init" and compile/generate it */
  1722.  
  1723.                         init = cmpCreateExprNode(NULL, TN_ASG, type, cmpCreateVarNode(NULL, lsym),
  1724.                                                                      init);
  1725.  
  1726.                         cmpChkVarInitExpr(init);
  1727.                         cmpILgen->genExpr(init, false);
  1728.                     }
  1729.  
  1730.                     /* We're done reading source text from the initializer */
  1731.  
  1732.                     cmpParser->parseDoneText(save);
  1733.                 }
  1734.                 else
  1735.                 {
  1736.                     /* Is this a local constant? */
  1737.  
  1738.                     if  (lsym->sdVar.sdvConst)
  1739.                     {
  1740.                         assert(stmt->tnFlags & TNF_VAR_CONST);
  1741.  
  1742.                         cmpParseConstDecl(lsym, init);
  1743.                     }
  1744.                     else
  1745.                     {
  1746.                         {
  1747.                             /* Create "var = init" and bind/compile/generate it */
  1748.  
  1749.                             assg = cmpParser->parseCreateUSymNode(lsym); assg->tnLineNo = stmt->tnLineNo;
  1750.                             init = cmpParser->parseCreateOperNode(TN_ASG, assg, init);
  1751.                             init->tnFlags |= TNF_ASG_INIT;
  1752.  
  1753.                             init = cmpBindExpr(init);
  1754.                             cmpChkVarInitExpr(init);
  1755.                             cmpILgen->genExpr(init, false);
  1756.                         }
  1757.                     }
  1758.                 }
  1759.             }
  1760.         }
  1761.         else
  1762.         {
  1763.             if  (!lsym->sdIsStatic && !lsym->sdVar.sdvCatchArg
  1764.                                    && !lsym->sdVar.sdvArgument)
  1765.             {
  1766.                 /* This local variable has not yet been initialized */
  1767.  
  1768.                 lsym->sdVar.sdvChkInit = true;
  1769.             }
  1770.         }
  1771.  
  1772.         if  (cmpConfig.ccGenDebug && lsym->sdName && !lsym->sdVar.sdvConst
  1773.                                                   && !lsym->sdVar.sdvArgument
  1774.                                                   && !lsym->sdIsStatic)
  1775.         {
  1776.             PCOR_SIGNATURE  sigPtr;
  1777.             size_t          sigLen;
  1778.  
  1779. //          printf("Debug info for local var: '%s'\n", lsym->sdSpelling());
  1780.  
  1781.             sigPtr = cmpTypeSig(lsym->sdType, &sigLen);
  1782.  
  1783.             if  (cmpSymWriter->DefineLocalVariable(cmpUniConv(lsym->sdName),
  1784.                                                    sigPtr,
  1785.                                                    sigLen,
  1786.                                                    lsym->sdVar.sdvILindex))
  1787.             {
  1788.                 cmpGenFatal(ERRdebugInfo);
  1789.             }
  1790.         }
  1791.  
  1792.         break;
  1793.  
  1794.     case TN_IF:
  1795.         {
  1796.             bitset          tmpBStrue;
  1797.             bitset          tmpBSfalse;
  1798.  
  1799.             ILblock         labTmp1;
  1800.             ILblock         labTmp2;
  1801.  
  1802.             bool            reached;
  1803.  
  1804.             Tree            stmtCond;
  1805.             Tree            stmtYes;
  1806.             Tree            stmtNo;
  1807.             int             cval;
  1808.  
  1809.             /* Get hold of the various parts */
  1810.  
  1811.             stmtCond = cmpBindCondition(stmt->tnOp.tnOp1);
  1812.  
  1813.             stmtNo   = NULL;
  1814.             stmtYes  = stmt->tnOp.tnOp2;
  1815.  
  1816.             if  (stmt->tnFlags & TNF_IF_HASELSE)
  1817.             {
  1818.                 assert(stmtYes->tnOper == TN_LIST);
  1819.  
  1820.                 stmtNo  = stmtYes->tnOp.tnOp2;
  1821.                 stmtYes = stmtYes->tnOp.tnOp1;
  1822.             }
  1823.  
  1824.             /* Can the condition be evaluated at compile time? */
  1825.  
  1826.             cval = cmpEvalCondition(stmtCond);
  1827.  
  1828.             /* Do we need to check for uninitialized variable use? */
  1829.  
  1830.             if  (cmpChkVarInit)
  1831.             {
  1832.                 /* Check the condition and compute the 'true' and 'false' sets */
  1833.  
  1834.                 cmpCheckUseCond(stmtCond, tmpBStrue , false,
  1835.                                           tmpBSfalse, false);
  1836.  
  1837.                 /* Use the 'true' set for the true branch of the 'if' */
  1838.  
  1839.                 cmpBitSetAssign(cmpVarsDefined, tmpBStrue);
  1840.             }
  1841.  
  1842.             /* Remember the initial reachability */
  1843.  
  1844.             reached = cmpStmtReachable;
  1845.  
  1846.             /* Test the 'if' condition (unless it is known already) */
  1847.  
  1848.             if  (cval)
  1849.             {
  1850.                 labTmp1 = cmpILgen->genFwdLabGet();
  1851.  
  1852.                 if  (cval < 0)
  1853.                     cmpILgen->genJump(labTmp1);
  1854.             }
  1855.             else
  1856.                 labTmp1 = cmpILgen->genTestCond(stmtCond, false);
  1857.  
  1858.             /* Generate the "true" branch of the statement */
  1859.  
  1860.             cmpStmt(stmtYes);
  1861.  
  1862.             /* Is there "false" (i.e. "else") branch? */
  1863.  
  1864.             if  (stmtNo)
  1865.             {
  1866.                 bool            rtmp;
  1867.  
  1868.                 labTmp2 = cmpILgen->genFwdLabGet();
  1869.  
  1870.                 /* Skip over the "else" if end of "true" part is reachable */
  1871.  
  1872.                 if  (cmpStmtReachable)
  1873.                     cmpILgen->genJump(labTmp2);
  1874.  
  1875.                 cmpILgen->genFwdLabDef(labTmp1);
  1876.  
  1877.                 /* Swap the reachability values */
  1878.  
  1879.                 rtmp = cmpStmtReachable;
  1880.                        cmpStmtReachable = reached;
  1881.                                           reached = rtmp;
  1882.  
  1883.                 /* Do we need to check for uninitialized variable use? */
  1884.  
  1885.                 if  (cmpChkVarInit)
  1886.                 {
  1887.                     /* Save the current set as the new 'true' set */
  1888.  
  1889.                     cmpBitSetAssign(tmpBStrue, cmpVarsDefined);
  1890.  
  1891.                     /* Use the 'false' set for the other branch of the 'if' */
  1892.  
  1893.                     cmpBitSetAssign(cmpVarsDefined, tmpBSfalse);
  1894.  
  1895.                     /* Generate the "else" part now */
  1896.  
  1897.                     cmpStmt(stmtNo);
  1898.  
  1899.                     /* Is the end of the 'else' branch reachable? */
  1900.  
  1901.                     if  (!cmpStmtReachable)
  1902.                     {
  1903.                         /* The 'else' goes nowhere -- use the 'true' part then */
  1904.  
  1905.                         cmpBitSetAssign(cmpVarsDefined, tmpBStrue);
  1906.                     }
  1907.                     else if (reached)
  1908.                     {
  1909.                         /* Both branches reachable -- use the intersection */
  1910.  
  1911.                         cmpBitSetIntsct(cmpVarsDefined, tmpBStrue);
  1912.                     }
  1913.                 }
  1914.                 else
  1915.                     cmpStmt(stmtNo);
  1916.  
  1917.                 labTmp1 = labTmp2;
  1918.             }
  1919.             else
  1920.             {
  1921.                 /* There is no 'else', is the 'true' block's end reachable? */
  1922.  
  1923.                 if  (cmpChkVarInit && cmpStmtReachable)
  1924.                 {
  1925.                     /* Use the intersection of the 'true' and 'false' sets */
  1926.  
  1927.                     cmpBitSetIntsct(cmpVarsDefined, tmpBSfalse);
  1928.                 }
  1929.  
  1930.                 if      (cval > 0)
  1931.                     reached = false;
  1932.                 else if (cval < 0)
  1933.                     cmpStmtReachable = reached;
  1934.             }
  1935.  
  1936.             cmpILgen->genFwdLabDef(labTmp1);
  1937.  
  1938.             /* The end is reachable if either branch is */
  1939.  
  1940.             cmpStmtReachable |= reached;
  1941.  
  1942.             /* Free up any bitsets we may have created */
  1943.  
  1944.             if  (cmpChkVarInit)
  1945.             {
  1946.                 cmpBitSetDone(tmpBStrue);
  1947.                 cmpBitSetDone(tmpBSfalse);
  1948.             }
  1949.         }
  1950.         break;
  1951.  
  1952.     case TN_DO:
  1953.         cmpStmtDo(stmt);
  1954.         break;
  1955.  
  1956.     case TN_FOR:
  1957.         cmpStmtFor(stmt);
  1958.         break;
  1959.  
  1960.     case TN_WHILE:
  1961.         cmpStmtWhile(stmt);
  1962.         break;
  1963.  
  1964.     case TN_SWITCH:
  1965.         cmpStmtSwitch(stmt);
  1966.         break;
  1967.  
  1968.     case TN_CASE:
  1969.  
  1970.         /* If the switch wasn't reachable, an error has already been issued */
  1971.  
  1972.         cmpStmtReachable = true;
  1973.  
  1974.         /* Create a label and assign it to the case/default */
  1975.  
  1976.         cmpILgen->genFwdLabDef(stmt->tnCase.tncLabel);
  1977.         break;
  1978.  
  1979.     case TN_BREAK:
  1980.     case TN_CONTINUE:
  1981.  
  1982.         /* Was there a loop label specification? */
  1983.  
  1984.         name = NULL;
  1985.         if  (stmt->tnOp.tnOp1)
  1986.         {
  1987.             assert(stmt->tnOp.tnOp1->tnOper == TN_NAME);
  1988.             name = stmt->tnOp.tnOp1->tnName.tnNameId;
  1989.         }
  1990.  
  1991.         /* Look for an enclosing statement that looks appropriate */
  1992.  
  1993.         for (nest = cmpStmtNest, exitTry = exitHnd = false;
  1994.              nest;
  1995.              nest = nest->snOuter)
  1996.         {
  1997.             switch (nest->snStmtKind)
  1998.             {
  1999.             case TN_SWITCH:
  2000.  
  2001.                 /* Only allow "break" from a switch statement */
  2002.  
  2003.                 if  (stmt->tnOper != TN_BREAK)
  2004.                     continue;
  2005.  
  2006.                 break;
  2007.  
  2008.             case TN_DO:
  2009.             case TN_FOR:
  2010.             case TN_WHILE:
  2011.                 break;
  2012.  
  2013.             case TN_NONE:
  2014.                 continue;
  2015.  
  2016.             case TN_TRY:
  2017.                 exitTry = true;
  2018.                 continue;
  2019.  
  2020.             case TN_CATCH:
  2021.                 exitHnd = true;
  2022.                 continue;
  2023.  
  2024.             case TN_FINALLY:
  2025.                 cmpError(ERRfinExit);
  2026.                 goto DONE;
  2027.  
  2028.             default:
  2029.                 NO_WAY(!"unexpected stmt kind");
  2030.             }
  2031.  
  2032.             /* Here we have a useable statement, check the label */
  2033.  
  2034.             if  (name)
  2035.             {
  2036.                 if  (nest->snLabel == NULL || nest->snLabel->sdName != name)
  2037.                     continue;
  2038.             }
  2039.  
  2040.             /* Everything checks out, we can generate the jump now */
  2041.  
  2042.             if  (stmt->tnOper == TN_BREAK)
  2043.             {
  2044.                 if  (exitHnd)
  2045.                     cmpILgen->genCatchEnd(true);
  2046.  
  2047.                 if  (exitTry || exitHnd)
  2048.                     cmpILgen->genLeave(nest->snLabBreak);
  2049.                 else
  2050.                     cmpILgen->genJump (nest->snLabBreak);
  2051.  
  2052.                 /* Are we checking for uninitialized variable use? */
  2053.  
  2054.                 if  (cmpChkVarInit)
  2055.                 {
  2056.                     /* Initialize or intersect the "break" set */
  2057.  
  2058.                     if  (nest->snHadBreak)
  2059.                         cmpBitSetIntsct(nest->snDefBreak, cmpVarsDefined);
  2060.                     else
  2061.                         cmpBitSetCreate(nest->snDefBreak, cmpVarsDefined);
  2062.                 }
  2063.  
  2064.                 nest->snHadBreak = true;
  2065.             }
  2066.             else
  2067.             {
  2068.                 if  (exitHnd)
  2069.                     cmpILgen->genCatchEnd(true);
  2070.  
  2071.                 if  (exitTry || exitHnd)
  2072.                     cmpILgen->genLeave(nest->snLabCont);
  2073.                 else
  2074.                     cmpILgen->genJump (nest->snLabCont);
  2075.  
  2076.                 /* Are we checking for uninitialized variable use? */
  2077.  
  2078.                 if  (cmpChkVarInit)
  2079.                 {
  2080.                     /* Initialize or intersect the "continue" set */
  2081.  
  2082.                     if  (nest->snHadCont)
  2083.                         cmpBitSetIntsct(nest->snDefCont, cmpVarsDefined);
  2084.                     else
  2085.                         cmpBitSetCreate(nest->snDefCont, cmpVarsDefined);
  2086.                 }
  2087.  
  2088.                 nest->snHadCont = true;
  2089.             }
  2090.  
  2091.             cmpStmtReachable = false;
  2092.             goto DONE;
  2093.         }
  2094.  
  2095.         cmpError((stmt->tnOper == TN_BREAK) ? ERRbadBreak : ERRbadCont);
  2096.         break;
  2097.  
  2098.     case TN_LABEL:
  2099.  
  2100.         /* We have to be careful - redefined labels have NULL symbol links */
  2101.  
  2102.         lsym = NULL;
  2103.  
  2104.         if  (stmt->tnOp.tnOp1)
  2105.         {
  2106.             assert(stmt->tnOp.tnOp1->tnOper == TN_LCL_SYM);
  2107.             lsym = stmt->tnOp.tnOp1->tnLclSym.tnLclSym;
  2108.             assert(lsym && lsym->sdSymKind == SYM_LABEL);
  2109.  
  2110.             cmpILgen->genFwdLabDef(lsym->sdLabel.sdlILlab);
  2111.         }
  2112.  
  2113.         /* For now assume all labels are reachable */
  2114.  
  2115.         cmpStmtReachable = true;
  2116.  
  2117.         /* Is there a statement attached? */
  2118.  
  2119.         if  (stmt->tnOp.tnOp2 && stmt->tnOp.tnOp2->tnOper == TN_LIST)
  2120.         {
  2121.             /* Get hold of the statement and see if it's a loop */
  2122.  
  2123.             stmt = stmt->tnOp.tnOp2->tnOp.tnOp1;
  2124.  
  2125.             switch (stmt->tnOper)
  2126.             {
  2127.             case TN_DO:     cmpStmtDo    (stmt, lsym); break;
  2128.             case TN_FOR:    cmpStmtFor   (stmt, lsym); break;
  2129.             case TN_WHILE:  cmpStmtWhile (stmt, lsym); break;
  2130.             case TN_SWITCH: cmpStmtSwitch(stmt, lsym); break;
  2131.  
  2132.             default:
  2133.                 goto AGAIN;
  2134.             }
  2135.         }
  2136.         break;
  2137.  
  2138.     case TN_GOTO:
  2139.  
  2140.         /* Get hold of the label name */
  2141.  
  2142.         assert(stmt->tnOp.tnOp1);
  2143.         assert(stmt->tnOp.tnOp1->tnOper == TN_NAME);
  2144.         name = stmt->tnOp.tnOp1->tnName.tnNameId;
  2145.  
  2146.         /* Look for the label symbol in the label scope */
  2147.  
  2148.         lsym = cmpLabScp ? cmpGlobalST->stLookupLabSym(name, cmpLabScp) : NULL;
  2149.  
  2150.         if  (lsym)
  2151.         {
  2152.             assert(lsym->sdSymKind == SYM_LABEL);
  2153.  
  2154.             /* Are we in an exception handler block? */
  2155.  
  2156.             if  (cmpInTryBlk || cmpInHndBlk)
  2157.                 cmpILgen->genLeave(lsym->sdLabel.sdlILlab);
  2158.             else
  2159.                 cmpILgen->genJump (lsym->sdLabel.sdlILlab);
  2160.         }
  2161.         else
  2162.         {
  2163.             cmpError(ERRundefLab, name);
  2164.         }
  2165.  
  2166.         cmpStmtReachable = false;
  2167.         break;
  2168.  
  2169.     case TN_EXCLUDE:
  2170.         cmpStmtExcl(stmt);
  2171.         break;
  2172.  
  2173.     case TN_RETURN:
  2174.  
  2175.         /* Can't return out of finally blocks */
  2176.  
  2177.         if  (cmpInFinBlk)
  2178.         {
  2179.             cmpError(ERRfinExit);
  2180.             break;
  2181.         }
  2182.  
  2183.         /* Are going to need a return value label ? */
  2184.  
  2185.         if  (cmpInTryBlk || cmpInHndBlk)
  2186.         {
  2187.             /* Make sure we have the label */
  2188.  
  2189.             if  (cmpLeaveLab == NULL)
  2190.                  cmpLeaveLab = cmpILgen->genFwdLabGet();
  2191.         }
  2192.  
  2193.         /* Are we in a function with a non-void return value? */
  2194.  
  2195.         if  (cmpCurFncRvt == TYP_VOID || cmpCurFncSym->sdFnc.sdfCtor)
  2196.         {
  2197.             /* 'void' function, there should be no return value */
  2198.  
  2199.             if  (stmt->tnOp.tnOp1)
  2200.             {
  2201.                 cmpError(ERRcantRet);
  2202.             }
  2203.             else
  2204.             {
  2205.                 if  (cmpChkMemInit)
  2206.                     cmpChkMemInits();
  2207.  
  2208.                 if  (cmpInTryBlk || cmpInHndBlk)
  2209.                 {
  2210.                     if  (cmpInHndBlk)
  2211.                         cmpILgen->genCatchEnd(true);
  2212.  
  2213.                     cmpILgen->genLeave(cmpLeaveLab);
  2214.                 }
  2215.                 else
  2216.                     cmpILgen->genStmtRet(NULL);
  2217.             }
  2218.         }
  2219.         else
  2220.         {
  2221.             /* Non-void function, we better have a return value */
  2222.  
  2223.             if  (!stmt->tnOp.tnOp1)
  2224.             {
  2225.                 cmpError(ERRmisgRet, cmpCurFncTyp);
  2226.             }
  2227.             else
  2228.             {
  2229.                 Tree            retv;
  2230.  
  2231.                 /* Coerce the return value to the right type and bind it */
  2232.  
  2233.                 retv = cmpParser->parseCreateOperNode(TN_CAST, stmt->tnOp.tnOp1, NULL);
  2234.                 retv->tnType = cmpCurFncRtp;
  2235.  
  2236.                 /* Bind the return value expression */
  2237.  
  2238.                 retv = cmpFoldExpression(cmpBindExpr(retv));
  2239.  
  2240.                 cmpChkVarInitExpr(retv);
  2241.  
  2242.                 if  (cmpInTryBlk || cmpInHndBlk)
  2243.                 {
  2244.                     Tree            tmpx;
  2245.  
  2246.                     /* Make sure we have a temp for the return value */
  2247.  
  2248.                     if  (cmpLeaveTmp == NULL)
  2249.                          cmpLeaveTmp = cmpTempVarMake(cmpCurFncRtp);
  2250.  
  2251.                     /* Store the return value in the temp */
  2252.  
  2253.                     tmpx = cmpCreateVarNode (NULL, cmpLeaveTmp);
  2254.                     retv = cmpCreateExprNode(NULL, TN_ASG, cmpCurFncRtp, tmpx, retv);
  2255.  
  2256.                     /* Generate code for the return value */
  2257.  
  2258.                     cmpILgen->genExpr(retv, false);
  2259.  
  2260.                     /* We can get out of the try/catch block now */
  2261.  
  2262.                     if  (cmpInHndBlk)
  2263.                         cmpILgen->genCatchEnd(true);
  2264.  
  2265.                     cmpILgen->genLeave(cmpLeaveLab);
  2266.  
  2267.                     goto DONE_RET;
  2268.                 }
  2269.  
  2270. #ifdef  OLD_IL
  2271.                 if  (cmpConfig.ccOILgen)
  2272.                     cmpOIgen->GOIstmtRet(retv);
  2273.                 else
  2274. #endif
  2275.                     cmpILgen->genStmtRet(retv);
  2276.             }
  2277.         }
  2278.  
  2279.     DONE_RET:
  2280.  
  2281.         cmpStmtReachable = false;
  2282.         break;
  2283.  
  2284.     case TN_ASSERT:
  2285.  
  2286.         /* If there is no condition, we're presumably ignoring these */
  2287.  
  2288.         if  (!stmt->tnOp.tnOp1)
  2289.         {
  2290.             assert(cmpConfig.ccAsserts == 0);
  2291.             break;
  2292.         }
  2293.  
  2294.         /* Bind the condition */
  2295.  
  2296.         cond = cmpBindCondition(stmt->tnOp.tnOp1);
  2297.  
  2298.         /* Are we supposed to take asserts seriously? */
  2299.  
  2300.         if  (cmpConfig.ccAsserts != 0)
  2301.         {
  2302.             int             condVal;
  2303.             SymDef          abtSym;
  2304.             const   char *  srcStr = NULL;
  2305.  
  2306.             /* Make sure we have the assertAbort routine symbol */
  2307.  
  2308.             abtSym = cmpAsserAbtSym;
  2309.  
  2310.             if  (abtSym == NULL)
  2311.             {
  2312.                 abtSym = cmpGlobalST->stLookupNspSym(cmpIdentAssertAbt,
  2313.                                                      NS_NORM,
  2314.                                                      cmpGlobalNS);
  2315.  
  2316.                 if  (!abtSym)
  2317.                 {
  2318.                     // ISSUE: flag this with an error/warning?
  2319.  
  2320.                     break;
  2321.                 }
  2322.  
  2323.                 // UNDONE: check that the arglist is reasonable
  2324.  
  2325.                 cmpAsserAbtSym = abtSym;
  2326.             }
  2327.  
  2328.             /* Test the condition and see if it's always/never true */
  2329.  
  2330.             condVal = cmpEvalCondition(cond);
  2331.  
  2332.             if  (condVal <= 0)
  2333.             {
  2334.                 Tree        args = NULL;
  2335.                 Tree        expr;
  2336.                 Tree        func;
  2337.  
  2338.                 ILblock     labOK;
  2339.  
  2340.                 /* If the condition isn't know, generate the test */
  2341.  
  2342.                 if  (condVal == 0)
  2343.                     labOK  = cmpILgen->genTestCond(cond, true);
  2344.  
  2345.                 /* Are we supposed to report the source position? */
  2346.  
  2347.                 if  (cmpConfig.ccAsserts > 1)
  2348.                 {
  2349.                     Tree            argx;
  2350.  
  2351.                     assert(cmpErrorComp);
  2352.                     assert(cmpErrorTree);
  2353.                     assert(cmpErrorTree->tnLineNo);
  2354.  
  2355.                     /* Construct the argument list, inside out (i.e. R->L) */
  2356.  
  2357.                     argx = cmpCreateIconNode(NULL, cmpErrorTree->tnLineNo, TYP_UINT);
  2358.                     args = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, argx, NULL);
  2359.  
  2360.                     /* The source file is in front of the line# */
  2361.  
  2362.                     argx = cmpCreateSconNode(cmpErrorComp->sdComp.sdcSrcFile,
  2363.                                              strlen(cmpErrorComp->sdComp.sdcSrcFile),
  2364.                                              false,
  2365.                                              cmpTypeCharPtr);
  2366.                     args = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, argx, args);
  2367.  
  2368.                     /* The condition string is the first argument */
  2369.  
  2370.                     argx = cmpCreateSconNode("", 0, false, cmpTypeCharPtr);
  2371.                     args = cmpCreateExprNode(NULL, TN_LIST, cmpTypeVoid, argx, args);
  2372.                 }
  2373.  
  2374.                 // UNDONE: The following isn't quite right, the name may
  2375.                 // UNDONE: bind to the wrong symbol.
  2376.  
  2377.                 func = cmpParser->parseCreateNameNode(cmpIdentAssertAbt);
  2378.                 expr = cmpParser->parseCreateOperNode(TN_CALL, func, args);
  2379. //              expr->tnFncSym.tnFncSym  = abtSym;
  2380. //              expr->tnFncSym.tnFncArgs = args;
  2381. //              expr->tnFncSym.tnFncObj  = NULL;
  2382.  
  2383.                 /* Generate the failure code */
  2384.  
  2385.                 cmpILgen->genAssertFail(cmpBindExpr(expr));
  2386.  
  2387.                 /* If we tested the condition, define the skip label */
  2388.  
  2389.                 if  (condVal == 0)
  2390.                     cmpILgen->genFwdLabDef(labOK);
  2391.             }
  2392.         }
  2393.  
  2394.         break;
  2395.  
  2396.     case TN_TRY:
  2397.         cmpStmtTry(stmt);
  2398.         break;
  2399.  
  2400.     case TN_LIST:
  2401.  
  2402.         cmpStmt(stmt->tnOp.tnOp1);
  2403.         stmt = stmt->tnOp.tnOp2;
  2404.         if  (stmt)
  2405.             goto AGAIN;
  2406.         break;
  2407.  
  2408.     case TN_INST_STUB:
  2409.         cmpILgen->genInstStub();
  2410.         cmpStmtReachable = false;
  2411.         break;
  2412.     }
  2413.  
  2414. DONE:
  2415.  
  2416.     /* The stack should be empty at the end of each statement */
  2417.  
  2418. #ifdef  OLD_IL
  2419.     if  (!cmpConfig.ccOILgen)
  2420. #endif
  2421.         assert(cmpILgen->genCurStkLvl == 0 || cmpErrorCount);
  2422. }
  2423.  
  2424. /*****************************************************************************
  2425.  *
  2426.  *  Helpers that implement various operations on large bitsets.
  2427.  */
  2428.  
  2429. void                compiler::cmpBS_bigCreate(OUT bitset REF bs)
  2430. {
  2431.     assert(cmpLargeBSsize);
  2432.  
  2433. #ifdef  DEBUG
  2434.     assert(bs.bsCheck != 0xBEEFCAFE || &bs == &cmpVarsIgnore); bs.bsCheck = 0xBEEFCAFE;
  2435. #endif
  2436.  
  2437. #if MGDDATA
  2438.     bs.bsLargeVal = new BYTE[cmpLargeBSsize];
  2439. #else
  2440.     bs.bsLargeVal = (BYTE*)SMCgetMem(this, roundUp(cmpLargeBSsize));
  2441.     memset(bs.bsLargeVal, 0, cmpLargeBSsize);
  2442. #endif
  2443.  
  2444. //  printf("Create    [%08X] size=%u\n", &bs, cmpLargeBSsize);
  2445. }
  2446.  
  2447. void                compiler::cmpBS_bigDone  (OUT bitset REF bs)
  2448. {
  2449.     assert(cmpLargeBSsize);
  2450.  
  2451. //  printf("Free      [%08X]\n", &bs);
  2452.  
  2453. #ifdef  DEBUG
  2454.     assert(bs.bsCheck == 0xBEEFCAFE); bs.bsCheck = 0;
  2455. #endif
  2456.  
  2457. #if!MGDDATA
  2458.     SMCrlsMem(this, bs.bsLargeVal);
  2459. #endif
  2460.  
  2461. }
  2462.  
  2463. void                compiler::cmpBS_bigWrite(INOUT bitset REF bs, unsigned pos,
  2464.                                                                   unsigned val)
  2465. {
  2466.     unsigned        offs =      (pos / bitsetLargeSize);
  2467.     unsigned        mask = 1 << (pos % bitsetLargeSize);
  2468.  
  2469.     assert(offs < cmpLargeBSsize);
  2470.  
  2471. #ifdef  DEBUG
  2472.     assert(bs.bsCheck == 0xBEEFCAFE);
  2473. #endif
  2474.  
  2475.     if  (val)
  2476.         bs.bsLargeVal[offs] |=  mask;
  2477.     else
  2478.         bs.bsLargeVal[offs] &= ~mask;
  2479. }
  2480.  
  2481. unsigned            compiler::cmpBS_bigRead  (IN   bitset REF bs, unsigned pos)
  2482. {
  2483.     unsigned        offs =      (pos / bitsetLargeSize);
  2484.     unsigned        mask = 1 << (pos % bitsetLargeSize);
  2485.  
  2486.     assert(offs < cmpLargeBSsize);
  2487.  
  2488. #ifdef  DEBUG
  2489.     assert(bs.bsCheck == 0xBEEFCAFE);
  2490. #endif
  2491.  
  2492.     return  ((bs.bsLargeVal[offs] & mask) != 0);
  2493. }
  2494.  
  2495. void                compiler::cmpBS_bigCreate(  OUT bitset REF dst,
  2496.                                               IN    bitset REF src)
  2497. {
  2498.     cmpBS_bigCreate(dst);
  2499.     cmpBS_bigAssign(dst, src);
  2500. }
  2501.  
  2502. void                compiler::cmpBS_bigAssign(  OUT bitset REF dst,
  2503.                                               IN    bitset REF src)
  2504. {
  2505. //  printf("Copy      [%08X]  = [%08X]\n", &dst, &src);
  2506.  
  2507. #ifdef  DEBUG
  2508.     assert(src.bsCheck == 0xBEEFCAFE);
  2509.     assert(dst.bsCheck == 0xBEEFCAFE);
  2510. #endif
  2511.  
  2512.     memcpy(dst.bsLargeVal, src.bsLargeVal, cmpLargeBSsize);
  2513. }
  2514.  
  2515. void                compiler::cmpBS_bigUnion (INOUT bitset REF bs1,
  2516.                                               IN    bitset REF bs2)
  2517. {
  2518.     unsigned        i  = cmpLargeBSsize;
  2519.  
  2520.     BYTE    *       p1 = bs1.bsLargeVal;
  2521.     BYTE    *       p2 = bs2.bsLargeVal;
  2522.  
  2523. //  printf("Union     [%08X] |= [%08X]\n", &bs1, &bs2);
  2524.  
  2525. #ifdef  DEBUG
  2526.     assert(bs1.bsCheck == 0xBEEFCAFE);
  2527.     assert(bs2.bsCheck == 0xBEEFCAFE);
  2528. #endif
  2529.  
  2530.     do
  2531.     {
  2532.         *p1 |= *p2;
  2533.     }
  2534.     while (++p1, ++p2, --i);
  2535. }
  2536.  
  2537. void                compiler::cmpBS_bigIntsct(INOUT bitset REF bs1,
  2538.                                               IN    bitset REF bs2)
  2539. {
  2540.     unsigned        i  = cmpLargeBSsize;
  2541.  
  2542.     BYTE    *       p1 = bs1.bsLargeVal;
  2543.     BYTE    *       p2 = bs2.bsLargeVal;
  2544.  
  2545. //  printf("Intersect [%08X] |= [%08X]\n", &bs1, &bs2);
  2546.  
  2547. #ifdef  DEBUG
  2548.     assert(bs1.bsCheck == 0xBEEFCAFE);
  2549.     assert(bs2.bsCheck == 0xBEEFCAFE);
  2550. #endif
  2551.  
  2552.     do
  2553.     {
  2554.         *p1 &= *p2;
  2555.     }
  2556.     while (++p1, ++p2, --i);
  2557. }
  2558.  
  2559. /*****************************************************************************
  2560.  *
  2561.  *  Initialize/shut down the uninitialized variable use detection logic.
  2562.  */
  2563.  
  2564. void                compiler::cmpChkVarInitBeg(unsigned lclVarCnt, bool hadGoto)
  2565. {
  2566.     assert(cmpConfig.ccSafeMode || cmpConfig.ccChkUseDef);
  2567.  
  2568.     /* Initialize the bitset logic based on the local variable count */
  2569.  
  2570.     cmpBitSetInit(lclVarCnt);
  2571.  
  2572.     /* Record whether we have gotos (implies irreducible flow-graph) */
  2573.  
  2574.     cmpGotoPresent = hadGoto;
  2575.  
  2576.     /* Clear the "initialized" and "flagged" variable sets */
  2577.  
  2578.     cmpBitSetCreate(cmpVarsDefined);
  2579.     cmpBitSetCreate(cmpVarsFlagged);
  2580. }
  2581.  
  2582. void                compiler::cmpChkVarInitEnd()
  2583. {
  2584.     cmpBitSetDone  (cmpVarsDefined);
  2585.     cmpBitSetDone  (cmpVarsFlagged);
  2586. }
  2587.  
  2588. /*****************************************************************************
  2589.  *
  2590.  *  Check a condition expression for uninitialized variable use. The routine
  2591.  *  returns two definition sets: one gives the definition set for when the
  2592.  *  condition is true, the other one for when it's false.
  2593.  *
  2594.  *  If the caller is interested only in one of the sets, pass true for one
  2595.  *  of the 'skip' arguments and 'cmpVarsIgnore' for its bitset argument.
  2596.  */
  2597.  
  2598. void                compiler::cmpCheckUseCond(Tree expr, OUT bitset REF yesBS,
  2599.                                                          bool           yesSkip,
  2600.                                                          OUT bitset REF  noBS,
  2601.                                                          bool            noSkip)
  2602. {
  2603.     /* Check for one of the short-circuit operators */
  2604.  
  2605.     switch (expr->tnOper)
  2606.     {
  2607.     case TN_LOG_OR:
  2608.  
  2609.         /* The first  condition will always be evaluated */
  2610.  
  2611.         cmpCheckUseCond(expr->tnOp.tnOp1, yesBS,         false,
  2612.                                           cmpVarsIgnore, true);
  2613.  
  2614.         /* The second condition will be evaluated if the first one is false */
  2615.  
  2616.         cmpCheckUseCond(expr->tnOp.tnOp2, cmpVarsIgnore, true,
  2617.                                           noBS,          false);
  2618.  
  2619.         return;
  2620.  
  2621.     case TN_LOG_AND:
  2622.  
  2623.         /* The first  condition will always be evaluated */
  2624.  
  2625.         cmpCheckUseCond(expr->tnOp.tnOp1, cmpVarsIgnore, true,
  2626.                                           noBS,          false);
  2627.  
  2628.         /* The second condition will be evaluated if the first one is true  */
  2629.  
  2630.         cmpCheckUseCond(expr->tnOp.tnOp2, yesBS,         false,
  2631.                                           cmpVarsIgnore, true);
  2632.  
  2633.         return;
  2634.  
  2635.     default:
  2636.  
  2637.         /* Not a short-circuit operator: both sets will be the same */
  2638.  
  2639.         cmpChkVarInitExpr(expr);
  2640.  
  2641.         if  (!yesSkip) cmpBitSetCreate(yesBS, cmpVarsDefined);
  2642.         if  (! noSkip) cmpBitSetCreate( noBS, cmpVarsDefined);
  2643.  
  2644.         return;
  2645.     }
  2646. }
  2647.  
  2648. /*****************************************************************************
  2649.  *
  2650.  *  Check the given expression for variable use/def.
  2651.  */
  2652.  
  2653. void                compiler::cmpChkVarInitExprRec(Tree expr)
  2654. {
  2655.     treeOps         oper;
  2656.     unsigned        kind;
  2657.  
  2658. AGAIN:
  2659.  
  2660.     assert(expr);
  2661.  
  2662. #if!MGDDATA
  2663.     assert((int)expr != 0xDDDDDDDD && (int)expr != 0xCCCCCCCC);
  2664. #endif
  2665.  
  2666.     /* What kind of a node do we have? */
  2667.  
  2668.     oper = expr->tnOperGet ();
  2669.     kind = expr->tnOperKind();
  2670.  
  2671.     /* Is this a constant/leaf node? */
  2672.  
  2673.     if  (kind & (TNK_CONST|TNK_LEAF))
  2674.         return;
  2675.  
  2676.     /* Is it a 'simple' unary/binary operator? */
  2677.  
  2678.     if  (kind & TNK_SMPOP)
  2679.     {
  2680.         Tree            op1 = expr->tnOp.tnOp1;
  2681.         Tree            op2 = expr->tnOp.tnOp2;
  2682.  
  2683.         /* Make sure the flags are properly set */
  2684.  
  2685.         if  (kind & TNK_ASGOP)
  2686.         {
  2687.             assert((op2->tnFlags & TNF_ASG_DEST) == 0);
  2688.  
  2689.             /* Is this an assignment operator? */
  2690.  
  2691.             if  (oper == TN_ASG)
  2692.                 op1->tnFlags |=  TNF_ASG_DEST;
  2693.             else
  2694.                 op1->tnFlags &= ~TNF_ASG_DEST;
  2695.         }
  2696.  
  2697.         /* Is there a second operand? */
  2698.  
  2699.         if  (expr->tnOp.tnOp2)
  2700.         {
  2701.             if  (expr->tnOp.tnOp1)
  2702.             {
  2703.                 /* Special case: vararg-beg */
  2704.  
  2705.                 if  (oper == TN_VARARG_BEG)
  2706.                 {
  2707.                     Tree            arg1;
  2708.                     Tree            arg2;
  2709.  
  2710.                     assert(op1->tnOper == TN_LIST);
  2711.  
  2712.                     arg1 = op1->tnOp.tnOp1;
  2713.                     arg2 = op1->tnOp.tnOp2;
  2714.  
  2715.                     /* The first suboperand is the target variable */
  2716.  
  2717.                     assert(arg1->tnOper == TN_LCL_SYM);
  2718.  
  2719.                     arg1->tnFlags |=  TNF_ASG_DEST;
  2720.  
  2721.                     cmpChkVarInitExprRec(arg1);
  2722.                     cmpChkVarInitExprRec(arg2);
  2723.  
  2724.                     expr = op2;
  2725.                     goto AGAIN;
  2726.                 }
  2727.  
  2728.                 cmpChkVarInitExprRec(op1);
  2729.  
  2730.                 /* Special case: short-circuit operators */
  2731.  
  2732.                 if  (oper == TN_LOG_OR || oper == TN_LOG_AND)
  2733.                 {
  2734.                     bitset          tempBS;
  2735.  
  2736.                     /* Save the set after the first condition */
  2737.  
  2738.                     cmpBitSetCreate(tempBS, cmpVarsDefined);
  2739.  
  2740.                     /* Process the second condition */
  2741.  
  2742.                     cmpChkVarInitExprRec(op2);
  2743.  
  2744.                     /* Only the first condition is guaranteed to be evaluated */
  2745.  
  2746.                     cmpBitSetAssign(cmpVarsDefined, tempBS);
  2747.                     cmpBitSetDone(tempBS);
  2748.                     return;
  2749.                 }
  2750.             }
  2751.  
  2752.             expr = op2;
  2753.             goto AGAIN;
  2754.         }
  2755.  
  2756.         /* Special case: address of */
  2757.  
  2758.         if  (oper == TN_ADDROF)
  2759.         {
  2760.             if  (op1->tnOper == TN_LCL_SYM)
  2761.             {
  2762.                 op1->tnFlags |=  TNF_ASG_DEST;
  2763.                 cmpChkVarInitExprRec(op1);
  2764.                 op1->tnFlags &= ~TNF_ASG_DEST;
  2765.  
  2766.                 return;
  2767.             }
  2768.         }
  2769.  
  2770.         expr = op1;
  2771.         if  (expr)
  2772.             goto AGAIN;
  2773.  
  2774.         return;
  2775.     }
  2776.  
  2777.     /* See what kind of a special operator we have here */
  2778.  
  2779.     switch  (oper)
  2780.     {
  2781.         SymDef          sym;
  2782.  
  2783.     case TN_LCL_SYM:
  2784.  
  2785.         /* Get hold of the variable symbol and its index */
  2786.  
  2787.         sym = expr->tnLclSym.tnLclSym;
  2788.  
  2789.     CHK_INIT:
  2790.  
  2791.         assert(sym->sdSymKind == SYM_VAR);
  2792.  
  2793.         /* Check for initialization if necessary */
  2794.  
  2795.         if  (sym->sdVar.sdvChkInit)
  2796.         {
  2797.             unsigned        ind;
  2798.  
  2799.             assert(sym->sdVar.sdvLocal || (sym->sdIsMember && sym->sdIsSealed));
  2800.  
  2801.             /* Get hold of the variable's index */
  2802.  
  2803.             ind = sym->sdVar.sdvILindex;
  2804.  
  2805.             /* Is this a definition or use? */
  2806.  
  2807.             if  (expr->tnFlags & TNF_ASG_DEST)
  2808.             {
  2809.                 if  (sym->sdIsMember)
  2810.                 {
  2811.                     /* Static constants may only be assigned once */
  2812.  
  2813.                     if  (cmpBitSetRead(cmpVarsDefined, ind))
  2814.                         cmpErrorQnm(ERRdupMemInit, sym);
  2815.                 }
  2816.  
  2817.                 cmpBitSetWrite(cmpVarsDefined, ind, 1);
  2818.             }
  2819.             else
  2820.             {
  2821.                 /* Check the current 'def' bitset for this variable */
  2822.  
  2823.                 if  (cmpBitSetRead(cmpVarsDefined, ind))
  2824.                     return;
  2825.  
  2826.                 /* Don't issue a message if the symbol has already been flagged */
  2827.  
  2828.                 if  (!cmpBitSetRead(cmpVarsFlagged, ind) && !cmpGotoPresent)
  2829.                 {
  2830.                     cmpRecErrorPos(expr);
  2831.  
  2832.                     if      (cmpConfig.ccSafeMode || sym->sdType->tdIsManaged)
  2833.                         cmpGenError(ERRundefUse, sym->sdSpelling());
  2834.                     else
  2835.                         cmpGenWarn (WRNundefUse, sym->sdSpelling());
  2836.  
  2837.                     cmpBitSetWrite(cmpVarsFlagged, ind, 1);
  2838.                 }
  2839.             }
  2840.         }
  2841.  
  2842.         break;
  2843.  
  2844.     case TN_FNC_SYM:
  2845.  
  2846.         if  (expr->tnFncSym.tnFncObj)
  2847.             cmpChkVarInitExprRec(expr->tnFncSym.tnFncObj);
  2848.  
  2849.         if  (expr->tnFncSym.tnFncArgs)
  2850.         {
  2851.             Tree            args = expr->tnFncSym.tnFncArgs;
  2852.  
  2853.             do
  2854.             {
  2855.                 Tree            argx;
  2856.  
  2857.                 /* Get hold of the next argument value */
  2858.  
  2859.                 assert(args->tnOper == TN_LIST);
  2860.                 argx = args->tnOp.tnOp1;
  2861.  
  2862.                 /* Is this an "out" argument? */
  2863.  
  2864.                 if  (argx->tnOper == TN_ADDROF && (argx->tnFlags & TNF_ADR_OUTARG))
  2865.                 {
  2866.                     /* Mark the argument as assignment target */
  2867.  
  2868.                     argx->tnOp.tnOp1->tnFlags |= TNF_ASG_DEST;
  2869.                 }
  2870.  
  2871.                 /* Check the expression */
  2872.  
  2873.                 cmpChkVarInitExprRec(argx);
  2874.  
  2875.                 /* Move to the next argument, if any */
  2876.  
  2877.                 args = args->tnOp.tnOp2;
  2878.             }
  2879.             while (args);
  2880.         }
  2881.         break;
  2882.  
  2883.     case TN_VAR_SYM:
  2884.  
  2885.         /* Process the instance pointer, if any */
  2886.  
  2887.         if  (expr->tnVarSym.tnVarObj)
  2888.         {
  2889.             assert(expr->tnLclSym.tnLclSym->sdVar.sdvChkInit == false);
  2890.  
  2891.             expr = expr->tnVarSym.tnVarObj;
  2892.             goto AGAIN;
  2893.         }
  2894.  
  2895.         /* Get hold of the member symbol and check initialization */
  2896.  
  2897.         sym = expr->tnLclSym.tnLclSym;
  2898.         goto CHK_INIT;
  2899.  
  2900.     case TN_BFM_SYM:
  2901.         expr = expr->tnBitFld.tnBFinst; assert(expr);
  2902.         goto AGAIN;
  2903.  
  2904.     case TN_FNC_PTR:
  2905.     case TN_ERROR:
  2906.     case TN_NONE:
  2907.         break;
  2908.  
  2909.     default:
  2910. #ifdef DEBUG
  2911.         cmpParser->parseDispTree(expr);
  2912. #endif
  2913.         assert(!"invalid/unhandled expression node");
  2914.     }
  2915. }
  2916.  
  2917. /*****************************************************************************
  2918.  *
  2919.  *  We're exiting a static constructor, make sure all the right members have
  2920.  *  been initialized.
  2921.  */
  2922.  
  2923. void                compiler::cmpChkMemInits()
  2924. {
  2925.     SymDef          memSym;
  2926.  
  2927.     assert(cmpCurFncSym->sdFnc.sdfCtor);
  2928.     assert(cmpCurFncSym->sdIsStatic);
  2929.  
  2930.     for (memSym = cmpCurFncSym->sdParent->sdScope.sdScope.sdsChildList;
  2931.          memSym;
  2932.          memSym = memSym->sdNextInScope)
  2933.     {
  2934.         if  (memSym->sdSymKind == SYM_VAR &&
  2935.              memSym->sdIsSealed           &&
  2936.              memSym->sdIsStatic           &&
  2937.              memSym->sdVar.sdvChkInit)
  2938.         {
  2939.             if  (!cmpBitSetRead(cmpVarsDefined, memSym->sdVar.sdvILindex))
  2940.             {
  2941.                 if  (cmpCurFncSym->sdIsImplicit)
  2942.                     cmpSetSrcPos(memSym);
  2943.  
  2944.                 cmpErrorQnm(ERRnoVarInit, memSym);
  2945.             }
  2946.         }
  2947.     }
  2948. }
  2949.  
  2950. /*****************************************************************************
  2951.  *
  2952.  *  We're compiling a constructor, see if there are any member initializers
  2953.  *  we need to add to its body.
  2954.  */
  2955.  
  2956. void                compiler::cmpAddCTinits()
  2957. {
  2958.     Scanner         ourScanner;
  2959.     SymDef          memSym;
  2960.  
  2961.     SymDef          fncSym = cmpCurFncSym; assert(fncSym->sdFnc.sdfCtor);
  2962.  
  2963.     bool            isStat = fncSym->sdIsStatic;
  2964.     SymDef          clsSym = fncSym->sdParent;
  2965.  
  2966.     assert(clsSym->sdSymKind == SYM_CLASS);
  2967.  
  2968.     /* We better make sure this only happens at most one time */
  2969.  
  2970. #ifndef NDEBUG
  2971.     assert(cmpDidCTinits == false); cmpDidCTinits = true;
  2972. #endif
  2973.  
  2974.     /* Is this an unmanaged class? */
  2975.  
  2976.     if  (!clsSym->sdIsManaged)
  2977.     {
  2978.         /* Does the class have any virtual functions ? */
  2979.  
  2980.         if  (clsSym->sdClass.sdcHasVptr)
  2981.         {
  2982.             SymDef          vtabSym;
  2983.             Tree            vtabExp;
  2984.             Tree            vtabAdr;
  2985.  
  2986.             vtabSym = clsSym->sdClass.sdcVtableSym;
  2987.  
  2988.             if  (!vtabSym)
  2989.             {
  2990.                 SymList             list;
  2991.  
  2992.                 /* Declare the vtable variable */
  2993.  
  2994.                 vtabSym = cmpGlobalST->stDeclareSym(cmpGlobalHT->tokenToIdent(tkVIRTUAL),
  2995.                                                     SYM_VAR,
  2996.                                                     NS_HIDE,
  2997.                                                     clsSym);
  2998.  
  2999.                 vtabSym->sdVar.sdvIsVtable = true;
  3000.                 vtabSym->sdType            = cmpTypeVoid;
  3001.                 vtabSym->sdAccessLevel     = ACL_DEFAULT;
  3002.  
  3003.                 /* Record the vtable, we'll generate its contents later */
  3004.  
  3005. #if MGDDATA
  3006.                 list = new SymList;
  3007. #else
  3008.                 list =    (SymList)cmpAllocPerm.nraAlloc(sizeof(*list));
  3009. #endif
  3010.  
  3011.                 list->slSym  = vtabSym;
  3012.                 list->slNext = cmpVtableList;
  3013.                                cmpVtableList = list;
  3014.  
  3015.                 cmpVtableCount++;
  3016.  
  3017.                 /* Remember the vtable symbol, we might need it again */
  3018.  
  3019.                 clsSym->sdClass.sdcVtableSym = vtabSym;
  3020.             }
  3021.  
  3022.             assert(vtabSym);
  3023.             assert(vtabSym->sdSymKind == SYM_VAR);
  3024.             assert(vtabSym->sdVar.sdvIsVtable);
  3025.  
  3026.             /* Assign the vtable pointer value: "*[this+offs] = &vtable" */
  3027.  
  3028.             vtabExp = cmpThisRef();
  3029.  
  3030.             /* Add the vptr offset if there is a base with no vptrs */
  3031.  
  3032.             if  (clsSym->sdClass.sdc1stVptr &&
  3033.                  clsSym->sdType->tdClass.tdcBase)
  3034.             {
  3035.                 TypDef          baseCls;
  3036.                 Tree            offsExp;
  3037.  
  3038.                 baseCls = clsSym->sdType->tdClass.tdcBase;
  3039.  
  3040.                 assert(baseCls->tdTypeKind == TYP_CLASS);
  3041.  
  3042.                 offsExp = cmpCreateIconNode(NULL, baseCls->tdClass.tdcSize, TYP_UINT);
  3043.                 vtabExp = cmpCreateExprNode(NULL, TN_ADD, vtabExp->tnType, vtabExp,
  3044.                                                                            offsExp);
  3045.  
  3046.             }
  3047.  
  3048.             /* Deref the "[this+vptroffs]" expression */
  3049.  
  3050.             vtabExp = cmpCreateExprNode(NULL, TN_IND, cmpTypeVoidPtr, vtabExp, NULL);
  3051.  
  3052.             /* Take the address of the vtable variable */
  3053.  
  3054.             vtabAdr = cmpCreateExprNode(NULL, TN_VAR_SYM, cmpTypeVoid);
  3055.  
  3056.             vtabAdr->tnVarSym.tnVarSym = vtabSym;
  3057.             vtabAdr->tnVarSym.tnVarObj = NULL;
  3058.  
  3059.             vtabAdr = cmpCreateExprNode(NULL, TN_ADDROF, cmpTypeVoidPtr, vtabAdr, NULL);
  3060.  
  3061.             /* Assign the address of the vtable to the vptr member */
  3062.  
  3063.             vtabExp = cmpCreateExprNode(NULL, TN_ASG, cmpTypeVoidPtr, vtabExp, vtabAdr);
  3064.  
  3065.             cmpILgen->genExpr(vtabExp, false);
  3066.         }
  3067.     }
  3068.  
  3069.     /* Does the class have any initializers that apply to this ctor? */
  3070.  
  3071.     if  (isStat)
  3072.     {
  3073.         if  (!clsSym->sdClass.sdcStatInit)
  3074.             return;
  3075.     }
  3076.     else
  3077.     {
  3078.         if  (!clsSym->sdClass.sdcInstInit)
  3079.             return;
  3080.     }
  3081.  
  3082.     /* Walk the members looking for initializers to add to the ctor */
  3083.  
  3084.     ourScanner = cmpScanner;
  3085.  
  3086.     for (memSym = clsSym->sdScope.sdScope.sdsChildList;
  3087.          memSym;
  3088.          memSym = memSym->sdNextInScope)
  3089.     {
  3090.         if  (memSym->sdSymKind != SYM_VAR)
  3091.             continue;
  3092.  
  3093.         /* Is it the right kind of a symbol? */
  3094.  
  3095.         if  ((bool)memSym->sdIsStatic != isStat)
  3096.             continue;
  3097.  
  3098. //      if  (!strcmp(fncSym->          sdSpelling(), "static") &&
  3099. //           !strcmp(fncSym->sdParent->sdSpelling(), "PermissionToken")) forceDebugBreak();
  3100.  
  3101.         /* Does this member have an initializer? */
  3102.  
  3103.         if  (memSym->sdSrcDefList)
  3104.         {
  3105.             Tree            init;
  3106.             Tree            expr;
  3107.             parserState     save;
  3108.  
  3109.             ExtList         memInit;
  3110.             TypDef          memType;
  3111.  
  3112.             /* Get hold of the initializer definition descriptor */
  3113.  
  3114.             memInit = (ExtList)memSym->sdSrcDefList;
  3115.  
  3116.             assert(memInit->dlExtended);
  3117.             assert(memInit->mlSym == memSym);
  3118.  
  3119.             memType = memSym->sdType;
  3120.  
  3121.             /* Prepare the initializer assignment expression */
  3122.  
  3123.             init = cmpCreateExprNode(NULL, TN_VAR_SYM, memType);
  3124.  
  3125.             init->tnVarSym.tnVarObj = isStat ? NULL : cmpThisRef();
  3126.             init->tnVarSym.tnVarSym = memSym;
  3127.  
  3128.             /* Prepare to parse the initializer */
  3129.  
  3130.             cmpParser->parsePrepText(&memInit->dlDef, memInit->dlComp, save);
  3131.  
  3132.             /* Is this an array initializer? */
  3133.  
  3134.             if  (ourScanner->scanTok.tok == tkLCurly)
  3135.             {
  3136.                 expr = cmpBindArrayExpr(memType);
  3137.                 expr = cmpCreateExprNode(NULL, TN_NEW , memType, expr);
  3138.             }
  3139.             else
  3140.             {
  3141.                 expr = cmpParser->parseExprComma();
  3142.                 expr = cmpBindExpr(expr);
  3143.             }
  3144.  
  3145.             /* Make sure the expression terminated properly */
  3146.  
  3147.             if  (ourScanner->scanTok.tok != tkComma &&
  3148.                  ourScanner->scanTok.tok != tkSColon)
  3149.             {
  3150.                 cmpError(ERRnoEOX);
  3151.             }
  3152.  
  3153.             /* Coerce the value to the right type and assign it */
  3154.  
  3155.             expr = cmpCastOfExpr(expr, memSym->sdType, false);
  3156.             init = cmpCreateExprNode(NULL, TN_ASG , memType, init, expr);
  3157.  
  3158.             cmpILgen->genExpr(init, false);
  3159.  
  3160.             cmpParser->parseDoneText(save);
  3161.         }
  3162.     }
  3163. }
  3164.  
  3165. /*****************************************************************************
  3166.  *
  3167.  *  Process the given list of local variable declarations.
  3168.  *
  3169.  *  IMPORTANT:  It is the caller's responsibility to preserve the value of
  3170.  *              'cmpCurScp' when calling this routine!
  3171.  */
  3172.  
  3173. SymDef              compiler::cmpBlockDecl(Tree block, bool outer,
  3174.                                                        bool genDecl,
  3175.                                                        bool isCatch)
  3176. {
  3177.     SymTab          ourStab = cmpGlobalST;
  3178.  
  3179.     ArgDef          argList = NULL;
  3180.  
  3181.     SymDef          blockScp;
  3182.     Tree            blockLst;
  3183.  
  3184.     assert(block || outer);
  3185.  
  3186.     /* Create a scope symbol for the block */
  3187.  
  3188.     cmpCurScp = blockScp = ourStab->stDeclareLcl(NULL,
  3189.                                                  SYM_SCOPE,
  3190.                                                  NS_HIDE,
  3191.                                                  cmpCurScp,
  3192.                                                  &cmpAllocCGen);
  3193.  
  3194.     if  (cmpConfig.ccGenDebug && !cmpCurFncSym->sdIsImplicit
  3195.                               && !(block->tnFlags & TNF_BLK_NUSER))
  3196.     {
  3197.         unsigned        scopeId;
  3198.  
  3199.         /* For debug info, open a new lexical scope */
  3200.  
  3201.         if (cmpSymWriter->OpenScope(0, &scopeId))
  3202.             cmpGenFatal(ERRdebugInfo);
  3203.  
  3204.         cmpCurScp->sdScope.sdSWscopeId  = scopeId;
  3205.         cmpCurScp->sdScope.sdBegBlkAddr = cmpILgen->genBuffCurAddr();
  3206.         cmpCurScp->sdScope.sdBegBlkOffs = cmpILgen->genBuffCurOffs();
  3207.     }
  3208.  
  3209.     assert(block->tnOper == TN_BLOCK); blockLst = block->tnBlock.tnBlkDecl;
  3210.  
  3211.     /* Record the outermost function scope when we create it */
  3212.  
  3213.     if  (outer)
  3214.     {
  3215.         assert(cmpCurFncTyp->tdTypeKind == TYP_FNC);
  3216.  
  3217.         /* Get hold of the function argument list */
  3218.  
  3219.         argList = cmpCurFncTyp->tdFnc.tdfArgs.adArgs;
  3220.  
  3221.         /* Is this a non-static member function? */
  3222.  
  3223.         if  (cmpCurFncSym->sdIsMember && !cmpCurFncSym->sdIsStatic)
  3224.         {
  3225.             SymDef          thisSym;
  3226.             SymDef           clsSym;
  3227.             TypDef           clsTyp;
  3228.  
  3229.             /* Get hold of the class type */
  3230.  
  3231.             clsSym = cmpCurFncSym->sdParent;
  3232.             assert(clsSym->sdSymKind  == SYM_CLASS);
  3233.             clsTyp = clsSym->sdType;
  3234.             assert(clsTyp->tdTypeKind == TYP_CLASS);
  3235.  
  3236.             /* Declare the "this" argument */
  3237.  
  3238.             thisSym = ourStab->stDeclareLcl(cmpGlobalHT->tokenToIdent(tkTHIS),
  3239.                                             SYM_VAR,
  3240.                                             NS_NORM,
  3241.                                             blockScp,
  3242.                                             &cmpAllocCGen);
  3243.  
  3244.             thisSym->sdCompileState    = CS_DECLARED;
  3245.             thisSym->sdAccessLevel     = ACL_PUBLIC;
  3246.             thisSym->sdType            = clsTyp->tdClass.tdcRefTyp;
  3247.             thisSym->sdVar.sdvLocal    = true;
  3248.             thisSym->sdVar.sdvArgument = true;
  3249.             thisSym->sdVar.sdvILindex  = cmpILgen->genNextArgNum();
  3250.  
  3251.             /* Tell everyone else where to find the "this" argument symbol */
  3252.  
  3253.             cmpThisSym = thisSym;
  3254.  
  3255.             /* Are we supposed to (implicitly) call a base class constructor? */
  3256.  
  3257.             if  (cmpBaseCTcall)
  3258.             {
  3259.                 Tree            baseCall;
  3260.  
  3261.                 assert(cmpCurFncSym->sdFnc.sdfCtor);
  3262.  
  3263.                 SymDef          clsSym = cmpCurFncSym->sdParent;
  3264.  
  3265.                 assert(clsSym->sdSymKind == SYM_CLASS);
  3266.                 assert(clsSym->sdType->tdClass.tdcBase);
  3267.  
  3268.                 baseCall = cmpCallCtor(clsSym->sdType->tdClass.tdcBase, NULL);
  3269.                 if  (baseCall && baseCall->tnOper != TN_ERROR)
  3270.                 {
  3271.                     assert(baseCall->tnOper == TN_NEW);
  3272.                     baseCall = baseCall->tnOp.tnOp1;
  3273.                     assert(baseCall->tnOper == TN_FNC_SYM);
  3274.                     baseCall->tnFncSym.tnFncObj = cmpThisRef();
  3275.  
  3276.                     cmpILgen->genExpr(baseCall, false);
  3277.                 }
  3278.             }
  3279.         }
  3280.         else
  3281.             cmpThisSym = NULL;
  3282.     }
  3283.  
  3284.     /* Declare all the local symbols contained in the block */
  3285.  
  3286.     while (blockLst)
  3287.     {
  3288.         Tree            info;
  3289.         Ident           name;
  3290.         SymDef          localSym;
  3291.         Tree            blockDcl;
  3292.  
  3293.         /* Grab the next declaration entry */
  3294.  
  3295.         blockDcl = blockLst;
  3296.  
  3297.         if  (blockDcl->tnOper == TN_LIST)
  3298.             blockDcl = blockDcl->tnOp.tnOp1;
  3299.  
  3300.         assert(blockDcl->tnOper == TN_VAR_DECL);
  3301.  
  3302.         info = blockDcl->tnDcl.tnDclInfo;
  3303.         if  (blockDcl->tnFlags & TNF_VAR_INIT)
  3304.         {
  3305.             assert(info->tnOper == TN_LIST);
  3306.             info = info->tnOp.tnOp1;
  3307.         }
  3308.  
  3309.         assert(info->tnOper == TN_NAME); name = info->tnName.tnNameId;
  3310.  
  3311.         /* If there was a redefinition, we shouldn't have made it here */
  3312.  
  3313.         assert(name == NULL || ourStab->stLookupLclSym(name, blockScp) == NULL);
  3314.  
  3315.         /* Is this a static variable? */
  3316.  
  3317.         if  (blockDcl->tnFlags & TNF_VAR_STATIC)
  3318.         {
  3319.             SymList         list;
  3320.  
  3321.             /* Declare the symbol, making sure it sticks around */
  3322.  
  3323.             localSym = ourStab->stDeclareLcl(name,
  3324.                                              SYM_VAR,
  3325.                                              NS_NORM,
  3326.                                              blockScp,
  3327.                                              &cmpAllocPerm);
  3328.  
  3329.             localSym->sdIsStatic = true;
  3330.  
  3331.             /* Add it to the list of local statics */
  3332.  
  3333. #if MGDDATA
  3334.             list = new SymList;
  3335. #else
  3336.             list =    (SymList)cmpAllocCGen.nraAlloc(sizeof(*list));
  3337. #endif
  3338.  
  3339.             list->slSym  = localSym;
  3340.             list->slNext = cmpLclStatListT;
  3341.                            cmpLclStatListT = list;
  3342.         }
  3343.         else
  3344.         {
  3345.             /* Declare the local variable symbol */
  3346.  
  3347.             localSym = ourStab->stDeclareLcl(name,
  3348.                                              SYM_VAR,
  3349.                                              NS_NORM,
  3350.                                              blockScp,
  3351.                                              &cmpAllocCGen);
  3352.  
  3353.             localSym->sdVar.sdvLocal = true;
  3354.  
  3355.             /* Is this a local constant? */
  3356.  
  3357.             if  (blockDcl->tnFlags & TNF_VAR_CONST)
  3358.                 localSym->sdVar.sdvConst = true;
  3359.         }
  3360.  
  3361.         localSym->sdCompileState = CS_KNOWN;
  3362.         localSym->sdAccessLevel  = ACL_PUBLIC;
  3363.  
  3364. #ifdef  DEBUG
  3365.         if  (!(blockDcl->tnFlags & TNF_VAR_ARG)) localSym->sdType = NULL;
  3366. #endif
  3367.  
  3368. //      printf("Pre-dcl local  [%08X] '%s'\n", localSym, cmpGlobalST->stTypeName(NULL, localSym, NULL, NULL, false));
  3369.  
  3370.         /* Save the symbol reference in the declaration node */
  3371.  
  3372.         blockDcl->tnDcl.tnDclSym = localSym; assert(localSym->sdIsDefined == false);
  3373.  
  3374.         /* Mark the symbol as argument / local var and assign it an index */
  3375.  
  3376.         if  (blockDcl->tnFlags & TNF_VAR_ARG)
  3377.         {
  3378.             /* Check and set the type of the argument */
  3379.  
  3380.             cmpBindType(blockDcl->tnType, false, false);
  3381.  
  3382.             localSym->sdType            = blockDcl->tnType;
  3383.             localSym->sdCompileState    = CS_DECLARED;
  3384.             localSym->sdVar.sdvArgument = true;
  3385.  
  3386. #ifdef  OLD_IL
  3387.             if  (!cmpConfig.ccOILgen)
  3388. #endif
  3389.             localSym->sdVar.sdvILindex  = cmpILgen->genNextArgNum();
  3390.  
  3391.             /* Is this a "byref" argument? */
  3392.  
  3393.             assert(outer);
  3394.             assert(argList);
  3395.             assert(argList->adName == localSym->sdName);
  3396.  
  3397.             if  (cmpCurFncTyp->tdFnc.tdfArgs.adExtRec)
  3398.             {
  3399.                 unsigned        argFlags;
  3400.  
  3401.                 assert(argList->adIsExt);
  3402.  
  3403.                 argFlags = ((ArgExt)argList)->adFlags;
  3404.  
  3405.                 if      (argFlags & (ARGF_MODE_OUT|ARGF_MODE_INOUT))
  3406.                     localSym->sdVar.sdvMgdByRef = true;
  3407.                 else if (argFlags & (ARGF_MODE_REF))
  3408.                     localSym->sdVar.sdvUmgByRef = true;
  3409.             }
  3410.  
  3411.             argList = argList->adNext;
  3412.         }
  3413.         else if (!localSym->sdIsStatic && !localSym->sdVar.sdvConst)
  3414.         {
  3415.             if  (localSym->sdIsImplicit)
  3416.             {
  3417. #ifndef NDEBUG
  3418.                 localSym->sdVar.sdvILindex = (unsigned)-1;
  3419. #endif
  3420.             }
  3421.             else
  3422.                 localSym->sdVar.sdvILindex = cmpILgen->genNextLclNum();
  3423.  
  3424.             /* Is this a 'catch' exception handler? */
  3425.  
  3426.             if  (isCatch)
  3427.             {
  3428.                 /* This is the start of a 'catch' - save the caught object */
  3429.  
  3430.                 cmpILgen->genCatchBeg(localSym);
  3431.  
  3432.                 /* Mark the symbol appropriately */
  3433.  
  3434.                 localSym->sdVar.sdvCatchArg = true;
  3435.  
  3436.                 /* Only do this for the very first local variable */
  3437.  
  3438.                 isCatch = false;
  3439.             }
  3440.         }
  3441. #ifdef  DEBUG
  3442.         else
  3443.         {
  3444.             localSym->sdVar.sdvILindex = 0xBEEF;    // to detect improper use
  3445.         }
  3446. #endif
  3447.  
  3448.         /* If this is a "for" loop scope, process the declaration fully */
  3449.  
  3450.         if  (block->tnFlags & TNF_BLK_FOR)
  3451.             cmpStmt(blockDcl);
  3452.  
  3453.         /* Locate the next declaration entry */
  3454.  
  3455.         blockLst = blockLst->tnDcl.tnDclNext;
  3456.     }
  3457.  
  3458.     /* Return the scope we've created */
  3459.  
  3460.     return  blockScp;
  3461. }
  3462.  
  3463. /*****************************************************************************
  3464.  *
  3465.  *  Compile and generate code for the given block of statements.
  3466.  */
  3467.  
  3468. SymDef              compiler::cmpBlock(Tree block, bool outer)
  3469. {
  3470.     Tree            stmt;
  3471.  
  3472.     SymTab          stab     = cmpGlobalST;
  3473.     SymDef          outerScp = cmpCurScp;
  3474.     SymDef          blockScp = NULL;
  3475.  
  3476.     assert(block);
  3477.  
  3478.     if  (block->tnOper == TN_ERROR)
  3479.         goto EXIT;
  3480.  
  3481.     assert(block->tnOper == TN_BLOCK);
  3482.  
  3483.     /* Are there any local variables / arguments in this scope? */
  3484.  
  3485.     if  (block->tnBlock.tnBlkDecl || outer)
  3486.     {
  3487.         blockScp = cmpBlockDecl(block,
  3488.                                 outer,
  3489.                                 false,
  3490.                                 (block->tnFlags & TNF_BLK_CATCH) != 0);
  3491.  
  3492. #ifdef  OLD_IL
  3493.         if  (cmpConfig.ccOILgen) cmpOIgen->GOIgenFncEnt(blockScp, outer);
  3494. #endif
  3495.  
  3496.         /*
  3497.             If this is a constructor and there was no call to a ctor
  3498.             of the same class or a base class (or this is a class that
  3499.             has no base class, such as Object or a value type), we'll
  3500.             insert any member initializers at the ctor's beginning.
  3501.          */
  3502.  
  3503.         if  (outer && cmpCurFncSym->sdFnc.sdfCtor)
  3504.         {
  3505.             if  (cmpCurFncSym->sdIsStatic || cmpBaseCTcall)
  3506.             {
  3507.                 cmpAddCTinits();
  3508.             }
  3509.             else
  3510.             {
  3511.                 TypDef          clsTyp = cmpCurFncSym->sdParent->sdType;
  3512.  
  3513.                 if  (clsTyp->tdClass.tdcValueType || !clsTyp->tdClass.tdcBase)
  3514.                     cmpAddCTinits();
  3515.             }
  3516.         }
  3517.     }
  3518.  
  3519.     /* Now process all the statements/declarations in the block */
  3520.  
  3521.     for (stmt = block->tnBlock.tnBlkStmt; stmt; stmt = stmt->tnOp.tnOp2)
  3522.     {
  3523.         Tree            ones;
  3524.  
  3525.         assert(stmt->tnOper == TN_LIST);
  3526.         ones = stmt->tnOp.tnOp1;
  3527.  
  3528.         while (ones->tnOper == TN_LIST)
  3529.         {
  3530.             cmpStmt(ones->tnOp.tnOp1);
  3531.             ones =  ones->tnOp.tnOp2;
  3532.  
  3533.             if  (!ones)
  3534.                 goto NXTS;
  3535.         }
  3536.  
  3537.         cmpStmt(ones);
  3538.  
  3539.     NXTS:;
  3540.  
  3541.     }
  3542.  
  3543.     /* For debug info, close a lexical scope if one was opened */
  3544.  
  3545.     if  (cmpConfig.ccGenDebug && cmpCurScp != outerScp
  3546.                               && cmpCurFncSym->sdIsImplicit == false)
  3547.     {
  3548.         if  (cmpSymWriter->CloseScope(0))
  3549.             cmpGenFatal(ERRdebugInfo);
  3550.  
  3551.         cmpCurScp->sdScope.sdEndBlkAddr = cmpILgen->genBuffCurAddr();
  3552.         cmpCurScp->sdScope.sdEndBlkOffs = cmpILgen->genBuffCurOffs();
  3553.     }
  3554.  
  3555. EXIT:
  3556.  
  3557.     /* Make sure we restore the previous scope */
  3558.  
  3559.     cmpCurScp = outerScp;
  3560.  
  3561.     /* Return the scope we've created */
  3562.  
  3563.     return  blockScp;
  3564. }
  3565.  
  3566. /*****************************************************************************
  3567.  *
  3568.  *  Generate IL for a function - start.
  3569.  */
  3570.  
  3571. SymDef              compiler::cmpGenFNbodyBeg(SymDef    fncSym,
  3572.                                               Tree      body,
  3573.                                               bool      hadGoto,
  3574.                                               unsigned  lclVarCnt)
  3575. {
  3576.     TypDef          fncTyp;
  3577.     SymDef          fncScp;
  3578.  
  3579.     assert(cmpCurScp == NULL);
  3580.  
  3581.     /* Get hold of the function type and make sure it looks OK */
  3582.  
  3583.     assert(fncSym && fncSym->sdSymKind  == SYM_FNC);
  3584.     fncTyp = fncSym->sdType;
  3585.     assert(fncTyp && fncTyp->tdTypeKind == TYP_FNC);
  3586.  
  3587.     /* Make the function symbol and type available to everyone */
  3588.  
  3589.     cmpCurFncSym   = fncSym;
  3590.     cmpCurFncTyp   = fncTyp;
  3591.     cmpCurFncRtp   = cmpActualType(fncTyp->tdFnc.tdfRett);
  3592.     cmpCurFncRvt   = cmpCurFncRtp->tdTypeKindGet();
  3593.  
  3594.     /* We don't have any local static variables yet */
  3595.  
  3596.     cmpLclStatListT = NULL;
  3597.  
  3598.     /* We haven't had any returns out of try/catch */
  3599.  
  3600.     cmpLeaveLab    = NULL;
  3601.     cmpLeaveTmp    = NULL;
  3602.  
  3603.     cmpInTryBlk    = 0;
  3604.     cmpInHndBlk    = 0;
  3605.  
  3606.     /* We haven't initialized any instance members */
  3607.  
  3608. #ifndef NDEBUG
  3609.     cmpDidCTinits  = false;
  3610. #endif
  3611.  
  3612.     /* Do we need to check for uninitialized variable use? */
  3613.  
  3614.     cmpLclVarCnt   = lclVarCnt;
  3615.     cmpChkVarInit  = false;
  3616.     cmpChkMemInit  = false;
  3617.  
  3618.     if  (cmpConfig.ccSafeMode || cmpConfig.ccChkUseDef)
  3619.         cmpChkVarInit = true;
  3620.  
  3621.     /* Static ctors have to init all constant members */
  3622.  
  3623.     if  (fncSym->sdFnc.sdfCtor && fncSym->sdIsStatic)
  3624.     {
  3625.         /* Track any uninitialized constant static members */
  3626.  
  3627.         SymDef          memSym;
  3628.  
  3629.         for (memSym = fncSym->sdParent->sdScope.sdScope.sdsChildList;
  3630.              memSym;
  3631.              memSym = memSym->sdNextInScope)
  3632.         {
  3633.             if  (memSym->sdSymKind == SYM_VAR &&
  3634.                  memSym->sdIsSealed           &&
  3635.                  memSym->sdIsStatic           && !memSym->sdVar.sdvHadInit)
  3636.             {
  3637.                 /* We'll have to track this sucker's initialization state */
  3638.  
  3639.                 memSym->sdVar.sdvILindex = lclVarCnt++;
  3640.  
  3641. //              if  (!strcmp(memSym->sdSpelling(), "DaysToMonth365")) forceDebugBreak();
  3642.  
  3643.                 /* Allow assignment to the variable in the ctor body */
  3644.  
  3645.                 memSym->sdVar.sdvHadInit = true;
  3646.                 memSym->sdVar.sdvCanInit = true;
  3647.                 memSym->sdVar.sdvChkInit = true;
  3648.  
  3649.                 /* We'll definitely need to track initializions */
  3650.  
  3651.                 cmpChkVarInit = true;
  3652.                 cmpChkMemInit = true;
  3653.             }
  3654.         }
  3655.     }
  3656.  
  3657.     /* Start up the initialization checking logic if necessary */
  3658.  
  3659.     if  (cmpChkVarInit)
  3660.         cmpChkVarInitBeg(lclVarCnt, hadGoto);
  3661.  
  3662.     /* Get the statement list started */
  3663.  
  3664.     cmpStmtLast.snStmtExpr = NULL;
  3665.     cmpStmtLast.snStmtKind = TN_NONE;
  3666.     cmpStmtLast.snLabel    = NULL;
  3667.     cmpStmtLast.snLabCont  = NULL;
  3668.     cmpStmtLast.snLabBreak = NULL;
  3669.     cmpStmtLast.snOuter    = NULL;
  3670.  
  3671.     cmpStmtNest            = &cmpStmtLast;
  3672.  
  3673. //  printf("\nGen IL for '%s'\n", fncSym->sdSpelling());
  3674. //  if  (!strcmp(fncSym->sdSpelling(), "")) forceDebugBreak();
  3675.  
  3676. #ifdef DEBUG
  3677.  
  3678.     if  (cmpConfig.ccVerbose >= 4)
  3679.     {
  3680.         printf("Compile function body:\n");
  3681.         cmpParser->parseDispTree(body);
  3682.     }
  3683. #endif
  3684.  
  3685. #ifdef  OLD_IL
  3686.     if  (cmpConfig.ccOILgen) cmpOIgen->GOIgenFncBeg(fncSym, cmpCurFncSrcBeg);
  3687. #endif
  3688.  
  3689.     /* The entry point of the function is always reachable */
  3690.  
  3691.     cmpStmtReachable = true;
  3692.  
  3693.     /* Compile and generate code for the function body */
  3694.  
  3695.     fncScp = cmpBlock(body, true);
  3696.  
  3697.     /* Make sure someone didn't leave a statement entry in the list */
  3698.  
  3699.     assert(cmpStmtNest == &cmpStmtLast);
  3700.  
  3701.     /* Make sure we didn't lose track of try/catch blocks */
  3702.  
  3703.     assert(cmpInTryBlk == 0);
  3704.     assert(cmpInHndBlk == 0);
  3705.  
  3706. #ifndef NDEBUG
  3707.  
  3708.     /* Make sure the right thing happened with instance members */
  3709.  
  3710.     bool            shouldHaveInitializedMembers = false;
  3711.  
  3712.     /*
  3713.         Constructors should always initialize any members with initializers,
  3714.         the only exception is when there is an explicit call to another ctor
  3715.         within the same class.
  3716.      */
  3717.  
  3718.     if  (fncSym->sdFnc.sdfCtor)
  3719.     {
  3720.         if  (fncSym->sdIsStatic || !cmpThisCTcall)
  3721.         {
  3722.             shouldHaveInitializedMembers = true;
  3723.         }
  3724.         else
  3725.         {
  3726.             TypDef          clsTyp = fncSym->sdParent->sdType;
  3727.  
  3728.             if  (clsTyp->tdClass.tdcValueType || !clsTyp->tdClass.tdcBase)
  3729.                 shouldHaveInitializedMembers = true;
  3730.         }
  3731.     }
  3732.  
  3733.     assert(cmpDidCTinits == shouldHaveInitializedMembers);
  3734.  
  3735. #endif
  3736.  
  3737.     /* Do we need to add a return statement? */
  3738.  
  3739.     if  (cmpStmtReachable)
  3740.     {
  3741.         if  (cmpCurFncRvt == TYP_VOID || cmpCurFncSym->sdFnc.sdfCtor)
  3742.         {
  3743.             if  (cmpChkMemInit)
  3744.                 cmpChkMemInits();
  3745.  
  3746. #ifdef  OLD_IL
  3747.             if  (cmpConfig.ccOILgen)
  3748.                 cmpOIgen->GOIstmtRet(NULL);
  3749.             else
  3750. #endif
  3751.                 cmpILgen->genStmtRet(NULL);
  3752.         }
  3753.         else
  3754.         {
  3755.             assert(body->tnOper == TN_BLOCK);
  3756.             cmpErrorTree = NULL;
  3757.             cmpScanner->scanSetTokenPos(body->tnBlock.tnBlkSrcEnd);
  3758.  
  3759.             cmpError(ERRmisgRet, cmpCurFncTyp->tdFnc.tdfRett);
  3760.         }
  3761.     }
  3762.  
  3763.     /* Do we need a label for a return from try/catch ? */
  3764.  
  3765.     if  (cmpLeaveLab)
  3766.     {
  3767.         cmpILgen->genFwdLabDef(cmpLeaveLab);
  3768.  
  3769.         if  (cmpLeaveTmp)
  3770.         {
  3771.             /* Non-void value: return the value of the temp */
  3772.  
  3773.             assert(cmpCurFncRtp->tdTypeKind != TYP_VOID);
  3774.  
  3775.             cmpILgen->genStmtRet(cmpCreateVarNode(NULL, cmpLeaveTmp));
  3776.  
  3777.             cmpTempVarDone(cmpLeaveTmp);
  3778.         }
  3779.         else
  3780.         {
  3781.             /* No return value: just return */
  3782.  
  3783.             assert(cmpCurFncRtp->tdTypeKind == TYP_VOID);
  3784.             cmpILgen->genStmtRet(NULL);
  3785.         }
  3786.     }
  3787.  
  3788.     /* Did we do static member initialization checking ? */
  3789.  
  3790.     if  (cmpChkMemInit)
  3791.     {
  3792.         SymDef          memSym;
  3793.  
  3794.         assert(fncSym->sdFnc.sdfCtor);
  3795.         assert(fncSym->sdIsStatic);
  3796.  
  3797.         for (memSym = fncSym->sdParent->sdScope.sdScope.sdsChildList;
  3798.              memSym;
  3799.              memSym = memSym->sdNextInScope)
  3800.         {
  3801.             if  (memSym->sdSymKind == SYM_VAR &&
  3802.                  memSym->sdIsSealed           &&
  3803.                  memSym->sdIsStatic           &&
  3804.                  memSym->sdVar.sdvChkInit)
  3805.             {
  3806.                 memSym->sdVar.sdvHadInit = true;
  3807.                 memSym->sdVar.sdvCanInit = false;
  3808.                 memSym->sdVar.sdvChkInit = false;
  3809.             }
  3810.         }
  3811.     }
  3812.  
  3813.     /* Did we check for uninitialized variable use? */
  3814.  
  3815.     if  (cmpChkVarInit)
  3816.         cmpChkVarInitEnd();
  3817.  
  3818. #ifdef  OLD_IL
  3819.     if  (cmpConfig.ccOILgen) cmpOIgen->GOIgenFncEnd(cmpCurFncSrcEnd);
  3820. #endif
  3821.  
  3822.     return  fncScp;
  3823. }
  3824.  
  3825. /*****************************************************************************
  3826.  *
  3827.  *  Generate IL for a function - end.
  3828.  */
  3829.  
  3830. void                compiler::cmpGenFNbodyEnd()
  3831. {
  3832.     SymList         list;
  3833.  
  3834.     /* Walk the list of variables declared as static locals with the function */
  3835.  
  3836.     list = cmpLclStatListT;
  3837.     if  (!list)
  3838.         return;
  3839.  
  3840.     do
  3841.     {
  3842.         SymList         next   = list->slNext;
  3843.         SymDef          varSym = list->slSym;
  3844.  
  3845.         assert(varSym->sdSymKind == SYM_VAR);
  3846.         assert(varSym->sdVar.sdvLocal == false);
  3847.         assert(varSym->sdIsStatic);
  3848.  
  3849.         /* Change the parent so the variable appears to be a global */
  3850.  
  3851.         varSym->sdParent    = cmpGlobalNS;
  3852.         varSym->sdNameSpace = NS_HIDE;
  3853.  
  3854.         /* Make sure the space for the variable has been allocated */
  3855.  
  3856.         if  (varSym->sdType && !varSym->sdIsManaged)
  3857.         {
  3858.             cmpAllocGlobVar(varSym);
  3859.  
  3860.             /* Record the variable so that we set its RVA at the very end */
  3861.  
  3862. #if MGDDATA
  3863.             list = new SymList;
  3864. #else
  3865.             list =    (SymList)cmpAllocPerm.nraAlloc(sizeof(*list));
  3866. #endif
  3867.  
  3868.             list->slSym  = varSym;
  3869.             list->slNext = cmpLclStatListP;
  3870.                            cmpLclStatListP = list;
  3871.         }
  3872.  
  3873.         list = next;
  3874.     }
  3875.     while (list);
  3876. }
  3877.  
  3878. /*****************************************************************************/
  3879.