Parser::StmtResult Parser::ParseWriteStmt() { SourceLocation Loc = ConsumeToken(); // clist if(!ExpectAndConsume(tok::l_paren)) return StmtError(); UnitSpec *US = nullptr; FormatSpec *FS = nullptr; US = ParseUNITSpec(false); if(ConsumeIfPresent(tok::comma)) { bool IsFormatLabeled = false; if(ConsumeIfPresent(tok::kw_FMT)) { if(!ExpectAndConsume(tok::equal)) return StmtError(); IsFormatLabeled = true; } FS = ParseFMTSpec(IsFormatLabeled); } if(!ExpectAndConsume(tok::r_paren)) return StmtError(); // iolist SmallVector<ExprResult, 4> OutputItemList; ParseIOList(OutputItemList); return Actions.ActOnWriteStmt(Context, Loc, US, FS, OutputItemList, StmtLabel); }
/// ParseEQUIVALENCEStmt - Parse the EQUIVALENCE statement. /// /// [R554]: /// equivalence-stmt := /// EQUIVALENCE equivalence-set-list Parser::StmtResult Parser::ParseEQUIVALENCEStmt() { // Check if this is an assignment. if (IsNextToken(tok::equal)) return StmtResult(); auto Loc = ConsumeToken(); SmallVector<Stmt*, 8> StmtList; SmallVector<Expr*, 8> ObjectList; bool OuterError = false; while(true) { auto PartLoc = Tok.getLocation(); if(!ExpectAndConsume(tok::l_paren)) { if(!SkipUntil(tok::l_paren)) { OuterError = true; break; } } ObjectList.clear(); bool InnerError = false; do { auto E = ParseExpectedExpression(); if(E.isInvalid()) { InnerError = true; break; } else if(E.isUsable()) ObjectList.push_back(E.get()); } while(ConsumeIfPresent(tok::comma)); auto S = Actions.ActOnEQUIVALENCE(Context, Loc, PartLoc, ObjectList, nullptr); if(S.isUsable()) StmtList.push_back(S.get()); if(InnerError) { if(!SkipUntil(tok::r_paren, true, true)) { OuterError = true; break; } } if(!ExpectAndConsume(tok::r_paren)) { if(!SkipUntil(tok::r_paren)) { OuterError = true; break; } } if(ConsumeIfPresent(tok::comma)) continue; if(IsPresent(tok::l_paren)) { ExpectAndConsume(tok::comma); continue; } break; } if(OuterError) SkipUntilNextStatement(); else ExpectStatementEnd(); return Actions.ActOnCompoundStmt(Context, Loc, StmtList, StmtLabel); }
/// FIXME: todo implied-do ExprResult Parser::ParseArrayConstructor() { auto Loc = ConsumeParenSlash(); SourceLocation EndLoc = Tok.getLocation(); SmallVector<Expr*, 16> ExprList; if(ConsumeIfPresent(tok::slashr_paren)) return Actions.ActOnArrayConstructorExpr(Context, Loc, EndLoc, ExprList); do { auto E = ParseExpectedExpression(); if(E.isInvalid()) goto error; if(E.isUsable()) ExprList.push_back(E.get()); } while(ConsumeIfPresent(tok::comma)); EndLoc = Tok.getLocation(); if(!ExpectAndConsume(tok::slashr_paren)) goto error; return Actions.ActOnArrayConstructorExpr(Context, Loc, EndLoc, ExprList); error: EndLoc = Tok.getLocation(); SkipUntil(tok::slashr_paren); return Actions.ActOnArrayConstructorExpr(Context, Loc, EndLoc, ExprList); }
/// ParseCOMMONStmt - Parse the COMMON statement. /// /// [5.5.2] R557: /// common-stmt := /// COMMON # /// # [ / [common-block-name] / ] common-block-object-list # /// # [ [,] / [common-block-name / # /// # common-block-object-list ] ... Parser::StmtResult Parser::ParseCOMMONStmt() { // Check if this is an assignment. if (IsNextToken(tok::equal)) return StmtResult(); auto Loc = ConsumeToken(); SmallVector<Stmt*, 8> StmtList; SmallVector<Expr*, 8> ObjectList; SourceLocation BlockIDLoc; const IdentifierInfo *BlockID = nullptr; bool Error = false; do { if(ConsumeIfPresent(tok::slash)) { if(ConsumeIfPresent(tok::slash)) BlockID = nullptr; else { BlockIDLoc = Tok.getLocation(); BlockID = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier)) { Error = true; break; } if(!ExpectAndConsume(tok::slash)) { Error = true; break; } } } else if(ConsumeIfPresent(tok::slashslash)) BlockID = nullptr; auto IDLoc = Tok.getLocation(); auto IDInfo = Tok.getIdentifierInfo(); SmallVector<ArraySpec*, 8> Dimensions; if(!ExpectAndConsume(tok::identifier)) { Error = true; break; } if(IsPresent(tok::l_paren)) { if(ParseArraySpec(Dimensions)) { Error = true; break; } } Actions.ActOnCOMMON(Context, Loc, BlockIDLoc, IDLoc, BlockID, IDInfo, Dimensions); } while(ConsumeIfPresent(tok::comma)); if(Error) SkipUntilNextStatement(); else ExpectStatementEnd(); return Actions.ActOnCompoundStmt(Context, Loc, StmtList, StmtLabel); }
// FIXME: Fortran 2008 stuff. /// ParseDerivedTypeDefinitionStmt - Parse a type or a class definition. /// /// [R422]: /// derived-type-def := /// derived-type-stmt /// [ private-sequence-stmt ] ... /// component-def-stmt /// [ component-def-stmt ] ... /// end-type-stmt /// /// [R423]: /// derived-type-stmt := /// TYPE [ [ , access-spec ] :: ] type-name /// /// [R424]: /// private-sequence-stmt := /// PRIVATE or SEQUENCE /// /// [R425]: /// component-def-stmt := /// type-spec [ [ component-attr-spec-list ] :: ] component-decl-list /// /// [R426]: /// component-attr-spec-list := /// POINTER or /// DIMENSION( component-array-spec ) /// /// [R427]: /// component-array-spec := /// explicit-shape-spec-list or /// deffered-shape-spec-list /// /// [R428]: /// component-decl := /// component-name [ ( component-array-spec ) ] /// [ * char-length ] [ component-initialization ] /// /// [R429]: /// component-initialization := /// = initialization-expr or /// => NULL() /// /// [R430]: /// end-type-stmt := /// END TYPE [ type-name ] bool Parser::ParseDerivedTypeDefinitionStmt() { bool IsClass = Tok.is(tok::kw_CLASS); auto Loc = ConsumeToken(); if(ConsumeIfPresent(tok::comma)) { //FIXME: access-spec } ConsumeIfPresent(tok::coloncolon); auto ID = Tok.getIdentifierInfo(); auto IDLoc = Tok.getLocation(); if(!ExpectAndConsume(tok::identifier)) { SkipUntilNextStatement(); return true; } else ExpectStatementEnd(); Actions.ActOnDerivedTypeDecl(Context, Loc, IDLoc, ID); // FIXME: private if(Tok.is(tok::kw_SEQUENCE)) { Actions.ActOnDerivedTypeSequenceStmt(Context, ConsumeToken()); ExpectStatementEnd(); } bool Done = false; while(!Done) { switch(Tok.getKind()) { case tok::kw_TYPE: case tok::kw_CLASS: case tok::kw_INTEGER: case tok::kw_REAL: case tok::kw_COMPLEX: case tok::kw_CHARACTER: case tok::kw_BYTE: case tok::kw_LOGICAL: case tok::kw_DOUBLEPRECISION: case tok::kw_DOUBLECOMPLEX: if(ParseDerivedTypeComponentStmt()) SkipUntilNextStatement(); else ExpectStatementEnd(); break; default: Done = true; break; } } ParseEndTypeStmt(); Actions.ActOnEndDerivedTypeDecl(Context); return false; error: return true; }
Parser::StmtResult Parser::ParseDoStmt() { auto Loc = ConsumeToken(); auto CurStmtLoc = LocFirstStmtToken; ExprResult TerminalStmt; VarExpr *DoVar = nullptr; ExprResult E1, E2, E3; auto EqLoc = Loc; if(IsPresent(tok::int_literal_constant)) { TerminalStmt = ParseStatementLabelReference(); if(TerminalStmt.isInvalid()) return StmtError(); } bool isDo = ConsumeIfPresent(tok::comma); if(isDo && IsPresent(tok::kw_WHILE)) return ParseDoWhileStmt(isDo); // the do var auto IDInfo = Tok.getIdentifierInfo(); auto IDRange = getTokenRange(); auto IDLoc = Tok.getLocation(); if(!ExpectAndConsume(tok::identifier)) goto error; EqLoc = getMaxLocationOfCurrentToken(); if(Features.FixedForm && !isDo && IsPresent(tok::l_paren)) return ReparseAmbiguousAssignmentStatement(); if(!ExpectAndConsume(tok::equal)) goto error; E1 = ParseExpectedFollowupExpression("="); if(E1.isInvalid()) goto error; if(Features.FixedForm && !isDo && Tok.isAtStartOfStatement()) return ReparseAmbiguousAssignmentStatement(CurStmtLoc); if(!ExpectAndConsume(tok::comma)) goto error; E2 = ParseExpectedFollowupExpression(","); if(E2.isInvalid()) goto error; if(ConsumeIfPresent(tok::comma)) { E3 = ParseExpectedFollowupExpression(","); if(E3.isInvalid()) goto error; } if(auto VD = Actions.ExpectVarRefOrDeclImplicitVar(IDLoc, IDInfo)) DoVar = VarExpr::Create(Context, IDRange, VD); return Actions.ActOnDoStmt(Context, Loc, EqLoc, TerminalStmt, DoVar, E1, E2, E3, StmtConstructName, StmtLabel); error: if(IDInfo) { if(auto VD = Actions.ExpectVarRefOrDeclImplicitVar(IDLoc, IDInfo)) DoVar = VarExpr::Create(Context, IDRange, VD); } SkipUntilNextStatement(); return Actions.ActOnDoStmt(Context, Loc, EqLoc, TerminalStmt, DoVar, E1, E2, E3, StmtConstructName, StmtLabel); }
/// ParseDataReference - Parse a data reference. /// /// R611: /// data-ref := /// part-ref [ % part-ref ] ... ExprResult Parser::ParseDataReference() { std::vector<ExprResult> Exprs; do { ExprResult E = ParsePartReference(); if (E.isInvalid()) return E; Exprs.push_back(E); } while (ConsumeIfPresent(tok::percent) || ConsumeIfPresent(tok::period)); return Actions.ActOnDataReference(Exprs); }
bool Parser::ParseDerivedTypeComponentStmt() { // type-spec DeclSpec DS; if(ParseDeclarationTypeSpec(DS, true, false)) return true; // component-attr-spec if(ConsumeIfPresent(tok::comma)) { do { auto Kind = Tok.getKind(); auto Loc = Tok.getLocation(); auto ID = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier)) return true; if(Kind == tok::kw_POINTER) Actions.ActOnAttrSpec(Loc, DS, DeclSpec::AS_pointer); else if(Kind == tok::kw_DIMENSION) { if(ParseDimensionAttributeSpec(Loc, DS)) return true; } else { if(isAttributeSpec(Kind)) Diag.Report(Loc, diag::err_use_of_attr_spec_in_type_decl) << ID; else Diag.Report(Loc, diag::err_expected_attr_spec); if(!SkipUntil(tok::coloncolon, true, true)) return true; break; } } while(ConsumeIfPresent(tok::comma)); if(!ExpectAndConsume(tok::coloncolon)) return true; } else ConsumeIfPresent(tok::coloncolon); // component-decl-list do { auto IDLoc = Tok.getLocation(); auto ID = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier)) return true; DeclSpec ObjectDS(DS); if(ParseObjectArraySpec(IDLoc, ObjectDS)) return true; if(ParseObjectCharLength(IDLoc, ObjectDS)) return true; // FIXME: initialization expressions Actions.ActOnDerivedTypeFieldDecl(Context, ObjectDS, IDLoc, ID); } while(ConsumeIfPresent(tok::comma)); return false; }
Parser::StmtResult Parser::ParseGotoStmt() { SourceLocation Loc = ConsumeToken(); if(ConsumeIfPresent(tok::l_paren)) { // computed goto. SmallVector<Expr*, 4> Targets; do { auto E = ParseStatementLabelReference(); if(E.isInvalid()) break; Targets.append(1, E.get()); } while(ConsumeIfPresent(tok::comma)); ExprResult Operand; bool ParseOperand = true; if(!ExpectAndConsume(tok::r_paren)) { if(!SkipUntil(tok::r_paren)) ParseOperand = false; } if(ParseOperand) Operand = ParseExpectedExpression(); return Actions.ActOnComputedGotoStmt(Context, Loc, Targets, Operand, StmtLabel); } auto Destination = ParseStatementLabelReference(); if(Destination.isInvalid()) { if(!IsPresent(tok::identifier)) { Diag.Report(getExpectedLoc(), diag::err_expected_stmt_label_after) << "GO TO"; return StmtError(); } auto IDInfo = Tok.getIdentifierInfo(); auto IDLoc = ConsumeToken(); auto VD = Actions.ExpectVarRef(IDLoc, IDInfo); if(!VD) return StmtError(); auto Var = VarExpr::Create(Context, IDLoc, VD); // Assigned goto SmallVector<Expr*, 4> AllowedValues; if(ConsumeIfPresent(tok::l_paren)) { do { auto E = ParseStatementLabelReference(); if(E.isInvalid()) { Diag.Report(getExpectedLoc(), diag::err_expected_stmt_label); SkipUntilNextStatement(); return Actions.ActOnAssignedGotoStmt(Context, Loc, Var, AllowedValues, StmtLabel); } AllowedValues.append(1, E.get()); } while(ConsumeIfPresent(tok::comma)); ExpectAndConsume(tok::r_paren); } return Actions.ActOnAssignedGotoStmt(Context, Loc, Var, AllowedValues, StmtLabel); } // Uncoditional goto return Actions.ActOnGotoStmt(Context, Loc, Destination, StmtLabel); }
Parser::StmtResult Parser::ParseCaseStmt() { auto Loc = ConsumeToken(); if(ConsumeIfPresent(tok::kw_DEFAULT)) { ParseTrailingConstructName(); return Actions.ActOnCaseDefaultStmt(Context, Loc, StmtConstructName, StmtLabel); } SmallVector<Expr*, 8> Values; ExpectAndConsume(tok::l_paren); do { auto ColonLoc = Tok.getLocation(); if(ConsumeIfPresent(tok::colon)) { auto E = ParseExpectedFollowupExpression(":"); if(E.isInvalid()) goto error; if(E.isUsable()) Values.push_back(RangeExpr::Create(Context, ColonLoc, nullptr, E.get())); } else { auto E = ParseExpectedExpression(); if(E.isInvalid()) goto error; ColonLoc = Tok.getLocation(); if(ConsumeIfPresent(tok::colon)) { if(!(IsPresent(tok::comma) || IsPresent(tok::r_paren))) { auto E2 = ParseExpectedFollowupExpression(":"); if(E2.isInvalid()) goto error; if(E.isUsable() || E2.isUsable()) Values.push_back(RangeExpr::Create(Context, ColonLoc, E.get(), E2.get())); } else { if(E.isUsable()) Values.push_back(RangeExpr::Create(Context, ColonLoc, E.get(), nullptr)); } } else { if(E.isUsable()) Values.push_back(E.get()); } } } while(ConsumeIfPresent(tok::comma)); if(ExpectAndConsume(tok::r_paren)) { ParseTrailingConstructName(); } else SkipUntilNextStatement(); return Actions.ActOnCaseStmt(Context, Loc, Values, StmtConstructName, StmtLabel); error: if(SkipUntil(tok::r_paren)) { ParseTrailingConstructName(); } else SkipUntilNextStatement(); return Actions.ActOnCaseStmt(Context, Loc, Values, StmtConstructName, StmtLabel); }
bool Parser::ParseCharacterStarLengthSpec(DeclSpec &DS) { ExprResult Len; if(ConsumeIfPresent(tok::l_paren)) { if(ConsumeIfPresent(tok::star)) { DS.setStartLengthSelector(); } else Len = ParseExpectedFollowupExpression("("); if(!ExpectAndConsume(tok::r_paren)) return true; } else Len = ParseExpectedFollowupExpression("*"); if(Len.isInvalid()) return true; if(Len.isUsable()) DS.setLengthSelector(Len.take()); return false; }
bool Parser::ParseObjectCharLength(SourceLocation Loc, DeclSpec &DS) { if(DS.getTypeSpecType() == TST_character && ConsumeIfPresent(tok::star)) { if (DS.hasLengthSelector()) Diag.Report(getExpectedLoc(), diag::err_duplicate_len_selector); return ParseCharacterStarLengthSpec(DS); } return false; }
void Parser::ParseIOList(SmallVectorImpl<ExprResult> &List) { while(!Tok.isAtStartOfStatement()) { auto E = ParseExpression(); if(E.isUsable()) List.push_back(E); if(!ConsumeIfPresent(tok::comma)) break; } }
/// Parse the optional KIND or LEN selector. /// /// [R405]: /// kind-selector := /// ( [ KIND = ] scalar-int-initialization-expr ) /// [R425]: /// length-selector := /// ( [ LEN = ] type-param-value ) ExprResult Parser::ParseSelector(bool IsKindSel) { if (ConsumeIfPresent(IsKindSel ? tok::kw_KIND : tok::kw_LEN)) { if (!ExpectAndConsume(tok::equal)) return ExprError(); // TODO: We have a "REAL (KIND(10D0)) :: x" situation. } return ParseExpression(); }
UnitSpec *Parser::ParseUNITSpec(bool IsLabeled) { auto Loc = Tok.getLocation(); if(!ConsumeIfPresent(tok::star)) { auto E = ParseExpression(); if(!E.isInvalid()) return Actions.ActOnUnitSpec(Context, E, Loc, IsLabeled); } return Actions.ActOnStarUnitSpec(Context, Loc, IsLabeled); }
// ParseLevel5Expr - Level-5 expressions are level-4 expressions optionally // involving the logical operators. // // R717: // level-5-expr := // [ level-5-expr equiv-op ] equiv-operand // R716: // equiv-operand := // [ equiv-operand or-op ] or-operand // R715: // or-operand := // [ or-operand and-op ] and-operand // R714: // and-operand := // [ not-op ] level-4-expr // // R718: // not-op := // .NOT. // R719: // and-op := // .AND. // R720: // or-op := // .OR. // R721: // equiv-op := // .EQV. // or .NEQV. Parser::ExprResult Parser::ParseAndOperand() { SourceLocation NotLoc = Tok.getLocation(); bool Negate = ConsumeIfPresent(tok::kw_NOT); ExprResult E = ParseLevel4Expr(); if (E.isInvalid()) return E; if (Negate) E = Actions.ActOnUnaryExpr(Context, NotLoc, UnaryExpr::Not, E); return E; }
/// ParseDIMENSIONStmt - Parse the DIMENSION statement. /// /// [R535]: /// dimension-stmt := /// DIMENSION [::] array-name ( array-spec ) # /// # [ , array-name ( array-spec ) ] ... Parser::StmtResult Parser::ParseDIMENSIONStmt() { // Check if this is an assignment. if (IsNextToken(tok::equal)) return StmtResult(); auto Loc = ConsumeToken(); ConsumeIfPresent(tok::coloncolon); SmallVector<Stmt*, 8> StmtList; SmallVector<ArraySpec*, 4> Dimensions; while (true) { auto IDLoc = Tok.getLocation(); auto II = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier)) { if(!SkipUntil(tok::comma, tok::identifier, true, true)) break; if(ConsumeIfPresent(tok::comma)) continue; else { IDLoc = Tok.getLocation(); II = Tok.getIdentifierInfo(); ConsumeToken(); } } // FIXME: improve error recovery Dimensions.clear(); if(ParseArraySpec(Dimensions)) return StmtError(); auto Stmt = Actions.ActOnDIMENSION(Context, Loc, IDLoc, II, Dimensions, nullptr); if(Stmt.isUsable()) StmtList.push_back(Stmt.take()); if(Tok.isAtStartOfStatement()) break; if(!ExpectAndConsume(tok::comma)) { if(!SkipUntil(tok::comma)) break; } } return Actions.ActOnCompoundStmt(Context, Loc, StmtList, StmtLabel); }
/// ParseINTRINSICStmt - Parse the INTRINSIC statement. /// /// [R1216]: /// intrinsic-stmt := /// INTRINSIC [::] intrinsic-procedure-name-list Parser::StmtResult Parser::ParseINTRINSICStmt(bool IsActuallyExternal) { // Check if this is an assignment. if (IsNextToken(tok::equal)) return StmtResult(); auto Loc = ConsumeToken(); ConsumeIfPresent(tok::coloncolon); SmallVector<Stmt *,8> StmtList; while(true) { auto IDLoc = Tok.getLocation(); auto II = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier)) { if(!SkipUntil(tok::comma, tok::identifier, true, true)) break; if(ConsumeIfPresent(tok::comma)) continue; else { IDLoc = Tok.getLocation(); II = Tok.getIdentifierInfo(); ConsumeToken(); } } auto Stmt = IsActuallyExternal? Actions.ActOnEXTERNAL(Context, Loc, IDLoc, II, nullptr): Actions.ActOnINTRINSIC(Context, Loc, IDLoc, II, nullptr); if(Stmt.isUsable()) StmtList.push_back(Stmt.take()); if(Tok.isAtStartOfStatement()) break; if(!ExpectAndConsume(tok::comma)) { if(!SkipUntil(tok::comma)) break; } } return Actions.ActOnCompoundStmt(Context, Loc, StmtList, StmtLabel); }
/// ParsePARAMETERStmt - Parse the PARAMETER statement. /// /// [R548]: /// parameter-stmt := /// PARAMETER ( named-constant-def-list ) Parser::StmtResult Parser::ParsePARAMETERStmt() { // Check if this is an assignment. if (IsNextToken(tok::equal)) return StmtResult(); auto Loc = ConsumeToken(); SmallVector<Stmt*, 8> StmtList; if(!ExpectAndConsume(tok::l_paren)) { if(!SkipUntil(tok::l_paren)) return StmtError(); } while(true) { auto IDLoc = Tok.getLocation(); auto II = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier)) { if(!SkipUntil(tok::comma)) break; else continue; } auto EqualLoc = Tok.getLocation(); if(!ExpectAndConsume(tok::equal)) { if(!SkipUntil(tok::comma)) break; else continue; } ExprResult ConstExpr = ParseExpression(); if(ConstExpr.isUsable()) { auto Stmt = Actions.ActOnPARAMETER(Context, Loc, EqualLoc, IDLoc, II, ConstExpr, nullptr); if(Stmt.isUsable()) StmtList.push_back(Stmt.take()); } if(ConsumeIfPresent(tok::comma)) continue; if(isTokenIdentifier() && !Tok.isAtStartOfStatement()) { ExpectAndConsume(tok::comma); continue; } break; } if(!ExpectAndConsume(tok::r_paren)) SkipUntilNextStatement(); return Actions.ActOnCompoundStmt(Context, Loc, StmtList, StmtLabel); }
ExprResult Parser::ParseArraySection(const char *PunctuationTok) { ExprResult LB, UB, Stride; bool Range = false; auto ColonLoc = Tok.getLocation(); if(ConsumeIfPresent(tok::colon)) { Range = true; if(!IsPresent(tok::colon) && !IsPresent(tok::comma) && !IsPresent(tok::r_paren)) { UB = ParseExpectedFollowupExpression(":"); if(UB.isInvalid()) return UB; } } else { LB = ParseExpectedFollowupExpression(PunctuationTok); if(LB.isInvalid()) return LB; ColonLoc = Tok.getLocation(); if(ConsumeIfPresent(tok::colon)) { Range = true; if(!IsPresent(tok::colon) && !IsPresent(tok::comma) && !IsPresent(tok::r_paren)) { UB = ParseExpectedFollowupExpression(":"); if(UB.isInvalid()) return UB; } } } if(ConsumeIfPresent(tok::colon)) { Stride = ParseExpectedFollowupExpression(":"); if(Stride.isInvalid()) return Stride; } if(Stride.isUsable()) return StridedRangeExpr::Create(Context, ColonLoc, LB.get(), UB.get(), Stride.get()); if(Range) return RangeExpr::Create(Context, ColonLoc, LB.get(), UB.get()); return LB; }
/// ParseFunctionCallArgumentList - Parses an argument list to a call expression. ExprResult Parser::ParseFunctionCallArgumentList(SmallVectorImpl<Expr*> &Args, SourceLocation &RParenLoc) { if(!ExpectAndConsume(tok::l_paren)) return ExprError(); RParenLoc = getExpectedLoc(); if(ConsumeIfPresent(tok::r_paren)) return ExprResult(); auto PunctuationTok = "("; do { if(Tok.isAtStartOfStatement()) break; auto E = ParseExpectedFollowupExpression(PunctuationTok); if(E.isInvalid()) SkipUntil(tok::comma, tok::r_paren, true, true); else Args.push_back(E.get()); PunctuationTok = ","; } while (ConsumeIfPresent(tok::comma)); RParenLoc = getExpectedLoc(); ExpectAndConsume(tok::r_paren, 0, "", tok::r_paren); return ExprResult(); }
/// ParseAssignmentStmt /// [R732]: /// assignment-stmt := /// variable = expr Parser::StmtResult Parser::ParseAssignmentStmt() { ExprResult LHS = ParsePrimaryExpr(true); if(LHS.isInvalid()) return StmtError(); SourceLocation Loc = Tok.getLocation(); if(!ConsumeIfPresent(tok::equal)) { Diag.Report(getExpectedLoc(),diag::err_expected_equal); return StmtError(); } ExprResult RHS = ParseExpectedFollowupExpression("="); if(RHS.isInvalid()) return StmtError(); return Actions.ActOnAssignmentStmt(Context, Loc, LHS, RHS, StmtLabel); }
/// ParseSubstring - Parse a substring. /// /// R608: /// substring := /// parent-string ( substring-range ) /// R609: /// parent-string := /// scalar-variable-name /// or array-element /// or coindexed-named-object /// or scalar-structure-component /// or scalar-constant /// R610: /// substring-range := /// [ scalar-int-expr ] : [ scalar-int-expr ] ExprResult Parser::ParseSubstring(ExprResult Target) { ExprResult StartingPoint, EndPoint; auto Loc = ConsumeParen(); if(!ConsumeIfPresent(tok::colon)) { StartingPoint = ParseExpectedFollowupExpression("("); if(StartingPoint.isInvalid()) SkipUntil(tok::colon, true, true); Loc = Tok.getLocation(); if(!ExpectAndConsume(tok::colon, 0, "", tok::r_paren)) goto done; } if(!ConsumeIfPresent(tok::r_paren)) { EndPoint = ParseExpectedFollowupExpression(":"); if(EndPoint.isInvalid()) SkipUntil(tok::r_paren, true, true); ExpectAndConsume(tok::r_paren, 0, "", tok::r_paren); } done: return Actions.ActOnSubstringExpr(Context, Loc, Target.get(), StartingPoint.get(), EndPoint.get()); }
bool Parser::ParseEntityDeclarationList(DeclSpec &DS, SmallVectorImpl<DeclResult> &Decls) { do { auto IDLoc = Tok.getLocation(); auto ID = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier)) return true; DeclSpec ObjectDS(DS); if(ParseObjectArraySpec(IDLoc, ObjectDS)) return true; if(ParseObjectCharLength(IDLoc, ObjectDS)) return true; Decls.push_back(Actions.ActOnEntityDecl(Context, ObjectDS, IDLoc, ID)); } while(ConsumeIfPresent(tok::comma)); return false; }
FormatSpec *Parser::ParseFMTSpec(bool IsLabeled) { auto Loc = Tok.getLocation(); if(!ConsumeIfPresent(tok::star)) { if(Tok.is(tok::int_literal_constant)) { auto Destination = ParseStatementLabelReference(); if(!Destination.isInvalid()) return Actions.ActOnLabelFormatSpec(Context, Loc, Destination); } auto E = ParseExpression(); if(E.isUsable()) return Actions.ActOnExpressionFormatSpec(Context, Loc, E.get()); // NB: return empty format string on error. return Actions.ActOnExpressionFormatSpec(Context, Loc, CharacterConstantExpr::Create(Context, Loc, "", Context.CharacterTy)); } return Actions.ActOnStarFormatSpec(Context, Loc); }
Parser::StmtResult Parser::ParseIfStmt() { auto Loc = ConsumeToken(); ExprResult Condition; if (!ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "IF")) goto error; Condition = ParseExpectedFollowupExpression("("); if(Condition.isInvalid()) { if(!SkipUntil(tok::r_paren, true, true)) goto error; } if (!ExpectAndConsume(tok::r_paren)) goto error; if(Features.FixedForm && !Tok.isAtStartOfStatement()) ReLexAmbiguousIdentifier(FixedFormAmbiguities.getMatcherForKeywordsAfterIF()); if (!ConsumeIfPresent(tok::kw_THEN)) { // if-stmt if(Tok.isAtStartOfStatement()) { Diag.Report(getExpectedLoc(), diag::err_expected_executable_stmt); return StmtError(); } auto Result = Actions.ActOnIfStmt(Context, Loc, Condition, StmtConstructName, StmtLabel); if(Result.isInvalid()) return Result; // NB: Don't give the action stmt my label StmtLabel = nullptr; auto Action = ParseActionStmt(); Actions.ActOnEndIfStmt(Context, Loc, ConstructName(SourceLocation(), nullptr), nullptr); return Action.isInvalid()? StmtError() : Result; } // if-construct. return Actions.ActOnIfStmt(Context, Loc, Condition, StmtConstructName, StmtLabel); error: SkipUntilNextStatement(); return Actions.ActOnIfStmt(Context, Loc, Condition, StmtConstructName, StmtLabel); }
/// ParseArrauSubscript - Parse an Array Subscript Expression ExprResult Parser::ParseArraySubscript(ExprResult Target) { SmallVector<Expr*, 8> ExprList; auto Loc = ConsumeParen(); bool IgnoreRParen = false; auto PunctuationTok = "("; do { if(Tok.isAtStartOfStatement()) IgnoreRParen = true; auto E = ParseArraySection(PunctuationTok); if(E.isInvalid()) SkipUntil(tok::comma, tok::r_paren, true, true); if(E.isUsable()) ExprList.push_back(E.get()); PunctuationTok = ","; } while(ConsumeIfPresent(tok::comma)); auto RParenLoc = getExpectedLoc(); if(!IgnoreRParen) ExpectAndConsume(tok::r_paren, 0, "", tok::r_paren); return Actions.ActOnSubscriptExpr(Context, Loc, RParenLoc, Target.get(), ExprList); }
// ParsePrimaryExpr - Parse a primary expression. // // [R701]: // primary := // constant // or designator // or array-constructor // or structure-constructor // or function-reference // or type-param-inquiry // or type-param-name // or ( expr ) Parser::ExprResult Parser::ParsePrimaryExpr(bool IsLvalue) { ExprResult E; SourceLocation Loc = Tok.getLocation(); // FIXME: Add rest of the primary expressions. switch (Tok.getKind()) { default: if (isTokenIdentifier()) goto possible_keyword_as_ident; Diag.Report(getExpectedLoc(), diag::err_expected_expression); return ExprError(); case tok::error: Lex(); return ExprError(); case tok::l_paren: { ConsumeParen(); E = ParseExpression(); // complex constant. if(ConsumeIfPresent(tok::comma)) { if(E.isInvalid()) return E; auto ImPart = ParseExpectedFollowupExpression(","); if(ImPart.isInvalid()) return ImPart; E = Actions.ActOnComplexConstantExpr(Context, Loc, getMaxLocationOfCurrentToken(), E, ImPart); } ExpectAndConsume(tok::r_paren, 0, "", tok::r_paren); break; } case tok::l_parenslash : { return ParseArrayConstructor(); break; } case tok::logical_literal_constant: { std::string NumStr; CleanLiteral(Tok, NumStr); StringRef Data(NumStr); std::pair<StringRef, StringRef> StrPair = Data.split('_'); E = LogicalConstantExpr::Create(Context, getTokenRange(), StrPair.first, Context.LogicalTy); SetKindSelector(cast<ConstantExpr>(E.get()), StrPair.second); ConsumeToken(); break; } case tok::binary_boz_constant: case tok::octal_boz_constant: case tok::hex_boz_constant: { std::string NumStr; CleanLiteral(Tok, NumStr); StringRef Data(NumStr); std::pair<StringRef, StringRef> StrPair = Data.split('_'); E = BOZConstantExpr::Create(Context, Loc, getMaxLocationOfCurrentToken(), StrPair.first); SetKindSelector(cast<ConstantExpr>(E.get()), StrPair.second); ConsumeToken(); break; } case tok::char_literal_constant: { std::string NumStr; CleanLiteral(Tok, NumStr); E = CharacterConstantExpr::Create(Context, getTokenRange(), StringRef(NumStr), Context.CharacterTy); ConsumeToken(); // Possible substring if(IsPresent(tok::l_paren)) return ParseSubstring(E); break; } case tok::int_literal_constant: { std::string NumStr; CleanLiteral(Tok, NumStr); StringRef Data(NumStr); std::pair<StringRef, StringRef> StrPair = Data.split('_'); E = IntegerConstantExpr::Create(Context, getTokenRange(), StrPair.first); SetKindSelector(cast<ConstantExpr>(E.get()), StrPair.second); Lex(); break; } case tok::real_literal_constant: { std::string NumStr; CleanLiteral(Tok, NumStr); StringRef Data(NumStr); std::pair<StringRef, StringRef> StrPair = Data.split('_'); E = RealConstantExpr::Create(Context, getTokenRange(), NumStr, Context.RealTy); SetKindSelector(cast<ConstantExpr>(E.get()), StrPair.second); ConsumeToken(); break; } case tok::double_precision_literal_constant: { std::string NumStr; CleanLiteral(Tok, NumStr); // Replace the d/D exponent into e exponent for(size_t I = 0, Len = NumStr.length(); I < Len; ++I) { if(NumStr[I] == 'd' || NumStr[I] == 'D') { NumStr[I] = 'e'; break; } else if(NumStr[I] == '_') break; } StringRef Data(NumStr); std::pair<StringRef, StringRef> StrPair = Data.split('_'); E = RealConstantExpr::Create(Context, getTokenRange(), NumStr, Context.DoublePrecisionTy); SetKindSelector(cast<ConstantExpr>(E.get()), StrPair.second); ConsumeToken(); break; } case tok::identifier: possible_keyword_as_ident: E = Parser::ParseDesignator(IsLvalue); if (E.isInvalid()) return E; break; case tok::minus: Lex(); E = Parser::ParsePrimaryExpr(); if (E.isInvalid()) return E; E = Actions.ActOnUnaryExpr(Context, Loc, UnaryExpr::Minus, E); break; case tok::plus: Lex(); E = Parser::ParsePrimaryExpr(); if (E.isInvalid()) return E; E = Actions.ActOnUnaryExpr(Context, Loc, UnaryExpr::Plus, E); break; } return E; }
/// ParseSAVEStmt - Parse the SAVE statement. /// /// [R543]: /// save-stmt := /// SAVE [ [::] saved-entity-list ] Parser::StmtResult Parser::ParseSAVEStmt() { // Check if this is an assignment. if (IsNextToken(tok::equal)) return StmtResult(); auto Loc = ConsumeToken(); if(Tok.isAtStartOfStatement()) return Actions.ActOnSAVE(Context, Loc, StmtLabel); bool IsSaveStmt = ConsumeIfPresent(tok::coloncolon); SmallVector<Stmt *,8> StmtList; bool ListParsedOk = true; auto IDLoc = Tok.getLocation(); auto II = Tok.getIdentifierInfo(); StmtResult Stmt; if(ConsumeIfPresent(tok::slash)) { IDLoc = Tok.getLocation(); II = Tok.getIdentifierInfo(); if(ExpectAndConsume(tok::identifier)) { if(!ExpectAndConsume(tok::slash)) ListParsedOk = false; Stmt = Actions.ActOnSAVECommonBlock(Context, Loc, IDLoc, II); } else ListParsedOk = false; } else if(ExpectAndConsume(tok::identifier)) { if(!IsSaveStmt && Features.FixedForm && (IsPresent(tok::equal) || IsPresent(tok::l_paren))) return ReparseAmbiguousAssignmentStatement(); Stmt = Actions.ActOnSAVE(Context, Loc, IDLoc, II, nullptr); } else ListParsedOk = false; if(Stmt.isUsable()) StmtList.push_back(Stmt.get()); if(ListParsedOk) { while(ConsumeIfPresent(tok::comma)) { IDLoc = Tok.getLocation(); II = Tok.getIdentifierInfo(); if(ConsumeIfPresent(tok::slash)) { IDLoc = Tok.getLocation(); II = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier)) { ListParsedOk = false; break; } if(!ExpectAndConsume(tok::slash)) { ListParsedOk = false; break; } Stmt = Actions.ActOnSAVECommonBlock(Context, Loc, IDLoc, II); } else if(ExpectAndConsume(tok::identifier)) Stmt = Actions.ActOnSAVE(Context, Loc, IDLoc, II, nullptr); else { ListParsedOk = false; break; } if(Stmt.isUsable()) StmtList.push_back(Stmt.get()); } } if(ListParsedOk) ExpectStatementEnd(); else SkipUntilNextStatement(); return Actions.ActOnCompoundStmt(Context, Loc, StmtList, StmtLabel); }
/// ParseIMPLICITStmt - Parse the IMPLICIT statement. /// /// [R560]: /// implicit-stmt := /// IMPLICIT implicit-spec-list /// or IMPLICIT NONE Parser::StmtResult Parser::ParseIMPLICITStmt() { // Check if this is an assignment. if (IsNextToken(tok::equal)) return StmtResult(); auto Loc = ConsumeToken(); if (ConsumeIfPresent(tok::kw_NONE)) { auto Result = Actions.ActOnIMPLICIT(Context, Loc, StmtLabel); ExpectStatementEnd(); return Result; } SmallVector<Stmt*, 8> StmtList; while(true) { // FIXME: improved error recovery DeclSpec DS; if (ParseDeclarationTypeSpec(DS, false)) return StmtError(); if(!ExpectAndConsume(tok::l_paren)) { if(!SkipUntil(tok::l_paren)) break; } bool InnerError = false; while(true) { auto FirstLoc = Tok.getLocation(); auto First = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier, diag::err_expected_letter)) { if(!SkipUntil(tok::comma)) { InnerError = true; break; } continue; } if(First->getName().size() > 1) { Diag.Report(FirstLoc, diag::err_expected_letter); } const IdentifierInfo *Second = nullptr; if (ConsumeIfPresent(tok::minus)) { auto SecondLoc = Tok.getLocation(); Second = Tok.getIdentifierInfo(); if(!ExpectAndConsume(tok::identifier, diag::err_expected_letter)) { if(!SkipUntil(tok::comma)) { InnerError = true; break; } continue; } if(Second->getName().size() > 1) { Diag.Report(SecondLoc, diag::err_expected_letter); } } auto Stmt = Actions.ActOnIMPLICIT(Context, Loc, DS, std::make_pair(First, Second), nullptr); if(Stmt.isUsable()) StmtList.push_back(Stmt.take()); if(ConsumeIfPresent(tok::comma)) continue; break; } if(InnerError && Tok.isAtStartOfStatement()) break; if(!ExpectAndConsume(tok::r_paren)) { if(!SkipUntil(tok::r_paren)) break; } if(Tok.isAtStartOfStatement()) break; if(!ExpectAndConsume(tok::comma)) { if(!SkipUntil(tok::comma)) break; } } ExpectStatementEnd(); return Actions.ActOnCompoundStmt(Context, Loc, StmtList, StmtLabel); }