-- Flow.mesa
--   last modified by Sweet, February 20, 1981  2:58 PM
--   last modified by Satterthwaite,  5-Oct-81 11:28:06

DIRECTORY
  Alloc: TYPE USING [Notifier],
  Code: TYPE USING [caseCVState, catchcount, CodeNotImplemented, curctxlvl],
  CodeDefs: TYPE USING [
    Base, Byte, codeType, JumpType, LabelCCIndex, LabelInfoRecord, LabelInfoIndex,
    LabelInfoNull, Lexeme, NamedLabelInfoIndex, NullLex, VarComponent, VarIndex],
  Environment: TYPE USING [bitsPerWord],
  FOpCodes: TYPE USING [
    qDCOMP, qDUCOMP, qFCOMP, qLI, qLL, qLP, qOR, qPUSH, qSFC],
  Literals: TYPE USING [Base, LTIndex, ltType],
  P5: TYPE USING [
    Exp, FreeHeapLex, GenAnonLex, LogHeapFree, PushLex, PushRhs, 
    StatementTree, SysCall, TypeRel],
  P5L: TYPE USING [
    EasilyLoadable, FieldOfVar, InCode, LoadAddress, LoadBoth, LoadComponent, 
    LoadVar, LongVarAddress, MakeComponent, ReusableCopies, VarAlignment,
    VarForLex, Words],
  P5S: TYPE USING [],
  P5U: TYPE USING [
    FreeChunk, GetChunk, InsertLabel, LabelAlloc, Out0, Out1, OutJump, 
    PushLitVal, TreeLiteral, TreeLiteralValue],
  PrincOps: TYPE USING [localbase, returnOffset],
  SDDefs: TYPE USING [sBLTE, sBLTEC, sBLTECL, sBLTEL],
  Stack: TYPE USING [Decr, Dump, Incr, Mark, Require],
  Symbols: TYPE USING [HTIndex],
  Tree: TYPE USING [Base, Index, Link, NodeName, Null, treeType],
  TreeOps: TYPE USING [GetHash, GetNode, ScanList];

Flow: PROGRAM
    IMPORTS CPtr: Code, P5U, P5L, P5, TreeOps, Stack 
    EXPORTS CodeDefs, P5, P5S =
  BEGIN
  OPEN CodeDefs;

  -- imported definitions

  wordlength: CARDINAL = Environment.bitsPerWord;
  HTIndex: TYPE = Symbols.HTIndex;

  labelStack: LabelInfoIndex ← LabelInfoNull;

  UndeclaredLabel: SIGNAL [HTIndex] = CODE;

  tb: Tree.Base;		-- tree base (local copy)
  cb: CodeDefs.Base;		-- code base (local copy)
  ltb: Literals.Base;		-- literal table

  FlowNotify: PUBLIC Alloc.Notifier =
    BEGIN  -- called by allocator whenever table area is repacked
    tb ← base[Tree.treeType];
    cb ← base[codeType];
    ltb ← base[Literals.ltType];
    END;

  JumpNN: PACKED ARRAY Tree.NodeName[relE..relLE] OF JumpType ← [
    relE:JumpE, relN:JumpN, relL:JumpL, relGE:JumpGE, relG:JumpG, relLE:JumpLE];

  UJumpNN: PACKED ARRAY Tree.NodeName[relE..relLE] OF JumpType ← [
    relE:JumpE, relN:JumpN, relL:UJumpL, relGE:UJumpGE, relG:UJumpG, relLE:UJumpLE];

  RNN: ARRAY Tree.NodeName[relE..relLE] OF Tree.NodeName = [
    relE:relE, relN:relN, relL:relG, relGE:relLE, relG:relL, relLE:relGE];

  CNN: ARRAY Tree.NodeName[relE..relLE] OF Tree.NodeName = [
    relE:relN, relN:relE, relL:relGE, relGE:relL, relG:relLE, relLE:relG];

  FlowTree: PUBLIC PROC [t: Tree.Link, tf: BOOLEAN, label: LabelCCIndex] =
    BEGIN -- produces code to jump to label on condition tf
    node: Tree.Index;
    WITH t SELECT FROM
      symbol =>
	BEGIN
	l: se Lexeme = [se[index]];
	P5.PushLex[l];
	P5U.PushLitVal[0];
	P5U.OutJump[IF tf THEN JumpN ELSE JumpE, label];
	END;
      subtree =>
	BEGIN
	node ← index;
	SELECT tb[node].name FROM
	  and, or =>
	    BEGIN ENABLE P5.LogHeapFree => RESUME [FALSE, NullLex];
	    label1: LabelCCIndex;
	    sw: BOOLEAN = (IF tb[node].name = and THEN tf ELSE ~tf);
	    IF sw THEN
	      BEGIN
	      label1←P5U.LabelAlloc[];
	      FlowTree[tb[node].son[1], ~tf, label1];
	      FlowTree[tb[node].son[2], tf, label];
	      P5U.InsertLabel[label1];
	      END
	    ELSE
	      BEGIN
	      FlowTree[tb[node].son[1], tf, label];
	      FlowTree[tb[node].son[2], tf, label];
	      END;
	    END;
	  not => FlowTree[tb[node].son[1], ~tf, label];
	  cast => FlowTree[tb[node].son[1], tf, label]; -- ignore casts
	  in => FlowIn[t, tf, label];
	  notin => FlowIn[t, ~tf, label];
	  relE, relN, relL, relGE, relG, relLE => SFRel[node, tf, label];
	  istype => P5.TypeRel[node, tf, label];
	  ENDCASE => -- must be a BOOLEAN expression
	    BEGIN
	    P5.PushRhs[t];
	    P5U.PushLitVal[0];
	    P5U.OutJump[IF tf THEN JumpN ELSE JumpE, label];
	    END;
	END;
      literal =>
	BEGIN
	val: CARDINAL = P5U.TreeLiteralValue[t];
	IF tf = (val # 0) THEN P5U.OutJump[Jump, label];
	END;
      ENDCASE;
    END;

  SFRel: PROC [node: Tree.Index, tf: BOOLEAN, label: LabelCCIndex] =
    BEGIN -- main subroutine of Cflow for handling relationals
    t1: Tree.Link ← tb[node].son[1];
    t2: Tree.Link;
    n: Tree.NodeName ← tb[node].name;
    hLex1, hLex2: se Lexeme ← NullLex;
    r1, r2: VarIndex;
    IF P5U.TreeLiteral[t1] THEN {n ← RNN[n]; t2 ← t1; t1 ← tb[node].son[2]}
    ELSE t2 ← tb[node].son[2];
    IF ~tf THEN n ← CNN[n];
    r1 ← P5L.VarForLex[P5.Exp[t1 ! P5.LogHeapFree =>
      IF calltree = t1 THEN RESUME [TRUE, hLex1 ← P5.GenAnonLex[1]]
      ELSE RESUME [FALSE, NullLex]]];
    r2 ← P5L.VarForLex[P5.Exp[t2 ! P5.LogHeapFree =>
      IF calltree = t2 THEN RESUME [TRUE, hLex2 ← P5.GenAnonLex[1]]
      ELSE RESUME [FALSE, NullLex]]];
    VarVarComp[
      r1: r1, r2: r2, n: n,
      real: tb[node].attr1, signed: tb[node].attr3, 
      hLex1: hLex1, hLex2: hLex2, label: label,
      commutable: t1 # Tree.Null];
    END;

  VarVarComp: PROC [
      r1, r2: VarIndex, n: Tree.NodeName, real, signed: BOOLEAN,
      hLex1, hLex2: se Lexeme, label: LabelCCIndex,
      commutable: BOOLEAN ← FALSE] =
    BEGIN
    wSize: CARDINAL;
    bSize, bd1, bd2: [0..wordlength);
    nw: CARDINAL;

    FreeHeapNodes: PROC =
      BEGIN
      IF hLex1 # NullLex THEN P5.FreeHeapLex[hLex1];
      IF hLex2 # NullLex THEN P5.FreeHeapLex[hLex2];
      hLex1 ← hLex2 ← NullLex;
      END;

    [wSize: wSize, bSize: bSize, bd: bd1] ← P5L.VarAlignment[r1, load];
    [bd: bd2] ← P5L.VarAlignment[r2, load];
    nw ← P5L.Words[wSize, bSize]; -- r1 and r2 are same size if > 1
    IF nw > 1 AND bd1 # bd2 THEN SIGNAL CPtr.CodeNotImplemented;
    IF nw <= 2 THEN
      BEGIN
      c1: VarComponent ← P5L.MakeComponent[r1];
      c2: VarComponent ← P5L.MakeComponent[r2];
	BEGIN
	IF n = relE OR n = relN THEN WITH c2 SELECT FROM
	  const => IF wSize = 2 AND bSize = 0 AND ~real AND d1 = 0 AND d2 = 0 THEN
	    BEGIN
	    P5L.LoadComponent[c1];
	    P5U.Out0[FOpCodes.qOR];
	    GO TO double;
	    END;
	  ENDCASE;
	P5L.LoadBoth[@c1, @c2, (n = relE OR n = relN) AND commutable];
	IF nw = 2 THEN
	  BEGIN
	  P5U.Out0[IF real THEN FOpCodes.qFCOMP 
		ELSE IF signed THEN FOpCodes.qDCOMP ELSE FOpCodes.qDUCOMP];
	  GO TO double;
	  END;
	FreeHeapNodes[];
	EXITS
	  double => {FreeHeapNodes[]; P5U.Out1[FOpCodes.qLI, 0]};
	END;
      P5U.OutJump[IF signed OR nw = 2 THEN JumpNN[n] ELSE UJumpNN[n], label];
      END
    ELSE
      BEGIN -- multiword quantities, n = relE or relN
      IF bSize = 0 THEN
	BEGIN
	code: BOOLEAN ← FALSE;
	long1, long2: BOOLEAN;
	CompFn: ARRAY BOOLEAN OF ARRAY BOOLEAN OF Byte = [
	  [SDDefs.sBLTE, SDDefs.sBLTEL], [SDDefs.sBLTEC, SDDefs.sBLTECL]];
	Stack.Dump[]; Stack.Mark[]; -- so procedure call will work
	IF P5L.InCode[r1] THEN {tr: VarIndex = r1; r1 ← r2; r2 ← tr};
	IF P5L.InCode[r2] THEN code ← TRUE;
	long2 ← P5L.LongVarAddress[r2];
	long1 ← P5L.LoadAddress[r: r1, codeOk: FALSE];
	IF ~long1 AND long2 THEN {P5U.Out0[FOpCodes.qLP]; long1 ← TRUE};
	P5U.Out1[FOpCodes.qLI, nw];
	[] ← P5L.LoadAddress[r: r2, codeOk: TRUE];
	IF ~code AND long1 AND ~long2 THEN P5U.Out0[FOpCodes.qLP];
	P5.SysCall[CompFn[code][long1]];
	Stack.Incr[1];
        FreeHeapNodes[];
	P5U.Out1[FOpCodes.qLI, 0];
	P5U.OutJump[IF n # relE THEN JumpE ELSE JumpN, label]
	END
      ELSE
	BEGIN -- do in two pieces
	r1a, r1b: VarIndex;
	r2a, r2b: VarIndex;
	firstEq, secondComp: LabelCCIndex;
	[first: r1b, next: r1a] ← P5L.ReusableCopies[r1, load, FALSE];
	[first: r2b, next: r2a] ← P5L.ReusableCopies[r2, load, FALSE];
	IF bd1 # 0 THEN
	  BEGIN
	  P5L.FieldOfVar[r: r1b, bSize: bSize];
	  P5L.FieldOfVar[r: r1a, bd: bSize, wSize: wSize];
	  P5L.FieldOfVar[r: r2b, bSize: bSize];
	  P5L.FieldOfVar[r: r2a, bd: bSize, wSize: wSize];
	  END
	ELSE
	  BEGIN
	  P5L.FieldOfVar[r: r1b, wSize: wSize];
	  P5L.FieldOfVar[r: r1a, wd: wSize, bSize: bSize];
	  P5L.FieldOfVar[r: r2b, wSize: wSize];
	  P5L.FieldOfVar[r: r2a, wd: wSize, bSize: bSize];
	  END;
        secondComp ← P5U.LabelAlloc[];
	IF n = relN THEN firstEq ← label 
	ELSE firstEq ← P5U.LabelAlloc[];
	VarVarComp[r1b, r2b, relE, real, signed, NullLex, NullLex, secondComp];
	FreeHeapNodes[];  -- this looks awful here, but Final sorts it all out
	P5U.OutJump[Jump, firstEq];
	P5U.InsertLabel[secondComp];
	VarVarComp[r1a, r2a, n, real, signed, hLex1, hLex2, label];
	IF n # relN THEN P5U.InsertLabel[firstEq];
	END;
      END;
    END;

  FlowIn: PROC [t: Tree.Link, tf: BOOLEAN, label: LabelCCIndex] =
    BEGIN -- generates code for IN expression in flow context
    node: Tree.Index = TreeOps.GetNode[t];
    t1: Tree.Link = tb[node].son[1];
    subNode: Tree.Index = TreeOps.GetNode[tb[node].son[2]];	-- interval node
    n: Tree.NodeName = tb[subNode].name;
    real: BOOLEAN = tb[subNode].attr1;
    double: BOOLEAN = real OR tb[subNode].attr2;
    signed: BOOLEAN = tb[subNode].attr3;
    tLow: Tree.Link = tb[subNode].son[1];
    tUp: Tree.Link = tb[subNode].son[2];
    jumpNN: POINTER TO PACKED ARRAY Tree.NodeName[relE..relLE] OF JumpType ←
      IF double OR signed THEN @JumpNN ELSE @UJumpNN;
    r1: VarIndex;
    hLex: se Lexeme ← NullLex;

    IF real THEN  
      IF t = Tree.Null AND CPtr.caseCVState = singleLoaded THEN
	Stack.Require[1]
      ELSE Stack.Dump[];
    r1 ← P5L.VarForLex[P5.Exp[t1 ! P5.LogHeapFree =>
          IF calltree = t1 THEN RESUME [TRUE, hLex ← P5.GenAnonLex[1]]
	  ELSE RESUME [FALSE, NullLex]]];
    IF ~real AND Zero[tLow] AND (~signed OR Constant[tUp])
     AND (n = intCO OR n = intCC) THEN
      BEGIN
      P5L.LoadVar[r1];
      IF hLex # NullLex THEN {P5.FreeHeapLex[hLex]; hLex ← NullLex};
      P5.PushRhs[tUp ! P5.LogHeapFree => 
	    IF calltree = tUp THEN RESUME [TRUE, hLex ← P5.GenAnonLex[1]]
	    ELSE RESUME [FALSE, NullLex]];
      IF double THEN
 	{P5U.Out0[FOpCodes.qDUCOMP]; P5U.PushLitVal[0]; jumpNN ← @JumpNN}
      ELSE jumpNN ← @UJumpNN;
      IF hLex # NullLex THEN {P5.FreeHeapLex[hLex]; hLex ← NullLex};
      SELECT n FROM
	intCO => P5U.OutJump[IF tf THEN jumpNN[relL] ELSE jumpNN[relGE], label];
	intCC => P5U.OutJump[IF tf THEN jumpNN[relLE] ELSE jumpNN[relG], label];
	ENDCASE;
      END
    ELSE
      BEGIN
      fail: LabelCCIndex = P5U.LabelAlloc[];

      OutDComp: PROC =
	BEGIN
	P5U.Out0[IF real THEN FOpCodes.qFCOMP
	    ELSE IF signed THEN FOpCodes.qDCOMP ELSE FOpCodes.qDUCOMP];
	P5U.PushLitVal[0];
	END;

      var1: VarComponent ← P5L.MakeComponent[r1];
      IF double THEN var1 ← P5L.EasilyLoadable[var1, load];
      P5L.LoadComponent[var1];
      IF hLex # NullLex THEN {P5.FreeHeapLex[hLex]; hLex ← NullLex};
      P5.PushRhs[tLow ! P5.LogHeapFree =>
	IF calltree = tLow THEN RESUME [TRUE, hLex ← P5.GenAnonLex[1]]
	ELSE RESUME [FALSE, NullLex]];
      IF double THEN OutDComp[];
      IF hLex # NullLex THEN {P5.FreeHeapLex[hLex]; hLex ← NullLex};
      SELECT n FROM
	intOO,intOC => P5U.OutJump[jumpNN[relLE], IF tf THEN fail ELSE label];
	intCO,intCC => P5U.OutJump[jumpNN[relL], IF tf THEN fail ELSE label];
	ENDCASE;
      IF double THEN P5L.LoadComponent[var1]
      ELSE P5U.Out0[FOpCodes.qPUSH];
      P5.PushRhs[tUp ! P5.LogHeapFree =>
	IF calltree = tUp THEN RESUME [TRUE, hLex ← P5.GenAnonLex[1]]
	ELSE RESUME [FALSE, NullLex]];
      IF double THEN OutDComp[];
      IF hLex # NullLex THEN P5.FreeHeapLex[hLex]; 
      SELECT n FROM
	intOO,intCO => P5U.OutJump[IF tf THEN jumpNN[relL] ELSE jumpNN[relGE], label];
	intOC,intCC => P5U.OutJump[IF tf THEN jumpNN[relLE] ELSE jumpNN[relG], label];
	ENDCASE;
      P5U.InsertLabel[fail];
      END;
    END;

  Constant: PROC [t: Tree.Link] RETURNS [BOOLEAN] =
    BEGIN
    RETURN [WITH t SELECT FROM
      literal => TRUE,
      subtree => tb[index].name = mwconst,
      ENDCASE => FALSE]
    END;

  Zero: PROC [t: Tree.Link] RETURNS [BOOLEAN] =
    BEGIN
    lti: Literals.LTIndex;
    WITH lt: t SELECT FROM
      literal => WITH lt.info SELECT FROM
	word => lti ← index;
	ENDCASE => RETURN [FALSE];
      subtree => 
	BEGIN
	node: Tree.Index = lt.index;
	IF tb[node].name = mwconst THEN RETURN [Zero[tb[node].son[1]]]
	ELSE RETURN [FALSE];
	END;
      ENDCASE => RETURN [FALSE];
    WITH ll: ltb[lti] SELECT FROM
      short => RETURN [ll.value = 0];
      long => SELECT ll.length FROM
	1 => RETURN [ll.value[0] = 0];
	2 => RETURN [ll.value[1] = 0 AND ll.value[0] = 0];
	ENDCASE => RETURN [FALSE];
      ENDCASE => RETURN [FALSE];
    END;

  CatchMark: PUBLIC PROC [node: Tree.Index] =
    BEGIN -- process a CONTINUEd or RETRYed statement
    l: LabelInfoIndex ← P5U.GetChunk[SIZE[LabelInfoRecord]];
    retry: LabelCCIndex = P5U.LabelAlloc[];
    continue: LabelCCIndex = P5U.LabelAlloc[];
    cb[l] ← [thread: labelStack, catchLevel: CPtr.catchcount, body:
      stmt[retry: retry, continue: continue]];
    labelStack ← l;
    P5U.InsertLabel[retry];
    tb[node].son[1] ← P5.StatementTree[tb[node].son[1]];
    P5U.InsertLabel[continue];
    IF labelStack # l THEN ERROR;
    labelStack ← cb[l].thread;
    P5U.FreeChunk[l, SIZE[LabelInfoRecord]];
    END;

  Label: PUBLIC PROC [node: Tree.Index] =
    BEGIN -- process an exitable block
    elabel: LabelCCIndex = P5U.LabelAlloc[];
    labelmark: LabelInfoIndex = labelStack;
    TreeOps.ScanList[tb[node].son[2], LabelCreate];
    tb[node].son[1] ← P5.StatementTree[tb[node].son[1]];
    P5U.OutJump[Jump, elabel];
    LabelList[tb[node].son[2], elabel, labelmark];
    P5U.InsertLabel[elabel];
    END;


  GetLabelMark: PUBLIC PROC RETURNS [LabelInfoIndex] =
    {RETURN [labelStack]};


  PopLabels: PROC [first: LabelInfoIndex] =
    BEGIN
    oldl: LabelInfoIndex;
    UNTIL first = LabelInfoNull DO
      oldl ← first;
      first ← cb[first].thread;
      P5U.FreeChunk[oldl, SIZE[LabelInfoRecord]];
      ENDLOOP;
    END;

  ObscureLabels: PROC [mark: LabelInfoIndex] RETURNS [first: LabelInfoIndex] =
    BEGIN
    first ← labelStack;
    UNTIL labelStack = LabelInfoNull OR  cb[labelStack].thread = mark DO 
      labelStack ← cb[labelStack].thread;
      ENDLOOP;
    cb[labelStack].thread ← LabelInfoNull;
    labelStack ← mark;
    RETURN
    END;

  FindLabel: PROC [start: LabelInfoIndex, hti: HTIndex] RETURNS [NamedLabelInfoIndex] =
    BEGIN
    FOR l: LabelInfoIndex ← start, cb[l].thread UNTIL l = LabelInfoNull DO
      WITH li: cb[l] SELECT FROM
        named => IF li.hti = hti THEN RETURN [LOOPHOLE[l]];
        ENDCASE;
      ENDLOOP;
    ERROR UndeclaredLabel[hti]
    END;

  LabelList: PUBLIC PROC [t: Tree.Link, elabel: LabelCCIndex, mark: LabelInfoIndex] =
    BEGIN -- generates code for labels
    toBind: LabelInfoIndex = ObscureLabels[mark];

    PutLabel: PROC [t: Tree.Link] =
      BEGIN
      P5U.InsertLabel[cb[FindLabel[toBind, TreeOps.GetHash[t]]].cci];
      END;

    CLabelItem: PROC [t: Tree.Link] =
      BEGIN -- generates code for a labelitem
      node: Tree.Index = TreeOps.GetNode[t];
      TreeOps.ScanList[tb[node].son[1], PutLabel];
      tb[node].son[2] ← P5.StatementTree[tb[node].son[2]];
      P5U.OutJump[Jump, elabel];
      END;

    TreeOps.ScanList[t, CLabelItem];
    PopLabels[toBind];
    END;



  LabelCreate: PUBLIC PROC [t: Tree.Link] =
    BEGIN -- sets up label cells for labels
    node: Tree.Index = TreeOps.GetNode[t];
    TreeOps.ScanList[tb[node].son[1], PushLabel];
    END;


  PushLabel: PROC [t: Tree.Link] =
    BEGIN -- stacks a label for an EXIT clause
    l: LabelInfoIndex = P5U.GetChunk[SIZE[LabelInfoRecord]];
    cb[l] ← [thread: labelStack, catchLevel: CPtr.catchcount, body:
	  named[hti: TreeOps.GetHash[t], cci: P5U.LabelAlloc[]]];
    labelStack ← l;
    END;


  MakeExitLabel: PUBLIC PROC RETURNS [exit, loop: LabelCCIndex] =
    BEGIN -- sets up anonymous label for EXITs
    l: LabelInfoIndex = P5U.GetChunk[SIZE[LabelInfoRecord]];
    exit ← P5U.LabelAlloc[];
    loop ← P5U.LabelAlloc[];
    cb[l] ← [thread: labelStack, catchLevel: CPtr.catchcount, body:
      loop[exit: exit, loop: loop]];
    labelStack ← l;
    RETURN
    END;


  Retry: PUBLIC PROC =
    BEGIN -- process RETRY statement
    FOR l: LabelInfoIndex ← labelStack, cb[l].thread UNTIL l = LabelInfoNull DO
      WITH li: cb[l] SELECT FROM
	stmt => {ExplicitJump[li.catchLevel, li.retry]; RETURN};
	ENDCASE;
      ENDLOOP;
    ERROR
    END;


  Continue: PUBLIC PROC =
    BEGIN -- process CONTINUE statement
    FOR l: LabelInfoIndex ← labelStack, cb[l].thread UNTIL l = LabelInfoNull DO
      WITH li: cb[l] SELECT FROM
	stmt => {ExplicitJump[li.catchLevel, li.continue]; RETURN};
	ENDCASE;
      ENDLOOP;
    ERROR
    END;


  Exit: PUBLIC PROC =
    BEGIN  -- generate code for EXIT
    FOR l: LabelInfoIndex ← labelStack, cb[l].thread UNTIL l = LabelInfoNull DO
      WITH li: cb[l] SELECT FROM
	loop => {ExplicitJump[li.catchLevel, li.exit]; RETURN};
	ENDCASE;
      ENDLOOP;
    ERROR
    END;

  Loop: PUBLIC PROC =
    BEGIN  -- generate code for LOOP
    FOR l: LabelInfoIndex ← labelStack, cb[l].thread UNTIL l = LabelInfoNull DO
      WITH li: cb[l] SELECT FROM
	loop => {ExplicitJump[li.catchLevel, li.loop]; RETURN};
	ENDCASE;
      ENDLOOP;
    ERROR
    END;


  GoTo: PUBLIC PROC [node: Tree.Index] =
    BEGIN  -- generate code for GOTO
    l: NamedLabelInfoIndex = FindLabel[labelStack, TreeOps.GetHash[tb[node].son[1]]];
    ExplicitJump[cb[l].catchLevel, cb[l].cci];
    END;


  ExplicitJump: PROC [cc: CARDINAL, lc: LabelCCIndex] =
    BEGIN -- process EXIT/REPEAT/GOTO/etc. statement
    IF CPtr.catchcount = cc THEN P5U.OutJump[Jump, lc]
    ELSE
      BEGIN
      var: VarComponent = [wSize: 1, space: frame[
	wd: PrincOps.localbase,
	level: CPtr.curctxlvl-(CPtr.catchcount-cc-1)]];
      P5L.LoadComponent[var];
      P5U.PushLitVal[-1];
      P5U.Out1[FOpCodes.qLL, PrincOps.returnOffset];
      P5U.Out0[FOpCodes.qSFC];
      Stack.Decr[2];
      P5U.OutJump[Jump, lc];
      END;
    END;

  END.