Created
May 29, 2016 17:53
-
-
Save rkhapov/a8dd783fe154813fc2f76649a6f7d9ec to your computer and use it in GitHub Desktop.
1438
This file contains 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
#include <iostream> | |
#include <vector> | |
#include <cctype> | |
#include <string> | |
#include <cstring> | |
#include <sstream> | |
#include <map> | |
enum { PRINT, END, LET, ADD, SUB, MUL, DIV, | |
MOD, OR, AND, XOR, NOT, GOTO, | |
IFEQ, IFNEQ, IFGE, IFG, IFLE, IFL, NOP }; | |
const std::string codesPrint[] = { "PRINT", "END", "LET", "ADD", "SUB", "MUL", "DIV", | |
"MOD", "OR", "AND", "XOR", "NOT", "GOTO", | |
"IFEQ", "IFNEQ", "IFGE", "IFG", "IFLE", "IFL", "NOP" }; | |
enum { NUMBER = 1, VARIABLE }; | |
typedef long dword; | |
unsigned long long count = 0; | |
std::map<std::string, dword> variables; | |
std::map<std::string, unsigned int> labels; | |
bool halt = false; | |
struct Operand | |
{ | |
int type = -1; | |
std::string name; | |
dword value; | |
dword getValue() const | |
{ | |
if (type == NUMBER) | |
return value; | |
return variables[name]; | |
} | |
}; | |
struct Instruction | |
{ | |
int code = -1; | |
Operand op1; | |
Operand op2; | |
Operand op3; | |
std::string label; | |
}; | |
std::vector<Instruction> program; | |
void cutString(const std::string &source, const std::string &delim, std::vector<std::string> &out) | |
{ | |
static char buffer[200]; | |
std::strcpy(buffer, source.c_str()); | |
char *token = std::strtok(buffer, delim.c_str()); | |
while (token != nullptr) | |
{ | |
out.push_back(token); | |
token = std::strtok(nullptr, delim.c_str()); | |
} | |
} | |
void toLowerCase(std::string &str) | |
{ | |
for (std::size_t i = 0; i < str.size(); i++) | |
str[i] = std::tolower(str[i]); | |
} | |
dword strToNum(const std::string &str) | |
{ | |
std::stringstream ss; | |
ss << str; | |
int v; | |
ss >> v; | |
return v; | |
} | |
Operand decodeOperand(const std::string &operand) | |
{ | |
Operand op; | |
if (std::isalpha(operand[0])) | |
{ | |
op.type = VARIABLE; | |
op.name = operand; | |
} | |
else | |
{ | |
op.type = NUMBER; | |
op.value = strToNum(operand); | |
} | |
return op; | |
} | |
Instruction decodeInstruciton(const std::string &str) | |
{ | |
Instruction instruction; | |
std::vector<std::string> tokens; | |
cutString(str, " \t", tokens); | |
if (*(--tokens[0].end()) == ':') //label | |
{ | |
toLowerCase(tokens[0]); | |
const std::string &labelName = tokens[0].substr(0, tokens[0].size() - 1); | |
labels[labelName] = program.size(); | |
tokens.erase(tokens.begin()); | |
} | |
if (tokens.size() == 0) | |
{ | |
instruction.code = NOP; | |
} | |
else if (tokens.size() == 1) | |
{ | |
instruction.code = END; | |
} | |
else if (tokens.size() == 2) | |
{ | |
if (tokens[0][0] == 'p' || tokens[0][0] == 'P') | |
{ | |
instruction.code = PRINT; | |
instruction.op1 = decodeOperand(tokens[1]); | |
} | |
else | |
{ | |
instruction.code = GOTO; | |
instruction.label = tokens[1]; | |
} | |
} | |
else if (tokens.size() == 3) | |
{ | |
instruction.code = LET; | |
instruction.op1 = decodeOperand(tokens[0]); | |
instruction.op2 = decodeOperand(tokens[2]); | |
} | |
else if (tokens.size() == 4) | |
{ | |
instruction.code = NOT; | |
instruction.op1 = decodeOperand(tokens[0]); | |
instruction.op2 = decodeOperand(tokens[3]); | |
} | |
else if (tokens.size() == 5) | |
{ | |
instruction.op1 = decodeOperand(tokens[0]); | |
instruction.op2 = decodeOperand(tokens[2]); | |
instruction.op3 = decodeOperand(tokens[4]); | |
toLowerCase(tokens[3]); | |
if (tokens[3][0] == 'o') | |
tokens[3] = "|"; | |
else if (tokens[3][0] == 'a') | |
tokens[3] = "&"; | |
else if (tokens[3][0] == 'x') | |
tokens[3] = "^"; | |
static const std::string op = "+-*/%|&^"; | |
instruction.code = op.find(tokens[3]) + ADD; | |
} | |
else | |
{ | |
instruction.op1 = decodeOperand(tokens[1]); | |
instruction.op2 = decodeOperand(tokens[3]); | |
toLowerCase(tokens[5]); | |
instruction.label = tokens[5]; | |
static const std::string op = "==!=>= ><= <"; | |
if (tokens[2].size() == 1) | |
tokens[2] = " " + tokens[2]; | |
instruction.code = op.find(tokens[2]) / 2 + IFEQ; | |
} | |
return instruction; | |
} | |
unsigned int exec(unsigned int ip) | |
{ | |
const Instruction &instruction = program[ip]; | |
if (count >= 10000000 && !halt) | |
{ | |
std::cout << "Program terminated. Variables state:" << std::endl; | |
for (auto it = variables.begin(); it != variables.end(); it++) | |
{ | |
std::cout << it->first << ": " << it->second << std::endl; | |
} | |
halt = true; | |
return 0; | |
} | |
switch (instruction.code) | |
{ | |
case PRINT: | |
if (instruction.op1.type == NUMBER) | |
{ | |
std::cout << instruction.op1.value << std::endl; | |
} | |
else | |
{ | |
std::cout << variables[instruction.op1.name] << std::endl; | |
} | |
ip++; | |
break; | |
case END: | |
halt = true; | |
ip++; | |
break; | |
case LET: | |
variables[instruction.op1.name] = instruction.op2.getValue(); | |
ip++; | |
break; | |
case ADD: | |
variables[instruction.op1.name] = instruction.op2.getValue() + instruction.op3.getValue(); | |
ip++; | |
break; | |
case SUB: | |
variables[instruction.op1.name] = instruction.op2.getValue() - instruction.op3.getValue(); | |
ip++; | |
break; | |
case MUL: | |
variables[instruction.op1.name] = instruction.op2.getValue() * instruction.op3.getValue(); | |
ip++; | |
break; | |
case DIV: | |
variables[instruction.op1.name] = instruction.op2.getValue() / instruction.op3.getValue(); | |
ip++; | |
break; | |
case MOD: | |
variables[instruction.op1.name] = instruction.op2.getValue() % instruction.op3.getValue(); | |
if (variables[instruction.op1.name] < 0) | |
variables[instruction.op1.name] += std::abs(instruction.op3.getValue()); | |
ip++; | |
break; | |
case OR: | |
variables[instruction.op1.name] = instruction.op2.getValue() | instruction.op3.getValue(); | |
ip++; | |
break; | |
case AND: | |
variables[instruction.op1.name] = instruction.op2.getValue() & instruction.op3.getValue(); | |
ip++; | |
break; | |
case XOR: | |
variables[instruction.op1.name] = instruction.op2.getValue() ^ instruction.op3.getValue(); | |
ip++; | |
break; | |
case NOT: | |
variables[instruction.op1.name] = ~instruction.op2.getValue(); | |
ip++; | |
break; | |
case GOTO: | |
ip = labels[instruction.label]; | |
break; | |
case IFEQ: | |
if (instruction.op1.getValue() == instruction.op2.getValue()) | |
ip = labels[instruction.label]; | |
else | |
ip++; | |
break; | |
case IFNEQ: | |
if (instruction.op1.getValue() != instruction.op2.getValue()) | |
ip = labels[instruction.label]; | |
else | |
ip++; | |
break; | |
case IFGE: | |
if (instruction.op1.getValue() >= instruction.op2.getValue()) | |
ip = labels[instruction.label]; | |
else | |
ip++; | |
break; | |
case IFG: | |
if (instruction.op1.getValue() > instruction.op2.getValue()) | |
ip = labels[instruction.label]; | |
else | |
ip++; | |
break; | |
case IFLE: | |
if (instruction.op1.getValue() <= instruction.op2.getValue()) | |
ip = labels[instruction.label]; | |
else | |
ip++; | |
break; | |
case IFL: | |
if (instruction.op1.getValue() < instruction.op2.getValue()) | |
ip = labels[instruction.label]; | |
else | |
ip++; | |
break; | |
} | |
return ip; | |
} | |
int main() | |
{ | |
unsigned int ip = 0; | |
std::string string; | |
while (!std::cin.eof()) | |
{ | |
std::getline(std::cin, string); | |
if (string.empty()) | |
continue; | |
Instruction i = decodeInstruciton(string); | |
if (i.code != NOP) | |
program.push_back(i); | |
} | |
Instruction end; | |
end.code = END; | |
program.push_back(end); | |
while (!halt) | |
{ | |
ip = exec(ip); | |
count++; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment