%define api.pure full %define api.prefix {kalmia} %locations %define parse.error verbose %param { yyscan_t scanner } %code top { #include #include #include } %code requires { typedef void* yyscan_t; struct kalmia_t { void *current; int index; }; struct ka_float_array_t { char *id; size_t count; double *buf; }; } %parse-param { struct kalmia_t *result } %code { int yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t scanner); int yyerror(YYLTYPE *yyllocp, yyscan_t unused, struct kalmia_t *unused2, const char *msg); #define KAI_ABORT -1 #define KAI_NOMEM -2 #define KAI_ABORTF(...) \ do { \ kai_abortf_(&yylloc, __VA_ARGS__); \ YYABORT; \ } while(0) void kai_abortf_(YYLTYPE *yyllocp, const char *fmt, ...); /* float arrays */ int kai_set_float_array_attrs(struct ka_float_array_t *a, char *id, char *count); #define KAI_WRAP(call) \ do { \ int err = call; \ if (err == KAI_ABORT) { \ KAI_ABORTF("call returned error: %s", #call); \ } \ else if (err == KAI_NOMEM) { \ KAI_ABORTF("call ran out of memory: %s", #call); \ } \ } while(0) } %union { long lval; double dval; char *sval; char cval; struct ka_float_array_t float_array; } %token PROLOG %token S_TAG_OPEN E_TAG_OPEN TAG_CLOSE EMPTY_TAG_CLOSE %token NAME %token ATTR %token TEXT %token INTEGER %token DOUBLE %token DATE; %token FLOAT_ARRAY %type float_array %type float_array_start %type float_array_attributes %token ID_ATTR COUNT_ATTR %type attr %% document: PROLOG element; elements: element | elements element ; element: empty_tag | start_tag end_tag | start_tag content end_tag | float_array ; content: elements | integers | doubles | DATE ; empty_tag: S_TAG_OPEN NAME attributes EMPTY_TAG_CLOSE { printf("empty tag: %s\n", $2); } ; start_tag: S_TAG_OPEN NAME attributes TAG_CLOSE { printf("enter tag: %s\n", $2); result->current = NULL; } ; end_tag: E_TAG_OPEN NAME TAG_CLOSE { printf("exit tag: %s\n", $2); } ; attributes: | attribute | attributes attribute ; attribute: ATTR attr { printf("attribute: %s=%s\n", $1, $2); } | ID_ATTR attr | COUNT_ATTR attr ; float_array: float_array_start doubles float_array_close { $$ = $1; printf("float_array[id='%s', count=%lu]{ ", $$.id, $$.count); for (size_t i=0; i<$$.count; i++) { printf("%f, ", $$.buf[i]); } printf("}\n"); } ; float_array_start: S_TAG_OPEN FLOAT_ARRAY float_array_attributes TAG_CLOSE { $$ = $3; result->current = $$.buf; result->index = 0; } ; float_array_close: E_TAG_OPEN FLOAT_ARRAY TAG_CLOSE ; float_array_attributes: COUNT_ATTR attr { KAI_WRAP(kai_set_float_array_attrs(&$$, NULL, $2)); } | COUNT_ATTR attr ID_ATTR attr { KAI_WRAP(kai_set_float_array_attrs(&$$, $4, $2)); } | ID_ATTR attr COUNT_ATTR attr { KAI_WRAP(kai_set_float_array_attrs(&$$, $2, $4)); } ; attr: '=' '"' TEXT '"' { $$ = $3; } ; integers: INTEGER { printf("%ld\n", $1); } | integers INTEGER { printf("%ld\n", $2); } ; doubles: DOUBLE { if (result->current != NULL) { ((double*) result->current)[result->index] = $1; result->index += 1; } } | doubles DOUBLE { if (result->current != NULL) { ((double*) result->current)[result->index] = $2; result->index += 1; } } ; %% int yyerror( YYLTYPE *yyllocp, yyscan_t unused, struct kalmia_t *unused2, const char *msg) { fprintf( stderr, "[%d:%d]: %s\n", yyllocp->first_line, yyllocp->first_column, msg ); return 1; } void kai_abortf_(YYLTYPE *yyllocp, const char *fmt, ...) { va_list args, args_len; va_start(args, fmt); va_copy(args_len, args); size_t len = vsnprintf(NULL, 0, fmt, args_len) + 1; va_end(args_len); char *buf = malloc(sizeof(char) * len); if (buf == NULL) { fprintf(stderr, "failed to allocate buffer for error message!\n"); return; } vsnprintf(buf, len, fmt, args); va_end(args); yyerror(yyllocp, NULL, NULL, buf); } /* float arrays */ int kai_set_float_array_attrs( struct ka_float_array_t *a, char *id, char *count) { a->id = id; char *end = NULL; a->count = strtoll(count, &end, 10); if (end == count) { return -1; } a->buf = malloc(sizeof(double) * a->count); if (a->buf == NULL) { return -2; } return 0; }