Menu ▾ ▴

#873 Error when redefining a lower level element in relaxed hierarchy

unclassified
open
nobody
None
5 - default
2023-02-20
2023-02-19
Chris G
No

In the relax level hierarchy (-frelax-level-hierarchy) mode, it should be possible to redifine a level that previously appeared with a lower level number "on the same level". This is available at least in IBM COBOL.

Minimal example:

       IDENTIFICATION DIVISION.
       PROGRAM-ID.  RELAX-REDEFINE.
       DATA DIVISION.
       WORKING-STORAGE SECTION. 
       01 WS-A.
          03 WS-B.
             04 FILLER  PIC X.
          02 WS-C REDEFINES WS-B. *> 02 redefines 03 level.
             10 FILLER     PIC X.
       PROCEDURE DIVISION.
           MOVE 'A' TO WS-B
           DISPLAY WS-C
           GOBACK.
       END PROGRAM RELAX-REDEFINE.

We have already investigated the bug and found a possible solution, but a more detailed investigation of the proposed solution is still pending. The diff of the proposal will follow in the close future.

Discussion

  • Chris G

    Chris G - 2023-02-20

    In the current GnuCOBOL (3.2-rc2) implementation (field.c#540) for the event of

           01 WS-A.
              03 WS-B PIC X.
             02 WS-C PIC X.
    

    with relaxed level hierarchy, the tree is transformed to

           01 WS-A.
             02 "FILLER 1".
              03 WS-B PIC X.
             02 WS-C PIC X.
    

    in order to keep the level numbers. This leads to a problem in the moment of redefining WS-B from WS-C, because WS-C cannot find it on the same tree level anymore. Our proposed solution does not add the additional "FILLER 1", instead it transforms the tree to represent

           01 WS-A.
             02 WS-B PIC X.
             02 WS-C PIC X.
    

    This way WS-B can be reached from WS-C, although some level numbers are changed. However, this should not lead to any problems, since if there were an 02-level above WS-B, WS-C should not be able to redefine WS-B (same situation as with "FILLER 1", but this time intended and not valid).

    One could discuss whether it is necessary to change the level numbers at all, since one could theoretically also set WS-B->sister to WS-C and slightly adjust the "if for the same level numbers in REDEFINES", but this could bring possible (later) problems, since in the datastructure tree two elements are on the same tree level, but not on the same COBOL level.

     

    Last edit: Chris G 2023-02-20
    • Simon Sobisch

      Simon Sobisch - 2023-02-20

      What about:

             01 WS-A.
                03 WS-B PIC X.
                03 WS-B2 PIC X.
                03 WS-B3 PIC X.
                03 WS-B4 PIC X.
               02 WS-C PIC X.
      

      ?

      Currently we include a single filler which solves the problem, but I guess you now move all WS-Bs to the level 02, right?

      It seems that all you really want is to prevent the error

      level number of REDEFINES entries must be identical

      right?

      In this case the explicit check in field.c around line 660 is the one to adjust, possibly depending on cb_indirect_redefines and/or cb_relax_level_hierarchy, no?

       
      • Chris G

        Chris G - 2023-02-20

        Exactly, in this case we would raise all WS-B* to 02. We also looked at cb_indirect_redefines, but that is a different setting. Indirect redefines allows A to be redefined by B and B by C (so a kind of chain of redefinitions). So something like this:

               01 A PIC X.
               01 B REDEFINES A PIC X.
               01 C REDEFINES B PIC X.
        

        The problem with field#652-660 and why we adjusted it in the other place is that at field#660 one no longer has information about the fact that "FILLER 1" was inserted by cobc and not by the user (at least we had not seen any source of information).
        For example a user might write

               01 WS-A.
                 02 FILLER.
                  03 WS-B       PIC X.
                 02 WS-C        REDEFINES WS-B PIC X.
        

        which should result in an error, but only if the user inserted the FILLER, not if cobc inserted it. So we figured, instead of creating a complex decision tree there, we look at where the filler level is inserted.

         
  • Simon Sobisch

    Simon Sobisch - 2023-02-20

    Are you sure that

           01 WS-A.
             02 FILLER.
              03 WS-B       PIC X.
             02 WS-C        REDEFINES WS-B PIC X.
    

    results in an error with IBM, but

           01 WS-A2.
              03 WS-B2       PIC X.
             02 WS-C2        REDEFINES WS-B2 PIC X.
    

    doesn't? Sigh, at least that's the case with MicroFocus, the second compiles but the first raises:

        21   02 WS-C        REDEFINES WS-B PIC X.
    
    * 204-S*******************************                                       **
    **    REDEFINES on incorrect field
    

    The problem with field#652-660 and why we adjusted it in the other place is that at field#660 one no longer has information about the fact that "FILLER 1" was inserted by cobc and not by the user (at least we had not seen any source of information).

    I see. One thing that would be possible and may be useful in any case (also for the other places where we build an "internal filler" is to add a flag_internal_field to cb_field; and use f->parent->flag_internal_field to decide about the error message.

     
    • Chris G

      Chris G - 2023-02-20

      Yeah, the first example results in an error:

      IGYDS1066-S "REDEFINES" object "WS-B" was not the immediately preceding level-2 data
                  item.  The "REDEFINES" clause was discarded.
      

      whereas the second doesn't... I reacted the same way when we tried that out.

      One thing that would be possible and may be useful in any case (also for the other places where we build an "internal filler" is to add a flag_internal_field to cb_field

      I agree, such a flag would probably be useful for future references. I did a little digging in the code and cb_build_filler is called a few times, although I stumbled upon a few more places where cobc builds a tree without fillers (e.g. cb_build_debug_item or cb_validate_program_data), would they qualify as flag_internal_field = 1 too? There are some obvious places where cobc adds/builds an additional tree (parser.y#7711), but there are also some places which represent a huge call hierarchy maybe returning FILLER (e.g. cb_name_1, whereas I don't know where the result of this would be used in). I don't know if the effort would be worth it to implement the flag properly or having a "mostly unused flag".

      Although I (personally) don't like the "changing the level numbers" method in our proposal, I think it won't break anything, since it only effects this (admittedly weird usage: redefining with relaxed level hierarchy) situation.

       

Log in to post a comment.