Skip to content

Instantly share code, notes, and snippets.

@rkhapov
Created May 29, 2016 17:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rkhapov/a8dd783fe154813fc2f76649a6f7d9ec to your computer and use it in GitHub Desktop.
Save rkhapov/a8dd783fe154813fc2f76649a6f7d9ec to your computer and use it in GitHub Desktop.
1438
#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