Current time: 26.09.2017, 06:57 Hello There, Guest! (LoginRegister)
Language: english | russian  

Post Reply 
Threaded Mode | Linear Mode
2B (Дваб)
» Форумный язык программирования (Фяп)
Author Message
Berserker Offline
Administrators

Posts: 10164
Post: #1

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

   Структура виртуальной машины (ВМ).
   ВМ построена на стёковой основе. Стёк - это список элементов, над которым определено всего две операции: добавить элемент в конец списка и получить последний элемент списка, удалив его из структуры. Стёк не имеет размеров, точнее он ограничен лишь размерами оперативной памяти пользователя. Для того, чтобы поместить элемент в стёк, достаточно лишь назвать его:
Code:
1 2 3

   После выполнения кода стёк будет содержать элементы 1, 2, 3.
   Все команды ВМ получают аргументы с вершины стёка. Например, команда сложения чисел (а также объединения строк) "add" сперва достаёт с вершины два элемента, складывает их, а затем помещает результат в стёк. Также работает и большинство других команд.
Code:
4 6 add

   После выполнения кода в стёке будет лишь одно число: 10.

   Переменные.
   В отличие от константных значений, коими являются строки ('5' или 'heh' или "привет"), числа (0, 6.777, -12), логические значения (true - истина, false - ложь) существует ещё ячейки памяти со своими собственными именами, чьи значения могут меняться по ходу выполнения программ. Такие ячейки памяти называются переменными.
Code:
'МояПерваяПеременная' var

   Создаст в текущем контексте переменную с именем "МояПерваяПеременная" и начальным значением 0. Если бы в коде кавычки были опущены, то смысл был бы иной: положить значение переменной в стёк.

   Поток управления программы.
   Редко когда логика программы не содержит условий или циклов. В двабе управление потоков программы реализовано на низком уровне, близком к ассемблеру, при помощи условных переходов и меток. Рассмотри в начале объявление меток и переходы на них.
Code:
1
4
"метка" jmp
6
:метка
add

   Что окажется на вершине стёка после выполнения данного кода? Давайте посмотрим по шагам. 1 - положили единицу в стёк. 4 - положили 4 в стёк (стёк: 1, 4). "метка" - положили строку в стёк (стёк: 1, 4, "метка"). jmp - команда перехода на метку с указанным именем. С вершины стёка достаётся значение "метка", затем ВМ определяет её адрес и переходит прямо к позиции :метка, минуя "положить в стёк 6". Далее команда сложения достанет верхние аргументы (1, 4) и положит в стёк результат сложения (5).
   Вывод: для объявления метки необходимо поставить знак двоеточия, за которым незамедлительно написать имя метки без кавычек.
   
   Условные переходы. Допустим, мы хотим написать простую программу, определяющую, какое число ввёл пользователь (для простоты будем считать, что пользователь введёт корректное число). Программа должна возвратить: "положительное" - если число > 0, "отрицательное", если число < 0 и "нуль" - если число = 0. В примере ниже используются две функции работы с консолью: read - читает ввод пользователя и помещает его в стёк, write - выводит строку на экран. Функция dup помещает в стёк копию верхнего элемента.
Code:
clrscr; очищаем экран
read; считываем число с клавиатуры
dup; помещаем его копию на вершину стёка
0; число, с которым сравниваем
>; команда возвращает логическое значение сравнения двух верхних элементов стёка (равносильно считанное_число > 0?)
'НеПоложительное'; имя метки для перехода
jf; перейти на метку если условие ложно (Jump if False)
'Положительное'; результат
'Вывод' jmp; безусловный переход к выводу результата на экран
:НеПоложительное
dup 0 <; проверяем, может быть число меньше нуля?
'РавноНулю' jf; если нет, значит равно нулю и переходим на соответствующую метку
; иначе
'Отрицательное'; результат
'Вывод' jmp; безусловный переход к выводу результата на экран
:РавноНулю
'Нуль'; результат
:Вывод
clrscr; очищаем экран
write; выводим результат

   Циклы или повторяемые действия.
   Предположим, мы хотим вывести на экран числа 1..10. Вариант "в лоб" мы даже не рассматриваем (1 write 2 write 3 write...).
Code:
'i' var; объявили переменную- счётчик цикла
1 'i' mov; присвоили переменной начальное значение 1
:Цикл
i dup write; выводим текущее значение счётчика
1 add dup 'i' mov; увеличили счётчик на 1
10 > 'Цикл' jf; повторить, пока счётчик не зайдёт за 10

   Подпрограммы и контексты.
   Линейный код рано или поздно разрастается и становится трудночитаем. На лицо необходимость разбить его на простые и понятные блоки - подпрограммы. Подпрограмму можно вызвать, передав её определённые параметры (через наш универсальный стёк). Она в свою очередь тоже может вернуть результат. Возврат из подпрограммы переводит поток управления на следующую команду после той, что вызвала подпрограмму. Важно свойство подпрограмм - то, что они обладают своим набором переменных. Все переменные, которые будут объявлены в подпрограмме, по возврату из неё будут уничтожены. Глобальными переменными называются те, которые были объявлены на самом высоком уровне. К ним есть доступ из любой подпрограммы. Однако если вы объявили глобальную переменную А, а потом локальную А, то все обращения к А в подпрограмме будут касаться только локальной переменной. Иными словами вы перекрыли область видимости переменной.
   Пример подпрограммы, сравнивающей два числа и возвращающей ("Больше", "Меньше" или "Равно")
Code:
'start' jmp; переходим на начало программы, минуя блок подпрограмм
; Подпрограмма Сравнить (a, b)
:Сравнить
'b' var 'b' mov; переменная b теперь содержит аргумент b
'a' var 'a' mov; переменная a содержит аргумент а
a b > 'НеБольше' jf
'Больше'
ret; команда возврата из подпрограммы
:НеБольше
a b < 'Равно' jf
'Меньше'
ret
:Равно
'Равно'
ret

:start
clrscr
'Введите первое число: ' write read nl write
num dup isnan 'Ошибка' jt
'Введите второе число: ' write read nl write
num dup isnan 'Ошибка' jt
'Сравнить' call
ret
:Ошибка
'Некорректный ввод!' write
22.08.2010 19:23
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 10164
Post: #2

Список комманд:
Code:
// Работа с переменными
'var':  Объявление переменной (Name)
mov:  Установить значение переменной (NewValue, VarName)
val:  Получить значение переменной по её имени (VarName)
get:  Получить значение свойства объекта (AttrName, Object)
set:  Установить значение свойства объекта (NewValue, AttrName, Object)
del:  Удалить свойство у объекта (AttrName, Object)
obj:  Вызов метода объекта (Arguments..., NumberOfArguments, MethodName, Object)
nil:  Возвращает пустой объект
arr:  Возвращает пустой массив
// Системные
push:  Положить в стёк (Value), неявный вызов через само значение:    5 'hellow' true
pushvar:  Положить в стёк значение переменной (VarName), неявный вызов через имя переменной:    a b c
// Работа со стёком
dup:  Продублировать значение на верхушке стёка (Value)
swap:  Меняет местами два верхних элемента стёка (Value1, Value2)
drop:  Удаляет верхний элемент со стёка (Value)
copy:  Положить в стёк копию N-ого элемента стёка, считая от вершины (N), нумерация элементов с нуля
// Математические
inc:  Увеличивает на один (Value)
dec:  Уменьшает на один (Value)
add:  Складывает два числа (a, b), => a + b
sub:  Вычитает два числа (a, b), => a - b
mul:  Перемножает два числа (a, b) => a * b
div:  Делит два числа (a, b) => a / b
mod:  Возвращает остаток от деления a на b (a, b) => Остаток (a / b)
pow:  Возводит число в степень (Value, Power) => Value^Power
exp:  Возвращает e в степени Power (Power) => e^Power
ln:  Натуральный логарифм от x (x) => ln x
abs:  Возвращает модуль числа (x) => |x|
sqrt:  Квадратный корень из числа (x) => x^0.5
floor:  Возвращает наибольшее целое, меньшее или равное аргументу
ceil:  Округляет число в большую сторону (x):    4.1 => 5, 4.6 => 5, 4.0 = > 4
round:  Округляет число по правилам математики (x):    4.4 => 4, 4.5 => 5
min:  Возвращает минимальное из двух чисел (a, b)
max:  Возвращает максимальное из двух чисел (a, b)
rand:  Возвращает псевдослучайное число с плавающей запятой в диапазоне 0..1:    0,256875696...
sin:  Синус числа (x)
cos:  Косинус числа (x)
tan:  Тангес числа (x)
asin:  Арксинус числа (x)
acos:  Арккосинус числа (x)
atan:  Арктангенс числа (x)
// Преобразования и проверки типов
isnan:  Возвращает true, если число не является числом
num:  Преобразует аргумент к числу. Осторожно, нужна проверка на isnan
str:  Преобразует аргумент в строку
// Логические операции (возвращают true или false)
'=':  Возвращает true, если два значения равны и их типы одинаковы (a, b)
'<>':  Возвращает true, если два значения не равны или их типы разные (a, b)
'<':  Возвращает true, если a < b (a, b)
'<=':  Возвращает true, если a <= b (a, b)
'>':  Возвращает true, если a > b (a, b)
'>=':  Возвращает true, если a >= b (a, b)
// Операции над логическими типами (с автоматическим приведением аргументом к логическому)
'and':  Возвращает true, если оба аргумента истинны (a, b)
'or':  Возвращает true, если хотя бы один из аргументов истинен (a, b)
'xor':  Возвращает true, если первый аргумент либо второй истинен (a, b)
'not':  Логическое отрицание аргумента (a):    true => false, false => true
// Операции над группами бит
bitand:  AND (a, b)
bitor:  OR (a, b)
bitxor:  XOR (a, b)
bitnot:  NOT (a)
// Управление потом исполнения
jmp:  Осуществляет прыжок на указанную метку (LabelName)
jt:  Прыжок на метку, если условие истинно (Condition, LabelName)
jf:  Прыжок на метку, если условие ложно (Condition, LabelName)
call:  Вызов подпрограммы (LabelName)
callt:  Вызов подпрограммы, если условие истинно (Condition, LabelName)
callf:  Вызов подпрограммы, если условие ложно (Condition, LabelName)
ret:  Возврат из подпрограммы или основного кода
// Диалоги
alert:  Отображает сообщение с указанным текстом (Message)
// Консоль
clrscr:  Очищает окно консоли
read:  Считывает строку из консоли
write:  Выводит строку в консоль
sleep:  Ожидание в миллисекундах

Список констант:
Code:
'true': true,
'false': false,
'nl': '',
'NaN': NaN,
'INF-': Number.NEGATIVE_INFINITY,
'INF+': Number.POSITIVE_INFINITY,
'e': Math.E,
'pi': Math.PI,
'log2e': Math.LOG2E,
'log10e': Math.LOG10E
22.08.2010 20:31
Find all posts by this user Quote this message in a reply
« Next Oldest | Next Newest »
Post Reply 


Forum Jump:

Powered by MyBB Copyright © 2002-2017 MyBB Group