// Purpose.  Interpreter                private:
//                                         C c;  D d;
// Define a grammar for a language,     };
// and map each rule to a class.
                                        class Acti { public:
#include <iostream.h>                      int eval( char* i, char* o ) {
#include <string.h>                           if (e.eval(i,o)) return 1;
                                              if (f.eval(i,o)) return 1;
int sub(char* i, char* o, char* c) {          return 0; }
   strcat(o, c);  strcpy(i, &(i[1]));   private:
   return 1; }                             E e;  F f;
                                        };
class A { public:                       class Pass { public:
   int eval( char* i, char* o ) {          int eval( char* i, char* o ) {
      if (i[0] == 'a')                        if (g.eval(i,o)) return 1;
         return sub(i,o,"1");                 if (h.eval(i,o)) return 1;
      return 0; } };                          return 0; }
class B { public:                       private:
   int eval( char* i, char* o ) {          G g;  H h;
      if (i[0] == 'b')                  };
         return sub(i,o,"2");
      return 0; } };                    class NP { public:
class C { public:                          int eval( char* i, char* o ) {
   int eval( char* i, char* o ) {             if (arti.eval(i,o))
      if (i[0] == 'c')                           if (noun.eval(i,o)) return 1;
         return sub(i,o,"3");                 return 0; }
      return 0; } };                    private:
class D { public:                          Arti arti;  Noun noun;
   int eval( char* i, char* o ) {       };
      if (i[0] == 'd')                  class Verb { public:
         return sub(i,o,"4");              int eval( char* i, char* o ) {
      return 0; } };                          if (acti.eval(i,o)) return 1;
class E { public:                             if (pass.eval(i,o)) return 1;
   int eval( char* i, char* o ) {             return 0; }
      if (i[0] == 'e')                  private:
         return sub(i,o,"5");              Acti acti;  Pass pass;
      return 0; } };                    };
class F { public:
   int eval( char* i, char* o ) {       class Sent { public:
      if (i[0] == 'f')                     int eval( char* i, char* o ) {
         return sub(i,o,"6");                 if (np.eval(i,o))
      return 0; } };                             if (verb.eval(i,o)) return 1;
class G { public:                             return 0; }
   int eval( char* i, char* o ) {       private:
      if (i[0] == 'g')                     NP np;  Verb verb;
         return sub(i,o,"7");           };
      return 0; } };
class H { public:                       void main( void )
   int eval( char* i, char* o ) {       {
      if (i[0] == 'h')                     Sent S;  char* t[] = {"ace","bdh",
         return sub(i,o,"8");                            "abc","ceg","bcfgh"};
      return 0; } };                       char  i[10], o[10];
                                           for (int j=0; j < 5; j++) {
class Arti { public:                          strcpy(i,t[j]); strcpy(o,"");
   int eval( char* i, char* o ) {             cout << i << " is ";
      if (a.eval(i,o)) return 1;              if ( ! S.eval(i,o) || i[0])
      if (b.eval(i,o)) return 1;                 cout << "bad" << endl;
      return 0; }                             else
private:                                         cout << o << endl; }
   A a;  B b;                           }
};
class Noun { public:                    // ace is 135
   int eval( char* i, char* o ) {       // bdh is 248
      if (c.eval(i,o)) return 1;        // abc is bad
      if (d.eval(i,o)) return 1;        // ceg is bad
      return 0; }                       // bcfgh is bad



// Purpose.  Interpreter design pattern demo (with Template Method)
//
// Discussion.  Uses a class hierarchy to represent the grammar given
// below.  When a roman numeral is provided, the class hierarchy validates
// and interprets the string.  RNInterpreter "has" 4 sub-interpreters.
// Each sub-interpreter receives the "context" (remaining unparsed string
// and cumulative parsed value) and contributes its share to the processing.
// Sub-interpreters simply define the Template Methods declared in the base
// class RNInterpreter.
//   romanNumeral ::= {thousands} {hundreds} {tens} {ones}
//   thousands, hundreds, tens, ones ::= nine | four | {five} {one} {one} {one}
//   nine ::= "CM" | "XC" | "IX"
//   four ::= "CD" | "XL" | "IV"
//   five ::= 'D' | 'L' | 'V'
//   one  ::= 'M' | 'C' | 'X' | 'I'

#include <iostream.h>
#include <string.h>

class Thousand;  class Hundred;  class Ten;  class One;

class RNInterpreter {
public:
      RNInterpreter();          // ctor for client
      RNInterpreter( int ) { }  // ctor for subclasses, avoids infinite loop
      int interpret( char* );   // interpret() for client
      virtual void interpret( char* input, int& total ) {   // for internal use
            int  index;  index = 0;
            if ( ! strncmp(input, nine(), 2)) {
                  total += 9 * multiplier();
                  index += 2; }
            else if ( ! strncmp(input, four(), 2)) {
                  total += 4 * multiplier();
                  index += 2; }
            else {
                  if (input[0] == five()) {
                        total += 5 * multiplier();
                        index = 1; }
                  else index = 0;
                  for (int end = index + 3 ; index < end; index++)
                        if (input[index] == one())
                              total += 1 * multiplier();
                        else break; }
            strcpy( input, &(input[index])); }  // remove leading chars processed
protected:  // cannot be pure virtual because client asks for instance
      virtual char  one()        { }            virtual char* four() { }
      virtual char  five()       { }            virtual char* nine() { }
      virtual int   multiplier() { }
private:
      RNInterpreter*  thousands;                RNInterpreter*  hundreds;
      RNInterpreter*  tens;                     RNInterpreter*  ones;
};

class Thousand : public RNInterpreter {
public:  // provide 1-arg ctor to avoid infinite loop in base class ctor
      Thousand( int ) : RNInterpreter(1) { }
protected:
      char  one()        { return 'M'; }  char* four() { return ""; }
      char  five()       { return '\0'; } char* nine() { return ""; }
      int   multiplier() { return 1000; }
};

class Hundred : public RNInterpreter {
public:
      Hundred( int ) : RNInterpreter(1) { }
protected:
      char  one()        { return 'C'; }  char* four() { return "CD"; }
      char  five()       { return 'D'; }  char* nine() { return "CM"; }
      int   multiplier() { return 100; }
};

class Ten : public RNInterpreter {
public:
      Ten( int ) : RNInterpreter(1) { }
protected:
      char  one()        { return 'X'; }  char* four() { return "XL"; }
      char  five()       { return 'L'; }  char* nine() { return "XC"; }
      int   multiplier() { return 10; }
};

class One : public RNInterpreter {
public:
      One( int ) : RNInterpreter(1) { }
protected:
      char  one()        { return 'I'; }  char* four() { return "IV"; }
      char  five()       { return 'V'; }  char* nine() { return "IX"; }
      int   multiplier() { return 1; }
};

RNInterpreter::RNInterpreter() {  // use 1-arg ctor to avoid infinite loop
      thousands = new Thousand(1);        hundreds = new Hundred(1);
      tens      = new Ten(1);                   ones     = new One(1); }

int RNInterpreter::interpret( char* input ) {
      int  total;  total = 0;
      thousands->interpret( input, total );
      hundreds->interpret( input, total );
      tens->interpret( input, total );
      ones->interpret( input, total );
      if (strcmp(input, ""))  // if input was invalid, return 0
            return 0;
      return total; }


void main() {
      RNInterpreter interpreter;
      char          input[20];
      cout << "Enter Roman Numeral: ";
      while (cin >> input)
      {
            cout << "   interpretation is " << interpreter.interpret(input) << endl;
            cout << "Enter Roman Numeral: ";
      }
}

// Enter Roman Numeral: MCMXCVI
//    interpretation is 1996
// Enter Roman Numeral: MMMCMXCIX
//    interpretation is 3999
// Enter Roman Numeral: MMMM
//    interpretation is 0
// Enter Roman Numeral: MDCLXVIIII
//    interpretation is 0
// Enter Roman Numeral: CXCX
//    interpretation is 0
// Enter Roman Numeral: MDCLXVI
//    interpretation is 1666
// Enter Roman Numeral: DCCCLXXXVIII
//    interpretation is 888