使用循环将参数传递给宏

时间:2017-01-20 18:36:52

标签: loops parameters macros sap abap

有一个任务用宏填充深层结构,其中结构组件的名称相似,可以通过带索引的简单循环构造。 例如,结构是root-level1-level2-level3-level4

我想用以下嵌套宏填充它

DEFINE iterate_menges.
 do &4 times.
  fill &1 &2 sy-index level4.
 enddo.
END-OF-DEFINITION.

DEFINE fill.
 cs_root-sheet&1-&2-level&3-&4 = 'some_value'.
END-OF-DEFINITION.

但是这个概念不起作用,sy-index被视为文本。错误

  找不到

组件cs_root-sheet1-level2- levelsy-index-level4

显示了

,但是数字文字非常有效。

这里应该使用什么语法?

ADDITION:这是我在SCN上找到的一个示例代码段,它运行正常。为什么会这样?

DEFINE ADD_MAPPING.
 p_c = &1.
 CONDENSE p_c.
 CONCATENATE 'p_old' p_c INTO p_c.
 ASSIGN (p_c) TO <fs>.
 WRITE <fs>.
END-OF-DEFINITION.

DO 14 TIMES.
 ADD_MAPPING sy-index.
ENDDO.

P.S。是的,我知道宏是不可取的,不安全的,完全不应该使用,但我对这个特殊问题感兴趣而不是最佳实践建议。

3 个答案:

答案 0 :(得分:1)

系统正在完成documentation中所述的操作。不幸的是,在这种情况下,英语翻译缺少一些细节,而不是德国原始文本,更重要的是,恕我直言。使用宏不是某种调用,它是在编译之前发生的文本替换。参数被替换,而不是评估 - 它们不能被评估,因为在大多数情况下,该值在编译时是未知的,仅在运行时。要执行您想要执行的操作,您必须使用ASSIGN COMPONENT ... OF ...

等动态访问技术

答案 1 :(得分:1)

使用动态编程,将fill宏更改为:

  DATA l_field TYPE string.
  FIELD-SYMBOLS <l_value> TYPE any.
  DEFINE fill.
    l_field = &3.
    CONDENSE l_field.
    CONCATENATE 'cs_root-sheet&1-&2-level' l_field '-&4' INTO l_field.
    ASSIGN (l_field) TO <l_value>.
    IF sy-subrc = 0.
      <l_value> = 'some_value'.
    ELSE.
      " TODO: error handling?
    ENDIF.
  END-OF-DEFINITION.

虽然您可能希望在sy-subrc之后检查ASSIGN,因为该参数是不变的(仅在运行时已知),因此在编译时不会像其他一样检测到错误参数会。

您还可以为DO循环的上限添加编译时验证,因为您知道sy-index的最大值。为此,您可以在iterate_menges宏中添加一个不执行的引用:

  DEFINE iterate_menges.
    IF 1 = 0. " compile-time boundary validation test
      cs_root-sheet&1-&2-level&4-level4 = ''.
    ENDIF.
    DO &4 TIMES.
     fill &1 &2 sy-index level4.
    ENDDO.
  END-OF-DEFINITION.

第二种方法是添加一个case语句。只有在您知道该部分中始终存在一定数量的字段时才能使用此功能(当然应始终至少有一个......)。因此,如果您知道DO循环的底界,那么您可以将以下内容编码为优化:

  CASE &3.
    WHEN 1. " set 1
    WHEN 2. " set 2
    WHEN 3. " set 3
    " ...

    WHEN OTHERS.
      " dynamic set
  ENDCASE.

由于动态集较慢,优化紧密循环总是一个好主意。

答案 2 :(得分:-2)

您尝试做的事情是不可能的,因为宏只在编译时才知道。它们不是ABAP中模块化手段的一部分。

甚至可以编写自己版本的Brainfuck。请看下面的例子。

REPORT zzz.

TYPES: BEGIN OF t1,
         sheet1 TYPE c,
         sheet2 TYPE c,
       END OF t1.

DATA:
  cs_root TYPE t1.

DEFINE test.
  cs_root-sheet&1 = 'costam'.
END-OF-DEFINITION.

DEFINE brainfuck.
  &4=>&1&3 &2.
END-OF-DEFINITION.

START-OF-SELECTION.
  brainfuck IF_SYSTEM_UUID_STATIC~CREATE_UUID_X16 ) ( CL_SYSTEM_UUID.
  test sy-index.

根据其他答案回答您的评论。解决方案看起来像这样。

REPORT zzz.

TYPES: BEGIN OF t4,
    level4 TYPE c,
  END OF t4.

TYPES: BEGIN OF t3,
    level1 TYPE t4,
    level2 TYPE t4,
  END OF t3.

TYPES: BEGIN OF t2,
    level1 TYPE t3,
    level2 TYPE t3,
  END OF t2.

TYPES: BEGIN OF t1,
    sheet1 TYPE t2,
    sheet2 TYPE t2,
  END OF t1.

CLASS lcl_test DEFINITION FINAL.
  PUBLIC SECTION.
    CLASS-METHODS:
      test
        IMPORTING
          i_1 TYPE i
          i_2 TYPE i
          i_3 TYPE i
        CHANGING
          cs_root TYPE t1.
ENDCLASS.

CLASS lcl_test IMPLEMENTATION.
  METHOD test.
    ASSIGN COMPONENT |sheet{ i_1 }| OF STRUCTURE cs_root TO FIELD-SYMBOL(<fs_sheet>).
    IF sy-subrc = 0.
      ASSIGN COMPONENT |level{ i_2 }| OF STRUCTURE <fs_sheet> TO FIELD-SYMBOL(<fs_level1>).
      IF sy-subrc = 0.
        ASSIGN COMPONENT |level{ i_3 }| OF STRUCTURE <fs_level1> TO FIELD-SYMBOL(<fs_level2>).
        IF sy-subrc = 0.
          ASSIGN COMPONENT 'level4' OF STRUCTURE <fs_level2> TO FIELD-SYMBOL(<fs_level3>).
          IF sy-subrc = 0.
            <fs_level3> = 'some_value'.
          ENDIF.
        ENDIF.
      ENDIF.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

DEFINE test.
  lcl_test=>test(
    EXPORTING
      i_1 = &1
      i_2 = &2
      i_3 = &3
    CHANGING
      cs_root = &4
  ).
END-OF-DEFINITION.

DATA: gs_root TYPE t1.

START-OF-SELECTION.
  DO 14 TIMES.
    test 1 2 sy-index gs_root.
  ENDDO.