%{ #include #include #include extern int yylex(); extern int yylineno; extern char* yytext; void yyerror(const char* s); /* Data structures for CSV representation */ typedef struct field_node { char* content; struct field_node* next; } field_node_t; typedef struct record_node { field_node_t* fields; struct record_node* next; } record_node_t; typedef struct csv_file { record_node_t* header; record_node_t* records; } csv_file_t; /* Global variables */ csv_file_t* csv_data = NULL; /* Helper functions */ field_node_t* create_field(char* content); record_node_t* create_record(field_node_t* fields); field_node_t* append_field(field_node_t* list, field_node_t* new_field); record_node_t* append_record(record_node_t* list, record_node_t* new_record); void print_csv(csv_file_t* csv); void free_csv(csv_file_t* csv); %} %union { char* str; struct field_node* field_list; struct record_node* record_node; struct csv_file* csv_file; } %token FIELD_TOK %token COMMA_TOK %token CRLF_TOK %type field_list %type field %type header %type record %type record_list %type file %start file %% file: /* empty file */ { csv_data = malloc(sizeof(csv_file_t)); if (!csv_data) YYERROR; csv_data->header = NULL; csv_data->records = NULL; $$ = csv_data; } | header { csv_data = malloc(sizeof(csv_file_t)); if (!csv_data) YYERROR; csv_data->header = create_record($1); csv_data->records = NULL; $$ = csv_data; } | header CRLF_TOK { csv_data = malloc(sizeof(csv_file_t)); if (!csv_data) YYERROR; csv_data->header = create_record($1); csv_data->records = NULL; $$ = csv_data; } | record_list { csv_data = malloc(sizeof(csv_file_t)); if (!csv_data) YYERROR; csv_data->header = NULL; csv_data->records = $1; $$ = csv_data; } | record_list CRLF_TOK { csv_data = malloc(sizeof(csv_file_t)); if (!csv_data) YYERROR; csv_data->header = NULL; csv_data->records = $1; $$ = csv_data; } | header CRLF_TOK record_list { csv_data = malloc(sizeof(csv_file_t)); if (!csv_data) YYERROR; csv_data->header = create_record($1); csv_data->records = $3; $$ = csv_data; } | header CRLF_TOK record_list CRLF_TOK { csv_data = malloc(sizeof(csv_file_t)); if (!csv_data) YYERROR; csv_data->header = create_record($1); csv_data->records = $3; $$ = csv_data; } ; header: field_list { $$ = $1; } ; record_list: record { $$ = $1; } | record_list CRLF_TOK record { $$ = append_record($1, $3); } ; record: field_list { $$ = create_record($1); } ; field_list: field { $$ = $1; } | field_list COMMA_TOK field { $$ = append_field($1, $3); } ; field: FIELD_TOK { $$ = create_field($1); } | /* empty field */ { $$ = create_field(""); } ; %% void yyerror(const char* s) { fprintf(stderr, "Parse error at line %d: %s\n", yylineno, s); if (yytext) { fprintf(stderr, "Near token: %s\n", yytext); } } field_node_t* create_field(char* content) { field_node_t* field = malloc(sizeof(field_node_t)); if (!field) return NULL; field->content = content ? strdup(content) : strdup(""); if (!field->content) { free(field); return NULL; } field->next = NULL; return field; } record_node_t* create_record(field_node_t* fields) { record_node_t* record = malloc(sizeof(record_node_t)); if (!record) return NULL; record->fields = fields; record->next = NULL; return record; } field_node_t* append_field(field_node_t* list, field_node_t* new_field) { if (!list) return new_field; field_node_t* current = list; while (current->next) { current = current->next; } current->next = new_field; return list; } record_node_t* append_record(record_node_t* list, record_node_t* new_record) { if (!list) return new_record; record_node_t* current = list; while (current->next) { current = current->next; } current->next = new_record; return list; } void print_csv(csv_file_t* csv) { if (!csv) return; if (csv->header) { printf("Header: "); field_node_t* field = csv->header->fields; while (field) { printf("[%s]", field->content ? field->content : ""); if (field->next) printf(", "); field = field->next; } printf("\n"); } record_node_t* record = csv->records; int record_num = 1; while (record) { printf("Record %d: ", record_num++); field_node_t* field = record->fields; while (field) { printf("[%s]", field->content ? field->content : ""); if (field->next) printf(", "); field = field->next; } printf("\n"); record = record->next; } } void free_field_list(field_node_t* fields) { while (fields) { field_node_t* next = fields->next; free(fields->content); free(fields); fields = next; } } void free_record_list(record_node_t* records) { while (records) { record_node_t* next = records->next; free_field_list(records->fields); free(records); records = next; } } void free_csv(csv_file_t* csv) { if (!csv) return; if (csv->header) { free_field_list(csv->header->fields); free(csv->header); } free_record_list(csv->records); free(csv); } int main() { printf("CSV Parser - Enter CSV data (Ctrl+D to end):\n"); int result = yyparse(); if (result == 0) { printf("\nParsing successful!\n\n"); print_csv(csv_data); } else { printf("\nParsing failed!\n"); } free_csv(csv_data); return result; }