Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Непейвода Н.Н. -> "Основания программирования " -> 206

Основания программирования - Непейвода Н.Н.

Непейвода Н.Н., Скопин И.Н. Основания программирования — Институт компьютерных исследований , 2002. — 919 c.
Скачать (прямая ссылка): osnovanprogramm2002.pdf
Предыдущая << 1 .. 200 201 202 203 204 205 < 206 > 207 208 209 210 211 212 .. 316 >> Следующая

10.2. ПОДСЧЕТ ДЛИН СЛОВ
587
• Как поступать в конце процесса? Чтение заключительного символа ('\n') должно прекращать возможные попытки последующего обращения к чтению. Следовательно, нужно позаботиться о завершающих переходах. В предлагаемой программе принято решение о завершающем переходе к нулевой строке, которая, согласно преддуему, является нестандартной.
Следует подчеркнуть, что данные соглашения не являются абсолютными, и поставленные вопросы нуждаются в решении всякий раз, когда реализуется переход от табличного представления к программе.
С учетом сделанных замечаний программа, решающая задачу подсчета длин строк методом интерпретации таблиц , мо ет быть записана следу -им образом.
Программа 10.2.8 Длины слов: интерпретатор конечного автомата
#include <stdio.h> char symbol; int cnt;
// переменная для чтения потока символов // переменная для счета длин слов
int c0(), c1(), c2(); //
void a0(), a1(), a2(), a3(); //
int handler ( int i ); struct T_StructTableLine {
int (*condition)(); void (*action)(); int ref;
функции-условия функции-действия обработчик строк таблиц
поле для имени состояния избточно поле условия поле действия
поле перехода: индекс строки таблицы, которая будет обрабатываться следующей, или признак заверения процесса
T_StructTableLine
Table[]={ {c0,a0,1},// таблица инициализируется статически,
{c1,a1,4}, // альтернативное решение — специальная
{c2,a0,1}, // функция задания начальных значений.
{c0,a0,0}, // Оно более гибкое, но менее
{c1,a2,4}, // эффективно.
{c2,a3,1}, // О наглядности см. комментарий
{c0,a3,0}}; // в тексте.
}
588
ГЛАВА 10. МЕТОДЫ ПРОГРАММИРОВАНИЯ ОТ СОСТОЯНИЙ
void main() {
int iSt=0; do {
iSt = handler ( iSt ); }
while (iSt);
}
int handler ( int i ) {
if (Table[i].condition()) { Table[i].action();
if (Table[i].ref) symbol = getchar (); return Table[i].ref; } else return ++i;
}
//Описания используемых функций: int c0(){return true;}
int c1(){return 'a'<=symbol && symbol <= 'z';} int c2(){return symbol != '\n';}
void a0(){}
void a1(){printf ("%c", symbol);cnt= 1;} void a2(){printf ("%c", symbol);cnt++;} void a3(){printf ("- %i\n", cnt);}
10.2.6. Обсуждение решения
Как уже говорилось, функция подразумевает выделение памяти (в стеке), следовательно, вызовы Table[i].condition() и Table[i].action() нарушают теоретический постулат о том, что конечному автомату не требуется динамическая память. Но фактически здесь нет никакого противоречия:
• Во-первых, теоретическое "не требуется" совсем не обязательно долж-но буквально реализовваться. апротив, на кадом уровне требу тся свои средства.
10.2.
589
• Во-вторых, не искл чается, что транслятор, проанализировав транслируемый текст, сможет построить код, который учитывает фактические режимы работы функций, и, как следствие, будут заменены вызовы функций на пряме переходы к ну нм фрагментам.
• В-третьих, при елании мо но бло отказаться от задания условий и действий функциями, а вместо этого составить специальне "неиспол-няемые" фрагменты и задать переход к ним взамен взовов. ослед-ний путь — ручное кодирование предыдущей возможности и, в то же время, реализация ранее указанного подхода (см. пункт e) на стр. 586).
а первй взгляд мо ет показаться, что задача оптимизации вызовов в С/С++/С# системах программирования решается с помощью прагматической директивы inline. В самом деле, использование встраиваемых (inline) функции имеет цель подмену вызова размеением кода тела функции в точке взова.
днако в данном случае это не приведет к елаемому: компилятору просто некуда вставлять код функции, а потому директива inline будет проигнорирована.
Если только что отмеченные недостатки метода автоматического встраивания таблиц в программы мо но считать не очень значительными, то следующая критика уже принципиальна. Более того, приводимые далее замечания ну но рассматривать в качестве баз для развития подхода в целом и выработки адекватного технологического (и значит, в определенном смысле универсального) метода.
Как у е отмечалось, фрагменты, описваие условия и действия в таблице конечного автомата и реализованне как процедурне вставки, с точки зрения препроцессора (не препроцессора систем программирования, а специального преобразователя, генерируего представление таблицы для интерпретации) являются нераспознаваемыми данными, которые он просто пропускает без изменений для другой обработки С-компилятором. нтер-претатор е, наоборот, не в силах сам исполнять процедуры, а потому трактует сслки на них (в соответствуих полях) как данне. Таким образом, условия и действия в таблице двойственн : они явля тся одновременно и данными, и программными фрагментами. Автоматический преобразователь таблиц , не понимая языка таких двойственнх данных, пытается, тем не менее, их объединить с обычными данными (в рассматриваемом случае это индекс строк переходов) в одной структуре.
а первй взгляд ка ется, что ситуация суественно упростилась бы в языке, в котором есть возможность воспринимать данные как выполнимые
Предыдущая << 1 .. 200 201 202 203 204 205 < 206 > 207 208 209 210 211 212 .. 316 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100