8a8b883450
they have LF at the end of the line on UN*X and CR/LF on Windows; hopefully this means that if a CR/LF version is checked in on Windows, the CRs will be stripped so that they show up only when checked out on Windows, not on UN*X. svn path=/trunk/; revision=11400
256 lines
5.5 KiB
Text
256 lines
5.5 KiB
Text
/* $Id$ */
|
|
|
|
%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 "drange.h"
|
|
|
|
/* 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*}
|
|
%destructor sentence {stnode_free($$);}
|
|
|
|
%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($$);}
|
|
|
|
/* 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;
|
|
|
|
/* 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; }
|
|
|
|
expr(X) ::= LPAREN expr(Y) RPAREN.
|
|
{
|
|
X = Y;
|
|
}
|
|
|
|
|
|
/* 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; }
|
|
|
|
|
|
|