diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-01-03 12:23:44 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-01-03 12:23:52 +0200 |
commit | 80ed5e611de0e31eed65ee207f1fd64ad097e6d1 (patch) | |
tree | 40979fe5ecadaa3d1351c645ff7988a87218e142 /mimetypes/grammar.y | |
parent | a4edd153e4cdf703c98008313743b112274e760f (diff) | |
download | fileserv-80ed5e611de0e31eed65ee207f1fd64ad097e6d1.tar.gz fileserv-80ed5e611de0e31eed65ee207f1fd64ad097e6d1.tar.bz2 |
Add mimetypes library.
Ported from GNU Mailutils.
Diffstat (limited to 'mimetypes/grammar.y')
-rw-r--r-- | mimetypes/grammar.y | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/mimetypes/grammar.y b/mimetypes/grammar.y new file mode 100644 index 0000000..2ae1997 --- /dev/null +++ b/mimetypes/grammar.y @@ -0,0 +1,397 @@ +%{ +/* This file is part of fileserv. + Copyright (C) 2017, 2018 Sergey Poznyakoff + + Fileserv is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Fileserv is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with fileserv. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <ctype.h> +#include "mtint.h" +#include "grammar.h" + +static void +yyprint (FILE *output, unsigned short toknum, YYSTYPE val) +{ + switch (toknum) + { + case TYPE: + case IDENT: + case STRING: + fprintf (output, "[%lu] %s", (unsigned long) val.string.len, + val.string.ptr); + break; + + case EOL: + fprintf (output, "\\n"); + break; + + default: + if (isprint (toknum)) + fprintf (output, "'%c'", toknum); + else + fprintf (output, "tok(%d)", toknum); + break; + } +} + +#define YYPRINT yyprint + + +static void +arg_list_append (struct arg_list *al, struct mimetypes_string const *str) +{ + struct arg_elt *elt; + elt = malloc (sizeof *elt); + elt->string.ptr = str->ptr; + elt->string.len = str->len; + LLE_APPEND (al, elt, link); +} + +static void +arg_list_destroy (struct arg_list *al) +{ + struct arg_elt *elt; + while ((elt = LL_FIRST (al)) != NULL) + { + /* FIXME: free? */ + LLE_UNLINK (al, elt, link); + } +} + +//FIXME +struct rule_list rule_list = LL_HEAD_INITIALIZER; + +static struct node *make_node (enum node_type type, + struct locus_range const *loc); +static struct node *make_binary_node (int op, + struct node *left, struct node *rigth, + struct locus_range const *loc); +static struct node *make_negation_node (struct node *p, + struct locus_range const *loc); + +static struct node *make_suffix_node (struct mimetypes_string *suffix, + struct locus_range const *loc); +static struct node *make_functional_node (char *ident, struct arg_list *list, + struct locus_range const *loc); + +static size_t errors; +%} + +%locations +%expect 15 + +%token <string> TYPE IDENT +%token <string> STRING +%token EOL BOGUS PRIORITY + +%left ',' +%left '+' + +%type <string> arg +%type <list> arglist +%type <node> function stmt rule maybe_rule +%type <result> priority maybe_priority + +%union { + struct mimetypes_string string; + char *s; + struct arg_list list; + int result; + struct node *node; +} + +%% + +input : list + ; + +list : rule_line + | list EOL rule_line + ; + +rule_line: /* empty */ + | TYPE maybe_rule maybe_priority + { + struct rule *p = malloc (sizeof (*p)); + LLE_APPEND (&rule_list, p, link); + p->type = $1.ptr; + p->node = $2; + p->priority = $3; + locus_point_copy (&p->loc.beg, &@1.beg); + locus_point_copy (&p->loc.end, &@3.end); +#if 0 + YY_LOCATION_PRINT (stderr, p->loc); + fprintf (stderr, ": rule %s\n", p->type); +#endif + } + | BOGUS + { + YYERROR; + } + | error + { + errors++; + // arg_list_destroy (); //FIXME + lex_next_rule (); + yyerrok; + yyclearin; + } + ; + +maybe_rule: /* empty */ + { + $$ = make_node (true_node, &yylloc); + } + | rule + ; + +rule : stmt + | rule rule %prec ',' + { + struct locus_range lr; + lr.beg = @1.beg; + lr.end = @2.end; + $$ = make_binary_node (L_OR, $1, $2, &lr); + } + | rule ',' rule + { + struct locus_range lr; + lr.beg = @1.beg; + lr.end = @3.end; + $$ = make_binary_node (L_OR, $1, $3, &lr); + } + | rule '+' rule + { + struct locus_range lr; + lr.beg = @1.beg; + lr.end = @3.end; + $$ = make_binary_node (L_AND, $1, $3, &lr); + } + ; + +stmt : '!' stmt + { + $$ = make_negation_node ($2, &@2); + } + | '(' rule ')' + { + $$ = $2; + } + | STRING + { + $$ = make_suffix_node (&$1, &@1); + } + | function + | BOGUS + { + YYERROR; + } + ; + +priority : PRIORITY '(' arglist ')' + { + if (LL_COUNT (&$3) != 1) + { + mimetypes_error_at (&@1, "priority takes single numberic argument"); + YYERROR; + } + $$ = atoi (LL_FIRST (&$3)->string.ptr); + arg_list_destroy (&$3); + } + ; + +maybe_priority: /* empty */ + { + $$ = 100; + } + | priority + ; + +function : IDENT '(' arglist ')' + { + struct locus_range lr; + lr.beg = @1.beg; + lr.end = @4.end; + + $$ = make_functional_node ($1.ptr, &$3, &lr); + if (!$$) + YYERROR; + } + ; + +arglist : arg + { + LL_HEAD_INIT (&$$); + arg_list_append (&$$, &$1); + } + | arglist ',' arg + { + arg_list_append (&$1, &$3); + $$ = $1; + } + ; + +arg : STRING + | BOGUS + { + YYERROR; + } + ; + +%% + +int +mimetypes_parse (const char *name) +{ + int rc; + char *p; + if (mimetypes_open (name)) + return 1; + p = getenv ("MIMETYPE_DEBUG_GRAM"); + yydebug = p ? (*p - '0') : 0; + rc = yyparse (); + mimetypes_close (); + return rc || errors; +} + +static struct node * +make_node (enum node_type type, struct locus_range const *loc) +{ + struct node *p = malloc (sizeof *p); + p->type = type; + locus_range_init (&p->loc); + locus_range_copy (&p->loc, loc); + return p; +} + +static struct node * +make_binary_node (int op, struct node *left, struct node *right, + struct locus_range const *loc) +{ + struct node *node = make_node (binary_node, loc); + + node->v.bin.op = op; + node->v.bin.arg1 = left; + node->v.bin.arg2 = right; + return node; +} + +struct node * +make_negation_node (struct node *p, struct locus_range const *loc) +{ + struct node *node = make_node (negation_node, loc); + node->v.arg = p; + return node; +} + +struct node * +make_suffix_node (struct mimetypes_string *suffix, + struct locus_range const *loc) +{ + struct node *node = make_node (suffix_node, loc); + node->v.suffix = *suffix; + return node; +} + + +struct node * +make_functional_node (char *ident, struct arg_list *list, + struct locus_range const *loc) +{ + size_t count, i; + struct builtin_tab const *p; + struct node *node; + union argument *args; + struct arg_elt *elt; + + p = find_builtin (ident); + if (!p) + { + mimetypes_error_at (loc, "unknown builtin: %s", ident); + return NULL; + } + + count = LL_COUNT (list); + i = strlen (p->args); + + if (count < i) + { + mimetypes_error_at (loc, "too few arguments in call to %s", ident); + return NULL; + } + else if (count > i) + { + mimetypes_error_at (loc, "too many arguments in call to %s", ident); + return NULL; + } + + args = calloc (count, sizeof *args); + i = 0; + LL_FOREACH (list, elt, link) + { + char *tmp; + + switch (p->args[i]) + { + case 'd': + args[i].number = strtoul (elt->string.ptr, &tmp, 0); + if (*tmp) + goto err; + break; + + case 's': + args[i].string = elt->string; + break; + + case 'x': + { + int rc = regcomp (&args[i].rx, elt->string.ptr, + REG_EXTENDED|REG_NOSUB); + if (rc) + { + char errbuf[512]; + regerror (rc, &args[i].rx, errbuf, sizeof errbuf); + mimetypes_error_at (loc, "%s", errbuf); + return NULL; + } + } + break; + + case 'c': + args[i].c = strtoul (elt->string.ptr, &tmp, 0); + if (*tmp) + goto err; + break; + + default: + abort (); + } + i++; + } + + node = make_node (functional_node, loc); + node->v.function.fun = p->handler; + node->v.function.args = args; + return node; + + err: + mimetypes_error_at (loc, "argument %lu has wrong type in call to %s", + (unsigned long) i, ident); + return NULL; +} + + + |