SECD - виртуальная функциональная машина
Деревья и их записьРассмотрим бинарные деревья, состоящие из узлов и листьев. Каждый узел имеет два подчиненных дерева: правое и левое. Листья содержат слова, состоящие из букв и символа подчеркивания. Например: У некоторых узлов листья могут отсутствовать. Будем обозначать их специальным значением NIL. Для записи дерева “в строку” будем использовать такой способ: ( левое_поддерево . правое_поддерево ) Дерево из предыдущего примера будет выглядеть так: ( мама . ( мыла . раму ) ) Для сокращения записи длинных деревьев “с правым уклоном” будем применять следующие правила:
Тогда дерево из предыдущего примера можно переписать так: ( мама мыла . раму ) Регистры машиныНаша вычислительная машина будет оперировать деревьями. Обрабатываемые деревья хранятся в пяти регистрах с именами “стек”, “аргументы”, “команды”, “история” и “словарь”. Стек предназначен для обрабатываемых данных. Большинство команд так или иначе преобразуют содержимое стека. Левое поддерево стека будем называть верхним, или первым элементом. В регистре команд находится список команд, которые надо выполнить. Машина циклически извлекает первую команду из списка и выполняет ее, т.е. преобразует содержимое всех регистров в соответствии со смыслом команды. Регистр аргументов содержит значения аргументов текущей выполняемой функции. Их значения доступны посредством команды _arg. Регистр истории заполняется при вызове функции и хранит необходимые данные для возврата к вызывающей функции. Команда _if также выполняется аналогично вызову функции и использует регистр истории. Регистр словаря содержит информацию обо всех функциях, определенных командой _define и доступных для вызова командой _call. ВыполнениеЕсли в качестве команды выступает слово, начинающееся с символа подчеркивания, оно выполняется по специальному алгоритму. Иначе команда заносится в регистр стека в качестве левого поддерева:
Это также можно отобразить в следующем виде:
ВозвратЕсли регистр команд оказался пустым, это означает, что выполнение текущей функции закончено, и следует вернуться к вызывающей функции. Если регистр истории непустой, производится следующее действие:
Если же и регистр команд, и регистр истории пусты, машина завершает работу, и результатом выполнения программы считается значение на вершине стека.
Специальные команды_head – выделение левого поддереваКоманда _head извлекает из стека верхний элемент и заменяет его на левое поддерево этого элемента.
_tail – выделение правого поддереваКоманда _head извлекает из стека верхний элемент и заменяет его на правое поддерево этого элемента.
_cons – создание дереваКоманда _cons извлекает из стека два верхних элемента, объединяет их в дерево и помещает результат в первый элемент стека.
_sym – проверка словаКоманда _sym проверяет, является ли верхний элемент стека простым словом. Она замещает верхний элемент словом TRUE в случае простого слова, или FALSE в случае дерева или значения NIL.
Здесь t равно TRUE или FALSE.
_eq – сравнение деревьевКоманда _cons извлекает из стека два верхних элемента, проверяет их на равенство и помещает результат TRUE или FALSE в первый элемент стека. Два дерева считаются равными, если они “выглядят” одинаково.
Здесь t равно TRUE или FALSE.
_if – условный операторКоманда _if извлекает из стека верхний элемент и выбирает один из потоков команд, в зависимости от истинности значения. Если остаток регистра команд непуст, состояние регистров сохраняется в истории, как при команде _call.
Здесь y равно a если x равно TRUE, иначе y равно b.
Если остаток регистра команд `c’ пустой, то команда выполняется более оптимальным образом (конечная рекурсия):
_arg – извлечение аргумента функцииКоманда _arg помещает на стек копию списка аргументов текущей функции из регистра аргументов. Конкретные аргументы затем можно вычислить комбинацией команд _head и _tail.
_def – определение новой функцииКоманда _define извлекает из стека имя и тело новой функции, и добавляет их в начало регистра словаря. При поиске функции словарь просматривается от начала к концу, поэтому новое определение может “затенять” старое определение функции с тем же именем.
_call – вызов функцииКоманда _call:
Если остаток регистра команд `c’ пустой, то команда выполняется более оптимальным образом (конечная рекурсия):
Copyright (C) 2001-2005 Сергей Вакуленко |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||