// Purpose. Interpreter private: // C c; D d; // Define a grammar for a language, }; // and map each rule to a class. class Acti { public: #include int eval( char* i, char* o ) { #include 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 #include 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