/// version-specifier = <identifier> /// version-specifier = [<identifier>:] [ version ] VersionResult ParserImpl::ParseVersionSpecifier() { const Identifier *Label = 0; if (Tok.kind == Token::Identifier) { Token LTok = Tok; Label = GetOrCreateIdentifier(Tok); ConsumeToken(); if (Tok.kind != Token::Colon) { VersionSymTabTy::iterator it = VersionSymTab.find(Label); if (it == VersionSymTab.end()) { Error("invalid version reference.", LTok); return VersionResult(false, UpdateList(0, NULL)); } return it->second; } ConsumeToken(); if (VersionSymTab.count(Label)) { Error("duplicate update list label definition.", LTok); Label = 0; } } VersionResult Res = ParseVersion(); // Define update list to avoid use-of-undef errors. if (!Res.isValid()) { Res = VersionResult(true, UpdateList(Array::CreateArray("", 0), NULL)); } if (Label) VersionSymTab.insert(std::make_pair(Label, Res.get())); return Res; }
/// version - '[' update-list? ']' '@' version-specifier /// update-list - empty /// update-list - lhs '=' rhs [',' update-list] VersionResult ParserImpl::ParseVersion() { if (Tok.kind != Token::LSquare) return VersionResult(false, UpdateList(0, NULL)); std::vector<WriteInfo> Writes; ConsumeLSquare(); for (;;) { Token LHSTok = Tok; NumberOrExprResult LHS = ParseNumberOrExpr(); if (Tok.kind != Token::Equals) { Error("expected '='.", Tok); break; } ConsumeToken(); Token RHSTok = Tok; NumberOrExprResult RHS = ParseNumberOrExpr(); Writes.push_back(WriteInfo(LHS, RHS, LHSTok, RHSTok)); if (Tok.kind == Token::Comma) ConsumeToken(); else break; } ExpectRSquare("expected close of update list"); VersionHandle Base(0, NULL); if (Tok.kind != Token::At) { Error("expected '@'.", Tok); return VersionResult(false, UpdateList(0, NULL)); } ConsumeExpectedToken(Token::At); VersionResult BaseRes = ParseVersionSpecifier(); if (!BaseRes.isValid()) return BaseRes; Base = BaseRes.get(); Expr::Width ArrayDomainType = Expr::Int32; Expr::Width ArrayRangeType = Expr::Int8; for (std::vector<WriteInfo>::reverse_iterator it = Writes.rbegin(), ie = Writes.rend(); it != ie; ++it) { const WriteInfo &WI = *it; ExprResult LHS, RHS; // FIXME: This can be factored into common helper for coercing a // NumberOrExpr into an Expr. if (WI.LHS.isNumber()) { LHS = ParseNumberToken(ArrayDomainType, WI.LHS.getNumber()); } else { LHS = WI.LHS.getExpr(); if (LHS.isValid() && LHS.get()->getWidth() != ArrayDomainType) { Error("invalid write index (doesn't match array domain).", WI.LHSTok); LHS = ExprResult(); } } if (WI.RHS.isNumber()) { RHS = ParseNumberToken(ArrayRangeType, WI.RHS.getNumber()); } else { RHS = WI.RHS.getExpr(); if (RHS.isValid() && RHS.get()->getWidth() != ArrayRangeType) { Error("invalid write value (doesn't match array range).", WI.RHSTok); RHS = ExprResult(); } } if (LHS.isValid() && RHS.isValid()) Base.extend(LHS.get(), RHS.get()); } return Base; }
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()); } }