aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2024-01-19 01:17:19 +0100
committerMarvin Borner2024-01-19 01:20:38 +0100
commit10a757d4ad95bf3e16e3b6df4fa989778312dac1 (patch)
tree7e65e7207ab099a28cd0b30480133dd9da4ab997
parent8d9b40605dc8caa92fa501770b917a7b50cac5dc (diff)
Bits/ASCII writer abstraction
-rw-r--r--readme.md2
-rw-r--r--src/targets/bblc.c71
-rw-r--r--src/targets/blc.c134
-rw-r--r--src/targets/unbblc.c71
-rw-r--r--src/targets/unblc.c79
-rwxr-xr-xtest/run14
6 files changed, 177 insertions, 194 deletions
diff --git a/readme.md b/readme.md
index f266870..44191ea 100644
--- a/readme.md
+++ b/readme.md
@@ -19,7 +19,7 @@ benchmarking, or general term optimization.
`unbblc` (bits) and `unblc` (ASCII 0/1).
- Planned: “normal” programming languages
-## Shared `bblc` benchmarks
+## Benchmarks
Some deliberately unoptimized test cases from `test/`, evaluated using
`./run` and measured in bits:
diff --git a/src/targets/bblc.c b/src/targets/bblc.c
deleted file mode 100644
index 555d400..0000000
--- a/src/targets/bblc.c
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2024, Marvin Borner <dev@marvinborner.de>
-// SPDX-License-Identifier: MIT
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <target.h>
-#include <parse.h>
-#include <log.h>
-
-static void write_bit(char val, FILE *file, char *byte, int *bit)
-{
- if (*bit > 7) { // flush byte
- fwrite(byte, 1, 1, file);
- *byte = 0;
- *bit = 0;
- }
-
- // TODO: which endianness should be default?
- if (val)
- *byte |= 1UL << *bit;
- /* *byte |= 1UL << (7 - *bit); */
- (*bit)++;
-}
-
-static void fprint_bblc(struct term *term, struct bloc_parsed *bloc, FILE *file,
- char *byte, int *bit)
-{
- switch (term->type) {
- case ABS:
- write_bit(0, file, byte, bit);
- write_bit(0, file, byte, bit);
- fprint_bblc(term->u.abs.term, bloc, file, byte, bit);
- break;
- case APP:
- write_bit(0, file, byte, bit);
- write_bit(1, file, byte, bit);
- fprint_bblc(term->u.app.lhs, bloc, file, byte, bit);
- fprint_bblc(term->u.app.rhs, bloc, file, byte, bit);
- break;
- case VAR:
- for (int i = 0; i <= term->u.var.index; i++)
- write_bit(1, file, byte, bit);
- write_bit(0, file, byte, bit);
- break;
- case REF:
- if (term->u.ref.index + 1 >= bloc->length)
- fatal("invalid ref index %ld\n", term->u.ref.index);
- fprint_bblc(bloc->entries[bloc->length - term->u.ref.index - 2],
- bloc, file, byte, bit);
- break;
- default:
- fatal("invalid type %d\n", term->type);
- }
-}
-
-static void write_bblc(struct bloc_parsed *bloc, FILE *file)
-{
- char byte = 0;
- int bit = 0;
- fprint_bblc(bloc->entries[bloc->length - 1], bloc, file, &byte, &bit);
-
- if (bit)
- fwrite(&byte, 1, 1, file);
-}
-
-struct target_spec target_bblc = {
- .name = "bblc",
- .exec = write_bblc,
-};
diff --git a/src/targets/blc.c b/src/targets/blc.c
index 3d76966..c4c51d4 100644
--- a/src/targets/blc.c
+++ b/src/targets/blc.c
@@ -17,49 +17,76 @@
#define META_CLOSED 0x1
#define META_OPEN 0x2
-static void fprint_blc_substituted(struct term *term, struct bloc_parsed *bloc,
- size_t *positions_inv, void **closed,
- int depth, size_t position, FILE *file)
+struct context {
+ enum { WRITE_BITS, WRITE_ASCII } type;
+ FILE *file;
+ char *byte;
+ int *bit;
+
+ // general (constant) helper vars
+ size_t *positions_inv;
+ size_t position;
+ void **closed;
+ struct bloc_parsed *bloc;
+};
+
+static void write_context(struct context *context, const char *bits)
+{
+ if (context->type == WRITE_ASCII) {
+ fprintf(context->file, "%s", bits);
+ return;
+ }
+
+ // WRITE_BITS
+ for (const char *p = bits; *p; p++) {
+ if (*context->bit > 7) { // flush byte
+ fwrite(context->byte, 1, 1, context->file);
+ *context->byte = 0;
+ *context->bit = 0;
+ }
+
+ // TODO: which endianness should be default?
+ if (*p & 1)
+ *context->byte |= 1UL << *context->bit;
+ (*context->bit)++;
+ }
+}
+
+static void write_blc_substituted(struct term *term, int depth,
+ struct context *context)
{
switch (term->type) {
case ABS:
- fprintf(file, "00");
- fprint_blc_substituted(term->u.abs.term, bloc, positions_inv,
- closed, depth + 1, position, file);
+ write_context(context, "00");
+ write_blc_substituted(term->u.abs.term, depth + 1, context);
break;
case APP:
- fprintf(file, "01");
- fprint_blc_substituted(term->u.app.lhs, bloc, positions_inv,
- closed, depth, position, file);
- fprint_blc_substituted(term->u.app.rhs, bloc, positions_inv,
- closed, depth, position, file);
+ write_context(context, "01");
+ write_blc_substituted(term->u.app.lhs, depth, context);
+ write_blc_substituted(term->u.app.rhs, depth, context);
break;
case VAR:
for (int i = 0; i <= term->u.var.index; i++)
- fprintf(file, "1");
- fprintf(file, "0");
+ write_context(context, "1");
+ write_context(context, "0");
break;
case REF:
- if (term->u.ref.index + 1 >= bloc->length)
+ if (term->u.ref.index + 1 >= context->bloc->length)
fatal("invalid ref index %ld\n", term->u.ref.index);
- if (closed[term->u.ref.index]) {
- int index =
- depth +
- (positions_inv[term->u.ref.index] - position) -
- 1;
- debug("index=%d depth=%ld ref=%ld inv=%ld pos=%ld sub=%ld\n",
- index, depth, term->u.ref.index,
- positions_inv[term->u.ref.index], position,
- positions_inv[term->u.ref.index] - position);
+ if (context->closed[term->u.ref.index]) {
+ int index = depth +
+ (context->positions_inv[term->u.ref.index] -
+ context->position) -
+ 1;
assert(index >= 0);
for (int i = 0; i <= index; i++)
- fprintf(file, "1");
- fprintf(file, "0");
+ write_context(context, "1");
+ write_context(context, "0");
} else {
- fprint_blc_substituted(bloc->entries[term->u.ref.index],
- bloc, positions_inv, closed,
- depth, position, file);
+ write_blc_substituted(
+ context->bloc->entries[term->u.ref.index],
+ depth, context);
}
break;
default:
@@ -67,8 +94,8 @@ static void fprint_blc_substituted(struct term *term, struct bloc_parsed *bloc,
}
}
-static void fprint_blc(size_t *positions, void *closed,
- struct bloc_parsed *bloc, FILE *file)
+static void write_blc_ordered(size_t *positions, void *closed,
+ struct bloc_parsed *bloc, struct context *context)
{
size_t *positions_inv =
calloc(bloc->length * sizeof(*positions_inv), 1);
@@ -79,7 +106,7 @@ static void fprint_blc(size_t *positions, void *closed,
end++;
if (end >= bloc->length || !positions[end])
break;
- fprintf(file, "0100"); // ([
+ write_context(context, "0100"); // ([
}
// create inv, s.t. ref inc0 -> pos lr
@@ -88,10 +115,14 @@ static void fprint_blc(size_t *positions, void *closed,
positions_inv[positions[i] - 1] = end - i - 1;
}
+ context->positions_inv = positions_inv;
+ context->bloc = bloc;
+ context->closed = closed;
+
for (size_t i = end; i > 0; i--) {
- fprint_blc_substituted(bloc->entries[positions[i - 1] - 1],
- bloc, positions_inv, closed, 0, end - i,
- file);
+ context->position = end - i;
+ write_blc_substituted(bloc->entries[positions[i - 1] - 1], 0,
+ context);
}
free(positions_inv);
@@ -179,7 +210,7 @@ static size_t *topological_sort(char **bitmaps, size_t length)
return positions;
}
-static void write_blc(struct bloc_parsed *bloc, FILE *file)
+static void write_blc(struct bloc_parsed *bloc, struct context *context)
{
char **bitmaps = malloc(bloc->length * sizeof(*bitmaps));
for (size_t i = 0; i < bloc->length; i++) {
@@ -194,7 +225,7 @@ static void write_blc(struct bloc_parsed *bloc, FILE *file)
}
size_t *positions = topological_sort(bitmaps, bloc->length);
- fprint_blc(positions, bitmaps, bloc, file);
+ write_blc_ordered(positions, bitmaps, bloc, context);
for (size_t i = 0; i < bloc->length; i++) {
if (bitmaps[i])
@@ -204,7 +235,36 @@ static void write_blc(struct bloc_parsed *bloc, FILE *file)
free(positions);
}
+static void write_blc_ascii(struct bloc_parsed *bloc, FILE *file)
+{
+ struct context context = {
+ .type = WRITE_ASCII,
+ .file = file,
+ };
+ write_blc(bloc, &context);
+}
+
+static void write_blc_bits(struct bloc_parsed *bloc, FILE *file)
+{
+ char byte = 0;
+ int bit = 0;
+ struct context context = {
+ .type = WRITE_BITS,
+ .file = file,
+ .byte = &byte,
+ .bit = &bit,
+ };
+ write_blc(bloc, &context);
+ if (bit)
+ fwrite(&byte, 1, 1, file);
+}
+
struct target_spec target_blc = {
.name = "blc",
- .exec = write_blc,
+ .exec = write_blc_ascii,
+};
+
+struct target_spec target_bblc = {
+ .name = "bblc",
+ .exec = write_blc_bits,
};
diff --git a/src/targets/unbblc.c b/src/targets/unbblc.c
deleted file mode 100644
index 4c3a3c9..0000000
--- a/src/targets/unbblc.c
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2024, Marvin Borner <dev@marvinborner.de>
-// SPDX-License-Identifier: MIT
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <target.h>
-#include <parse.h>
-#include <log.h>
-
-static void write_bit(char val, FILE *file, char *byte, int *bit)
-{
- if (*bit > 7) { // flush byte
- fwrite(byte, 1, 1, file);
- *byte = 0;
- *bit = 0;
- }
-
- // TODO: which endianness should be default?
- if (val)
- *byte |= 1UL << *bit;
- /* *byte |= 1UL << (7 - *bit); */
- (*bit)++;
-}
-
-static void fprint_unbblc(struct term *term, struct bloc_parsed *bloc,
- FILE *file, char *byte, int *bit)
-{
- switch (term->type) {
- case ABS:
- write_bit(0, file, byte, bit);
- write_bit(0, file, byte, bit);
- fprint_unbblc(term->u.abs.term, bloc, file, byte, bit);
- break;
- case APP:
- write_bit(0, file, byte, bit);
- write_bit(1, file, byte, bit);
- fprint_unbblc(term->u.app.lhs, bloc, file, byte, bit);
- fprint_unbblc(term->u.app.rhs, bloc, file, byte, bit);
- break;
- case VAR:
- for (int i = 0; i <= term->u.var.index; i++)
- write_bit(1, file, byte, bit);
- write_bit(0, file, byte, bit);
- break;
- case REF:
- if (term->u.ref.index + 1 >= bloc->length)
- fatal("invalid ref index %ld\n", term->u.ref.index);
- fprint_unbblc(bloc->entries[term->u.ref.index], bloc, file,
- byte, bit);
- break;
- default:
- fatal("invalid type %d\n", term->type);
- }
-}
-
-static void write_unbblc(struct bloc_parsed *bloc, FILE *file)
-{
- char byte = 0;
- int bit = 0;
- fprint_unbblc(bloc->entries[bloc->length - 1], bloc, file, &byte, &bit);
-
- if (bit)
- fwrite(&byte, 1, 1, file);
-}
-
-struct target_spec target_unbblc = {
- .name = "unbblc",
- .exec = write_unbblc,
-};
diff --git a/src/targets/unblc.c b/src/targets/unblc.c
index 2d10418..3c4beb2 100644
--- a/src/targets/unblc.c
+++ b/src/targets/unblc.c
@@ -9,40 +9,93 @@
#include <parse.h>
#include <log.h>
-static void fprint_unblc(struct term *term, struct bloc_parsed *bloc,
- FILE *file)
+struct context {
+ enum { WRITE_BITS, WRITE_ASCII } type;
+ FILE *file;
+ char *byte;
+ int *bit;
+};
+
+static void write_context(struct context *context, const char *bits)
+{
+ if (context->type == WRITE_ASCII) {
+ fprintf(context->file, "%s", bits);
+ return;
+ }
+
+ // WRITE_BITS
+ for (const char *p = bits; *p; p++) {
+ if (*context->bit > 7) { // flush byte
+ fwrite(context->byte, 1, 1, context->file);
+ *context->byte = 0;
+ *context->bit = 0;
+ }
+
+ // TODO: which endianness should be default?
+ if (*p & 1)
+ *context->byte |= 1UL << *context->bit;
+ (*context->bit)++;
+ }
+}
+
+static void write_unblc(struct term *term, struct bloc_parsed *bloc,
+ struct context *context)
{
switch (term->type) {
case ABS:
- fprintf(file, "00");
- fprint_unblc(term->u.abs.term, bloc, file);
+ write_context(context, "00");
+ write_unblc(term->u.abs.term, bloc, context);
break;
case APP:
- fprintf(file, "01");
- fprint_unblc(term->u.app.lhs, bloc, file);
- fprint_unblc(term->u.app.rhs, bloc, file);
+ write_context(context, "01");
+ write_unblc(term->u.app.lhs, bloc, context);
+ write_unblc(term->u.app.rhs, bloc, context);
break;
case VAR:
for (int i = 0; i <= term->u.var.index; i++)
- fprintf(file, "1");
- fprintf(file, "0");
+ write_context(context, "1");
+ write_context(context, "0");
break;
case REF:
if (term->u.ref.index + 1 >= bloc->length)
fatal("invalid ref index %ld\n", term->u.ref.index);
- fprint_unblc(bloc->entries[term->u.ref.index], bloc, file);
+ write_unblc(bloc->entries[term->u.ref.index], bloc, context);
break;
default:
fatal("invalid type %d\n", term->type);
}
}
-static void write_unblc(struct bloc_parsed *bloc, FILE *file)
+static void write_unblc_ascii(struct bloc_parsed *bloc, FILE *file)
{
- fprint_unblc(bloc->entries[bloc->length - 1], bloc, file);
+ struct context context = {
+ .type = WRITE_ASCII,
+ .file = file,
+ };
+ write_unblc(bloc->entries[bloc->length - 1], bloc, &context);
+}
+
+static void write_unblc_bits(struct bloc_parsed *bloc, FILE *file)
+{
+ char byte = 0;
+ int bit = 0;
+ struct context context = {
+ .type = WRITE_BITS,
+ .file = file,
+ .byte = &byte,
+ .bit = &bit,
+ };
+ write_unblc(bloc->entries[bloc->length - 1], bloc, &context);
+ if (bit)
+ fwrite(&byte, 1, 1, file);
}
struct target_spec target_unblc = {
.name = "unblc",
- .exec = write_unblc,
+ .exec = write_unblc_ascii,
+};
+
+struct target_spec target_unbblc = {
+ .name = "unbblc",
+ .exec = write_unblc_bits,
};
diff --git a/test/run b/test/run
index 5ef28da..736521a 100755
--- a/test/run
+++ b/test/run
@@ -1,6 +1,6 @@
#!/bin/sh
-set -e
+# set -e
FAIL="\033[0;31m[FAIL]\033[0m "
SUCC="\033[0;32m[ OK ]\033[0m "
@@ -10,11 +10,17 @@ rm -f ../build/*.out ../build/*.blc ../build/*.bloc
for file in *.blc; do
bloc --from-blc -i "$file" -o ../build/"$file".bloc
../build/blocade -i ../build/"$file".bloc -t blc -o ../build/"$file".bloc.blc
+ ../build/blocade -i ../build/"$file".bloc -t bblc -o ../build/"$file".bloc.bblc
bruijn -E "$file" &>../build/"$file".out
+
bruijn -E ../build/"$file".bloc.blc &>../build/"$file".bloc.blc.out
cmp ../build/"$file".out ../build/"$file".bloc.blc.out && printf "$SUCC" || printf "$FAIL"
echo "blc res cmp on $file"
+ bruijn -e ../build/"$file".bloc.bblc &>../build/"$file".bloc.bblc.out
+ cmp ../build/"$file".out ../build/"$file".bloc.bblc.out && printf "$SUCC" || printf "$FAIL"
+ echo "bblc res cmp on $file"
+
../build/blocade -i ../build/"$file".bloc -t unblc -o ../build/"$file".bloc.unblc
cmp ../build/"$file".bloc.unblc "$file" && printf "$SUCC" || printf "$FAIL"
echo "unblc inp cmp on $file"
@@ -23,11 +29,17 @@ done
for file in *.blc.io; do
bloc --from-blc -i "$file" -o ../build/"$file".bloc
../build/blocade -i ../build/"$file".bloc -t blc -o ../build/"$file".bloc.blc
+ ../build/blocade -i ../build/"$file".bloc -t bblc -o ../build/"$file".bloc.bblc
cat "$file".in | bruijn -E "$file" &>../build/"$file".out
+
cat "$file".in | bruijn -E ../build/"$file".bloc.blc &>../build/"$file".bloc.blc.out
cmp ../build/"$file".out ../build/"$file".bloc.blc.out && printf "$SUCC" || printf "$FAIL"
echo "blc res cmp on $file"
+ cat "$file".in | bruijn -e ../build/"$file".bloc.bblc &>../build/"$file".bloc.bblc.out
+ cmp ../build/"$file".out ../build/"$file".bloc.bblc.out && printf "$SUCC" || printf "$FAIL"
+ echo "bblc res cmp on $file"
+
../build/blocade -i ../build/"$file".bloc -t unblc -o ../build/"$file".bloc.unblc
cmp ../build/"$file".bloc.unblc "$file" && printf "$SUCC" || printf "$FAIL"
echo "unblc inp cmp on $file"