State Machine Patterns
Parser Phase
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
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;
}
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);enum ParsePhase readLine(enum ParsePhase phase, int lineOk)
pass 1 of 210enum ParsePhase readLine(enum ParsePhase phase0, int lineOk1) {11 if (!lineOk) {if (phase == PARSE_HEADER)
13}14if (phase0 == PARSE_HEADER0) {15 return PARSE_BODY1;16}phase ← 1
27phase→ 1 = readLine(phase, 1);28phase1 = readLine(phase, secondLineOk1);enum ParsePhase readLine(enum ParsePhase phase, int lineOk)
pass 2 of 210enum ParsePhase readLine(enum ParsePhase phase1, int lineOk1) {11 if (!lineOk) {if (phase == PARSE_BODY)
16}17if (phase1 == PARSE_BODY1) {18 return PARSE_DONE2;19}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
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);enum ParsePhase readLine(enum ParsePhase phase, int lineOk)
pass 1 of 210enum ParsePhase readLine(enum ParsePhase phase0, int lineOk1) {11 if (!lineOk) {if (phase == PARSE_HEADER)
13}14if (phase0 == PARSE_HEADER0) {15 return PARSE_BODY1;16}phase ← 1
27phase→ 1 = readLine(phase, 1);28phase1 = readLine(phase, secondLineOk0);enum ParsePhase readLine(enum ParsePhase phase, int lineOk)
pass 2 of 210enum ParsePhase readLine(enum ParsePhase phase1, int lineOk0) {11 if (!lineOk) {if (!lineOk)
10enum ParsePhase readLine(enum ParsePhase phase, int lineOk) {11 if (!lineOk0) {12 return PARSE_ERROR3;13 }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