]> begriffs open source - sa-parse/blob - src/csv.y
initial
[sa-parse] / src / csv.y
1 %{
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 extern int yylex();
7 extern int yylineno;
8 extern char* yytext;
9
10 void yyerror(const char* s);
11
12 /* Data structures for CSV representation */
13 typedef struct field_node {
14     char* content;
15     struct field_node* next;
16 } field_node_t;
17
18 typedef struct record_node {
19     field_node_t* fields;
20     struct record_node* next;
21 } record_node_t;
22
23 typedef struct csv_file {
24     record_node_t* header;
25     record_node_t* records;
26 } csv_file_t;
27
28 /* Global variables */
29 csv_file_t* csv_data = NULL;
30
31 /* Helper functions */
32 field_node_t* create_field(char* content);
33 record_node_t* create_record(field_node_t* fields);
34 field_node_t* append_field(field_node_t* list, field_node_t* new_field);
35 record_node_t* append_record(record_node_t* list, record_node_t* new_record);
36 void print_csv(csv_file_t* csv);
37 void free_csv(csv_file_t* csv);
38 %}
39
40 %union {
41     char* str;
42     struct field_node* field_list;
43     struct record_node* record_node;
44     struct csv_file* csv_file;
45 }
46
47 %token <str> FIELD_TOK
48 %token COMMA_TOK
49 %token CRLF_TOK
50
51 %type <field_list> field_list
52 %type <field_list> field
53 %type <field_list> header
54 %type <record_node> record
55 %type <record_node> record_list
56 %type <csv_file> file
57
58 %start file
59
60 %%
61
62 file:
63     /* empty file */
64     {
65         csv_data = malloc(sizeof(csv_file_t));
66         if (!csv_data) YYERROR;
67         csv_data->header = NULL;
68         csv_data->records = NULL;
69         $$ = csv_data;
70     }
71     | header
72     {
73         csv_data = malloc(sizeof(csv_file_t));
74         if (!csv_data) YYERROR;
75         csv_data->header = create_record($1);
76         csv_data->records = NULL;
77         $$ = csv_data;
78     }
79     | header CRLF_TOK
80     {
81         csv_data = malloc(sizeof(csv_file_t));
82         if (!csv_data) YYERROR;
83         csv_data->header = create_record($1);
84         csv_data->records = NULL;
85         $$ = csv_data;
86     }
87     | record_list
88     {
89         csv_data = malloc(sizeof(csv_file_t));
90         if (!csv_data) YYERROR;
91         csv_data->header = NULL;
92         csv_data->records = $1;
93         $$ = csv_data;
94     }
95     | record_list CRLF_TOK
96     {
97         csv_data = malloc(sizeof(csv_file_t));
98         if (!csv_data) YYERROR;
99         csv_data->header = NULL;
100         csv_data->records = $1;
101         $$ = csv_data;
102     }
103     | header CRLF_TOK record_list
104     {
105         csv_data = malloc(sizeof(csv_file_t));
106         if (!csv_data) YYERROR;
107         csv_data->header = create_record($1);
108         csv_data->records = $3;
109         $$ = csv_data;
110     }
111     | header CRLF_TOK record_list CRLF_TOK
112     {
113         csv_data = malloc(sizeof(csv_file_t));
114         if (!csv_data) YYERROR;
115         csv_data->header = create_record($1);
116         csv_data->records = $3;
117         $$ = csv_data;
118     }
119     ;
120
121 header:
122     field_list
123     {
124         $$ = $1;
125     }
126     ;
127
128 record_list:
129     record
130     {
131         $$ = $1;
132     }
133     | record_list CRLF_TOK record
134     {
135         $$ = append_record($1, $3);
136     }
137     ;
138
139 record:
140     field_list
141     {
142         $$ = create_record($1);
143     }
144     ;
145
146 field_list:
147     field
148     {
149         $$ = $1;
150     }
151     | field_list COMMA_TOK field
152     {
153         $$ = append_field($1, $3);
154     }
155     ;
156
157 field:
158     FIELD_TOK
159     {
160         $$ = create_field($1);
161     }
162     | /* empty field */
163     {
164         $$ = create_field("");
165     }
166     ;
167
168 %%
169
170 void yyerror(const char* s) {
171     fprintf(stderr, "Parse error at line %d: %s\n", yylineno, s);
172     if (yytext) {
173         fprintf(stderr, "Near token: %s\n", yytext);
174     }
175 }
176
177 field_node_t* create_field(char* content) {
178     field_node_t* field = malloc(sizeof(field_node_t));
179     if (!field) return NULL;
180     field->content = content ? strdup(content) : strdup("");
181     if (!field->content) {
182         free(field);
183         return NULL;
184     }
185     field->next = NULL;
186     return field;
187 }
188
189 record_node_t* create_record(field_node_t* fields) {
190     record_node_t* record = malloc(sizeof(record_node_t));
191     if (!record) return NULL;
192     record->fields = fields;
193     record->next = NULL;
194     return record;
195 }
196
197 field_node_t* append_field(field_node_t* list, field_node_t* new_field) {
198     if (!list) return new_field;
199     
200     field_node_t* current = list;
201     while (current->next) {
202         current = current->next;
203     }
204     current->next = new_field;
205     return list;
206 }
207
208 record_node_t* append_record(record_node_t* list, record_node_t* new_record) {
209     if (!list) return new_record;
210     
211     record_node_t* current = list;
212     while (current->next) {
213         current = current->next;
214     }
215     current->next = new_record;
216     return list;
217 }
218
219 void print_csv(csv_file_t* csv) {
220     if (!csv) return;
221     
222     if (csv->header) {
223         printf("Header: ");
224         field_node_t* field = csv->header->fields;
225         while (field) {
226             printf("[%s]", field->content ? field->content : "");
227             if (field->next) printf(", ");
228             field = field->next;
229         }
230         printf("\n");
231     }
232     
233     record_node_t* record = csv->records;
234     int record_num = 1;
235     while (record) {
236         printf("Record %d: ", record_num++);
237         field_node_t* field = record->fields;
238         while (field) {
239             printf("[%s]", field->content ? field->content : "");
240             if (field->next) printf(", ");
241             field = field->next;
242         }
243         printf("\n");
244         record = record->next;
245     }
246 }
247
248 void free_field_list(field_node_t* fields) {
249     while (fields) {
250         field_node_t* next = fields->next;
251         free(fields->content);
252         free(fields);
253         fields = next;
254     }
255 }
256
257 void free_record_list(record_node_t* records) {
258     while (records) {
259         record_node_t* next = records->next;
260         free_field_list(records->fields);
261         free(records);
262         records = next;
263     }
264 }
265
266 void free_csv(csv_file_t* csv) {
267     if (!csv) return;
268     
269     if (csv->header) {
270         free_field_list(csv->header->fields);
271         free(csv->header);
272     }
273     
274     free_record_list(csv->records);
275     free(csv);
276 }
277
278 int main() {
279     printf("CSV Parser - Enter CSV data (Ctrl+D to end):\n");
280     
281     int result = yyparse();
282     
283     if (result == 0) {
284         printf("\nParsing successful!\n\n");
285         print_csv(csv_data);
286     } else {
287         printf("\nParsing failed!\n");
288     }
289     
290     free_csv(csv_data);
291     return result;
292 }