Skip to content

Commit 493ac94

Browse files
committed
Brainfuck interpreter.
1 parent 362efa0 commit 493ac94

File tree

6 files changed

+225
-0
lines changed

6 files changed

+225
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ function(add_meta_project arg)
1313
endfunction(add_meta_project)
1414

1515
add_meta_project(turing-machine)
16+
add_meta_project(brainfuck)

brainfuck/interpreter.hpp

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#pragma once
2+
3+
#include "common/conditional.hpp"
4+
#include "common/string.hpp"
5+
6+
#include "memory.hpp"
7+
8+
namespace meta {
9+
namespace brainfuck {
10+
11+
template <typename memory = initial_memory,
12+
typename input = make_string<>,
13+
typename output = make_string<>>
14+
struct state {
15+
using mem = memory;
16+
using in = input;
17+
using out = output;
18+
};
19+
20+
template <typename command, typename st>
21+
struct _interpret_command {
22+
using result = st;
23+
};
24+
25+
template <typename st>
26+
struct _interpret_command<chr<'>'>, st> {
27+
using result = state<typename st::mem::rshift,
28+
typename st::in,
29+
typename st::out>;
30+
};
31+
32+
template <typename st>
33+
struct _interpret_command<chr<'<'>, st> {
34+
using result = state<typename st::mem::lshift,
35+
typename st::in,
36+
typename st::out>;
37+
};
38+
39+
template <typename st>
40+
struct _interpret_command<chr<'+'>, st> {
41+
using result = state<call<inc_cursor, typename st::mem>,
42+
typename st::in,
43+
typename st::out>;
44+
};
45+
46+
template <typename st>
47+
struct _interpret_command<chr<'-'>, st> {
48+
using result = state<call<dec_cursor, typename st::mem>,
49+
typename st::in,
50+
typename st::out>;
51+
};
52+
53+
template <typename st>
54+
struct _interpret_command<chr<'.'>, st> {
55+
using result = state<typename st::mem,
56+
typename st::in,
57+
append<typename st::mem::get, typename st::out>>;
58+
};
59+
60+
template <typename st>
61+
struct _interpret_command<chr<','>, st> {
62+
using in_value = peek<typename st::in, chr<>>;
63+
using result = state<call<turing::set_cursor, typename st::mem, in_value>,
64+
pop<typename st::in>,
65+
typename st::out>;
66+
};
67+
68+
CREATE_ALIAS(interpret_command);
69+
70+
template <typename program, typename loop = list<>, int counter = 0>
71+
struct find_loop :
72+
public find_loop<pop<program>, append<peek<program>, loop>, counter> {};
73+
74+
template <typename... cmds, typename loop, int counter>
75+
struct find_loop<list<chr<'['>, cmds...>, loop, counter> :
76+
public find_loop<list<cmds...>, append<chr<'['>, loop>, counter + 1> {};
77+
78+
template <typename... cmds, typename loop, int counter>
79+
struct find_loop<list<chr<']'>, cmds...>, loop, counter> :
80+
public find_loop<list<cmds...>, append<chr<']'>, loop>, counter - 1> {};
81+
82+
template <typename... cmds, typename loop>
83+
struct find_loop<list<chr<']'>, cmds...>, loop, 0> {
84+
using remaining_program = list<cmds...>;
85+
using loop_program = loop;
86+
};
87+
88+
template <typename program, typename st = state<>>
89+
struct _interpret {
90+
using command = peek<program>;
91+
using next_state = interpret_command<command, st>;
92+
using result = typename _interpret<pop<program>, next_state>::result;
93+
};
94+
95+
template <typename... commands, typename st>
96+
struct _interpret<list<chr<'['>, commands...>, st> {
97+
using program = list<commands...>;
98+
using loop = find_loop<program>;
99+
using end_loop = is_same<chr<0>, typename st::mem::get>;
100+
using next_state =
101+
conditional<end_loop,
102+
st,
103+
typename _interpret<typename loop::loop_program, st>::result>;
104+
using next_program =
105+
conditional<end_loop,
106+
typename loop::remaining_program,
107+
push<chr<'['>, program>>;
108+
using result = typename _interpret<next_program, next_state>::result;
109+
};
110+
111+
template <typename st>
112+
struct _interpret<list<>, st> {
113+
using result = st;
114+
};
115+
116+
CREATE_ALIAS(interpret);
117+
118+
}
119+
}

brainfuck/main.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include "common/string.hpp"
2+
3+
#include "interpreter.hpp"
4+
5+
int main() {
6+
7+
// from Wikipedia:
8+
// https://en.wikipedia.org/wiki/Brainfuck#Hello_World.21
9+
using hello_world =
10+
meta::make_string<'+','+','+','+','+','+','+','+','[','>','+','+',
11+
'+','+','[','>','+','+','>','+','+','+','>','+',
12+
'+','+','>','+','<','<','<','<','-',']','>','+',
13+
'>','+','>','-','>','>','+','[','<',']','<','-',
14+
']','>','>','.','>','-','-','-','.','+','+','+',
15+
'+','+','+','+','.','.','+','+','+','.','>','>',
16+
'.','<','-','.','<','.','+','+','+','.','-','-',
17+
'-','-','-','-','.','-','-','-','-','-','-','-',
18+
'-','.','>','>','+','.','>','+','+','.'>;
19+
20+
using hw_output = meta::brainfuck::interpret<hello_world>::out;
21+
22+
return 0;
23+
}

brainfuck/memory.hpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#pragma once
2+
3+
#include "common/macros.hpp"
4+
#include "common/list.hpp"
5+
#include "common/string.hpp"
6+
7+
#include "turing-machine/tape.hpp"
8+
9+
namespace meta {
10+
namespace brainfuck {
11+
12+
using initial_memory = meta::turing::tape<chr<>, list<>, list<>, chr<>>;
13+
14+
template <typename c>
15+
struct __inc_chr;
16+
17+
template <char c>
18+
struct __inc_chr<chr<c>> {
19+
using result = chr<c+1>;
20+
};
21+
22+
template <>
23+
struct __inc_chr<chr<(char)255>> {
24+
using result = chr<>;
25+
};
26+
27+
CREATE_ALIAS(_inc_chr);
28+
using inc_chr = lambda<_inc_chr>;
29+
30+
template <typename c>
31+
struct __dec_chr;
32+
33+
template <char c>
34+
struct __dec_chr<chr<c>> {
35+
using result = chr<c-1>;
36+
};
37+
38+
template <>
39+
struct __dec_chr<chr<(char)0>> {
40+
using result = chr<(char)255>;
41+
};
42+
43+
CREATE_ALIAS(_dec_chr);
44+
using dec_chr = lambda<_dec_chr>;
45+
46+
template <typename mem>
47+
using _inc_cursor = typename mem::template set<call<inc_chr, typename mem::get>>;
48+
using inc_cursor = lambda<_inc_cursor>;
49+
50+
template <typename mem>
51+
using _dec_cursor = typename mem::template set<call<dec_chr, typename mem::get>>;
52+
using dec_cursor = lambda<_dec_cursor>;
53+
54+
}
55+
}

common/string.hpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#pragma once
2+
3+
#include "list.hpp"
4+
5+
namespace meta {
6+
7+
template <char c = (char)0>
8+
struct chr {
9+
static constexpr char value { c };
10+
};
11+
12+
template <char... cs>
13+
struct _make_string {
14+
using result = list<>;
15+
};
16+
17+
template <char c, char... cs>
18+
struct _make_string<c, cs...> {
19+
using result = push<chr<c>,
20+
typename _make_string<cs...>::result>;
21+
};
22+
23+
template <char... cs>
24+
using make_string = typename _make_string<cs...>::result;
25+
26+
}

readme.org

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ basic building blocks.
1111
- [[./common/][common/]]: libraries implementing shared functionality. Contains
1212
implementations of type lists, conditionals, lambdas, among others.
1313
- [[./turing-machine][turing-machine/]]: a Turing Machine simulator.
14+
- [[./brainfuck/][brainfuck/]]: an interpreter for the Brainfuck programming language.

0 commit comments

Comments
 (0)