/* $Id: grammar.lemon,v 1.6 2003/08/27 15:23:04 gram Exp $ */ %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 %u 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. %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) ::= FIELD(F). { T = stnode_new(STTYPE_TEST, NULL); sttype_test_set1(T, TEST_OP_EXISTS, F); } /* 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_CONTAINS. { O = TEST_OP_CONTAINS; }