Skip to content

Commit c935d57

Browse files
committed
Documented FSM transition table
1 parent c8d8d62 commit c935d57

File tree

1 file changed

+29
-8
lines changed

1 file changed

+29
-8
lines changed

csv2json.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,35 @@ extern int csv2json(FILE *input, FILE *output)
101101
# define get(c) (((c)=getc(input)) != EOF)
102102
# define put(c) putc((c), output)
103103
# define print(s) fputs((s), output)
104+
# define eof (c==EOF)
104105
# define error(s) errmsg=(s); goto EXIT
105106
# define onerror (errmsg!=NULL)
106107
# define imply(a,c) (!(a) || (c))
107108

109+
/* Transition table for the FSM (extended mode):
110+
*
111+
* |R |F |P |Q |C
112+
* =======|=======|=======|=======|=======|=======
113+
* LF |R |R |R |Q |R
114+
* , |F |F |F |... |F
115+
* " |... |Q |P |C |Q
116+
* \ |... |P |P |Q |...
117+
* HT |... |P |P |Q |...
118+
* CR | | | |Q |
119+
* ... |=> F |P |P |Q |!
120+
* EOF |$ |$ |$ |! |$
121+
* ===============================================
122+
*
123+
* States: R=StartRecord, F=StartField, P=Plain, Q=Quoted, C=Closing
124+
* Legend: $=Stop; !=Halt; ...=default transition;
125+
* => =direct transition; without reading new input;
126+
* =empty cell means ignored input;
127+
* Initial state: StartRecord
128+
*/
129+
130+
/* Initial state */
108131
go(StartRecord);
109-
while (get(c)) {
132+
while (get(c)) { /* exit loop at EOF or error */
110133
# ifndef NDEBUG
111134
/* helpers for loop invariants */
112135
old_nr=nr; old_nf=nf; old_nl=nl; old_nc=nc;
@@ -121,7 +144,7 @@ extern int csv2json(FILE *input, FILE *output)
121144
&& (c == '\r' && state != Quoted)) /* and except CR inside quoted fields */
122145
goto NEXT;
123146

124-
/* FSM */
147+
/* Transition table */
125148
switch (state) {
126149
when StartRecord:
127150
assert(nf == 1);
@@ -189,11 +212,12 @@ extern int csv2json(FILE *input, FILE *output)
189212
# endif
190213
}
191214
EXIT:
192-
assert(imply(onerror, nc!=0 && (state==StartRecord || state==Closing)));
215+
assert(imply(onerror, nc!=0));
216+
assert(imply(onerror, state==Closing || (!ALLOW_EMPTY_LINES && state==StartRecord)));
217+
assert(imply(!eof, state==Closing));
193218
switch (state) {
194219
when StartRecord:
195220
assert(imply(nc!=0, old_c=='\n'));
196-
assert(c==EOF);
197221
if (nc == 0) {
198222
assert(nl==1 && nf==1 && nr==1);
199223
# if ALLOW_EMPTY_LINES
@@ -204,15 +228,12 @@ extern int csv2json(FILE *input, FILE *output)
204228
# endif
205229
}
206230
when StartField: print(NULL_FIELDn);
207-
assert(c==EOF);
208231
when Plain: print(CLOSE_BRACKET);
209-
assert(c==EOF);
210232
assert(old_c!='\n');
211233
when Quoted: print(CLOSE_BRACKET);
212-
assert(c==EOF);
213234
errmsg = "unexpected end of field";
214235
when Closing: print(CLOSE_BRACKET);
215-
assert((c==EOF) != onerror);
236+
assert(eof != onerror);
216237
assert(old_c!='\n');
217238
}
218239
fflush(output);

0 commit comments

Comments
 (0)