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

Reply via email to