Acc!!
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 } }