brainfucked
This commit is contained in:
commit
fafd290ed9
8 changed files with 449 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
bin
|
13
LICENSE
Normal file
13
LICENSE
Normal 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
39
Makefile
Normal 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
136
src/interpreter.c
Normal 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
5
src/interpreter.h
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "program.h"
|
||||||
|
|
||||||
|
void run_program(Program* program);
|
39
src/main.c
Normal file
39
src/main.c
Normal 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
166
src/program.c
Normal 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
50
src/program.h
Normal 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);
|
Loading…
Reference in a new issue