Рассмотрим применение конечных автоматов на примере такой задачи, как удаление всех комментариев из текста программы на языке c++.
В файле могут быть комментарии типа:
Так же существуют строковые константы типа
В этих константах могут встречаться символы комментариев // или /* */,но комментарии в таком случае включаться не должны. Также в строковой константе может встретиться символ « », означающий спецсимвол, следующий после него (перевод строки, табуляцию и т. д.). Среди спецсимволов есть " и ´, которые не закрывают открытые кавычки, а должны выводится на экран (например: printf(" кавычки " и ´ "); ).
Для решения этой задачи через конечные автоматы определим все возможные состояния, в которых может находиться автомат:
enum STATE
{
STATE_BASIC, // 1. базовое состояние(обычный текст)
STATE_SLASHSTAR, // 2. комментарии типа /* вфывыфвфы */
STATE_SLASHSLASH, // 3. комментарии типа // авырпворп
STATE_SINGLEQUOTES, // 4. текст ´sadsadasdas´
STATE_DOUBLEQUOTES, // 5. текст "выфвыфвыф"
STATE_BASIC_SLASH, /* 6. состояние при первом слэше в базовом состоянии * /*/
STATE_SINGLEQUTES_SLASH, // 7. состояние при первом слэше в тексте внутри кавычек
STATE_DOUBLEQUOTES_SLASH, // 8. состояние при первом слэше в тексте внутри кавычек
STATE_SLASHSTAR_STAR // 9. состояние при звезде в комментариях типа /* */
};
Изобразим переходы состояний автомата в виде графа (рис. 1), в котором:
из 1 состояния автомат может перейти:
из 5 состояния автомат может перейти:
из 4 состояния автомат может перейти:
из 6 состояния автомат может перейти:
из 8 состояния автомат может перейти:
из 7 состояния автомат может перейти:
из 3 состояния автомат может перейти:
из 2 состояния автомат может перейти:
из 8 состояния автомат может перейти:
Получилась, практически, готовая программа. Осталось только при переходах из состояния в состояние добавить необходимые действия (в нашем случае, вывод символов в выходной файл, где надо).
Получившаяся программа:
#include
#include
#include
enum STATE
{
STATE_BASIC, // базовое состояние(обычный текст)
STATE_SLASHSTAR, // комментарии типа /* вфывыфвфы */
STATE_SLASHSLASH, // комментарии типа //
STATE_SINGLEQUOTES, // текст ´sadsadasdas´
STATE_DOUBLEQUOTES, // текст "выфвыфвыф"
STATE_BASIC_SLASH, /* состояние при первом слэше в базовом состоянии * /*/
STATE_SINGLEQUTES_SLASH, // состояние при первом слэше в тексте внутри кавычек
STATE_DOUBLEQUOTES_SLASH, // состояние при первом слэше в тексте внутри кавычек
STATE_SLASHSTAR_STAR // состояние при звезде в комментариях типа /* */
};
int main()
{
std::ifstream file_in;
std::ofstream file_out;
file_in.open("main.cpp");
if (!file_in)
{ std::cout << "Error // open "main.cpp"" << std::endl; return 1;
}
file_out.open( "main_out.cpp");
if (! file_out )
{ std::cout << "Error // open "main_out.cpp"" << std::endl; file_in.close(); return 1;
}
STATE state = STATE_BASIC; // начальное состояние
char ch; // текущий считанный из входного файла символ
while ( 1 )
{
file_in.get(ch);
if ( file_in.eof() )
{
if (state == STATE_BASIC_SLASH)
file_out.put( ´/´ ); // на случай если конец файла пришелся на состоние
// STATE_BASIC_SLASH и поэтому не напечатался символ "/"
break;
}
switch( state )
{
case STATE_BASIC:
switch(ch)
{
case ´"´: state = STATE_DOUBLEQUOTES; file_out.put( ch ); break;
case ´´´: state = STATE_SINGLEQUOTES; file_out.put( ch ); break;
case ´/´: state = STATE_BASIC_SLASH; break;
default: file_out.put( ch ); break;
}
break;
case STATE_BASIC_SLASH:
switch(ch)
{
case ´/´: state = STATE_SLASHSLASH; break;
case ´*´: state = STATE_SLASHSTAR; break;
default: file_out.put( ´/´ ); file_out.put( ch ); break;
}
break;
case STATE_DOUBLEQUOTES:
switch(ch)
{
case ´"´:
case ´ ´: state =STATE_BASIC; file_out.put( ch ); break;
case ´´: state =STATE_DOUBLEQUOTES_SLASH;file_out.put( ch );break;
default: file_out.put( ch ); break;
}
break;
case STATE_DOUBLEQUOTES_SLASH: state =STATE_DOUBLEQUOTES;file_out.put( ch ); break;
case STATE_SINGLEQUOTES:
switch(ch)
{
case ´´´:
case ´ ´: state = STATE_BASIC; file_out.put( ch ); break;
case ´´: state = STATE_DOUBLEQUOTES_SLASH; file_out.put( ch ); break;
default: file_out.put( ch ); break;
}
break;
case STATE_SINGLEQUTES_SLASH:
switch(ch)
{
case ´ ´: state = STATE_BASIC; file_out.put( ch ); break;
default: file_out.put( ch ); break;
}
break;
case STATE_SLASHSLASH:
switch ( ch )
{
case ´ ´: state = STATE_BASIC; file_out.put( ch ); break;
default: break;
}
break;
case STATE_SLASHSTAR:
switch ( ch )
{
case ´*´: state = STATE_SLASHSTAR_STAR; break;
default: break;
}
break;
case STATE_SLASHSTAR_STAR:
switch( ch )
{
case ´/´: state = STATE_BASIC; break;
default: state = STATE_SLASHSTAR; break;
}
break;
}
}
file_in.close();
file_out.close();
}
Преимуществом использования конечных автоматов является: