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