6
\$\begingroup\$

I've created a new language called "EasyFlow." Your task is to simplify writing BrainFlow programs by compiling EasyFlow to BrainFlow. That is, you take an EasyFlow program and output a BrainFlow program which does the same thing. EasyFlow is defined as follows:

  • The program starts out with a list of variables. A variable is anything that matches [a-zA-Z][a-zA-Z0-9]*. The variables are separated by commas and the list is followed by a semicolon.
  • The program then has zero or more statements. All statements are followed by a ;. Each statement consists of
    • A print statement print(<variable>);
    • An input statement, which copies the next input byte into the variable: input(<variable>);.
    • An assignment: <variable> = <expression>;. An expression consists of an <integer> from 0 to 255 inclusive (but see bonuses for more).
    • An increment <variable> += <expression> or decrement <variable> -= <expression>.
    • Control statements
      • if(<variable>) { <statement>*; }; An if statement, which has a body of one or more if statements. Notice the semicolon at the end of the if statement.
      • while(<variable>) { <statement>*; }; A while statement.

Comments are denoted with // and, you must ignore everything for the rest of the line. Spaces can be put anywhere except between variables (so a b is invalid and not equivalent to ab), between integers, and between inputs and prints. Invalid syntax/statements, however, is undefined behavior.

Input: Input can be taken from anywhere (file, HTML <textarea> element etc.) Example input (doubles the char code of the input and outputs it as a character):

// Define variables
inputNumber, total;
// Get input
input(inputNumber);
// Set total to inputNumber * 2
// Reduce inputNumber and add 2 to total until inputNumber is 0
while (inputNumber) {
    inputNumber -= 1;
    total += 2;
};
print(total);

Output: The output should be a valid BrainFlow program which does the same thing as the input program. However, you can use a shorthand notation <command><number> which indicates <command> repeated <number> times. This can only be applied to + - > < commands. Note that this version of BrainFlow overflows numbers at 256, which is also the length of the tape. You do not have to worry about too many slots being taken up, the program is guaranteed to have less than or equal to 100 bytes as variables. In addition, there won't be anything extreme like a[a[a[a ... repeat 50 times ]]]] = 6.

[ The variable inputNumber is at location 0
    and the variable total is at location 1 ]
, Get input for inputNumber
[
        - Subtract 1
        > Move to location of total
        +2 Add two
        < Move to location of inputNumber
]
>. Print the number

Bonuses: There are a wide variety of bonuses you can earn. Your final score is your character count multiplied by all the bonuses that you earn. The bonuses are:

  • 0.9: Instead of invalid syntax/statements being undefined behavior, fail to compile, printing the line number of the invalid syntax. This means your program should fail to compile on a b = 5; or c = 3 5; or prin t(a);. (The error message can read E:<line>
  • 0.9: Allow declarations of arrays as <variable>[<integer]. All arrays must have a fixed length. Allow access from arrays using <variable>[<expression>]. Assigning <variable> = <expression> is an invalid statement if <variable> is an array. In addition LEN(<variable>) should return the (constant) length of <variable>.
  • 0.7: Allow <expression> to also be a <variable>. That is, the following should correctly compile: a = b;, a[a[0]] = c;, b[a[a[b]]] = c; and so on. (Of course, the array part only applies if you took that bonus).
    • These bonuses are obtainable after getting the previous bonus.
    • 0.7: Allow <expression> to be addition and subtraction. That is, we have <expression> + <expression> or <expression> - <expression>.
    • 0.7: Allow <expression> to include ==, !, &&, || operators
    • 0.6: Allow <expression> to include <, <=, >, >= operators
    • 0.5: Allow multiplication. This must follow the order of operations e.g. <epxression> + <expression> * <expression>.
  • 0.00000000000001: Compile C to BrainFlow. (Please don't actually do this)

    Example with a few bonuses:

Input: (Calculates the last one-based index of a given number in the string "141592" or 0 if it doesn't exist).

pi[6], inputNumber, index, finalIndex; // An array with 6 slots and input number
pi[0] = 1;
pi[1] = 4;
pi[2] = 1;
pi[3] = 5;
pi[4] = 9;
pi[5] = 2;
input(inputNumber);
inputNumber -= 48; // Get inputNumber as a digit
index = LEN(pi); // evaluates to index = 6
while (index) {
    index -= 1;
    if (inputNumber == pi[index]) {
        finalIndex = index + 1;
        index = 0; // break the loop
    };
};
finalIndex += 48; // Hack to convert to character if finalIndex < 10
print(finalIndex);

You can find an interpreter for brainflow written in coffeescript here (along with the compiled version of the above program).

This is code golf. The answer with the lowest score wins.

Here is my attempt in ES6 javascript function at a whopping 561 characters if white space and comments are removed and with no bonuses:

// Defines a function called `compile`
compile = a => {
    h = a => {
        for (; a;) {
            // Create a copy of the input string
            var c = a;
            // Replace print statements with "."
            a = a[R](l, (a, d) => {
                e(d);
                b += ".";
                return ""
            })[R](m, (a, d) => { // Replace input statements with ","
                e(d);
                b += ",";
                return ""
            })[R](n, (a, d, c, g) => { // Replace equal to, increment, and decrements
                e(d);
                b += (c || "[-]+") + g;
                return ""
            })[R](p, (a, c, f, g) => { // Replace if and while loops
                e(f);
                b += "[";
                h(g);
                "if" == c ? b += "[>]^" : e(f);
                b += "]";
                return ""
            });
            // If the copy is the same as the input string
            // i.e. no changes were made in replacing, we've reached the end, break
            if (c == a) break
        }
    };
    // A function which moves to the variable location
    e = a => {
        // Go to zeroth position
        b += "[>]^";
        // f[a] is where the variable is located, move there
        b += ">" + f[a]
    };
    var b = "",
        R = "replace";
    // Remove comments and whitespace
    a = a[R](/\/\/.*?\n/g, "")[R](/[\s\n\t]+|/g, "");
    // Regexes
    var l = /^print\((.*?)\);/, // Print statements
        m = /^input\((.*?)\);/, // Input statements
        n = /^([a-zA-Z0-9]+)([\+\-]?)=(\d+);/, // Assignments
        p = // If and while statements
        /(if|while)\((.*?)\)\{(.*?)\};/,
        k = a.split(";")[0].split(","); // Get the variables
    a = a.slice(a.indexOf(";") + 1); // Strip variables from program
    // Assign each variable a unique index
    for (var f = {}, c = 0; c < k.length; ++c) f[k[c]] = c;
    // Compile
    h(a);
    return b // Return
};

I'm sure many people can do better!

\$\endgroup\$
  • \$\begingroup\$ I take it that golfing your solution to better than 561 bytes wouldn't count as a valid answer? \$\endgroup\$ – COTO Oct 9 '14 at 0:13
  • \$\begingroup\$ @COTO Yeah, it's a valid answer. (But keep in mind, the 561 was obtained if whitespace and comments are stripped from the example). Also, make it significantly (maybe 30-50 chars minimum) less than 561 (don't post an answer with 560) \$\endgroup\$ – soktinpk Oct 9 '14 at 0:19
  • 2
    \$\begingroup\$ I kind of want to write a C to easyflow compiler now.. \$\endgroup\$ – Claudiu Oct 9 '14 at 3:04
3
+50
\$\begingroup\$

Javascript ES6 - 366 bytes

Minified:

C=a=>(R="replace",e=a=>"[>]^>"+C[a],h=a=>a[R](/(if|while)\((.*?)\)\{(.*?)\};/g,(a,c,f,g)=>e(f)+"["+h(g)+(c[2]?e(f):"[>]^")+"]")[R](/print\((.*?)\);/g,(a,d)=>e(d)+".")[R](/input\((.*?)\);/g,(a,d)=>e(d)+",")[R](/([a-z\d]+)(\W?)=(\d+);/ig,(a,d,c,g)=>e(d)+(c||"[-]+")+g),[,k,a]=/(.*?);(.*)/.exec(a[R](/\/\/.*?\n/g,'')[R](/\s+/g,'')),k.split(",").map((a,b)=>C[a]=b),h(a))

Expanded:

C = a => (
    R = "replace",
    e = a => "[>]^>" + C[a],

    h = a =>
        a[R]( /(if|while)\((.*?)\)\{(.*?)\};/g,
            (a, c, f, g) => e(f) + "[" + h(g) + (c[2] ? e(f) : "[>]^") + "]" )

         [R]( /print\((.*?)\);/g,
            (a, d) => e(d) + "." )

         [R]( /input\((.*?)\);/g,
            (a, d) => e(d) + "," )

         [R]( /([a-z\d]+)(\W?)=(\d+);/ig,
            (a, d, c, g) => e(d) + (c || "[-]+") + g ),

    [,k,a] = /(.*?);(.*)/.exec( a[R]( /\/\/.*?\n/g, '' )[R]( /\s+/g, '' ) ),

    k.split(",").map( (a,b) => C[a] = b ),
    h(a)
)

This is simply a tweaked, refactored, and re-golfed version of the reference implementation in the OP. Most of the saved bytes occur through regex optimizations, elimination of loops, and switching from a push (i.e. b += ...) architecture to an inline architecture.

My apologies for the lack of creativity, but it's all I had time for. Hopefully it will inspire a few more intrepid souls to take the plunge. ;)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.