Match Brainfuck compiler output in C89 port

This commit is contained in:
Hermes Agent
2026-08-17 23:32:22 +00:00
parent c64064172c
commit 0bb59bbb6d
3 changed files with 105 additions and 19 deletions
+5 -2
View File
@@ -44,7 +44,9 @@ Notes:
override the default `$HOME/.peppermint/store.json` location. override the default `$HOME/.peppermint/store.json` location.
- `version` prints `Peppermint Version 0.0.1[platform]`. - `version` prints `Peppermint Version 0.0.1[platform]`.
- `bf` is a separate Brainfuck runner. With `--compile=true`, it also writes the - `bf` is a separate Brainfuck runner. With `--compile=true`, it also writes the
original Long-language-style output to `dist/test.long`. original Long-language-style output to `dist/test.long`. The compiler follows
the upstream static conversion pass: it records cell values observed at `.`
instructions and ignores Brainfuck loop/control execution while compiling.
## Language behavior ## Language behavior
@@ -89,4 +91,5 @@ portable tab-separated project store at `$HOME/.peppermint/store.json` (or
The test script rebuilds with strict C89 flags, then checks legacy direct-file The test script rebuilds with strict C89 flags, then checks legacy direct-file
execution, command dispatch, expressions, relational operators, mutable vs. execution, command dispatch, expressions, relational operators, mutable vs.
constant assignment, builtins, project init/config/list/run behavior, version constant assignment, builtins, project init/config/list/run behavior, version
output, and the Brainfuck runner/compiler command. output, and the Brainfuck runner/compiler command including static Long output
semantics.
+81 -17
View File
@@ -1170,51 +1170,115 @@ static int pm_command_list(void)
return 0; return 0;
} }
static int pm_bf_append_text(char **buffer, size_t *used, size_t *capacity,
const char *part)
{
size_t length;
size_t needed;
size_t next_capacity;
char *next;
length = strlen(part);
needed = *used + length + 1U;
if (needed > *capacity) {
next_capacity = *capacity;
while (next_capacity < needed) {
if (next_capacity > ((size_t)-1) / 2U) return 0;
next_capacity *= 2U;
}
next = (char *)realloc(*buffer, next_capacity);
if (next == NULL) return 0;
*buffer = next;
*capacity = next_capacity;
}
memcpy(*buffer + *used, part, length + 1U);
*used += length;
return 1;
}
static int pm_bf_ensure_compile_cell(int **cells, long index, long *capacity)
{
long next_capacity;
int *next;
long i;
if (index < *capacity) return 1;
next_capacity = *capacity;
while (next_capacity <= index) {
if (next_capacity > 1073741823L) return 0;
next_capacity *= 2L;
}
next = (int *)realloc(*cells, (size_t)next_capacity * sizeof(int));
if (next == NULL) return 0;
for (i = *capacity; i < next_capacity; i++) next[i] = 0;
*cells = next;
*capacity = next_capacity;
return 1;
}
static int pm_bf_compile(const char *source) static int pm_bf_compile(const char *source)
{ {
int cells[PM_BF_CELLS]; int *cells;
int pointer; long capacity;
long pointer;
const char *p; const char *p;
int value; int value;
char compiled[PM_TEXT_MAX]; char *compiled;
char part[64]; char part[64];
char *dir; char *dir;
char *out; char *out;
size_t used; size_t used;
int i; size_t compiled_capacity;
for (i = 0; i < PM_BF_CELLS; i++) cells[i] = 0; int ok;
pointer = 0; cells = (int *)calloc(1U, sizeof(int));
compiled_capacity = 128U;
compiled = (char *)malloc(compiled_capacity);
if (cells == NULL || compiled == NULL) {
free(cells);
free(compiled);
return 0;
}
capacity = 1L;
pointer = 0L;
value = 0; value = 0;
compiled[0] = '\0';
used = 0U; used = 0U;
compiled[0] = '\0';
p = source; p = source;
while (*p != '\0') { while (*p != '\0') {
if (*p == '+') cells[pointer]++; if (*p == '+') cells[pointer]++;
else if (*p == '-') cells[pointer]--; else if (*p == '-') cells[pointer]--;
else if (*p == '>' && pointer < PM_BF_CELLS - 1) pointer++; else if (*p == '>') {
else if (*p == '<' && pointer > 0) pointer--; pointer++;
else if (*p == '.') { if (!pm_bf_ensure_compile_cell(&cells, pointer, &capacity)) {
free(cells);
free(compiled);
return 0;
}
} else if (*p == '<') {
if (pointer != 0L) pointer--;
} else if (*p == '.') {
int diff; int diff;
diff = cells[pointer] - value; diff = cells[pointer] - value;
value = cells[pointer]; value = cells[pointer];
if (diff < 0) sprintf(part, "%d-", -diff); if (diff < 0) sprintf(part, "%d-", -diff);
else sprintf(part, "%d+", diff); else sprintf(part, "%d+", diff);
if (used + strlen(part) < sizeof(compiled)) { if (!pm_bf_append_text(&compiled, &used, &compiled_capacity, part)) {
strcat(compiled, part); free(cells);
used += strlen(part); free(compiled);
return 0;
} }
} }
p++; p++;
} }
dir = pm_join_path(".", "dist"); dir = pm_join_path(".", "dist");
if (dir == NULL) return 0; if (dir == NULL) { free(cells); free(compiled); return 0; }
pm_make_dir(dir); pm_make_dir(dir);
out = pm_join_path(dir, "test.long"); out = pm_join_path(dir, "test.long");
free(dir); free(dir);
if (out == NULL) return 0; if (out == NULL) { free(cells); free(compiled); return 0; }
i = pm_write_file(out, compiled); ok = pm_write_file(out, compiled);
free(out); free(out);
return i; free(cells);
free(compiled);
return ok;
} }
static int pm_bf_execute(const char *source) static int pm_bf_execute(const char *source)
+19
View File
@@ -96,6 +96,25 @@ if [ ! -f dist/test.long ]; then
printf '%s\n' 'bf compile did not create dist/test.long' >&2 printf '%s\n' 'bf compile did not create dist/test.long' >&2
exit 1 exit 1
fi fi
compiled=$(sed -n '1p' dist/test.long)
if [ "$compiled" != '9+' ]; then
printf '%s\n' "unexpected bf compile output:" "$compiled" >&2
exit 1
fi
rm -rf dist
: > /tmp/peppermint-c89-bf-far.bf
i=0
while [ "$i" -lt 30000 ]; do
printf '>' >> /tmp/peppermint-c89-bf-far.bf
i=$((i + 1))
done
printf '+.>+.<.' >> /tmp/peppermint-c89-bf-far.bf
./peppermint bf --file=/tmp/peppermint-c89-bf-far.bf --compile=true >/tmp/peppermint-c89-bf-far.out
compiled=$(sed -n '1p' dist/test.long)
if [ "$compiled" != '1+0+0+' ]; then
printf '%s\n' "bf compile collapsed cells beyond interpreter memory:" "$compiled" >&2
exit 1
fi
rm -rf dist "$tmpdir" rm -rf dist "$tmpdir"
output=$(./peppermint version) output=$(./peppermint version)