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


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