/// 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."); }
/// ParseParenExpr - Parse a parenthesized expression with the given /// \arg ExpectedType. \arg ExpectedType can be invalid if the type /// cannot be inferred from the context. /// /// paren-expr = '(' type number ')' /// paren-expr = '(' identifier [type] expr+ ') /// paren-expr = '(' ('Read' | 'ReadMSB' | 'ReadLSB') type expr update-list ')' ExprResult ParserImpl::ParseParenExpr(TypeResult FIXME_UNUSED) { if (Tok.kind != Token::LParen) { Error("unexpected token."); ConsumeAnyToken(); return ExprResult(); } ConsumeLParen(); // Check for coercion case (w32 11). if (Tok.kind == Token::KWWidth) { TypeResult ExpectedType = ParseTypeSpecifier(); if (Tok.kind != Token::Number) { Error("coercion can only apply to a number."); SkipUntilRParen(); return ExprResult(); } // Make sure this was a type specifier we support. ExprResult Res; if (ExpectedType.isValid()) Res = ParseNumber(ExpectedType.get()); else ConsumeToken(); ExpectRParen("unexpected argument in coercion."); return Res; } if (Tok.kind != Token::Identifier) { Error("unexpected token, expected expression."); SkipUntilRParen(); return ExprResult(); } Token Name = Tok; ConsumeToken(); // FIXME: Use invalid type (i.e. width==0)? Token TypeTok = Tok; bool HasType = TypeTok.kind == Token::KWWidth; TypeResult Type = HasType ? ParseTypeSpecifier() : Expr::Bool; // FIXME: For now just skip to rparen on error. It might be nice // to try and actually parse the child nodes though for error // messages & better recovery? if (!Type.isValid()) { SkipUntilRParen(); return ExprResult(); } Expr::Width ResTy = Type.get(); unsigned ExprKind; bool IsFixed; int NumArgs; if (!LookupExprInfo(Name, ExprKind, IsFixed, NumArgs)) { // FIXME: For now just skip to rparen on error. It might be nice // to try and actually parse the child nodes though for error // messages & better recovery? Error("unknown expression kind.", Name); SkipUntilRParen(); return ExprResult(); } // See if we have to parse this form specially. if (NumArgs == -1) { switch (ExprKind) { case eMacroKind_Concat: return ParseConcatParenExpr(Name, ResTy); case Expr::Extract: return ParseExtractParenExpr(Name, ResTy); case eMacroKind_ReadLSB: case eMacroKind_ReadMSB: case Expr::Read: return ParseAnyReadParenExpr(Name, ExprKind, ResTy); default: Error("internal error, unimplemented special form.", Name); SkipUntilRParen(); return ExprResult(Builder->Constant(0, ResTy)); } } switch (NumArgs) { case 1: return ParseUnaryParenExpr(Name, ExprKind, IsFixed, ResTy); case 2: return ParseBinaryParenExpr(Name, ExprKind, IsFixed, ResTy); case 3: if (ExprKind == Expr::Select) return ParseSelectParenExpr(Name, ResTy); default: assert(0 && "Invalid argument kind (number of args)."); return ExprResult(); } }
/// 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; }
/// 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; }