summaryrefslogtreecommitdiff
path: root/tf.h
blob: 4c01764f3b5aaf266cde6d1ded2d95e952b6914b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
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. */