State Machine Patterns
Token State
A tokenizer can track whether it is outside or inside a word.
tokenizer
The state changes when the scan crosses between spaces and word characters.
count
The count increases only when the machine enters a word.
Token State
token_state.c
Replay: real traced execution (multi-file project)
#include <stdio.h>
enum TokenState {
TOKEN_OUTSIDE,
TOKEN_INSIDE
};
int countWords(const char *text) {
enum TokenState state = TOKEN_OUTSIDE;
int count = 0;
for (int i = 0; text[i] != '\0'; i++) {
char ch = text[i];
if (ch == ' ') {
state = TOKEN_OUTSIDE;
} else if (state == TOKEN_OUTSIDE) {
count++;
state = TOKEN_INSIDE;
}
}
return count;
}
int main(void) {
int useLong = 0;
const char *text = useLong ? "red blue green" : "red blue";
int words = countWords(text);
printf("useLong=%d words=%d\n", useLong, words);
return 0;
}
#include <stdio.h>
enum TokenState {
TOKEN_OUTSIDE,
TOKEN_INSIDE
};
int countWords(const char *text) {
enum TokenState state = TOKEN_OUTSIDE;
int count = 0;
for (int i = 0; text[i] != '\0'; i++) {
char ch = text[i];
if (ch == ' ') {
state = TOKEN_OUTSIDE;
} else if (state == TOKEN_OUTSIDE) {
count++;
state = TOKEN_INSIDE;
}
}
return count;
}
int main(void) {
int useLong = 1;
const char *text = useLong ? "red blue green" : "red blue";
int words = countWords(text);
printf("useLong=%d words=%d\n", useLong, words);
return 0;
}
useLong ← 0, text ← red blue
25int main(void) {26 int useLong→ 0 = 0; //@useLong=127 const char *text→ red blue = useLong0 ? "red blue green" : "red blue";28 int words = countWords(textred blue);int countWords(const char *text)
8int countWords(const char *textred blue) {9 enum TokenState state = TOKEN_OUTSIDE;ch ← r
pass 1 of 812for (int i0 = 0; text[i]r != '\0'; i++) {13 char ch→ r = text[i]r;14 if (ch == ' ') {All 8 passes — pass 1 is the card above pass itext[i]TOKEN_OUTSIDETOKEN_INSIDEchcountstate1 0 r 0 1 r 0 → 1 0 → 1 2 1 e — — e — — 3 2 d — — d — — 4 3 0 — — 1 → 0 5 4 b 0 1 b 1 → 2 0 → 1 6 5 l — — l — — 7 6 u — — u — — 8 7 e — — e — — count ← 1, state ← 1
pass 1 of 215 state = TOKEN_OUTSIDE;16} else if (state0 == TOKEN_OUTSIDE0) {17 count→ 1++;18 state→ 1 = TOKEN_INSIDE1;19}state ← 0
13char ch = text[i];14if (ch == ' ') {15 state→ 0 = TOKEN_OUTSIDE0;16} else if (state == TOKEN_OUTSIDE) {count ← 2, state ← 1
pass 2 of 215 state = TOKEN_OUTSIDE;16} else if (state0 == TOKEN_OUTSIDE0) {17 count→ 2++;18 state→ 1 = TOKEN_INSIDE1;19}return count;
22 return count2;23}words ← 2
27 const char *text = useLong ? "red blue green" : "red blue";28 int words→ 2 = countWords(textred blue);2930 printf("useLong=%d words=%d\n", useLong0, words2);31 return 0;32}outputuseLong=0 words=2
useLong ← 1, text ← red blue green
25int main(void) {26 int useLong→ 1 = 1;27 const char *text→ red blue green = useLong1 ? "red blue green" : "red blue";28 int words = countWords(textred blue green);int countWords(const char *text)
8int countWords(const char *textred blue green) {9 enum TokenState state = TOKEN_OUTSIDE;ch ← r
pass 1 of 1412for (int i0 = 0; text[i]r != '\0'; i++) {13 char ch→ r = text[i]r;14 if (ch == ' ') {14 passes — pass 1 is the card above pass itext[i]TOKEN_OUTSIDEchstate1 0 r — r — 2 1 e — e — 3 2 d — d — 4 3 0 1 → 0 5 4 b — b — 6 5 l — l — 7 6 u — u — 8 7 e — e — 9 8 0 1 → 0 ⋯ 3 more passes ⋯ 13 12 e — e — 14 13 n — n — count ← 1, state ← 1
pass 1 of 315 state = TOKEN_OUTSIDE;16} else if (state0 == TOKEN_OUTSIDE0) {17 count→ 1++;18 state→ 1 = TOKEN_INSIDE1;19}All 3 passes — pass 1 is the card above pass chcountstate1 0 → 1 0 → 1 2 1 → 2 0 → 1 3 — 2 → 3 0 → 1 state ← 0
pass 1 of 213char ch = text[i];14if (ch == ' ') {15 state→ 0 = TOKEN_OUTSIDE0;16} else if (state == TOKEN_OUTSIDE) {state ← 0
pass 2 of 213char ch = text[i];14if (ch == ' ') {15 state→ 0 = TOKEN_OUTSIDE0;16} else if (state == TOKEN_OUTSIDE) {return count;
22 return count3;23}words ← 3
27 const char *text = useLong ? "red blue green" : "red blue";28 int words→ 3 = countWords(textred blue green);2930 printf("useLong=%d words=%d\n", useLong1, words3);31 return 0;32}outputuseLong=1 words=3