diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-05-03 17:49:29 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-05-03 21:23:21 +0300 |
commit | 3d679b3df641f59fb81ca1651799f4e2965ed67e (patch) | |
tree | 5a614ee25cff44d015ee9e6f6920e2ba19379bba /src/grecs-gram.y | |
parent | 24ec67c9f6375d34d88e79981ed8abbe15a78169 (diff) | |
download | grecs-3d679b3df641f59fb81ca1651799f4e2965ed67e.tar.gz grecs-3d679b3df641f59fb81ca1651799f4e2965ed67e.tar.bz2 |
Switch to the two-layer model. Add testsuite.
The configuration file parser creates a syntax tree. This step
does not require any knowledge about which keywords are allowed.
The user can then either use that tree directly, or post-process
it using parser tables. The latter approach is equivalent to
previous versions of grecs.
Diffstat (limited to 'src/grecs-gram.y')
-rw-r--r-- | src/grecs-gram.y | 715 |
1 files changed, 41 insertions, 674 deletions
diff --git a/src/grecs-gram.y b/src/grecs-gram.y index f65e2dd..c2429a4 100644 --- a/src/grecs-gram.y +++ b/src/grecs-gram.y @@ -22,45 +22,22 @@ #include <grecs-gram.h> #include <stdlib.h> #include <stdarg.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <sys/un.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> #include <string.h> #include <errno.h> -typedef union -{ - struct sockaddr s; - struct sockaddr_in s_in; - struct sockaddr_un s_un; -} sockaddr_union_t; - -static struct grecs_keyword config_keywords; -static struct grecs_keyword *cursect; -#define CURRENT_BASE ((char*)(cursect ? cursect->callback_data : NULL)) -static struct grecs_list *sections; +static struct grecs_node *parse_tree; int grecs_error_count; int grecs_default_port = 0; -static void *target_ptr(struct grecs_keyword *kwp, char *base); -static void stmt_begin(struct grecs_keyword *kwp, grecs_value_t tag); -static void stmt_end(struct grecs_keyword *kwp); -static struct grecs_keyword *find_keyword(const char *ident); - -static void process_ident(struct grecs_keyword *kwp, grecs_value_t *value); -static struct grecs_list *simple_list_create(int dispose); %} %union { - char *string; - grecs_value_t value; - struct grecs_list *list; - struct grecs_keyword *kw; + char *string; + grecs_value_t value; + struct grecs_list *list; + struct grecs_node *node; + struct { struct grecs_node *head, *tail; } node_list; } %token <string> IDENT STRING QSTRING MSTRING @@ -68,39 +45,47 @@ static struct grecs_list *simple_list_create(int dispose); %type <list> slist0 %type <value> value tag vallist %type <list> values list vlist -%type <kw> ident +%type <node> stmt simple block +%type <node_list> stmtlist %% input : stmtlist + { + parse_tree = $1.head; + } ; stmtlist: stmt + { + $$.head = $$.tail = $1; + } | stmtlist stmt + { + grecs_node_bind($1.tail, $2, 0); + } ; stmt : simple | block ; -simple : ident vallist ';' +simple : IDENT vallist ';' { - process_ident($1, &$2); + $$ = grecs_node_create(grecs_node_stmt, + &grecs_current_locus); + $$->ident = $1; + $$->value = $2; } ; -block : ident tag { stmt_begin($<kw>1, $<value>2); } '{' stmtlist '}' opt_sc +block : IDENT tag '{' stmtlist '}' opt_sc { - stmt_end($1); - } - ; - -ident : IDENT - { - $$ = find_keyword($1); - if (!$$) - grecs_error(&grecs_current_locus, 0, - _("Unknown keyword")); + $$ = grecs_node_create(grecs_node_block, + &grecs_current_locus); + $$->ident = $1; + $$->value = $2; + grecs_node_bind($$, $4.head, 1); } ; @@ -135,7 +120,7 @@ vallist : vlist vlist : value { - $$ = simple_list_create(0); + $$ = _grecs_simple_list_create(0); grecs_list_append($$, grecs_value_dup(&$1)); } | vlist value @@ -169,7 +154,6 @@ string : STRING slist : slist0 { struct grecs_list_entry *ep; - const void *p; grecs_line_begin(); for (ep = $1->head; ep; ep = ep->next) @@ -181,7 +165,7 @@ slist : slist0 slist0 : QSTRING { - $$ = simple_list_create(0); + $$ = _grecs_simple_list_create(0); grecs_list_append($$, $1); } | slist0 QSTRING @@ -207,7 +191,7 @@ list : '(' ')' values : value { - $$ = simple_list_create(0); + $$ = _grecs_simple_list_create(0); grecs_list_append($$, grecs_value_dup(&$1)); } | values ',' value @@ -236,8 +220,8 @@ listel_dispose(void *el) free(el); } -static struct grecs_list * -simple_list_create(int dispose) +struct grecs_list * +_grecs_simple_list_create(int dispose) { struct grecs_list *lp = grecs_list_create(); if (dispose) @@ -307,59 +291,20 @@ grecs_asprintf(char **pbuf, size_t *psize, const char *fmt, ...) return rc; } -void -grecs_warning(grecs_locus_t *locus, int errcode, const char *fmt, ...) -{ - va_list ap; - char *buf = NULL; - size_t size = 0; - - va_start(ap, fmt); - if (grecs_vasprintf(&buf, &size, fmt, ap)) - grecs_alloc_die(); - va_end(ap); - grecs_print_diag(locus, 0, errcode, buf); - free(buf); -} - -void -grecs_error(grecs_locus_t *locus, int errcode, const char *fmt, ...) -{ - va_list ap; - char *buf = NULL; - size_t size = 0; - - va_start(ap, fmt); - if (grecs_vasprintf(&buf, &size, fmt, ap)) - grecs_alloc_die(); - va_end(ap); - grecs_print_diag(locus, 1, errcode, buf); - free(buf); - grecs_error_count++; -} - -void -grecs_set_keywords(struct grecs_keyword *kwd) -{ - config_keywords.kwd = kwd; -} - -int +struct grecs_node * grecs_parse(const char *name) { int rc; if (grecs_lex_begin(name)) - return 1; - cursect = &config_keywords; - if (sections) { - grecs_list_free(sections); - sections = NULL; - } + return NULL; + parse_tree = NULL; rc = yyparse(); grecs_lex_end(); - if (grecs_error_count) - rc = 1; - return rc; + if (grecs_error_count) { + grecs_tree_free(parse_tree); + parse_tree = NULL; + } + return parse_tree; } void @@ -370,583 +315,5 @@ grecs_gram_trace(int n) -static void * -target_ptr(struct grecs_keyword *kwp, char *base) -{ - if (kwp->varptr) - base = (char*) kwp->varptr + kwp->offset; - else if (base) - base += kwp->offset; - - return base; -} - -static int -fake_callback(enum grecs_callback_command cmd, - grecs_locus_t *locus, - void *varptr, - grecs_value_t *value, - void *cb_data) -{ - return 0; -} - -static struct grecs_keyword fake = { - "*", - NULL, - NULL, - grecs_type_void, - NULL, - 0, - fake_callback, - NULL, - &fake -}; - -static void -stmt_begin(struct grecs_keyword *kwp, grecs_value_t tag) -{ - void *target; - - if (!sections) - sections = grecs_list_create(); - grecs_list_push(sections, cursect); - if (kwp) { - target = target_ptr(kwp, CURRENT_BASE); - cursect = kwp; - if (kwp->callback && - kwp->callback(grecs_callback_section_begin, - &grecs_current_locus, /* FIXME */ - target, - &tag, - &kwp->callback_data)) - cursect = &fake; - } else - /* install "ignore-all" section */ - cursect = kwp; -} - -static void -stmt_end(struct grecs_keyword *kwp) -{ - grecs_callback_fn callback = NULL; - void *dataptr = NULL; - - if (cursect && cursect->callback) { - callback = cursect->callback; - dataptr = &cursect->callback_data; - } - - cursect = (struct grecs_keyword *) grecs_list_pop(sections); - if (!cursect) - abort(); - if (callback) - callback(grecs_callback_section_end, - &grecs_current_locus, /* FIXME */ - kwp ? target_ptr(kwp, CURRENT_BASE) : NULL, - NULL, - dataptr); -} - -static struct grecs_keyword * -find_keyword(const char *ident) -{ - struct grecs_keyword *kwp; - - if (cursect && cursect != &fake) { - for (kwp = cursect->kwd; kwp->ident; kwp++) - if (strcmp(kwp->ident, ident) == 0) - return kwp; - } else { - return &fake; - } - return NULL; -} - -static int -string_to_bool(const char *string, int *pval, grecs_locus_t *locus) -{ - if (strcmp(string, "yes") == 0 - || strcmp(string, "true") == 0 - || strcmp(string, "t") == 0 - || strcmp(string, "1") == 0) - *pval = 1; - else if (strcmp(string, "no") == 0 - || strcmp(string, "false") == 0 - || strcmp(string, "nil") == 0 - || strcmp(string, "0") == 0) - *pval = 0; - else { - grecs_error(locus, 0, - _("%s: not a valid boolean value"), - string); - return 1; - } - return 0; -} - -static int -string_to_host(struct in_addr *in, const char *string, grecs_locus_t *locus) -{ - if (inet_aton(string, in) == 0) { - struct hostent *hp; - - hp = gethostbyname(string); - if (hp == NULL) - return 1; - memcpy(in, hp->h_addr, sizeof(struct in_addr)); - } - return 0; -} - -static int -string_to_sockaddr(struct grecs_sockaddr *sp, const char *string, - grecs_locus_t *locus) -{ - if (string[0] == '/') { - struct sockaddr_un s_un; - if (strlen(string) >= sizeof(s_un.sun_path)) { - grecs_error(locus, 0, - _("%s: UNIX socket name too long"), - string); - return 1; - } - s_un.sun_family = AF_UNIX; - strcpy(s_un.sun_path, string); - sp->len = sizeof(s_un); - sp->sa = grecs_malloc(sp->len); - memcpy(sp->sa, &s_un, sp->len); - } else { - char *p = strchr(string, ':'); - size_t len; - struct sockaddr_in sa; - - sa.sin_family = AF_INET; - if (p) - len = p - string; - else - len = strlen(string); - - if (len == 0) - sa.sin_addr.s_addr = INADDR_ANY; - else { - char *host = grecs_malloc(len + 1); - memcpy(host, string, len); - host[len] = 0; - - if (string_to_host(&sa.sin_addr, host, locus)) { - grecs_error(locus, 0, - _("%s: not a valid IP address or hostname"), - host); - free(host); - return 1; - } - free(host); - } - - if (p) { - struct servent *serv; - - p++; - serv = getservbyname(p, "tcp"); - if (serv != NULL) - sa.sin_port = serv->s_port; - else { - unsigned long l; - char *q; - - /* Not in services, maybe a number? */ - l = strtoul(p, &q, 0); - - if (*q || l > USHRT_MAX) { - grecs_error(locus, 0, - _("%s: not a valid port number"), p); - return 1; - } - sa.sin_port = htons(l); - } - } else if (grecs_default_port) - sa.sin_port = grecs_default_port; - else { - grecs_error(locus, 0, _("missing port number")); - return 1; - } - sp->len = sizeof(sa); - sp->sa = grecs_malloc(sp->len); - memcpy(sp->sa, &sa, sp->len); - } - return 0; -} - - -/* The TYPE_* defines come from gnulib's intprops.h */ - -/* True if the arithmetic type T is signed. */ -# define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) - -/* The maximum and minimum values for the integer type T. These - macros have undefined behavior if T is signed and has padding bits. */ -# define TYPE_MINIMUM(t) \ - ((t) (! TYPE_SIGNED(t) \ - ? (t) 0 \ - : TYPE_SIGNED_MAGNITUDE(t) \ - ? ~ (t) 0 \ - : ~ TYPE_MAXIMUM(t))) -# define TYPE_MAXIMUM(t) \ - ((t) (! TYPE_SIGNED(t) \ - ? (t) -1 \ - : ((((t) 1 << (sizeof(t) * CHAR_BIT - 2)) - 1) * 2 + 1))) -# define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1) - - -#define STRTONUM(s, type, base, res, limit, loc) \ - { \ - type sum = 0; \ - \ - for (; *s; s++) \ - { \ - type x; \ - \ - if ('0' <= *s && *s <= '9') \ - x = sum * base + *s - '0'; \ - else if (base == 16 && 'a' <= *s && *s <= 'f') \ - x = sum * base + *s - 'a'; \ - else if (base == 16 && 'A' <= *s && *s <= 'F') \ - x = sum * base + *s - 'A'; \ - else \ - break; \ - if (x <= sum) \ - { \ - grecs_error(loc, 0, _("numeric overflow")); \ - return 1; \ - } \ - else if (limit && x > limit) \ - { \ - grecs_error(loc, 0, _("value out of allowed range")); \ - return 1; \ - } \ - sum = x; \ - } \ - res = sum; \ - } - -#define STRxTONUM(s, type, res, limit, loc) \ - { \ - int base; \ - if (*s == '0') \ - { \ - s++; \ - if (*s == 0) \ - base = 10; \ - else if (*s == 'x' || *s == 'X') \ - { \ - s++; \ - base = 16; \ - } \ - else \ - base = 8; \ - } else \ - base = 10; \ - STRTONUM(s, type, base, res, limit, loc); \ - } - -#define GETUNUM(str, type, res, loc) \ - { \ - type tmpres; \ - const char *s = str; \ - STRxTONUM(s, type, tmpres, 0, loc); \ - if (*s) \ - { \ - grecs_error(loc, 0, _("not a number (stopped near `%s')"), \ - s); \ - return 1; \ - } \ - res = tmpres; \ - } - -#define GETSNUM(str, type, res, loc) \ - { \ - unsigned type tmpres; \ - const char *s = str; \ - int sign; \ - unsigned type limit; \ - \ - if (*s == '-') \ - { \ - sign = 1; \ - s++; \ - limit = TYPE_MINIMUM(type); \ - limit = - limit; \ - } \ - else \ - { \ - sign = 0; \ - limit = TYPE_MAXIMUM(type); \ - } \ - \ - STRxTONUM(s, unsigned type, tmpres, limit, loc); \ - if (*s) \ - { \ - grecs_error(loc, 0, _("not a number (stopped near `%s')"), s); \ - return 1; \ - } \ - res = sign ? - tmpres : tmpres; \ - } - - -int -grecs_string_convert(void *target, enum grecs_data_type type, - const char *string, grecs_locus_t *locus) -{ - switch (type) { - case grecs_type_void: - abort(); - - case grecs_type_string: - *(const char**)target = string; - break; - - case grecs_type_short: - GETUNUM(string, short, *(short*)target, locus); - break; - - case grecs_type_ushort: - GETUNUM(string, unsigned short, *(unsigned short*)target, locus); - break; - - case grecs_type_bool: - return string_to_bool(string, (int*)target, locus); - - case grecs_type_int: - GETSNUM(string, int, *(int*)target, locus); - break; - - case grecs_type_uint: - GETUNUM(string, unsigned int, *(unsigned int*)target, locus); - break; - - case grecs_type_long: - GETSNUM(string, long, *(long*)target, locus); - break; - - case grecs_type_ulong: - GETUNUM(string, unsigned long, *(unsigned long*)target, locus); - break; - - case grecs_type_size: - GETUNUM(string, size_t, *(size_t*)target, locus); - break; - /*FIXME - case grecs_type_off: - GETSNUM(string, off_t, *(off_t*)target, locus); - break; - */ - case grecs_type_time: - /*FIXME: Use getdate */ - GETUNUM(string, time_t, *(time_t*)target, locus); - break; - - case grecs_type_ipv4: - if (inet_aton(string, (struct in_addr *)target)) { - grecs_error(locus, 0, _("%s: not a valid IP address"), - string); - return 1; - } - break; - - case grecs_type_host: - if (string_to_host((struct in_addr *)target, string, locus)) { - grecs_error(locus, 0, - _("%s: not a valid IP address or hostname"), - string); - return 1; - } - break; - - case grecs_type_sockaddr: - return string_to_sockaddr((struct grecs_sockaddr *)target, string, - locus); - - /* FIXME: */ - case grecs_type_cidr: - grecs_error(locus, 0, - _("INTERNAL ERROR at %s:%d"), __FILE__, __LINE__); - abort(); - - case grecs_type_section: - grecs_error(locus, 0, - _("invalid use of block statement")); - return 1; - } - return 0; -} - -struct grecs_prop -{ - size_t size; - int (*cmp)(const void *, const void *); -}; - -static int -string_cmp(const void *elt1, const void *elt2) -{ - return strcmp((const char *)elt1,(const char *)elt2); -} - -#define __grecs_name_cat__(a,b) a ## b -#define NUMCMP(type) __grecs_name_cat__(type,_cmp) -#define __DECL_NUMCMP(type,ctype) \ - static int \ - NUMCMP(type)(const void *elt1, const void *elt2) \ - { \ - return memcmp(elt1, elt2, sizeof(ctype)); \ - } -#define DECL_NUMCMP(type) __DECL_NUMCMP(type,type) - -DECL_NUMCMP(short) -DECL_NUMCMP(int) -DECL_NUMCMP(long) -DECL_NUMCMP(size_t) -/*FIXME DECL_NUMCMP(off_t)*/ -DECL_NUMCMP(time_t) -__DECL_NUMCMP(in_addr, struct in_addr) -__DECL_NUMCMP(grecs_sockaddr, struct grecs_sockaddr) - -struct grecs_prop grecs_prop_tab[] = { - { 0, NULL }, /* grecs_type_void */ - { sizeof(char*), string_cmp }, /* grecs_type_string */ - { sizeof(short), NUMCMP(short) }, /* grecs_type_short */ - { sizeof(unsigned short), NUMCMP(short) }, /* grecs_type_ushort */ - { sizeof(int), NUMCMP(int) }, /* grecs_type_int */ - { sizeof(unsigned int), NUMCMP(int) }, /* grecs_type_uint */ - { sizeof(long), NUMCMP(long) }, /* grecs_type_long */ - { sizeof(unsigned long), NUMCMP(long) }, /* grecs_type_ulong */ - { sizeof(size_t), NUMCMP(size_t) }, /* grecs_type_size */ -#if 0 - FIXME - { sizeof(off_t), NUMCMP(off_t) }, /* grecs_type_off */ -#endif - { sizeof(time_t), NUMCMP(time_t) }, /* grecs_type_time */ - { sizeof(int), NUMCMP(int) }, /* grecs_type_bool */ - { sizeof(struct in_addr), NUMCMP(in_addr) }, /* grecs_type_ipv4 */ - { 0, NULL }, /* FIXME: grecs_type_cidr */ - { sizeof(struct in_addr), NUMCMP(in_addr) }, /* grecs_type_host */ - { sizeof(struct grecs_sockaddr), NUMCMP(grecs_sockaddr) }, - /* grecs_type_sockaddr */ - { 0, NULL } /* grecs_type_section */ -}; -#define grecs_prop_count \ - (sizeof(grecs_prop_tab) / sizeof(grecs_prop_tab[0])) - -void -grecs_process_ident(struct grecs_keyword *kwp, grecs_value_t *value, - void *base, grecs_locus_t *locus) -{ - void *target; - - if (!kwp) - return; - - target = target_ptr(kwp, (char *) base); - - if (kwp->callback) - kwp->callback(grecs_callback_set_value, - locus, - target, - value, - &kwp->callback_data); - else if (value->type == GRECS_TYPE_ARRAY) { - grecs_error(locus, 0, - _("too many arguments to `%s'; missing semicolon?"), - kwp->ident); - return; - } else if (value->type == GRECS_TYPE_LIST) { - if (GRECS_IS_LIST(kwp->type)) { - struct grecs_list_entry *ep; - enum grecs_data_type type = GRECS_TYPE(kwp->type); - int num = 1; - struct grecs_list *list; - size_t size; - - if (type >= grecs_prop_count - || (size = grecs_prop_tab[type].size) == 0) { - grecs_error(locus, 0, - _("INTERNAL ERROR at %s:%d: " - "unhandled data type %d"), - __FILE__, __LINE__, type); - abort(); - } - - list = grecs_list_create(); - list->cmp = grecs_prop_tab[type].cmp; - - for (ep = value->v.list->head; ep; ep = ep->next) { - const grecs_value_t *vp = ep->data; - - if (vp->type != GRECS_TYPE_STRING) - grecs_error(locus, 0, - _("%s: incompatible data type in list item #%d"), - kwp->ident, num); - else if (type == grecs_type_string) - grecs_list_append(list, - (void*) vp->v.string); - else { - void *ptr = grecs_malloc(size); - if (grecs_string_convert(ptr, - type, - vp->v.string, - locus) == 0) - grecs_list_append(list, ptr); - else - free(ptr); - } - } - *(struct grecs_list**)target = list; - } else { - grecs_error(locus, 0, - _("incompatible data type for `%s'"), - kwp->ident); - return; - } - } else if (GRECS_IS_LIST(kwp->type)) { - struct grecs_list *list; - enum grecs_data_type type = GRECS_TYPE(kwp->type); - size_t size; - void *ptr; - - if (type >= grecs_prop_count - || (size = grecs_prop_tab[type].size) == 0) { - grecs_error(locus, 0, - _("INTERNAL ERROR at %s:%d: unhandled data type %d"), - __FILE__, __LINE__, type); - abort(); - } - - list = grecs_list_create(); - list->cmp = grecs_prop_tab[type].cmp; - list->free_entry = listel_dispose; - if (type == grecs_type_string) - grecs_list_append(list, value->v.string); - else { - ptr = grecs_malloc(size); - if (grecs_string_convert(ptr, type, value->v.string, locus)) { - free(ptr); - grecs_list_free(list); - return; - } - grecs_list_append(list, ptr); - } - *(struct grecs_list**)target = list; - } else - grecs_string_convert(target, GRECS_TYPE(kwp->type), - value->v.string, - locus); -} - -static void -process_ident(struct grecs_keyword *kwp, grecs_value_t *value) -{ - grecs_process_ident(kwp, value, CURRENT_BASE, &grecs_current_locus); -} |