# Off-Topic Discussion > The Lounge > Tech Talk >  >  My brainfuck (Java)

## Sornaensis

So this term I am taking a Java course, and as a simple exercise I implemented my own version of >>>Brainfuck<<<

It can take a brainfuck string as a commandline parameter and interpret and execute it immediately, and it can take file input as well. Additionally it can compile brainfuck into a binary file to be executed without having to be precompiled.

An array of 30,000 short integers [chars] to play around with, currently.

Here're the language specs:




```
Commands --
+ -- Increment the current memory cell
-  -- Decrement the current memory cell
< -- Decrement the memory position
> -- Increment the memory position
[ -- If the current memory cell is 0, skip to the next matching ']'
] -- If the current memory cell is non zero, skip to the previous matching '['
. -- Print the value of the current memory cell as an integer to standard output
, -- Print the value of the current memory cell as a single character to standard output
^ -- Accept one 16 bit integer from standard input and assign the current memory cell that value
$ -- Accept one character from standard input and assign the current memory cell that value
c -- For simplicity's sake, this takes the following character from a source file and places its value into the current memory cell
w -- This takes the characters proceeding it as a single 16 bit integer and places it into the current memory cell

Comments --

/ -- Start and end a comment block

Macros -- I implemented a simple #macro system as well
#place <location/of/filename> 
#define <MyMacro> (param1,param2) wparam1 > wparam2 [-<+>] / Adds param2 to param1 /

#MyMacro (23,12)
```


Here's an example program --




```

#define <PrintInt> (x) wx.
#define <Putstring> (r,s,t,u,v,w,x,y,z) cr,cs,ct,cu,cv,cw,cx,cy,cz,
#define <AddTwo> (f,s) wf >ws [-<+>]< / This adds two numbers together by using the second parameter as a loop counter /
#AddTwo (23,57)
.w10,
#Putstring (D,e,r,p,!, , , , ) / This prints 'Derp!' lolo /
w10,
 [-] / Zero out out mems for s's 'n g's /
  #Putstring (P,i,c,k, ,a, ,n,u)
#Putstring (m,b,e,r,:, ,\b,\b, )
^
/ Get a number from stdin /
>
#Putstring (P,i,c,k, ,a, ,n,u)
#Putstring (m,b,e,r,:, ,\b,\b, )
^
/ Get another # from stdin /
>
#Putstring (T,h,e, ,s,u,m, ,=)
c ,
<
/ Tell the user what's coming up /
[- < + >]<.
/ Get the sum /
#AddTwo (78,12)
/ This is just proof of concept /
 / This shit down here returns 1 or 0 - the inverse boolean value of the current mem cell. i.e. !(boolean)memory[memcell] /
[
  [
    -
  ]
  @
]
+
@ 


```


Call the program with --




```
java -jar brainfuck.jar "brainfuck code to interpret"
java -jar brainfuck.jar -f "name of file to interpret"
java -jar brainfuck.jar -c "name of file to compile" "name of binary file to output"
java -jar brainfuck.jar -e "name of binary file to execute"
java -jar brainfuck.jar -h (Shows help stuff)
```


and finally, the source code -




```
import java.io.*;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.regex.Matcher;

class BrainFKParser{
    private Hashtable<String, Integer> symbol_map;
    private Hashtable<String, ArrayList<String>> def_macros;
    private Hashtable<String, String> exp_macros;
    
    BrainFKParser(){
        symbol_map = new Hashtable<String, Integer>();
        def_macros = new Hashtable<String, ArrayList<String>>();
        exp_macros = new Hashtable<String, String>();
    }
    
    public boolean AddSymbol(String name, int opcode){
         if(!symbol_map.containsKey(name)){
             symbol_map.put(name, opcode);
             return true;
         }
         return false;
     }
     
     public ArrayList<Integer> ParseString(String fn){
         if(!MatchBraces(fn)){
            return null;
         }
         ArrayList<Integer> program = new ArrayList();
         
         String temp = "";
         for(int i=0;i<fn.length();++i){
             temp += fn.charAt(i);
             
             if("c".equals(temp) && (i+1<fn.length())){
                 if(fn.charAt(i+1) != '\\'){
                    //System.out.println("Found character: " + fn.charAt(i) + " " + fn.charAt(i+1));
                    program.add(symbol_map.get(temp) | fn.charAt(i+1));
                 }else if(i+2<fn.length()){
                     //System.out.println("Found control character: " + fn.charAt(i+1) + " " + fn.charAt(i+2));
                     switch(fn.charAt(i+2)){
                         case 'n':
                             program.add(symbol_map.get(temp) | '\n');
                             break;
                         case 'b':
                             program.add(symbol_map.get(temp) | '\b');
                             break;
                         case 'r':
                             program.add(symbol_map.get(temp) | '\r');
                             break;
                         case '\\':
                             program.add(symbol_map.get(temp) | '\\');
                             break;
                         case '0':
                             program.add(symbol_map.get(temp) | '\0');
                             break;
                     }
                     ++i;
                 }
                 ++i;
             }
             else if("w".equals(temp)){
                 String number = "", temp2 = "";
                 for(++i;i<fn.length();++i){
                     temp2 += fn.charAt(i);
                     if(!symbol_map.containsKey(temp2) && Character.isDigit(fn.charAt(i))){
                         number += temp2;
                     }
                     else if(symbol_map.containsKey(temp2)){
                         --i;
                         break;
                     }
                     temp2 = "";
                 }
                 if(number.length() > 0){
                    program.add(symbol_map.get(temp) | Short.valueOf(number));   
                 }
             }
             else if(symbol_map.containsKey(temp)){
                program.add(symbol_map.get(temp));
             }
             temp = "";
         }
         
         return program;
    }
     
    public String PreParse(String fn) throws FileNotFoundException, IOException{
        String brainFKCode = "", temp = "";
        
         for(int i=0;i<fn.length();++i){
             boolean ischar = false;
             temp += fn.charAt(i);
             
             if(i > 0){
                 if(fn.charAt(i-1) == 'c'){
                     ischar = true;
                 }
             }
             
             if("#".equals(temp) && !ischar){
                 String macroname = "", filename = "", params = "", expression = "", temp2 = "";
                 
                 for(++i;i<fn.length();++i){
                     
                     temp2 += fn.charAt(i);
                     
                     if(!Character.isWhitespace(fn.charAt(i)) && !(filename.length() > 0) && !(params.length() > 0) && !(expression.length() > 0) && !"\n".equals(temp2) && !"\r".equals(temp2) && !"<".equals(temp2) && !"(".equals(temp2)){
                         macroname += temp2;
                     }
                     else if("<".equals(temp2) && !(expression.length() > 0)){
                         for(;i<fn.length();++i){
                             if(fn.charAt(i) != '>' && fn.charAt(i) != '<'){
                                 filename += fn.charAt(i);
                             }
                             else if(fn.charAt(i) == '>'){
                                 break;
                             }
                         }
                     }
                     else if("(".equals(temp2)){
                         for(++i;i<fn.length();++i){
                             if(fn.charAt(i) != ')' && fn.charAt(i) != '('){
                                 params += fn.charAt(i);
                             }
                             else{
                                 break;
                             }
                         }
                     }
                     else if(!Character.isWhitespace(fn.charAt(i)) && filename.length() > 0 && params.length() > 0 && !"\n".equals(temp2) && !"\r".equals(temp2)){
                         expression += temp2;
                     }
                     else if("\n".equals(temp2) || "\r".equals(temp2)){
                         --i;
                         break;
                     }
                     
                     temp2 = "";
                 }
                 if(macroname.length() > 0 ){
                    brainFKCode += FillMacro(macroname, filename, params, expression);
                 }
             }
             else if("/".equals(temp) && !ischar && i < fn.length()){
                 for(++i;i < fn.length();++i){
                     temp += fn.charAt(i);
                     if (fn.charAt(i) == '/'){
                         break;
                     }
                 }
                 //System.out.println("Found a comment: " + temp);
                 temp = "";
             }
             else{
                 brainFKCode += temp;
             }
             
             temp = "";
         }
         
         return brainFKCode;        
    }
     
    public boolean MatchBraces(String fn){
        
        int braces = 0;
        for(int i=0;i<fn.length();++i){
            switch(fn.charAt(i)){
                case '[': //Beginning of brace/brace nest
                {
                    braces = 1;
                    for(++i;braces != 0 && i<fn.length();++i){
                        switch(fn.charAt(i)){
                            case '[':
                            {
                                ++braces;
                            }break;
                            case ']':
                            {
                                --braces;
                            }break;
                        }
                    }
                }break;
                case ']': //Out of place brace
                {
                    System.out.println("Fatal error:\n\t\tMismatched braces");
                    return false;
                }
            }
        }
        
        return braces == 0 ? true : false;
    }
    
    private String FillMacro(String macroname, String filename, String params, String expression) throws FileNotFoundException, IOException{
        
        String expansion = "";
        //macroname  = macroname.toLowerCase();
        
        //System.out.println(params);
        
        if("place".equals(macroname) && filename.length() > 0){
            BufferedReader inputStream = new BufferedReader(new FileReader(filename));
            while(inputStream.ready()){
                expansion += String.valueOf((char)inputStream.read());
            }
        }
        else if("sysplace".equals(macroname) && filename.length() > 0){
            filename = "/usr/include/brainfk/" + filename;
            BufferedReader inputStream = new BufferedReader(new FileReader(filename));
            while(inputStream.ready()){
                expansion += String.valueOf((char)inputStream.read());
            }
        }
        else if("define".equals(macroname) && filename.length() > 0 && params.length() > 0 && expression.length() > 0){
            //System.out.println("Defining a macro... " + macroname + " " + filename + " " + params + " " + expression);
            String temp = "";
            ArrayList<String> parameters = new ArrayList<String>();
            for(int i=0;i<params.length();++i){
                if(params.charAt(i) != ','){
                    temp += params.charAt(i);
                    //System.out.println(temp);
                }
                else{
                    parameters.add(temp);
                    temp ="";
                }
            }
            if(temp.length() > 0){
                parameters.add(temp);
            }
            def_macros.put(filename, parameters);
            exp_macros.put(filename, PreParse(expression));
            //System.out.println("Macro defined");
        }
        else if(def_macros.containsKey(macroname) && exp_macros.containsKey(macroname)){
            //System.out.println("Found def'd macro");
            String temp = "";
            ArrayList<String> parameters = new ArrayList<String>();
            for(int i=0;i<params.length();++i){
                if(params.charAt(i) != ','){
                    temp += params.charAt(i);
                }
                else if(params.charAt(i) == ',' || (i+1) == params.length()){
                    parameters.add(temp);
                    temp ="";
                }
            }
            if(temp.length() > 0){
                parameters.add(temp);
                temp = "";
            }
            //System.out.println(parameters.size() + " " + def_macros.get(macroname).size());
            temp = exp_macros.get(macroname);
            //System.out.println(temp);
            if(parameters. size() == def_macros.get(macroname).size()){
                for(int i=0;i<parameters.size();++i){
                    //System.out.println(def_macros.get(macroname).get(i) + " " + parameters.get(i));
                    temp = temp.replace(def_macros.get(macroname).get(i), parameters.get(i));
                    //System.out.println(temp);
                }
            }
            
            expansion += temp;
            //System.out.println(expansion);
        }
        
        return PreParse(expansion);
        
    }
     
}

class BrainFKEngine{
    private ArrayList<Integer> code;
    private char[] memory;
    private int step, mem_ptr, memory_size;
    private boolean exit = false;
    
    BrainFKEngine(ArrayList<Integer> program, int memsize){
        code = program;
        memory_size = memsize;
        mem_ptr = 0;
        step = 0;
        memory = new char[memory_size];

        for(int i = 0;i<memory_size;++i){
            memory[i] = 0;
        }
    }
    
    public Integer Execute() throws IOException{
        while(!exit && step<code.size()){
            switch(code.get(step) >> 16){
                case 0x01: // '+'
                    ++memory[mem_ptr];
                    break;

                case 0x02: // '-'
                    --memory[mem_ptr];
                    break;

                case 0x03: // '>'
                {
                   if(mem_ptr < memory_size-1){
                       ++mem_ptr;
                   }
                   else{
                       mem_ptr = 0;
                   }
                }
                    break;

                case 0x04: // '<'
                {
                   if(mem_ptr > 0){
                       --mem_ptr;
                   }
                   else{
                       mem_ptr = memory_size-1;
                   }
                }
                    break;

                case 0x05: // '['
                {
                    if(memory[mem_ptr] == 0){
                        int brackets = 1;
                        while(step < code.size() && brackets != 0){
                            ++step;
                            if(code.get(step) >> 16 == 0x05){
                                ++brackets;
                            }
                            if(code.get(step) >> 16 == 0x06){
                                --brackets;
                            }
                        }
                    }
                }
                    break;

                case 0x06: // ']'
                {
                    if(memory[mem_ptr] != 0){
                        int brackets = 1;
                        while(brackets != 0 && step > 0){
                            --step;
                            if(code.get(step) >> 16 == 0x05){
                                --brackets;
                            }
                            if(code.get(step) >> 16 == 0x06){
                                ++brackets;
                            }
                        }
                    }
                }
                    break;

                case 0x07: // '.'
                    System.out.print((int)memory[mem_ptr]);
                    break;

                case 0x08: // ','
                    System.out.print(String.valueOf(memory[mem_ptr]));
                    break;
                case 0x09: // '$'
                    memory[mem_ptr] = (char)System.in.read();
                    break;
                case 0x0A: // '^'
                {
                    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
                    String number = in.readLine();
                    memory[mem_ptr] = (char)Integer.valueOf(number).intValue();
                }
                    break;
                case 0x0B: // '@'
                    exit = true;
                    break;
                case 0x0C: // 'c' + char
                    memory[mem_ptr] = (char)(code.get(step) ^ 0x0C0000);
                    break;
                case 0x0D: // 'w' + short integer
                    memory[mem_ptr] = (char)(code.get(step) ^ 0x0D0000);
                    break;
            }
            ++step;
        }
        return (int)memory[mem_ptr];
    }
    
}

public class BrainFKInterpreter {

    public static void main(String[] args) throws IOException {
       
       BrainFKParser Compiler = new BrainFKParser();
       
       
       Compiler.AddSymbol("+",  0x010000); //Incrument Current Memory Cell
       Compiler.AddSymbol("-",  0x020000); //Decrument Current Memory Cell
       Compiler.AddSymbol(">",  0x030000); //Incrument Memory Pointer
       Compiler.AddSymbol("<",  0x040000); //Decrument Memory Pointer
       Compiler.AddSymbol("[",  0x050000); //Jump to next matching ] if zero
       Compiler.AddSymbol("]",  0x060000); //Jump to previous matching [ if not zero
       Compiler.AddSymbol(".",  0x070000); //Print current memory cell as an integer
       Compiler.AddSymbol(",",  0x080000); //Print current memory cell as a character
       Compiler.AddSymbol("$",  0x090000); //Read one character from standard input
       Compiler.AddSymbol("^",  0x0A0000); //Read integer from standard input
       Compiler.AddSymbol("@",  0x0B0000); //Halt Program Execution
       Compiler.AddSymbol("c",  0x0C0000); //Take next tape token as character and set the current memory cell to that value
       Compiler.AddSymbol("w",  0x0D0000); //Take next tape tokens as decimal digits until another command is found and set current memory cell to the short integer value
       
       BrainFKEngine Executioner;
       if(args.length>2){ // 3 commandline args or more
            if("-c".equals(args[0].toLowerCase()) && args[1].length() > 0 && args[2].length() > 0){
                BufferedReader inputStream = new BufferedReader(new FileReader(args[1]));
                String brainfksource = "";
                while(inputStream.ready()){
                    brainfksource += String.valueOf((char)inputStream.read());
                }
                ArrayList<Integer> brainfkopcodes = Compiler.ParseString(Compiler.PreParse(brainfksource));
                
                if(brainfkopcodes == null){
                    return;
                }
                
                BufferedWriter outputStream = new BufferedWriter(new FileWriter(args[2]));
                for(int i=0;i<brainfkopcodes.size();++i){
                    char[] buffer = new char[2];
                    buffer[0] = (char)(brainfkopcodes.get(i) >> 16);
                    buffer[1] = (char)((brainfkopcodes.get(i) << 16) >> 16);
                    outputStream.write(buffer);
                    //System.out.println(buffer);
                }
                outputStream.close();
                System.out.println("Compiled file \'" + args[1] + "\' into binary file \'" + args[2] + "\' - execute with command brainfk -e " + args[2]);
            }
            
       }
       else if(args.length>1){ // 2 commandline args or more
           if("-f".equals(args[0].toLowerCase()) && args[1].length() > 0){
                BufferedReader inputStream = new BufferedReader(new FileReader(args[1]));
                String brainfksource = "";
                while(inputStream.ready()){
                    brainfksource += String.valueOf((char)inputStream.read());
                }
                inputStream.close();
                Executioner = new BrainFKEngine(Compiler.ParseString(Compiler.PreParse(brainfksource)), 30000);
                
                if(Executioner == null){
                    return;
                }
                
                System.out.println("\nReturned Status: " + Executioner.Execute());
            }else if("-e".equals(args[0].toLowerCase()) && args[1].length() > 0){
                BufferedReader inputStream = new BufferedReader(new FileReader(args[1]));
                ArrayList<Integer> bfkbinary = new ArrayList<Integer>();
                
                while(inputStream.ready()){
                    char[] buffer = new char[2];
                    inputStream.read(buffer);
                    int opcode = buffer[0]; 
                    opcode <<= 16;
                    opcode += buffer[1];
                    bfkbinary.add(opcode);
                    //System.out.println(opcode);
                }
                inputStream.close();
                Executioner = new BrainFKEngine(bfkbinary, 30000);
                System.out.println("\nReturned Status: " + Executioner.Execute());
            }
            
       }
       else if(args.length>0 && !"-h".equals(args[0])){ // Just one commandline arg
           Executioner = new BrainFKEngine(Compiler.ParseString(Compiler.PreParse(args[0])), 30000);
           
           if(Executioner == null){
                return;
            }
           
           System.out.println("\nReturned Status: " + Executioner.Execute());
       }else{ // No commandline arguments
           System.out.println("brainfk - \n\tUseage: brainfk \"brainfk source code to interpret\"\t\t\tParse and execute enquoted code\n\t\t[-f][brainfk source filename]\t\t\t\t\tParse and execute brainfk source file\n\t\t[-c][brainfk source filename]"
                   + "[compiled output filename]\t\tCompile input filename and output to output filename as brainfk binary\n\t\t[-e][compiled brainfk filename]\t\t\t\t\tExecute brainfk binary code\n\t\t[-h/--help]\t\t\t\t\t\t\tShow this help message");
       }
    }
}
```

----------


## Marvo

What a waste of time. Write a java compiler next time.

----------


## Sornaensis

Already on it.

----------

