/*--------------------------------------------------------------------------- // BoogiePL - //--------------------------------------------------------------------------*/ /*using System;*/ using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using Microsoft.Boogie; using Microsoft.Basetypes; using Bpl = Microsoft.Boogie; COMPILER BoogiePL /*--------------------------------------------------------------------------*/ readonly Program/*!*/ Pgm; readonly Expr/*!*/ dummyExpr; readonly Cmd/*!*/ dummyCmd; readonly Block/*!*/ dummyBlock; readonly Bpl.Type/*!*/ dummyType; readonly List/*!*/ dummyExprSeq; readonly TransferCmd/*!*/ dummyTransferCmd; readonly StructuredCmd/*!*/ dummyStructuredCmd; /// ///Returns the number of parsing errors encountered. If 0, "program" returns as ///the parsed program. /// public static int Parse (string/*!*/ filename, /*maybe null*/ List defines, out /*maybe null*/ Program program, bool useBaseName=false) /* throws System.IO.IOException */ { Contract.Requires(filename != null); Contract.Requires(cce.NonNullElements(defines,true)); if (defines == null) { defines = new List(); } if (filename == "stdin.bpl") { var s = ParserHelper.Fill(Console.In, defines); return Parse(s, filename, out program, useBaseName); } else { FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); var s = ParserHelper.Fill(stream, defines); var ret = Parse(s, filename, out program, useBaseName); stream.Close(); return ret; } } public static int Parse (string s, string/*!*/ filename, out /*maybe null*/ Program program, bool useBaseName=false) /* throws System.IO.IOException */ { Contract.Requires(s != null); Contract.Requires(filename != null); byte[]/*!*/ buffer = cce.NonNull(UTF8Encoding.Default.GetBytes(s)); MemoryStream ms = new MemoryStream(buffer,false); Errors errors = new Errors(); Scanner scanner = new Scanner(ms, errors, filename, useBaseName); Parser parser = new Parser(scanner, errors, false); parser.Parse(); if (parser.errors.count == 0) { program = parser.Pgm; program.ProcessDatatypeConstructors(); return 0; } else { program = null; return parser.errors.count; } } public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, bool disambiguation) : this(scanner, errors) { // initialize readonly fields Pgm = new Program(); dummyExpr = new LiteralExpr(Token.NoToken, false); dummyCmd = new AssumeCmd(Token.NoToken, dummyExpr); dummyBlock = new Block(Token.NoToken, "dummyBlock", new List(), new ReturnCmd(Token.NoToken)); dummyType = new BasicType(Token.NoToken, SimpleType.Bool); dummyExprSeq = new List (); dummyTransferCmd = new ReturnCmd(Token.NoToken); dummyStructuredCmd = new BreakCmd(Token.NoToken, null); } // Class to represent the bounds of a bitvector expression t[a:b]. // Objects of this class only exist during parsing and are directly // turned into BvExtract before they get anywhere else private class BvBounds : Expr { public BigNum Lower; public BigNum Upper; public BvBounds(IToken/*!*/ tok, BigNum lower, BigNum upper) : base(tok) { Contract.Requires(tok != null); this.Lower = lower; this.Upper = upper; } public override Bpl.Type/*!*/ ShallowType { get {Contract.Ensures(Contract.Result() != null); return Bpl.Type.Int; } } public override void Resolve(ResolutionContext/*!*/ rc) { // Contract.Requires(rc != null); rc.Error(this, "bitvector bounds in illegal position"); } public override void Emit(TokenTextWriter/*!*/ stream, int contextBindingStrength, bool fragileContext) { Contract.Assert(false);throw new cce.UnreachableException(); } public override void ComputeFreeVariables(GSet/*!*/ freeVars) { Contract.Assert(false);throw new cce.UnreachableException(); } } /*--------------------------------------------------------------------------*/ CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". digit = "0123456789". special = "'~#$^_.?`". glyph = "`~!@#$%^&*()-_=+[{]}|;:',<.>/?\\". cr = '\r'. lf = '\n'. tab = '\t'. space = ' '. quote = '"'. newLine = cr + lf. regularStringChar = ANY - quote - newLine. nondigit = letter + special. nonquote = letter + digit + space + glyph. /*------------------------------------------------------------------------*/ TOKENS ident = [ '\\' ] nondigit {nondigit | digit}. bvlit = digit {digit} 'b' 'v' digit {digit}. digits = digit {digit}. string = quote { regularStringChar | "\\\"" } quote. decimal = digit {digit} 'e' [ '-' ] digit {digit} . dec_float = digit {digit} '.' digit {digit} [ 'e' [ '-' ] digit {digit} ] . float = [ '-' ] digit {digit} 'e' [ '-' ] digit {digit} 'f' digit {digit} 'e' digit {digit} | '0' 'N' 'a' 'N' digit {digit} 'e' digit {digit} | '0' 'n' 'a' 'n' digit {digit} 'e' digit {digit} | '0' '+' 'o' 'o' digit {digit} 'e' digit {digit} | '0' '-' 'o' 'o' digit {digit} 'e' digit {digit} . COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab /*------------------------------------------------------------------------*/ PRODUCTIONS /*------------------------------------------------------------------------*/ BoogiePL = (. List/*!*/ vs; List/*!*/ ds; Axiom/*!*/ ax; List/*!*/ ts; Procedure/*!*/ pr; Implementation im; Implementation/*!*/ nnim; .) { Consts (. foreach(Bpl.Variable/*!*/ v in vs){ Contract.Assert(v != null); Pgm.AddTopLevelDeclaration(v); } .) | Function (. foreach(Bpl.Declaration/*!*/ d in ds){ Contract.Assert(d != null); Pgm.AddTopLevelDeclaration(d); } .) | Axiom (. Pgm.AddTopLevelDeclaration(ax); .) | UserDefinedTypes (. foreach(Declaration/*!*/ td in ts){ Contract.Assert(td != null); Pgm.AddTopLevelDeclaration(td); } .) | GlobalVars (. foreach(Bpl.Variable/*!*/ v in vs){ Contract.Assert(v != null); Pgm.AddTopLevelDeclaration(v); } .) | Procedure (. Pgm.AddTopLevelDeclaration(pr); if (im != null) { Pgm.AddTopLevelDeclaration(im); } .) | Implementation (. Pgm.AddTopLevelDeclaration(nnim); .) } EOF . /*------------------------------------------------------------------------*/ GlobalVars<.out List/*!*/ ds.> = (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); QKeyValue kv = null; ds = new List(); var dsx = ds; .) "var" { Attribute } IdsTypeWheres ";" . LocalVars<.List/*!*/ ds.> = (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); QKeyValue kv = null; .) "var" { Attribute } IdsTypeWheres ";" . ProcFormals<.bool incoming, bool allowWhereClauses, out List/*!*/ ds.> = (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); ds = new List(); var dsx = ds; var context = allowWhereClauses ? "procedure formals" : "the 'implementation' copies of formals"; .) "(" [ AttrsIdsTypeWheres ] ")" . BoundVars<.IToken/*!*/ x, out List/*!*/ ds.> = (. Contract.Requires(x != null); Contract.Ensures(Contract.ValueAtReturn(out ds) != null); List/*!*/ tyds = new List(); ds = new List(); var dsx = ds; .) AttrsIdsTypeWheres . /*------------------------------------------------------------------------*/ /* IdsType is used with const declarations */ IdsType<.out List/*!*/ tyds.> = (. Contract.Ensures(Contract.ValueAtReturn(out tyds) != null); List/*!*/ ids; Bpl.Type/*!*/ ty; .) Idents ":" Type (. tyds = new List(); foreach(Token/*!*/ id in ids){ Contract.Assert(id != null); tyds.Add(new TypedIdent(id, id.val, ty, null)); } .) . /* AttrsIdsTypeWheres is used with the declarations of formals and bound variables */ AttrsIdsTypeWheres<. bool allowAttributes, bool allowWhereClauses, string context, System.Action action .> = AttributesIdsTypeWhere { "," AttributesIdsTypeWhere } . IdsTypeWheres<. bool allowWhereClauses, string context, System.Action action .> = IdsTypeWhere { "," IdsTypeWhere } . AttributesIdsTypeWhere<. bool allowAttributes, bool allowWhereClauses, string context, System.Action action .> = (. QKeyValue kv = null; .) { Attribute (. if (!allowAttributes) { kv = null; this.SemErr("attributes are not allowed on " + context); } .) } IdsTypeWhere . /* context is allowed to be null if allowWhereClauses is true */ IdsTypeWhere<. bool allowWhereClauses, string context, System.Action action .> = (. List/*!*/ ids; Bpl.Type/*!*/ ty; Expr wh = null; Expr/*!*/ nne; .) Idents ":" Type [ "where" Expression (. if (!allowWhereClauses) { this.SemErr("where clause not allowed on " + context); } else { wh = nne; } .) ] (. foreach(Token/*!*/ id in ids){ Contract.Assert(id != null); action(new TypedIdent(id, id.val, ty, wh)); } .) . /*------------------------------------------------------------------------*/ Type = (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; ty = dummyType; .) ( TypeAtom | Ident (. List/*!*/ args = new List (); .) [ TypeArgs ] (. ty = new UnresolvedTypeIdentifier (tok, tok.val, args); .) | MapType ) . TypeArgs<.List/*!*/ ts.> = (.Contract.Requires(ts != null); IToken/*!*/ tok; Bpl.Type/*!*/ ty; .) ( TypeAtom (. ts.Add(ty); .) [ TypeArgs ] | Ident (. List/*!*/ args = new List (); ts.Add(new UnresolvedTypeIdentifier (tok, tok.val, args)); .) [ TypeArgs ] | MapType (. ts.Add(ty); .) ) . TypeAtom = (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); ty = dummyType; .) ( "int" (. ty = new BasicType(t, SimpleType.Int); .) | "real" (. ty = new BasicType(t, SimpleType.Real); .) | "bool" (. ty = new BasicType(t, SimpleType.Bool); .) /* note: bitvectors and floats are handled in UnresolvedTypeIdentifier */ | "(" Type ")" ) . MapType = (.Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken tok = null; IToken/*!*/ nnTok; List/*!*/ arguments = new List(); Bpl.Type/*!*/ result; List/*!*/ typeParameters = new List(); .) [ TypeParams (. tok = nnTok; .) ] "[" (. if (tok == null) tok = t; .) [ Types ] "]" Type (. ty = new MapType(tok, typeParameters, arguments, result); .) . TypeParams<.out IToken/*!*/ tok, out List/*!*/ typeParams.> = (.Contract.Ensures(Contract.ValueAtReturn(out tok) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); List/*!*/ typeParamToks; .) "<" (. tok = t; .) Idents ">" (. typeParams = new List (); foreach(Token/*!*/ id in typeParamToks){ Contract.Assert(id != null); typeParams.Add(new TypeVariable(id, id.val));} .) . Types<.List/*!*/ ts.> = (. Contract.Requires(ts != null); Bpl.Type/*!*/ ty; .) Type (. ts.Add(ty); .) { "," Type (. ts.Add(ty); .) } . /*------------------------------------------------------------------------*/ Consts<.out List/*!*/ ds.> = (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); IToken/*!*/ y; List/*!*/ xs; ds = new List(); bool u = false; QKeyValue kv = null; bool ChildrenComplete = false; List Parents = null; .) "const" (. y = t; .) { Attribute } [ "unique" (. u = true; .) ] IdsType [ OrderSpec ] (. bool makeClone = false; foreach(TypedIdent/*!*/ x in xs){ Contract.Assert(x != null); // ensure that no sharing is introduced List ParentsClone; if (makeClone && Parents != null) { ParentsClone = new List (); foreach (ConstantParent/*!*/ p in Parents){ Contract.Assert(p != null); ParentsClone.Add(new ConstantParent ( new IdentifierExpr (p.Parent.tok, p.Parent.Name), p.Unique));} } else { ParentsClone = Parents; } makeClone = true; ds.Add(new Constant(y, x, u, ParentsClone, ChildrenComplete, kv)); } .) ";" . OrderSpec<.out bool ChildrenComplete, out List Parents.> = (.Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out Parents),true)); ChildrenComplete = false; Parents = null; bool u; IToken/*!*/ parent; .) "extends" (. Parents = new List (); u = false; .) [ [ "unique" (. u = true; .) ] Ident (. Parents.Add(new ConstantParent ( new IdentifierExpr(parent, parent.val), u)); .) { "," (. u = false; .) [ "unique" (. u = true; .) ] Ident (. Parents.Add(new ConstantParent ( new IdentifierExpr(parent, parent.val), u)); .) } ] [ "complete" (. ChildrenComplete = true; .) ] . /*------------------------------------------------------------------------*/ Function<.out List/*!*/ ds.> = (. Contract.Ensures(Contract.ValueAtReturn(out ds) != null); ds = new List(); IToken/*!*/ z; IToken/*!*/ typeParamTok; var typeParams = new List(); var arguments = new List(); TypedIdent/*!*/ tyd; TypedIdent retTyd = null; Bpl.Type/*!*/ retTy; QKeyValue argKv = null; QKeyValue kv = null; Expr definition = null; Expr/*!*/ tmp; .) "function" { Attribute } Ident [ TypeParams ] "(" [ VarOrType (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .) { "," VarOrType (. arguments.Add(new Formal(tyd.tok, tyd, true, argKv)); .) } ] ")" (. argKv = null; .) ( "returns" "(" VarOrType ")" | ":" Type (. retTyd = new TypedIdent(retTy.tok, TypedIdent.NoName, retTy); .) ) ( "{" Expression (. definition = tmp; .) "}" | ";" ) (. if (retTyd == null) { // construct a dummy type for the case of syntax error retTyd = new TypedIdent(t, TypedIdent.NoName, new BasicType(t, SimpleType.Int)); } Function/*!*/ func = new Function(z, z.val, typeParams, arguments, new Formal(retTyd.tok, retTyd, false, argKv), null, kv); Contract.Assert(func != null); ds.Add(func); bool allUnnamed = true; foreach(Formal/*!*/ f in arguments){ Contract.Assert(f != null); if (f.TypedIdent.HasName) { allUnnamed = false; break; } } if (!allUnnamed) { Bpl.Type prevType = null; for (int i = arguments.Count; 0 <= --i; ) { TypedIdent/*!*/ curr = cce.NonNull(arguments[i]).TypedIdent; if (curr.HasName) { // the argument was given as both an identifier and a type prevType = curr.Type; } else { // the argument was given as just one "thing", which syntactically parsed as a type if (prevType == null) { this.errors.SemErr(curr.tok, "the type of the last parameter is unspecified"); break; } Bpl.Type ty = curr.Type; var uti = ty as UnresolvedTypeIdentifier; if (uti != null && uti.Arguments.Count == 0) { // the given "thing" was just an identifier, so let's use it as the name of the parameter curr.Name = uti.Name; curr.Type = prevType; } else { this.errors.SemErr(curr.tok, "expecting an identifier as parameter name"); } } } } if (definition != null) { // generate either an axiom or a function body if (QKeyValue.FindBoolAttribute(kv, "inline")) { func.Body = definition; } else { ds.Add(func.CreateDefinitionAxiom(definition, kv)); } } .) . VarOrType = (. Contract.Ensures(Contract.ValueAtReturn(out tyd) != null); string/*!*/ varName = TypedIdent.NoName; Bpl.Type/*!*/ ty; IToken/*!*/ tok; kv = null; .) { Attribute } Type (. tok = ty.tok; .) [ ":" (. var uti = ty as UnresolvedTypeIdentifier; if (uti != null && uti.Arguments.Count == 0) { varName = uti.Name; } else { this.SemErr("expected identifier before ':'"); } .) Type ] (. tyd = new TypedIdent(tok, varName, ty); .) . /*------------------------------------------------------------------------*/ Axiom = (.Contract.Ensures(Contract.ValueAtReturn(out m) != null); Expr/*!*/ e; QKeyValue kv = null; .) "axiom" { Attribute } (. IToken/*!*/ x = t; .) Proposition ";" (. m = new Axiom(x,e, null, kv); .) . /*------------------------------------------------------------------------*/ UserDefinedTypes<.out List/*!*/ ts.> = (. Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out ts))); Declaration/*!*/ decl; QKeyValue kv = null; ts = new List (); .) "type" { Attribute } UserDefinedType (. ts.Add(decl); .) { "," UserDefinedType (. ts.Add(decl); .) } ";" . UserDefinedType = (. Contract.Ensures(Contract.ValueAtReturn(out decl) != null); IToken/*!*/ id; List/*!*/ paramTokens = new List (); Bpl.Type/*!*/ body = dummyType; bool synonym = false; .) Ident [ WhiteSpaceIdents ] [ "=" Type (. synonym = true; .) ] (. if (synonym) { List/*!*/ typeParams = new List(); foreach(Token/*!*/ t in paramTokens){ Contract.Assert(t != null); typeParams.Add(new TypeVariable(t, t.val));} decl = new TypeSynonymDecl(id, id.val, typeParams, body, kv); } else { decl = new TypeCtorDecl(id, id.val, paramTokens.Count, kv); } .) . /*------------------------------------------------------------------------*/ Procedure = (. Contract.Ensures(Contract.ValueAtReturn(out proc) != null); IToken/*!*/ x; List/*!*/ typeParams; List/*!*/ ins, outs; List/*!*/ pre = new List(); List/*!*/ mods = new List(); List/*!*/ post = new List(); List/*!*/ locals = new List(); StmtList/*!*/ stmtList; QKeyValue kv = null; impl = null; .) "procedure" ProcSignature ( ";" { Spec } | { Spec } ImplBody (. impl = new Implementation(x, x.val, typeParams, Formal.StripWhereClauses(ins), Formal.StripWhereClauses(outs), locals, stmtList, kv == null ? null : (QKeyValue)kv.Clone(), this.errors); .) ) (. proc = new Procedure(x, x.val, typeParams, ins, outs, pre, mods, post, kv); .) . Implementation = (. Contract.Ensures(Contract.ValueAtReturn(out impl) != null); IToken/*!*/ x; List/*!*/ typeParams; List/*!*/ ins, outs; List/*!*/ locals; StmtList/*!*/ stmtList; QKeyValue kv; .) "implementation" ProcSignature ImplBody (. impl = new Implementation(x, x.val, typeParams, ins, outs, locals, stmtList, kv, this.errors); .) . ProcSignature<.bool allowWhereClausesOnFormals, out IToken/*!*/ name, out List/*!*/ typeParams, out List/*!*/ ins, out List/*!*/ outs, out QKeyValue kv.> = (. Contract.Ensures(Contract.ValueAtReturn(out name) != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); Contract.Ensures(Contract.ValueAtReturn(out ins) != null); Contract.Ensures(Contract.ValueAtReturn(out outs) != null); IToken/*!*/ typeParamTok; typeParams = new List(); outs = new List(); kv = null; .) { Attribute } Ident [ TypeParams ] ProcFormals [ "returns" ProcFormals ] . Spec<.List/*!*/ pre, List/*!*/ mods, List/*!*/ post.> = (.Contract.Requires(pre != null); Contract.Requires(mods != null); Contract.Requires(post != null); List/*!*/ ms; .) ( "modifies" [ Idents (. foreach(IToken/*!*/ m in ms){ Contract.Assert(m != null); mods.Add(new IdentifierExpr(m, m.val)); } .) ] ";" | "free" SpecPrePost | SpecPrePost ) . SpecPrePost<.bool free, List/*!*/ pre, List/*!*/ post.> = (. Contract.Requires(pre != null); Contract.Requires(post != null); Expr/*!*/ e; Token tok = null; QKeyValue kv = null; .) ( "requires" (. tok = t; .) { Attribute } Proposition ";" (. pre.Add(new Requires(tok, free, e, null, kv)); .) | "ensures" (. tok = t; .) { Attribute } Proposition ";" (. post.Add(new Ensures(tok, free, e, null, kv)); .) ) . /*------------------------------------------------------------------------*/ ImplBody<.out List/*!*/ locals, out StmtList/*!*/ stmtList.> = (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); locals = new List(); .) "{" { LocalVars } StmtList . /* the StmtList also reads the final curly brace */ StmtList = (. Contract.Ensures(Contract.ValueAtReturn(out stmtList) != null); List bigblocks = new List(); /* built-up state for the current BigBlock: */ IToken startToken = null; string currentLabel = null; List 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; .) { ( LabelOrCmd (. if (c != null) { // LabelOrCmd read a Cmd Contract.Assert(label == null); if (startToken == null) { startToken = c.tok; cs = new List(); } 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(); } .) | StructuredCmd (. ec = ecn; if (startToken == null) { startToken = ec.tok; cs = new List(); } Contract.Assert(cs != null); b = new BigBlock(startToken, currentLabel, cs, ec, null); bigblocks.Add(b); startToken = null; currentLabel = null; cs = null; .) | TransferCmd (. tc = tcn; if (startToken == null) { startToken = tc.tok; cs = new List(); } Contract.Assert(cs != null); b = new BigBlock(startToken, currentLabel, cs, null, tc); bigblocks.Add(b); startToken = null; currentLabel = null; cs = null; .) ) } "}" (. IToken/*!*/ endCurly = t; if (startToken == null && bigblocks.Count == 0) { startToken = t; cs = new List(); } if (startToken != null) { Contract.Assert(cs != null); b = new BigBlock(startToken, currentLabel, cs, null, null); bigblocks.Add(b); } stmtList = new StmtList(bigblocks, endCurly); .) . TransferCmd = (. Contract.Ensures(Contract.ValueAtReturn(out tc) != null); tc = dummyTransferCmd; Token y; List/*!*/ xs; List ss = new List(); .) ( "goto" (. y = t; .) Idents (. foreach(IToken/*!*/ s in xs){ Contract.Assert(s != null); ss.Add(s.val); } tc = new GotoCmd(y, ss); .) | "return" (. tc = new ReturnCmd(t); .) ) ";" . StructuredCmd = (. Contract.Ensures(Contract.ValueAtReturn(out ec) != null); ec = dummyStructuredCmd; Contract.Assume(cce.IsPeerConsistent(ec)); IfCmd/*!*/ ifcmd; WhileCmd/*!*/ wcmd; BreakCmd/*!*/ bcmd; .) ( IfCmd (. ec = ifcmd; .) | WhileCmd (. ec = wcmd; .) | BreakCmd (. ec = bcmd; .) ) . IfCmd = (. Contract.Ensures(Contract.ValueAtReturn(out ifcmd) != null); IToken/*!*/ x; Expr guard; StmtList/*!*/ thn; IfCmd/*!*/ elseIf; IfCmd elseIfOption = null; StmtList/*!*/ els; StmtList elseOption = null; .) "if" (. x = t; .) Guard "{" StmtList [ "else" ( IfCmd (. elseIfOption = elseIf; .) | "{" StmtList (. elseOption = els; .) ) ] (. ifcmd = new IfCmd(x, guard, thn, elseIfOption, elseOption); .) . WhileCmd = (. Contract.Ensures(Contract.ValueAtReturn(out wcmd) != null); IToken/*!*/ x; Token z; Expr guard; Expr/*!*/ e; bool isFree; List invariants = new List(); StmtList/*!*/ body; QKeyValue kv = null; .) "while" (. x = t; .) Guard (. Contract.Assume(guard == null || cce.Owner.None(guard)); .) { (. isFree = false; z = la/*lookahead token*/; .) [ "free" (. isFree = true; .) ] "invariant" { Attribute } Expression (. if (isFree) { invariants.Add(new AssumeCmd(z, e, kv)); } else { invariants.Add(new AssertCmd(z, e, kv)); } kv = null; .) ";" } "{" StmtList (. wcmd = new WhileCmd(x, guard, invariants, body); .) . Guard = (. Expr/*!*/ ee; e = null; .) "(" ( "*" (. e = null; .) | Expression (. e = ee; .) ) ")" . BreakCmd = (.Contract.Ensures(Contract.ValueAtReturn(out bcmd) != null); IToken/*!*/ x; IToken/*!*/ y; string breakLabel = null; .) "break" (. x = t; .) [ Ident (. breakLabel = y.val; .) ] ";" (. bcmd = new BreakCmd(x, breakLabel); .) . /*------------------------------------------------------------------------*/ LabelOrCmd /* ensures (c == null) != (label != null) */ = (. IToken/*!*/ x; Expr/*!*/ e; List/*!*/ xs; List ids; c = dummyCmd; label = null; Cmd/*!*/ cn; QKeyValue kv = null; .) ( LabelOrAssign | "assert" (. x = t; .) { Attribute } Proposition (. c = new AssertCmd(x, e, kv); .) ";" | "assume" (. x = t; .) { Attribute } Proposition (. c = new AssumeCmd(x, e, kv); .) ";" | "havoc" (. x = t; .) Idents ";" (. ids = new List(); foreach(IToken/*!*/ y in xs){ Contract.Assert(y != null); ids.Add(new IdentifierExpr(y, y.val)); } c = new HavocCmd(x,ids); .) | CallCmd ";" (. c = cn; .) | ParCallCmd (. c = cn; .) | "yield" (. x = t; .) ";" (. c = new YieldCmd(x); .) ) . /*------------------------------------------------------------------------*/ LabelOrAssign /* ensures (c == null) != (label != null) */ = (. IToken/*!*/ id; IToken/*!*/ x, y; Expr/*!*/ e0; c = dummyCmd; label = null; AssignLhs/*!*/ lhs; List/*!*/ lhss; List/*!*/ rhss; List/*!*/ indexes; .) Ident (. x = t; .) ( ":" (. c = null; label = x; .) | (. lhss = new List(); .) (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .) { MapAssignIndex (. lhs = new MapAssignLhs(y, lhs, indexes); .) } (. lhss.Add(lhs); .) { "," Ident (. lhs = new SimpleAssignLhs(id, new IdentifierExpr(id, id.val)); .) { MapAssignIndex (. lhs = new MapAssignLhs(y, lhs, indexes); .) } (. lhss.Add(lhs); .) } ":=" (. x = t; /* use location of := */ .) Expression (. rhss = new List (); rhss.Add(e0); .) { "," Expression (. rhss.Add(e0); .) } ";" (. c = new AssignCmd(x, lhss, rhss); .) ) . MapAssignIndex<.out IToken/*!*/ x, out List/*!*/ indexes.> = (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out indexes))); indexes = new List (); Expr/*!*/ e; .) "[" (. x = t; .) [ Expression (. indexes.Add(e); .) { "," Expression (. indexes.Add(e); .) } ] "]" . /*------------------------------------------------------------------------*/ CallCmd = (. Contract.Ensures(Contract.ValueAtReturn(out c) != null); IToken x; bool isAsync = false; bool isFree = false; QKeyValue kv = null; c = null; .) [ "async" (. isAsync = true; .) ] [ "free" (. isFree = true; .) ] "call" (. x = t; .) { Attribute } CallParams (. .) . ParCallCmd = (. Contract.Ensures(Contract.ValueAtReturn(out d) != null); IToken x; QKeyValue kv = null; Cmd c = null; List callCmds = new List(); .) "par" (. x = t; .) { Attribute } CallParams (. callCmds.Add((CallCmd)c); .) { "|" CallParams (. callCmds.Add((CallCmd)c); .) } ";" (. d = new ParCallCmd(x, callCmds, kv); .) . CallParams = (. List ids = new List(); List es = new List(); Expr en; IToken first; IToken p; c = null; .) Ident ( "(" [ Expression (. es.Add(en); .) { "," Expression (. es.Add(en); .) } ] ")" (. c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; .) | (. ids.Add(new IdentifierExpr(first, first.val)); .) [ "," Ident (. ids.Add(new IdentifierExpr(p, p.val)); .) { "," Ident (. ids.Add(new IdentifierExpr(p, p.val)); .) } ] ":=" Ident "(" [ Expression (. es.Add(en); .) { "," Expression (. es.Add(en); .) } ] ")" (. c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; .) ) . /*------------------------------------------------------------------------*/ Proposition =(.Contract.Ensures(Contract.ValueAtReturn(out e) != null);.) Expression . /*------------------------------------------------------------------------*/ Idents<.out List/*!*/ xs.> = (.Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List(); .) Ident (. xs.Add(id); .) { "," Ident (. xs.Add(id); .) } . /*------------------------------------------------------------------------*/ WhiteSpaceIdents<.out List/*!*/ xs.> = (. Contract.Ensures(Contract.ValueAtReturn(out xs) != null); IToken/*!*/ id; xs = new List(); .) Ident (. xs.Add(id); .) { Ident (. xs.Add(id); .) } . /*------------------------------------------------------------------------*/ Expressions<.out List/*!*/ es.> = (. Contract.Ensures(Contract.ValueAtReturn(out es) != null); Expr/*!*/ e; es = new List(); .) Expression (. es.Add(e); .) { "," Expression (. es.Add(e); .) } . /*------------------------------------------------------------------------*/ Expression<.out Expr/*!*/ e0.> = (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) ImpliesExpression { EquivOp (. x = t; .) ImpliesExpression (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Iff, e0, e1); .) } . EquivOp = "<==>" | '\u21d4'. /*------------------------------------------------------------------------*/ ImpliesExpression = (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) LogicalExpression [ ImpliesOp (. x = t; .) /* recurse because implication is right-associative */ ImpliesExpression (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e0, e1); .) | ExpliesOp (. if (noExplies) this.SemErr("illegal mixture of ==> and <==, use parentheses to disambiguate"); x = t; .) LogicalExpression (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .) /* loop because explies is left-associative */ { ExpliesOp (. x = t; .) LogicalExpression (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Imp, e1, e0); .) } ] . ImpliesOp = "==>" | '\u21d2'. ExpliesOp = "<==" | '\u21d0'. /*------------------------------------------------------------------------*/ LogicalExpression = (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) RelationalExpression [ AndOp (. x = t; .) RelationalExpression (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .) { AndOp (. x = t; .) RelationalExpression (. e0 = Expr.Binary(x, BinaryOperator.Opcode.And, e0, e1); .) } | OrOp (. x = t; .) RelationalExpression (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .) { OrOp (. x = t; .) RelationalExpression (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Or, e0, e1); .) } ] . AndOp = "&&" | '\u2227'. OrOp = "||" | '\u2228'. /*------------------------------------------------------------------------*/ RelationalExpression = (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) BvTerm [ RelOp BvTerm (. e0 = Expr.Binary(x, op, e0, e1); .) ] . RelOp = (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) ( "==" (. x = t; op=BinaryOperator.Opcode.Eq; .) | "<" (. x = t; op=BinaryOperator.Opcode.Lt; .) | ">" (. x = t; op=BinaryOperator.Opcode.Gt; .) | "<=" (. x = t; op=BinaryOperator.Opcode.Le; .) | ">=" (. x = t; op=BinaryOperator.Opcode.Ge; .) | "!=" (. x = t; op=BinaryOperator.Opcode.Neq; .) | "<:" (. x = t; op=BinaryOperator.Opcode.Subtype; .) | '\u2260' (. x = t; op=BinaryOperator.Opcode.Neq; .) | '\u2264' (. x = t; op=BinaryOperator.Opcode.Le; .) | '\u2265' (. x = t; op=BinaryOperator.Opcode.Ge; .) ) . /*------------------------------------------------------------------------*/ BvTerm = (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) Term { "++" (. x = t; .) Term (. e0 = new BvConcatExpr(x, e0, e1); .) } . /*------------------------------------------------------------------------*/ Term = (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) Factor { AddOp Factor (. e0 = Expr.Binary(x, op, e0, e1); .) } . AddOp = (.Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) ( "+" (. x = t; op=BinaryOperator.Opcode.Add; .) | "-" (. x = t; op=BinaryOperator.Opcode.Sub; .) ) . /*------------------------------------------------------------------------*/ Factor = (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; BinaryOperator.Opcode op; .) Power { MulOp Power (. e0 = Expr.Binary(x, op, e0, e1); .) } . MulOp = (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryOperator.Opcode.Add/*(dummy)*/; .) ( "*" (. x = t; op=BinaryOperator.Opcode.Mul; .) | "div" (. x = t; op=BinaryOperator.Opcode.Div; .) | "mod" (. x = t; op=BinaryOperator.Opcode.Mod; .) | "/" (. x = t; op=BinaryOperator.Opcode.RealDiv; .) ) . /*------------------------------------------------------------------------*/ Power = (.Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expr/*!*/ e1; .) UnaryExpression [ "**" (. x = t; .) /* recurse because exponentation is right-associative */ Power (. e0 = Expr.Binary(x, BinaryOperator.Opcode.Pow, e0, e1); .) ] . /*------------------------------------------------------------------------*/ UnaryExpression = (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; e = dummyExpr; .) ( "-" (. x = t; .) UnaryExpression (. e = Expr.Unary(x, UnaryOperator.Opcode.Neg, e); .) | NegOp (. x = t; .) UnaryExpression (. e = Expr.Unary(x, UnaryOperator.Opcode.Not, e); .) | CoercionExpression ) . NegOp = "!" | '\u00ac'. /*------------------------------------------------------------------------*/ /* This production creates ambiguities, because types can start with "<" (polymorphic map types), but can also be followed by "<" (inequalities). Coco deals with these ambiguities in a reasonable way by preferring to read further types (type arguments) over relational symbols. E.g., "5 : C < 0" will cause a parse error because "<" is treated as the beginning of a map type. */ CoercionExpression = (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; Bpl.Type/*!*/ coercedTo; BigNum bn; .) ArrayExpression { ":" (. x = t; .) ( Type (. e = Expr.CoerceType(x, e, coercedTo); .) | Nat /* This means that we really look at a bitvector expression t[a:b] */ (. if (!(e is LiteralExpr) || !((LiteralExpr)e).isBigNum) { this.SemErr("arguments of extract need to be integer literals"); e = new BvBounds(x, bn, BigNum.ZERO); } else { e = new BvBounds(x, bn, ((LiteralExpr)e).asBigNum); } .) ) } . /*------------------------------------------------------------------------*/ ArrayExpression = (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; Expr/*!*/ index0 = dummyExpr; Expr/*!*/ e1; bool store; bool bvExtract; List/*!*/ allArgs = dummyExprSeq; .) AtomExpression { "[" (. x = t; allArgs = new List (); allArgs.Add(e); store = false; bvExtract = false; .) [ Expression (. if (index0 is BvBounds) bvExtract = true; else allArgs.Add(index0); .) { "," Expression (. if (bvExtract || e1 is BvBounds) this.SemErr("bitvectors only have one dimension"); allArgs.Add(e1); .) } [ ":=" Expression (. if (bvExtract || e1 is BvBounds) this.SemErr("assignment to bitvectors is not possible"); allArgs.Add(e1); store = true; .) ] | ":=" Expression (. allArgs.Add(e1); store = true; .) ] "]" (. if (store) e = new NAryExpr(x, new MapStore(x, allArgs.Count - 2), allArgs); else if (bvExtract) e = new BvExtractExpr(x, e, ((BvBounds)index0).Upper.ToIntSafe, ((BvBounds)index0).Lower.ToIntSafe); else e = new NAryExpr(x, new MapSelect(x, allArgs.Count - 1), allArgs); .) } . /*------------------------------------------------------------------------*/ AtomExpression = (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; int n; BigNum bn; BigDec bd; BigFloat bf; List/*!*/ es; List/*!*/ ds; Trigger trig; List/*!*/ typeParams; IdentifierExpr/*!*/ id; QKeyValue kv; e = dummyExpr; List/*!*/ locals; List/*!*/ blocks; .) ( "false" (. e = new LiteralExpr(t, false); .) | "true" (. e = new LiteralExpr(t, true); .) | Nat (. e = new LiteralExpr(t, bn); .) | Dec (. e = new LiteralExpr(t, bd); .) | Float (. e = new LiteralExpr(t, bf); .) | BvLit (. e = new LiteralExpr(t, bn, n); .) | Ident (. id = new IdentifierExpr(x, x.val); e = id; .) [ "(" ( Expressions (. e = new NAryExpr(x, new FunctionCall(id), es); .) | /* empty */ (. e = new NAryExpr(x, new FunctionCall(id), new List()); .) ) ")" ] | "old" (. x = t; .) "(" Expression ")" (. e = new OldExpr(x, e); .) | "int" (. x = t; .) "(" Expression ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToInt), new List{ e }); .) | "real" (. x = t; .) "(" Expression ")" (. e = new NAryExpr(x, new ArithmeticCoercion(x, ArithmeticCoercion.CoercionType.ToReal), new List{ e }); .) | "(" ( Expression (. if (e is BvBounds) this.SemErr("parentheses around bitvector bounds " + "are not allowed"); .) | Forall (. x = t; .) QuantifierBody (. if (typeParams.Count + ds.Count > 0) e = new ForallExpr(x, typeParams, ds, kv, trig, e); .) | Exists (. x = t; .) QuantifierBody (. if (typeParams.Count + ds.Count > 0) e = new ExistsExpr(x, typeParams, ds, kv, trig, e); .) | Lambda (. x = t; .) QuantifierBody (. if (trig != null) SemErr("triggers not allowed in lambda expressions"); if (typeParams.Count + ds.Count > 0) e = new LambdaExpr(x, typeParams, ds, kv, e); .) ) ")" | IfThenElseExpression | CodeExpression (. e = new CodeExpr(locals, blocks); .) ) . CodeExpression<.out List/*!*/ locals, out List/*!*/ blocks.> = (. Contract.Ensures(Contract.ValueAtReturn(out locals) != null); Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out blocks))); locals = new List(); Block/*!*/ b; blocks = new List(); .) "|{" { LocalVars } SpecBlock (. blocks.Add(b); .) { SpecBlock (. blocks.Add(b); .) } "}|" . SpecBlock = (. Contract.Ensures(Contract.ValueAtReturn(out b) != null); IToken/*!*/ x; IToken/*!*/ y; Cmd c; IToken label; List cs = new List(); List/*!*/ xs; List ss = new List(); b = dummyBlock; Expr/*!*/ e; .) Ident ":" { LabelOrCmd (. if (c != null) { Contract.Assert(label == null); cs.Add(c); } else { Contract.Assert(label != null); SemErr("SpecBlock's can only have one label"); } .) } ( "goto" (. y = t; .) Idents (. foreach(IToken/*!*/ s in xs){ Contract.Assert(s != null); ss.Add(s.val); } b = new Block(x,x.val,cs,new GotoCmd(y,ss)); .) | "return" Expression (. b = new Block(x,x.val,cs,new ReturnExprCmd(t,e)); .) ) ";" . Attribute = (. Trigger trig = null; .) AttributeOrTrigger (. if (trig != null) this.SemErr("only attributes, not triggers, allowed here"); .) . AttributeOrTrigger = (. IToken/*!*/ tok; Expr/*!*/ e; List/*!*/ es; string key; List parameters; object/*!*/ param; .) "{" (. tok = t; .) ( ":" ident (. key = t.val; parameters = new List(); .) [ AttributeParameter (. parameters.Add(param); .) { "," AttributeParameter (. parameters.Add(param); .) } ] (. if (key == "nopats") { if (parameters.Count == 1 && parameters[0] is Expr) { e = (Expr)parameters[0]; if(trig==null){ trig = new Trigger(tok, false, new List { e }, null); } else { trig.AddLast(new Trigger(tok, false, new List { e }, null)); } } else { this.SemErr("the 'nopats' quantifier attribute expects a string-literal parameter"); } } else { if (kv==null) { kv = new QKeyValue(tok, key, parameters, null); } else { kv.AddLast(new QKeyValue(tok, key, parameters, null)); } } .) | Expression (. es = new List { e }; .) { "," Expression (. es.Add(e); .) } (. if (trig==null) { trig = new Trigger(tok, true, es, null); } else { trig.AddLast(new Trigger(tok, true, es, null)); } .) ) "}" . AttributeParameter = (. Contract.Ensures(Contract.ValueAtReturn(out o) != null); o = "error"; Expr/*!*/ e; .) ( string (. o = t.val.Substring(1, t.val.Length-2); .) | Expression (. o = e; .) ) . IfThenElseExpression = (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ tok; Expr/*!*/ e0, e1, e2; e = dummyExpr; .) "if" (. tok = t; .) Expression "then" Expression "else" Expression (. e = new NAryExpr(tok, new IfThenElse(tok), new List{ e0, e1, e2 }); .) . QuantifierBody<.IToken/*!*/ q, out List/*!*/ typeParams, out List/*!*/ ds, out QKeyValue kv, out Trigger trig, out Expr/*!*/ body.> = (. Contract.Requires(q != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); Contract.Ensures(Contract.ValueAtReturn(out ds) != null); Contract.Ensures(Contract.ValueAtReturn(out body) != null); trig = null; typeParams = new List (); IToken/*!*/ tok; kv = null; ds = new List (); .) ( TypeParams [ BoundVars ] | BoundVars ) QSep { AttributeOrTrigger } Expression . Forall = "forall" | '\u2200'. Exists = "exists" | '\u2203'. Lambda = "lambda" | '\u03bb'. QSep = "::" | '\u2022'. /*------------------------------------------------------------------------*/ Ident =(.Contract.Ensures(Contract.ValueAtReturn(out x) != null);.) ident (. x = t; if (x.val.StartsWith("\\")) x.val = x.val.Substring(1); .) . /*------------------------------------------------------------------------*/ Nat = digits (. try { n = BigNum.FromString(t.val); } catch (FormatException) { this.SemErr("incorrectly formatted number"); n = BigNum.ZERO; } .) . /*------------------------------------------------------------------------*/ Dec = (. string s = ""; .) ( decimal (. s = t.val; .) | dec_float (. s = t.val; .) ) (. try { n = BigDec.FromString(s); } catch (FormatException) { this.SemErr("incorrectly formatted number"); n = BigDec.ZERO; } .) . /*------------------------------------------------------------------------*/ BvLit = bvlit (. int pos = t.val.IndexOf("bv"); string a = t.val.Substring(0, pos); string b = t.val.Substring(pos + 2); try { n = BigNum.FromString(a); m = Convert.ToInt32(b); } catch (FormatException) { this.SemErr("incorrectly formatted bitvector"); n = BigNum.ZERO; m = 0; } .) . Float = (. string s = ""; .) ( float (. s = t.val; .) ) (. try { n = BigFloat.FromString(s); } catch (FormatException e) { this.SemErr("incorrectly formatted floating point, " + e.Message); n = BigFloat.ZERO; } .) . END BoogiePL.