Печать, Инкремент, Декремент, Псевдоним - Interpret Prindeal

30

Prindeal (произносится как prin-dee-al ) - это новый эзотерический язык программирования, который имеет только четыре команды: pr int , in crement , de crement и al ias . Несмотря на минимализм, в Prindeal можно выполнять сложные математические операции, умело комбинируя четыре команды.

Ваша задача в этом коде состоит в том, чтобы написать самую короткую программу, которая может запускать код Prindeal.

Спецификация длинная, но я постарался сделать ее как можно более понятной, и я верю, что если вы приложите усилия, чтобы изучить Prindeal, вы найдете ее довольно элегантной!


Интерпретация Приндейла

предварительная обработка

Перед интерпретацией программы Prindeal из нее необходимо удалить эти вещи в следующем порядке:

  1. Все, что идет после #знака до конца строки, плюс #само. (Это комментарии.)
  2. Конечный пробел на любой строке.
  3. Полностью пустые строки.

Например, программа Prindeal

p cat #The next line has 7 trailing spaces.
p dog       

#p mouse

будет предварительно обработан в

p cat
p dog

С этого момента мы будем предполагать, что этот шаг предварительной обработки был выполнен.

переменные

Нам нужно быстро определить переменные, прежде чем показывать, как они используются.

Переменные (и ссылки на переменные) - это то, что передается в аргументы команд Prindeal. Переменные всегда являются глобальными , поэтому изменения переменной, независимо от того, где они происходят, отражаются повсеместно.

Каждая переменная содержит неотрицательное целое число произвольной точности (0, 1, 2, 3, ...). Переменные не нужно предварительно инициализировать - они всегда начинаются со значения 0 при первом использовании или вызове.

Имя переменной может быть любой непустой строкой буквенно-цифровых символов и подчеркиваний, которая не начинается с цифры - [a-zA-Z_][0-9a-zA-Z_]*в регулярном выражении . Они чувствительны к регистру, поэтому spiny_lumpsuck3rи Spiny_lumpsuck3rявляются разными переменными.

выполнение

Prindeal - это императивный язык программирования. Когда программа Prindeal запущена, ее операторы выполняются сверху вниз по порядку, а затем программа завершается.

Каждый без отступа строки в Prindeal программы является утверждение , что включает в себя выполнение одной команды , которые могут или не могут принимать аргументы.

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

Не псевдонимы Заявления

За исключением псевдонима , каждое утверждение в программе Prindeal имеет вид:

[command name] [argument 1] [argument 2] [argument 3] ...

Может быть произвольное количество аргументов (включая их вообще). Каждый аргумент всегда является переменной или (как мы увидим при обсуждении псевдонима ) ссылкой на переменную .

По завершении выполнения каждый оператор помечается как неудачный или успешный в зависимости от того, были ли обнаружены ошибки или нет. (Это действительно имеет значение, только когда мы используем псевдоним .)

Встроенные функции print , increment и expment являются операторами с вышеуказанной формой. Вот что они делают:

  1. print имеет имя команды pи принимает один аргумент. Он печатает имя переданной переменной и ее значение (в десятичной дроби), разделенные знаком «=», а затем символ новой строки. Это всегда помечается как успех .

    Например, программа Prindeal

    p _MyVariable_321
    p screaming_hairy_armadillo
    

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

    _MyVariable_321 = 0
    screaming_hairy_armadillo = 0
    

    потому что все переменные начинаются с 0. (Пробелы до и после знака равенства обязательны).

  2. инкремент имеет имя команды iи принимает один аргумент. Он увеличивает значение переменной, переданной на 1. Он всегда помечается как успешный .

    Например, программа

    i alpaca
    p alpaca
    i alpaca
    p alpaca
    

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

    alpaca = 1
    alpaca = 2
    

    Обратите внимание, как alpacaбыл увеличен с 0 до 1, хотя он никогда не был доступен раньше.

  3. декремент имеет имя команды dи принимает один аргумент. Если переданная переменная отлична от нуля, ее значение уменьшается на 1, и оператор помечается как успешный . Если переданная переменная равна 0, то ничего не делается, и оператор помечается как сбой .

    Например, программа

    i malamute
    p malamute
    d malamute    #success
    p malamute
    d malamute    #failure
    p malamute
    d akita       #failure
    p akita
    

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

    malamute = 1
    malamute = 0
    malamute = 0
    akita = 0
    

    Обратите внимание, что уменьшение переменной со значением 0 является единственным способом вызвать ошибку .

Псевдоним Постановка и команды Связанных

Команда псевдонимов имеет специальный синтаксис и является наиболее мощной, поскольку ее можно использовать для определения новых команд. Псевдоним имя команды aи псевдоним оператор имеет вид:

a [name of new command]
 [statement A]
 [statement B]
 [statement C]

Где каждый [statement X]представляет какое-либо утверждение без псевдонима , то есть что-то с формой [command name] [argument 1] [argument 2] [argument 3] ....

Имя псевдонима команды [name of new command]может быть любой непустой строкой буквенно-цифровых символов и подчеркиваний, которая начинается не с цифры, а [a-zA-Z_][0-9a-zA-Z_]*в регулярном выражении.

(Это тот же набор имен, что и для переменных, но псевдонимные команды и переменные - это разные вещи, используемые в разных местах . Переменная может называться так же, как и команда без каких-либо вредных последствий.)

Когда выполняется псевдоним , новая команда добавляется вместе с исходными четырьмя p i d aкомандами. Новая команда может использоваться как [command name]операторы in и вызываться с аргументами, как и любая другая команда без псевдонимов .

Когда выполняется оператор с псевдонимом команды , запускаются ровно еще два оператора из его исходного оператора псевдонима :

  • [statement A] всегда работает
  • [statement B]выполняется, если [statement A]был успех
  • [statement C]выполняется, если [statement A]был сбой

Операторы A, B и C всегда выполняются лениво , т.е. они оцениваются на лету во время выполнения.

По завершении выполнения команда с псевдонимом помечается тем же флагом успеха или неудачи, что и оператор B или C, в зависимости от того, какая команда была выполнена . ( Сами псевдонимы не нужно помечать, поскольку они не могут встречаться внутри себя.)

Псевдоним Пример 1

Скажем, мы хотим новую команду, которая увеличивает переменную в frogдва раза. Это псевдоним заявления достигает этого:

a increment_frog_twice
 i frog
 i frog
 d frog

Оператор A ( i frog) всегда выполняется и всегда помечается как успешный, поэтому оператор B ( i frog) также всегда выполняется, и frog , следовательно, переменная увеличивается на 2. Команда increment_frog_twiceвсегда помечается как успешная, поскольку оператор B всегда выполняется, а B всегда является успех . Оператор C ( d frog) никогда не выполняется.

Итак, вывод

a increment_frog_twice
 i frog
 i frog
 d frog
p frog
increment_frog_twice
p frog

было бы

frog = 0
frog = 2

Мы можем обобщить этот пример, чтобы любая переменная могла быть увеличена в два раза, дав аргументированной команде-псевдониму.

В операторе псевдонима положительные целые числа 1, 2, 3 и т. Д. Представляют 1-й, 2-й, 3-й и т. Д. Аргументы, передаваемые в команду с псевдонимом. (Эти аргументы могут быть простыми переменными или ссылками на сами переменные.) Эти числа могут появляться только в аргументах операторов A, B и C в операторе псевдонимов . Для них не имеет смысла появляться в другом месте.

Псевдоним Пример 2

Это обобщает последний пример - любая переданная переменная increment_twiceбудет увеличена на 2, потому что 1это ссылка на первый переданный аргумент:

a increment_twice
 i 1
 i 1
 d 1 #never reached
p toad
increment_twice toad
p toad

Результатом этой программы будет

toad = 0
toad = 2

Затем мы можем создать псевдоним другой команды, которая принимает два аргумента и вызывает increment_twiceоба из них:

a increment_twice
 i 1
 i 1
 d 1 #never reached
a increment_both_twice
 increment_twice 1
 increment_twice 2
 d 1 #never reached
increment_both_twice platypus duck
p platypus
p duck

Выход здесь будет

platypus = 2
duck = 2

Важно понимать, что псевдонимные команды могут быть рекурсивными, поскольку именно в этом заключается их истинная сила. Например, мы можем сделать команду, которая устанавливает любую переданную переменную в 0:

Псевдоним Пример 3

Команда set_to_zeroпринимает один аргумент и устанавливает свою переменную в 0 и помечается как успешная после завершения:

a set_to_zero
 d 1
 set_to_zero 1
 i _dummy_
i oryx
i oryx
i oryx
p oryx
set_to_zero oryx
p oryx

Результатом этой программы будет

oryx = 3
oryx = 0

Происходит то, что когда set_to_zero oryxвыполняется, d 1успешно уменьшается oryxс 3 до 2, затем set_to_zero 1вызывается, что аналогично set_to_zero oryxповторному вызову . Таким образом, процесс повторяется до тех пор, пока d 1не произойдет сбой , останавливая рекурсию и увеличивая _dummy_переменную, чтобы получить успех .


Вызов

Напишите программу, которая может выполнять код Prindeal точно так же, как описано выше. Возьмите код Prindeal через стандартный ввод, командную строку или в виде текстового файла. Распечатайте вывод программы Prindeal на стандартный вывод или ближайшую альтернативу вашего языка.

Кроме того, вы можете написать функцию, которая принимает код в виде строки и печатает или возвращает строку вывода.

Кроме того, вы можете предположить, что:

  • Входной код Prindeal будет содержать только переводы строк и печатный ASCII и (опционально), что он заканчивается пустой строкой.
  • Код ввода будет действительным Prindeal - правильно сформированный и синтаксически правильный.
  • Выполнение кода не приведет к возникновению бесконечных циклов и недопустимых ссылок на команды, которые не были определены, или аргументы, которые не были заданы.
  • Названия команд p, i, d, и aникогда не будет совмещенным над. (Вы не можете предполагать, что переменные не будут иметь этих имен.)

Кроме того, не имеет значения, что значения вашей переменной не являются целыми числами с произвольной точностью, так как будут проверяться только числа меньше 1000. Также хорошо, если у вашего языка есть рекурсивные ограничения (такие как Python ), с которыми могут столкнуться более сложные программы Prindeal, пока работает тестовая программа ниже.

Тестовая программа

Вот большая программа Prindeal, которая создает операции сложения, умножения и возведения в степень посредством использования фиктивных переменных (начиная с _условного обозначения) и множества вспомогательных псевдонимов:

#Command Definitions:
a s             #flag as a success
 i _
 d _
 d _
a f             #flag as a failure
 d _
 d _
 d _
a z             #1 = zero
 d 1
 z 1
 s
a n             #1 = one
 z 1
 i 1
 s
a move          #2 += 1, 1 = zero
 moveH 1 2
 move 1 2
 s
a moveH         #move helper
 d 1
 i 2
 f
a dupe          #2 += 1, 3 += 1, 1 = zero
 dupeH1 1 2 3
 dupe 1 2 3
 s
a dupeH1        #dupe helper
 d 1
 dupeH2 2 3
 f
a dupeH2        #dupe helper
 i 1
 i 2
 s
a copy          #2 = 1
 z 2
 copyH 1 2
 s
a copyH         #copy helper
 dupe 1 2 _copy
 move _copy 1
 s
a addTo         #1 += 2
 copy 2 _add
 #testing comments #
 move _add 1#in weird places # just because #
 s
#it's a g##d idea
###
a add           #1 = 2 + 3
 #its a good idea
 z 1
 addH 1 2 3
 s
##

#
a addH          #add helper
#this is a comment
 addTo 1 2 #as is this
 addTo 1 3
 s
a mul           #1 = 2 * 3
 mulH1 1 2
 mulH2 1 3
 s
a mulH1         #mul helper
 z 1
 copy 2 _mul
 s
a mulH2         #mul helper
 mulH3 1 2
 mulH2 1 2
 s
a mulH3         #mul helper
 d _mul
 addTo 1 2
 f
a mulBy         #1 *= 2
 mul _mulBy 1 2
 copy _mulBy 1
 s
a pow           #1 = 2^3
 powH1 1 3
 powH2 1 2
 s
a powH1         #pow helper
 n 1
 copy 2 _pow
 s
a powH2         #pow helper
 powH3 1 2
 powH2 1 2
 s
a powH3         #pow helper
 d _pow
 mulBy 1 2
 f

#Running Tests:
p A
p B
p C
n A         #A = 1
n B         #B = 1
add C A B   #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C   #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C   #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B   #d = d * B = 6 * 3 = 18
p ____
p d
d A         #A = A - 1 = 1 - 1 = 0
mulBy d A   #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B   #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C   #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B   #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C

(Если вы играете с этим кодом, имейте в виду, что многие команды завершатся неудачно, если одна и та же переменная будет указана несколько раз в качестве аргумента. Это легко исправить, но в результате получается более длинный код.)

Ваш переводчик Prindeal должен быть в состоянии произвести точный вывод:

A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729

счет

Самый короткий код в байтах побеждает. Tiebreaker переходит на более раннюю подачу.

Бонус Брауни: написать классную программу на Приндее. Я реализовал сложение и умножение, вы можете сделать вычитание или деление?

Кальвин Хобби
источник
О, чувак, я думаю, что на этот раз я оставлю Пита в покое и вытащу Лисп! Один вопрос - функции и переменные живут в совершенно разных пространствах имен, верно? Так что я могу увеличить p, а затем p p, что бы вывести 1, верно?
orlp
@ или правильно (Там есть некоторые заметки об этом.)
Увлечения Кэлвина
2
Я не могу быть единственным, кто думает о PRNDL, когда вижу название языка.
Downgoat
Есть ли максимальное количество аргументов, которые будут переданы псевдониму команды?
Зак Гейтс,
@ZachGates Нету
Увлечения Келвина

Ответы:

9

Pyth, 162 136 байт

JfTmchcd\#).zKHW<ZlJI!e=T@J~+Z1=@Tk)=k0 .x=J+]h=Nm.xL@Tskd@K=NhT+]+tN0>J~Z0,=Y.x@H=eT0?qN\pps[Td\=dYb)?xGN?qN\iXHThY?YXTH_1=k1XKT:JZ=+Z3

Демонстрация.

Гольф 26 символов, встраивая переменные и изменяя Iи Eоснованный поток управления на ?и .xоснованный поток управления.

Впервые у меня закончились переменные в Pyth. Каждая переменная в Pyth ( bdkGHNTYи JK) использовалась, и я хотел использовать bв качестве новой строки. К счастью, я смог использовать Nдве совершенно разные вещи в разных частях программы, и это все еще работает.

Ungolfed (запустить с -m):

JfTmchcd\#).z
KH
W<ZlJ
  I!e=T@J~+Z1
    =@Tk)
  =k0
     .x
      =J+]h=Nm.xL@Tskd@K=NhT+]+tN0>J~Z0
      ,
        =Y.x@H=eT0
        ?qN\p
          ps[Td\=dYb)
          ?xGN
            ?qN\i
              XHThY
              ?Y
                XTH_1
                =k1
            XKT:JZ=+Z3
isaacg
источник
3
Мне нравится, что я до сих пор не могу сказать, что он делает, даже если без него ...
Джерри Иеремия
Что ж, это делает вывод, что Пиф не завершен по Тьюрингу ...
Эрик Игрок в гольф
8

Python 2, 600 584 397 373 байта

Это мое собственное решение для игры в гольф. Любой желающий может улучшить его или следовать его логике в своем собственном ответе, пока дается атрибуция.

Самое приятное в том, что рекурсия не выполняется, поэтому у нее никогда не будет проблем с пределом рекурсии Python. Например, программа Sp Countup Prindeal может работать бесконечно долго.

p=filter(len,[l.split('#')[0].split()for l in input().split('\n')]);m={};v={};i=0
while i<len(p):
 s=p[i]
 if'('in`s`:s=s[f]
 n,f=s[0],0
 if n in m:a,b,c=([s[int(g)]if g.isdigit()else g for g in t]for t in m[n]);p=[a,(b,c)]+p[i+1:];i=0;continue
 s=s[1]
 q=v.get(s,0)
 if'd'>n:m[s]=p[i+1:i+4];i+=3
 elif'i'<n:print s,'=',q
 elif'd'<n:v[s]=q+1
 elif q:v[s]-=1
 else:f=1
 i+=1

Это программа, которая принимает в строке программы в кавычках экранированные строки, например
'p _MyVariable_321\np screaming_hairy_armadillo'.

Я взял различные сигналы игры в гольф от Sp - х и PIETŲ в ответах. Спасибо, парни :)

Кальвин Хобби
источник
6

Python 3 345 336 335 328 байт

a=0
A={}
V={}
def f(l):
 if l[0]in"d p i":c,u=l;U=V[u]=V.get(u,0)+"pi".find(c);S=U<0;V[u]+=S;c<"p"or print(u,"=",U)
 else:d=lambda q:[w.isdigit()and l[int(w)]or w for w in A[l[0]][q]];S=f(d(1+f(d(0))))
 return S
for z in open("P"):
 l=z.split("#")[0].split()
 if"a "==z[:2]:a,s,*x=3,l[1]
 elif l*a:x+=l,;a-=1;A[s]=x
 elif l:f(l)

(-6 байт благодаря @orlp)

Все еще играю в гольф. Предполагается, что программа хранится в файле с именем P.

Размещение вызовов fвнутри лямбды dпозволило бы сэкономить несколько байтов, но это сделало бы, что последний тестовый случай достиг максимальной глубины рекурсии.

Некоторые программы Prindeal

Бесполезная программа вычитания

Вот бесполезная программа вычитания . Это бесполезно, потому что, даже если оно правильно вычитается, оно не возвращает соответственно успех / неудачу.

Выход должен быть:

a = 15
b = 6
__________ = 0
a = 9
b = 6

Посчитать

a helper
 p 1
 countup 1
 i success

a countup
 i 1
 helper 1
 d failure

countup n

Считает вверх и печатает nнавсегда. Может работать как тест на скорость интерпретатора (остерегайтесь длинных трассировок при прерывании клавиатуры).

Sp3000
источник
2
Все в этом вопросе пропустили этот гольф, я не понимаю почему. l[:(l+"#").find("#")]и все его вариации могут быть заменены простыми l.split('#')[0].
orlp
@orlp был настолько сосредоточен на findтом, что я забыл, что ты мог бы просто, splitдаже если #бы там не было. Спасибо :)
Sp3000
6

JavaScript (ES6), 273 258

Редактировать Исправлены ошибки и добавлен настоящий набор тестов.

Не считая ведущих пробелов и переносов.

Конечно, можно играть в гольф немного больше.

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

Протестируйте выполнение сниппета в любом браузере, совместимом с EcmaScript 6 (в частности, не Chrome, не MSIE. Я тестировал на Firefox, Safari 9 мог пойти)

F=p=>(
  p=p.match(/^[^#\n]+/gm).filter(r=>r.trim(o='',v=[])),
  s={
    '':_=>1,
    p:a=>o+=a+` = ${v[a]||0}\n`,
    i:a=>v[a]=-~v[a],
    d:a=>v[a]&&v[a]--,
    a:(n,j)=>s[n]=(u,t,a)=>x(p[!x(p[j+1],0,a,1)+j+2],0,a,1)
  },
  p.map(x=(r,i,w,l,a=r.split(/ +/).slice(l).map(x=>-x?w[x]:x))=>s[a[0]](a[1],i,a)),
  o
)

// TEST

$('#O tr').each(function() {
  var $cells = $(this).find('td')
  var prg = $cells.eq(0).text()
  console.log(prg)
  var output = F(prg)
  $cells.eq(1).text(output)
})
#O td { vertical-align:top; white-space: pre; border: 1px solid #888; font-family:monospace }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
<tr><th>Program</th><th>Outpout</th></tr>
<tbody id=O>  
<tr><td>p _MyVariable_321
p screaming_hairy_armadillo</td><td></td></tr>
<tr><td>i alpaca
p alpaca
i alpaca
p alpaca</td><td></td></tr>
<tr><td>i malamute
p malamute
d malamute    #success
p malamute
d malamute    #failure
p malamute
d akita       #failure
p akita</td><td></td></tr>
<tr><td>a increment_frog_twice
 i frog
 i frog
 d frog
p frog
increment_frog_twice
p frog</td><td></td></tr>
<tr><td>a increment_twice
 i 1
 i 1
 d 1 #never reached
a increment_both_twice
 increment_twice 1
 increment_twice 2
 d 1 #never reached
increment_both_twice platypus duck
p platypus
p duck</td><td></td></tr>
<tr><td>a set_to_zero
 d 1
 set_to_zero 1
 i _dummy_
i oryx
i oryx
i oryx
p oryx
set_to_zero oryx
p oryx</td><td></td></tr>
<tr><td>#Command Definitions:
a s             #flag as a success
 i _
 d _
 d _
a f             #flag as a failure
 d _
 d _
 d _
a z             #1 = zero
 d 1
 z 1
 s
a n             #1 = one
 z 1
 i 1
 s
a move          #2 += 1, 1 = zero
 moveH 1 2
 move 1 2
 s
a moveH         #move helper
 d 1
 i 2
 f
a dupe          #2 += 1, 3 += 1, 1 = zero
 dupeH1 1 2 3
 dupe 1 2 3
 s
a dupeH1        #dupe helper
 d 1
 dupeH2 2 3
 f
a dupeH2        #dupe helper
 i 1
 i 2
 s
a copy          #2 = 1
 z 2
 copyH 1 2
 s
a copyH         #copy helper
 dupe 1 2 _copy
 move _copy 1
 s
a addTo         #1 += 2
 copy 2 _add
 #testing comments #
 move _add 1#in weird places # just because #
 s
#it's a g##d idea
###
a add           #1 = 2 + 3
 #its a good idea
 z 1
 addH 1 2 3
 s
##

#
a addH          #add helper
#this is a comment
 addTo 1 2 #as is this
 addTo 1 3
 s
a mul           #1 = 2 * 3
 mulH1 1 2
 mulH2 1 3
 s
a mulH1         #mul helper
 z 1
 copy 2 _mul
 s
a mulH2         #mul helper
 mulH3 1 2
 mulH2 1 2
 s
a mulH3         #mul helper
 d _mul
 addTo 1 2
 f
a mulBy         #1 *= 2
 mul _mulBy 1 2
 copy _mulBy 1
 s
a pow           #1 = 2^3
 powH1 1 3
 powH2 1 2
 s
a powH1         #pow helper
 n 1
 copy 2 _pow
 s
a powH2         #pow helper
 powH3 1 2
 powH2 1 2
 s
a powH3         #pow helper
 d _pow
 mulBy 1 2
 f

#Running Tests:
p A
p B
p C
n A         #A = 1
n B         #B = 1
add C A B   #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C   #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C   #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B   #d = d * B = 6 * 3 = 18
p ____
p d
d A         #A = A - 1 = 1 - 1 = 0
mulBy d A   #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B   #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C   #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B   #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C  
</td><td></td></tr>
</tbody>
</table>

edc65
источник
Я добавил еще несколько комментариев к тестовой программе, и похоже, что они заставили ваш код не работать.
Увлечения Кэлвина
@ Calvin'sHobbies первый быстрый патч
edc65
3

C # 6, 653 байта

Вот моя запись среди моря Python ...

class P{string[]l;string r="";Dictionary<string,int>v=new Dictionary<string,int>();Dictionary<string,int>s=new Dictionary<string,int>();public string R(string t){l=t.Split('\n');for(int i=0;i<l.Length;i++){var z=l[i].Split(' ');if(z[0]=="a"){s.Add(z[1],i);i+=3;}else E(i, null);}return r;}bool E(int n,string[]p){var z=l[n].Split(' ');var a=z.Skip(1).Select(x=>Char.IsDigit(x[0])?p[int.Parse(x)-1]:x).ToArray();if(a.Length>0&&!v.ContainsKey(a[0]))v[a[0]]=0;if (z[0]=="p")r+=$"{a[0]} = {v[a[0]]}\n";else if(z[0]=="i")v[a[0]]++;else if(z[0]=="d")if(v[a[0]]>0)v[a[0]]--;else return false;else{var y=s[z[0]];return E(y+1,a)?E(y+2,a):E(y+3,a);}return true;}}

Расширено и прокомментировано:

class Prindeal
{
    string[] lines;
    string result = "";
    Dictionary<string, int> variables = new Dictionary<string, int>();
    Dictionary<string, int> statements = new Dictionary<string, int>();

    public string Run(string text)
    {
        lines = text.Split('\n');

        for (int i = 0; i < lines.Length; i++)
        {
            // Split on spaces to get the statement and any arguments
            var z = lines[i].Split(' ');

            // Are we defining a new statement?
            if (z[0] == "a")
            {
                // Add to the statements dictionary, step over definition statements
                statements.Add(z[1], i);
                i += 3;
            }
            else
            {
                // Execute the statement
                Execute(i, null);
            }
        }

        return result;
    }

    bool Execute(int lineNumber, string[] parameters)
    {
        // Split on spaces to get the statement and any arguments
        var z = lines[lineNumber].Split(' ');

        // Parse the arguments - if it's a number, get the corresponding 
        // parameter from the calling statement
        var arguments = z.Skip(1).Select(
            x => Char.IsDigit(x[0]) ? 
            parameters[int.Parse(x) - 1] : 
            x)
            .ToArray();

        // If the first argument isn't already in the variables dict, add it
        if (arguments.Length > 0 && !variables.ContainsKey(arguments[0])) variables[arguments[0]] = 0;

        // Print statement, using string interpolation
        if (z[0] == "p")
            result += $"{arguments[0]} = {variables[arguments[0]]}\n";
        // Increment statement
        else if (z[0] == "i")
            variables[arguments[0]]++;
        // Decrement statement
        else if (z[0] == "d")
            if (variables[arguments[0]] > 0)
                variables[arguments[0]]--;
            else
                return false;
        else
        {
            // Get the line number to jump to
            var y = statements[z[0]];

            // Execute A ? B : C
            return Execute(y + 1, arguments) ? Execute(y + 2, arguments) : Execute(y + 3, arguments);
        }

        // If we reach this point, it's from a 'p', 'i' or 'd' statement which has succeeded
        return true;
    }
}

Чтобы использовать его, просто создайте экземпляр класса и вызовите R()метод, например:

string prindealText = new StreamReader("prindeal.txt").ReadToEnd();
Console.WriteLine(new P().R(prindealText));
Sok
источник
3

Обыкновенный Лисп, +758 646 619

(progn(set-macro-character #\#(get-macro-character #\;))(setf(readtable-case *readtable*):invert)(#3=defun v(s)(if(boundp s)(eval s)0))(#3# i(s)(set s(1+ (v s))))(#3# d(s)(and(plusp(v s))(set s(1-(v s)))))(#3# p(s)(format t"~A = ~A~%"s(v s)))(defmacro a(n . p)`(#3#,(cadr n)(&rest g)(if,@p)))(#3# k(s)(typecase s(integer`(nth,(1- s)g))(symbol `',s)(t(list*(car s)(mapcar 'k(cdr s))))))(#3# r()(prog(l p q)$(setf p()l(make-string-input-stream(or(read-line()()())(return))))@(when(setf p(read l()()))(push p q)(go @))(if q(return(k(reverse q)))(go $))))(do ((x(r)(r)))((not x))(eval(if(eq(car x)'a)`(,@x,(r),(r),(r))x))))

Вставьте это file.lispи назовите, например sbcl --script file.lisp; ввод читается из стандартного потока ввода.

Эта версия анализирует расширенный набор Prindeal: без особых сложностей вы можете получить доступ ко всем Common Lisp из источника Prindeal. Я считаю это особенностью переводчика.

Комментируемая версия

;; copy-readtable is only used during development, so that I do not 
;; mess with my running environment. The real code starts with the
;; progn below, which is superfluous of course inside a let.
(let ((*readtable* (copy-readtable)))

  ;; I use PROGN in the golfed version so that I can have the whole
  ;; program as a unique tree. This allows me to define reader 
  ;; variables like #3=defun in order to gain a few bytes by writing
  ;; #3# instead of defun. Reader variables are removed in
  ;; this human-friendly version.
  (progn
    ;; Let # point to the same reader function as ;
    ;; Of course, ; is still usable as a comment delimiter
    (set-macro-character #\#
                         (get-macro-character #\;))

    ;; :invert does what is necessary to enable case-sensitive reading
    ;; and printing of symbols
    (setf (readtable-case *readtable*) :invert)

    ;; value of symbol, or zero
    (defun v(s)(if(boundp s)(eval s)0))

    ;; increment
    (defun i(s)(set s(1+ (v s))))

    ;; decrement
    (defun d(s)(and(plusp(v s))(set s(1-(v s)))))

    ;; print
    (defun p(s)(format t"~A = ~A~%"s(v s)))

    ;; alias: wrap an "if" inside a "defun".
    ;; YES, that means you can redefine ANY lisp function with "a" !
    ;; A safer version would properly intern symbols in a dedicated package.
    ;;
    ;; Notice the G variable.  We take advantage of the "unhygienic"
    ;; (what a bad adjective) nature of macros to create a context
    ;; where G is bound to the argument list. The same G is referenced
    ;; implicitely later.
    (defmacro a(n . p)`(defun,(cadr n)(&rest g)(if,@p)))

    ;; Canonicalize expressions:
    ;;
    ;; - if s is a symbol, return s quoted. All functions manipulate
    ;; symbols in order to allow the undeclared use of variables. With
    ;; symbols, we can check for boundness.
    ;;
    ;; - if s is an integer, then we are inside an alias definition. The
    ;; integer is replaced by an access to the s'th element of the
    ;; implicit argument list G using (nth (1- s) g). G will be bound
    ;; when the expressions is injected in the defun corresponding to
    ;; the alias, or else an error will be signaled: either because G
    ;; is unbound, or because you defined a variable named G which is
    ;; by construction not a list. Since we do not sanitize properly
    ;; the input, you could bind G globally to a list, but that would be
    ;; nasty.
    ;; 
    ;; - Finally, if s is a list, apply k to all but the first
    ;; elements of s.  The first element is a symbol but we do not
    ;; need to quote it because we want to call the function
    ;; associated with the symbol. Due to the Lisp-2-ness
    ;; of Common Lisp, functions and variables can coexist
    ;; with the same name.
    ;;
    (defun k(s)(typecase s
                 (integer`(nth,(1- s)g))
                 (symbol`',s)
                 (t(list*(car s)(mapcar #'k(cdr s))))))

    ;; Reader function
    (defun r()
      (prog (l ; current line, as an input-stream reading a string
             p ; current read form
             q ; whole line and return value, as a list
             )

         ;; PROG includes an implicit TAGBODY. Below, $ and @ are
         ;; labels for GO statements (gotos).

       $ (setf
          ;; emtpy p
          p ()

          ;; Read a whole line and if we do not fail, build an input
          ;; stream to read from it.
          l (make-string-input-stream
             (or (read-line()()()) ;; try to read a line,
                 (return)          ;; but return from prog if we reach
                                   ;; the end of file.
                 )))
       @ (when (setf p (read l()()))
           ;; Read a lisp expression, put it in p and if p is not nil
           ;; push it into q.  A nil could happen at the end of the
           ;; line or if someone (you know who) inserted an empty list
           ;; in the file being read.
           ;; 
           ;; Thanks to the readtable which now handles comments
           ;; and spaces for us, nothing needs to be done here to
           ;; preprocess the input.

           (push p q) (go @))

         ;; If we read an empty line, q can be nil. In this case, go
         ;; back to $ and read another line. If q is not nil, reverse
         ;; it (we pushed, remember), canonicalize it and return the
         ;; result.
         (if q (return(k(reverse q))) (go $)))
      )

    ;; Read/eval loop.  When reading "(a name)", we read the three
    ;; next lines and append them to the first so that it builds a
    ;; call the the alias definition macro a. Otherwise, just eval x.
    (do((x(r)(r))((not x))
      (eval (if (eq(car x'a))
                `(,@x,(r),(r),(r))
                x)))))

пример

~$ sbcl --script file.lisp < testfile

A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729

Если мы заменим evalна printв цикле read / eval, то увидим, что оценивается:

(a 's (i '_) (d '_) (d '_)) 
(a 'f (d '_) (d '_) (d '_)) 
(a 'z (d (nth 0 g)) (z (nth 0 g)) (s)) 
(a 'n (z (nth 0 g)) (i (nth 0 g)) (s)) 
(a 'move (moveH (nth 0 g) (nth 1 g)) (move (nth 0 g) (nth 1 g)) (s)) 
(a 'moveH (d (nth 0 g)) (i (nth 1 g)) (f)) 
(a 'dupe (dupeH1 (nth 0 g) (nth 1 g) (nth 2 g))
   (dupe (nth 0 g) (nth 1 g) (nth 2 g)) (s)) 
(a 'dupeH1 (d (nth 0 g)) (dupeH2 (nth 1 g) (nth 2 g)) (f)) 
(a 'dupeH2 (i (nth 0 g)) (i (nth 1 g)) (s)) 
(a 'copy (z (nth 1 g)) (copyH (nth 0 g) (nth 1 g)) (s)) 
(a 'copyH (dupe (nth 0 g) (nth 1 g) '_copy) (move '_copy (nth 0 g)) (s)) 
(a 'addTo (copy (nth 1 g) '_add) (move '_add (nth 0 g)) (s)) 
(a 'add (z (nth 0 g)) (addH (nth 0 g) (nth 1 g) (nth 2 g)) (s)) 
(a 'addH (addTo (nth 0 g) (nth 1 g)) (addTo (nth 0 g) (nth 2 g)) (s)) 
(a 'mul (mulH1 (nth 0 g) (nth 1 g)) (mulH2 (nth 0 g) (nth 2 g)) (s)) 
(a 'mulH1 (z (nth 0 g)) (copy (nth 1 g) '_mul) (s)) 
(a 'mulH2 (mulH3 (nth 0 g) (nth 1 g)) (mulH2 (nth 0 g) (nth 1 g)) (s)) 
(a 'mulH3 (d '_mul) (addTo (nth 0 g) (nth 1 g)) (f)) 
(a 'mulBy (mul '_mulBy (nth 0 g) (nth 1 g)) (copy '_mulBy (nth 0 g)) (s)) 
(a 'pow (powH1 (nth 0 g) (nth 2 g)) (powH2 (nth 0 g) (nth 1 g)) (s)) 
(a 'powH1 (n (nth 0 g)) (copy (nth 1 g) '_pow) (s)) 
(a 'powH2 (powH3 (nth 0 g) (nth 1 g)) (powH2 (nth 0 g) (nth 1 g)) (s)) 
(a 'powH3 (d '_pow) (mulBy (nth 0 g) (nth 1 g)) (f)) 
(p 'A) 
(p 'B) 
(p 'C) 
(n 'A) 
(n 'B) 
(add 'C 'A 'B) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(add 'B 'A 'C) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(mul 'd 'B 'C) 
(p '____) 
(p 'd) 
(mulBy 'd 'B) 
(p '____) 
(p 'd) 
(d 'A) 
(mulBy 'd 'A) 
(p '____) 
(p 'd) 
(pow 'A 'C 'B) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(pow 'A 'B 'C) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(pow 'C 'A 'B) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C)

Macroexpansion

Если мы выберем следующее определение псевдонима:

(a 'powH2 (powH3 (nth 0 g) (nth 1 g)) (powH2 (nth 0 g) (nth 1 g)) (s))

... мы можем видеть ссылки на переменную с именем, gкоторая нигде не найдена в лексической области видимости. Но после макроразложения вот фактический код, который оценивается:

(defun powH2 (&rest g)
  (if (powH3 (nth 0 g) (nth 1 g))
      (powH2 (nth 0 g) (nth 1 g))
      (s))) 

Теперь gссылается на список аргументов определяемой функции.

CoreDump
источник
2

Python 2, 486 байт

Это эталонное решение, в котором я играл больше (в настоящее время - 98 байт).

import sys;sys.setrecursionlimit(2000)
def r(s):
 n=s[0]
 if n in A:f=lambda i:r([s[int(t)]if'0'<t[0]<':'else t for t in A[n][i]]);return f(1+(f(0)or 0))
 k=s[1]
 if'i'<n:print k,'=',V.get(k,0)
 elif'd'<n:V[k]=-~V[k]if k in V else 1
 elif'a'<n:
    if~-(k in V)or V[k]<1:return 1
    V[k]-=1
 else:A[k]=s[2:]
A={};V={};c=filter(bool,([l,l[:l.find('#')]]['#'in l]for l in input().split('\n')))
while c:
 s=c[0].split();c=c[1:]
 if'a'!=s[0]:r(s)
 else:r(['a',s[1]]+map(str.split,c[:3]));c=c[3:]

Изменения (что я помню):

  • автоматическое преобразование логического целого числа ( [l,l[:l.find('#')]]['#'in l]).
  • установить или увеличить в одном выражении ( V[k]=-~V[k]if k in V else 1)
  • больше псевдонимов для более длинных выражений ( k=s[1])
  • в главном цикле нет счетчика, вместо этого очищается список ввода
  • printавтоматическое добавление пробелов ( print k,'=',V.get(k,0))
  • проверка цифр 1-9 ( '0'<t[0]<':')
  • переворачивая возвращаемые значения, rчтобы сохранить returnс
  • удаление повторения нарезки и расщепления ( map(str.split,c[:3])))
PurkkaKoodari
источник
1

Python 3, 1322 байта

Golfed:

import re,sys;sys.setrecursionlimit(2000);F,L=filter,list
class P:
 N,O,F=0,{},{}
 def __init__(S,c):
  S.B,S.E={"p":S.P,"i":S.I,"d":S.D,"a":S.L},dict(enumerate(F(None,[i.split('#')[0].rstrip()for i in c.splitlines()])))
  while S.N in S.E:S.X(S.E[S.N])
 def V(S, v, y, z=0):
  if re.match("[\w_][\d\w_]*",v):
   if not v in y:
    if z is not None:y[v]=z
    else:return False
   return True
  return False
 def A(S):S.N+=1
 def P(S,v):
  if S.V(v,S.O):print("{0} = {1}".format(v, S.O[v]));return True
  return False
 def I(S,v):
  if S.V(v, S.O):S.O[v]+=1;return True
  return False
 def D(S,v):
  if S.V(v,S.O)and S.O[v]>0:S.O[v]-=1;return True
  return False
 def L(S,v):
  e=[]
  if S.V(v,S.F,e):
   for i in range(3):S.A();e.append(S.E[S.N].lstrip())
   return True
  return False
 def C(S,c,v):
  def R(Z,v):
   for i in re.findall("\s(\d+)", Z):Z=Z.replace(" %s"%i," %s"%v[int(i)-1])
   return Z
  Q,m,f=map(lambda l:R(l,v),S.F[c])
  if S.X(Q,False):return S.X(m,False)
  return S.X(f,False)
 def X(S,Z,C=True):
  u=re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?",Z)
  if u:
   c,v=map(lambda i:''if i is None else i,u.groups());v=L(F(None,v.split(' ')))
   if S.V(c,S.F,None):
    T=S.C(c, v)
    if C:S.A()
   elif S.V(c,S.B,None):
    T=S.B[c](*v)
    if C:S.A()
   else:return False
   return T
  return False

Ungolfed:

import re

class Prindeal:
    iline = 0
    local = {}
    udef = {}
    content  = {}

    def __init__(self, c):
        self.built = {
            "p": self.print,
            "i": self.increment,
            "d": self.decrement,
            "a": self.alias,
        }
        self.content = dict(enumerate(filter(None, [i.split('#')[0].rstrip()for i in c.splitlines()])))
        while self.iline in self.content:
            self.execute_line(self.content[self.iline])

    def validate_name(self, varname, stack, default=0):
        if re.match("[\w_][\d\w_]*", varname):
            if not varname in stack:
                if default is not None:
                    stack[varname] = default
                else:
                    return False
            return True
        return False

    def advance_stack(self):
        self.iline += 1

    def print(self, varname):
        if self.validate_name(varname, self.local):
            print("{0} = {1}".format(varname, self.local[varname]))
            return True
        return False

    def increment(self, varname):
        if self.validate_name(varname, self.local):
            self.local[varname] += 1
            return True
        return False

    def decrement(self, varname):
        if self.validate_name(varname, self.local) and self.local[varname] > 0:
            self.local[varname] -= 1
            return True
        return False

    def alias(self, aliasname):
        indexed_lines = []
        if self.validate_name(aliasname, self.udef, indexed_lines):
            for i in range(3):
                self.advance_stack()
                indexed_lines.append(self.content[self.iline].lstrip())
            return True
        return False

    def execute_alias(self, cmd, variables):
        def parse_args(line, variables):
            for i in re.findall("\s(\d+)", line):
                line = line.replace(" %s" % i, " %s" % variables[int(i) - 1])
            return line
        init, success, failure = map(lambda l: parse_args(l, variables), self.udef[cmd])
        if self.execute_line(init, False):
            return self.execute_line(success, False)
        return self.execute_line(failure, False)

    def execute_line(self, line, cont=True):
        valid_execution = re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?", line)
        if valid_execution:
            cmd, variables = map(lambda i: '' if i is None else i, valid_execution.groups())
            variables = list(filter(None, variables.split(' ')))
            if self.validate_name(cmd, self.udef, None):
                temp = self.execute_alias(cmd, variables)
                if cont:
                    self.advance_stack()
            elif self.validate_name(cmd, self.built, None):
                temp = self.built[cmd](*variables)
                if cont:
                    self.advance_stack()
            else:
                return False
            return temp
        return False

Использование:

P(c)

Где cтекстовое содержание.

Примеры:

Однострочные строки принимаются:

  • P("p cat")
  • P("p dog\ni dog\np dog")

Многолинейные строки также принимаются:

P("""
p dog
i dog
p dog
""")

Или:

P("""p dog
i dog
p dog""")

И т.п.

Заметки:

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

pow C A B   #C = A ^ B = 9 ^ 3 = 729

Отсюда sys.setrecursionlimit(2000).

Зак Гейтс
источник
1
Он будет использовать несколько байтов, но не могли бы вы использовать sys.setrecursionlimit () для правильной работы с псевдонимом pow?
Корвин
Я мог бы, но OP заявил, что такие языки, как Python (которые имеют ограничения рекурсии), принимаются как есть. Тем не менее, я добавлю исправление по запросу OP. @Corwin
Зак Гейтс,
Справедливо. Пропустил это в спец. @ZachGates
Корвин
1

Python - 695 688 байт

def p(v):print v,"=",w.get(v,0)
def i(v):w[v]=w.get(v,0)+1
def d(v):
 if v in w:
<TAB>w[v]-=1
<TAB>if not w[v]:del w[v]
 else:return 1
def a(n,b,d,h):
 def g(*a):
<TAB>i=1;f=b;s=d;t=h
<TAB>for v in a:v=q+v+q;k=q+j(i)+q;f=c(f,k,v);s=c(s,k,v);t=c(t,k,v);i+=1
<TAB>y=u(t,e)if u(f,e)else u(s,e);i=1;return y
 e[n]=g
q="'";w=x={};u=eval;e={'a':a,'d':d,'i':i,'p':p};import sys;l=sys.stdin.readlines();r="";j=str;c=j.replace;sys.setrecursionlimit(2000)
for h in l:
 h = h.strip()
 if not h:continue
 l = h.split();f=l[0];n=f+"("
 if "#" in f:continue
 for g in l[1:]:
<TAB>b=g.find("#")+1
<TAB>if b:g=g[:b-1]
<TAB>if g:n+="'%s',"%g
<TAB>if b:break
 if x:x-=1;d+='"%s)",'%n
 else:x=(f=="a")*3;d=n
 if not x:d+=")\n";r+=d
exec r in e

<TAB> буквальный символ табуляции

pppery
источник
1

C ++, 1111 байт

Это C ++ - настолько идиоматичный, насколько я мог.
Это означает, что он должен быть более C ++ и меньше C-ish.
Это также означает, что он больше, чем эквивалентная программа на Си.
Я думаю, что C ++ соперничает с Java по многословной стандартной библиотеке.
Компилируется с VS2013 и g ++ 4.9.2 (с -std = c ++ 11)

#include<array>
#include<iostream>
#include<map>
#include<regex>
#include<sstream>
#include<stack>
#define B std::
#define a first
#define b second
#define c(s);else if(x.a==s)
#define d(n)B getline(B cin,r##n)
#define e(n)r##n=B regex_replace(r##n,q,"$1");
#define f(n)do{d(n);e(n)}while(r##n.empty());
#define g B string
#define h B istream_iterator<g>
#define i p.top().a
#define j p.empty()
#define k B pair
#define u continue;
#define w B back_inserter
typedef B vector<g>s;typedef B array<g,3>A;typedef k<k<long,A>,s>t;B map<g,A>m;B map<g,long>n;B stack<t>p;B regex q("^ *(.*?) *(#.*)?$");int main(){g r0,r1,r2,r3;while(d(0)){e(0)if(r0.empty())u p.push(t{{0,{{r0,"",""}}},{}});bool z;while(!j){k<g,s>x;B istringstream ss(i.b[i.a]);ss>>x.a;B copy(h(ss),h(),w(x.b));s o;B transform(B begin(x.b),B end(x.b),w(o),[](g y){int v=atoi(y.c_str());return v>0?p.top().b[v-1]:y;});z=true;if(0)c("")c("p")B cout<<o[0]<<" = "<<n[o[0]]<<B endl c("i")n[o[0]]++c("d")n[o[0]]-=(z=n[o[0]])c("a"){f(1)f(2)f(3)m.insert(B make_pair(o[0],A{{r1,r2,r3}}));}else{p.push(t{{0,m[x.a]},o});u}while(!j&&i.a)p.pop();if(!j)i.a+=1+!z;}}}

Ниже оригинал. Если кто-нибудь может придумать способ сделать его более идиоматичным и более коротким одновременно, пожалуйста, дайте мне знать.

#include <array>
#include <iostream>
#include <map>
#include <regex>
#include <sstream>
#include <stack>

typedef std::vector<std::string> List;
typedef std::pair<std::string, List> Statement;
typedef std::array<std::string, 3> Alias;
typedef std::pair<long, Alias> IndexedAlias;
typedef std::pair<IndexedAlias, List> Item;

std::map<std::string, Alias> aliases;
std::map<std::string, long> variables;
std::stack<Item> stack;
std::regex re("^ *(.*?) *(#.*)?$");

int main()
{
    std::string line, line1, line2, line3;
    while (std::getline(std::cin, line)) // control-Z to exit
    {
        line = std::regex_replace(line, re, "$1");
        if (line.empty()) continue;
        stack.push(Item{ { 0, { { line, "", "" } } }, {} });

        bool flag;
        while (!stack.empty())
        {
            Statement statement;
            std::istringstream ss(stack.top().first.second[stack.top().first.first]);
            ss >> statement.first;
            std::copy(std::istream_iterator<std::string>(ss), std::istream_iterator<std::string>(), std::back_inserter(statement.second));

            List arguments;
            std::transform(std::begin(statement.second), std::end(statement.second), std::back_inserter(arguments),
                [](std::string arg){ int i = atoi(arg.c_str()); return i > 0 ? stack.top().second[i - 1] : arg; });

            flag = true;
            if (statement.first == "")
                ;
            else if (statement.first == "p")
                std::cout << arguments[0] << " = " << variables[arguments[0]] << std::endl;
            else if (statement.first == "i")
                variables[arguments[0]]++;
            else if (statement.first == "d")
                variables[arguments[0]] -= (flag = variables[arguments[0]]);
            else if (statement.first == "a")
            {
                do { std::getline(std::cin, line1); line1 = std::regex_replace(line1, re, "$1"); } while (line1.empty());
                do { std::getline(std::cin, line2); line2 = std::regex_replace(line2, re, "$1"); } while (line2.empty());
                do { std::getline(std::cin, line3); line3 = std::regex_replace(line3, re, "$1"); } while (line3.empty());
                aliases.insert(std::make_pair(arguments[0], Alias{ { line1, line2, line3 } }));
            }
            else
            {
                stack.push(Item{ { 0, aliases[statement.first] }, arguments });
                continue;
            }

            while (!stack.empty() && stack.top().first.first) stack.pop();
            if (!stack.empty()) stack.top().first.first += 1 + !flag;
        }
    }

    std::cout << "-- Variables --" << std::endl;
    std::transform(std::begin(variables), std::end(variables), std::ostream_iterator<std::string>(std::cout, "\n"),
        [](std::map<std::string, long>::value_type pair){ std::ostringstream ss; ss << pair.first << " = " << pair.second; return ss.str(); });
    std::cout << "-- Aliases --" << std::endl;
    std::transform(std::begin(aliases), std::end(aliases), std::ostream_iterator<std::string>(std::cout, "\n"),
        [](std::map<std::string, Alias>::value_type pair){ std::ostringstream ss; ss << pair.first << " = [1]:" << pair.second[0] << " [2]:" << pair.second[1] << " [3]:" << pair.second[1]; return ss.str(); });
    std::cout << "---------------" << std::endl;

    return 0;
}
Джерри Иеремия
источник
0

Хаскелл, 1009

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

import qualified Data.Map as M
import Control.Monad.State.Lazy
import Data.List
type A=M.Map String
data P=P(A Int)(A([String]->StateT P IO Int))
a f=evalStateT f(P M.empty$M.fromList[("i",\(b:_)->(+1)%b),("d",\(b:_)->pred%b),("p",\(b:_)->i b>>= \v->liftIO(putStrLn$b++"="++show v)>>q 1)])
e(k:l)=do{(P v a)<-get;put.P v$M.insert k(m l)a;q 1}
g t s f= \a->t a>>= \b->if b>0then s a else f a
f%k=f<$>i k>>= \v->if v<0then k#0>>q 0else k#v>>q 1
i k=get>>= \(P v _)->q$M.findWithDefault 0 k v
k#v=get>>= \(P b a)->put$P(M.insert k v b)a
l k=get>>= \(P _ a)->q$a M.!k
f s=let(f:a)=r s in($a)<$>l f>>=id
m(t:s:f:_)=g(k t)(k s)(k f)
k s=let(f:b)=r s in\a->($(map((\y z->if all(\c->c>'/'&&c<':')z then y!!(read z-1)else z)a)b))<$>l f>>=id
n=dropWhileEnd(==' ').takeWhile(not.(=='#')).dropWhile(==' ')
o[]=[]
o(l:ls)|(head.r$l)=="a"=(l:take 3 ls):(o$drop 3 ls)|1>0=[l]:o ls
p s|length s>1=e$(n.tail.head$s):tail s|1>0=f.head$s
q=return
main=join$a.(\s->mapM_ p(o.filter(not.null).map n.lines$s))<$>getContents
r=words
Анк-Морпорка
источник