void StmtList(out StmtList/*!*/ stmtList) { Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); List<BigBlock/*!*/> bigblocks = new List<BigBlock/*!*/>(); /* built-up state for the current BigBlock: */ IToken startToken = null; string currentLabel = null; List<Cmd> cs = null; /* invariant: startToken != null ==> cs != null */ /* temporary variables: */ IToken label; Cmd c; BigBlock b; StructuredCmd ec = null; StructuredCmd/*!*/ ecn; TransferCmd tc = null; TransferCmd/*!*/ tcn; while (StartOf(7)) { if (StartOf(8)) { LabelOrCmd(out c, out label); if (c != null) { // LabelOrCmd read a Cmd Contract.Assert(label == null); if (startToken == null) { startToken = c.tok; cs = new List<Cmd>(); } Contract.Assert(cs != null); cs.Add(c); } else { // LabelOrCmd read a label Contract.Assert(label != null); if (startToken != null) { Contract.Assert(cs != null); // dump the built-up state into a BigBlock b = new BigBlock(startToken, currentLabel, cs, null, null); bigblocks.Add(b); cs = null; } startToken = label; currentLabel = label.val; cs = new List<Cmd>(); } } else if (la.kind == 41 || la.kind == 43 || la.kind == 46) { StructuredCmd(out ecn); ec = ecn; if (startToken == null) { startToken = ec.tok; cs = new List<Cmd>(); } Contract.Assert(cs != null); b = new BigBlock(startToken, currentLabel, cs, ec, null); bigblocks.Add(b); startToken = null; currentLabel = null; cs = null; } else { TransferCmd(out tcn); tc = tcn; if (startToken == null) { startToken = tc.tok; cs = new List<Cmd>(); } Contract.Assert(cs != null); b = new BigBlock(startToken, currentLabel, cs, null, tc); bigblocks.Add(b); startToken = null; currentLabel = null; cs = null; } } Expect(29); IToken/*!*/ endCurly = t; if (startToken == null && bigblocks.Count == 0) { startToken = t; cs = new List<Cmd>(); } if (startToken != null) { Contract.Assert(cs != null); b = new BigBlock(startToken, currentLabel, cs, null, null); bigblocks.Add(b); } stmtList = new StmtList(bigblocks, endCurly); }
TransferCmd GotoSuccessor(IToken tok, BigBlock b) { Contract.Requires(b != null); Contract.Requires(tok != null); Contract.Ensures(Contract.Result<TransferCmd>() != null); if (b.successorBigBlock != null) { return new GotoCmd(tok, new List<String> { b.successorBigBlock.LabelName }); } else { return new ReturnCmd(tok); } }
void RecordSuccessors(StmtList stmtList, BigBlock successor) { Contract.Requires(stmtList != null); for (int i = stmtList.BigBlocks.Count; 0 <= --i; ) { BigBlock big = stmtList.BigBlocks[i]; big.successorBigBlock = successor; if (big.ec is WhileCmd) { WhileCmd wcmd = (WhileCmd)big.ec; RecordSuccessors(wcmd.Body, successor); } else { for (IfCmd ifcmd = big.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { RecordSuccessors(ifcmd.thn, successor); if (ifcmd.elseBlock != null) { RecordSuccessors(ifcmd.elseBlock, successor); } } } successor = big; } }
void CheckLegalLabels(StmtList stmtList, StmtList parentContext, BigBlock parentBigBlock) { Contract.Requires(stmtList != null); Contract.Requires((parentContext == null) == (parentBigBlock == null)); Contract.Requires(stmtList.ParentContext == null); // it hasn't been set yet //modifies stmtList.*; Contract.Ensures(stmtList.ParentContext == parentContext); stmtList.ParentContext = parentContext; stmtList.ParentBigBlock = parentBigBlock; // record the labels declared in this StmtList foreach (BigBlock b in stmtList.BigBlocks) { if (b.LabelName != null) { string n = b.LabelName; if (n.StartsWith(prefix)) { if (prefix.Length < n.Length && n[prefix.Length] == '0') { prefix += "1"; } else { prefix += "0"; } } stmtList.Labels.Add(b.LabelName); } } // check that labels in this and nested StmtList's are legal foreach (BigBlock b in stmtList.BigBlocks) { // goto's must reference blocks in enclosing blocks if (b.tc is GotoCmd) { GotoCmd g = (GotoCmd)b.tc; foreach (string/*!*/ lbl in cce.NonNull(g.labelNames)) { Contract.Assert(lbl != null); /* bool found = false; for (StmtList sl = stmtList; sl != null; sl = sl.ParentContext) { if (sl.Labels.Contains(lbl)) { found = true; break; } } if (!found) { this.errorHandler.SemErr(g.tok, "Error: goto label '" + lbl + "' is undefined or out of reach"); } */ if (!allLabels.Contains(lbl)) { this.errorHandler.SemErr(g.tok, "Error: goto label '" + lbl + "' is undefined"); } } } // break labels must refer to an enclosing while statement else if (b.ec is BreakCmd) { BreakCmd bcmd = (BreakCmd)b.ec; Contract.Assert(bcmd.BreakEnclosure == null); // it hasn't been initialized yet bool found = false; for (StmtList sl = stmtList; sl.ParentBigBlock != null; sl = sl.ParentContext) { cce.LoopInvariant(sl != null); BigBlock bb = sl.ParentBigBlock; if (bcmd.Label == null) { // a label-less break statement breaks out of the innermost enclosing while statement if (bb.ec is WhileCmd) { bcmd.BreakEnclosure = bb; found = true; break; } } else if (bcmd.Label == bb.LabelName) { // a break statement with a label can break out of both if statements and while statements if (bb.simpleCmds.Count == 0) { // this is a good target: the label refers to the if/while statement bcmd.BreakEnclosure = bb; } else { // the label of bb refers to the first statement of bb, which in which case is a simple statement, not an if/while statement this.errorHandler.SemErr(bcmd.tok, "Error: break label '" + bcmd.Label + "' must designate an enclosing statement"); } found = true; // don't look any further, since we've found a matching label break; } } if (!found) { if (bcmd.Label == null) { this.errorHandler.SemErr(bcmd.tok, "Error: break statement is not inside a loop"); } else { this.errorHandler.SemErr(bcmd.tok, "Error: break label '" + bcmd.Label + "' must designate an enclosing statement"); } } } // recurse else if (b.ec is WhileCmd) { WhileCmd wcmd = (WhileCmd)b.ec; CheckLegalLabels(wcmd.Body, stmtList, b); } else { for (IfCmd ifcmd = b.ec as IfCmd; ifcmd != null; ifcmd = ifcmd.elseIf) { CheckLegalLabels(ifcmd.thn, stmtList, b); if (ifcmd.elseBlock != null) { CheckLegalLabels(ifcmd.elseBlock, stmtList, b); } } } } }