fork download
  1. #include <istream>
  2. #include <ostream>
  3. #include <string>
  4. #include <stdexcept>
  5.  
  6. #include <boost/numeric/ublas/matrix.hpp>
  7.  
  8. namespace BefungeInterpreter
  9. {
  10. struct InterpreteException : public std::logic_error
  11. {
  12. InterpreteException(std::string const& w):
  13. std::logic_error(w){}
  14. };
  15.  
  16. boost::numeric::ublas::matrix<char> toMatrix(std::string const&);
  17.  
  18. void process(boost::numeric::ublas::matrix<char>&, std::ostream&, std::istream&);
  19. }
  20.  
  21. #include <ostream>
  22.  
  23. namespace BefungeInterpreter
  24. {
  25. namespace Miscellaneous
  26. {
  27. enum class Direction
  28. {
  29. right,
  30. left,
  31. up,
  32. down
  33. };
  34.  
  35. inline std::string toString(Direction const d)
  36. {
  37. #define makro(C) if(d == Direction::C) return #C;
  38. makro(down)
  39. makro(right)
  40. makro(left)
  41. makro(up)
  42. #undef makro
  43. }
  44. }
  45. }
  46.  
  47. #include <boost/lexical_cast.hpp>
  48.  
  49. #include <iterator>
  50. #include <vector>
  51. #include <stack>
  52.  
  53. #define get_from_stack(C) auto C = stack.top();\
  54.   stack.pop();
  55.  
  56.  
  57. boost::numeric::ublas::matrix<char> BefungeInterpreter::toMatrix(std::string const& s)
  58. {
  59. boost::numeric::ublas::matrix<char> rval(1, 1);
  60. size_t X = 0, Y = 0;
  61. for(auto c : s)
  62. if(c == '\n')
  63. {
  64. X = 0;
  65. ++Y;
  66. rval.resize(rval.size1(), Y + 1);
  67. }
  68. else
  69. {
  70. if(X == rval.size1())
  71. rval.resize(X + 1, rval.size2());
  72. rval(X++, Y) = c;
  73. }
  74.  
  75. return rval;
  76. }
  77.  
  78. void makeStepNCheck(size_t &X, size_t &Y, BefungeInterpreter::Miscellaneous::Direction const dir, size_t const righter_bound, size_t const lower_bound)
  79. {
  80. using BefungeInterpreter::Miscellaneous::Direction;
  81.  
  82. size_t const before_x = X,
  83. before_y = Y;
  84.  
  85. bool failure = false;
  86. switch(dir)
  87. {
  88. case Direction::down: failure = ++Y >= lower_bound; break;
  89. case Direction::right: failure = ++X >= righter_bound; break;
  90. case Direction::left: failure = X-- == 0; break;
  91. case Direction::up: failure = Y-- == 0; break;
  92. default: break;
  93. }
  94. if(failure)
  95. {
  96. throw BefungeInterpreter::InterpreteException("Reached end of direction - no instructions!\n"
  97. "Position: (" + boost::lexical_cast<std::string>(before_x) + "|" + boost::lexical_cast<std::string>(before_y) + ")\n"
  98. "Direction: " + toString(dir) + "\n"
  99. "Bounds: (" + boost::lexical_cast<std::string>(righter_bound) + "|" + boost::lexical_cast<std::string>(lower_bound) + ")");
  100. }
  101. }
  102.  
  103. void BefungeInterpreter::process(boost::numeric::ublas::matrix<char>& matrix, std::ostream& os, std::istream& is)
  104. {
  105. using BefungeInterpreter::Miscellaneous::Direction;
  106.  
  107. size_t X = 0,
  108. Y = 0;
  109.  
  110. Direction direction{Direction::right};
  111.  
  112. typedef unsigned long long stack_t;
  113. std::stack<stack_t> stack;
  114.  
  115. bool string_mode = false;
  116.  
  117. auto makeStepNCheck = std::bind(::makeStepNCheck,
  118. std::ref(X),
  119. std::ref(Y),
  120. std::cref(direction),
  121. std::placeholders::_1,
  122. std::placeholders::_2);
  123.  
  124. for(bool exit = false;!exit;exit ? (void)0 : makeStepNCheck(matrix.size1(), matrix.size2()))
  125. {
  126. char const ch = matrix(X, Y);
  127.  
  128. #ifdef DEBUG
  129. std::cout << "Position: (" + boost::lexical_cast<std::string>(X) + "|" + boost::lexical_cast<std::string>(Y) + ") '" + std::string{ch} + "'\n";
  130. #endif
  131.  
  132. if(ch == '"')
  133. {
  134. string_mode = !string_mode;
  135. continue;
  136. }
  137.  
  138. if(string_mode)
  139. stack.push(ch);
  140.  
  141. else
  142. switch(ch)
  143. {
  144. /// MISCELLANEOUS *************************************************************
  145. case '@':
  146. exit = true;
  147. break;
  148.  
  149. case ':':
  150. stack.push(stack.top());
  151. break;
  152.  
  153. case ' ':
  154. break;
  155.  
  156. case '#':
  157. makeStepNCheck(matrix.size1(), matrix.size2());
  158. break;
  159.  
  160. case '0':case '1':case '2':
  161. case '3':case '4':case '5':
  162. case '6':case '7':case '8':
  163. case '9':
  164.  
  165. stack.push(ch - '0');
  166. break;
  167.  
  168. case 'g':
  169. {
  170. get_from_stack(y)
  171. get_from_stack(x)
  172.  
  173. stack.push(matrix(x, y));
  174. break;
  175. }
  176. case 'p':
  177. {
  178. get_from_stack(y)
  179. get_from_stack(x)
  180. get_from_stack(v)
  181.  
  182. matrix(x, y) = v;
  183. break;
  184. }
  185.  
  186. /// INPUT OPERATIONS ****
  187. case '&': stack.push(*std::istream_iterator<stack_t>(is)); break;
  188. case '~': stack.push(*std::istream_iterator<char>(is)); break;
  189.  
  190. /// DIRECTION OPERATIONS (not qualified ops!) *********************************
  191.  
  192. case '>': {direction = Direction::right; break;}
  193. case '<': {direction = Direction::left; break;}
  194. case 'v': {direction = Direction::down; break;}
  195. case '^': {direction = Direction::up; break;}
  196. case '?':
  197. {
  198. std::vector<Direction> s;
  199. if(X) s.push_back(Direction::left);
  200. if(Y) s.push_back(Direction::up);
  201. if(Y < matrix.size2() - 1) s.push_back(Direction::down);
  202. if(X < matrix.size1() - 1) s.push_back(Direction::right);
  203.  
  204. direction = s[rand() % s.size()];
  205. break;
  206. }
  207.  
  208. /// BINARY OPERATIONS *********************************************************
  209. case '+':
  210. case '-':
  211. case '*':
  212. case '/':
  213. case '%':
  214. case '\\':
  215. case '`':
  216. {
  217. get_from_stack(a)
  218. get_from_stack(b)
  219.  
  220. switch(ch)
  221. {
  222. case '+': stack.push(a + b); break;
  223. case '-': stack.push(b - a); break;
  224. case '*': stack.push(a * b); break;
  225. case '/': stack.push(a / b); break;
  226. case '%': stack.push(a % b); break;
  227. case '\\': stack.push(a); stack.push(b); break;
  228. case '`': stack.push(b > a ? 1 : 0);
  229. default: break;
  230. }
  231. break;
  232. }
  233.  
  234. /// UNARY OPERATIONS **********************************************************
  235. case '!':
  236. case '_':
  237. case '|':
  238. case '.':
  239. case ',':
  240. case '$':
  241. {
  242. get_from_stack(a)
  243.  
  244. switch(ch)
  245. {
  246. case '!': stack.push(a ? 0 : 1); break;
  247. case '_': direction = (a ? Direction::left : Direction::right); break;
  248. case '|': direction = (a ? Direction::up : Direction::down); break;
  249. case '.': os << a; break;
  250. case ',': os << static_cast<char>(a); break;
  251. default: break;
  252. }
  253. break;
  254. }
  255.  
  256.  
  257. default:
  258. throw InterpreteException("Unknown character in code!\n"
  259. "Character (ASCII): " + boost::lexical_cast<std::string>((int)ch) + "\n"
  260. "Character : " + std::string(1, ch));
  261. }
  262. }
  263. }
  264.  
  265. #include <iostream>
  266. #include <cstdlib>
  267. #include <ctime>
  268. #include <sstream>
  269. #include <fstream>
  270.  
  271. int main() try
  272. {
  273. srand(time(nullptr));
  274.  
  275. std::ostringstream stream;
  276. stream << ">25*\"!dlrow ,olleH\":v \n"
  277. " v:,_@ \n"
  278. " > ^ ";
  279.  
  280. auto m = BefungeInterpreter::toMatrix(stream.str());
  281. BefungeInterpreter::process(m, std::cout, std::cin);
  282. }
  283. catch(BefungeInterpreter::InterpreteException const& b)
  284. {
  285. std::cerr << "An interprete exception occured!\n"
  286. << b.what();
  287. }
  288. catch(std::exception const& e)
  289. {
  290. std::cerr << "A standard exception occured!\n"
  291. << e.what() << '\n'
  292. << "Terminating!";
  293. std::exit(-1);
  294. }
  295. catch(...)
  296. {
  297. std::cerr << "An unknown exception occured!\n"
  298. "Terminating!";
  299. std::exit(-2);
  300. }
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty