104 lines
5.4 KiB
Markdown
104 lines
5.4 KiB
Markdown
## 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 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/
|