Anyfix表記を実装してください!


16

プレフィックス表記では、演算子は引数の前に来るため、演算子next()が再帰的に呼び出されることを想像できます。中置記法では、演算子は引数の間を行き来するので、単純に構文解析ツリーと考えることができます。後置記法では、演算子は引数の後に来るため、スタックベースと考えることができます。

anyfix表記では、演算子はどこにでも行くことができます*。演算子が表示され、十分な引数がない場合、演算子は十分な引数があるまで待機します。この課題のために、非常に基本的なanyfix評価器を実装することになります。(anyfixは、ここで遊んだり、ここでチェックしたりできるように放棄したレクリエーション言語であることに注意してください

次のコマンドをサポートする必要があります。

(アリティ1)

  • 複製する

(アリティ2)

  • 添加
  • 乗算
  • 等式:0またはを返します1

これらのコマンドには、任意の5つの非空白記号を使用できます。デモンストレーションのために、"複製、×乗算、加算として使用し+ます。

リテラルについては、負でない整数のみをサポートする必要がありますが、インタープリターはすべての整数(言語の(合理的な)整数範囲内)を含めることができる必要があります。

例を見てみましょう10+5。ストレージは、キューではなくスタックとして動作する必要があります。最初に、スタックはから始まり[]、キューに入れられた演算子リストはから始まり[]ます。次に、リテラル10が評価され、スタックが作成されます[10]。次に、演算子+が評価されます。これには2つの引数が必要です。ただし、スタックには引数が1つしかないため、キュー演算子リストはになり['+']ます。次に、リテラル5が評価され、スタックが作成されます[10, 5]。この時点で、演算子'+'を評価して、スタック[15]とキューを作成できます[]

最終的な結果は、あるべき[15]ために+ 10 510 + 510 5 +

より難しい例を見てみましょう10+"。スタックとキューは[]andで始まります[]10最初に評価され、スタックが作成されます[10]。次に、+が評価されますが、これはスタックを変更せず(十分な引数がないため)、queueを作成します['+']。次に、"評価されます。これはすぐに実行できるため、スタックが作成されます[10, 10]+これで、スタックが[20]キューになるように評価できます[]。最終結果は[20]です。

操作の順序はどうですか?

を見てみましょう×+"10 10。スタックとキューは両方とも次のように開始します[]

  • ×:スタックは変更されず、キューは ['×']ます。
  • +:スタックは変更されず、キューは ['×', '+']ます。
  • ":スタックは変更されず、キューは ['×', '+', '"']ます。
  • 10:スタックはになり[10]ます。にもかかわらず×、それが最初に表示されますので、最初の演算子が評価されるようにする必要があり、"それが評価されるので、すぐに実行しないと演算子のどれもそれができる前にすることができます。スタックがに[10, 10]なり、キューになります['×', '+']×これで評価できるようになり、スタック[100]とキューが作成されます['+']
  • 10:スタックはになり[100, 10]+評価できるようになります。スタックがに[110]なり、キューになります[]

最終結果は [110]です。

これらのデモで使用されるコマンドは、anyfix言語のコマンドと一致しています。ただし、最後の例は、インタープリターのバグが原因で機能しません。(免責事項:あなたの提出物はanyfixインタープリターでは使用されません)

チャレンジ

5つの空白以外の数字以外の文字のセットを選択し、上記の仕様に従ってanyfixインタープリターを作成します。プログラムは、特異配列またはそれに含まれる値を出力できます。値のスタックには実行の終了時に単一の値のみが含まれ、演算子のキューは実行の終了時に空になることが保証されています。

これはので、バイト単位の最短コードが勝ちです。

テストケース

これらのテストケースでは、duplicate is "、negative is -、加算is +、乗算is ×、および等式is =です。

Input -> Output
1+2×3 -> 9
1"+"+ -> 4
2"××" -> 16
3"×+" -> 18
3"+×" -> 36
123"= -> 1 ("= always gives 1)
1+2=3 -> 1
1"=2+ -> 3
1-2-+ -> -3
-1-2+ -> 3 (hehe, the `-1` becomes `+1` at the `-` rather than making the `2` a `-1`)
+×"10 10 -> 200 (after the 10 is duplicated (duplication is delayed), 10 + 10 is performed and then 20 * 10, giving 200)

ルール

  • 標準的な抜け穴が適用されます
  • 必要に応じて、anyfix公式通訳を利用してゴルフをすることもできます。恐ろしく失うことを期待しています。

入力は文字列として与えられ、出力はいずれかの文字列表現の配列である単一の整数として出力されます。入力にはスペース、数字、選択した5文字のみが含まれると想定できます。

* 実際はそうではなくて


2
どこにでも行く*™。
ジョナサンアラン

等値演算子の結果は何ですか?0そして1
フェリックスパルメン

1
@JonathanAllanは上記を参照してください。私は、コマンドRIPを削除
HyperNeutrino

1
@RickHitchcock確かに。
ハイパーニュートリノ

1
おそらく×+"10 10、テストケース、または1)空白の使用、2)重複演算子の使用の遅延(完全に見逃した2つのこと)などの例を含める必要があります。
アーナルド

回答:


5

JavaScriptの(ES6)、204の 203 200バイト

整数を返します。

e=>e.replace(/\d+|\S/g,v=>{for((1/v?s:v>','?u:b)[U='unshift'](v);!!u[0]/s[0]?s[U](u.pop()>'c'?s[0]:-S()):!!b[0]/s[1]?s[U](+eval(S(o=b.pop())+(o<'$'?'==':o)+S())):0;);},s=[],u=[],b=[],S=_=>s.shift())|s

使用される文字:

  • +:追加
  • *:乗算
  • #:平等
  • d:複製
  • -:負

テストケース

フォーマットおよびコメント

e => e.replace(                     // given an expression e, for each value v matching
  /\d+|\S/g, v => {                 // a group of digits or any other non-whitespace char.
    for(                            //   this loop processes as many operators as possible
      (                             //   insert v at the beginning of the relevant stack:
        1 / v ? s : v > ',' ? u : b //     either value, unary operator or binary operator
      )[U = 'unshift'](v);          //     (s[], u[] or b[] respectively)
      !!u[0] / s[0] ?               //   if there's at least 1 value and 1 unary operator:
        s[U](                       //     unshift into s[]:
          u.pop() > 'c' ?           //       for the duplicate operator:
            s[0]                    //         a copy of the last value
          :                         //       else, for the negative operator:
            -S()                    //         the opposite of the last value
        ) :                         //     end of unshift()
      !!b[0] / s[1] ?               //   if there's at least 2 values and 1 binary operator:
        s[U](                       //     unshift into s[]:
          +eval(                    //       the result of the following expression:
            S(o = b.pop()) +        //         the last value, followed by the
            (o < '$' ? '==' : o) +  //         binary operator o with '#' replaced by '=='
            S()                     //         followed by the penultimate value
          )                         //       end of eval()
        ) : 0;                      //     end of unshift()
    );                              //   end of for()
  },                                // end of replace() callback
  s = [],                           // initialize the value stack s[]
  u = [],                           // initialize the unary operator stack u[]
  b = [],                           // initialize the binary operator stack b[]
  S = _ => s.shift()                // S = helper function to shift from s[]
) | s                               // return the final result

これがうまくいくとは思わないでください-1+-2。-3の代わりに3を返します。
リックヒッチコック

1
@RickHitchcock私の理解では、すぐに2番目を-適用する必要があります-1
アーナルド

別のオペレーターのに来るので、私は2番目-が行くと思うでしょう。おそらく@HyperNeutrinoが明確にすることができます。状況によっては、否定演算子があいまいになる場合があります。2
リックヒッチコック

3

JavaScript(ES6)、162 152 143 150バイト

(s,N=s.replace(/(-?\d+)-|-(-)/g,'- $1 ').match(/(- ?)*?\d+|R/g))=>+eval(`R=${N[0]>'9'?N[1]:N[0]},${s.match(/[+*=]/g).map((o,i)=>'R=R'+o+'='+N[i+1])}`)

わずかに未使用:

(s,
 N=s.replace(/(-?\d+)-|-(-)/g,'- $1 ').      //change postfix negatives to prefix,
                                             //and change "--" to "- - "
     match(/(- ?)*?\d+|R/g)                  //grab numbers and duplicates
)=>+eval(`R=${N[0] > '9' ?  N[1] : N[0]},    //handle a delayed duplicate
          ${s.match(/[+*=]/g).               //grab the operators
              map((o,i)=>'R=R'+o+'='+N[i+1]) //create a comma-separated list of assignments
           }
         `)

説明

*乗算とR複製に使用しています。他の演算子は質問の場合と同じです。

N 数字の配列(重複を含む)になります。

replace負の符号が来る場合に処理した後に番号を。例えば、それが変更されます1-まで- 1-1-します- -1

evals.matchバイナリ演算子のアレイを作成します。これには、常に要素が1つ少ないことに注意してくださいN

関数の結果は、eval数値と演算子のマッピングです。

eval各テストケースの編集内容は次のとおりです。

0+2*3        R=0,R=R+=2,R=R*=3        = 6 
1+2*3        R=1,R=R+=2,R=R*=3        = 9 
1R+R+        R=1,R=R+=R,R=R+=R        = 4 
2R**R        R=2,R=R*=R,R=R*=R        = 16 
3R*+R        R=3,R=R*=R,R=R+=R        = 18 
3R+*R        R=3,R=R+=R,R=R*=R        = 36 
123R=        R=123,R=R==R             = 1 
1+2=3        R=1,R=R+=2,R=R==3        = 1 
1R=2+        R=1,R=R==R,R=R+=2        = 3 
1-2-+        R=- 1,R=R+=- 2           = -3 
-1-2+        R=1,R=R+=2               = 3 
*+R10 10     R=10,R=R*=10,R=R+=10     = 110 
+*R10 10     R=10,R=R+=10,R=R*=10     = 200 
-1+--2       R=-1,R=R+=- -2           = 1 
-1+-2        R=-1,R=R+=-2             = -3 

JavaScript式のコンマ演算子は最後の式の結果をmap返すため、使用可能な式が自動的に返されます。

+符号が前に必要とされるeval変更することtrue1してfalseまで0

R変数重複演算子の両方として使用するmapのサブ式がます。

テストケース:


2
replace意図したとおりに動作するとは思わない。これは3を返し-1+--2、私1は正しいと思います(利用可能な1ものに対する2番目の引数がある前に変更が3回署名するため+、結果は-1 + 2)。
フェリックスパルメン

素晴らしいキャッチ、@ FelixPalmen。修正されました。
リックヒッチコック

2

JavaScript、321 311バイト

_="f=a=>(a.replace(/\\d+|./g,mq!~(b='+*=\"- '.indexOf(a))|b>2j3j4j5&&o+aw1/y?(y*=-1wcz:1/y?oywcz:hz,rql.map(z=>m(lki,1)[0],i)),hq1/s[1]?sk0,2,+eval(`y${a=='='?a+a:a}s[1]`)):cz,cqlki,0,a),s=[],l=[],e='splice'),s)z(a,i)ys[0]w)^r``:q=z=>os.unshift(k[e](j?b-";for(i of"jkoqwyz")with(_.split(i))_=join(pop());eval(_)

オンラインでお試しください!

5つの文字は、*乗算の場合を除いて、質問と同じです。
スクリプトはRegPackを使用して圧縮されます。元のスクリプトは_、評価後に変数に保存されます。


これがうまくいくとは思わないでください-1+-2。-3の代わりに3を返します。
リックヒッチコック

@RickHitchcock。なぜあなたはそれが-3代わりに戻るべきだと信じ3ますか?

否定的な演算子を誤解している可能性があります。一般的に-1 + -2-3、ですが、--1 + 2代わりに解析する必要がありますか?
リックヒッチコック

1
@RickHitchcock。私は結果がかなり確信してい3ます。前に2も、スタック上に来る、第二が-評価され、したがって、我々は1 2 +確かにあります3。ああ、おそらくあなたもあなたの答えを編集する必要があります。

あなたはおそらく正しいです。あなたとArnauldは同じ答えを受け取り、OPに説明を求めました。できればまた投票しますか。
リックヒッチコック

1

ハスケル、251バイト

(#([],[]))
(x:r)#(o,n)|x>'9'=r#h(o++[x],n)|[(a,t)]<-lex$x:r=t#h(o,read a:n)
_#(o,n:_)=n
h=e.e
e(o:s,n:m:r)|o>'N'=e(s,g[o]n m:r)
e(o:s,n:r)|o=='D'=e(s,n:n:r)|o=='N'=e(s,-n:r)
e(o:s,n)|(p,m)<-e(s,n)=(o:p,m)
e t=t
g"a"=(+)
g"m"=(*)
g"q"=(((0^).abs).).(-)

オンラインでお試しください!次の文字を使用します:a加算、m乗算、q等値、D複製、およびN否定。(e平等のために使用したかったのですが、数値としてlex解析する問題に遭遇しました2e3。)使用例:(#([],[])) "2a3 4m"yields 20


1

6502マシンコード(C64)、697バイト

00 C0 A2 00 86 29 86 26 86 27 86 28 86 4B 86 4C 86 CC 20 E4 FF F0 FB C9 0D F0
10 C9 20 30 F3 A6 27 9D B7 C2 20 D2 FF E6 27 D0 E7 C6 CC A9 20 20 1C EA A9 0D
20 D2 FF 20 95 C0 20 09 C1 20 95 C0 A6 26 E4 27 F0 4E BD B7 C2 E6 26 C9 20 F0
E8 C9 2D D0 09 A6 4C A9 01 9D B7 C3 D0 32 C9 22 D0 09 A6 4C A9 02 9D B7 C3 D0
25 C9 2B D0 09 A6 4C A9 81 9D B7 C3 D0 18 C9 2A D0 09 A6 4C A9 82 9D B7 C3 D0
0B C9 3D D0 0D A6 4C A9 83 9D B7 C3 E6 28 E6 4C D0 A3 4C 8A C2 A6 29 F0 6F A4
28 F0 6B CA F0 4B C6 28 A6 4B E6 4B BD B7 C3 F0 F5 30 14 AA CA D0 0B 20 7B C2
20 E1 C1 20 4D C2 D0 D9 20 5C C2 D0 D4 29 0F AA CA D0 0B 20 6D C2 20 08 C2 20
4D C2 D0 C3 CA D0 0B 20 6D C2 20 16 C2 20 4D C2 D0 B5 20 6D C2 20 F4 C1 20 4D
C2 D0 AA A4 4B B9 B7 C3 F0 02 10 AC C8 C4 4C F0 0F B9 B7 C3 F0 F6 30 F4 AA A9
00 99 B7 C3 F0 A6 60 A0 00 A6 26 E4 27 F0 15 BD B7 C2 C9 30 30 0E C9 3A 10 0A
E6 26 99 37 C4 C8 C0 05 D0 E5 C0 00 F0 08 A9 00 99 37 C4 20 39 C2 60 A2 FF E8
BD 37 C4 D0 FA A0 06 88 CA 30 0A BD 37 C4 29 0F 99 37 C4 10 F2 A9 00 99 37 C4
88 10 F8 A9 00 8D 3D C4 8D 3E C4 A2 10 A0 7B 18 B9 BD C3 90 02 09 10 4A 99 BD
C3 C8 10 F2 6E 3E C4 6E 3D C4 CA D0 01 60 A0 04 B9 38 C4 C9 08 30 05 E9 03 99
38 C4 88 10 F1 30 D2 A2 06 A9 00 9D 36 C4 CA D0 FA A2 10 A0 04 B9 38 C4 C9 05
30 05 69 02 99 38 C4 88 10 F1 A0 04 0E 3D C4 2E 3E C4 B9 38 C4 2A C9 10 29 0F
99 38 C4 88 10 F2 CA D0 D6 C0 05 F0 06 C8 B9 37 C4 F0 F6 09 30 9D 37 C4 E8 C8
C0 06 F0 05 B9 37 C4 90 F0 A9 00 9D 37 C4 60 A9 FF 45 FC 85 9F A9 FF 45 FB 85
9E E6 9E D0 02 E6 9F 60 A2 00 86 9F A5 FB C5 FD D0 07 A5 FC C5 FE D0 01 E8 86
9E 60 A5 FB 18 65 FD 85 9E A5 FC 65 FE 85 9F 60 A9 00 85 9E 85 9F A2 10 46 FC
66 FB 90 0D A5 FD 18 65 9E 85 9E A5 FE 65 9F 85 9F 06 FD 26 FE CA 10 E6 60 20
33 C1 A6 29 AD 3D C4 9D 3F C4 AD 3E C4 9D 3F C5 E6 29 60 A6 29 A5 9E 9D 3F C4
A5 9F 9D 3F C5 E6 29 60 A6 29 BD 3E C4 9D 3F C4 BD 3E C5 9D 3F C5 E6 29 60 C6
29 A6 29 BD 3F C4 85 FD BD 3F C5 85 FE C6 29 A6 29 BD 3F C4 85 FB BD 3F C5 85
FC 60 A6 29 BD 3E C5 10 13 20 7B C2 20 E1 C1 20 4D C2 A9 2D 20 D2 FF A6 29 BD
3E C5 8D 3E C4 BD 3E C4 8D 3D C4 20 8B C1 A9 37 A0 C4 4C 1E AB

オンラインデモ

使用法 sys49152、次にanyfix式を入力し、returnキーを押します。

  • エラーチェックがほとんどないため、無効な式での面白い出力が予想されます。
  • 乗算の記号は *、他のすべては推奨されています。
  • 最大入力長は256文字です。キューに入れられる演算子は127個までです。
  • 入力ルーチン制御文字を処理ため、タイプミスしないでください;)
  • 整数は16ビット符号付きで、オーバーフローは静かにラップアラウンドします。
  • このCPUも乗算とC64 OS / ROMはあなたを与えるものではありません知っていないため、バイト数が少し大きい任意の進文字列から/までの整数算術演算または変換を。

ここだ読めるCA65スタイルアセンブラソースコードは


1

VB.NET(.NET 4.5)615の 576バイト

-39バイト、Felix Palmenに変更\r\nして\n

必要Imports System.Collections.Generic(バイトカウントに含まれる)

Dim s=New Stack(Of Long),q=New List(Of String),i=Nothing,t=0,c=0
Function A(n)
For Each c In n
If Long.TryParse(c,t)Then
i=i &"0"+t
Else
If c<>" "Then q.Add(c)
If i<>A Then s.Push(i)
i=A
End If
If i=A Then E
Next
If i<>A Then s.Push(i)
E
A=s
End Function
Sub E()
c=s.Count
If c=0Then Exit Sub
For Each op In q
If op="-"Or op="d"Or c>1Then
Select Case op
Case"*"
s.Push(s.Pop*s.Pop)
Case"+"
s.Push(s.Pop+s.Pop)
Case"="
s.Push(-(s.Pop=s.Pop))
Case"-"
s.Push(-s.Pop)
Case"d"
s.Push(s.Peek)
End Select
q.Remove(op)
E
Exit Sub
End If
Next
End Sub

エントリポイントはFunctionですA。入力として文字列を受け取り、Stack(Of Long)

記号:

  • 追加- +
  • 乗算- *
  • 平等- =
  • 否定- -
  • 複製- d

概要:

関数Aは入力を受け取り、それをトークン化します。a Long?を使用して、複数桁の整数の合計を実行します。Nothingを行いは、現在整数を読み取っていないこと示しています。

サブルーチンEは、整数のスタックと演算子のキューを受け取り、anyfix表記を評価します。アクションがなくなるまで再帰的に自身を呼び出します。

グローバルパラメータを一度に宣言して、宣言とパラメータの受け渡しの両方でバイトを節約します。

からの戻り値Aは、一致する変数に値を割り当てることで設定されますA

VBはとTrue同等-1であるため、正しい値を取得するために操作は結果を否定する必要があります。

オンラインでお試しください!



ところで、で、Importsバイトカウントのみを取得します576- カウントを間違えていませんか?
フェリックスパルメン

@FelixPalmenの\r\n代わりに数えた\nので、ここで矛盾が生じます。
ブライアンJ

@FelixPalmenはTIOを追加しました。思い出させてくれてありがとう!:)(ああ、私はあなたがすでにこの投稿に参加していることに気付いていませんでした)
ブライアンJ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.