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