%{ #include #include #include "oconfig.h" 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 char *unquote (const char *orig); 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_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 /* arguments */ %type argument %type argument_list /* blocks */ %type block_begin %type block %type block_end /* statements */ %type option %type statement %type statement_list %% string: QUOTED_STRING {$$ = unquote ($1);} | UNQUOTED_STRING {$$ = strdup ($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 (oconfig_value_t)); $$.argument[$$.argument_num-1] = $2; } | argument { $$.argument = malloc (sizeof (oconfig_value_t)); $$.argument[0] = $1; $$.argument_num = 1; } ; identifier: UNQUOTED_STRING {$$ = strdup ($1);} ; option: identifier argument_list EOL { memset (&$$, '\0', sizeof ($$)); $$.key = $1; $$.values = $2.argument; $$.values_num = $2.argument_num; } ; block_begin: OPENBRAC identifier argument_list CLOSEBRAC EOL { memset (&$$, '\0', sizeof ($$)); $$.key = $2; $$.values = $3.argument; $$.values_num = $3.argument_num; } ; block_end: OPENBRAC SLASH identifier CLOSEBRAC EOL { $$ = $3; } ; block: block_begin statement_list block_end { if (strcmp ($1.key, $3) != 0) { printf ("block_begin = %s; block_end = %s;\n", $1.key, $3); yyerror ("Block not closed..\n"); exit (1); } $$ = $1; $$.children = $2.statement; $$.children_num = $2.statement_num; } ; statement: option {$$ = $1;} | block {$$ = $1;} | EOL {$$.values_num = 0;} ; statement_list: statement_list statement { $$ = $1; if ($2.values_num > 0) { $$.statement_num++; $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t)); $$.statement[$$.statement_num-1] = $2; } } | statement { if ($1.values_num > 0) { $$.statement = malloc (sizeof (oconfig_item_t)); $$.statement[0] = $1; $$.statement_num = 1; } else { $$.statement = NULL; $$.statement_num = 0; } } ; 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 char *unquote (const char *orig) { char *ret = strdup (orig); int len; int i; if (ret == NULL) return (NULL); len = strlen (ret); if ((len < 2) || (ret[0] != '"') || (ret[len - 1] != '"')) return (ret); ret++; len -= 2; ret[len] = '\0'; for (i = 0; i < len; i++) { if (ret[i] == '\\') { memmove (ret + i, ret + (i + 1), len - i); len--; } } return (ret); } /* char *unquote */ 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); }