Brainfuck interpreter

This commit is contained in:
kwullaer 2017-01-29 19:58:29 +01:00
parent 6a41ea1f36
commit 85566d511c
11 changed files with 317 additions and 1 deletions

View File

@ -1,4 +1,5 @@
add_subdirectory(json)
add_subdirectory(calc)
add_subdirectory(brainfuck)
add_custom_target(examples DEPENDS json calc)
add_custom_target(examples DEPENDS json calc bf)

View File

@ -0,0 +1,19 @@
add_custom_command(DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/bfLexer.lxs"
COMMAND "${LEXESIS_EXE}" ARGS -d "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/bfLexer.lxs"
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/BfLexer.h" "${CMAKE_CURRENT_BINARY_DIR}/BfLexer.cpp")
find_program(PARSODUS_EXE Parsodus PATH "${CMAKE_CURRENT_BINARY_DIR}/../../bin")
add_custom_command(DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/bfParser.pds"
COMMAND "${PARSODUS_EXE}" ARGS -d "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/bfParser.pds"
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/bfParser.h" "${CMAKE_CURRENT_BINARY_DIR}/bfParser.cpp")
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
add_executable(bf
EXCLUDE_FROM_ALL
main.cpp
parser.cpp
generator.cpp
"${CMAKE_CURRENT_BINARY_DIR}/BfLexer.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/bfParser.cpp")

View File

@ -0,0 +1,13 @@
PLUS = \+
MINUS = -
GREATER = >
LESS = <
POINT = \.
COMMA = ,
LBRACKET = \[
RBRACKET = \]
ignore = \n|.
MINUS = -
GREATER = >
LESS = <

View File

@ -0,0 +1,28 @@
parser: SLR(1)
lexesis: bfLexer.lxs
terminals:
"PLUS"
"MINUS"
"GREATER"
"LESS"
"POINT"
"COMMA"
"LBRACKET"
"RBRACKET"
precedence:
left
nonassoc
right
start: <program>
grammar:
<program> ::= <instruction> <program> [PROGRAM]
| [EMPTY]
;
<instruction> ::= "PLUS" [OPERATION]
| "MINUS" [OPERATION]
| "GREATER" [OPERATION]
| "LESS" [OPERATION]
| "POINT" [OPERATION]
| "COMMA" [OPERATION]
| "LBRACKET" <program> "RBRACKET" [LOOP]
;

View File

@ -0,0 +1,62 @@
#include "generator.h"
#include "instruction.h"
#include <iostream>
#include <cstring>
namespace bf {
void Generator::run() {
counter = 0;
std::memset(array, 0, sizeof(array));
while (!lbrackets.empty())
lbrackets.pop();
for(int instruct = 0; instruct < program.size(); instruct++) {
switch(program[instruct]) {
case Instruction::EMPTY: break;
case Instruction::PLUS:
array[counter]++;
break;
case Instruction::MINUS:
array[counter]--;
break;
case Instruction::GREATER:
if (++counter == 30000) {
std::cout << "Tried to access unavailable memory" << std::endl;
return;
} break;
case Instruction::LESS:
if (--counter == -1) {
std::cout << "Tried to access unavailable memory" << std::endl;
return;
} break;
case Instruction::POINT:
std::cout << (char)array[counter];
break;
case Instruction::COMMA:
char c;
std::cin >> c;
array[counter] = (int)c;
break;
case Instruction::LBRACKET:
lbrackets.push(instruct);
if (array[counter] == 0)
while (program[++instruct] != Instruction::RBRACKET) {}
break;
case Instruction::RBRACKET:
if (array[counter] != 0)
instruct = lbrackets.top();
else
lbrackets.pop();
break;
default: // Won't happen
break;
}
}
}
} // namespace bf

View File

@ -0,0 +1,30 @@
#ifndef GENERATOR_H
#define GENERATOR_H
#include "instruction.h"
#include <deque>
#include <stack>
namespace bf {
class Generator {
public:
Generator(std::deque<Instruction> program) :
program(program) { }
void run();
private:
std::deque<Instruction> program;
int array[30000];
int counter;
std::stack<int> lbrackets;
};
} // namespace bf
#endif

View File

@ -0,0 +1,21 @@
#pragma once
#ifndef INSTRUCTION_H
#define INSTRUCTION_H
namespace bf {
enum class Instruction {
EMPTY,
PLUS,
MINUS,
GREATER,
LESS,
POINT,
COMMA,
LBRACKET,
RBRACKET
};
}
#endif

View File

@ -0,0 +1,19 @@
#include "parser.h"
#include "BfLexer.h"
#include "generator.h"
#include "instruction.h"
#include <iostream>
#include <fstream>
using namespace std;
using namespace bf;
int main(int argc, char** argv) {
ifstream file(argv[1]);
BfLexer lex(file);
Parser parser(lex);
Generator gen(*(parser.parse()));
gen.run();
return 0;
}

View File

@ -0,0 +1,91 @@
#include "parser.h"
#include "instruction.h"
#include <iostream>
namespace bf {
Parser::Parser(BfLexer lex) :
bfParser<std::unique_ptr<std::deque<Instruction>>>(), m_lex(lex) {
}
Parser::Token Parser::lex() {
try {
BfLexer::Token orig = m_lex.nextToken();
std::deque<Instruction> pm;
switch(orig.type) {
case BfLexer::PLUS: {
pm.push_back(Instruction::PLUS);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm);
//std::cout << "PARSING: found PLUS " << (int)Instruction::PLUS << std::endl;
return Token{ bfParser_Symbol::T_PLUS, std::move(p) };
} case BfLexer::MINUS: {
pm.push_back(Instruction::MINUS);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm);
//std::cout << "PARSING: found MINUS" << (int)Instruction::MINUS << std::endl;
return Token{ bfParser_Symbol::T_MINUS, std::move(p) };
} case BfLexer::GREATER: {
pm.push_back(Instruction::GREATER);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm);
//std::cout << "PARSING: found GREATER" << (int)Instruction::GREATER << std::endl;
return Token{ bfParser_Symbol::T_GREATER, std::move(p) };
} case BfLexer::LESS: {
pm.push_back(Instruction::LESS);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm);
//std::cout << "PARSING: found LESS" << (int)Instruction::LESS << std::endl;
return Token{ bfParser_Symbol::T_LESS, std::move(p) };
} case BfLexer::POINT: {
pm.push_back(Instruction::POINT);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm);
//std::cout << "PARSING: found POINT" << (int)Instruction::POINT << std::endl;
return Token{ bfParser_Symbol::T_POINT, std::move(p) };
} case BfLexer::COMMA: {
pm.push_back(Instruction::COMMA);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm);
//std::cout << "PARSING: found COMMA" << (int)Instruction::COMMA << std::endl;
return Token{ bfParser_Symbol::T_COMMA, std::move(p) };
} case BfLexer::LBRACKET: {
pm.push_back(Instruction::LBRACKET);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm);
//std::cout << "PARSING: found LBRACKET" << (int)Instruction::LBRACKET << std::endl;
return Token{ bfParser_Symbol::T_LBRACKET, std::move(p) };
} case BfLexer::RBRACKET: {
pm.push_back(Instruction::RBRACKET);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm);
//std::cout << "PARSING: found RBRACKET" << (int)Instruction::RBRACKET << std::endl;
return Token{ bfParser_Symbol::T_RBRACKET, std::move(p) };
}
}
} catch(BfLexer::NoMoreTokens) {
return Token{ bfParser_Symbol::T_EOF, nullptr };
}
}
std::unique_ptr<std::deque<Instruction>> Parser::reduce_PROGRAM(std::deque<Token> subparts) {
// <program> ::= <instruction> <program>
if (subparts[1].value == nullptr)
return std::move(subparts[0].value);
for(auto& instr : *(subparts[1].value))
subparts[0].value->push_back(instr);
return std::move(subparts[0].value);
}
std::unique_ptr<std::deque<Instruction>> Parser::reduce_EMPTY(std::deque<Token> subparts) {
// <program> ::=
return nullptr;
}
std::unique_ptr<std::deque<Instruction>> Parser::reduce_OPERATION(std::deque<Token> subparts) {
// <instruction> ::= "PLUS" | "MINUS" | ... | "COMMA"
return std::move(subparts[0].value);
}
std::unique_ptr<std::deque<Instruction>> Parser::reduce_LOOP(std::deque<Token> subparts) {
// <instruction> ::= "LBRACKET" <program> "RBRACKET"
subparts[1].value->push_front(Instruction::LBRACKET);
subparts[1].value->push_back(Instruction::RBRACKET);
//std::cout << "PARSING: found LOOP" << std::endl;
//for(auto& s : *(subparts[1].value)) std::cout << "LOOP: " << (int)s << std::endl;
return std::move(subparts[1].value);
}
} // namespace bf

View File

@ -0,0 +1,31 @@
#pragma once
#ifndef PARSER_H
#define PARSER_H
#include "bfParser.h"
#include "BfLexer.h"
#include "instruction.h"
#include <deque>
#include <memory>
namespace bf {
class Parser : public bfParser<std::unique_ptr<std::deque<Instruction>>> {
public:
Parser(BfLexer lex);
protected:
Token lex() override;
std::unique_ptr<std::deque<Instruction>> reduce_PROGRAM(std::deque<Token> subparts) override;
std::unique_ptr<std::deque<Instruction>> reduce_EMPTY(std::deque<Token> subparts) override;
std::unique_ptr<std::deque<Instruction>> reduce_OPERATION(std::deque<Token> subparts) override;
std::unique_ptr<std::deque<Instruction>> reduce_LOOP(std::deque<Token> subparts) override;
private:
BfLexer m_lex;
};
}
#endif // PARSER_H

View File

@ -0,0 +1 @@
++++++++[>+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++>+++++++++++>++++++++++++>+++++++++++++>++++++++++++++>+++++++++++++++>++++++++++++++++<<<<<<<<<<<<<<<<-]>>>>>>>>>>.<<<<<<<<<<>>>>>>>>>>>>+.-<<<<<<<<<<<<>>>>>>>>>>>>>>++.--<<<<<<<<<<<<<<>>>>>>>>>>>>>>+++.---<<<<<<<<<<<<<<>>>>>>>>>>>>>>-.+<<<<<<<<<<<<<<>>>>>>>>>>>>>----.++++<<<<<<<<<<<<<>>>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<<<>>>>>>>>>>>>>>+++.---<<<<<<<<<<<<<<>>>>.<<<<>>>>>>>>>>>>>>>----.++++<<<<<<<<<<<<<<<>>>>>>>>>>>>>>-.+<<<<<<<<<<<<<<>>>>.<<<<>>>>>>>>>>>>>>>----.++++<<<<<<<<<<<<<<<>>>>>>>>>>>>>.<<<<<<<<<<<<<>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<>>>>.<<<<>>>>>>>>>>>>>>++.--<<<<<<<<<<<<<<>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<>>>>>>>>>>>>>>+++.---<<<<<<<<<<<<<<>>>>>>>>>>>>+++.---<<<<<<<<<<<<>>>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<<<>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<>>>>+.-<<<<>++.--<.