PageRenderTime 27ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/loonix/core/bfi.java

https://github.com/songhead95/loonix
Java | 336 lines | 287 code | 29 blank | 20 comment | 11 complexity | e17a6694b41d068a10959771c34548c3 MD5 | raw file
  1. package loonix.core;
  2. import java.io.PrintStream;
  3. import java.io.InputStream;
  4. /** This class is a brainfuck interpreter written by Sven Stucki.<br>
  5. * It lets you execute a bf program step-by-step for easy debugging or visualization or it can interpret the whole program at once.<br>
  6. * Release date: 2.7.2009
  7. * @author Sven Stucki
  8. */
  9. public class bfi {
  10. public String logbuffer = "";
  11. public Stdin in;
  12. public Stdout out;
  13. public Stderr err;
  14. /** Output of the brainfuck programm goes here, default = System.out **/
  15. public PrintStream ps; // Output stream
  16. /** Input of the brainfuck programm is read from here, default = System.in **/
  17. public InputStream is; // Input stream
  18. /** This points to the currently selected memory cell **/
  19. public int mp; // Memory pointer
  20. /** This array represents the memory of the brainfuck program **/
  21. public int[] cell; // Memory
  22. /** This is the index of the char in the code, which will be executed next **/
  23. private int cp; // Code pointer
  24. /** The code is stored in this String **/
  25. private String cmd; // Code
  26. /** This String contains all in the code allowed chars **/
  27. public final String CHARS = "<>+-[].,";
  28. /** Standard constructor, sets everything to default **/
  29. public bfi() {
  30. init( 30000 );
  31. }
  32. /** With this constructor you can specify the number of memory cells to provide, I/O uses default **/
  33. public bfi( int cnt ) {
  34. init( cnt );
  35. }
  36. /** This constructor lets you specify the number of memory cells, and the I/O Streams **/
  37. public bfi( int cnt, PrintStream p, InputStream i ) {
  38. ps = p;
  39. is = i;
  40. init( cnt );
  41. }
  42. /** Initialises / Resets the interpreter **/
  43. public void init( int cnt ) {
  44. cell = new int[cnt];
  45. mp = 0;
  46. if( cmd==null )
  47. cmd = "";
  48. if( ps==null )
  49. ps = System.out;
  50. if( is==null )
  51. is = System.in;
  52. }
  53. /** Resets the memory field and the pointers **/
  54. public void reset() {
  55. cell = new int[cell.length];
  56. mp = 0;
  57. cp = 0;
  58. }
  59. /** Set In- / PrintStream **/
  60. public void setInputStream( InputStream ips, PrintStream ops ) {
  61. is = ips;
  62. ps = ops;
  63. }
  64. /** Usable for running multiple programs in the same environment **/
  65. public void setPointer( int pos ) {
  66. mp = pos;
  67. }
  68. /** Loads brainfuck program, filters every char not in the CHARS constant or after a \ out of the String **/
  69. public void setProgram( String prg ) {
  70. boolean take = false;
  71. cmd = "";
  72. for( int i=0; i<prg.length(); i++ ) {
  73. if( take ) {
  74. cmd += prg.charAt(i);
  75. take = false;
  76. } else {
  77. if( CHARS.indexOf( prg.charAt(i) ) != -1 ) {
  78. cmd += prg.charAt(i);
  79. } else if( prg.charAt(i) == '\\' ) {
  80. cmd += "\\";
  81. take = true;
  82. }
  83. }
  84. }
  85. log( "Parsed program: " + cmd );
  86. }
  87. /** Returns next char **/
  88. public char getChar() {
  89. return getChar( this.cp );
  90. }
  91. /** Returns char from command string at specified position **/
  92. public char getChar( int nr ) {
  93. return cmd.charAt( nr );
  94. }
  95. /** Get a slice of the programm **/
  96. public String getChars( int start, int end ) {
  97. String tmp = "";
  98. for( int i=start-1; i<end; i++ ) {
  99. tmp += cmd.charAt(i);
  100. }
  101. return tmp;
  102. }
  103. /** Interpret program, set start address **/
  104. public boolean interpret( int spos ) {
  105. this.cp = spos;
  106. return interpret();
  107. }
  108. /** Start interpretation of programm **/
  109. public boolean interpret() {
  110. char inst;
  111. // Fetch next instruction
  112. try {
  113. inst = getChar();
  114. } catch( Exception e ) {
  115. return false;
  116. }
  117. // Parse instruction
  118. switch( inst ) {
  119. case '<':
  120. mp = (mp>0) ? mp-1 : 0;
  121. break;
  122. case '>':
  123. mp = (mp<cell.length) ? mp+1 : mp;
  124. break;
  125. case '+':
  126. cell[mp]++;
  127. break;
  128. case '-':
  129. cell[mp]--;
  130. break;
  131. case '[':
  132. if( cell[mp] == 0 )
  133. return jumpWhileEnd();
  134. break;
  135. case ']':
  136. return jumpWhileStart();
  137. // break;
  138. case '\\':
  139. try {
  140. cell[mp] = getChar( cp+1 );
  141. cp++;
  142. } catch( Exception e ) {
  143. return false;
  144. }
  145. break;
  146. case '*':
  147. if( cell[mp]==13 || cell[mp]==10){
  148. out.print("");
  149. } else {err.printc(cell[mp]);
  150. }
  151. break;
  152. case '.':
  153. if( cell[mp]==13 || cell[mp]==10 ) {
  154. // Printing out char 13 or 10 causes an exception (don't know why)
  155. out.print( "" );
  156. } else {
  157. out.printc( cell[mp] );
  158. }
  159. break;
  160. case ',':
  161. try {
  162. cell[mp] = in.read();
  163. } catch( Exception e ) {
  164. return false;
  165. }
  166. break;
  167. }
  168. cp++;
  169. return true;
  170. }
  171. /** This method searches the corresponding [ sign **/
  172. public boolean jumpWhileStart() {
  173. int level = 0;
  174. for( int i=cp-1; i>=0; i-- ) {
  175. switch( cmd.charAt(i) ) {
  176. case '[':
  177. if( level > 0 ) {
  178. level--;
  179. } else {
  180. cp = i;
  181. return true;
  182. }
  183. break;
  184. case ']':
  185. level++;
  186. break;
  187. }
  188. }
  189. return false;
  190. }
  191. /** This method searches trailing ] sign **/
  192. public boolean jumpWhileEnd() {
  193. int level = 0;
  194. for( int i=cp+1; i<cmd.length(); i++ ) {
  195. switch( cmd.charAt(i) ) {
  196. case '[':
  197. level++;
  198. break;
  199. case ']':
  200. if( level <= 0 ) {
  201. cp = i+1;
  202. return true;
  203. } else {
  204. level--;
  205. }
  206. break;
  207. }
  208. }
  209. return false;
  210. }
  211. /** This method goes through the whole code **/
  212. public void start(Stdin input, Stdout output, Stderr error) {
  213. in=input;
  214. out=output;
  215. err=error;
  216. start(0);
  217. }
  218. /** This method goes through the whole code starting at a certain point in the code **/
  219. public void start( int off ) {
  220. if( interpret(off) ) {
  221. while( interpret() );
  222. out.printc(-1);
  223. }
  224. try {
  225. log( "Programm terminated at instructions: " + getChars( cp-1, cp+2 ) );
  226. log( "Code before exception: " + getChars( 1, cp+2 ) );
  227. } catch( Exception e ) {
  228. log( "Programm terminated. " );
  229. if( cp >= cmd.length() ) {
  230. log( "(End of Program)" );
  231. } else {
  232. log( "(Exception, no debuggin info available)" );
  233. }
  234. }
  235. }
  236. /** If class is run directly, execute the argument as brainfuck program **/
  237. public static void main( String[] args ) {
  238. if( args.length < 1 ) {
  239. System.out.println( "Usage: " );
  240. System.out.println( "java bfi <brainfuck program>" );
  241. System.out.println();
  242. System.exit( -1 );
  243. }
  244. bfi bfi = new bfi();
  245. bfi.setProgram( args[0] );
  246. bfi.start(0);
  247. System.out.println();
  248. }
  249. public void log(String msg) {
  250. logbuffer = logbuffer + msg + "\n";
  251. }
  252. }