Автор материала рассказывает, как с помощью 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
Поделиться с друзьями
-->

Комментарии (13)


  1. vesper-bot
    17.07.2017 15:44
    +7

    Осталось на неё портировать Дум.


    1. vlad9486
      18.07.2017 13:30

      Портировать на нее браузер и запустить ее в самой себе. Жаль памяти не хватит.


  1. LoadRunner
    17.07.2017 15:55
    +10

    Осталось реализовать Гугл-таблицы в этой виртуальной машине.


    1. evgeniy2194
      17.07.2017 17:34

      Это божественно)


    1. riky
      17.07.2017 17:56

      но сначала запустить на ней образ линукса, сделать драйвер цветного дисплея (каждая ячейка таблицы — пиксель). попутно можно написать ms paint, и обязательно косынку. а потом можно и таблицы.


  1. HerrDonUlt
    17.07.2017 18:33

    это максимальная скорость выполнения, или есть ещё возможность ускорить? Хотелось бы попробовать что-нибудь, да закодить, но вот глаза утыкаются в производительность, уж простите.


    1. Tabernakulov
      17.07.2017 18:43

      В этом материале предложена только такая скорость.


  1. Ardanay
    17.07.2017 18:33
    +1

    Ассемблер в доках — это иронично.


  1. SlavikF
    18.07.2017 09:55

    Наверное не совсем по теме, но вот вы пишете:

    Добавлять новые элементы меню в интерфейс Google Документов с помощью своих пользовательских функций

    Возможно ли с помощью вот этих скриптов приделать тэги к Google Документам? Это единственная функция, которой мне у них не хватает.
    «Приделать тэги» — это:
    — любому документу можно поставить один или несколько тэгов
    — по этим тэгам можно искать


    1. Tabernakulov
      18.07.2017 13:38

      Думаю, имеет смысл скопировать решение, предложенное автором по ссылке. И поэкспериментировать.


  1. prospero78su
    18.07.2017 16:10

    Позвольте пожать Вам руку! Я впечатлён!))


  1. knagaev
    19.07.2017 17:35

    А почему нет тега «Ненормальное програмирование»? :)


    1. Tabernakulov
      19.07.2017 17:40

      Добавили.