statements.c

     1  //! @file statements.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 statements.
    25  
    26  #include <vif.h>
    27  
    28  int_4 patch (int_4 where, char *str)
    29  {
    30    if (where >= 0 && where < n_c_src) {
    31      C_SRC *lin = &object[where];
    32      if (str != NO_TEXT) {
    33        lin->text = f_stralloc (str);
    34      } else {
    35        lin->text = NO_TEXT;
    36      }
    37    } else {
    38      BUG ("patch");
    39    }
    40    return where;
    41  }
    42  
    43  void patch_args (void)
    44  {
    45    for (int_4 k = 0; k < nlocals; k++) {
    46      IDENT *idf = &locals[k];
    47      if (idf->arg) {
    48        NEW_RECORD (str);
    49        if (idf->external) {
    50          _srecordf (str, "%s (*%s)()", wtype (&idf->mode, NOARG, FUN), edit_f (C_NAME (idf)));
    51        } else if (IS_SCALAR (idf->mode)) {
    52          _srecordf (str, "%s%s", wtype (&idf->mode, ARG, NOFUN), C_NAME (idf));
    53        } else {
    54          _srecordf (str, "%s _p_ %s", wtype (&idf->mode, NOARG, FUN), C_NAME (idf));
    55        }
    56        if (idf->patch1 != 0) {
    57          patch (idf->patch1, str);
    58        }
    59        if (idf->patch2 != 0) {
    60          patch (idf->patch2, str);
    61        }
    62      }
    63    }
    64  }
    65  
    66  //
    67  // EXECUTABLE STATEMENTS
    68  //
    69  
    70  void vif_extensions(void)
    71  {
    72    if (TOKEN ("exit")) {
    73      code (nprocs, BODY, "break;\n");
    74    } else if (TOKEN ("break")) {
    75      code (nprocs, BODY, "break;\n");
    76    } else if (TOKEN ("cycle")) {
    77  // CYCLE
    78      code (nprocs, BODY, "continue;\n");
    79    } else {
    80      ERROR (3001, "syntax", curlex);
    81    }
    82    skip_card (FALSE);
    83  }
    84  
    85  void block_if (EXPR *reg, int_4 apatch, int_4 depth)
    86  {
    87  // Block IF.
    88    int_4 rc;
    89    skip_card (FALSE);
    90    NEW_RECORD (str);
    91    if (reg->mode.type != LOGICAL) {
    92      EXPECT (3002, "logical expression");
    93    }
    94    _srecordf (str, "if (%s) {\n", reg->str);
    95    patch (apatch, str);
    96    gen_statements (NO_LABEL, depth + 1);
    97    while (TOKEN ("elseif")) {
    98      EXPR reh;
    99      rc = scan ("(");
   100      rc = scan (EXPECT_NONE);
   101      macro_depth = 0;
   102      express (&reh, NOTYPE, NOLEN);
   103      rc = scan (")");
   104      rc = scan ("THEN");
   105      if (reh.mode.type != LOGICAL) {
   106        EXPECT (3003, "logical expression");
   107      }
   108      code (nprocs, BODY, "}\n");
   109      _srecordf (str, "else if (%s) {\n", reh.str);
   110      code (nprocs, BODY, str);
   111      gen_statements (NO_LABEL, depth + 1);
   112    }
   113    if (TOKEN ("else")) {
   114      skip_card (FALSE);
   115      code (nprocs, BODY, "}\n");
   116      code (nprocs, BODY, "else {\n");
   117      gen_statements (NO_LABEL, depth + 1);
   118    }
   119    if (TOKEN ("endif")) {
   120      skip_card (FALSE);
   121    } else {
   122      EXPECT (3004, "endif");
   123    }
   124    code (nprocs, BODY, "}\n");
   125    (void) rc;
   126  }
   127  
   128  void arith_if (EXPR *reg)
   129  {
   130  // Arithmetic IF.
   131    int_4 rc;
   132    NEW_RECORD (str);
   133    NEW_RECORD (tmp);
   134    NEW_RECORD (l1);
   135    NEW_RECORD (l2);
   136    NEW_RECORD (l3);
   137    LBL *lab1, *lab2, *lab3;
   138    IDENT *idf;
   139    int_4 N = 0;
   140  // Gather the labels
   141    RECCPY (l1, curlex);
   142    lab1 = find_label (l1);
   143    if (lab1 == NO_LABEL) {
   144      ERROR (3005, "no such label", l1);
   145      return;
   146    }
   147    lab1->jumped++;
   148    rc = scan (",");
   149    rc = scan (EXPECT_NONE);
   150    if (rc != INT_NUMBER) {
   151      EXPECT (3006, "label");
   152      return;
   153    }
   154    RECCPY (l2, curlex);
   155    lab2 = find_label (l2);
   156    if (lab2 == NO_LABEL) {
   157      ERROR (3007, "no such label", l2);
   158      return;
   159    }
   160    lab2->jumped++;
   161    rc = scan (",");
   162    if (rc == END_OF_LINE) {
   163      N = 2;
   164    } else {
   165      N = 3;
   166      rc = scan (EXPECT_NONE);
   167      if (rc != INT_NUMBER) {
   168        EXPECT (3008, "label");
   169        return;
   170      }
   171      RECCPY (l3, curlex);
   172      lab3 = find_label (l3);
   173      if (lab3 == NO_LABEL) {
   174        ERROR (3009, "no such label", l3);
   175        return;
   176      }
   177      lab3->jumped++;
   178    }
   179    if (N == 3) {
   180  // ANSI FORTRAN three-branch arithmetic statement.
   181      if (reg->mode.type != INTEGER && reg->mode.type != REAL) {
   182        EXPECT (3010, "integer or real expression");
   183      }
   184      _srecordf (tmp, "%s", edit_tmp (nloctmps++));
   185      idf = add_local (tmp, reg->mode.type, reg->mode.len, UNIQ, NOPATCH, NOARG, LOCAL, TEMP);
   186      _srecordf (str, "%s = %s;\n", C_NAME (idf), reg->str);
   187      code (nprocs, BODY, str);
   188      _srecordf (str, "if (%s < 0) {\n", C_NAME (idf));
   189      code (nprocs, BODY, str);
   190      _srecordf (str, "goto _l%d;\n", lab1->num);
   191      code (nprocs, BODY, str);
   192      _srecordf (str, "}");
   193      code (nprocs, BODY, str);
   194      _srecordf (str, "else if (%s == 0) {\n", C_NAME (idf));
   195      code (nprocs, BODY, str);
   196      _srecordf (str, "goto _l%d;\n", lab2->num);
   197      code (nprocs, BODY, str);
   198      _srecordf (str, "}");
   199      code (nprocs, BODY, str);
   200      _srecordf (str, "else {\n");
   201      code (nprocs, BODY, str);
   202      _srecordf (str, "goto _l%d;\n", lab3->num);
   203      code (nprocs, BODY, str);
   204      _srecordf (str, "}\n");
   205      code (nprocs, BODY, str);
   206    } else {
   207  // CRAY FORTRAN two-branch arithmetic statement.
   208      if (reg->mode.type != INTEGER && reg->mode.type != REAL && reg->mode.type != LOGICAL) {
   209        EXPECT (3011, "integer, real or logical expression");
   210      }
   211      if (reg->mode.type == INTEGER || reg->mode.type == REAL) {
   212        if (reg->variant == EXPR_VAR || reg->variant == EXPR_SLICE) {
   213          _srecordf (str, "if (%s != 0) {\n", reg->str);
   214        } else {
   215          _srecordf (str, "if ((%s) != 0) {\n", reg->str);
   216        }
   217      } else {
   218        if (reg->variant == EXPR_VAR || reg->variant == EXPR_SLICE) {
   219          _srecordf (str, "if (%s == TRUE) {\n", reg->str);
   220        } else {
   221          _srecordf (str, "if ((%s) == TRUE) {\n", reg->str);
   222        }
   223      }
   224      code (nprocs, BODY, str);
   225      _srecordf (str, "goto _l%d;\n", lab1->num);
   226      code (nprocs, BODY, str);
   227      _srecordf (str, "}");
   228      code (nprocs, BODY, str);
   229      _srecordf (str, "else {\n");
   230      code (nprocs, BODY, str);
   231      _srecordf (str, "goto _l%d;\n", lab2->num);
   232      code (nprocs, BODY, str);
   233      _srecordf (str, "}\n");
   234      code (nprocs, BODY, str);
   235    }
   236    skip_card (FALSE);
   237  }
   238  
   239  void conditional (int_4 depth, logical_4 block_allowed)
   240  {
   241    int_4 rc = scan ("(");
   242    int_4 apatch = code (nprocs, BODY, NO_TEXT);
   243    EXPR reg;
   244    rc = scan (EXPECT_NONE);
   245    macro_depth = 0;
   246    express (&reg, NOTYPE, NOLEN);
   247    rc = scan (")");
   248    rc = scan (EXPECT_NONE);
   249    if (TOKEN ("then") && block_allowed) {
   250      block_if (&reg, apatch, depth);
   251    } else if (rc == INT_NUMBER) {
   252      arith_if (&reg);
   253    } else {
   254  // Logical IF.
   255      NEW_RECORD (str);
   256      if (reg.mode.type != LOGICAL) {
   257        EXPECT (3012, "logical expression");
   258      }
   259      _srecordf (str, "if (%s) {\n", reg.str);
   260      patch (apatch, str);
   261      if (TOKEN ("if") && IS_NOT_ASSIGNMENT) {
   262        conditional (depth, FALSE);
   263      } else if (TOKEN ("do") && IS_NOT_ASSIGNMENT) {
   264        SYNTAX (3013, "invalid statement in logical IF");
   265      } else if (TOKEN ("end") && IS_NOT_ASSIGNMENT) {
   266        SYNTAX (3014, "invalid statement in logical IF");
   267      } else {
   268        executable ();
   269      }
   270      code (nprocs, BODY, "}\n");
   271    }
   272  }
   273  
   274  void do_loop (LBL * curlbl, int_4 depth)
   275  {
   276    int_4 rc;
   277    LBL *newlbl;
   278    EXPR lhs, from, to, by;
   279    NEW_RECORD (str);
   280    lhs.mode.type = NOTYPE;
   281    lhs.mode.len = 0;
   282    rc = scan (EXPECT_LABEL);
   283    if (rc != LABEL) {
   284      newlbl = NO_LABEL;
   285    } else {
   286      newlbl = find_label (curlex);
   287      if (newlbl == NO_LABEL) {
   288        ERROR (3015, "no such label", curlex);
   289        return;
   290      }
   291      if (curlbl != NO_LABEL && newlbl->line > curlbl->line) {
   292        ERROR (3016, "incorrect loop nesting", NO_TEXT);
   293        return;
   294      }
   295      rc = scan (EXPECT_NONE);
   296    }
   297    if (TOKEN ("repeat")) {
   298      skip_card (FALSE);
   299      code (nprocs, BODY, "do {\n");
   300      gen_statements (newlbl, depth + 1);
   301      code (nprocs, BODY, "} while (TRUE);\n");
   302    } else if (TOKEN ("while")) {
   303      rc = scan ("(");
   304      EXPR reg;
   305      rc = scan (EXPECT_NONE);
   306      macro_depth = 0;
   307      express (&reg, NOTYPE, NOLEN);
   308      rc = scan (")");
   309      skip_card (FALSE);
   310      if (reg.mode.type != LOGICAL) {
   311        EXPECT (3017, "logical expression");
   312      }
   313      _srecordf (str, "while (%s) {\n", reg.str);
   314      code (nprocs, BODY, str);
   315      gen_statements (newlbl, depth + 1);
   316      code (nprocs, BODY, "}\n");
   317    } else {
   318  // DO 1, I = 1, 10, 2
   319      if (TOKEN (",")) {
   320        rc = scan (EXPECT_NONE);
   321      }
   322      if (rc != WORD) {
   323        EXPECT (3018, "variable");
   324      } else {
   325        impl_decl (curlex, NO_MODE);
   326        macro_depth = 0;
   327        express (&lhs, NOTYPE, NOLEN);
   328        if (lhs.variant != EXPR_VAR) {
   329          EXPECT (3019, "variable");
   330          return;
   331        }
   332      }
   333      rc = scan ("=");
   334      rc = scan (EXPECT_NONE);
   335      macro_depth = 0;
   336      express (&from, lhs.mode.type, lhs.mode.len);
   337      rc = scan (",");
   338      rc = scan (EXPECT_NONE);
   339      macro_depth = 0;
   340      express (&to, lhs.mode.type, lhs.mode.len);
   341      rc = scan (EXPECT_NONE);
   342      if (TOKEN (",")) {
   343        rc = scan (EXPECT_NONE);
   344        macro_depth = 0;
   345        express (&by, lhs.mode.type, lhs.mode.len);
   346      } else {
   347        UNSCAN;
   348        RECCPY (by.str, "1");
   349      }
   350      skip_card (TRUE);
   351      if (f4_do_loops) {
   352        _srecordf (str, "%s = %s;\n", lhs.str, from.str);
   353        code (nprocs, BODY, str);
   354        code (nprocs, BODY, "do {\n");
   355        gen_statements (newlbl, depth + 1);
   356        if (strcmp (by.str, "1") == 0) {
   357          _srecordf (str, "(%s)++;\n", lhs.str);
   358          code (nprocs, BODY, str);
   359          code (nprocs, BODY, "}\n");
   360          _srecordf (str, "while (%s <= %s);\n", lhs.str, to.str);
   361          code (nprocs, BODY, str);
   362        } else if (strcmp (by.str, "-1") == 0) {
   363          _srecordf (str, "(%s)--;\n", lhs.str);
   364          code (nprocs, BODY, str);
   365          code (nprocs, BODY, "}\n");
   366          _srecordf (str, "while (%s >= %s);\n", lhs.str, to.str);
   367          code (nprocs, BODY, str);
   368        } else {
   369          _srecordf (str, "%s += %s;\n", lhs.str, by.str);
   370          code (nprocs, BODY, str);
   371          code (nprocs, BODY, "}\n");
   372          _srecordf (str, "while (%s > 0 ? %s <= %s : %s >= %s);\n", by.str, lhs.str, to.str, lhs.str, to.str);
   373          code (nprocs, BODY, str);
   374        }
   375      } else {
   376        if (strcmp (by.str, "1") == 0) {
   377          _srecordf (str, "for (%s = %s; %s <= %s; (%s)++) {\n", lhs.str, from.str, lhs.str, to.str, lhs.str);
   378        } else if (strcmp (by.str, "-1") == 0) {
   379          _srecordf (str, "for (%s = %s; %s >= %s; (%s)--) {\n", lhs.str, from.str, lhs.str, to.str, lhs.str);
   380        } else {
   381          _srecordf (str, "for (%s = %s; (%s > 0 ? %s <= %s : %s >= %s); %s += %s) {\n", lhs.str, from.str, by.str, lhs.str, to.str, lhs.str, to.str, lhs.str, by.str);
   382        }
   383        code (nprocs, BODY, str);
   384        gen_statements (newlbl, depth + 1);
   385        code (nprocs, BODY, "}\n");
   386      }
   387    }
   388  }
   389  
   390  LBL *lbl = NO_LABEL;
   391  
   392  void executable (void)
   393  {
   394    int_4 rc = curret;
   395    if (TOKEN ("call") && IS_NOT_ASSIGNMENT) {
   396  // CALL
   397      cpp_direct (nprocs, prelin, BODY);
   398      call ();
   399      code (nprocs, BODY, ";\n");
   400      skip_card (FALSE);
   401    } else if (TOKEN ("close") && IS_NOT_ASSIGNMENT) {
   402      cpp_direct (nprocs, prelin, BODY);
   403      vif_close ();
   404      skip_card (FALSE);
   405    } else if (TOKEN ("decode") && IS_NOT_ASSIGNMENT) {
   406  // DECODE
   407      int_4 nest = 0;
   408      cpp_direct (nprocs, prelin, BODY);
   409      do_io ("decode", &nest);
   410      if (nest != 0) {
   411        ERROR (3020, "unbalanced parentheses", NO_TEXT);
   412      }
   413      skip_card (FALSE);
   414    } else if (TOKEN ("encode") && IS_NOT_ASSIGNMENT) {
   415  // ENCODE
   416      int_4 nest = 0;
   417      cpp_direct (nprocs, prelin, BODY);
   418      do_io ("encode", &nest);
   419      if (nest != 0) {
   420        ERROR (3021, "unbalanced parentheses", NO_TEXT);
   421      }
   422      skip_card (FALSE);
   423    } else if (TOKEN ("endfile") && IS_NOT_ASSIGNMENT) {
   424      cpp_direct (nprocs, prelin, BODY);
   425      vif_endfile ();
   426      skip_card (FALSE);
   427    } else if (TOKEN ("continue") && IS_NOT_ASSIGNMENT) {
   428  // CONTINUE
   429      code (nprocs, BODY, ";\n");
   430      skip_card (FALSE);
   431    } else if (TOKEN ("goto") && IS_NOT_ASSIGNMENT) {
   432  // GOTO
   433      cpp_direct (nprocs, prelin, BODY);
   434      jump ();
   435    } else if (TOKEN ("open") && IS_NOT_ASSIGNMENT) {
   436      cpp_direct (nprocs, prelin, BODY);
   437      vif_open ();
   438      skip_card (FALSE);
   439    } else if (TOKEN ("pause") && IS_NOT_ASSIGNMENT) {
   440  // PAUSE
   441      NEW_RECORD (str);
   442      cpp_direct (nprocs, prelin, BODY);
   443      rc = scan (EXPECT_NONE);
   444      if (rc == INT_NUMBER) {
   445        sscanf (curlex, "%d", &rc);
   446        _srecordf (str, "printf (\"PAUSE: %d\\n.\");\n", rc);
   447      } else if (rc == TEXT && strlen (curlex) > 0) {
   448        curlex[strlen(curlex) - 1] = '\0';
   449        _srecordf (str, "printf (\"PAUSE: %s\\n.\");\n", &curlex[1]);
   450      } else {
   451        _srecordf (str, "printf (\"PAUSE\\n\");\n");
   452      }
   453      code (nprocs, BODY, str);
   454      code (nprocs, BODY, "(void) fgetc (stdin);\n");
   455      skip_card (FALSE);
   456    } else if (TOKEN ("read") && IS_NOT_ASSIGNMENT) {
   457  // READ
   458      int_4 nest = 0;
   459      cpp_direct (nprocs, prelin, BODY);
   460      do_io ("read", &nest);
   461      if (nest != 0) {
   462        ERROR (3022, "unbalanced parentheses", NO_TEXT);
   463      }
   464      skip_card (FALSE);
   465    } else if (TOKEN ("accept") && IS_NOT_ASSIGNMENT) {
   466  // ACCEPT
   467      int_4 nest = 0;
   468      cpp_direct (nprocs, prelin, BODY);
   469      do_io ("accept", &nest);
   470      if (nest != 0) {
   471        ERROR (3023, "unbalanced parentheses", NO_TEXT);
   472      }
   473      skip_card (FALSE);
   474    } else if (TOKEN ("return") && IS_NOT_ASSIGNMENT) {
   475  // RETURN
   476      cpp_direct (nprocs, prelin, BODY);
   477      labels[0].jumped++;
   478      code (nprocs, BODY, RETURN);
   479      skip_card (FALSE);
   480  //  ENTRY
   481    } else if (TOKEN ("entry") && IS_NOT_ASSIGNMENT) {
   482      ERROR (3024, "obsolete feature", "entry");
   483      skip_card (FALSE);
   484    } else if (TOKEN ("backspace") && IS_NOT_ASSIGNMENT) {
   485  // BACKSPACE
   486      cpp_direct (nprocs, prelin, BODY);
   487      vif_backspace ();
   488      skip_card (FALSE);
   489    } else if (TOKEN ("rewind") && IS_NOT_ASSIGNMENT) {
   490  // REWIND
   491      cpp_direct (nprocs, prelin, BODY);
   492      vif_rewind ();
   493      skip_card (FALSE);
   494    } else if (TOKEN ("stop") && IS_NOT_ASSIGNMENT) {
   495  // STOP 
   496      NEW_RECORD (str);
   497      cpp_direct (nprocs, prelin, BODY);
   498      rc = scan (EXPECT_NONE);
   499      if (rc == INT_NUMBER) {
   500        sscanf (curlex, "%d", &rc);
   501        _srecordf (str, "exit (%d);\n", rc);
   502      } else {
   503        _srecordf (str, "exit (EXIT_SUCCESS);\n");
   504      }
   505      code (nprocs, BODY, str);
   506      skip_card (FALSE);
   507    } else if (TOKEN ("write") && IS_NOT_ASSIGNMENT) {
   508  // WRITE
   509      int_4 nest = 0;
   510      cpp_direct (nprocs, prelin, BODY);
   511      do_io ("write", &nest);
   512      if (nest != 0) {
   513        ERROR (3025, "unbalanced parentheses", NO_TEXT);
   514      }
   515      skip_card (FALSE);
   516    } else if (TOKEN ("print") && IS_NOT_ASSIGNMENT) {
   517  // PRINT
   518      int_4 nest = 0;
   519      cpp_direct (nprocs, prelin, BODY);
   520      do_io ("print", &nest);
   521      if (nest != 0) {
   522        ERROR (3026, "unbalanced parentheses", NO_TEXT);
   523      }
   524      skip_card (FALSE);
   525    } else if (TOKEN ("punch") && IS_NOT_ASSIGNMENT) {
   526  // PUNCH
   527      int_4 nest = 0;
   528      cpp_direct (nprocs, prelin, BODY);
   529      do_io ("punch", &nest);
   530      if (nest != 0) {
   531        ERROR (3027, "unbalanced parentheses", NO_TEXT);
   532      }
   533      skip_card (FALSE);
   534    } else if (rc == WORD) {
   535  // Single-word extensions EXIT, CYCLE, BREAK, etcetera.
   536      SAVE_POS (1);
   537      rc = scan (EXPECT_NONE);
   538      if (rc == END_OF_LINE || rc == END_OF_MODULE) {
   539        RESTORE_POS (1);
   540        // RECCPY (curlex, prelex);
   541        vif_extensions ();
   542      } else {
   543        UNSCAN;
   544  // Primary - Assignation or call
   545        EXPR reg;
   546        MODE mode;
   547        cpp_direct (nprocs, prelin, BODY);
   548        (void) impl_decl (curlex, &mode);
   549        memset (&reg, 0, sizeof (EXPR));
   550        assign (&reg);
   551        code (nprocs, BODY, reg.str);
   552        code (nprocs, BODY, ";\n");
   553        skip_card (FALSE);
   554      }
   555    }
   556  }
   557  
   558  void gen_statements (LBL * dolbl, int_4 depth)
   559  {
   560    int_4 rc;
   561    while ((rc = scan (EXPECT_NONE)) != END_OF_MODULE) {
   562      macro_depth = 0;
   563  // Common mistakes.
   564      if (TOKEN ("program") && IS_NOT_ASSIGNMENT) {
   565        ERROR (3028, "check for missing END statement", NO_TEXT);
   566      } else if (TOKEN ("function") && IS_NOT_ASSIGNMENT) {
   567        ERROR (3029, "check for missing END statement", NO_TEXT);
   568      } else if (TOKEN ("subroutine") && IS_NOT_ASSIGNMENT) {
   569        ERROR (3030, "check for missing END statement", NO_TEXT);
   570      } else if (TOKEN ("block") && IS_NOT_ASSIGNMENT) {
   571        ERROR (3031, "check for missing END statement", NO_TEXT);
   572      }
   573  // FORTRAN statements.
   574      LBL *statlbl = NO_LABEL;
   575      if (rc == LABEL) {
   576        NEW_RECORD (str);
   577        statlbl = lbl = find_label (curlex);
   578        if (lbl == NO_LABEL) {
   579          ERROR (3032, "no such label", curlex);
   580        } else {
   581          _srecordf (str, "_l%d:;\n", lbl->num);
   582          lbl->patch = code (nprocs, BODY, str);
   583        }
   584        rc = scan (EXPECT_NONE);
   585        if (TOKEN ("continue")) {
   586          continue;               // Sic!
   587        }
   588      }
   589      _srecordf (stat_start, "%s:%s:%d", libnam, modnam, CUR_LIN.num);
   590      if (rc == DECLAR) {
   591        ERROR (3033, "declaration amidst executable statements", NO_TEXT);
   592      } else if (TOKEN ("assign")) {
   593  // ASSIGN statement, from before the Chicxulub impact.
   594  // Relic from when computers had no way to organize subroutine calls.
   595        rc = scan (EXPECT_LABEL);
   596        if (rc != LABEL) {
   597          SYNTAX (3034, "label expected");
   598        } else {
   599          LBL *slbl = find_label (curlex);
   600          if (slbl == NO_LABEL) {
   601            ERROR (3035, "no such label", NO_TEXT);
   602          }
   603          rc = scan ("to");
   604          EXPR reg;
   605          rc = scan (EXPECT_NONE);
   606          macro_depth = 0;
   607          express (&reg, INTEGER, 4);
   608          NEW_RECORD (str);
   609          _srecordf (str, "%s = %d;\n", reg.str, slbl->index);
   610          code (nprocs, BODY, str);
   611        }
   612        skip_card (FALSE);
   613      } else if (TOKEN ("end") && IS_NOT_ASSIGNMENT) {
   614        skip_card (FALSE);
   615        end_statements++;
   616  // END is not executable.
   617        NEW_RECORD (str);
   618        if (depth != 0) {
   619          SYNTAX (3036, "end must end a subprogram");
   620          abend = TRUE;
   621        }
   622  // Peephole optimisation, END following RETURN which is typical.
   623        if (n_c_src > 0) {
   624          C_SRC *lin = &object[n_c_src - 1];
   625          if (EQUAL (lin->text, RETURN)) {
   626            lin->text = NO_TEXT;
   627            labels[0].jumped--;
   628          }
   629        }
   630  // Return.
   631        labels[0].patch = code (nprocs, BODY, "_l0:;\n");
   632        _srecordf (str, "__calls[%d].calls++;\n", nprocs - 1);
   633        code (nprocs, BODY, str);
   634        if (func) {
   635          _srecordf (str, "return %s;\n", retnam);
   636        } else {
   637          _srecordf (str, "return 0;\n");
   638        }
   639        cpp_direct (nprocs, prelin, BODY);
   640        code (nprocs, BODY, str);
   641        return;
   642      } else if (TOKEN ("elseif") && IS_NOT_ASSIGNMENT) {
   643        if (depth > 0) {
   644          return;
   645        } else {
   646          SYNTAX (3037, "stray symbol");
   647        }
   648      } else if (TOKEN ("else") && IS_NOT_ASSIGNMENT) {
   649        if (depth > 0) {
   650          return;
   651        } else {
   652          SYNTAX (3038, "stray symbol");
   653        }
   654      } else if (TOKEN ("endif") && IS_NOT_ASSIGNMENT) {
   655        if (depth > 0) {
   656          return;
   657        } else {
   658          SYNTAX (3039, "stray symbol");
   659        }
   660      } else if (TOKEN ("until") && IS_NOT_ASSIGNMENT) {
   661        NEW_RECORD (str);
   662        rc = scan ("(");
   663        EXPR reg;
   664        rc = scan (EXPECT_NONE);
   665        macro_depth = 0;
   666        express (&reg, NOTYPE, NOLEN);
   667        rc = scan (")");
   668        if (reg.mode.type != LOGICAL) {
   669          EXPECT (3040, "logical expression");
   670        }
   671        _srecordf (str, "if (%s) {\n", reg.str);
   672        code (nprocs, BODY, str);
   673        _srecordf (str, "break;\n");
   674        code (nprocs, BODY, str);
   675        _srecordf (str, "}\n");
   676        code (nprocs, BODY, str);
   677        skip_card (FALSE);
   678      } else if (TOKEN ("if") && IS_NOT_ASSIGNMENT) {
   679        cpp_direct (nprocs, prelin, BODY);
   680        conditional (depth, TRUE);
   681      } else if (TOKEN ("do") && IS_NOT_ASSIGNMENT) {
   682        // DO
   683        cpp_direct (nprocs, prelin, BODY);
   684        do_loop (dolbl, depth);
   685        skip_card (FALSE);
   686      } else if (TOKEN ("enddo") && IS_NOT_ASSIGNMENT) {
   687        if (dolbl != NO_LABEL) {
   688          ERROR (3041, "misplaced end do", NO_TEXT);
   689        }
   690        if (depth > 0) {
   691          return;
   692        } else {
   693          SYNTAX (3042, "stray symbol");
   694        }
   695      } else if (TOKEN ("format") && IS_NOT_ASSIGNMENT) {
   696        cpp_direct (nprocs, prelin, FMT);
   697        format (statlbl);
   698        skip_card (FALSE);
   699      } else {
   700        executable ();
   701      }
   702  // Return for DO loop (ending label reached).
   703      if (dolbl != NO_LABEL && lbl != NO_LABEL && dolbl->num == lbl->num) {
   704        if (depth == 0) {
   705          BUG ("nesting");
   706        }
   707        return;
   708      }
   709    }
   710  }


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