Hello, At Wed, 24 Feb 2016 18:01:59 +0900, Masahiko Sawada <sawada.m...@gmail.com> wrote in <CAD21AoCetS5BMcTpXXtMwG0hyszZgNn=zk1u73gcwtgj-wn...@mail.gmail.com> > On Wed, Feb 24, 2016 at 5:37 PM, Kyotaro HORIGUCHI > <horiguchi.kyot...@lab.ntt.co.jp> wrote: > > Hello, > > > > Ok, I think we should concentrate the parser part for now. > > > > At Tue, 23 Feb 2016 17:44:44 +0900 (Tokyo Standard Time), Kyotaro HORIGUCHI > > <horiguchi.kyot...@lab.ntt.co.jp> wrote in > > <20160223.174444.178687579.horiguchi.kyot...@lab.ntt.co.jp> > >> Hello, ... > >> So, to preserve or following the current behavior expct the last > >> one, the following pattern definitions would do. The > >> lexer/grammer for the new format of s_s_names could be simpler > >> than what it is. > >> > >> space [ \n\r\f\t\v] /* See the definition of isspace(3) */ > >> whitespace {space}+ > >> dquote \" > >> app_name_chars [\x21-\x2b\x2d-\x7e] /* excluding ' ', ',' */ > >> app_name_indq_chars [\x20\x21\x23-\x7e] /* excluding '"' */ > >> app_name_dq_chars ({app_name_indq_chars}|{dquote}{dquote}) > >> delimiter {whitespace}*,{whitespace}* > >> app_name ({app_name_chars}+|{dquote}{app_name_dq_chars}+{dquote}) > >> s_s_names {app_name}({delimiter}{app_name})* > > > > > > So I made a hasty independent parser for the syntax including the > > group names for the convenience for separate testing. The parser > > takes input from stdin and prints the result structure. > > > > It can take old s_s_name format and new list format. We haven't > > discussed how to add gruop names but I added it as "<grpname>" > > just before the # of syncronous standbys of [] and {} lists. > > > > Is this usable for further discussions? > > Thank you for your suggestion. > > Another option is to add group name with ":" to immediately after set > of standbys as I said earlier. > <http://www.postgresql.org/message-id/cad21aoa9uqcbtndki0osd0yhn4fpgtrg6wuzettvpsyy2lq...@mail.gmail.com> > > s_s_names with group name would be as follows. > s_s_names = '2[local, 2[london1, london2, london3]:london, (tokyo1, > tokyo2):tokyo]' > > Though?
I have no problem with it. The attached new sample parser does so. By the way, your parser also complains for an example I've seen somewhere upthread "1[2,3,4]". This is because '2', '3' and '4' are regarded as INT, not NAME. Whether a sequence of digits is a prefix number of a list or a host name cannot be identified until reading some following characters. So my previous test.l defined NAME_OR_INTEGER and it is distinguished in the grammar side to resolve this problem. If you want them identified in the lexer side, it should do looking-forward as <NAME_OR_PREFIX>{prefix} in the attached test.l does. This makes the lexer a bit complex but in contrast test.y simpler. The test.l, test.y attached got refactored but .l gets a bit tricky.. regards, -- Kyotaro Horiguchi NTT Open Source Software Center
%{ #include <stdio.h> #include <stdlib.h> %} %option noyywrap %x DQNAME %x NAME_OR_PREFIX %x APPNAME %x GRPCLOSED space [ \t\n\r\f] whitespace {space}+ dquote \" app_name_chars [\x21-\x27\x2a\x2b\x2d-\x5a\x5c\x5e-\x7a\x7c\x7e] app_name_indq_chars [\x20\x21\x23-\x7e] app_name {app_name_chars}+ app_name_dq ({app_name_indq_chars}|{dquote}{dquote})+ delimiter {whitespace}*,{whitespace}* app_name_start {app_name_chars} any_app \*|({dquote}\*{dquote}) xdstart {dquote} xdstop {dquote} openlist [\[\(] prefix [0-9]+{whitespace}*{openlist} closelist [\]\)] %% {xdstart} { BEGIN(DQNAME); } <DQNAME>{xdstop} { BEGIN(INITIAL); } <DQNAME>{app_name_dq} { appname *name = (appname *)malloc(sizeof(appname)); int i, j; for (i = j = 0 ; j < 63 && yytext[i] ; i++, j++) { if (yytext[i] == '"') { if (yytext[i+1] == '"') name->str[j] = '"'; else fprintf(stderr, "illegal quote escape\n"); i++; } else name->str[j] = yytext[i]; } name->str[j] = 0; name->quoted = 1; yylval.name = name; return NAME; } {app_name_start} { BEGIN(NAME_OR_PREFIX); yyless(0);} <NAME_OR_PREFIX>{app_name} { appname *name = (appname *)malloc(sizeof(appname)); char *p; name->quoted = 0; strncpy(name->str, yytext, 63); name->str[63] = 0; for (p = name->str ; *p ; p++) { if (*p >= 'A' && *p <= 'Z') *p = *p + ('a' - 'A'); } yylval.name = name; BEGIN(INITIAL); return NAME; } <NAME_OR_PREFIX>{prefix} { static char prefix[16]; int i, l; /* find the last digit */ for (l = 0 ; l < 16 && isdigit(yytext[l]) ; l++); if (l > 15) fprintf(stderr, "too long prefix number for lists\n"); for (i = 0 ; i < l ; i++) prefix[i] = yytext[i]; prefix[i] = 0; yylval.str = strdup(prefix); /* prefix ends with a left brace or paren, so go backward by 1 char for further readin */ yyless(yyleng - 1); BEGIN(INITIAL); return PREFIX; } <GRPCLOSED>{whitespace}*. { BEGIN(INITIAL); if (yytext[yyleng - 1] == ':') return yytext[yyleng - 1]; yyless(0); } {delimiter} { return DELIMITER;} {openlist} { yylval.character = yytext[0]; return OPENLIST; } {closelist} { BEGIN(GRPCLOSED); yylval.character = yytext[0]; return CLOSELIST; } %% //int main(void) //{ // int r; // // while(r = yylex()) { // fprintf(stderr, "#%d:(%s)#", r, yylval.str); // yylval.str = ""; // } //}
%{ #include <stdio.h> #include <stdlib.h> #include <string.h> //#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 <str> PREFIX %token <name> NAME %token <character> OPENLIST CLOSELIST %token DELIMITER %type <syncdef> group_list name_list name_elem name_elem_nonlist %type <syncdef> old_list s_s_names %type <name> opt_groupname %type <str> 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 : "<none>"); 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"
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers