javascript

Как создать виртуальную машину в Google Таблицах

  • вторник, 18 июля 2017 г. в 03:13:16
https://habrahabr.ru/company/payonline/blog/319754/
  • Программирование
  • JavaScript
  • Google App Engine
  • Блог компании PayOnline


Автор материала рассказывает, как с помощью Google-таблиц создать виртуальную машину, которая генерирует числа Фибоначчи.

Недавно я заметил, что в Google Документах есть достаточно полнофункциональная система скриптов под названием Apps Script. Она позволяет вам писать на JavaScript некоторые довольно полезные вещи:

  • Запускать код в ответ на такие события, как открытие документов или изменение ячеек
  • Создавать пользовательские функции таблиц для формул в Google Таблицах
  • Использовать такие сервисы, как Google Переводчик для перевода текста или Gmail для отправки электронной почты
  • Добавлять новые элементы меню в интерфейс Google Документов с помощью своих пользовательских функций

Естественно, по этой причине мне пришлось создать что-нибудь интересное. Вот, смотрите: виртуальная машина в Google Таблицах, генерирующая числа Фибоначчи!

image

Как она работает


У ВМ есть область памяти в 100 ячеек, пронумерованных от 0 до 99. Каждая ячейка может содержать команду или целое значение.

Также существует стек, который начинается в нижней части области памяти и растет вверх.
Вот так выглядит лист ВМ, когда он пуст:

image

Обратите внимание на следующее:

  • RA, RB, RC и RD — это регистры общего назначения.
  • RI — это указатель на команду. Он указывает на следующую команду, которая должна быть выполнена в области памяти, которая подсвечивается зеленым цветом.
  • RS — это указатель на стек. Он указывает на ячейку памяти в верхней части стека. Она подсвечивается синим цветом.
  • Вывод (Output) отображает вывод программы.
  • Ошибка (Error) отображает любые ошибки, возникающие при анализе или выполнении команды.
  • Память (Memory) — это область из 100 ячеек памяти.

Чтобы запустить команду, Apps Script проверяет значение RI в фоновом режиме, чтобы понять, какая команда должна выполняться следующей. Она считывает команду в ячейке, на которую указывает RI, и анализирует ее.

Существуют команды для перемещения данных между памятью и регистрами, управления стеком или выполнения условных команд.

После выполнения команды значение RI увеличивается, чтобы указывать на следующую ячейку в памяти.

Использование


Существует специальное меню под названием «Компьютер» (Computer) с некоторыми функциями, которые используются для управления ВМ:

image

  • Запуск (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:

image

Код, начинающийся с jl ra 2 50, является функцией, которая принимает вводное значение в ra и возвращает результат в rd. Она вызывает себя рекурсивно для вычисления факториала значения в ra.

Как получить копию


Если вы хотите поиграться с ней самостоятельно, то можете сделать ее копию здесь.

Вы можете увидеть код Apps Script, выбрав «Инструменты» (Tools), а затем «Редактор скриптов» (Script Editor).

image