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