ミニ言語の構築ができる。
Composite とほぼ同じだがインタプリタの用途で使う特化したパターンらしい。 |
#include <stdio.h> // printf()
#include <deque> // STL std::deque<>
class CompositePtn // Composite パターン
// (InterpreterPtn とすべきですが…わざとです^^;)
{
public:
// 共通インターフェース(実行)
virtual int Interpret() = 0 ;
} ;
// 実装
class CommandValue : public CompositePtn
{
public:
char m_val ; // '0'〜'9'
virtual int Interpret() // 実行
{
return m_val - '0' ;
}
} ;
class CommandMul : public CompositePtn
{
public:
CompositePtn * m_left_value ;
CompositePtn * m_right_value ;
char * m_syntax ;
CommandMul()
{
// E -> E * F
m_syntax = "E -> E * F" ;
}
virtual int Interpret() // 実行
{
int l = m_left_value->Interpret() ;
int r = m_right_value->Interpret() ;
int a = l * r ;
printf( "interpret trace: %d = %d * %d\n", a, l, r ) ;
return a ;
}
} ;
class CommandDiv : public CompositePtn
{
public:
CompositePtn * m_left_value ;
CompositePtn * m_right_value ;
char * m_syntax ;
CommandDiv()
{
// E -> E / F
m_syntax = "E -> E / F" ;
}
virtual int Interpret() // 実行
{
int l = m_left_value->Interpret() ;
int r = m_right_value->Interpret() ;
int a = l / r ;
printf( "interpret trace: %d = %d / %d\n", a, l, r ) ;
return a ;
}
} ;
class CommandAdd : public CompositePtn
{
public:
CompositePtn * m_left_value ;
CompositePtn * m_right_value ;
char * m_syntax ;
CommandAdd()
{
// E -> E + E
m_syntax = "E -> E + E" ;
}
virtual int Interpret() // 実行
{
int l = m_left_value->Interpret() ;
int r = m_right_value->Interpret() ;
int a = l + r ;
printf( "interpret trace: %d = %d + %d\n", a, l, r ) ;
return a ;
}
} ;
class CommandSub : public CompositePtn
{
public:
CompositePtn * m_left_value ;
CompositePtn * m_right_value ;
char * m_syntax ;
CommandSub()
{
// E -> E - E
m_syntax = "E -> E - E" ;
}
virtual int Interpret() // 実行
{
int l = m_left_value->Interpret() ;
int r = m_right_value->Interpret() ;
int a = l - r ;
printf( "interpret trace: %d = %d - %d\n", a, l, r ) ;
return a ;
}
} ;
class StackTbl
{
// 処理中のコマンドと構文
std::deque< char > m_command_stack ;
std::deque< CompositePtn * > m_syntax_stack ;
// 確定した構文(delete 用)
std::deque< CompositePtn * > m_delete_tbl ;
public:
~StackTbl()
{
for ( int i=0 ; i<m_delete_tbl.size() ; ++i )
{
delete m_delete_tbl[i] ;
}
}
void CommandStackPut()
{
printf( "command_stack: " ) ;
int i = m_command_stack.size()-1 ;
for ( ; i>=0 ; --i )
{
printf( "%c, ", m_command_stack[i] ) ;
}
printf( "\n" ) ;
}
// 構文解析
template< class _Command >
bool Parse( _Command & in_cmd )
{
// _1234_6_8_
// "0 -> 5 7 9" ;
if ( m_command_stack.size() > 2
&& m_command_stack[2] == in_cmd.m_syntax[5]
&& m_command_stack[1] == in_cmd.m_syntax[7]
&& m_command_stack[0] == in_cmd.m_syntax[9]
)
{} else return false ; // NG
printf( "syntax trace : '%s'\n", in_cmd.m_syntax ) ;
// m_syntax に登録(CompositePtn の Tree を作成)
_Command * cmd = new _Command() ;
m_delete_tbl.push_back( cmd ) ; // delete 用
cmd->m_right_value = m_syntax_stack[0] ;
m_syntax_stack.pop_front() ;
cmd->m_left_value = m_syntax_stack[0] ;
m_syntax_stack.pop_front() ;
m_syntax_stack.push_front( cmd ) ;
// m_command を更新
m_command_stack.pop_front() ;
m_command_stack.pop_front() ;
m_command_stack[0] = in_cmd.m_syntax[0] ;
return true ; // OK
}
bool ParseValue()
{
if ( m_command_stack.size() > 0
&& m_command_stack[0] >= '0' // 数値
&& m_command_stack[0] <= '9' // 数値
)
{} else return false ; // NG
printf( "syntax trace : value %c\n", m_command_stack[0] ) ;
// m_syntax に登録(CompositePtn の Leaf を作成)
CommandValue * val = new CommandValue() ;
m_delete_tbl.push_back( val ) ; // delete 用
val->m_val = m_command_stack[0] ;
m_syntax_stack.push_front( val ) ;
// m_command を更新
m_command_stack[0] = 'F' ; // 数値 -> _F_
return true ; // OK
}
// E -> F
bool ParseEF()
{
if ( m_command_stack.size() > 0
&& m_command_stack[0] == 'F'
)
{} else return false ; // NG
m_command_stack[0] = 'E' ;
return true ; // OK
}
void CommandPush( char in )
{
m_command_stack.push_front( in ) ;
}
// 実行(最後に残った CompositePtn の根っこを実行)
int Interpret()
{
if ( m_command_stack.size() != 1
|| m_command_stack[0] != 'E'
)
{
puts( "syntax error" ) ;
return 0 ; // DUMMY
}
return m_syntax_stack[0]->Interpret() ;
}
} ;
// インタープリタ
int interpret( char * in_cmd )
{
StackTbl stack_tbl ;
CommandMul cmd_mul ;
CommandDiv cmd_div ;
CommandAdd cmd_add ;
CommandSub cmd_sub ;
// 構文解析
int size = strlen( in_cmd ) ;
int i = 0 ;
for ( ; ; ) // Hit しなくなるまで繰り返す
{
stack_tbl.CommandStackPut() ;
if ( stack_tbl.ParseValue() ) continue ;
if ( stack_tbl.Parse( cmd_mul ) ) continue ;
if ( stack_tbl.Parse( cmd_div ) ) continue ;
if ( stack_tbl.Parse( cmd_add ) ) continue ;
if ( stack_tbl.Parse( cmd_sub ) ) continue ;
// E -> F
if ( stack_tbl.ParseEF() )
{
// 先読み
// このままループに戻ると +, - が Hit してしまう。
// +, - より *, / を優先するため、
// 先読みして *, / がある場合は command_stack に積む。姑息ぅ
if ( i<size )
{
if ( in_cmd[i] == '*'
|| in_cmd[i] == '/'
)
{
stack_tbl.CommandPush( in_cmd[i] ) ;
for ( ++i ; in_cmd[i] == ' ' ; ) ++i ;
}
}
continue ;
}
// 次のコマンド
if ( i<size )
{
stack_tbl.CommandPush( in_cmd[i] ) ;
for ( ++i ; in_cmd[i] == ' ' ; ) ++i ;
continue ;
}
break ;
}
return stack_tbl.Interpret() ; // 実行
}
int main()
{
printf( "%d\n", interpret( "+" ) ) ;
printf( "syntax error\n" ) ;
printf( "%d\n", interpret( "1" ) ) ;
printf( "%d\n", 1 ) ;
printf( "%d\n", interpret( "1 + 2 * 3" ) ) ;
printf( "%d\n", 1 + 2 * 3 ) ;
printf( "%d\n", interpret( "1 + 2 + 3 + 4" ) ) ;
printf( "%d\n", 1 + 2 + 3 + 4 ) ;
printf( "%d\n", interpret( "1 - 2 - 3 - 4" ) ) ;
printf( "%d\n", 1 - 2 - 3 - 4 ) ;
printf( "%d\n", interpret( "1 + 2 - 3 + 4" ) ) ;
printf( "%d\n", 1 + 2 - 3 + 4 ) ;
printf( "%d\n", interpret( "1 + 2 * 3 + 4" ) ) ;
printf( "%d\n", 1 + 2 * 3 + 4 ) ;
printf( "%d\n", interpret( "1 * 2 + 3 * 4" ) ) ;
printf( "%d\n", 1 * 2 + 3 * 4 ) ;
printf( "%d\n", interpret( "2 * 3 * 4 * 5" ) ) ;
printf( "%d\n", 2 * 3 * 4 * 5 ) ;
printf( "%d\n", interpret( "9 / 3 / 2" ) ) ;
printf( "%d\n", 9 / 3 / 2 ) ;
printf( "%d\n", interpret( "3 * 9 / 6" ) ) ;
printf( "%d\n", 3 * 9 / 6 ) ;
return 0 ;
}
/* 実行結果
command_stack:
command_stack: +,
syntax error
0
syntax error
command_stack:
command_stack: 1,
syntax trace : value 1
command_stack: F,
command_stack: E,
1
1
command_stack:
command_stack: 1,
syntax trace : value 1
command_stack: F,
command_stack: E,
command_stack: E, +,
command_stack: E, +, 2,
syntax trace : value 2
command_stack: E, +, F,
command_stack: E, +, E, *,
command_stack: E, +, E, *, 3,
syntax trace : value 3
command_stack: E, +, E, *, F,
syntax trace : 'E -> E * F'
command_stack: E, +, E,
syntax trace : 'E -> E + E'
command_stack: E,
interpret trace: 6 = 2 * 3
interpret trace: 7 = 1 + 6
7
7
command_stack:
command_stack: 1,
syntax trace : value 1
command_stack: F,
command_stack: E,
command_stack: E, +,
command_stack: E, +, 2,
syntax trace : value 2
command_stack: E, +, F,
command_stack: E, +, E,
syntax trace : 'E -> E + E'
command_stack: E,
command_stack: E, +,
command_stack: E, +, 3,
syntax trace : value 3
command_stack: E, +, F,
command_stack: E, +, E,
syntax trace : 'E -> E + E'
command_stack: E,
command_stack: E, +,
command_stack: E, +, 4,
syntax trace : value 4
command_stack: E, +, F,
command_stack: E, +, E,
syntax trace : 'E -> E + E'
command_stack: E,
interpret trace: 3 = 1 + 2
interpret trace: 6 = 3 + 3
interpret trace: 10 = 6 + 4
10
10
command_stack:
command_stack: 1,
syntax trace : value 1
command_stack: F,
command_stack: E,
command_stack: E, -,
command_stack: E, -, 2,
syntax trace : value 2
command_stack: E, -, F,
command_stack: E, -, E,
syntax trace : 'E -> E - E'
command_stack: E,
command_stack: E, -,
command_stack: E, -, 3,
syntax trace : value 3
command_stack: E, -, F,
command_stack: E, -, E,
syntax trace : 'E -> E - E'
command_stack: E,
command_stack: E, -,
command_stack: E, -, 4,
syntax trace : value 4
command_stack: E, -, F,
command_stack: E, -, E,
syntax trace : 'E -> E - E'
command_stack: E,
interpret trace: -1 = 1 - 2
interpret trace: -4 = -1 - 3
interpret trace: -8 = -4 - 4
-8
-8
command_stack:
command_stack: 1,
syntax trace : value 1
command_stack: F,
command_stack: E,
command_stack: E, +,
command_stack: E, +, 2,
syntax trace : value 2
command_stack: E, +, F,
command_stack: E, +, E,
syntax trace : 'E -> E + E'
command_stack: E,
command_stack: E, -,
command_stack: E, -, 3,
syntax trace : value 3
command_stack: E, -, F,
command_stack: E, -, E,
syntax trace : 'E -> E - E'
command_stack: E,
command_stack: E, +,
command_stack: E, +, 4,
syntax trace : value 4
command_stack: E, +, F,
command_stack: E, +, E,
syntax trace : 'E -> E + E'
command_stack: E,
interpret trace: 3 = 1 + 2
interpret trace: 0 = 3 - 3
interpret trace: 4 = 0 + 4
4
4
command_stack:
command_stack: 1,
syntax trace : value 1
command_stack: F,
command_stack: E,
command_stack: E, +,
command_stack: E, +, 2,
syntax trace : value 2
command_stack: E, +, F,
command_stack: E, +, E, *,
command_stack: E, +, E, *, 3,
syntax trace : value 3
command_stack: E, +, E, *, F,
syntax trace : 'E -> E * F'
command_stack: E, +, E,
syntax trace : 'E -> E + E'
command_stack: E,
command_stack: E, +,
command_stack: E, +, 4,
syntax trace : value 4
command_stack: E, +, F,
command_stack: E, +, E,
syntax trace : 'E -> E + E'
command_stack: E,
interpret trace: 6 = 2 * 3
interpret trace: 7 = 1 + 6
interpret trace: 11 = 7 + 4
11
11
command_stack:
command_stack: 1,
syntax trace : value 1
command_stack: F,
command_stack: E, *,
command_stack: E, *, 2,
syntax trace : value 2
command_stack: E, *, F,
syntax trace : 'E -> E * F'
command_stack: E,
command_stack: E, +,
command_stack: E, +, 3,
syntax trace : value 3
command_stack: E, +, F,
command_stack: E, +, E, *,
command_stack: E, +, E, *, 4,
syntax trace : value 4
command_stack: E, +, E, *, F,
syntax trace : 'E -> E * F'
command_stack: E, +, E,
syntax trace : 'E -> E + E'
command_stack: E,
interpret trace: 2 = 1 * 2
interpret trace: 12 = 3 * 4
interpret trace: 14 = 2 + 12
14
14
command_stack:
command_stack: 2,
syntax trace : value 2
command_stack: F,
command_stack: E, *,
command_stack: E, *, 3,
syntax trace : value 3
command_stack: E, *, F,
syntax trace : 'E -> E * F'
command_stack: E,
command_stack: E, *,
command_stack: E, *, 4,
syntax trace : value 4
command_stack: E, *, F,
syntax trace : 'E -> E * F'
command_stack: E,
command_stack: E, *,
command_stack: E, *, 5,
syntax trace : value 5
command_stack: E, *, F,
syntax trace : 'E -> E * F'
command_stack: E,
interpret trace: 6 = 2 * 3
interpret trace: 24 = 6 * 4
interpret trace: 120 = 24 * 5
120
120
command_stack:
command_stack: 9,
syntax trace : value 9
command_stack: F,
command_stack: E, /,
command_stack: E, /, 3,
syntax trace : value 3
command_stack: E, /, F,
syntax trace : 'E -> E / F'
command_stack: E,
command_stack: E, /,
command_stack: E, /, 2,
syntax trace : value 2
command_stack: E, /, F,
syntax trace : 'E -> E / F'
command_stack: E,
interpret trace: 3 = 9 / 3
interpret trace: 1 = 3 / 2
1
1
command_stack:
command_stack: 3,
syntax trace : value 3
command_stack: F,
command_stack: E, *,
command_stack: E, *, 9,
syntax trace : value 9
command_stack: E, *, F,
syntax trace : 'E -> E * F'
command_stack: E,
command_stack: E, /,
command_stack: E, /, 6,
syntax trace : value 6
command_stack: E, /, F,
syntax trace : 'E -> E / F'
command_stack: E,
interpret trace: 27 = 3 * 9
interpret trace: 4 = 27 / 6
4
4
Press any key to continue
*/ |
|