Интерпретировать Киппл!

12

Вступление

Kipple - основанный на стеке эзотерический язык программирования, изобретенный Руне Бергом в марте 2003 года.

Киппл имеет 27 стеков, 4 оператора и структуру управления.

Стеки

Стопки названы a- zи содержат 32-битные целые числа. Существует также специальный стек @, чтобы сделать вывод чисел более удобным. Когда число вводится, @вместо него на самом деле вставляются значения ASCII цифр этого числа. (Например, если вы нажмете 12 к @, @вместо этого будет 49, а затем 50 ).

Ввод помещается в стек ввода iперед выполнением программы. Интерпретатор запросит значения для хранения iперед выполнением. После завершения выполнения все в выходном стеке oвыводится как символ ASCII. Так как это единственный механизм ввода-вывода в Kipple, взаимодействие с программой Kipple невозможно.

операторы

Операндом является либо идентификатор стека, либо 32-разрядное целое число со знаком.

Нажмите: >или<

Синтаксис: Operand>StackIndentifierилиStackIndentifier<Operand

Оператор Push берет операнд влево и помещает его в указанный стек. Например, 12>aпоместит значение 12 в стек a. вытолкнет a>bсамое верхнее значение из стека aи поместит его в стек b. Выгрузка пустого стека всегда возвращает 0. a<bЭто эквивалентно b>a. a<b>cвыскакивает самое верхнее значение из bи выдвигает к обоим cи a.

Добавлять: +

Синтаксис: StackIndentifier+Operand

Оператор Add помещает сумму самого верхнего элемента в стеке и операнда в стек. Если операнд является стеком, то значение извлекается из него. Например, если самое верхнее значение стека aравно 1, то a+2на него будет помещено 3. Если aпусто, то a+2нажмите 2 на него. Если самые верхние значения стека aи b1 и 2, то вытолкнет a+bзначение 2 из стека bи вставит 3 в стек a.

Вычесть: -

Синтаксис: StackIndentifier-Operand

Оператор Subtract работает точно так же, как оператор Add, за исключением того, что он вычитает вместо добавления.

Ясно: ?

Синтаксис: StackIndentifier?

Оператор Clear очищает стек, если его самый верхний элемент равен 0.

Переводчик будет игнорировать все , что не рядом с оператором, поэтому следующая программа будет работать: a+2 this will be ignored c<i. Тем не менее, правильный способ добавления комментариев - использование #символа. Все, что находится между a #и символом конца строки, удаляется перед выполнением. ASCII символ # 10 определяется как конец строки в Kipple.

Операнды могут совместно использоваться двумя операторами, например, a>b c>b c?могут быть записаны как a>b<c?.

Программа 1>a<2 a+aбудет aсодержать значения [1 4](снизу вверх), а не содержать [1 3]. Аналогично для -оператора.

Структура управления

В Kipple есть только одна структура управления: цикл.

Синтаксис: (StackIndentifier code )

Пока указанный стек не пуст, код в соответствующих скобках будет повторяться. Петли могут содержать другие петли. Например, (a a>b)переместит все значения стека aв стек b, хотя порядок будет обратным . Функционально идентичный, но более элегантный способ сделать это (a>b).

Примеры

100>@ (@>o)

Это будет выводить 100

33>o 100>o 108>o 114>o 111>o 87>o 32>o 111>o 108>o 108>o 101>o 72>o

Это напечатает "Hello World!". Когда oвыводится стек, он начинает выскакивать символы сверху вниз в стеке.

#prime.k by Jannis Harder
u<200
#change 200


k<2>m
u-2
(u-1 u>t u>z u<t
  (k>e e+0 e>r)
  (e>k)
  m+1
  m>t
  m>z
  m<t
  t<0>z? t?
  1>g
  (r>b
    m+0 m>a
    b+0 b>w
    (a-1 
      b+0 b>j
      j?
      1>s
      (j<0>s j?)
      s?
      (s<0 w+0 w>b s?)
      a>t
      a>z
      t>a
      b-1
      b>t
      b>z
      t>b
      z<0>t? z?
    a?)
    b?
    1>p
    (b<0 b? 0>p)
    p?
    (p 0>r? 0>p? 0>g)
  )
  g?
  (g m+0 m>k 0>g?)
u?)
(k>@
  10>o
  (@>o)
)

Это генератор простых чисел, но я не уверен, как он работает.

правила

  • Вы должны написать программу / функцию, которая интерпретирует Kipple. Эта программа / функция может получить программу Kipple через исходный файл или получить ее через STDIN непосредственно от пользователя. Если STDIN недоступен, он должен получить его с клавиатуры и продолжать получать до тех пор, пока не будет введен определенный непечатаемый символ. Например, если ваш интерпретатор написан на машинном коде x86, он будет получать символьно-программную программу Kipple с клавиатуры и продолжит делать это до тех пор, пока esc(или любая другая клавиша, которая не выдает печатный символ), не будет нажата.

  • Если есть ошибка, например, синтаксическая ошибка или переполнение стека, она должна каким-то образом подтвердить ее, например, возвращая 10 вместо 0 или сообщения об ошибках, выданные интерпретатором / компилятором, НО НЕ ПЕЧАТЬ СООБЩЕНИЙ ОШИБКИ .

  • Любые другие обычные правила для кода гольф применяются для этой задачи.

  • Ваш код будет протестирован с некоторыми примерами в архиве примеров Kipple.

Это . Самый короткий код в байтах победит. Удачи!


Обратите внимание, что в Kipple есть необязательный оператор, "но он не является частью спецификации, а просто дополнительной функцией в официальном интерпретаторе. Я не упомянул об этом здесь, поэтому его не нужно поддерживать в вашем представлении.

Если у вас есть какие-либо сомнения относительно какой-либо части спецификации, вы можете проверить ее с помощью официального переводчика, написанного на Java . Это загрузит zip-файл, содержащий скомпилированную программу и исходный код. Он лицензирован по лицензии GPL.


источник
1
У нас есть использовать 32-битные целые числа или мы можем пойти с естественным целочисленным типом реализации языка- хозяина? (Наиболее важными случаями, вероятно, являются 32-разрядные целые числа без знака, 8-разрядные целые числа со знаком или без знака и целые числа произвольной точности.)
Мартин Эндер,
ну, это было то, что я нашел в esotric wiki. да, потому что ваш интерпретатор может быть несовместим с другими программами kipple, механизм которых основан на этой функции
Можете ли вы быть более конкретным о поведении в случае ошибок? Таким образом, мы можем вернуть неправильный ответ или выдать ошибку, но мы не можем распечатать ошибку?
Алекс А.
@ Алекс А. Да, потому что это можно рассматривать как вывод программы, и вы можете создать программу, которая будет иметь тот же вывод, что и сообщение об ошибке. Также «дешевле» (использует меньше символов) отсутствие функции / оператора, который печатает сообщение об ошибке.
3
Какие пробелы могут появиться в исходной программе? Как я могу запросить ввод, iесли я беру исходную программу из стандартного ввода ?
orlp

Ответы:

6

C 709 702 байта

Счет байтов с удаленными символами новой строки (которые могут быть удалены), но для простоты чтения я выкладываю их здесь с символами новой строки:

#define R return
#define C ;break;case
c[999]={};*P=c;*S[28];M[99999]={};t;*T;
u(s,v){S[s]+=28;*S[s]=v;
if(s>26){for(t=v/10;t;t/=10)S[s]+=28;T=S[s];do{*T=48+v%10;T-=28;}while(v/=10);}}
o(s){t=S[s]-M>27;S[s]-=28*t;R S[s][28]*t;}
I(s){R s<65?27:s-97;}
O(int*p){if(!isdigit(*p))R o(I(*p));
for(;isdigit(p[-1]);--p);for(t=0;isdigit(*p);t*=10,t+=*p++-48);R t;}

main(i,a){for(i=0;i<28;++i)S[i]=M+i;
for(;~(*++P=getchar()););P=c+1;
for(;;){i=I(P[-1]);switch(*P++){
case 35:for(;*P++!=10;)
C'<':u(i,O(P))
C'>':u(I(*P),O(P-2))
C'+':u(i,*S[i]+O(P))
C'-':u(i,*S[i]-O(P))
C'?':if(!*S[i])S[i]=M+i
C'(':for(i=1,T=P;i;++T)i+=(*T==40)-(*T==41);if(S[I(*P)]-M<28)P=T;else u(26,P-c)
C')':P=c+o(26)-1
C-1:for(;i=o(14);)putchar(i); R 0;}}}

Скомпилируйте с gcc -w golf.c( -wзаставляет замолчать предупреждения для вашего здравомыслия).

Поддерживает все, кроме iввода, так как спрашивающий еще не ответил на мой вопрос о том, как это сделать, если вы берете код из stdin. Он не сообщает о синтаксических ошибках.

orlp
источник
Я ответил на ваш вопрос о стеке «i» в комментариях к главному посту.
Кстати, как он читает программы Kipple? через аргументы команды? как я должен использовать это?
@GLASSIC Ожидает программу на стандартный ввод.
orlp
До тех пор, пока не ? Как начать excution?
@ GLASSIC Просто передайте программу на стандартный ввод. Например ./a.out < prime.k.
orlp
3

Ruby, 718 байт (в настоящее время неконкурентоспособен)

я очень устал

Файл загружается как аргумент командной строки, а входные данные отправляются через STDIN. В качестве альтернативы, отправьте файл в STDIN, если вам не нужен ввод в iрегистр.

Из-за некоторой путаницы в отношении спецификации, текущая версия не обрабатывается a<b>cдолжным образом, и, следовательно, неконкурентоспособна, пока не будет исправлена.

a<b>cисправлено сейчас. Тем не менее, он по-прежнему возвращает неправильный результат при запуске функции простых чисел, поэтому он по-прежнему остается неконкурентным ответом.

(f=$<.read.gsub(/#.*?\n|\s[^+-<>#()?]*\s/m,' ').tr ?@,?`
t=Array.new(27){[]}
t[9]=STDIN.read.bytes
k=s=2**32-1
r=->c{c=c[0];c[0]==?(?(s[c[1..-2]]while[]!=t[c[1].ord-96]):(c=c.sub(/^(.)<(\D)>(.)/){$1+"<#{t[$2.ord-96].pop||0}>"+$3}.sub(/(\d+|.)(\W)(\d+|.)?/){_,x,y,z=*$~
a=x.ord-96
b=(z||?|).ord-96
q=->i,j=z{j[/\d/]?j.to_i: (t[i]||[]).pop||0}
l=t[a]
y<?-?(x==z ?l[-1]*=2:l<<(l.pop||0)+q[b]
l[-1]-=k while l[-1]>k/2):y<?.?(x==z ?l[-1]=0:l<<(l.pop||0)-q[b]
l[-1]+=k while l[-1]<-k/2-1):y<?>?t[a]+=a<1?q[b].to_s.bytes: [q[b]]:y<???
(t[b]+=b<1?q[a,x].to_s.bytes: [q[a,x]]): l[-1]==0?t[a]=[]:0
z||x}while c !~/^(\d+|.)$/)}
s=->c{(z=c.scan(/(\((\g<1>|\s)+\)|[^()\s]+)/m)).map &r}
s[f]
$><<t[15].reverse.map(&:chr)*'')rescue 0
Значение чернил
источник
+1 в любом случае. Вы пробовали программу Фибоначчи?
edc65
@ edc65 Программа последовательности Фиббоначи также печатает неправильную вещь: 0 1 1 2 4 8 16...интересно, если это ошибка спецификации
Value Ink
Нет, программа Фибоначчи - это дерьмо, например, строка a+0чепуха
edc65
Я предполагаю, что проблема простых чисел в том, что она не обрабатывает вложенные управляющие структуры, но я не знаю много о ruby, сомневаюсь, что мои догадки верны.
Эта программа должна правильно обрабатывать вложенные наборы паренов из-за рекурсивного совпадения регулярных выражений, /(\((\g<1>|\s)+\)|[^()\s]+)/mкоторое она использует для разделения на токены и группы токенов. ( Проверьте это на regex101 ). Это, вероятно, ошибка в остальной части моего анализа, но я не знаю, где.
Value Ink