@@ -101,12 +101,35 @@ extern int csv2json(FILE *input, FILE *output)
101
101
# define get (c ) (((c)=getc(input)) != EOF)
102
102
# define put (c ) putc((c), output)
103
103
# define print (s ) fputs((s), output)
104
+ # define eof (c==EOF)
104
105
# define error (s ) errmsg=(s); goto EXIT
105
106
# define onerror (errmsg!=NULL)
106
107
# define imply (a ,c ) (!(a) || (c))
107
108
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 */
108
131
go (StartRecord );
109
- while (get (c )) {
132
+ while (get (c )) { /* exit loop at EOF or error */
110
133
# ifndef NDEBUG
111
134
/* helpers for loop invariants */
112
135
old_nr = nr ; old_nf = nf ; old_nl = nl ; old_nc = nc ;
@@ -121,7 +144,7 @@ extern int csv2json(FILE *input, FILE *output)
121
144
&& (c == '\r' && state != Quoted )) /* and except CR inside quoted fields */
122
145
goto NEXT ;
123
146
124
- /* FSM */
147
+ /* Transition table */
125
148
switch (state ) {
126
149
when StartRecord :
127
150
assert (nf == 1 );
@@ -189,11 +212,12 @@ extern int csv2json(FILE *input, FILE *output)
189
212
# endif
190
213
}
191
214
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 ));
193
218
switch (state ) {
194
219
when StartRecord :
195
220
assert (imply (nc != 0 , old_c == '\n' ));
196
- assert (c == EOF );
197
221
if (nc == 0 ) {
198
222
assert (nl == 1 && nf == 1 && nr == 1 );
199
223
# if ALLOW_EMPTY_LINES
@@ -204,15 +228,12 @@ extern int csv2json(FILE *input, FILE *output)
204
228
# endif
205
229
}
206
230
when StartField : print (NULL_FIELDn );
207
- assert (c == EOF );
208
231
when Plain : print (CLOSE_BRACKET );
209
- assert (c == EOF );
210
232
assert (old_c != '\n' );
211
233
when Quoted : print (CLOSE_BRACKET );
212
- assert (c == EOF );
213
234
errmsg = "unexpected end of field" ;
214
235
when Closing : print (CLOSE_BRACKET );
215
- assert (( c == EOF ) != onerror );
236
+ assert (eof != onerror );
216
237
assert (old_c != '\n' );
217
238
}
218
239
fflush (output );
0 commit comments