diff options
| author | Andre Noll <maan@tuebingen.mpg.de> | 2018-01-11 23:40:23 +0100 |
|---|---|---|
| committer | Andre Noll <maan@tuebingen.mpg.de> | 2018-01-11 23:40:23 +0100 |
| commit | b95de7e4b629c3ffb90ae09b53d0178285e73629 (patch) | |
| tree | 2929492fa05274fc150e09c4821dbf52a65149f3 /tf.h | |
initialinitial
Diffstat (limited to 'tf.h')
| -rw-r--r-- | tf.h | 148 |
1 files changed, 148 insertions, 0 deletions
@@ -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. */ + |
