-3

LC-3 で電卓を作成する Web サイトで見つけた問題に取り組んでいます。私はそれを段階的に進めており、スタックを使用して現在行っていることについて何かを見ました。これまでのところ、スタックを使用するように変換するために誰かが私を助けることができるかどうか疑問に思っていました.これまでのところ、私はレジスタを使用しています! 以下のコードは明らかに不完全です。これは、いくつかのことを行う方法について調査を停止して開始したときに得たものです。私がこれまでに持っていたもののLC-3コードは次のとおりです。

        ;get first string from user
START   LEA R0, PROMPT1 ; Display the prompt
        PUTS
        LEA R0, BUFFER
        JSR READLINE

        ;convert string to number
        LEA R0, BUFFER
        JSR ATOI

        ;save the number
        ST  R0, FIRST_ARG

        ;get second string from user
        LEA R0, PROMPT2 ; Display the prompt
        PUTS
        LEA R0, BUFFER
        JSR READLINE

        ;convert string to number
        LEA R0, BUFFER
        JSR ATOI

        ;save the number
        ST  R0, SECOND_ARG

        ;load the arguments into R0 and R1
        LD  R0, FIRST_ARG
        LD  R1, SECOND_ARG

        JSR SUM 
PRINT_OUTPUT
        ;convert R0 into a string
        LEA R1, BUFFER
        JSR ITOA        ;not made yet, also will need division and subtraction subroutines

        ;print the sum of the two digits entered
        LEA R0, ANSWER  ; Display the prompt
        PUTS
        LEA R0, BUFFER
        PUTS

        ;print a new line character.
        LD  R0, ENTER
        OUT
STOP    HALT            ;

        ;subroutine SUM : calculates the sum of two numbers
        ;input: R0,R1
        ;output: R0 = R0 + R1
SUM
       ADD R0, R0, R1
       RET

        ;subroutine PROD : calculates the product of two numbers
        ;input: R0,R1
        ;output: R0 = R0 * R1
MUL
       ST  R2, MUL_SAVE_R2
       AND R2, R2, #0
       AND R1, R1, R1
MUL_START
       BRz MUL_END
       ADD R2, R2, R0
       ADD R1, R1, #-1
       BR  MUL_START
MUL_END
       ADD R0, R2, #0
       LD  R2, MUL_SAVE_R2
       RET
MUL_SAVE_R2 .FILL x0000

        ;subroutine READLINE : Reads a line of input from keyboard.
        ;input: R0. contains the address of the memory location where the
        ;   string must be placed.
READLINE
       ST  R7, RL_RETURN
       AND R1, R0, R0

RL_START
       ;get a character and echo it
       GETC
       OUT

       ;compare the character with ENTER which has ascii value 10
       ADD R2, R0, #-10
       BRz RL_END          ;the user typed ENTER, stop the loop
       STR R0, R1, #0      ;store whatever the user typed
       ADD R1, R1, #1      ;increment the pointer
       BR  RL_START
RL_END
       AND R0, R0, #0
       STR R0, R1, #0      ;write the null character
       LD  R7, RL_RETURN
       RET
RL_RETURN  .FILL x0000

;subroutine ATOI : Converts an ASCII string to an integer
;input: R0, contains the address of the string
;output: R0, should contain the integer value
ATOI
       ST  R7, ATOI_RETURN

       AND R2, R0, R0      ;R2 <- R0;
       AND R0, R0, #0      ;R0 <- 0
       ADD R1, R0, #10     ;R1 <- 10

       LD  R4, ASCIIZERO
       NOT R4, R4
       ADD R4, R4, #1      ;This is to convert ascii character to integer

ATOI_START
       LDR R5, R2, #0
       BRz ATOI_END        ;we've reached the end of the string

       AND R1, R1, #0
       ADD R1, R1, #10     ;R1 <- 10
       JSR MUL            ;multiply current number by 10

       ADD R5, R5, R4      ;subtract ASCIIZERO from R5
       BRn INVALID_INPUT   ;user typed something less than '0'
       ADD R6, R5, #-9
       BRp INVALID_INPUT   ;user typed something more than '9'

       ADD R0, R0, R5
       ADD R2, R2, #1      ;next character
       BR  ATOI_START
INVALID_INPUT
       AND R0, R0, #0      ;make R0 <- -1
       ADD R0, R0, #-1
ATOI_END
       LD  R7, ATOI_RETURN
       RET

ATOI_RETURN .FILL x0000


;allocate memory for the input
FIRST_ARG  .FILL x0000
SECOND_ARG .FILL x0000
BUFFER     .BLKW #15  ; allocating memory for storing user input.

POP
        LDR R0, R6, #0
        ADD R6, R6, #1
        RET

PUSH
        ADD R6, R6, #-1
        STR R0, R6, #0
        RET

;constants
MINUS      .FILL x002D; '-'
ENTER      .FILL x000A; newline character
PROMPT1    .STRINGZ "Please input the first digit > "
PROMPT2    .STRINGZ "Please input the second digit > "
ANSWER     .STRINGZ "Sum of the two digits entered = "
ASCIIZERO  .FILL x0030; '0'
.END
4

2 に答える 2

0

電卓を作成する簡単な方法は、逆ポーランド記法(RPN) を使用する電卓を作成することです。

RPN を使用する場合、トークンごとに入力トークンを読み取り、読み取りごとにアクションを実行します。トークンが数値の場合は、スタックにプッシュします。演算子の場合は、要素をスタックからポップして処理します。たとえば、演算子が の場合、+スタックの上位 2 つの要素をポップして追加し、合計をスタックにプッシュします。トークンの読み取りが完了すると、スタックの一番上の要素が答えになります。

トークンを簡単に取得できるようにするには、トークンを 1 つのスペースで区切る必要があります (少なくとも最初は)。

たとえば、ユーザーは次のように入力します。

7 5 + 12 /

するでしょう:

  1. トークン7を読み取り、pushそれを (スタックは現在7)
  2. トークン5を読み取り、pushそれを (スタックは現在5, 7)
  3. token を読み取り+、ポップ75てレジスタに追加し、push結果を追加します (スタックは now 12)
  4. トークン12を読み取り、pushそれを (スタックは現在12, 12)
  5. token を読み取り/、レジスターpop 1212分割し、pushその結果 (スタックは now 1) になります。
  6. Pop最終的な答えをレジスターに入れ、結果を出力します ( 1)。

Unix ユーティリティdcはこのように動作します (少なくとも、そうであるかのように動作します)。

標準の「中置」記法を含む他の種類の記法を使用することは、より困難になります。最も優れたC++プログラミング言語には、何が関係するかを理解するために、中置計算機のおもちゃの例があります(現在ない場合は以前の版にありました)。

于 2014-12-10T08:13:48.420 に答える
0

変数をスタック上の関数に渡すことについて質問している場合、1 つには、その必要はありません。レジスターの使用は、オプティマイザーが熱望するものです。

ただし、メカニズムはそれらをスタックにプッシュし (R13)、関数を呼び出してから、return を追加し、変数のサイズをスタック ポインターに追加します (2 x 32 ビット数 = 8 バイト)。

私はARMを信じています。関数が呼び出される前に、フレームポインター(R11)は自動的にスタックを指します。したがって、2 x 32 ビットの数値がスタックにプッシュされた場合、最初の数値は [R11, #-8] で、2 番目の数値は [R11, #-4] になります (スタックは最後から成長することに注意してください)。

于 2014-12-10T09:03:39.117 に答える