Моделювання машини реєстрації Мінських (I)


26

Існує багато формалізмів, тому, хоча ви можете знайти інші джерела корисними, я сподіваюся, що це досить чітко вказати, що вони не потрібні.

RM складається з машини кінцевих станів і кінцевої кількості іменованих регістрів, кожен з яких містить невід'ємне ціле число. Для зручності введення тексту це завдання вимагає, щоб штати також були названі.

Існує три типи стану: приріст і декремент, які обоє посилаються на певний реєстр; і припинити. Приріст держави збільшує свій регістр і передає контроль своєму наступнику. Стан декременту має двох наступників: якщо його регістр не дорівнює нулю, він зменшує його і передає контроль першому наступнику; в іншому випадку (тобто регістр дорівнює нулю), він просто передає контроль другому наступнику.

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

Введення з stdin. Формат введення складається з одного рядка за станом, а потім початкового вмісту регістра. Перший рядок - початковий стан. BNF для державних ліній:

line       ::= inc_line
             | dec_line
inc_line   ::= label ' : ' reg_name ' + ' state_name
dec_line   ::= label ' : ' reg_name ' - ' state_name ' ' state_name
state_name ::= label
             | '"' message '"'
label      ::= identifier
reg_name   ::= identifier

Існує деяка гнучкість у визначенні ідентифікатора та повідомлення. Ваша програма повинна прийняти не порожню буквено-цифрову рядок як ідентифікатор, але вона може прийняти більш загальні рядки, якщо вам зручніше (наприклад, якщо ваша мова підтримує ідентифікатори з підкресленнями, і вам це легше працювати). Аналогічно, для повідомлення ви повинні прийняти не порожній рядок з буквено-цифрових знаків і пробілів, але ви можете прийняти більш складні рядки, які дозволяють уникнути нових рядків і символів з подвійним цитуванням, якщо ви хочете.

Заключний рядок введення, який дає початкові значення регістру, - це розділений пробілом список призначень id-id = int, який повинен бути не порожнім. Не потрібно, щоб вона ініціалізувала всі регістри, названі в програмі: будь-який, який не ініціалізований, вважається рівним 0.

Ваша програма повинна прочитати вхід і імітувати RM. Коли він досягає стану завершення, він повинен випромінювати повідомлення, новий рядок, а потім значення всіх регістрів (у будь-якому зручному для людини читанні форматі та будь-якому порядку).

Примітка: формально регістри повинні містити цілі числа без обмежень. Однак ви можете припустити, що значення жодного регістру ніколи не перевищуватиме 2 ^ 30.

Кілька простих прикладів

a + = b, a = 0
s0 : a - s1 "Ok"
s1 : b + s0
a=3 b=4

Очікувані результати:

Ok
a=0 b=7
b + = a, t = 0
init : t - init d0
d0 : a - d1 a0
d1 : b + d2
d2 : t + d0
a0 : t - a1 "Ok"
a1 : a + a0
a=3 b=4

Очікувані результати:

Ok
a=3 b=7 t=0
Тестові приклади для машин, що складніше розбираються
s0 : t - s0 s1
s1 : t + "t is 1"
t=17

Очікувані результати:

t is 1
t=1

і

s0 : t - "t is nonzero" "t is zero"
t=1

Очікувані результати:

t is nonzero
t=0

Складніший приклад

Взяте з проблеми проблематичного коду Josephus у DailyWTF. Вхід - n (кількість солдатів) і k (заздалегідь), а вихід у r - (нульове індексування) положення людини, яка виживає.

init0 : k - init1 init3
init1 : r + init2
init2 : t + init0
init3 : t - init4 init5
init4 : k + init3
init5 : r - init6 "ERROR k is 0"
init6 : i + init7
init7 : n - loop0 "ERROR n is 0"
loop0 : n - loop1 "Ok"
loop1 : i + loop2
loop2 : k - loop3 loop5
loop3 : r + loop4
loop4 : t + loop2
loop5 : t - loop6 loop7
loop6 : k + loop5
loop7 : i - loop8 loopa
loop8 : r - loop9 loopc
loop9 : t + loop7
loopa : t - loopb loop7
loopb : i + loopa
loopc : t - loopd loopf
loopd : i + loope
loope : r + loopc
loopf : i + loop0
n=40 k=3

Очікувані результати:

Ok
i=40 k=3 n=0 r=27 t=0

Ця програма як зображення, для тих, хто мислить візуально і вважає корисним зрозуміти синтаксис: Проблема Йосифа Р.М.

Якщо вам сподобався цей гольф, подивіться на продовження .


Чи надходить вхід із stdin, з файлу чи з іншого місця?
Кевін Браун

@Bass, від stdin.
Пітер Тейлор

Вам слід додати кілька тестових випадків із такими складними для вирішення питаннями: 1) повідомленнями з пробілами, 2) повідомленнями з рівними знаками, 3) повідомленнями в рядку inc_line, 4) повідомленнями у першому стані dec_line, 5) повідомленнями у пробілах у випадки 3 і 4.
MtnViewMark

У граматиці є помилка: між двома записами state_name у dec_line має бути буквальний пробіл. Також незрозуміло, якщо ви хочете вимагати від людей прийому декількох пробілів між лексемами на вході.
MtnViewMark

2
@Peter: +1 для дійсно м'якого коду-гольфу з хорошим балансом специфікацій та простором для маневру! Більшість питань тут були занадто тонкими.
MtnViewMark

Відповіді:


10

Перл, 166

@p=<>;/=/,$_{$`}=$' for split$",pop@p;$o='\w+';(map{($r
,$o,$,,$b)=$'=~/".*?"|\S+/g if/^$o :/}@p),$_=$o=($_{$r}
+=','cmp$o)<0?do{$_{$r}=0;$b}:$,until/"/;say for eval,%_

Бігайте з perl -M5.010 file.

Почалося це зовсім по-іншому, але я боюся, що він зблизився з рішенням Ruby у багатьох областях до кінця. Здається, перевагою Рубі є "без сигіл", а Перл - "краща інтеграція регулярних виразів".

Трохи деталей із нутрощів, якщо ви не читаєте Perl:

  • @p=<>: прочитати весь опис машини на @p
  • /=/,$_{$`}=$' for split$",pop@p: для кожного ( for) призначення ( split$") в останньому рядку опису машини ( @p) знайдіть знак рівності ( /=/), а потім призначте значення клавіші $'hask%_$`
  • $o='\w+': початковий стан буде першим, щоб відповідати зразком Perl "слова символів"
  • until/"/: цикл, поки ми не досягнемо стану припинення:
    • map{($r,$o,$,,$b)=$'=~/".*?"|\S+/g if/^$o :/}@p: цикл на описі машини @p: коли ми знаходимось у рядку, що відповідає поточному стану ( if/^$o :/), токенізує ( /".*?"|\S+/g) решту рядка $'змінним ($r,$o,$,,$b). Трюк: та сама змінна, $oякщо спочатку використовується для імені мітки, а згодом для оператора. Як тільки мітка збігається, оператор її переосмислює, і оскільки мітку не можна (розумно) назвати + або -, вона більше ніколи не збігається.
    • $_=$o=($_{$r}+=','cmp$o)<0?do{$_{$r}=0;$b}:$,:
      - відрегулювати цільовий регістр $_{$r}вгору або вниз (магія ASCII: ','cmp'+'дорівнює 1, тоді ','cmp'-'як -1);
      - якщо результат негативний ( <0?, може статися лише для -)
      - тоді залишайтеся на 0 ( $_{$r}=0) і повертайте другу мітку $b;
      - ще повернути першу (можливо, єдину) мітку$,
    • До речі, це $,замість цього, $aщоб його можна було приклеїти до наступного маркера, untilне маючи пробілів між ними.
  • say for eval,%_: dump report ( eval) та вміст регістрів в%_

Товста кишка вам не потрібна /^$o :/. Карети однієї достатньо, щоб переконатися, що ви дивитесь лише на етикетки.
Lowjacker

@Lowjacker Мені це не потрібно, щоб визначити, що я на правильній етикетці, але мені потрібно, щоб це не було $'. Це один персонаж у регулярному вираженні, це було б три $c,для обліку ззовні. Крім того, деякі більші, але змінилися на токенізуючу форму.
JB

10

Python + C, 466 символів

Просто для розваги програма python, яка компілює програму RM на C, потім компілює & запускає C.

import sys,os,shlex
G=shlex.shlex(sys.stdin).get_token
A=B=''
C='_:'
V={}
J=lambda x:'goto '+x+';'if'"'!=x[0]else'{puts('+x+');goto _;}'
while 1:
 L,c=G(),G()
 if''==c:break
 if':'==c:
  v,d=G(),G()
  V[v]=1;B+=L+c+v+d+d+';'
  if'+'==d:B+=J(G())
  else:B+='if('+v+'>=0)'+J(G())+'else{'+v+'=0;'+J(G())+'}'
 else:A+=L+c+G()+';'
for v in V:C+='printf("'+v+'=%d\\n",'+v+');'
open('C.c','w').write('int '+','.join(V)+';main(){'+A+B+C+'}')
os.system('gcc -w C.c;./a.out')

3
Це не спрацює, якщо в регістрах є такі імена, як ' main', ' if' тощо.
Nabb

1
@Nabb: Buzzkill. Я залишаю читачеві, щоб додати в потрібних місцях префікси підкреслення.
Кіт Рендалл

6

Хаскелл, 444 символи

(w%f)(u@(s,v):z)|s==w=(s,f+v):z|t=u:(w%f)z
(w%f)[]=[(w,f)]
p#(a:z)|j==a=w p++[j]&z|t=(p++[a])#z;p#[]=w p
p&(a:z)|j==a=p:""#z|t=(p++[a])&z
c x=q(m!!0)$map((\(s,_:n)->(s,read n)).break(=='=')).w$last x where
 m=map(""#)$init x
 q[_,_,r,"+",s]d=n s$r%1$d
 q[_,_,r,_,s,z]d|maybe t(==0)(lookup r d)=n z d|t=n s$r%(-1)$d
 n('"':s)d=unlines[s,d>>=(\(r,v)->r++'=':shows v" ")]
 n s d=q(filter((==s).head)m!!0)d
main=interact$c.lines
t=1<3;j='"';w=words

Людина, це було важко! Правильна обробка повідомлень з пробілами в них коштує понад 70 символів. Форматування виводу, щоб бути більш "зрозумілим для людини", а відповідні приклади коштували ще 25.


  • Редагувати: (498 -> 482) різні невеликі вкладиші та деякі пропозиції @ FUZxxl
  • Редагувати: (482 -> 453) перемикатися назад, використовуючи фактичні числа для регістрів; застосовано багато трюків для гольфу
  • Редагувати: (453 -> 444) вбудоване форматування виводу та аналіз початкового значення

Я не знаю Haskell, тому я не можу розшифрувати весь синтаксис, але я можу розшифрувати достатньо, щоб побачити, що ви використовуєте списки для вмісту реєстру. Треба сказати, що я здивований, що це коротше, ніж використання ints.
Пітер Тейлор

Якщо whereрозмістити локальні прив’язки після того, як в один рядок, відокремлений крапками з комою, ви зможете заощадити 6 символів. І я здогадуюсь, що ви можете зберегти деякі символи у визначенні q, змінивши багатослівний if-then-else на захист шаблону.
FUZxxl

А також: Просто сліпо припустимо, що третє значення є "-"у визначенні qта використовуйте замість цього підкреслення.
FUZxxl

Я думаю, ви можете зберегти ще одну таблицю, змінивши рядок 8 на q[_,_,r,_,s,z]d|maybe t(==0)$lookup r d=n z d|t=n s$r%(-1)$d. Але все одно, ця програма в гольфі надзвичайно гарна.
FUZxxl

Ви можете значно скоротити синтаксичний аналіз, скориставшись lexпрелюдією. Наприклад, щось на зразок f[]=[];f s=lex s>>= \(t,r)->t:f rрозділить рядок на маркери при правильній обробці цитованих рядків.
hammar

6

Рубі 1,9, 214 212 211 198 195 192 181 175 173 175

*s,k=*$<
a,=s
b=Hash.new 0
eval k.gsub /(\w+)=/,';b["\1"]='
loop{x,y,r,o,t,f=a.scan /".*?"|\S+/
l=(b[r]-=o<=>?,)<0?(b[r]=0;f):t
l[?"]&&puts(eval(l),b)&exit
a,=s.grep /^#{l} /}

Я б очікував, що це не вдасться на префіксах один одного. Думки?
JB

Я не можу зробити так, щоб це працювало з будь-яким іншим випадком, крім прикладів. Що з цим
JB

Я думаю, це зараз виправлено.
Lowjacker

Ах, набагато краще. Дякую.
JB

3

Дельфи, 646

Delphi не пропонує дуже багато, що стосується розбиття рядків та інших матеріалів. На щастя, у нас є загальні колекції, що трохи допомагає, але це все-таки досить велике рішення:

uses SysUtils,Generics.Collections;type P=array[0..99]of string;Y=TDictionary<string,P>;Z=TDictionary<string,Int32>;var t:Y;l,i:string;j,k:Int32;q:P;u:Z;v:TPair<string,Int32>;begin t:=Y.Create;repeat if i=''then i:=q[0];t.Add(q[0],q);ReadLn(l);for j:=0to 6do begin k:=Pos(' ',l+' ');q[j]:=Copy(l,1,k-1);Delete(l,1,k)end;until q[1]<>':';u:=Z.Create;j:=0;repeat k:=Pos('=',q[j]);u.Add(Copy(q[j],1,k-1),StrToInt(Copy(q[j],k+1,99)));Inc(j)until q[j]='';repeat q:=t[i];i:=q[4];u.TryGetValue(q[2],j);if q[3]='+'then Inc(j)else if j=0then i:=q[5]else Dec(j);u.AddOrSetValue(q[2],j)until i[1]='"';WriteLn(i);for v in u do Write(v.Key,'=',v.Value,' ')end.

Тут розміщена та прокоментована версія:

uses SysUtils,Generics.Collections;
type
  // P is a declaration line, offsets:
  // 0 = label
  // 1 = ':'
  // 2 = register
  // 3 = operation ('-' or '+')
  // 4 = 1st state (or message)
  // 5 = 2nd state (or message)
  P=array[0..99]of string;
  // T is a dictionary of all state lines :
  Y=TDictionary<string,P>;
  // Z is a dictionary of all registers :
  Z=TDictionary<string,Int32>;
var
  t:Y;
  l,
  i:string;
  j,
  k:Int32;
  q:P;
  u:Z;
  v:TPair<string,Int32>;
begin
  // Read all input lines :
  t:=Y.Create;
  repeat
    // Put all lines into a record
    if i=''then i:=q[0];
    t.Add(q[0],q);
    // Split up each input line on spaces :
    ReadLn(l);
    for j:=0to 6do
    begin
      k:=Pos(' ',l+' ');
      q[j]:=Copy(l,1,k-1);
      Delete(l,1,k)
    end;
    // Stop when there are no more state transitions :
  until q[1]<>':';
  // Scan initial registers :
  u:=Z.Create;
  j:=0;
  repeat
    k:=Pos('=',q[j]);
    // Add each name=value pair to a dictionary :
    u.Add(Copy(q[j],1,k-1),StrToInt(Copy(q[j],k+1,99)));
    Inc(j)
  until q[j]='';
  // Execute the state machine :
  repeat
    q:=t[i];
    i:=q[4];
    u.TryGetValue(q[2],j);
    if q[3]='+'then
      Inc(j)
    else
      if j=0then
        i:=q[5]
      else
        Dec(j);
    u.AddOrSetValue(q[2],j)
  until i[1]='"';
  WriteLn(i);
  for v in u do
    Write(v.Key,'=',v.Value,' ')
end.

1

PHP, 446 441 402 398 395 389 371 370 366 символів

<?$t=trim;$e=explode;while($l=$t(fgets(STDIN))){if(strpos($l,"=")){foreach($e(" ",$l)as$b){list($k,$c)=$e("=",$b);$v[$k]=$c;}break;}list($k,$d)=$e(":",$l);$r[$z=$t($k)]=$t($d);$c=$c?:$z;}while($d=$e(" ",$r[$c],4)){$c=$v[$a=$d[0]]||!$d[3]?$d[2]:$d[3];if(!$r[$c]){eval("echo $c.'\n';");foreach($v as$k=>$c)echo$k."=".$c." ";die;}if(!$d[3]&&++$v[$a]||$v[$a]&&--$v[$a]);}

Безумовно


<?php

$register = array();
$values = array();

while($line = trim(fgets(STDIN))){

    if(strpos($line, "=")){

        // Set each value and then continue to the calculations

        foreach(explode(" ", $line) as $var){
            list($key, $val) = explode("=", $var);

            $values[$key] = $val;
        }

        break;
    }

    list($key, $data) = explode(":", $line);

    // Add data to the register

    $register[$z = trim($key)] = trim($data);

    // Set the first register

    $current = $current?:$z;
}

while($data = explode(" ", $register[$current], 4)){

    // Determine next register and current register

    $current = $values[$target = $data[0]] || !$data[3]? $data[2] : $data[3];

    // Will return true if the register does not exist (Messages wont have a register)

    if(!$register[$current]){

        // No need to strip the quotes this way

        eval("echo$current.'\n';");

        // Print all values in the right formatting

        foreach($values as $key => $val)
            echo $key."=".$val." ";

        die();
    }

    // Only subtraction has a third index
    // Only positive values return true

    // If there is no third index, then increase the value
    // If there is a third index, increment the decrease the value if it is positive

    // Uses PHP's short-circuit operators

    if(!$data[3] && ++$values[$target] || $values[$target] && --$values[$target]);
}

Журнал змін


446 -> 441 : Підтримує рядки для першого стану та деяке незначне стиснення
441 -> 402 : максимально стиснуте if / else та заяви про призначення,
402 -> 398 : Імена функцій можна використовувати як константи, які можна використовувати як рядки
398 -> 395 : Використовує оператори короткого замикання
395 -> 389 : Не потрібно іншої частини
389 -> 371 : Не потрібно використовувати array_key_exists ()
371 -> 370 : Видалено непотрібний простір
370 -> 366 : Видалено два непотрібні пробіли в передвісті


1

Гровий, 338

m={s=r=[:];z=[:]
it.eachLine{e->((e==~/\w+=.*/)?{(e=~/((\w+)=(\d+))+/).each{r[it[2]]=it[3] as int}}:{f=(e=~/(\w+) : (.*)/)[0];s=s?:f[1];z[f[1]]=f[2];})()}
while(s[0]!='"'){p=(z[s]=~/(\w+) (.) (\w+|(?:".*?")) ?(.*)?/)[0];s=p[3];a=r[p[1]]?:0;r[p[1]]=p[2]=='-'?a?a-1:{s=p[4];0}():a+1}
println s[1..-2]+"\n"+r.collect{k,v->"$k=$v"}.join(' ')}


['''s0 : a - s1 "Ok"
s1 : b + s0
a=3 b=4''':'''Ok
a=0 b=7''',
'''init : t - init d0
d0 : a - d1 a0
d1 : b + d2
d2 : t + d0
a0 : t - a1 "Ok"
a1 : a + a0
a=3 b=4''':'''Ok
a=3 b=7 t=0''',
'''s0 : t - s0 s1
s1 : t + "t is 1"
t=17''':'''t is 1
t=1''',
'''s0 : t - "t is nonzero" "t is zero"
t=1''':'''t is nonzero
t=0''',
'''init0 : k - init1 init3
init1 : r + init2
init2 : t + init0
init3 : t - init4 init5
init4 : k + init3
init5 : r - init6 "ERROR k is 0"
init6 : i + init7
init7 : n - loop0 "ERROR n is 0"
loop0 : n - loop1 "Ok"
loop1 : i + loop2
loop2 : k - loop3 loop5
loop3 : r + loop4
loop4 : t + loop2
loop5 : t - loop6 loop7
loop6 : k + loop5
loop7 : i - loop8 loopa
loop8 : r - loop9 loopc
loop9 : t + loop7
loopa : t - loopb loop7
loopb : i + loopa
loopc : t - loopd loopf
loopd : i + loope
loope : r + loopc
loopf : i + loop0
n=40 k=3''':'''Ok
i=40 k=3 n=0 r=27 t=0'''].collect {input,expectedOutput->
    def actualOutput = m(input)
    actualOutput == expectedOutput
}

1
Я перевірив це, але , схоже, нічого не виводить на stdout . Що потрібно додати, щоб побачити результати? (PS специфікація каже, що порядок регістрів на виході не має значення, тому ви можете зберегти 7 символів від .sort())
Пітер Тейлор

@Петер дякую за пораду - мені доведеться додати 8 символів для println- ну добре!
Арман

1

Clojure (344 символів)

Маючи декілька рядків для "читабельності":

(let[i(apply str(butlast(slurp *in*)))]
(loop[s(read-string i)p(->> i(replace(zipmap":\n=""[] "))(apply str)(format"{%s}")read-string)]
(let[c(p s)](cond(string? s)(println s"\n"(filter #(number?(% 1))p))
(=(c 1)'-)(let[z(=(get p(c 0)0)0)](recur(c(if z 3 2))(if z p(update-in p[(c 0)]dec))))
1(recur(c 2)(update-in p[(c 0)]#(if %(inc %)1)))))))

1

Постскрипт () () (852) (718)

На реальні цього разу. Виконує всі тестові справи. Це все ще вимагає, щоб програма RM негайно перейшла у потоці програми.

Редагувати: більше факторингу, скорочення назв процедур.

errordict/undefined{& " * 34 eq{.()= !{& " .(=). load " .( ).}forall ^()=
stop}{^ ^ " 0 @ : 0}ifelse}put<</^{pop}/&{dup}/:{def}/#{exch}/*{& 0
get}/.{print}/~{1 index}/"{=string cvs}/`{cvn # ^ #}/+={~ load add :}/++{1
~ length 1 sub getinterval}/S{/I where{^}{/I ~ cvx :}ifelse}/D{/? # :/_ #
cvlit :}/+{D S({//_ 1 +=//?})$ ^ :}/-{/| # : D S({//_ load 0 ne{//_ -1
+=//?}{//|}ifelse})$ ^ :}/![]/@{~/! #[# cvn ! aload length & 1 add #
roll]:}/;{(=)search ^ # ^ # cvi @ :}/${* 32 eq{++}if * 34 eq{& ++(")search
^ length 2 add 4 3 roll # 0 # getinterval cvx `}{token ^
#}ifelse}>>begin{currentfile =string readline ^( : )search{`( + )search{`
$ ^ +}{( - )search ^ ` $ $ ^ -}ifelse}{( ){search{;}{; I}ifelse}loop}ifelse}loop

Відступ та коментування додається програми.

%!
%Minsky Register Machine Simulation
errordict/undefined{ %replace the handler for the /undefined error
    & " * 34 eq{ % if, after conversion to string, it begins with '"',
        .()= !{ % print it, print newline, iterate through the register list
            & " .(=). load " .( ). % print regname=value
        }forall ^()= stop % print newline, END PROGRAM
    }{ % if it doesn't begin with '"', it's an uninitialized register
        ^ ^ " 0 @ : 0 %initialize register to zero, return zero
    }ifelse
}put
<<
/^{pop}
/&{dup}
/:{def} % cf FORTH
/#{exch}
/*{& 0 get} % cf C
/.{print} % cf BF

% these fragments were repeated several times
/~{1 index}
/"{=string cvs} % convert to string
/`{cvn # ^ #} % convert to name, exch, pop, exch
/+={~ load add :} % add a value to a variable
/++{1 ~ length 1 sub getinterval} % increment a "string pointer"

/S{/I where{^}{/I ~ cvx :}ifelse} %setINIT define initial state unless already done
/D{/? # :/_ # cvlit :} %sr define state and register for generated procedure
/+{D S({//_ 1 +=//?})$ ^ :} % generate an increment state and define
/-{/| # : D S({//_ load 0 ne{//_ -1 +=//?}{//|}ifelse})$ ^ :} % decrement state
/![] %REGS list of registers
/@{~/! #[# cvn ! aload length & 1 add # roll]:} %addreg append to REGS
/;{(=)search ^ # ^ # cvi @ :} %regline process a register assignment
/${ %tpe extract the next token or "string"
    * 32 eq{++}if %skip ahead if space
    * 34 eq{ %if quote, find the end-quote and snag both
        & ++(")search ^ length 2 add 4 3 roll # 0 # getinterval cvx `
    }{
        token ^ # %not a quote: pull a token, exch, pop
    }ifelse
}
>>begin

{
    currentfile =string readline ^
    ( : )search{ % if it's a state line
        `( + )search{ % if it's an increment
            ` $ ^ + %parse it
        }{
            ( - )search ^ ` $ $ ^ - %it's a decrement. Parse it
        }ifelse
    }{ % not a state, do register assignments, and call initial state
        ( ){search{;}{; I}ifelse}loop %Look Ma, no `exit`!
    }ifelse
}loop
init0 : k - init1 init3
init1 : r + init2
init2 : t + init0
init3 : t - init4 init5
init4 : k + init3
init5 : r - init6 "ERROR k is 0"
init6 : i + init7
init7 : n - loop0 "ERROR n is 0"
loop0 : n - loop1 "Ok"
loop1 : i + loop2
loop2 : k - loop3 loop5
loop3 : r + loop4
loop4 : t + loop2
loop5 : t - loop6 loop7
loop6 : k + loop5
loop7 : i - loop8 loopa
loop8 : r - loop9 loopc
loop9 : t + loop7
loopa : t - loopb loop7
loopb : i + loopa
loopc : t - loopd loopf
loopd : i + loope
loope : r + loopc
loopf : i + loop0
n=40 k=3

Минув час, коли я написав будь-який PostScript, але ви визначаєте функції з такими іменами regline? Ви не можете багато заощадити, називаючи їх такими, як R?
Пітер Тейлор

Так, звичайно. Але є й потенційна проблема, оскільки всі ці визначення співіснують зі станом та реєструють імена в одному словнику. Тому я намагався знайти знаки пунктуації з деяким мнемонічним значенням (тому я все ще можу його прочитати :). Я також сподіваюся знайти більше алгоритмічних скорочень, тому я не хотів витрачати занадто багато енергії, перш ніж я міг би на це подивитися свіжими очима.
luser droog

1

AWK - 447

BEGIN{FS=":"}NF<2{split($1,x," ");for(y in x){split(x[y],q,"=");
g[q[1]]=int(q[2])}}NF>1{w=$1;l=$2;gsub(/ /,"",w);if(!a)a=w;for(i=0;;)
{sub(/^ +/,"",l);if(l=="")break;if(substr(l,1,1)=="\""){l=substr(l,2);
z=index(l,"\"")}else{z=index(l," ");z||z=length(l)+1}d[w,i++]=
substr(l,1,z-1);l=substr(l,z+1)}}END{for(;;){if(!((a,0)in d))break;h=d[a,0];
if(d[a,1]~/+/){g[h]++;a=d[a,2]}else{a=g[h]?d[a,2]:d[a,3];g[h]&&g[h]--}}
print a;for(r in g)print r"="g[r]}

Це вихід для першого тесту:

% cat | awk -f mrm1.awk
s0 : a - s1 "Ok"
s1 : b + s0
a=3 b=4
^D
Ok
a=0
b=7

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.