Execute Brain****/Elena

From Rosetta Code

<lang elena>import system'collections; import system'routines; import system'dynamic;

import extensions; import extensions'scripting; import extensions'dynamic'expressions;

class TapeAssembler {

   Stack                theBrackets;
   List<TapeExpression> theTape;

   constructor()
   {
       theBrackets := new Stack();
       theTape := new List<TapeExpression>();

       theTape.append(TapeExpression.Declaring("ptr"));
       theTape.append(TapeExpression.Assigning("ptr", TapeExpression.Constant(0)))
   }

   constructor(assembly_program)
       <= ()
   {
       assembly_program(self)
   }    

   open()
   {
       theBrackets.push(theTape);
       theTape := new List<TapeExpression>()
   }

   close()
   {
       var loop := TapeExpression.Loop(
                         TapeExpression.MessageCall(
                            TapeExpression.MessageCall(
                               TapeExpression.Variable("tape"),
                               "at",
                               TapeExpression.Variable("ptr")
                            ),
                            "notequal",
                            TapeExpression.Constant($0)),
                         TapeExpression.Code(theTape.Value));

       theTape := theBrackets.pop();
       theTape.append(loop)                
   }

   input()
   {
       theTape.append(TapeExpression.MessageCall(
                       TapeExpression.Variable("tape"),
                       "setAt",
                       TapeExpression.Variable("ptr"),
                       TapeExpression.MessageCall(
                          TapeExpression.Constant(console),
                          "readChar"
                       )))
   }

   output()
   {
       theTape.append(TapeExpression.MessageCall(
                                TapeExpression.Constant(console), 
                                "write",
                                TapeExpression.MessageCall(
                                  TapeExpression.Variable("tape"),
                                  "at",
                                  TapeExpression.Variable("ptr")
                                )))
   }

   next()
   {
       theTape.append(TapeExpression.Assigning(
           "ptr",
           TapeExpression.MessageCall(
               TapeExpression.Variable("ptr"),
               "add",
               TapeExpression.Constant(1))))
   }

   previous()
   {
       theTape.append(TapeExpression.Assigning(
           "ptr",
           TapeExpression.MessageCall(
               TapeExpression.Variable("ptr"),
               "subtract",
               TapeExpression.Constant(1))))
   }

   increase()
   {
       theTape.append(TapeExpression.MessageCall(
                               TapeExpression.Variable("tape"),
                               "setAt",
                               TapeExpression.Variable("ptr"), 
                               TapeExpression.MessageCall(
                                   TapeExpression.Constant(CharValue),
                                   "load",
                                   TapeExpression.MessageCall(
                                       TapeExpression.MessageCall(
                                           TapeExpression.Constant(convertor),
                                           "toInt",
                                           TapeExpression.MessageCall(
                                               TapeExpression.Variable("tape"),
                                               "at",
                                               TapeExpression.Variable("ptr"))
                                       ),
                                       "add",
                                       TapeExpression.Constant(1)))))
   }

   decrease()
   {
       theTape.append(TapeExpression.MessageCall(
                               TapeExpression.Variable("tape"),
                               "setAt",
                               TapeExpression.Variable("ptr"), 
                               TapeExpression.MessageCall(
                                   TapeExpression.Constant(CharValue),
                                   "load",
                                   TapeExpression.MessageCall(
                                       TapeExpression.MessageCall(
                                           TapeExpression.Constant(convertor),
                                           "toInt",
                                           TapeExpression.MessageCall(
                                               TapeExpression.Variable("tape"),
                                               "at",
                                               TapeExpression.Variable("ptr"))
                                       ),
                                       "subtract",
                                       TapeExpression.Constant(1)))))

   }

   get()
   {
       var program := TapeExpression.Singleton(
               TapeExpression.Method(
                  "eval",
                  TapeExpression.Code(theTape.Value),
                  TapeExpression.Parameter("tape")));

       var o := (program.compiled())();

       ^(tape){ o.eval(tape) }
   }

}

const bf_program = "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.";

public program() {

   console.writeLine:bf_program;

   var bfAssemblyProgram := new ScriptEngine()
       .loadPath:"asmrules.es"
       .eval(bf_program);

   var bfProgram := new TapeAssembler(bfAssemblyProgram).get();

   var bfTape := Array.allocate(1024).populate:(int n => $0);

   bfProgram(bfTape)

}</lang> The grammar: <lang elena>[[

  #grammar transform
  #grammar cf
  #define start      ::= <= ( > => commands <= " * system'dynamic'ClosureTape= " # ) =>;
  #define commands   ::= command commands;
  #define commands   ::= comment commands;
  #define commands   ::= $eof;
  #define command    ::= <= += " %""output[0]"" system'dynamic'MessageClosure ^""new[1]"" " => ".";
  #define command    ::= <= += " %""input[0]"" system'dynamic'MessageClosure ^""new[1]"" " => ",";
  #define command    ::= <= += " %""previous[0]"" system'dynamic'MessageClosure ^""new[1]"" " => "<";
  #define command    ::= <= += " %""next[0]"" system'dynamic'MessageClosure ^""new[1]"" " => ">";
  #define command    ::= <= += " %""increase[0]"" system'dynamic'MessageClosure ^""new[1]"" " => "+";
  #define command    ::= <= += " %""decrease[0]"" system'dynamic'MessageClosure ^""new[1]"" " => "-";
  #define command    ::= <= += " %""open[0]"" system'dynamic'MessageClosure ^""new[1]"" " => "[";
  #define command    ::= <= += " %""close[0]"" system'dynamic'MessageClosure ^""new[1]"" " => "]";
  #define comment    ::= " " comments;
  #define comment    ::= "'" comments;
  #define comment    ::= "!" comments;
  #define comment    ::= $eol;
  #define comments   ::= $chr comments;
  #define comments   ::= $eps;
  #mode symbolic;

]]</lang>

Output:
ELENA VM 4.0.14 (C)2005-2019 by Alex Rakov
Initializing...
Done...
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
Hello World!