/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include #include #include #include #include #include #include #include #include #include #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. */