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 ("accept") && IS_NOT_ASSIGNMENT) {
   396  // ACCEPT
   397      int_4 nest = 0;
   398      cpp_direct (nprocs, prelin, BODY);
   399      do_io ("accept", &nest);
   400      if (nest != 0) {
   401        ERROR (3020, "unbalanced parentheses", NO_TEXT);
   402      }
   403      skip_card (FALSE);
   404    } else if (TOKEN ("backspace") && IS_NOT_ASSIGNMENT) {
   405  // BACKSPACE
   406      cpp_direct (nprocs, prelin, BODY);
   407      vif_backspace ();
   408      skip_card (FALSE);
   409    } else if (TOKEN ("call") && IS_NOT_ASSIGNMENT) {
   410  // CALL
   411      cpp_direct (nprocs, prelin, BODY);
   412      call ();
   413      code (nprocs, BODY, ";\n");
   414      skip_card (FALSE);
   415    } else if (TOKEN ("close") && IS_NOT_ASSIGNMENT) {
   416  // CLOSE
   417      cpp_direct (nprocs, prelin, BODY);
   418      vif_close ();
   419      skip_card (FALSE);
   420    } else if (TOKEN ("continue") && IS_NOT_ASSIGNMENT) {
   421  // CONTINUE
   422      code (nprocs, BODY, ";\n");
   423      skip_card (FALSE);
   424    } else if (TOKEN ("decode") && IS_NOT_ASSIGNMENT) {
   425  // DECODE
   426      int_4 nest = 0;
   427      cpp_direct (nprocs, prelin, BODY);
   428      do_io ("decode", &nest);
   429      if (nest != 0) {
   430        ERROR (3021, "unbalanced parentheses", NO_TEXT);
   431      }
   432      skip_card (FALSE);
   433    } else if (TOKEN ("encode") && IS_NOT_ASSIGNMENT) {
   434  // ENCODE
   435      int_4 nest = 0;
   436      cpp_direct (nprocs, prelin, BODY);
   437      do_io ("encode", &nest);
   438      if (nest != 0) {
   439        ERROR (3022, "unbalanced parentheses", NO_TEXT);
   440      }
   441      skip_card (FALSE);
   442    } else if (TOKEN ("endfile") && IS_NOT_ASSIGNMENT) {
   443  // ENDFILE
   444      cpp_direct (nprocs, prelin, BODY);
   445      vif_endfile ();
   446      skip_card (FALSE);
   447    } else if (TOKEN ("entry") && IS_NOT_ASSIGNMENT) {
   448  //  ENTRY
   449      ERROR (3023, "obsolete feature", "entry");
   450      skip_card (FALSE);
   451    } else if (TOKEN ("goto") && IS_NOT_ASSIGNMENT) {
   452  // GOTO
   453      cpp_direct (nprocs, prelin, BODY);
   454      jump ();
   455    } else if (TOKEN ("inquire") && IS_NOT_ASSIGNMENT) {
   456  // INQUIRE
   457      cpp_direct (nprocs, prelin, BODY);
   458      vif_inquire ();
   459      skip_card (FALSE);
   460    } else if (TOKEN ("open") && IS_NOT_ASSIGNMENT) {
   461  // OPEN
   462      cpp_direct (nprocs, prelin, BODY);
   463      vif_open ();
   464      skip_card (FALSE);
   465    } else if (TOKEN ("pause") && IS_NOT_ASSIGNMENT) {
   466  // PAUSE
   467      NEW_RECORD (str);
   468      cpp_direct (nprocs, prelin, BODY);
   469      rc = scan (EXPECT_NONE);
   470      if (rc == INT_NUMBER) {
   471        sscanf (curlex, "%d", &rc);
   472        _srecordf (str, "printf (\"PAUSE: %d\\n.\");\n", rc);
   473      } else if (rc == TEXT && strlen (curlex) > 0) {
   474        curlex[strlen(curlex) - 1] = '\0';
   475        _srecordf (str, "printf (\"PAUSE: %s\\n.\");\n", &curlex[1]);
   476      } else {
   477        _srecordf (str, "printf (\"PAUSE\\n\");\n");
   478      }
   479      code (nprocs, BODY, str);
   480      code (nprocs, BODY, "(void) fgetc (stdin);\n");
   481      skip_card (FALSE);
   482    } else if (TOKEN ("print") && IS_NOT_ASSIGNMENT) {
   483  // PRINT
   484      int_4 nest = 0;
   485      cpp_direct (nprocs, prelin, BODY);
   486      do_io ("print", &nest);
   487      if (nest != 0) {
   488        ERROR (3024, "unbalanced parentheses", NO_TEXT);
   489      }
   490      skip_card (FALSE);
   491    } else if (TOKEN ("punch") && IS_NOT_ASSIGNMENT) {
   492  // PUNCH
   493      int_4 nest = 0;
   494      cpp_direct (nprocs, prelin, BODY);
   495      do_io ("punch", &nest);
   496      if (nest != 0) {
   497        ERROR (3025, "unbalanced parentheses", NO_TEXT);
   498      }
   499      skip_card (FALSE);
   500    } else if (TOKEN ("read") && IS_NOT_ASSIGNMENT) {
   501  // READ
   502      int_4 nest = 0;
   503      cpp_direct (nprocs, prelin, BODY);
   504      do_io ("read", &nest);
   505      if (nest != 0) {
   506        ERROR (3026, "unbalanced parentheses", NO_TEXT);
   507      }
   508      skip_card (FALSE);
   509    } else if (TOKEN ("return") && IS_NOT_ASSIGNMENT) {
   510  // RETURN
   511      cpp_direct (nprocs, prelin, BODY);
   512      labels[0].jumped++;
   513      code (nprocs, BODY, RETURN);
   514      skip_card (FALSE);
   515    } else if (TOKEN ("rewind") && IS_NOT_ASSIGNMENT) {
   516  // REWIND
   517      cpp_direct (nprocs, prelin, BODY);
   518      vif_rewind ();
   519      skip_card (FALSE);
   520    } else if (TOKEN ("stop") && IS_NOT_ASSIGNMENT) {
   521  // STOP 
   522      NEW_RECORD (str);
   523      cpp_direct (nprocs, prelin, BODY);
   524      rc = scan (EXPECT_NONE);
   525      if (rc == INT_NUMBER) {
   526        sscanf (curlex, "%d", &rc);
   527        _srecordf (str, "exit (%d);\n", rc);
   528      } else {
   529        _srecordf (str, "exit (EXIT_SUCCESS);\n");
   530      }
   531      code (nprocs, BODY, str);
   532      skip_card (FALSE);
   533    } else if (TOKEN ("write") && IS_NOT_ASSIGNMENT) {
   534  // WRITE
   535      int_4 nest = 0;
   536      cpp_direct (nprocs, prelin, BODY);
   537      do_io ("write", &nest);
   538      if (nest != 0) {
   539        ERROR (3027, "unbalanced parentheses", NO_TEXT);
   540      }
   541      skip_card (FALSE);
   542    } else if (rc == WORD) {
   543  // Single-word extensions EXIT, CYCLE, BREAK, etcetera.
   544      SAVE_POS (1);
   545      rc = scan (EXPECT_NONE);
   546      if (rc == END_OF_LINE || rc == END_OF_MODULE) {
   547        RESTORE_POS (1);
   548        // RECCPY (curlex, prelex);
   549        vif_extensions ();
   550      } else {
   551        UNSCAN;
   552  // Primary - Assignation or call
   553        EXPR reg;
   554        MODE mode;
   555        cpp_direct (nprocs, prelin, BODY);
   556        (void) impl_decl (curlex, &mode);
   557        memset (&reg, 0, sizeof (EXPR));
   558        assign (&reg);
   559        code (nprocs, BODY, reg.str);
   560        code (nprocs, BODY, ";\n");
   561        skip_card (FALSE);
   562      }
   563    }
   564  }
   565  
   566  void gen_statements (LBL * dolbl, int_4 depth)
   567  {
   568    int_4 rc;
   569    while ((rc = scan (EXPECT_NONE)) != END_OF_MODULE) {
   570      macro_depth = 0;
   571  // Common mistakes.
   572      if (TOKEN ("program") && IS_NOT_ASSIGNMENT) {
   573        ERROR (3028, "check for missing END statement", NO_TEXT);
   574      } else if (TOKEN ("function") && IS_NOT_ASSIGNMENT) {
   575        ERROR (3029, "check for missing END statement", NO_TEXT);
   576      } else if (TOKEN ("subroutine") && IS_NOT_ASSIGNMENT) {
   577        ERROR (3030, "check for missing END statement", NO_TEXT);
   578      } else if (TOKEN ("block") && IS_NOT_ASSIGNMENT) {
   579        ERROR (3031, "check for missing END statement", NO_TEXT);
   580      }
   581  // FORTRAN statements.
   582      LBL *statlbl = NO_LABEL;
   583      if (rc == LABEL) {
   584        NEW_RECORD (str);
   585        statlbl = lbl = find_label (curlex);
   586        if (lbl == NO_LABEL) {
   587          ERROR (3032, "no such label", curlex);
   588        } else {
   589          _srecordf (str, "_l%d:;\n", lbl->num);
   590          lbl->patch = code (nprocs, BODY, str);
   591        }
   592        rc = scan (EXPECT_NONE);
   593        if (TOKEN ("continue")) {
   594          continue;               // Sic!
   595        }
   596      }
   597      _srecordf (stat_start, "%s:%s:%d", libnam, modnam, CUR_LIN.num);
   598      if (rc == DECLAR) {
   599        ERROR (3033, "declaration amidst executable statements", NO_TEXT);
   600      } else if (TOKEN ("assign")) {
   601  // ASSIGN statement, from before the Chicxulub impact.
   602  // Relic from when computers had no way to organize subroutine calls.
   603        rc = scan (EXPECT_LABEL);
   604        if (rc != LABEL) {
   605          SYNTAX (3034, "label expected");
   606        } else {
   607          LBL *slbl = find_label (curlex);
   608          if (slbl == NO_LABEL) {
   609            ERROR (3035, "no such label", NO_TEXT);
   610          }
   611          rc = scan ("to");
   612          EXPR reg;
   613          rc = scan (EXPECT_NONE);
   614          macro_depth = 0;
   615          express (&reg, INTEGER, 4);
   616          NEW_RECORD (str);
   617          _srecordf (str, "%s = %d;\n", reg.str, slbl->index);
   618          code (nprocs, BODY, str);
   619        }
   620        skip_card (FALSE);
   621      } else if (TOKEN ("end") && IS_NOT_ASSIGNMENT) {
   622        skip_card (FALSE);
   623        end_statements++;
   624  // END is not executable.
   625        NEW_RECORD (str);
   626        if (depth != 0) {
   627          SYNTAX (3036, "end must end a subprogram");
   628          abend = TRUE;
   629        }
   630  // Peephole optimisation, END following RETURN which is typical.
   631        if (n_c_src > 0) {
   632          C_SRC *lin = &object[n_c_src - 1];
   633          if (EQUAL (lin->text, RETURN)) {
   634            lin->text = NO_TEXT;
   635            labels[0].jumped--;
   636          }
   637        }
   638  // Return.
   639        labels[0].patch = code (nprocs, BODY, "_l0:;\n");
   640        _srecordf (str, "__calls[%d].calls++;\n", nprocs - 1);
   641        code (nprocs, BODY, str);
   642        if (func) {
   643          _srecordf (str, "return %s;\n", retnam);
   644        } else {
   645          _srecordf (str, "return 0;\n");
   646        }
   647        cpp_direct (nprocs, prelin, BODY);
   648        code (nprocs, BODY, str);
   649        return;
   650      } else if (TOKEN ("elseif") && IS_NOT_ASSIGNMENT) {
   651        if (depth > 0) {
   652          return;
   653        } else {
   654          SYNTAX (3037, "stray symbol");
   655        }
   656      } else if (TOKEN ("else") && IS_NOT_ASSIGNMENT) {
   657        if (depth > 0) {
   658          return;
   659        } else {
   660          SYNTAX (3038, "stray symbol");
   661        }
   662      } else if (TOKEN ("endif") && IS_NOT_ASSIGNMENT) {
   663        if (depth > 0) {
   664          return;
   665        } else {
   666          SYNTAX (3039, "stray symbol");
   667        }
   668      } else if (TOKEN ("until") && IS_NOT_ASSIGNMENT) {
   669        NEW_RECORD (str);
   670        rc = scan ("(");
   671        EXPR reg;
   672        rc = scan (EXPECT_NONE);
   673        macro_depth = 0;
   674        express (&reg, NOTYPE, NOLEN);
   675        rc = scan (")");
   676        if (reg.mode.type != LOGICAL) {
   677          EXPECT (3040, "logical expression");
   678        }
   679        _srecordf (str, "if (%s) {\n", reg.str);
   680        code (nprocs, BODY, str);
   681        _srecordf (str, "break;\n");
   682        code (nprocs, BODY, str);
   683        _srecordf (str, "}\n");
   684        code (nprocs, BODY, str);
   685        skip_card (FALSE);
   686      } else if (TOKEN ("if") && IS_NOT_ASSIGNMENT) {
   687        cpp_direct (nprocs, prelin, BODY);
   688        conditional (depth, TRUE);
   689      } else if (TOKEN ("do") && IS_NOT_ASSIGNMENT) {
   690        // DO
   691        cpp_direct (nprocs, prelin, BODY);
   692        do_loop (dolbl, depth);
   693        skip_card (FALSE);
   694      } else if (TOKEN ("enddo") && IS_NOT_ASSIGNMENT) {
   695        if (dolbl != NO_LABEL) {
   696          ERROR (3041, "misplaced end do", NO_TEXT);
   697        }
   698        if (depth > 0) {
   699          return;
   700        } else {
   701          SYNTAX (3042, "stray symbol");
   702        }
   703      } else if (TOKEN ("format") && IS_NOT_ASSIGNMENT) {
   704        cpp_direct (nprocs, prelin, FMT);
   705        format (statlbl);
   706        skip_card (FALSE);
   707      } else {
   708        executable ();
   709      }
   710  // Return for DO loop (ending label reached).
   711      if (dolbl != NO_LABEL && lbl != NO_LABEL && dolbl->num == lbl->num) {
   712        if (depth == 0) {
   713          BUG ("nesting");
   714        }
   715        return;
   716      }
   717    }
   718  }


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