#### Новшества в компиляторе и препроцессоре

##### Многозначные/многоязычные строки в RUN-TIME

CLIP предоставляет средства для разработки многоязычных программ и контролирования значений строк в RUN_TIME. Здесь и ниже под термином "language" подразумеваются не только "язык", а и другие причины, по которым необходимо организовать перегрузку строк. Например это может быть: "пользователь","время дня","квалификация пользователя" (бухгалтерам желательно выдавать сообщение "нажмите самую большую клавишу", а остальным "Нажмите любую клавишу"), а также другие критерии по вашему усмотрению.
В качестве примера приводится часть исходников из prg/samples с комментариями.

    //file: prg/samples/multilang.prg
    #define s1 [Hello world]     // keyword1
    #define s2 [Good bye world]  // keyword2
    // All strings enclosed in [] delimiters are localized keywords

    ? "Locale module name is:",__CLIP_MODULE__
    // __CLIP_MODULE__ is compile time predefined, it depends on -E compile switch
    ? "Default string1 is:",s1
    ? "Default string2 is:",s2
    ?
    ? "Install external data from lang1/ml1.mo:"
      ?? loadModuleMsg(__CLIP_MODULE__,"./locale.mo/lang1/"+__CLIP_MODULE__+".mo")
    ? "String1 for lang1 is:",s1
    ? "String2 for lang1 is:",s2
    ?
    ? "Install external data from lang2/ml1.mo:"
      ?? loadModuleMsg(__CLIP_MODULE__,"./locale.mo/lang2/"+__CLIP_MODULE__+".mo")
    ? "String1 for lang2 is:",s1
    ? "String2 for lang2 is:",s2

    ?
    return

    #file: prg/samples/Makefile
    # [ some defines skipped ]
    # CLIP_LOCALE_ROOT defines path where to save modules
    CLIP_LOCALE_ROOT=./
    export CLIP_LOCALE_ROOT
    # [ other targets skipped ]
    multilang: multilang.prg
    	$(CLIP) $(CLIPFLAGS) -e -M -E CLIP_MODULE="ml1" multilang.prg $(CLIPLIBS)
    	clip_msgmerge
    	clip_msgfmt

    #output from make processing
    /home/uri/prg/samples > make multilang
    /m2/uri/cliproot/bin/clip -a -O -b -e -M -E CLIP_MODULE="ml1" multilang.prg
    parsing file 'multilang.prg' ..
    open locale file './/locale.pot/ml1/multilang.pot'
    # at this moment keyword1 and keyword2 are moved to external pot-file
    .. done (23/2643 lines, 0 warnings, 1.47s)
    writing file 'multilang.c' .... done, 3546 bytes ,0.00s
    compile file 'multilang.c' .... done, 0.21s
    generate reference file 'multilang_ref.c' .... done, 0.04s
    make file 'multilang' .... done, 0.33s
    clip: 2 files, 2.05s
    # at this moment we create two or more directories (one per language)
    # compiler does not know how many languages will your app support,
    # so we need do it once. A new target language could be added at any time.
    # mkdir ./locale.po/lang1
    # mkdir ./locale.po/lang2
    clip_msgmerge
    # generate editable po-modules templates from pot-files
    use locale root ./
    module ml1
    locale lang1 ... OK.
    locale lang2 ... OK.
    # at this moment we edit files (translate keywords from english to
    # desired language). You will need to edit them next time as soon
    # as new keywords will be added to application.
    # vi ./locale.po/lang1/ml1.po
    # vi ./locale.po/lang2/ml1.po
    clip_msgfmt
    # generate loadable mo-modules
    use locale root ./
    locale lang1
    module ml1
    locale lang2
    module ml1

Все слова начинающиеся на HASH_, препроцессор переводит в hashstr("HASH_....."). Нам это нужно, для того чтобы уменьшить количество включаемых (#include) файлов. И вместо того чтобы писать

            #define HASH_asdf   12345678
            #define HASH_qwerty 231423534

и т.п., теперь можно просто в тексте программы использовать ключевые слова HASH_...., например:

            do case
            	case HASH_asdf
                    case HASH_qwerty
                    ....
            endcase

И, при этом, можно быть уверенным, что если в разных prg-файлах попадется набор символов HASH_asdf, то результат будет одинаков, как если бы это слово было бы объявлено через #define.

Препроцессор умеет доставать данные из окружения, например:

            #define $USER

будет фактически странслировано в

            #define uri

В частности, можно использовать переменную окружения CLIP_LANG для изменения языка, на котором говорят clip-библиотеки. Например:

            export CLIP_LANG=LANG_RUSSIAN

имеются предопределенные препроцессором #define:

    	__FILE__
    	__BASE_FILE__
    	__LINE__
    	__VERSION__
    	__CLIP__
    	__SYSTEM__
    	__DATE__
    	__TIME__

Появилась команда препроцессора #xdefine - это то же самое, что и #define, но не чувствительна к регистру объявляемого имени макроса.

Конфигурацию ключиков можно прописать в файл .cliprc, и положить этот файл в домашний или текущий каталог.

В дополнение к std.ch можно прописать еще несколько автоматически подключаемых заголовочных файлов, прописав в .cliprc-файле строчки типа:

     -U std.ch
     -U clip.ch
     -U config.ch

Ключики компилятора не совсем соответствуют стандартному Клиппер-компилятору. Формулировки ошибок и предупреждений компилятора совсем не соответствуют. Но я не думаю, что это несоответсвие доставит большие неприятности.

Компилятор умеет перекодировать исходные тексты в разные русские кодировки во время компиляции. Т.е. вы можете писать программы в DOS, и без всяких ухищрений собирать программы в UNIX. Единственное ограничение - имена файлов должны быть в нижнем регистре.

##### Компилятор умеет генерировать

- PO-файлы - псевдокод или продвинутые кодовые блоки - небольшой размер, быстрая компиляция, возможность загружать в run-time, медленное выполнение. Легко декомпилируются, но самого декомпилятора пока нет.
- С-программы - размер в 2-3 раза больше чем у PO, долго компилируются из С в объектные модули, работают на 30-50% быстрее чем PO, легко управляются штатными средствами С-разработчика, не подлежат декомпиляции. Но все-таки ручное кодирование более эффективно, как по размеру, так и по скорости выполнения. Так что если вам нужны быстродействующие функции - пишите их на С, или напишите нам что вам нужно, а мы напишем на С.
- C+PO-программы - псевдокод обернутый в С-программу - быстро компилируются. Имеют маленький размер, медленно работают, но зато управляются стандартными средствами С-разработчика. Декомпиляция теоретически возможна, но намного сложнее чем декомпиляция PO-файлов.
- Программы с использованием динамически загружаемых библиотек (-s). Для примера почитайте о clip_run.

O-файлы собираются в библиотеки стандартными библиотекарями.

PO-файлы собираются в библиотеки утилитой clipar.

Изменена формулировка команды GET, раньше она вызывала встроенную функцию _GET_, а теперь GETNEW с добавленными параметрами.

Теперь можно в run-time загружать псевдокод (кодовые блоки) из файлов, например делается файл mylib.prg, в котором

       func myfunc1
       return 1
       func myfunc2
       return 2

делается команда

       clip -p mylib.prg,

в результате рождается файл mylib.po с псевдокодом внутри.
А во время работы любой программы можно написать:

       load("mylib.po")
       ? myfunc1()
       ? myfunc2()

В довесок к outdev, outerr сделан еще один поток вывода информации - в log-файл.

        SET(_SET_LOGLEVEL,num_level) // задает уровень отладки
        SET(_SET_LOGFILE,filename)   // задает имя log-файла, если не задано,
                                        то весь вывод будет направлен в
                                        <имя_программы>.log
        OUTLOG(level, <list ,,,>)    // если level не указан или
        				    первым параметром указано не число,
        				    то данная информация будет выводиться
        				    в log-файл ВСЕГДА не зависимо от
        				    текущего уровня отладки.

Для прикладного логгирования используйте уровни 1-3, 4 уровень дает информацию о вызываемых функциях, скомпилированные как байт-код, 5 уровень выводит информацию о всех вызываемых функциях.
Примечание - log-файл не удаляется, так что позаботьтесь об этом сами.

Для пояснения и в качестве рекомендаций - я бы использовал

- 0 уровень - кто и когда запускал программу, errorsys, вызов критических операций типа индексации и "перерасчет зарплаты".
- 1 уровень - какие пункты меню вызывались, какие крупные модули программы использовались
- 3 уровень - анализ критических по времени процедур, анализ деятельности пользователей и подобное, печать документов, доступ к "секретным" данным, и т.п.

© Ю.Хныкин, uri@itk.ru, 2000