Как стать автором
Поиск
Написать публикацию
Обновить

Необычное использование препроцесора C

Недавно возникла задача написать документацию (user manual) к одному довольно большому проекту. Специфика задачи такова: необходимо сгенерировать много HTML файлов — около 600-700 для каждого языка (языков пока 8). Кроме того надо было дать набор фраз для перевода на другие языки – не будут же переводчики по 600-700 файлов переводить… Некоторые файлы похожи, некоторые отличаются, в целом их можно разделить на группы, хотя ни одного одинакового файла нет. Кроме того, надо иметь возможность поправить, к примеру, разметку всех страниц и т.п.

Немного подумав, начал писать свой формат «шаблонов» для этого дела и уже было начал генерировать файлы и набивать шаблоны. В процессе работы мой формат команд всё больше стал походить на команды препроцессора C, а возможностей стало не хватать, так что следующая идея родилась сама собой.
Решил я попробовать сам препроцессор C для своей задачи. Первое что попалось под руку — GNU ARM™ toolchain – для моей работы вещь незаменимая, поэтому всегда с собой – и дома и на работе. В общем, сгенерировал я тестовые файлики (см. ниже) и начал пробовать…

SRC\maintemplate.help
__TITLE__

__DATA__


SRC\DATA1\TEMPLATES\template1.help
#define __DATA__ Hello, world!
#define __TITLE__ Name: __EX_NAME_

SRC\DATA1\example1.help
#define __EX_NAME__ ABC
#include "TEMPLATES\template1.help"
#include "..\maintemplate.help"


Запускаем файл на препроцессор:
arm-elf-cpp SRC\DATA1\example1.help
После чего на выходе (stdout) имеем:

# 1 "SRC\\DATA1\\example1.help"
# 1 "<built-in>"
# 1 ""
# 1 "SRC\\DATA1\\example1.help"

# 1 "SRC\\DATA1\\/TEMPLATES\\template1.help" 1
# 3 "SRC\\DATA1\\example1.help" 2
# 1 "SRC\\DATA1\\/..\\maintemplate.help" 1
Name: ABC

Hello, world!

# 4 "SRC\\DATA1\\example1.help" 2

Имеем не совсем то, что хотели получить. Весь вид портит сервисная информация, надо бы её убрать… Ну, это же дело пяти секунд – на Delphi пишем маленькую утилитку – всего несколько строк:

{$APPTYPE CONSOLE}
var s:string;
begin
   while(not EOF(Input))do
    begin
    Readln(s);
    if(length(s)>0)and(s[1]<>'#')then writeln(s);
    end;
end.

И уже информацию на выходе препроцессора прогоняем через него:
arm-elf-cpp SRC\DATA1\example1.help|strip.exe
Результат работы:
Name: ABC

Hello, world!


Вуаля, всё готово. Осталось только «набить» мануалы, и автоматизировать весь процесс bat-файлом (для тех, кто не любит bat файлы – можно использовать make скрипт или ant-скрипт, но это уже тема для отдельной статьи).

SET SRCDIR=SRC\DATA1\
SET DSTDIR=DST\
arm-elf-cpp %SRCDIR%example1.help|strip.exe >%DSTDIR%example1.htm
arm-elf-cpp %SRCDIR%example2.help|strip.exe >%DSTDIR%example2.htm
arm-elf-cpp %SRCDIR%example3.help|strip.exe >%DSTDIR%example3.htm

Примечание 1:
Самый удобный вариант – финальную HTML разметку, общую для всех файлов, вынести в отдельный файл (в примерах он называется SRC\maintemplate.help). Тогда в конце каждого маленького файла, который описывает результирующий html документ, должна быть строка вроде этой:
#include "..\maintemplate.help"

Примечание 2:
Главным вопросом был русский (китайский/арабский) текст. Инструмент для этих целей подходит - UTF-8 работает на ура.

Примечание 3:
Очень не хватает многострокового #define, хотелось бы что-то вроде:
#multidefine
Some text, bla-bla-bla
Some text, bla-bla-bla
Some text, bla-bla-bla
#enddefine

Пока не знаю как решить этот вопрос (кроме варианта написания своего препроцессора), пользуюсь переносом строки (символ ’\’)

Примечание 4:
Минусы – Привязка к синтаксису препроцессора, но с этим у меня проблем не возникло – главное #define оглашать правильно. Привязанность к формату, отсутствие возможности генерации документов другого формата (PDF, RTF и т.п.). Как вариант – дополнительно использовать конвертеры.

P.S. В статье я описал лишь пример, реально же структура каталогов и файлов у меня немного другая, что впрочем, не столь важно. Кроме того я активно использую условную компиляцию и сложные инструкции #define, что раскрывает все возможности данного инструмента, но если сильно углубляться, то статья получится раздутой, так что начинающим в помощь:
ru.wikipedia.org/wiki/Препроцессор_Си
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.