PageRenderTime 24ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/main.cpp

https://gitlab.com/brainfuck-interpreter/brainfuck-interpreter
C++ | 215 lines | 154 code | 30 blank | 31 comment | 37 complexity | 9762aba8e9493ebe56ac6fcc0d9efdbd MD5 | raw file
Possible License(s): GPL-3.0
  1. /*
  2. * PROGRAM:
  3. * Brainfuck interpreter
  4. *
  5. * AUTHOR:
  6. * Théophile BASTIAN (a.k.a. Tobast)
  7. *
  8. * CONTACT & WEBSITE:
  9. * http://tobast.fr/ (contact feature included)
  10. * error-report@tobast.fr (error reporting only)
  11. *
  12. * SHORT DESCRIPTION:
  13. * See first license line.
  14. *
  15. * LICENSE:
  16. * This software is (another) classical brainfuck interpreter, with errors handling and support of both stdin and source-file argument.
  17. * Copyright (C) 2011 Théophile BASTIAN
  18. *
  19. * This program is free software: you can redistribute it and/or modify
  20. * it under the terms of the GNU General Public License as published by
  21. * the Free Software Foundation, either version 3 of the License, or
  22. * (at your option) any later version.
  23. *
  24. * This program is distributed in the hope that it will be useful,
  25. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  27. * GNU General Public License for more details.
  28. *
  29. * You should have received a copy of the GNU General Public License
  30. * along with this program. If not, see http://www.gnu.org/licenses/gpl.txt.
  31. */
  32. #include <iostream>
  33. #include <vector>
  34. #include <string>
  35. #include <stdexcept>
  36. #include <cstdio>
  37. #include <fstream>
  38. #define DEFAULT_MEM_VALUE 0
  39. using namespace std;
  40. string inputCode(void)
  41. {
  42. std::string outstr;
  43. cin.seekg(0, ios::end);
  44. if(!cin.fail()) // buffer not empty
  45. {
  46. cin.seekg(0, ios::beg);
  47. while(!cin.eof())
  48. outstr+=cin.get();
  49. cin.clear();
  50. }
  51. else
  52. {
  53. cin.seekg(0, ios::beg);
  54. cin.clear();
  55. while(1)
  56. {
  57. std::string tmp;
  58. std::cin >> tmp;
  59. outstr+=tmp;
  60. if(tmp.find(-1) != std::string::npos || tmp.find('\\') != string::npos) // found a ^D or a backslash
  61. break;
  62. }
  63. }
  64. return outstr;
  65. }
  66. int main(int argc, char** argv)
  67. {
  68. string code;
  69. vector<unsigned char> memtab(10000, DEFAULT_MEM_VALUE);
  70. unsigned ptr=0, i=0;
  71. bool quiet=true, inputfile=false;
  72. if(argc>1)
  73. {
  74. ifstream file(argv[1]);
  75. if(file)
  76. {
  77. inputfile=true;
  78. while(!file.eof())
  79. code+=file.get();
  80. file.close();
  81. }
  82. for(int i=1;i<argc;i++)
  83. {
  84. if(string(argv[i]) == "-v")
  85. quiet=false;
  86. }
  87. }
  88. if(!inputfile)
  89. code=inputCode();
  90. if(!quiet)
  91. cout << endl << "Executing...";
  92. cout << endl;
  93. try {
  94. for(i=0;i<code.size();i++)
  95. {
  96. int matchcount=0, input=0; // useful only for respectively ( [ & ] ) ; ,
  97. switch(code[i])
  98. {
  99. case '>':
  100. ptr++;
  101. if(ptr >= memtab.size())
  102. {
  103. if(memtab.size() == memtab.max_size())
  104. throw out_of_range("Maximal memory array index reached.");
  105. else if(memtab.size()+1000 > memtab.max_size())
  106. memtab.resize(memtab.max_size(), DEFAULT_MEM_VALUE);
  107. memtab.resize(memtab.size()+1000, DEFAULT_MEM_VALUE);
  108. }
  109. break;
  110. case '<':
  111. if(ptr==0) // will go under 0 (unsigned int must be above 0, either as a vector index).
  112. throw out_of_range("Minimal memory array index reached.");
  113. ptr--;
  114. break;
  115. case '+':
  116. memtab[ptr]++;
  117. break;
  118. case '-':
  119. memtab[ptr]--;
  120. break;
  121. case '.':
  122. cout << memtab[ptr];
  123. break;
  124. case ',':
  125. input=getchar();
  126. if(input < 0 || input > 128)
  127. throw range_error("Input out of byte range.");
  128. memtab[ptr]=(unsigned char) input;
  129. break;
  130. case '[':
  131. if(!memtab[ptr]) // jump to next ]
  132. {
  133. i++;
  134. for(;i<code.size();i++)
  135. {
  136. if(code[i]=='[')
  137. matchcount++;
  138. else if(code[i]==']')
  139. matchcount--;
  140. if(matchcount < 0)
  141. break;
  142. }
  143. if(matchcount>=0)
  144. throw runtime_error("No matching ']' found after '[' token.");
  145. }
  146. break;
  147. case ']':
  148. if(memtab[ptr]) // jump to previous [
  149. {
  150. i--;
  151. for(; i!=0 ; i--)
  152. {
  153. if(code[i]=='[')
  154. matchcount--;
  155. else if(code[i]==']')
  156. matchcount++;
  157. if(matchcount < 0)
  158. break;
  159. }
  160. if(code[i]=='[')
  161. matchcount--;
  162. if(matchcount>=0)
  163. throw runtime_error("No matching '[' found before ']' token.");
  164. }
  165. break;
  166. default:
  167. break;
  168. }
  169. }
  170. cout << endl;
  171. if(!quiet)
  172. cout << "Done." << endl;
  173. return 0;
  174. }
  175. catch(const range_error &e) {
  176. cerr << "FATAL: " << e.what() << endl;
  177. }
  178. catch(const out_of_range &e) {
  179. cerr << i+1 << " = " << code[i] << " : " << e.what() << ". Memory table size: 0 -> " << memtab.max_size() << "." << endl;
  180. }
  181. catch(const exception &e) {
  182. cerr << i+1 << " = " << code[i] << " : " << e.what() << endl;
  183. }
  184. return 1;
  185. }