Advertisement
Guest User

Untitled

a guest
Aug 30th, 2016
62
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.21 KB | None | 0 0
  1. #include <iostream>
  2. #include <algorithm>
  3. #include <string>
  4. #include <vector>
  5. #include <cassert>
  6.  
  7. namespace tf
  8. {
  9. /* Threadful - The threadiest esoteric language.
  10.  
  11. Every thread lives only one generation, but often creates new ones.
  12.  
  13. Threads have their own instruction pointer which also is their memory pointer, even if the program and the memory are separated.
  14. The memory is initialized to zero. (i.e. 0x0, not the '0' ASCII character)
  15. The memory available to the program holds 8-bit unsigned cells. The underflow and overflow behaviour is wrapping.
  16. The width of the program is typically defined by the size of the first line.
  17. Threads also have an origin pointer, which is used by most instructions to perform a calculation between the previous and the current cell.
  18. Those pointers triggers undefined behaviour or an interpreter crash if they're pointing to an value out of the program/memory.
  19. Threads may not interfere with others. When two or more threads at a time try to write on the same cell, that cell is zeroed out. It still allows two thread creation on the same cell.
  20. Threads cannot create a thread on their direct origin pointer, one exception is '!'.
  21.  
  22. A thread must point to a valid instruction. Else, undefined behaviour is triggered, or the interpreter crashes.
  23. */
  24.  
  25. // 'x' : Multiply
  26. // Create threads multiplying the current cell with the top left, top right, bottom right and bottom left cells.
  27.  
  28. // '/' : Divide
  29. // Create threads dividing the current cell with the bottom left and top right cells.
  30. // Division by zero triggers undefined behaviour or an interpreter crash.
  31.  
  32. // '%' : Modulo
  33. // Create threads performing a modulo with the current cell and the bottom left and top right cells.
  34.  
  35. // '+' : Add
  36. // Create threads adding the current cell with the top, right, bottom and left cells.
  37.  
  38. // '-' : Subtract
  39. // Create threads subtracting the current cell with the left and right cells.
  40.  
  41. // 'p' : Print
  42. // Prints the current cell's value as an ASCII character. Creates a no-operation thread to the bottom cell.
  43.  
  44. // 'g' : Get character
  45. // Gets a character from the user and sets the current cell's value to it. Creates a no-operation thread to the left cell.
  46.  
  47. // '=' : Copy
  48. // Creates threads copying the current cell to the left and right cells.
  49.  
  50. // '$' : Gate
  51. // If the origin pointer is the left cell, a no-operation thread will be created on the left.
  52. // If the origin pointer is the right cell, a no-operation thread will be created on the right.
  53. // BUT in those previous cases, if the value of the current cell is zero, a new gate will be created on the other direction instead.
  54.  
  55. // If the origin pointer is the top cell, a no-operation thread will be created to the bottom.
  56. // If the origin pointer is the bottom cell, a no-operation thread will be created to the top.
  57.  
  58. // '}' : '>' comparator
  59. // Conditional gate. Acts the same as the '$' gate, but it will open instead if the current cell is bigger than the origin cell.
  60.  
  61. // '{' : '<' comparator
  62. // Conditional gate. Acts the same as the '$' gate, but it will open instead if the current cell is smaller than the origin cell.
  63.  
  64. // '^' : Initializer cell
  65. // Defines the program start.
  66. // Creates a no-operation thread to the top cell, and sets its value to the value represented by the cell on the bottom (i.e. an ASCII character).
  67. // May be used for other reasons than defining program startup points.
  68.  
  69. // '*' : Propagator
  70. // Creates no-operation threads to the top left, top, top right, right, bottom right, bottom, bottom left and left cells.
  71. // Reminder : As stated by the language rules, it cannot create a thread on its origin cell.
  72.  
  73. // '#' : Bridge
  74. // If the origin pointer is the top cell, a no-operation thread will be created to the bottom.
  75. // If the origin pointer is the left cell, a no-operation thread will be created to the right.
  76. // etc.
  77.  
  78. // '!' : One-way vertical bridge
  79. // If the origin pointer is the top cell, a no-operation thread will be created to the bottom.
  80. // Else, threads are "bounced" back to their origin cell.
  81.  
  82. struct Cell
  83. {
  84. unsigned char instruction;
  85. uint8_t memory_value;
  86. uint8_t future_value;
  87. bool was_changed = false;
  88.  
  89. void set_future_value(const uint8_t future)
  90. {
  91. if (was_changed) // If two threads write on the same cell, then it's zeroed out.
  92. {
  93. future_value = 0;
  94. return;
  95. }
  96. was_changed = true;
  97. future_value = future;
  98. }
  99. };
  100.  
  101. template<typename T>
  102. struct Vec2
  103. {
  104. T x, y;
  105. };
  106.  
  107. typedef Vec2<unsigned> Vec2u;
  108. typedef Vec2<int> Vec2i;
  109.  
  110. struct Position
  111. {
  112. unsigned at;
  113.  
  114. Vec2u to_position(const unsigned width)
  115. {
  116. return Vec2u{at / width, at % width};
  117. }
  118.  
  119. Cell& get_cell(std::vector<Cell>& memory, const unsigned width) const
  120. {
  121. return memory[at];
  122. }
  123.  
  124. Position operator+(const Position& other) const
  125. {
  126. static Position new_pos = Position{at + other.at};
  127. return new_pos;
  128. }
  129.  
  130. Position operator-(const Position& other) const
  131. {
  132. static Position new_pos = Position{at - other.at};
  133. return new_pos;
  134. }
  135.  
  136. template<typename T>
  137. Position add_vec(const Vec2<T> other, const unsigned width) const
  138. {
  139. static Position new_pos = Position{at + (other.x + (other.y * width))};
  140. return new_pos;
  141. }
  142.  
  143. template<typename T>
  144. Position sub_vec(const Vec2<T> other, const unsigned width) const
  145. {
  146. static Position new_pos = Position{at - (other.x + (other.y * width))};
  147. return new_pos;
  148. }
  149.  
  150. bool operator==(const Position& other) const
  151. {
  152. return at == other.at;
  153. }
  154.  
  155. // Necessary?
  156. bool operator!=(const Position& other) const
  157. {
  158. return at != other.at;
  159. }
  160. };
  161.  
  162. struct Thread
  163. {
  164. Position current, origin;
  165. };
  166.  
  167. class Interpreter
  168. {
  169. std::vector<Thread> m_threads;
  170.  
  171. size_t m_width = 0;
  172. std::vector<Cell> m_memory;
  173.  
  174. public:
  175. Interpreter(const std::string& program)
  176. {
  177. auto first_linefeed = std::find(begin(program), end(program), '\n');
  178. assert(first_linefeed != end(program)); // Can't have a one-line program
  179.  
  180. m_width = first_linefeed - begin(program); // Get the position of the first line jump and set it as the size
  181.  
  182. {
  183. unsigned x = 0;
  184. for (const char& instr : program)
  185. {
  186. if (instr != '\n')
  187. {
  188. m_memory.push_back({static_cast<unsigned char>(instr), 0});
  189. }
  190. else
  191. {
  192. m_memory.resize(m_memory.size() + (m_width - x)); // Leave empty space
  193. x = 0; // Reset the x coord
  194. }
  195. assert(x++ < m_width);
  196. }
  197. }
  198. }
  199.  
  200. void preload()
  201. {
  202. // Fill the thread vector from initializer cells
  203. for (unsigned i = 0; i < m_memory.size(); ++i)
  204. {
  205. if (m_memory[i].instruction == '^')
  206. {
  207. Position pos{i};
  208. m_threads.push_back(Thread{pos, pos});
  209. }
  210. }
  211. }
  212.  
  213. inline void thread_create(const Position& position, // New thread's cell
  214. const Position& origin, // New thread's original position
  215. const Position& origin_origin, // Origin's original position
  216. const bool allow_eq_grandpa = false) // Allow the original's original position to be the same as the new position.
  217. {
  218. if (allow_eq_grandpa || position != origin_origin)
  219. {
  220. m_threads.push_back(Thread{position, origin});
  221. }
  222. }
  223.  
  224. void interprete()
  225. {
  226. while (m_threads.size()) // While there are still threads left
  227. {
  228. for (Thread& thread : m_threads)
  229. {
  230. Cell& current_cell = thread.current.get_cell(m_memory, m_width);
  231. Cell& original_cell = thread.origin.get_cell(m_memory, m_width);
  232.  
  233. switch(current_cell.instruction)
  234. {
  235. case 'x': // Multiply
  236. for (const Position& cpos : // thread creation pos
  237. { thread.current.add_vec(Vec2i{1, -1}, m_width), // Top right
  238. thread.current.add_vec(Vec2i{1, 1}, m_width), // Bottom right
  239. thread.current.add_vec(Vec2i{1, -1}, m_width), // Bottom left
  240. thread.current.add_vec(Vec2i{-1, 1}, m_width) }) // Top left
  241. {
  242. Cell& new_cell = cpos.get_cell(m_memory, m_width);
  243. new_cell.future_value = current_cell.memory_value * new_cell.memory_value;
  244. thread_create(cpos, thread.current, thread.origin);
  245. }
  246.  
  247. default:
  248. std::cerr << "Unknown instruction detected. Aborting." << std::endl;
  249. return;
  250. }
  251. }
  252. }
  253. }
  254. };
  255. }
  256.  
  257. int main()
  258. {
  259. const std::string program =
  260. "";
  261.  
  262. tf::Interpreter inter(program);
  263. inter.preload();
  264. //inter.interprete();
  265. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement