//
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