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, bison-flex has been updated
discards 1c66543ffc83ebf8fd6a99d6c576414746fb8d03 (commit)
discards 2b217ff620298dc2584492a9729ddfc5b1d64ed7 (commit)
discards c2f21c7193a71e0135e01878d25da72d14aee581 (commit)
discards f8a6fed825045cecfad10e6c8d4c85fb93bd2c04 (commit)
discards c7577402deb00b434907a27fb2d869d53b16cf32 (commit)
discards b4d1b13de7d3026e6fc87bd3de872594c5697c88 (commit)
discards 156d035b4cf119d51451cb90cee703812ff37b5e (commit)
discards f9cd1b61a9fe936777cb4011617c7a43e59d01d8 (commit)
discards 7e6b3e5ef9e1a4cada4af4653d95cd6676027e2f (commit)
discards 67f218604c5c5438280a46bf7deb8fb492f2719d (commit)
discards 125c1fc30521d55a51fc0a74c782bdb852e9b3b8 (commit)
via c8b655f76467dadf55b7b8574dbbb5093cab7150 (commit)
via 13d54abce0015041bd2aff388596235d52f62c7f (commit)
via 59b33c3181ccb0adffb1a880a697d8a4a04bd15d (commit)
via d5e631d306b61c6ad9c07124bb5891bf0cf71d43 (commit)
via bc07e03f3a325f0933545636c422ec9b8173b64d (commit)
via 3a848ee0a6421aa5f72bf9beca118b1a1e2cab67 (commit)
via 376e0b6fa1c00121243c1da2b28924214043885f (commit)
via b9670e25d481159101eaf50465669dce02a8e1ff (commit)
via 02b46dcd6b8cf12b306eca5dd7a036964e99cd98 (commit)
via e29ed3162dd00ccdbfb7eeeedf892a3e850c963e (commit)
via 92ce84f08d19187edef1807c98101dc61028d662 (commit)
via 3ce94781571362adb7f66ea6efe7dc9564d93d8d (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (1c66543ffc83ebf8fd6a99d6c576414746fb8d03)
N -- N -- N (c8b655f76467dadf55b7b8574dbbb5093cab7150)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
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/c8b655f76467dadf55b7b8574dbbb5093cab7150
commit c8b655f76467dadf55b7b8574dbbb5093cab7150
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/13d54abce0015041bd2aff388596235d52f62c7f
commit 13d54abce0015041bd2aff388596235d52f62c7f
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/59b33c3181ccb0adffb1a880a697d8a4a04bd15d
commit 59b33c3181ccb0adffb1a880a697d8a4a04bd15d
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/d5e631d306b61c6ad9c07124bb5891bf0cf71d43
commit d5e631d306b61c6ad9c07124bb5891bf0cf71d43
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/bc07e03f3a325f0933545636c422ec9b8173b64d
commit bc07e03f3a325f0933545636c422ec9b8173b64d
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/3a848ee0a6421aa5f72bf9beca118b1a1e2cab67
commit 3a848ee0a6421aa5f72bf9beca118b1a1e2cab67
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/376e0b6fa1c00121243c1da2b28924214043885f
commit 376e0b6fa1c00121243c1da2b28924214043885f
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/b9670e25d481159101eaf50465669dce02a8e1ff
commit b9670e25d481159101eaf50465669dce02a8e1ff
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/02b46dcd6b8cf12b306eca5dd7a036964e99cd98
commit 02b46dcd6b8cf12b306eca5dd7a036964e99cd98
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/e29ed3162dd00ccdbfb7eeeedf892a3e850c963e
commit e29ed3162dd00ccdbfb7eeeedf892a3e850c963e
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/92ce84f08d19187edef1807c98101dc61028d662
commit 92ce84f08d19187edef1807c98101dc61028d662
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/3ce94781571362adb7f66ea6efe7dc9564d93d8d
commit 3ce94781571362adb7f66ea6efe7dc9564d93d8d
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 $@
-----------------------------------------------------------------------
Summary of changes:
Makefile.am | 3 +--
query.h | 27 +++++++++++++++++++++++++++
2 files changed, 28 insertions(+), 2 deletions(-)
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")