%{ #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; void yyerror(const char *s); int yylex(void); int depth = 0; syncdef *defroot = NULL; syncdef *curr = NULL; %} %union { char *str; int ival; syncdef *syncdef; } %token NAME_OR_NUMBER %token QUOTED_NAME %token DELIMITER %type qlist plist name_list name_elem name_elem_nonlist %type old_list s_s_names list_maybe_with_name %type group_name %% 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; } | list_maybe_with_name { 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; } ; list_maybe_with_name: plist {$$ = $1;} | qlist {$$ = $1;} | '<' group_name '>' plist { $4->name = $2; $$ = $4; } | '<' group_name '>' qlist { $4->name = $2; $$ = $4; } ; group_name: NAME_OR_NUMBER { $$ = strdup($1); } | QUOTED_NAME { $$ = strdup($1); } ; plist: NAME_OR_NUMBER '[' name_list ']' { syncdef *t; 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; } } t = (syncdef*)malloc(sizeof(syncdef)); t->type = TE_PRIORITY_LIST; t->nsync = n; t->name = NULL; t->quoted = 0; t->nest = $3->nest + 1; t->elems = $3; t->next = NULL; $$ = t; } ; qlist: NAME_OR_NUMBER '{' name_list '}' { syncdef *t; 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 && strcmp(t->name, "*") == 0) { yyerror("\"*\" is not allowed in quorum list"); return 1; } } t = (syncdef*)malloc(sizeof(syncdef)); t->type = TE_QUORUM_LIST; t->nsync = n; t->name = NULL; t->quoted = 0; t->nest = $3->nest + 1; t->elems = $3; t->next = NULL; $$ = t; } ; 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; } | list_maybe_with_name { $$ = $1; } ; name_elem_nonlist: NAME_OR_NUMBER { syncdef *t = (syncdef*)malloc(sizeof(syncdef)); t->type = TE_HOSTNAME; t->nsync = 0; t->name = strdup($1); t->quoted = 0; t->nest = 0; t->elems = NULL; t->next = NULL; $$ = t; } | QUOTED_NAME { syncdef *t = (syncdef*)malloc(sizeof(syncdef)); t->type = TE_HOSTNAME; t->nsync = 0; t->name = strdup($1); t->quoted = 1; 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"