https://habrahabr.ru/company/payonline/blog/319754/- Программирование
- JavaScript
- Google App Engine
- Блог компании PayOnline
Автор материала рассказывает, как с помощью Google-таблиц создать виртуальную машину, которая генерирует числа Фибоначчи.
Недавно я заметил, что в Google Документах есть достаточно полнофункциональная система скриптов под названием
Apps Script. Она позволяет вам писать на JavaScript некоторые довольно полезные вещи:
- Запускать код в ответ на такие события, как открытие документов или изменение ячеек
- Создавать пользовательские функции таблиц для формул в Google Таблицах
- Использовать такие сервисы, как Google Переводчик для перевода текста или Gmail для отправки электронной почты
- Добавлять новые элементы меню в интерфейс Google Документов с помощью своих пользовательских функций
Естественно, по этой причине мне пришлось создать что-нибудь интересное. Вот, смотрите: виртуальная машина в Google Таблицах, генерирующая
числа Фибоначчи!
Как она работает
У ВМ есть область памяти в 100 ячеек, пронумерованных от 0 до 99. Каждая ячейка может содержать команду или целое значение.
Также существует стек, который начинается в нижней части области памяти и растет вверх.
Вот так выглядит лист ВМ, когда он пуст:
Обратите внимание на следующее:
- RA, RB, RC и RD — это регистры общего назначения.
- RI — это указатель на команду. Он указывает на следующую команду, которая должна быть выполнена в области памяти, которая подсвечивается зеленым цветом.
- RS — это указатель на стек. Он указывает на ячейку памяти в верхней части стека. Она подсвечивается синим цветом.
- Вывод (Output) отображает вывод программы.
- Ошибка (Error) отображает любые ошибки, возникающие при анализе или выполнении команды.
- Память (Memory) — это область из 100 ячеек памяти.
Чтобы запустить команду, Apps Script проверяет значение RI в фоновом режиме, чтобы понять, какая команда должна выполняться следующей. Она считывает команду в ячейке, на которую указывает RI, и анализирует ее.
Существуют команды для перемещения данных между памятью и регистрами, управления стеком или выполнения условных команд.
После выполнения команды значение RI увеличивается, чтобы указывать на следующую ячейку в памяти.
Использование
Существует специальное меню под названием «Компьютер» (Computer) с некоторыми функциями, которые используются для управления ВМ:
- Запуск (Run) запускает текущую программу до ее окончания или обнаружения ошибки.
- Шаг (Step) запускает одну команду, а затем приостанавливается.
- Сброс (Reset) очищает все регистры и поле вывода, тем самым подготавливая программу к повторному запуску.
- Загрузка факториальной программы (Load Factorial Program) загружает факториальный пример из другой таблицы.
- Загрузка программы Фибоначчи (Load Fibonacci Program) загружает пример Фибоначчи с другого листа.
Команды
Существует несколько реализованных команд:
Общие- mov dst src копирует значение из src в dst.
Математические- add dst src прибавляет dst к src и сохраняет результат в dst.
- sub dst src вычитает src из dst и сохраняет результат в dst.
- mul dst src умножает dst на src и сохраняет результат в dst.
Операции со стеком- push src загружает src в стек.
- pop dst извлекает значение из верхушки стека и сохраняет его в dst.
Переходы и условные команды- jmp target переходит к команде в ячейке, на которую ссылается target.
- jl cmp1 cmp2 target сравнивает cmp1 с cmp2. Если cmp1 меньше, чем cmp2, выполнение переходит к target.
Функции- call target — это вызов функции. Он загружает текущий указатель на команду в стек, чтобы он мог быть возвращен позже, а затем переходит к target.
- ret возвращает функцию. Он извлекает значение из стека и переходит к нему.
Прочее- output src записывает src в Вывод (Output): раздел интерфейса.
- end завершает программу.
Способы адресации
Операнды в приведенных выше командах могут принимать несколько форм:
Immediates — это литеральные значения, встроенные в команду. Примеры: 7 и123. Например, чтобы скопировать значение 7 в регистр ra:
mov ra 7
Registers ссылаются на регистры по имени. Примеры: ra, rb, rc. Чтобы скопировать значение из rc в rb:
mov rb rc
Memory ссылается на значение внутри ячейки области памяти. Примеры: $0, $10, $99. Чтобы скопировать значение из ra в первую ячейку памяти:
mov $0 ra
Чтобы скопировать значение из последней ячейки памяти в rd:
mov rd $99
Indirect ссылается на значение, на которое указывает ячейка памяти. Примеры: @15, @50. Поэтому, если ячейка памяти 10 содержит значение 20, а ячейка памяти 20 содержит значение 30, вы можете скопировать значение 30 в ra следующим образом:
mov ra @10
Он проверяет ячейку памяти 10, чтобы найти значение 20. Затем он обращается к ячейке памяти 20, чтобы найти значение 30, и копирует это значение в ra.
Рекурсия
Вы можете использовать стек и команды call и ret для выполнения рекурсивных вызовов. Вот пример, который использует рекурсию для генерации факториала числа 5:
Код, начинающийся с jl ra 2 50, является функцией, которая принимает вводное значение в ra и возвращает результат в rd. Она вызывает себя рекурсивно для вычисления факториала значения в ra.
Как получить копию
Если вы хотите поиграться с ней самостоятельно, то можете сделать ее копию
здесь.
Вы можете увидеть код Apps Script, выбрав «Инструменты» (Tools), а затем «Редактор скриптов» (Script Editor).