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

Руководство по Фокалу


Автор:
Жанр:
Изобретательство
Опубликован:
22.04.2025 — 23.04.2025
Читателей:
1
Аннотация:
Нет описания
Предыдущая глава  
↓ Содержание ↓
↑ Свернуть ↑
  Следующая глава
 
 

там начальными значениями её локальных переменных.

Что оператор Do передаёт управление указанной в нём строке точно, а Go и

If — примерно. И если строки с точно таким номером нет — это для них не ошибка.

Что оператор Ret может содержать одно выражение, которое так же как в Xecut

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

Ну разве что наглядно видно, что возвращается — вот это. И еще гарантия, что

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

значение в аккумуляторе. Может — реакция на событие: (см.(3)) она выполняется

"вне очереди" между операторами, но (вроде бы) А1 сохраняет.

Что оператор ! так же как и во многих утилитах UNIX`а позволяет обратиться

к операционной системе: весь остаток строки — это её команда. Можно например

удалить файл (!del имя_файла): создать то его Фокалу запросто, а удалять не

умеет. Можно перебраться в другой каталог (!cd имя_каталога); можно посмотреть

его содержимое (!dir). А можно запустить например Волков-Командер (!vc) — чтобы

лазить по каталогам с удобствами. А в нём еще и просмотрщик, и текстовый

редактор... ДосНавигатор (dn) запустить скорее всего не удастся — памяти

не хватит. И НортонКомандер (nc) скорее всего тоже. А вот шедевр товарища

Волкова — вполне.

Что оператор Coment игнорирующий всё до конца строки, может нынче

начинаться не только с буквы Ц, но и с "букв" @ # $ & ~ | :

В том же самом UNIX`е есть такое полезное правило, что если выполняемый файл

начинается с символов #! то дальше идёт текстовая строка, указывающая как

запустить программу, которая и будет этот файл выполнять. (В нашем случае -

интерпретатор Фокала.) Но #.... должно для неё выглядеть комментарием.

Вот и. А остальные символы, не являющиеся в Фокале служебными — за компанию.

(1.7) Усовершенствование функций (что мы выше упустили)

Что корню квадратному FSQrt и логарифму FLog с помощью второго параметра

можно указать основание. (В (1.0) логарифм был только натуральный, а корень

только квадратный. И то, при наличии операции возведения в степень...)

Что FATan(X,Y) эквивалентен FATan(X/Y) но гораздо лучше "ведёт себя" в

области значений Y близких к нулю.

Что FMOd (дробная часть числа), с двумя аргументами: FMOd(X,Y) — остаток

от деления X на Y нацело.

Что FRnd (без аргументов — генератор случайных чисел в диапазоне от -1.0

до +1.0, а с числовым аргументом — установка генератора в некоторое состояние),

принимает так же аргумент в виде текстовой строки: FRnd("пароль"), а так же

с аргументом -0 — устанавливает генератор по текущей дате/времени.

(Примечание: здесь использован тот факт, что в данной реализации у чисел

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

значения +0 и -0. А не в дополнительном, где ноль — единый. Возможно, в

других реализациях этот фокус не получится!)

Что FX (доступ к управляющим регистрам внешних устройств) без первого

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

выполняющий побитовое И над вторым и третьим аргументами, с некоторого момента

тоже воспользовался вот этим вот фокусом. И теперь:

FX(, +А, +Б) — И -> А&Б по прежнему проверка битов

FX(, +А, -Б) — И-НЕ -> А&~Б сброс битов

FX(, -А, +Б) — ИЛИ -> А|Б установка битов

FX(, -А, -Б) — ИСКЛ.ИЛИ -> А^Б инверсия битов

Для одного аргумента (при первом отсутствующем):

FX(, +А) -> ~А — инверсия всего 32-х разрядного значения

FX(, -А) -> lg2(А) — номер старшего значащего бита (двоичный порядок)

(а мантиса — в числовой аккумулятор А1: вдруг пригодится)

(2) Про графику говорить особо нечего: оператор Vizual рисовал графические

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

полигон... Однако они оказались излишне примитивны: калькулятору нужно совсем

не это, а возможность не особо напрягаясь, рисовать графики по вычисленным

точкам. В том числе в каких угодно осях, включая и сами оси...

И вообще видимо имеет смысл разделить графику на "растровую" — нижнего

уровня, рисующие вот такие вот графические примитивы по точкам. И включающую

две функции FТочка и FЛиния, организованные по аналогии с функцией FКурсор,

для текстового экрана. И "векторную" — вот этот самый оператор Vizual,

графическими примитивами для которого будут: начало координат, ось, точка

графика и коллекция вот таких точек, составляющая один график.

(3) Обработка ошибок.

Ну это совсем просто: ошибка вызывает прекращение выполнения программы и,

прежде чем "диалоговая" часть интерпретатора, общающаяся с пользователем,

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

всех вложенных подпрограмм. Что известно как "спуск по стэку". Оператор Quit

делает в точности то же самое, разве что никто не ругается.

Кто вдруг не знает, "стэк" это "стопка", "кипа". Для наглядности

представим себе стопку тарелок, или подносов в столовой: из середины не

вытащить (и не засунуть!) — положить можно только сверху, взять — тоже. Так

же работает магазин у пистолета или, например, у автомата Калашникова. Поэтому

организованная таким образом память называется еще "магазинной", в

противоположность очереди, или более общей "вагонной" памяти, где как у

состава на рельсах сортировочной станции вагончики могут как добавляться, так

и забираться с обоих концов.

Во всех (уважающих себя) алгоритмических языках вот по такому "стэковому"

принципу организована та самая штука, где сохраняются сведения о вызывающих

друг дружку подпрограммах. Потому что понадобятся эти "адреса возврата" тоже в

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

У Фокала тоже есть такой стэк. И знать о нём совсем не вредно: это в его

ячейках как раз и размещаются списки локальных переменных.

И вот в текущую (самую верхнюю) ячейку этого самого стэка возвратов,

принадлежащую выполняющейся в данный момент подпрограмме, оператор Break

помещает "ловушку" на ошибку или на "ситуацию". (Различаются они только

номерами.) Эта ловушка содержит две вещи: номер ситуации и "реакцию" на неё:

Break N_ош = N_стр_реакции; Возможно "нулевую" (т.е. ничего не делать):

Break N_ош; Можно сразу несколько номеров ситуаций: Break N1,N2,N3 = реакц;

Реакция — адрес подпрограммы, которая и будет устранять последствия ошибки.

Но это может быть и остаток текущей строки: Break N_ош = ; другие операторы...

Тогда в этот раз он разумеется не выполняется.

А оператору Quit разрешили порождать ситуацию не только с тем волшебным

номером, на который интерпретатор не ругается, а и с любым — указанным первым

аргументом (если он есть).

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

подпрограмме реакции — станут начальными значениями её локальных переменных.

А еще может быть аргумент в виде текстовой константы: сообщение об ошибке,

которое интерпретатор и выдаст пользователю (если не найдётся подходящей

ловушки). В прямой (нулевой) строке наличие текстового аргумента, даже

пустого, предотвращает завершение работы интерпретатора. (А то оператору Quit

только дай!...)

Ловушка поставленная оператором Break, плюс ситуация, порожденная оператором

Quit и составляют в совокупности упоминавшийся "структурный переход".

Позволяющий в частности досрочно выйти из цикла. Однако, выглядит всё это

примерно так:

— подпрограмма ставит ловушку и выполняет какие-то действия. Если всё

нормально, ловушка никак не влияет. И с завершением подпрограммы, удаляется

так же как и локальные переменные.

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

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

завершается. Ситуация "распространяется" на подпрограмму, вызвавшую данную,

потом на предыдущую... Пока таки не встретится подходящая ловушка, или пока

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

сообщит пользователю, что обо всём этом думает.

— если возникла ситуация, а ловушка — подходящая, она "срабатывает";

выполняется реакция, якобы исправляющая последствия этой ошибки,

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

(возвращает управление в точку её вызова) так, как будто никакой ошибки небыло.

Однако, а это ли нам нужно? Например в строке 3.5 у нас цикл, где мы

что-то ищем в большущем массиве А[], циклически перебирая его элементы. И вот

наконец нашли! Рассматривать остаток массива не требуется; параметр цикла как

раз и указывает найденный элемент:

3.5 Break 12; For i=1,N; If( годится_ли{ А[i] } ) 0,0; Quit 12

Здесь "годится_ли{...}" — конечно условность. Но это вполне может быть вызов

подпрограммы (с помощью FSBr) и в самом деле проверяющей — годится этот

элемент или нет. Всё хорошо, просто замечательно, вот только строки 3.6, 3.7 и.

т.д. выполнены уже не будут — выход из подпрограммы произойдёт немедленно. А

мы сделаем так:

3.5 For; Break 12; For i=1,N; If( годится_ли{ А[i] } ) 0,0; Quit 12

(См. чуть выше — там где (1.5).)

Ошибки 12 в Фокале заведомо нет.

Примечание: номера ошибок (и ситуаций) — дробные числа: ошибки тоже

объединяются в группы. И можно поставить ловушку как на одну конкретную,

так и на всю их группу.

Имеющиеся в наличии группы ошибок:

0 — действия человека за терминалом (например 0.3 — нажата Ctrl/C)

1 — синтаксические ошибки (например 1.4 — дисбаланс скобок)

2 — арифметические ошибки (например 2.1 — деление на ноль)

3 — ошибки ввода/вывода (например 3.2 — конец файла)

4 — прочие ошибки (например 4.3 — нет переменной)

5 — недостаток ресурсов (например 5.1 — не хватает оперативной памяти)

Полный список ошибок см.<<6>>

Однако, кроме "ситуаций" (внутренних) бывают еще и внешние по отношению к

программе "события". Например пользователь нажал на одну из кнопок клавиатуры.

Или кончился отправленный на воспроизведение звуковой фрагмент... Можно

конечно заставить программу всё время опрашивать — не кончился-ли? Но вообще-то

вот именно на такой случай и существуют прерывания. "События" Фокала это их

аналог.

Ловушку на событие ставит всё тот же оператор Break. Отличие в том, что

номера событий — отрицательные. И целые. Ловушки — глобальные. Реакция

обязательна: её отсутствие как раз и предписывает прекратить отслеживание

данного события.

Так как интерпретатор Фокала — медленный, события именно что

"отслеживаются": с каждым из них связан счетчик. И при возникновении события

он наращивается. А реакция запускается если он не-ноль при первой же

возможности (которая может представиться очень не скоро): подпрограмма реакции

запускается "вне очереди" после конца выполнения очередного оператора. (А

некоторые выполняются — ну очень долго! Например: Set x=FCHr(-1) ждёт до

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

поступит.) В самой реакции выполнение реакции на другие события запрещается.

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

Счетчик событий передаётся подпрограмме реакции первым аргументом. (Попадает

в локальную переменную &.) И сбрасывается.

Искусственно создать событие можно с помощью оператора Kill. Это без

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

неприемлемо. И поэтому не реализовано. А вот первый аргумент указывает ему

номер порождаемого события. (Знак числа игнорируется.)

Так как под ДОС`ом первые 255 событий соответствуют аппаратным прерываниям

компьютера, а некоторые из них — обращения к функциям БИОС`a и операционной

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

процессора, и через них же возвращают результат, то в операторе Kill второй

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

переменные текущей подпрограммы. (Без первого аргумента — сразу в переменные.)

Признак C, через который обычно указывает успешность обращения — в А1.

Номера собственных событий Фокала начинаются с 1000.

Полный список событий — см.<<6>> — там же где и список ситуаций.


* * *

(4.4) Форматное выражение в операторе Write %_форматное_выражение_

"Встроенные" форматные преобразования вида %Буковка — должны были быть

прежде всего "перекодировками": преобразованиями символов из виндовой

кодировки, попадающейся буквально на каждом шагу, в ДОС`овскую, с которой

только и работает Фокал. (Ну и обратно разумеется.) Чуть по-реже встречается

"уникод", КОИ-8 еще реже, а бывают и вовсе экзотические... А еще преобразование

меж большими и маленькими буквами (заглавными и строчными), меж русскими и

латинскими...

Правда с виндовыми текстами большая проблема: "сверхдлинные строчки".

Вишь конец строки они делают только в конце абзаца — де программное

обеспечение этот текст само на строчки разобьёт при отображении. (А то и шрифт

не "моноширинный" и ширина окна, куда всё это будет выводиться, неизвестно

какая... А места в памяти у них там под виндой немеряно, не то что у нас — с

ограничением на размер буфера в 122 байта...)

Но пока эта проблема не решена, пока суд да дело... Надо всётаки уметь

делать с текстовой строкой в А2 ну хоть что-то! Тем паче "маркер", указывающий

"текущую точку" в А2 у нас уже есть — был всегда, так же, как и сам А2. Ну

хотя бы кое-что вставить (туда где маркер): *"кое-что" и соответственно

удалить: /12 (в данном случае — 12 символов). И, разумеется, передвинуть

маркер как вперёд +3 так и назад -4. Совершенно необходимо так же уметь ставить

маркер в начало ^ и в конец $ строки. И иметь возможность это самое кое-что

найти: +"кое-что" и -"кое-что" тоже двигаясь в разные стороны от текущего

положения маркера. Всё это — хотя-бы с константами.

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

и поиск. (Который сперва был только в одну сторону — без плюсов и минусов, как

впрочем и перемещение.) Но в результате плюс и минус превратились в префиксы.

А маркер приобрёл еще и размер — чтобы указывать найденный фрагмент, а не

только его начало. И теперь делит строку на три части: то что под маркером, то

что перед ним и то что после. Основным операциям, (которых по прежнему всего

две: * и /) эти префиксы теперь указывают к чему их надо применить. Так: +*

вставляет перед маркером, -* после, а без префиксов — вместо. А удаление, если

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



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