%{ #include #include #include //#define YYDEBUG 1 typedef enum treeelemtype { TE_HOSTNAME, TE_PRIORITY_LIST, TE_QUORUM_LIST } treeelemtype; struct syncdef; typedef struct syncdef { treeelemtype type; char *name; int quoted; int nsync; int nest; struct syncdef *elems; struct syncdef *next; } syncdef; typedef struct { int quoted; char str[64]; } appname; void yyerror(const char *s); int yylex(void); int depth = 0; syncdef *defroot = NULL; syncdef *curr = NULL; %} %union { char character; char *str; appname *name; int ival; syncdef *syncdef; } %token PREFIX %token NAME %token OPENLIST CLOSELIST %token DELIMITER %type group_list name_list name_elem name_elem_nonlist %type old_list s_s_names %type opt_groupname %type opt_prefix %% s_s_names: old_list { syncdef *t = (syncdef*)malloc(sizeof(syncdef)); t->type = TE_PRIORITY_LIST; t->name = NULL; t->quoted = 0; t->nsync = 1; t->elems = $1; t->next = NULL; defroot = $$ = t; } | group_list { defroot = $$ = $1;} ; old_list: name_elem_nonlist { $$ = $1; } | old_list DELIMITER name_elem_nonlist { syncdef *p = $1; while (p->next) p = p->next; p->next = $3; } ; group_list: opt_prefix OPENLIST name_list CLOSELIST opt_groupname { syncdef *t; char *p = $1; int n = atoi($1); if (n == 0) { yyerror("prefix number is 0 or non-integer"); return 1; } if ($3->nest > 1) { yyerror("Up to 2 levels of nesting is supported"); return 1; } for (t = $3 ; t ; t = t->next) { if (t->type == TE_HOSTNAME && t->next && strcmp(t->name, "*") == 0) { yyerror("\"*\" is allowed only at the end of priority list"); return 1; } } if ($2 == '[' && $4 != ']' || $2 == '(' && $4 != ')') { yyerror("Unmatched group parentheses"); return 1; } t = (syncdef*)malloc(sizeof(syncdef)); t->type = ($2 == '[' ? TE_PRIORITY_LIST : TE_QUORUM_LIST); t->nsync = n; t->name = $5->str; t->quoted = $5->quoted; t->nest = $3->nest + 1; t->elems = $3; t->next = NULL; $$ = t; } ; opt_prefix: PREFIX { $$ = $1; } | { $$ = "1"; } ; opt_groupname: ':' NAME { $$ = $2; } | /* EMPTY */ { appname *name = (appname *)malloc(sizeof(name)); name->str[0] = 0; name->quoted = 0; $$ = name; } ; name_list: name_elem { $$ = $1; } | name_list DELIMITER name_elem { syncdef *p = $1; if (p->nest < $3->nest) p->nest = $3->nest; while (p->next) p = p->next; p->next = $3; $$ = $1; } ; name_elem: name_elem_nonlist { $$ = $1; } | group_list { $$ = $1; } ; name_elem_nonlist: NAME { syncdef *t = (syncdef*)malloc(sizeof(syncdef)); t->type = TE_HOSTNAME; t->nsync = 0; t->name = strdup($1->str); t->quoted = $1->quoted; t->nest = 0; t->elems = NULL; t->next = NULL; $$ = t; } ; %% void indent(int level) { int i; for (i = 0 ; i < level * 2 ; i++) putc(' ', stdout); } void dump_def(syncdef *def, int level) { char *typelabel[] = {"HOSTNAME", "PRIO_LIST", "QUORUM_LIST"}; syncdef *p; if (def == NULL) return; switch (def->type) { case TE_HOSTNAME: indent(level); puts("{"); indent(level+1); printf("TYPE: %s\n", typelabel[def->type]); indent(level+1); printf("HOSTNAME: %s\n", def->name); indent(level+1); printf("QUOTED: %s\n", def->quoted ? "Yes" : "No"); indent(level+1); printf("NEST: %d\n", def->nest); indent(level); puts("}"); if (def->next) dump_def(def->next, level); break; case TE_PRIORITY_LIST: case TE_QUORUM_LIST: indent(level); printf("TYPE: %s\n", typelabel[def->type]); indent(level); printf("GROUPNAME: %s\n", def->name ? def->name : ""); indent(level); printf("NSYNC: %d\n", def->nsync); indent(level); printf("NEST: %d\n", def->nest); indent(level); puts("CHILDREN {"); level++; dump_def(def->elems, level); level--; indent(level); puts("}"); if (def->next) dump_def(def->next, level); break; default: fprintf(stderr, "Unknown type?\n"); exit(1); } level--; } int main(void) { // yydebug = 1; if (!yyparse()) dump_def(defroot, 0); } void yyerror(const char* s) { fprintf(stderr, "Error: %s\n", s); } #include "lex.yy.c"