Login [Register]
Don't have an account? Register now to chat, post, use our tools, and much more.
_player1537 wrote:
Of course I'm serious! Also, I think I may try to steal part of your idea (the interactive terminal) and write that in my C version for practice, if you don't mind, of course.
Go ahead! Smile Are you writing a CLI or GUI version, if you don't mind me asking?
Perhaps CLI, but I think you are doing that. Which one are you doing, and I'll do the other one.
Oh, I'm writing a GUI version... as indicated by the screenshot. Wink
(CLI = Python interactive console in a terminal, GUI = something like IDLE on Windows)
Ah, then I'll do CLI Smile
Okay, here is the prizm basic merthese interpreter.

Code:

ClrText
1->X:1->Y
","->Str 1
While StrCmp(StrMid(Str 1,1,1)," ")/=0         ./=  means not equal to.
"Input"
?->Str 1
ClrText
For 1->A To StrLen(Str 1)
If StrCmp(StrMid(Str 1,A,1),"M")=0
Then
If X+5>21:Then
1->X:Y+1->Y:IfEnd
If Y>7:Then
ClrText:1->X:1->Y:IfEnd
Locate X,Y,"Merth"
X+5->X
IfEnd
If StrCmp(StrMid(Str 1,A,1),"E")=0
Then
1->x
Y+1->Y
If Y>7:Then
ClrText:1->Y:IfEnd
IfEnd
If StrCmp(StrMid(Str 1,A,1),"R")=0
Then
X+1->X
If X>21:Then
Y+1->Y:1->X:IfEnd
If Y>8:Then
1->Y:ClrText:1->X:IfEnd
IfEnd
If StrCmp(StrMid(Str 1,A,1),"T")=0
Then
RanInt#(1,13)->D
If D+X>21:Then
1->X:Y+1->Y:IfEnd
If Y>7:Then
ClrText:1->X:1->Y:IfEnd
For 1->B To D
RanInt#(1,26)->C
Locate X,Y,StrMid("ABCDEFGHIJKLMNOPQRSTUVWXYZ",C,1
X+1->X
Next
IfEnd
If StrCmp(StrMid(Str 1,A,1),"H")=0
Then
A+1->A
If A=StrLen(Str 1)+1
Then
Goto Z
IfEnd
WhileEnd
IfEnd
Next
1->X:1->Y
If StrCmp(StrMid(Str 1,1,1)," ")=0
Then
" "->Str 1
Else
","->Str 1
IfEnd
0->K
While K/=31                            /=   means not equal to.
Getkey->K
WhileEnd
ClrText
WhileEnd
Lbl Z
ClrText
Return

I know this is not 100% optimized, I worked on it at 11:00 last night, and was to tired(and lazy) to optimize completely. Also this program is 676 Bytes, and I probably could make that less, well I will do that right now.
A Haskell version. This is literally my first ever Haskell program, so it could probably be greatly improved, but it seems to work.

Code:
import System.IO
import System.Random

main :: IO ()
main = do
        end <- hIsEOF stdin
        if end
        then return ()
        else do
                c <- getChar
                s <- merthify c
                putStr s
                main

merthify :: Char -> IO [Char]
merthify 'm' = return "merth"
merthify 'e' = return "\n"
merthify 'r' = return " "
merthify 't' = do
        len <- randomRIO (0,13)
        randomString len
merthify 'h' = do
        skipUntil 'h'
        return ""
merthify _ = return ""

randomString :: Int -> IO String
randomString 0 = return ""
randomString s = do
        c <- randomRIO ('a','z')
        xs <- randomString (s - 1)
        return (c:xs)

skipUntil :: Char -> IO ()
skipUntil c = do
        end <- hIsEOF stdin
        if end
        then return ()
        else do
                r <- getChar
                if r == c
                then return ()
                else skipUntil c
Made a Merthese Interactive Console in C. Here it is:
Code:
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <ncurses.h>

#define randbool() (!kerm || rand() % 2)
#define BUFFER_SIZE 1024


int main(int argc, char** argv) {
    char inputbuffer[BUFFER_SIZE];
    int notfinished = true,
   kerm = false,
   seed = time(NULL),
   i = 1,
   quiet = false,
   reallyquiet = false;
       
    for(;i<argc;i++) {
   if( argv[i][0] == '-' ) {
       switch( argv[i][1] ) {
       case 'e':
      if( i+1 < argc )
          merthterpreter(argv[i+1], kerm);
      else
          printf("Please specify an expression to evaluate after the -e switch.\n");
      i++;
      break;
       case 'k':
      kerm = true;
      break;
       case 'K':
      kerm = false;
      break;
       case 's':
      if( i+1 < argc )
          srand(atoi(argv[i+1]));
      else
          printf("Please specify a number to set the seed to after the -s switch.\n");
      i++;
      break;
       case 'S':
      seed = time(NULL);
      break;
       case 'b':
      notfinished = false;
      break;
       case 'q':
      quiet = true;
      break;
       case 'Q':
      reallyquiet = true;
      quiet = true;
      break;
       case 'h':
      printf("Usage: ./merthese [-e expression] [-s seed] [-S] [-K] [-k] [-h] [-b] [-q] [-Q]\n\n");
      printf("-s number     - Set the seed to `number'\n");
      printf("-S            - Set the seed to the current time\n");
      printf("-h            - Display this help message\n");
      printf("-e expression - Evaluate `expression'\n");
      printf("-k            - Set the Merthing @ Kerm flag\n");
      printf("-b            - Don't use interactive mode\n");
      printf("-q            - Don't display header\n");
      printf("-Q            - Don't display any debug info\n");
      printf("-K            - Reset the Merthing @ Kerm flag\n\n");
      break;
       default:
      printf("\nUnrecognized switch: %s.  Use -h for help\n", argv[i]+1);
       }
   } else {
       merthterpreter(argv[i], kerm);
   }
    }
    if( !quiet )
   printf("\nInteractive Merthese Console - By Tanner Hobson\nUse /help for help\n");
   
    while( notfinished ) {
   memset(inputbuffer, '\0', BUFFER_SIZE);
   printf("\n>> ");
   fgets(inputbuffer, BUFFER_SIZE, stdin);
   if( strncmp(inputbuffer, "/quit", 5) == 0 )
       notfinished = false;
   else if( strncmp(inputbuffer, "/kerm", 5) == 0 )
       printf("Merthing @ Kerm flag is now %s.", (kerm = !kerm) ? "on" : "off");
   else if( strncmp(inputbuffer, "/seed", 5) == 0 )
       if( inputbuffer[6] == '\0' )
      printf("Seed is %d",(srand(seed))*0+ seed);
       else
      printf("Seed is now %d.", srand((seed = atoi(inputbuffer + 6)))*0+ seed);
   else if( strncmp(inputbuffer, "/help", 5) == 0 ) {
       printf("/kerm - Toggle the Merthing @ Kerm extension\n");
       printf("/quit - Exit the interactive terminal\n");
       printf("/seed - set the seed to use next\n");
       printf("/help - What you are reading now\n\n");
       printf("Type in the expression to be evaluated and then press RET");
   } else
       merthterpreter(inputbuffer, kerm);
    }
    printf("\n");
}

int merthterpreter(char* cur, int kerm) {
    int hflag = 0,
   j;
    char accum = '\0';

    for( j = 0; j < strlen( cur ) - 1; j++ ) {
   if ( cur[j] == 'h' )
       hflag = !hflag;
   if ( !hflag ) {
       switch ( cur[j] ) {
       case 'm':
      if( randbool() )
          printf("merth");
      else
          printf("%d", accum);
      break;
       case 'e':
      if( randbool() )
          printf("\n");
      else
          accum++;
      break;
       case 'r':
      if( randbool() )
          printf(" ");
      else
          accum = '\0';
      break;
       case 't':
      {
          int times = rand() % ((int)13.4);
          for ( ; times >= 0 ; times-- )
         printf("%c",(char)((rand() % 26) + 'a'));
      }
      break;
       case 'k':
      printf("%c", accum);
      break;
       }
   }
    }
}
Source for a Merthese compiler for .NET:


Code:
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Text;
using Microsoft.CSharp;

namespace Merthese.Compiler
{
    public class Program
    {
        static readonly Dictionary<char, List<string>> functionTable = new Dictionary<char, List<string>>
        {
            {'m', new List<string>{ "Console.Write(\"merth\");" }},
            {'e', new List<string>{ "Console.WriteLine();" }},
            {'r', new List<string>{ "Console.Write(\" \");" }},
            {'t', new List<string>{ "Console.Write(getRandomString(0.0, 13.4));" }},
            {'h', new List<string>{ "/*", "*/" }}
        };

        static void Main(string[] args)
        {
            if (args.Length != 1) { Console.WriteLine("Usage: mkc <program>\n"); return; }

            StringBuilder code = new StringBuilder();
            code.AppendLine("using System;");
            code.AppendLine();
            code.AppendLine("public class Program {");
            code.AppendLine("   static Random random;");
            code.AppendLine();
            code.AppendLine("   static string getRandomString(double min, double max) {");
            code.AppendLine("       int length = (int)(min + random.NextDouble() * (max - min));");
            code.AppendLine("       string result = \"\";");
            code.AppendLine("       while (length-- > 0)");
            code.AppendLine("           result += (char)random.Next(97, 123);");
            code.AppendLine("       return result;");
            code.AppendLine("   }");
            code.AppendLine();
            code.AppendLine("   static void Main(string[] args) {");
            code.AppendLine("       if (args.Length == 1)");
            code.AppendLine("           random = new Random(int.Parse(args[0]));");
            code.AppendLine("       else");
            code.AppendLine("           random = new Random();");
            code.AppendLine();
            int h = 0;
            foreach (char merthstruction in args[0])
            {
                if (merthstruction == 'h')
                    code.AppendLine("\t\t" + functionTable[merthstruction][h++ % 2]);
                else
                    code.AppendLine("\t\t" + functionTable[merthstruction][0]);
            }
            if ((h % 2) == 1) code.AppendLine("\t\t" + functionTable['h'][1]);
            code.AppendLine("   }");
            code.AppendLine("}");

            new CSharpCodeProvider().CompileAssemblyFromSource(new CompilerParameters(null, "merth.exe", false) { GenerateExecutable = true }, code.ToString());
        }
    }
}
Oooh, nice. But we need to read from more than just args[0]. What if there's a space. So:

Code:
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Text;
using Microsoft.CSharp;

namespace Merthese.Compiler
{
   public class Program
   {
      static readonly Dictionary<char, List<string>> functionTable = new Dictionary<char, List<string>>
      {
         {'m', new List<string>{ "Console.Write(\"merth\");" }},
         {'e', new List<string>{ "Console.WriteLine();" }},
         {'r', new List<string>{ "Console.Write(\" \");" }},
         {'t', new List<string>{ "Console.Write(getRandomString(0.0, 13.4));" }},
         {'h', new List<string>{ "/*", "*/" }}
      };

      static void Main(string[] args)
      {
         if (args.Length != 1) { Console.WriteLine("Usage: mkc <program>\n"); return; }

         StringBuilder code = new StringBuilder();
         code.AppendLine("using System;");
         code.AppendLine();
         code.AppendLine("public class Program {");
         code.AppendLine("   static Random random;");
         code.AppendLine();
         code.AppendLine("   static string getRandomString(double min, double max) {");
         code.AppendLine("      int length = (int)(min + random.NextDouble() * (max - min));");
         code.AppendLine("      string result = \"\";");
         code.AppendLine("      while (length-- > 0)");
         code.AppendLine("         result += (char)random.Next(97, 123);");
         code.AppendLine("      return result;");
         code.AppendLine("   }");
         code.AppendLine();
         code.AppendLine("   static void Main(string[] args) {");
         code.AppendLine("      if (args.Length == 1)");
         code.AppendLine("         random = new Random(int.Parse(args[0]));");
         code.AppendLine("      else");
         code.AppendLine("         random = new Random();");
         code.AppendLine();
         int h = 0;
         foreach (string word in args)
         {
            foreach (char merthstruction in word)
            {
               if (merthstruction == 'h')
                  code.AppendLine("\t\t" + functionTable[merthstruction][h++ % 2]);
               else
                  code.AppendLine("\t\t" + functionTable[merthstruction][0]);
            }
         }
         if ((h % 2) == 1) code.AppendLine("\t\t" + functionTable['h'][1]);
         code.AppendLine("   }");
         code.AppendLine("}");

         new CSharpCodeProvider().CompileAssemblyFromSource(new CompilerParameters(null, "merth.exe", false) { GenerateExecutable = true }, code.ToString());
      }
   }
}

(untested)
*bump*
I made some modifications from your base compiler:

Code:
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Text;
using Microsoft.CSharp;
using System.IO;

namespace Merthpiler {
   public class Merthpiler {
      static readonly Dictionary<char, List<string>> functionTable = new Dictionary<char, List<string>>
      {
         {'m', new List<string>{ "Console.Write(\"merth\");" }},
         {'e', new List<string>{ "Console.WriteLine();" }},
         {'r', new List<string>{ "Console.Write(\" \");" }},
         {'t', new List<string>{ "Console.Write(getRandomString(0.0, 13.4));" }},
         {'h', new List<string>{ "/*", "*/" }}
      };

      static void Main(string[] args) {
         string outFile = "merth.exe";
         string codeFile = "";
         for (int i = 0; i < args.Length - 1; i++) {
            switch (args[i]) {
               case "-o":
                  outFile = args[++i];
                  break;
               case "-c":
                  codeFile = args[++i];
                  break;
               default:
                  Console.WriteLine("Usage: Merthpiler [-o outputfile] [-c outputcodefile] programfile"); Environment.Exit(-1);
                  break;
            }
         }
         string inFile = args[args.Length - 1];
         if (!File.Exists(inFile)) { Console.WriteLine(string.Format("Cannot find file: {0}.", inFile)); Environment.Exit(-1); }

         StringBuilder code = new StringBuilder();
         code.AppendLine("using System;");
         code.AppendLine();
         code.AppendLine("public class Program {");
         code.AppendLine("   static Random random;");
         code.AppendLine();
         code.AppendLine("   static string getRandomString(double min, double max) {");
         code.AppendLine("      int length = (int)(min + random.NextDouble() * (max - min));");
         code.AppendLine("      string result = \"\";");
         code.AppendLine("      while (length-- > 0)");
         code.AppendLine("         result += (char)random.Next(97, 123);");
         code.AppendLine("      return result;");
         code.AppendLine("   }");
         code.AppendLine();
         code.AppendLine("   static void Main(string[] args) {");
         code.AppendLine("      if (args.Length == 1)");
         code.AppendLine("         random = new Random(int.Parse(args[0]));");
         code.AppendLine("      else");
         code.AppendLine("         random = new Random();");
         code.AppendLine();
         int h = 0;
         using (StreamReader sr = new StreamReader(inFile)) {
            while (!sr.EndOfStream) {
               char merthstruction = (char)sr.Read();
               if (functionTable.ContainsKey(merthstruction)) {
                  if (merthstruction == 'h')
                     code.AppendLine("\t\t" + functionTable[merthstruction][h++ % 2]);
                  else
                     code.AppendLine("\t\t" + functionTable[merthstruction][0]);
               }
            }
         }
         if ((h % 2) == 1) code.AppendLine("\t\t" + functionTable['h'][1]);
         code.AppendLine("   }");
         code.AppendLine("}");

         string finalCode = code.ToString();

         if (codeFile != "") { using (StreamWriter sr = new StreamWriter(codeFile)) { sr.Write(finalCode); } }

         new CSharpCodeProvider().CompileAssemblyFromSource(new CompilerParameters(null, outFile, false) { GenerateExecutable = true }, finalCode);
      }
   }
}

Now you pass in what you want the output file to be (defaults to "merth.exe"), what file the code will go in if you want it (defaults to ""), and takes in a file rather than the code on the command line. Also, I like your use of the Dictionary.
Nice, just fixed some of those.

Note also that the dictionary has lists instead of strings so that the nondeterministic Kerm/Nikky extensions can be added easily, though I will not be adding them myself.

This should be a little faster than the other implementations, for anyone still looking for seeds...
Ooh, good call. I'll switch that out now Smile.

I just realized I was using the wrong version of the Merthterpreter this whole time, I've been using the one that doesn't take a seed... Time to start over!
Updated (slightly cleaner) RPL version:


Code:

\<< "" 1. \-> out hflag
  \<<
    WHILE DUP "" \=/
    REPEAT DUP HEAD
      IF DUP "h" ==
      THEN 'hflag' -1. STO*
      ELSE
        IF hflag 0. >
        THEN
          CASE DUP "m" ==
            THEN "merth"
            END DUP "e" ==
            THEN "
"
            END DUP "r" ==
            THEN " "
            END DUP "t" ==
            THEN "" 1. RAND 13.4 *
              FOR i "abcdefghijklmnopqrstuvwxyz" RAND 26. * DUP SUB +
              NEXT
            END ""
          END 'out' SWAP STO+
        END
      END DROP TAIL
    END DROP out
  \>>
\>>


This one implements the Merthing @ Kerm extension:


Code:

\<< "" 1. 0. \-> out hflag accum
  \<<
    WHILE DUP "" \=/
    REPEAT DUP HEAD
      IF DUP "h" ==
      THEN 'hflag' -1. STO*
      ELSE
        IF hflag 0. >
        THEN
          CASE DUP "m" ==
            THEN
              IF RAND .5 <
              THEN "merth"
              ELSE accum R\->I \->STR
              END
            END DUP "e" ==
            THEN
              IF RAND .5 <
              THEN "
"
              ELSE "" 'accum' 1. STO+
              END
            END DUP "r" ==
            THEN
              IF RAND .5 <
              THEN " "
              ELSE "" 'accum' 0. STO*
              END
            END DUP "t" ==
            THEN "" 1. RAND 13.4 *
              FOR i "abcdefghijklmnopqrstuvwxyz" RAND 26. * DUP SUB +
              NEXT
            END DUP "k" ==
            THEN accum CHR
            END ""
          END 'out' SWAP STO+
        END
      END DROP TAIL
    END DROP out
  \>>
\>>


This is my current attempt at adding the Nikky extension, but looping is buggy (nested looping is broken and the accumulator gets destroyed) and the code is starting to get messy. I'm going to have to either restructure the program or change my approach to make it work properly in a clean way.


Code:

@ Program name: MERTH3
\<< "" 1. 0. \-> out hflag accum
  \<<
    WHILE DUP "" \=/
    REPEAT DUP HEAD
      IF DUP "h" ==
      THEN 'hflag' -1. STO*
      ELSE
        IF hflag 0. >
        THEN
          CASE DUP "m" ==
            THEN
              IF RAND .5 <
              THEN "merth"
              ELSE accum R\->I \->STR
              END
            END DUP "e" ==
            THEN
              IF RAND .5 <
              THEN "
"
              ELSE "" 'accum' 1. STO+
              END
            END DUP "r" ==
            THEN
              IF RAND .5 <
              THEN " "
              ELSE "" 'accum' 0. STO*
              END
            END DUP "t" ==
            THEN "" 1. RAND 13.4 *
              FOR i "abcdefghijklmnopqrstuvwxyz" RAND 26. * DUP SUB +
              NEXT
            END DUP "k" ==
            THEN
              IF RAND .5 <
              THEN accum CHR
              ELSE "nikky"
              END
            END DUP "n" ==
            THEN
                @ Get char after the 'n', manually remove it from the command
                @ stream, and then put it back where it was on the stack
              SWAP TAIL DUP HEAD NUM 'accum' SWAP STO+ SWAP ""
            END DUP "i" ==
            THEN
                @ Request string from user and use first char as new
                @ accumulator
              "" 'accum' "Character, please!" { 0. } INPUT NUM SWAP STO
            END DUP "y" ==
            THEN
                @ It wasn't clear to me how looping was supposed to be
                @ implemented, so I made 'y' repeat all the chars up to the
                @ next 'h'.
                @
                @ Get all the looping data and create a substring
                @ containing the chars to loop over
            SWAP DUP DUP DUP TAIL HEAD NUM \-> loopcount
              \<< "h" + "h" POS \-> loopend
                \<< 3. loopend SUB \-> loopcode
                  \<< "" 1. loopcount
                      @ Loop by having the program call itself because I
                      @ was too lazy to break it up into subroutines.
                      @ As a result, there are major issues with looping
                      @ that need to be fixed.
                    FOR i loopcode MERTH3 +
                    NEXT
                      @ Chop off now-executed looped code from the command
                      @ stream and get the stack back the way it was
                    SWAP DUP SIZE loopend SWAP SUB UNROT
                  \>>
                \>>
              \>>
            END ""
          END 'out' SWAP STO+
        END
      END DROP TAIL   @ Chop off just-processed character; ready for next pass
    END DROP out
  \>>
\>>
Funny how nikky killed the interpreter.
merthsoft wrote:
Ooh, good call. I'll switch that out now Smile.

I just realized I was using the wrong version of the Merthterpreter this whole time, I've been using the one that doesn't take a seed... Time to start over!
Wow, very impressive work there. >_< This is such a cool and popular project, I might even make it a frontpage news article, if you guys think it's worthy.
That would be awesome! I have said this a few times in IRC, and maybe in this topic, but I think that each we, someone should come up with a quick, easy esoetric language, or even just a small project that doesn't take long to write, and everyone could try to port it to 20 different languages Smile Also, I am going to rewrite my Lisp one to be a little bit more extensible. I also need to edit my console so that it has history, and uses a doubly-linked-list for it.
It would be cool to have a small project every week or so. Maybe not a language, but something short and sweet.
merthsoft wrote:
It would be cool to have a small project every week or so. Maybe not a language, but something short and sweet.
Definitely agreed. For something easy to port across a lot of languages, I guess ideally it wouldn't interface hardware, wouldn't be something that does complicated binary manipulation (since many languages [yes, I'm looking at you, Python] do poorly with binary strings), and would be short but fun.
Taking a different approach, I decided to write a Merthese-to-UserRPL “compiler” in UserRPL. As far as I know, everything works, including nested loops and accumulator handling in loops. Take that, Nikky! The only thing missing is the ability to choose which extensions are active; the Kerm and Nikky ones are always used.

Interestingly, I found this compiler overall easier to implement than the interpreter, though it probably doesn't look like it from the code. Razz

As before, the Merthese code goes on the top of the stack in a string, and executing the program ‘RUN’ will compile and execute it, leaving the output string on the stack in place of the code string. To just see the resulting code without running it, ‘COMPILE.FULL’ can be used instead. The generated code requires the pre-made subroutines M, E, R, T, I, and K, which it calls to implement most of the functions (this is done mainly to avoid duplicating many bytes of code over and over again).

On my HP 50g, the execution speed of both the compiler and compiled code seems quite respectable for interpreted UserRPL code.


Code:

@ Directory "NIKKY"
@ Size: 1923  Circ: # 4ABDh
DIR

  @@@ Code templates used to dynamically produce RPL code

  START.TMPL
"\<<
0 \-> \<-accum \<< \\"\\"
"
  END.TMPL "
\>>
\>>"
  M.TMPL "M + "
  E.TMPL "E + "
  R.TMPL "R + "
  T.TMPL "T + "
  K.TMPL "K + "
  N.TMPL "@$1@ '\<-accum' STO+ "
  I.TMPL "I "
  Y.TMPL
"1 @$1@
FOR i @$2@
NEXT
"

  @@@ Subroutines called by compiled code to perform Merthese operations

  M
  \<<
    IF RAND .5 <
    THEN "merth"
    ELSE \<-accum R\->I \->STR
    END
  \>>
  E
  \<<
    IF RAND .5 <
    THEN " "
    ELSE "" '\<-accum' 1. STO+
    END
  \>>
  R
  \<<
    IF RAND .5 <
    THEN "
"
    ELSE "" '\<-accum' 0. STO*
    END
  \>>
  T
  \<< "" 1. RAND 13.4 *
    FOR i
"abcdefghijklmnopqrstuvwxyz"
RAND 26. * DUP SUB +
    NEXT
  \>>
  I
  \<< '\<-accum'
"Character, please!" { 0. } INPUT NUM SWAP STO
  \>>
  K
  \<<
    IF RAND .5 <
    THEN \<-accum CHR
    ELSE "nikky"
    END
  \>>

  @@@ Take a string of Merthese code and the start position and
  @@@ search for the end of the looping structure, assuming that
  @@@ given code is already in an outer loop.  Take nested loops into
  @@@ account.

  LOOPEND
  \<< DUP 0 \-> code loopstart pos nestcount
    \<<
      DO code pos DUP SUB \-> c
        \<<
          CASE c "y" ==
            THEN 'pos' 2 STO+ 'nestcount' 1 STO+
            END c "n" ==
            THEN 'pos' 2 STO+
            END c "h" ==
            THEN 'nestcount' 1 STO- 'pos' 1 STO+
            END 'pos' 1 STO+
          END
        \>>
      UNTIL nestcount 0 < pos code SIZE > OR
      END pos
    \>>
  \>>

  @@@ Compile a subroutine of Merthese code

  COMPILE.ROUTINE
  \<< DUP SIZE 1. \-> incode insz chrp
    \<< ""
      WHILE chrp insz \<=
      REPEAT incode chrp DUP 1 + SUB DUP HEAD SWAP TAIL \-> c1 c2
        \<<
          CASE c1 "m" ==
            THEN M.TMPL
            END c1 "e" ==
            THEN E.TMPL
            END c1 "r" ==
            THEN R.TMPL
            END c1 "t" ==
            THEN T.TMPL
            END c1 "h" ==
              @ Skip over to next 'h'
            THEN incode chrp 1. + insz SUB "h" POS DUP chrp + SWAP 0.
              \=/ SWAP insz IFTE 'chrp' STO ""
            END c1 "k" ==
            THEN K.TMPL
            END c1 "n" ==
            THEN
              @ Replace string "@$1@" in 'N' code template with
              @ character to write to accumulator
            N.TMPL "@$1@" c2 NUM \->STR SREPL DROP 'chrp' 1 STO+
            END c1 "i" ==
            THEN I.TMPL
            END c1 "y" ==
            THEN
              @ Replace string "@$1@" in code template with number of
              @ times to loop.
            Y.TMPL "@$1@" c2 NUM \->STR SREPL DROP
              @ Replace "@$2@" with compiled loop body code:
            "@$2@"
            incode chrp 2 +    @ Get loop body of Merthese code only
            incode OVER LOOPEND DUP 1 -
                               @ Find end of loop
            'chrp' STO 1 -
                               @ Update Merthese character pointer for
                               @ next pass through main compiler loop
                               @ (will point past the end of this loop
                               @ since we're handling it all here)
            SUB COMPILE.ROUTINE
                               @ Compile the loop code (and any nested
                               @ loops, however many levels deep)
            SREPL DROP         @ Finally, we can add the compiled loop
                               @ body in place of the "@$2@" placeholder
            END ""
          END
        \>> + 'chrp' 1 STO+
      END
    \>>
  \>>

  @@@ Compile Merthese code, generating a full RPL program

  COMPILE.FULL
  \<< COMPILE.ROUTINE START.TMPL SWAP + END.TMPL +
    @ Reformat the code string by converting it to code and then back
    @ to a string to make it look nice
    STR\-> \->STR
  \>>

  @@@ Compile Merthese code and immediately execute it

  RUN
  \<< COMPILE.FULL STR\-> EVAL
  \>>
END


And now for my proposed extension:

Quote:
t: Outputs incrementing sequence of chars starting from accum. char with random length 0–13.4 (same as for 't' command). Randomly either leaves accum. unmodified or sets it to final char code + 1
e: Randomly outputs one of ‘.,;:-!?'’
v: Outputs the accum. char ROT13'ed if it's a letter (ASCII 65–90 or 97–122), unmodified otherwise
Here's the source code for a 68k Basic implementation that I wrote this morning. It supports the core of the language and the Merthing @ Kerm extension. I think the Nikky extension would be impossible to do with the way I wrote it, and I'm not sure if there's a better way to write it.

It works, but it's a little slow. Maybe a 68k C implementation (which I'll do as well, perhaps) would run better.

It was generated by DaisukeEdit, but after doing that I replaced the "->" character with the string "->", so you won't be able to just plug it back into there. (I did the same with "!=").


Code:
merthese(cmds)
Prgm
Local i,j,chr,out,letters,rnd,nexth,accum
{"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"}->letters

Define nexth(cmds)=Func
Local i,chr
""->chr
0->i
If inString(cmds,"h")=0 Then
 Return cmds
EndIf
While chr!="h"
 i+1->i
 mid(cmds,i,1)->chr
EndWhile
Return mid(cmds,i+1)
EndFunc

" "->chr
""->out
0->accum
0->i
ClrIO
While chr!=""
 i+1->i
 mid(cmds,i,1)->chr
 If chr="m" Then
  If rand()<.5 Then
   out&"merth"->out
  Else
   out&string(accum)->out
  EndIf
 ElseIf chr="e" Then
  If rand()<.5 Then
   out&char(13)->out
  Else
    accum+1->accum
  EndIf
 ElseIf chr="r" Then
  If rand()<.5 Then
   out&" "->out
  Else
   0->accum
  EndIf
 ElseIf chr="t" Then
  rand(13)->rnd
  For j,0,rnd
   out&letters[rand(26)]->out
 EndFor
 ElseIf chr="h" Then
  nexth(mid(cmds,i+1))->cmds
  0->i
 ElseIf chr="k" Then
  out&char(accum)->out
 EndIf
EndWhile
0->i
" "->chr
While chr!=""
 i+1->i
 mid(out,i,1)->chr
 If chr=char(13) Then
  Disp mid(out,1,i-1)
  mid(out,i+1)->out
  0->i
 EndIf
EndWhile
Disp out
EndPrgm
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 4 of 7
» All times are GMT - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement