/* SPDX-License-Identifier: GPL-3.0-only */ /* * Provide more verbose and specific error messages instead of just "syntax * error". */ %define parse.error verbose /* * Verbose error messages may contain incorrect information if LAC (Lookahead * Correction) is not enabled. */ %define parse.lac full /* Avoid symbol clashes (lopsub might also expose yy* symbols). */ %define api.prefix {txp_yy} /* * Although locations are automatically enabled as soon as the grammar uses the * special @N tokens, specifying %locations explicitly allows for more accurate * syntax error messages. */ %locations /* * Generate a pure (reentrant) parser. With this option enabled, yylval and * yylloc become local variables in yyparse(), and a different calling * convention is used for yylex(). */ %define api.pure full /* Additional arguments to yylex(), yyparse() and yyerror() */ %param {struct txp_context *ctx} %param {struct txp_ast_node **ast} %param {txp_yyscan_t yyscanner} /* reentrant lexers */ %{ #include "tf.h" #include "txp.bison.h" int yylex(TXP_YYSTYPE *lvalp, TXP_YYLTYPE *llocp, struct txp_context *ctx, struct txp_ast_node **ast, txp_yyscan_t yyscanner); static void yyerror(YYLTYPE *llocp, struct txp_context *ctx, struct txp_ast_node **ast, txp_yyscan_t yyscanner, const char *msg); %} %union { struct txp_ast_node *node; } /* terminals */ %token NUM %token STRING_LITERAL %token REGEX_PATTERN /* keywords with semantic value */ %token LEN %token FALSE TRUE %token TEXT /* keywords without semantic value */ %token TAG /* operators, ordered by precendence */ %left OR %left AND %left EQUAL NOT_EQUAL %left LESS_THAN LESS_OR_EQUAL GREATER_OR_EQUAL REGEX_MATCH FILENAME_MATCH %left '-' '+' %left '*' '/' %right NOT NEG /* negation (unary minus) */ /* nonterminals */ %type string %type exp %type boolexp %% program: /* empty */ {*ast = NULL; return 0;} | string {*ast = $1; return 0;} | exp {*ast = $1; return 0;} | boolexp {*ast = $1; return 0;} string: STRING_LITERAL {$$ = $1;} | TEXT {$$ = txp_new_ast_leaf_node(TEXT);} ; exp: NUM {$$ = $1;} | exp '+' exp {$$ = ast_node_new_binary('+', $1, $3);} | exp '-' exp {$$ = ast_node_new_binary('-', $1, $3);} | exp '*' exp {$$ = ast_node_new_binary('*', $1, $3);} | exp '/' exp {$$ = ast_node_new_binary('/', $1, $3);} | '-' exp %prec NEG {$$ = ast_node_new_unary(NEG, $2);} | '(' exp ')' {$$ = $2;} | LEN {$$ = txp_new_ast_leaf_node(LEN);} ; boolexp: TAG '(' STRING_LITERAL ')' {$$ = ast_node_new_unary(TAG, $3);} | TRUE {$$ = txp_new_ast_leaf_node(TRUE);} | FALSE {$$ = txp_new_ast_leaf_node(FALSE);} | '(' boolexp ')' {$$ = $2;} | boolexp OR boolexp {$$ = ast_node_new_binary(OR, $1, $3);} | boolexp AND boolexp {$$ = ast_node_new_binary(AND, $1, $3);} | NOT boolexp {$$ = ast_node_new_unary(NOT, $2);} | exp EQUAL exp {$$ = ast_node_new_binary(EQUAL, $1, $3);} | exp NOT_EQUAL exp {$$ = ast_node_new_binary(NOT_EQUAL, $1, $3);} | exp '<' exp {$$ = ast_node_new_binary('<', $1, $3);} | exp '>' exp {$$ = ast_node_new_binary('>', $1, $3);} | exp LESS_OR_EQUAL exp { $$ = ast_node_new_binary(LESS_OR_EQUAL, $1, $3); } | exp GREATER_OR_EQUAL exp { $$ = ast_node_new_binary(GREATER_OR_EQUAL, $1, $3); } | string REGEX_MATCH REGEX_PATTERN { $$ = ast_node_new_binary(REGEX_MATCH, $1, $3); } | string EQUAL string {$$ = ast_node_new_binary(EQUAL, $1, $3);} | string NOT_EQUAL string {$$ = ast_node_new_binary(NOT_EQUAL, $1, $3);} ; %% /* Called by yyparse() on error */ static void yyerror(YYLTYPE *llocp, struct txp_context *ctx, __attribute__ ((unused)) struct txp_ast_node **ast, __attribute__ ((unused)) txp_yyscan_t yyscanner, const char *msg) { txp_parse_error(llocp->first_line, ctx, "%s", msg); }