This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project iwhd.git.
The branch, master has been updated
via 0317fd51b2994b9c512122ce97092fd3d0252ffc (commit)
via d28494103e69b75ca5a242b09eb761570d15f930 (commit)
via 2d0b629e6cf361f18e660df7419c66ae61c56355 (commit)
via 136c20fc5c20bc053f86c643d2863d8ceb116dac (commit)
via 7a1642252d00263da1b36237661fb310f9d9cee7 (commit)
via 8da2bda33280f84f2a209be74f3cb4abd9798ef9 (commit)
via 61be1a9c7d0e2756613470fb82e285c980635950 (commit)
via 319d8c1f35ff61956c5c319976b81fed70b24267 (commit)
via cc926cc887f194d8ec7c97e7905baa669fff185e (commit)
via c366f6de5cb002e3306197e8ef2249b3120c635b (commit)
via 8d267f6f44e8c64623f66dfbb73673297c2514d5 (commit)
via b3302bb0a5b82689d8c890cc703fd0efc55512b8 (commit)
via 43e90569e516a77ed71bc2d568e8a25e2e1bc15d (commit)
via 172ce552307317456a644868ad02aba5b3528ba8 (commit)
via 66864937990bf7de81e6e5e2fba6ebf521f109c3 (commit)
via e1f97c75f4afa180643691324fa0552877fd8454 (commit)
via cddd16da84f4beb975f9e96546ea7ad1a6557fb8 (commit)
via 31e05f1f8045bd38d47eeacfd09a4c27895b10db (commit)
via 90c6359047186d03e04a4e73e99d0c935e40be1a (commit)
via 41f6621794a607e2a8a5940d6fb2be22746d2cf1 (commit)
via 9d0990a469ada32886e0c09e98da498a5106b2fd (commit)
via 19f9c826b6a2e6ad5dc51f1e1c4030f1eac82553 (commit)
via 5ed3c7cb77b0d921759f9407dd17dbb9b2b54ba3 (commit)
via fd0cbe4410ec2b1ad831e418b472cc46fd4cacaf (commit)
from 9ca9c3d6bdd3d210b5c58fca4bc9c63aacbea78d (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/iwhd.git/commit/0317fd51b2994b9c512122ce97092fd3d0252ffc
commit 0317fd51b2994b9c512122ce97092fd3d0252ffc
Author: Jim Meyering <meyering(a)redhat.com>
Date: Mon Oct 18 16:36:45 2010 +0200
avoid NULL deref on failed strdup
* qlexer.l: Don't dereference NULL on failed strdup.
diff --git a/qlexer.l b/qlexer.l
index c51bad8..5f354df 100644
--- a/qlexer.l
+++ b/qlexer.l
@@ -17,10 +17,14 @@
%%
"[^"]*" { yytext[yyleng-1] = 0; yytext++;
- yylval_param->str = strdup(yytext); return T_STRING; }
-~[^~]*~ { yylval_param->str = strdup(yytext); return T_DATE; }
-[0-9]+ { yylval_param->str = strdup(yytext); return T_NUMBER; }
-[a-z_]+ { yylval_param->str = strdup(yytext); return T_ID; }
+ yylval_param->str = strdup(yytext);
+ return yylval_param->str ? T_STRING : T_INVALID; }
+~[^~]*~ { yylval_param->str = strdup(yytext);
+ return yylval_param->str ? T_DATE : T_INVALID; }
+[0-9]+ { yylval_param->str = strdup(yytext);
+ return yylval_param->str ? T_NUMBER : T_INVALID; }
+[a-z_]+ { yylval_param->str = strdup(yytext);
+ return yylval_param->str ? T_ID : T_INVALID; }
[=$#()<>.] { return yytext[0]; }
! { return T_NOT; }
&& { return T_AND; }
http://repo.or.cz/w/iwhd.git/commit/d28494103e69b75ca5a242b09eb761570d15f930
commit d28494103e69b75ca5a242b09eb761570d15f930
Author: Jim Meyering <meyering(a)redhat.com>
Date: Mon Oct 18 16:24:39 2010 +0200
xrealloc was not used; #if-0 it out
diff --git a/qparser.y b/qparser.y
index 4ddf5ff..e5bd1ad 100644
--- a/qparser.y
+++ b/qparser.y
@@ -44,6 +44,7 @@ xmalloc (size_t n)
return p;
}
+#if 0 // not used
/* Change the size of an allocated block of memory P to N bytes,
with error checking. */
static void *
@@ -54,6 +55,7 @@ xrealloc (void *p, size_t n)
xalloc_die ();
return p;
}
+#endif
/* Clone an object P of size S, with error checking. There's no need
for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any
http://repo.or.cz/w/iwhd.git/commit/2d0b629e6cf361f18e660df7419c66ae61c56355
commit 2d0b629e6cf361f18e660df7419c66ae61c56355
Author: Jim Meyering <meyering(a)redhat.com>
Date: Mon Oct 18 14:02:33 2010 +0200
now that lexer calls strdup, free those strings
diff --git a/qparser.y b/qparser.y
index a82309a..4ddf5ff 100644
--- a/qparser.y
+++ b/qparser.y
@@ -82,6 +82,7 @@ make_number (const char *text)
tmp->as_num = strtoll(text,NULL,10);
tmp->resolved = NULL;
}
+ free ((void *) text);
return tmp;
}
@@ -96,6 +97,7 @@ make_string (const char *text, type_t t)
tmp->as_str = xstrdup(text);
tmp->resolved = NULL;
}
+ free ((void *) text);
return tmp;
}
@@ -133,6 +135,7 @@ make_link (value_t *left, const char *right)
char *copy;
copy = xstrdup(right);
+ free ((void *) right);
if (!copy) {
return NULL;
}
http://repo.or.cz/w/iwhd.git/commit/136c20fc5c20bc053f86c643d2863d8ceb116dac
commit 136c20fc5c20bc053f86c643d2863d8ceb116dac
Author: Jim Meyering <meyering(a)redhat.com>
Date: Mon Oct 18 12:37:57 2010 +0200
qlexer.l: rewrite not to need static var, at_eof.
diff --git a/qlexer.l b/qlexer.l
index 551d590..c51bad8 100644
--- a/qlexer.l
+++ b/qlexer.l
@@ -9,8 +9,6 @@
#include "iwhd-qparser.h"
#undef YY_DECL
#define YY_DECL extern int yylex (YYSTYPE *yylval_param, yyscan_t yyscanner)
-
-static int at_eof = 0;
%}
%option warn nounput noinput noyywrap
@@ -30,7 +28,7 @@ static int at_eof = 0;
[ tnr]+ { return T_SPACE; }
. { return T_INVALID; }
-<<EOF>> { at_eof = 1; yyterminate (); }
+<<EOF>> { yyterminate (); /* aka return 0; */ }
%%
@@ -50,9 +48,12 @@ main (int argc, char **argv)
YY_BUFFER_STATE buf
= yy_scan_string (""!@#" ~xxx~ 123 abc $#()<>=!&|.",
scanner);
- do {
+ while (1) {
YYSTYPE v;
int t = yylex(&v, scanner);
+ if (t == 0)
+ break;
+
switch (t) {
case T_STRING:
if (!yytext[0]) {
@@ -72,7 +73,7 @@ main (int argc, char **argv)
default:
printf("%dn",t);
}
- } while (!at_eof);
+ }
yy_delete_buffer (buf, scanner);
yylex_destroy (scanner);
http://repo.or.cz/w/iwhd.git/commit/7a1642252d00263da1b36237661fb310f9d9cee7
commit 7a1642252d00263da1b36237661fb310f9d9cee7
Author: Jim Meyering <meyering(a)redhat.com>
Date: Mon Oct 18 12:31:33 2010 +0200
handle yylex_init failure
diff --git a/qparser.y b/qparser.y
index c7e2fe8..a82309a 100644
--- a/qparser.y
+++ b/qparser.y
@@ -495,7 +495,8 @@ value_t *
parse (const char *text)
{
yyscan_t scanner;
- yylex_init (&scanner);
+ if (yylex_init (&scanner))
+ error (0, errno, "failed to initialize query parser");
YY_BUFFER_STATE buf = yy_scan_string (text, scanner);
value_t *result;
value_t *r = yyparse (scanner, &result) == 0 ? result : NULL;
http://repo.or.cz/w/iwhd.git/commit/8da2bda33280f84f2a209be74f3cb4abd9798ef9
commit 8da2bda33280f84f2a209be74f3cb4abd9798ef9
Author: Jim Meyering <meyering(a)redhat.com>
Date: Mon Oct 18 12:20:45 2010 +0200
pure, almost
diff --git a/qlexer.l b/qlexer.l
index e394800..551d590 100644
--- a/qlexer.l
+++ b/qlexer.l
@@ -1,4 +1,3 @@
-%option warn nounput noinput noyywrap
%{
#include <config.h>
#include <stdio.h>
@@ -9,17 +8,21 @@
#include "iwhd-qparser.h"
#undef YY_DECL
-#define YY_DECL extern int yylex (YYSTYPE *lvalp)
+#define YY_DECL extern int yylex (YYSTYPE *yylval_param, yyscan_t yyscanner)
static int at_eof = 0;
%}
+%option warn nounput noinput noyywrap
+%option bison-bridge reentrant
+
%%
-"[^"]*" { yytext[yyleng-1] = 0; yytext++; return T_STRING; }
-~[^~]*~ { return T_DATE; }
-[0-9]+ { return T_NUMBER; }
-[a-z_]+ { return T_ID; }
+"[^"]*" { yytext[yyleng-1] = 0; yytext++;
+ yylval_param->str = strdup(yytext); return T_STRING; }
+~[^~]*~ { yylval_param->str = strdup(yytext); return T_DATE; }
+[0-9]+ { yylval_param->str = strdup(yytext); return T_NUMBER; }
+[a-z_]+ { yylval_param->str = strdup(yytext); return T_ID; }
[=$#()<>.] { return yytext[0]; }
! { return T_NOT; }
&& { return T_AND; }
@@ -42,12 +45,14 @@ yyerror (const char *msg)
int
main (int argc, char **argv)
{
-
- yy_scan_string(""!@#" ~xxx~ 123 abc $#()<>=!&|.");
+ yyscan_t scanner;
+ yylex_init (&scanner);
+ YY_BUFFER_STATE buf
+ = yy_scan_string (""!@#" ~xxx~ 123 abc $#()<>=!&|.",
scanner);
do {
YYSTYPE v;
- int t = yylex(&v);
+ int t = yylex(&v, scanner);
switch (t) {
case T_STRING:
if (!yytext[0]) {
@@ -69,6 +74,9 @@ main (int argc, char **argv)
}
} while (!at_eof);
+ yy_delete_buffer (buf, scanner);
+ yylex_destroy (scanner);
+
return 0;
}
#endif
diff --git a/qparser.y b/qparser.y
index e8a60d0..c7e2fe8 100644
--- a/qparser.y
+++ b/qparser.y
@@ -19,7 +19,7 @@
#include <string.h>
#include <ctype.h>
-#define YY_DECL int yylex(YYSTYPE *);
+#define YY_DECL int yylex(YYSTYPE *, void *scanner);
YY_DECL
static void
@@ -141,16 +141,6 @@ make_link (value_t *left, const char *right)
}
/*
- * For some reason the bison-generated code isn't setting up yysv* properly,
- * so $n doesn't work with terminals. Be very careful to use this only
- * when the token we want is the last one in the current rule. If the
- * syntax ever gets complicated enough that we can't get away with that, we'll
- * just have to wrap all the terminals in singleton non-terminals just so that
- * $n will work in the real syntax rules.
- */
-extern char *yytext;
-
-/*
* IMO it's wrong for us to get into the bbool_expr=policy rule when there's
* a syntax error, but we do. The good news is that it's easy to free the
* erroneous tree properly this way. The bad news is that we need to wait
@@ -161,7 +151,7 @@ extern char *yytext;
static int syntax_error = 0;
void
-yyerror (value_t **result, const char *msg)
+yyerror (void *scanner, value_t **result, const char *msg)
{
// error (0, 0, "parse error: %sn", msg);
// FIXME do this via param, not file-global
@@ -170,6 +160,8 @@ yyerror (value_t **result, const char *msg)
%}
+%lex-param { yyscan_t scanner }
+%parse-param { void *scanner }
%parse-param { value_t **result }
%token <str> T_STRING T_COMP T_DATE T_ID T_LINK T_NUMBER T_OFIELD T_SFIELD
@@ -288,35 +280,35 @@ link_field:
}|
link_field '.' T_ID {
// printf("found LINK FIELDn");
- $$ = make_link($1,yytext);
+ $$ = make_link($1,$3);
};
field:
'$' T_ID {
// printf("found DOLLAR FIELDn");
- $$ = make_string(yytext,T_OFIELD);
+ $$ = make_string($2,T_OFIELD);
}|
'#' T_ID {
// printf("found WAFFLE FIELDn");
- $$ = make_string(yytext,T_SFIELD);
+ $$ = make_string($2,T_SFIELD);
};
literal:
T_NUMBER {
- // printf("found NUMBER %sn",yytext);
- $$ = make_number(yytext);
+ // printf("found NUMBER %sn",$1);
+ $$ = make_number($1);
}|
T_STRING {
- // printf("found STRING %sn",yytext);
- $$ = make_string(yytext,T_STRING);
+ // printf("found STRING %sn",$1);
+ $$ = make_string($1,T_STRING);
}|
T_DATE {
// printf("found DATEn");
- $$ = make_string(yytext,T_DATE);
+ $$ = make_string($1,T_DATE);
}|
T_ID {
- // printf("found ID %sn",yytext);
- $$ = make_string(yytext,T_ID);
+ // printf("found ID %sn",$1);
+ $$ = make_string($1,T_ID);
};
paren_expr:
@@ -502,10 +494,13 @@ free_value (value_t *v)
value_t *
parse (const char *text)
{
- yy_scan_string(text);
+ yyscan_t scanner;
+ yylex_init (&scanner);
+ YY_BUFFER_STATE buf = yy_scan_string (text, scanner);
value_t *result;
- value_t *r = yyparse (&result) == 0 ? result : NULL;
- yylex_destroy();
+ value_t *r = yyparse (scanner, &result) == 0 ? result : NULL;
+ yy_delete_buffer (buf, scanner);
+ yylex_destroy (scanner);
return r;
}
http://repo.or.cz/w/iwhd.git/commit/61be1a9c7d0e2756613470fb82e285c980635950
commit 61be1a9c7d0e2756613470fb82e285c980635950
Author: Jim Meyering <meyering(a)redhat.com>
Date: Mon Oct 18 11:16:05 2010 +0200
add beginnings of %union support
diff --git a/qparser.y b/qparser.y
index cb59065..e8a60d0 100644
--- a/qparser.y
+++ b/qparser.y
@@ -3,14 +3,21 @@
%{
#include <config.h>
+#include "query.h"
+#include "iwhd-qparser.h"
+%}
+
+%union {
+ char *str;
+ struct value_t *val;
+}
+
+%{
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
-#define YYSTYPE value_t *
-#include "query.h"
-#include "iwhd-qparser.h"
#define YY_DECL int yylex(YYSTYPE *);
YY_DECL
@@ -165,10 +172,11 @@ yyerror (value_t **result, const char *msg)
%parse-param { value_t **result }
-%token T_STRING T_DATE T_NUMBER T_ID
-%token T_NOT T_AND T_OR
-%token T_SPACE T_INVALID
-%token T_OFIELD T_SFIELD T_COMP T_LINK
+%token <str> T_STRING T_COMP T_DATE T_ID T_LINK T_NUMBER T_OFIELD T_SFIELD
+%token T_NOT T_AND T_OR T_SPACE T_INVALID
+
+%type <val> atom bbool_expr comp_expr field
+%type <val> link_field literal paren_expr ubool_expr
%start policy
http://repo.or.cz/w/iwhd.git/commit/319d8c1f35ff61956c5c319976b81fed70b24267
commit 319d8c1f35ff61956c5c319976b81fed70b24267
Author: Jim Meyering <meyering(a)redhat.com>
Date: Mon Oct 18 11:01:54 2010 +0200
query.h: use struct value_t (same name as typedef)
This is required to allow bison to parse the incoming %union decl.
diff --git a/query.h b/query.h
index 83ad2b4..523dd91 100644
--- a/query.h
+++ b/query.h
@@ -42,15 +42,15 @@ typedef enum yytokentype type_t;
* a value_t, but for T_LINK it's a bare string.
* TBD: use a separate as_link union member for T_LINK.
*/
-typedef struct _value {
+typedef struct value_t {
type_t type;
union {
long long as_num;
char *as_str;
struct {
comp_t op;
- struct _value *left;
- struct _value *right;
+ struct value_t *left;
+ struct value_t *right;
} as_tree;
};
const char *resolved; /* saved result for T_OFIELD/T_SFIELD/T_LINK */
http://repo.or.cz/w/iwhd.git/commit/cc926cc887f194d8ec7c97e7905baa669fff185e
commit cc926cc887f194d8ec7c97e7905baa669fff185e
Author: Jim Meyering <meyering(a)redhat.com>
Date: Mon Oct 18 10:55:19 2010 +0200
add missing #define part of double-inclusion guard
diff --git a/query.h b/query.h
index 253e19b..83ad2b4 100644
--- a/query.h
+++ b/query.h
@@ -13,7 +13,8 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <
http://www.gnu.org/licenses/>. */
-#if !defined(_QUERY_H)
+#ifndef _QUERY_H
+#define _QUERY_H 1
#if defined(__CPLUSPLUS__) || defined(__cplusplus)
extern "C" {
http://repo.or.cz/w/iwhd.git/commit/c366f6de5cb002e3306197e8ef2249b3120c635b
commit c366f6de5cb002e3306197e8ef2249b3120c635b
Author: Jim Meyering <meyering(a)redhat.com>
Date: Mon Oct 18 10:16:44 2010 +0200
lex && and || as tokens, not "&" and "|"
There is no point in allowing spaces between the bytes
of these operators.
diff --git a/qlexer.l b/qlexer.l
index 41232a3..e394800 100644
--- a/qlexer.l
+++ b/qlexer.l
@@ -22,8 +22,8 @@ static int at_eof = 0;
[a-z_]+ { return T_ID; }
[=$#()<>.] { return yytext[0]; }
! { return T_NOT; }
-& { return T_AND; }
-| { return T_OR; }
+&& { return T_AND; }
+|| { return T_OR; }
[ tnr]+ { return T_SPACE; }
. { return T_INVALID; }
diff --git a/qparser.y b/qparser.y
index bb6e760..cb59065 100644
--- a/qparser.y
+++ b/qparser.y
@@ -189,13 +189,13 @@ bbool_expr:
// printf("promoting ubool_expr to bbool_exprn");
$$ = $1;
}|
- bbool_expr T_AND T_AND ubool_expr {
+ bbool_expr T_AND ubool_expr {
// printf("found AND expressionn");
- $$ = make_tree(T_AND,$1,$4);
+ $$ = make_tree(T_AND,$1,$3);
}|
- bbool_expr T_OR T_OR ubool_expr {
+ bbool_expr T_OR ubool_expr {
// printf("found OR expressionn");
- $$ = make_tree(T_OR,$1,$4);
+ $$ = make_tree(T_OR,$1,$3);
}|
bbool_expr T_SPACE {
$$ = $1;
http://repo.or.cz/w/iwhd.git/commit/8d267f6f44e8c64623f66dfbb73673297c2514d5
commit 8d267f6f44e8c64623f66dfbb73673297c2514d5
Author: Jeff Darcy <jdarcy(a)redhat.com>
Date: Fri Oct 15 12:01:20 2010 -0400
Add query.h comments back in.
diff --git a/query.h b/query.h
index b726632..253e19b 100644
--- a/query.h
+++ b/query.h
@@ -21,14 +21,26 @@ extern "C" {
#include "iwhd-qparser.h"
+/*
+ * Comparisons are all the same type to the parser, but when it comes to
+ * evaluation we need to know the difference so we use these subtypes.
+ */
typedef enum {
C_LESSTHAN, C_LESSOREQ,
C_EQUAL, C_DIFFERENT,
C_GREATEROREQ, C_GREATERTHAN
} comp_t;
+/* The actual values are generated by the parser. */
typedef enum yytokentype type_t;
+/*
+ * Universal AST object. T_NUMBER uses as_num, and some day T_DATE might as
+ * well. Several types (T_STRING, T_ID, T_*FIELD) all use as_str. The rest
+ * use as_tree, but there's a caveat. In most cases as_tree.right really is
+ * a value_t, but for T_LINK it's a bare string.
+ * TBD: use a separate as_link union member for T_LINK.
+ */
typedef struct _value {
type_t type;
union {
@@ -43,12 +55,27 @@ typedef struct _value {
const char *resolved; /* saved result for T_OFIELD/T_SFIELD/T_LINK */
} value_t;
+/*
+ * In a higher-level language, this would be a method pointer. It's just
+ * a pointer to a function plus a little piece of the caller's context (in
+ * the replication-policy case it's the current bucket and key) so that we
+ * can do concurrent evaluations with separate contexts.
+ */
typedef struct {
const char *(*func) (void *, const char *);
void *ctx;
} getter_t;
#define CALL_GETTER(g,x) g->func(g->ctx,x)
+/*
+ * In the normal case a caller would invoke parse once, eval multiple times,
+ * and free_value once. print_value is just for debugging/testing.
+ * TBD: make parse reentrant (eval already is, free_value doesn't need to be.
+ * Unfortunately, a quick scan of generated code and information on the web
+ * seems to indicate that even a "reentrant" bison parser only encapsulates
+ * user state and still relies quite a bit on internal globals. That might
+ * mean that we just have to put a lock around it instead.
+ */
int eval (const value_t *expr,
const getter_t *oget, const getter_t *sget);
void free_value (value_t *);
http://repo.or.cz/w/iwhd.git/commit/b3302bb0a5b82689d8c890cc703fd0efc55512b8
commit b3302bb0a5b82689d8c890cc703fd0efc55512b8
Author: Jim Meyering <meyering(a)redhat.com>
Date: Fri Oct 15 15:07:19 2010 +0200
build: ensure we use only Flex
diff --git a/qlexer.l b/qlexer.l
index c4d3a63..41232a3 100644
--- a/qlexer.l
+++ b/qlexer.l
@@ -3,6 +3,10 @@
#include <config.h>
#include <stdio.h>
+#ifndef FLEX_SCANNER
+# error This scanner must be made using flex, not lex.
+#endif
+
#include "iwhd-qparser.h"
#undef YY_DECL
#define YY_DECL extern int yylex (YYSTYPE *lvalp)
http://repo.or.cz/w/iwhd.git/commit/43e90569e516a77ed71bc2d568e8a25e2e1bc15d
commit 43e90569e516a77ed71bc2d568e8a25e2e1bc15d
Author: Jim Meyering <meyering(a)redhat.com>
Date: Fri Oct 15 14:24:21 2010 +0200
qlexer.l: simplify
* qlexer.l: Include <config.h> first.
Use a few %options.
Use <<EOF>> rather than yywrap.
diff --git a/qlexer.l b/qlexer.l
index 7ae9e87..c4d3a63 100644
--- a/qlexer.l
+++ b/qlexer.l
@@ -1,9 +1,13 @@
+%option warn nounput noinput noyywrap
%{
+#include <config.h>
#include <stdio.h>
#include "iwhd-qparser.h"
#undef YY_DECL
#define YY_DECL extern int yylex (YYSTYPE *lvalp)
+
+static int at_eof = 0;
%}
%%
@@ -19,15 +23,10 @@
[ tnr]+ { return T_SPACE; }
. { return T_INVALID; }
-%%
+<<EOF>> { at_eof = 1; yyterminate (); }
-static int at_eof = 0;
-int
-yywrap (void)
-{
- return ++at_eof;
-}
+%%
#if defined(UNIT_TEST)
static void
http://repo.or.cz/w/iwhd.git/commit/172ce552307317456a644868ad02aba5b3528ba8
commit 172ce552307317456a644868ad02aba5b3528ba8
Author: Jim Meyering <meyering(a)redhat.com>
Date: Fri Oct 15 13:05:44 2010 +0200
avoid undefined-yydecl warning
diff --git a/qlexer.l b/qlexer.l
index bd2e196..7ae9e87 100644
--- a/qlexer.l
+++ b/qlexer.l
@@ -2,6 +2,7 @@
#include <stdio.h>
#include "iwhd-qparser.h"
+#undef YY_DECL
#define YY_DECL extern int yylex (YYSTYPE *lvalp)
%}
diff --git a/qparser.y b/qparser.y
index c52c2ba..bb6e760 100644
--- a/qparser.y
+++ b/qparser.y
@@ -12,6 +12,9 @@
#include "query.h"
#include "iwhd-qparser.h"
+#define YY_DECL int yylex(YYSTYPE *);
+YY_DECL
+
static void
xalloc_die (void)
{
http://repo.or.cz/w/iwhd.git/commit/66864937990bf7de81e6e5e2fba6ebf521f109c3
commit 66864937990bf7de81e6e5e2fba6ebf521f109c3
Author: Jim Meyering <meyering(a)redhat.com>
Date: Thu Oct 14 18:00:11 2010 +0200
use literals in bison
diff --git a/qlexer.l b/qlexer.l
index 33c86a6..bd2e196 100644
--- a/qlexer.l
+++ b/qlexer.l
@@ -11,17 +11,10 @@
~[^~]*~ { return T_DATE; }
[0-9]+ { return T_NUMBER; }
[a-z_]+ { return T_ID; }
-$ { return T_DOLLAR; }
-# { return T_WAFFLE; }
-( { return T_LPAREN; }
-) { return T_RPAREN; }
-< { return T_LESS; }
-> { return T_GREATER; }
-= { return T_EQUAL; }
+[=$#()<>.] { return yytext[0]; }
! { return T_NOT; }
& { return T_AND; }
| { return T_OR; }
-. { return T_DOT; }
[ tnr]+ { return T_SPACE; }
. { return T_INVALID; }
diff --git a/qparser.y b/qparser.y
index 1f3a389..c52c2ba 100644
--- a/qparser.y
+++ b/qparser.y
@@ -163,9 +163,6 @@ yyerror (value_t **result, const char *msg)
%parse-param { value_t **result }
%token T_STRING T_DATE T_NUMBER T_ID
-%token T_DOLLAR T_WAFFLE T_DOT
-%token T_LPAREN T_RPAREN
-%token T_LESS T_GREATER T_EQUAL
%token T_NOT T_AND T_OR
%token T_SPACE T_INVALID
%token T_OFIELD T_SFIELD T_COMP T_LINK
@@ -224,27 +221,27 @@ comp_expr:
// printf("promoting atom to comp_exprn");
$$ = $1;
}|
- atom T_LESS atom {
+ atom '<' atom {
// printf("found LESS THAN expressionn");
$$ = make_comp(C_LESSTHAN,$1,$3);
}|
- atom T_LESS T_EQUAL atom {
+ atom '<' '=' atom {
// printf("found LESS OR EQUAL expressionn");
$$ = make_comp(C_LESSOREQ,$1,$4);
}|
- atom T_EQUAL T_EQUAL atom {
+ atom '=' '=' atom {
// printf("found EQUAL expressionn");
$$ = make_comp(C_EQUAL,$1,$4);
}|
- atom T_NOT T_EQUAL atom {
+ atom T_NOT '=' atom {
// printf("found NOT EQUAL expressionn");
$$ = make_comp(C_DIFFERENT,$1,$4);
}|
- atom T_GREATER T_EQUAL atom {
+ atom '>' '=' atom {
// printf("found GREATER OR EQUAL expressionn");
$$ = make_comp(C_GREATEROREQ,$1,$4);
}|
- atom T_GREATER atom {
+ atom '>' atom {
// printf("found GREATER THAN expressionn");
$$ = make_comp(C_GREATERTHAN,$1,$3);
}|
@@ -278,17 +275,17 @@ link_field:
// printf("promoting field to link_fieldn");
$$ = $1;
}|
- link_field T_DOT T_ID {
+ link_field '.' T_ID {
// printf("found LINK FIELDn");
$$ = make_link($1,yytext);
};
field:
- T_DOLLAR T_ID {
+ '$' T_ID {
// printf("found DOLLAR FIELDn");
$$ = make_string(yytext,T_OFIELD);
}|
- T_WAFFLE T_ID {
+ '#' T_ID {
// printf("found WAFFLE FIELDn");
$$ = make_string(yytext,T_SFIELD);
};
@@ -312,7 +309,7 @@ literal:
};
paren_expr:
- T_LPAREN bbool_expr T_RPAREN {
+ '(' bbool_expr ')' {
// printf("found PAREN expressionn");
$$ = $2;
};
http://repo.or.cz/w/iwhd.git/commit/e1f97c75f4afa180643691324fa0552877fd8454
commit e1f97c75f4afa180643691324fa0552877fd8454
Author: Jim Meyering <meyering(a)redhat.com>
Date: Thu Oct 14 17:01:43 2010 +0200
static and const
diff --git a/qlexer.l b/qlexer.l
index c90bf15..33c86a6 100644
--- a/qlexer.l
+++ b/qlexer.l
@@ -27,7 +27,7 @@
%%
-int at_eof = 0;
+static int at_eof = 0;
int
yywrap (void)
@@ -37,7 +37,7 @@ yywrap (void)
#if defined(UNIT_TEST)
static void
-yyerror (char *msg)
+yyerror (const char *msg)
{
printf("%s: %sn",__func__,msg);
}
diff --git a/qparser.y b/qparser.y
index 82f9774..1f3a389 100644
--- a/qparser.y
+++ b/qparser.y
@@ -1,3 +1,6 @@
+%define api.pure
+%error-verbose
+
%{
#include <config.h>
#include <error.h>
@@ -59,7 +62,7 @@ xstrdup (char const *string)
}
/* TBD: use separate function to parse dates differently */
-value_t *
+static value_t *
make_number (const char *text)
{
value_t *tmp = malloc(sizeof(*tmp));
@@ -73,7 +76,7 @@ make_number (const char *text)
return tmp;
}
-value_t *
+static value_t *
make_string (const char *text, type_t t)
{
value_t *tmp = malloc(sizeof(*tmp));
@@ -87,23 +90,23 @@ make_string (const char *text, type_t t)
return tmp;
}
-value_t *
-make_tree (type_t t, value_t *left, value_t *right)
+static value_t *
+make_tree (type_t t, const value_t *left, const value_t *right)
{
value_t *tmp = malloc(sizeof(*tmp));
if (tmp) {
tmp->type = t;
- tmp->as_tree.left = left;
- tmp->as_tree.right = right;
+ tmp->as_tree.left = (value_t *) left;
+ tmp->as_tree.right = (value_t *) right;
tmp->resolved = NULL;
}
return tmp;
}
-value_t *
-make_comp (comp_t c, value_t *left, value_t *right)
+static value_t *
+make_comp (comp_t c, const value_t *left, const value_t *right)
{
value_t *tmp = make_tree(T_COMP,left,right);
@@ -114,8 +117,8 @@ make_comp (comp_t c, value_t *left, value_t *right)
return tmp;
}
-value_t *
-make_link (value_t *left, char *right)
+static value_t *
+make_link (value_t *left, const char *right)
{
char *copy;
@@ -157,7 +160,6 @@ yyerror (value_t **result, const char *msg)
%}
-%define api.pure
%parse-param { value_t **result }
%token T_STRING T_DATE T_NUMBER T_ID
@@ -318,7 +320,7 @@ paren_expr:
%%
#if defined PARSER_UNIT_TEST
-struct { char *name; char *value; } hacked_obj_fields[] = {
+static const struct { char *name; char *value; } hacked_obj_fields[] = {
/* Fake object fields for generic unit testing. */
{ "a", "2" }, { "b", "7" }, { "c",
"11" },
/* This one's here to test links (e.g. $template.owner.name). */
@@ -327,7 +329,7 @@ struct { char *name; char *value; } hacked_obj_fields[] = {
};
/* Fake out the eval code for unit testing. */
-const char *
+static const char *
unit_oget_func (void * notused, const char *text)
{
int i;
@@ -340,18 +342,18 @@ unit_oget_func (void * notused, const char *text)
return NULL;
}
-getter_t unit_oget = { unit_oget_func };
+static const getter_t unit_oget = { unit_oget_func };
/*
* Same as above, but the site-field stuff is so similar to the object-field
* stuff that it's not worth exercising too much separately.
*/
-const char *
+static const char *
unit_sget_func (void * notused, const char *text)
{
return "never";
}
-getter_t unit_sget = { unit_sget_func };
+static const getter_t unit_sget = { unit_sget_func };
/* Fake links from an object/key tuple to an object/key string. */
struct { char *obj; char *key; char *value; } hacked_links[] = {
@@ -360,7 +362,7 @@ struct { char *obj; char *key; char *value; } hacked_links[] = {
{ NULL }
};
-char *
+static char *
follow_link (const char *object, const char *key)
{
unsigned int i;
@@ -381,7 +383,7 @@ follow_link (const char *object, const char *key)
extern char *follow_link (const char *object, const char *key);
#endif
-void
+static void
_print_value (const value_t *v, int level)
{
if (!v) {
@@ -505,7 +507,7 @@ parse (const char *text)
* and booleans.
*/
static const char *
-string_value (value_t *v, getter_t *oget, getter_t *sget)
+string_value (value_t *v, const getter_t *oget, const getter_t *sget)
{
const char *left;
@@ -537,7 +539,7 @@ string_value (value_t *v, getter_t *oget, getter_t *sget)
* Check whether a string looks like a simple decimal number. There's
* probably a library function for this somewhere.
*/
-int
+static int
is_ok_number (const char *a_str)
{
const char *p;
@@ -563,9 +565,9 @@ is_ok_number (const char *a_str)
* but the code is actually structured a different way to allow re-use of
* common operator-specific code at the end for both cases.
*/
-int
+static int
compare (value_t *left, comp_t op, value_t *right,
- getter_t *oget, getter_t *sget)
+ const getter_t *oget, const getter_t *sget)
{
const char *lstr;
const char *rstr;
@@ -652,7 +654,7 @@ compare (value_t *left, comp_t op, value_t *right,
*/
int
-eval (const value_t *v, getter_t *oget, getter_t *sget)
+eval (const value_t *v, const getter_t *oget, const getter_t *sget)
{
int res;
const char *str;
diff --git a/query.h b/query.h
index f7823e2..b726632 100644
--- a/query.h
+++ b/query.h
@@ -49,7 +49,8 @@ typedef struct {
} getter_t;
#define CALL_GETTER(g,x) g->func(g->ctx,x)
-int eval (const value_t *expr, getter_t *oget, getter_t *sget);
+int eval (const value_t *expr,
+ const getter_t *oget, const getter_t *sget);
void free_value (value_t *);
void print_value (const value_t *);
http://repo.or.cz/w/iwhd.git/commit/cddd16da84f4beb975f9e96546ea7ad1a6557fb8
commit cddd16da84f4beb975f9e96546ea7ad1a6557fb8
Author: Jim Meyering <meyering(a)redhat.com>
Date: Thu Oct 14 16:43:06 2010 +0200
cast away "const" on free argument
diff --git a/qparser.y b/qparser.y
index c23c03e..82f9774 100644
--- a/qparser.y
+++ b/qparser.y
@@ -459,7 +459,7 @@ free_value (value_t *v)
printf("freeing resolved string "%s" (%p)n",
v->resolved, v->resolved);
}
- free(v->resolved);
+ free((void *)v->resolved);
switch (v->type) {
case T_STRING:
http://repo.or.cz/w/iwhd.git/commit/31e05f1f8045bd38d47eeacfd09a4c27895b10db
commit 31e05f1f8045bd38d47eeacfd09a4c27895b10db
Author: Jim Meyering <meyering(a)redhat.com>
Date: Thu Oct 14 16:41:36 2010 +0200
qparser.y: Include <ctype.h> for use of isdigit
diff --git a/qparser.y b/qparser.y
index 81b2ef6..c23c03e 100644
--- a/qparser.y
+++ b/qparser.y
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#define YYSTYPE value_t *
#include "query.h"
#include "iwhd-qparser.h"
http://repo.or.cz/w/iwhd.git/commit/90c6359047186d03e04a4e73e99d0c935e40be1a
commit 90c6359047186d03e04a4e73e99d0c935e40be1a
Author: Jim Meyering <meyering(a)redhat.com>
Date: Thu Oct 14 16:16:24 2010 +0200
apply Jeff's link-following change
diff --git a/qparser.y b/qparser.y
index d028098..81b2ef6 100644
--- a/qparser.y
+++ b/qparser.y
@@ -519,12 +519,14 @@ string_value (value_t *v, getter_t *oget, getter_t *sget)
case T_SFIELD:
return sget ? CALL_GETTER(sget,v->as_str) : NULL;
case T_LINK:
- left = string_value(v->as_tree.left,oget,sget);
- if (left) {
- return follow_link((char *)left,
- (char *)v->as_tree.right);
+ if (!v->resolved) {
+ left = string_value(v->as_tree.left,oget,sget);
+ if (left) {
+ v->resolved = follow_link((char *)left,
+ (char *)v->as_tree.right);
+ }
}
- /* Fall through. */
+ return v->resolved;
default:
return NULL;
}
http://repo.or.cz/w/iwhd.git/commit/41f6621794a607e2a8a5940d6fb2be22746d2cf1
commit 41f6621794a607e2a8a5940d6fb2be22746d2cf1
Author: Jim Meyering <meyering(a)redhat.com>
Date: Thu Oct 14 16:07:33 2010 +0200
apply jeffs leak-fixing patch from master (manually merge 3 failed hunks)
diff --git a/qparser.y b/qparser.y
index 7902c90..d028098 100644
--- a/qparser.y
+++ b/qparser.y
@@ -66,6 +66,7 @@ make_number (const char *text)
if (tmp) {
tmp->type = T_NUMBER;
tmp->as_num = strtoll(text,NULL,10);
+ tmp->resolved = NULL;
}
return tmp;
@@ -79,6 +80,7 @@ make_string (const char *text, type_t t)
if (tmp) {
tmp->type = t;
tmp->as_str = xstrdup(text);
+ tmp->resolved = NULL;
}
return tmp;
@@ -93,6 +95,7 @@ make_tree (type_t t, value_t *left, value_t *right)
tmp->type = t;
tmp->as_tree.left = left;
tmp->as_tree.right = right;
+ tmp->resolved = NULL;
}
return tmp;
@@ -115,7 +118,7 @@ make_link (value_t *left, char *right)
{
char *copy;
- copy = strdup(right);
+ copy = xstrdup(right);
if (!copy) {
return NULL;
}
@@ -451,6 +454,12 @@ free_value (value_t *v)
return;
}
+ if (v->resolved) {
+ printf("freeing resolved string "%s" (%p)n",
+ v->resolved, v->resolved);
+ }
+ free(v->resolved);
+
switch (v->type) {
case T_STRING:
case T_OFIELD:
@@ -504,8 +513,7 @@ string_value (value_t *v, getter_t *oget, getter_t *sget)
return v->as_str;
case T_OFIELD:
if (!v->resolved) {
- v->resolved = oget
- ? CALL_GETTER(oget,v->as_str) : NULL;
+ v->resolved = oget ? CALL_GETTER(oget,v->as_str) : NULL;
}
return v->resolved;
case T_SFIELD:
http://repo.or.cz/w/iwhd.git/commit/9d0990a469ada32886e0c09e98da498a5106b2fd
commit 9d0990a469ada32886e0c09e98da498a5106b2fd
Author: Jim Meyering <meyering(a)redhat.com>
Date: Thu Oct 14 16:02:08 2010 +0200
parse-test now passes
diff --git a/qparser.y b/qparser.y
index 32e7aac..7902c90 100644
--- a/qparser.y
+++ b/qparser.y
@@ -170,7 +170,6 @@ yyerror (value_t **result, const char *msg)
policy:
bbool_expr {
- printf("policy completen");
if (syntax_error) {
printf("bad policy!n");
}
@@ -314,6 +313,70 @@ paren_expr:
%%
+#if defined PARSER_UNIT_TEST
+struct { char *name; char *value; } hacked_obj_fields[] = {
+ /* Fake object fields for generic unit testing. */
+ { "a", "2" }, { "b", "7" }, { "c",
"11" },
+ /* This one's here to test links (e.g. $template.owner.name). */
+ { "template", "templates/the_tmpl" },
+ { NULL }
+};
+
+/* Fake out the eval code for unit testing. */
+const char *
+unit_oget_func (void * notused, const char *text)
+{
+ int i;
+
+ for (i = 0; hacked_obj_fields[i].name; ++i) {
+ if (!strcmp(hacked_obj_fields[i].name,text)) {
+ return xstrdup(hacked_obj_fields[i].value);
+ }
+ }
+
+ return NULL;
+}
+getter_t unit_oget = { unit_oget_func };
+
+/*
+ * Same as above, but the site-field stuff is so similar to the object-field
+ * stuff that it's not worth exercising too much separately.
+ */
+const char *
+unit_sget_func (void * notused, const char *text)
+{
+ return "never";
+}
+getter_t unit_sget = { unit_sget_func };
+
+/* Fake links from an object/key tuple to an object/key string. */
+struct { char *obj; char *key; char *value; } hacked_links[] = {
+ { "templates/the_tmpl", "owner", "users/the_user" },
+ { "users/the_user", "name", "Jeff Darcy" },
+ { NULL }
+};
+
+char *
+follow_link (const char *object, const char *key)
+{
+ unsigned int i;
+
+ for (i = 0; hacked_links[i].obj; ++i) {
+ if (strcmp(object,hacked_links[i].obj)) {
+ continue;
+ }
+ if (strcmp(key,hacked_links[i].key)) {
+ continue;
+ }
+ return hacked_links[i].value;
+ }
+
+ return NULL;
+}
+#else
+extern char *follow_link (const char *object, const char *key);
+#endif
+
void
_print_value (const value_t *v, int level)
{
@@ -330,7 +393,7 @@ _print_value (const value_t *v, int level)
printf("%*sSTRING %sn",level,"",v->as_str);
break;
case T_OFIELD:
-#if defined(UNIT_TEST)
+#if defined PARSER_UNIT_TEST
printf("%*sOBJECT FIELD %s (%s)n",level,"",v->as_str,
unit_oget_func(NULL,v->as_str));
#else
@@ -338,7 +401,7 @@ _print_value (const value_t *v, int level)
#endif
break;
case T_SFIELD:
-#if defined(UNIT_TEST)
+#if defined PARSER_UNIT_TEST
printf("%*sSERVER FIELD %s (%s)n",level,"",v->as_str,
unit_sget_func(NULL,v->as_str));
#else
@@ -426,10 +489,208 @@ parse (const char *text)
return r;
}
+/*
+ * Return the string value of an expression for comparison or display, iff
+ * all component parts are string-valued themselves. That excludes numbers
+ * and booleans.
+ */
+static const char *
+string_value (value_t *v, getter_t *oget, getter_t *sget)
+{
+ const char *left;
+
+ switch (v->type) {
+ case T_STRING:
+ return v->as_str;
+ case T_OFIELD:
+ if (!v->resolved) {
+ v->resolved = oget
+ ? CALL_GETTER(oget,v->as_str) : NULL;
+ }
+ return v->resolved;
+ case T_SFIELD:
+ return sget ? CALL_GETTER(sget,v->as_str) : NULL;
+ case T_LINK:
+ left = string_value(v->as_tree.left,oget,sget);
+ if (left) {
+ return follow_link((char *)left,
+ (char *)v->as_tree.right);
+ }
+ /* Fall through. */
+ default:
+ return NULL;
+ }
+}
+
+/*
+ * Check whether a string looks like a simple decimal number. There's
+ * probably a library function for this somewhere.
+ */
+int
+is_ok_number (const char *a_str)
+{
+ const char *p;
+
+ if (!a_str) {
+ return 0;
+ }
+
+ for (p = a_str; *p; ++p) {
+ if (!isdigit(*p)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Comparisons are a bit messy. If both sides are numbers, strings that look
+ * like numbers, or expressions that evaluate to numbers (booleans evaluate
+ * to 0/1), then we do a numeric comparison. Otherwise, if both sides
+ * evaluate to strings, we attempt a string comparison. That's the logic,
+ * but the code is actually structured a different way to allow re-use of
+ * common operator-specific code at the end for both cases.
+ */
+int
+compare (value_t *left, comp_t op, value_t *right,
+ getter_t *oget, getter_t *sget)
+{
+ const char *lstr;
+ const char *rstr;
+ int lval = 0; // solely to placate gcc
+ int rval;
+ int num_ok = 1;
+
+ lstr = string_value(left,oget,sget);
+ rstr = string_value(right,oget,sget);
+
+ if (left->type == T_NUMBER) {
+ lval = left->as_num;
+ }
+ else if (lstr) {
+ if (is_ok_number(lstr)) {
+ lval = strtoll(lstr,NULL,0);
+ }
+ else {
+ num_ok = 0;
+ }
+ }
+ else {
+ lval = eval(left,oget,sget);
+ if (lval < 0) {
+ return lval;
+ }
+ }
+
+ if (right->type == T_NUMBER) {
+ rval = right->as_num;
+ }
+ else if (rstr) {
+ if (is_ok_number(rstr)) {
+ rval = strtoll(rstr,NULL,0);
+ }
+ else {
+ num_ok = 0;
+ }
+ }
+ else {
+ rval = eval(right,oget,sget);
+ if (rval < 0) {
+ return rval;
+ }
+ }
+
+ /*
+ * Strcmp returns -1/0/1, but -1 for us would mean an error and
+ * which of 0/1 we return depends on which comparison operatoer
+ * we're dealing with. Therefore, we stick the strcmp result on
+ * the left side and let the switch below do an operator-appropriate
+ * compare against zero on the right.
+ */
+ if (!num_ok) {
+ if (!lstr || !rstr) {
+ return -1;
+ }
+ lval = strcmp(lstr,rstr);
+ rval = 0;
+ }
+
+ switch (op) {
+ case C_LESSTHAN: return (lval < rval);
+ case C_LESSOREQ: return (lval <= rval);
+ case C_EQUAL: return (lval == rval);
+ case C_DIFFERENT: return (lval != rval);
+ case C_GREATEROREQ: return (lval >= rval);
+ case C_GREATERTHAN: return (lval > rval);
+ default:
+ return -1;
+ }
+}
+
+/*
+ * Evaluate an AST in the current context to one of:
+ * true=1
+ * false=0
+ * error=-1
+ * It's up to the caller whether error is functionally the same as false.
+ * Note that even T_NUMBER gets squeezed down to these three values. The
+ * only thing numbers are used for is comparing against other numbers to
+ * yield a boolean for the query or replication-policy code. If you want
+ * something that returns a number, this is the wrong language for it.
+ */
+
+int
+eval (const value_t *v, getter_t *oget, getter_t *sget)
+{
+ int res;
+ const char *str;
+
+ switch (v->type) {
+ case T_NUMBER:
+ return v->as_num != 0;
+ case T_STRING:
+ return v->as_str && *v->as_str;
+ case T_OFIELD:
+ str = CALL_GETTER(oget,v->as_str);
+ return str && *str;
+ case T_SFIELD:
+ str = CALL_GETTER(sget,v->as_str);
+ return str && *str;
+ case T_LINK:
+ str = string_value(v->as_tree.left,oget,sget);
+ if (str) {
+ str = follow_link(str,(char *)v->as_tree.right);
+ }
+ return str && *str;
+ case T_COMP:
+ return compare(v->as_tree.left,(comp_t)v->as_tree.op,
+ v->as_tree.right, oget, sget);
+ case T_NOT:
+ res = eval(v->as_tree.left,oget,sget);
+ return (res >= 0) ? !res : res;
+ case T_AND:
+ res = eval(v->as_tree.left,oget,sget);
+ if (res > 0) {
+ res = eval(v->as_tree.right,oget,sget);
+ }
+ return res;
+ case T_OR:
+ res = eval(v->as_tree.left,oget,sget);
+ if (res > 0) {
+ return res;
+ }
+ return eval(v->as_tree.right,oget,sget);
+ default:
+ return -1;
+ }
+}
+
#ifdef PARSER_UNIT_TEST
int
main (int argc, char **argv)
{
+ int fail = 0;
unsigned int i;
for (i = 1; i < argc; ++i)
{
@@ -437,22 +698,21 @@ main (int argc, char **argv)
if (!expr)
{
printf ("could not parse '%s'n", argv[i]);
+ fail = 1;
continue;
}
print_value (expr);
-#if 0
- char *str = string_value (expr, &unit_oget, &unit_sget);
+
+ const char *str = string_value (expr, &unit_oget, &unit_sget);
if (str)
{
printf ("s= %sn", str);
continue;
}
- res = eval (expr, &unit_oget, &unit_sget);
- printf ("d= %dn", res);
-#endif
+ printf ("d= %dn", eval (expr, &unit_oget, &unit_sget));
}
- return 0;
+ return fail;
}
#endif
http://repo.or.cz/w/iwhd.git/commit/19f9c826b6a2e6ad5dc51f1e1c4030f1eac82553
commit 19f9c826b6a2e6ad5dc51f1e1c4030f1eac82553
Author: Jim Meyering <meyering(a)redhat.com>
Date: Fri Oct 15 14:50:59 2010 +0200
build: rearrange things to use Bison/Flex; adapt; clean up
diff --git a/.gitignore b/.gitignore
index e032047..c495020 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,11 @@ config.log
config.status
configure
iwhd
-query-orig.c
-query.c
+iwhd-*.tar.gz
+iwhd-qparser.c
+iwhd-qparser.h
+qlexer.c
stamp-h1
+t/*.log
+t/parser
+t/parser.c
diff --git a/Makefile.am b/Makefile.am
index ac88336..60dce9a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,11 +18,14 @@ AM_CFLAGS = -W -Wall -Wextra -Wno-unused -Wformat-security
AM_CPPFLAGS = -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include
+iwhd_YFLAGS = -d
+
SUBDIRS = t
ACLOCAL_AMFLAGS = -I ax
bin_PROGRAMS = iwhd
-EXTRA_DIST = query.leg
+EXTRA_DIST = iwhd-qparser.h
+BUILT_SOURCES = iwhd-qparser.h qlexer.c
# iwhd is short for Image WareHouse Daemon.
@@ -37,7 +40,7 @@ iwhd_SOURCES = mpipe.h replica.c replica.h - query.c +
qparser.y query.h rest.c setup.c @@ -46,6 +49,8 @@ iwhd_SOURCES = template.c
template.h
+EXTRA_iwhd_SOURCES = qlexer.l
+
iwhd_CPPFLAGS = $(HAIL_CFLAGS)
iwhd_LDADD = -lmongoclient @@ -60,18 +65,6 @@ iwhd_LDADD = $(GLIB2_LIB)
$(HAIL_LIBS)
-# leg is a lexer/parser-generator
-#
http://piumarta.com/software/peg/peg-0.1.4.tar.gz
-query-orig.c: query.leg
- leg < $(srcdir)/query.leg > $@-t && mv $@-t $@
-
-# Apply this patch to fix NULL-deref bugs in the generated query-orig.c:
-query.c: query-orig.c query.c.diff
- patch --fuzz=0 query-orig.c $(srcdir)/query.c.diff --output=$@-t
- mv $@-t $@
-
-BUILT_SOURCES = query.c
-CLEANFILES = query-orig.c
-MOSTLYCLEANFILES = query.c query-orig.c-t
-MAINTAINERCLEANFILES = query.c query-orig.c
-EXTRA_DIST += query.c.diff
+MOSTLYCLEANFILES = qlexer.c
+MAINTAINERCLEANFILES = qlexer.c
+EXTRA_DIST += qlexer.c
diff --git a/configure.ac b/configure.ac
index bd0609b..afbe4c3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -28,10 +28,8 @@ AM_SILENT_RULES([yes]) # make --enable-silent-rules the default.
AC_PROG_CXX
AC_PROG_CC
AM_PROG_CC_C_O
-
-leg -V > /dev/null 2>&1 ||
- AC_MSG_ERROR([you need the leg program to build this code;
- <
http://piumarta.com/software/peg/>])
+AC_PROG_YACC
+AC_PROG_LEX
AC_CHECK_LIB([curl], [curl_easy_init],
[CURL_LIB=-lcurl],
diff --git a/qlexer.l b/qlexer.l
index 73e685f..c90bf15 100644
--- a/qlexer.l
+++ b/qlexer.l
@@ -1,22 +1,13 @@
%{
#include <stdio.h>
-#if defined(UNIT_TEST)
-enum {
- T_STRING, T_DATE, T_NUMBER, T_ID,
- T_DOLLAR, T_WAFFLE, T_LPAREN, T_RPAREN,
- T_LESS, T_GREATER, T_EQUAL, T_NOT,
- T_AND, T_OR, T_DOT, T_SPACE,
- T_INVALID
-};
-#else
-#include "qparser.tab.h"
-#endif
+#include "iwhd-qparser.h"
+#define YY_DECL extern int yylex (YYSTYPE *lvalp)
%}
%%
-"[^"]*" { return T_STRING; }
+"[^"]*" { yytext[yyleng-1] = 0; yytext++; return T_STRING; }
~[^~]*~ { return T_DATE; }
[0-9]+ { return T_NUMBER; }
[a-z_]+ { return T_ID; }
@@ -54,12 +45,12 @@ yyerror (char *msg)
int
main (int argc, char **argv)
{
- int t;
yy_scan_string(""!@#" ~xxx~ 123 abc $#()<>=!&|.");
do {
- t = yylex();
+ YYSTYPE v;
+ int t = yylex(&v);
switch (t) {
case T_STRING:
if (!yytext[0]) {
diff --git a/qparser.y b/qparser.y
index 7df27a1..32e7aac 100644
--- a/qparser.y
+++ b/qparser.y
@@ -4,9 +4,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "query.h"
#define YYSTYPE value_t *
-#include "qparser.h"
+#include "query.h"
+#include "iwhd-qparser.h"
static void
xalloc_die (void)
@@ -133,9 +133,6 @@ make_link (value_t *left, char *right)
*/
extern char *yytext;
-/* In a sane world, yyparse would return this. */
-value_t *cur_val;
-
/*
* IMO it's wrong for us to get into the bbool_expr=policy rule when there's
* a syntax error, but we do. The good news is that it's easy to free the
@@ -144,17 +141,21 @@ value_t *cur_val;
* ourselves) to figure out whether we got a valid tree or not.
* No, yynerrs doesn't seem to give the right answer.
*/
-int syntax_error = 0;
+static int syntax_error = 0;
void
-yyerror (char *msg)
+yyerror (value_t **result, const char *msg)
{
- printf("%s: %sn",__func__,msg);
- syntax_error = 1;
+ // error (0, 0, "parse error: %sn", msg);
+ // FIXME do this via param, not file-global
+ syntax_error = 1;
}
%}
+%define api.pure
+%parse-param { value_t **result }
+
%token T_STRING T_DATE T_NUMBER T_ID
%token T_DOLLAR T_WAFFLE T_DOT
%token T_LPAREN T_RPAREN
@@ -174,21 +175,21 @@ policy:
printf("bad policy!n");
}
else {
- cur_val = $1;
+ *result = $1;
}
};
bbool_expr:
ubool_expr {
- printf("promoting ubool_expr to bbool_exprn");
+ // printf("promoting ubool_expr to bbool_exprn");
$$ = $1;
}|
bbool_expr T_AND T_AND ubool_expr {
- printf("found AND expressionn");
+ // printf("found AND expressionn");
$$ = make_tree(T_AND,$1,$4);
}|
bbool_expr T_OR T_OR ubool_expr {
- printf("found OR expressionn");
+ // printf("found OR expressionn");
$$ = make_tree(T_OR,$1,$4);
}|
bbool_expr T_SPACE {
@@ -199,11 +200,11 @@ bbool_expr:
ubool_expr:
comp_expr {
- printf("promoting comp_expr to ubool_exprn");
+ // printf("promoting comp_expr to ubool_exprn");
$$ = $1;
}|
T_NOT comp_expr {
- printf("found NOT expressionn");
+ // printf("found NOT expressionn");
$$ = make_tree(T_NOT,$2,NULL);
}|
ubool_expr T_SPACE {
@@ -215,31 +216,31 @@ ubool_expr:
comp_expr:
atom {
- printf("promoting atom to comp_exprn");
+ // printf("promoting atom to comp_exprn");
$$ = $1;
}|
atom T_LESS atom {
- printf("found LESS THAN expressionn");
+ // printf("found LESS THAN expressionn");
$$ = make_comp(C_LESSTHAN,$1,$3);
}|
atom T_LESS T_EQUAL atom {
- printf("found LESS OR EQUAL expressionn");
+ // printf("found LESS OR EQUAL expressionn");
$$ = make_comp(C_LESSOREQ,$1,$4);
}|
atom T_EQUAL T_EQUAL atom {
- printf("found EQUAL expressionn");
+ // printf("found EQUAL expressionn");
$$ = make_comp(C_EQUAL,$1,$4);
}|
atom T_NOT T_EQUAL atom {
- printf("found NOT EQUAL expressionn");
+ // printf("found NOT EQUAL expressionn");
$$ = make_comp(C_DIFFERENT,$1,$4);
}|
atom T_GREATER T_EQUAL atom {
- printf("found GREATER OR EQUAL expressionn");
+ // printf("found GREATER OR EQUAL expressionn");
$$ = make_comp(C_GREATEROREQ,$1,$4);
}|
atom T_GREATER atom {
- printf("found GREATER THAN expressionn");
+ // printf("found GREATER THAN expressionn");
$$ = make_comp(C_GREATERTHAN,$1,$3);
}|
comp_expr T_SPACE {
@@ -250,15 +251,15 @@ comp_expr:
atom:
link_field {
- printf("promoting link_field to atomn");
+ // printf("promoting link_field to atomn");
$$ = $1;
}|
literal {
- printf("promoting literal to atomn");
+ // printf("promoting literal to atomn");
$$ = $1;
}|
paren_expr {
- printf("promoting paren_expr to atomn");
+ // printf("promoting paren_expr to atomn");
$$ = $1;
}|
atom T_SPACE {
@@ -269,45 +270,45 @@ atom:
link_field:
field {
- printf("promoting field to link_fieldn");
+ // printf("promoting field to link_fieldn");
$$ = $1;
}|
link_field T_DOT T_ID {
- printf("found LINK FIELDn");
+ // printf("found LINK FIELDn");
$$ = make_link($1,yytext);
};
field:
T_DOLLAR T_ID {
- printf("found DOLLAR FIELDn");
+ // printf("found DOLLAR FIELDn");
$$ = make_string(yytext,T_OFIELD);
}|
T_WAFFLE T_ID {
- printf("found WAFFLE FIELDn");
+ // printf("found WAFFLE FIELDn");
$$ = make_string(yytext,T_SFIELD);
};
literal:
T_NUMBER {
- printf("found NUMBER %sn",yytext);
+ // printf("found NUMBER %sn",yytext);
$$ = make_number(yytext);
}|
T_STRING {
- printf("found STRING %sn",yytext);
+ // printf("found STRING %sn",yytext);
$$ = make_string(yytext,T_STRING);
}|
T_DATE {
- printf("found DATEn");
+ // printf("found DATEn");
$$ = make_string(yytext,T_DATE);
}|
T_ID {
- printf("found ID %sn",yytext);
+ // printf("found ID %sn",yytext);
$$ = make_string(yytext,T_ID);
};
paren_expr:
T_LPAREN bbool_expr T_RPAREN {
- printf("found PAREN expressionn");
+ // printf("found PAREN expressionn");
$$ = $2;
};
@@ -413,39 +414,45 @@ free_value (value_t *v)
}
}
+#include "qlexer.c"
+
+value_t *
+parse (const char *text)
+{
+ yy_scan_string(text);
+ value_t *result;
+ value_t *r = yyparse (&result) == 0 ? result : NULL;
+ yylex_destroy();
+ return r;
+}
+
+#ifdef PARSER_UNIT_TEST
int
main (int argc, char **argv)
{
- char *data = "#a=="fubar"&&!($b.c.d<3)";
- char *edata = "gobbledy-gook";
-
- yy_scan_string(data);
- yyparse();
- if (cur_val) {
- if (!syntax_error) {
- print_value(cur_val);
- }
- else {
- printf("discarding erroneous parse treen");
- }
- free_value(cur_val);
- cur_val = NULL;
+ unsigned int i;
+ for (i = 1; i < argc; ++i)
+ {
+ value_t *expr = parse (argv[i]);
+ if (!expr)
+ {
+ printf ("could not parse '%s'n", argv[i]);
+ continue;
}
- yylex_destroy();
- yy_scan_string(edata);
- yyparse();
- if (cur_val) {
- if (!syntax_error) {
- print_value(cur_val);
- }
- else {
- printf("discarding erroneous parse treen");
- }
- free_value(cur_val);
- cur_val = NULL;
+ print_value (expr);
+#if 0
+ char *str = string_value (expr, &unit_oget, &unit_sget);
+ if (str)
+ {
+ printf ("s= %sn", str);
+ continue;
}
- yylex_destroy();
+ res = eval (expr, &unit_oget, &unit_sget);
+ printf ("d= %dn", res);
+#endif
+ }
- return 0;
+ return 0;
}
+#endif
diff --git a/query.h b/query.h
index 8189633..f7823e2 100644
--- a/query.h
+++ b/query.h
@@ -19,16 +19,15 @@
extern "C" {
#endif
+#include "iwhd-qparser.h"
+
typedef enum {
C_LESSTHAN, C_LESSOREQ,
C_EQUAL, C_DIFFERENT,
C_GREATEROREQ, C_GREATERTHAN
} comp_t;
-typedef enum {
- T_NUMBER, T_STRING, T_OFIELD, T_SFIELD,
- T_COMP, T_NOT, T_AND, T_OR, T_LINK
-} type_t;
+typedef enum yytokentype type_t;
typedef struct _value {
type_t type;
@@ -50,12 +49,12 @@ typedef struct {
} getter_t;
#define CALL_GETTER(g,x) g->func(g->ctx,x)
-
-value_t *parse (const char *text);
int eval (const value_t *expr, getter_t *oget, getter_t *sget);
void free_value (value_t *);
void print_value (const value_t *);
+value_t *parse (const char *text);
+
#if defined(__CPLUSPLUS__) || defined(__cplusplus)
}
#endif
diff --git a/t/Makefile.am b/t/Makefile.am
index 91f0ad4..c2a0af6 100644
--- a/t/Makefile.am
+++ b/t/Makefile.am
@@ -34,8 +34,8 @@ parser_CPPFLAGS = -I $(top_srcdir)
parser.c: Makefile.am
rm -f $@-t $@
- printf '#define UNIT_TEST 1n' > $@-t
- printf '#include "query.c"n' >> $@-t
+ printf '#define PARSER_UNIT_TEST 1n' > $@-t
+ printf '#include "iwhd-qparser.c"n' >> $@-t
chmod a=r $@-t
mv $@-t $@
http://repo.or.cz/w/iwhd.git/commit/5ed3c7cb77b0d921759f9407dd17dbb9b2b54ba3
commit 5ed3c7cb77b0d921759f9407dd17dbb9b2b54ba3
Author: Jim Meyering <meyering(a)redhat.com>
Date: Thu Oct 14 16:54:58 2010 +0200
remove query.leg and query.c.diff
* query.c.diff: Remove file.
* query.leg: Likewise.
diff --git a/query.c.diff b/query.c.diff
deleted file mode 100644
index 1442652..0000000
--- a/query.c.diff
+++ /dev/null
@@ -1,47 +0,0 @@
---- query-orig.c 2010-10-12 12:32:09.666434835 -0400
-+++ query.c 2010-10-12 12:32:09.692391504 -0400
-@@ -594,7 +594,7 @@ YY_LOCAL(int) yyrefill(void)
- while (yybuflen - yypos < 512)
- {
- yybuflen *= 2;
-- yybuf= realloc(yybuf, yybuflen);
-+ yybuf= xrealloc(yybuf, yybuflen);
- }
- YY_INPUT((yybuf + yypos), yyn, (yybuflen - yypos));
- if (!yyn) return 0;
-@@ -659,7 +659,7 @@ YY_LOCAL(void) yyDo(yyaction action, int
- while (yythunkpos >= yythunkslen)
- {
- yythunkslen *= 2;
-- yythunks= realloc(yythunks, sizeof(yythunk) * yythunkslen);
-+ yythunks= xrealloc(yythunks, sizeof(yythunk) * yythunkslen);
- }
- yythunks[yythunkpos].begin= begin;
- yythunks[yythunkpos].end= end;
-@@ -677,7 +677,7 @@ YY_LOCAL(int) yyText(int begin, int end)
- while (yytextlen < (yyleng - 1))
- {
- yytextlen *= 2;
-- yytext= realloc(yytext, yytextlen);
-+ yytext= xrealloc(yytext, yytextlen);
- }
- memcpy(yytext, yybuf + begin, yyleng);
- }
-@@ -1215,13 +1215,13 @@ YY_PARSE(int) YYPARSEFROM(yyrule yystart
- if (!yybuflen)
- {
- yybuflen= 1024;
-- yybuf= malloc(yybuflen);
-+ yybuf= xmalloc(yybuflen);
- yytextlen= 1024;
-- yytext= malloc(yytextlen);
-+ yytext= xmalloc(yytextlen);
- yythunkslen= 32;
-- yythunks= malloc(sizeof(yythunk) * yythunkslen);
-+ yythunks= xmalloc(sizeof(yythunk) * yythunkslen);
- yyvalslen= 32;
-- yyvals= malloc(sizeof(YYSTYPE) * yyvalslen);
-+ yyvals= xmalloc(sizeof(YYSTYPE) * yyvalslen);
- yybegin= yyend= yypos= yylimit= yythunkpos= 0;
- }
- yybegin= yyend= yypos;
diff --git a/query.leg b/query.leg
deleted file mode 100644
index 403f0d0..0000000
--- a/query.leg
+++ /dev/null
@@ -1,617 +0,0 @@
-%{
-/* Copyright (C) 2010 Red Hat, Inc.
-
- This program 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 of the License, or
- (at your option) any later version.
-
- This program 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 this program. If not, see <
http://www.gnu.org/licenses/>. */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <error.h>
-#include "query.h"
-
-const char *arg_buf;
-int arg_off;
-int arg_len;
-value_t **cur_expr;
-
-static void
-xalloc_die (void)
-{
- error (EXIT_FAILURE, 0, "%s", "memory exhausted");
-
- /* The `noreturn' cannot be given to error, since it may return if
- its first argument is 0. To help compilers understand the
- xalloc_die does not return, call abort. Also, the abort is a
- safety feature if exit_failure is 0 (which shouldn't happen). */
- abort ();
-}
-
-/* Allocate N bytes of memory dynamically, with error checking. */
-static void *
-xmalloc (size_t n)
-{
- void *p = malloc (n);
- if (!p && n != 0)
- xalloc_die ();
- return p;
-}
-
-/* Change the size of an allocated block of memory P to N bytes,
- with error checking. */
-static void *
-xrealloc (void *p, size_t n)
-{
- p = realloc (p, n);
- if (!p && n != 0)
- xalloc_die ();
- return p;
-}
-
-/* Clone an object P of size S, with error checking. There's no need
- for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any
- need for an arithmetic overflow check. */
-static void *
-xmemdup (void const *p, size_t s)
-{
- return memcpy (xmalloc (s), p, s);
-}
-
-/* Clone STRING. */
-static char *
-xstrdup (char const *string)
-{
- return xmemdup (string, strlen (string) + 1);
-}
-
-/* TBD: use separate function to parse dates differently */
-value_t *
-make_number (const char *text)
-{
- value_t *tmp = malloc(sizeof(*tmp));
-
- if (tmp) {
- tmp->type = T_NUMBER;
- tmp->as_num = strtoll(text,NULL,10);
- tmp->resolved = NULL;
- }
-
- return tmp;
-}
-
-value_t *
-make_string (const char *text, type_t t)
-{
- value_t *tmp = malloc(sizeof(*tmp));
-
- if (tmp) {
- tmp->type = t;
- tmp->as_str = xstrdup(text);
- tmp->resolved = NULL;
- }
-
- return tmp;
-}
-
-value_t *
-make_tree (type_t t, value_t *left, value_t *right)
-{
- value_t *tmp = malloc(sizeof(*tmp));
-
- if (tmp) {
- tmp->type = t;
- tmp->as_tree.left = left;
- tmp->as_tree.right = right;
- tmp->resolved = NULL;
- }
-
- return tmp;
-}
-
-value_t *
-make_comp (comp_t c, value_t *left, value_t *right)
-{
- value_t *tmp = make_tree(T_COMP,left,right);
-
- if (tmp) {
- tmp->as_tree.op = c;
- }
-
- return tmp;
-}
-
-value_t *
-make_link (value_t *left, value_t *right)
-{
- char *copy;
-
- copy = xstrdup((char *)right);
- if (!copy) {
- return NULL;
- }
-
- return make_tree(T_LINK,left,(value_t *)copy);
-}
-
-#if defined(UNIT_TEST)
-struct { char *name; char *value; } hacked_obj_fields[] = {
- /* Fake object fields for generic unit testing. */
- { "a", "2" }, { "b", "7" }, { "c",
"11" },
- /* This one's here to test links (e.g. $template.owner.name). */
- { "template", "templates/the_tmpl" },
- { NULL }
-};
-
-/* Fake out the eval code for unit testing. */
-const char *
-unit_oget_func (void * notused, const char *text)
-{
- int i;
-
- for (i = 0; hacked_obj_fields[i].name; ++i) {
- if (!strcmp(hacked_obj_fields[i].name,text)) {
- return xstrdup(hacked_obj_fields[i].value);
- }
- }
-
- return NULL;
-}
-getter_t unit_oget = { unit_oget_func };
-
-/*
- * Same as above, but the site-field stuff is so similar to the object-field
- * stuff that it's not worth exercising too much separately.
- */
-const char *
-unit_sget_func (void * notused, const char *text)
-{
- return "never";
-}
-getter_t unit_sget = { unit_sget_func };
-
-/* Fake links from an object/key tuple to an object/key string. */
-struct { char *obj; char *key; char *value; } hacked_links[] = {
- { "templates/the_tmpl", "owner", "users/the_user" },
- { "users/the_user", "name", "Jeff Darcy" },
- { NULL }
-};
-
-char *
-follow_link (const char *object, const char *key)
-{
- unsigned int i;
-
- for (i = 0; hacked_links[i].obj; ++i) {
- if (strcmp(object,hacked_links[i].obj)) {
- continue;
- }
- if (strcmp(key,hacked_links[i].key)) {
- continue;
- }
- return hacked_links[i].value;
- }
-
- return NULL;
-}
-#else
-extern char *follow_link (const char *object, const char *key);
-#endif
-
-/*
- * Return the string value of an expression for comparison or display, iff
- * all component parts are string-valued themselves. That excludes numbers
- * and booleans.
- */
-const char *
-string_value (value_t *v, getter_t *oget, getter_t *sget)
-{
- const char *left;
-
- switch (v->type) {
- case T_STRING:
- return v->as_str;
- case T_OFIELD:
- if (!v->resolved) {
- v->resolved = oget
- ? CALL_GETTER(oget,v->as_str) : NULL;
- }
- return v->resolved;
- case T_SFIELD:
- return sget ? CALL_GETTER(sget,v->as_str) : NULL;
- case T_LINK:
- if (!v->resolved) {
- left = string_value(v->as_tree.left,oget,sget);
- if (left) {
- v->resolved = follow_link((char *)left,
- (char *)v->as_tree.right);
- }
- }
- return v->resolved;
- default:
- return NULL;
- }
-}
-
-/*
- * Check whether a string looks like a simple decimal number. There's
- * probably a library function for this somewhere.
- */
-int
-is_ok_number (const char *a_str)
-{
- const char *p;
-
- if (!a_str) {
- return 0;
- }
-
- for (p = a_str; *p; ++p) {
- if (!isdigit(*p)) {
- return 0;
- }
- }
-
- return 1;
-}
-
-/*
- * Comparisons are a bit messy. If both sides are numbers, strings that look
- * like numbers, or expressions that evaluate to numbers (booleans evaluate
- * to 0/1), then we do a numeric comparison. Otherwise, if both sides
- * evaluate to strings, we attempt a string comparison. That's the logic,
- * but the code is actually structured a different way to allow re-use of
- * common operator-specific code at the end for both cases.
- */
-int
-compare (value_t *left, comp_t op, value_t *right,
- getter_t *oget, getter_t *sget)
-{
- const char *lstr;
- const char *rstr;
- int lval = 0; // solely to placate gcc
- int rval;
- int num_ok = 1;
-
- lstr = string_value(left,oget,sget);
- rstr = string_value(right,oget,sget);
-
- if (left->type == T_NUMBER) {
- lval = left->as_num;
- }
- else if (lstr) {
- if (is_ok_number(lstr)) {
- lval = strtoll(lstr,NULL,0);
- }
- else {
- num_ok = 0;
- }
- }
- else {
- lval = eval(left,oget,sget);
- if (lval < 0) {
- return lval;
- }
- }
-
- if (right->type == T_NUMBER) {
- rval = right->as_num;
- }
- else if (rstr) {
- if (is_ok_number(rstr)) {
- rval = strtoll(rstr,NULL,0);
- }
- else {
- num_ok = 0;
- }
- }
- else {
- rval = eval(right,oget,sget);
- if (rval < 0) {
- return rval;
- }
- }
-
- /*
- * Strcmp returns -1/0/1, but -1 for us would mean an error and
- * which of 0/1 we return depends on which comparison operatoer
- * we're dealing with. Therefore, we stick the strcmp result on
- * the left side and let the switch below do an operator-appropriate
- * compare against zero on the right.
- */
- if (!num_ok) {
- if (!lstr || !rstr) {
- return -1;
- }
- lval = strcmp(lstr,rstr);
- rval = 0;
- }
-
- switch (op) {
- case C_LESSTHAN: return (lval < rval);
- case C_LESSOREQ: return (lval <= rval);
- case C_EQUAL: return (lval == rval);
- case C_DIFFERENT: return (lval != rval);
- case C_GREATEROREQ: return (lval >= rval);
- case C_GREATERTHAN: return (lval > rval);
- default:
- return -1;
- }
-}
-
-void
-_print_value (const value_t *v, int level)
-{
- if (!v) {
- printf("%*sNULLn",level,"");
- return;
- }
-
- switch (v->type) {
- case T_NUMBER:
- printf("%*sNUMBER %lldn",level,"",v->as_num);
- break;
- case T_STRING:
- printf("%*sSTRING %sn",level,"",v->as_str);
- break;
- case T_OFIELD:
-#if defined(UNIT_TEST)
- printf("%*sOBJECT FIELD %s (%s)n",level,"",v->as_str,
- unit_oget_func(NULL,v->as_str));
-#else
- printf("%*sOBJECT FIELD %sn",level,"",v->as_str);
-#endif
- break;
- case T_SFIELD:
-#if defined(UNIT_TEST)
- printf("%*sSERVER FIELD %s (%s)n",level,"",v->as_str,
- unit_sget_func(NULL,v->as_str));
-#else
- printf("%*sSERVER FIELD %sn",level,"",v->as_str);
-#endif
- break;
- case T_COMP:
- printf("%*sCOMPARISONn",level,"");
- _print_value(v->as_tree.left,level+2);
- _print_value(v->as_tree.right,level+2);
- break;
- case T_NOT:
- printf("%*sNOTn",level,"");
- _print_value(v->as_tree.left,level+2);
- break;
- case T_AND:
- printf("%*sANDn",level,"");
- _print_value(v->as_tree.left,level+2);
- _print_value(v->as_tree.right,level+2);
- break;
- case T_OR:
- printf("%*sORn",level,"");
- _print_value(v->as_tree.left,level+2);
- _print_value(v->as_tree.right,level+2);
- break;
- case T_LINK:
- printf("%*sLINKn",level,"");
- _print_value(v->as_tree.left,level+2);
- printf("%*sDEST FIELD %sn",level+2,"",
- (char *)v->as_tree.right);
- break;
- default:
- printf("%*sUNKNOWN %dn",level,"",v->type);
- }
-}
-
-void
-print_value (const value_t *v)
-{
- _print_value(v,0);
-}
-
-void
-free_value (value_t *v)
-{
- if (!v) {
- return;
- }
-
- free((char *)v->resolved);
-
- switch (v->type) {
- case T_STRING:
- case T_OFIELD:
- case T_SFIELD:
- free(v->as_str);
- free(v);
- break;
- case T_LINK:
- free_value(v->as_tree.left);
- free(v->as_tree.right);
- free(v);
- break;
- case T_COMP:
- case T_AND:
- case T_OR:
- free_value(v->as_tree.right);
- /* Fall through. */
- case T_NOT:
- free_value(v->as_tree.left);
- /* Fall through. */
- default:
- free(v);
- }
-}
-
-/*
- * Evaluate an AST in the current context to one of:
- * true=1
- * false=0
- * error=-1
- * It's up to the caller whether error is functionally the same as false.
- * Note that even T_NUMBER gets squeezed down to these three values. The
- * only thing numbers are used for is comparing against other numbers to
- * yield a boolean for the query or replication-policy code. If you want
- * something that returns a number, this is the wrong language for it.
- */
-
-int
-eval (const value_t *v, getter_t *oget, getter_t *sget)
-{
- int res;
- const char *str;
-
- switch (v->type) {
- case T_NUMBER:
- return v->as_num != 0;
- case T_STRING:
- return v->as_str && *v->as_str;
- case T_OFIELD:
- str = CALL_GETTER(oget,v->as_str);
- return str && *str;
- case T_SFIELD:
- str = CALL_GETTER(sget,v->as_str);
- return str && *str;
- case T_LINK:
- str = string_value(v->as_tree.left,oget,sget);
- if (str) {
- str = follow_link(str,(char *)v->as_tree.right);
- }
- return str && *str;
- case T_COMP:
- return compare(v->as_tree.left,(comp_t)v->as_tree.op,
- v->as_tree.right, oget, sget);
- case T_NOT:
- res = eval(v->as_tree.left,oget,sget);
- return (res >= 0) ? !res : res;
- case T_AND:
- res = eval(v->as_tree.left,oget,sget);
- if (res > 0) {
- res = eval(v->as_tree.right,oget,sget);
- }
- return res;
- case T_OR:
- res = eval(v->as_tree.left,oget,sget);
- if (res > 0) {
- return res;
- }
- return eval(v->as_tree.right,oget,sget);
- default:
- return -1;
- }
-}
-
-#define YY_INPUT(buf,result,max) { - result = (arg_off < arg_len) ? (*buf =
arg_buf[arg_off++], 1) - : (arg_off == arg_len) ? (*buf = 'n', ++arg_off, 1) :
0; -}
-
-#define YYSTYPE value_t *
-%}
-
-Stmt = - BoolExpr - EOL { *cur_expr = $$; }
- | ( !EOL . )* EOL
-
-BoolExpr = l:NotExpr
- ( ( - AND - r:NotExpr )
- { $$ = l = make_tree(T_AND,l,r); }
- | ( - OR - r:NotExpr )
- { $$ = l = make_tree(T_OR,l,r); } )*
-
-NotExpr = CompExpr -
- | NOT - e:CompExpr - { $$ = make_tree(T_NOT,e,NULL); }
-
-CompExpr = l:Atom
- ( ( - LESS - r:Atom { $$ = make_comp(C_LESSTHAN,l,r); } )
- | ( - LESS EQUAL - r:Atom { $$ = make_comp(C_LESSOREQ,l,r); } )
- | ( - EQUAL EQUAL - r:Atom { $$ = make_comp(C_EQUAL,l,r); } )
- | ( - NOT EQUAL - r:Atom { $$ = make_comp(C_DIFFERENT,l,r); } )
- | ( - GREATER EQUAL - r:Atom { $$ = make_comp(C_GREATEROREQ,l,r); } )
- | ( - GREATER - r:Atom { $$ = make_comp(C_GREATERTHAN,l,r); } ) )?
-
-Atom = ( Literal | LinkField | ParenExpr )
-
-Literal = NUMBER | STRING | TIME
-
-LinkField = f:Field ( DOT i:ID { $$ = f = make_link(f,i); } )*
-
-Field = DOLLAR i:ID { $$ = make_string((char *)i,T_OFIELD); }
- | WAFFLE i:ID { $$ = make_string((char *)i,T_SFIELD); }
-
-ParenExpr = OPEN - v:BoolExpr - CLOSE - { $$ = v; }
-
-NUMBER = < [0-9]+ > { $$ = make_number(yytext); }
-STRING = '"' < [^"]* > '"' { $$ =
make_string(yytext,T_STRING); }
-TIME = '~' < [^~]* > '~' { $$ = make_number(yytext); }
-ID = < [a-z_]+ > { $$ = (YYSTYPE)yytext; }
-DOLLAR = '$'
-WAFFLE = '#'
-OPEN = '('
-CLOSE = ')'
-LESS = '<'
-GREATER = '>'
-EQUAL = '='
-NOT = '!'
-AND = '&&'
-OR = '||'
-DOT = '.'
-
-- = [ t]*
-EOL = 'n' | 'rn' | 'r' | ';'
-
-%%
-
-/* TBD: This isn't thread safe. */
-value_t *
-parse (const char *text)
-{
- value_t *expr = NULL;
-
- arg_buf = text;
- arg_len = strlen(text);
- arg_off = 0;
- cur_expr = &expr;
-
- while (yyparse()) {
- }
-
- return expr;
-}
-
-#if defined(UNIT_TEST)
-int
-main (int argc, char **argv)
-{
- int i;
- value_t *expr;
- int res;
- const char *str;
- unsigned int failed = 0;
-
- for (i = 1; i < argc; ++i) {
- expr = parse(argv[i]);
- if (!expr) {
- printf("could not parse '%s'n",argv[i]);
- ++failed;
- continue;
- }
- print_value(expr);
- str = string_value(expr,&unit_oget,&unit_sget);
- if (str) {
- printf("s= %sn",str);
- continue;
- }
- res = eval(expr,&unit_oget,&unit_sget);
- printf("d= %dn",res);
- }
-
- return failed;
-}
-#endif
http://repo.or.cz/w/iwhd.git/commit/fd0cbe4410ec2b1ad831e418b472cc46fd4cacaf
commit fd0cbe4410ec2b1ad831e418b472cc46fd4cacaf
Author: Jeff Darcy <jdarcy(a)redhat.com>
Date: Tue Oct 12 17:18:16 2010 +0200
rewrite query parser using Bison, not peg/leg
* qparser.y: New file.
* qparser.l: New file.
diff --git a/qlexer.l b/qlexer.l
new file mode 100644
index 0000000..73e685f
--- /dev/null
+++ b/qlexer.l
@@ -0,0 +1,86 @@
+%{
+#include <stdio.h>
+
+#if defined(UNIT_TEST)
+enum {
+ T_STRING, T_DATE, T_NUMBER, T_ID,
+ T_DOLLAR, T_WAFFLE, T_LPAREN, T_RPAREN,
+ T_LESS, T_GREATER, T_EQUAL, T_NOT,
+ T_AND, T_OR, T_DOT, T_SPACE,
+ T_INVALID
+};
+#else
+#include "qparser.tab.h"
+#endif
+%}
+
+%%
+
+"[^"]*" { return T_STRING; }
+~[^~]*~ { return T_DATE; }
+[0-9]+ { return T_NUMBER; }
+[a-z_]+ { return T_ID; }
+$ { return T_DOLLAR; }
+# { return T_WAFFLE; }
+( { return T_LPAREN; }
+) { return T_RPAREN; }
+< { return T_LESS; }
+> { return T_GREATER; }
+= { return T_EQUAL; }
+! { return T_NOT; }
+& { return T_AND; }
+| { return T_OR; }
+. { return T_DOT; }
+[ tnr]+ { return T_SPACE; }
+. { return T_INVALID; }
+
+%%
+
+int at_eof = 0;
+
+int
+yywrap (void)
+{
+ return ++at_eof;
+}
+
+#if defined(UNIT_TEST)
+static void
+yyerror (char *msg)
+{
+ printf("%s: %sn",__func__,msg);
+}
+
+int
+main (int argc, char **argv)
+{
+ int t;
+
+ yy_scan_string(""!@#" ~xxx~ 123 abc $#()<>=!&|.");
+
+ do {
+ t = yylex();
+ switch (t) {
+ case T_STRING:
+ if (!yytext[0]) {
+ printf("EOFn");
+ break;
+ }
+ case T_DATE:
+ case T_NUMBER:
+ case T_ID:
+ printf("%d %sn",t,yytext);
+ break;
+ case T_SPACE:
+ break;
+ case T_INVALID:
+ printf("INVALID %cn",yytext[0]);
+ break;
+ default:
+ printf("%dn",t);
+ }
+ } while (!at_eof);
+
+ return 0;
+}
+#endif
diff --git a/qparser.y b/qparser.y
new file mode 100644
index 0000000..7df27a1
--- /dev/null
+++ b/qparser.y
@@ -0,0 +1,451 @@
+%{
+#include <config.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "query.h"
+#define YYSTYPE value_t *
+#include "qparser.h"
+
+static void
+xalloc_die (void)
+{
+ error (EXIT_FAILURE, 0, "%s", "memory exhausted");
+
+ /* The `noreturn' cannot be given to error, since it may return if
+ its first argument is 0. To help compilers understand the
+ xalloc_die does not return, call abort. Also, the abort is a
+ safety feature if exit_failure is 0 (which shouldn't happen). */
+ abort ();
+}
+
+/* Allocate N bytes of memory dynamically, with error checking. */
+static void *
+xmalloc (size_t n)
+{
+ void *p = malloc (n);
+ if (!p && n != 0)
+ xalloc_die ();
+ return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+ with error checking. */
+static void *
+xrealloc (void *p, size_t n)
+{
+ p = realloc (p, n);
+ if (!p && n != 0)
+ xalloc_die ();
+ return p;
+}
+
+/* Clone an object P of size S, with error checking. There's no need
+ for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any
+ need for an arithmetic overflow check. */
+static void *
+xmemdup (void const *p, size_t s)
+{
+ return memcpy (xmalloc (s), p, s);
+}
+
+/* Clone STRING. */
+static char *
+xstrdup (char const *string)
+{
+ return xmemdup (string, strlen (string) + 1);
+}
+
+/* TBD: use separate function to parse dates differently */
+value_t *
+make_number (const char *text)
+{
+ value_t *tmp = malloc(sizeof(*tmp));
+
+ if (tmp) {
+ tmp->type = T_NUMBER;
+ tmp->as_num = strtoll(text,NULL,10);
+ }
+
+ return tmp;
+}
+
+value_t *
+make_string (const char *text, type_t t)
+{
+ value_t *tmp = malloc(sizeof(*tmp));
+
+ if (tmp) {
+ tmp->type = t;
+ tmp->as_str = xstrdup(text);
+ }
+
+ return tmp;
+}
+
+value_t *
+make_tree (type_t t, value_t *left, value_t *right)
+{
+ value_t *tmp = malloc(sizeof(*tmp));
+
+ if (tmp) {
+ tmp->type = t;
+ tmp->as_tree.left = left;
+ tmp->as_tree.right = right;
+ }
+
+ return tmp;
+}
+
+value_t *
+make_comp (comp_t c, value_t *left, value_t *right)
+{
+ value_t *tmp = make_tree(T_COMP,left,right);
+
+ if (tmp) {
+ tmp->as_tree.op = c;
+ }
+
+ return tmp;
+}
+
+value_t *
+make_link (value_t *left, char *right)
+{
+ char *copy;
+
+ copy = strdup(right);
+ if (!copy) {
+ return NULL;
+ }
+
+ return make_tree(T_LINK,left,(value_t *)copy);
+}
+
+/*
+ * For some reason the bison-generated code isn't setting up yysv* properly,
+ * so $n doesn't work with terminals. Be very careful to use this only
+ * when the token we want is the last one in the current rule. If the
+ * syntax ever gets complicated enough that we can't get away with that, we'll
+ * just have to wrap all the terminals in singleton non-terminals just so that
+ * $n will work in the real syntax rules.
+ */
+extern char *yytext;
+
+/* In a sane world, yyparse would return this. */
+value_t *cur_val;
+
+/*
+ * IMO it's wrong for us to get into the bbool_expr=policy rule when there's
+ * a syntax error, but we do. The good news is that it's easy to free the
+ * erroneous tree properly this way. The bad news is that we need to wait
+ * until yyparse is done, then check this flag (which we have to maintain
+ * ourselves) to figure out whether we got a valid tree or not.
+ * No, yynerrs doesn't seem to give the right answer.
+ */
+int syntax_error = 0;
+
+void
+yyerror (char *msg)
+{
+ printf("%s: %sn",__func__,msg);
+ syntax_error = 1;
+}
+
+%}
+
+%token T_STRING T_DATE T_NUMBER T_ID
+%token T_DOLLAR T_WAFFLE T_DOT
+%token T_LPAREN T_RPAREN
+%token T_LESS T_GREATER T_EQUAL
+%token T_NOT T_AND T_OR
+%token T_SPACE T_INVALID
+%token T_OFIELD T_SFIELD T_COMP T_LINK
+
+%start policy
+
+%%
+
+policy:
+ bbool_expr {
+ printf("policy completen");
+ if (syntax_error) {
+ printf("bad policy!n");
+ }
+ else {
+ cur_val = $1;
+ }
+ };
+
+bbool_expr:
+ ubool_expr {
+ printf("promoting ubool_expr to bbool_exprn");
+ $$ = $1;
+ }|
+ bbool_expr T_AND T_AND ubool_expr {
+ printf("found AND expressionn");
+ $$ = make_tree(T_AND,$1,$4);
+ }|
+ bbool_expr T_OR T_OR ubool_expr {
+ printf("found OR expressionn");
+ $$ = make_tree(T_OR,$1,$4);
+ }|
+ bbool_expr T_SPACE {
+ $$ = $1;
+ }| T_SPACE bbool_expr {
+ $$ = $2;
+ };
+
+ubool_expr:
+ comp_expr {
+ printf("promoting comp_expr to ubool_exprn");
+ $$ = $1;
+ }|
+ T_NOT comp_expr {
+ printf("found NOT expressionn");
+ $$ = make_tree(T_NOT,$2,NULL);
+ }|
+ ubool_expr T_SPACE {
+ $$ = $1;
+ }| T_SPACE ubool_expr {
+ $$ = $2;
+ };
+
+
+comp_expr:
+ atom {
+ printf("promoting atom to comp_exprn");
+ $$ = $1;
+ }|
+ atom T_LESS atom {
+ printf("found LESS THAN expressionn");
+ $$ = make_comp(C_LESSTHAN,$1,$3);
+ }|
+ atom T_LESS T_EQUAL atom {
+ printf("found LESS OR EQUAL expressionn");
+ $$ = make_comp(C_LESSOREQ,$1,$4);
+ }|
+ atom T_EQUAL T_EQUAL atom {
+ printf("found EQUAL expressionn");
+ $$ = make_comp(C_EQUAL,$1,$4);
+ }|
+ atom T_NOT T_EQUAL atom {
+ printf("found NOT EQUAL expressionn");
+ $$ = make_comp(C_DIFFERENT,$1,$4);
+ }|
+ atom T_GREATER T_EQUAL atom {
+ printf("found GREATER OR EQUAL expressionn");
+ $$ = make_comp(C_GREATEROREQ,$1,$4);
+ }|
+ atom T_GREATER atom {
+ printf("found GREATER THAN expressionn");
+ $$ = make_comp(C_GREATERTHAN,$1,$3);
+ }|
+ comp_expr T_SPACE {
+ $$ = $1;
+ }| T_SPACE comp_expr {
+ $$ = $2;
+ };
+
+atom:
+ link_field {
+ printf("promoting link_field to atomn");
+ $$ = $1;
+ }|
+ literal {
+ printf("promoting literal to atomn");
+ $$ = $1;
+ }|
+ paren_expr {
+ printf("promoting paren_expr to atomn");
+ $$ = $1;
+ }|
+ atom T_SPACE {
+ $$ = $1;
+ }| T_SPACE atom {
+ $$ = $2;
+ };
+
+link_field:
+ field {
+ printf("promoting field to link_fieldn");
+ $$ = $1;
+ }|
+ link_field T_DOT T_ID {
+ printf("found LINK FIELDn");
+ $$ = make_link($1,yytext);
+ };
+
+field:
+ T_DOLLAR T_ID {
+ printf("found DOLLAR FIELDn");
+ $$ = make_string(yytext,T_OFIELD);
+ }|
+ T_WAFFLE T_ID {
+ printf("found WAFFLE FIELDn");
+ $$ = make_string(yytext,T_SFIELD);
+ };
+
+literal:
+ T_NUMBER {
+ printf("found NUMBER %sn",yytext);
+ $$ = make_number(yytext);
+ }|
+ T_STRING {
+ printf("found STRING %sn",yytext);
+ $$ = make_string(yytext,T_STRING);
+ }|
+ T_DATE {
+ printf("found DATEn");
+ $$ = make_string(yytext,T_DATE);
+ }|
+ T_ID {
+ printf("found ID %sn",yytext);
+ $$ = make_string(yytext,T_ID);
+ };
+
+paren_expr:
+ T_LPAREN bbool_expr T_RPAREN {
+ printf("found PAREN expressionn");
+ $$ = $2;
+ };
+
+%%
+
+void
+_print_value (const value_t *v, int level)
+{
+ if (!v) {
+ printf("%*sNULLn",level,"");
+ return;
+ }
+
+ switch (v->type) {
+ case T_NUMBER:
+ printf("%*sNUMBER %lldn",level,"",v->as_num);
+ break;
+ case T_STRING:
+ printf("%*sSTRING %sn",level,"",v->as_str);
+ break;
+ case T_OFIELD:
+#if defined(UNIT_TEST)
+ printf("%*sOBJECT FIELD %s (%s)n",level,"",v->as_str,
+ unit_oget_func(NULL,v->as_str));
+#else
+ printf("%*sOBJECT FIELD %sn",level,"",v->as_str);
+#endif
+ break;
+ case T_SFIELD:
+#if defined(UNIT_TEST)
+ printf("%*sSERVER FIELD %s (%s)n",level,"",v->as_str,
+ unit_sget_func(NULL,v->as_str));
+#else
+ printf("%*sSERVER FIELD %sn",level,"",v->as_str);
+#endif
+ break;
+ case T_COMP:
+ printf("%*sCOMPARISONn",level,"");
+ _print_value(v->as_tree.left,level+2);
+ _print_value(v->as_tree.right,level+2);
+ break;
+ case T_NOT:
+ printf("%*sNOTn",level,"");
+ _print_value(v->as_tree.left,level+2);
+ break;
+ case T_AND:
+ printf("%*sANDn",level,"");
+ _print_value(v->as_tree.left,level+2);
+ _print_value(v->as_tree.right,level+2);
+ break;
+ case T_OR:
+ printf("%*sORn",level,"");
+ _print_value(v->as_tree.left,level+2);
+ _print_value(v->as_tree.right,level+2);
+ break;
+ case T_LINK:
+ printf("%*sLINKn",level,"");
+ _print_value(v->as_tree.left,level+2);
+ printf("%*sDEST FIELD %sn",level+2,"",
+ (char *)v->as_tree.right);
+ break;
+ default:
+ printf("%*sUNKNOWN %dn",level,"",v->type);
+ }
+}
+
+void
+print_value (const value_t *v)
+{
+ _print_value(v,0);
+}
+
+void
+free_value (value_t *v)
+{
+ if (!v) {
+ return;
+ }
+
+ switch (v->type) {
+ case T_STRING:
+ case T_OFIELD:
+ case T_SFIELD:
+ case T_ID:
+ free(v->as_str);
+ free(v);
+ break;
+ case T_LINK:
+ free_value(v->as_tree.left);
+ free(v->as_tree.right);
+ free(v);
+ break;
+ case T_COMP:
+ case T_AND:
+ case T_OR:
+ free_value(v->as_tree.right);
+ /* Fall through. */
+ case T_NOT:
+ free_value(v->as_tree.left);
+ /* Fall through. */
+ default:
+ free(v);
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ char *data = "#a=="fubar"&&!($b.c.d<3)";
+ char *edata = "gobbledy-gook";
+
+ yy_scan_string(data);
+ yyparse();
+ if (cur_val) {
+ if (!syntax_error) {
+ print_value(cur_val);
+ }
+ else {
+ printf("discarding erroneous parse treen");
+ }
+ free_value(cur_val);
+ cur_val = NULL;
+ }
+ yylex_destroy();
+
+ yy_scan_string(edata);
+ yyparse();
+ if (cur_val) {
+ if (!syntax_error) {
+ print_value(cur_val);
+ }
+ else {
+ printf("discarding erroneous parse treen");
+ }
+ free_value(cur_val);
+ cur_val = NULL;
+ }
+ yylex_destroy();
+
+ return 0;
+}
-----------------------------------------------------------------------
Summary of changes:
.gitignore | 9 +-
Makefile.am | 27 +--
configure.ac | 6 +-
qlexer.l | 87 +++++++
query.leg => qparser.y | 617 +++++++++++++++++++++++++++++-------------------
query.c.diff | 47 ----
query.h | 50 +++-
t/Makefile.am | 4 +-
8 files changed, 517 insertions(+), 330 deletions(-)
create mode 100644 qlexer.l
rename query.leg => qparser.y (62%)
delete mode 100644 query.c.diff
repo.or.cz automatic notification. Contact project admin jim(a)meyering.net
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
iwhd.git ("image warehouse daemon")