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


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