summaryrefslogtreecommitdiff
path: root/other/gramble/producer.c
blob: 55346b85b519cbf706ab7c596f39d5309053575d (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
/* gramble - grammar ramble
 * production engine for grammar derivations
 *
 * -scut
 */


/* we use a pushdown ntm like construct to generate valid derivations of the
 * original grammar.
 */


/* terminal structure
 *
 * a simple word consisting of characters
 */
typedef struct {
	unsigned int	word_len;	/* length, not including NUL */
	unsigned char *	word;		/* if word_Len > 0: must be non-NULL */
} terminal;


/* nonterminal structure
 *
 * contains 'plist', a pointer to a production list of that nonterminal
 */
typedef struct {
	unsigned int	pcount;	/* number of productions for that nterm */
	symbol **	plist;	/* list of productions for that nonterminal */
} nonterminal;


/* symbol structure
 *
 * shared linked list of symbols consisting of terminals and nonterminals.
 * `next' being NULL marks the end of the derivation. `prev' being NULL marks
 * the first.
 * exactly one of `term' or `nterm' has to be non-NULL and point to a valid
 * structure.
 */
typedef struct symbol {
	symbol *	prev;
	symbol *	next;
	terminal *	term;
	nonterminal *	nterm;
} symbol;


/* prod_genstatement
 *
 * derive a nonterminal completely to nonterminals. stop when the output
 * buffer `obuf' has been filled with `obuf_len' bytes or when there are
 * no more nonterminals to derive. start to derive from nonterminal `step'.
 *
 * return number of terminal characters derived on success
 * return -1 on failure
 */

unsigned int
prod_genstatement (nonterminal *step,
	unsigned char *obuf, unsigned long int obuf_len)
{
	unsigned int	produced = 0,
			sub_produced = 0;
	unsigned int	psel;	/* production selector */
	symbol *	prod;	/* production to use */


	if (obuf_len == 0)
		return (0);

	/* TODO: choose a more custom selection over a random pick
	 */
	psel = random_get (0, step->pcount - 1);

	for (prod = start->plist[psel] ; prod != NULL ; prod = prod->next) {

		/* terminals */
		if (prod->term != NULL) {
			if (prod->term->word_len < obuf_len) {
				memcpy (obuf, prod->term->word,
					prod->term->word_len);
				obuf += prod->term->word_len;
				obuf_len -= prod->term->word_len;
				produced += prod->term->word_len;
			} else	/* no room left :-( */
				return (produced);

		/* non-terminals */
		} else if (prod->nterm != NULL) {

			sub_produced = prod_genstatement (prod->nterm,
				obuf, obuf_len);
			obuf += sub_produced;
			obuf_len -= sub_produced;
		}
	}

	/* finished deriving */
	return (produced);
}