-- Statement.mesa, modified by Sweet, November 18, 1979  12:00 AM

DIRECTORY
  AltoDefs: FROM "altodefs" USING [BYTE, wordlength],
  Code: FROM "code" USING [
    actenable, caseCVState, catchcount, catchoutrecord, cfs, 
    CodeNotImplemented, codeptr, curctxlvl, dStar, fileindex, framesz, 
    inlineFileIndex, mwCaseCV, StackNotEmptyAtStatement, xtracting],
  CodeDefs: FROM "codedefs" USING [
    CaseCVState, CCIndex, CCItem, CodeCCIndex, EXLRIndex, JumpCCNull, 
    JumpType, LabelCCIndex, LabelCCNull, Lexeme, NULLfileindex, NullLex, 
    OtherCCIndex, StackIndex, TempStateRecord, VarComponent, VarIndex, 
    VarNull],
  ComData: FROM "comdata" USING [bodyIndex, switches, textIndex],
  ControlDefs: FROM "controldefs" USING [AllocationVectorSize, localbase],
  FOpCodes: FROM "fopcodes" USING [
    qBCAST, qBCASTL, qBNDCK, qCATCH, qDADD, qDCOMP, qDEC, qDST, qDSUB, 
    qDUCOMP, qINC, qLL, qLP, qLST, qLSTF, qNOOP, qNOTIFY, qNOTIFYL, qPUSH, 
    qRET, qSL],
  Log: FROM "log" USING [Error],
  P5: FROM "p5" USING [
    Exp, FlowTree, GenAnonLex, GenHeapLex, GetLabelMark, LabelCreate, 
    LabelList, LogHeapFree, MakeExitLabel, P5Error, PopInVals, PopLabels, 
    PopTempState, PurgeHeapList, PurgePendTempList, PushHeapList, PushLex, 
    PushRhs, PushTempState, ReleaseTempLex, SAssign, SysError, TTAssign],
  P5L: FROM "p5l" USING [
    CopyToTemp, LoadAddress, LoadVar, MakeComponent, NormalizeExp, NormalLex, 
    OVarItem, ReleaseLex, VarForLex],
  P5S: FROM "p5s" USING [
    Assign, Call, CatchMark, Continue, Exit, Extract, GoTo, Join, Label, Lock, 
    Loop, ProcInit, Restart, Result, Resume, Retry, Return, RetWithError, 
    SigErr, Start, Stop, Subst, Unlock, Wait],
  P5U: FROM "p5u" USING [
    CCellAlloc, ComputeFrameSize, CreateLabel, EnumerateCaseArms, FreeChunk, 
    InsertLabel, LabelAlloc, Out0, Out1, OutJump, PushLitVal, TreeLiteral, 
    TreeLiteralValue, WordsForOperand],
  Stack: FROM "stack" USING [
    Clear, Decr, Depth, Dump, Incr, Mark, New, Off, On, Pop, Require, Reset, 
    ResetToMark, Restore, UnMark],
  SymbolOps: FROM "symbolops" USING [WordsForType],
  Symbols: FROM "symbols" USING [
    bodyType, BTIndex, ContextLevel, CTXIndex, CTXNull, ctxType, HTIndex, 
    ISEIndex, ISENull, RecordSEIndex, RecordSENull, SEIndex, SENull, SERecord, 
    seType],
  SymbolSegment: FROM "symbolsegment" USING [ByteIndex],
  SystemDefs: FROM "systemdefs" USING [AllocateHeapNode, FreeHeapNode],
  Table: FROM "table" USING [Base, Limit, Notifier],
  Tree: FROM "tree" USING [Index, Link, NodeName, Null, treeType],
  TreeOps: FROM "treeops" USING [
    FreeTree, ListLength, ReverseUpdateList, ScanList, SetShared, UpdateList];

Statement: PROGRAM
    IMPORTS MPtr: ComData, CPtr: Code, P5U, CodeDefs, P5L, P5, P5S, 
      Stack, SymbolOps, SystemDefs, TreeOps, Log 
    EXPORTS CodeDefs, P5 =
  BEGIN
  OPEN FOpCodes, CodeDefs;


  -- imported definitions

  BYTE: TYPE = AltoDefs.BYTE;
  wordlength: CARDINAL = AltoDefs.wordlength;

  ContextLevel: TYPE = Symbols.ContextLevel;
  CTXIndex: TYPE = Symbols.CTXIndex;
  CTXNull: CTXIndex = Symbols.CTXNull;
  HTIndex: TYPE = Symbols.HTIndex;
  ISEIndex: TYPE = Symbols.ISEIndex;
  ISENull: ISEIndex = Symbols.ISENull;
  RecordSEIndex: TYPE = Symbols.RecordSEIndex;
  RecordSENull: RecordSEIndex = Symbols.RecordSENull;
  SEIndex: TYPE = Symbols.SEIndex;
  SENull: SEIndex = Symbols.SENull;
  SERecord: TYPE = Symbols.SERecord;
  BTIndex: TYPE = Symbols.BTIndex;


  tb: Table.Base;		-- tree base (local copy)
  seb: Table.Base;		-- semantic entry base (local copy)
  ctxb: Table.Base;		-- context entry base (local copy)
  cb: Table.Base;		-- code base (local copy)
  bb: Table.Base;		-- body base (local copy)

  StatementNotify: PUBLIC Table.Notifier =
    BEGIN  -- called by allocator whenever table area is repacked
    seb ← base[Symbols.seType];
    ctxb ← base[Symbols.ctxType];
    cb ← tb ← base[Tree.treeType];
    bb ← base[Symbols.bodyType];
    RETURN
    END;

  CatchFrameTooLarge: SIGNAL = CODE;

  recentStmt: PUBLIC Tree.Link; -- for debugging

  StatementTree: PUBLIC PROCEDURE [t: Tree.Link] RETURNS[Tree.Link] =
    BEGIN -- generates code for Mesa statements
    node: Tree.Index;
    savheaplist: ISEIndex;
    saveIndex: CARDINAL = MPtr.textIndex;

    recentStmt ← t;
    IF t = Tree.Null THEN RETURN[Tree.Null];
    BEGIN
    ENABLE 
      BEGIN
      P5.LogHeapFree => RESUME[TRUE, P5.GenHeapLex[]];
      CPtr.CodeNotImplemented => IF ~MPtr.switches['d] THEN
	GO TO unimplementedConstruct
      END;
    savheaplist ← P5.PushHeapList[];
    WITH t SELECT FROM
      subtree =>
	BEGIN
        fIndex: SymbolSegment.ByteIndex ← CPtr.inlineFileIndex;
	node ← index;
	IF fIndex = NULLfileindex THEN fIndex ← tb[node].info;
	CPtr.fileindex ← MPtr.textIndex ← fIndex;
	IF ~CPtr.xtracting AND Stack.Depth[] # 0 THEN
	  BEGIN SIGNAL CPtr.StackNotEmptyAtStatement; Stack.Clear[]; END;
	SELECT tb[node].name FROM
	  block => Block[node];
	  start => P5S.Start[node];
	  restart => P5S.Restart[node];
	  stop => P5S.Stop[node];
	  dst => DumpState[node];
	  lst => LoadState[node];
	  lstf => LoadStateFree[node];
	  call, portcall => P5S.Call[node];
	  signal,error => P5S.SigErr[node];
	  syserror => P5.SysError[];
	  label => P5S.Label[node];
	  assign => P5S.Assign[node];
	  extract => P5S.Extract[node];
	  if => IfStmt[node];
	  case => [] ← CaseStmtExp[node, FALSE];
	  do => DoStmt[node];
	  exit => P5S.Exit[];
	  loop => P5S.Loop[];
	  retry => P5S.Retry[];
	  continue => P5S.Continue[];
	  goto => P5S.GoTo[node];
	  catchmark => P5S.CatchMark[node];
	  return => P5S.Return[node];
	  resume => P5S.Resume[node];
	  result => P5S.Result[node];
	  open => Open[node];
	  enable => Enable[node];
	  procinit => P5S.ProcInit[node];
	  wait => P5S.Wait[node];
	  notify => Notify[node];
	  broadcast => Broadcast[node];
	  join => P5S.Join[node];
	  unlock => P5S.Unlock[node];
	  lock => P5S.Lock[node];
          subst => P5S.Subst[node];
	  xerror => P5S.RetWithError[node];
	  null => NULL;
	  list => t ← TreeOps.UpdateList[t, StatementTree];
	  ENDCASE => GO TO unimplementedConstruct;
	END;
      ENDCASE;
    P5.PurgeHeapList[savheaplist];
    P5.PurgePendTempList[];
    EXITS
      unimplementedConstruct =>
	BEGIN
	Log.Error[unimplemented];
	Stack.Clear[];
	END;
    END;
    MPtr.textIndex ← saveIndex;
    [] ← TreeOps.FreeTree[t];
    RETURN[Tree.Null]
    END;


  Open: PROCEDURE [node: Tree.Index] =
    BEGIN
    OPEN TreeOps;
    sCopen: PROCEDURE [t: Tree.Link] RETURNS [Tree.Link] =
      BEGIN
      SetShared[t, FALSE];
      RETURN[FreeTree[t]]
      END;

    tb[node].son[2] ← StatementTree[tb[node].son[2]];
    tb[node].son[1] ← ReverseUpdateList[tb[node].son[1], sCopen];
    RETURN
    END;


  DumpState: PROCEDURE [node: Tree.Index] =
    BEGIN -- generates dumpstate
    DLState[node, qDST];
    RETURN
    END;


  LoadState: PROCEDURE [node: Tree.Index] =
    BEGIN -- generates loadstate
    DLState[node, qLST];
    RETURN
    END;


  LoadStateFree: PROCEDURE [node: Tree.Index] =
    BEGIN -- generates loadstateandfree
    DLState[node, qLSTF];
    P5U.OutJump[JumpRet, LabelCCNull];
    RETURN
    END;


  InvalidStateStorageLocation: SIGNAL = CODE;


  DLState: PROCEDURE [node: Tree.Index, opc: BYTE] =
    BEGIN -- does state move after checking for small currentcontext address
    var: VarComponent;

    var ← P5L.MakeComponent[P5L.VarForLex[P5.Exp[tb[node].son[1]]]];
    WITH var SELECT FROM
      frame => IF level = CPtr.curctxlvl AND wd IN BYTE THEN
	BEGIN
	P5U.Out1[opc, wd];
	RETURN
	END;
      ENDCASE;
    SIGNAL InvalidStateStorageLocation;
    END;

  Block: PROCEDURE [node: Tree.Index] =
    BEGIN
    bti: BTIndex ← tb[node].info;
    WITH bb[bti].info SELECT FROM
      Internal => IF CPtr.inlineFileIndex = NULLfileindex THEN
	  CPtr.fileindex ← MPtr.textIndex ← sourceIndex
	ELSE sourceIndex ← CPtr.inlineFileIndex;
      ENDCASE;
    P5U.CCellAlloc[other];
    cb[LOOPHOLE[CPtr.codeptr, OtherCCIndex]].obody ← 
	startbody[index: bti];
    tb[node].son[1] ← TreeOps.UpdateList[tb[node].son[1], StatementTree];
    tb[node].son[2] ← TreeOps.UpdateList[tb[node].son[2], StatementTree];
    P5U.CCellAlloc[other];
    cb[LOOPHOLE[CPtr.codeptr, OtherCCIndex]].obody ← 
	endbody[index: bti];
    END;


  IfStmt: PROCEDURE [node: Tree.Index] =
    BEGIN -- generates code for an IF statement
    ilabel,elabel: LabelCCIndex;

    elabel←P5U.LabelAlloc[];
    P5.FlowTree[tb[node].son[1], FALSE, elabel];
    tb[node].son[2] ← StatementTree[tb[node].son[2]];
    IF tb[node].son[3] # Tree.Null THEN
      BEGIN
      P5U.OutJump[Jump, ilabel←P5U.LabelAlloc[]];
      P5U.InsertLabel[elabel];
      tb[node].son[3] ← StatementTree[tb[node].son[3]];
      P5U.InsertLabel[ilabel];
      END
    ELSE P5U.InsertLabel[elabel];
    RETURN
    END;


  CaseStmtExp: PUBLIC PROCEDURE [node: Tree.Index, iscasexp: BOOLEAN] RETURNS [Lexeme] =
    BEGIN -- generate code for CASE statment and expression
    caseEndLabel: LabelCCIndex ← P5U.LabelAlloc[];
    caseLPEndLabel: LabelCCIndex ← P5U.LabelAlloc[];
    cvSize: CARDINAL ← P5U.WordsForOperand[tb[node].son[1]];
    nwords: CARDINAL ←
	IF iscasexp THEN SymbolOps.WordsForType[tb[node].info] ELSE 0;
    savemwCaseCV: Lexeme ← CPtr.mwCaseCV;
    savextracting: BOOLEAN ← CPtr.xtracting;
    savecaseCVState: CaseCVState ← CPtr.caseCVState;
    allConst: BOOLEAN;
    CheckConst: PROCEDURE [t: Tree.Link] =
      BEGIN
      allConst ← allConst AND P5U.TreeLiteral[t];
      END;
    longExpValue: BOOLEAN;
    cvtlex: se Lexeme ← NullLex;
    valTsei: ISEIndex ← ISENull;
    sCitem: PROCEDURE [t: Tree.Link] =
      BEGIN
      faillabel: LabelCCIndex = P5U.LabelAlloc[];
      longx: BOOLEAN ← FALSE;
      r: VarIndex;
      WITH t SELECT FROM
	subtree => [r, valTsei] ← CaseItem[index, iscasexp,
	  FALSE, valTsei, faillabel];
	ENDCASE;
      IF iscasexp THEN 
	BEGIN
	[long: longx, tsei: valTsei] ← P5L.NormalizeExp[r, valTsei, allConst];
	Stack.ResetToMark[];
	END;
      P5U.OutJump[Jump, IF longx THEN caseLPEndLabel ELSE caseEndLabel];
      P5U.InsertLabel[faillabel];
      RETURN
      END;
    cvr: VarIndex;

    CPtr.xtracting ← FALSE;
    IF ~CPtr.dStar THEN Stack.Dump[];
    cvr ← P5L.VarForLex[P5.Exp[tb[node].son[1]]];
    IF iscasexp THEN 
      BEGIN
      Stack.Mark[];
      allConst ← TRUE;
      P5U.EnumerateCaseArms[node, CheckConst];
      END;
    IF cvSize = 1 THEN
      BEGIN
      P5L.LoadVar[cvr];
      CPtr.caseCVState ← singleLoaded;
      END
    ELSE
      BEGIN
      cvtlex ← P5.GenAnonLex[cvSize];
      CPtr.mwCaseCV ←
	[bdo[P5L.OVarItem[P5L.CopyToTemp[cvr, cvtlex.lexsei].var]]];
      CPtr.caseCVState ← multi;
      END;
    BEGIN ENABLE 
      P5.LogHeapFree => IF iscasexp THEN RESUME[FALSE, NullLex];
      TreeOps.ScanList[tb[node].son[2], sCitem];
      IF iscasexp THEN
	BEGIN
	r: VarIndex ← P5L.VarForLex[P5.Exp[tb[node].son[3]]];
	long: BOOLEAN ← P5L.NormalizeExp[r, valTsei, allConst].long;
	P5U.OutJump[Jump, IF long THEN caseLPEndLabel ELSE caseEndLabel];
	Stack.UnMark[];
	END
      ELSE tb[node].son[3] ← StatementTree[tb[node].son[3]];
    END;
    P5U.InsertLabel[caseEndLabel];
    longExpValue ← cb[caseLPEndLabel].jumplist # JumpCCNull;
    IF longExpValue THEN P5U.Out0[qLP]; -- unreachable if all arms long
    P5U.InsertLabel[caseLPEndLabel];
    IF cvtlex # NullLex THEN 
      BEGIN
      P5.ReleaseTempLex[cvtlex];
      P5L.ReleaseLex[CPtr.mwCaseCV];
      END;
    IF valTsei # ISENull THEN P5.ReleaseTempLex[[se[valTsei]]];
    CPtr.mwCaseCV ← savemwCaseCV;
    CPtr.caseCVState ← savecaseCVState;
    CPtr.xtracting ← savextracting;
    tb[node].son[1] ← TreeOps.FreeTree[tb[node].son[1]];
    tb[node].son[2] ← TreeOps.FreeTree[tb[node].son[2]];
    tb[node].son[3] ← TreeOps.FreeTree[tb[node].son[3]];
    IF tb[node].nSons > 3 THEN TreeOps.SetShared[tb[node].son[4], FALSE];
    IF iscasexp THEN RETURN [P5L.NormalLex[nwords, longExpValue, allConst]]
    ELSE RETURN [NullLex];
    END;


  NewBranches: PROCEDURE [t: Tree.Link, itemlabel, faillabel: LabelCCIndex,
			bt: DESCRIPTOR FOR ARRAY OF LabelCCIndex]
		RETURNS [new: BOOLEAN] =
    BEGIN -- sees if any new branches need to be added to branch table
    i: CARDINAL;
    snb: PROCEDURE [t: Tree.Link] =
      BEGIN
      i ← P5U.TreeLiteralValue[t];
      IF bt[i] = faillabel THEN
	BEGIN bt[i] ← itemlabel; new ← TRUE; END;
      RETURN
      END;

    new ← FALSE;
    TreeOps.ScanList[t, snb];
    RETURN
    END;


  Branch: PROCEDURE [node: Tree.Index, isexp: BOOLEAN, tempsei: ISEIndex, faillabel: LabelCCIndex] RETURNS [r: VarIndex, tsei: ISEIndex] =
    BEGIN -- generate code for case switch if range is densely packed
    nwords, range, i: CARDINAL;
    btcp, savcodeptr: CCIndex;
    valLabel, valLPLabel: LabelCCIndex;
    bt: DESCRIPTOR FOR ARRAY OF LabelCCIndex;
    first: BOOLEAN ← TRUE;
    allConst: BOOLEAN;
    longExp: BOOLEAN;
    LookForConst: PROCEDURE [t: Tree.Link] =
      BEGIN
      allConst ← allConst AND P5U.TreeLiteral[t];
      END;
    scb: PROCEDURE [t: Tree.Link] =
      BEGIN
      itemlabel: LabelCCIndex;

      WITH t SELECT FROM
	subtree =>
	  BEGIN -- is an item
	  longx: BOOLEAN ← FALSE;
	  bnode: Tree.Index ← index;
	  itemlabel ← P5U.LabelAlloc[];
	  IF NewBranches[tb[bnode].son[1], itemlabel, faillabel, bt] THEN
	    BEGIN
	    P5U.InsertLabel[itemlabel];
	    IF isexp THEN
	      BEGIN
	      longx: BOOLEAN;
	      tr: VarIndex;
	      IF first THEN first ← FALSE ELSE Stack.ResetToMark[];
	      tr ← P5L.VarForLex[P5.Exp[tb[bnode].son[2]]];
	      [nwords: nwords, long: longx, tsei: tsei] ← 
		P5L.NormalizeExp[tr, tsei, allConst];
	      END
	    ELSE tb[bnode].son[2] ← StatementTree[tb[bnode].son[2]];
	    P5U.OutJump[Jump, IF longx THEN valLPLabel ELSE valLabel];
	    END
	  ELSE P5U.FreeChunk[itemlabel, SIZE[label CCItem]];
	  RETURN
	  END;
	ENDCASE
      END;

    tsei ← tempsei;
    IF isexp THEN 
      BEGIN
      allConst ← TRUE;
      TreeOps.ScanList[tb[node].son[3], LookForConst];
      END;
    range ← P5U.TreeLiteralValue[tb[node].son[2]];
    valLabel ← P5U.LabelAlloc[];
    valLPLabel ← P5U.LabelAlloc[];
    IF ~CPtr.dStar THEN
      IF CPtr.caseCVState = singleLoaded THEN Stack.Require[1]
      ELSE Stack.Dump[];
    P5.PushRhs[tb[node].son[1]];
    P5U.PushLitVal[range];
    Stack.Decr[2];
    P5U.CCellAlloc[other];
    cb[LOOPHOLE[CPtr.codeptr, OtherCCIndex]].obody ← 
	table[btab: , tablecodebytes: 3, taboffset: ];
    btcp ← CPtr.codeptr;
    P5U.OutJump[JumpCA, faillabel];
    bt ← DESCRIPTOR[SystemDefs.AllocateHeapNode[range], range];
    FOR i IN [0..range) DO bt[i] ← faillabel ENDLOOP;
    TreeOps.ScanList[tb[node].son[3], scb];
    savcodeptr ← CPtr.codeptr;
    CPtr.codeptr ← btcp;
    FOR i IN [0..range) DO P5U.OutJump[JumpC, bt[i]] ENDLOOP;
    CPtr.codeptr ← savcodeptr;
    P5U.InsertLabel[valLabel];
    longExp ← cb[valLPLabel].jumplist # JumpCCNull;
    IF longExp THEN P5U.Out0[qLP];
    P5U.InsertLabel[valLPLabel];
    SystemDefs.FreeHeapNode[BASE[bt]];
    IF isexp THEN RETURN [
      P5L.VarForLex[P5L.NormalLex[nwords, longExp, allConst]], tsei]
    ELSE RETURN [VarNull, tsei];
    END;


  CaseItem: PROCEDURE [node: Tree.Index, isexp, isenable: BOOLEAN, tempsei: ISEIndex, faillabel: LabelCCIndex] RETURNS [r: VarIndex, tsei: ISEIndex] =
    BEGIN -- generate code for a CASE item
    itemlabel: LabelCCIndex;
    irecord, savcatchoutrecord: RecordSEIndex;
    sei: Table.Base RELATIVE POINTER [0..Table.Limit) TO transfer cons SERecord;
    savinctxlevel, savoutctxlevel: ContextLevel;
    ictx, octx: CTXIndex ← CTXNull;
    lasson: CARDINAL;
    thisson: CARDINAL ← 0;
    sci: PROCEDURE [t: Tree.Link] =
      BEGIN
      IF thisson # lasson THEN
	BEGIN
	P5.FlowTree[t, TRUE, itemlabel];
	thisson ← thisson+1;
	END
      ELSE
	BEGIN
	P5.FlowTree[t, FALSE, faillabel];
	P5U.InsertLabel[itemlabel];
	END;
      RETURN
      END;

    tsei ← tempsei; r ← VarNull;
    IF tb[node].name = caseswitch THEN
      BEGIN
      [r, tsei] ← Branch[node, isexp, tsei, faillabel];
      RETURN
      END;
    WITH t1: tb[node].son[1] SELECT FROM
      subtree =>
	BEGIN
	itemlabel ← P5U.LabelAlloc[];
	IF tb[t1.index].name # list THEN lasson ← 0
	ELSE lasson ← TreeOps.ListLength[t1]-1;
	TreeOps.ScanList[t1, sci];
	END;
      ENDCASE => P5.FlowTree[t1, FALSE, faillabel];
    IF isexp THEN r ← P5L.VarForLex[P5.Exp[tb[node].son[2]]]
    ELSE
      IF isenable THEN
	BEGIN
	savcatchoutrecord ← CPtr.catchoutrecord;
	sei ← tb[node].info;
	IF sei # SENull THEN
	  BEGIN
	  irecord ← seb[sei].inRecord;
	  CPtr.catchoutrecord ← seb[sei].outRecord;
	  IF irecord # RecordSENull THEN
	    BEGIN
	    ictx ← seb[irecord].fieldCtx;
	    savinctxlevel ← ctxb[ictx].level;
	    ctxb[ictx].level ← CPtr.curctxlvl;
	    END;
	  IF CPtr.catchoutrecord # RecordSENull THEN
	    BEGIN
	    octx ← seb[CPtr.catchoutrecord].fieldCtx;
	    savoutctxlevel ← ctxb[octx].level;
	    ctxb[octx].level ← CPtr.curctxlvl;
	    END;
	  END
	ELSE irecord ← CPtr.catchoutrecord ← RecordSENull;
	P5.PopInVals[irecord, TRUE];
	tb[node].son[2] ← StatementTree[tb[node].son[2]];
	IF ictx # CTXNull THEN ctxb[ictx].level ← savinctxlevel;
	IF octx # CTXNull THEN ctxb[octx].level ← savoutctxlevel;
	CPtr.catchoutrecord ← savcatchoutrecord;
	END
      ELSE tb[node].son[2] ← StatementTree[tb[node].son[2]];
    RETURN
    END;


  DoStmt: PROCEDURE [rootnode: Tree.Index] =
    BEGIN --  generates code for all the loop statments
    steploop, tempindex, tempend, uploop, forseqloop, signed, long, bigforseq: BOOLEAN ← FALSE;
    t, Sson, Eson: Tree.Link;
    node, node2: Tree.Index;
    inttype: Tree.NodeName;
    indexlex: se Lexeme;
    endlex: Lexeme;
    toplabel: LabelCCIndex ← P5U.LabelAlloc[];
    startlabel: LabelCCIndex;
    finlabel: LabelCCIndex ← P5U.LabelAlloc[];
    endlabel, looplabel: LabelCCIndex;
    labelmark: EXLRIndex ← P5.GetLabelMark[];
    updateCV: PROCEDURE [loadlong: BOOLEAN] =
      BEGIN
      IF long THEN
        BEGIN
	IF ~CPtr.dStar THEN
	  IF loadlong THEN
	    BEGIN Stack.Dump[]; P5.PushLex[indexlex]; END
          ELSE Stack.Require[2];
	P5U.PushLitVal[1]; P5U.PushLitVal[0];
	P5U.Out0[IF uploop THEN qDADD ELSE qDSUB];
	P5.SAssign[indexlex.lexsei];
	END
      ELSE P5U.Out0[IF uploop THEN qINC ELSE qDEC];
      END;

    -- set up for EXIT clause

    [exit: endlabel, loop: looplabel] ← P5.MakeExitLabel[];
    TreeOps.ScanList[tb[rootnode].son[5], P5.LabelCreate];

    -- handle initialization node

    t ← tb[rootnode].son[1];
    WITH t SELECT FROM
      subtree =>
       IF t # Tree.Null THEN
	BEGIN
	node ← index;
	SELECT tb[node].name FROM
	  forseq =>
	    BEGIN
	    t1: Tree.Link ← tb[node].son[1];
	    t2: Tree.Link ← tb[node].son[2];
	    WITH t1 SELECT FROM
	      symbol => indexlex ← [se[index]];
	      ENDCASE;
	    forseqloop ← TRUE;
	    bigforseq ← P5U.WordsForOperand[t1] > 2;
	    IF bigforseq THEN
	      BEGIN
	      P5.TTAssign[t1, t2];
	      P5U.InsertLabel[toplabel];
	      END
	    ELSE
	      BEGIN
	      P5.PushRhs[t2];
	      P5U.InsertLabel[toplabel];
	      P5.SAssign[indexlex.lexsei];
	      END;
	    END;
	  upthru, downthru =>
	    BEGIN
	    cvBound: Tree.Link = tb[node].son[3];
	    nonempty: BOOLEAN = tb[node].attr1;
	    steploop ← TRUE;
	    uploop ← tb[node].name = upthru;
	    WITH tb[node].son[2] SELECT FROM
	      subtree =>
		BEGIN
		node2 ← index;
		inttype ← tb[node2].name;
		IF tb[node2].attr1 THEN SIGNAL CPtr.CodeNotImplemented;
		long ← tb[node2].attr2;
		signed ← tb[node2].attr3;
		END;
	      ENDCASE;
	    WITH tb[node].son[1] SELECT FROM
	      subtree => -- son1 is empty
		BEGIN
		indexlex ← P5.GenAnonLex[IF long THEN 2 ELSE 1];
		tempindex ← TRUE;
		END;
	      symbol => indexlex ← Lexeme[se[index]];
	      ENDCASE;
	    WITH tb[node].son[2] SELECT FROM
	      subtree =>
		BEGIN
		IF uploop THEN
		  BEGIN Sson ← tb[node2].son[1]; Eson ← tb[node2].son[2]; END
		ELSE
		  BEGIN
		  SELECT inttype FROM
		    intCO => inttype ← intOC;
		    intOC => inttype ← intCO;
		    ENDCASE;
		  Sson ← tb[node2].son[2];
		  Eson ← tb[node2].son[1];
		  END;
		WITH e: Eson SELECT FROM
		  literal =>
		    WITH e.info SELECT FROM
		      word => endlex ←
			 Lexeme[literal[word[index]]];
		      ENDCASE => P5.P5Error[769];
		  ENDCASE =>
		    BEGIN
		    P5.PushRhs[e]; tempend ← TRUE;
		    P5.SAssign[
		      (endlex ← P5.GenAnonLex[IF long THEN 2 ELSE 1]).lexsei];
		    END;
		startlabel ← P5U.LabelAlloc[];
		IF long AND ~CPtr.dStar THEN Stack.Dump[];
		P5.PushRhs[Sson];
		IF long THEN P5.SAssign[indexlex.lexsei];
		IF (inttype = intCC OR inttype = intOO) AND ~nonempty THEN
		    BEGIN -- earlier passes check for empty intervals

		    TopTest: ARRAY BOOLEAN OF
		      ARRAY BOOLEAN OF ARRAY BOOLEAN OF JumpType =
			[[[UJumpL,UJumpLE],	-- unsigned, down, closed/open
			[UJumpG,UJumpGE]],	-- unsigned, up, closed/open
			[[JumpL,JumpLE],	-- signed, down, closed/open
			[JumpG,JumpGE]]];	-- signed, up, closed/open

		    IF long THEN BEGIN P5U.Out0[qPUSH]; P5U.Out0[qPUSH] END;
		    P5.PushLex[endlex];
		    IF long THEN
		      BEGIN
		      P5U.Out0[IF signed THEN qDCOMP ELSE qDUCOMP];
		      P5U.PushLitVal[0]
		      END;
		    P5U.OutJump[
		      TopTest[long OR signed][uploop][inttype = intOO],
		      finlabel];
		    IF ~long THEN P5U.Out0[qPUSH];
		    END;
		IF ~long THEN Stack.Decr[1];
		P5U.OutJump[Jump, startlabel];
		P5U.InsertLabel[toplabel];
		IF ~long THEN P5U.Out0[qPUSH];
		SELECT inttype FROM
		  intCC => BEGIN updateCV[TRUE]; P5U.InsertLabel[startlabel]; END;
		  intOC => updateCV[TRUE];
		  intCO, intOO => NULL;
		  ENDCASE;
		IF ~long THEN
		  BEGIN
		  IF cvBound # Tree.Null THEN
		    BEGIN P5.PushRhs[cvBound]; P5U.Out0[FOpCodes.qBNDCK]; END;
		  P5.SAssign[indexlex.lexsei];
		  END;
		END;
	      ENDCASE;
	    END;
	  ENDCASE;
	END
       ELSE P5U.InsertLabel[toplabel];
      ENDCASE;

    -- now the pre-body test

    IF tb[rootnode].son[2] # Tree.Null THEN
      P5.FlowTree[tb[rootnode].son[2], FALSE, finlabel];

    -- ignore the opens

    -- tb[node].son3;

    -- now the body

    tb[rootnode].son[4] ← StatementTree[tb[rootnode].son[4]];

    -- now (update and) test the control variable

    P5U.InsertLabel[looplabel];
    IF steploop THEN
      BEGIN
      IF long AND (inttype = intOC OR inttype = intOO) THEN
	P5U.InsertLabel[startlabel];
      P5.PushLex[indexlex];
      SELECT inttype FROM
	intCC => NULL;
	intCO => BEGIN updateCV[FALSE]; P5U.InsertLabel[startlabel]; END;
	intOC => IF ~long THEN P5U.InsertLabel[startlabel];
	intOO => 
	  BEGIN 
	  IF ~long THEN P5U.InsertLabel[startlabel]; 
	  updateCV[FALSE]; 
	  END;
	ENDCASE;
      IF long THEN SELECT inttype FROM
	intCO, intOO => BEGIN P5U.Out0[qPUSH]; P5U.Out0[qPUSH] END;
	ENDCASE;
      P5.PushLex[endlex];
      IF long THEN
	BEGIN
	P5U.Out0[IF signed THEN qDCOMP ELSE qDUCOMP];
	P5U.PushLitVal[0]
	END;
      P5U.OutJump[
	    IF ~long AND ~signed THEN 
	      IF uploop THEN UJumpL ELSE UJumpG
	    ELSE IF uploop THEN JumpL ELSE JumpG, toplabel];
      P5U.OutJump[Jump, finlabel];
      IF tempend THEN P5.ReleaseTempLex[LOOPHOLE[endlex, se Lexeme]];
      IF tempindex THEN P5.ReleaseTempLex[indexlex];
      END
    ELSE
      BEGIN
      IF forseqloop THEN
	BEGIN
	WITH tb[rootnode].son[1] SELECT FROM
	  subtree => 
	    BEGIN
	    t3: Tree.Link ← tb[index].son[3];
	    IF bigforseq THEN P5.TTAssign[[symbol[indexlex.lexsei]], t3]
	    ELSE P5.PushRhs[t3!
		P5.LogHeapFree => RESUME[FALSE, NullLex]];
	    END;
	  ENDCASE;
	END;
      P5U.OutJump[Jump, toplabel];
      END;
    Stack.Reset[];

    -- now the labelled EXITs

    P5.LabelList[tb[rootnode].son[5], endlabel];
    P5.PopLabels[labelmark];

    -- finally the FINISHED clause

    P5U.InsertLabel[finlabel];
    tb[rootnode].son[6] ← StatementTree[tb[rootnode].son[6]];
    P5U.InsertLabel[endlabel];
    RETURN
    END;


  CatchPhrase: PUBLIC PROCEDURE [node: Tree.Index] =
    BEGIN -- process a catchphrase at procedure call
    aroundlabel: LabelCCIndex ← P5U.LabelAlloc[];
    savcfs: CARDINAL ← CPtr.cfs;
    r: CodeCCIndex;

    CPtr.catchcount ← CPtr.catchcount + 1;
    P5U.Out1[qCATCH, 0];
    r ← LOOPHOLE[CPtr.codeptr, CodeCCIndex];
    P5U.OutJump[JumpA, aroundlabel];
    SCatchPhrase[node];
    cb[r].parameters[1] ← CPtr.cfs;
    P5U.InsertLabel[aroundlabel];
    CPtr.catchcount ← CPtr.catchcount - 1;
    CPtr.cfs ← savcfs;
    RETURN
    END;


  Enable: PROCEDURE [node: Tree.Index] =
    BEGIN -- generate code for an ENABLE
    aroundlabel: LabelCCIndex ← P5U.LabelAlloc[];
    enablelabel: LabelCCIndex;
    savactenable: LabelCCIndex ← CPtr.actenable;
    savcfs: CARDINAL ← CPtr.cfs;

    CPtr.catchcount ← CPtr.catchcount + 1;
    P5U.Out0[FOpCodes.qNOOP]; -- to get a FGT entry on the jump around
    P5U.OutJump[JumpA,aroundlabel];
    enablelabel ← P5U.CreateLabel[];
    WITH tb[node].son[1] SELECT FROM
      subtree => SCatchPhrase[index];
      ENDCASE;
    P5U.InsertLabel[aroundlabel];
    CPtr.actenable ← enablelabel;
    CPtr.catchcount ← CPtr.catchcount -1;
    tb[node].son[2] ← StatementTree[tb[node].son[2]];
    CPtr.actenable ← savactenable;
    CPtr.cfs ← savcfs;
    RETURN
    END;


  SCatchPhrase: PUBLIC PROCEDURE [node: Tree.Index] =
    BEGIN -- main subr for catchphrases and ENABLEs
    saveCaseCVState: CaseCVState = CPtr.caseCVState;
    endlabel: LabelCCIndex ← P5U.LabelAlloc[];
    oldstkptr: StackIndex = Stack.New[];
    msgtemp, sigtemp: se Lexeme;
    saveactenable: LabelCCIndex = CPtr.actenable;
    tempstate: TempStateRecord;
    sscc: PROCEDURE [t: Tree.Link] =
      BEGIN
      fail: LabelCCIndex = P5U.LabelAlloc[];
      WITH t SELECT FROM
	subtree => [] ← CaseItem[
	  node:index, isexp:FALSE, isenable:TRUE,
	  tempsei: ISENull, faillabel: fail];
	ENDCASE;
      P5U.OutJump[Jump, endlabel];
      P5U.InsertLabel[fail];
      RETURN
      END;

    CPtr.curctxlvl ← CPtr.curctxlvl + 1;
    P5.PushTempState[@tempstate, tb[node].info];
    Stack.Incr[1]; -- signal code is on stack
    IF CPtr.actenable # LabelCCNull THEN
      BEGIN
      sigtemp ← P5.GenAnonLex[1];
      msgtemp ← P5.GenAnonLex[1];
      P5U.Out1[qLL,ControlDefs.localbase+1];
      P5.SAssign[msgtemp.lexsei];
      P5.SAssign[sigtemp.lexsei];
      P5.PushLex[sigtemp];
      END;
    CPtr.caseCVState ← singleLoaded;
    CPtr.actenable ← LabelCCNull;
    TreeOps.ScanList[tb[node].son[1], sscc];
    IF tb[node].son[1] = Tree.Null THEN Stack.Pop[];
    IF tb[node].son[2] # Tree.Null THEN
      tb[node].son[2] ← StatementTree[tb[node].son[2]];
    CPtr.actenable ← saveactenable;
    P5U.InsertLabel[endlabel];
    Stack.Off[];
    IF CPtr.actenable # LabelCCNull THEN
      BEGIN
      P5.PushLex[sigtemp];
      P5.PushLex[msgtemp];
      P5U.Out1[qSL,ControlDefs.localbase+1];
      P5U.OutJump[Jump,CPtr.actenable];
      P5.ReleaseTempLex[msgtemp];
      P5.ReleaseTempLex[sigtemp];
      END
    ELSE
      BEGIN
      P5U.PushLitVal[0];
      P5U.Out0[qRET];
      P5U.OutJump[JumpRet,LabelCCNull];
      END;
    Stack.On[];
    CPtr.curctxlvl ← CPtr.curctxlvl-1;
    CPtr.caseCVState ← saveCaseCVState;
    BEGIN
    fs: CARDINAL ← CPtr.framesz;
    P5.PopTempState[@tempstate];
    CPtr.cfs ← P5U.ComputeFrameSize[fs];
    END;
    IF bb[MPtr.bodyIndex].resident THEN
      CPtr.cfs ← CPtr.cfs+ControlDefs.AllocationVectorSize;
    Stack.Restore[oldstkptr];
    RETURN
    END;

  Notify: PROCEDURE [node: Tree.Index] =
    BEGIN
    r: VarIndex = P5L.VarForLex[P5.Exp[tb[node].son[1]]];
    P5U.Out0[IF P5L.LoadAddress[r].long THEN qNOTIFYL 
	ELSE qNOTIFY];
    END;

  Broadcast: PROCEDURE [node: Tree.Index] =
    BEGIN
    r: VarIndex = P5L.VarForLex[P5.Exp[tb[node].son[1]]];
    P5U.Out0[IF P5L.LoadAddress[r].long THEN qBCASTL
	ELSE qBCAST];
    END;

  END..