Last active
January 22, 2018 13:42
-
-
Save ysakasin/f80c4050a76d71eb65c5dd00a45572d6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Copyright (c) 2018 SAKATA Sinji. Released under the MIT license. | |
| #include <fstream> | |
| #include <iostream> | |
| #include <iterator> | |
| #include <string> | |
| #include <vector> | |
| using namespace std; | |
| const int DataSize = 30000; | |
| enum OP_CODE { | |
| OP_ADD_PTR = 0, | |
| OP_ADD_DATA, | |
| OP_READ, | |
| OP_OUT, | |
| OP_JUMP, | |
| OP_JUMP_BK, | |
| }; | |
| const string code_s[] = { | |
| "addptr", "adddata", "read", "out", "jump", "jumpbk", | |
| }; | |
| struct Operation { | |
| OP_CODE op; | |
| int value; | |
| }; | |
| using Program = vector<Operation>; | |
| Program parse(const string &code) { | |
| int cp = 0; | |
| int pp = 0; | |
| vector<int> bracket_pp; | |
| Program program; | |
| program.push_back({OP_ADD_DATA, 0}); | |
| while (cp < code.length()) { | |
| int jump_to; | |
| switch (code[cp]) { | |
| case '>': | |
| if (program.back().op != OP_ADD_PTR) { | |
| program.push_back({OP_ADD_PTR, 0}); | |
| } | |
| program.back().value++; | |
| break; | |
| case '<': | |
| if (program.back().op != OP_ADD_PTR) { | |
| program.push_back({OP_ADD_PTR, 0}); | |
| } | |
| program.back().value--; | |
| break; | |
| case '+': | |
| if (program.back().op != OP_ADD_DATA) { | |
| program.push_back({OP_ADD_DATA, 0}); | |
| } | |
| program.back().value++; | |
| break; | |
| case '-': | |
| if (program.back().op != OP_ADD_DATA) { | |
| program.push_back({OP_ADD_DATA, 0}); | |
| } | |
| program.back().value--; | |
| break; | |
| case '.': | |
| program.push_back({OP_OUT, 1}); | |
| break; | |
| case ',': | |
| program.push_back({OP_READ, 1}); | |
| break; | |
| case '[': | |
| bracket_pp.push_back(program.size()); | |
| program.push_back({OP_JUMP, 0}); | |
| break; | |
| case ']': | |
| jump_to = bracket_pp.back(); | |
| bracket_pp.pop_back(); | |
| program[jump_to].value = program.size(); | |
| program.push_back({OP_JUMP_BK, jump_to}); | |
| break; | |
| default: | |
| break; // ignore | |
| } | |
| cp++; | |
| } | |
| return program; | |
| } | |
| void print_op(const Operation &o) { | |
| cout << code_s[o.op] << " " << o.value << endl; | |
| } | |
| void print_program(const Program &program) { | |
| int line = 0; | |
| for (const auto &o : program) { | |
| cout << line << ":"; | |
| print_op(o); | |
| line++; | |
| } | |
| } | |
| void eval(const Program &program) { | |
| int pp = 0; | |
| int ptr = 0; | |
| uint8_t data[DataSize] = {}; | |
| while (pp < program.size()) { | |
| OP_CODE op = program[pp].op; | |
| int value = program[pp].value; | |
| // print_op(program[pp]); | |
| switch (op) { | |
| case OP_ADD_DATA: | |
| data[ptr] += value; | |
| break; | |
| case OP_ADD_PTR: | |
| ptr += value; | |
| break; | |
| case OP_READ: | |
| cin >> data[ptr]; | |
| break; | |
| case OP_OUT: | |
| cout << data[ptr]; | |
| break; | |
| case OP_JUMP: | |
| if (data[ptr] == 0) | |
| pp = value; | |
| break; | |
| case OP_JUMP_BK: | |
| if (data[ptr] != 0) | |
| pp = value; | |
| break; | |
| } | |
| pp++; | |
| } | |
| } | |
| void eval(const string &code) { | |
| int cp = 0; | |
| int ptr = 0; | |
| uint8_t data[DataSize] = {}; | |
| while (cp < code.length()) { | |
| switch (code[cp]) { | |
| case '>': | |
| ptr++; | |
| break; | |
| case '<': | |
| ptr--; | |
| break; | |
| case '+': | |
| data[ptr]++; | |
| break; | |
| case '-': | |
| data[ptr]--; | |
| break; | |
| case '.': | |
| putchar(data[ptr]); | |
| break; | |
| case ',': | |
| cin >> data[ptr]; | |
| break; | |
| case '[': | |
| if (data[ptr] == 0) { | |
| int bracket_cnt = 0; | |
| while (code[++cp] != ']' || bracket_cnt != 0) { | |
| if (code[cp] == '[') | |
| bracket_cnt++; | |
| else if (code[cp] == ']') | |
| bracket_cnt--; | |
| } | |
| } | |
| break; | |
| case ']': | |
| if (data[ptr] != 0) { | |
| int bracket_cnt = 0; | |
| while (code[--cp] != '[' || bracket_cnt != 0) { | |
| if (code[cp] == ']') | |
| bracket_cnt++; | |
| else if (code[cp] == '[') | |
| bracket_cnt--; | |
| } | |
| } | |
| break; | |
| default:; // ignore | |
| } | |
| cp++; | |
| } | |
| } | |
| int main(int argc, char *argv[]) { | |
| if (argc != 2) { | |
| cerr << "require source code" << endl; | |
| return -1; | |
| } | |
| string src(argv[1]); | |
| ifstream ifs(src); | |
| if (ifs.fail()) { | |
| std::cerr << src << ": Not found." << std::endl; | |
| return -1; | |
| } | |
| istreambuf_iterator<char> it(ifs); | |
| istreambuf_iterator<char> last; | |
| string code(it, last); | |
| Program program = parse(code); | |
| // print_program(program); | |
| eval(program); | |
| // eval(code); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment