Problem solve Get help with specific problems with your technologies, process and projects.

Show nesting in ABAP code

Copy and paste the attached function module-code to create a utility to show you how your ABAP is nested.

Copy and paste the attached function module-code to create a utility to show you how your ABAP is nested. Your code should NOT start in column 1 and Pretty Printer indentation is expected.

Shown below is:
1) Sample output
2) Function module
3) Sample program to invoke function module

Type ZCDF_T_PGM_TEXT is a table type definition, standard table, default key, with structure ZCDF_PGM_TEXT that has a single field called txt that is character, length 80.

The code was written in 4.6C. 4.7 users might want to add the TRY command.

Question/comments? I can be reached at cfolwell@csc.com.
1) 
FORM any_form.
  IF this = true.
  | CASE x.
  | ] WHEN '1'.
  | ] WHEN '2'.
  | ] [ statement.
  | ] [ IF that = true.
  | ] [ } statement.
  | ] [ } statement.
  | ] [ } statement.
  | ] [ } CASE t.
  | ] [ } { WHEN OTHERS.
  | ] [ } ENDCASE.
  | ] [ ENDIF.
  | ] WHEN '3'.
  | ] [ statement.
  | ] [ statement.
  | ] WHEN OTHERS.
  | ENDCASE.
  ENDIF.
ENDFORM.

2)
FUNCTION z_cdf_lineup_commands .
*"----------------------------------------------------------------------
*"*"Local interface:
*"  IMPORTING
*"     VALUE(IP_LINEUP_TXT) TYPE  C DEFAULT '|][}{'
*"  CHANGING
*"     REFERENCE(CP_PGM_TEXT) TYPE  ZCDF_T_PGM_TEXT
*"----------------------------------------------------------------------

  DATA:
    lw_nest_ind(1)     TYPE c, "nest character needed?
    lw_overlay_txt(80) TYPE c, "line of nesting markings
    lw_txt_len_num     TYPE i, "length of marking chars
    lw_char_ofs_num    TYPE i, "offset of nesting character to use
    lw_cmnd_ofs_num    TYPE i, "offset of SAP command of interest
    lw_deep_num        TYPE i. "how many nested levels deep?

  FIELD-SYMBOLS:
    <l_pgm_line> TYPE zcdf_pgm_text.

* Find first space, then sy-fdpos tells length of data.

  IF ip_lineup_txt CA '# #'.

    lw_txt_len_num = sy-fdpos.

  ELSE.  "no blanks

    DESCRIBE FIELD ip_lineup_txt
      LENGTH lw_txt_len_num.

  ENDIF.

* LOOP thru program text and add nesting markings.

  LOOP AT cp_pgm_text
    ASSIGNING <l_pgm_line>.

*   Avoid comment lines.

    IF <l_pgm_line>-txt(1) NE '*'.

*     Find first command on line.
*      Only a single comand per line
*      The command cannot start in column 1, must be
*      in a processing block.

      IF <l_pgm_line>-txt CS ' IF '        OR
         <l_pgm_line>-txt CS ' CASE '      OR
         <l_pgm_line>-txt CS ' LOOP '      OR
         <l_pgm_line>-txt CS ' LOOP. '     OR
         <l_pgm_line>-txt CS ' SELECT '    OR
         <l_pgm_line>-txt CS ' CATCH '     OR
         <l_pgm_line>-txt CS ' DEFINE '    OR
         <l_pgm_line>-txt CS ' TRY '       OR
         <l_pgm_line>-txt CS ' BEGIN OF '  OR
         <l_pgm_line>-txt CS ' WHILE '.

*       Save offset of the command without leading space.

        lw_cmnd_ofs_num = sy-fdpos + 1.

*       Avoid command in a line ending comment.  First get the offset
*        of the start of the comment if any.  If found, sy-fdpos
*        will contain the offset.  If not found, sy-fdpos is set
*        to the length of the text.

        IF <l_pgm_line>-txt CS '"'.
        ENDIF.

*       Only continue if the command was found before the ".

        IF lw_cmnd_ofs_num < sy-fdpos.

          lw_nest_ind = 'X'.

*         Special handling for SELECT.  Some versions of SELECT are
*          NOT loops, for example SELECT SINGLE and
*          SELECT...INTO TABLE.  If not a loop, then no nesting
*          mark required.

          IF <l_pgm_line>-txt+lw_cmnd_ofs_num(6) = 'SELECT'.

            lw_nest_ind = space.

            PERFORM check_select_command
              USING cp_pgm_text
                    sy-tabix
              CHANGING lw_nest_ind.

          ENDIF.

*         Add nesting character if needed.

          IF lw_nest_ind = 'X'.

            lw_deep_num      = lw_deep_num + 1.
            lw_char_ofs_num  = ( lw_deep_num - 1 ) MOD lw_txt_len_num.

*           If the offset has become negative,
*            something strange has happened.  For example, this can
*            happen if IFs are not indented properly.
*            Avoid negative offsets.

            IF lw_char_ofs_num < 0.
              lw_char_ofs_num = 0.
            ENDIF.

*           Set marking in overlay line.

            lw_overlay_txt+lw_cmnd_ofs_num(1) =
              ip_lineup_txt+lw_char_ofs_num(1).

*           Special handling for CASE.  WHEN must follow so provide for
*            a marking of WHEN.

            IF <l_pgm_line>-txt+lw_cmnd_ofs_num(4) = 'CASE'.

              lw_deep_num      = lw_deep_num + 1.
              lw_char_ofs_num  = ( lw_deep_num - 1 ) MOD lw_txt_len_num.

*             If the offset has become negative,
*              something strange has happened.  For example, this can
*              happen if IFs are not indented properly.
*              Avoid negative offsets.

              IF lw_char_ofs_num < 0.
                lw_char_ofs_num = 0.
              ENDIF.

*             Set marking in overlay line for upcoming WHEN statement.
*              Assumption is that indentation is 2 characters.

              lw_cmnd_ofs_num = lw_cmnd_ofs_num + 2.

              lw_overlay_txt+lw_cmnd_ofs_num(1) =
                ip_lineup_txt+lw_char_ofs_num(1).

            ENDIF.

          ENDIF.

        ENDIF.

      ENDIF.

*     Now check for ending commands.
*      Starting and ending commands on the same line are supported.
*      Multiple commands on a line are not supported.

      IF <l_pgm_line>-txt CS ' ENDIF. '              OR
         <l_pgm_line>-txt CS ' ENDCASE. '            OR
         <l_pgm_line>-txt CS ' ENDLOOP. '            OR
         <l_pgm_line>-txt CS ' ENDSELECT. '          OR
         <l_pgm_line>-txt CS ' ENDCATCH. '           OR
         <l_pgm_line>-txt CS ' ENDTRY. '             OR
         <l_pgm_line>-txt CS ' END-OF_DEFINITION. '  OR
         <l_pgm_line>-txt CS ' END OF '              OR
         <l_pgm_line>-txt CS ' ENDWHILE. '.

*       Save offset of the command without leading space.

        lw_cmnd_ofs_num = sy-fdpos + 1.

*       Avoid ending command in a line ending comment.

        IF <l_pgm_line>-txt CS '"'.
        ENDIF.

*       Only continue if the ending command was found before the ".

        IF lw_cmnd_ofs_num < sy-fdpos.

*         Find the current end of the overlay line.

          IF lw_overlay_txt CP '*# '.

            lw_char_ofs_num = sy-fdpos - 1.

*           Something strange has happened.  Avoid negative offsets.

            IF lw_char_ofs_num < 0.
              lw_char_ofs_num = 0.
            ENDIF.

*           Remove marking (+ everything to the right)
*            from overlay line.

            lw_overlay_txt+lw_char_ofs_num = space.

            lw_deep_num = lw_deep_num - 1.

*           Special handling for ENDCASE. When CASE found, both
*            CASE and WHEN were marked. Now for ENDCASE, undo
*            mark for both CASE and WHEN.

            IF <l_pgm_line>-txt+lw_cmnd_ofs_num(7) = 'ENDCASE'.

*             Find current end of overlay line.

              IF lw_overlay_txt CP '*# '.

                lw_char_ofs_num = sy-fdpos - 1.

*               Something strange has happened.  Avoid negative offsets.

                IF lw_char_ofs_num < 0.
                  lw_char_ofs_num = 0.
                ENDIF.

*               Remove marking (+ everything to the right)
*                from overlay

                lw_overlay_txt+lw_char_ofs_num = space.

                lw_deep_num = lw_deep_num - 1.

              ENDIF.

            ENDIF.

          ENDIF.

        ENDIF.

      ENDIF.

    ENDIF.

*   Insert nesting marks into source code.

    OVERLAY <l_pgm_line>-txt WITH lw_overlay_txt.

  ENDLOOP.

ENDFUNCTION.

*---------------------------------------------------------------------*
*      Form  check_select_command
*
*       Check if a SELECT command is initiating a loop
*       requiring ENDSELECT
*
*       Input Parameters -
*         ipt_pgm_text   - Program Text;passed by ref to avoid copying
*         ip_tabix       - Index in table where SELECT was found
*       Changing Parameters -
*         cp_nest_ind    - 'X' indicates SELECT starts a loop
*----------------------------------------------------------------------*

FORM check_select_command
  USING ipt_pgm_text    TYPE zcdf_t_pgm_text
        value(ip_tabix) TYPE sy-tabix
  CHANGING cp_nest_ind  TYPE c.

  DATA:
    l_period_ind  TYPE zgn_ind,
    l_fdpos       TYPE sy-fdpos,
    lwa_pgm_text  TYPE zcdf_pgm_text,
    l_select_txt  TYPE string.

  cp_nest_ind  = space.
  l_period_ind = space.

  LOOP AT ipt_pgm_text
    FROM ip_tabix
    INTO lwa_pgm_text.

*   Avoid comment lines.

    CHECK lwa_pgm_text-txt(1) NE '*'.

*   Eliminate any line ending comment.

    IF lwa_pgm_text-txt CS '"'.
    ENDIF.

    IF sy-fdpos NE 0 AND sy-fdpos LE 79.
      lwa_pgm_text-txt+sy-fdpos = space.
    ENDIF.

*   If ending period found, eliminate anything after the period.

    IF lwa_pgm_text-txt CS '.'.
    ENDIF.

    IF sy-fdpos NE 0 AND sy-fdpos LE 79.
      l_period_ind = 'X'.
    ENDIF.

    IF sy-fdpos NE 0 AND sy-fdpos LT 79.
      l_fdpos = sy-fdpos + 1.
      lwa_pgm_text-txt+l_fdpos = space.
    ENDIF.

*   Add to our string.

    CONCATENATE l_select_txt lwa_pgm_text-txt
                INTO l_select_txt
                SEPARATED BY space.

*   If period found, SELECT end has been reached.

    IF l_period_ind = 'X'.
      EXIT.                 "EXIT the LOOP
    ENDIF.

  ENDLOOP.

* Our STRING variable now has the complete SELECT command.
*  Cleanup before we do our searches.

  CONDENSE l_select_txt.

* Look for options determining if loop started.

* Loading into an internal table without package size does NOT
*  start a loop.

  IF ( l_select_txt CS 'INTO TABLE'                             OR
       l_select_txt CS 'INTO CORRESPONDING FIELDS OF TABLE'     OR
       l_select_txt CS 'APPENDING TABLE'                        OR
       l_select_txt CS 'APPENDING CORRESPONDING FIELDS OF TABLE' )  AND
     l_select_txt NS 'PACKAGE SIZE'.

    cp_nest_ind = space.      "no loop
    EXIT.                     "EXIT subroutine

  ENDIF.

* SELECT SINGLE does NOT start loop.

  IF l_select_txt CS 'SELECT SINGLE'.

    cp_nest_ind = space.      "no loop
    EXIT.                     "EXIT subroutine

  ENDIF.

* Otherwise, start SELECT LOOP

  cp_nest_ind = 'X'.

ENDFORM.                    " check_select_command

3)
REPORT  zcdf_show_program.

PARAMETER: pa_rpt  TYPE programm   OBLIGATORY,
           pa_ste  TYPE rdir_rstat OBLIGATORY
                   DEFAULT 'A'.      " 'A'ctive or 'I'nactive source.

DATA:
  t_abap_text TYPE zcdf_t_pgm_text.

START-OF-SELECTION.

  READ REPORT pa_rpt INTO t_abap_text STATE pa_ste.
  
  CALL FUNCTION 'Z_CDF_LINEUP_COMMANDS'
       CHANGING
            cp_pgm_text = t_abap_text.

  EDITOR-CALL FOR t_abap_text.
This was last published in October 2003

Dig Deeper on SAP ABAP

Start the conversation

Send me notifications when other members comment.

Please create a username to comment.

-ADS BY GOOGLE

SearchERP

SearchOracle

SearchDataManagement

SearchAWS

SearchBusinessAnalytics

SearchCRM

SearchContentManagement

SearchHRSoftware

Close