1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | // Code derived from Stroustrup's PPP2 book
// § 6.4 Grammars
// -and beginning on p 191
//------------------------------------------------------------------------------
/*
Parsing the expression 2 + 3
(read from bottom up):
Expression
^
A simple expression grammar |
---------+--------
| | |
Expression: Expression | |
Term ^ | |
Expression "+" Term // addition | | |
Expression "–" Term // subtraction | | |
| | |
Term: Term | Term
Primary ^ | ^
Term "*" Primary // multiplication | | |
Term "/" Primary // division | | |
Term "%" Primary // remainder (modulo) | | |
| | |
Primary: Primary | Primary
Number ^ | ^
"(" Expression ")" // grouping | | |
| | |
Number: | | |
floating-point-literal | | |
2 + 3
*/
//------------------------------------------------------------------------------
#include <iostream>
using std::cin;
using std::cout;
// a simple user-defined type
class Token {
public:
Token(char ch) : kind{ch} {}
Token(char ch, double val) : kind{ch}, value{val} {}
char kind = '0';
double value = 0.0;
};
//------------------------------------------------------------------------------
Token get_token()
{
char ch;
cin >> ch; // note that >> skips whitespace (space, newline, tab, etc.)
switch (ch) {
case ';':
case '+': // addition-only for this example
return Token{ch}; // let each character represent itself
case '2': // handle the digits 2 or 3 (only) for this example:
case '3': { //
cin.putback(ch); // put digit back into the input stream
double val;
cin >> val; // read a floating-point number
return Token{'8', val};
}
default: return Token{'K'}; // 'K' is invalid
}
}
//------------------------------------------------------------------------------
double expression(); // addition only
double term(); // pass-thru
double primary(); // number only
//------------------------------------------------------------------------------
// Note: this is a greatly-simplified (but working) example, to demonstrate the
// grammar call-chain involved in parsing the basic expression of four tokens:
//
// 2 + 3 ;
//
// -the idea is to simplify function internals enough for easy comprehensibility
int main()
{
cout << "enter: 2+3; \n";
cout << expression() << '\n';
}
double expression()
{
double left = term(); // read and evaluate a Term
Token t = get_token(); // get the next token from cin
switch (t.kind) { // see which kind of token that is
case '+':
return left + expression(); // read and evaluate an Expression,
// then do an add
default: return left; // return the value of the Term
}
}
double term()
{
double left = primary(); // read and evaluate a Primary
return left;
}
// just return the number, for this example
double primary()
{
Token t = get_token();
switch (t.kind) {
case '8': // we use '8' to represent a number
return t.value; // return the number's value
default: return 0.0;
}
}
|
build & run:
g++ -std=c++20 -O2 -Wall -pedantic ./ch_06/main_p191.cpp && ./a.out