A parser can move through named phases and enter an error state when input fails.

phase Phases make a parser's progress visible and testable.
error An error transition can override the normal path and preserve the failure state.

Parser Phase

secondLineOk
parser_phase.c
Replay: real traced execution (multi-file project)
#include <stdio.h>

enum ParsePhase {
    PARSE_HEADER,
    PARSE_BODY,
    PARSE_DONE,
    PARSE_ERROR
};

enum ParsePhase readLine(enum ParsePhase phase, int lineOk) {
    if (!lineOk) {
        return PARSE_ERROR;
    }
    if (phase == PARSE_HEADER) {
        return PARSE_BODY;
    }
    if (phase == PARSE_BODY) {
        return PARSE_DONE;
    }
    return phase;
}

int main(void) {
    int secondLineOk = 1;
    enum ParsePhase phase = PARSE_HEADER;

    phase = readLine(phase, 1);
    phase = readLine(phase, secondLineOk);

    printf("secondLineOk=%d phase=%d\n", secondLineOk, phase);
    return 0;
}
#include <stdio.h>

enum ParsePhase {
    PARSE_HEADER,
    PARSE_BODY,
    PARSE_DONE,
    PARSE_ERROR
};

enum ParsePhase readLine(enum ParsePhase phase, int lineOk) {
    if (!lineOk) {
        return PARSE_ERROR;
    }
    if (phase == PARSE_HEADER) {
        return PARSE_BODY;
    }
    if (phase == PARSE_BODY) {
        return PARSE_DONE;
    }
    return phase;
}

int main(void) {
    int secondLineOk = 0;
    enum ParsePhase phase = PARSE_HEADER;

    phase = readLine(phase, 1);
    phase = readLine(phase, secondLineOk);

    printf("secondLineOk=%d phase=%d\n", secondLineOk, phase);
    return 0;
}
  1. secondLineOk ← 1

    23int main(void) {24    int secondLineOk→ 1 = 1; //@secondLineOk=025    enum ParsePhase phase = PARSE_HEADER;2627    phase0 = readLine(phase, 1);28    phase = readLine(phase, secondLineOk);
  2. enum ParsePhase readLine(enum ParsePhase phase, int lineOk)

    pass 1 of 2
    10enum ParsePhase readLine(enum ParsePhase phase0, int lineOk1) {11    if (!lineOk) {
  3. if (phase == PARSE_HEADER)

    13}14if (phase0 == PARSE_HEADER0) {15    return PARSE_BODY1;16}
  4. phase ← 1

    27phase→ 1 = readLine(phase, 1);28phase1 = readLine(phase, secondLineOk1);
  5. enum ParsePhase readLine(enum ParsePhase phase, int lineOk)

    pass 2 of 2
    10enum ParsePhase readLine(enum ParsePhase phase1, int lineOk1) {11    if (!lineOk) {
  6. if (phase == PARSE_BODY)

    16}17if (phase1 == PARSE_BODY1) {18    return PARSE_DONE2;19}
  7. phase ← 2

    27    phase = readLine(phase, 1);28    phase→ 2 = readLine(phase, secondLineOk1);2930    printf("secondLineOk=%d phase=%d\n", secondLineOk1, phase2);31    return 0;32}
    outputsecondLineOk=1 phase=2
  1. secondLineOk ← 0

    23int main(void) {24    int secondLineOk→ 0 = 0;25    enum ParsePhase phase = PARSE_HEADER;2627    phase0 = readLine(phase, 1);28    phase = readLine(phase, secondLineOk);
  2. enum ParsePhase readLine(enum ParsePhase phase, int lineOk)

    pass 1 of 2
    10enum ParsePhase readLine(enum ParsePhase phase0, int lineOk1) {11    if (!lineOk) {
  3. if (phase == PARSE_HEADER)

    13}14if (phase0 == PARSE_HEADER0) {15    return PARSE_BODY1;16}
  4. phase ← 1

    27phase→ 1 = readLine(phase, 1);28phase1 = readLine(phase, secondLineOk0);
  5. enum ParsePhase readLine(enum ParsePhase phase, int lineOk)

    pass 2 of 2
    10enum ParsePhase readLine(enum ParsePhase phase1, int lineOk0) {11    if (!lineOk) {
  6. if (!lineOk)

    10enum ParsePhase readLine(enum ParsePhase phase, int lineOk) {11    if (!lineOk0) {12        return PARSE_ERROR3;13    }
  7. phase ← 3

    27    phase = readLine(phase, 1);28    phase→ 3 = readLine(phase, secondLineOk0);2930    printf("secondLineOk=%d phase=%d\n", secondLineOk0, phase3);31    return 0;32}
    outputsecondLineOk=0 phase=3