Update copyright
[oweals/jsonpath.git] / parser.y
index 40b25f5e1fa2237df1b692ee264bd8ff5df73a15..513fea608ca86cac5acac44d7a917b941ce9d755 100644 (file)
--- a/parser.y
+++ b/parser.y
@@ -1,6 +1,6 @@
 %{
 /*
- * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
+ * Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <stdio.h>
+#include <stdlib.h>
 #include <stdarg.h>
+#include <string.h>
+
 #include <libubox/utils.h>
 
-#include "lexer.h"
 #include "parser.h"
 
-static struct jp_opcode *op_pool = NULL;
 static struct jp_opcode *append_op(struct jp_opcode *a, struct jp_opcode *b);
 
-int yyparse(struct jp_opcode **tree, const char **error);
-void yyerror(struct jp_opcode **expr, const char **error, const char *msg);
+int yylex(struct jp_state *s);
+void *yy_scan_string (const char *str);
+int yylex_destroy(void);
+
+int yyparse(struct jp_state *s);
+void yyerror(struct jp_state *s, const char *msg);
 
 %}
 
 %output  "parser.c"
 %defines "parser.h"
 
-%parse-param { struct jp_opcode **expr }
-%parse-param { const char **error }
-
-%code provides {
-
-#ifndef JP_OPCODE
-# define JP_OPCODE
-       struct jp_opcode {
-               int type;
-               struct jp_opcode *next;
-               struct jp_opcode *down;
-               struct jp_opcode *sibling;
-               char *str;
-               int num;
-       };
-#endif
+%parse-param { struct jp_state *s }
+%lex-param { struct jp_state *s }
+
+%code requires {
+
+#ifndef __PARSER_H_
+#define __PARSER_H_
 
-struct jp_opcode *_jp_alloc_op(int type, int num, char *str, ...);
-#define jp_alloc_op(type, num, str, ...) _jp_alloc_op(type, num, str, ##__VA_ARGS__, NULL)
+struct jp_opcode {
+       int type;
+       struct jp_opcode *next;
+       struct jp_opcode *down;
+       struct jp_opcode *sibling;
+       char *str;
+       int num;
+};
 
-struct jp_opcode *jp_parse(const char *expr, const char **error);
-void jp_free(void);
+struct jp_state {
+       struct jp_opcode *pool;
+       struct jp_opcode *path;
+       char *error;
+       char str_quote;
+       char str_buf[128];
+       char *str_ptr;
+};
+
+struct jp_opcode *_jp_alloc_op(struct jp_state *s, int type, int num, char *str, ...);
+#define jp_alloc_op(type, num, str, ...) _jp_alloc_op(s, type, num, str, ##__VA_ARGS__, NULL)
+
+struct jp_state *jp_parse(const char *expr);
+void jp_free(struct jp_state *s);
+
+#endif
 
 }
 
@@ -63,18 +80,18 @@ void jp_free(void);
 
 
 %token T_ROOT T_THIS T_DOT T_BROPEN T_BRCLOSE
-%token T_OR T_AND T_LT T_LE T_GT T_GE T_EQ T_NE T_POPEN T_PCLOSE T_NOT
+%token T_OR T_AND T_LT T_LE T_GT T_GE T_EQ T_NE T_POPEN T_PCLOSE T_NOT T_UNION
 
 %token <op> T_BOOL T_NUMBER T_STRING T_LABEL T_WILDCARD
 
-%type <op> expr path segments segment or_exps or_exp and_exps and_exp cmp_exp unary_exp
+%type <op> expr path segments segment union_exps union_exp or_exps or_exp and_exps and_exp cmp_exp unary_exp
 
 %error-verbose
 
 %%
 
 input
-       : expr                                                  { *expr = $1; }
+       : expr                                                  { s->path = $1; }
        ;
 
 expr
@@ -95,7 +112,16 @@ segments
 segment
        : T_DOT T_LABEL                                 { $$ = $2; }
        | T_DOT T_WILDCARD                              { $$ = $2; }
-       | T_BROPEN or_exps T_BRCLOSE    { $$ = $2; }
+       | T_BROPEN union_exps T_BRCLOSE { $$ = $2; }
+       ;
+
+union_exps
+       : union_exp                                             { $$ = $1->sibling ? jp_alloc_op(T_UNION, 0, NULL, $1) : $1; }
+       ;
+
+union_exp
+       : union_exp T_UNION or_exps             { $$ = append_op($1, $3); }
+       | or_exps                                               { $$ = $1; }
        ;
 
 or_exps
@@ -139,10 +165,9 @@ unary_exp
 %%
 
 void
-yyerror(struct jp_opcode **expr, const char **error, const char *msg)
+yyerror(struct jp_state *s, const char *msg)
 {
-       *error = msg;
-       jp_free();
+       s->error = strdup(msg);
 }
 
 static struct jp_opcode *
@@ -159,7 +184,7 @@ append_op(struct jp_opcode *a, struct jp_opcode *b)
 }
 
 struct jp_opcode *
-_jp_alloc_op(int type, int num, char *str, ...)
+_jp_alloc_op(struct jp_state *s, int type, int num, char *str, ...)
 {
        va_list ap;
        char *ptr;
@@ -171,7 +196,7 @@ _jp_alloc_op(int type, int num, char *str, ...)
        if (!newop)
        {
                fprintf(stderr, "Out of memory\n");
-               exit(1);
+               exit(127);
        }
 
        newop->type = type;
@@ -190,42 +215,46 @@ _jp_alloc_op(int type, int num, char *str, ...)
 
        va_end(ap);
 
-       newop->next = op_pool;
-       op_pool = newop;
+       newop->next = s->pool;
+       s->pool = newop;
 
        return newop;
 }
 
-struct jp_opcode *
-jp_parse(const char *expr, const char **error)
+struct jp_state *
+jp_parse(const char *expr)
 {
-       void *buf;
-       struct jp_opcode *tree;
+       struct jp_state *s;
+
+       s = calloc(1, sizeof(*s));
 
-       buf = yy_scan_string(expr);
+       if (!s)
+               return NULL;
 
-       if (yyparse(&tree, error))
-               tree = NULL;
-       else
-               *error = NULL;
+       yy_scan_string(expr);
+
+       if (yyparse(s))
+               s->path = NULL;
 
-       yy_delete_buffer(buf);
        yylex_destroy();
 
-       return tree;
+       return s;
 }
 
 void
-jp_free(void)
+jp_free(struct jp_state *s)
 {
        struct jp_opcode *op, *tmp;
 
-       for (op = op_pool; op;)
+       for (op = s->pool; op;)
        {
                tmp = op->next;
                free(op);
                op = tmp;
        }
 
-       op_pool = NULL;
+       if (s->error)
+               free(s->error);
+
+       free(s);
 }