com_stats(): Work around bogus gcc warning.
[tfortune.git] / txp.y
1 /* SPDX-License-Identifier: GPL-3.0-only */
2
3 /*
4  * Provide more verbose and specific error messages instead of just "syntax
5  * error".
6  */
7 %define parse.error verbose
8
9 /*
10  * Verbose error messages may contain incorrect information if LAC (Lookahead
11  * Correction) is not enabled.
12  */
13 %define parse.lac full
14
15 /* Avoid symbol clashes (lopsub might also expose yy* symbols). */
16 %define api.prefix {txp_yy}
17
18 /*
19  * Although locations are automatically enabled as soon as the grammar uses the
20  * special @N tokens, specifying %locations explicitly allows for more accurate
21  * syntax error messages.
22  */
23 %locations
24
25 /*
26  * Generate a pure (reentrant) parser. With this option enabled, yylval and
27  * yylloc become local variables in yyparse(), and a different calling
28  * convention is used for yylex().
29  */
30 %define api.pure full
31
32 /* Additional arguments to yylex(), yyparse() and yyerror() */
33 %param {struct txp_context *ctx}
34 %param {struct txp_ast_node **ast}
35 %param {txp_yyscan_t yyscanner} /* reentrant lexers */
36
37 %{
38 #include "tf.h"
39 #include "txp.bison.h"
40
41 int yylex(TXP_YYSTYPE *lvalp, TXP_YYLTYPE *llocp, struct txp_context *ctx,
42                 struct txp_ast_node **ast, txp_yyscan_t yyscanner);
43 static void yyerror(YYLTYPE *llocp, struct txp_context *ctx,
44                 struct txp_ast_node **ast, txp_yyscan_t yyscanner, const char *msg);
45
46 %}
47
48 %union {
49         struct txp_ast_node *node;
50 }
51
52 /* terminals */
53 %token <node> NUM
54 %token <node> STRING_LITERAL
55 %token <node> REGEX_PATTERN
56
57 /* keywords with semantic value */
58 %token <node> LEN
59 %token <node> FALSE TRUE
60 %token <node> TEXT
61
62 /* keywords without semantic value */
63 %token TAG
64
65 /* operators, ordered by precendence */
66 %left OR
67 %left AND
68 %left EQUAL NOT_EQUAL
69 %left LESS_THAN LESS_OR_EQUAL GREATER_OR_EQUAL REGEX_MATCH FILENAME_MATCH
70 %left '-' '+'
71 %left '*' '/'
72 %right NOT NEG /* negation (unary minus) */
73
74 /* nonterminals */
75 %type <node> string
76 %type <node> exp
77 %type <node> boolexp
78
79 %%
80
81 program:
82         /* empty */ {*ast = NULL; return 0;}
83         | string {*ast = $1; return 0;}
84         | exp {*ast = $1; return 0;}
85         | boolexp {*ast = $1; return 0;}
86
87 string: STRING_LITERAL {$$ = $1;}
88         | TEXT {$$ = txp_new_ast_leaf_node(TEXT);}
89 ;
90
91 exp: NUM {$$ = $1;}
92         | exp '+' exp {$$ = ast_node_new_binary('+', $1, $3);}
93         | exp '-' exp {$$ = ast_node_new_binary('-', $1, $3);}
94         | exp '*' exp {$$ = ast_node_new_binary('*', $1, $3);}
95         | exp '/' exp {$$ = ast_node_new_binary('/', $1, $3);}
96         | '-' exp %prec NEG {$$ = ast_node_new_unary(NEG, $2);}
97         | '(' exp ')' {$$ = $2;}
98         | LEN {$$ = txp_new_ast_leaf_node(LEN);}
99 ;
100
101 boolexp: TAG '(' STRING_LITERAL ')' {$$ = ast_node_new_unary(TAG, $3);}
102         | TRUE {$$ = txp_new_ast_leaf_node(TRUE);}
103         | FALSE {$$ = txp_new_ast_leaf_node(FALSE);}
104         | '(' boolexp ')' {$$ = $2;}
105         | boolexp OR boolexp {$$ = ast_node_new_binary(OR, $1, $3);}
106         | boolexp AND boolexp {$$ = ast_node_new_binary(AND, $1, $3);}
107         | NOT boolexp {$$ = ast_node_new_unary(NOT, $2);}
108         | exp EQUAL exp {$$ = ast_node_new_binary(EQUAL, $1, $3);}
109         | exp NOT_EQUAL exp {$$ = ast_node_new_binary(NOT_EQUAL, $1, $3);}
110         | exp '<' exp {$$ = ast_node_new_binary('<', $1, $3);}
111         | exp '>' exp {$$ = ast_node_new_binary('>', $1, $3);}
112         | exp LESS_OR_EQUAL exp {
113                 $$ = ast_node_new_binary(LESS_OR_EQUAL, $1, $3);
114         }
115         | exp GREATER_OR_EQUAL exp {
116                 $$ = ast_node_new_binary(GREATER_OR_EQUAL, $1, $3);
117         }
118         | string REGEX_MATCH REGEX_PATTERN {
119                 $$ = ast_node_new_binary(REGEX_MATCH, $1, $3);
120         }
121         | string EQUAL string {$$ = ast_node_new_binary(EQUAL, $1, $3);}
122         | string NOT_EQUAL string {$$ = ast_node_new_binary(NOT_EQUAL, $1, $3);}
123 ;
124 %%
125
126 /* Called by yyparse() on error */
127 static void yyerror(YYLTYPE *llocp, struct txp_context *ctx,
128                 __attribute__ ((unused)) struct txp_ast_node **ast,
129                 __attribute__ ((unused)) txp_yyscan_t yyscanner,
130                 const char *msg)
131 {
132         txp_parse_error(llocp->first_line, ctx, "%s", msg);
133 }