Advertisement
Guest User

tokens_netodude

a guest
Dec 16th, 2014
340
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.33 KB | None | 0 0
  1.  
  2. //
  3. // This is example code from Chapter 7.8.3 "Predefined names" of
  4. // "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
  5. //
  6.  
  7. #include "std_lib_facilities.h"
  8.  
  9. /*
  10.     Simple calculator
  11.  
  12.     Revision history:
  13.  
  14.         Revised by Bjarne Stroustrup May 2007
  15.         Revised by Bjarne Stroustrup August 2006
  16.         Revised by Bjarne Stroustrup August 2004
  17.         Originally written by Bjarne Stroustrup
  18.             (bs@cs.tamu.edu) Spring 2004.
  19.  
  20.     This program implements a basic expression calculator.
  21.     Input from cin; output to cout.
  22.  
  23.     The grammar for input is:
  24.  
  25.     Calculation:
  26.         Statement
  27.         Print
  28.         Quit
  29.         Calculation Statement
  30.  
  31.     Statement:
  32.         Declaration
  33.         Expression
  34.  
  35.     Declaration:
  36.         "let" Name "=" Expression
  37.  
  38.     Print:
  39.         ;
  40.  
  41.     Quit:
  42.         q
  43.  
  44.     Expression:
  45.         Term
  46.         Expression + Term
  47.         Expression - Term
  48.     Term:
  49.         Primary
  50.         Term * Primary
  51.         Term / Primary
  52.         Term % Primary
  53.     Primary:
  54.         Number
  55.         Name
  56.         ( Expression )
  57.         - Primary
  58.         + Primary
  59.     Number:
  60.         floating-point-literal
  61.  
  62.  
  63.         Input comes from cin through the Token_stream called ts.
  64. */
  65.  
  66. //------------------------------------------------------------------------------
  67.  
  68. const char number = '8';    // t.kind==number means that t is a number Token
  69. const char quit   = 'q';    // t.kind==quit means that t is a quit Token
  70. const char print  = ';';    // t.kind==print means that t is a print Token
  71. const char name   = 'a';    // name token
  72. const char let    = 'L';    // declaration token
  73. const string declkey = "let";// declaration keyword
  74. const string prompt  = "> ";
  75. const string result  = "= "; // used to indicate that what follows is a result
  76.  
  77. //------------------------------------------------------------------------------
  78.  
  79. class Token {
  80. public:
  81.     char kind;        // what kind of token
  82.     double value;     // for numbers: a value
  83.     string name;      // for names: name itself
  84.     Token(char ch)             : kind(ch), value(0)   {}
  85.     Token(char ch, double val) : kind(ch), value(val) {}
  86.     Token(char ch, string n)   : kind(ch), name(n)    {}
  87. };
  88.  
  89. //------------------------------------------------------------------------------
  90.  
  91. class Token_stream {
  92. public:
  93.     Token_stream();   // make a Token_stream that reads from cin
  94.     Token get();      // get a Token (get() is defined elsewhere)
  95.     void putback(Token t);    // put a Token back
  96.     void ignore(char c);      // discard tokens up to an including a c
  97. private:
  98.     bool full;        // is there a Token in the buffer?
  99.     Token buffer;     // here is where we keep a Token put back using putback()
  100. };
  101.  
  102. //------------------------------------------------------------------------------
  103.  
  104. // The constructor just sets full to indicate that the buffer is empty:
  105. Token_stream::Token_stream()
  106. :full(false), buffer(0)    // no Token in buffer
  107. {
  108. }
  109.  
  110. //------------------------------------------------------------------------------
  111.  
  112. // The putback() member function puts its argument back into the Token_stream's buffer:
  113. void Token_stream::putback(Token t)
  114. {
  115.     if (full) error("putback() into a full buffer");
  116.     buffer = t;       // copy t to buffer
  117.     full = true;      // buffer is now full
  118. }
  119.  
  120. //------------------------------------------------------------------------------
  121.  
  122. Token Token_stream::get() // read characters from cin and compose a Token
  123. {
  124.     if (full) {         // check if we already have a Token ready
  125.         full=false;
  126.         return buffer;
  127.     }
  128.  
  129.     char ch;
  130.     cin >> ch;          // note that >> skips whitespace (space, newline, tab, etc.)
  131.  
  132.     switch (ch) {
  133.     case quit:
  134.     case print:
  135.     case '(':
  136.     case ')':
  137.     case '+':
  138.     case '-':
  139.     case '*':
  140.     case '/':
  141.     case '%':
  142.     case '=':
  143.         return Token(ch); // let each character represent itself
  144.     case '.':             // a floating-point literal can start with a dot
  145.     case '0': case '1': case '2': case '3': case '4':
  146.     case '5': case '6': case '7': case '8': case '9':    // numeric literal
  147.     {
  148.         cin.putback(ch);// put digit back into the input stream
  149.         double val;
  150.         cin >> val;     // read a floating-point number
  151.         return Token(number,val);
  152.     }
  153.     default:
  154.         if (isalpha(ch)) {
  155.             string s;
  156.             s += ch;
  157.             while (cin.get(ch) && (isalpha(ch) || isdigit(ch))) s+=ch;
  158.             cin.putback(ch);
  159.             if (s == declkey) return Token(let); // keyword "let"
  160.             return Token(name,s);
  161.         }
  162.         error("Bad token");
  163.     }
  164. }
  165.  
  166. //------------------------------------------------------------------------------
  167.  
  168. void Token_stream::ignore(char c)
  169.     // c represents the kind of a Token
  170. {
  171.     // first look in buffer:
  172.     if (full && c==buffer.kind) {
  173.         full = false;
  174.         return;
  175.     }
  176.     full = false;
  177.  
  178.     // now search input:
  179.     char ch = 0;
  180.     while (cin>>ch)
  181.         if (ch==c) return;
  182. }
  183.  
  184. //------------------------------------------------------------------------------
  185.  
  186. Token_stream ts;        // provides get() and putback()
  187.  
  188. //------------------------------------------------------------------------------
  189.  
  190. class Variable {
  191. public:
  192.     string name;
  193.     double value;
  194.     Variable (string n, double v) :name(n), value(v) { }
  195. };
  196.  
  197. //------------------------------------------------------------------------------
  198.  
  199. vector<Variable> var_table;
  200.  
  201. //------------------------------------------------------------------------------
  202.  
  203. double get_value(string s)
  204.     // return the value of the Variable names s
  205. {
  206.     for (int i = 0; i<var_table.size(); ++i)
  207.         if (var_table[i].name == s) return var_table[i].value;
  208.     error("get: undefined variable ", s);
  209. }
  210.  
  211. //------------------------------------------------------------------------------
  212.  
  213. void set_value(string s, double d)
  214.     // set the Variable named s to d
  215. {
  216.     for (int i = 0; i<var_table.size(); ++i)
  217.         if (var_table[i].name == s) {
  218.             var_table[i].value = d;
  219.             return;
  220.         }
  221.     error("set: undefined variable ", s);
  222. }
  223.  
  224. //------------------------------------------------------------------------------
  225.  
  226. bool is_declared(string var)
  227.     // is var already in var_table?
  228. {
  229.     for (int i = 0; i<var_table.size(); ++i)
  230.         if (var_table[i].name == var) return true;
  231.     return false;
  232. }
  233.  
  234. //------------------------------------------------------------------------------
  235.  
  236. double define_name(string var, double val)
  237.     // add (var,val) to var_table
  238. {
  239.     if (is_declared(var)) error(var," declared twice");
  240.     var_table.push_back(Variable(var,val));
  241.     return val;
  242. }
  243.  
  244. //------------------------------------------------------------------------------
  245.  
  246. double expression();    // declaration so that primary() can call expression()
  247.  
  248. //------------------------------------------------------------------------------
  249.  
  250. // deal with numbers and parentheses
  251. double primary()
  252. {
  253.     Token t = ts.get();
  254.     switch (t.kind) {
  255.     case '(':           // handle '(' expression ')'
  256.         {
  257.             double d = expression();
  258.             t = ts.get();
  259.             if (t.kind != ')') error("')' expected");
  260.             return d;
  261.         }
  262.     case number:
  263.         return t.value;    // return the number's value
  264.     case name:
  265.         return get_value(t.name); // return the variable's value
  266.     case '-':
  267.         return - primary();
  268.     case '+':
  269.         return primary();
  270.     default:
  271.         error("primary expected");
  272.     }
  273. }
  274.  
  275. //------------------------------------------------------------------------------
  276.  
  277. // deal with *, /, and %
  278. double term()
  279. {
  280.     double left = primary();
  281.     Token t = ts.get(); // get the next token from token stream
  282.  
  283.     while(true) {
  284.         switch (t.kind) {
  285.         case '*':
  286.             left *= primary();
  287.             t = ts.get();
  288.             break;
  289.         case '/':
  290.             {
  291.                 double d = primary();
  292.                 if (d == 0) error("divide by zero");
  293.                 left /= d;
  294.                 t = ts.get();
  295.                 break;
  296.             }
  297.         case '%':
  298.             {
  299.                 int i1 = narrow_cast<int>(left);
  300.                 int i2 = narrow_cast<int>(term());
  301.                 if (i2 == 0) error("%: divide by zero");
  302.                 left = i1%i2;
  303.                 t = ts.get();
  304.                 break;
  305.             }
  306.         default:
  307.             ts.putback(t);        // put t back into the token stream
  308.             return left;
  309.         }
  310.     }
  311. }
  312.  
  313. //------------------------------------------------------------------------------
  314.  
  315. // deal with + and -
  316. double expression()
  317. {
  318.     double left = term();      // read and evaluate a Term
  319.     Token t = ts.get();        // get the next token from token stream
  320.  
  321.     while(true) {
  322.         switch(t.kind) {
  323.         case '+':
  324.             left += term();    // evaluate Term and add
  325.             t = ts.get();
  326.             break;
  327.         case '-':
  328.             left -= term();    // evaluate Term and subtract
  329.             t = ts.get();
  330.             break;
  331.         default:
  332.             ts.putback(t);     // put t back into the token stream
  333.             return left;       // finally: no more + or -: return the answer
  334.         }
  335.     }
  336. }
  337.  
  338. //------------------------------------------------------------------------------
  339.  
  340. double declaration()
  341.     // handle: name = expression
  342.     // declare a variable called "name" with the initial value "expression"
  343. {
  344.     Token t = ts.get();
  345.     if (t.kind != name) error ("name expected in declaration");
  346.     string var_name = t.name;
  347.  
  348.     Token t2 = ts.get();
  349.     if (t2.kind != '=') error("= missing in declaration of ", var_name);
  350.  
  351.     double d = expression();
  352.     define_name(var_name,d);
  353.     return d;
  354. }
  355.  
  356. //------------------------------------------------------------------------------
  357.  
  358. double statement()
  359. {
  360.     Token t = ts.get();
  361.     switch (t.kind) {
  362.     case let:
  363.         return declaration();
  364.     default:
  365.         ts.putback(t);
  366.         return expression();
  367.     }
  368. }
  369.  
  370. //------------------------------------------------------------------------------
  371.  
  372. void clean_up_mess()
  373. {
  374.     ts.ignore(print);
  375. }
  376.  
  377. //------------------------------------------------------------------------------
  378.  
  379. void calculate()
  380. {
  381.     while (cin)
  382.       try {
  383.         cout << prompt;
  384.         Token t = ts.get();
  385.         while (t.kind == print) t=ts.get();    // first discard all "prints"
  386.         if (t.kind == quit) return;        // quit
  387.         ts.putback(t);
  388.         cout << result << statement() << endl;
  389.     }
  390.     catch (exception& e) {
  391.         cerr << e.what() << endl;        // write error message
  392.         clean_up_mess();
  393.     }
  394. }
  395.  
  396. //------------------------------------------------------------------------------
  397.  
  398. int main()
  399. try {
  400.     // predefine names:
  401.     define_name("pi",3.1415926535);
  402.     define_name("e",2.7182818284);
  403.  
  404.     calculate();
  405.  
  406.     keep_window_open();    // cope with Windows console mode
  407.     return 0;
  408. }
  409. catch (exception& e) {
  410.     cerr << e.what() << endl;
  411.     keep_window_open("~~");
  412.     return 1;
  413. }
  414. catch (...) {
  415.     cerr << "exception \n";
  416.     keep_window_open("~~");
  417.     return 2;
  418. }
  419.  
  420. //------------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement