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

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


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

целей) решил сперва немножко развлечься — сделать слегка "доведенную до ума"

реализацию традиционного Фокала (назвав это Фокал-1А). Вот до сих пор и

развлекаюсь...

Идея там была вот какая: строка + строка это их сцепление ("конкатенация");

строка * число — это размножение строки, дублирование указанное числом

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

сомножителей... (Разница появляется если это самое "число раз" — не целое.)

Если же число отрицательное, то строка инвертируется. Унарный минус — чисто

инверсия строки (т.е. буковки в обратном порядке), а унарный плюс — получение

длины (т.е. результат — число). (А для комплексного числа унарный плюс это

получение комплексно-сопряженного.) Соответстенно деление строки на число это

её разрезание. Вернее — взять часть строки с указанного символа, которые

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

порядке (т.е. число / строка) можно — результат будет ноль или указанное

числом количество символов. Если число отрицательное, то с конца.

Вычитание строк это их сравнение: поиск позиции, с которой одна строка

входит в другую: числа в операторе If сравниваются именно так! Если вторая

строка "больше" — результат будет отрицательный, а если ни одна из них не

часть другой — то ноль.

Вычитание значения из самого себя это еще и возможность определить его тип:

для числа получится ноль, для строки — единица (она же сама в себя входит с

первой позиции!), а вот для "пустого" значения результат будет -1.

Это самое пустое значение при любых других операциях даёт ошибку, а содержится

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

параметр соответствующий её позиции.

Сложение и вычитание строки и числа я было хотел запретить — сделать чтобы

они давали ошибку, но если трактовать число как код символа и соответственно

числовое значение как односимвольную строку... Встроенная в Фокал функция FCHr

делает именно так, значит можно и тут.

Операция ^ и для чисел самая трудозатратная, так пусть такой же будет и

для строк: "полукорреляция" — сопоставление двух строк на предмет поиска общей

подстроки. Вернее самой длинной из них, буде совпадений окажется несколько.

А "полу" потому, что неполная. А то полная корреляция строки с собою найдёт её

всю целиком. (А то мы не знаем, что совпадает сама с собою!) Нам вообще-то надо

повторяющийся фрагмент: (S/2)^S (здесь мы в первом операнде отрезали от S

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

fmax(S1^S2,S2^S1).

Ну что можно сказать? Всё вроде бы логично, разве что, с одной стороны,

слишком много внимания не больно-то реально нужным реверсу строки и её

размножению (но это диктуют имеющиеся у нас операции), а с другой — всего этого

явно недостаточно: возможных действий со строками куда больше...

Например буковки бывают заглавные и строчные, а так же русские и латинские.

При сравнении двух строк (в том числе на полное равенство: (S1-S2)*(S2-S1)) в

одних случаях все их надо считать разными, а в других — совпадающими. Ну и как?

(Ввести некие внутренние признаки эквивалентности, устанавливать и сбрасывать

их некоторой спецфункцией? Некрасиво получается...) И это далеко не

единственное...

Вон в Бейсике ввели для работы со строками кучу функций, "поручив"

встроенным операциям только самое очевидное, типа конкатенации. Нам такого

щастья и даром не надь... Сложно, громоздко и необозримо даже с помощью

встроенной справочной системы.

В общем оставались у нас две "неокученные" операции: умножение и деление

строки на строку. Вот и решено было, что второй операнд в них — не простая

строка, а специальная — составленная по некоторым правилам. Строка1 / строка2

это будет сопоставление с шаблоном, а строка1 * строка3 — "перекодировка".

Здесь строка3 это последовательность ПАР шаблонов: включающих анализирующий

шаблон и генерирующий. Если первый сопоставился с неким фрагментом строки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 (что значит "подпрограмма":

"sub" это "под", а "routine" — рутина и есть!), но заранее ничего не

объявляется: первый аргумент 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 там означает что таковых пока нет. (Ибо номера

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



Иные расы и виды существ 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)
Закрыть
Закрыть
Закрыть
↑ Вверх