transput.c

     
   1  //! @file transput.c
   2  //! @author J. Marcel van der Veer
   3  //
   4  //! @section Copyright
   5  //
   6  // This file is part of VIF - vintage FORTRAN compiler.
   7  // Copyright 2020-2025 J. Marcel van der Veer <algol68g@xs4all.nl>.
   8  //
   9  //! @section License
  10  //
  11  // This program is free software; you can redistribute it and/or modify it 
  12  // under the terms of the GNU General Public License as published by the 
  13  // Free Software Foundation; either version 3 of the License, or 
  14  // (at your option) any later version.
  15  //
  16  // This program is distributed in the hope that it will be useful, but 
  17  // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  18  // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
  19  // more details. You should have received a copy of the GNU General Public 
  20  // License along with this program. If not, see <http://www.gnu.org/licenses/>.
  21  
  22  //! @section Synopsis
  23  //!
  24  //! Compile Fortran IO.
  25  
  26  #include <vif.h>
  27  
  28  static char *unum (EXPR *unit)
  29  {
  30    if (unit->mode.type == INTEGER) {
  31      return unit->str;
  32    } else {
  33      return "0";
  34    }
  35  }
  36  
  37  void save_iostat (char *iostat)
  38  {
  39    if (iostat != NO_TEXT) {
  40      EXPR loc; RECORD ios, str;
  41      MODE mode = (MODE) {.type = INTEGER, .len = 4, .dim = 0};
  42      _srecordf (ios, "%s", iostat);
  43      RECCLR (loc.str);
  44      factor_variable (&loc, NULL, &mode, ios);
  45      if (loc.mode.type == mode.type && loc.mode.len == mode.len) {
  46        _srecordf (str, "%s = errno;\n", loc.str);
  47        code (nprocs, BODY, str);
  48      } else {
  49        MODE_ERROR (3001, qtype (&(loc.mode)), qtype (&mode));
  50      }
  51    }
  52  }
  53  
  54  void io_event (char *proc, EXPR *unit, char *iorc, LBL *endlbl, LBL *errlbl)
  55  {
  56    if (EQUAL (proc, "write")) {
  57      RECORD str;
  58      if (errlbl == NO_LABEL) {
  59        _srecordf (str, "_write_err (%s, %s, _ioerr_%s (\"%s\", %s));\n", iorc, unum (unit), proc, stat_start, unum (unit));
  60      } else {
  61        _srecordf (str, "_write_err (%s, %s, goto _l%d);\n", iorc, unum (unit), errlbl->num);
  62      }
  63      code (nprocs, BODY, str);
  64    } else if (EQUAL (proc, "read")) {
  65      RECORD str1, str2, str;
  66      if (endlbl == NO_LABEL) {
  67        _srecordf (str1, "_ioend_%s (\"%s\", %s)", proc, stat_start, unum (unit));
  68      } else {
  69        _srecordf (str1, "goto _l%d", endlbl->num);
  70      }
  71      if (errlbl == NO_LABEL) {
  72        _srecordf (str2, "_ioerr_%s (\"%s\", %s)", proc, stat_start, unum (unit));
  73      } else {
  74        _srecordf (str2, "goto _l%d", errlbl->num);
  75      }
  76      _srecordf (str, "_read_err (%s, %s, %s, %s);\n", iorc, unum (unit), str1, str2);
  77      code (nprocs, BODY, str);
  78    } else {
  79      BUG ("io_event");
  80    }
  81  }
  82  
  83  void io_parm (EXPR *reg, char *elem)
  84  {
  85    if (reg->variant == EXPR_VAR) {
  86      if (IS_ROW (reg->mode)) {
  87        _srecordf (elem, "%s", reg->str);
  88      } else if (reg->str[0] == '*') {
  89        _srecordf (elem, "%s", &reg->str[1]);
  90      } else if (reg->mode.type == CHARACTER) {
  91        _srecordf (elem, "%s", reg->str);
  92      } else {
  93        (void) impl_decl (reg->str, NO_MODE);
  94        _srecordf (elem, "&%s", reg->str);
  95      }
  96    } else if (reg->variant == EXPR_SLICE) {
  97      _srecordf (elem, "&%s", reg->str);
  98    } else {
  99      RECORD tmp;
 100      _srecordf (tmp, "%s", edit_tmp (nloctmps++));
 101      if (reg->mode.type == CHARACTER) {
 102        norm_mode (&reg->mode);
 103        if (reg->mode.len == 0) {
 104          add_local (tmp, reg->mode.type, MAX_STRLEN, UNIQ, NOPATCH, NOARG, LOCAL, TEMP);
 105          _srecordf (elem, "strcpy (%s, %s);\n", tmp, reg->str);
 106        } else {
 107          add_local (tmp, reg->mode.type, reg->mode.len, UNIQ, NOPATCH, NOARG, LOCAL, TEMP);
 108          _srecordf (elem, "bufcpy (%s, %s, %d);\n", tmp, reg->str, reg->mode.len);
 109        }
 110        code (nprocs, BODY, elem);
 111        _srecordf (elem, "%s", tmp);
 112      } else {
 113        add_local (tmp, reg->mode.type, reg->mode.len, UNIQ, NOPATCH, NOARG, LOCAL, TEMP);
 114        _srecordf (elem, "%s = %s;\n", tmp, reg->str);
 115        code (nprocs, BODY, elem);
 116        _srecordf (elem, "&%s", tmp);
 117      }
 118    }
 119  }
 120  
 121  void io_text_items (char *proc, EXPR *unit, char *fstr, char *fid, char *iorc, LBL *endlbl, LBL *errlbl)
 122  {
 123    RECORD str;
 124    if (EQUAL (proc, "write")) {
 125      _srecordf (str, "while (%s[%s] != NULL && %s[%s] == FMT_TEXT) {\n", fstr, fid, fstr, fid);
 126      code (nprocs, BODY, str);
 127      _srecordf (str, "%s = _vifprintf (%s, %s[%s + 2], NULL, NOTYPE, 0);\n", iorc, unum (unit), fstr, fid);
 128      code (nprocs, BODY, str);
 129      io_event (proc, unit, iorc, endlbl, errlbl);
 130      _srecordf (str, "%s += 3;\n", fid);
 131      code (nprocs, BODY, str);
 132      code (nprocs, BODY, "}\n");
 133    } else if (EQUAL (proc, "read")) {
 134      _srecordf (str, "while (%s[%s] != NULL && %s[%s] == FMT_TEXT) {\n", fstr, fid, fstr, fid);
 135      code (nprocs, BODY, str);
 136      _srecordf (str, "%s = _vifscanf (%s, %s[%s + 1], NULL, NOTYPE, 0);\n", iorc, unum (unit), fstr, fid);
 137      code (nprocs, BODY, str);
 138      io_event (proc, unit, iorc, endlbl, errlbl);
 139      _srecordf (str, "%s += 3;\n", fid);
 140      code (nprocs, BODY, str);
 141      code (nprocs, BODY, "}\n");
 142    }
 143  }
 144  
 145  void io_format (char *proc, EXPR *unit, char *fstr, char *fid, char *iorc, LBL *endlbl, LBL *errlbl, char *elem, char *type, int_4 len)
 146  {
 147    RECORD str;
 148    if (EQUAL (proc, "write")) {
 149      _srecordf (str, "if (%s[%s] == NULL) {\n", fstr, fid);
 150      code (nprocs, BODY, str);
 151      _srecordf (str, "%s = 0;\n", fid);
 152      code (nprocs, BODY, str);
 153      _srecordf (str, "%s = fprintf (_ffile[%s].unit, \"\\n\");\n", iorc, unum (unit));
 154      code (nprocs, BODY, str);
 155      io_text_items (proc, unit, fstr, fid, iorc, endlbl, errlbl);
 156      code (nprocs, BODY, "};\n");
 157      _srecordf (str, "%s = _vifprintf (%s, %s[%s + 2], %s, %s, %d);\n", iorc, unum (unit), fstr, fid, elem, type, len);
 158      code (nprocs, BODY, str);
 159      io_event (proc, unit, iorc, endlbl, errlbl);
 160      _srecordf (str, "%s += 3;\n", fid);
 161      code (nprocs, BODY, str);
 162      io_text_items (proc, unit, fstr, fid, iorc, endlbl, errlbl);
 163    } else if (EQUAL (proc, "read")) {
 164      _srecordf (str, "if (%s[%s] == NULL) {\n", fstr, fid);
 165      code (nprocs, BODY, str);
 166      _srecordf (str, "%s = 0;\n", fid);
 167      code (nprocs, BODY, str);
 168      _srecordf (str, "_vifscanf (%s, NULL, NULL, NOTYPE, 0);\n", unum (unit));
 169      code (nprocs, BODY, str);
 170      io_text_items (proc, unit, fstr, fid, iorc, endlbl, errlbl);
 171      code (nprocs, BODY, "};\n");
 172      _srecordf (str, "%s = _vifscanf (%s, %s[%s + 1], %s, %s, %d);\n", iorc, unum (unit), fstr, fid, elem, type, len);
 173      code (nprocs, BODY, str);
 174      io_event (proc, unit, iorc, endlbl, errlbl);
 175      _srecordf (str, "%s += 3;\n", fid);
 176      code (nprocs, BODY, str);
 177      io_text_items (proc, unit, fstr, fid, iorc, endlbl, errlbl);
 178    }
 179  }
 180  
 181  void io_elemuf (char *proc, EXPR *unit, EXPR *reg, char *iorc, LBL *endlbl, LBL *errlbl, int_4 *items)
 182  {
 183    RECORD str, elem;
 184    RECCLR (elem);
 185    io_parm (reg, elem);
 186    if (EQUAL (proc, "write")) {
 187      _srecordf (str, "%s = fwrite (%s", iorc, elem);
 188      code (nprocs, BODY, str);
 189    } else if (EQUAL (proc, "read")) {
 190      _srecordf (str, "%s = fread (%s", iorc, elem);
 191      code (nprocs, BODY, str);
 192    } else {
 193      BUG ("io_elemuf");
 194    }
 195    _srecordf (str, ", sizeof (%s), ", wtype (&reg->mode, NOARG, NOFUN));
 196    code (nprocs, BODY, str);
 197    if (reg->variant == EXPR_VAR && IS_ROW (reg->mode)) {
 198      code_row_len (reg->idf);
 199    } else {
 200      code (nprocs, BODY, "1");
 201    }
 202    _srecordf (str, ", _ffile[%s].unit);\n", unum (unit));
 203    code (nprocs, BODY, str);
 204    io_event (proc, unit, iorc, endlbl, errlbl);
 205  }
 206  
 207  void io_elemstd (char *proc, EXPR *unit, EXPR *reg, char *fstr, char *fid, char *iorc, LBL *endlbl, LBL *errlbl, int_4 *items)
 208  {
 209    RECORD str, elem;
 210    RECCLR (elem);
 211    io_parm (reg, elem);
 212    if (reg->mode.type == INTEGER) {
 213      if (EQUAL (proc, "write")) {
 214        _srecordf (str, "%s = _vifprintf (%s, \"%%d\", %s, INTEGER, %d);\n", iorc, unum (unit), elem, reg->mode.len);
 215      } else if (EQUAL (proc, "read")) {
 216        _srecordf (str, "%s = _vifscanf (%s, \"%%d\", %s, INTEGER, %d);\n", iorc, unum (unit), elem, reg->mode.len);
 217      }
 218    } else if (reg->mode.type == LOGICAL) {
 219      if (EQUAL (proc, "write")) {
 220        _srecordf (str, "%s = _vifprintf (%s, \"%%c\", %s, LOGICAL, %d);\n", iorc, unum (unit), elem, reg->mode.len);
 221      } else if (EQUAL (proc, "read")) {
 222        _srecordf (str, "%s = _vifscanf (%s, \"%%c\", %s, LOGICAL, %d);\n", iorc, unum (unit), elem, reg->mode.len);
 223      }
 224    } else if (reg->mode.type == REAL) {
 225      if (EQUAL (proc, "write")) {
 226        RECORD fmt;
 227        if (reg->mode.len == 32) {
 228          _srecordf (fmt, "\"%%.%de\"", FLT256_DIG);
 229          _srecordf (str, "%s = _vifprintf (%s, %s, %s, REAL, %d);\n", iorc, unum (unit), fmt, elem, reg->mode.len);
 230        } else if (reg->mode.len == 16) {
 231          _srecordf (fmt, "\"%%.%de\"", FLT128_DIG);
 232          _srecordf (str, "%s = _vifprintf (%s, %s, %s, REAL, %d);\n", iorc, unum (unit), fmt, elem, reg->mode.len);
 233        } else if (reg->mode.len == 8) {
 234          _srecordf (fmt, "\"%%.%de\"", DBL_DIG);
 235          _srecordf (str, "%s = _vifprintf (%s, %s, %s, REAL, %d);\n", iorc, unum (unit), fmt, elem, reg->mode.len);
 236        } else if (reg->mode.len == 4) {
 237          _srecordf (fmt, "\"%%.%de\"", FLT_DIG);
 238          _srecordf (str, "%s = _vifprintf (%s, %s, %s, REAL, %d);\n", iorc, unum (unit), fmt, elem, reg->mode.len);
 239        }
 240      } else if (EQUAL (proc, "read")) {
 241        _srecordf (str, "%s = _vifscanf (%s, \"%%e\", %s, REAL, %d);\n", iorc, unum (unit), elem, reg->mode.len);
 242      }
 243    } else if (reg->mode.type == COMPLEX) {
 244      if (EQUAL (proc, "write")) {
 245        RECORD fmt;
 246        if (reg->mode.len == 8) {
 247          _srecordf (fmt, "\"%%.%de\"", FLT_DIG);
 248        } else if (reg->mode.len == 16) {
 249          _srecordf (fmt, "\"%%.%de\"", DBL_DIG);
 250        } else if (reg->mode.len == 32) {
 251          _srecordf (fmt, "\"%%.%de\"", FLT128_DIG);
 252        } else if (reg->mode.len == 64) {
 253          _srecordf (fmt, "\"%%.%de\"", FLT256_DIG);
 254        }
 255        _srecordf (str, "%s = _vifprintf (%s, %s, %s, COMPLEX, %d);\n", iorc, unum (unit), fmt, elem, reg->mode.len);
 256        code (nprocs, BODY, str);
 257        io_event (proc, unit, iorc, endlbl, errlbl);
 258        _srecordf (str, "%s = _vifprintf (%s, \" \", NULL, NOTYPE, 0);\n", iorc, unum (unit));
 259        code (nprocs, BODY, str);
 260        io_event (proc, unit, iorc, endlbl, errlbl);
 261        _srecordf (str, "%s = _vifprintf (%s, %s, %s, COMPLEX, -%d);\n", iorc, unum (unit), fmt, elem, reg->mode.len);
 262      } else if (EQUAL (proc, "read")) {
 263        _srecordf (str, "%s = _vifscanf (%s, \"%%e\", %s, COMPLEX, %d);\n", iorc, unum (unit), elem, reg->mode.len);
 264        code (nprocs, BODY, str);
 265        io_event (proc, unit, iorc, endlbl, errlbl);
 266        _srecordf (str, "%s = _vifscanf (%s, \"%%e\", %s, COMPLEX, -%d);\n", iorc, unum (unit), elem, reg->mode.len);
 267      }
 268    } else if (reg->mode.type == CHARACTER) {
 269      if (EQUAL (proc, "write")) {
 270  //    _srecordf (str, "%s = _vifprintf (%s, \"%%-%ds\", %s, CHARACTER, %d);\n", iorc, unum (unit), reg->mode.len, elem, reg->mode.len);
 271        _srecordf (str, "%s = _vifprintf (%s, \"%%s\", %s, CHARACTER, %d);\n", iorc, unum (unit), elem, reg->mode.len);
 272      } else if (EQUAL (proc, "read")) {
 273  //    _srecordf (str, "%s = _vifscanf (%s, \"%%%ds\", %s, CHARACTER, %d);\n", iorc, unum (unit), reg->mode.len, elem, reg->mode.len);
 274        _srecordf (str, "%s = _vifscanf (%s, \"%%s\", %s, CHARACTER, %d);\n", iorc, unum (unit), elem, reg->mode.len);
 275      }
 276    }
 277    code (nprocs, BODY, str);
 278    io_event (proc, unit, iorc, endlbl, errlbl);
 279    (*items) ++;
 280  }
 281  
 282  void io_elemf (char *proc, EXPR *unit, EXPR *reg, char *fstr, char *fid, char *iorc, LBL *endlbl, LBL *errlbl, int_4 *items)
 283  {
 284    RECORD elem;
 285    RECCLR (elem);
 286    io_parm (reg, elem);
 287    if (reg->mode.type == INTEGER) {
 288      io_format (proc, unit, fstr, fid, iorc, endlbl, errlbl, elem, "INTEGER", reg->mode.len);
 289      (*items) ++;
 290    } else if (reg->mode.type == LOGICAL) {
 291      io_format (proc, unit, fstr, fid, iorc, endlbl, errlbl, elem, "LOGICAL", reg->mode.len);
 292      (*items) ++;
 293    } else if (reg->mode.type == REAL) {
 294      io_format (proc, unit, fstr, fid, iorc, endlbl, errlbl, elem, "REAL", reg->mode.len);
 295      (*items) ++;
 296    } else if (reg->mode.type == COMPLEX) {
 297      io_format (proc, unit, fstr, fid, iorc, endlbl, errlbl, elem, "COMPLEX", reg->mode.len);
 298      io_format (proc, unit, fstr, fid, iorc, endlbl, errlbl, elem, "COMPLEX", -reg->mode.len);
 299      (*items) ++;
 300    } else if (reg->mode.type == CHARACTER) {
 301      io_format (proc, unit, fstr, fid, iorc, endlbl, errlbl, elem, "CHARACTER", reg->mode.len);
 302      (*items) ++;
 303    }
 304  }
 305  
 306  void io_array (char *proc, EXPR *unit, EXPR *reg, int_4 form, char *fstr, char *fid, char *iorc, LBL *endlbl, LBL *errlbl, int_4 *items)
 307  {
 308    RECORD str, tmpa, tmpk;
 309    EXPR elem;
 310    IDENT *ptr;
 311    _srecordf (tmpa, "_arr_%d", nloctmps++);
 312    ptr = add_local (tmpa, reg->mode.type, reg->mode.len, NOUNIQ, NOPATCH, NOARG, LOCAL, TEMP);
 313    ptr->alias = reg->idf;
 314    _srecordf (tmpk, "_k_%d", nloctmps++);
 315    add_local (tmpk, INTEGER, 4, NOUNIQ, NOPATCH, NOARG, LOCAL, TEMP);
 316    _srecordf (str, "for (%s = %s %s, %s = 0; %s < ", tmpa, ptr_to_array (ptr, NOCONST, CAST, ACTUAL), reg->str, tmpk, tmpk);
 317    code (nprocs, BODY, str);
 318    code_row_len (reg->idf);
 319    _srecordf (str, "; %s++, %s++) {\n", tmpa, tmpk);
 320    code (nprocs, BODY, str);
 321    memcpy (&elem, reg, sizeof (EXPR));
 322    elem.mode.dim = 0;
 323    if (EQUAL (proc, "read")) {
 324      _srecordf (elem.str, "%s", tmpa);
 325    } else if (EQUAL (proc, "write")) {
 326      _srecordf (elem.str, "*%s", tmpa);
 327    } else {
 328      BUG ("io_array");
 329    }
 330    if (form == STDFORMAT) {
 331      io_elemstd (proc, unit, &elem, fstr, fid, iorc, endlbl, errlbl, items);
 332    } else if (form == FORMATTED) {
 333      io_elemf (proc, unit, &elem, fstr, fid, iorc, endlbl, errlbl, items);
 334    }
 335    code (nprocs, BODY, "}\n");
 336  }
 337  
 338  void io_elem (char *proc, EXPR *unit, int_4 form, char *fstr, char *fid, char *iorc, LBL *endlbl, LBL *errlbl, int_4 *items)
 339  {
 340    EXPR reg;
 341    express (&reg, NOTYPE, 0);
 342    if (form == UNFORMATTED) {
 343      io_elemuf (proc, unit, &reg, iorc, endlbl, errlbl, items);
 344    } else if (form == STDFORMAT) {
 345      if (reg.variant == EXPR_VAR && IS_ROW (reg.mode)) {
 346        io_array (proc, unit, &reg, form, fstr, fid, iorc, endlbl, errlbl, items);
 347      } else {
 348        io_elemstd (proc, unit, &reg, fstr, fid, iorc, endlbl, errlbl, items);
 349      }
 350    } else if (form == FORMATTED) {
 351      if (reg.variant == EXPR_VAR && IS_ROW (reg.mode)) {
 352        io_array (proc, unit, &reg, form, fstr, fid, iorc, endlbl, errlbl, items);
 353      } else {
 354        io_elemf (proc, unit, &reg, fstr, fid, iorc, endlbl, errlbl, items);
 355      }
 356    } else {
 357      BUG ("IO formatting unspecified");
 358    }
 359  }
 360  
 361  int_4 impl_do (void)
 362  {
 363  // Quick check whether (...) in a list is an implied DO loop.
 364    int_4 rc, nest = 1;
 365    while ((rc = scan (EXPECT_NONE)) != END_OF_LINE) {
 366      if (TOKEN ("(")) {
 367        nest++;
 368      } else if (TOKEN (")")) {
 369        nest--;
 370        if (nest == 0) {
 371          return FALSE;
 372        }
 373      } else if (nest == 1 && TOKEN (",")) {
 374  // Trigger is the sequence ", I =" in outer nest.
 375        rc = scan (EXPECT_NONE);
 376        if (rc == WORD) {
 377          RECORD name;
 378          RECCLR (name);
 379          strcpy (name, curlex);
 380          rc = scan (EXPECT_NONE);
 381          if (TOKEN ("=")) {
 382            (void) impl_decl (name, NO_MODE);
 383            return TRUE;
 384          } else {
 385            UNSCAN;
 386          }
 387        }
 388      }
 389    }
 390    (void) rc;
 391    return FALSE;
 392  }
 393  
 394  void io_list (char *proc, EXPR *unit, int_4 form, char *fstr, char *fid, char *iorc, LBL *endlbl, LBL *errlbl, int_4 lpatch, int_4 *nest, int_4 *items)
 395  {
 396    while (WITHIN) {
 397      int_4 rc;
 398      if (TOKEN (",")) {
 399        rc = scan (EXPECT_NONE);
 400        if (! WITHIN) {
 401          SYNTAX (3002, prelex);
 402          break;
 403        }
 404        if (TOKEN (",")) {
 405          SYNTAX (3003, ",,");
 406          continue;
 407        }
 408      } else {
 409        rc = scan (EXPECT_NONE);
 410        if (TOKEN (",")) {
 411          continue;
 412        }
 413      }
 414      if (! WITHIN) {
 415        break;
 416      }
 417      if (TOKEN ("(")) {
 418        SAVE_PRE;
 419  // Quick lookahead.
 420        int_4 loop = impl_do ();
 421  // Restore.
 422        RESTORE_POS;
 423        rc = scan ("(");
 424  // Decide.
 425        if (loop) {
 426          (*nest)++;
 427          int_4 where = code (nprocs, BODY, NO_TEXT);
 428          io_list (proc, unit, form, fstr, fid, iorc, endlbl, errlbl, where, nest, items);
 429        } else {
 430          io_elem (proc, unit, form, fstr, fid, iorc, endlbl, errlbl, items);
 431          rc = scan (EXPECT_NONE);
 432        }
 433      } else if (TOKEN (")")) {
 434  // Expression closed by ')'
 435        (*nest)--;
 436        return;
 437      } else if (rc == WORD) {
 438        if (*nest == 0) {
 439          io_elem (proc, unit, form, fstr, fid, iorc, endlbl, errlbl, items);
 440          rc = scan (EXPECT_NONE);
 441        } else {
 442          SAVE_PRE;
 443          rc = scan (EXPECT_NONE);
 444          if (!TOKEN ("=")) {
 445            RESTORE_POS;
 446            rc = scan (EXPECT_NONE);
 447            io_elem (proc, unit, form, fstr, fid, iorc, endlbl, errlbl, items);
 448            rc = scan (EXPECT_NONE);
 449          } else {
 450            RECORD lid, loop;
 451            EXPR from, to, by;
 452            MODE mode;
 453            IDENT *idf = impl_decl (prelex, &mode);
 454            if (idf->arg || idf->alias != NULL) {
 455              _srecordf (lid, "*%s", C_NAME (idf));
 456            } else {
 457             (void) idf_full_c_name (lid, idf);
 458            }
 459            rc = scan (EXPECT_NONE);
 460            express (&from, idf->mode.type, idf->mode.len);
 461            rc = scan (",");
 462            rc = scan (EXPECT_NONE);
 463            express (&to, idf->mode.type, idf->mode.len);
 464            rc = scan (EXPECT_NONE);
 465            if (TOKEN (",")) {
 466              rc = scan (EXPECT_NONE);
 467              express (&by, idf->mode.type, idf->mode.len);
 468              _srecordf (loop, "for (%s = %s; %s <= %s; %s += %s) {\n", 
 469                        lid, from.str, lid, to.str, lid, by.str);
 470              rc = scan (EXPECT_NONE);
 471            } else {
 472              _srecordf (loop, "for (%s = %s; %s <= %s; %s++) {\n", 
 473                        lid, from.str, lid, to.str, lid);
 474            }
 475            patch (lpatch, loop);
 476            if (TOKEN (")")) {
 477  // Implied DO loop closed by ')'.
 478              (*nest)--;
 479              code (nprocs, BODY, "}; // implied DO \n");
 480            } else {
 481              EXPECT (3004, ")");
 482            }
 483            return;
 484          }
 485        }
 486      } else {
 487        io_elem (proc, unit, form, fstr, fid, iorc, endlbl, errlbl, items);
 488        rc = scan (EXPECT_NONE);
 489      }
 490    }
 491  }
 492  
 493  void io_unit (EXPR *unit, int_4 defunit)
 494  {
 495  // Reasonable default.
 496    unit->mode.type = INTEGER;
 497    unit->mode.len = 4;
 498  //
 499    if (TOKEN ("*")) {
 500      _srecordf (unit->str, "%d", defunit);
 501    } else if (TOKEN ("stdin")) {
 502      _srecordf (unit->str, "STDF_IN");
 503    } else if (TOKEN ("stdout")) {
 504      _srecordf (unit->str, "STDF_OUT");
 505    } else if (TOKEN ("stderr")) {
 506      _srecordf (unit->str, "STDF_ERR");
 507    } else {
 508      EXPR reg;
 509      express (&reg, NOTYPE, NOLEN);
 510      if (reg.mode.type == INTEGER) {
 511        if (reg.variant == EXPR_CONST) {
 512          _srecordf (unit->str, "%s", reg.str);
 513          int_4 val;
 514          (void) isint_4 (unit->str, &val);
 515          if (val < 1 || val > MAX_FILES - 1) {
 516            ERROR (3005, "unit number out of range", unit->str);
 517          }
 518        } else {
 519          RECORD str;
 520          _srecordf (unit->str, "%s", edit_unit (nloctmps++));
 521          add_local (unit->str, INTEGER, 4, NOUNIQ, NOPATCH, NOARG, LOCAL, TEMP);
 522          _srecordf (str, "%s = %s;\n", unit, reg.str);
 523          code (nprocs, BODY, str);
 524        }   
 525      } else if (reg.mode.type == CHARACTER) {
 526        if (reg.variant == EXPR_CONST) {
 527          ERROR (3006, "unit cannot be a denotation", unit->str);
 528        } else {
 529          _srecordf (unit->str, "%s", reg.str);
 530          unit->mode = reg.mode;
 531        }
 532      } else {
 533        ERROR (3007, "unit must be INTEGER or CHARACTER", NO_TEXT);
 534      }
 535    }
 536  }
 537  
 538  void io_specs (EXPR *unit, int_4 defunit, char *fmt, char **fn, char **form, char **action, int_4 *lrecl, char **disp, LBL **end, LBL **err, char **iostat)
 539  {
 540    int_4 rc, parm = 1;
 541    unit->str[0] = '\0';
 542    fmt[0] = '\0';
 543    *form = form_unformatted;
 544    *fn = NO_TEXT;
 545    *action = action_default;
 546    *disp = disp_old;
 547    *end = NO_LABEL;
 548    *err = NO_LABEL;
 549    *iostat = NO_TEXT;
 550  //
 551    rc = scan (EXPECT_NONE); 
 552    while (!TOKEN (")") && rc != END_OF_MODULE) {
 553  // ([UNIT], [FMT] [, FMT=n | FILE=expr | FORM=str | action=str |  DISP=str |  END=n | ERR=n])
 554      if (TOKEN ("*") && parm == 2) {
 555        *form = form_formatted;
 556      } else if (rc == TEXT && parm == 2) {
 557        int_4 k = format_str (curlex);
 558        _srecordf (fmt, "%d", k);
 559        *form = form_formatted;
 560      } else if (TOKEN ("unit")) {
 561        rc = scan ("=");
 562        rc = scan (EXPECT_NONE);
 563        io_unit (unit, defunit);
 564      } else if (TOKEN ("file")) {
 565        EXPR reg;
 566        rc = scan ("=");
 567        rc = scan (EXPECT_NONE);
 568        if (express (&reg, CHARACTER, NOLEN)) {
 569          *fn = f_stralloc (reg.str);
 570        }
 571      } else if (TOKEN ("form")) {
 572        rc = scan ("=");
 573        rc = scan (EXPECT_NONE);
 574        if (TOKEN ("formatted")) {
 575          *form = form_formatted;
 576        } else if (TOKEN ("unformatted")) {
 577          *form = form_unformatted;
 578        } else {
 579          SYNTAX (3008, "invalid FORM specification");
 580        }
 581      } else if (TOKEN ("action") || TOKEN ("access")) {
 582        rc = scan ("=");
 583        rc = scan (EXPECT_NONE);
 584        if (TOKEN ("read")) {
 585          *action = action_read;
 586        } else if (TOKEN ("write")) {
 587          *action = action_write;
 588        } else if (TOKEN ("readwrite")) {
 589          *action = action_readwrite;
 590        } else {
 591          SYNTAX (3009, "invalid ACCESS specification");
 592        }
 593      } else if (TOKEN ("disp") || TOKEN ("status")) {
 594  // Straight from JCL :-)
 595        rc = scan ("=");
 596        rc = scan (EXPECT_NONE);
 597        if (TOKEN ("\"old\"")) {
 598          *disp = disp_old;
 599        } else if (TOKEN ("\"new\"")) {
 600          *disp = disp_new;
 601        } else if (TOKEN ("\"keep\"")) {
 602          *disp = disp_keep;
 603        } else if (TOKEN ("\"delete\"")) {
 604          *disp = disp_delete;
 605        } else if (TOKEN ("\"unknown\"")) {
 606          *disp = disp_new;
 607        } else {
 608          SYNTAX (3010, "invalid DISP specification");
 609        }
 610      } else if (TOKEN ("lrecl")) {
 611        rc = scan ("=");
 612        if ((rc = scan (EXPECT_NONE)) == INT_NUMBER) {
 613          (void) isint_4 (curlex, lrecl);
 614        } else {
 615          EXPECT (3011, "record length");
 616        }
 617      } else if (TOKEN ("fmt")) {
 618        rc = scan ("=");
 619        rc = scan (EXPECT_LABEL);
 620        if (TOKEN ("*")) {
 621          fmt[0] = '\0';
 622          *form = form_formatted;
 623        } else if (rc == WORD || rc == LABEL) {
 624          bufcpy (fmt, curlex, RECLN);
 625          *form = form_formatted;
 626        } else if (rc == TEXT) {
 627          int_4 k = format_str (curlex);
 628          _srecordf (fmt, "%d", k);
 629          *form = form_formatted;
 630        } else {
 631          EXPECT (3012, "label or format string");
 632        }
 633      } else if (TOKEN ("end")) {
 634        rc = scan ("=");
 635        if ((rc = scan (EXPECT_LABEL)) == LABEL) {
 636          if (((*end) = find_label (curlex)) == NO_LABEL) {
 637            ERROR (3013, "no such label", curlex);
 638          }
 639          (*end)->jumped++;
 640        } else {
 641          EXPECT (3014, "label");
 642        }
 643      } else if (TOKEN ("err")) {
 644        rc = scan ("=");
 645        if ((rc = scan (EXPECT_LABEL)) == LABEL) {
 646          if (((*err) = find_label (curlex)) == NO_LABEL) {
 647            ERROR (3015, "no such label", curlex);
 648          }
 649          (*err)->jumped++;
 650        } else {
 651          EXPECT (3016, "label");
 652        }
 653      } else if (TOKEN ("iostat")) {
 654        rc = scan ("=");
 655        rc = scan (EXPECT_NONE);
 656        if (rc != WORD) {
 657          EXPECT (3017, "variable")
 658        } else {
 659          *iostat = f_stralloc (curlex);
 660        }
 661      } else if ((rc == WORD || rc == INT_NUMBER) && parm == 2) {
 662        bufcpy (fmt, curlex, RECLN);
 663        *form = form_formatted;
 664      } else if (parm == 1) {
 665        io_unit (unit, defunit);
 666      } else {
 667        SYNTAX (3018, curlex);
 668      }
 669  // Next item.
 670      parm++;
 671      rc = scan (EXPECT_NONE); 
 672      if (TOKEN (",")) {
 673        rc = scan (EXPECT_NONE); 
 674      } else if (TOKEN (")")) {
 675        ;
 676      } else {
 677        SYNTAX (3019, curlex);
 678      }
 679    }
 680  }
 681  
 682  void vif_close (void)
 683  {
 684    int_4 rc, lrecl = 0;
 685    char *daction = NO_TEXT, *ddisp = NO_TEXT, *dfn = NO_TEXT, *dform = NO_TEXT, *iostat = NO_TEXT;
 686    RECORD str, fmt;
 687    EXPR unit;
 688    LBL *endlbl = NO_LABEL, *errlbl = NO_LABEL;
 689    RECCLR (fmt);
 690    rc = scan (EXPECT_NONE);
 691    io_specs (&unit, ERR, fmt, &dfn, &dform, &daction, &lrecl, &ddisp, &endlbl, &errlbl, &iostat);
 692    _srecordf (str, "_fcheck (\"%s\", %s, NULL, NULL);\n", stat_start, unum (&unit));
 693    code (nprocs, BODY, str);
 694    _srecordf (str, "if (_ffile[%s].unit != NULL) {\n", unum (&unit));
 695    code (nprocs, BODY, str);
 696    _srecordf (str, "_funregister (\"%s\", %s);\n", stat_start, unum (&unit));
 697    code (nprocs, BODY, str);
 698    if (iostat != NO_TEXT) {
 699      RECORD ios;
 700      _srecordf (ios, "%s = errno;\n", iostat);
 701      code (nprocs, BODY, ios);
 702    } else {
 703      code (nprocs, BODY, "if (errno != 0) {\n");
 704      if (errlbl == NO_LABEL) {
 705        _srecordf (str, "_ioerr (\"%s\", %s);\n", stat_start, unum (&unit));
 706      } else {
 707        _srecordf (str, "goto _l%d;\n", errlbl->num);
 708      }
 709      code (nprocs, BODY, str);
 710      code (nprocs, BODY, "}\n");
 711      code (nprocs, BODY, "}\n");
 712    }
 713    (void) rc;
 714  }
 715  
 716  void vif_rewind (void)
 717  {
 718    int_4 rc, lrecl = 0;
 719    char *daction = NO_TEXT, *ddisp = NO_TEXT, *dfn = NO_TEXT, *dform = NO_TEXT, *iostat = NO_TEXT;
 720    RECORD str, fmt;
 721    EXPR unit;
 722    LBL *endlbl = NO_LABEL, *errlbl = NO_LABEL;
 723    RECCLR (fmt);
 724    rc = scan (EXPECT_NONE);
 725    io_specs (&unit, ERR, fmt, &dfn, &dform, &daction, &lrecl, &ddisp, &endlbl, &errlbl, &iostat);
 726    _srecordf (str, "_fcheck (\"%s\", %s, NULL, NULL);\n", stat_start, unum (&unit));
 727    code (nprocs, BODY, str);
 728    _srecordf (str, "if (_ffile[%s].unit != NULL) {\n", unum (&unit));
 729    code (nprocs, BODY, str);
 730    _srecordf (str, "rewind (_ffile[%s].unit);\n", unum (&unit));
 731    code (nprocs, BODY, str);
 732    if (iostat != NO_TEXT) {
 733      RECORD ios;
 734      _srecordf (ios, "%s = errno;\n", iostat);
 735      code (nprocs, BODY, ios);
 736    } else {
 737      code (nprocs, BODY, "if (errno != 0) {\n");
 738      if (errlbl == NO_LABEL) {
 739        _srecordf (str, "_ioerr (\"%s\", %s);\n", stat_start, unum (&unit));
 740      } else {
 741        _srecordf (str, "goto _l%d;\n", errlbl->num);
 742      }
 743      code (nprocs, BODY, str);
 744      code (nprocs, BODY, "}\n");
 745      code (nprocs, BODY, "}\n");
 746    }
 747    (void) rc;
 748  }
 749  
 750  void vif_open (void)
 751  {
 752    int_4 rc, lrecl = 0;
 753    char *daction = NO_TEXT, *dfn = NO_TEXT, *dform = NO_TEXT, *ddisp = NO_TEXT, *iostat = NO_TEXT;
 754    LBL *endlbl = NO_LABEL, *errlbl = NO_LABEL;
 755    RECORD str, fmt;
 756    EXPR unit;
 757    RECCLR (fmt);
 758    rc = scan (EXPECT_NONE);
 759    io_specs (&unit, ERR, fmt, &dfn, &dform, &daction, &lrecl, &ddisp, &endlbl, &errlbl, &iostat);
 760    if (dfn != NO_TEXT) {
 761      _srecordf (str, "_fregister (\"%s\", %s, %d, %s, %s, %s, %s);\n", stat_start, unum (&unit), lrecl, dfn, dform, daction, ddisp);
 762    } else {
 763      _srecordf (str, "_fregister (\"%s\", %s, %d, NULL, %s, %s, %s);\n", stat_start, unum (&unit), lrecl, dform, daction, ddisp);
 764    }
 765    code (nprocs, BODY, str);
 766    if (iostat != NO_TEXT) {
 767      RECORD ios;
 768      _srecordf (ios, "%s = errno;\n", iostat);
 769      code (nprocs, BODY, ios);
 770    }
 771    (void) rc;
 772  }
 773  
 774  void do_io (char *proc, int_4 *nest)
 775  {
 776    int_4 form = UNFORMATTED, lrecl = 0;
 777    LBL *endlbl = NO_LABEL, *errlbl = NO_LABEL;
 778    RECORD fstr, fid, iorc, str, fmt;
 779    char *daction = NO_TEXT, *ddisp = NO_TEXT, *dfn = NO_TEXT, *dform = NO_TEXT, *iostat = NO_TEXT;
 780    EXPR unit;
 781    unit.mode.type = INTEGER;
 782    unit.mode.len = 4;
 783    fmt[0] = '\0';
 784    fstr[0] = '\0';
 785    fid[0] = '\0';
 786    iorc[0] = '\0';
 787    int_4 rc = scan (EXPECT_NONE);
 788    if (EQUAL (proc, "read") || EQUAL (proc, "accept")) {
 789      if (TOKEN ("*")) {
 790        _srecordf (unit.str, "STDF_IN");
 791        dform = form_formatted;
 792        rc = scan (EXPECT_NONE);
 793      } else if (rc == INT_NUMBER) { // FORTRAN II
 794        _srecordf (unit.str, "STDF_IN");
 795        bufcpy (fmt, curlex, RECLN);
 796        dform = form_formatted;
 797        rc = scan (EXPECT_NONE);
 798      } else if (rc == TEXT) {
 799        _srecordf (unit.str, "STDF_IN");
 800        int_4 k = format_str (curlex);
 801        _srecordf (fmt, "%d", k);
 802        dform = form_formatted;
 803        rc = scan (EXPECT_NONE);
 804      } else {
 805        io_specs (&unit, STDF_IN, fmt, &dfn, &dform, &daction, &lrecl, &ddisp, &endlbl, &errlbl, &iostat);
 806      }
 807    } else if (EQUAL (proc, "write") || EQUAL (proc, "print") || EQUAL (proc, "punch")) {
 808      if (TOKEN ("*")) {
 809        _srecordf (unit.str, "STDF_OUT");
 810        dform = form_formatted;
 811        rc = scan (EXPECT_NONE);
 812      } else if (rc == INT_NUMBER) { // FORTRAN II
 813        _srecordf (unit.str, "STDF_OUT");
 814        bufcpy (fmt, curlex, RECLN);
 815        dform = form_formatted;
 816        rc = scan (EXPECT_NONE);
 817      } else if (rc == TEXT) {
 818        _srecordf (unit.str, "STDF_OUT");
 819        int_4 k = format_str (curlex);
 820        _srecordf (fmt, "%d", k);
 821        dform = form_formatted;
 822        rc = scan (EXPECT_NONE);
 823      } else {
 824        io_specs (&unit, STDF_OUT, fmt, &dfn, &dform, &daction, &lrecl, &ddisp, &endlbl, &errlbl, &iostat);
 825      }
 826    }
 827    if (strlen (fmt) == 0 && dform != form_unformatted) {
 828      form = STDFORMAT;
 829    } else if (strlen (fmt) == 0 && dform == form_unformatted) {
 830      form = UNFORMATTED;
 831    } else {
 832      form = FORMATTED;
 833    }
 834  // IO to a string implies UNIT=0.
 835    if (unit.mode.type == CHARACTER) {
 836      if (EQUAL (proc, "read")) {
 837        _srecordf (str, "_ffile[0].unit = fmemopen (%s, %d, \"r\");\n", unit.str, unit.mode.len + 1);
 838      } else if (EQUAL (proc, "accept")) {
 839        _srecordf (str, "_ffile[0].unit = fmemopen (%s, %d, \"r\");\n", unit.str, unit.mode.len + 1);
 840      } else if (EQUAL (proc, "write")) {
 841        _srecordf (str, "_ffile[0].unit = fmemopen (%s, %d, \"w\");\n", unit.str, unit.mode.len + 1);
 842      } else if (EQUAL (proc, "print")) {
 843        _srecordf (str, "_ffile[0].unit = fmemopen (%s, %d, \"w\");\n", unit.str, unit.mode.len + 1);
 844      } else if (EQUAL (proc, "punch")) {
 845        _srecordf (str, "_ffile[0].unit = fmemopen (%s, %d, \"w\");\n", unit.str, unit.mode.len + 1);
 846      }
 847      code (nprocs, BODY, str);
 848    }
 849  // Runtime checks - can the file do this?
 850    if (EQUAL (proc, "read")) {
 851      _srecordf (str, "_fcheck (\"%s\", %s, action_read, %s);\n", stat_start, unum (&unit), dform);
 852    } else if (EQUAL (proc, "accept")) {
 853      _srecordf (str, "_fcheck (\"%s\", %s, action_read, %s);\n", stat_start, unum (&unit), dform);
 854    } else if (EQUAL (proc, "write")) {
 855      _srecordf (str, "_fcheck (\"%s\", %s, action_write, %s);\n", stat_start, unum (&unit), dform);
 856    } else if (EQUAL (proc, "print")) {
 857      _srecordf (str, "_fcheck (\"%s\", %s, action_write, %s);\n", stat_start, unum (&unit), dform);
 858    } else if (EQUAL (proc, "punch")) {
 859      _srecordf (str, "_fcheck (\"%s\", %s, action_write, %s);\n", stat_start, unum (&unit), dform);
 860    }
 861    code (nprocs, BODY, str);
 862    if (form == FORMATTED) {
 863      RECORD fcnt;
 864      int_4 val;
 865      _srecordf (fid, "__fcnt");
 866      add_local (fid, INTEGER, 4, NOUNIQ, NOPATCH, NOARG, LOCAL, TEMP);
 867      _srecordf (iorc, "__rc");
 868      add_local (iorc, INTEGER, 4, NOUNIQ, NOPATCH, NOARG, LOCAL, TEMP);
 869      _srecordf (fcnt, "%s = 0;\n", fid);
 870      code (nprocs, BODY, fcnt);
 871      if (isint_4 (fmt, &val)) {
 872        _srecordf (fstr, "%s", edit_fmt (val));
 873      } else {
 874        MODE mode;
 875        IDENT *idf = find_local (fmt, &mode);
 876        if (idf == NO_IDENT) {
 877          ERROR (3020, "undeclared format identifier", fmt);
 878        } else if (mode.type == INTEGER) {
 879  // Assigned FORMAT.
 880          _srecordf (str, "switch (%s) {\n", C_NAME (idf));
 881          code (nprocs, BODY, str);
 882          code (nprocs, BODY, "default:\n");
 883          for (int_4 k = 0; k < nlabels; k++) {
 884            LBL *L = &labels[k];
 885            if (L->format) {
 886              L->jumped++;
 887              _srecordf (str, "case %d: __fmt_a = %s; break;\n", L->index, edit_fmt(L->num));
 888              code (nprocs, BODY, str);
 889            }
 890          }
 891          code (nprocs, BODY, "}\n");
 892          strcpy (fstr, "__fmt_a");
 893        } else if (mode.type == CHARACTER) {
 894          _srecordf (str, "__fmt_a = _vif_jit (\"%s\", %s);\n", stat_start, C_NAME (idf));
 895          code (nprocs, BODY, str);
 896          strcpy (fstr, "__fmt_a");
 897        } else {
 898          ERROR (3021, "format identifier mode error", qtype (&mode));
 899        }
 900      }
 901    } else {
 902      _srecordf (iorc, "__rc_%d", nloctmps++);
 903      add_local (iorc, INTEGER, 4, NOUNIQ, NOPATCH, NOARG, LOCAL, TEMP);
 904    }
 905  // Start-of-record.
 906    if (form == FORMATTED) {
 907      if (EQUAL (proc, "read")) {
 908        io_text_items ("read", &unit, fstr, fid, iorc, endlbl, errlbl);
 909      } else if (EQUAL (proc, "accept")) {
 910        io_text_items ("read", &unit, fstr, fid, iorc, endlbl, errlbl);
 911      } else if (EQUAL (proc, "write")) {
 912        io_text_items ("write", &unit, fstr, fid, iorc, endlbl, errlbl);
 913      } else if (EQUAL (proc, "print")) {
 914        io_text_items ("write", &unit, fstr, fid, iorc, endlbl, errlbl);
 915      } else if (EQUAL (proc, "punch")) {
 916        io_text_items ("write", &unit, fstr, fid, iorc, endlbl, errlbl);
 917      }
 918    }
 919    int_4 items = 0;
 920    if (EQUAL (proc, "read")) {
 921      io_list ("read", &unit, form, fstr, fid, iorc, endlbl, errlbl, ERR, nest, &items);
 922    } else if (EQUAL (proc, "accept")) {
 923      io_list ("read", &unit, form, fstr, fid, iorc, endlbl, errlbl, ERR, nest, &items);
 924    } else if (EQUAL (proc, "write")) {
 925      io_list ("write", &unit, form, fstr, fid, iorc, endlbl, errlbl, ERR, nest, &items);
 926    } else if (EQUAL (proc, "print")) {
 927      io_list ("write", &unit, form, fstr, fid, iorc, endlbl, errlbl, ERR, nest, &items);
 928    } else if (EQUAL (proc, "punch")) {
 929      io_list ("write", &unit, form, fstr, fid, iorc, endlbl, errlbl, ERR, nest, &items);
 930    }
 931    if (unit.mode.type == CHARACTER) {
 932  // IO to a string implies UNIT=0.
 933      code (nprocs, BODY, "_fclose (0);\n");
 934    } else if (EQUAL (proc, "write") || EQUAL (proc, "print") || EQUAL (proc, "punch")) {
 935  // End-of-record.
 936      if (form != UNFORMATTED) {
 937        _srecordf (str, "_write_eol (%s);\n", unum (&unit));
 938        code (nprocs, BODY, str);
 939      }
 940    } else if (EQUAL (proc, "read") || EQUAL (proc, "accept")) {
 941  // End-of-record.
 942      if (form != UNFORMATTED) {
 943        _srecordf (str, "_read_eol (%s);\n", unum (&unit));
 944        code (nprocs, BODY, str);
 945      }
 946    }
 947  //
 948    save_iostat (iostat);
 949  //
 950    (void) rc;
 951  }
     


© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)