10 void yyerror(const char* s);
12 /* Data structures for CSV representation */
13 typedef struct field_node {
15 struct field_node* next;
18 typedef struct record_node {
20 struct record_node* next;
23 typedef struct csv_file {
24 record_node_t* header;
25 record_node_t* records;
28 /* Global variables */
29 csv_file_t* csv_data = NULL;
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);
42 struct field_node* field_list;
43 struct record_node* record_node;
44 struct csv_file* csv_file;
47 %token <str> FIELD_TOK
51 %type <field_list> field_list
52 %type <field_list> field_opt
53 %type <record_node> record
54 %type <record_node> consumed_record
64 csv_data = malloc(sizeof(csv_file_t));
65 if (!csv_data) YYERROR;
66 csv_data->header = NULL;
67 csv_data->records = $1;
70 | file CRLF_TOK consumed_record
72 csv_data->records = append_record(csv_data->records, $3);
87 $$ = create_record($1);
97 | field_list COMMA_TOK field_opt
99 $$ = append_field($1, $3);
106 $$ = create_field($1);
111 /* Empty field - create field with empty string */
112 char* empty_content = strdup("");
113 if (!empty_content) YYERROR;
114 $$ = create_field(empty_content);
121 void yyerror(const char* s) {
122 fprintf(stderr, "Parse error at line %d: %s\n", yylineno, s);
124 fprintf(stderr, "Near token: %s\n", yytext);
128 field_node_t* create_field(char* content) {
129 field_node_t* field = malloc(sizeof(field_node_t));
130 if (!field) return NULL;
131 /* Use the content directly without duplicating since lexer already allocated it */
132 field->content = content;
133 if (!field->content) {
134 field->content = strdup("");
135 if (!field->content) {
144 record_node_t* create_record(field_node_t* fields) {
145 record_node_t* record = malloc(sizeof(record_node_t));
146 if (!record) return NULL;
147 record->fields = fields;
152 field_node_t* append_field(field_node_t* list, field_node_t* new_field) {
153 if (!list) return new_field;
155 field_node_t* current = list;
156 while (current->next) {
157 current = current->next;
159 current->next = new_field;
163 record_node_t* append_record(record_node_t* list, record_node_t* new_record) {
164 if (!list) return new_record;
166 record_node_t* current = list;
167 while (current->next) {
168 current = current->next;
170 current->next = new_record;
174 void print_csv(csv_file_t* csv) {
179 field_node_t* field = csv->header->fields;
181 printf("[%s]", field->content ? field->content : "");
182 if (field->next) printf(", ");
188 record_node_t* record = csv->records;
191 printf("Record %d: ", record_num++);
192 field_node_t* field = record->fields;
194 printf("[%s]", field->content ? field->content : "");
195 if (field->next) printf(", ");
199 record = record->next;
203 void free_field_list(field_node_t* fields) {
205 field_node_t* next = fields->next;
206 free(fields->content);
212 void free_record_list(record_node_t* records) {
214 record_node_t* next = records->next;
215 free_field_list(records->fields);
221 void free_csv(csv_file_t* csv) {
225 free_field_list(csv->header->fields);
229 free_record_list(csv->records);
234 printf("CSV Parser - Enter CSV data (Ctrl+D to end):\n");
236 int result = yyparse();
239 printf("\nParsing successful!\n\n");
242 printf("\nParsing failed!\n");