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

Дополнение к гл. 4 книжки о Фокале


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

2.1 Однако, самому создать заведомо локальную переменную просто присвоив ей первый раз значение: Set &N=... Можно, но без гарантии: вдруг такая уже есть где-то ниже по стеку? Здесь нам на помощь придёт... Раньше это был только оператор Kill, но он — страшненький ("убить"). Но теперь еще и оператор Do и функция FSUBr. У которых теперь может быть сколько угодно дополнительных параметров — для передачи их в качестве аргументов в подпрограмму. Надо только, чтобы они все по "основной профессии" ничего не делали. Для чего первый (главный!) параметр должен отсутствовать. Тогда следующие помещаются в заведомо локальные переменные. Но "позиционным" методом. То есть учинить таким способом переменную &-тридцать-с-лишним — затруднительно.

5.3.3 Идея воспользоваться побочным эффектом, не дав оператору или функции действовать по прямому назначению — злонамеренно пропустив главный параметр, применима так же и к функции FX позволяющей обращаться к аппаратуре напрямую. И потому еще более опасной, чем оператор Kill: про устройство, которым пытаемся управлять, надо знать почти всё, иначе будет ОЙ!

В принципе у неё два аргумента — команда и адрес (номер порта). Но если команда — на запись (-1 или -2) то нужен третий — что писать. А если на проверку (0) то тоже нужен третий — маска, указывающая какие биты проверять. Потому что проверка — это считывание порта и выделение отдельных битов с помощью побитового "И" с маской.

Главный аргумент здесь — команда. Если её пропустить, то функция никуда не лезет, а просто выполняет побитовое "И" между целой частью второго и третьего аргументов.

5.3.4 Как известно, спецфункция FSUBr, передающая управление подпрограмме из середины выражения, еще и должна туда вернуть вычисленный этой подпрограммой результат. Уточним, что возвращает она значение, застрявшее в неком числовом аккумуляторе — внутренней переменной Фокала.

Если функция никакой подпрограммы не вызывает (в виду отсутствия главного аргумента, указывающего её адрес), то всё равно возвращает содержимое этого аккумулятора. В него попадают значения выражений, правда не всех: которые в операторах передачи управления (Go, Do, If) — нет. (Да и зачем бы нам могли понадобиться эти номера программных строчек?) Но кроме того и некоторые вещи, которые никаким другим способом не получить. Например счетчик количества строк, принадлежащий упомянутому в п.5.1 просмотрщику. (Что пригождается в демонстрационных программах, выводящих на экран обширные тексты.)

5.1.1 Если пользователю надоест читать выдаваемый просмотрщиком текст, то он нажмет кнопку ESC и просмотрщик прекратит. Но демонстрационной программе надо как-то узнать о сём прискорбном факте. (И, например, промотать остаток текста чтобы добраться до следующих за ним команд.) Здесь нам поможет буфер клавиатуры...

В нём помещается ровно одно число — либо признак что он пуст, либо код нажатой кнопки. (Еще одно нажатие и будет ошибка 0.2 "переполнение буфера клавиатуры"!) Впрочем, забирает его оттуда только функция FCHR, а все остальные только очищают. (И просмотрщик — тоже.) А позволяет проверить функция FTEll. (Потому что если он пуст — FCHR будет висеть и ждать нажатия кнопки.)

Ну так на то, что буфер клавиатуры пуст, одинаково указывают и 0 и -1. Но все всегда помещают туда 0, а -1 — только просмотрщик в случае если пользователь таки нажал ESC.

1.0 Заметим, что кроме аккумулятора под число, хранящего последний результат, в Фокале есть аналогичная вещь для объектов ввода/вывода — специально для уже упоминавшейся функции FTEll. Которая должна сообщить текущую позицию в файле. Вот только в каком? Наоткрывать их можно десятка полтора. А если в "текущем", так их — два: те, на которые указывают каналы ввода и вывода. Вот и было решено, что это тот, к которому было последнее по времени обращение. Пусть даже и совершенно фиктивное...

4.0 ...И еще один аккумулятор — для хранения (и использования) текстовой строки. Заметим, он не придуман, организован, реализован (как для FTEll), а обнаружен. Потому что, как оказалось, был всегда...

3.1 Страшненький оператор Kill искусственно порождает "событие". Его исходная функция — сброс аппаратуры в некое "исходное" состояние, хотя и не реализована, но зарезервирована за оператором без аргументов. А пока он ничего не делает.

Первый аргумент оператора указывает номер события, которое надо породить. (А без него он тоже ничего не делает.) А вот второй и следующие аргументы — параметры этого события: некоторые прерывания, которые учиняет сей оператор, суть обращения к операционной системе (или BIOS`у). Им полагается передать параметры (как правило через регистры процессора) и потом получить результат (через них-же). Оператор не функция — значение не возвращает. (Возвращает однако — через числовой аккумулятор: либо 0, либо код ДОС`овской ошибки — если признак Ц в слове признаков процессора установлен — так все прерывания обычно об ошибке сообщают.) К тому же их здесь сразу несколько. Ну и куда же их девать, если не разложить по локальным переменным ТЕКУЩЕЙ подпрограммы? (Есть языки, где функция может вернуть сразу несколько значений, но это явно не наш случай. Да и там они как правило сразу раскладываются по переменным.) Поэтому дополнительные аргументы этого оператора перед прерыванием и помещаются в регистры, а после из них — в локальные переменные. А лишние, или если оператор ничего не делает (и не собирается — за отсутствием первого аргумента) то сразу в переменные.

Но всё равно оператор — страшненький. Обращаться осторожно!

3.2 Внутреннюю "ситуацию" искусственно порождает оператор Quit. В принципе он делал это всегда, но теперь ему можно указать — какую именно. Плюс параметры, для передаче подпрограмме реакции.

Оператор Quit без аргументов по-прежнему останавливает выполнение программы, причем так, что интерфейсная часть интерпретатора "не ругается". Для этого он порождает ситуацию с номером -1. На которую не поставить ловушку. Потому что в операторе Break отрицательными числами обозначаются "события".

3.3 Ситуации, возникающие естественным образом — это ошибки, которые интерпретатор обнаруживает в ходе выполнения программы. Номер ошибки (и вообще ситуации), так же как и номер строки — дробное число. В результате чего ошибки разбиты на группы по типам:

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

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

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

4 — прочие ошибки времени выполнения (типа не найдена строка программы)

5 — исчерпание или недоступность ресурсов (типа не хватает памяти) И в дополнение к ним группа ноль:

0 — действия пользователя (типа он нажал Ctrl/Ц)

Например ошибка 4.3 — нет переменной: попытка взять значение из переменной, в которую еще ничего не клали. И соответственно места в памяти под неё не выделяли. Или уже освободили — оператором Eraze.

### Ограничение текущей версии: не более 100 групп ситуаций и не более 100 ситуаций в группе. Т.е. под это, как и для хранения номера строки, выделено всего по одному байту.

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

3.4 А вот номер события — целый, и при том отрицательный. (Хотя, если так подумать, то пожалуй и для них стоило бы ввести группы...)

3.5 Реакция как на "событие", так и на "ситуацию" заказывается и отменяется оператором Break. Например:

B N=R — установит на событие (или ситуацию) с номером N реакцию в виде вызова подпрограммы R. Здесь N и R — числа, точнее выражения, их вычисляющие. (В приведённом виде это будут значения переменных с именами 'N' и 'R'.)

B N — установит "нулевую" реакцию (для события — просто её отменит), а

B N = ; остаток строки — установит в качестве реакции остаток текущей строки, который сейчас разумеется выполняться не будет.

2.2 Так как имя локальной переменной состоит в основном из её номера... Вернее номера позиции при "позиционной" (а других не держим) передаче параметров в подпрограмму. ...То к ним ко всем разом можно обращаться как к одномерному массиву: не только &N где N — число, но и &(NN), где NN — выражение произвольного вида.

Что, кроме всего прочего, даёт доступ и к локальным переменным с экзотическими номерами -1, -2 и.т.п. И которые как правило используются для служебных целей. В частности в &(-1) при передаче параметров помещается их количество. Точнее — индекс последнего из параметров. А в &(-2) — номер ситуации (ошибки) на которую сработала ловушка.

2.2.1* Бывает еще "ключевая" или "именная" передача параметров. Это когда у подпрограммы их большая куча. Мы их все, может, и знать не знаем — передаём только некоторые, написав: имя=значение; а у всех остальных остаются значения по-умолчанию. Но это же надо заранее "объявить" в подпрограмме все эти параметры, указав для каждого из них имя (при чем желательно "говорящее") и его значение на случай если ничего не передадут. Всё это явно не для Фокала. Тут мы принципиально ничего заранее не объявляем и не описываем!

3.6 Для каждой ошибочной ситуации предусмотрена текстовая строка, которую интерфейсная часть интерпретатора выдаёт в качестве сообщения об ошибке.

Оператору Quit такая тоже причитается. Для чего один из его аргументов может быть текстовой константой. В т.ч. пустой — важно само её наличие. Которое, кстати, предотвращает выход из интерпретатора в случае если Quit выполняется не в "косвенной" строке (нумерованной, сохраненной в памяти) а в "прямой" — введенной с терминала или из командного (он же "скриптовый") файла.

Это сообщение, а так же программная строка, вызвавшая ошибку, сохраняются во внутренних переменных интерпретатора. И при необходимости могут быть получены функцией FTEll (см. далее), на которую свалили всё, что не знали кому поручить.


* * *

Чтобы плавно перейти от локальных переменных и ситуаций, которые уже практически полностью рассмотрены, обратно к "удобствам и красивостям", а главное — к тому, как додуманы и доопределены некоторые из операторов (и функций), рассмотрим типовой пример: надо преждевременно выйти из цикла For.

Типа с его помощью мы последовательно перебираем... Ну не важно что, да хоть сами целые числа и ищем подходящее. Каковым пусть будет число 22. А попутно что-то с ними делаем (ну хоть на терминал выводим). И вот — нашли! Дальше перебирать не надо, цикл надо завершить.

Дополнительное условие: надо чтобы всё это было в одну строчку. (Это мы скриптовые файлы писать метим!)

6.2 Как известно, тело цикла (остаток строки после оператора) — подпрограмма. Просто перейти оттуда куда либо оператором Go (как в других языках) — не поможет: по завершении строчки, куда перешли, управление вернется заголовку цикла. А оператор Ret послужит аналогом "continue" других языков — управление вернется заголовку цикла сразу.

Кроме того, все три выражения в заголовке цикла вычисляются один раз — перед его началом. (А не каждый раз, как например "условие" и "шаг" в аналогичном операторе языка Си.) Так что цикл с плавающей верхней границей или переменным шагом средствами самого языка не сделаешь. (Это для Си подобное — рабочий момент, а для такого программируемого калькулятора, как Фокал — редкая экзотика.)

Типовое решение — установить параметр цикла больше конечного значения, нехорошо тем, что в данном случае он и содержит номер найденного элемента. (Можно конешно скопировать в другую переменную, но не изящно это.)

Применим вышеописанный структурный переход, например по ситуации 17:

F; B 17; F i=1,1000; T i; I(i-22)0,,0; Q 17,""

Что видим? Самый обычный цикл до тысячи; самый обычный оператор Type распечатывающий параметр цикла; оператор If, решающий что искомое число уже найдено, со странными номерами строк...

Так же видим что ловушку без реакции ставит оператор B 17; а саму ситуацию порождает оператор Q 17,"" с дополнительным аргументом в виде пустой текстовой константы — вот как раз чтобы, если это всё это в "нулевой" строке — не вывалиться из интерпретатора.

А самый первый в строке оператор For почему-то состоит только из одного ключевого слова...

5.4.1 Оператор For.

Как известно, остаток строки после оператора For — тело цикла, выполняется как подпрограмма. Много раз — пока...

Ну так в форме с одним только ключевым словом — один единственный раз. Вот для такого случая как здесь у нас. А то, после срабатывания ловушки на ситуацию, происходит выход из подпрограммы, которая её поставила. Вот мы и сделали подпрограмму в виде одной только текущей строки.

Задумаемся, а до каких пор выполняется тело цикла? Ну ясный пень, что пока значение параметра цикла не достигнет конечного значения. Однако, не вполне понятно, что значит "достигнуть"? Станет больше конечного значения (ну или меньше, если шаг отрицательный) — это да. А что делать если мы сразу установили начальное значение близко к конечному — надо ли выполнить тело цикла хотя бы один раз? Принимаем решение, что если ближе чем на пол шага — тогда эта итерация цикла будет последней. Ну и если вышел за конечное значение — тоже на пол шага или больше.

Если конечное значение не указано — тело цикла выполняется один раз. (Как подпрограмма, естественно.) Если не указан только шаг — то он всегда устанавливается либо +1 либо -1 в зависимости от того, что больше — начальное значение или конечное. А чтобы цикл никуда не двигался (чтобы например искусственно в теле цикла сделать этот шаг переменным) надо честно указать шаг равный нулю.

5.4.2 Оператор If.

Как известно, оператор If в зависимости от значения выражения, указанного в качестве условия, передаёт управление по одному из трех адресов. Но если последние из них отсутствуют, то в соответствующих им случаях выполняется остаток строки.

Во-первых решено, что вычисляется только один из них, а остальные два — нет. Потому что это могут быть полноценные выражения, в том числе содержащие спецфункцию FSUBr, что фактически вызов подпрограммы.

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

Ну и в третьих решено, что нулевой номер относится к следующей программной строке: выполнение текущей просто завершается. А некорректный номер строки (например -1) эквивалентен его отсутствию — приводит к выполнению остатка строки после оператора. Что позволяет вообще обойтись без переходов куда либо: в зависимости от условия остаток строки либо выполняется, либо нет.

Например: if(x)0, ,0; t "X==0"! или: if(x-y)0, ,0; t "X==Y"!

if(x) ,0; t "X!=0"! if(x-y) ,0; t "X!=Y"!

if(x)0,0; t "X> 0"! if(x-y)0,0; t "X> Y"!

if(x)0; t "X>=0"! if(x-y)0; t "X>=Y"!

if(x) ,0,0; t "X< 0"! if(x-y) ,0,0; t "X< Y"!

if(x) , ,0; t "X<=0"! if(x-y) , ,0; t "X<=Y"!

5.4.3 Оператор Go.

Остался в точности таким же как и был. Но для него решено, что некорректный номер строки по прежнему вызывает ошибку, а вот нулевой — относится к текущей строке. Что позволяет (вместе с вышеописанным оператором If) сделать цикл в пределах одной строки, в том числе введенной с терминала или скриптового файла.

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



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