summaryrefslogtreecommitdiff
path: root/txp.y
diff options
context:
space:
mode:
Diffstat (limited to 'txp.y')
-rw-r--r--txp.y130
1 files changed, 130 insertions, 0 deletions
diff --git a/txp.y b/txp.y
new file mode 100644
index 0000000..578b2a4
--- /dev/null
+++ b/txp.y
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * 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 <node> NUM
+%token <node> STRING_LITERAL
+%token <node> REGEX_PATTERN
+
+/* keywords with semantic value */
+%token <node> NUM_LINES
+%token <node> FALSE TRUE
+
+/* 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 <node> string
+%type <node> exp
+%type <node> 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;}
+;
+
+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;}
+ | NUM_LINES {$$ = txp_new_ast_leaf_node(NUM_LINES);}
+;
+
+boolexp: 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);
+}