User:Blashyrkh/A+B-brainfuck

From Esolang
Jump to navigation Jump to search

My implementation of A+B Problem in Brainfuck. Stripped version is 316 bytes long. It uses decimal representation for calculations. Here's the full version with explanation (probably TOO verbose):

; Blashyrkh's elementary school of brainfuck programming
; Take your seats kids

; Let's solve more general problem: A plus B plus C plus etc until EOF
; A plus B would work as a special case
; Each input number (maybe except the last one) should be followed by LF
; Being good boys and girls we will accept both 'minus one' and 'no change' styles of EOF
; Any character other than digit or LF (ascii 10) would ruin everything
; Beware brainfuck interpreters that DO NOT replace CRLF with LF on Windows!

; == Memory layout ==
; |EOF| 0 | 0 | x |   | x |   | x |      Input buffer
; |   |   |   |   | a |   | a |   |      Accumulator
;
; == Work cycle ==
; read addendum to input buffer and reverse it in process
;   if read ends with EOF then special flag is set which is analyzed after summation
;   input of current addendum ends with LF or EOF
;   EOF flag breaks the main loop
;   add the addendum to the accumulator
;   normalize accumulator digits (propagate carry bit)
;   repeat
; handle special cases (leading zeroes and zero result)
; print result

; Main loop always starts at cell zero where EOF flag resides
; The flag is zero normally (and initially) and set to one if EOF is encountered during the input loop
-[
  ; Reset EOF flag back to its original value (zero)
  +

  ; Set position to cell number 3
  ; That's where the first read symbol will be stored
  >>>

  ; Remember that we promised to be good boys and girls (ok I did not you)
  ; We shall accept both 'minus one' and 'no change' EOF
  ; It means that we have to set a cell to minus one before performing input into it
  -[
    ; Input!
    ,+

    ; Current input cell (let's name it 'x' for now) is:
    ;    0       in case of EOF
    ;   11       in case of LF
    ;   49~58    in case of digit
    ; Let's look at the diagram:
    ; | 0 | 0 | 0 | x | a | ? |  (case A)
    ;               ^
    ; | 0 | 0 | 0 | 0 | a | ? |  (case B)
    ;               ^
    ; Case A: subtract 11 from x
    ; Case B: set EOF flag and leave x=0

    [-----------<<->]<+[<]>
    ; | 0 | 0 | 0 | x | a | ? |    x=38~47 or 0
    ;           ^
    ; | 0 | 0 | 1 | 0 | a | ? |
    ;           ^
    [-<<+>>]>
    ; | 0 | 0 | 0 | x | a | ? |    x=38~47
    ;               ^
    ; |EOF| 0 | 0 | 0 | a | ? |    EOF or LF
    ;               ^

    ; if a digit was entered then we need to shift the whole input two cells
    ; rightwards to prepare place for the next input digit
    ; otherwise change nothing
    [
      ; | 0 | 0 | 0 | x | a | x | a | x |    x=38~47
      ;               ^

      <++++++[->------<]>-

      ; | 0 | 0 | 0 | x | a | x | a | x |    x=1~10
      ;               ^

      [>>]<<

      ; | 0 | 0 | 0 | x | a | x | a | x | a | 0 |
      ;                               ^

      [[->>+<<]<<]

      ; | 0 | 0 | 0 | 0 | a | x | a | x | a | x |
      ;       ^

      >+>

      ; | 0 | 0 | 1 | 0 | a | x | a | x | a | x |
      ;               ^
    ]

    ; | 0 | 0 | 1 | 0 | a | x | a | x | a | x |  when we wait for next digit of current number
    ;               ^
    ; |EOF| 0 | 0 | 0 | a | x | a | x | a | x |  when EOF or LF was entered
    ;               ^

    <[->-<]>

    ; | 0 | 0 | 0 | _1| a | x | a | x | a | x |
    ;               ^
    ; |EOF| 0 | 0 | 0 | a | x | a | x | a | x |
    ;               ^
    ; If EOF or LF was entered then we break the loop
    ; Otherwise we put 'minus one' input the cell and repeat input
  ]

  ; |EOF| 0 | 0 | 0 | a | x | a | x | ?
  ;               ^

  ; Addendum is stored to 'x' cells where x=1~10
  ; Accumulator is in 'a' cells where a=1~10
  ; But length of accumulator and of the last addendum may be different

  ; Let's add new addendum to accumulator and clear (reset to zero) all x cells
  ; Iterate over 'x' cells
  >>[
    ; Point to corresponding 'a' cell
    <

    ; | ? | 0 | a | x |
    ;           ^
    ; | ? | 0 | 0 | x |
    ;           ^
    ; Zero 'a' cell means that this accumulator cell was not initialized yet (implicit zero)
    ; If 'a' is zero than we can move 'x' there
    ; Otherwise we add 'x' and subtract 1 since 'x' are also 1~10
    [>-[-<+>]]
    ; | ? | 0 | a'| 0 |
    ;               ^
    ; | ? | 0 | 0 | x |
    ;           ^
    <[<]>>
    ; | ? | 0 | a'| 0 |
    ;               ^
    ; | ? | 0 | 0 | x |
    ;               ^
    [-<+>]
    ; | ? | 0 | a'| 0 |
    ;               ^
    ; | ? | 0 | x | 0 |
    ;               ^
    ; Bingo!

    ; Move to next 'x' cell
    >>
  ]

  ; Move to last guaranteed nonzero accumulator cell
  <<<

  ; Rewind
  [<<]>>

  ; Addendum is added to accumulator but its digits are not normalized
  ; They are 1~19 instead of 1~10
  ; We need to normalize them and propagate carry bit
  ; |EOF| 0 | 0 | 0 | a | 0 | a | 0 | a |
  ;                   ^
  [
    >++++++++++

    ; |EOF| 0 | 0 | 0 | a | 10| a | 0 | a |
    ;                       ^
    [
      <-<+>[<-]<
      ; |EOF| 0 | 0 | 0 | a'| ? | a | 0 | a |
      ;           ^
      ; |EOF| 0 | 0 | 1 | 0 | ? | a | 0 | a |
      ;               ^

      [->++++++++++>>>-<<<<<]
      ; |EOF| 0 | 0 | 0 | a'| ? | a | 0 | a |
      ;           ^
      ; |EOF| 0 | 0 | 0 | 10| ? | a | _1| a |
      ;           ^
      >>>-
    ]

    ; It worked ok for the first digit
    ; But we need to process the rest of accumulator
    ; We need space for it
    ; Each digit needs two zeroes to the left of it
    ; So we have to move already processed digits one cell left
    ; |EOF| 0 | 0 | 0 | a | 0 | a | c'| a |
    ;                       ^

    <[-<+>]>>>+

    ; |EOF| 0 | 0 | a | 0 | 0 | a | c | a |
    ;                               ^

    ; Next thing to do: what is 'c'? It's carry flag which should be added to the next 'a'
    ; Why didn't we add it already? Because a=0 along with c=1 has special meaning: 'a' must be set to 2!
    ; It's because a=0 means "not yet initialized accumulator cell" and we have to perform this
    ; initialization (:=1) before adding carry bit
    [
      ; |EOF| 0 | 0 | a | 0 | 0 | a | 1 | a |   '*' should be incremented
      ;                           *   ^
      ; |EOF| 0 | 0 | a | 0 | 0 | 0 | 1 | a |   '*' should be set to 2
      ;                           *   ^

      -<[>]++

      ; |EOF| 0 | 0 | a | 0 | 0 | a | 2 | a |
      ;                               ^
      ; |EOF| 0 | 0 | a | 0 | 0 | 2 | 0 | a |
      ;                           ^

      <[+>--<<]>>

      ; |EOF| 0 | 0 | a | 0 | 0 | a'| 0 | a |
      ;                               ^
      ; |EOF| 0 | 0 | a | 0 | 0 | 2 | 0 | a |
      ;                               ^
    ]

    ; Point to next accumulator cell and repeat the loop
    <
  ]

  ; Now accumulator is OK but it's shifted one cell left
  ; |EOF| 0 | 0 | a | 0 | a | 0 | 0 | 0 |
  ;                                   ^
  <<<[[->+<]<<]
  ; |EOF| 0 | 0 | 0 | a | 0 | a | 0 | 0 |
  ;       ^

  ; Continue if not EOF
  <-
]

; Now we're almost ready to print our result
; Two special cases must be handled though
;   (1) leading zeroes
;   (2) no digits at all

>+>>>[>>]<<

[
  ; | 0 | 1 | 0 | 0 | a | 0 | a | 0 | 1 |   leading zero looks like this
  ;                                   ^
  ; | 0 | 1 | 0 | 0 | a | 0 | a | 0 | a |
  ;                                   ^

  -[+[<<]]

  ; | 0 | 1 | 0 | 0 | a | 0 | a | 0 | 0 |
  ;                                   ^
  ; | 0 | 1 | 0 | 0 | a | 0 | a | 0 | a |
  ;           ^

  <[->>]<

  ; | 0 | 1 | 0 | 0 | a | 0 | a | 0 | 0 |
  ;                           ^
  ; | 0 | 0 | 0 | 0 | a | 0 | a | 0 | a |
  ;           ^
]

; Probably no digits left at all (result was zero but all zeroes were removed)
; | 0 | 1 | 0 | 0 | 0 |
;           ^
; | 0 | 0 | 0 | 0 | a |
;           ^
<[->>>+<<<]

; Now print digits from right to left

; First let's rewind and add 47 to each digit (thus convert to ascii range)
>>>[->++++++[-<++++++++>]>]<<

; And print them all backwards
[.<<]

; print LF
++++++++++.

; That's all folks!