Category:Mastermind
This programming language may be used to instruct a computer to perform a task.
See Also: |
|
---|
Mastermind is a programming language designed specifically to create Brainf*** code. The Mastermind IDE includes a Rust-based compiler, which converts (compiles) Mastermind source programs into Brainf***. The current Mastermind compiler generates Brainf*** code assuming an infinite bi-directional tape, as well as 8-bit wrapping cells [1].
Usage
Variables & Values
Variables can be defined as single cells, or as contiguous sets of cells:
// single-cell:
let var = 56;
let c = 'g';
let bool = true; // true/false equivalent to 1/0
// multi-cell:
let array[4] = [1, 2, 3, 4];
let string[5] = "hello";
If left uninitialised, a cell is assumed to have a value of 0.
Expressions consist of simple adds and subtractions, arrays and strings cannot be used in expressions:
// supported:
var += 4 + (5 - 4 + (3 - 2));
var = 'g' - 23 + true;
var = var + 5; // inefficient but supported
var += array[0] + 5;
let arr[3] = [4 + 3 - ('5' - 46), 1, 3];
// NOT supported:
var += [4, 5, 7][1] + 3;
Array indices must be compile-time constant integers
Input & Output
Single bytes can be output using the output operator:
output 'h';
output var;
output var + 6;
output array[0];
// the following are equivalent:
output '\n';
output 10;
Likewise for input:
input var;
input arr[2];
There is also * spread syntax and support for strings and arrays for ease of use:
output "hello";
output ['1', '2', '3'];
output *array;
input *array;
Loops
The simplest is the while loop, which only supports cell references, not expressions:
while var {
// do stuff
// var -= 1;
// etc
}
Draining loops
The "drain" loop is equivalent to the common Brainf*** construction of repeating an action N times, where N is the value of a tape cell. Hence, "draining" the cell while doing the actions in the loop body.
drain var {
}
// shorthand for following:
while var {
// do stuff
var -= 1;
}
This destructively loops as many times as the value in the cell being referenced, this can be used with expressions:
drain 10 {}
drain var - 6 {}
There is also shorthand "into" syntax for adding to other cells:
drain var into other_var other_var_2 *spread_array etc;
// example of typical "for loop":
let i;
drain 10 into i {
output '0' + i; // inefficient for the example
}
// "0123456789"
// equivalent to the following:
let i;
let N = 10;
while N {
output '0' + i;
}
Copying loops
The "copy" loop is equivalent to the drain loop, except it is not destructive. This means the variable can be accessed safely from inside the loop body.
copy var into other_var *spread_var etc;
// examples:
copy var {
// this will output the original var value, var times
output var;
}
let rows = 3;
let columns = 6;
let total;
drain rows {
copy columns into total {
output '.';
}
}
// ......
// ......
// ......
If/Else
The "if" and "else" keywords operate similar to C, except "else if" is not supported. The code in the "if" body will be executed if the provided expression is positive, otherwise the "else" body is executed. If the "not" keyword is used, the behavior is reversed. Examples:
if 13 {
output "13";
}
if var {
output "true";
} else {
output "false";
}
// typical equivalence use-case:
if not var - 10 {
// ==
} else {
// !=
}
Functions
Functions work like templates/macros, as they do not perform any passing by value. All functions are in-lined at compile time. This means multiple calls to a large function will significantly increase your compiled Brainf*** size.
For this reason, function arguments are given using < angled bracket > syntax, much like generic functions in other languages:
def quote<arg> {
output 39; // ASCII single quote
output arg;
output 39;
}
let N = 'g';
quote<N>;
N += 3;
quote<N>;
// gj
Imports
Imports work much like the C preprocessor:
#include "other_file"
This copies the contents of "other_file" into the current file at compile-time.
In-line Brainf*** features
In-line Brainf*** allows the programmer to define custom behavior as if writing raw Brainf***, this is analogous to C's in-line Assembly.
// This is its most basic form:
// find the next cell that equals -1
bf {
+[->+]-
}
// This is its more advanced form:
// input a line of lowercase letters and output the uppercase version
// this is an intentionally inefficient example
bf @3 clobbers var *spread_var etc {
,----------[++++++++++>,----------]
<[<]>
[
{
let g @0;
assert g unknown;
output g + ('A' - 'a');
// embedded Mastermind!
}
>
]
// now clear and return
<[[-]<]>
}
It is the programmer's responsibility to clear used cells and return back to the cell in which the in-line Brainf*** context began. If the programmer does not do this, any Mastermind code after the in-line Brainf*** command will likely break.
Memory location specifiers
For hand-tuning optimizations and in-line Brainf*** that reads from Mastermind variables, you can specify the location on the Brainf*** tape: Variables can be fixed to a specified location on the eventual Brainf*** tape. This can also be done with in-line Brainf*** code sections. This can be used to share values between Mastermind and Brainf*** contexts.
let var @3 = 4;
// compiled: >>>++++
bf @4 {
<><><>
}
// compiled: >>>><><><>
Clobbering and Assertions
The Mastermind compiler will try to predict the value of cells at compile-time, so it can prevent unnecessary cell clean-ups and unreachable code (with optimizations turned on). If your in-line Brainf*** affects existing Mastermind variables, you should tell the compiler using the "clobbers" keyword, the syntax is similar to the drain into variable list:
bf clobbers var *spread_var other_var etc {}
The compiler will now assume nothing about the values of those variables afterwards.
If instead you want to tell the compiler specifically that a value has become certain, you can use assert:
assert var equals 3;
// most common use cases:
assert var equals 0;
assert var unknown;
Asserting a variable as unknown is equivalent to clobbering.
Embedded Mastermind
Embedding Mastermind into your in-line Brainf*** allows you to use Mastermind syntax features for programs within your Brainf***, this is useful for N-length string based programs, or anything not possible in pure Mastermind:
let sum @0;
bf @0 {
>>
// read input (until eof) to the tape, nullifying any spaces or newlines
// (this is probably not a good practical example, ideas are appreciated)
,[
{
let c @0;
assert c unknown; // needed otherwise the compiler assumes c = 0
if not (c - '\n') {
c = 0;
}
if not (c - ' ') {
c = 0;
}
}
>,
]
}
Memory location specifiers are relative to the current Mastermind context. Also, top-level variables are not cleared by default in Mastermind contexts, this allows you to "leave" variables in cells for your Brainf*** to use. If you want your embedded Mastermind to clean itself up, you can simply open a scope at the top level:
bf {
++----++[][][<><><>] // the program doesn't matter for this example
{
// variables here will not be cleared
let g @2;
assert g unknown;
{
// variables here will be cleared
let b = 32;
}
}
{{
// self-cleaning Mastermind code here
}}
}
Advanced
All Mastermind features are available within the embedded Mastermind contexts, including in-line Brainf*** code.
bf {
++++[
{
let i @0;
assert i unknown;
let j @1 = i + 1;
bf @1 {
[.+]
{
// even more layers are possible
bf {
{
output "h"
}
}
}
}
}
-]
}
References
Pages in category "Mastermind"
The following 2 pages are in this category, out of 2 total.