Brainfuck interpreter
This commit is contained in:
parent
6a41ea1f36
commit
85566d511c
|
@ -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)
|
||||
|
|
|
@ -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")
|
|
@ -0,0 +1,13 @@
|
|||
PLUS = \+
|
||||
MINUS = -
|
||||
GREATER = >
|
||||
LESS = <
|
||||
POINT = \.
|
||||
COMMA = ,
|
||||
LBRACKET = \[
|
||||
RBRACKET = \]
|
||||
ignore = \n|.
|
||||
MINUS = -
|
||||
GREATER = >
|
||||
LESS = <
|
||||
|
|
@ -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]
|
||||
;
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
++++++++[>+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++>+++++++++++>++++++++++++>+++++++++++++>++++++++++++++>+++++++++++++++>++++++++++++++++<<<<<<<<<<<<<<<<-]>>>>>>>>>>.<<<<<<<<<<>>>>>>>>>>>>+.-<<<<<<<<<<<<>>>>>>>>>>>>>>++.--<<<<<<<<<<<<<<>>>>>>>>>>>>>>+++.---<<<<<<<<<<<<<<>>>>>>>>>>>>>>-.+<<<<<<<<<<<<<<>>>>>>>>>>>>>----.++++<<<<<<<<<<<<<>>>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<<<>>>>>>>>>>>>>>+++.---<<<<<<<<<<<<<<>>>>.<<<<>>>>>>>>>>>>>>>----.++++<<<<<<<<<<<<<<<>>>>>>>>>>>>>>-.+<<<<<<<<<<<<<<>>>>.<<<<>>>>>>>>>>>>>>>----.++++<<<<<<<<<<<<<<<>>>>>>>>>>>>>.<<<<<<<<<<<<<>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<>>>>.<<<<>>>>>>>>>>>>>>++.--<<<<<<<<<<<<<<>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<>>>>>>>>>>>>>>+++.---<<<<<<<<<<<<<<>>>>>>>>>>>>+++.---<<<<<<<<<<<<>>>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<<<>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<>>>>+.-<<<<>++.--<.
|
Loading…
Reference in New Issue