fork download
  1.  
  2. /*
  3. calculator08buggy.cpp
  4.  
  5. Helpful comments removed.
  6.  
  7. We have inserted 3 bugs that the compiler will catch and 3 that it won't.
  8. */
  9.  
  10. //#include "std_lib_facilities.h"
  11. #include <iostream>
  12. #include <string>
  13. #include <vector>
  14. #include <exception>
  15. #include <cctype>
  16.  
  17. using namespace std;
  18.  
  19. struct runtime_error : public exception {
  20. string msg;
  21. runtime_error(string s) :msg(s) {}
  22. ~runtime_error() throw() {}
  23. const char* what() const throw() { return msg.c_str(); }
  24. };
  25.  
  26. inline void error(string s, string t="") {
  27. throw runtime_error(s+" "+t);
  28. }
  29.  
  30. struct Token {
  31. char kind;
  32. double value;
  33. string name;
  34. Token(char ch) :kind(ch), value(0) { }
  35. Token(char ch, double val) :kind(ch), value(val) { }
  36. Token(char ch, string s) :kind(ch), name(s) { }
  37. };
  38.  
  39. class Token_stream {
  40. bool full;
  41. Token buffer;
  42. public:
  43. Token_stream() :full(0), buffer(0) { }
  44.  
  45. Token get();
  46. void unget(Token t) { buffer=t; full=true; }
  47.  
  48. void ignore(char);
  49. };
  50.  
  51. const char let = 'L';
  52. const char quit = 'Q';
  53. const char print = ';';
  54. const char number = '8';
  55. const char name = 'a';
  56.  
  57. Token Token_stream::get()
  58. {
  59. if (full) { full=false; return buffer; }
  60. char ch;
  61. cin >> ch;
  62. switch (ch) {
  63. case '(':
  64. case ')':
  65. case '+':
  66. case '-':
  67. case '*':
  68. case '/':
  69. case '%':
  70. case ';':
  71. case '=':
  72. return Token(ch);
  73. case '.':
  74. case '0':
  75. case '1':
  76. case '2':
  77. case '3':
  78. case '4':
  79. case '5':
  80. case '6':
  81. case '7':
  82. case '8':
  83. case '9':
  84. { cin.unget();
  85. double val;
  86. cin >> val;
  87. return Token(number,val);
  88. }
  89. default:
  90. if (isalpha(ch)) {
  91. string s;
  92. s += ch;
  93. while(cin.get(ch) && (isalpha(ch) || isdigit(ch))) s+=ch;
  94. cin.unget();
  95. if (s == "let") return Token(let);
  96. if (s == "quit") return Token(quit);
  97. return Token(name,s);
  98. }
  99. error("Bad token");
  100. }
  101. }
  102.  
  103. void Token_stream::ignore(char c)
  104. {
  105. if (full && c==buffer.kind) {
  106. full = false;
  107. return;
  108. }
  109. full = false;
  110.  
  111. char ch;
  112. while (cin>>ch)
  113. if (ch==c) return;
  114. }
  115.  
  116. struct Variable {
  117. string name;
  118. double value;
  119. Variable(string n, double v) :name(n), value(v) { }
  120. };
  121.  
  122. vector<Variable> names;
  123.  
  124. double get_value(string s)
  125. {
  126. for (int i = 0; i<names.size(); ++i)
  127. if (names[i].name == s) return names[i].value;
  128. error("get: undefined name ",s);
  129. }
  130.  
  131. void set_value(string s, double d)
  132. {
  133. for (int i = 0; i<=names.size(); ++i)
  134. if (names[i].name == s) {
  135. names[i].value = d;
  136. return;
  137. }
  138. error("set: undefined name ",s);
  139. }
  140.  
  141. bool is_declared(string s)
  142. {
  143. for (int i = 0; i<names.size(); ++i)
  144. if (names[i].name == s) return true;
  145. return false;
  146. }
  147.  
  148. Token_stream ts;
  149.  
  150. double expression();
  151.  
  152. double primary()
  153. {
  154. Token t = ts.get();
  155. switch (t.kind) {
  156. case '(':
  157. { double d = expression();
  158. t = ts.get();
  159. if (t.kind != ')') error("'(' expected");
  160. }
  161. case '-':
  162. return - primary();
  163. case number:
  164. return t.value;
  165. case name:
  166. return get_value(t.name);
  167. default:
  168. error("primary expected");
  169. }
  170. }
  171.  
  172. double term()
  173. {
  174. double left = primary();
  175. while(true) {
  176. Token t = ts.get();
  177. switch(t.kind) {
  178. case '*':
  179. left *= primary();
  180. break;
  181. case '/':
  182. { double d = primary();
  183. if (d == 0) error("divide by zero");
  184. left /= d;
  185. break;
  186. }
  187. default:
  188. ts.unget(t);
  189. return left;
  190. }
  191. }
  192. }
  193.  
  194. double expression()
  195. {
  196. double left = term();
  197. while(true) {
  198. Token t = ts.get();
  199. switch(t.kind) {
  200. case '+':
  201. left += term();
  202. break;
  203. case '-':
  204. left -= term();
  205. break;
  206. default:
  207. ts.unget(t);
  208. return left;
  209. }
  210. }
  211. }
  212.  
  213. double declaration()
  214. {
  215. Token t = ts.get();
  216. if (t.kind != 'a') error ("name expected in declaration");
  217. string name = t.name;
  218. if (is_declared(name)) error(name, " declared twice");
  219. Token t2 = ts.get();
  220. if (t2.kind != '=') error("= missing in declaration of " ,name);
  221. double d = expression();
  222. names.push_back(Variable(name,d));
  223. return d;
  224. }
  225.  
  226. double statement()
  227. {
  228. Token t = ts.get();
  229. switch(t.kind) {
  230. case let:
  231. return declaration();
  232. default:
  233. ts.unget(t);
  234. return expression();
  235. }
  236. }
  237.  
  238. void clean_up_mess()
  239. {
  240. ts.ignore(print);
  241. }
  242.  
  243. const string prompt = "> ";
  244. const string result = "= ";
  245.  
  246. void calculate()
  247. {
  248. while(true) try {
  249. cout << prompt;
  250. Token t = ts.get();
  251. while (t.kind == print) t=ts.get();
  252. if (t.kind == quit) return;
  253. ts.unget(t);
  254. cout << result << statement() << endl;
  255. }
  256. catch(runtime_error& e) {
  257. cerr << e.what() << endl;
  258. clean_up_mess();
  259. }
  260. }
  261.  
  262. int main()
  263.  
  264. try {
  265. calculate();
  266. return 0;
  267. }
  268. catch (exception& e) {
  269. cerr << "exception: " << e.what() << endl;
  270. char c;
  271. while (cin >>c&& c!=';') ;
  272. return 1;
  273. }
  274. catch (...) {
  275. cerr << "exception\n";
  276. char c;
  277. while (cin>>c && c!=';');
  278. return 2;
  279. }
Success #stdin #stdout 0s 3444KB
stdin
19+5
let abc=5
let efg=7
abc*efg
quit
stdout
> = 24
> = 5
> = 7
> = 35
>