dfilter: Use a string lval type in scanner
Minor change to decouple the AST data structures from the lexical scanner. We pass a structure to allow for some future enhancements.
This commit is contained in:
parent
42101494db
commit
0e4851b025
|
@ -55,14 +55,37 @@ typedef struct {
|
|||
gboolean in_set; /* true if parsing set elements for the membership operator */
|
||||
} df_scanner_state_t;
|
||||
|
||||
typedef struct {
|
||||
char *value;
|
||||
} df_lval_t;
|
||||
|
||||
static inline df_lval_t *
|
||||
df_lval_new(void)
|
||||
{
|
||||
return g_new0(df_lval_t, 1);
|
||||
}
|
||||
|
||||
static inline char *
|
||||
df_lval_value(df_lval_t *lval)
|
||||
{
|
||||
return lval->value;
|
||||
}
|
||||
|
||||
static inline void
|
||||
df_lval_free(df_lval_t *lval)
|
||||
{
|
||||
if (lval) {
|
||||
g_free(lval->value);
|
||||
g_free(lval);
|
||||
}
|
||||
}
|
||||
|
||||
/* Constructor/Destructor prototypes for Lemon Parser */
|
||||
void *DfilterAlloc(void* (*)(gsize));
|
||||
|
||||
void DfilterFree(void*, void (*)(void *));
|
||||
void Dfilter(void*, int, stnode_t*, dfwork_t*);
|
||||
|
||||
/* Scanner's lval */
|
||||
extern stnode_t *df_lval;
|
||||
void Dfilter(void*, int, df_lval_t*, dfwork_t*);
|
||||
|
||||
/* Return value for error in scanner. */
|
||||
#define SCAN_FAILED -1 /* not 0, as that means end-of-input */
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
|
||||
#define DFILTER_TOKEN_ID_OFFSET 1
|
||||
|
||||
/* Scanner's lval */
|
||||
extern df_lval_t *df_lval;
|
||||
|
||||
/* Holds the singular instance of our Lemon parser object */
|
||||
static void* ParserObj = NULL;
|
||||
|
||||
|
@ -383,7 +386,7 @@ dfilter_compile(const gchar *text, dfilter_t **dfp, gchar **err_msg)
|
|||
df_set_extra(&state, scanner);
|
||||
|
||||
while (1) {
|
||||
df_lval = stnode_new(STTYPE_UNINITIALIZED, NULL, NULL);
|
||||
df_lval = df_lval_new();
|
||||
token = df_lex(scanner);
|
||||
|
||||
/* Check for scanner failure */
|
||||
|
@ -399,11 +402,11 @@ dfilter_compile(const gchar *text, dfilter_t **dfp, gchar **err_msg)
|
|||
|
||||
ws_debug("(%u) Token %d %s %s",
|
||||
++token_count, token, tokenstr(token),
|
||||
stnode_token_value(df_lval));
|
||||
df_lval_value(df_lval));
|
||||
|
||||
/* Give the token to the parser */
|
||||
Dfilter(ParserObj, token, df_lval, dfw);
|
||||
/* We've used the stnode_t, so we don't want to free it */
|
||||
/* The parser has freed the lval for us. */
|
||||
df_lval = NULL;
|
||||
|
||||
if (dfw->syntax_error) {
|
||||
|
@ -413,10 +416,10 @@ dfilter_compile(const gchar *text, dfilter_t **dfp, gchar **err_msg)
|
|||
|
||||
} /* while (1) */
|
||||
|
||||
/* If we created an stnode_t but didn't use it, free it; the
|
||||
/* If we created a df_lval_t but didn't use it, free it; the
|
||||
* parser doesn't know about it and won't free it for us. */
|
||||
if (df_lval) {
|
||||
stnode_free(df_lval);
|
||||
df_lval_free(df_lval);
|
||||
df_lval = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,10 +27,10 @@
|
|||
%extra_argument {dfwork_t *dfw}
|
||||
|
||||
/* Terminal and Non-Terminal types and destructors */
|
||||
%token_type {stnode_t*}
|
||||
%token_type {df_lval_t*}
|
||||
%token_destructor {
|
||||
(void) dfw; /* Mark unused, similar to Q_UNUSED */
|
||||
stnode_free($$);
|
||||
(void)dfw;
|
||||
df_lval_free($$);
|
||||
}
|
||||
|
||||
%type sentence {stnode_t*}
|
||||
|
@ -42,6 +42,9 @@
|
|||
%type entity {stnode_t*}
|
||||
%destructor entity {stnode_free($$);}
|
||||
|
||||
%type function {stnode_t*}
|
||||
%destructor function {stnode_free($$);}
|
||||
|
||||
%type relation_test {stnode_t*}
|
||||
%destructor relation_test {stnode_free($$);}
|
||||
|
||||
|
@ -75,37 +78,8 @@ any "error" symbols are shifted, if possible. */
|
|||
return;
|
||||
}
|
||||
|
||||
switch(stnode_type_id(TOKEN)) {
|
||||
case STTYPE_UNINITIALIZED: /* fall-through */
|
||||
case STTYPE_UNPARSED:
|
||||
if (stnode_token_value(TOKEN) != NULL)
|
||||
dfilter_fail(dfw, "\"%s\" was unexpected in this context.",
|
||||
stnode_token_value(TOKEN));
|
||||
else
|
||||
dfilter_fail(dfw, "Syntax error.");
|
||||
break;
|
||||
case STTYPE_STRING:
|
||||
dfilter_fail(dfw, "The string \"%s\" was unexpected in this context.",
|
||||
(char *)stnode_data(TOKEN));
|
||||
break;
|
||||
case STTYPE_CHARCONST:
|
||||
dfilter_fail(dfw, "The character constant \"%s\" was unexpected in this context.",
|
||||
(char *)stnode_data(TOKEN));
|
||||
break;
|
||||
/* These aren't handed to use as terminal tokens from
|
||||
the scanner, so was can assert that we'll never
|
||||
see them here. */
|
||||
case STTYPE_NUM_TYPES:
|
||||
case STTYPE_FIELD:
|
||||
case STTYPE_FUNCTION:
|
||||
case STTYPE_RANGE:
|
||||
case STTYPE_FVALUE:
|
||||
case STTYPE_PCRE:
|
||||
case STTYPE_SET:
|
||||
case STTYPE_TEST:
|
||||
ws_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
dfilter_fail(dfw, "\"%s\" was unexpected in this context.",
|
||||
df_lval_value(TOKEN));
|
||||
dfw->syntax_error = TRUE;
|
||||
}
|
||||
|
||||
|
@ -161,9 +135,22 @@ logical_test(T) ::= entity(E).
|
|||
|
||||
|
||||
/* Entities, or things that can be compared/tested/checked */
|
||||
entity(E) ::= STRING(S). { E = S; }
|
||||
entity(E) ::= CHARCONST(C). { E = C; }
|
||||
entity(E) ::= UNPARSED(U). { E = dfilter_resolve_unparsed(dfw, U); }
|
||||
entity(E) ::= STRING(S).
|
||||
{
|
||||
E = stnode_new(STTYPE_STRING, df_lval_value(S), df_lval_value(S));
|
||||
df_lval_free(S);
|
||||
}
|
||||
entity(E) ::= CHARCONST(C).
|
||||
{
|
||||
E = stnode_new(STTYPE_CHARCONST, df_lval_value(C), df_lval_value(C));
|
||||
df_lval_free(C);
|
||||
}
|
||||
entity(E) ::= UNPARSED(U).
|
||||
{
|
||||
E = stnode_new(STTYPE_UNPARSED, df_lval_value(U), df_lval_value(U));
|
||||
dfilter_resolve_unparsed(dfw, E);
|
||||
df_lval_free(U);
|
||||
}
|
||||
entity(E) ::= range(R). { E = R; }
|
||||
entity(E) ::= function(F). { E = F; }
|
||||
|
||||
|
@ -193,13 +180,13 @@ range_node(D) ::= RANGE(R).
|
|||
{
|
||||
char *err = NULL;
|
||||
|
||||
D = drange_node_from_str(stnode_token_value(R), &err);
|
||||
D = drange_node_from_str(df_lval_value(R), &err);
|
||||
if (err != NULL) {
|
||||
dfilter_parse_fail(dfw, "%s", err);
|
||||
g_free(err);
|
||||
}
|
||||
|
||||
stnode_free(R);
|
||||
df_lval_free(R);
|
||||
}
|
||||
|
||||
rel_binop(O) ::= TEST_ANY_EQ. { O = TEST_OP_ANY_EQ; }
|
||||
|
@ -287,16 +274,16 @@ set_node_list(L) ::= set_node_list(P) WHITESPACE entity(X) DOTDOT entity(Y).
|
|||
/* A function can have one or more parameters */
|
||||
function(F) ::= UNPARSED(U) LPAREN function_params(P) RPAREN.
|
||||
{
|
||||
F = dfilter_new_function(dfw, stnode_token_value(U));
|
||||
stnode_free(U);
|
||||
F = dfilter_new_function(dfw, df_lval_value(U));
|
||||
sttype_function_set_params(F, P);
|
||||
df_lval_free(U);
|
||||
}
|
||||
|
||||
/* A function can have zero parameters. */
|
||||
function(F) ::= UNPARSED(U) LPAREN RPAREN.
|
||||
{
|
||||
F = dfilter_new_function(dfw, stnode_token_value(U));
|
||||
stnode_free(U);
|
||||
F = dfilter_new_function(dfw, df_lval_value(U));
|
||||
df_lval_free(U);
|
||||
}
|
||||
|
||||
function_params(P) ::= entity(E).
|
||||
|
|
|
@ -75,11 +75,10 @@
|
|||
*/
|
||||
DIAG_OFF_FLEX
|
||||
|
||||
stnode_t *df_lval;
|
||||
df_lval_t *df_lval;
|
||||
|
||||
static int set_lval_str(int token, const char *token_value);
|
||||
static int simple(int token, const char *token_value);
|
||||
#define SIMPLE(token) simple(token, yytext)
|
||||
#define SIMPLE(token) set_lval_str(token, yytext)
|
||||
|
||||
/*
|
||||
* Sleazy hack to suppress compiler warnings in yy_fatal_error().
|
||||
|
@ -106,24 +105,26 @@ static int simple(int token, const char *token_value);
|
|||
* should have used commas from the beginning, but now we are stuck with
|
||||
* whitespace as separators. */
|
||||
if (yyextra->in_set) {
|
||||
return simple(TOKEN_WHITESPACE, NULL);
|
||||
return set_lval_str(TOKEN_WHITESPACE, " ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
"(" return SIMPLE(TOKEN_LPAREN);
|
||||
")" return SIMPLE(TOKEN_RPAREN);
|
||||
"," return SIMPLE(TOKEN_COMMA);
|
||||
|
||||
"{"[[:blank:]\n]* {
|
||||
yyextra->in_set = TRUE;
|
||||
return simple(TOKEN_LBRACE, "{");
|
||||
return set_lval_str(TOKEN_LBRACE, "{");
|
||||
}
|
||||
[[:blank:]\n]*".."[[:blank:]\n]* return simple(TOKEN_DOTDOT, "..");
|
||||
|
||||
[[:blank:]\n]*".."[[:blank:]\n]* {
|
||||
return set_lval_str(TOKEN_DOTDOT, "..");
|
||||
}
|
||||
|
||||
[[:blank:]\n]*"}" {
|
||||
yyextra->in_set = FALSE;
|
||||
return simple(TOKEN_RBRACE, "}");
|
||||
return set_lval_str(TOKEN_RBRACE, "}");
|
||||
}
|
||||
|
||||
"==" return SIMPLE(TOKEN_TEST_ANY_EQ);
|
||||
|
@ -379,35 +380,9 @@ static int simple(int token, const char *token_value);
|
|||
*/
|
||||
DIAG_ON_FLEX
|
||||
|
||||
static int
|
||||
simple(int token, const char *token_value)
|
||||
{
|
||||
stnode_init(df_lval, STTYPE_UNINITIALIZED, NULL, token_value);
|
||||
return token;
|
||||
}
|
||||
|
||||
static int
|
||||
set_lval_str(int token, const char *token_value)
|
||||
{
|
||||
sttype_id_t type_id;
|
||||
|
||||
switch (token) {
|
||||
case TOKEN_STRING:
|
||||
type_id = STTYPE_STRING;
|
||||
break;
|
||||
case TOKEN_CHARCONST:
|
||||
type_id = STTYPE_CHARCONST;
|
||||
break;
|
||||
case TOKEN_UNPARSED:
|
||||
type_id = STTYPE_UNPARSED;
|
||||
break;
|
||||
case TOKEN_RANGE:
|
||||
/* Not used in AST. */
|
||||
type_id = STTYPE_UNINITIALIZED;
|
||||
break;
|
||||
default:
|
||||
ws_assert_not_reached();
|
||||
}
|
||||
stnode_init(df_lval, type_id, (gpointer)token_value, token_value);
|
||||
df_lval->value = g_strdup(token_value);
|
||||
return token;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue