Fastlane

== Introduction ==
Fastlane is an esoteric language created by User:TuxCrafting that has a peculiar way of doing flow control by controlling the "speed" of the instruction pointer.
== Semantics ==
There are 26 arbitrary precision counters, a to z, of which only one can be selected at any given time.
By default, a is selected.
The instruction pointer also has a "speed", which is the number by which it is incremented at the end of each executed instruction.
The speed defaults to 1 and can be negative.
The instruction pointer wraps around; execution must be explicitely halted to stop.
== Instructions ==
Instruction	Description
a - z 	Select a counter.
> 	Increment the instruction pointer speed.
< 	Decrement the instruction pointer speed.
+ 	Increment the currently selected counter.
- 	Decrement the currently selected counter.
* 	Skip the next instruction.
% 	Skip the next instruction if the currently selected counter is zero.
@ 	Skip the next instruction if the currently selected counter is nonzero.
! 	Output the numeric value of the currently selected counter.
? 	Input the numeric value of the currently selected counter. Undefined behavior if the input cannot be parsed.
. 	Output the character value of the currently selected counter.
, 	Input the character value of the currently selected counter. EOF is 0.
$ 	Halt execution.
Every other character (including whitespace and newlines) is a no-op (It is customary to use #).
== Examples ==
=== (Unoptimized) Hello world ===
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.+++++++++++++++++++++++++++++.+++++++..+++.-------------------------------------------------------------------.------------.+++++++++++++++++++++++++++++++++++++++++++++++++++++++.++++++++++++++++++++++++.+++.------.--------.-------------------------------------------------------------------.-----------------------.$
=== Truth machine ===
?!@$*>!<
=== Add two numbers ===
#?#b#?#*<a@>*b*!*$-b+a%>b#!#$
== Computational class ==
Fastlane is Turing complete by translating a 25-counter Minsky machine into it.
The Minsky machine has three instructions:
* INC [counter] [next], increments a counter, where [counter] is the counter number (1-25) and [next] the address of the next instruction.
* DEC [counter] [nextZ] [nextNZ], decrements a counter, where [counter] is the counter number (1-25), [nextZ] the address of the next instruction if the counter was zero and [nextNZ] the address of the next instruction if the counter was nonzero.
* HLT, halts.
The uses of the Fastlane counters are:
* a: Current address.
* b-z: Minsky machine counters.
Each instruction is encoded as:
* INC [counter] [next] is [counter letter]+a[next times +]
* DEC [counter] [nextZ] [nextNZ] is [counter letter]@>>
… Well, kind of. There also needs to be two other jump instructions at a special place in the interleaved body. See a bit below.
* HLT is $
DEC instructions are then prepended by two dummy instructions which will be replaced later. If the DEC instruction was at the start of the program, a dummy jump is added at the start.
The instructions are then all translated to their Fastlane representation. The order is reversed, and if there are more than 2 instructions, the first instruction in the list is placed at the last position.
Then, for each DEC instruction:
* The instruction right after becomes ####<-a[nextNZ times +]
* The instruction two after becomes ####<a[nextZ times +]
They are then all padded with NOPs and interleaved like abcdabcdabcd…
Then, a way to examine the state and execute the corresponding snippet, an “accelerator”, is required.
The accelerator is formed by:
* Start with a.
* If there is more than 1 instruction:
** Append @>-#>
** If there are exactly 2 instructions:
*** Append #
** If there are more than 2 instructions:
*** Set i to be from 1 to the number of instructions minus 2:
**** Append [i times #]@[i times #][i+2 times >][i+1 times #]-
And at the end, a way of decelerating back to 1 to wrap back is required.
The decelerator is formed by:
* Start with an empty string.
* If there is more than 1 instruction:
** Set i to be from the number of instructions minus 1 to 1:
*** Append [i times <]#*[i-1 times #]<
The final code is the concatenation of the accelerator, the interleaved body, and the decelerator.
== Implementation ==
Simple implementation in C, requires GNU MP.
// Fastlane interpreter in C.
// Build with: cc -o fastlane fastlane.c -lgmp
#include <gmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
	if (argc != 2) {
		fprintf(stderr, "Usage: %s <file>\n", argv[0]);
		return 1;
	}
	FILE *f = strcmp(argv[1], "-") == 0 ? stdin : fopen(argv[1], "r");
	if (f == NULL) {
		fprintf(stderr, "Can't open file.\n");
		return 1;
	}
	char *code = NULL;
	size_t code_len = 0;
	size_t code_i = 0;
	while (!ferror(f) && !feof(f)) {
		if (code_i >= code_len) {
			code = realloc(code, code_len += 512);
		}
		char c;
		if ((c = fgetc(f)) != EOF) {
			code[code_i++] = c;
		}
	}
	if (f != stdin) {
		fclose(f);
	}
	ptrdiff_t ip = 0;
	ptrdiff_t ip_speed = 1;
	mpz_t counters[26];
	size_t counter = 0;
	char running = 1;
	for (size_t i = 0; i < 26; i++) {
		mpz_init(counters[i]);
	}
#define NEXT ip = (ip + ip_speed) % code_i
	while (running) {
		char c = code[ip];
		if (c >= 'a' && c <= 'z') {
			counter = c - 'a';
		}
		switch (c) {
		case '>': ip_speed += 1; break;
		case '<': ip_speed -= 1; break;
		case '+': mpz_add_ui(counters[counter], counters[counter], 1); break;
		case '-': mpz_sub_ui(counters[counter], counters[counter], 1); break;
		case '*': ip += ip_speed; break;
		case '%': if (mpz_cmp_ui(counters[counter], 0) == 0) NEXT; break;
		case '@': if (mpz_cmp_ui(counters[counter], 0) != 0) NEXT; break;
		case '!': mpz_out_str(stdout, 10, counters[counter]); putchar('\n'); break;
		case '?': mpz_inp_str(counters[counter], stdin, 10); break;
		case '.': putchar(mpz_get_ui(counters[counter]) & 255); break;
		case ',': c = getchar(); mpz_set_ui(counters[counter], c == EOF ? 0 : c & 255); break;
		case '$': running = 0;
		}
		NEXT;
	}
	for (size_t i = 0; i < 26; i++) {
		mpz_clear(counters[i]);
	}
	return 0;
}
Category:Languages
Category:2019
Category:Turing complete
Category:Implemented