blob: 80979c2c9783573ea7e88dcd6724337be2ff09fd [file] [log] [blame]
/* $Id: grammar.lemon 21321 2007-04-03 19:08:00Z lego $ */
%include {
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "dfilter-int.h"
#include "syntax-tree.h"
#include "sttype-range.h"
#include "sttype-test.h"
#include "sttype-function.h"
#include "drange.h"
#include "grammar.h"
#ifdef _WIN32
#pragma warning(disable:4671)
#endif
/* End of C code */
}
/* Parser Information */
%name Dfilter
%token_prefix TOKEN_
%extra_argument {dfwork_t *dfw}
/* Terminal and Non-Terminal types and destructors */
%token_type {stnode_t*}
%token_destructor {stnode_free($$);}
%type sentence {stnode_t*}
%type expr {stnode_t*}
%destructor expr {stnode_free($$);}
%type entity {stnode_t*}
%destructor entity {stnode_free($$);}
%type relation_test {stnode_t*}
%destructor relation_test {stnode_free($$);}
%type logical_test {stnode_t*}
%destructor logical_test {stnode_free($$);}
%type rel_op2 {test_op_t}
%type range {stnode_t*}
%destructor range {stnode_free($$);}
%type drnode {drange_node*}
%destructor drnode {drange_node_free($$);}
%type drnode_list {GSList*}
%destructor drnode_list {drange_node_free_list($$);}
%type funcparams {GSList*}
%destructor funcparams {st_funcparams_free($$);}
/* This is called as soon as a syntax error happens. After that,
any "error" symbols are shifted, if possible. */
%syntax_error {
header_field_info *hfinfo;
if (!TOKEN) {
dfilter_fail("Unexpected end of filter string.");
return;
}
switch(stnode_type_id(TOKEN)) {
case STTYPE_UNINITIALIZED:
dfilter_fail("Syntax error.");
break;
case STTYPE_TEST:
dfilter_fail("Syntax error, TEST.");
break;
case STTYPE_STRING:
dfilter_fail("The string \"%s\" was unexpected in this context.",
stnode_data(TOKEN));
break;
case STTYPE_UNPARSED:
dfilter_fail("\"%s\" was unexpected in this context.",
stnode_data(TOKEN));
break;
case STTYPE_INTEGER:
dfilter_fail("The integer %d was unexpected in this context.",
stnode_value(TOKEN));
break;
case STTYPE_FIELD:
hfinfo = stnode_data(TOKEN);
dfilter_fail("Syntax error near \"%s\".", hfinfo->abbrev);
break;
case STTYPE_FUNCTION:
dfilter_fail("The function s was unexpected in this context.");
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_RANGE:
case STTYPE_FVALUE:
g_assert_not_reached();
break;
}
}
/* When a parse fails, mark an error. This occurs after
the above syntax_error code and after the parser fails to
use error recovery, shifting an "error" symbol and successfully
shifting 3 more symbols. */
%parse_failure {
dfw->syntax_error = TRUE;
}
/* ----------------- The grammar -------------- */
/* Associativity */
%left TEST_AND.
%left TEST_OR.
%nonassoc TEST_EQ TEST_NE TEST_LT TEST_LE TEST_GT TEST_GE TEST_CONTAINS TEST_MATCHES TEST_BITWISE_AND.
%right TEST_NOT.
/* Top-level targets */
sentence ::= expr(X). { dfw->st_root = X; }
sentence ::= . { dfw->st_root = NULL; }
expr(X) ::= relation_test(R). { X = R; }
expr(X) ::= logical_test(L). { X = L; }
/* Logical tests */
logical_test(T) ::= expr(E) TEST_AND expr(F).
{
T = stnode_new(STTYPE_TEST, NULL);
sttype_test_set2(T, TEST_OP_AND, E, F);
}
logical_test(T) ::= expr(E) TEST_OR expr(F).
{
T = stnode_new(STTYPE_TEST, NULL);
sttype_test_set2(T, TEST_OP_OR, E, F);
}
logical_test(T) ::= TEST_NOT expr(E).
{
T = stnode_new(STTYPE_TEST, NULL);
sttype_test_set1(T, TEST_OP_NOT, E);
}
logical_test(T) ::= entity(E).
{
T = stnode_new(STTYPE_TEST, NULL);
sttype_test_set1(T, TEST_OP_EXISTS, E);
}
/* Entities, or things that can be compared/tested/checked */
entity(E) ::= FIELD(F). { E = F; }
entity(E) ::= STRING(S). { E = S; }
entity(E) ::= UNPARSED(U). { E = U; }
entity(E) ::= range(R). { E = R; }
/* Ranges */
range(R) ::= FIELD(F) LBRACKET drnode_list(L) RBRACKET.
{
R = stnode_new(STTYPE_RANGE, NULL);
sttype_range_set(R, F, L);
/* Delete the list, but not the drange_nodes that
* the list contains. */
g_slist_free(L);
}
drnode_list(L) ::= drnode(D).
{
L = g_slist_append(NULL, D);
}
drnode_list(L) ::= drnode_list(P) COMMA drnode(D).
{
L = g_slist_append(P, D);
}
/* x:y is offset:length */
drnode(D) ::= INTEGER(X) COLON INTEGER(Y).
{
D = drange_node_new();
drange_node_set_start_offset(D, stnode_value(X));
drange_node_set_length(D, stnode_value(Y));
stnode_free(X);
stnode_free(Y);
}
/* x-y == offset:offset */
drnode(D) ::= INTEGER(X) HYPHEN INTEGER(Y).
{
D = drange_node_new();
drange_node_set_start_offset(D, stnode_value(X));
drange_node_set_end_offset(D, stnode_value(Y));
stnode_free(X);
stnode_free(Y);
}
/* :y == from start to offset */
drnode(D) ::= COLON INTEGER(Y).
{
D = drange_node_new();
drange_node_set_start_offset(D, 0);
drange_node_set_length(D, stnode_value(Y));
stnode_free(Y);
}
/* x: from offset to end */
drnode(D) ::= INTEGER(X) COLON.
{
D = drange_node_new();
drange_node_set_start_offset(D, stnode_value(X));
drange_node_set_to_the_end(D);
stnode_free(X);
}
/* x == x:1 */
drnode(D) ::= INTEGER(X).
{
D = drange_node_new();
drange_node_set_start_offset(D, stnode_value(X));
drange_node_set_length(D, 1);
stnode_free(X);
}
/* Relational tests */
relation_test(T) ::= entity(E) rel_op2(O) entity(F).
{
T = stnode_new(STTYPE_TEST, NULL);
sttype_test_set2(T, O, E, F);
}
rel_op2(O) ::= TEST_EQ. { O = TEST_OP_EQ; }
rel_op2(O) ::= TEST_NE. { O = TEST_OP_NE; }
rel_op2(O) ::= TEST_GT. { O = TEST_OP_GT; }
rel_op2(O) ::= TEST_GE. { O = TEST_OP_GE; }
rel_op2(O) ::= TEST_LT. { O = TEST_OP_LT; }
rel_op2(O) ::= TEST_LE. { O = TEST_OP_LE; }
rel_op2(O) ::= TEST_BITWISE_AND. { O = TEST_OP_BITWISE_AND; }
rel_op2(O) ::= TEST_CONTAINS. { O = TEST_OP_CONTAINS; }
rel_op2(O) ::= TEST_MATCHES. { O = TEST_OP_MATCHES; }
/* Functions */
/* A function can have one or more parameters */
entity(E) ::= FUNCTION(F) LPAREN funcparams(P) RPAREN.
{
E = F;
sttype_function_set_params(E, P);
}
/* A function can have zero parameters. */
entity(E) ::= FUNCTION(F) LPAREN RPAREN.
{
E = F;
}
funcparams(P) ::= entity(E).
{
P = g_slist_append(NULL, E);
}
funcparams(P) ::= funcparams(L) COMMA entity(E).
{
P = g_slist_append(L, E);
}
/* Any expression inside parens is simply that expression */
expr(X) ::= LPAREN expr(Y) RPAREN.
{
X = Y;
}