The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

B.5 Генерация отчётов — report.awk

B.5 Генерация отчётов — report.awk

Предыдущая  Содержание  Следующая V*D*V

report.awk содержит функции для загрузки отчёты из файлов и генерации выходных данных из отчётов. Это единственный модуль, который выполняет распечатку в поток стандартного вывода; поэтому отслеживание номеров строк происходит в этом модуле. Доступна простая функция puts(), чтобы распечатать строку с символом перевода строки.

Отчёты загружаются вызовом loadReports() с указанием имени файла для загрузки отчётов из него. Чтобы упростить отладку, отчёты не могут быть перезаписаны.

Отчёты генерируются вызовом gen() с указанием имени отчёта. Приложены определённое усилия, чтобы избежать эмиссии начальных пробелов или более, чем одной пустой строки подряд: глобальная переменная newLine равна 0 в крайнем левом положении или 1, как только что-то было распечатано; внутренняя функция lf() распечатывает перевод строки и уменьшает newLine на 1. Пробелы добавляются только если newLine равна 1, то есть если мы внутри строки. Переводы строк добавляются только если newLine не -1, то есть если только что не был сделан перевод строки.

Генерация отчёта основывается на нескольких простых наблюдениях: очень просто прочитать строки отчёта, использовать split(), чтобы разделить их на слова используя одиночные пробелы или знаки табуляции, и сохранить их в большом массиве Token[]. Другой массив Report[] содержит для каждого имени отчёта индекс его первого слова в Token[]. Внутренняя функция endReport() проверяет, что количество фигурных скобок в каждом отчёте сбалансировано, и завершает каждый отчёт дополнительной закрывающей фигурной скобкой.

Если одиночный пробел или символ табуляции используется в качестве символа разделения, и если мы генерируем единственный пробел для пустого слова, отчёт сильно похож на сгенерированный вывод: два пробела представляют один пробел на выходе. Генерация будет достаточно эффективна, если мы сможем быстро идентифицировать слова, которые будут оставлены без изменений (они не начинаются с одинарного обратного апострофа), и если у нас есть быстрый способ искать замены (они хранятся в массиве Replace[], проиндексированного по словам, которые будут заменяться). Элементы Replace[] главным образом установлены функциями, определёнными в parse.awk, которые просматривают базу данных: setClass(), setMethod() и setDeclarator() устанавливают информацию, описанную в таблице в конце страницы руководства ooc в разделе C.1.

Группы реализовать просто. При чтении строк отчёта после каждого слова, начинающегося с `{, то есть в начале каждой группы, мы сохраняем индекс слова после соответствующей `}, то есть индекс после окончания группы. Это требует поддержания стека открытых фигурных скобок, но этот стек может быть сохранён в тех же местах, где мы позже сохраним индексы соответствующих закрывающих фигурных скобок.

Генератор отчётов работает рекурсивно. Содержание группы интерпретируется вызовом genGroup(), который возвращается при достижении закрывающей фигурной скобки. В цикле можно сделать так много вызовов, как необходимо, и в конечном счёте мы продолжаем выполнение до следующего индекса позиции после группы. На глобальном уровне каждый отчёт завершается одним дополнительным маркером закрывающей фигурной скобки. Группы `{if так же просты:

 

OOC_Report_Generation_-_report_1

 

Если сравнение удаётся, мы рекурсивно выполняем группу. В любом случае выполнение продолжается после группы. Для `{else у нас есть следующее расположение:

 

OOC_Report_Generation_-_report_2

 

Если сравнение удаётся, рекурсивно выполняем его группу. Впоследствии мы можем следовать за обоими индексными значениями, или можем принять меры к тому, чтобы группа `{else всегда пропускалась, когда с нею встречаются непосредственно. Если сравнение не удаётся, и если индекс после `{if указывает на `{else, мы переходим к `{else и рекурсивно выполняем эту группу. Впоследствии мы проследуем за индексом, как обычно.

Маркер завершения `} может содержать произвольный текст после фигурной скобки. Однако есть два особых случая. Цикл по параметрам метода вызывает genGroup() с дополнительным параметром more, установленным в 1, пока всё ещё есть необработанные параметры метода. Если more установлен, genGroup() выдаёт запятую и пробел для завершающего маркера `},. Это упрощает генерацию списков параметров.

Другим специальным маркером завершения является `}n, который приводит к дополнительному переводу строки, если было выведено что-нибудь для группы. genGroup() возвращает значение истинности, указывающее, был ли он завершен маркером `}n, или нет. Такие функции, как genLoopMethods(), которые управляют циклом вызовов genGroup(), возвращают значение genGroup(), если был вход в цикл и ложь в противном случае. Наконец, genGroup() выдаст обязательный дополнительный перевод строки, если функция цикла возвратит истину, то есть если был вход в цикл и он завершился `}n. Это упрощает размещение блоков в сгенерированном коде.

Модуль отладки report.dbg принимает имя файла, например c.rep, и загружает отчёты из этого файла. Если  имя отчёта будет допустимым, он выведет на экран отчёт посимвольно. Если all или reports, покажет все отчёты.

 

Предыдущая  Содержание  Следующая