fmtparse.c

Go to the documentation of this file.
00001 /*
00002 
00003   Copyright (C) 2000, 2001, Silicon Graphics, Inc.  All Rights Reserved.
00004 
00005   This program is free software; you can redistribute it and/or modify it
00006   under the terms of version 2.1 of the GNU Lesser General Public License 
00007   as published by the Free Software Foundation.
00008 
00009   This program is distributed in the hope that it would be useful, but
00010   WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013   Further, this software is distributed without any warranty that it is
00014   free of the rightful claim of any third person regarding infringement 
00015   or the like.  Any license provided herein, whether implied or 
00016   otherwise, applies only to this software file.  Patent licenses, if
00017   any, provided herein do not apply to combinations of this program with 
00018   other software, or any other product whatsoever.  
00019 
00020   You should have received a copy of the GNU Lesser General Public 
00021   License along with this program; if not, write the Free Software 
00022   Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, 
00023   USA.
00024 
00025   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00026   Mountain View, CA 94043, or:
00027 
00028   http://www.sgi.com
00029 
00030   For further information regarding this notice, see:
00031 
00032   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00033 
00034 */
00035 
00036 
00037 
00038 #ifndef _OLD_ERROR_NUMBERS
00039 #pragma ident "@(#) libf/fio/fmtparse.c 92.3    06/18/99 19:52:04"
00040 #endif
00041 #include "lio.h"        /* For spiffy IS_DIGIT() macro */
00042 #include <ctype.h>
00043 #ifndef _ABSOFT
00044 #include <malloc.h>
00045 #else
00046 #include <stdlib.h>
00047 #endif
00048 #include <string.h>
00049 #include <cray/format.h>
00050 #include <cray/nassert.h>
00051 #include <cray/portdefs.h>
00052 
00053 typedef struct  {
00054         char            fmt_ch;         /* Current character in format     */
00055         char            *fmt_ptr;       /* Pointer to current format char. */
00056         short           caller;         /* Caller is library or compiler   */
00057         short           depth;          /* Current format nesting depth    */
00058         short           maxdepth;       /* Maximum format nesting depth    */
00059         short           fatal_err;      /* Flag to indicate fatal error    */
00060         long            desc_col;       /* Pointer to actual edit desc.    */
00061         long            fmt_pos;        /* Current position in format      */
00062         long            fmt_len;        /* Number of characters in format  */
00063         fmt_type        *parsed;        /* Pointer to parsed format block  */
00064         fmt_type        *pptr;          /* Pointer to current parsed entry */
00065         fmt_type        *revert;        /* Pointer to reversion point      */
00066         msg_type        *stat;          /* Pointer to error status word    */
00067         _Error_function *iss_msg;       /* Pointer to format error handler */
00068 } parse_block;
00069 
00070 /* Declare 'forward' functions for type-checking */
00071 
00072 static void
00073 fmterr (        parse_block     *pfmt,
00074                 short           msg_num,
00075                 short           code,
00076                 long            column);
00077 
00078 static short
00079 process_paren_group (   parse_block     *pfmt,
00080                         fmt_type        *ploc);
00081 
00082 /* Table of nonrepeatable characters */
00083 
00084 static int64 non_repeatable[2] = {
00085         0x00000000297EFFE0,     /* " $ ' ) * + , - . 0-9 : */
00086         0x0000180800001800      /* S T \ s t */
00087 };
00088 
00089 /*
00090  * Macros to return next character and gather up a number.
00091  * At start, fmt_ptr needs to be incremented.  At end,
00092  * fmt_ptr points to the returned character.  Input is
00093  * a Fortran character string, so EOS is not always '\0'.
00094  */
00095 
00096 #define GET(P) {                                                \
00097         do {                                                    \
00098                 if (++P->fmt_pos > P->fmt_len) {                \
00099                         P->fmt_ch       = '\0';                 \
00100                         P->fmt_pos--;                           \
00101                         break;                                  \
00102                 }                                               \
00103                 P->fmt_ch       = *(++P->fmt_ptr);              \
00104         } while (P->fmt_ch == ' ' || P->fmt_ch == '\t');        \
00105 }
00106 
00107 #define GETNUM(P, M) {                                          \
00108         do {                                                    \
00109                 M       = (M + M + (M << 3)) + ((int64) P->fmt_ch - ZERO);\
00110                 GET(P);                                         \
00111         } while (IS_DIGIT(P->fmt_ch));                          \
00112 }
00113 
00114 /* Bridge for symbol renaming */
00115 
00116 #ifndef E_WITH_D_NON_ANSI
00117 #define E_WITH_D_NON_ANSI       DW_IS_NON_ANSI
00118 #endif
00119 
00120 /*
00121  *      _fmt_parse()
00122  *
00123  *      Description:    This routine initializes variables for the format
00124  *                      parser, positions the input to the first character,
00125  *                      calls the actual format parser and cleans up.
00126  *
00127  *      Called By:      cft77, cft90 and the I/O library.
00128  *
00129  *      Calls:          process_paren_group
00130  *                      calloc
00131  *                      realloc
00132  *                      fmterr
00133  *
00134  *      Input parameters:
00135  *              msg_rtn         Pointer to a pointer to the message routine to 
00136  *                              be called if this is a compiler call.  NULL if 
00137  *                              this is a library call.
00138  *              format_str      Pointer to the format string to be parsed.
00139  *              routine_caller  Library/compiler flag.
00140  *
00141  *      Output parameters:
00142  *              fmt_str_len     The length in words of the parsed format.
00143  *              msg_out_ptr     Pointer to the list of messages found.
00144  *
00145  *      Returns:        A pointer to the parsed format string.  The first
00146  *                      two-word entry of the parsed format is for control
00147  *                      information; the first word is reserved for use by
00148  *                      the compiler, the second word is reserved for use
00149  *                      by the parser and library.
00150  *
00151  *      Note:           The input parameters are pointers to interface with
00152  *                      Pascal.
00153  */
00154 
00155 fmt_type *
00156 _fmt_parse(
00157         _Error_function **msg_rtn,
00158         char            *format_str,
00159         long            routine_caller,
00160         long            *fmt_str_len,
00161         msg_type        *lib_err_msg
00162 )
00163 {
00164         register short  length;
00165         parse_block     *pfmt, p;
00166 
00167         /* Basic assertions */
00168 
00169         assert (format_str != NULL);
00170         assert (routine_caller >= 0 && routine_caller <= MAX_CALL_FLAG);
00171         assert (fmt_str_len != NULL);
00172         assert (*fmt_str_len > 0);
00173         assert (routine_caller == LIB_CALL ? lib_err_msg != NULL : 1);
00174         assert (routine_caller != LIB_CALL ? msg_rtn != NULL : 1);
00175 
00176         /*
00177          * If this routine is called from the library (routine_caller =
00178          * LIB_CALL) then the parser returns the number and position of the
00179          * first fatal error found--if any--and then exits.  Any other caller
00180          * (e.g., compilers) must provide their own error routine by passing
00181          * a pointer to the routine in the first argument.  The parser will
00182          * continue parsing until the end of the format is reached.
00183          */
00184 
00185         pfmt            = &p;
00186 
00187         pfmt->fmt_pos   = 0;
00188         pfmt->depth     = 0;
00189         pfmt->maxdepth  = 0;
00190         pfmt->fatal_err = FALSE;
00191         pfmt->iss_msg   = (msg_rtn == NULL ? NULL : *msg_rtn);
00192         pfmt->stat      = lib_err_msg;
00193         pfmt->fmt_ptr   = format_str - 1; /* Set for first GET call */
00194         pfmt->fmt_len   = *fmt_str_len;
00195         pfmt->caller    = routine_caller;
00196 
00197         GET(pfmt);
00198 
00199         pfmt->desc_col  = pfmt->fmt_pos;
00200 
00201         if (pfmt->fmt_ch == '(') {
00202                 GET(pfmt);
00203         }
00204         else {
00205                 fmterr(pfmt, EXPECTING_LEFT_PAREN, FALL, 0);
00206 
00207                 /* Library quits at first fatal error */
00208 
00209                 if (pfmt->caller == LIB_CALL)
00210                         return( (fmt_type *) NULL);
00211         }
00212 
00213         /*
00214          * We need to allocate a parsed format structure with enough
00215          * entries to accommodate this format (we'll free any unused
00216          * entries when we're done).  Our initial guess is the number
00217          * of characters in the format plus two (one for the header and
00218          * one for the REVERT_OP entry).  Note that for a long, sparse
00219          * format (with lots of blanks), this will allocate way too
00220          * much space.
00221          */
00222 
00223         pfmt->parsed    = (fmt_type *) calloc(pfmt->fmt_len + 2,
00224                                                 sizeof(fmt_type));
00225 
00226         if (pfmt->parsed == NULL) {
00227 
00228                 fmterr(pfmt, UNABLE_TO_MALLOC_MEMORY, FALL, 0);
00229 
00230                 /* No place for format, so quit */
00231 
00232                 return( (fmt_type *) NULL);
00233         }
00234 
00235         pfmt->pptr              = pfmt->parsed + 1;
00236         pfmt->revert            = pfmt->pptr;
00237 
00238         /* Parse the format string */
00239 
00240         (void) process_paren_group(pfmt, pfmt->pptr);
00241 
00242         if (pfmt->fatal_err) {
00243                 free( (char *) pfmt->parsed);   /* Return memory */
00244                 pfmt->parsed    = NULL;
00245                 length          = 0;
00246         }
00247         else {
00248                 length                  = pfmt->pptr - pfmt->parsed;
00249                 pfmt->parsed->offset    = PARSER_LEVEL;
00250                 pfmt->parsed->rep_count = pfmt->maxdepth + 1;
00251 
00252                 if (pfmt->fmt_ch != '\0')
00253                         fmterr(pfmt, TRAILING_CHARS, FALL, 0);
00254 
00255                 if (pfmt->caller == LIB_CALL)
00256                         pfmt->parsed    = (fmt_type *) realloc (
00257                                                 (char *) pfmt->parsed,
00258                                                 length * FMT_ENTRY_BYTE_SIZE );
00259         }
00260 
00261         *fmt_str_len    = length * FMT_ENTRY_WORD_SIZE;
00262 
00263         return(pfmt->parsed);
00264 
00265 } /* _parsfmt */
00266 
00267 /*
00268  *      fmterr()
00269  *
00270  *      Description:    This routine processes errors encountered while
00271  *                      parsing formats.
00272  *
00273  *      Called By:      All routines in this file.
00274  *
00275  *      Input parameters:
00276  *              pfmt            Parsing information block
00277  *              msg_num         Message number (see format.h)
00278  *              code            Compiler applicability code
00279  *                              FALL    Error/warning applies to all compilers
00280  *                              F77     Error/warning applies only to f77
00281  *                              F90     Error/warning applies only to f90
00282  *                              F95     Error/warning applies only to f95
00283  *              column          Column number corresponding to error.  If
00284  *                              zero, use current position.
00285  *
00286  *      Returns:        Nothing
00287  *
00288  *      Note:           Two column pointers are passed to the error processing
00289  *                      routine.  The first points to the position in the
00290  *                      format where the actual error occurred; the second
00291  *                      points to the edit descriptor being processed.
00292  */
00293 
00294 static void
00295 fmterr(
00296         parse_block     *pfmt,
00297         short           msg_num,
00298         short           code,
00299         long            column
00300 )
00301 {
00302         register short  callflg;
00303 
00304         callflg = 0;    /* Assume no call to error function */
00305 
00306         if (msg_num >= FIRST_FATAL_MESSAGE)
00307                 pfmt->fatal_err = TRUE;
00308 
00309         if (column == 0)
00310                 column  = pfmt->fmt_pos;
00311 
00312         switch (pfmt->caller) {
00313 
00314                 case LIB_CALL:
00315 
00316                         /* Ignore warnings and non-ANSI messages */
00317 
00318                         if (msg_num >= FIRST_FATAL_MESSAGE) {
00319                                 pfmt->stat->msg_number  = msg_num;
00320                                 pfmt->stat->msg_column  = column;
00321                                 pfmt->stat->desc_column = pfmt->desc_col;
00322                         }
00323                         break;
00324 
00325                 case COMPILER_CALL_NO_ANSI:
00326 
00327                         /* Ignore ANSI messages */
00328 
00329                         callflg = (msg_num < FIRST_NON_ANSI_MESSAGE ||
00330                                    msg_num >= FIRST_FATAL_MESSAGE);
00331                         break;
00332 
00333                 case COMPILER_CALL_ANSI:
00334 
00335                         /* Call compiler error routine */
00336 
00337                         callflg = 1;
00338                         break;
00339 
00340                 case COMPILER_CALL_ANSI_77:
00341 
00342                         /* Ignore any non-f77 messages */
00343 
00344                         callflg = (code & F77);
00345                         break;
00346 
00347                 case COMPILER_CALL_ANSI_90:
00348 
00349                         /* Ignore any non-f90 messages */
00350 
00351                         callflg = (code & F90);
00352                         break;
00353 
00354                 case COMPILER_CALL_ANSI_95:
00355 
00356                         /* Ignore any non-f95 messages */
00357 
00358                         callflg = (code & F95);
00359                         break;
00360         } /* switch */
00361 
00362         if (callflg != 0)
00363                 (*pfmt->iss_msg) (msg_num, column, pfmt->desc_col);
00364 
00365         return;
00366 
00367 } /* fmterr */
00368 
00369 /*
00370  *      recover()
00371  *
00372  *      Description:    This routine tries to recover from a fatal error by
00373  *                      searching for the character: ',', ')', '(', '"', '*',
00374  *                      "'", or EOF after the error.  This should position
00375  *                      the parser at a valid format descriptor.
00376  *
00377  *      Called By:      process_paren_group
00378  *                      process_defg
00379  *                      process_bioz
00380  *                      process_arl
00381  *                      process_minus
00382  *
00383  *      Input parameters:
00384  *              pfmt            Parsing information block
00385  *
00386  *      Returns:        Nothing
00387  */
00388 
00389 static void
00390 recover(
00391         parse_block     *pfmt
00392 )
00393 {
00394         register short  found_char;
00395 
00396         found_char      = FALSE;
00397 
00398         if (pfmt->caller != LIB_CALL)
00399                 do {                    
00400                         switch (pfmt->fmt_ch) {
00401                                 case ',':               
00402                                 case ')':       
00403                                 case '(':
00404                                 case '"':                       
00405                                 case '*':               
00406                                 case '\'':      
00407                                 case '\0':
00408                                         found_char      = TRUE; 
00409                                         break;  
00410 
00411                                 default:
00412                                         GET(pfmt);              
00413                                         break;  
00414                         } /* switch */          
00415                 } while (!found_char);
00416 
00417         return;
00418 
00419 } /* recover */
00420 
00421 /*
00422  *      nonzero_integer()
00423  *
00424  *      Description:    This routine finds and returns a nonzero integer
00425  *                      or issues an error.
00426  *
00427  *      Called By:      process_t
00428  *
00429  *      Calls:          fmterr
00430  *
00431  *      Input parameters:
00432  *              pfmt            Parsing information block
00433  *
00434  *      Output parameters:
00435  *              size            The nonzero integer.
00436  *
00437  *      Returns:        TRUE if a nonzero integer is found, else FALSE.
00438  */
00439 
00440 static short
00441 nonzero_integer(
00442         parse_block     *pfmt,
00443         long            *size
00444 )
00445 {
00446         register short  return_val;
00447         register int64  value;
00448         register long   col;
00449 
00450         if (IS_DIGIT(pfmt->fmt_ch)) {
00451 
00452                 col             = pfmt->fmt_pos;
00453                 return_val      = TRUE;
00454                 value           = *size;
00455 
00456                 GETNUM(pfmt, value);
00457 
00458                 if (value == 0) {
00459                         fmterr(pfmt, FIELD_WIDTH_ZERO, FALL, col);
00460                         value   = 1;
00461                 }
00462                 else
00463                         if (value > MAX_FIELD_WIDTH) {
00464                                 fmterr(pfmt, FIELD_TOO_LARGE, FALL, col);
00465                                 value   = MAX_FIELD_WIDTH;
00466                         }
00467         }
00468         else {
00469                 fmterr(pfmt, EXPECTING_INTEGER, FALL, 0);
00470                 return_val      = FALSE;
00471                 value           = 1;
00472         }
00473 
00474         *size   = value;        /* Update value */
00475 
00476         return(return_val);
00477 
00478 } /* nonzero_integer */
00479 
00480 /*
00481  *      process_arl()
00482  *
00483  *      Description:    This does semantic checking and generates text for
00484  *                      the A, L and R data edit-descriptors.
00485  *
00486  *      Called By:      process_paren_group
00487  *
00488  *      Calls:          fmterr
00489  *
00490  *      Input parameters:
00491  *              pfmt            Parsing information block
00492  *              op_code         Is it A, L or R?
00493  *
00494  *      Valid forms:
00495  *                      A
00496  *                      Aw
00497  *                      L       (MIPSpro extension)
00498  *                      Lw
00499  *                      R       (MIPSpro extension)
00500  *                      Rw
00501  *
00502  *      Returns:        Nothing
00503  */
00504 
00505 static void
00506 process_arl(
00507         parse_block     *pfmt,
00508         unsigned short  op_code
00509 )
00510 {
00511         register long   col;
00512         register int64  size;
00513 
00514         size    = 0;
00515 
00516         GET(pfmt);
00517 
00518         if (IS_DIGIT(pfmt->fmt_ch)) {
00519 
00520                 col     = pfmt->fmt_pos;
00521 
00522                 GETNUM(pfmt, size);
00523 
00524                 if (size == 0) {
00525 #ifdef  _OLD_ERROR_NUMBERS
00526                         fmterr(pfmt, FIELD_WIDTH_ZERO, FALL, col);
00527                         size    = 1;
00528 #else
00529                         fmterr(pfmt, ZERO_WIDTH_NON_ANSI, FALL, col);
00530 #endif
00531                 }
00532                 else
00533                         if (size > MAX_FIELD_WIDTH) {
00534                                 fmterr(pfmt, FIELD_TOO_LARGE, FALL, col);
00535                                 size    = MAX_FIELD_WIDTH;
00536                         }
00537         }
00538         else
00539                 if (op_code != A_ED) {
00540 #ifdef  _OLD_ERROR_NUMBERS
00541                         fmterr(pfmt, EXPECTING_INTEGER, FALL, 0);
00542                         recover(pfmt);
00543 #else
00544                         fmterr(pfmt, MISSING_WIDTH_NON_ANSI, FALL, pfmt->fmt_pos);
00545 #endif
00546                 }
00547 
00548         pfmt->pptr->op_code     = op_code;
00549         pfmt->pptr->field_width = size;
00550         pfmt->pptr              = pfmt->pptr + 1;
00551 
00552         return;
00553 
00554 } /* process_arl */
00555 
00556 /*
00557  *      process_defg()
00558  *
00559  *      Description:    This does semantic checking and generates text for
00560  *                      the D, E, EN, ES, F, and G data edit-descriptors.
00561  *
00562  *      Called By:      process_paren_group
00563  *
00564  *      Calls:          fmterr
00565  *
00566  *      Input parameters:
00567  *              pfmt            Parsing information block
00568  *              op_code         Is it D, E, EN, ES, F or G?
00569  *
00570  *      Valid forms:
00571  *                      D       (MIPSpro extension)
00572  *                      Dw.d
00573  *                      Dw.dEe  (Cray extension)
00574  *                      E       (MIPSpro extension)
00575  *                      Ew.d
00576  *                      Ew.dEe
00577  *                      EN      (f90 or later, MIPSpro-style extension)
00578  *                      ENw.d   (f90 or later)
00579  *                      ENw.dEe (f90 or later)
00580  *                      ES      (f90 or later, MIPSpro-style extension)
00581  *                      ESw.d   (f90 or later)
00582  *                      ESw.dEe (f90 or later)
00583  *                      F       (MIPSpro extension)
00584  *                      Fw.d    (w can be zero in f95 or later)
00585  *                      G       (MIPSpro extension)
00586  *                      Gw.d
00587  *                      Gw.dEe
00588  *
00589  *      Returns:        Nothing
00590  */
00591 
00592 static void
00593 process_defg(
00594         parse_block     *pfmt,
00595         unsigned short  op_code
00596 )
00597 {
00598         register short  dset;
00599         register long   col;
00600         register int64  esize;
00601         register int64  dsize;
00602         register int64  wsize;
00603 
00604         dset    = 1;
00605         dsize   = 0;
00606         esize   = 0;
00607         wsize   = 0;
00608 
00609         GET(pfmt);
00610 
00611         if (IS_DIGIT(pfmt->fmt_ch)) {
00612 
00613                 col     = pfmt->fmt_pos;
00614 
00615                 GETNUM(pfmt, wsize);
00616 
00617                 if (wsize == 0) {
00618 #ifdef  _OLD_ERROR_NUMBERS
00619                         fmterr(pfmt, FIELD_WIDTH_ZERO, FALL, col);
00620                         wsize   = 1;
00621 #else
00622                         register short  code;
00623 
00624                         code    = (op_code == F_ED) ? (F77 | F90) : FALL;
00625 
00626                         fmterr(pfmt, ZERO_WIDTH_NON_ANSI, code, col);
00627 #endif
00628                 }
00629                 else
00630                         if (wsize > MAX_FIELD_WIDTH) {
00631                                 fmterr(pfmt, FIELD_TOO_LARGE, FALL, col);
00632                                 wsize   = MAX_FIELD_WIDTH;
00633                         }
00634 
00635                 if (pfmt->fmt_ch == '.') {
00636 
00637                         GET(pfmt);
00638 
00639                         if (IS_DIGIT(pfmt->fmt_ch)) {
00640 
00641                                 col     = pfmt->fmt_pos;
00642                                 dset    = 0;
00643                                 dsize   = 0;
00644 
00645                                 GETNUM(pfmt, dsize);
00646 
00647                                 if (dsize > MAX_DECIMAL_FIELD) {
00648                                         fmterr(pfmt, FIELD_TOO_LARGE, FALL, col);
00649                                         dsize   = MAX_DECIMAL_FIELD;
00650                                 }
00651 
00652                                 if (toupper(pfmt->fmt_ch) == 'E' &&
00653                                     op_code != F_ED) {
00654                                         register long   col_e;
00655 
00656                                         col_e   = pfmt->fmt_pos; /* Position of 'E' */
00657 
00658                                         GET(pfmt);
00659 
00660                                         if (IS_DIGIT(pfmt->fmt_ch)) {
00661 
00662                                                 col     = pfmt->fmt_pos;
00663 
00664                                                 GETNUM(pfmt, esize);
00665 
00666                                                 if (esize == 0) {
00667                                                         fmterr(pfmt,
00668                                                                 FIELD_WIDTH_ZERO,
00669                                                                 FALL,
00670                                                                 col);
00671                                                         esize   = 1;
00672                                                 }
00673                                                 else
00674                                                         if (esize > MAX_EXPONENT) {
00675                                                                 fmterr(pfmt,
00676                                                                 FIELD_TOO_LARGE,
00677                                                                 FALL, col);
00678                                                                 esize   = MAX_EXPONENT;
00679                                                         }
00680 
00681                                                 if (op_code == D_ED)
00682                                                         fmterr(pfmt, E_WITH_D_NON_ANSI,
00683                                                                 FALL, col_e);
00684                                         }
00685                                         else {
00686                                                 fmterr(pfmt, EXPECTING_INTEGER,
00687                                                         FALL, 0);
00688                                                 recover(pfmt);
00689                                         }
00690                                 }
00691                         }
00692                         else {
00693                                 fmterr(pfmt, EXPECTING_INTEGER, FALL, 0);
00694                                 recover(pfmt);
00695                         }
00696                 }
00697                 else {
00698                         fmterr(pfmt, EXPECTING_PERIOD, FALL, 0);
00699                         recover(pfmt);
00700                 }
00701         }
00702         else {
00703 #ifdef  _OLD_ERROR_NUMBERS
00704                 fmterr(pfmt, EXPECTING_INTEGER, FALL, 0);
00705                 recover(pfmt);
00706 #else
00707                 fmterr(pfmt, MISSING_WIDTH_NON_ANSI, FALL, pfmt->fmt_pos);
00708 #endif
00709         }
00710 
00711         pfmt->pptr->op_code             = op_code;
00712         pfmt->pptr->exponent            = esize;
00713         pfmt->pptr->field_width         = wsize;
00714         pfmt->pptr->digits_field        = dsize;
00715         pfmt->pptr->default_digits      = dset;
00716         pfmt->pptr                      = pfmt->pptr + 1;
00717 
00718         return;
00719 
00720 } /* process_defg */
00721 
00722 /*
00723  *      process_bioz()
00724  *
00725  *      Description:    This does semantic checking and generates text for
00726  *                      the B, I, O, and Z data edit-descriptors.
00727  *
00728  *      Called By:      process_paren_group
00729  *
00730  *      Calls:          fmterr
00731  *
00732  *      Input parameters:
00733  *              pfmt            Parsing information block
00734  *              op_code         Is it B, I, O or Z?
00735  *
00736  *      Valid forms:
00737  *                      B       (MIPSpro extension)
00738  *                      Bw      (w can be zero in f95 or later)
00739  *                      Bw.m    (w can be zero in f95 or later)
00740  *                      I       (MIPSpro extension)
00741  *                      Iw      (w can be zero in f95 or later)
00742  *                      Iw.m    (w can be zero in f95 or later)
00743  *                      O       (MIPSpro extension)
00744  *                      Ow      (w can be zero in f95 or later)
00745  *                      Ow.m    (w can be zero in f95 or later)
00746  *                      Z       (MIPSpro extension)
00747  *                      Zw      (w can be zero in f95 or later)
00748  *                      Zw.m    (w can be zero in f95 or later)
00749  *
00750  *      Returns:        Nothing
00751  */
00752 
00753 static void
00754 process_bioz(
00755         parse_block     *pfmt,
00756         unsigned short  op_code
00757 )
00758 {
00759         register short  dset;
00760         register long   col;
00761         register int64  dsize;
00762         register int64  wsize;
00763 
00764         dset    = 1;
00765         dsize   = 1;
00766         wsize   = 0;
00767 
00768         GET(pfmt);
00769 
00770         if (IS_DIGIT(pfmt->fmt_ch)) {
00771 
00772                 col     = pfmt->fmt_pos; 
00773 
00774                 GETNUM(pfmt, wsize);
00775 
00776                 if (wsize == 0) {
00777 #ifdef  _OLD_ERROR_NUMBERS
00778                         fmterr(pfmt, FIELD_WIDTH_ZERO, FALL, col);
00779                         wsize   = 1;
00780 #else
00781                         fmterr(pfmt, ZERO_WIDTH_NON_ANSI, (F77 | F90), col);
00782 #endif
00783                 } else
00784                         if (wsize > MAX_FIELD_WIDTH) {
00785                                 fmterr(pfmt, FIELD_TOO_LARGE, FALL, col);
00786                                 wsize   = MAX_FIELD_WIDTH;
00787                         }
00788 
00789                 if (pfmt->fmt_ch == '.') {
00790 
00791                         GET(pfmt);
00792 
00793                         if (IS_DIGIT(pfmt->fmt_ch)) {
00794 
00795                                 col     = pfmt->fmt_pos; 
00796                                 dsize   = 0;
00797                                 dset    = 0;
00798 
00799                                 GETNUM(pfmt, dsize);
00800 
00801                                 if (dsize > MAX_DECIMAL_FIELD) {
00802                                         fmterr(pfmt, FIELD_TOO_LARGE, FALL, col);
00803                                         dsize   = MAX_DECIMAL_FIELD;
00804                                 }
00805                         }
00806                         else {
00807                                 fmterr(pfmt, EXPECTING_INTEGER, FALL, 0);
00808                                 recover(pfmt);
00809                         }
00810                 }
00811         }
00812         else {
00813 #ifdef  _OLD_ERROR_NUMBERS
00814                 fmterr(pfmt, EXPECTING_INTEGER, FALL, 0);
00815                 recover(pfmt);
00816 #else
00817                 fmterr(pfmt, MISSING_WIDTH_NON_ANSI, FALL, pfmt->fmt_pos); 
00818 #endif
00819         }
00820 
00821         pfmt->pptr->op_code             = op_code;
00822         pfmt->pptr->field_width         = wsize;
00823         pfmt->pptr->digits_field        = dsize;
00824         pfmt->pptr->default_digits      = dset;
00825         pfmt->pptr                      = pfmt->pptr + 1;
00826 
00827         return;
00828 
00829 } /* process_bioz */
00830 
00831 /*
00832  *      process_t()
00833  *
00834  *      Description:    This does semantic checking and generates text for
00835  *                      the Tw, TLw and TRw edit-descriptors.
00836  *
00837  *      Called By:      process_paren_group
00838  *
00839  *      Calls:          nonzero_integer
00840  *
00841  *      Input parameters:
00842  *              pfmt            Parsing information block
00843  *
00844  *      Returns:        Nothing
00845  */
00846 
00847 static void
00848 process_t(
00849         parse_block     *pfmt
00850 )
00851 {
00852         long            size;
00853         register char   ch;
00854 
00855         size    = 0;
00856 
00857         GET(pfmt);
00858 
00859         ch      = toupper(pfmt->fmt_ch);
00860 
00861         if (ch == 'R') {
00862 
00863                 GET(pfmt);
00864 
00865                 if (nonzero_integer(pfmt, &size)) {
00866                         pfmt->pptr->op_code     = TR_ED;
00867                         pfmt->pptr->field_width = size;
00868                         pfmt->pptr              = pfmt->pptr + 1;
00869                 }
00870         }
00871         else
00872                 if (ch == 'L') {
00873 
00874                         GET(pfmt);
00875 
00876                         if (nonzero_integer(pfmt, &size)) {
00877                                 pfmt->pptr->op_code     = TL_ED;
00878                                 pfmt->pptr->field_width = size;
00879                                 pfmt->pptr              = pfmt->pptr + 1;
00880                         }
00881                 }
00882                 else
00883                         if (nonzero_integer(pfmt, &size)) {
00884                                 pfmt->pptr->op_code     = T_ED;
00885                                 pfmt->pptr->field_width = size;
00886                                 pfmt->pptr->rep_count   = 1;
00887                                 pfmt->pptr              = pfmt->pptr + 1;
00888                         }
00889 
00890         return;
00891 
00892 } /* process_t */
00893 
00894 /*
00895  *      process_p()
00896  *
00897  *      Description:    This does semantic checking and generates text for
00898  *                      the P edit-descriptor.  It also checks for the ANSI
00899  *                      comma requirement.
00900  *
00901  *      Called By:      process_paren_group
00902  *                      process_minus
00903  *
00904  *      Calls:          fmterr
00905  *
00906  *      Input parameters:
00907  *              pfmt            Parsing information block
00908  *              scale_factor    The P edit-descriptor scale factor.  Because
00909  *                              the scale_factor is a signed quantity, it is
00910  *                              stored in the rep_count field.
00911  *
00912  *      Returns:        Nothing
00913  */
00914 
00915 static void
00916 process_p(
00917         parse_block     *pfmt,
00918         long            scale_factor
00919 )
00920 {
00921         pfmt->pptr->op_code     = P_ED;
00922         pfmt->pptr->offset      = pfmt->fmt_pos;
00923         pfmt->pptr->rep_count   = scale_factor;
00924         pfmt->pptr              = pfmt->pptr + 1;
00925 
00926         GET(pfmt);
00927 
00928         switch (pfmt->fmt_ch) {
00929                 case ',':
00930                 case 'D':
00931                 case 'E':
00932                 case 'F':
00933                 case 'G':
00934                 case 'd':
00935                 case 'e':
00936                 case 'f':
00937                 case 'g':
00938                 case ')':
00939                 case ':':
00940                 case '/':
00941                 case '\0':
00942                         break;  /* Do Nothing */
00943 
00944                 default:
00945                         fmterr(pfmt, ANSI_COMMA_REQ, FALL, 0);
00946                         break;
00947         } /* switch */
00948 
00949         return;
00950 
00951 } /* process_p */
00952 
00953 /*
00954  *      process_char_string()
00955  *
00956  *      Description:    This does semantic checking of and moves the
00957  *                      character string to the intermediate text.
00958  *
00959  *      Called By:      process_paren_group
00960  *
00961  *      Calls:          fmterr
00962  *
00963  *      Input parameters:
00964  *              pfmt            Parsing information block
00965  *
00966  *      Returns:        Nothing
00967  */
00968 
00969 static void
00970 process_char_string(
00971         parse_block     *pfmt
00972 )
00973 {
00974         char            *str_ptr;
00975         register long    size;
00976 
00977         size    = 0;
00978         str_ptr = (char *) (pfmt->pptr + 1);
00979 
00980         for ( ; ; ) {
00981 
00982                 if (++pfmt->fmt_pos > pfmt->fmt_len) {
00983                         pfmt->fmt_pos   = pfmt->fmt_pos - 1;
00984                         pfmt->fmt_ch    = '\0';
00985                         fmterr(pfmt, NONTERMINATED_LITERAL, FALL, 0);
00986                         break;
00987                 }
00988 
00989                 if (*(++pfmt->fmt_ptr) == pfmt->fmt_ch) {
00990 
00991                         if (pfmt->fmt_pos == pfmt->fmt_len) {
00992                                 pfmt->fmt_ch    = '\0';
00993                                 break;
00994                         }
00995 
00996                         if (*(pfmt->fmt_ptr+1) != pfmt->fmt_ch) {
00997                                 GET(pfmt);
00998                                 break;
00999                         }
01000                         else {
01001                                 pfmt->fmt_pos   = pfmt->fmt_pos + 1;
01002                                 pfmt->fmt_ptr   = pfmt->fmt_ptr + 1;
01003                         }
01004                 }
01005 
01006                 *str_ptr++      = *pfmt->fmt_ptr;
01007                 size            = size + 1;
01008         } /* for */
01009 
01010         pfmt->pptr->op_code     = STRING_ED;
01011         pfmt->pptr->field_width = size;
01012         pfmt->pptr              = pfmt->pptr +
01013                 ((size + FMT_ENTRY_BYTE_SIZE - 1) / FMT_ENTRY_BYTE_SIZE) + 1;
01014 
01015         return;
01016 
01017 } /* process_char_string */
01018 
01019 /*
01020  *      process_minus()
01021  *
01022  *      Description:    This does semantic checking for the use of the '-'
01023  *                      in a format string.
01024  *
01025  *      Called By:      process_paren_group
01026  *
01027  *      Calls:          fmterr
01028  *                      process_p
01029  *
01030  *      Input parameters:
01031  *              pfmt            Parsing information block
01032  *
01033  *      Returns:        FALSE if +/-P, because a comma is not required by
01034  *                      the P edit-descriptor; TRUE otherwise, because a
01035  *                      comma is required.
01036  */
01037 
01038 static short
01039 process_minus(
01040         parse_block     *pfmt
01041 )
01042 {
01043         register short  return_val;
01044         register long   col_m;
01045         register long   col_n;
01046 
01047         return_val      = TRUE;                 /* Assume TRUE */
01048         col_m           = pfmt->fmt_pos;        /* Position of '-' */
01049 
01050         GET(pfmt);
01051 
01052         col_n           = pfmt->fmt_pos;        /* Position of token after '-' */
01053 
01054         if (IS_DIGIT(pfmt->fmt_ch)) {
01055                 register int64  size;
01056                 register char   ch;
01057 
01058                 size    = 0;
01059 
01060                 GETNUM(pfmt, size);
01061 
01062                 ch      = toupper(pfmt->fmt_ch);
01063 
01064                 if (ch == 'P') {
01065 
01066                         pfmt->desc_col  = pfmt->fmt_pos;
01067                         return_val      = FALSE;
01068 
01069                         if (size > MAX_REP_COUNT) {
01070                                 fmterr(pfmt, FIELD_TOO_LARGE, FALL, col_n);
01071                                 size    = MAX_REP_COUNT;
01072                         }
01073 
01074                         process_p(pfmt, (long) -size);
01075                 }
01076                 else
01077                         if (ch == 'X') {
01078 
01079                                 pfmt->desc_col  = pfmt->fmt_pos;
01080 
01081                                 fmterr(pfmt, MINUS_X_NON_ANSI, FALL, col_m);
01082 
01083                                 if (size == 0) {
01084                                         fmterr(pfmt, FIELD_WIDTH_ZERO, FALL,
01085                                                 col_n);
01086                                         size    = 1;
01087                                 }
01088                                 else
01089                                         if (size > MAX_FIELD_WIDTH) {
01090                                                 fmterr(pfmt, FIELD_TOO_LARGE,
01091                                                         FALL, col_n);
01092                                                 size    = MAX_FIELD_WIDTH;
01093                                         }
01094 
01095                                 pfmt->pptr->op_code     = TL_ED;
01096                                 pfmt->pptr->offset      = pfmt->fmt_pos;
01097                                 pfmt->pptr->field_width = size;
01098                                 pfmt->pptr              = pfmt->pptr + 1;
01099 
01100                                 GET(pfmt);
01101                         }
01102                         else {
01103                                 fmterr(pfmt, EXPECTING_P_OR_X, FALL, col_n);
01104                                 recover(pfmt);
01105                         }
01106         }
01107         else {
01108                 fmterr(pfmt, EXPECTING_INTEGER, FALL, col_n);
01109                 recover(pfmt);
01110         }
01111 
01112         return(return_val);
01113 
01114 } /* process_minus */
01115 
01116 /*
01117  *      process_paren_group()
01118  *
01119  *      Description:    This is a recursive routine that processes a
01120  *                      parentheses group and all edit-descriptors in
01121  *                      that group.  Whenever an open parenthesis is
01122  *                      found (which is not immediately followed by a
01123  *                      close parenthesis), this routine calls itself.
01124  *                      It does semantic checking, ANSI checking, creates
01125  *                      a parsed output that is directly usable by the
01126  *                      run-time I/O libraries.  It also performs the
01127  *                      following optimizations:
01128  *
01129  *                      1) Discards empty parentheses groups,
01130  *                      2) Combines edit-descriptors that are alike, such
01131  *                         as: X becomes TR, -X becomes TL, and Hollerith
01132  *                         and character strings become STRING,
01133  *                      3) Changes things like  6(4a3) to 24a3.
01134  *
01135  *      Called By:      process_paren_group
01136  *                      _parsfmt
01137  *
01138  *      Calls:          fmterr
01139  *                      process_arl
01140  *                      process_bioz
01141  *                      process_char_string
01142  *                      process_defg
01143  *                      process_minus
01144  *                      process_p
01145  *                      process_t
01146  *
01147  *      Input parameters:
01148  *              pfmt    Parsing information block
01149  *              ploc    The location of the current open parenthesis
01150  *                      in the parsed format.
01151  *
01152  *      Returns:        The number of edit-descriptors encountered.  If at
01153  *                      least one of the edit-descriptors was a data edit-
01154  *                      descriptor, then the number of edit-descriptors is
01155  *                      negated.
01156  */
01157 
01158 static short
01159 process_paren_group(
01160         parse_block     *pfmt,
01161         fmt_type        *ploc
01162 )
01163 {
01164         register short  comma_req_flag;
01165         register short  data_ed;
01166         register short  found_rep_count;
01167         register short  outer_paren;
01168         register short  num_eds;
01169         register short  op_code;
01170         register short  temp;
01171         register long   num_start;
01172         register long   old_pos;
01173         register int64  repeat_count;
01174         register char   ch;
01175         char            *old_ptr;
01176 
01177         num_eds         = 0;
01178         data_ed         = FALSE;
01179         outer_paren     = (pfmt->pptr == ploc);
01180 
01181         do {    /* for each item in the parentheses group */
01182 
01183                 num_start       = pfmt->fmt_pos;
01184                 pfmt->desc_col  = pfmt->fmt_pos;
01185                 comma_req_flag  = TRUE;
01186                 num_eds         = num_eds + 1;  /* Assume an edit-descriptor */
01187 
01188                 if (IS_DIGIT(pfmt->fmt_ch)) {
01189                         register short  j, k;
01190 
01191                         repeat_count    = 0;
01192                         found_rep_count = TRUE;
01193 
01194                         GETNUM(pfmt, repeat_count);
01195 
01196                         pfmt->desc_col  = pfmt->fmt_pos;
01197 
01198                         /* Check if nonrepeatable edit-descriptor */
01199 
01200                         j       = (((short) pfmt->fmt_ch) >> 6) & 1;
01201                         k       = ((short) pfmt->fmt_ch) & 077;
01202 
01203                         if ((non_repeatable[j] << k) < 0)
01204                                 fmterr(pfmt, INVALID_REP_COUNT, FALL, num_start);
01205                         else {          /* 0P is valid */
01206 
01207                                 ch      = toupper(pfmt->fmt_ch);
01208 
01209                                 if (repeat_count == 0 && ch != 'P') {
01210 
01211                                         if (ch == 'H')
01212                                                 fmterr(pfmt,
01213                                                         ZERO_OR_NO_HOLLERITH_CNT,
01214                                                         FALL, num_start);
01215 
01216                                         /*
01217                                          * Do not issue message for B here
01218                                          * because it may be a BN or BZ edit-
01219                                          * descriptor.  The INVALID_REP_COUNT
01220                                          * error will be issued, if necessary,
01221                                          * when the B edit-descriptor is
01222                                          * processed.
01223                                          */
01224 
01225                                         else
01226                                                 if (ch != 'B')
01227                                                         fmterr(pfmt,
01228                                                                 ZERO_REP_COUNT,
01229                                                                 FALL, num_start);
01230                                 }
01231 
01232                                 /*
01233                                  * Ensure that the repeat count hasn't overflowed.  We
01234                                  * skip this check for the H, X and / edit-descriptors
01235                                  * since they use the repeat count as the field width
01236                                  * and will check it against a different limit.
01237                                  */
01238 
01239                                 if (repeat_count > MAX_REP_COUNT)
01240                                         if (ch != 'X' && ch != 'H' && ch != '/') {
01241                                                 fmterr(pfmt, FIELD_TOO_LARGE,
01242                                                         FALL, num_start);
01243                                                 repeat_count    = MAX_REP_COUNT;
01244                                         }
01245                         } 
01246                 }
01247                 else {  /* not a digit */
01248                         repeat_count    = 1;
01249                         found_rep_count = FALSE;
01250                 }
01251 
01252                 pfmt->pptr->offset      = pfmt->fmt_pos;
01253                 pfmt->pptr->rep_count   = repeat_count;
01254 
01255                 switch (toupper(pfmt->fmt_ch)) {
01256 
01257                         case '(':       /* Start of parentheses group */ 
01258 
01259                                 num_eds                 = num_eds - 1;
01260                                 pfmt->pptr->op_code     = REPEAT_OP;
01261                                 pfmt->pptr              = pfmt->pptr + 1;
01262                                 pfmt->depth             = pfmt->depth + 1;
01263 
01264                                 /*
01265                                  * If level one parentheses group, then
01266                                  * it's a possible reversion point.
01267                                  */
01268 
01269                                 if (pfmt->depth == 1)
01270                                         data_ed = FALSE;
01271 
01272                                 GET(pfmt);
01273 
01274                                 /*
01275                                  * process_paren_group() is called
01276                                  * recursively and returns the number
01277                                  * of edit-descriptors found in the
01278                                  * parentheses group.  The negative
01279                                  * count of edit-descriptors is
01280                                  * returned if at least one of them
01281                                  * is a data edit-descriptor.
01282                                  */
01283 
01284                                 temp    = process_paren_group(pfmt,
01285                                                 pfmt->pptr - 1);
01286 
01287                                 /*
01288                                  * Check if at least one data edit-
01289                                  * descriptor was found.
01290                                  */
01291 
01292                                 if (temp < 0) {
01293                                         data_ed = TRUE;
01294                                         temp    = -temp;
01295                                 }
01296 
01297                                 num_eds = num_eds + temp;
01298                                 break;
01299 
01300                         case 'A':       /* A[w] data edit-descriptor */
01301                                 data_ed = TRUE;
01302                                 process_arl(pfmt, A_ED);
01303                                 break;
01304 
01305                         case 'D':       /* Dw.d[Ee] data edit-descriptor */
01306                                 data_ed = TRUE;
01307                                 process_defg(pfmt, D_ED);
01308                                 break;
01309 
01310                         case 'F':       /* Fw.d data edit-descriptor */
01311                                 data_ed = TRUE;
01312                                 process_defg(pfmt, F_ED);
01313                                 break;
01314 
01315                         case 'I':       /* Iw[.m] data edit-descriptor */
01316                                 data_ed = TRUE;
01317                                 process_bioz(pfmt, I_ED);
01318                                 break;
01319 
01320                         case 'X':       /* nX control edit-descriptor */
01321 
01322                                 if (!found_rep_count)
01323                                         fmterr(pfmt, NON_ANSI_EDIT_DESCRIPTOR,
01324                                                 FALL, 0);
01325                                 else
01326                                         if (repeat_count > MAX_FIELD_WIDTH) {
01327                                                 fmterr(pfmt, FIELD_TOO_LARGE,
01328                                                         FALL, num_start);
01329                                                 repeat_count    = MAX_FIELD_WIDTH;
01330                                         }
01331 
01332                                 pfmt->pptr->op_code     = TR_ED;
01333                                 pfmt->pptr->field_width = repeat_count;
01334                                 pfmt->pptr->rep_count   = 1;
01335                                 pfmt->pptr              = pfmt->pptr + 1;
01336 
01337                                 GET(pfmt);
01338                                 break;
01339 
01340                         case 'H':       /* nHc[c] string edit-descriptor */
01341                                 fmterr(pfmt, H_IS_OBSOLETE_IN_F90, F90, 0);
01342                                 fmterr(pfmt, NON_ANSI_EDIT_DESCRIPTOR, F95, 0);
01343 
01344                                 if (found_rep_count) {
01345                                         register int    left;
01346 
01347                                         if (repeat_count > MAX_FIELD_WIDTH) {
01348                                                 fmterr(pfmt, FIELD_TOO_LARGE,
01349                                                         FALL, num_start);
01350                                                 repeat_count    = MAX_FIELD_WIDTH;
01351                                         }
01352 
01353                                         left    = pfmt->fmt_len - pfmt->fmt_pos;
01354 
01355                                         if (repeat_count > left)
01356                                                 repeat_count    = (int64) left;
01357 
01358                                         pfmt->pptr->op_code     = STRING_ED;
01359                                         pfmt->pptr->field_width = repeat_count;
01360                                         pfmt->pptr->rep_count   = 1;
01361                                         pfmt->pptr              = pfmt->pptr + 1;
01362 
01363                                         (void) strncpy((char *) pfmt->pptr,
01364                                                 pfmt->fmt_ptr + 1, (int) repeat_count);
01365 
01366                                         pfmt->pptr      = pfmt->pptr + 1 +
01367                                                 ((repeat_count - 1) / FMT_ENTRY_BYTE_SIZE);
01368                                         pfmt->fmt_ptr   = pfmt->fmt_ptr + repeat_count;
01369                                         pfmt->fmt_pos   = pfmt->fmt_pos + repeat_count;
01370 
01371                                         GET(pfmt);
01372 
01373                                         if (pfmt->fmt_ch == '\0')
01374                                                 fmterr(pfmt, NONTERMINATED_LITERAL,
01375                                                         FALL, 0);
01376                                 }
01377                                 else {
01378                                         fmterr(pfmt, ZERO_OR_NO_HOLLERITH_CNT,
01379                                                 FALL, num_start);
01380                                         recover(pfmt);
01381                                 }
01382                                 break;
01383 
01384                         case '*':       /* *[c]* string edit-descriptor */
01385                         case '"':       /* "[c]" string edit-descriptor */
01386                                 fmterr(pfmt, NON_ANSI_EDIT_DESCRIPTOR, FALL, 0);
01387 
01388                         /* Break intentionally omitted - should fall through */
01389 
01390                         case '\'':      /* '[c]' string edit-descriptor */
01391                                 process_char_string(pfmt);
01392                                 break;
01393 
01394                         case 'G':       /* Gw.d[Ee] data edit-descriptor */
01395                                 data_ed = TRUE;
01396                                 process_defg(pfmt, G_ED);
01397                                 break;
01398 
01399                         case 'E':       /* Ew.d[Ee], ESw.d[Ee] or ENw.d[Ee]
01400                                                 data edit-descriptors */
01401                                 data_ed = TRUE;
01402                                 op_code = E_ED;
01403                                 old_pos = pfmt->fmt_pos;
01404                                 old_ptr = pfmt->fmt_ptr;
01405 
01406                                 GET(pfmt);
01407 
01408                                 ch      = toupper(pfmt->fmt_ch);
01409 
01410                                 if (ch == 'N' || ch == 'S') {
01411 
01412                                         fmterr(pfmt, NON_ANSI_EDIT_DESCRIPTOR,
01413                                                 F77, old_pos);
01414 
01415                                         op_code = (ch == 'N') ? EN_ED : ES_ED;
01416 
01417                                 }
01418                                 else {  /* Back up */
01419                                         pfmt->fmt_pos   = old_pos;
01420                                         pfmt->fmt_ptr   = old_ptr;
01421                                 }
01422 
01423                                 process_defg(pfmt, op_code);
01424                                 break;
01425 
01426                         case 'B':       /* Bw[.m] data edit-descriptor or BN or
01427                                                 BZ control edit-descriptors */
01428 
01429                                 old_pos = pfmt->fmt_pos;
01430                                 old_ptr = pfmt->fmt_ptr;
01431 
01432                                 GET(pfmt);
01433 
01434                                 ch      = toupper(pfmt->fmt_ch);
01435 
01436                                 if (ch == 'N' || ch == 'Z') {
01437 
01438                                         if (found_rep_count)
01439                                                 fmterr(pfmt, INVALID_REP_COUNT,
01440                                                         FALL, num_start);
01441 
01442                                         pfmt->pptr->op_code     = (ch == 'N') ?
01443                                                                 BN_ED : BZ_ED;
01444                                         pfmt->pptr              = pfmt->pptr + 1;
01445 
01446                                         GET(pfmt);
01447                                 }
01448                                 else {
01449                                         if (repeat_count == 0)
01450                                                 fmterr(pfmt, ZERO_REP_COUNT,
01451                                                         FALL, num_start);
01452 
01453                                         /* Back up */
01454 
01455                                         pfmt->fmt_pos   = old_pos;
01456                                         pfmt->fmt_ptr   = old_ptr;
01457 
01458                                         fmterr(pfmt, NON_ANSI_EDIT_DESCRIPTOR,
01459                                                 F77, 0);
01460 
01461                                         data_ed = TRUE;
01462                                         process_bioz(pfmt, B_ED);
01463                                         break;
01464                                 }
01465                                 break;
01466 
01467                         case 'R':       /* Rw data edit-descriptor */
01468                                 data_ed = TRUE;
01469                                 fmterr(pfmt, NON_ANSI_EDIT_DESCRIPTOR, FALL, 0);
01470                                 process_arl(pfmt, R_ED);
01471                                 break;
01472 
01473                         case 'L':       /* Lw data edit-descriptor */
01474                                 data_ed = TRUE;
01475                                 process_arl(pfmt, L_ED);
01476                                 break;
01477 
01478                         case 'P':       /* nP control edit-descriptor */
01479                                 if (!found_rep_count)
01480                                         fmterr(pfmt, EXPECTING_INTEGER, FALL,
01481                                                         0);
01482 
01483                                 process_p(pfmt, (long) repeat_count);
01484                                 comma_req_flag  = FALSE;
01485                                 break;
01486 
01487                         case 'O':       /* Ow[.m] data edit-descriptor */
01488                                 data_ed = TRUE;
01489                                 fmterr(pfmt, NON_ANSI_EDIT_DESCRIPTOR, F77, 0);
01490                                 process_bioz(pfmt, O_ED);
01491                                 break;
01492 
01493                         case 'Z':       /* Zw[.m] data edit-descriptor */
01494                                 data_ed = TRUE;
01495                                 fmterr(pfmt, NON_ANSI_EDIT_DESCRIPTOR, F77, 0);
01496                                 process_bioz(pfmt, Z_ED);
01497                                 break;
01498 
01499                         case '/':       /* [n]/ control edit-descriptor */
01500                                 if (found_rep_count) {
01501 
01502                                         if (repeat_count > MAX_FIELD_WIDTH) {
01503                                                 fmterr(pfmt, FIELD_TOO_LARGE,
01504                                                         FALL, num_start);
01505                                                 repeat_count    = MAX_FIELD_WIDTH;
01506                                         }
01507 
01508                                         fmterr(pfmt, REP_SLASH_NON_ANSI,
01509                                                 F77, num_start);
01510                                 }
01511 
01512                                 pfmt->pptr->op_code     = SLASH_ED;
01513                                 pfmt->pptr->field_width = repeat_count;
01514                                 pfmt->pptr->rep_count   = 1;
01515                                 pfmt->pptr              = pfmt->pptr + 1;
01516 
01517                                 comma_req_flag          = FALSE;
01518 
01519                                 GET(pfmt);
01520                                 break;
01521 
01522                         case '+': /* '+' valid only before P edit-descriptor */
01523                                 GET(pfmt);
01524 
01525                                 if (IS_DIGIT(pfmt->fmt_ch)) {
01526                                         register int64  size;
01527 
01528                                         size            = 0;
01529                                         num_start       = pfmt->fmt_pos;
01530 
01531                                         GETNUM(pfmt, size);
01532 
01533                                         if (toupper(pfmt->fmt_ch) == 'P') {
01534 
01535                                                 pfmt->desc_col  = pfmt->fmt_pos;
01536 
01537                                                 if (size > MAX_REP_COUNT) {
01538                                                         fmterr(pfmt, FIELD_TOO_LARGE,
01539                                                                 FALL, num_start);
01540                                                         size    = MAX_REP_COUNT;
01541                                                 }
01542 
01543                                                 process_p(pfmt, (long) size);
01544 
01545                                                 comma_req_flag  = FALSE;
01546                                                 break;  /*  Good exit */
01547                                         }
01548 
01549                                         fmterr(pfmt, EXPECTING_P_OR_X, FALL, 0);
01550                                 }
01551                                 else
01552                                         fmterr(pfmt, EXPECTING_INTEGER, FALL, 0);
01553 
01554                                 recover(pfmt);
01555                                 break;
01556 
01557                         case '-':       /* '-' valid only before P or X edit-
01558                                                 descriptors */
01559                                 comma_req_flag  = process_minus(pfmt);
01560                                 break;
01561 
01562                         case ':':       /* : control edit-descriptor */
01563                                 pfmt->pptr->op_code     = COLON_ED;
01564                                 pfmt->pptr              = pfmt->pptr + 1;
01565 
01566                                 GET(pfmt);
01567 
01568                                 comma_req_flag          = FALSE;
01569                                 break;
01570 
01571                         case 'Q':       /* Q control edit-descriptor */
01572                                 fmterr(pfmt, NON_ANSI_EDIT_DESCRIPTOR, FALL, 0);
01573 
01574                                 pfmt->pptr->op_code     = Q_ED;
01575                                 pfmt->pptr              = pfmt->pptr + 1;
01576 
01577                                 GET(pfmt);
01578 
01579                                 comma_req_flag          = FALSE;
01580                                 data_ed                 = TRUE; 
01581                                 break;
01582 
01583                         case '$':       /* $ control edit-descriptor */
01584                         case '\\':      /* \ control edit-descriptor */
01585                                 fmterr(pfmt, NON_ANSI_EDIT_DESCRIPTOR, FALL, 0);
01586 
01587                                 pfmt->pptr->op_code     = DOLLAR_ED;
01588                                 pfmt->pptr              = pfmt->pptr + 1;
01589 
01590                                 GET(pfmt);
01591 
01592                                 comma_req_flag          = FALSE;
01593                                 break;
01594 
01595                         case 'S': /* S, SP or SS control edit-descriptor */
01596                                 GET(pfmt);
01597 
01598                                 ch      = toupper(pfmt->fmt_ch);
01599 
01600                                 if (ch == 'S' || ch == 'P') {
01601                                         op_code = (ch == 'S') ? SS_ED : SP_ED;
01602                                         GET(pfmt);
01603                                 }
01604                                 else
01605                                         op_code = S_ED;
01606 
01607                                 pfmt->pptr->op_code     = op_code;
01608                                 pfmt->pptr              = pfmt->pptr + 1;
01609                                 break;
01610 
01611                         case 'T': /* T, TL or TR control edit-descriptor */
01612                                 process_t(pfmt);
01613                                 break;
01614 
01615 #ifndef _OLD_ERROR_NUMBERS
01616                         case ',': /* No edit descriptor, issue warning */
01617                                 fmterr(pfmt, NON_ANSI_NULL_DESCRIPTOR, FALL, 0);
01618                                 GET(pfmt);
01619 
01620                                 comma_req_flag          = FALSE;
01621                                 break;
01622 #endif
01623 
01624                         case ')':       /* End of parentheses group */
01625                                 num_eds = num_eds - 1;
01626 
01627                                 if (num_eds == 0 && !outer_paren)
01628                                         fmterr(pfmt, ANSI_EMPTY_PAREN_MSG,
01629                                                         FALL, 0);
01630                                 break;
01631 
01632                         case '\0':      /* Oops, premature end of format */
01633                                 fmterr(pfmt, EXPECTING_RIGHT_PAREN, FALL, 0);
01634                                 return(0);
01635 
01636                         default:        /* Unknown edit-descriptor */
01637                                 fmterr(pfmt, UNKNOWN_EDIT_DESCRIPTOR, FALL, 0);
01638                                 recover(pfmt);
01639                                 break;
01640 
01641                 } /* switch */
01642 
01643                 if (pfmt->fmt_ch == ',') {
01644                         register long   col;
01645 
01646                         col     = pfmt->fmt_pos;        /* Position of comma */
01647 
01648                         GET(pfmt);
01649 
01650                         if (pfmt->fmt_ch == ')') {
01651                                 pfmt->desc_col  = col;
01652                                 fmterr(pfmt, COMMA_NON_ANSI, FALL, col);
01653                         }
01654                 }
01655                 else
01656                         if (comma_req_flag)
01657                                 switch (pfmt->fmt_ch) {
01658 
01659                                         case ')':
01660                                         case ':':
01661                                         case '/':
01662                                         case '\0':
01663                                                 break;
01664 
01665                                         default:
01666                                                 fmterr(pfmt, ANSI_COMMA_REQ,
01667                                                         FALL, 0);
01668                                                 break;
01669                                 } /* switch */
01670 
01671                 if (pfmt->fatal_err && pfmt->caller == LIB_CALL)
01672                         return(0);
01673 
01674         } while (pfmt->fmt_ch != ')');
01675 
01676         if (outer_paren) {                      /* End of format found */
01677                 pfmt->pptr->op_code     = REVERT_OP;
01678                 pfmt->pptr->rep_count   = pfmt->revert - pfmt->pptr;
01679                 pfmt->pptr->offset      = pfmt->fmt_pos;
01680                 pfmt->pptr->rgcdedf     = data_ed;
01681                 pfmt->pptr              = pfmt->pptr + 1;
01682         }
01683         else {
01684 
01685         /*
01686          * End of internal parentheses group.  Try to simplify the parsed
01687          * format by attempting to coalesce entries.  Entries are coalesced
01688          * if one of the following conditions applies:
01689          *
01690          * 1) Empty or redundant parentheses groups.  Constructs of the form:
01691          *    '...()...' or '((...))' can be removed or simplified in the
01692          *    parsed format.
01693          *
01694          * 2) Singly-repeated parentheses group.  Constructs of the form:
01695          *    '(...)' or '1(...)' can be simplified to '...'.
01696          *
01697          * 3) Single edit-descriptor parentheses group.  Constructs of the
01698          *    form:  '...n(e)...' or '...n(m(e))...', where 'e' is any single
01699          *    edit-descriptor and 'n' and 'm' are repetition counts, can be
01700          *    simplified to '...ne...' or '...n*me...', respectively.
01701          *
01702          *    a) If the single edit-descriptor is a P, BN, BZ, S, SP, SS, :
01703          *       or $ descriptor, the repeat count is ignored.  So a format
01704          *       of the form:  '...15(BZ)...' becomes '...BZ...'.
01705          *
01706          *    b) If the single edit-descriptor is a TL, TR, T or X edit-
01707          *       descriptor, the repeat count is folded into the count (width)
01708          *       field.  So a format of the form:  '...4(5X)...' becomes
01709          *       '...20X...'.
01710          *
01711          *    c) For all other edit-descriptors, the repeat count is folded
01712          *       into the existing repeat count.  So a format of the form:
01713          *       '...3(4F9.2)...' becomes '...12F9.2...'.
01714          *
01715          * Entries are NOT coalesced if their combined rep_count fields would
01716          * exceed the maximum possible rep_count.  Note that any possible
01717          * reversion point must be marked before a parentheses group is removed.
01718          *
01719          * Note that two adjacent identical edit descriptors which do not span
01720          * a reversion point could be coalesced (e.g., 'I8,I8' to '2I8'); but
01721          * in this case the offset field would be incorrect for some of the
01722          * coalesced edit descriptors.  If a run-time error occurred while
01723          * processing one of those edit descriptors the run-time diagnostic
01724          * might point at the wrong edit descriptor.
01725          */
01726 
01727                 if (pfmt->depth == 1)
01728                         pfmt->revert    = ploc; /* Mark possible reversion point */
01729 
01730                 if (ploc + 1 == pfmt->pptr && ploc->op_code == REPEAT_OP) {
01731 
01732                         /* Clear empty parentheses group and remove it */
01733 
01734                         pfmt->pptr      = pfmt->pptr - 1;
01735 
01736                         (void) memset((void *) pfmt->pptr, 0, 2 * sizeof(fmt_type));
01737 
01738                 }
01739                 else {
01740 
01741                         if ((num_eds == 1 ||    /* If one edit-descriptor or */
01742                             (ploc->op_code == REPEAT_OP &&
01743                              ploc->rep_count == 1) ) && /* Unary repeat count */
01744                             ploc->rep_count * (ploc+1)->rep_count <
01745                                 MAX_REP_COUNT) {
01746 
01747                                 unsigned int    size;
01748                                 fmt_type        *ppsp;
01749 
01750                                 /* Coalesce entries */
01751 
01752                                 pfmt->pptr      = pfmt->pptr - 1;
01753                                 ppsp            = ploc + 1;
01754 
01755                                 switch (ppsp->op_code) {
01756 
01757                                         case P_ED:
01758                                         case BN_ED:
01759                                         case BZ_ED:
01760                                         case COLON_ED:
01761                                         case S_ED:
01762                                         case SP_ED:
01763                                         case SS_ED:
01764                                         case T_ED:
01765                                         case DOLLAR_ED:
01766 
01767                                                 /* Simply ignore rep_count */
01768 
01769                                                 break;
01770 
01771                                         case SLASH_ED:
01772                                         case TL_ED:
01773                                         case TR_ED:
01774 
01775                                                 /*
01776                                                  * Fold rep_count into width,
01777                                                  * if it'll fit.
01778                                                  */
01779 
01780                                                 size    = ploc->rep_count *
01781                                                           ppsp->field_width;
01782 
01783                                                 if (size < MAX_FIELD_WIDTH) {
01784                                                         ppsp->field_width       =
01785                                                                 size;
01786                                                         ppsp->rep_count = 1;
01787                                                 }
01788                                                 else /* Fold into rep_count */
01789                                                         ppsp->rep_count =
01790                                                                 ppsp->rep_count *
01791                                                                 ploc->rep_count;
01792 
01793                                                 break;
01794 
01795                                         default:
01796 
01797                                                 /* Cascade rep_counts */
01798 
01799                                                 ppsp->rep_count =
01800                                                         ppsp->rep_count *
01801                                                         ploc->rep_count;
01802                                                 break;
01803 
01804                                 } /* switch (ppsp->op_code) */
01805 
01806                                 /* Move entries */
01807 
01808                                 (void) memmove((void *) ploc, (void *) ppsp,
01809                                                 (pfmt->pptr - ploc) * sizeof(fmt_type));
01810 
01811                                 /* Clear vacated entries */
01812 
01813                                 (void) memset((void *) pfmt->pptr, 0, 2 * sizeof(fmt_type));
01814 
01815                         }
01816                         else {
01817                                 pfmt->pptr->op_code     = ENDREP_OP;
01818                                 pfmt->pptr->rep_count   = ploc - pfmt->pptr;
01819                                 pfmt->pptr->offset      = pfmt->fmt_pos;
01820                                 pfmt->pptr              = pfmt->pptr + 1;
01821 
01822                                 if (pfmt->maxdepth < pfmt->depth)
01823                                         pfmt->maxdepth  = pfmt->depth;
01824                         }
01825                 }
01826         }
01827 
01828         pfmt->depth     = pfmt->depth - 1;
01829 
01830         GET(pfmt);
01831 
01832         if (data_ed)
01833                 num_eds = -num_eds;
01834 
01835         return(num_eds);
01836 
01837 } /* process_paren_group */

Generated on Tue Nov 17 05:54:42 2009 for Open64 (mfef90, whirl2f, and IR tools) by  doxygen 1.6.1