brainfucked

This commit is contained in:
Murphy 2023-04-13 17:04:05 -04:00
commit fafd290ed9
8 changed files with 449 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
bin

13
LICENSE Normal file
View file

@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

39
Makefile Normal file
View file

@ -0,0 +1,39 @@
CC = gcc
INCFLAGS = -Isrc
CCFLAGS = -std=c99 -Wall -Wextra -pedantic -O2
CCFLAGS += $(INCFLAGS)
LDFLAGS += $(INCFLAGS)
LDFLAGS += -lpthread
BIN = bin
APP = $(BIN)/app
SRC = $(shell find src -name "*.c")
OBJ = $(SRC:%.c=$(BIN)/%.o)
.PHONY: clean build
dirs:
mkdir -p ./$(BIN)
mkdir -p ./$(BIN)/src
run: build
$(APP)
build: dirs ${OBJ}
${CC} -o $(APP) $(filter %.o,$^) $(LDFLAGS)
$(BIN)/%.o: %.c
$(CC) -o $@ -c $< $(CCFLAGS)
clean:
rm -rf $(APP)
rm -rf $(BIN)
install:
cp $(APP) /usr/local/bin/brainfucked
uninstall:
rm /usr/local/bin/brainfucked

136
src/interpreter.c Normal file
View file

@ -0,0 +1,136 @@
#include "interpreter.h"
#include "program.h"
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void loop_end(Program* program) {
uint32_t count = 1;
Symbol s;
while (true) {
program_next(program, &s);
if (s == StartLoop) {
count++;
} else if (s == EndLoop) {
count--;
} else if (s == Eof) {
return;
}
if (count == 0) return;
}
}
static void loop_start(Program* program) {
uint32_t count = 1;
Symbol s;
program_last(program, &s);
while (true) {
program_last(program, &s);
if (s == StartLoop) {
count--;
} else if (s == EndLoop) {
count++;
} else if (s == Eof) {
return;
}
if (count == 0) {
return;
};
}
}
static void recurse_program(Program* program, Tape* tape) {
Symbol s;
next:
program_next(program, &s);
switch (s) {
case MoveLeft:
tape_left(tape);
break;
case MoveRight:
tape_right(tape);
break;
case Increment:
tape_set(tape, tape_get(tape) + 1);
break;
case Decrement:
tape_set(tape, tape_get(tape) - 1);
break;
case StartLoop:
if (tape_get(tape) == 0)
loop_end(program);
break;
case EndLoop:
if (tape_get(tape) != 0)
loop_start(program);
break;
case PutChar: {
printf("%c", tape_get(tape));
break;
}
case GetChar: {
uint8_t c = (uint8_t) getchar();
tape_set(tape, c);
break;
}
case Allocate: {
uint8_t len = tape_get(tape);
Tape* new = malloc(sizeof(Tape));
tape_init(len, tape);
void* ptr = (void*) tape_ptr(tape);
memcpy(ptr, &new, sizeof(Tape*));
break;
}
case Free: {
Tape* old;
void* ptr = (void*) tape_ptr(tape);
memcpy(&old, ptr, sizeof(Tape*));
memset(ptr, 0, sizeof(Tape*));
free(old);
break;
}
case EnterTape: {
Tape* cur;
void* ptr = (void*) tape_ptr(tape);
memcpy(&cur, ptr, sizeof(Tape*));
recurse_program(program, cur);
break;
}
case GetString: {
uint8_t len = tape_get(tape);
void* ptr = (void*) tape_ptr(tape);
fgets(ptr, len, stdin);
break;
}
case PutString: {
char* ptr = (char*) tape_ptr(tape);
printf("%s", ptr);
break;
}
case Clear:
printf("\033c");
break;
case LeaveTape:
case Eof:
case Invalid:
return;
}
goto next;
}
void run_program(Program* program) {
Tape tape;
tape_init(sizeof(void*), &tape);
recurse_program(program, &tape);
tape_free(&tape);
}

5
src/interpreter.h Normal file
View file

@ -0,0 +1,5 @@
#pragma once
#include "program.h"
void run_program(Program* program);

39
src/main.c Normal file
View file

@ -0,0 +1,39 @@
#include "program.h"
#include "interpreter.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
/// < Move pointer left
/// > Move pointer right
/// + Increment cell by one
/// - Decrement cell by one
/// [ Jump past the matching ] if the cell at the pointer is 0
/// ] Jump back to the matching [ if the cell at the pointer is nonzero
/// . Output ascii at current cell
/// , Input ascii into current cell
/// * Allocate new tape size of current cell and replace with pointer
/// ! Free allocated pointer in current cell
/// ( Go to tape at pointer in current cell
/// ) Leave tape last entered
/// ` Output null terminated string at current cell
/// ~ Input string into current cells with max length in current cell
/// % Clear screen
int main(int argc, char** argv) {
if (argc != 2) {
printf("usage: brainfucked infile\n");
return EXIT_FAILURE;
}
Program program;
program_init(argv[1], &program);
run_program(&program);
program_free(&program);
return EXIT_SUCCESS;
}

166
src/program.c Normal file
View file

@ -0,0 +1,166 @@
#include "program.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
static FILE* f;
static uint32_t count;
static char next_char() {
char c;
if (fread(&c, 1, 1, f) != 1) {
return EOF;
} else {
count++;
return c;
}
}
static Symbol next_symbol() {
char c = next_char();
retest:
switch (c) {
case '<':
return MoveLeft;
case '>':
return MoveRight;
case '+':
return Increment;
case '-':
return Decrement;
case '[':
return StartLoop;
case ']':
return EndLoop;
case '.':
return PutChar;
case ',':
return GetChar;
case '*':
return Allocate;
case '!':
return Free;
case '(':
return EnterTape;
case ')':
return LeaveTape;
case '`':
return PutString;
case '~':
return GetString;
case '%':
return Clear;
case '\n':
case ' ':
while(c = next_char(), c == '\n' || c == ' ');
goto retest;
case '/':
while(c = next_char(), c != '\n' && c != EOF);
goto retest;
case EOF:
return Eof;
default:
return Invalid;
}
}
void program_init(char* file_path, Program* program) {
f = fopen (file_path, "r");
if (f == NULL) {
printf("error: failed to open %s (%s)\n", file_path, strerror(errno));
exit(EXIT_FAILURE);
}
uint32_t capacity = 8;
count = 0;
program->data = malloc(capacity * sizeof(Symbol));
program->len = 0;
Symbol s;
while(true) {
s = next_symbol();
if (s == Invalid) {
printf("error: invalid symbol at character %d\n", count);
exit(EXIT_FAILURE);
}
if (program->len == capacity) {
capacity *= 2;
program->data = realloc(program->data, capacity * sizeof(Symbol));
}
program->data[program->len] = s;
program->len++;
if (s == Eof) break;
}
fclose(f);
}
void program_peek(Program* program, Symbol* symbol) {
*symbol = program->data[program->index];
}
void program_next(Program* program, Symbol* symbol) {
if (program->index >= program->len) {
*symbol = Eof;
return;
}
program_peek(program, symbol);
program->index++;
}
void program_last(Program* program, Symbol* symbol) {
if (program->index == 0) {
*symbol = Eof;
return;
}
program->index--;
program_peek(program, symbol);
}
void program_free(Program* program) {
free(program->data);
}
void tape_init(uint32_t len, Tape* tape) {
tape->len = len;
tape->data = malloc(len);
tape->index = 0;
memset(tape->data, 0, len);
}
void tape_left(Tape* tape) {
if (tape->index == 0) {
tape->index = tape->len - 1;
} else {
tape->index--;
}
}
void tape_right(Tape* tape) {
tape->index++;
tape->index %= tape->len;
}
uint8_t tape_get(Tape* tape) {
return tape->data[tape->index];
}
void tape_set(Tape* tape, uint8_t value) {
tape->data[tape->index] = value;
}
uint8_t* tape_ptr(Tape* tape) {
return tape->data;
}
void tape_free(Tape* tape) {
free(tape->data);
}

50
src/program.h Normal file
View file

@ -0,0 +1,50 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
typedef enum {
MoveLeft,
MoveRight,
Increment,
Decrement,
StartLoop,
EndLoop,
PutChar,
GetChar,
Allocate,
Free,
EnterTape,
LeaveTape,
PutString,
GetString,
Clear,
Eof,
Invalid
} Symbol;
typedef struct {
uint32_t len;
uint32_t index;
Symbol* data;
} Program;
void program_init(char* file_path, Program* program);
void program_peek(Program* program, Symbol* symbol);
void program_next(Program* program, Symbol* symbol);
void program_last(Program* program, Symbol* symbol);
void program_free(Program* program);
typedef struct {
uint32_t len;
uint32_t index;
uint8_t* data;
} Tape;
void tape_init(uint32_t len, Tape* tape);
void tape_left(Tape* tape);
void tape_right(Tape* tape);
uint8_t tape_get(Tape* tape);
void tape_set(Tape* tape, uint8_t value);
uint8_t* tape_ptr(Tape* tape);
void tape_free(Tape* tape);