Страница произведения
Войти
Зарегистрироваться
Страница произведения

Фокал - часть 3 (пишется)


Автор:
Опубликован:
24.05.2026 — 24.05.2026
Читателей:
1
Аннотация:
Типа продолжение к "Фокал снаружи и внутри"
Предыдущая глава  
↓ Содержание ↓
↑ Свернуть ↑
  Следующая глава
 
 

шаблон и генерирующий. Если первый сопоставился с неким фрагментом строки1, то

он заменяется на фрагмент сгенерированный вторым по образчику. Например так

можно найти (и выделить) в строке S слово Вася (но только одно): S/"Вася" или

даже любое слово на В состоящее из русских буковок: S/"В*%р" — найдётся и

Вася и Ваня и Вагонетка (а вот от слова ВАННА — только первая буква В). Или

можно (из хулиганских побуждений) заменить все буквы Е на Э (и заглавные и

строчные), чтобы получилось как у Великого Комбинатора на пишущей машинке с

турецким акцентом: S*"ЕЭеэ" ("Значит, по Вашему я — начальник отдЭлЭния?

Свинья Вы, Шура после этого!"(Ц))

И вот тут — на общем случае генерирующих шаблонов, мы и приплыли! Нет, с

простыми частными случаями (например замена всех заглавных букв на строчные:

S*"%Р%р%Л%л" и русских и латинских) более-менее всё понятно. Но нам же хочется

самый общий! А в общем случае может быть что угодно. В частности оные шаблоны

(они же регулярные выражения) с помощью двух видов скобочек: () обозначающих

последовательность и [] — выбор, могут вкладываться друг в дружку на любую

глубину, в точности так же как выражения арифметические. (Конструкция (...)

срабатывает если последовательно сопоставились все находящиеся внутри шаблоны,

а [...] — если хотя бы один.) И всё это еще и с учетом префиксов повторения.)

Ну и что с этим делать? В смысле — как реализовать? Чтобы прояснить этот

вопрос, книжку пришлось писать. ("Фокал снаружи и внутри".) По принципу: не

знаешь сам — объясни другому! Глядишь, и у тебя самого в голове малость

прояснится. И таки да — помогло: с такого разбега, хотя и не с первой попытки,

но проблему генерирующих шаблонов я таки забодал...


* * *

А про ёлку-то ты не забыл, боярин дубовый?! (Ц)

У нас же типа пересказ, что там было в первой серии. А даже "канон" еще

не весь изложил!

А что осталось? Ну буквально же один аспект — про функцию, определяемую

пользователем. И, да — еще хотя бы перечислить операторы и функции:

Comment — коментарий: ничего не делает, игнорируется всё до конца строки

собственно вычисления

Set переменная = выражение; — присваивает значение выражения переменной

Xecut выражение; — только вычисляет, результат — теряется

(Надо бы eXecut — "выполнить", да буква Е занята под более важный Eraze.)

ввод/вывод

Аск список ввода; — ввод

Type список вывода; — вывод

Operate устройство; — переключение каналов ввода/вывода

обслуживание программы

Write номер_строки_или_группы; — вывод текста программы

Eraze номер_строки_или_группы; — удаление

Modify номер_строки_или_группы; — исправление (чтобы заново не вводить)

управление

Go номер_строки_или_группы; — безусловная передача управления

If (условие) N1, N2, N3; — условная передача управления

Do номер_строки_или_группы; — передача управления подпрограмме

Ret — возврат из подпрограммы

Quit — прекращение выполнения

For переменная = нач, кон, шаг; тело цикла до конца строки — цикл

дополнительно

? и ?? — включение/выключение трассировки и пошагового режима

Break — установить реакцию на внешнее событие

Kill — устроить такое событие, или хотя бы системный сброс

Vizual — нечто графическое

! командная строка операционной системы — обращение к ОС

Help ключевое_слово — справка

а так же

Load — подгрузить дополнительные функции (до сих пор не реализовано)

Provide — выделить место под очень большой массив (тоже не реализовано)

Job номер_строки_или_группы; — запустить впараллель (только планируется)

Да, это смесь того что сейчас есть, раньше было и возможно еще будет...

А функции...

математические: FSQrt FExp FLOg — корень, Е в степени Х, логарифм

FSIn FCOS FTAn — тригонометрические

FASin FACos FATan — обратные к ним

преобразования чисел: FABs FSGn — модуль, знак

FItr FMOd — целая и дробная часть числа

специальные: FRnd — генератор случайных чисел

FCHr — посимвольный ввод/вывод

FCLk — отсчет временных интервалов

FX — обращение к управляющим регистрам внешних устройств

FSBr — обращение к подпрограмме как к функции

Все подпрограммы что в Фокале что в Бейскике — "процедуры". Параметры, если

они им нужны, получают через глобальные переменные. (А они — все глобальные.)

Через них же, если что, могут вернуть результат. Но есть ситуации, когда

необходима именно функция, которую можно было бы вызвать из середины выражения.

Функция как раз и отличается от процедуры тем, что возвращает результат так,

что его можно сразу использовать для дальнейшего вычисления этого выражения.

Да и параметры (они же аргументы) в этом случае должны быть подвыражениями

того же выражения. И в Фокале и в Бейсике для этого есть "функция, определяемая

пользователем".

В Бейсике она объявляется заранее с помощью оператора DEF и вызывается

с помощью встроенной функции FNх где "х" первая буква имени, указанного при

объявлении. (Напоминаю: в те поры и переменные в Бейсике тоже распознавались

только по одной первой букве их имени.)

В Фокале для тех же целей — функция FSUbroutine (что значит "подпрограмма"),

но заранее ничего не объявляется: первый аргумент FSUb указывает куда передать

управление, а второй передаётся в качестве параметра — присваивается

спецпеременной с именем & которая может быть только одна, увы.

Но я в своей реализации разрешил передавать не один, а любое, произвольное

количество параметров. Которые становятся начальными значениями по-настоящему

локальных переменных с именами &0 (она же просто &), &1, &2, &3... К которым

к тому же можно обращаться как к одномерному массиву &[i]... И к тем же самым

переменным, равняясь на UNIX`овский sh, разрешил обращаться: $0, $1, $2... $[i]

(а на самом деле далеко не сразу вспомнил, как же в Фокале называется эта

чертова переменная — параметр подпрограммы).

Самое интересное здесь — как возвращается результат? Самое логичное, если

бы в качестве результата FSBr возвращалось то значение, которое вычислено в

операторе возврата из подпрограммы Ret. (Все и всегда так делают!) Ан,

фокаловскому оператору Ret выражение не положено. (Хотя я у себя разрешил.)

Более того — этого самого Ret может и не быть: "естественная подпрограмма"

вернёт управление и так — по достижении её конца... Оказалось, что

результатом FSBr становится значение последнего выражения, вычисленного перед

возвратом из вызванной ею подпрограммы. Вычисленное в любом операторе, в том

числе Xecut, который результат вроде как теряет...

Получается, что где-то в недрах Фокала есть скрытая переменная (назовём её

"аккумулятором" или А1), куда попадает результат любого выражения. Вот что там

оказалось на момент возврата, то и возвращается!

Намотаем это на ус: оказывается, Фокал страдает аккумуляторностью!

А1 — первый из обнаруженных аккумуляторов, но не единственный: потом были еще

найдены А2 и А3.

Если усов пока нет — можно приклеить или даже нарисовать.

А что касается глобальности/локальности переменной &, то она значима только

если из подпрограммы, вызванной с помощью FSBr мы вызовем еще такую же — тоже с

передачей ей параметра. Например пишем в командной строке:

1.1 t &; x fsbr(1.2, 222222); t & !

1.2 t &

x fsbr(1.1,111111);

Что будет напечатано? Если (как у меня): 111111 222222 111111 то

переменная & по-настоящему локальная, а если: 111111 222222 222222 то нет.

И тогда фигу нам с маком, а не рекурсия...

Рекурсия, это когда подпрограмма вызывает самоё себя, прямо или косвенно.

Полезная штука, совершенно необходимая для обхода дерева. Не путешествия

вокруг берёзы или например сосны, а что-то типа разбора арифметического

выражения: дерево здесь это граф без циклов, каковым это выражение удобно

представляется: операции — вершины (узлы), связи их с операндами — веточки, а

сам такой операнд — либо листик, если это константа или переменная, либо тоже

узел, если это подвыражение, заключенные в скобочки. Или обращение к функции

с параметрами, для вычисления которых тоже задействованы подвыражения. Самая

первая вершина, из которой и растёт дерево, принято называть "корнем". Вот

например для: 1+2+3 или 1+(2+3) или (a+1)*(b-2)/c^3 или -sin(x)+cos(2*x)

+ + / +

дерево: ┌┴┐ ┌┴┐ ┌──┴──┐ ┌──┴──┐

+ 3 1 + * ^ — cos

┌┴┐ ┌┴┐ ┌─┴─┐ ┌┴┐ │ │

1 2 2 3 + — c 3 sin *

┌┴┐ ┌┴┐ │ ┌┴┐

Ха, все деревья — корнями вверх! a 1 b 2 x 2 x

Соорудить нечто подобное можно и здесь, в Фокале. Да, ни структур ни

ссылок нету... (Вершины обычно изображаются структурами, а веточки — ссылками

из них друг на друга...) Ну и что? Массивы-то у нас здесь — динамические! Ну

для разбора выражения надо со строками и/или отдельными символами работать...

(Тоже можно, но пока сложно и громоздко получится.) А вот пусть нам вводят

числа, а мы должны их запоминать (это запросто: массивы то — динамические),

а вот как все ввели — мы должны выдать их в отсортированном порядке!

Вот такая задачка. Основная проблема здесь — узнать, что числа кончились.

А вот пусть среди них не может быть числа ноль. Вернее ноль — обязательно

последний. Да, можно тупо запоминать числа в элементы массива, а потом, перед

выдачей, просто отсортировать его. Ну хотя бы методом "пузырька"...

1.1 T "вводите числа, 0 — последнее"!; S N=-1;

1.2 S N=N+1; A x[N]; If(x[N]) 1.2, 1.3, 1.2

1.3 If(N) 1.4,1.4; D 2; D 3; T !"Всё."!; Q

1.4 t "Чего же сразу-то ноль? Сортировать нечего!"!; Q

2.1 S j=0; C сортировка методом пузырька — самая тривиальная...

2.2 S j=j+1; S k=0; F i=0,N-j,1; S y=x[i]; If(x[i+1]-y) 2.7;

2.3 If(-k) 2.2; R; C k — признак, что хоть одну пару переставили местами

2.7 S x[i]=x[i+1]; S x[i+1]=y; S k=k+1; C вот как раз это обмен такой пары

3.1 F i=0,N; T x[i]; C тупо выдаём содержимое массива как есть

...Но мы будем сортировать их сразу в процессе получения: строить

бинарное дерево. Корень — всегда нулевой элемент массива (то есть самое первое

полученное число); m[] и b[] указывают на поддеревья, где все числа меньше и

больше вот этого, а -1 там означает что таковых пока нет. (Ибо номера

элементов массива — с нуля.)

1.1 T "вводите числа, 0 — последнее"!; S N=-1;

1.2 A y; D 2; If(y) 1.2, 1.3, 1.2; C помещение в массив вынесли в группу 2

1.3 If(N) 1.4,1.4; X FSBr(3,0); T !"Всё."!; Q

1.4 t "Чего же сразу-то ноль? Вот даже выдавать нечего..."!; Q

C не только x[]=y но и ссылки на поддеревья устанавливаем...

2.1 S N=N+1; S x[N]=y; S m[N]=-1; S b[N]=-1; S i=0; If(-N)2.2; R;

2.2 S z=x[i]-y; S j=b[i]; I(z) 2.3; S j=m[i]

C то же самое на Си: j = (y>=x[i]) ? b[i] : m[i]; по-моему куда понятней!

2.3 If(j) 2.4; S i=j; G 2.2; C спуск по дереву линейный — можно без рекурсии

2.4 If(z) 2.5; S m[i]=N; R; C очередное число повесим как "листик"

2.5 S b[i]=N; R;

C Вот он — обход дерева с помощью рекурсии. Почти в одну строчку...

3.1 If(&) 3.2; X FSBr(3,m[&]); T x[&]; X FSBr(3,b[&]);

3.2 R

Надо ли тут чего разжевывать, или и так всё понятно? Ну разве что — что

квадратные скобки при обращении к массиву — выпендрёж чистой воды: это не Си,

можно любые... Впрочем, и построение бинарного дерева вместо сортировки вот для

такой задачки — тоже выпендрёж. А вот его обход (уж коли у нас дерево) — нет:

он возможен только рекурсией. (Но штука таки дорогая — стэк жрет неумеренно...)

Но обычно в качестве примера на рекурсию все и всегда приводят вычисление

факториала: произведения всех чисел от 1 до N (что обычно обозначается как N!)

потому что видите-ли: (N+1)! = (N+1)*N! Они что — опухли?! Здесь дерево

вырождается в линейную последовательность, для обхода которой достаточно

обычного цикла. Однако вместо того, чтобы написать:

s X=1; f i=2,N,1; s X=X*i; C и всё: X==N! — осталось только напечатать

t N,"! = ",X

и поискать другой, более содержательный пример, сооружают нечто типа:

4.1 if(1-&)4.2; x 1; r

4.2 x &*fsbr(4,&-1); r

t N,"! = ",fsbr(4,N)

Как ни странно, это будет работать, даже если переменная & не локальная.

А вот если бы написали не &*fsbr(...) а fsbr(...)*& — вот тогда нет! Понятно,

почему?

Разумеется, у меня локальные переменные тоже создаются автоматически в

момент первого присваивания. Но уничтожаются при выходе из подпрограммы. При

этом становится доступным предыдущий комплект, если он был. Кроме того, если

данная локальная переменная не существует — это не ошибка, как для глобальной:

она ищется в предыдущих комплектах, а если так и не найдена — то будет ноль.


* * *

И вот теперь, когда с "каноном" — "базовым", исходным Фокалом, надеюсь,

всё более-менее понятно, краткое содержание первой части сего опуса.

(Напоминаю: опус это сам Фокал-1А.)

Всё вышеописанное я либо просто воспроизвёл (сохранив и то, что обычно

считают недостатками: всего два значащих символа в имени переменной и "вето"

на букву Ф), либо немножко модернизировал. Прежде всего уточнил и дополнил

концепцию ввода/вывода, в том числе в части взаимодействия с файловой

системой ОС. Ну и так, кое-что по-мелочи — разные удобства и красивости:

— оператор Help для получения справок; просмотрщик к нему (аналог

UNIX`овского more) чтобы их с удобством просматривать; "экранный" редактор

командной строки со всяческими прибамбасами, чтобы с удобствами её набирать.

Или править с помощью оператора Modify. Работающего поэтому только и

исключительно с терминалом, независимо от того куда направлены каналы ввода и

вывода.

— вот эти самые по-настоящему локальные переменные — как позиционные

параметры при вызове подпрограммы с помощью FSUbr, так и сами по себе. И плюс

к ним — произвольное количество параметров не только у FSUbr но и у других

встроенных функций (де лишние будут просто игнорироваться). А так же

возможность пропуска параметра или параметр в виде текстовой константы — для

расширения функциональности без увеличения количества этих самых встроенных

функций. Например FSQrt(X) — просто квадратный корень, а FSQrt(X,N) — корень

N-ой степени; FLOg(X) — логарифм натуральный, а FLOg(X,N) — по основанию N.

Или суровая и опасная функция FX( действие, адрес, параметр ) производящая

действия с управляющими регистрами внешних устройств (каковых действий всего

12345 ... 121314
Предыдущая глава  
↓ Содержание ↓
↑ Свернуть ↑
  Следующая глава



Иные расы и виды существ 11 списков
Ангелы (Произведений: 91)
Оборотни (Произведений: 181)
Орки, гоблины, гномы, назгулы, тролли (Произведений: 41)
Эльфы, эльфы-полукровки, дроу (Произведений: 230)
Привидения, призраки, полтергейсты, духи (Произведений: 74)
Боги, полубоги, божественные сущности (Произведений: 165)
Вампиры (Произведений: 241)
Демоны (Произведений: 265)
Драконы (Произведений: 164)
Особенная раса, вид (созданные автором) (Произведений: 122)
Редкие расы (но не авторские) (Произведений: 107)
Профессии, занятия, стили жизни 8 списков
Внутренний мир человека. Мысли и жизнь 4 списка
Миры фэнтези и фантастики: каноны, апокрифы, смешение жанров 7 списков
О взаимоотношениях 7 списков
Герои 13 списков
Земля 6 списков
Альтернативная история (Произведений: 213)
Аномальные зоны (Произведений: 73)
Городские истории (Произведений: 306)
Исторические фантазии (Произведений: 98)
Постапокалиптика (Произведений: 104)
Стилизации и этнические мотивы (Произведений: 130)
Попадалово 5 списков
Противостояние 9 списков
О чувствах 3 списка
Следующее поколение 4 списка
Детское фэнтези (Произведений: 39)
Для самых маленьких (Произведений: 34)
О животных (Произведений: 48)
Поучительные сказки, притчи (Произведений: 82)
Закрыть
Закрыть
Закрыть
↑ Вверх