@database beginner.guide 

@Master beginner 

@Width 75 


This is the AmigaGuide® file beginner.guide, produced by Makeinfo-1.55 from 
the input file beginner.


@NODE "main" "Введение в Amiga E"
@Next "Понимание Программы" 
@Prev "Contents.guide/main" 
@Toc "Contents.guide/main" 

 Введение в Amiga E
********************

   Для взаимодействия с вашей любимицей Ammy, вы должны уметь разговаривать
на  языке,  который  она  понимает.   К  счастью,  у нас есть большой выбор
подобных  языков,  каждый  из  которых,  решает определенный круг задач.  К
примеру,  БЕЙСИК  (в  большинстве  своих  реализаций)  простой и легкий для
изучения  (но как известно страдает медлительностью полученного кода) и как
следствие  -  идеален  для начинающих.  Ассемблер, с другой стороны требует
усиленного  изучения  и  создание  программ  на  нем  (особенно графических
интерфейсов)  -  крайне утомительное и скучное занятие (хотя многие могут с
этим и не согласиться), но при правильном использовании, вы сможете создать
максимально  скоростные  программы  и  именно  поэтому, язык в значительной
степени востребован коммерческими программистами.

Как  видите, в качестве примеров были приведены две крайности и большинство
софтверных  фирм  и  учебных  заведений  предпочитают  использовать этакого
середнячка,  между простотой использования и скоростью полученных программ,
конечно же вы догадались, речь идет о C(++) или Паскаль/Модула-2.

  Программы,  созданные на E, ну очень похожи на Паскалевские или Модула-2,
но все же в основе своей, Е ближе всего к классическому С.  Любой, знакомый
с   этими   языками   с   необыкновенной  легкостью  сможет  изучить  Е,  и
единственное,  на  чем  ему  нужно  будет  заострить  свое внимание.  это -
уникальные,  присущие  только  Е  особенности, которые впрочем, тоже были в
своем   большинстве  позаимствованы  (естественно  в  силу  своих  полезных
качеств)  из  других языков.  Этот материал преследует своей целью помочь в
освоении  Е,  людям  не  сильно  обременненым  навыками  программирования и
поэтому   может   показаться   слишком   банальным   для   профессиональных
программистов  и  для  них  рекомендуется  сразу  окунуться  в "E Reference
Manual",  хотя  все  же  некоторые  части  данного опуса могут пригодится и
профессионалам...

Часть  Первая  (та,  которую  вы  сейчас  изволите  читать),  позволит  вам
проникнуть  в  основы языка Е и собственно программирования в целом.  Часть
Вторая  затрагивает  более  глубинные  структуры Е, покрывает более сложные
темы  и  раскрывает  уникальные  возможности  языка.   Часть  Третья делает
основной  упор  на  примеры программ, так сказать, будет проведена разведка
боем.   В  завершении,  Часть  Четвертая  представляет  из себя Приложения,
поверьте вы найдете там множество полезной дополнительной информации.


 @{" Простая программа " Link "Простая программа" } 


@ENDNODE

@NODE "Простая программа" "Простая программа"
@Toc "main" 

Простая программа
=================

Если  вы  продолжаете  читать,  вам  наверняка  не терпится незамедлительно
начать  программировать  на  E, но вы не знаете с чего начать.  Так и быть,
вот  вам  сразу  небольшой  пример  на засыпку!  :) Да, вы должны уже уметь
пользоваться  редактором  ЕЕ  (хотя, вы можете использовать любой текстовый
редактор  по  своему вкусу, правда, при этом вы потеряете несколько удобных
штучек), подробное описание которого дано в шестом номере PowerAmiga.

 @{" Проект " Link "Проект" } 
 @{" Компиляция " Link "Компиляция" } 
 @{" Исполнение " Link "Исполнение" } 


@ENDNODE

@NODE "Проект" "Проект"
@Next "Компиляция" 
@Toc "Простая программа" 

Проект
------

Введите указанные ниже строки в редакторе ЕЕ и сохраните как файл с именем
simple.e (будьте внимательны при наборе строк!)

     PROC main()
       WriteF('Моя первая прога')
     ENDPROC

Не  пытайтесь  пока  вносить изменения в этот пример.  Обратите внимание на
то, что регистр букв имеет ключевое значение.


@ENDNODE

@NODE "Компиляция" "Компиляция"
@Next "Исполнение" 
@Prev "Проект" 
@Toc "Простая программа" 

Компиляция
----------

  Сохранив  файл,  мы можем приступить к превращению обычных строк текста в
работающий  исполняемый  файл  -  программу.   Для этого достаточно войти в
редакторе  ЕЕ  в  меню Tools и выбрать пункт Compile.  Можно пойти и другим
путем  -  перейти в директорию Bin вашей инсталляции Е (или скопировать сам
компилятор ec в ваш дир C:) и ввести такую строку:
 
  ec T:simple.e

(директория  T:   это  то  место,  куда сохранен наш пример, вы естественно
можете поменять этот параметр по своему усмотрению.)

Немного  побурчав, компилятор закончит свою работу и как по волшебству, там
же (дир T:) появится файл simple!


@ENDNODE

@NODE "Исполнение" "Исполнение"
@Prev "Компиляция" 
@Toc "Простая программа" 

Исполнение
----------

  Если  все  прошло  нормально, вы сможете запустить свою первую программу,
набрав в CLI строку:

   T:simple

Вот  полная  пошаговая  инструкция,  директория Systems - системный раздел,
Stasis - RAM диск, соответственно подставьте ваши названия:

     Systems: > cd t:
     Stasis:T > ec simple или ae:bin/ec simple
     Amiga E Compiler/Assembler/Linker/PP v3.3a registered -= DiGiTaL CoRRuPTioN `97 =- 
     lexical analysing ...
     parsing and compiling ...
     no errors
     Stasis:T > simple
     Моя первая прогаStasis:T >

У  вас  на  экране  должно быть примерно то же самое, если все было сделано
правильно.   Обратите внимание на работу нашей программы - последняя строка
-  вывод  сообщения:  Моя первая прога.  В том, что вывод немного кривоват,
есть  своя  изюминка,  со временем мы сможем модернизировать данный пример,
навести лоск, так сказать.


@ENDNODE

@NODE "Понимание Программы" "Понимание Программы"
@Next "Переменные и Выражения" 
@Prev "main" 
@Toc "Contents.guide/main" 

Понимание программы
*******************

  Для понимания работы программы, (а программой является даже наш совсем не
сложный  обсуждаемый  пример)  требуется знать совсем немного.  Как вы сами
уже  догадались,  все  что делает наш пример программы - это вывод на экран
определенного  сообщения  и  сообщение, как таковое является частью строки,
которую  мы  с  вами написали в проекте (сорце, исходном тексте) программы.
Первое, что мы с вами сделаем - это изменим само сообщение, которое выводит
наша программулька! ;)


 @{" Изменение сообщения " Link "Изменение сообщения" } 
 @{" Процедуры " Link "Процедуры" } 
 @{" Параметры " Link "Параметры" } 
 @{" Стринги " Link "Стринги" } 
 @{" Стилизация, Макросы и Читабельность " Link "Стиль, Макросы и Читабельность" } 
 @{" Простая такая, программа " Link "Простая такая, программа" } 

@ENDNODE

@NODE "Изменение сообщения" "Изменение сообщения"
@Next "Процедуры" 
@Toc "Понимание Программы" 

Изменение сообщения
===================

   Отредактируйте в файле строку, введя новое сообщение между двумя знаками
'  и  откомпилируйте,  использовав  те  же действия что и раньше.  Да, и не
используйте  других  знаков  ',  кроме  тех,  которые присутствуют в данном
примере.   Если все прошло как надо, после запуска программы вы увидите уже
совсем  другой  результат,  а именно - ваше собственное сообщение!  Если же
возникли  проблемы,  сравните  оригинальный  файл проекта и ваш собственный
(измененный) и убедитесь, что вы извращались только с текстом, ограниченным
знаками '!  :)


 @{" Возня с примером " Link "Возня с примером" } 
 @{" Краткий обзор " Link "Краткий обзор" } 


@ENDNODE

@NODE "Возня с примером" "Возня с примером"
@Next "Краткий обзор" 
@Toc "Изменение сообщения" 


Возня с примером
----------------

   Простое  баловство,  а  точнее,  метод  научного  тыка  -  лучший способ
самообучения!   Доказательство  тому,  наша  работа с представленными здесь
простыми  примерами!  Не забегайте слишком далеко вперед и если ваши ролики
заехали вдруг за шарики, быстрее бросайтесь к соответствуещему примерчику и
"мамочка" (это я, если не понятно) вам все растолкует!  :D


@ENDNODE

@NODE "Краткий обзор" "Краткий обзор"
@Prev "Возня с примером" 
@Toc "Изменение сообщения" 


Краткий обзор
--------------

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


   *   Процедуры:  Мы определили процедуру, названную main (главная) и
     использовали  опять же процедуру, но уже встроенную - WriteF.  Говоря
     по-существу, процедура - маленькая,  но гордая программа, так как
     имеет свое собственное имя или название, кому как больше нравится!

   *  Параметры:  Сообщение в скобках после WriteF в нашей программе,
      это - параметр для WriteF!  Параметры являются данными, с которыми
     может и должна работать процедура.

   *  Стринги: Сообщение, которoе мы невзначай подкинули для WriteF - набор
      символов, заключенных в мощные кандалы - знаки '. Вот это дело и
      зовется - стринг. Кусок текста, говоря русским народным языком.


@ENDNODE

@NODE "Процедуры" "Процедуры"
@Next "Параметры" 
@Prev "Изменение сообщения" 
@Toc "Понимание Программы" 

Процедуры
=========

   Как  было  раньше  отмечено,  процедура  является  небольшой  программой
носящей  свое  уникальное  имя.   И  примите  к сведению, когда запускается
Е-программа,  исполняется  высокомерная  процедура с именем main и никак не
иначе!   Поэтому,  если  вы  хотите написать на Е работающую программу, без
определения  главной  процедуры  main()  вам не обойтись.  Другие процедуры
(встроенные  или  определенные  пользователем)  могут  быть  запущены  (или
вызваны)  из  главной, что собственно говоря мы и сделали в нашем случае (я
про  пример)  с  WriteF.   К  примеру,  если  процедура  britney() вызывает
процедуру  spears(),  код  (или  мини-программа)  относящиеся  к  процедуре
spears()  будут  выполнены.  Это также может сопровождаться вызовами других
процедур  и  после  завершения  обращения к процедуре spears(), продолжится
дальнейшее  выполнение  оставшейся части кода процедуры britney() и это как
пить дать, будет следующая строка процедуры.  Когда же будет достигнут конец
процедуры  main()  это будет означать полный конец britney spears, в смысле
программе будет полный конец!  :^) Однако, много воды может утечь и не одну
сигару можно выкурить, пока процедура отпахает с начала и до своего конца и
иногда  прога  вообще  может  и  не захотеть заканчиваться, они ведь разные
бывают!  В другом случае, прога может зависнуть, в смысле глюкануть и тогда
ваша  Ammy  пойдет  к  восточному  дядюшке  Guru  медитировать,  об этом вы
узнаете,  когда  увидите  красную  рамочку,  а может и не узнаете.  Короче,
видеоэффекты вам обеспечены!  :)


 @{" Определение Процедуры " Link "Определение процедуры" } 
 @{" Исполнение Процедуры " Link "Исполнение процедуры" } 
 @{" Усовершенствование примера " Link "Усовершенствование примера" } 


@ENDNODE

@NODE "Определение процедуры" "Определение процедуры"
@Next "Исполнение процедуры" 
@Toc "Процедуры" 

Определение Процедуры
---------------------

   Определить  процедуру  можно  с  помощью ключевого слова PROC, следом за
которым  должно  быть  задано  имя  новой  процедуры (начальная буква имени
должна  быть  маленькой),  описание  параметров, которые она может взять (в
скобках),   набор   из  строк,  формирующих  собственно  тело  процедуры  и
заканчиваться  все  должно  ключевым  словом ENDPROC.  Взгляните еще раз на
нашу кроху-прогу и вы увидите все составляющие, описанные выше. См. @{"Проект " Link "Проект" }


@ENDNODE

@NODE "Исполнение процедуры" "Исполнение процедуры"
@Next "Усовершенствование примера" 
@Prev "Определение процедуры" 
@Toc "Процедуры" 

Исполнение процедуры
--------------------

   Процедуры  могут  быть вызваны (или выполнены) из тела другой процедуры.
Вы можете сделать это указав имя и следом в скобках, необходимые данные для
работы процедуры.  Посмотрите на вызов WriteF() в нашем примере.  См. @{"Проект " Link "Проект" }


@ENDNODE

@NODE "Усовершенствование примера" "Усовершенствование примера"
@Prev "Исполнение процедуры" 
@Toc "Процедуры" 

Усовершенствование примера
--------------------------

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

     PROC main()
       WriteF('Моя первая прога')
       cameron()
     ENDPROC
     
     PROC cameron()
       WriteF('...стала немного круче')
     ENDPROC

Вам может показаться это несколько сложным, но это только на первый взгляд.
Все,  что  мы  сделали  - определили вторую процедуру под именем cameron(),
которая  по  сути  копия  основной,  ибо результат ее работы тот же - вывод
текстового  сообщения.   Мы  вызвали  эту процедуру в нашей main() сражу же
после  строки  вывода  уже  знакомого  нам сообщения.  И поэтому сообщение,
которое  выведет  собственно  сама  cameron()  будет  уже  после основного.
Откомпилируйте этот модернизированный пример и вам все станет ясно.


@ENDNODE

@NODE "Параметры" "Параметры"
@Next "Стринги" 
@Prev "Процедуры" 
@Toc "Понимание Программы" 

Параметры
=========

   В  основном  мы используем процедуры для работы с определенными данными.
В   нашем   примере   мы  манипулировали  процедурой  WriteF()  для  вывода
определенного сообщения.  Мы передавали сообщение в качестве параметра (или
аргумента)  для  WriteF()  поместив его между двух скобок - ( и ), сразу же
после  имени  процедуры.   Когда же мы вызывали процедуру cameron(), нам не
требовалось  использовать  каких-либо  данных  и  поэтому  скобки  остались
пустыми. Какая жалость! :)

При определении процедуры мы задаем как много и какого типа данные мы хотим
использовать  в  работе  с  процедурой и когда мы вызываем эту процедуру мы
даем  ей эти необходимые данные, без которых ей не радовать нас безотказной
работой  и  превосходным  результатом.   Заметьте, что процедура cameron(),
впрочем как и наша королева main(), имеют пустые скобки при их определении.
Это  означает,  что  процедуры такого типа не могут принять от нас данных в
качестве параметров, когда мы их (процедуры, конечно) невзначай потревожим,
в смысле вызовем.

Перед  тем, как мы сможем сами определять процедуры, которые будут способны
заключать  в  свои  объятия  параметры,  мы  должны пройти курс по работе с
интересными  существами, которых именуют никак не иначе как переменные!  Мы
обязательно займемся этим, но только в следующей части манускрипта.
См.@{"Глобальные и локальные переменные" Link "Глобальные и локальные переменные" }


@ENDNODE

@NODE "Стринги" "Стринги"
@Next "Стиль, Макросы и Читабельность" 
@Prev "Параметры" 
@Toc "Понимание Программы" 

Стринги
=======

   Набор  символов  между  двумя  знаками ' называется стрингом.  Почти все
символы  можно  использовать в качестве стринга, кроме \\ и как вы понимаете
'.   Эти  символы  имеют  специальное назначение.  К примеру перевод строки
обозначается двумя символами \\n.  Теперь вспомним про изюм!  :) Самое время
навести красоту на нашу прогушку, чтобы сообщение не липло к кому попало.

Сделайте-ка вот так:

     PROC main()
       WriteF('Моя первая прога\\n')
       cameron()
     ENDPROC
     
     PROC cameron()
       WriteF('...стала немного круче\\n')
     ENDPROC

Откомпилируйте и запустите, как обычно.  Правда, стало намного симпатичнее?
Строчка  за  строчкой, строчит пулемет...  И к системной подсказке (prompt)
мы  больше  не  клеимся.   Итак,  проблемку с переводом строк мы пролечили,
ностальгировать и сравнивать с тем, что было раньше можно здесь: @{"Исполнение" Link "Execution" }


@ENDNODE

@NODE "Стиль, Макросы и Читабельность" "Стиль, Макросы и Читабельность"
@Next "Простая такая, программа" 
@Prev "Стринги" 
@Toc "Понимание Программы" 

Стиль, Макросы и Читабельность
==============================

   Смотрите-ка,  наш  примерчик,  чего-то  раздвоением  аж на две процедуры
main()  и  cameron()  заболел!   Однако  ж,  это нам здесь вовсе ни к чему.
Давайте сострижем лишнее и уложимся в одну полезную процедуру.

     PROC main()
       WriteF('Моя первая прога\\n')
       WriteF('...наконец станет когда-нибудь круче?\\n')
     ENDPROC

   Что  же мы натворили?  А вот что, заменили вызов процедуры cameron(), на
код  из  которого она состояла (это называется подстановкой процедуры).  Не
новость,  что  почти  все программы могут быть легко уложены в одну главную
процедуру, без каких-либо обращений к другим процедурам.  Однако, разбиение
программы  на  части  с  использованием  процедур,  обычно  приводит  текст
программы к более читабельному виду.  Также не будет лишним давать названия
процедурам,  адекватно  их функциональности.  K примеру процедура cameron()
имеет  имя  собственное  в названии и из этого можно сделать вывод, что она
или  работает  с  сообщениями или с чем-либо подобным.  Хорошо написанная в
таком стиле программа, будет читаться как увлекательный роман!

    Другая  веская  причина для использования процедур, состоит в разгрузке
кода  программы от повторяющихся участков.  Представьте себе, что вам нужно
несколько  раз по ходу программы напечатать определенное длинное сообщение.
Вы конечно можете каждый раз писать его в тексте программы заново или же вы
можете  реализовать  отдельную  процедуру для этой задачи и когда вам будет
нужно  вывести  сообщение,  вставите простой вызов этой процедуры и все!  К
тому  же,  представьте себе если вы захотите отредактировать это сообщение,
вам  придется  бегать  по  всему тексту программы, выискивая этот текст и в
случае  длинного  сообщения  вас  не спасет даже функция замены в редакторе
CED!   А  в  случае  использования  процедуры,  все  будет легко доступно и
удобно!

P.S.   Наиболее  подходящим  по смыслу и по краткости переводом слова Reuse
(повторное  использование)  мне  показался  термин "макрос", в дальнейшем я
буду именно его и использовать.  Так что уж простите!  ;)


@ENDNODE

@NODE "Простая такая, программа" "Простая такая, программа"
@Prev "Стиль, Макросы и Читабельность" 
@Toc "Понимание Программы" 

Простая такая, программа
========================

   Простушка-прога  теперь  стала  (я  горячо на это надеюсь, нервно теребя
остатки  волос  на  своей  бренной голове, а их у меня, не так уж мало!) по
настоящему   простой   и  для  вас.   Единственным  белым  пятном  осталась
встроенная   процедура  WriteF().   Язычок  E  имеет  множество  встроенных
процедур  и  в  дальнейшем  мы  с  ними  встретимся и даже завяжем интимные
отношения!  :D

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

  Наш  простенький  пример программы, тоже не промах и делает все эти вещи,
кроме  разве,  что первых двух пунктов, но это не столь важно.  Вы говорите
компьютеру  (по-хорошему) запустить откомпилированную программу (которую вы
добросовестно  набивали,  то  есть  вводили  данные) и эти данные (ласковые
слова,  которые вы хотели вывести на экран) будут освобождены из заточения!
Затем  эти  данные  будут  отданы (на растерзание) в качестве параметра для
процедуры  WriteF() (вы не станете отрицать, это можно назвать манипуляцией
данными?),  которая  оттопырится  по  полной, выведя буквицы на экран!  Для
тренировки  наших  собственных  манипуляторов  (вы  ведь  хотите тоже уметь
манипулировать?) вы должны получить лиловый пояс по переменным и выражениям
(в том числе и нецензурным).  %^)


@ENDNODE

@NODE "Переменные и Выражения" "Переменные и Выражения"
@Next "Управление ходом программы" 
@Prev "Понимание Программы" 
@Toc "Contents.guide/main" 

Переменные и выражения
**********************

   Любой,  кто  имел  счастье пройти курс школьной алгебры, вероятно знает,
что  переменная  всего  лишь  именованный кусман данных.  В алгебре данными
обычно  являются  числа,  но  в  Е  это может быть все что угодно (стринг к
примеру).  Такое безобразие, вытворяемое с данными, как сложение двух чисел
обзывается  выражением.   Результат  выражения  в  свою  очередь может быть
использован  для  построения  более  крупных  выражений.  Сразу к прилавку,
23674+7829  это  выражение,  а  вот  уже  более  крупное  с  использованием
результата от предыдущего 172531803-(23674+7829).  Извиняюсь за пристрастие
к  крупным  суммам!  =) Хорошая новость - вы можете использовать переменные
как  проекцию  данных  при  работе  с  выражениями,  вот  смотрите,  если x
представляет число 1, а y содержит 5, тогда y-x будет 4!  Чудеса!  ;) Вот в
этих  нижних  двух  пунктах  вы  точно  узнаете какие типы переменных можно
определять и что из себя представляют различные виды выражений.

 @{" Переменные " Link "Переменные" } 
 @{" Выражения " Link "Выражения" } 


@ENDNODE

@NODE "Переменные" "Переменные"
@Next "Выражения" 
@Toc "Переменные и Выражения" 

Переменные
==========

   Переменные  в языке программирования Е способны содержать различные виды
данных  (точнее их называют - типы).  Однако перед тем как переменная будет
использована  она  должна  быть  определена  и  этот  ритуал  известен  как
объявление  или  декларирование  (если  кто  любит  засорять  русской язык)
переменной.   Это самое объявление переменной также описывает зону действия
переменной, или она будет доступна из любой точки программы или же только в
ходе   выполнения   конкретной  процедуры  (то  есть  будет  ли  переменная
глобальной  или  же  локальной).   Не  стоит  забывать  о  том, что данные,
хранимые в переменной, могут быть изменены при использовании присвоений.  В
следующие разделах эти темы будут рассмотрены более детально.


 @{" Типы переменных  " Link "Типы переменных" } 
 @{" Объявление переменных " Link "Объявление переменных" } 
 @{" Присвоение " Link "Присвоение" } 
 @{" Глобальные и локальные переменные " Link "Глобальные и локальные переменные" } 
 @{" Модификация примера " Link "Модификация примера" } 


@ENDNODE

@NODE "Типы переменных" "Типы переменных"
@Next "Объявление переменных" 
@Toc "Переменные" 

Типы переменных
---------------

   В  Е переменные - место хранения для данных (и как ни странно, место это
находится  в  оперативной  памяти нашей Ammy).  Различные виды данных могут
требовать   различных   объемов  памяти  для  хранения.   Но  данные  могут
группироваться  вместе  по  типу  и  два  набора  данных  одинакового  типа
потребуют  одинакового  пространства для хранения.  Каждая переменная имеет
связь с определенным типом, который и фиксирует максимальный размер памяти,
требуемый  для  хранения  данной  переменной.   Чаще  всего, переменные в Е
хранят в себе тип LONG (длинное целое).  Этот тип переменных способен брать
на  себя  целые числа в диапазоне от -2.147.483.648 до 2.147.483.647, что в
обычных  условиях болee чем достаточно.  Конечно, существуют и другие типы,
такие  как INT и LIST, и даже более трансцедентные вещи, но на первое время
нам хватит и старины LONG'a!  =)


@ENDNODE

@NODE "Объявление переменных" "Объявление переменных"
@Next "Присвоение" 
@Prev "Типы переменных" 
@Toc "Переменные" 

Объявление переменных
---------------------

   Для  того,  чтобы  иметь  возможность  использовать  переменную, ее надо
сначала   громко   и   внятно   объявить.   Эта  инициация  производится  с
использованием  ключевого  слова  DEF (от define - определять) и дальнейшим
перечислением  (через запятые) имен переменных, с которыми мы хотим иметь в
дальнейшем дело.

Эти переменные все имеют тип LONG по умолчанию (позднее мы увидим как можно
объявлять  переменные  других  типов)  Несколько  примеров внесут ясность в
данный вопрос:

     DEF x
     
     DEF a, b, c

В  первой  строке объявляется одна переменная x, во второй же более тяжелый
случай - мы объявили переменные a, b и c, но могли бы и продолжить!  :)


@ENDNODE

@NODE "Присвоение" "Присвоение"
@Next "Глобальные и локальные переменные" 
@Prev "Объявление переменных" 
@Toc "Переменные" 

Присвоение
----------

   Данные,  хранящиеся  в  переменных  могут  быть  изменены  и  обычно это
достигается с помощью присвоений.  Присвоение состоит из имени переменной и
выражения,  определяющего  набор  новых  данных  для наполнения переменной.
Символ  :=  разделяет  переменную  от  выражения.  K примеру, следующий код
демонстрирует    сохранение   в   переменной   x   числа   2.    Слева   от
символа-разделителя находится имя переменной, которая подлежит, так сказать
трансмутации   (наполнению   новыми  данными)  и  соответственно  справа  -
выражение источник новых данных (в нашем случае, просто число 2).

     x := 2

Далее,  следует  более  сложный образчик, использующий значение, раннее уже
сохраненное   в   переменной,   как   часть  выражения,  выполняющего  роль
наполнителя  новыми  данными  для переменной.  Значение выражения справа от
разделителя  :=  расшифровывается  как значение, сохраненное в переменной x
плюс  1.   Это  новое  значение  переписывает предыдущие данные.  (Так, что
общий эффект состоит в том, что x увеличивается на 1).

     x := x + 1

Возможно,   ситуация  станет  яснее  после  рассмотрения  более  наглядного
примера,  который  даже  не изменяет содержимого переменной x.  Признаться,
этот  отрывок  кода  просто бездарно тратит драгоценное процессорное время,
ибо все, что он делает, так это извлекает значение переменной x и сохраняет
его обратно без каких-либо изменений!

     x := x


@ENDNODE

@NODE "Глобальные и локальные переменные" "Глобальные и локальные переменные"
@Next "Модификация примера" 
@Prev "Присвоение" 
@Toc "Переменные" 

Глобальные и локальные переменные (и параметры процедуры)
---------------------------------------------------------

   Существуют  два  типа  переменных:   глобальные  и  локальные.   Данные,
хранимые   глобальными   переменными  могут  читаться  и  изменяться  всеми
процедурами  без  исключения,  в  противовес  этому, данные, содержащиеся в
локальных переменных, доступны только процедуре, для которой эти переменные
являются   родными   (то   есть,  находятся  в  пределах  тела  процедуры).
Глобальные  переменные  должны быть объявлены до самого первого определения
процедуры.  Локальные переменные объявляются внутри процедуры (между PROC и
ENDPROC),  с  которой они хотят породниться.  К примеру, следующий фрагмент
кода   объявляет  глобальную  переменную  w  и  сладкую  парочку  локальных
переменных x и y:

     DEF w
     
     PROC main()
       DEF x
       x:=2
       w:=1
       diana()
     ENDPROC
     
     PROC diana()
       DEF y
       y:=3
       w:=2
     ENDPROC

Переменная  x  является  локальной  для  процедуры  main(),  a y совершенно
локальна  для  процедуры  diana().  Обе процедуры, и main() и diana() могут
читать  и  изменять  значение  глобальной переменной w, но diana() не может
оперировать  со  значением переменной x (так как эта переменная локальна (и
лояльна) только для процедуры main()).  Аналогично и в случае с main(), эта
процедура  не  может  получить  доступ к переменной y, являющейся локальной
собственностью процедуры diana().

   Локальные  переменные одной процедуры абсолютно различны (хотел ввернуть
словечко  помощнее,  да  передумал)  по  сравнению  с такими же переменными
другой  процедуры.   По этой причине возможно использование одинаковых имен
для  локальных переменных без какого-либо риска.  Посмотрите, как это будет
выглядеть,  применительно  к  обсуждаемому выше примеру:  (мы переименовали
локальную переменную y в процедуре diana() на x)

     DEF w
     
     PROC main()
       DEF x
       x:=2
       w:=1
       diana()
     ENDPROC
     
     PROC diana()
       DEF x
       x:=3
       w:=2
     ENDPROC

Это  возможно  в  силу  того, что присвоение значения x в процедуре diana()
может сработать, только относительно локальной переменной x, находящейся во
власти  процедуры  diana()  (так  же  как и переменная x в процедуре main()
локальна  относительно только main() и не может быть доступна из процедруры
diana()).

   Если  локальная переменная в процедуре имеет одинаковое имя с глобальной
переменной,  то  в  дальнейшем  приоритет  получает  локальная  переменная.
Поэтому,  доступа  к глобальной переменной в этом случае уже не получить, и
беда такая зовется - сужение области действия глобальной переменной.

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

     DEF y
     
     PROC onemore(x)
       y:=x+1
     ENDPROC

Этот пример не является полноценной программой, поэтому не пытайтесь его
компилировать. 

Мы  объявили переменную y (которая будет типом LONG) и процедуру onemore().
Процедура  была  определена  с  параметром  x  и это равносильно объявлению
локальной  переменной.   Когда onemore() будет вызвана ей обязательно будет
передан  параметр и он в свою очередь будет сохранен в локальной переменной
x  до  исполнения  основного  кода процедуры onemore().  Затем основной код
сохраняет  значение  x  плюс  1  в  глобальной переменной y.  Вот несколько
примеров вызова процедуры onemore():

       onemore(120)
       onemore(52+34)
       onemore(y)

   Процедура  может  быть  сконфигурированна для работы с любым количеством
параметров.  Ниже вы увидите процедуру addthem() способную работать с двумя
параметрами,  a  и  b,  естественно  при  вызове такой процедуры мы обязаны
удовлетворить  ее условия и предоставить ей для работы эти самые параметры.
Обратите внимание, что значения, хранимые в параметрических переменных (a и
b)  могут  меняться  по ходу выполнения кода процедуры, так как они, ни что
иное,  как  локальные  переменные  относительно  процедуры.   (Единственное
существенное  различие  между  локальными  и  параметрическими  переменными
состоит в том, что параметрические переменные инициализируются с значениями
переданными им в качестве параметров во время вызова процедуры.)

     DEF y
     
     PROC addthem(a, b)
       a:=a+2
       y:=a*b
     ENDPROC

Вот примерно так можно вызывать процедуру addthem():

       addthem(120,-20)
       addthem(52,34)
       addthem(y,y)

   Глобальные  переменные  по  умолчанию при инициализации получают нулевое
значение.   Параметрические  переменные,  конечно  же,  инициализируются со
значениями,  получаемыми  ими  в  качестве параметров при вызове процедуры.
Локальные  же  переменные не инициализируются.  Это означает, что локальная
переменная  содержит  случайное значение, когда код процедуры выполняется в
первый раз.  Поэтому, только программер несет полную ответственность за то,
чтобы  не  было никаких попыток работать со значениями локальных переменных
до их инициализации.  Очевидным способом инициализации локальной переменной
является  использование  присвоений,  но  есть  также  метод  инициализации
значения переменной как части объявления  (см. Инициализируемые Объявления)
Инициализация переменных - важный фактор в создании программ, и практически
всегда,   пренебрежение   ею,   является  основной  причиной  неадекватного
поведения программ.


@ENDNODE

@NODE "Модификация примера" "Модификация примера"
@Prev "Глобальные и локальные переменные" 
@Toc "Переменные" 

Модификация примера
-------------------

  До  того,  как  мы  приступим  к  дальнейшим актам насилия по отношению к
нашему  многострадальному  примеру,  мы должны, ну хоть что-нибудь узнать о
WriteF().   Как мы уже знаем, комбинация \\n в стринге дает перевод  строки.
Так  вот,  есть  еще несколько других, не менее важных сочетаний символов в
стринге  и несколько из них, используются исключительно в процедурах такого
плана как WriteF().  Одна из таких комбинаций \\d, для  описания которой, мы
сначала все же приложимся к исходнику и накурочим новых строчек.

     PROC main()
       WriteF('Моя первая прога\\n')
       fred()
     ENDPROC
     
     PROC fred()
       WriteF('...кидается к нам с номером \\d\\n', 236)
     ENDPROC

Ну  как,  догадались  в чем дело?  В любом случае, компильните пример и все
встанет  на  свои  места.   Если  все  пошло  путем,  вы  должны непременно
лицезреть  второе  сообщение  заканчивающееся  цифрами, которые были отданы
WriteF()  как второй параметр.  И все, что делает комбинация  \\d - отмечает
место  в  стринге  куда  будет выводится число.  Вот, что вы должны увидеть
после запуска видоизмененного примера:

     Моя первая прога
     ...кидается к нам с номером 236

Продолжим кодить наш пример:

     PROC main()
       WriteF('Моя первая прога\\n')
       fred()
     ENDPROC
     
     PROC fred()
       WriteF('...уже раз \\d изменялась\\n', 16)
     ENDPROC

Пример  очень  похож на предыдущий, но более наглядно демонстрирует  как \\d
определяет место где происходит печать числа.  Для проверки вот, что должно
быть у вас на экране:

     Моя первая прога
     ...уже раз 16 изменялась

Попробуем с двумя числами.

     PROC main()
       WriteF('Моя все еще первая прога\\n')
       fred()
     ENDPROC
     
     PROC fred()
       WriteF('...кидается к нам уже с числами \\d и \\d\\n', 16, 236)
     ENDPROC

Потому,  как  мы  печатаем  два числа, вполне логично предположить, что для
точного наведения цифр на цель, нам понадобятся две упаковки \\d,  а еще два
числа,  представленные как параметры, расположенные в порядке, в котором мы
хотим  увидеть  их на экране.  Число 16 будет выводиться перед `и' и раньше
числа 236.  Что вы должны увидеть:

     Моя все еще первая прога
     ...кидается к нам с числами 16 и 236

   А сейчас пристегнитесь, мы совершим субсветовой прыжок и передадим числа
процедуре fred() в качестве параметров.  Просто окиньте ясным взглядом этот
и предыдущий примеры и найдите множество отличий! =) 

     PROC main()
       WriteF('Моя первая прога\\n')
       fred(16, 236)
     ENDPROC
     
     PROC fred(a,b)
       WriteF('...опять ползет ко мне с этими \\d и \\d\\n', a,b)
     ENDPROC

Вот  прямо  сейчас  мы  подкинули пару локальных переменных a и b процедуре
WriteF(),  а она и рада!  Это знаете ли, абсолютно тоже самое, что передать
значения,  содержащиеся  в этих переменных (предыдущий пример именно этим и
занимался)  и  поэтому  на  экране  будет  все  тоже  самое.   Совсем скоро
(буквально в следующем разделе) мы будем жонглировать переменными, применяя
мощную  арифметику  на  субъектах a и b (и поверьте сидением на трубе им не
отделаться) и затем заставим WriteF() напечатать нам результат.


@ENDNODE

@NODE "Выражения" "Выражения"
@Prev "Переменные" 
@Toc "Переменные и Выражения" 

Выражения
=========

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


 @{" Математика " Link "Математика" } 
 @{" Логика и сравнение " Link "Логика и сравнение" } 
 @{" Порядок и группировка " Link "Порядок и группировка" } 


@ENDNODE

@NODE "Математика" "Математика"
@Next "Логика и сравнение" 
@Toc "Выражения" 

Математика
----------

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

Символ  +,  как  нетрудно  догадаться  используется  для  сложения,  -  для
вычитания,  * - для умножения и / для деления (тут надо быть повнимательнее
и  не нароком не перепутать \\ используемый в стрингах с // применяемый при
делении).  Вот и свеженькие выражения подоспели:

       1+2+3+4
       15-5
       5*2
       330/33
       -10+20
       3*3+1

Результат  каждого  из  этих выражений равен 10.  Последний пример, кстати,
построен по правилам упорядовачивания (см. @{"Порядок и Группировка" Link "Порядок и группировка" }).

   Выражения,  рассмотренные  нами  выше,  используют в качестве операторов
целые  числа,  так  что  работаешь  с целыми и в результате получишь целые.
Безусловно,  числа  с  плавающей запятой также могут быть применены в Е с Е
(что  это  был  бы  за  язык,  если бы у него этого не было!), но числа эти
крайне  капризные и требуют особых навыков при работе с ними ( см.  Числа с
Плавающей Запятой).  Числа эти могут быть как и с очень небольшим остатком,
так  и с гигантским, но всегда есть ограничение по точности (имеется в виду
количество цифр после запятой).


@ENDNODE

@NODE "Логика и сравнение" "Логика и сравнение"
@Next "Порядок и группировка" 
@Prev "Математика" 
@Toc "Выражения" 

Логика и сравнение
------------------

   Логика   является  основой  любого  компьютера.   Компьютеры  неспособны
предугадывать  следущий шаг, вместо этого они полагаются на твердые факты и
точные  причинные  связи.   Рассмотрим  защиту  паролем  на  многих  играх.
Компьютер должен решить правильное ли вы ввели слово или код, перед тем как
допустить  вас  к  игре.   Когда  вы играете, игра тоже постоянно принимает
решения:  попал ли луч лазера из вашего бластера по пришельцу?, остались ли
у   вас  еще  жизни  (или  активирован  ли  cheat  mode),  и  т.п.   Логика
контролирует выполнение программы.

   В  Е,  константы  TRUE  (истина)  и FALSE (ложь) представляют истинные и
ложные значения соответственно, операторы AND (и) и OR (или) также являются
стандартными  логическими  операторами.   Операторы  сравнения = (равно), >
(больше  чем), < (меньше чем), >= (больше или равно), <= (меньше или равно)
и <> (не равно).  Все приведенные выражения истинны:

       TRUE
       TRUE AND TRUE
       TRUE OR FALSE
       1=1
       2>1
       3<>0

A эти - жалкие лгунишки:

       FALSE
       TRUE AND FALSE
       FALSE OR FALSE
       0=2
       2<1
       (2<1) AND (-1=0)

Последний  пример  обязан  использовать  скобки.   Мы  узнаем  почему так в
следующем разделе (тут опять не обошлось без упорядочивания).

   Значения  истинности  TRUE  и  FALSE на самом деле представлены числами.
Это  показывает  как  работает  логическая система в Е.  TRUE - число -1, а
FALSE  -  0.   Именно  такие  числа  и  выступают в качестве параметров для
логических  операторов  AND и OR.  Фактически, AND и OR - операторы битовой
логики  (см.   Oператоры AND и OR), поэтому в большинстве случаев, любое не
нулевое  число  воспринимается как TRUE значение.  Иногда удобно полагаться
на   это,   но   все   же   правильнее  (и  нагляднее)  использовать  более
недвусмысленный   подход.   В  дальнейшем  вы  сами  увидите  подтверждение
вышеперечисленным фактам при возникновении двояких ситуаций.


@ENDNODE

@NODE "Порядок и группировка" "Порядок и группировка"
@Prev "Логика и сравнение" 
@Toc "Выражения" 

Порядок и группировка
---------------------

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

Это  означает,  что  такие  выражения  как  1+3*3  на Е не дадут ожидаемого
математиком  результата.   В нашем случае 1+3*3 выдаст результат - 12.  Это
происходит  потому,  что сложение (1+3) выполняется до умножения, так как в
выражении  расположено  раньше  умножения.   Если  же в выражении умножение
будет  предшествовать  сложению (так собственно говоря обычно и происходит)
то  и  выполнятся  будет  в  первую  очередь.   И  в  этом случае результат
выражения  3*3+1  удовлетворит  и школьного учителя и апологета яыка Е, ибо
будет равен 10.

   Для устранения данных различий, мы можем применить скобки как инструмент
группировки  выражения.   Если мы напишем 1+(3*3) результат будет равен 10.
Произошло   это  по  причине  принуждения  Е  выполнить  в  первую  очередь
умножение.   Поначалу  это может показаться несколько неуклюжим приемом, но
поверьте,  вы  сами  убедитесь,  что  это  гораздо  лучше, чем учить глупые
правила,  где расписано в каком очередности должны быть выполнены операторы
(на  С  это просто PITA, вы просто до смерти замучаетесь расставлять скобки
для достижения своей цели!).

   
   Имеем выражение (еще из предыдущего раздела):

       (2<1) AND (-1=0)

Выражение ложно.  Если мы уберем скобки из выражения:

       2<1 AND -1=0

Это будет аналогично:

       ((2<1) AND -1) = 0

Сейчас,  число  -1  не используется для представления истинности значений с
оператором  AND,  но  мы  то  знаем, что TRUE - число -1, и Е то же знает и
делает  на  это  поправку, и компилятор E не имеет причин для недовольства.
Вскоре мы подробно разберем как в действительности работают операторы AND и
OR  (см.   Операторы  AND  и  OR),  но  в данным момент нам более интересно
проработать то, как же будет рассчитано Е наше выражение:

  1. Двойка не может быть меньше единицы, так что 2<1 будет
     соответствовать FALSE.

            (FALSE AND -1) = 0

  2.     TRUE равносильно числу -1, поэтому мы можем заменить -1 на TRUE.

            (FALSE AND TRUE) = 0

  3.     FALSE AND TRUE это FALSE.

            (FALSE) = 0

  4.     FALSE всегда равно нулю, этим мы и воспользуемся.

            0 = 0

  5. Нуль равен нулю, результат выражения TRUE.

            TRUE

Результат  просчитанного  Е  выражения - истина.  Но первоначальный вариант
выражения (со скобками) приводил к совершенно противоположному результату -
оно  было  ложным.   Как  видите группировка с использованием скобок крайне
важна!   И не составляет никакого труда правильно использовать данный метод
при разработке своих алгоритмов.


@ENDNODE

@NODE "Управление ходом программы" "Управление ходом программы"
@Next "Подведение итогов" 
@Prev "Переменные и Выражения" 
@Toc "Contents.guide/main" 

Управление ходом программы
**************************

   Компьютерная  программа  часто  вынуждена  повторять  выполнение  группы
действий  или  же исполнять какие-либо действия в зависимости от результата
некоторого  решения.   К  примеру,  программа печати всех чисел в диапазоне
единицы  и  сотни  -  было бы очень долго и утомительно (и добавлю - глупо)
набирать  отдельную  строку кода для операции печати каждого числа, гораздо
лучше  использовать переменную и наращивая ее значение в цикле, выводить на
печать.
        Другим  аспектом  управления  является  выбор  для выполнения между
различными   участками   кода.    Практический  случай:   происходит  сбой,
программа может в зависимости от критичности ситуации или продолжить работу
или  же  вывести посмертное сообщение об ошибке с последующим выходом - эта
часть  программы является классическим образчиком структуры под названием -
блок условий.

 @{" Блоки условий " Link "Блоки условий" } 
 @{" Циклы " Link "Циклы" } 

@ENDNODE

@NODE "Блоки условий" "Блоки условий"
@Next "Циклы" 
@Toc "Управление ходом программы" 

Блоки условий
=============

   Существуют два вида блоков условий (конечно не вообще, а применительно к
реализации  их  в  Е):   IF (ЕСЛИ) и SELECT (ВЫБОР).  Примеры данных блоков
приведены  в  виде  фрагментов  кода  на  Е (обратите внимание:  примеры не
являются полноценными программами).

       IF x>0
         x:=x+1
         WriteF('Увеличение: x теперь \\d\\n', x)
       ELSEIF x<0
         x:=x-1
         WriteF('Уменьшение: x теперь \\d\\n', x)
       ELSE
         WriteF('Ноль: x пустой как 0\\n')
       ENDIF

В  рассматриваемом  выше IF блоке первая часть проверяет больше ли значение
x,  чем  ноль и если это так, x увеличивается и новое значение выводится на
экран (вместе с сообщением о том, что x кажется потолстел!)

Далее  программа  пропускает  оставшуюся  часть  блока и может приступить к
выполнению  кода,  следующего  за  ENDIF.   В ситуации же когда x не больше
нуля,  управление  получает  ELSEIF и в случае x меньшего чем ноль он будет
беспощадно добит уменьшением и распечатан и блок будет завершен.

Ну  и  последнее условие, если x не больше нуля и не меньше (а просто равен
этому  самому  нулю)  во  власть  вступает  ELSE  и  мы узнаем о том, что x
действительно ноль без палочки! ;)

IF конструкции подробно рассмотренно в ссылках ниже.

 @{" IF блок " Link "IF блок" } 
 @{" IF выражение " Link "IF выражение" } 

       SELECT x
         CASE 0
           WriteF('x является нулем\\n')
         CASE 10
           WriteF('x десятка\\n')
         CASE -2
           WriteF('x в минусе -2\\n')
         DEFAULT
           WriteF('x не ноль, не десять и даже не -2\\n')
       ENDSELECT

SELECT  блок  в  чем-то  напоминает  IF блок - также выполняются какие-либо
действия  в  зависимости  от  значения  x.  Однако, x проверяется только на
соответствие  нескольким  значениям, определенным в CASE директивах.  Если,
ни  одно  из  этих значений не совпало с x, управление получает DEFAULT (ПО
УМОЛЧАНИЮ) часть блока.

   Существует  также  разновидность  SELECT блока (известная как SELECT..OF
блок)  способная  работать  с  диапазонами  значений  и  крайне  быстрая по
скорости.  Два вида SELECT блоков будут детально описаны в этих главах.

 @{" SELECT блок " Link "SELECT блок" } 
 @{" SELECT..OF блок " Link "SELECT..OF блок" } 


@ENDNODE

@NODE "IF блок" "IF блок"
@Next "IF выражение" 
@Toc "Блоки условий" 

IF блок
-------

   IF  блок воплощен в данную земную форму (участки, такие как `выражениеА`
всего лишь указания на то, какие именно виды Е кода могут быть использованы
в данных точках блока, но они не являются Е кодом):

       IF выражениеA
         кодA
       ELSEIF выражениеB
         кодB
       ELSE
         кодC
       ENDIF

Расшифровка:

   *  Если  выражениеA  истинно  (то  есть  представляет из себя логическое
      значение TRUE или любое не нулевое число), кодА будет немедленно
      выполнен.

   * Если выражениеA ложно (в смысле, содержит в себе логическое FALSE или
     ноль) и выражениеB - истинно, к работе приступает кодB.

   * Если и выражениеА и выражениеB - ложны, кодC будет рад предложить свои
     услуги! :)

ELSE часть является опциональной, но если вы все же решите ее использовать,
разместите  в  самом  конце  блока, непосредственно перед ENDIF.  Думаю, не
лишним  будет  добавить,  что  нет никаких ограничений на количество ELSEIF
между IF и ELSE.

   Как  альтернатива  к  обсуждаемой  выше  форме  блока, (где каждая часть
является отдельной строкой) более упрощенный моностроковый вид:

       IF выражение THEN кодA ELSE кодB

Конечно,  при  работе  с  данной формой вы не сможете использовать ELSEIF и
придется впихивать все в одну строку.  Еще обратите внимание на то, что для
разделения выраженияА и выраженияВ использован токен THEN. В целом же,
данная форма в основном предназначена для использования в IF выражениях,
о которых пойдет речь ниже (см. @{"IF выражение" Link "IF выражение" }).

   Чтобы  сделать  вещи  более понятными, взгляните на несколько фрагментов
кода на Е, которые проиллюстрируют применение допустимых IF блоков:

       IF x>0 THEN x:=x+1 ELSE x:=0
     
       IF x>0
         x:=x+1
       ELSE
         x:=0
       ENDIF
     
       IF x=0 THEN WriteF('x нуль\\n')
     
       IF x=0
         WriteF('x нуль\\n')
       ENDIF
     
       IF x<0
         Write('Отрицательный x\\n')
       ELSEIF x>2000
         Write('Слишком большой x\\n')
       ELSEIF (x=2000) OR (x=0)
         Write('Бегущий по лезвию бритвы x\\n')
       ENDIF
     
       IF x>0
         IF x>2000
           WriteF('Большой x\\n')
         ELSE
           WriteF('Прикольный x\\n')
         ENDIF
       ELSE
         IF x<-800 THEN WriteF('Мелкий x\\n') ELSE Write('Отрицательный x')
       ENDIF

В  последнем  примере  присутствуют  вложенные  IF блоки (IF блок внутри IF
блока).

Здесь нет повода для сомнений относительно того, к какому блоку принадлежат
ELSE  или  ELSEIF  части,  потому  как  начало  и конец каждого блока четко
обозначены.   К  примеру,  первая  строка  с  ELSE  может  быть  однозначно
определена как часть вложенного IF блока.

   По  oчевидной причине, условия заложенные в IF и ELSEIF частях не должны
накладываться  друг  на  друга  (то  есть,  по крайней мере одно из условий
должно  быть  истинно).  Eсли же подобное происходит (конфликт условий), то
преимущество  получает  самое  первое  удовлетворяющее  запросу встреченное
условие.   Наглядно  продемонстрируем это в двух идентичных по своей работе
примерах:

       IF x>0
         WriteF('x больше нуля\\n')
       ELSEIF x>200
         WriteF('x больше 200\\n')
       ELSE
         WriteF('x слишком мал\\n')
       ENDIF
     
       IF x>0
         WriteF('x больше нуля\\n')
       ELSE
         WriteF('x слишком мал\\n')
       ENDIF

ELSEIF  в  первом  фрагменте  проверяет  x  на  превышение 200.  Но в таком
случае,  проверка в IF части выявит истину (можно не сомневаться в том, что
x  определенно  больше  нуля,  если  он  же  больше, чем 200), и только код
привязанный к IF будет подлежать исполнению!  Общее впечатление от всего IF
блока такое, как будто ELSEIF и нет здесь вовсе!  ;)


@ENDNODE

@NODE "IF выражение" "IF выражение"
@Next "SELECT блок" 
@Prev "IF блок" 
@Toc "Блоки условий" 

IF выражение
------------
   
   IF  наиболее  часто  используемая  конструкция,  в  числе разновидностей
которой  -  IF  выражение.   IF блок - оператор и работает в зависимости от
выполняющейся строки кода, в то время как IF выражение - выражение, которое
работает со своим собственным значением.

Вот к примеру дан IF блок:

       IF x>0
         y:=x+1
       ELSE
         y:=0
       ENDIF

он может быть воплощен в более легкую форму IF выражения:

       y:=(IF x>0 THEN x+1 ELSE 0)

Особой  нужды  в скобках здесь нет, но они делают пример более читабельным.
Так  как  IF  блок  только  и  делает,  что  осуществляет (в зависимости от
условий)  выбор  между присвоениями y, строки кода выполняющие эти действия
очень похожи (они оба являются классическими присвоениями), скорее различие
в значениях, кои присваиваются y.

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

   Более совершенная форма IF выражения:

       IF выражение THEN выражениеA ELSE выражениеB

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

Но  как  видите, здесь присутствует только ELSE ветвление (в блоке же может
быть  еще и ELSEIF).  Это означает, что выражение всегда принимает значение
(это или выражениеA или выражениеB, в зависимости от значения `выражения`),
и нет никакого хаоса с кучей условий.

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


@ENDNODE

@NODE "SELECT блок" "SELECT блок"
@Next "SELECT..OF блок" 
@Prev "IF выражение" 
@Toc "Блоки условий" 

SELECT блок
-----------

   SELECT блок имеет следующую форму:

       SELECT переменная
       CASE выражениеA
         кодA
       CASE выражениеB
         кодB
       DEFAULT
         кодC
       ENDSELECT

Значение селективной переменной (обозначена как `переменная` в SELECT части
блока)  сравнивается  со  значением  выражения  в каждом CASE случае.  Если
удача  на  нашей  стороне  и  значение  совпало, будет выполнен код в самой
первой  совпавшей с условием CASE части.  Кстати, количество CASE ветвлений
между SELECT и DEFAULT ограничено только вашей фантазией!  ;)

Если сравнение прошло неудачно, код в DEFAULT с радостью вступит в дело!  В
принципе  DEFAULT'a  может  и  не  быть  в составе блока, но уж если будет,
будьте так любезны, разместите его после всех CASE (прямо перед ENDSELECT).

Вам  должно  быть  ясно,  что SELECT блоки легко могут быть переписаны в IF
блоки  (кому  только  это  надо?),  ибо  проверки  в  IF  и  ELSEIF  частях
эквивалентны  проверке селективной переменной.  Сомневаетесь?  ;) Следующий
два фрагмента кода абсолютно идентичны:

       SELECT x
       CASE 22
         WriteF('x 22\\n')
       CASE (y+z)/2
         WriteF('x (y+x)/2\\n')
       DEFAULT
         WriteF('x не содержит значимых данных\\n')
       ENDSELECT
     
       IF x=22
         WriteF('x 22\\n')
       ELSEIF x=(y+z)/2
         WriteF('x (y+x)/2\\n')
       ELSE
         WriteF('x не содержит значимых данных\\n')
       ENDIF

Обратите  внимание  на  то,  что  IF  и  ELSEIF  части  перенесены  из CASE
ветвлений,  ELSE  телепортирована  из  DEFAULT  и  порядок  следования всех
конструкций  сохранен.   Преимущество SELECT блока очевидно - вы можете без
труда   видеть,   какие  значения  x  участвуют  в  проверке  и  также  нет
необходимости постоянно дублировать x=.


@ENDNODE

@NODE "SELECT..OF блок" "SELECT..OF блок"
@Prev "SELECT блок" 
@Toc "Блоки условий" 

SELECT..OF блок
---------------

    SELECT..OF  блок  устроен  немного сложнее, чем обычный SELECT блок, но
может быть не менее полезным.  Вот его структура:

       SELECT максдиапазон OF выражение
       CASE константаA
         кодA
       CASE константаB1 TO константаB2
         кодB
       CASE диапазон1, диапазон2
         кодC
       DEFAULT
         кодD
       ENDSELECT

   Значение,  выделенное как `выражение`, может быть любым выражением, а не
только  переменной,  что  мы  наблюдали в нормальном SELECT блоке.  Однако,
максдиапазон,   константаА,  константаВ  и  константаВ2  должны  быть  явно
заданными   числами,   то   есть  являться  константами  (см.   Константы).
Максдиапазон,  в  свою  очередь должен быть положительной константой, а все
другие   константы  могут  иметь  разброс  значений  между  0  и  значением
максдиапазон.  (включая 0, но исключая максдиапазон).  Уфффф!  ;)

   Значения для CASE задаются используя диапазоны чисел.  Простой диапазон,
это такая одинокая константа (первый случай CASE в верхнем примере).  Более
классический способ задания диапазона приведен во втором CASE, там применен
токен  TO (константаB2 должна быть больше, чем константаB1).  Также, в CASE
части  именно  SELECT..OF  блока  возможно  задавать  целые серии возможных
диапазонов  для  сопоставления,  разделяя каждый из них запятой, это хорошо
видно в третьем CASE, все в том же верхнем примере.

Вот,  взгляните,  все  нижеперечисленные CASE строки абсолютно идентичны по
действию  и  используются  для  попадания  в  число,  в диапазоне от 1 до 5
(включительно):

       CASE 1 TO 5
     
       CASE 1, 2, 3, 4, 5
     
       CASE 1 TO 3, 3 TO 5
     
       CASE 1, 2 TO 3, 4, 5
     
       CASE 1, 5, 2, 4, 3
     
       CASE 2 TO 3, 5, 1, 4

   Если  значение выражения меньше нуля, больше или равно максдиапазону или
же  не  совпадает ни с одной из констант, заданных в CASE диапазонах, тогда
контроль  получает DEFAULT часть блока.  В противном случае, выполнится код
в  первой, совпавшей с критерием CASE части.  Как и в обычном SELECT блоке,
DEFAULT часть задается по желанию.

   Следующий  SELECT..OF  блок  печатает  (в  числовой форме) день месяца с
окончанием (клево!):

       SELECT 32 OF day
       CASE 1, 4, 5, 9 TO 21, 31
         WriteF('Это \\dый день месяца\\n', day)
       CASE 2, 6 TO 8, 22, 26 TO 28
         WriteF('Это \\dой день месяца\\n', day)
       CASE 3, 23
         WriteF('Это \\dий день месяца\\n', day)
       DEFAULT
         WriteF('Ошибка: неправильный день=\\d\\n', day)
       ENDSELECT

Максдиапазон  для  этого  блока  равен  32,  соответственно  31  становится
максимальным  значением  для  использования  в CASE частях.  Если к примеру
значение  day  станет  100,  тогда  код  в  DEFAULT  проработат и сообщит о
неправильно заданном дне месяца.

   Можно  для  сравнения  попробовать написать тоже самое, но с IF блоками,
как говорится - почувствуй разницу:
       
IF (day=1) OR (day=4) OR (day=5) OR ((day>=9) AND (day<=21)) OR (day=31)
    WriteF('Это \\dый день месяца\\n', day)
ELSEIF (day=2) OR ((day>=6) AND (day<=8))
    WriteF('Это \\dой день месяца\\n', day)
ELSEIF (day=22) OR ((day>=26) AND (day<=28))
    WriteF('Это \\dой день месяца\\n', day)
ELSEIF (day=3) OR (day=23)
    WriteF('Это \\dий день месяца\\n', day)
ELSE
    WriteF('Ошибка: неправильный день=\\d\\n', day)
ENDIF

Тут  даже  пришлось  разнести  один ELSEIF на два, ибо не влезло все в одну
строку!  %)

Разделение  запятыми  двух диапазонов в CASE части может быть безболезненно
заменено  на  OR  или  на  два  выражения сравнения, ну а TO диапазон может
разменяться  на  AND  и  опять  же  два выражения сравнения (не забывайте о
тщательном   @{" скобизме " Link "Пояснение" }   в  результирующих  выражениях!).

   Ясно,  как  Божий  день,  что  SELЕCT..OF  блок  и более понятен и легче
читается,  по сравнению со своим собратом - IF блоком.  Также, SELECT..OF и
гораздо  быстрее,  ибо  нет в нем сравнений, какие присутствуют в IF блоке.
Вместо   этого,   совпадающее  значение  используется  непосредственно  для
перехода  к  соответствующей  CASE  части.   Но  не  все  коту - масленица,
значение   максдиапазон   напрямую   влияет   на  размер  скомпилированного
exe'шника,  так  что  рекомендуется  использовать SELECT..OF блоки только с
небольшими значениями максдиапазона.  Более подробно об этом можно узнать в
`Руководстве по языку Е'.


@ENDNODE

@NODE "Циклы" "Циклы"
@Prev "Блоки условий" 
@Toc "Управление ходом программы" 

Циклы
=====

   Циклы  рождены  для  одной  цели  - дать возможность программе выполнять
определенные  последовательности действий снова и снова.  Думаю, простейшим
примером,  демонстрирующим  мощь  циклов, можно назвать FOR цикл.  Конечно,
этим  разнообразие  циклов  не  ограничивается, просто с остальными членами
данного семейства будет легче познакомиться после встречи именно с FOR!  Oн
у нас младшенький!  =)


 @{" FOR цикл " Link "FOR цикл" } 
 @{" WHILE цикл " Link "WHILE цикл" } 
 @{" REPEAT..UNTIL цикл " Link "REPEAT..UNTIL цикл" } 


@ENDNODE

@NODE "FOR цикл" "FOR цикл"
@Next "WHILE цикл" 
@Toc "Циклы" 

FOR цикл
--------
   
   Если  вы  хотите  написать программу печати чисел от 1 до 100, вы можете
или  набрать  вручную  каждое  число и лишиться тем самым, своих отпечатков
пальцев   или   же  воспользоваться  переменной  и  небольшим  FOR  циклом.
Попробуйте скомпилировать эту E программу (пробел после  \\d в стринге нужен
для разделения числа при печати):

     PROC main()
       DEF x
       FOR x:=1 TO 100
         WriteF('\\d ', x)
       ENDFOR
       WriteF('\\n')
     ENDPROC

После  запуска  произойдет  вывод на экран диапазона чисел от 1 до 100, так
как  мы  впрочем  и  задумывали.   Пример работает, благодаря использованию
локальной  переменной  x для хранения числа, выводимого на экран.  FOR цикл
начинает  свою  работу  с установки x в 1 (присмотритесь, это тот фрагмент,
что  очень  напоминает  присвоение).  Затем, выполняется код, расположенный
между  FOR  и  ENDFOR  (значение  x выводится на печать).  После достижения
программой ENDFOR, она увеличивает x и проверяет его значение на превышение
100 (ограничение, которое мы установили в части блока TO).  Если превышение
предела  все  же  произошло, цикл завершается и оставшийся код после ENDFOR
подтверждает это, запустившись на исполнение.  Однако, если же, мы не вышли
за  рамки  100,  весь  код, внедренный в тело цикла между директивами FOR и
ENDFOR  будет  выполняться вновь и вновь, а значение x с каждым разом будет
становиться все больше.

Для полной ясности, ниже дан код, который выполняет абсолютно ту же работу,
что и наш пример выше (кстати, строка ...  не является E кодом, здесь всего
лишь подразумевается расположение 97 других WriteF конструкций):

     PROC main()
       WriteF('\\d ', 1)
       WriteF('\\d ', 2)
       ...
       WriteF('\\d ', 100)
       WriteF('\\n')
     ENDPROC

   Вот шаблон-описатель по использованию цикла FOR:

       FOR переменная := выражениеA TO выражениеB STEP число
         код
       ENDFOR

Построение  цикла  FOR  начинается с задания переменной, служащей счетчиком
цикла.   (в  примере выше это был x).  Фрагмент "выражениеA" дает начальное
значение  для  циклической  переменной,  а  "выражениеB" определяет верхний
предел.  STEP (ШАГ) часть позволяет определить значение (число), на которое
будет  наращиваться  циклическая  переменная  на  каждом  проходе цикла.  В
отличии  от  значений  задаваемых  для начала цикла и конца (которые вполне
могут  состоять  из  произвольных выражений), значение для STEP должно быть
константой   (см.   Константы).   Если  же  директива  STEP  не  была  явно
определена,  она  по  умолчанию  устанавливается в 1 (как в нашем примере).
Отрицательные  значения  для  STEP  допускаются,  это  может пригодится при
работе с отрицательными числами.  Ноль не может быть использован в качестве
параметра для STEP.

   Так же как и блок IF, FOR цикл может иметь однострочную форму:

    FOR переменная := выражениеA TO выражениеB STEP выражениеC DO код


@ENDNODE

@NODE "WHILE цикл" "WHILE цикл"
@Next "REPEAT..UNTIL цикл" 
@Prev "FOR цикл" 
@Toc "Циклы" 

WHILE цикл
----------

   FOR  цикл  использует  циклическую  переменную  и  проверяет,  когда  ее
значение  превысит  заложенное  в  цикл  ограничение.   WHILE  (ПОКА)  цикл
позволяет  вам определять свои собственные проверки в цикле.  Вот, извольте
представить   очередной  пример,  функционально  он  аналогичен  примеру  в
предыдущей главе:

     PROC main()
       DEF x
       x:=1
       WHILE x<=100
         WriteF('\\d ', x)
         x:=x+1
       ENDWHILE
       WriteF('\\n')
     ENDPROC

Мы  заменили  FOR  цикл  на инициализацию x и на WHILE цикл с кодом внутри,
выполняющим увеличение x. Теперь мы можем воочию лицезреть внутреннюю
подноготную FOR цикла, ибо механизм его работы - вот он! %)

  Важно  знать, что наша проверка x<=100 происходит до выполнения основного
кода  в  теле  цикла.   Это  означает, что возможна ситуация, когда начинка
цикла  не  будет  выполнена  ни  разу.   Проиллюстрирую  -  если мы сделаем
проверку  x>=100 результат будет - ложь, притом в самом начале цикла (ибо x
был   инициализирован  присвоением  в  1,  до  собственно,  самого  цикла).
Поэтому,  цикл  моментально  прекратит свое существование и выполнение кода
продолжится непосредственно после директивы ENDWHILE.

   А вот примерчик немного посложнеe:

     PROC main()
       DEF x,y
       x:=1
       y:=2
       WHILE (x<10) AND (y<10)
         WriteF('x \\d и y \\d\\n', x, y)
         x:=x+2
         y:=y+2
       ENDWHILE
     ENDPROC

На  этот  раз  мы воспользовались двумя локальными переменными.  Как только
одна  из  них принимает значение 10 или больше - цикл завершается.  Немного
окинув  вглядом  наш  код,  обнаруживаем,  что x при инициализации получает
значение  1  и  при каждом удачном прохождении цикла увеличивается на 2.  И
поэтому,  будет  всегда  иметь  четное  значение,  а  y же напротив, всегда
получается нечетным

Проверка  WHILE  цикла показывает нам, что на печать не могут быть выведены
любые  числа  больше,  чем  10  или равные ему.  Исходя из этого факта и из
того,  что начальное значение x 1, а у 2, приходим к очевидному выводу (бог
мой,  когда  ж  я  закончу  этот  гайд...),  в смысле, мы можем определенно
сказать, что последняя пара чисел будет равна семи и восьми соответственно!

Запустите  программу  и убедитесь в этом.  У вас на экране должно быть тоже
самое:

     x  1 и y  2
     x  3 и y  4
     x  5 и y  6
     x  7 и y  8

   Подобно FOR циклу и здесь присутствует строковый вариант WHILE цикла:

       WHILE выражение DO код

   Завершение  цикла  всегда  представляет большую проблему (да?  не знал).
Для  FOR  циклов  можно  гарантировать,  что  они завершат свою работу, как
только  будет  достигнут  верхний  предел (если конечно, вы не нахимичите с
циклической  переменной).  В WHILE циклах (и во всех других тоже) напротив,
можно  войти  в  мертвую  петлю и крутиться в ней до второго пришествия.  К
примеру,  если  в  цикле  присутствует  проверка 1<2, то это условие всегда
будет  истинно  и  никакая  сила  (кроме  reset'a)  не сможет изменить это!
Поэтому,   вы   просто   обязаны  позаботиться  о  том,  чтобы  циклы  хоть
когда-нибудь,  но  кончались!   Вы  ведь  хотите,  чтобы  ваша программа по
хорошему завершала свою работу?  ;) Кстати, есть хитрющий способ завершения
любых  циклов  с  использованием  JUMP  директивы,  но об этом как-нибудь в
другой раз.  %)


@ENDNODE

@NODE "REPEAT..UNTIL цикл" "REPEAT..UNTIL цикл"
@Prev "WHILE цикл" 
@Toc "Циклы" 

REPEAT..UNTIL цикл
------------------

   Цикл  REPEAT..UNTIL  (ПОВТОРЯТЬ..ДО) очень похож на WHILE.  Единственное
различие  -  место  расположения проверки цикла и способ, каким выполняется
эта  самая  проверка.   Для  наглядной  демонстрации  всего вышесказанного,
вашему  вниманию  предлагается переписанная под использование REPEAT..UNTIL
цикл  программа  из  предыдущих  двух  глав  (попробуйте  найти характерные
отличия):

     PROC main()
       DEF x
       x:=1
       REPEAT
         WriteF('\\d ', x)
         x:=x+1
       UNTIL x>100
       WriteF('\\n')
     ENDPROC

Так же, как и в случае с WHILE циклом, здесь присутствует инициализация x и
дополнительный блок в цикле для увеличения x.  Однако, на этот раз проверка
располагается  в  конце  цикла  (в  UNTIL части) и выполняется она только в
конце  каждого  прохода  по  циклу.   Это  различие  означает,  что  код  в
REPEAT..UNTIL  цикле  выполняется по меньшей мере один раз, тогда как код в
WHILE цикле может и вовсе быть не выполненным ни разу.

Также,   логическое   действие   проверки  полностью  соответствует  своему
наименованию:  REPEAT..UNTIL (ПОВТОРЯТЬ..ДО) цикл работает до тех пор, пока
условие  не  примет  значение  истины,  в  то  время  как WHILE (ПОКА) цикл
выполняется,  пока  условие  истинно.   Следовательно,  REPEAT..UNTIL  цикл
функционирует  только  пока  условие  ложно!  На первый взгляд, кажется тут
черт  ногу  сломит,  но  не  надо  паники,  просто  знайте  -  как читается
конструкция так она и работает.  %)


@ENDNODE

@NODE "Подведение итогов" "Подведение итогов"
@Next "Format.guide/main" 
@Prev "Управление ходом программы" 
@Toc "Contents.guide/main" 

Подведение итогов
*****************

   Вот  и  наступил  конец  первой  части нашего суперкурса, смею надеяться
этого  достаточно для успешного начала.  Если вам удалось ухватить основные
концепции,  у  вас  хорошая  позиция для массированой атаки на Часть вторую
великой книги E, в которой потенциал языка раскрывается еще сильнее!

   Наступило самое подходящее время освежить память примерами из предыдущих
частей  курса,  ибо  сейчас  мы  постараемся  охватить  в одном примере все
базовые  конструкции  языка  Е,  которые мы изучили.  Здесь рассматривается
пример  использования  WHILE цикла.  Просто для того, чтобы было удобнее, в
данном  примере все строки пронумерованы (не пытайтесь компилировать данный
пример вместе с номерами строк!)

      1.  PROC main()
      2.    DEF x,y
      3.    x:=1
      4.    y:=2
      5.    WHILE (x<10) AND (y<10)
      6.      WriteF('x \\d и y \\d\\n', x, y)
      7.      x:=x+2
      8.      y:=y+2
      9.    ENDWHILE
     10.  ENDPROC

Теперь, если вы успешно прошли наш курс, вы способны безошибочно определить
все  директивы  и  построения,  перечисленные в таблице ниже.  Если же нет,
ничто не мешает вам вернуться к предыдущим главам курса и внести ясность во
все  возникшие  у  вас  вопросы!   Или  же  можете  поискать руководство по
программированию  на  E,  получше,  чем  то, которое вы сейчас читаете, вам
решать! B-)


     Строки   Описание
     ---------------------------------------------------------
      1-10    Определение процедуры.
     
         1    Объявление процедуры main(), без параметров.
     
         2    Объявление локальных переменных x и y.
     
      3, 4    Инициализация x и y с использованием присвоений.
     
       5-9    WHILE цикл.
     
         5    Проверка для WHILE цикла, использующая
              логический оператор AND, оператор сравнения <,
              и скобки для группировки выражения.
     
         6    Вызов встроенной процедуры WriteF()
              с использованием параметров. Параметры:
              стринг, указатели для расположения чисел,
              \\d и перевод строки \\n.
     
      7, 8    Присвоения x и y, увеличение их значений на 2.
     
         9    Указатель конца WHILE блока.
     
        10    Указатель конца всей процедуры в целом.

                  @{" И слово его повело народы! ;) " Link "Mind Engine" }

@ENDNODE


@NODE "Пояснение" "Пояснение"
@Next "Циклы" 
@Prev "SELECT..OF блок" 
@Toc "Блоки условий"

Я имел ввиду - закрывайте скобками их как следует!  :D

@ENDNODE

@NODE "Mind Engine" "Mind Engine"
@Next "Format.guide/main"  
@Prev "Подведение итогов"
@Toc "Contents.guide/main" 

Все  это время вас сопровождал и направлял я - Mind Engine, свое восхищение
вы можете выразить по адресу:  mindengine@mail.ru

                     A за сим, разрешите откланяться!
             Меня ждут другие великие свершения и подвиги! B-)

                                  Adjos!

                                 25.04.03

@ENDNODE

