Acc!!

From Esolang
Jump to navigation Jump to search

Acc!! is a Turing tarpit built on unbounded integer math, loops, and a single accumulator.

Language description

Acc!! is an imperative programming language. The syntax is designed to be fairly readable; the main challenge is the semantics.

Expressions

All values in Acc!! are unbounded integers. They can be combined in arbitrarily complex expressions using the following infix operators:

  • +, addition
  • -, subtraction; unary negation
  • *, multiplication
  • /, integer division
  • %, modulo
  • ^, exponentiation

An expression can include integer literals, loop counter variables (a-z), the accumulator variable _, and the special value N, which reads a character from stdin and returns its character code each time it is used. Parentheses can be used to enforce precedence of operations. Any other character in an expression, other than whitespace, is a syntax error.

Statements

Acc!! contains three types of statements:

Bare expression

Any expression standing by itself is evaluated and assigned to the accumulator (which is accessible as _). Thus, 3 is a statement that sets the accumulator to 3; _ * 2 multiplies the accumulator by 2; and N % 48 reads a character and sets the accumulator to its character code mod 48.

The accumulator is the only variable whose value can be set directly; loop variables and N can be used in calculations but not modified.

The accumulator is initially 0.

Write statement

Write expr

Outputs a single character with the given ASCII/Unicode value to stdout. The character code expr can be any expression.

Count-while loop

Count var while expr {
}

Sets var to 0 and loops while expr is nonzero, incrementing var after each iteration. Equivalent to for(int var = 0; expr; var++) in C-like languages (but with unbounded integers). The loop counter var can be any single lowercase letter a-z. The condition expr can be any expression, not necessarily involving the loop counter. Loop counter variables are only available inside their loops; attempting to reference them afterwards causes an error.

Input and output

Each time N is referenced in an expression, Acc!! reads one character from stdin. (This means you only get one shot to read each character; the next time you use N, you'll be reading the next one.) N evaluates to the character code of the character. In the official Python interpreter, each line of input (including the last) is terminated with a newline (character 10). Once end-of-file has been reached (e.g. if stdin was redirected from a file or if the user enters an EOF manually), N evaluates to 0 for the rest of the program.

A character can be output to stdout by passing its character code to the Write statement.

Whitespace and comments

Leading and trailing whitespace and empty lines are ignored. Loop headers must be formatted exactly as shown above, including a single space between the loop header and opening curly brace. Whitespace inside expressions is optional.

# begins a single-line comment.

History

Acc!! was created by User:Dlosc for the challenge Create a programming language that only appears to be unusable on Code Golf StackExchange. The initial version was called Acc!; however, because it allowed loop counters to be referenced after their loops completed, it turned out to be too usable. This led to the creation of the second version.

Examples

Hello, world!

Write 72
Write 101
Write 108
Write 108
Write 111
Write 44
Write 32
Write 87
Write 111
Write 114
Write 108
Write 100
Write 33

Truth-machine

N
Write _
Count i while _/49 {
  Write _
}

Convert a string to lowercase

N
Count i while _ {
  Write _ + (_/65)*(90/_)*32
  N
}

Find the highest unique digit in a number

We conceptually partition the accumulator into two sections: _%81 stores the most recently read character, while _/81 stores ten counters, one for each digit, denoting whether that digit has occurred 0, 1, or 2+ times. For example, an accumulator value of 3214945 (20001100002001 in base 3) represents the following:

Occurrences of       Next character
9 8 7 6 5 4 3 2 1 0
-------------------  --------------
2 0 0 0 1 1 0 0 0 0  7 (character code 55, or 2001 in base 3)

When a digit occurs more than 2 times, we cap its occurrence count at 2. Then once all digits have been processed, the answer is the highest digit that has 1 as its occurrence count.

### Part 1: read the input and count digit occurrences

# Read the first character into the accumulator
N
# Loop while the most-recently-read character was a digit (>= charcode 48):
Count i while _%81/48 {
  # The digit we just read is _%81-48
  # Its occurrence count is (_/81)/3^(_%81-48)%3
  # We add 1 to the occurrence count; but if the occurrence count was already 2,
  # we also subtract 1, leaving it unchanged
  _ + (1 - ((_/81)/3^(_%81-48)%3) / 2) * 81 * 3^(_%81-48)
  # Clear out the previously read character and read a new character
  _ - _%81 + N
}

### Part 2: output the highest unique digit

# Count up i, starting at 0, until the accumulator gets zeroed out
Count i while _ {
  # 9-i is the current digit
  # Its occurrence count is (_/81)/3^(9-i)%3
  # Loop if the occurrence count is odd (i.e. 1, not 0 or 2):
  Count j while ((_/81)/3^(9-i)%3) % 2 {
    # Output that digit
    Write (9-i) + 48
    # Zero out the accumulator, causing both loops to end
    0
  }
}

External resources