Друк, приріст, декрет, псевдоніми - інтерпретувати Prindeal


30

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

Ваше завдання в цій проблемі з гольфовим кодом - написати найкоротшу програму, яка може запустити 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] ...

Може бути довільна кількість аргументів (включаючи їх взагалі немає). Кожен аргумент - це завжди змінна або (як ми побачимо при обговоренні псевдоніму ) посилання на змінну .

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

Вбудований друк , приріст та декремент - це твердження із наведеною формою. Ось що вони роблять:

  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 є єдиним способом створення помилки .

Ім'я користувача Постановка і команди Пов'язаних

Команда alias має спеціальний синтаксис і є найпотужнішою, оскільки її можна використовувати для визначення нових команд. Ім'я команди псевдонім є, 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]у висловлюваннях та викликана аргументами, як і будь-яка інша команда, яка псевдонімом .

Коли виконується оператор із псевдонімом імені команди, виконується рівно ще два оператори з його початкового оператора псевдоніма :

  • [statement A] завжди працює
  • [statement B]запускається, якщо [statement A]був 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 - завжди a успіх . Заява C ( d frog) ніколи не виконується.

Тож вихід на

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

був би

frog = 0
frog = 2

Ми можемо узагальнити цей приклад, так що будь-яку змінну можна збільшити вдвічі, подавши команду aliase в аргумент.

В операторі псевдоніму додатні цілі числа 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 через stdin, командний рядок або як текстовий файл. Роздрукуйте вихід програми Prindeal на stdout або найближчу альтернативу вашій мові.

Крім того, ви можете написати функцію, яка приймає код як рядок і друкує або повертає вихідний рядок.

Крім того, ви можете припустити, що:

  • Вхідний код 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

Оцінка балів

Виграє найкоротший код у байтах. Tiereaker переходить до більш раннього подання.

Бонус на брауні: Напишіть класну програму в Prindeal. Я реалізував додавання та множення, чи можна зробити віднімання чи ділення?


О людино, я думаю, колись я залишу Піта в спокої і витягну Лисп! Одне питання - функції та змінні живуть у абсолютно різних просторах імен, правда? Тож я можу збільшувати p, а потім p p, який би надрукував 1, правда?
orlp

@orlp Правильно. (У цьому є деякі замітки.)
Захоплення Кальвіна

2
Я не можу бути єдиним, хто думає про PRNDL, коли бачу назву мови.
Пуховик

Чи є максимальна кількість аргументів, які будуть передані в інший спосіб?
Зак Гейтс

Відповіді:


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

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

Golfed з 26 символів, вбудовування змінних і зміни від Iі на Eоснові потік управління , щоб ?і.x на основі потоку управління.

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

Безголів (бігти з -м):

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

3
Мені подобається, як я досі не можу сказати, що це робиться навіть із невольфем ...
Джеррі Єремія

Ну, і підсумовуємо, що Піт не є Тюрінгом-завершеним ...
Ерік Покірний

8

Python 2, 600 584 397 373 байт

Це моє власне контрольне рішення для гольфу. Будь-хто може вдосконалити його або дотримуватися його логіки у власній відповіді до тих пір, поки надається атрибуція.

Акуратна частина цього полягає в тому, що ніякої рекурсії не робиться, тому у неї ніколи не буде проблем з обмеженням рекурсії Python. Наприклад, програма Count Count Prindeal Sp може працювати безстроково.

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назавжди. Можливо, це може бути тестом на швидкість перекладача (остерігайтеся довгих відслідковувань перерви на клавіатурі).


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>


Я додав ще кілька коментарів до програми тестування, і, схоже, вони змусили ваш код не працювати.
Захоплення Кальвіна

@ Calvin'sHobbies перший, швидкий патч
edc65

3

C # 6, 653 байти

Ось мій запис, серед моря Пітона ...

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));

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: без особливих труднощів ви можете отримати доступ до всіх звичайних 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в / 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)

Макророзширення

Якщо ми виберемо таке псевдонім визначення:

(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посилається на список аргументів визначеної функції.


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навколо, щоб зберегти returns
  • видалення повторення нарізки та розщеплення ( map(str.split,c[:3])))

1

Пітон 3, 1322 байти

Гольф:

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

Безголовки:

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?
Корвін

Я міг би, але ОП заявив, що такі мови, як Python (які мають обмеження рекурсії), приймаються як є. Однак я додам виправлення, якщо цього вимагатиме ОП. @Corwin
Zach Gates

Досить справедливо. Пропустив це у спец. @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> є буквальним символом вкладки.


1

C ++, 1111 байт

Цей C ++ - такий ідіоматичний, як я міг би це зробити.
Це означає зробити його більше C ++ - ish і менше C-ish.
Це також означає, що вона більша, ніж еквівалентна програма C.
Я думаю, що 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.