diff options
| author | sanine <sanine.not@pm.me> | 2025-10-27 10:52:01 -0500 | 
|---|---|---|
| committer | sanine <sanine.not@pm.me> | 2025-10-27 10:52:01 -0500 | 
| commit | 8f63364c2b1ec54e104c189db43805917800b789 (patch) | |
| tree | 8329eb5a9955667f1aa8d2e22110062d841379c7 | |
| parent | 11f8fd4418a068c76fc7c810967a6bf285ee74b6 (diff) | |
implement basic grammatical expansionc-version
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | expression.c | 105 | ||||
| -rw-r--r-- | expression.h | 22 | ||||
| -rw-r--r-- | expression.test.c | 61 | ||||
| -rw-r--r-- | lily-test.h | 741 | 
6 files changed, 926 insertions, 7 deletions
| @@ -1,3 +1,4 @@  *.swp  *.swo  example +test @@ -1,2 +1,5 @@  example: genalg.h genalg.c genalg.example.c  	gcc -g -o example genalg.c genalg.example.c -Wall -Wextra -Wpedantic -Werror -lm + +test: expression.h expression.c expression.test.c +	gcc -g -o test expression.c expression.test.c -Wall -Wextra -Wpedantic -Werror -lm diff --git a/expression.c b/expression.c index 11904fc..f4d7b26 100644 --- a/expression.c +++ b/expression.c @@ -1,5 +1,6 @@  #include <stdlib.h>  #include <stdio.h> +#include <string.h>  #include "expression.h" @@ -65,7 +66,7 @@ int li_prod_rule_add(  } -li_grammar_t * li_grammar_alloc(size_t num_nonterminal) { +li_grammar_t * li_grammar_alloc(int num_nonterminal) {    li_grammar_t *grammar = malloc(sizeof(li_grammar_t));    if (grammar == NULL) {      fprintf(stderr, "failed to allocate grammar\n"); @@ -77,18 +78,18 @@ li_grammar_t * li_grammar_alloc(size_t num_nonterminal) {      free(grammar);      return NULL;    } -  for (size_t i=0; i<num_nonterminal; i++) { +  for (int i=0; i<num_nonterminal; i++) {      grammar->rules[i].num_productions = 0;      grammar->rules[i].head = NULL;    } -  grammar->num_nonterminal = NULL; +  grammar->num_nonterminal = num_nonterminal;    return grammar;  }  void li_grammar_free(li_grammar_t *grammar) {    if (grammar != NULL) { -    for (size_t i=0; i<grammar->num_nonterminal; i++) { +    for (int i=0; i<grammar->num_nonterminal; i++) {        li_production_free(grammar->rules[i].head);      }      free(grammar->rules); @@ -100,7 +101,7 @@ void li_grammar_free(li_grammar_t *grammar) {  int li_grammar_rule_add(    li_grammar_t *grammar, int nonterminal, size_t seq_len, int *seq  ) { -  if (nonterminal < 0 || nonterminal >= grammar->num_nonterminal) { +  if (nonterminal >= grammar->num_nonterminal) {      return 2;    }    return li_prod_rule_add(grammar->rules + nonterminal, seq_len, seq); @@ -108,3 +109,97 @@ int li_grammar_rule_add( +int stack_push(int *stack, size_t stack_sz, size_t *top, int value) { +  *top += 1; +  if (*top >= stack_sz) { +    fprintf(stderr, "grammar stack overflow!\n"); +    return 1; +  } +  stack[*top] = value; +  return 0; +} + + +int stack_pop(int *stack, size_t *top, int *value) { +  if (*top == ((size_t)-1)) { +    fprintf(stderr, "grammar stack underflow!\n"); +    return 1; +  } + +  *value = stack[*top]; +  *top -=1; +  return 0; +} + + +int expand_production( +  li_grammar_t *grammar,  +  int *dst, size_t sz, size_t *len, +  int *stack, size_t stack_sz, size_t *top, +  int symbol, +  const uint8_t *randomness, size_t rand_sz +) { +  struct li_production_rule_t rule = grammar->rules[symbol]; +  struct li_production_t *prod; +  if (rule.num_productions == 0) { +    // empty rule, nothing to do +    return 0; +  } else if (rule.num_productions == 1) { +    // pick only production +    prod = rule.head; +  } else { +    // use randomness to select production +    int selection = randomness[0] % rule.num_productions; +    randomness += 1; +    rand_sz -= 1; +    prod = rule.head; +    for (int i=0; i<selection; i++) { +      prod = prod->next; +    } +  } + +  // push production to stack +  for (int i=prod->seq_len-1; i>=0; i--) { +    if (stack_push(stack, stack_sz, top, prod->seq[i]) != 0) { +      return 1; +    } +  } + +  // pop production from stack, recursing on nonterminals +  while (*top != ((size_t)-1)) { +    int symbol; +    if (stack_pop(stack, top, &symbol) != 0) { +      return 1; +    } +    if (symbol < grammar->num_nonterminal) { +      int err = expand_production(grammar, dst, sz, len, stack, stack_sz, top, symbol, randomness, rand_sz); +      if (err != 0) { +        return err; +      } +    } else { +      if (*len > sz) { +        fprintf(stderr, "exceeded maximum output buffer length\n"); +        return 1; +      } +      dst[*len] = symbol; +      *len += 1; +    } +  } + +  return 0; +} + + + +int li_grammar_rule_expand( +  li_grammar_t *grammar,  +  int *dst, size_t *len,  +  int *stack, size_t stack_sz,  +  int symbol,  +  const uint8_t *randomness, size_t rand_sz +) { +  size_t sz = *len; +  *len = 0; +  size_t top = -1; +  return expand_production(grammar, dst, sz, len, stack, stack_sz, &top, symbol, randomness, rand_sz); +} diff --git a/expression.h b/expression.h index 36a0e02..e288a77 100644 --- a/expression.h +++ b/expression.h @@ -1,6 +1,8 @@  #ifndef LICHEN_EXPRESSION_H  #define LICHEN_EXPRESSION_H +#include <stdint.h> +  /****************************************************************   *    * a grammar is built on both nonterminals and terminals. both are @@ -32,11 +34,27 @@ int li_prod_rule_add(struct li_production_rule_t *rule, size_t seq_len, int *seq  typedef struct li_grammar_t {    struct li_production_rule_t *rules; -  size_t num_nonterminal; +  int num_nonterminal;  } li_grammar_t; -li_rammar_t * li_grammar_alloc(size_t num_nonterminal); +li_grammar_t * li_grammar_alloc(int num_nonterminal);  void li_grammar_free(li_grammar_t *grammar);  int li_grammar_rule_add(li_grammar_t *grammar, int nonterminal, size_t seq_len, int *seq); +// expand a symbol into only nonterminals +// dst is a buffer to place the expansion into, and len should initially contain the size of the buffer +// stack is a buffer used internally to expand the rule, and stack_sz is the size of the stack +// symbol is the symbol to start with +// randomness is a sequence of random values, from any source, and rand_sz is the length of the sequence +// if successful, this function will return 0 and dst will contain the expanded sequence, with len containing +// the length of the actual expansion +// if unsuccessful, this function will return nonzero. dst, len, and stack may be modified in unpredictable ways. +int li_grammar_rule_expand( +  li_grammar_t *grammar,  +  int *dst, size_t *len,  +  int *stack, size_t stack_sz,  +  int symbol,  +  const uint8_t *randomness, size_t rand_sz +); +  #endif diff --git a/expression.test.c b/expression.test.c new file mode 100644 index 0000000..234347d --- /dev/null +++ b/expression.test.c @@ -0,0 +1,61 @@ +#define LILY_IMPLEMENTATION +#include "lily-test.h" +#include "expression.h" + + +LILY_FILE_BEGIN(expression_suite) + + +enum simple_symbol_t { +  START, +  SIMPLE_NUM_NONTERMINALS, +  A, B, C, +}; + +LILY_TEST("expand basic expression") { +  li_grammar_t *grammar = li_grammar_alloc(SIMPLE_NUM_NONTERMINALS); +  REQUIRE_NEQ(grammar, NULL, "%p"); + +  int err; + +  int rule0[] = { A, START, B }; +  err = li_grammar_rule_add(grammar, START, 3, rule0); +  CHECK_EQ(err, 0, "%d"); +  int rule1[] = { C }; +  err = li_grammar_rule_add(grammar, START, 1, rule1); +  CHECK_EQ(err, 0, "%d"); + +  int buf[32]; size_t bufsz = 32; int stack[32]; +  uint8_t rand[] = { 1, 1, 1, 0 }; + +  err = li_grammar_rule_expand(grammar, buf, &bufsz, stack, 32, START, rand, 4); + +  REQUIRE_EQ(err, 0, "%d"); +  CHECK_EQ(bufsz, 7, "%lu"); + +  CHECK_EQ(buf[0], A, "%d"); +  CHECK_EQ(buf[1], A, "%d"); +  CHECK_EQ(buf[2], A, "%d"); + +  CHECK_EQ(buf[3], C, "%d"); + +  CHECK_EQ(buf[4], B, "%d"); +  CHECK_EQ(buf[5], B, "%d"); +  CHECK_EQ(buf[6], B, "%d"); + +  li_grammar_free(grammar); +} +#include LILY_PUSH_TEST() + + +#define LILY_FILE_END +#include LILY_REGISTER_TESTS() + + + +int main() { +  lily_begin(); +  expression_suite(); +  lily_finish(); +  return 0; +} diff --git a/lily-test.h b/lily-test.h new file mode 100644 index 0000000..8c1ad13 --- /dev/null +++ b/lily-test.h @@ -0,0 +1,741 @@ +/**************************************************************** + * + * ======== lily-test ======== + * + * a midsize C unit testing library + * copyright (c) 2022 kate swanson (sanine) + * + * This is anti-capitalist software, released for free use by individuals and + * organizations that do not operate by capitalist principles. + * + * Permission is hereby granted, free of charge, to any person or + * organization (the "User") obtaining a copy of this software and associated + * documentation files (the "Software"), to use, copy, modify, merge, + * distribute, and/or sell copies of the Software, subject to the following  + * conditions: + * + * 1. The above copyright notice and this permission notice shall be included + *    in all copies or modified versions of the Software. + * + * 2. The User is one of the following: + *    a. An individual person, laboring for themselves + *    b. A non-profit organization + *    c. An educational institution + *    d. An organization that seeks shared profit for all of its members, and + *       allows non-members to set the cost of their labor + * + * 3. If the User is an organization with owners, then all owners are workers + *    and all workers are owners with equal equity and/or equal vote. + * + * 4. If the User is an organization, then the User is not law enforcement or + *    military, or working for or under either. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT EXPRESS OR IMPLIED WARRANTY OF + * ANY KIND, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://anticapitalist.software/ + * https://sanine.net + * + ****************************************************************/ + + +#ifndef LILY_TEST_H +#define LILY_TEST_H + +#define LILY_VERSION_MAJOR 2 +#define LILY_VERSION_MINOR 0 +#define LILY_VERSION_PATCH 1 + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <setjmp.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <math.h> +#include <string.h> + +#define STR_IMP(x) #x +#define STR(x) STR_IMP(x) +/* define SOURCE_PATH_SIZE to strip away the +   leading parts of the full compilation path */ +#ifndef SOURCE_PATH_SIZE +#define LILY_LOCATION (__FILE__ ":" STR(__LINE__)) +#else +#define LILY_LOCATION ((__FILE__ ":" STR(__LINE__)) + SOURCE_PATH_SIZE) +#endif + +#define LILY_NULLSAFE(x) (x==NULL ? "(nil)" : x) +int lily_streq(const char *str1, const char *str2); + + +/* self-location macro */ +#ifndef LILY_TEST_H_LOCATION +#define LILY_TEST_H_LOCATION "lily-test.h" +#endif + + +/* counter macros */ +#define LILY_HEX_(x) 0x##x +#define LILY_HEX(x) LILY_HEX_(x) +#define LILY_COUNTER_POS_0 0 +#define LILY_COUNTER_POS_1 0 +#define LILY_COUNTER_POS_2 0 +#define LILY_COUNTER__(a, b, c) 0x##a##b##c +#define LILY_COUNTER_(a, b, c) LILY_COUNTER__(a, b, c) +#define LILY_COUNTER LILY_COUNTER_(LILY_COUNTER_POS_2, LILY_COUNTER_POS_1, LILY_COUNTER_POS_0) + +/* automatic registration macros */ +typedef struct lily_ll_node_t { +	struct lily_ll_node_t *next; +	void (*f)(); +} lily_ll_node_t; +#define LILY_FILE_BEGIN(unique_id) \ +static lily_ll_node_t lily_ll_last = { NULL, NULL }; \ +static void file_runner(); \ +void (*unique_id)() = file_runner; + +#define LILY_LIST_HEAD lily_ll_last +#define LILY_LIST_NEXT lily_ll_last +#define LILY_PUSH_TEST() LILY_TEST_H_LOCATION +#define LILY_REGISTER_TESTS() LILY_TEST_H_LOCATION + +#define LILY_CAT_(x, y) x##y +#define LILY_CAT(x, y) LILY_CAT_(x, y) +#define LILY_ANON(x) LILY_CAT(x, LILY_COUNTER) +#define LILY_ANON_WRAP LILY_ANON(LILY_WRAP_) +#define LILY_ANON_FUNC LILY_ANON(LILY_FUNCTION_) +#define LILY_ANON_NODE LILY_ANON(LILY_NODE_) +#define LILY_ANON_DESC LILY_ANON(LILY_DESCRIPTION_) + +#define LILY_TEST_(wrap, f, desc_str, description) \ +static void f(); \ +static void wrap() \ +{ \ +	lily_g.test_name = description; \ +	f(); \ +} \ +static void f() + +#define LILY_TEST(description) LILY_TEST_(LILY_ANON_WRAP, LILY_ANON_FUNC, LILY_ANON_DESC, description) + +/* assertions */ +typedef struct lily_test_msg_t { +	struct lily_test_msg_t *next; +	char *msg; +	const char *location; +} lily_test_msg_t; +void lily_msg_destroy(lily_test_msg_t *m); + +void lily_info(const char *location, const char *fmt, ...); +#define LILY_INFO_(location, ...) \ +	lily_info(location, __VA_ARGS__) +#define LILY_INFO(...) LILY_INFO_(LILY_LOCATION, __VA_ARGS__) +#define INFO(...) LILY_INFO(__VA_ARGS__) + +void lily_check(int x, const char *location, const char *fmt, ...); +#define LILY_CHECK_(str, x, location) \ +	lily_check(x, location, "CHECK failed: %s", str) +#define LILY_CHECK(x) LILY_CHECK_(STR(x), x, LILY_LOCATION) +#define CHECK(x) LILY_CHECK(x) + +#define LILY_CHECK_CMP_(x, y, xstr, ystr, cmp, cmpstr, fmt) \ +	lily_check((x) cmp (y), LILY_LOCATION, \ +		"CHECK failed: %s " cmpstr " %s\n    %s = " fmt "\n    %s = " fmt,\ +		xstr, ystr,  xstr, x,  ystr, y) +#define LILY_CHECK_CMP(x, cmp, y, fmt) LILY_CHECK_CMP_(x, y, #x, #y, cmp, #cmp, fmt) + +/* check comparision assertions */ +#define CHECK_EQ(x, y, fmt) LILY_CHECK_CMP(x, ==, y, fmt) +#define CHECK_NEQ(x, y, fmt) LILY_CHECK_CMP(x, !=, y, fmt) +#define CHECK_LT(x, y, fmt) LILY_CHECK_CMP(x, <, y, fmt) +#define CHECK_LE(x, y, fmt) LILY_CHECK_CMP(x, <=, y, fmt) +#define CHECK_GT(x, y, fmt) LILY_CHECK_CMP(x, >, y, fmt) +#define CHECK_GE(x, y, fmt) LILY_CHECK_CMP(x, >=, y, fmt) + +#define LILY_CHECK_EQF(x, y, xstr, ystr, fmt) \ +	lily_check(fabs(x-y) < lily_g.epsilon, LILY_LOCATION, \ +		"CHECK failed: %s == %s\n    %s = " fmt "\n    %s = " fmt "\n    epsilon: %f", \ +		xstr, ystr, xstr, x, ystr, y, lily_g.epsilon) +#define CHECK_EQF(x, y, fmt) LILY_CHECK_EQF(x, y, #x, #y, fmt) + +#define LILY_CHECK_EQS(x, y, xstr, ystr) \ +	lily_check(lily_streq(x, y), LILY_LOCATION, \ +		"CHECK failed: %s == %s\n    %s = \"%s\"\n    %s = \"%s\"", \ +		xstr, ystr,  xstr, x,  ystr, y) +#define CHECK_EQS(x, y) LILY_CHECK_EQS(x, y, #x, #y) + + +void lily_require(int x, const char *location, const char *fmt, ...); +#define LILY_REQUIRE_(str, x, location) \ +	lily_require(x, location, "REQUIRE failed: %s", str) +#define LILY_REQUIRE(x) LILY_REQUIRE_(STR(x), x, LILY_LOCATION) +#define REQUIRE(x) LILY_REQUIRE(x) + +#define LILY_REQUIRE_CMP_(x, y, xstr, ystr, cmp, cmpstr, fmt) \ +	lily_require((x) cmp (y), LILY_LOCATION, \ +		"REQUIRE failed: %s " cmpstr " %s\n    %s = " fmt "\n    %s = " fmt,\ +		xstr, ystr,  xstr, x,  ystr, y) +#define LILY_REQUIRE_CMP(x, cmp, y, fmt) LILY_REQUIRE_CMP_(x, y, #x, #y, cmp, #cmp, fmt) + +/* require comparison assertions */ +#define REQUIRE_EQ(x, y, fmt) LILY_REQUIRE_CMP(x, ==, y, fmt) +#define REQUIRE_NEQ(x, y, fmt) LILY_REQUIRE_CMP(x, !=, y, fmt) +#define REQUIRE_LT(x, y, fmt) LILY_REQUIRE_CMP(x, <, y, fmt) +#define REQUIRE_LE(x, y, fmt) LILY_REQUIRE_CMP(x, <=, y, fmt) +#define REQUIRE_GT(x, y, fmt) LILY_REQUIRE_CMP(x, >, y, fmt) +#define REQUIRE_GE(x, y, fmt) LILY_REQUIRE_CMP(x, >=, y, fmt) + +#define LILY_REQUIRE_EQF(x, y, xstr, ystr, fmt) \ +	lily_require(fabs(x-y) < lily_g.epsilon, LILY_LOCATION, \ +		"REQUIRE failed: %s == %s\n    %s = " fmt "\n    %s = " fmt "\n    epsilon: %f", \ +		xstr, ystr, xstr, x, ystr, y, lily_g.epsilon) +#define REQUIRE_EQF(x, y, fmt) LILY_REQUIRE_EQF(x, y, #x, #y, fmt) + +#define LILY_REQUIRE_EQS(x, y, xstr, ystr) \ +	lily_require(lily_streq(x, y), LILY_LOCATION, \ +		"REQUIRE failed: %s == %s\n    %s = \"%s\"\n    %s = \"%s\"", \ +		xstr, ystr,  xstr, x,  ystr, y) +#define REQUIRE_EQS(x, y) LILY_REQUIRE_EQS(x, y, #x, #y) + + +void lily_begin(); +void lily_finish(); +void lily_run_test(void (*test)()); +void lily_set_epsilon(double epsilon); + + +extern struct lily_global_t { +	int failed; +	jmp_buf env; +	const char *test_name; +	lily_test_msg_t HEAD; +	lily_test_msg_t *TAIL; +	int n_assertions; +	int n_assertions_failed; +	int n_tests; +	int n_tests_failed; +	double epsilon; +} lily_g; + +#ifdef LILY_IMPLEMENTATION +struct lily_global_t lily_g; + +lily_test_msg_t *lily_msg_create(const char *location, const char *fmt, va_list args) +{ +	lily_test_msg_t *m = (lily_test_msg_t*) malloc(sizeof(lily_test_msg_t)); +	if (m == NULL) { +		return NULL; +	} +	m->next = NULL; +	m->location = location; + +	va_list args_len; +	va_copy(args_len, args); +	size_t len = vsnprintf(NULL, 0, fmt, args_len) + 1; +	va_end(args_len); + +	m->msg = (char*) malloc(len * sizeof(char)); +	if (m->msg == NULL) { +		free(m); +		return NULL; +	} +	vsnprintf(m->msg, len, fmt, args); + +	return m; +} + +void lily_msg_destroy(lily_test_msg_t *m) +{ +	if (m == NULL) { +		/* ignore */ +		return; +	} + +	if (m->next != NULL) { +		// destroy the whole chain +		lily_msg_destroy(m->next); +	} + +	free(m->msg); +	free(m); +} + + +void lily_run_test(void (*test)()) +{ +	lily_g.n_tests += 1; +	lily_g.HEAD.next = NULL; +	lily_g.TAIL = &(lily_g.HEAD); +	lily_g.failed = 0; +	int jumped = setjmp(lily_g.env); + +	if (!jumped) { +		test(); +	} + +	if (lily_g.failed) { +		lily_g.n_tests_failed += 1; +		printf("================================================================================\n"); +		printf("test \"%s\" failed!\n\n", lily_g.test_name); +		lily_test_msg_t *n = lily_g.HEAD.next; +		while(n != NULL) { +			printf("  %s\n    [%s]\n\n", n->msg, n->location); +			n = n->next; +		} +	} +	lily_msg_destroy(lily_g.HEAD.next); +} + + +void lily_info(const char *location, const char *fmt, ...) +{ +	va_list args; +	va_start(args, fmt); +	lily_test_msg_t *m = lily_msg_create(location, fmt, args); +	va_end(args); + +	lily_g.TAIL->next = m; +	lily_g.TAIL = m; +} + +void lily_check(int x, const char *location, const char *fmt, ...) +{ +	lily_g.n_assertions += 1; +	if (!x) { +		// assertion failed +		lily_g.n_assertions_failed += 1; + +		va_list args; +		va_start(args, fmt); +		lily_test_msg_t *m = lily_msg_create(location, fmt, args); +		va_end(args); + +		lily_g.TAIL->next = m; +		lily_g.TAIL = m; +		lily_g.failed = 1; +	} +} + + +void lily_require(int x, const char *location, const char *fmt, ...) +{ +	lily_g.n_assertions += 1; +	if (!x) { +		// assertion failed +		lily_g.n_assertions_failed += 1; + +		va_list args; +		va_start(args, fmt); +		lily_test_msg_t *m = lily_msg_create(location, fmt, args); +		va_end(args); + +		lily_g.TAIL->next = m; +		lily_g.TAIL = m; +		lily_g.failed = 1; + +		/* longjump out of test */ +		longjmp(lily_g.env, 1); +	} +} + + +void lily_begin() +{ +	lily_g.n_tests = 0; +	lily_g.n_tests_failed = 0; +	lily_g.n_assertions_failed = 0; +	lily_g.n_assertions_failed = 0; +	lily_g.epsilon = 1e-3; + +	printf("================================================================================\n"); +	printf("lily-test version %d.%d.%d\n", LILY_VERSION_MAJOR, LILY_VERSION_MINOR, LILY_VERSION_PATCH); +} + + +void lily_finish() +{ +	printf("================================================================================\n"); +	printf("ran %d tests (%d failed)\n",  +		lily_g.n_tests, lily_g.n_tests_failed); +	printf("checked %d asserts (%d failed)\n", +		lily_g.n_assertions, lily_g.n_assertions_failed); +} + + +void lily_set_epsilon(double epsilon) +{ +	lily_g.epsilon = epsilon; +} + + +int lily_streq(const char *str1, const char *str2) +{ +	if (str1 == NULL && str2 == NULL) { +		/* both are null (and therefore equal, i guess) */ +		return 1; +	} + +	if (str1 == NULL || str2 == NULL) { +		/* only one is null */ +		return 0; +	} + +	/* neither are null, check normal string equality */ +	return strcmp(str1, str2) == 0; +} +#endif + +/* ifdef LILY_TEST_H */ +#else + +/* counter incrementing */ +/* this counter can count up to 4096, but it should be pretty trivial to extend it more or less arbitrarily far */ +/* to increment the counter, just #define LILY_COUNTER_INCREMENT and then include this file again */ +#ifdef LILY_COUNTER_INCREMENT +#undef LILY_COUNTER_INCREMENT +    /* ones position */ +#	if LILY_HEX(LILY_COUNTER_POS_0) == 0 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 1 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 1 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 2 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 2 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 3 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 3 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 4 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 4 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 5 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 5 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 6 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 6 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 7 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 7 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 8 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 8 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 9 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 9 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 a +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 10 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 b +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 11 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 c +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 12 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 d +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 13 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 e +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 14 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 f +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 15 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 0 +        /* sixteens position */ +#		if LILY_HEX(LILY_COUNTER_POS_1) == 0 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 1 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 1 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 2 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 2 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 3 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 3 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 4 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 4 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 5 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 5 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 6 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 6 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 7 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 7 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 8 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 8 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 9 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 9 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 a +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 10 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 b +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 11 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 c +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 12 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 d +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 13 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 e +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 14 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 f +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 15 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 0 +            /* 256s position */ +#			if LILY_HEX(LILY_COUNTER_POS_2) == 0 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 1 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 1 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 2 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 2 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 3 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 3 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 4 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 4 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 5 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 5 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 6 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 6 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 7 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 7 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 8 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 8 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 9 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 9 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 a +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 10 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 b +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 11 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 c +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 12 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 d +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 13 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 e +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 14 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 f +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 15 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 0 +#			endif +#		endif +#	endif + +#elif defined(LILY_COUNTER_DECREMENT) +#undef LILY_COUNTER_DECREMENT +    /* ones position */ +#	if LILY_HEX(LILY_COUNTER_POS_0) == 15 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 e +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 14 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 d +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 13 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 c +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 12 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 b +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 11 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 a +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 10 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 9 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 9 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 8 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 8 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 7 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 7 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 6 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 6 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 5 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 5 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 4 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 4 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 3 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 3 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 2 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 2 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 1 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 1 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 0 +#	elif LILY_HEX(LILY_COUNTER_POS_0) == 0 +#		undef LILY_COUNTER_POS_0 +#		define LILY_COUNTER_POS_0 f +		/* sixteens position */ +#		if LILY_HEX(LILY_COUNTER_POS_1) == 15 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 e +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 14 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 d +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 13 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 c +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 12 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 b +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 11 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 a +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 10 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 9 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 9 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 8 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 8 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 7 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 7 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 6 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 6 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 5 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 5 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 4 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 4 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 3 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 3 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 2 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 2 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 1 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 1 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 0 +#		elif LILY_HEX(LILY_COUNTER_POS_1) == 0 +#			undef LILY_COUNTER_POS_1 +#			define LILY_COUNTER_POS_1 f +			/* 256s position */ +#			if LILY_HEX(LILY_COUNTER_POS_2) == 15 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 e +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 14 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 d +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 13 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 c +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 12 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 b +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 11 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 a +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 10 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 9 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 9 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 8 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 8 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 7 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 7 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 6 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 6 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 5 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 5 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 4 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 4 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 3 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 3 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 2 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 2 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 1 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 1 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 0 +#			elif LILY_HEX(LILY_COUNTER_POS_2) == 0 +#				undef LILY_COUNTER_POS_2 +#				define LILY_COUNTER_POS_2 f +#			endif +#		endif +#	endif + + +#elif defined(LILY_FILE_END) +/* ending a file */ + +/* LILY_LIST_HEAD is one too high, so we decrement */ +#define LILY_COUNTER_DECREMENT +#include LILY_TEST_H_LOCATION + +void file_runner() +{ +	lily_ll_node_t *n = &LILY_LIST_HEAD; +	while (n->next != NULL) { +		lily_run_test(n->f); +		n = n->next; +	} +} + +#else +/* register new test */ + +static lily_ll_node_t LILY_ANON_NODE = { +#define LILY_COUNTER_DECREMENT +#include LILY_TEST_H_LOCATION +	&LILY_LIST_HEAD, +#define LILY_COUNTER_INCREMENT +#include LILY_TEST_H_LOCATION +	LILY_ANON_WRAP, +}; +#undef LILY_LIST_HEAD +#define LILY_LIST_HEAD LILY_ANON_NODE +#define LILY_COUNTER_INCREMENT +#include LILY_TEST_H_LOCATION + +#endif + +#endif | 
