// 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::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); }
Parser::StmtResult Parser::ParseSelectCaseStmt() { auto Loc = ConsumeToken(); ExprResult Operand; if(ExpectAndConsume(tok::l_paren)) { Operand = ParseExpectedFollowupExpression("("); if(Operand.isUsable()) { if(!ExpectAndConsume(tok::r_paren)) SkipUntilNextStatement(); } else SkipUntilNextStatement(); } else SkipUntilNextStatement(); return Actions.ActOnSelectCaseStmt(Context, Loc, Operand, StmtConstructName, 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); }
Parser::StmtResult Parser::ParseAmbiguousAssignmentStmt() { ParseStatementLabel(); auto S = ParseAssignmentStmt(); if(S.isInvalid()) SkipUntilNextStatement(); else ExpectStatementEnd(); return S; }
/// 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); }
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); }
/// 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); }
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::ParseCallStmt() { auto Loc = ConsumeToken(); SourceLocation RParenLoc = getExpectedLoc(); auto ID = Tok.getIdentifierInfo(); auto IDLoc = Tok.getLocation(); if(!ExpectAndConsume(tok::identifier)) return StmtError(); SmallVector<Expr*, 8> Arguments; if(!Tok.isAtStartOfStatement()) { if(ParseFunctionCallArgumentList(Arguments, RParenLoc).isInvalid()) SkipUntilNextStatement(); } return Actions.ActOnCallStmt(Context, Loc, RParenLoc, IDLoc, ID, Arguments, StmtLabel); }
// FIXME: fixed-form THENconstructname Parser::StmtResult Parser::ParseElseIfStmt() { auto Loc = ConsumeToken(); ExprResult Condition; if (!ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "ELSE 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 (!ExpectAndConsumeFixedFormAmbiguous(tok::kw_THEN, diag::err_expected_kw, "THEN")) goto error; ParseTrailingConstructName(); return Actions.ActOnElseIfStmt(Context, Loc, Condition, StmtConstructName, StmtLabel); error: SkipUntilNextStatement(); return Actions.ActOnElseIfStmt(Context, Loc, Condition, StmtConstructName, StmtLabel); }
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); }
/// 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); }