Clem - это минимальный стековый язык программирования с функциями первого класса. Ваша цель - написать переводчика для языка Clem. Следует правильно выполнить все примеры, включенные в справочную реализацию, которая доступна здесь .
- Как обычно, применяются стандартные лазейки .
- Наименьший вход по количеству байтов выигрывает.
Клемский язык
Clem - это стековый язык программирования с первоклассными функциями. Лучший способ выучить Клема - запустить clem
интерпретатор без аргументов. Он начнется в интерактивном режиме, что позволит вам играть с доступными командами. Чтобы запустить примеры программ, введите clem example.clm
где example - название программы. Этого краткого урока должно быть достаточно, чтобы вы начали.
Есть два основных класса функций. Атомарные функции и составные функции. Составные функции - это списки, составленные из других составных функций и атомарных функций. Обратите внимание, что составная функция не может содержать себя.
Атомные функции
Первый тип атомарной функции является константой . Константа это просто целое значение. Например, -10. Когда интерпретатор встречает константу , он помещает ее в стек. Беги clem
сейчас. Введите -10
в командной строке. Тебе следует увидеть
> -10
001: (-10)
>
Значение 001
описывает положение функции в стеке и (-10)
является константой, которую вы только что ввели. Теперь введите +11
в подсказке. Тебе следует увидеть
> +11
002: (-10)
001: (11)
>
Обратите внимание, что (-10)
переместился на вторую позицию в стеке и (11)
теперь занимает первую. Это природа стека! Вы заметите, что -
это также команда декремента. Всякий раз, когда -
или +
перед числом, они обозначают знак этого числа, а не соответствующую команду. Все остальные элементарные функции являются командами . Всего 14:
@ Rotate the top three functions on the stack
# Pop the function on top of the stack and push it twice
$ Swap the top two functions on top of the stack
% Pop the function on top of the stack and throw it away
/ Pop a compound function. Split off the first function, push what's left,
then push the first function.
. Pop two functions, concatenate them and push the result
+ Pop a function. If its a constant then increment it. Push it
- Pop a function. If its a constant then decrement it. Push it
< Get a character from STDIN and push it to the stack. Pushes -1 on EOF.
> Pop a function and print its ASCII character if its a constant
c Pop a function and print its value if its a constant
w Pop a function from the stack. Peek at the top of the stack. While it is
a non-zero constant, execute the function.
Ввод команды в командной строке выполнит команду. Введите #
в командной строке (дублирующая команда). Тебе следует увидеть
> #
003: (-10)
002: (11)
001: (11)
>
Обратите внимание, что (11) было продублировано. Теперь введите %
в командной строке (команда сброса). Тебе следует увидеть
> %
002: (-10)
001: (11)
>
Чтобы поместить команду в стек, просто заключите ее в скобки. Введите (-)
в командной строке. Это перенесет оператор декремента в стек. Тебе следует увидеть
> (-)
003: (-10)
002: (11)
001: (-)
>
Составные функции
Вы также можете заключить несколько атомарных функций в круглые скобки, чтобы сформировать составную функцию. Когда вы вводите составную функцию в приглашении, она помещается в стек. Введите ($+$)
в командной строке. Тебе следует увидеть
> ($+$)
004: (-10)
003: (11)
002: (-)
001: ($ + $)
>
Технически все в стеке является составной функцией. Однако некоторые составные функции в стеке состоят из одной атомарной функции (в этом случае мы будем считать их атомарными функциями для удобства). При манипулировании составными функциями в стеке .
команда (сцепление) часто бывает полезна. Введите .
сейчас. Тебе следует увидеть
> .
003: (-10)
002: (11)
001: (- $ + $)
>
Обратите внимание, что первая и вторая функции в стеке были объединены, и что вторая функция в стеке стоит первой в результирующем списке. Чтобы выполнить функцию, находящуюся в стеке (атомарную или составную), мы должны выполнить w
команду (while). Команда w
вставляет первую функцию в стек и выполняет ее многократно, если вторая функция в стеке является ненулевой константой. Попробуйте предсказать, что произойдет, если мы введем w
. Теперь введите w
. Тебе следует увидеть
> w
002: (1)
001: (0)
>
Это то, что вы ожидали? Два числа, находящиеся на вершине стека, были добавлены, и их сумма остается. Давайте попробуем это снова. Сначала мы опустим ноль и нажмем 10, набрав %10
. Тебе следует увидеть
> %10
002: (1)
001: (10)
>
Теперь мы напечатаем всю функцию за один раз, но %
в конце добавим дополнительную, чтобы избавиться от нуля. Введите (-$+$)w%
в командной строке. Тебе следует увидеть
> (-$+$)w%
001: (11)
>
(Обратите внимание, что этот алгоритм работает, только если первая константа в стеке положительна).
Струны
Строки также присутствуют. Они в основном синтаксические сахара, но могут быть весьма полезными. Когда интерпретатор встречает строку, он помещает каждый символ от последнего к первому в стек. Тип, %
чтобы отбросить 11 из предыдущего примера. Теперь введите 0 10 "Hi!"
приглашение. 0
Будет вставить NULL терминатора и 10
вставляет символ новой строки. Тебе следует увидеть
> 0 10 "Hi!"
005: (0)
004: (10)
003: (33)
002: (105)
001: (72)
>
Печатайте (>)w
символы из стека, пока мы не встретим терминатор NULL. Тебе следует увидеть
> (>)w
Hi!
001: (0)
>
Выводы
Надеюсь, этого будет достаточно, чтобы вы начали работать с переводчиком. Дизайн языка должен быть относительно простым. Дайте мне знать, если что-то ужасно неясно :) Несколько вещей были намеренно оставлены неопределенными: значения должны быть подписаны и не менее 16 бит, стек должен быть достаточно большим, чтобы запускать все справочные программы и т. Д. Многие детали не были вырезаны здесь, потому что полная спецификация языка была бы слишком большой для публикации (а я еще не написал: P). Если есть сомнения, имитируйте эталонную реализацию.