Скриптовые языки и обработка текстов

Лекция читается также для слушателей курса кафедры АЯ «Парадигмы программирования».

Базис

Алгоритм + структура данных = программа.

  • (примем это за рабочую гипотезу)
  • Текстовое представление исходных кодов программ — для человека

  • Произвольное представление исходных данных — только для роботов?

Тезиc

Данные тоже должны быть текстовыми

  • (примем это за рабочую гипотезу)
  • Текстовый поток управления; пример: команды и командная строка

  • Текстовые пространства имён данных; пример: экспансия файлового подхода, /proc

  • По возможности — текстовые денные; пример: конфигурационные файлы, XPM

    • Вариант — преобразованные в текст; пример hexdump

Антитезис

Что же, всё теперь руками делать?

  • Основной элемент командной строки ОС —­программа. Программа сама себя не запустит, и результатов своей работы не обработает!
  • Предположим, исходные данные не текстовые. Мы их преобразовали в текст, посмотрели, а дальше что?

Синтез

Пускай текст управляет текстом!

  • Языки склейки и алгоритмически полные командные интерпретаторы
    • Более точно: язык склейки (скриптовой) — язык программной манипуляции интерфейсами прикладной среды.
    • В нашем случае — текстовыми

      • Конкретный случай: unix shell, в котором в качестве среды выступает множество утилит (программ) и файлы.

  • Всевозможные языки обработки текстов:
    • Языки контекстной обработки (например, основанные на регулярных выражениях)
    • Макрообработка

Выглядит как план целого С/К, правда?

Командная оболочка

Глава из учебника Unix shell как язык склейки:

  1. Среда: утилиты и файлы *nix-подобной системы
  2. Интерфейс — командная строка
    • В действительности, современный шелл (например, bash) — ЯП, интерпретатор командной строки и язык склейки одновременно

Особенности:

Кроме того:

Контекстная обработка

Нужно много инструментов по обработке текстов!

Регулярное выражение

(нужно не менее лекции, так что не сейчас)

Макроподстановка

Задача: параметризовать текст.

Самый популярный вариант — препроцессор Си и другие макронадстройки над языками.

M4

Чуть ли не единственный из известных.

Принцип:

Вот этот текст разумный http://mbreen.com/m4.html

Примеры просьба прощёлкивать! Если нет linux под рукой — можно воспользоваться любым online linux-окружением, например http://repl.it. При открытии редактора там в правой части запускается натуральная linux-консоль.

В ней можно запустить m4, но лучше что-нибудь вроде cat > o; echo "===="; m4 < o, чтобы ввод и вывод не перемешивались. Ввод заканчивается новой строкой и Ctrl+D для обозначения конца файла.

Макроопределение и макроподстановка

define(AUTHOR, W. Shakespeare)
`AUTHOR' is AUTHOR

define(AUTHOR, Me)
define(AUTHOR, A. Maclean)
`AUTHOR' is AUTHOR or Me?

define(AUTHOR, W. Shakespeare)
define(AUTHOR, A. Maclean)
`AUTHOR' is AUTHOR

define(`AUTHOR', Me)dnl
define(`AUTHOR', A. Maclean)dnl
`AUTHOR' is AUTHOR or Me?

Вложенность кавычек

define(`definenum', `define(`num', `99')')
num
definenum
num

define(`definenum', define(`num', `99'))
num

Условные операторы

ifdef()

Только на сопоставление

define(`a', b)dnl
ifelse(a, b, c, d)
ifelse(a, B, c, d)

define(`a', d)dnl
define(`e', b)dnl
ifelse(a, b, b-true, c, c-true, d, d-true, all-false)
ifelse(e, b, b-true, c, c-true, d, d-true, all-false)

Типы данных

translit(`Highgest leet of all', `etl', 371)

Параметрические макросы и циклы

Параметры — это просто $№ в теле макроподствновки

define(`NONTERM', non-terminal)dnl
define(`param', `All: $*
All-quoted: $@
Number: $#; Second: $2')dnl
param(one, two by two, NONTERM, three)
param(`one', `two by two', `NONTERM', `three')

Цикл == рекурсия!

Остальные циклы (forloop, foreach cмоделированы в соотв. библиотеках)

Потоки вывода

Часть текста можно перенаправить в синтетический поток, по окончании работы M4 они припишутся в конец в порядке нумерации (0 — основной поток)

one
divert(3)dnl
two
three
divert(1)dnl
four
five
divert(0)dnl
six
seven

Поток -1 не направляется никуда (а определённые макросы остаются!), а ещё поток можно закрыть и вставить по месту с помощью undivert()

divert(-1)
Здесь можно писать что угодно
значение имеют только макроопределения
define(`c', > $1)
divert(0)dnl
c(выхожу один)
divert(1)dnl
c(я на дорогу)
divert(0)dnl
c(сквозь туман)
undivert(1)dnl
тернистый путь блестит

Далее везде…

Фактически, декларативный алгоритмически полный язык

Потоковый редактор sed

Общая структура программы список инструкций вида:

Контекстный адрес:

Команды:

Примеры:

Алсо, полнота по Тюрингу повсюду

AWK

Общая структура программы список инструкций вида:

Команды реализуют Си-подобный синтаксис

Контекстный адрес:

Примеры:

GAWK

Примеры

Фактически, полноценный ЯП, на котором бы много писали, если бы не …

Perl

Не пойдём дальше Википедии

???

Особенности Linux

Autoconf и m4

Д/З

  1. Попробовать немного примеров по m4, sed и gawk (по ссылкам в плане есть изрядно примеров). Прочитать последнее замечание в плане этой лекции

  2. Взять любой проект из домашних заданий, содержащий более одного файла на Си (например, .c и .h) и использующий autotools для сборки.

    • Пользуясь тем, что configure.ac — shell-скрипт с m4-макросами, добавить туда код на шелле, который для всех .h и .c файлов будет добавлять в начало каждого строку вида

        /* COMMENT:: Полное название программы, версия: дата */
      если её там нет, и обновлять её (заменять на новую), если она там есть,
      • …а также будет выводить эту строку на стандартный вывод.
      • Всё это, разумеется, происходит при запуске ./configure

    • (Подсказка. Для начала можно отладить внешний сценарий, который заменяет/подставляет в начало какую-нибудь строку вида /* COMMENT::…*/)

    • Можно пользоваться sed -i или awk -i inplace (пример в конце описания), grep, если не получится, то вообще чем угодно из стандартного окружения.

    • Строка Полное название программы, версия: дата генрируется из соответствующих макросов AC_INIT, поэтому этот сценарий надо оформить как include-файл для configure.ac или просто вписать этот код в конец configure.ac

    • Убедиться, что полученная конструкция работает и не ломает сборку
  3. Поместить очищенный от генератов проект (по идее в нем будет изменён configure.ac и, возможно, добавлен include-файл для него) в подкаталог 12_ScriptingText целевого репозитория

  4. Как примерно должно выглядеть решение:
    • Файл insver.sh: отладочный вариант, который подставляет/заменяет в .h и .c файлах строку /* COMMENT::…*/ (пока только с текущей датой, с помощью `date`):

      •    1 $ grep 'MSG=' insver.sh
           2 MSG="COMMENT:: `date`"
           3 $ head -2 *.c *.h
           4 ==> cats.c <==
           5 #include <stdio.h>
           6 #include <glib.h>
           7 
           8 ==> kitty.c <==
           9 #include "cats.h"
          10 #include "config.h"
          11 
          12 ==> cats.h <==
          13 #ifndef _MYMODULE_CAT_H_
          14 #define _MYMODULE_CAT_H_
          15 
          16 $ sh insver.sh
          17 COMMENT:: Сб дек  5 12:28:12 UTC 2020
          18 $ head -2 *.c *.h
          19 ==> cats.c <==
          20 /* COMMENT:: Сб дек  5 12:28:12 UTC 2020 */
          21 #include <stdio.h>
          22 
          23 ==> kitty.c <==
          24 /* COMMENT:: Сб дек  5 12:28:12 UTC 2020 */
          25 #include "cats.h"
          26 
          27 ==> cats.h <==
          28 /* COMMENT:: Сб дек  5 12:28:12 UTC 2020 */
          29 #ifndef _MYMODULE_CAT_H_
          30 
          31 $ sh insver.sh
          32 COMMENT:: Сб дек  5 12:28:54 UTC 2020
          33 
          34 $ head -2 *.c *.h
          35 ==> cats.c <==
          36 /* COMMENT:: Сб дек  5 12:28:54 UTC 2020 */
          37 #include <stdio.h>
          38 
          39 
        
    • Добавим туда макросы, которые определяются в configure.ac. Теперь если запустить insver.sh, в комментарии попадут нераскрытые макросы.

    • У нас два пути:
      1. Объявить файл шаблоном в AC_CONFIG_FILES(), переименовать в insver.sh.in и добавить в строку подстановки макросы для имени и версии. В configure.ac вписать запуск генерата

      2. Добавить в строку подстановки переменные shell, в которые эти макросы раскрываются, и за-include-ить его прямо в конец configure.ac

        • В autoconf открывающая и закрывающая кавычки переименованы в «[» и «]» (не используйте их в сценарии), а директива M4 include() — в m4_include()

    • Получится примерно следующее:
         1 $ grep AC_INIT configure.ac
         2 AC_INIT([GLib/GObject examples], [0.0], [george@altlinux.org])
         3 $ autoreconf -fisv
         4 
         5 $ ./configure
         6 
         7 COMMENT:: GLib/GObject examples, 0.0: Sat Dec  5 12:58:44 UTC 2020
         8 $ head -2 cats.c
         9 /* COMMENT:: GLib/GObject examples, 0.0: Sat Dec  5 12:58:44 UTC 2020 */
        10 #include <stdio.h>
      

LecturesCMC/LinuxApplicationDevelopment2020/12_ScriptingText (последним исправлял пользователь FrBrGeorge 2020-12-05 16:01:30)