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:
João Valverde 2021-10-26 10:09:36 +01:00
parent 42101494db
commit 0e4851b025
4 changed files with 75 additions and 87 deletions

View File

@ -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 */

View File

@ -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;
}

View File

@ -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).

View File

@ -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;
}