%{ #include #include #include "oconfig.h" static oconfig_item_t *ci_root; static oconfig_item_t *ci_current; static oconfig_item_t *statement_list; static int statement_list_num; static oconfig_value_t *argument_list; static int argument_list_num; struct statement_list_s { oconfig_item_t *statement; int statement_num; }; typedef struct statement_list_s statement_list_t; struct argument_list_s { oconfig_value_t *argument; int argument_num; }; typedef struct argument_list_s argument_list_t; static void dump_ci (oconfig_item_t *ci, int shift); %} %start entire_file %union { double number; int boolean; char *string; oconfig_value_t cv; oconfig_value_t *cvp; oconfig_item_t ci; argument_list_t al; statement_list_t sl; } %token NUMBER %token TRUE FALSE %token QUOTED_STRING UNQUOTED_STRING %token SLASH OPENBRAC CLOSEBRAC EOL %type string %type identifier %type block_end %type argument %type argument_list %type block_begin %type block %type option %type statement %type statement_list %% string: QUOTED_STRING {$$ = $1;} | UNQUOTED_STRING {$$ = $1;} ; argument: NUMBER {$$.value.number = $1; $$.type = OCONFIG_TYPE_NUMBER;} | TRUE {$$.value.boolean = 1; $$.type = OCONFIG_TYPE_BOOLEAN;} | FALSE {$$.value.boolean = 0; $$.type = OCONFIG_TYPE_BOOLEAN;} | string {$$.value.string = $1; $$.type = OCONFIG_TYPE_STRING;} ; argument_list: argument_list argument { $$ = $1; $$.argument_num++; $$.argument = realloc ($$.argument, $$.argument_num * sizeof (argument_list_t)); $$.argument[$$.argument_num-1] = $2; } | argument { $$.argument = malloc (sizeof (argument_list_t)); $$.argument[0] = $1; $$.argument_num = 1; } ; identifier: UNQUOTED_STRING {$$ = $1;} ; option: identifier argument_list EOL { memset (&$$, '\0', sizeof ($$)); $$.key = $1; $$.values = $2.argument; $$.values_num = $2.argument_num; printf ("Option `%s' has %i arguments\n", $$.key, $$.values_num); } ; block_begin: OPENBRAC identifier argument_list CLOSEBRAC EOL { memset (&$$, '\0', sizeof ($$)); $$.key = $2; $$.values = $3.argument; $$.values_num = $3.argument_num; printf ("Begin block `%s'\n", $2); } ; block_end: OPENBRAC SLASH identifier CLOSEBRAC EOL {$$ = $3; printf ("End block `%s'\n", $3);} ; block: block_begin statement_list block_end { if (strcmp ($1.key, $3) != 0) yyerror ("Block %s not closed..\n", $1); $$ = $1; $$.children = $2.statement; } ; statement: option {$$ = $1;} | block {$$ = $1;} | EOL {/* ignore */} ; statement_list: statement_list statement { $$ = $1; $$.statement_num++; $$.statement = realloc ($$.statement, $$.statement_num * sizeof (statement_list_t)); $$.statement[$$.statement_num-1] = $2; printf ("statement_list: length = %i\n", $$.statement_num); } | statement { $$.statement = malloc (sizeof (statement_list_t)); $$.statement[0] = $1; $$.statement_num = 1; } ; entire_file: statement_list { int i; for (i = 0; i < $1.statement_num; i++) dump_ci ($1.statement + i, 0); } ; %% #include "lex.yy.c" /* void yyerror (char *s) { fprintf (stderr, "%s\n", s); } int yylex (void) { return (getc (stdin)); } */ int main (int argc, char **argv) { yyparse (); return (0); } static void dump_ci (oconfig_item_t *ci, int shift) { int i; if (shift > 0) printf ("%*s", "", shift); printf ("%s", ci->key); for (i = 0; i < ci->values_num; i++) { oconfig_value_t cv = ci->values[i]; if (cv.type == OCONFIG_TYPE_STRING) printf (" `%s'", cv.value.string); else if (cv.type == OCONFIG_TYPE_NUMBER) printf (" %lf", cv.value.number); else if (cv.type == OCONFIG_TYPE_BOOLEAN) printf (" %s", cv.value.boolean ? "true" : "false"); else printf ("", cv.type); } printf ("\n"); for (i = 0; i < ci->children_num; i++) dump_ci (ci->children + i, shift + 1); }