Имитация машины регистра Минского (I)

26

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

RM состоит из конечного автомата и конечного числа именованных регистров, каждый из которых содержит неотрицательное целое число. Для простоты ввода текста эта задача требует, чтобы также были названы состояния.

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

Для «правильности» в качестве языка программирования конечные состояния принимают жестко запрограммированную строку для печати (так что вы можете указать исключительное завершение).

Ввод от стандартного ввода. Формат ввода состоит из одной строки на состояние, за которой следует начальное содержимое регистра. Первая строка - это начальное состояние. БНФ для государственных линий это:

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

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

Последняя строка ввода, которая дает начальные значения регистра, представляет собой разделенный пробелами список присваиваний идентификатора = 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

Более сложный пример

Взято из проблемы кода проблемы 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

Эта программа в виде картинки для тех, кто мыслит визуально и считает полезным понять синтаксис: Проблема Иосифа Р. М.

Если вам понравился этот гольф, посмотрите на продолжение .

Питер Тейлор
источник
Вход поступает из стандартного ввода, из файла или из другого места?
Кевин Браун
@ Бас, из стандартного.
Питер Тейлор
Вы должны добавить несколько тестовых случаев со следующими трудными для обработки проблемами: 1) сообщения с пробелами, 2) сообщения с символами равенства, 3) сообщения в inc_line, 4) сообщения в первом состоянии dec_line, 5) сообщения в пробелах в случаи 3 и 4.
MtnViewMark
В грамматике есть ошибка: между двумя записями state_name в dec_line должен быть буквальный пробел. Также неясно, хотите ли вы требовать, чтобы люди принимали несколько пробелов между токенами во входных данных.
MtnViewMark
2
@Peter: +1 за действительно мясистый код-гольф с хорошим балансом спецификаций и возможностей для маневра! Большинство вопросов здесь были слишком тонкими.
MtnViewMark

Ответы:

10

Perl, 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 «лучшая интеграция с регулярными выражениями».

Немного подробностей изнутри, если вы не читаете Perl:

  • @p=<>: прочитайте полное описание машины @p
  • /=/,$_{$`}=$' for split$",pop@p: для каждого ( for) assignment ( split$") в последней строке описания машины ( @p) найдите знак равенства ( /=/), затем присвойте значение ключу $'hask%_$`
  • $o='\w+': начальное состояние будет первым, чтобы соответствовать регулярному выражению Perl "символы слова"
  • until/"/: loop, пока мы не достигнем состояния завершения:
    • map{($r,$o,$,,$b)=$'=~/".*?"|\S+/g if/^$o :/}@p: loop на машинном описании @p: когда мы находимся в строке, совпадающей с текущим состоянием ( if/^$o :/), tokenize ( /".*?"|\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) и содержимое регистров в%_
JB
источник
Тебе не нужна толстая кишка /^$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' и т. Д.
Набб
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) встроенное форматирование вывода и разбор начального значения
MtnViewMark
источник
Я не знаю Haskell, поэтому я не могу расшифровать весь синтаксис, но я могу достаточно расшифровать, чтобы убедиться, что вы используете списки для содержимого регистра. Должен сказать, я удивлен, что это короче, чем использование целых.
Питер Тейлор
Поместив локальные привязки 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
Вы можете значительно сократить код синтаксического анализа, воспользовавшись преимуществами lexPrelude. Например, что-то подобное f[]=[];f s=lex s>>= \(t,r)->t:f rразделит строку на токены при правильной обработке строк в кавычках.
Хаммар
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} /}
Lowjacker
источник
Я ожидаю, что это не сработает на префиксах меток друг друга. Мысли?
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.
PatrickvL
источник
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]);}

Ungolfed


<?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 : удалено два ненужных пробела в foreach

Кевин Браун
источник
1

Groovy, 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
}
Armand
источник
1
Я проверил это, но он ничего не выводит на стандартный вывод . Что мне нужно добавить, чтобы увидеть результаты? (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?
Питер Тейлор
Да, безусловно. Но есть и потенциальная проблема, поскольку все эти определения сосуществуют с именами состояний и регистров в одном словаре. Поэтому я пытался найти знаки препинания с некоторым мнемоническим значением (так что я все еще могу его прочитать :). Я также надеюсь найти больше алгоритмических сокращений, поэтому я не хотел тратить слишком много энергии, прежде чем я смогу взглянуть на это свежим взглядом.
Люсер Дрог
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
Дэн Андреатта
источник