web-dev-qa-db-ja.com

dc unix:同じ配列インデックスに新しい値を格納した後でも初期値を保持する

dcのマンページにあるこの例を理解できません。

$ dc  
 1 0:a 0Sa 2 0:a La 0;ap  
 1  

私にとって答えは2でなければなりません:

  1. 1 0:a
    ここでは、配列aの0番目の位置に1を格納します。

  2. 0Sa
    次に、レジスタaのスタックに0をプッシュします。

  3. 2 0:aここでも、配列aの0番目の位置に2を格納します。これにより、その位置に格納されていた前の1が上書きされます。

  4. La
    次に、レジスタaのスタックに格納されている0をポップし、メインスタックにプッシュします。

  5. 0;a
    ここで、もう一度0をメインスタックにプッシュし、それをポップして配列インデックスとして使用するため、配列aの0番目の場所に格納されている2をメインスタックにプッシュします。

  6. p
    メインスタックの一番上である2を出力します。したがって、答えは2になります。

何が足りないのですか?

PS- dcをタグとして使用したかったのですが、存在しないようで、少なくとも1つのタグを使用する必要があるため、debian(私のワークステーションOS)を使用しました。

5
rootkea

配列とスタックを混合する場合と同じです。この例では、レジスタaが配列とスタックの両方として使用されています。

1 0:a 
0 Sa 
2 0:a 
La 
0;a p
  1. 最初の:a-レジスタa配列として扱われます。
  2. 次に、Sa --register aはスタックとして扱われます。実際には、配列をpt 1.から下にプッシュし、new配列を作成します。 manのように:レジスタのスタックされた各インスタンスには独自の配列が関連付けられていることに注意してください。
  3. 次に、:a --register aarrayとして扱われます。前の値と最初の配列値を押し下げます。
  4. 次に、La --register astackとして扱われます。最初に到達するにはstacked arraya[0]=2は配列であるため破棄されます。
  5. 次に、;a --register aarrayとして扱われます。これで、残っている値は1つだけになり、最初の配列値がaに追加されます。これは1です。

いくつかの例については回答の最後にあります。


コメントによる:

"レジスタごとにいくつの配列とスタックがありますか? 1つのレジスタに1つのスタックと1つの個別の配列があると思いました。"

スタック:

dcのスタックは、プッシュダウンスタックまたはLIFO(後入れ先出し)です。レストランのプレートと同じです。

      ,------ pop / Push - take / leave 
    /
   |
   v
[-----] top
[-----]           ...                 ...                .
[-----]          [-----]             [-----]            ..
 (main)        (register-a)        (register-b)        ...

mainスタックまたはworkスタックがあります。これは、レジスタを要求する操作が指定されていない限り使用されます。各レジスタには独自のスタックがあります。

基本レジスタ操作:

  • Srpop one value from main stack and Push it into stack r。両方のスタックが変更されました。
  • Lrpop onerで指定されたレジスタスタックからの値Pushそれをmainスタックにプッシュします。両方のスタックが変更されました。
  • srpop onemainスタックからの値およびwriteそれを登録するr。実際には、レジスタrで指定されたスタックの最上位の値を変更します。そのスタックに値がない場合は、追加します。 mainスタックが変更されました。 スタックの登録変更された値の横に保持されます。
  • lrreadレジスタrからの値。事実上、複数ある場合は最上位の値です。 main変更されました。 スタックの登録保存されます。
  • :rpop two value from mainスタックし、レジスタrの配列の2番目の値を格納する場所のインデックスとして最初の最上位を使用します。 main変更されました。 スタックの登録保存されます。
  • ;rpop oneスタックからの値mainスタックから、rで指定されたレジスタ内の現在の配列から読み取るインデックスとして使用します。 main変更されました。 スタックの登録保存されます。

スタックと配列が混在

見る1つの方法はペアです。開始すると、すべてのレジスタが空になります。 Srによって要素をスタックに追加すると、hideそのスタック内の基礎となる要素がすべて追加されます。あなたがするように言う:

1 Sx
2 Sx
4 Sx

x = (S)  4     VISIBLE
    (S)  2     HIDDEN
    (S)  1     HIDDEN

これで、changeレジスタの値x、つまり;最上位の要素をsxで変更すると、スタック内の要素の数を変更せずにlxで読み取ることができます。

lx p  # Read value in register x - in effect read topmost element from stack.
4     # Printed value by p.
3 sx  # Change value in register x - in effect change topmost element in stack.

x = (S)  3     VISIBLE
    (S)  2     HIDDEN
    (S)  1     HIDDEN

配列要素を追加することにした場合、物事はより複雑な方向に進み始めます。

4 1:x
5 2:x

x = [A] 
        [2]=5  VISIBLE
        [1]=4  VISIBLE
    (S)  3     VISIBLE
    (S)  2     HIDDEN
    (S)  1     HIDDEN

これで、スタック内のcurrent配列に値が追加されました。 [〜#〜] visible [〜#〜]要素を読み取って変更できます。

44 1:x
55 2:x
33 sx

1;x p # Read and print index 1
44

lx p  # Read and print stack top.
33

x = [A] 
        [2]=55  VISIBLE
        [1]=44  VISIBLE
    (S)  33     VISIBLE
    (S)  2      HIDDEN
    (S)  1      HIDDEN

その場合、addスタック要素は、その上の配列に値を追加したため、stack frameは展開不可能であると言うことができます。したがって、新しいスタックフレームが追加されます。

6 Sx
7 Sx

x = (S)  7      VISIBLE
    (S)  6      HIDDEN
    [A] 
        [2]=55  HIDDEN
        [1]=44  HIDDEN
    (S)  33     HIDDEN
    (S)  2      HIDDEN
    (S)  1      HIDDEN

last配列にアクセスしようとすると、非表示になります。実際には、空の配列から読み取り、結果はデフォルト値0になります。レジスタ値7srで変更できますが、上記の2つのスタック要素を削除しない限り、2レベル下の配列にアクセスすることはできません。

ここでいくつかの配列要素を追加することにした場合、それらは最上位のスタック要素とともに(ペアの配列として)配置された新しい配列に追加されます。

8 1:x
9 2:x

x = [A]
        [2]=9   VISIBLE
        [1]=8   VISIBLE
    (S)  7      VISIBLE
    (S)  6      HIDDEN
    [A] 
        [2]=55  HIDDEN
        [1]=44  HIDDEN
    (S)  33     HIDDEN
    (S)  2      HIDDEN
    (S)  1      HIDDEN

Nowスタックのpopを実行すると、7がポップされますが、配列があるため(いわば)それも削除されます。

Lx p  # Pop + print top stack element.
7     # Value printed.

x = (S)  6      VISIBLE
    [A] 
        [2]=55  HIDDEN
        [1]=44  HIDDEN
    (S)  33     HIDDEN
    (S)  2      HIDDEN
    (S)  1      HIDDEN

8および9の配列はなくなりました。値が6のスタック要素が表示されます。ただし、基になるアレイはブロックされます。 1;x pによる読み取りyield 。

ある意味では、スタック要素はブロックされていますが、配列は不透明であると言えます。配列は、スタック要素に対してhanging onのようなものです。

stackからさらに別のpopを実行して、基になるスタック要素+配列を明らかにする必要があります。

Lx p  # Pop + print top stack element.
6     # Value printed.

x = [A] 
        [2]=55  VISIBLE
        [1]=44  VISIBLE
    (S)  33     VISIBLE
    (S)  2      HIDDEN
    (S)  1      HIDDEN

結論として、配列とスタックの数はレジスタごとに1つに制限されていないと言えます。

レジスタごとにいくつの配列とスタックがありますか?
–そのレジスタで実行するSr操作と:r操作の交互の数によって異なります。

別の見方をすれば、スタックは1つだけですが、複数の配列がありますiff配列要素の追加の間にスタック要素を追加します...

さらに別の言い方をすれば、現在の配列はいつでもそうではないということです。

[register][array]

だが

[register][stack-element][array]

これは:

[register][stack-element][array][...]
[register][stack-element][array][1]
[register][stack-element][array][0]

また、stack-element部分は不透明、読み取り専用などです。ただし、その場合は、スタック要素の値は必要ないことも覚えておく必要があります。配列値をレジスタに追加するだけでOKです。

または、各スタック要素は、変更可能なゼロで埋められた配列とペアになっています。

1 Sx
2 Sx
3 Sx
4 1:x
5 2:x
6 Sx
7 Sx
8 1:x
9 2:x

x = (S)  7   +   A[0]=0   A[1]=8   A[2]=9   A[3]=0  ...  A[2048]=0
    (S)  6   +   A[0]=0             ...                  A[2048]=0
    (S) 33   +   A[0]=0   A[1]=4   A[2]=5   A[3]=0  ...  A[2048]=0
    (S)  2   +   A[0]=0             ...                  A[2048]=0
    (S)  1   +   A[0]=0             ...                  A[2048]=0

それがもう少し明確になったことを願っています。


いくつかの例


$ dc
[ein]  0:a
[zwei] Sa
[drei] 0:a

0;ap   # Copy + print index 0 of topmost array in register a
drei

Lap    # Throws away [drei] and pops+prints first element in stack*
zwei

0;ap   # Copy + print index 0 of first array 
ein

$ dc
[uno]    0:a  # Array a(1)
[dos]    1:a  # Array a(1)
[tres]   2:a  # Array a(1)

[cuatro] Sa   # Array a(2)
[cinco]  Sa   # Array a(2)
[seis]   Sa   # Array a(2)

[siete]  0:a  # Array a(3)
[ocho]   1:a  # Array a(3)
[nueve]  2:a  # Array a(3)

Laf      # Throws away Array 3 to get to first stack array, Array 2.
seis

Laf
cinco
seis

Laf
cuatro
cinco
seis

2;af      # Now we're at the first array, Array 1.
tres
cuatro
cinco
seis

1;af
dos
tres
cuatro
cinco
seis

0;af
uno
dos
tres
cuatro
cinco
seis
6
Runium

dcはコンパイラーであり、非常に古いコンパイラーであることを覚えておく必要があります。これは一種の機械語であり、スタック指向の計算機です。それはかなり強力ですが、そのインターフェースはあなたのために設計されていません-それはあなたが他の言語で書いた命令を効率的に処理するように設計されています。

dcは、直感的な方法でデータを保存しません。 dcstuffs stuff。すぐに実行されない場合に新しい入力を読み取るとき、値はスタックに投げられるだけです。スタック内のすべてのものはすでにプッシュダウンされています-一番上が最新で一番下が最も古いです。最も古いスタックメンバーを取得するには、最新のスタックメンバーを処理する必要があります。

多くの人がそれだけ得ることができます。結局のところ、スタックはそれほど奇妙ではありません-それは一種の洗濯かごのようなものです。しかし、それもかなり1次元であり、dcはそれよりもはるかに進んでいます。

つまり、入力スタック、つまりメインスタックがあります。これは、dcのすべての命令入力と出力がデフォルトで行われる場所です。それはあなたがそれにコマンドを与えるときにあなたが働くものです。しかし、他のすべてのレジスターもあります-少なくとも256個です。これらのそれぞれは、それ自体へのスタックでもあります。

通常、レジスタは[Ss]aveコマンドと[Ll]oadコマンドを使用して操作します。メインスタックの最上位の値をスカラー値としてレジスタaに保存するには、saを実行します。その後、lを使用して、いつでもこのスカラー値をメインスタックの最上位にlaoadして戻すことができます。さて、レジスタaの現在のインスタンスが最新のままである限り、つまり、可能です。

old-スカラー値が残っている-の上にレジスタanewスカラーインスタンスを作成するには、Saを使用できます。このコマンドはメインスタックをポップし、レジスタaスタックをスタックします。 laとは異なり、Laコマンドはレジスタの破壊的なLoadです-そのコマンドでスカラー値がメインスタックにポップされると、レジスタのそのインスタンス内のすべてが破棄され、レジスタの以前のインスタンスに再びアクセスできるようになります。

それだけでも、少し練習すれば簡単に理解できます。メインスタックと同じですが、レジスタごとに1つずつあります。しかし、各レジスタにはさらに別の次元があります-それらの配列です。

各レジスタの各インスタンスは配列を取得します。デフォルトのサイズは1つあたり2048インデックスだと思いますが、スタックがどれだけ深くなるのか疑問に思うことがよくあり、かなり深いとしか言​​えません。レジスタの新しいスカラー値をインスタンス化するときは、そのスカラー値をプッシュダウンするだけでなく、その配列もプッシュダウンします。新しいインスタンスには新しい配列があり、古いインスタンスの配列はそのまま残り、新しいインスタンスをポップした後のスカラー値と同じようにアクセスできます。

配列インデックスへのアクセスには少し注意が必要です。そもそも、ほとんどすべてのメインスタック操作はとにかく破壊的です。また、配列インデックスにアクセスする唯一の方法は、メインスタックからその値を取得して、それを呼び出すことです。インデックス参照はその時点で破棄されるため、思い出すのが難しい場合があります。 oOは、インデックスカウンターを保持するのに役立ちますが、インデックス1または0で試さないでください。

とにかく、レジスタの配列とそのスタックは独立していませんが、むしろ相互依存して多次元です。練習と忍耐、そして少し超人間的な決意があれば、奇妙にクールなことができます。幸運を。

3
mikeserv

同じ質問に遭遇しましたが、manページ自体の例を囲むテキストを注意深く読み直すだけで十分でした。

   :r     Will  pop  the top two values off of the stack.  The old sec-
          ond-to-top value will be stored in the array  r,  indexed  by
          the old top-of-stack value.

   ;r     Pops  the top-of-stack and uses it as an index into the array
          r.  The selected value is then pushed onto the stack.

   Note that each stacked instance of a  register  has  its  own  array
   associated  with  it.   Thus  1  0:a 0Sa 2 0:a La 0;ap will print 1,
   because the 2 was stored in  an  instance  of  0:a  that  was  later
   popped.

ここの最後の段落はあなたの質問に完全に答えます。 2は、後でポップされた0:aのインスタンスに格納されました(Laがレジスタaのスカラー値をメインスタックに配置すると、サイレントに破棄されます)。

0
Wildcard