1 //===-- lib/Parser/io-parsers.cpp -----------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // Per-type parsers for I/O statements and FORMAT 10 11 #include "basic-parsers.h" 12 #include "debug-parser.h" 13 #include "expr-parsers.h" 14 #include "misc-parsers.h" 15 #include "stmt-parser.h" 16 #include "token-parsers.h" 17 #include "type-parser-implementation.h" 18 #include "flang/Parser/characters.h" 19 #include "flang/Parser/parse-tree.h" 20 21 namespace Fortran::parser { 22 // R1201 io-unit -> file-unit-number | * | internal-file-variable 23 // R1203 internal-file-variable -> char-variable 24 // R905 char-variable -> variable 25 // "char-variable" is attempted first since it's not type constrained but 26 // syntactically ambiguous with "file-unit-number", which is constrained. 27 TYPE_PARSER(construct<IoUnit>(variable / !"="_tok) || 28 construct<IoUnit>(fileUnitNumber) || construct<IoUnit>(star)) 29 30 // R1202 file-unit-number -> scalar-int-expr 31 TYPE_PARSER(construct<FileUnitNumber>(scalarIntExpr / !"="_tok)) 32 33 // R1204 open-stmt -> OPEN ( connect-spec-list ) 34 TYPE_CONTEXT_PARSER("OPEN statement"_en_US, 35 construct<OpenStmt>( 36 "OPEN (" >> nonemptyList("expected connection specifications"_err_en_US, 37 Parser<ConnectSpec>{}) / 38 ")")) 39 40 // R1206 file-name-expr -> scalar-default-char-expr 41 constexpr auto fileNameExpr{scalarDefaultCharExpr}; 42 43 // R1205 connect-spec -> 44 // [UNIT =] file-unit-number | ACCESS = scalar-default-char-expr | 45 // ACTION = scalar-default-char-expr | 46 // ASYNCHRONOUS = scalar-default-char-expr | 47 // BLANK = scalar-default-char-expr | 48 // DECIMAL = scalar-default-char-expr | 49 // DELIM = scalar-default-char-expr | 50 // ENCODING = scalar-default-char-expr | ERR = label | 51 // FILE = file-name-expr | FORM = scalar-default-char-expr | 52 // IOMSG = iomsg-variable | IOSTAT = scalar-int-variable | 53 // NEWUNIT = scalar-int-variable | PAD = scalar-default-char-expr | 54 // POSITION = scalar-default-char-expr | RECL = scalar-int-expr | 55 // ROUND = scalar-default-char-expr | SIGN = scalar-default-char-expr | 56 // STATUS = scalar-default-char-expr 57 // @ | CONVERT = scalar-default-char-variable 58 // @ | DISPOSE = scalar-default-char-variable 59 constexpr auto statusExpr{construct<StatusExpr>(scalarDefaultCharExpr)}; 60 constexpr auto errLabel{construct<ErrLabel>(label)}; 61 62 TYPE_PARSER(first(construct<ConnectSpec>(maybe("UNIT ="_tok) >> fileUnitNumber), 63 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 64 "ACCESS =" >> pure(ConnectSpec::CharExpr::Kind::Access), 65 scalarDefaultCharExpr)), 66 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 67 "ACTION =" >> pure(ConnectSpec::CharExpr::Kind::Action), 68 scalarDefaultCharExpr)), 69 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 70 "ASYNCHRONOUS =" >> pure(ConnectSpec::CharExpr::Kind::Asynchronous), 71 scalarDefaultCharExpr)), 72 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 73 "BLANK =" >> pure(ConnectSpec::CharExpr::Kind::Blank), 74 scalarDefaultCharExpr)), 75 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 76 "DECIMAL =" >> pure(ConnectSpec::CharExpr::Kind::Decimal), 77 scalarDefaultCharExpr)), 78 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 79 "DELIM =" >> pure(ConnectSpec::CharExpr::Kind::Delim), 80 scalarDefaultCharExpr)), 81 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 82 "ENCODING =" >> pure(ConnectSpec::CharExpr::Kind::Encoding), 83 scalarDefaultCharExpr)), 84 construct<ConnectSpec>("ERR =" >> errLabel), 85 construct<ConnectSpec>("FILE =" >> fileNameExpr), 86 extension<LanguageFeature::FileName>( 87 construct<ConnectSpec>("NAME =" >> fileNameExpr)), 88 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 89 "FORM =" >> pure(ConnectSpec::CharExpr::Kind::Form), 90 scalarDefaultCharExpr)), 91 construct<ConnectSpec>("IOMSG =" >> msgVariable), 92 construct<ConnectSpec>("IOSTAT =" >> statVariable), 93 construct<ConnectSpec>(construct<ConnectSpec::Newunit>( 94 "NEWUNIT =" >> scalar(integer(variable)))), 95 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 96 "PAD =" >> pure(ConnectSpec::CharExpr::Kind::Pad), 97 scalarDefaultCharExpr)), 98 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 99 "POSITION =" >> pure(ConnectSpec::CharExpr::Kind::Position), 100 scalarDefaultCharExpr)), 101 construct<ConnectSpec>( 102 construct<ConnectSpec::Recl>("RECL =" >> scalarIntExpr)), 103 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 104 "ROUND =" >> pure(ConnectSpec::CharExpr::Kind::Round), 105 scalarDefaultCharExpr)), 106 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 107 "SIGN =" >> pure(ConnectSpec::CharExpr::Kind::Sign), 108 scalarDefaultCharExpr)), 109 construct<ConnectSpec>("STATUS =" >> statusExpr), 110 extension<LanguageFeature::Convert>( 111 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 112 "CONVERT =" >> pure(ConnectSpec::CharExpr::Kind::Convert), 113 scalarDefaultCharExpr))), 114 extension<LanguageFeature::Dispose>( 115 construct<ConnectSpec>(construct<ConnectSpec::CharExpr>( 116 "DISPOSE =" >> pure(ConnectSpec::CharExpr::Kind::Dispose), 117 scalarDefaultCharExpr))))) 118 119 // R1209 close-spec -> 120 // [UNIT =] file-unit-number | IOSTAT = scalar-int-variable | 121 // IOMSG = iomsg-variable | ERR = label | 122 // STATUS = scalar-default-char-expr 123 constexpr auto closeSpec{first( 124 construct<CloseStmt::CloseSpec>(maybe("UNIT ="_tok) >> fileUnitNumber), 125 construct<CloseStmt::CloseSpec>("IOSTAT =" >> statVariable), 126 construct<CloseStmt::CloseSpec>("IOMSG =" >> msgVariable), 127 construct<CloseStmt::CloseSpec>("ERR =" >> errLabel), 128 construct<CloseStmt::CloseSpec>("STATUS =" >> statusExpr))}; 129 130 // R1208 close-stmt -> CLOSE ( close-spec-list ) 131 TYPE_CONTEXT_PARSER("CLOSE statement"_en_US, 132 construct<CloseStmt>("CLOSE" >> parenthesized(nonemptyList(closeSpec)))) 133 134 // R1210 read-stmt -> 135 // READ ( io-control-spec-list ) [input-item-list] | 136 // READ format [, input-item-list] 137 constexpr auto inputItemList{ 138 extension<LanguageFeature::IOListLeadingComma>( 139 some("," >> inputItem)) || // legacy extension: leading comma 140 optionalList(inputItem)}; 141 142 TYPE_CONTEXT_PARSER("READ statement"_en_US, 143 construct<ReadStmt>("READ (" >> 144 construct<std::optional<IoUnit>>(maybe("UNIT ="_tok) >> ioUnit), 145 "," >> construct<std::optional<Format>>(format), 146 defaulted("," >> nonemptyList(ioControlSpec)) / ")", inputItemList) || 147 construct<ReadStmt>( 148 "READ (" >> construct<std::optional<IoUnit>>(ioUnit), 149 construct<std::optional<Format>>(), 150 defaulted("," >> nonemptyList(ioControlSpec)) / ")", 151 inputItemList) || 152 construct<ReadStmt>("READ" >> construct<std::optional<IoUnit>>(), 153 construct<std::optional<Format>>(), 154 parenthesized(nonemptyList(ioControlSpec)), inputItemList) || 155 construct<ReadStmt>("READ" >> construct<std::optional<IoUnit>>(), 156 construct<std::optional<Format>>(format), 157 construct<std::list<IoControlSpec>>(), many("," >> inputItem))) 158 159 // R1214 id-variable -> scalar-int-variable 160 constexpr auto idVariable{construct<IdVariable>(scalarIntVariable)}; 161 162 // R1213 io-control-spec -> 163 // [UNIT =] io-unit | [FMT =] format | [NML =] namelist-group-name | 164 // ADVANCE = scalar-default-char-expr | 165 // ASYNCHRONOUS = scalar-default-char-constant-expr | 166 // BLANK = scalar-default-char-expr | 167 // DECIMAL = scalar-default-char-expr | 168 // DELIM = scalar-default-char-expr | END = label | EOR = label | 169 // ERR = label | ID = id-variable | IOMSG = iomsg-variable | 170 // IOSTAT = scalar-int-variable | PAD = scalar-default-char-expr | 171 // POS = scalar-int-expr | REC = scalar-int-expr | 172 // ROUND = scalar-default-char-expr | SIGN = scalar-default-char-expr | 173 // SIZE = scalar-int-variable 174 constexpr auto endLabel{construct<EndLabel>(label)}; 175 constexpr auto eorLabel{construct<EorLabel>(label)}; 176 TYPE_PARSER(first(construct<IoControlSpec>("UNIT =" >> ioUnit), 177 construct<IoControlSpec>("FMT =" >> format), 178 construct<IoControlSpec>("NML =" >> name), 179 construct<IoControlSpec>( 180 "ADVANCE =" >> construct<IoControlSpec::CharExpr>( 181 pure(IoControlSpec::CharExpr::Kind::Advance), 182 scalarDefaultCharExpr)), 183 construct<IoControlSpec>(construct<IoControlSpec::Asynchronous>( 184 "ASYNCHRONOUS =" >> scalarDefaultCharConstantExpr)), 185 construct<IoControlSpec>("BLANK =" >> 186 construct<IoControlSpec::CharExpr>( 187 pure(IoControlSpec::CharExpr::Kind::Blank), scalarDefaultCharExpr)), 188 construct<IoControlSpec>( 189 "DECIMAL =" >> construct<IoControlSpec::CharExpr>( 190 pure(IoControlSpec::CharExpr::Kind::Decimal), 191 scalarDefaultCharExpr)), 192 construct<IoControlSpec>("DELIM =" >> 193 construct<IoControlSpec::CharExpr>( 194 pure(IoControlSpec::CharExpr::Kind::Delim), scalarDefaultCharExpr)), 195 construct<IoControlSpec>("END =" >> endLabel), 196 construct<IoControlSpec>("EOR =" >> eorLabel), 197 construct<IoControlSpec>("ERR =" >> errLabel), 198 construct<IoControlSpec>("ID =" >> idVariable), 199 construct<IoControlSpec>("IOMSG = " >> msgVariable), 200 construct<IoControlSpec>("IOSTAT = " >> statVariable), 201 construct<IoControlSpec>("PAD =" >> 202 construct<IoControlSpec::CharExpr>( 203 pure(IoControlSpec::CharExpr::Kind::Pad), scalarDefaultCharExpr)), 204 construct<IoControlSpec>( 205 "POS =" >> construct<IoControlSpec::Pos>(scalarIntExpr)), 206 construct<IoControlSpec>( 207 "REC =" >> construct<IoControlSpec::Rec>(scalarIntExpr)), 208 construct<IoControlSpec>("ROUND =" >> 209 construct<IoControlSpec::CharExpr>( 210 pure(IoControlSpec::CharExpr::Kind::Round), scalarDefaultCharExpr)), 211 construct<IoControlSpec>("SIGN =" >> 212 construct<IoControlSpec::CharExpr>( 213 pure(IoControlSpec::CharExpr::Kind::Sign), scalarDefaultCharExpr)), 214 construct<IoControlSpec>( 215 "SIZE =" >> construct<IoControlSpec::Size>(scalarIntVariable)))) 216 217 // R1211 write-stmt -> WRITE ( io-control-spec-list ) [output-item-list] 218 constexpr auto outputItemList{ 219 extension<LanguageFeature::IOListLeadingComma>( 220 some("," >> outputItem)) || // legacy: allow leading comma 221 optionalList(outputItem)}; 222 223 TYPE_CONTEXT_PARSER("WRITE statement"_en_US, 224 construct<WriteStmt>("WRITE (" >> 225 construct<std::optional<IoUnit>>(maybe("UNIT ="_tok) >> ioUnit), 226 "," >> construct<std::optional<Format>>(format), 227 defaulted("," >> nonemptyList(ioControlSpec)) / ")", outputItemList) || 228 construct<WriteStmt>( 229 "WRITE (" >> construct<std::optional<IoUnit>>(ioUnit), 230 construct<std::optional<Format>>(), 231 defaulted("," >> nonemptyList(ioControlSpec)) / ")", 232 outputItemList) || 233 construct<WriteStmt>("WRITE" >> construct<std::optional<IoUnit>>(), 234 construct<std::optional<Format>>(), 235 parenthesized(nonemptyList(ioControlSpec)), outputItemList)) 236 237 // R1212 print-stmt PRINT format [, output-item-list] 238 TYPE_CONTEXT_PARSER("PRINT statement"_en_US, 239 construct<PrintStmt>( 240 "PRINT" >> format, defaulted("," >> nonemptyList(outputItem)))) 241 242 // R1215 format -> default-char-expr | label | * 243 // deprecated(ASSIGN): | scalar-int-name 244 TYPE_PARSER(construct<Format>(label / !"_."_ch) || 245 construct<Format>(expr / !"="_tok) || construct<Format>(star)) 246 247 // R1216 input-item -> variable | io-implied-do 248 TYPE_PARSER(construct<InputItem>(variable) || 249 construct<InputItem>(indirect(inputImpliedDo))) 250 251 // R1217 output-item -> expr | io-implied-do 252 TYPE_PARSER(construct<OutputItem>(expr) || 253 construct<OutputItem>(indirect(outputImpliedDo))) 254 255 // R1220 io-implied-do-control -> 256 // do-variable = scalar-int-expr , scalar-int-expr [, scalar-int-expr] 257 constexpr auto ioImpliedDoControl{loopBounds(scalarIntExpr)}; 258 259 // R1218 io-implied-do -> ( io-implied-do-object-list , io-implied-do-control ) 260 // R1219 io-implied-do-object -> input-item | output-item 261 TYPE_CONTEXT_PARSER("input implied DO"_en_US, 262 parenthesized( 263 construct<InputImpliedDo>(nonemptyList(inputItem / lookAhead(","_tok)), 264 "," >> ioImpliedDoControl))) 265 TYPE_CONTEXT_PARSER("output implied DO"_en_US, 266 parenthesized(construct<OutputImpliedDo>( 267 nonemptyList(outputItem / lookAhead(","_tok)), 268 "," >> ioImpliedDoControl))) 269 270 // R1222 wait-stmt -> WAIT ( wait-spec-list ) 271 TYPE_CONTEXT_PARSER("WAIT statement"_en_US, 272 "WAIT" >> 273 parenthesized(construct<WaitStmt>(nonemptyList(Parser<WaitSpec>{})))) 274 275 // R1223 wait-spec -> 276 // [UNIT =] file-unit-number | END = label | EOR = label | ERR = label | 277 // ID = scalar-int-expr | IOMSG = iomsg-variable | 278 // IOSTAT = scalar-int-variable 279 constexpr auto idExpr{construct<IdExpr>(scalarIntExpr)}; 280 281 TYPE_PARSER(first(construct<WaitSpec>(maybe("UNIT ="_tok) >> fileUnitNumber), 282 construct<WaitSpec>("END =" >> endLabel), 283 construct<WaitSpec>("EOR =" >> eorLabel), 284 construct<WaitSpec>("ERR =" >> errLabel), 285 construct<WaitSpec>("ID =" >> idExpr), 286 construct<WaitSpec>("IOMSG =" >> msgVariable), 287 construct<WaitSpec>("IOSTAT =" >> statVariable))) 288 289 template <typename A> common::IfNoLvalue<std::list<A>, A> singletonList(A &&x) { 290 std::list<A> result; 291 result.push_front(std::move(x)); 292 return result; 293 } 294 constexpr auto bareUnitNumberAsList{ 295 applyFunction(singletonList<PositionOrFlushSpec>, 296 construct<PositionOrFlushSpec>(fileUnitNumber))}; 297 constexpr auto positionOrFlushSpecList{ 298 parenthesized(nonemptyList(positionOrFlushSpec)) || bareUnitNumberAsList}; 299 300 // R1224 backspace-stmt -> 301 // BACKSPACE file-unit-number | BACKSPACE ( position-spec-list ) 302 TYPE_CONTEXT_PARSER("BACKSPACE statement"_en_US, 303 construct<BackspaceStmt>("BACKSPACE" >> positionOrFlushSpecList)) 304 305 // R1225 endfile-stmt -> 306 // ENDFILE file-unit-number | ENDFILE ( position-spec-list ) 307 TYPE_CONTEXT_PARSER("ENDFILE statement"_en_US, 308 construct<EndfileStmt>("ENDFILE" >> positionOrFlushSpecList)) 309 310 // R1226 rewind-stmt -> REWIND file-unit-number | REWIND ( position-spec-list ) 311 TYPE_CONTEXT_PARSER("REWIND statement"_en_US, 312 construct<RewindStmt>("REWIND" >> positionOrFlushSpecList)) 313 314 // R1227 position-spec -> 315 // [UNIT =] file-unit-number | IOMSG = iomsg-variable | 316 // IOSTAT = scalar-int-variable | ERR = label 317 // R1229 flush-spec -> 318 // [UNIT =] file-unit-number | IOSTAT = scalar-int-variable | 319 // IOMSG = iomsg-variable | ERR = label 320 TYPE_PARSER( 321 construct<PositionOrFlushSpec>(maybe("UNIT ="_tok) >> fileUnitNumber) || 322 construct<PositionOrFlushSpec>("IOMSG =" >> msgVariable) || 323 construct<PositionOrFlushSpec>("IOSTAT =" >> statVariable) || 324 construct<PositionOrFlushSpec>("ERR =" >> errLabel)) 325 326 // R1228 flush-stmt -> FLUSH file-unit-number | FLUSH ( flush-spec-list ) 327 TYPE_CONTEXT_PARSER("FLUSH statement"_en_US, 328 construct<FlushStmt>("FLUSH" >> positionOrFlushSpecList)) 329 330 // R1231 inquire-spec -> 331 // [UNIT =] file-unit-number | FILE = file-name-expr | 332 // ACCESS = scalar-default-char-variable | 333 // ACTION = scalar-default-char-variable | 334 // ASYNCHRONOUS = scalar-default-char-variable | 335 // BLANK = scalar-default-char-variable | 336 // DECIMAL = scalar-default-char-variable | 337 // DELIM = scalar-default-char-variable | 338 // ENCODING = scalar-default-char-variable | 339 // ERR = label | EXIST = scalar-logical-variable | 340 // FORM = scalar-default-char-variable | 341 // FORMATTED = scalar-default-char-variable | 342 // ID = scalar-int-expr | IOMSG = iomsg-variable | 343 // IOSTAT = scalar-int-variable | 344 // NAME = scalar-default-char-variable | 345 // NAMED = scalar-logical-variable | 346 // NEXTREC = scalar-int-variable | NUMBER = scalar-int-variable | 347 // OPENED = scalar-logical-variable | 348 // PAD = scalar-default-char-variable | 349 // PENDING = scalar-logical-variable | POS = scalar-int-variable | 350 // POSITION = scalar-default-char-variable | 351 // READ = scalar-default-char-variable | 352 // READWRITE = scalar-default-char-variable | 353 // RECL = scalar-int-variable | ROUND = scalar-default-char-variable | 354 // SEQUENTIAL = scalar-default-char-variable | 355 // SIGN = scalar-default-char-variable | 356 // SIZE = scalar-int-variable | 357 // STREAM = scalar-default-char-variable | 358 // STATUS = scalar-default-char-variable | 359 // WRITE = scalar-default-char-variable 360 // @ | CONVERT = scalar-default-char-variable 361 // | DISPOSE = scalar-default-char-variable 362 TYPE_PARSER(first(construct<InquireSpec>(maybe("UNIT ="_tok) >> fileUnitNumber), 363 construct<InquireSpec>("FILE =" >> fileNameExpr), 364 construct<InquireSpec>( 365 "ACCESS =" >> construct<InquireSpec::CharVar>( 366 pure(InquireSpec::CharVar::Kind::Access), 367 scalarDefaultCharVariable)), 368 construct<InquireSpec>( 369 "ACTION =" >> construct<InquireSpec::CharVar>( 370 pure(InquireSpec::CharVar::Kind::Action), 371 scalarDefaultCharVariable)), 372 construct<InquireSpec>( 373 "ASYNCHRONOUS =" >> construct<InquireSpec::CharVar>( 374 pure(InquireSpec::CharVar::Kind::Asynchronous), 375 scalarDefaultCharVariable)), 376 construct<InquireSpec>("BLANK =" >> 377 construct<InquireSpec::CharVar>(pure(InquireSpec::CharVar::Kind::Blank), 378 scalarDefaultCharVariable)), 379 construct<InquireSpec>( 380 "DECIMAL =" >> construct<InquireSpec::CharVar>( 381 pure(InquireSpec::CharVar::Kind::Decimal), 382 scalarDefaultCharVariable)), 383 construct<InquireSpec>("DELIM =" >> 384 construct<InquireSpec::CharVar>(pure(InquireSpec::CharVar::Kind::Delim), 385 scalarDefaultCharVariable)), 386 construct<InquireSpec>( 387 "DIRECT =" >> construct<InquireSpec::CharVar>( 388 pure(InquireSpec::CharVar::Kind::Direct), 389 scalarDefaultCharVariable)), 390 construct<InquireSpec>( 391 "ENCODING =" >> construct<InquireSpec::CharVar>( 392 pure(InquireSpec::CharVar::Kind::Encoding), 393 scalarDefaultCharVariable)), 394 construct<InquireSpec>("ERR =" >> errLabel), 395 construct<InquireSpec>("EXIST =" >> 396 construct<InquireSpec::LogVar>( 397 pure(InquireSpec::LogVar::Kind::Exist), scalarLogicalVariable)), 398 construct<InquireSpec>("FORM =" >> 399 construct<InquireSpec::CharVar>( 400 pure(InquireSpec::CharVar::Kind::Form), scalarDefaultCharVariable)), 401 construct<InquireSpec>( 402 "FORMATTED =" >> construct<InquireSpec::CharVar>( 403 pure(InquireSpec::CharVar::Kind::Formatted), 404 scalarDefaultCharVariable)), 405 construct<InquireSpec>("ID =" >> idExpr), 406 construct<InquireSpec>("IOMSG =" >> 407 construct<InquireSpec::CharVar>(pure(InquireSpec::CharVar::Kind::Iomsg), 408 scalarDefaultCharVariable)), 409 construct<InquireSpec>("IOSTAT =" >> 410 construct<InquireSpec::IntVar>(pure(InquireSpec::IntVar::Kind::Iostat), 411 scalar(integer(variable)))), 412 construct<InquireSpec>("NAME =" >> 413 construct<InquireSpec::CharVar>( 414 pure(InquireSpec::CharVar::Kind::Name), scalarDefaultCharVariable)), 415 construct<InquireSpec>("NAMED =" >> 416 construct<InquireSpec::LogVar>( 417 pure(InquireSpec::LogVar::Kind::Named), scalarLogicalVariable)), 418 construct<InquireSpec>("NEXTREC =" >> 419 construct<InquireSpec::IntVar>(pure(InquireSpec::IntVar::Kind::Nextrec), 420 scalar(integer(variable)))), 421 construct<InquireSpec>("NUMBER =" >> 422 construct<InquireSpec::IntVar>(pure(InquireSpec::IntVar::Kind::Number), 423 scalar(integer(variable)))), 424 construct<InquireSpec>("OPENED =" >> 425 construct<InquireSpec::LogVar>( 426 pure(InquireSpec::LogVar::Kind::Opened), scalarLogicalVariable)), 427 construct<InquireSpec>("PAD =" >> 428 construct<InquireSpec::CharVar>( 429 pure(InquireSpec::CharVar::Kind::Pad), scalarDefaultCharVariable)), 430 construct<InquireSpec>("PENDING =" >> 431 construct<InquireSpec::LogVar>( 432 pure(InquireSpec::LogVar::Kind::Pending), scalarLogicalVariable)), 433 construct<InquireSpec>("POS =" >> 434 construct<InquireSpec::IntVar>( 435 pure(InquireSpec::IntVar::Kind::Pos), scalar(integer(variable)))), 436 construct<InquireSpec>( 437 "POSITION =" >> construct<InquireSpec::CharVar>( 438 pure(InquireSpec::CharVar::Kind::Position), 439 scalarDefaultCharVariable)), 440 construct<InquireSpec>("READ =" >> 441 construct<InquireSpec::CharVar>( 442 pure(InquireSpec::CharVar::Kind::Read), scalarDefaultCharVariable)), 443 construct<InquireSpec>( 444 "READWRITE =" >> construct<InquireSpec::CharVar>( 445 pure(InquireSpec::CharVar::Kind::Readwrite), 446 scalarDefaultCharVariable)), 447 construct<InquireSpec>("RECL =" >> 448 construct<InquireSpec::IntVar>( 449 pure(InquireSpec::IntVar::Kind::Recl), scalar(integer(variable)))), 450 construct<InquireSpec>("ROUND =" >> 451 construct<InquireSpec::CharVar>(pure(InquireSpec::CharVar::Kind::Round), 452 scalarDefaultCharVariable)), 453 construct<InquireSpec>( 454 "SEQUENTIAL =" >> construct<InquireSpec::CharVar>( 455 pure(InquireSpec::CharVar::Kind::Sequential), 456 scalarDefaultCharVariable)), 457 construct<InquireSpec>("SIGN =" >> 458 construct<InquireSpec::CharVar>( 459 pure(InquireSpec::CharVar::Kind::Sign), scalarDefaultCharVariable)), 460 construct<InquireSpec>("SIZE =" >> 461 construct<InquireSpec::IntVar>( 462 pure(InquireSpec::IntVar::Kind::Size), scalar(integer(variable)))), 463 construct<InquireSpec>( 464 "STREAM =" >> construct<InquireSpec::CharVar>( 465 pure(InquireSpec::CharVar::Kind::Stream), 466 scalarDefaultCharVariable)), 467 construct<InquireSpec>( 468 "STATUS =" >> construct<InquireSpec::CharVar>( 469 pure(InquireSpec::CharVar::Kind::Status), 470 scalarDefaultCharVariable)), 471 construct<InquireSpec>( 472 "UNFORMATTED =" >> construct<InquireSpec::CharVar>( 473 pure(InquireSpec::CharVar::Kind::Unformatted), 474 scalarDefaultCharVariable)), 475 construct<InquireSpec>("WRITE =" >> 476 construct<InquireSpec::CharVar>(pure(InquireSpec::CharVar::Kind::Write), 477 scalarDefaultCharVariable)), 478 extension<LanguageFeature::Convert>(construct<InquireSpec>( 479 "CONVERT =" >> construct<InquireSpec::CharVar>( 480 pure(InquireSpec::CharVar::Kind::Convert), 481 scalarDefaultCharVariable))), 482 extension<LanguageFeature::Dispose>(construct<InquireSpec>( 483 "DISPOSE =" >> construct<InquireSpec::CharVar>( 484 pure(InquireSpec::CharVar::Kind::Dispose), 485 scalarDefaultCharVariable))))) 486 487 // R1230 inquire-stmt -> 488 // INQUIRE ( inquire-spec-list ) | 489 // INQUIRE ( IOLENGTH = scalar-int-variable ) output-item-list 490 TYPE_CONTEXT_PARSER("INQUIRE statement"_en_US, 491 "INQUIRE" >> 492 (construct<InquireStmt>( 493 parenthesized(nonemptyList(Parser<InquireSpec>{}))) || 494 construct<InquireStmt>(construct<InquireStmt::Iolength>( 495 parenthesized("IOLENGTH =" >> scalar(integer(variable))), 496 nonemptyList(outputItem))))) 497 498 // R1301 format-stmt -> FORMAT format-specification 499 // 13.2.1 allows spaces to appear "at any point" within a format specification 500 // without effect, except of course within a character string edit descriptor. 501 TYPE_CONTEXT_PARSER("FORMAT statement"_en_US, 502 construct<FormatStmt>("FORMAT" >> Parser<format::FormatSpecification>{})) 503 504 // R1321 char-string-edit-desc 505 // N.B. C1313 disallows any kind parameter on the character literal. 506 constexpr auto charStringEditDesc{ 507 space >> (charLiteralConstantWithoutKind || rawHollerithLiteral)}; 508 509 // R1303 format-items -> format-item [[,] format-item]... 510 constexpr auto formatItems{ 511 nonemptySeparated(space >> Parser<format::FormatItem>{}, maybe(","_tok))}; 512 513 // R1306 r -> digit-string 514 constexpr DigitStringIgnoreSpaces repeat; 515 516 // R1304 format-item -> 517 // [r] data-edit-desc | control-edit-desc | char-string-edit-desc | 518 // [r] ( format-items ) 519 TYPE_PARSER(construct<format::FormatItem>( 520 maybe(repeat), Parser<format::IntrinsicTypeDataEditDesc>{}) || 521 construct<format::FormatItem>( 522 maybe(repeat), Parser<format::DerivedTypeDataEditDesc>{}) || 523 construct<format::FormatItem>(Parser<format::ControlEditDesc>{}) || 524 construct<format::FormatItem>(charStringEditDesc) || 525 construct<format::FormatItem>(maybe(repeat), parenthesized(formatItems))) 526 527 // R1302 format-specification -> 528 // ( [format-items] ) | ( [format-items ,] unlimited-format-item ) 529 // R1305 unlimited-format-item -> * ( format-items ) 530 // minor extension: the comma is optional before the unlimited-format-item 531 TYPE_PARSER(parenthesized(construct<format::FormatSpecification>( 532 defaulted(formatItems / maybe(","_tok)), 533 "*" >> parenthesized(formatItems)) || 534 construct<format::FormatSpecification>(defaulted(formatItems)))) 535 // R1308 w -> digit-string 536 // R1309 m -> digit-string 537 // R1310 d -> digit-string 538 // R1311 e -> digit-string 539 constexpr auto width{repeat}; 540 constexpr auto mandatoryWidth{construct<std::optional<int>>(width)}; 541 constexpr auto digits{repeat}; 542 constexpr auto noInt{construct<std::optional<int>>()}; 543 constexpr auto mandatoryDigits{construct<std::optional<int>>("." >> width)}; 544 545 // R1307 data-edit-desc -> 546 // I w [. m] | B w [. m] | O w [. m] | Z w [. m] | F w . d | 547 // E w . d [E e] | EN w . d [E e] | ES w . d [E e] | EX w . d [E e] | 548 // G w [. d [E e]] | L w | A [w] | D w . d | 549 // DT [char-literal-constant] [( v-list )] 550 // (part 1 of 2) 551 TYPE_PARSER(construct<format::IntrinsicTypeDataEditDesc>( 552 "I" >> pure(format::IntrinsicTypeDataEditDesc::Kind::I) || 553 "B" >> pure(format::IntrinsicTypeDataEditDesc::Kind::B) || 554 "O" >> pure(format::IntrinsicTypeDataEditDesc::Kind::O) || 555 "Z" >> pure(format::IntrinsicTypeDataEditDesc::Kind::Z), 556 mandatoryWidth, maybe("." >> digits), noInt) || 557 construct<format::IntrinsicTypeDataEditDesc>( 558 "F" >> pure(format::IntrinsicTypeDataEditDesc::Kind::F) || 559 "D" >> pure(format::IntrinsicTypeDataEditDesc::Kind::D), 560 mandatoryWidth, mandatoryDigits, noInt) || 561 construct<format::IntrinsicTypeDataEditDesc>( 562 "E" >> ("N" >> pure(format::IntrinsicTypeDataEditDesc::Kind::EN) || 563 "S" >> pure(format::IntrinsicTypeDataEditDesc::Kind::ES) || 564 "X" >> pure(format::IntrinsicTypeDataEditDesc::Kind::EX) || 565 pure(format::IntrinsicTypeDataEditDesc::Kind::E)), 566 mandatoryWidth, mandatoryDigits, maybe("E" >> digits)) || 567 construct<format::IntrinsicTypeDataEditDesc>( 568 "G" >> pure(format::IntrinsicTypeDataEditDesc::Kind::G), mandatoryWidth, 569 mandatoryDigits, maybe("E" >> digits)) || 570 construct<format::IntrinsicTypeDataEditDesc>( 571 "G" >> pure(format::IntrinsicTypeDataEditDesc::Kind::G) || 572 "L" >> pure(format::IntrinsicTypeDataEditDesc::Kind::L), 573 mandatoryWidth, noInt, noInt) || 574 construct<format::IntrinsicTypeDataEditDesc>( 575 "A" >> pure(format::IntrinsicTypeDataEditDesc::Kind::A), maybe(width), 576 noInt, noInt) || 577 // PGI/Intel extension: omitting width (and all else that follows) 578 extension<LanguageFeature::AbbreviatedEditDescriptor>( 579 construct<format::IntrinsicTypeDataEditDesc>( 580 "I" >> pure(format::IntrinsicTypeDataEditDesc::Kind::I) || 581 ("B"_tok / !letter /* don't occlude BN & BZ */) >> 582 pure(format::IntrinsicTypeDataEditDesc::Kind::B) || 583 "O" >> pure(format::IntrinsicTypeDataEditDesc::Kind::O) || 584 "Z" >> pure(format::IntrinsicTypeDataEditDesc::Kind::Z) || 585 "F" >> pure(format::IntrinsicTypeDataEditDesc::Kind::F) || 586 ("D"_tok / !letter /* don't occlude DT, DC, & DP */) >> 587 pure(format::IntrinsicTypeDataEditDesc::Kind::D) || 588 "E" >> 589 ("N" >> pure(format::IntrinsicTypeDataEditDesc::Kind::EN) || 590 "S" >> 591 pure(format::IntrinsicTypeDataEditDesc::Kind::ES) || 592 "X" >> 593 pure(format::IntrinsicTypeDataEditDesc::Kind::EX) || 594 pure(format::IntrinsicTypeDataEditDesc::Kind::E)) || 595 "G" >> pure(format::IntrinsicTypeDataEditDesc::Kind::G) || 596 "L" >> pure(format::IntrinsicTypeDataEditDesc::Kind::L), 597 noInt, noInt, noInt))) 598 599 // R1307 data-edit-desc (part 2 of 2) 600 // R1312 v -> [sign] digit-string 601 constexpr SignedDigitStringIgnoreSpaces scaleFactor; 602 TYPE_PARSER(construct<format::DerivedTypeDataEditDesc>( 603 "D" >> "T"_tok >> defaulted(charLiteralConstantWithoutKind), 604 defaulted(parenthesized(nonemptyList(scaleFactor))))) 605 606 // R1314 k -> [sign] digit-string 607 constexpr PositiveDigitStringIgnoreSpaces count; 608 609 // R1313 control-edit-desc -> 610 // position-edit-desc | [r] / | : | sign-edit-desc | k P | 611 // blank-interp-edit-desc | round-edit-desc | decimal-edit-desc | 612 // @ \ | $ 613 // R1315 position-edit-desc -> T n | TL n | TR n | n X 614 // R1316 n -> digit-string 615 // R1317 sign-edit-desc -> SS | SP | S 616 // R1318 blank-interp-edit-desc -> BN | BZ 617 // R1319 round-edit-desc -> RU | RD | RZ | RN | RC | RP 618 // R1320 decimal-edit-desc -> DC | DP 619 TYPE_PARSER(construct<format::ControlEditDesc>( 620 "T" >> ("L" >> pure(format::ControlEditDesc::Kind::TL) || 621 "R" >> pure(format::ControlEditDesc::Kind::TR) || 622 pure(format::ControlEditDesc::Kind::T)), 623 count) || 624 construct<format::ControlEditDesc>(count, 625 "X" >> pure(format::ControlEditDesc::Kind::X) || 626 "/" >> pure(format::ControlEditDesc::Kind::Slash)) || 627 construct<format::ControlEditDesc>( 628 "X" >> pure(format::ControlEditDesc::Kind::X) || 629 "/" >> pure(format::ControlEditDesc::Kind::Slash)) || 630 construct<format::ControlEditDesc>( 631 scaleFactor, "P" >> pure(format::ControlEditDesc::Kind::P)) || 632 construct<format::ControlEditDesc>( 633 ":" >> pure(format::ControlEditDesc::Kind::Colon)) || 634 "S" >> ("S" >> construct<format::ControlEditDesc>( 635 pure(format::ControlEditDesc::Kind::SS)) || 636 "P" >> construct<format::ControlEditDesc>( 637 pure(format::ControlEditDesc::Kind::SP)) || 638 construct<format::ControlEditDesc>( 639 pure(format::ControlEditDesc::Kind::S))) || 640 "B" >> ("N" >> construct<format::ControlEditDesc>( 641 pure(format::ControlEditDesc::Kind::BN)) || 642 "Z" >> construct<format::ControlEditDesc>( 643 pure(format::ControlEditDesc::Kind::BZ))) || 644 "R" >> ("U" >> construct<format::ControlEditDesc>( 645 pure(format::ControlEditDesc::Kind::RU)) || 646 "D" >> construct<format::ControlEditDesc>( 647 pure(format::ControlEditDesc::Kind::RD)) || 648 "Z" >> construct<format::ControlEditDesc>( 649 pure(format::ControlEditDesc::Kind::RZ)) || 650 "N" >> construct<format::ControlEditDesc>( 651 pure(format::ControlEditDesc::Kind::RN)) || 652 "C" >> construct<format::ControlEditDesc>( 653 pure(format::ControlEditDesc::Kind::RC)) || 654 "P" >> construct<format::ControlEditDesc>( 655 pure(format::ControlEditDesc::Kind::RP))) || 656 "D" >> ("C" >> construct<format::ControlEditDesc>( 657 pure(format::ControlEditDesc::Kind::DC)) || 658 "P" >> construct<format::ControlEditDesc>( 659 pure(format::ControlEditDesc::Kind::DP))) || 660 extension<LanguageFeature::AdditionalFormats>( 661 "$" >> construct<format::ControlEditDesc>( 662 pure(format::ControlEditDesc::Kind::Dollar)) || 663 "\\" >> construct<format::ControlEditDesc>( 664 pure(format::ControlEditDesc::Kind::Backslash)))) 665 } // namespace Fortran::parser 666