/// ParseMatchedBinaryArgs - Parse a pair of arguments who are /// expected to be of the same type. Upon return, if both LHS and RHS /// are valid then they are guaranteed to have the same type. /// /// Name - The name token of the expression, for diagnostics. /// ExpectType - The expected type of the arguments, if known. void ParserImpl::ParseMatchedBinaryArgs(const Token &Name, TypeResult ExpectType, ExprResult &LHS, ExprResult &RHS) { if (Tok.kind == Token::RParen) { Error("unexpected end of arguments.", Name); ConsumeRParen(); return; } // Avoid NumberOrExprResult overhead and give more precise // diagnostics when we know the type. if (ExpectType.isValid()) { LHS = ParseExpr(ExpectType); if (Tok.kind == Token::RParen) { Error("unexpected end of arguments.", Name); ConsumeRParen(); return; } RHS = ParseExpr(ExpectType); } else { NumberOrExprResult LHS_NOE = ParseNumberOrExpr(); if (Tok.kind == Token::RParen) { Error("unexpected end of arguments.", Name); ConsumeRParen(); return; } if (LHS_NOE.isNumber()) { NumberOrExprResult RHS_NOE = ParseNumberOrExpr(); if (RHS_NOE.isNumber()) { Error("ambiguous arguments to expression.", Name); } else { RHS = RHS_NOE.getExpr(); if (RHS.isValid()) LHS = ParseNumberToken(RHS.get()->getWidth(), LHS_NOE.getNumber()); } } else { LHS = LHS_NOE.getExpr(); if (!LHS.isValid()) { // FIXME: Should suppress ambiguity warnings here. RHS = ParseExpr(TypeResult()); } else { RHS = ParseExpr(LHS.get()->getWidth()); } } } ExpectRParen("unexpected argument to expression."); }
// FIXME: Rewrite to only accept binary form. Make type optional. ExprResult ParserImpl::ParseConcatParenExpr(const Token &Name, Expr::Width ResTy) { std::vector<ExprHandle> Kids; unsigned Width = 0; while (Tok.kind != Token::RParen) { ExprResult E = ParseExpr(TypeResult()); // Skip to end of expr on error. if (!E.isValid()) { SkipUntilRParen(); return Builder->Constant(0, ResTy); } Kids.push_back(E.get()); Width += E.get()->getWidth(); } ConsumeRParen(); if (Width != ResTy) { Error("concat does not match expected result size."); return Builder->Constant(0, ResTy); } // FIXME: Use builder! return ConcatExpr::createN(Kids.size(), &Kids[0]); }
ExprResult ParserImpl::ParseUnaryParenExpr(const Token &Name, unsigned Kind, bool IsFixed, Expr::Width ResTy) { if (Tok.kind == Token::RParen) { Error("unexpected end of arguments.", Name); ConsumeRParen(); return Builder->Constant(0, ResTy); } ExprResult Arg = ParseExpr(IsFixed ? ResTy : TypeResult()); if (!Arg.isValid()) Arg = Builder->Constant(0, ResTy); ExpectRParen("unexpected argument in unary expression."); ExprHandle E = Arg.get(); switch (Kind) { case eMacroKind_Neg: return Builder->Sub(Builder->Constant(0, E->getWidth()), E); case Expr::Not: // FIXME: Type check arguments. return Builder->Not(E); case Expr::SExt: // FIXME: Type check arguments. return Builder->SExt(E, ResTy); case Expr::ZExt: // FIXME: Type check arguments. return Builder->ZExt(E, ResTy); default: Error("internal error, unhandled kind.", Name); return Builder->Constant(0, ResTy); } }
IntegerResult ParserImpl::ParseIntegerConstant(Expr::Width Type) { ExprResult Res = ParseNumber(Type); if (!Res.isValid()) return IntegerResult(); return cast<ConstantExpr>(Res.get())->getZExtValue(Type); }
ExprResult ParserImpl::ParseSelectParenExpr(const Token &Name, Expr::Width ResTy) { // FIXME: Why does this need to be here? if (Tok.kind == Token::RParen) { Error("unexpected end of arguments.", Name); ConsumeRParen(); return Builder->Constant(0, ResTy); } ExprResult Cond = ParseExpr(Expr::Bool); ExprResult LHS, RHS; ParseMatchedBinaryArgs(Name, ResTy, LHS, RHS); if (!Cond.isValid() || !LHS.isValid() || !RHS.isValid()) return Builder->Constant(0, ResTy); return Builder->Select(Cond.get(), LHS.get(), RHS.get()); }
ExprResult ParserImpl::ParseExtractParenExpr(const Token &Name, Expr::Width ResTy) { IntegerResult OffsetExpr = ParseIntegerConstant(Expr::Int32); ExprResult Child = ParseExpr(TypeResult()); ExpectRParen("unexpected argument to expression."); if (!OffsetExpr.isValid() || !Child.isValid()) return Builder->Constant(0, ResTy); unsigned Offset = (unsigned) OffsetExpr.get(); if (Offset + ResTy > Child.get()->getWidth()) { Error("extract out-of-range of child expression.", Name); return Builder->Constant(0, ResTy); } return Builder->Extract(Child.get(), Offset, ResTy); }
/// ParseExpr - Parse an expression with the given \arg /// ExpectedType. \arg ExpectedType can be invalid if the type cannot /// be inferred from the context. /// /// expr = false | true /// expr = <constant> /// expr = <identifier> /// expr = [<identifier>:] paren-expr ExprResult ParserImpl::ParseExpr(TypeResult ExpectedType) { // FIXME: Is it right to need to do this here? if (Tok.kind == Token::EndOfFile) { Error("unexpected end of file."); return ExprResult(); } if (Tok.kind == Token::KWFalse || Tok.kind == Token::KWTrue) { bool Value = Tok.kind == Token::KWTrue; ConsumeToken(); return ExprResult(Builder->Constant(Value, Expr::Bool)); } if (Tok.kind == Token::Number) { if (!ExpectedType.isValid()) { Error("cannot infer type of number."); ConsumeToken(); return ExprResult(); } return ParseNumber(ExpectedType.get()); } const Identifier *Label = 0; if (Tok.kind == Token::Identifier) { Token LTok = Tok; Label = GetOrCreateIdentifier(Tok); ConsumeToken(); if (Tok.kind != Token::Colon) { ExprSymTabTy::iterator it = ExprSymTab.find(Label); if (it == ExprSymTab.end()) { Error("invalid expression label reference.", LTok); return ExprResult(); } return it->second; } ConsumeToken(); if (ExprSymTab.count(Label)) { Error("duplicate expression label definition.", LTok); Label = 0; } } Token Start = Tok; ExprResult Res = ParseParenExpr(ExpectedType); if (!Res.isValid()) { // If we know the type, define the identifier just so we don't get // use-of-undef errors. // FIXME: Maybe we should let the symbol table map to invalid // entries? if (Label && ExpectedType.isValid()) { ref<Expr> Value = Builder->Constant(0, ExpectedType.get()); ExprSymTab.insert(std::make_pair(Label, Value)); } return Res; } else if (ExpectedType.isValid()) { // Type check result. if (Res.get()->getWidth() != ExpectedType.get()) { // FIXME: Need more info, and range Error("expression has incorrect type.", Start); return ExprResult(); } } if (Label) ExprSymTab.insert(std::make_pair(Label, Res.get())); return Res; }
/// ParseQueryCommand - Parse query command. The lexer should be /// positioned at the 'query' keyword. /// /// 'query' expressions-list expression [expressions-list [array-list]] DeclResult ParserImpl::ParseQueryCommand() { std::vector<ExprHandle> Constraints; std::vector<ExprHandle> Values; std::vector<const Array*> Objects; ExprResult Res; // FIXME: We need a command for this. Or something. ExprSymTab.clear(); VersionSymTab.clear(); // Reinsert initial array versions. // FIXME: Remove this! for (std::map<const Identifier*, const ArrayDecl*>::iterator it = ArraySymTab.begin(), ie = ArraySymTab.end(); it != ie; ++it) { VersionSymTab.insert(std::make_pair(it->second->Name, UpdateList(it->second->Root, NULL))); } ConsumeExpectedToken(Token::KWQuery); if (Tok.kind != Token::LSquare) { Error("malformed query, expected constraint list."); SkipUntilRParen(); return DeclResult(); } ConsumeLSquare(); // FIXME: Should avoid reading past unbalanced parens here. while (Tok.kind != Token::RSquare) { if (Tok.kind == Token::EndOfFile) { Error("unexpected end of file."); Res = ExprResult(Builder->Constant(0, Expr::Bool)); goto exit; } ExprResult Constraint = ParseExpr(TypeResult(Expr::Bool)); if (Constraint.isValid()) Constraints.push_back(Constraint.get()); } ConsumeRSquare(); Res = ParseExpr(TypeResult(Expr::Bool)); if (!Res.isValid()) // Error emitted by ParseExpr. Res = ExprResult(Builder->Constant(0, Expr::Bool)); // Return if there are no optional lists of things to evaluate. if (Tok.kind == Token::RParen) goto exit; if (Tok.kind != Token::LSquare) { Error("malformed query, expected expression list."); SkipUntilRParen(); return DeclResult(); } ConsumeLSquare(); // FIXME: Should avoid reading past unbalanced parens here. while (Tok.kind != Token::RSquare) { if (Tok.kind == Token::EndOfFile) { Error("unexpected end of file."); goto exit; } ExprResult Res = ParseExpr(TypeResult()); if (Res.isValid()) Values.push_back(Res.get()); } ConsumeRSquare(); // Return if there are no optional lists of things to evaluate. if (Tok.kind == Token::RParen) goto exit; if (Tok.kind != Token::LSquare) { Error("malformed query, expected array list."); SkipUntilRParen(); return DeclResult(); } ConsumeLSquare(); // FIXME: Should avoid reading past unbalanced parens here. while (Tok.kind != Token::RSquare) { if (Tok.kind == Token::EndOfFile) { Error("unexpected end of file."); goto exit; } // FIXME: Factor out. if (Tok.kind != Token::Identifier) { Error("unexpected token."); ConsumeToken(); continue; } Token LTok = Tok; const Identifier *Label = GetOrCreateIdentifier(Tok); ConsumeToken(); // Lookup array. std::map<const Identifier*, const ArrayDecl*>::iterator it = ArraySymTab.find(Label); if (it == ArraySymTab.end()) { Error("unknown array", LTok); } else { Objects.push_back(it->second->Root); } } ConsumeRSquare(); exit: if (Tok.kind != Token::EndOfFile) ExpectRParen("unexpected argument to 'query'."); // If we assume that the queries are independent, we clear the array // table from the previous declarations if (ClearArrayAfterQuery) ArraySymTab.clear(); return new QueryCommand(Constraints, Res.get(), Values, Objects); }
/// ParseArrayDecl - Parse an array declaration. The lexer should be positioned /// at the opening 'array'. /// /// array-declaration = "array" name "[" [ size ] "]" ":" domain "->" range /// "=" array-initializer /// array-initializer = "symbolic" | "{" { numeric-literal } "}" DeclResult ParserImpl::ParseArrayDecl() { // FIXME: Recovery here is horrible, we need to scan to next decl start or // something. ConsumeExpectedToken(Token::KWArray); if (Tok.kind != Token::Identifier) { Error("expected identifier token."); return DeclResult(); } Token Name = Tok; IntegerResult Size; TypeResult DomainType; TypeResult RangeType; std::vector< ref<ConstantExpr> > Values; ConsumeToken(); if (Tok.kind != Token::LSquare) { Error("expected '['."); goto exit; } ConsumeLSquare(); if (Tok.kind != Token::RSquare) { Size = ParseIntegerConstant(64); } if (Tok.kind != Token::RSquare) { Error("expected ']'."); goto exit; } ConsumeRSquare(); if (Tok.kind != Token::Colon) { Error("expected ':'."); goto exit; } ConsumeExpectedToken(Token::Colon); DomainType = ParseTypeSpecifier(); if (Tok.kind != Token::Arrow) { Error("expected '->'."); goto exit; } ConsumeExpectedToken(Token::Arrow); RangeType = ParseTypeSpecifier(); if (Tok.kind != Token::Equals) { Error("expected '='."); goto exit; } ConsumeExpectedToken(Token::Equals); if (Tok.kind == Token::KWSymbolic) { ConsumeExpectedToken(Token::KWSymbolic); } else if (Tok.kind == Token::LSquare) { ConsumeLSquare(); while (Tok.kind != Token::RSquare) { if (Tok.kind == Token::EndOfFile) { Error("unexpected end of file."); goto exit; } ExprResult Res = ParseNumber(RangeType.get()); if (Res.isValid()) Values.push_back(cast<ConstantExpr>(Res.get())); } ConsumeRSquare(); } else { Error("expected 'symbolic' or '['."); goto exit; } // Type check size. if (!Size.isValid()) { if (Values.empty()) { Error("unsized arrays are not yet supported."); Size = 1; } else { Size = Values.size(); } } if (!Values.empty()) { if (Size.get() != Values.size()) { // FIXME: Lame message. Error("constant arrays must be completely specified."); Values.clear(); } // for (unsigned i = 0; i != Size.get(); ++i) { // TODO: Check: Must be constant expression. //} } // FIXME: Validate that size makes sense for domain type. if (DomainType.get() != Expr::Int32) { Error("array domain must currently be w32."); DomainType = Expr::Int32; Values.clear(); } if (RangeType.get() != Expr::Int8) { Error("array domain must currently be w8."); RangeType = Expr::Int8; Values.clear(); } // FIXME: Validate that this array is undeclared. exit: if (!Size.isValid()) Size = 1; if (!DomainType.isValid()) DomainType = 32; if (!RangeType.isValid()) RangeType = 8; // FIXME: Array should take domain and range. const Identifier *Label = GetOrCreateIdentifier(Name); const Array *Root; if (!Values.empty()) Root = TheArrayCache.CreateArray(Label->Name, Size.get(), &Values[0], &Values[0] + Values.size()); else Root = TheArrayCache.CreateArray(Label->Name, Size.get()); ArrayDecl *AD = new ArrayDecl(Label, Size.get(), DomainType.get(), RangeType.get(), Root); ArraySymTab[Label] = AD; // Create the initial version reference. VersionSymTab.insert(std::make_pair(Label, UpdateList(Root, NULL))); return AD; }
ExprResult ParserImpl::ParseAnyReadParenExpr(const Token &Name, unsigned Kind, Expr::Width ResTy) { NumberOrExprResult Index = ParseNumberOrExpr(); VersionResult Array = ParseVersionSpecifier(); ExpectRParen("unexpected argument in read expression."); if (!Array.isValid()) return Builder->Constant(0, ResTy); // FIXME: Need generic way to get array width. Needs to work with // anonymous arrays. Expr::Width ArrayDomainType = Expr::Int32; Expr::Width ArrayRangeType = Expr::Int8; // Coerce number to correct type. ExprResult IndexExpr; if (Index.isNumber()) IndexExpr = ParseNumberToken(ArrayDomainType, Index.getNumber()); else IndexExpr = Index.getExpr(); if (!IndexExpr.isValid()) return Builder->Constant(0, ResTy); else if (IndexExpr.get()->getWidth() != ArrayDomainType) { Error("index width does not match array domain."); return Builder->Constant(0, ResTy); } // FIXME: Check range width. switch (Kind) { default: assert(0 && "Invalid kind."); return Builder->Constant(0, ResTy); case eMacroKind_ReadLSB: case eMacroKind_ReadMSB: { unsigned NumReads = ResTy / ArrayRangeType; if (ResTy != NumReads*ArrayRangeType) { Error("invalid ordered read (not multiple of range type).", Name); return Builder->Constant(0, ResTy); } std::vector<ExprHandle> Kids(NumReads); ExprHandle Index = IndexExpr.get(); for (unsigned i=0; i != NumReads; ++i) { // FIXME: We rely on folding here to not complicate things to where the // Read macro pattern fails to match. ExprHandle OffsetIndex = Index; if (i) OffsetIndex = AddExpr::create(OffsetIndex, Builder->Constant(i, ArrayDomainType)); Kids[i] = Builder->Read(Array.get(), OffsetIndex); } if (Kind == eMacroKind_ReadLSB) std::reverse(Kids.begin(), Kids.end()); // FIXME: Use builder! return ConcatExpr::createN(NumReads, &Kids[0]); } case Expr::Read: return Builder->Read(Array.get(), IndexExpr.get()); } }