Skip to content

Instantly share code, notes, and snippets.

@p7g
Created February 12, 2022 16:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save p7g/9a6d15291f42391cac24cd6f69011a30 to your computer and use it in GitHub Desktop.
Save p7g/9a6d15291f42391cac24cd6f69011a30 to your computer and use it in GitHub Desktop.
Manually translated joe -> C, this BF implementations runs only 14% slower than bf.c
// vim: ft=java
import joe.collections.ArrayList;
import joe.fs.File;
import joe.io.StdOut;
import joe.io.StdErr;
class Tape {
final ArrayList<uint> data;
uint pos;
Tape() {
data = new ArrayList<uint>();
data.push(0);
pos = 0;
}
~Tape() {
delete data;
}
uint get() {
return data.get(pos);
}
void inc(int amount) {
data.set(pos, data.get(pos) + amount);
}
void move(int amount) {
pos += amount;
while (pos >= data.length())
data.push(0);
}
}
interface Op {
void run(Tape tape);
}
class Inc implements Op {
final int amount;
Inc(int amount_) {
amount = amount_;
}
void run(Tape tape) {
tape.inc(amount);
}
}
class Move implements Op {
final int amount;
Move(int amount_) {
amount = amount_;
}
void run(Tape tape) {
tape.move(amount);
}
}
class Print implements Op {
void run(Tape tape) {
StdOut s = StdOut.get();
s.writeByte(tape.get());
s.flush();
}
}
class Loop implements Op {
final Op[] ops;
Loop(Op[] ops_) {
ops = ops_;
}
~Loop() {
delete ops;
}
void run(Tape tape) {
// hack to dereference `this` pointer outside of loop
Op[] ops = this.ops;
while (tape.get() != 0)
Bf.run(ops, tape);
}
}
class Bf {
static Op[] parse(Iterator<char> it) {
ArrayList<Op> ops = new ArrayList<Op>();
loop:
while (it.hasNext()) {
switch (it.next()) {
case '+':
ops.push(new Inc(1));
break;
case '-':
ops.push(new Inc(-1));
break;
case '>':
ops.push(new Move(1));
break;
case '<':
ops.push(new Move(-1));
break;
case '.':
ops.push(new Print());
break;
case '[':
ops.push(new Loop(parse(it)));
break;
case ']':
break loop;
}
}
return ops.intoSlice();
}
static void run(Op[] ops, Tape tape) {
for (int i = 0; i < ops.length(); i += 1) {
op.run(tape);
}
}
static int main(String[] args) {
if (args.length() < 2) {
StdErr.get().writeString("Expected filename arg\n");
return 1;
}
File f = new File(args[1]);
Op[] ops = parse(f.iterator());
delete f;
Tape tape = new Tape();
run(ops, tape);
delete ops;
delete tape;
return 0;
}
}
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
// Forward declarations
typedef uint32_t joe_uint;
typedef int32_t joe_int;
typedef bool joe_bool;
typedef char joe_char;
typedef struct ArrayList_uint *ArrayList_uint;
typedef struct ArrayList_Op *ArrayList_Op;
typedef struct Tape *Tape;
typedef struct Op Op;
typedef struct slice_Op slice_Op;
typedef struct Iterator_char Iterator_char;
typedef struct String String;
typedef struct slice_String slice_String;
typedef struct slice_uint slice_uint;
typedef struct FileIterator *FileIterator;
// Transparent classes (i.e. 1 final field), need to somehow sort by dependency
typedef joe_int Inc;
typedef joe_int Move;
typedef void Print;
typedef slice_Op *Loop; // it's a pointer because Loop implements an interface
typedef FILE *File;
typedef joe_char *Pointer_char;
typedef joe_uint *Pointer_uint;
typedef Pointer_char StaticString;
typedef Op *Pointer_Op;
typedef String *Pointer_String;
// vtables
struct Op_vtable {
void (*destructor)(void *);
void (*run)(void *, Tape);
};
struct Iterator_char_vtable {
void (*destructor)(void *);
joe_bool (*hasNext)(void *);
joe_char (*next)(void *);
};
struct String_vtable {
void (*destructor)(void *);
Pointer_char (*asPointer)(void *);
};
// interface struct declarations
struct Op {
void *data;
struct Op_vtable *vtable;
};
struct String {
void *data;
struct String_vtable *vtable;
};
struct Iterator_char {
void *data;
struct Iterator_char_vtable *vtable;
};
// class struct declarations
struct slice_uint {
joe_uint length;
joe_uint *data;
};
struct slice_Op {
joe_uint length;
Op *data;
};
struct slice_String {
joe_uint length;
String *data;
};
struct ArrayList_uint {
joe_uint length;
slice_uint data;
};
struct ArrayList_Op {
joe_uint length;
slice_Op data;
};
struct Tape {
ArrayList_uint data;
joe_uint pos;
};
struct FileIterator {
File f;
joe_int peeked;
};
// Method prototypes
static void Tape_constructor(Tape *);
static void Tape_destructor(Tape);
static joe_uint Tape_get(Tape);
static void Tape_inc(Tape, joe_int);
static void Tape_move(Tape, joe_int);
static void Inc_constructor(Inc *, joe_int);
static void Inc_destructor(Inc);
static void Inc_run(Inc, Tape);
static void Move_constructor(Move *, joe_int);
static void Move_destructor(Move);
static void Move_run(Move, Tape);
static void Print_destructor(void *);
static void Print_run(void *, Tape);
static void Loop_constructor(Loop *, slice_Op);
static void Loop_destructor(Loop);
static void Loop_run(Loop, Tape);
static void ArrayList_uint_constructor(ArrayList_uint *);
static void ArrayList_uint_destructor(ArrayList_uint);
static joe_uint ArrayList_uint_get(ArrayList_uint, joe_uint);
static void ArrayList_uint_set(ArrayList_uint, joe_uint, joe_uint);
static joe_uint ArrayList_uint_length(ArrayList_uint);
static void ArrayList_uint_push(ArrayList_uint, joe_uint);
static void ArrayList_Op_constructor(ArrayList_Op *);
static void ArrayList_Op_push(ArrayList_Op, Op);
static slice_Op ArrayList_Op_intoSlice(ArrayList_Op);
static void slice_Op_constructor(slice_Op *, Pointer_Op, joe_uint);
static void slice_Op_destructor(slice_Op);
static joe_uint slice_Op_length(slice_Op);
static slice_Op slice_Op_extend(slice_Op, joe_uint);
static void slice_uint_constructor(slice_uint *, Pointer_uint, joe_uint);
static void slice_uint_destructor(slice_uint);
static joe_uint slice_uint_length(slice_uint);
static slice_uint slice_uint_extend(slice_uint, joe_uint);
static void slice_String_constructor(slice_String *, Pointer_String, joe_uint);
static void slice_String_destructor(slice_String);
static joe_uint slice_String_length(slice_String);
static void StaticString_constructor(StaticString *, Pointer_char);
static void StaticString_destructor(StaticString);
static Pointer_char StaticString_asPointer(StaticString);
static void File_constructor(File *, String);
static void File_destructor(File);
static FileIterator File_iterator(File);
static void FileIterator_constructor(FileIterator *, File);
static void FileIterator_destructor(FileIterator);
static joe_bool FileIterator_hasNext(FileIterator);
static joe_char FileIterator_next(FileIterator);
static slice_Op Bf_parse(Iterator_char);
static void Bf_run(slice_Op, Tape);
static int Bf_main(slice_String);
// vtable declarations
static struct String_vtable StaticString_String_vtable = {
(void *) StaticString_destructor,
(void *) StaticString_asPointer,
};
static struct Op_vtable Inc_Op_vtable = {
(void *) Inc_destructor,
(void *) Inc_run,
};
static struct Op_vtable Move_Op_vtable = {
(void *) Move_destructor,
(void *) Move_run,
};
static struct Op_vtable Print_Op_vtable = {
(void *) Print_destructor,
(void *) Print_run,
};
static struct Op_vtable Loop_Op_vtable = {
(void *) Loop_destructor,
(void *) Loop_run,
};
static struct Iterator_char_vtable FileIterator_Iterator_char_vtable = {
(void *) FileIterator_destructor,
(void *) FileIterator_hasNext,
(void *) FileIterator_next,
};
// method implementations
static void Tape_constructor(Tape *this)
{
*this = malloc(sizeof(**this));
ArrayList_uint_constructor(&(*this)->data);
ArrayList_uint_push((*this)->data, 0);
(*this)->pos = 0;
}
static void Tape_destructor(Tape this)
{
ArrayList_uint_destructor(this->data);
free(this);
}
static joe_uint Tape_get(Tape this)
{
return ArrayList_uint_get(this->data, this->pos);
}
static void Tape_inc(Tape this, joe_int amount)
{
ArrayList_uint_set(this->data,
this->pos,
ArrayList_uint_get(this->data, this->pos) + amount);
}
static void Tape_move(Tape this, joe_int amount)
{
this->pos += amount;
while (this->pos >= ArrayList_uint_length(this->data))
ArrayList_uint_push(this->data, 0);
}
static void Inc_constructor(Inc *this, joe_int amount)
{
*this = amount;
}
static void Inc_destructor(Inc this)
{
(void) this;
}
static void Inc_run(Inc this, Tape tape)
{
Tape_inc(tape, this);
}
static void Move_constructor(Move *this, joe_int amount)
{
*this = amount;
}
static void Move_destructor(Move this)
{
(void) this;
}
static void Move_run(Move this, Tape tape)
{
Tape_move(tape, this);
}
static void Print_destructor(void *this)
{
}
static void Print_run(void *this, Tape tape)
{
(void) this;
// FIXME: cheating
putchar(Tape_get(tape));
fflush(stdout);
}
static void Loop_constructor(Loop *this, slice_Op ops)
{
*this = malloc(sizeof(**this));
(*this)->data = ops.data;
(*this)->length = ops.length;
}
static void Loop_destructor(Loop this)
{
slice_Op_destructor(*this);
free(this);
}
static void Loop_run(Loop this, Tape tape)
{
slice_Op ops = *this;
while (Tape_get(tape) != 0)
Bf_run(ops, tape);
}
static void ArrayList_uint_constructor(ArrayList_uint *this)
{
*this = malloc(sizeof(**this));
(*this)->length = 0;
slice_uint_constructor(&(*this)->data, NULL, 0);
}
static void ArrayList_uint_destructor(ArrayList_uint this)
{
slice_uint_destructor(this->data);
free(this);
}
static joe_uint ArrayList_uint_get(ArrayList_uint this, joe_uint idx)
{
// FIXME: slice ops directly translated? bounds checks?
return this->data.data[idx];
}
static void ArrayList_uint_set(ArrayList_uint this, joe_uint idx, joe_uint val)
{
this->data.data[idx] = val;
}
static joe_uint ArrayList_uint_length(ArrayList_uint this)
{
return this->length;
}
static void ArrayList_uint_push(ArrayList_uint this, joe_uint val)
{
if (this->length == slice_uint_length(this->data)) {
joe_uint cap = slice_uint_length(this->data);
if (cap == 0)
cap = 4;
this->data = slice_uint_extend(this->data, cap << 1);
}
this->data.data[this->length++] = val;
}
static void ArrayList_Op_constructor(ArrayList_Op *this)
{
*this = malloc(sizeof(**this));
(*this)->length = 0;
slice_Op_constructor(&(*this)->data, NULL, 0);
}
static void ArrayList_Op_push(ArrayList_Op this, Op val)
{
if (this->length == slice_Op_length(this->data)) {
joe_uint cap = slice_Op_length(this->data);
if (cap == 0)
cap = 4;
this->data = slice_Op_extend(this->data, cap << 1);
}
this->data.data[this->length++] = val;
}
static slice_Op ArrayList_Op_intoSlice(ArrayList_Op this)
{
slice_Op data = this->data;
data.length = this->length;
free(this);
return data;
}
static void slice_Op_constructor(slice_Op *this, Pointer_Op data, joe_uint length)
{
this->data = data;
this->length = length;
}
static void slice_Op_destructor(slice_Op this)
{
for (joe_int i = 0; i < this.length; i += 1) {
Op item = this.data[i];
item.vtable->destructor(item.data);
}
if (this.data)
free(this.data);
}
static joe_uint slice_Op_length(slice_Op this)
{
return this.length;
}
static slice_Op slice_Op_extend(slice_Op this, joe_uint length)
{
slice_Op newSlice;
newSlice.data = realloc(this.data, sizeof(*this.data) * length);
newSlice.length = length;
return newSlice;
}
static void slice_uint_constructor(slice_uint *this, Pointer_uint data, joe_uint length)
{
this->data = data;
this->length = length;
}
static void slice_uint_destructor(slice_uint this)
{
free(this.data);
}
static joe_uint slice_uint_length(slice_uint this)
{
return this.length;
}
static slice_uint slice_uint_extend(slice_uint this, joe_uint length)
{
slice_uint newSlice;
newSlice.data = realloc(this.data, sizeof(*this.data) * length);
newSlice.length = length;
return newSlice;
}
static void slice_String_constructor(slice_String *this, Pointer_String data, joe_uint length)
{
this->data = data;
this->length = length;
}
static void slice_String_destructor(slice_String this)
{
for (joe_int i = 0; i < this.length; i += 1) {
String item = this.data[i];
item.vtable->destructor(item.data);
}
if (this.data)
free(this.data);
}
static joe_uint slice_String_length(slice_String this)
{
return this.length;
}
static void StaticString_constructor(StaticString *this, Pointer_char str)
{
*this = str;
}
static void StaticString_destructor(StaticString this)
{
(void) this;
}
static Pointer_char StaticString_asPointer(StaticString this)
{
return this;
}
static void File_constructor(File *this, String name)
{
*this = fopen(name.vtable->asPointer(name.data), "r");
}
static void File_destructor(File this)
{
if (this)
fclose(this);
}
static FileIterator File_iterator(File this)
{
FileIterator it;
FileIterator_constructor(&it, this);
return it;
}
static void FileIterator_constructor(FileIterator *this, File file)
{
*this = malloc(sizeof(**this));
(*this)->f = file;
(*this)->peeked = -1;
}
static void FileIterator_destructor(FileIterator this)
{
free(this);
}
static joe_bool FileIterator_hasNext(FileIterator this)
{
if (this->peeked != -1)
return true;
this->peeked = fgetc(this->f);
return !feof(this->f);
}
static joe_char FileIterator_next(FileIterator this)
{
if (this->peeked != -1) {
joe_char c = this->peeked;
this->peeked = -1;
return c;
}
return fgetc(this->f);
}
static slice_Op Bf_parse(Iterator_char it)
{
ArrayList_Op ops;
ArrayList_Op_constructor(&ops);
while (it.vtable->hasNext(it.data)) {
switch (it.vtable->next(it.data)) {
case '+': {
Inc tmp1;
Inc_constructor(&tmp1, 1);
union {
void *as_ptr;
int as_int;
} data;
data.as_int = tmp1;
Op op;
op.data = data.as_ptr;
op.vtable = &Inc_Op_vtable;
ArrayList_Op_push(ops, op);
break;
}
case '-': {
Inc tmp1;
Inc_constructor(&tmp1, -1);
union {
void *as_ptr;
int as_int;
} data;
data.as_int = tmp1;
Op op;
op.data = data.as_ptr;
op.vtable = &Inc_Op_vtable;
ArrayList_Op_push(ops, op);
break;
}
case '>': {
Move tmp1;
Move_constructor(&tmp1, 1);
union {
void *as_ptr;
int as_int;
} data;
data.as_int = tmp1;
Op op;
op.data = data.as_ptr;
op.vtable = &Move_Op_vtable;
ArrayList_Op_push(ops, op);
break;
}
case '<': {
Move tmp1;
Move_constructor(&tmp1, -1);
union {
void *as_ptr;
int as_int;
} data;
data.as_int = tmp1;
Op op;
op.data = data.as_ptr;
op.vtable = &Move_Op_vtable;
ArrayList_Op_push(ops, op);
break;
}
case '.': {
Op op;
op.data = NULL;
op.vtable = &Print_Op_vtable;
ArrayList_Op_push(ops, op);
break;
}
case '[': {
Loop tmp1;
Loop_constructor(&tmp1, Bf_parse(it));
Op op;
op.data = tmp1;
op.vtable = &Loop_Op_vtable;
ArrayList_Op_push(ops, op);
break;
}
case ']':
goto end_loop;
}
}
end_loop:
return ArrayList_Op_intoSlice(ops);
}
static void Bf_run(slice_Op ops, Tape tape)
{
for (joe_int i = 0; i < slice_Op_length(ops); i += 1) {
Op tmp1 = ops.data[i];
tmp1.vtable->run(tmp1.data, tape);
}
}
static int Bf_main(slice_String argv)
{
if (slice_String_length(argv) < 2) {
fputs("Expected filename arg\n", stderr);
return 1;
}
File f;
File_constructor(&f, argv.data[1]);
if (!f) {
perror("fopen");
return 1;
}
FileIterator tmp1 = File_iterator(f);
Iterator_char tmp2;
tmp2.data = tmp1;
tmp2.vtable = &FileIterator_Iterator_char_vtable;
slice_Op ops = Bf_parse(tmp2);
FileIterator_destructor(tmp1);
File_destructor(f);
Tape tape;
Tape_constructor(&tape);
Bf_run(ops, tape);
slice_Op_destructor(ops);
Tape_destructor(tape);
return 0;
}
int main(int argc, char **argv)
{
slice_String argv_slice;
slice_String_constructor(&argv_slice, malloc(sizeof(String) * argc), argc);
for (joe_int i = 0; i < argc; i += 1) {
StaticString s;
StaticString_constructor(&s, argv[i]);
argv_slice.data[i].data = s;
argv_slice.data[i].vtable = &StaticString_String_vtable;
}
joe_int retval = Bf_main(argv_slice);
slice_String_destructor(argv_slice);
return retval;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment