https://rentry.org/PPP2_p195

// Code derived from Stroustrup's PPP2 book
// § 6.4.2 Writing a grammar
//  -and beginning on p 195

//------------------------------------------------------------------------------
/*

List:
    "{" Sequence "}"

Sequence
    Element
    Element " , " Sequence

Element:
    "A"
    "B"

*/
//------------------------------------------------------------------------------

#include <iostream>
#include <stdexcept>
#include <string>

using std::cerr;
using std::cin;
using std::cout;
using std::exception;
using std::runtime_error;
using std::string;

void error(std::string const& s) { throw runtime_error(s); }

//------------------------------------------------------------------------------

// a simple user-defined type
class Token {
 public:
  Token(char ch) : kind{ch} {}

  char kind = '0';
};

//------------------------------------------------------------------------------

class Token_stream {
 public:
  Token_stream();  // make a Token_stream that reads from cin

  Token get();             // get a Token
  void  putback(Token t);  // put a Token back

 private:
  bool  full;    // is there a Token in the buffer?
  Token buffer;  // here is where we keep a Token put back using putback()
};

Token_stream::Token_stream() : full{false}, buffer{0}  // no Token in buffer
{
}

Token Token_stream::get()
{
  if (full) {  // do we already have a Token ready?
    // remove token from buffer:
    full = false;
    return buffer;
  }

  char ch;
  cin >> ch;

  switch (ch) {
    case '{':
    case '}':
    case ',':
    case 'A':
    case 'B': return Token{ch};  // let each character represent itself
    default:
      cout << "  === in Token_stream::get() ch = '" << ch << "'\n";
      return Token{'K'};  // invalid
  }
}

// The putback() member function puts its argument back into the Token_stream's
// buffer:
void Token_stream::putback(Token t)
{
  buffer = t;     // copy t to buffer
  full   = true;  // buffer is now full
}

//------------------------------------------------------------------------------

bool        listing();
std::string sequence();
std::string element();

Token_stream ts;  // provides get() and putback()

//------------------------------------------------------------------------------

// Note: this is an example to demonstrate parsing the expression of these
// eleven tokens:
//      { A , A , A , A , B }
//
// -the idea is to use the functions together to analyze if the input string is
// a valid List, according to the grammar given above.

int main()
try {
  cout << "enter:  {A, A, A, A, B}\n";

  bool valid = listing();
  if (valid)
    cout << "  :  this is a valid list\n";

} catch (exception& e) {
  cerr << "error: " << e.what() << '\n';
  return 1;

} catch (...) {
  cerr << "Oops: unknown exception!\n";
  return 2;
}

bool listing()
{
  string left = "";  // begin with empty slate

  Token t = ts.get();  // get the first Token from the Token stream
                       //
  switch (t.kind) {    // see which kind of token it is
    case '{':          // handle "{" Sequence "}"
      left += "{ ";

      left += sequence();

      t = ts.get();

      if (t.kind != '}') {
        cout << left << '\n';
        error(" '}' expected");
        return false;  // shouldn't reach here

      } else {
        left += " }";
        cout << left;
        return true;
      }
      break;
    default:
      error("unexpected type in listing : '" + string{t.kind} + "'");
      return false;  // shouldn't reach here
  }
}

std::string sequence()
{
  string left = element();

  Token t = ts.get();

  while (true) {
    switch (t.kind) {  // see which kind of token it is
      case ',':        // handle Element " , " Sequence
        left += ", ";
        left += sequence();
        return left;
        break;
      case '}':
        ts.putback(t);
        return left;
        break;
      default:
        error("unexpected next token in sequence : '" + string{t.kind} + "'");
        return "foo";  // shouldn't reach here
    }
  }
}

std::string element()
{
  Token t = ts.get();

  switch (t.kind) {  // see which kind of token it is
    case 'A':
    case 'B': return string{t.kind}; break;
    default:
      error("unexpected type in element : '" + string{t.kind} + "'");
      return "foo";  // shouldn't reach here
  }
}

build & run:

g++ -std=c++20 -O2 -Wall -pedantic ./ch_06/main_p195.cpp && ./a.out

PrevUpNext

Edit
Pub: 17 Mar 2023 06:45 UTC
Edit: 02 May 2023 20:54 UTC
Views: 861