9 void csv_error(const char* s);
11 /* Data structures for CSV representation */
12 typedef struct field_node {
14 struct field_node* next;
17 typedef struct record_node {
19 struct record_node* next;
22 typedef struct csv_file {
23 record_node_t* header;
24 record_node_t* records;
27 /* Global variables */
28 csv_file_t* csv_data = NULL;
30 /* Helper functions */
31 field_node_t* create_field(char* content);
32 record_node_t* create_record(field_node_t* fields);
33 field_node_t* append_field(field_node_t* list, field_node_t* new_field);
34 record_node_t* append_record(record_node_t* list, record_node_t* new_record);
35 void print_csv(csv_file_t* csv);
36 void free_csv(csv_file_t* csv);
41 struct field_node* field_list;
42 struct record_node* record_node;
43 struct csv_file* csv_file;
46 %define api.prefix {csv_}
49 %token <str> FIELD_TOK
53 %type <field_list> field_list
54 %type <field_list> field_opt
55 %type <record_node> record
56 %type <record_node> consumed_record
66 csv_data = malloc(sizeof(csv_file_t));
67 if (!csv_data) YYERROR;
68 csv_data->header = NULL;
69 csv_data->records = $1;
72 | file CRLF_TOK consumed_record
74 csv_data->records = append_record(csv_data->records, $3);
89 $$ = create_record($1);
99 | field_list COMMA_TOK field_opt
101 $$ = append_field($1, $3);
108 $$ = create_field($1);
113 /* Empty field - create field with empty string */
114 char* empty_content = strdup("");
115 if (!empty_content) YYERROR;
116 $$ = create_field(empty_content);
123 void csv_error(const char* s) {
124 fprintf(stderr, "Parse error at line %d: %s\n", csv_lineno, s);
126 fprintf(stderr, "Near token: %s\n", csv_text);
130 field_node_t* create_field(char* content) {
131 field_node_t* field = malloc(sizeof(field_node_t));
132 if (!field) return NULL;
133 /* Use the content directly without duplicating since lexer already allocated it */
134 field->content = content;
135 if (!field->content) {
136 field->content = strdup("");
137 if (!field->content) {
146 record_node_t* create_record(field_node_t* fields) {
147 record_node_t* record = malloc(sizeof(record_node_t));
148 if (!record) return NULL;
149 record->fields = fields;
154 field_node_t* append_field(field_node_t* list, field_node_t* new_field) {
155 if (!list) return new_field;
157 field_node_t* current = list;
158 while (current->next) {
159 current = current->next;
161 current->next = new_field;
165 record_node_t* append_record(record_node_t* list, record_node_t* new_record) {
166 if (!list) return new_record;
168 record_node_t* current = list;
169 while (current->next) {
170 current = current->next;
172 current->next = new_record;
176 void print_csv(csv_file_t* csv) {
181 field_node_t* field = csv->header->fields;
183 printf("[%s]", field->content ? field->content : "");
184 if (field->next) printf(", ");
190 record_node_t* record = csv->records;
193 printf("Record %d: ", record_num++);
194 field_node_t* field = record->fields;
196 printf("[%s]", field->content ? field->content : "");
197 if (field->next) printf(", ");
201 record = record->next;
205 void free_field_list(field_node_t* fields) {
207 field_node_t* next = fields->next;
208 free(fields->content);
214 void free_record_list(record_node_t* records) {
216 record_node_t* next = records->next;
217 free_field_list(records->fields);
223 void free_csv(csv_file_t* csv) {
227 free_field_list(csv->header->fields);
231 free_record_list(csv->records);
236 printf("CSV Parser - Enter CSV data (Ctrl+D to end):\n");
238 int result = csv_parse();
241 printf("\nParsing successful!\n\n");
244 printf("\nParsing failed!\n");