PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/src/org/faabtech/brainfuck/impl/TrollScriptEngine.java

http://github.com/clone1018/Shocky
Java | 209 lines | 117 code | 16 blank | 76 comment | 44 complexity | e727da25956427d5575d0d81339fa4ca MD5 | raw file
Possible License(s): 0BSD, Apache-2.0
  1. package org.faabtech.brainfuck.impl;
  2. import java.io.InputStream;
  3. import java.io.OutputStream;
  4. import java.io.PrintStream;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. import org.faabtech.brainfuck.BrainfuckEngine;
  8. /**
  9. * The {@link TrollScriptEngine} is an implementation for the
  10. * <code>brainfuck<code> dialect
  11. * <code>TrollScript</code>.
  12. *
  13. * @author Fabian M.
  14. */
  15. public class TrollScriptEngine extends BrainfuckEngine {
  16. /**
  17. * The default length of a token.
  18. */
  19. protected int defaultTokenLength = 3;
  20. /**
  21. * The {@link Token} class contains tokens in <code>TrollScript</code>.
  22. *
  23. * @author Fabian M.
  24. */
  25. protected static class Token {
  26. public final static String START = "tro";
  27. public final static String NEXT = "ooo";
  28. public final static String PREVIOUS = "ool";
  29. public final static String PLUS = "olo";
  30. public final static String MINUS = "oll";
  31. public final static String OUTPUT = "loo";
  32. public final static String INPUT = "lol";
  33. public final static String BRACKET_LEFT = "llo";
  34. public final static String BRACKET_RIGHT = "lll";
  35. public final static String END = "ll.";
  36. }
  37. /**
  38. * Constructs a new {@link TrollScriptEngine} instance.
  39. *
  40. * @param cells
  41. * The amount of memory cells.
  42. */
  43. public TrollScriptEngine(int cells) {
  44. this(cells, new PrintStream(System.out), System.in);
  45. }
  46. /**
  47. * Constructs a new {@link TrollScriptEngine} instance.
  48. *
  49. * @param cells
  50. * The amount of memory cells.
  51. * @param out
  52. * The outputstream of this program.
  53. */
  54. public TrollScriptEngine(int cells, OutputStream out) {
  55. this(cells, out, System.in);
  56. }
  57. /**
  58. * Constructs a new {@link TrollScriptEngine} instance.
  59. *
  60. * @param cells
  61. * The amount of memory cells.
  62. * @param out
  63. * The printstream of this program.
  64. * @param in
  65. * The outputstream of this program.
  66. */
  67. public TrollScriptEngine(int cells, OutputStream out, InputStream in) {
  68. super(cells, out, in);
  69. }
  70. /**
  71. * Interprets the given string.
  72. *
  73. * @param str
  74. * The string to interpret.
  75. * @throws Exception
  76. */
  77. @Override
  78. public void interpret(String str) throws Exception {
  79. // Is this program already started?
  80. boolean started = false;
  81. // List with tokens.defaultTokenLenght
  82. List<String> tokens = new ArrayList<String>();
  83. // It fine that all TrollScript tokens are 3 characters long :)
  84. // So we aren't going to loop through all characters.
  85. for (; charPointer < str.length(); ) {
  86. String token = "";
  87. if (charPointer + defaultTokenLength <= str.length())
  88. // The string we found.
  89. token = str.substring(charPointer, charPointer + defaultTokenLength);
  90. else
  91. token = str.substring(charPointer, charPointer
  92. + (str.length() - charPointer));
  93. // Is it a token?
  94. if (isValidToken(token)) {
  95. if (token.equalsIgnoreCase(Token.START))
  96. started = true;
  97. else if (token.equalsIgnoreCase(Token.END))
  98. break;
  99. else if (started)
  100. tokens.add(token);
  101. charPointer += defaultTokenLength;
  102. } else if (charPointer + defaultTokenLength > str.length()) {
  103. charPointer += (str.length() - charPointer);
  104. } else {
  105. charPointer++;
  106. }
  107. }
  108. // Loop through all tokens.
  109. for (int tokenPointer = 0; tokenPointer < tokens.size(); ) {
  110. String token = tokens.get(tokenPointer);
  111. if (token.equalsIgnoreCase(Token.NEXT)) {
  112. // increment the data pointer (to point to the next cell
  113. // to the
  114. // right).
  115. dataPointer = (dataPointer == data.length - 1 ? 0 : dataPointer + 1);
  116. }
  117. if (token.equalsIgnoreCase(Token.PREVIOUS)) {
  118. // decrement the data pointer (to point to the next cell
  119. // to the
  120. // left).
  121. dataPointer = (dataPointer == 0 ? data.length - 1 : dataPointer - 1);
  122. }
  123. if (token.equalsIgnoreCase(Token.PLUS)) {
  124. // increment (increase by one) the byte at the data
  125. // pointer.
  126. data[dataPointer]++;
  127. }
  128. if (token.equalsIgnoreCase(Token.MINUS)) {
  129. // decrement (decrease by one) the byte at the data
  130. // pointer.
  131. data[dataPointer]--;
  132. }
  133. if (token.equalsIgnoreCase(Token.OUTPUT)) {
  134. // Output the byte at the current index in a character.
  135. outWriter.write((char) data[dataPointer]);
  136. // Flush the outputstream.
  137. outWriter.flush();
  138. }
  139. if (token.equalsIgnoreCase(Token.INPUT)) {
  140. // accept one byte of input, storing its value in the
  141. // byte at the data pointer.
  142. data[dataPointer] = (byte) consoleReader.read();
  143. }
  144. if (token.equalsIgnoreCase(Token.BRACKET_LEFT)) {
  145. if (data[dataPointer] == 0) {
  146. int level = 1;
  147. while (level > 0) {
  148. tokenPointer++;
  149. if (tokens.get(tokenPointer).equalsIgnoreCase(Token.BRACKET_LEFT))
  150. level++;
  151. else if (tokens.get(tokenPointer).equalsIgnoreCase(Token.BRACKET_RIGHT))
  152. level--;
  153. }
  154. }
  155. }
  156. if (token.equalsIgnoreCase(Token.BRACKET_RIGHT)) {
  157. if (data[dataPointer] != 0) {
  158. int level = 1;
  159. while (level > 0) {
  160. tokenPointer--;
  161. if (tokens.get(tokenPointer).equalsIgnoreCase(Token.BRACKET_LEFT))
  162. level--;
  163. else if (tokens.get(tokenPointer).equalsIgnoreCase(Token.BRACKET_RIGHT))
  164. level++;
  165. }
  166. }
  167. }
  168. tokenPointer++;
  169. }
  170. // Clear all data.
  171. initate(data.length);
  172. }
  173. /**
  174. * Is the given token a valid <code>TrollScript</code> token.
  175. *
  176. * @param token
  177. * The token to check.
  178. * @return <code>true</code> if the given token is a valid
  179. * <code>TrollScript</code> token, <code>false</code> otherwise.
  180. */
  181. protected boolean isValidToken(String token) {
  182. if (token.equalsIgnoreCase(Token.START) || token.equalsIgnoreCase(Token.NEXT)
  183. || token.equalsIgnoreCase(Token.PREVIOUS) || token.equalsIgnoreCase(Token.PLUS)
  184. || token.equalsIgnoreCase(Token.MINUS) || token.equalsIgnoreCase(Token.OUTPUT)
  185. || token.equalsIgnoreCase(Token.INPUT)
  186. || token.equalsIgnoreCase(Token.BRACKET_LEFT)
  187. || token.equalsIgnoreCase(Token.BRACKET_RIGHT)
  188. || token.equalsIgnoreCase(Token.END)) {
  189. return true;
  190. }
  191. return false;
  192. }
  193. }