summaryrefslogtreecommitdiff
path: root/tf.h
diff options
context:
space:
mode:
Diffstat (limited to 'tf.h')
-rw-r--r--tf.h148
1 files changed, 148 insertions, 0 deletions
diff --git a/tf.h b/tf.h
new file mode 100644
index 0000000..4c01764
--- /dev/null
+++ b/tf.h
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <fnmatch.h>
+#include <regex.h>
+#include <assert.h>
+#include <lopsub.h>
+
+#include "err.h"
+
+/* Opaque, only known to ast.c. Passed to the generated txp_yyparse(). */
+struct txp_context;
+
+/*
+ * Since we use a reentrant lexer, all functions generated by flex(1)
+ * receive an additional argument of this type.
+ */
+typedef void *txp_yyscan_t;
+
+/* Parsed regex pattern. */
+struct txp_re_pattern {
+ regex_t preg; /* Pre-compiled regex. */
+ unsigned flags; /* Subset of the cflags described in regex(3). */
+};
+
+/*
+ * The possible values of a node in the abstract syntax tree (AST).
+ *
+ * Constant semantic values (string literals, numeric constants and regex
+ * patterns which are part of the tag expression) are determined during
+ * txp_init() while values which depend on the epigram (tags, number of lines,
+ * etc.) are determined during txp_eval_row().
+ *
+ * This union, and the txp_ast_node structure below are used extensively in
+ * txp.y. However, both need to be public because the lexer must be able to
+ * create AST nodes for the constant semantic values.
+ */
+union txp_semantic_value {
+ bool boolval; /* Comparators, =~ and =|. */
+ char *strval; /* String literals, tags, path. */
+ int64_t intval; /* Constants, bitrate, frequency, etc. */
+ struct txp_re_pattern re_pattern; /*< Right-hand side operand of =~. */
+};
+
+/*
+ * A node is either interior or a leaf node. Interior nodes have at least one
+ * child while leaf nodes have a semantic value and no children.
+ *
+ * Examples: (a) STRING_LITERAL has a semantic value (the unescaped string
+ * literal) and no children, (b) NEG (unary minus) has no semantic value but
+ * one child (the numeric expression that is to be negated), (c) LESS_OR_EQUAL
+ * has no semantic value and two children (the two numeric expressions being
+ * compared).
+ */
+struct txp_ast_node {
+ /* Corresponds to a token type, for example LESS_OR_EQUAL. */
+ int id;
+ union {
+ /* Pointers to the child nodes (interior nodes only). */
+ struct txp_ast_node **children;
+ /* Leaf nodes only. */
+ union txp_semantic_value sv;
+ };
+ /*
+ * The number of children is implicitly given by the id, but we include
+ * it here to avoid having to maintain a lookup table. The AST is
+ * usually small, so we can afford to waste a byte per node.
+ */
+ uint8_t num_children;
+};
+
+enum loglevels {LOGLEVELS, NUM_LOGLEVELS};
+#define DEBUG_LOG(f,...) txp_log(LL_DEBUG, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
+#define INFO_LOG(f,...) txp_log(LL_INFO, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
+#define NOTICE_LOG(f,...) txp_log(LL_NOTICE, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
+#define WARNING_LOG(f,...) txp_log(LL_WARNING, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
+#define ERROR_LOG(f,...) txp_log(LL_ERROR, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
+#define CRIT_LOG(f,...) txp_log(LL_CRIT, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
+#define EMERG_LOG(f,...) txp_log(LL_EMERG, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
+
+/* tfortune.c */
+
+void txp_log(int ll, const char* fmt,...);
+
+/* Called from both the lexer and the parser. */
+__attribute__ ((format (printf, 3, 4)))
+void txp_parse_error(int line, struct txp_context *ctx, const char *fmt, ...);
+
+/* Helper functions for the lexer. */
+unsigned parse_quoted_string(const char *src, const char quote_chars[2],
+ char **result);
+int txp_parse_regex_pattern(const char *src, struct txp_re_pattern *result);
+
+/* ast.c */
+struct txp_ast_node *ast_node_new_unary(int id, struct txp_ast_node *child);
+struct txp_ast_node *ast_node_new_binary(int id, struct txp_ast_node *left,
+ struct txp_ast_node *right);
+
+/*
+ * Allocate a new leaf node for the abstract syntax tree.
+ *
+ * This returns a pointer to a node whose ->num_children field is initialized
+ * to zero. The ->id field is initialized with the given id. The caller is
+ * expected to initialize the ->sv field.
+ */
+struct txp_ast_node *txp_new_ast_leaf_node(int id);
+
+/*
+ * Evaluate an abstract syntax tree, starting at the root node.
+ *
+ * The root node argument should be the pointer that was returned from an
+ * earlier call to txp_init() via the context pointer. The context contains the
+ * information about the epigram.
+ *
+ * Returns true if the AST evaluates to true, a non-empty string, or a non-zero
+ * number, false otherwise.
+ */
+bool txp_eval_ast(struct txp_ast_node *root, struct txp_context *ctx);
+
+/*
+ * Deallocate an abstract syntax tree.
+ *
+ * This frees the memory occupied by the nodes of the AST, the child pointers
+ * of the internal nodes and the (constant) semantic values of the leaf nodes
+ * (string literals and pre-compiled regular expressions).
+ */
+void txp_free_ast(struct txp_ast_node *root);
+
+
+/* util.c */
+int atoi64(const char *str, int64_t *value);
+unsigned xvasprintf(char **result, const char *fmt, va_list ap);
+unsigned xasprintf(char **result, const char *fmt, ...);
+void *xmalloc(size_t size);
+void *xcalloc(size_t size);
+int xregcomp(regex_t *preg, const char *regex, int cflags);
+
+/* txp.c */
+
+/* txp.y. */
+