## forth В этой задаче нужно написать интерпретатор [языка программирования Forth](https://en.wikipedia.org/wiki/Forth_(programming_language)). Forth - это стек-ориентированный, конкатенативный (конкатенация двух фрагментов кода выражает их композицию) язык программирования. В нашем примитивном случае язык состоит из стека, хранящего целые числа, и словаря известных операций. Каждая операция вынимает некоторое (возможно нулевое) количество чисел со стека и кладёт некоторое (возможно нулевое) количество чисел на стек. Полноценный Forth, с ячейками памяти, циклами, условными переходами и множеством стандартных операций позволяет писать довольно сложные программы и используется в микропроцессорах. #### Примеры программ В каждом примере на последней строке приведено результирующее значение стека. Положить 3 числа на стек: ``` 1 2 3 Stack: 1, 2, 3 ``` Положить 2 числа на стек, исполнить операцию `+` (достать 2 числа со стека и положить на стек их сумму) ``` 1 2 + Stack: 3 ``` Положить число на стек и выполнить операцию `drop` (достать верхнее значение из стека) ``` 1 drop Stack: ``` Определить операцию ("слово" в терминологии Forth) `drop2` для удаления двух верхних значений со стека, положить 2 числа на стек и воспользоваться `drop2`: ``` : drop2 drop drop ; 1 2 drop2 Stack: ``` ### Грамматика У языка нет официальной грамматики. Она определяется простым алгоритмом. Интерпретатор считывает строку ввода, разбивает на части, используя пробелы в качестве разделителя, анализирует каждую часть на принадлежность к лексемам языка ("словам"). Все известные языку слова хранятся в словаре. Если алгоритм натыкается на знакомое слово, он исполняет связанный с ним исходный код. Незнакомые слова интерпретируются как числа и добавляются в стек. В случае успеха интерпретатор продолжает разбор входного потока. Если и поиск, и преобразование чисел завершаются неудачно, интерпретатор печатает слово, за которым следует сообщение об ошибке, указывающее, что слово не распознано, сбрасывает входной поток и ждет нового пользовательского ввода. ### Что нужно сделать? Нужно написать реализацию функций `NewEvaluator` и `Evaluator.Process`. Первая создаёт объект исполнителя Forth кода, а вторая парсит и исполняет. Требуется поддержать следующие слова: * `+`, `-`, `*`, `/` удаляют со стека два верхних значения и кладут результат соответствующей целочисленной арифметической операции * `dup` кладёт на стек верхнее значение * `over` кладёт на стек второе сверху значение * `drop` удаляет верхнее значение со стека * `swap` меняет два верхних значения стека местами При нехватке аргументов `Process` должна возвращать ошибки. Также нужно поддержать определение новых слов. ``` : word definition ; ``` где `word` -- это case-insensitive имя новой операции, а `definition` состоит из известных слов и чисел, разделённых пробелами. Слова можно переопределять. При реализации механизма определений обратите внимание на юнит-тест ```go { description: "no redefinition", input: []string{": foo 5 ;", ": bar foo ;", ": foo 6 ;", "bar foo"}, expected: []int{5, 6}, }, ``` То есть семантика слова вычисляется непосредственно при определении и не меняется при переопределении "зависимостей". ### Проверка решения Для запуска тестов нужно выполнить следующую команду: ``` go test -v ./forth/... ``` #### Интерактивная среда В [main.go](./main.go) написана небольшая обёртка вашей реализации, позволяющая интерактивно взаимодействовать с интерпретатором. ``` go build . && ./forth Welcome to Forth evaluator! To exit type "bye". >1 2 + Stack: 3 > ``` ### Ссылки * https://en.wikipedia.org/wiki/Forth_(programming_language) * https://golang.org/pkg/strings/