Beginner

Control Flow in ABAP

Learn conditionals, loops, and branching in ABAP - including IF/ELSEIF, CASE/WHEN, DO, WHILE, LOOP AT, and the modern COND expression

Control flow is how a program decides what to do next - branching on conditions, repeating actions, and iterating over collections. ABAP, despite its enterprise pedigree and 1983 origins, provides a familiar set of structured control flow statements: IF/ELSEIF/ELSE, CASE/WHEN, DO, WHILE, and LOOP AT for internal tables.

What makes ABAP’s control flow distinctive is its tight integration with the system field sy-subrc (return code) and sy-index (loop iteration counter), which are implicitly set by many statements. Loop bodies frequently check these system fields rather than capturing return values directly. Modern ABAP (7.40+) also adds expression-style constructs like COND and SWITCH that work inline as functional expressions, blurring the line between statements and expressions.

In this tutorial you’ll see every major control flow construct in a single runnable program. The example uses the open-abap transpiler to execute on Node.js, so no SAP system is required.

Conditionals: IF / ELSEIF / ELSE

ABAP uses IF, optional ELSEIF branches, an optional ELSE, and a closing ENDIF. Comparison operators come in both symbolic (=, <>, <, >, <=, >=) and textual (EQ, NE, LT, GT, LE, GE) forms - both styles are common in legacy code. Logical operators are AND, OR, and NOT.

Branching: CASE / WHEN

CASE evaluates an expression once and matches it against WHEN branches. WHEN OTHERS is the default case (similar to default in C-family languages). Unlike C, ABAP does not have fall-through - each WHEN is independent.

Loops: DO, WHILE, and LOOP AT

ABAP has three loop forms:

  • DO ... ENDDO - unconditional loop, often combined with TIMES to set a fixed count. Inside the loop, sy-index holds the 1-based iteration counter.
  • WHILE ... ENDWHILE - loop while a condition holds.
  • LOOP AT ... ENDLOOP - iterate over an internal table (ABAP’s built-in collection type). This is the most common loop in real ABAP code.

EXIT leaves the current loop entirely. CONTINUE skips to the next iteration. CHECK is similar to CONTINUE but with an embedded condition: CHECK lv_x > 0. skips the iteration if the condition is false.

Modern: COND and SWITCH expressions

Since ABAP 7.40, the COND and SWITCH constructor operators provide expression-style conditionals that return a value - useful for assignments and inline parameters where a full IF/CASE block would be clumsy.

Putting It All Together

Create a file named control_flow.abap:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
REPORT zcontrol.

" --- IF / ELSEIF / ELSE ---
DATA(lv_score) = 85.
IF lv_score >= 90.
  WRITE 'Grade: A'.
ELSEIF lv_score >= 80.
  WRITE 'Grade: B'.
ELSEIF lv_score >= 70.
  WRITE 'Grade: C'.
ELSE.
  WRITE 'Grade: F'.
ENDIF.

" --- CASE / WHEN with WHEN OTHERS ---
DATA(lv_day) = 3.
CASE lv_day.
  WHEN 1.
    WRITE / 'Monday'.
  WHEN 2.
    WRITE / 'Tuesday'.
  WHEN 3.
    WRITE / 'Wednesday'.
  WHEN OTHERS.
    WRITE / 'Unknown day'.
ENDCASE.

" --- DO ... TIMES with sy-index ---
DO 3 TIMES.
  WRITE / |Iteration { sy-index }|.
ENDDO.

" --- WHILE loop ---
DATA(lv_count) = 1.
WHILE lv_count <= 3.
  WRITE / |Count: { lv_count }|.
  lv_count = lv_count + 1.
ENDWHILE.

" --- LOOP AT an internal table ---
DATA: lt_fruits TYPE STANDARD TABLE OF string.
APPEND `apple` TO lt_fruits.
APPEND `banana` TO lt_fruits.
APPEND `cherry` TO lt_fruits.

LOOP AT lt_fruits INTO DATA(lv_fruit).
  WRITE / |Fruit: { lv_fruit }|.
ENDLOOP.

" --- EXIT and CONTINUE ---
DO 5 TIMES.
  IF sy-index = 4.
    EXIT.
  ENDIF.
  IF sy-index = 2.
    CONTINUE.
  ENDIF.
  WRITE / |Kept: { sy-index }|.
ENDDO.

" --- Nested loop with logical operators ---
DATA(lv_x) = 5.
DATA(lv_y) = 10.
IF lv_x > 0 AND lv_y > 0.
  WRITE / 'Both positive'.
ENDIF.

" --- COND expression (ABAP 7.40+) ---
DATA(lv_n) = 7.
DATA(lv_parity) = COND string(
  WHEN lv_n MOD 2 = 0 THEN `even`
  ELSE `odd` ).
WRITE / |{ lv_n } is { lv_parity }|.

" --- SWITCH expression (ABAP 7.40+) ---
DATA(lv_code) = 'B'.
DATA(lv_label) = SWITCH string( lv_code
  WHEN 'A' THEN `Alpha`
  WHEN 'B' THEN `Bravo`
  WHEN 'C' THEN `Charlie`
  ELSE `Unknown` ).
WRITE / |Code { lv_code } = { lv_label }|.

Running with Docker

Run the program using the same open-abap transpiler pattern from the Hello World tutorial - this time pointing at control_flow.abap instead of hello.abap.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Pull the Node.js image
docker pull node:20

# Run the ABAP program
docker run --rm -v $(pwd):/work node:20 sh -c '
cd /work && mkdir -p abap_project/src && cd abap_project && \
npm init -y >/dev/null 2>&1 && \
npm install --silent @abaplint/transpiler-cli @abaplint/runtime 2>/dev/null && \
echo "{\"input_folder\":\"src\",\"output_folder\":\"output\",\"write_unit_tests\":false,\"options\":{\"ignoreSyntaxCheck\":true}}" > abap_transpile.json && \
echo "{\"global\":{\"files\":\"/src/**/*.*\"},\"syntax\":{\"version\":\"v702\",\"errorNamespace\":\".\"}}" > abaplint.json && \
cp /work/control_flow.abap src/zcontrol.prog.abap && \
echo "<?xml version=\"1.0\"?><abapGit version=\"v1.0.0\"><asx:abap xmlns:asx=\"http://www.sap.com/abapxml\"><asx:values><PROGDIR><NAME>ZCONTROL</NAME><SUBC>1</SUBC></PROGDIR></asx:values></asx:abap></abapGit>" > src/zcontrol.prog.xml && \
./node_modules/.bin/abap_transpile >/dev/null && \
echo "import runtime from \"@abaplint/runtime\";globalThis.abap = new runtime.ABAP();await import(\"./output/zcontrol.prog.mjs\");" > run.mjs && \
node run.mjs && cd /work && rm -rf abap_project'

The transpiler converts the ABAP source to JavaScript, then @abaplint/runtime executes it - reproducing ABAP’s list buffer output on stdout.

Expected Output

Grade: B
Wednesday
Iteration 1
Iteration 2
Iteration 3
Count: 1
Count: 2
Count: 3
Fruit: apple
Fruit: banana
Fruit: cherry
Kept: 1
Kept: 3
Both positive
7 is odd
Code B = Bravo

Notes on Behavior

A few details worth calling out:

  • The first WRITE (without /) goes on the first line of the list. Every subsequent WRITE / adds a new line. This is why the Grade: B line has no leading newline.
  • sy-index is 1-based and is set automatically by DO, WHILE, and LOOP AT. It is reset to its outer value when a loop ends, so nested loops do not corrupt the outer counter.
  • In the EXIT/CONTINUE loop, iteration 2 is skipped (CONTINUE) and iteration 4 terminates the loop (EXIT), leaving only iterations 1 and 3 in the output.
  • COND and SWITCH require the result type as a parameter (COND string( ... )). Without it, the compiler cannot infer the return type.
  • MOD is ABAP’s modulo operator. lv_n MOD 2 returns the remainder.

Real-World ABAP Control Flow

In production SAP code, control flow is dominated by LOOP AT over internal tables - typically results from SELECT statements against the database. A typical pattern looks like:

1
2
3
4
5
6
7
8
SELECT * FROM customers
  INTO TABLE @DATA(lt_customers)
  WHERE country = 'US'.

LOOP AT lt_customers INTO DATA(ls_customer).
  CHECK ls_customer-status = 'ACTIVE'.
  " process active US customers
ENDLOOP.

Here CHECK acts as an inline filter inside the loop - one of ABAP’s compact idioms.

Key Concepts

  • IF/ELSEIF/ELSE/ENDIF - standard conditional branching; comparison operators come in symbolic and textual forms.
  • CASE/WHEN/WHEN OTHERS/ENDCASE - multi-way branching with no fall-through.
  • DO ... ENDDO - unconditional loop; combine with TIMES for a fixed count and use sy-index for the 1-based iteration counter.
  • WHILE ... ENDWHILE - condition-controlled loop.
  • LOOP AT ... ENDLOOP - the workhorse loop for iterating internal tables in real ABAP code.
  • EXIT, CONTINUE, CHECK - leave a loop, skip an iteration, or skip an iteration when a condition fails.
  • COND and SWITCH - 7.40+ expression-style conditionals that return a value, usable inline in assignments.
  • sy-index and sy-subrc - system fields implicitly set by control flow statements; reading them is idiomatic ABAP.

Running Today

All examples can be run using Docker:

docker pull node:20
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining