#!/usr/bin/perl 


 use strict;
 use warnings;
 use utf8;
 # for unicode character properties.
 # use Unicode::UCD qw(charprop);
 # use IO::File;
 #use IO::BufReader;
 #use IO::BufWriter;
 use Getopt::Long;
 use List::Util;  # for all function
 use Carp; # For croak and confess

 package Machine; 
   use constant { true => 1, false => 0 };

   sub new {
     # my ($class) = @_;
     my $class = shift;  # 
     binmode STDOUT, ":encoding(UTF-8)";

     my $self = {
       accumulator   => 0,       # counter for anything
       peep          => "",      # next char in input stream
       charsRead     => 0,       # No. of chars read so far init:0
       linesRead     => 1,       # No. of lines read so far init:1
       inputBuffer   => [],      # reversed array of input chars/graphemes
       outputBuffer  => "",      # where string output will go
       inputType    => "unset",  # reading from stdin/string/file etc
       sinkType      => "stdout",# 
       work          => "",      # text accumulator
       stack         => [],      # parse token stack
       tapeLength    => 100,     # tape initial length
       tape          => [ map { "" } 1..100 ], # array of token attributes
       marks         => [ map { "" } 1..100 ], # tape marks
       cell          => 0,       # pointer to current cell
       input         => *STDIN,  # text input stream
       output        => *STDOUT, #
       eof           => false,    # end of stream reached? (boolean)
       escape        => "\\",   # char used to "escape" others: default "\"
       delimiter     => "*",      # push/pop delimiter (default is "*")
     };
     bless $self, $class;
     return $self;
   }

   sub fillInputStringBuffer {
     my ($self, $text) = @_;
     my $revtext = reverse $text;
     # push onto the array
     push @{$self->{inputBuffer}}, split //, $revtext;
   }

   sub fillInputBuffer {
     my $self = shift;
     my $text = shift;
     # grapheme clusters regex is X in perl
     # the grapheme cluster splitter is making an extra empty char 
     # in the array

     # not working?
     # my @charArray = reverse split(/(\X)/, $text);

     #my @graphemes = $text =~ m/X/g;
     #my @charArray = reverse(@graphemes);
     my @charArray = reverse split(//, $text);
     push (@{$self->{inputBuffer}}, @charArray);
     # display the input buffer array
     # print "[",join(", ", @{$self->{inputBuffer}}),"]";
   }

   # read one character from the input stream and
   #   update the machine. This reads though an inputBuffer/inputChars
   #   so as to handle unicode grapheme clusters (which can be more
   #   than one "character").
   # 
   sub readChar {
     my $self = shift;

     #  this exit code should never be called in a translated script
     #  because the Machine:parse() method will return just before
     #  a read() on self.eof But I should keep this here in case
     #  the machine methods are used outside of a parse() method?
     if ($self->{eof}) {
       # need to return from parse method (i.e break loop) when reading on eof.
       exit 0; # print("eof exit")
     }

     my $result = 0; my $line = "";
     $self->{charsRead} += 1;
     # increment lines
     if ($self->{peep} eq "\n") { $self->{linesRead} += 1; }
     $self->{work} .= $self->{peep};

     # fix: it would be better not to have an if else here
     # stdin.all/string/file all read the whole input stream
     #    at once into a buffer.
     my $inputType = $self->{inputType};
     if ($inputType eq "stdin" || $inputType eq "string" || 
         $inputType eq "file") {
       if (!@{$self->{inputBuffer}}) {
         $self->{eof} = true;
         $self->{peep} = "";
       } else {
         $self->{peep} = "";
         # the inputBuffer is a reversed array. pop() returns the last element
         my $char = pop @{$self->{inputBuffer}};
         $self->{peep} .= $char if defined $char;
       }
       return;
     } elsif ($inputType eq "stdinstream") {
       # read from stdin one line at a time. 
       # 
     } elsif ($inputType eq "filestream") {
       # if (scalar(@{$self->{inputBuffer}}) == 0) {
       if (!@{$self->{inputBuffer}}) {
         my $bytes = $self->{input}->getline(\$line);
         if ($bytes > 0) {
           $self->fillInputBuffer($line);
         } else {
           $self->{eof} = true;
           $self->{peep} = "";
         }
       }
       if (scalar(@{$self->{inputBuffer}}) > 0) {
         $self->{peep} = "";
         my $char = pop @{$self->{inputBuffer}};
         $self->{peep} .= $char if defined $char;
       }
       return;
     } else {
       print STDERR "Machine.inputType error ", $inputType, " while trying to read input\n";
       exit 1;
     }
   } # read

   # function Machine:write(output)
   sub writeText {
     my $self = shift;
     my $outputType = $self->{sinkType};
     if ($outputType eq "stdout") {
       print $self->{work};
     } elsif ($outputType eq "file") {
       print {$self->{output}} $self->{work} or die "Error writing to file: $!";
     } elsif ($outputType eq "string") {
       $self->{outputBuffer} .= $self->{work};
     } else {
       print STDERR "Machine.sinkType error for type ", $outputType, "\n";
     }
   }

   # increment tape pointer by one
   sub increment {
     my ($self) = @_;
     $self->{cell}++;
     if ($self->{cell} >= $self->{tapeLength}) {
       for (my $ii = 1; $ii <= 50; $ii++) {
         push @{$self->{tape}}, "";
         push @{$self->{marks}}, "";
       }
       $self->{tapeLength} += 50;
     }
   }

   # Machine.decrement() is usually compiled inline

   # remove escape char, the char should be a string because it could be
   # a unicode grapheme cluster (diacritics etc) 
   sub unescapeChar {
     my ($self, $c) = @_;
     # dont unescape chars that are not escaped!
     my $countEscapes = 0;
     my $s = "";
     # let nextChar = ;
     return if length($self->{work}) == 0;

     for my $nextChar (split //, $self->{work}) {
       if ($nextChar eq $c && ($countEscapes % 2 == 1)) {
         # assuming that the escape char is only one char?
         # remove last escape char
         substr($s, -1) = "";
       }
       if ($nextChar eq $self->{escape}) {
         $countEscapes++;
       } else {
         $countEscapes = 0;
       }
       $s .= $nextChar;
     }
     $self->{work} = $s;
   }

   #  add escape character, dont escape chars that are already escaped!
   #  this seems not to work when escaping the escape char! which is 
   #  a substantial problem. I may have to use replace instead for the 
   #  escape char?
   #    modify this for grapheme clusters.
   #   
   sub escapeChar {
     my ($self, $c) = @_;
     my $countEscapes = 0;
     my $s = "";
     return if length($self->{work}) == 0;
     for my $nextChar (split //, $self->{work}) {
       if ($nextChar eq $c && ($countEscapes % 2 == 0)) {
         $s .= $self->{escape};
       }
       if ($nextChar eq $self->{escape}) {
         $countEscapes++;
       } else {
         $countEscapes = 0;
       }
       $s .= $nextChar;
     }
     $self->{work} = $s;
   }

   # # a helper to see how many trailing escape chars 
   sub countEscaped {
     my ($self, $suffix) = @_;
     my $s = $self->{work};
     my $count = 0;
     if (substr($s, -length($suffix)) eq $suffix) {
       $s = substr($s, 0, length($s) - length($suffix));
     }
     while (substr($s, -length($self->{escape})) eq $self->{escape}) {
       $count++;
       $s = substr($s, 0, length($s) - length($self->{escape}));
     }
     return $count;
   }

   #  reads the input stream until the work end with text. It is
   #    better to call this readUntil instead of until because some
   #       languages dont like keywords as methods. Same for read()
   #       should be readChar() 
   sub readUntil {
     my ($self, $suffix) = @_;
     # read at least one character
     return if $self->{eof};
     $self->readChar();
     while (true) {
       return if $self->{eof};
       if (substr($self->{work}, -length($suffix)) eq $suffix) {
         return if $self->countEscaped($suffix) % 2 == 0;
       }
       $self->readChar();
     }
   }

   # pop the first token from the stack into the workspace
   sub popToken {
     my $self = shift;   # a reference to the pep machine
     if (!@{$self->{stack}}) { return false; }
     $self->{work} = pop(@{$self->{stack}}) . $self->{work};
     if ($self->{cell} > 0) { $self->{cell} -= 1; }
     return true;
   }

   # push the first token from the workspace to the stack
   sub pushToken {
     my $self = shift;   # a reference to the pep machine
     # dont increment the tape pointer on an empty push
     if (length($self->{work}) == 0) { return false; }

     # I iterate the workspace buffer chars so that this method
     # can be easily adapted for grapheme clusters
     my $token = "";
     my $remainder = "";
     my @chars = split(//, $self->{work});

     # maybe for grapheme clusters
     # my @chars = split(/X/, $self->{work});
     for (my $ii = 0; $ii < scalar(@chars); $ii++) {
       my $c = $chars[$ii];
       $token .= $c;
       if ($c eq $self->{delimiter}) {
         push @{$self->{stack}}, $token;
         $remainder = join "", @chars[$ii+1 .. $#chars];
         $self->{work} = "";
         $self->{work} .= $remainder;
         $self->increment();
         return true;
       }
     }
     # push the whole workspace if there is no token delimiter
     push @{$self->{stack}}, $token;
     $self->{work} = "";
     $self->increment();
     return true;
   }

   # save the workspace to file "sav.pp"
   # we can put this inline?
   sub writeToFile {
     my ($self) = @_;
     my $filename = "sav.pp";
     open my $fh, ">:utf8", $filename or 
       die "Could not open file [$filename] for writing: $!";
     print $fh $self->{work};
     close $fh;
   }

   sub goToMark {
     my ($self, $mark) = @_;
     for (my $ii = 0; $ii < @{$self->{marks}}; $ii++) {
       # print("ii:", $ii, " mark:", $thismark,"\n");
       if ($self->{marks}[$ii] eq $mark) {
         $self->{cell} = $ii;
         return;
       }
     }
     print "badmark '$mark'!\n";
     exit 1;
   }

   # # remove existing marks with the same name and add new mark 
   sub addMark {
     my ($self, $newMark) = @_;
     # remove existing marks with the same name.
     for my $mark (@{$self->{marks}}) {
       if ($mark eq $newMark) {
         $mark = "";
       }
     }
     $self->{marks}[$self->{cell}] = $newMark;
   }

   # # check if the workspace matches given list class eg [hjk]
   #    or a range class eg [a-p]. The class string will be "[a-p]" ie
   #    with brackets [:alpha:] may have already been made into something else by the
   #    compiler.
   #    fix: for grapheme clusters and more complete classes
   #   
   sub matchClass {
     my ($self, $text, $class) = @_;
     # empty text should never match a class.
     return false if length($text) == 0;

     # a character type class like [:alpha:]
     # print("class: $class");
         
     if ($class =~ /^\[:(.+):\]$/ && $class ne "[:]" && $class ne "[::]") {
       my $charType = $1;
       my @chars = split //, $text;
       if ($charType eq "alnum") { return $text =~ /^\w+$/; }
       if ($charType eq "alpha") { return $text =~ /^[[:alpha:]]+$/; }
       if ($charType eq "ascii") { return $text =~ /^[[:ascii:]]+$/; }
       if ($charType eq "word") { return $text =~ /^[\w_]+$/; }
       if ($charType eq "blank") { return $text =~ /^[\s\t]+$/; }
       if ($charType eq "control") { return $text =~ /^[[:cntrl:]]+$/; }
       if ($charType eq "cntrl") { return $text =~ /^[[:cntrl:]]+$/; }
       if ($charType eq "digit") { return $text =~ /^\d+$/;}
       if ($charType eq "graph") { return $text =~ /^[[:graph:]]+$/; }
       if ($charType eq "lower") { return $text =~ /^[[:lower:]]+$/; }
       if ($charType eq "upper") { return $text =~ /^[[:upper:]]+$/; }
       if ($charType eq "print") { return $text =~ /^[[:print:]]+$/; 
         # and not eq " "
       }
       if ($charType eq "punct") { return $text =~ /^[[:punct:]]+$/; }
       if ($charType eq "space") { return $text =~ /^\s+$/; }
       if ($charType eq "xdigit") { return $text =~ /^[0-9a-fA-F]+$/; }
       print STDERR "unrecognised char class in translated nom script\n";
       print STDERR "$charType\n";
       exit 1;
       return false;
     }

     # get a vector of chars except the first and last which are [ and ]
     my @charList = split //, substr($class, 1, length($class)-2);
     # is a range class like [a-z]
     if (scalar(@charList) == 3 && $charList[1] eq "-") {
       my ($start, undef, $end) = @charList;
       my @chars = split(//, $text);
       #print("chars: @chars");
       #return all { $_ ge $start && $_ le $end } @chars;
       # modify split for grapheme clusters?
       for my $char (split //, $text) {
         if ($char lt $start || $char gt $end) { return false; }
       }
       return true;
     }

     # list class like: [xyzabc]
     # check if all characters in text are in the class list
     # my @textChars = split //, $text;

     # Create a hash for faster lookup?
     my %charHash = map { $_ => 1 } @charList; 
     for my $char (split //, $text) {
       return false unless exists $charHash{$char};
     }
     return true;

     #return all { grep { $_ eq $textChars[$_] } @charList } 0 .. $#textChars;
     #return false;
     # also must handle eg [:alpha:] This can be done with char methods
   }

   # # a plain text string replace function on the workspace 
   sub replace {
     my ($self, $old, $new) = @_;
     return if length($old) == 0;
     return if $old eq $new;
     $old = quotemeta($old);
     $self->{work} =~ s/$old/$new/g;
   }

   #  make the workspace capital case 
   sub capitalise {
     my ($self) = @_;
     my $result = "";
     my $capitalize_next = 1;
     for my $c (split //, $self->{work}) {
       if ($c =~ /[[:alpha:]]/) {
         if ($capitalize_next) {
           $result .= uc $c;
           $capitalize_next = false;
         } else {
           $result .= lc $c;
         }
       } else {
         $result .= $c;
         if ($c eq "\n" || $c eq " " || $c eq "." || $c eq "?" || $c eq "!") {
           $capitalize_next = true;
         }
       }
     }
     $self->{work} = $result;
   }

   #  print the internal state of the pep/nom parsing machine. This
   #    is handy for debugging 
   sub printState {
     my $self = shift;
     print 
       "\n--------- Machine State ------------- \n",
       "(input buffer:", join(",", @{$self->{inputBuffer}}), ")\n",
       "Stack[", join(",", @{$self->{stack}}), "]", 
       " Work[", $self->{work}, "]",
       " Peep[", $self->{peep}, "]\n",
       "Acc:", $self->{accumulator},
       " EOF:", $self->{eof} eq true? "true":"false", 
       " Esc:", $self->{escape},
       " Delim:", $self->{delimiter}, 
       " Chars:", $self->{charsRead}, " ";
     print "Lines:", $self->{linesRead}, "\n";
     print "-------------- Tape ----------------- \n";
     print "Tape Size: ", $self->{tapeLength}, "\n";
     my $start = 0;
     if ($self->{cell} > 3) {
       $start = $self->{cell} - 4;
     }
     my $end = $self->{cell} + 4;
     for (my $ii = $start; $ii <= $end; $ii++) {
       print "    $ii ";
       if ($ii == $self->{cell}) { print "> ["; }
       else { print "  ["; }
       if (defined $self->{tape}[$ii]) {
         print $self->{tape}[$ii], "] (m:", $self->{marks}[$ii], ")\n";
       } else {
         print "]\n";
       }
     }
   }

   # # makes the machine read from a string also needs to prime
   #    the "peep" value. 
   sub setStringInput {
     my ($self, $text) = @_;
     $self->{inputType} = "string";
     $self->{inputBuffer} = [];
     $self->fillInputBuffer($text);
     # prime the "peep" with the 1st char
     $self->{peep} = ""; $self->readChar(); $self->{charsRead} = 0;
   }

   # # makes the machine write to a string 
   sub setStringOutput {
     my ($self) = @_;
     $self->{sinkType} = "string";
   }

   # # parse/translate from a string and return the translated
   #    string 
   sub parseString {
     my ($self, $input) = @_;
     $self->setStringInput($input);
     $self->{sinkType} = "string";
     $self->parse();
     return $self->{outputBuffer};
   }

   # # makes the machine read from a file stream line by line,
   #    not from stdin 
   sub setFileStreamInput {
     my ($self, $filename) = @_;
     unless (checkTextFile($filename)) { exit 1; }
     open my $fh, "<:utf8", $filename or 
       die "Cannot open file [$filename] for reading: $!";
     $self->{input} = IO::BufReader->new($fh);
     $self->{inputType} = "filestream";
     # prime the peep, the read() method should refill the
     # inputChars or inputBuffer if it is empty.
     $self->{peep} = ""; $self->readChar(); $self->{charsRead} = 0;
   }

   # # makes the machine read from a file line buffer array
   #    but this also needs to prime the "peep" value 
   sub setFileInput {
     my ($self, $filename) = @_;
     open my $fh, "<:utf8", $filename or 
       die "Could not open file [$filename] for reading: $!";
     my $text = do { local $/ = undef; <$fh> };
     close $fh;
     # there is an extra newline being added, I dont know where.
     if ($text =~ s/\n$//) {}
     $self->{inputType} = "file";
     $self->{inputBuffer} = [];
     $self->fillInputBuffer($text);
     # prime the "peep" with the 1st char
     $self->{peep} = ""; $self->readChar(); $self->{charsRead} = 0;
   }

   # # makes the machine write to a file not to stdout (the default) 
   sub setFileOutput {
     my ($self, $filename) = @_;
     unless (checkTextFile($filename)) { exit 1; }
     open my $fh, ">:utf8", $filename or 
       die "Cannot create file [$filename] for writing: $!";
     $self->{output} = IO::BufWriter->new($fh);
     $self->{sinkType} = "file";
   }

   # parse from a file and put result in file
   sub parseFile {
     my ($self, $inputFile, $outputFile) = @_;
     $self->setFileInput($inputFile);
     $self->setFileOutput($outputFile);
     $self->parse();
   }

   # # parse from any stream, fix handle 
   # #
   # sub parseStream {
   #   my ($self, $reader) = @_;
   #   # $self->{input} = $reader; # Needs proper handling of reader type
   #   $self->parse();
   # }
   # 

   # # this is the default parsing mode. If no other is selected
   #    it will be activated when parse() is first called. I activate it when
   #    parse is 1st called because otherwise it will block if no stdin
   #    is availabel. It also sets stdout as output 
   sub setStandardInput {
     my $self = shift;
     $self->{inputType} = "stdin";
     $self->{sinkType} = "stdout";
     # for printing wide characters
     binmode STDOUT, ":encoding(UTF-8)";
     # binmode STDERR, ":encoding(UTF-8)";

     # $self->{input} = *STDIN;
     # $self->{output} = *STDOUT;

     # read the whole of stdin into the inputBuffer
     $self->{inputBuffer} = [];
     my $buffer = "";
     #  my $stdin = join("", <STDIN>);
     while (<STDIN>) { $buffer .= $_; }
     
     # print("buffer: [$buffer]\n");
     $self->fillInputBuffer($buffer);
     # prime the "peep" with the 1st char, but this doesnt count as
     # a character read.
     $self->{peep} = ""; $self->readChar(); $self->{charsRead} = 0;
   }


   # This function performs all sorts of magic and shenanigans. 
   # Creates a new method runScript() and evaluates it, 
   # thus acting as an interpreter of a scriptfile given to an
   # -f switch. This method only works when the nom to perl translator has 
   # been run on itself with:
   #   >> pep -f translate.perl.pss translate.perl.pss > interp.perl.pl
   #   >> echo "read; print; print; clear; " > test.pss
   #   >> chmod a+x interp.perl.pl
   #   >> echo buzz | ./interp.perl.pl -f test.pss
   #   >> (output should be "bbuuzz")
   # Only those who have achieved
   # true enlightenment will understand this method.
   sub interpret {
     my $self = shift;          # the parse machine 
     my $filename = "";
     # fix using get opts
     if ($ARGV[0] eq "-f") { $filename = $ARGV[1]; }
     if ($ARGV[0] =~ /^-f/) { 
       $filename = $ARGV[1]; $filename =~ s/^..//;
     }
     if ((!defined $filename) || ($filename eq "")) { return; }
     my $method = $self->parseFile($filename);
     # remove everything except the parse method and rename
     # the method so that it doesnt clash with the existing parse
     # method
     $method =~ s/^.*sub parse \{/sub runScript \{/s;
     # to debug
     # print $method; return;
     # add this new method to the current class via evaluation
     eval($method);
     # execute the new method, thus interpreting the script-file 
     # that was provide
     $self->runScript(*STDIN, *STDOUT);
   }

   # parse and translate the input stdin/file/string 
   sub parse {
     my $self = shift;
     # some temporary variables
     my $text = ""; my $mark = "";

     if ($self->{inputType} eq "unset") {
       $self->setStandardInput();
     }
    
     # -----------
     # translated nom code inserted below
     # -----------
     
      SCRIPT:
      while (true) {
        LEX: { 
          if ($self->{eof}) { last SCRIPT; } $self->readChar(); # read 
          if ($self->matchClass($self->{work}, "[\n]")) {
            $self->{charsRead} = 0; # nochars 
          }
          if ($self->matchClass($self->{work}, "[:space:]")) {
            $self->{work} = '';  # clear 
            if ($self->{eof}) {
              last LEX;
            }
            if (!($self->{eof})) {
              next SCRIPT;
            }
          }
          if ($self->matchClass($self->{work}, "[<>}()!BE,.;]")) {
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} .= "*"; # add 
            $self->pushToken();
            last LEX;
          }
          if ($self->matchClass($self->{work}, "[{]")) {
            $self->{work} = '';  # clear 
            $self->{work} .= "line:"; # add 
            $self->{work} .= $self->{linesRead}; # lines 
            $self->{work} .= " char:"; # add 
            $self->{work} .= $self->{charsRead}; # chars 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "{*"; # add 
            $self->pushToken();
            last LEX;
          }
          if (($self->matchClass($self->{work}, "[:alpha:]")) || ($self->matchClass($self->{work}, "[-+^0=]"))) {
            if ($self->{work} eq "0") {
              $self->{work} = '';  # clear 
              $self->{work} .= "zero"; # add 
            }
            if ($self->{work} eq "^") {
              $self->{work} = '';  # clear 
              $self->{work} .= "escape"; # add 
            }
            if ($self->{work} eq "+") {
              # while 
              while ($self->matchClass($self->{peep}, "[+]")) {
                if ($self->{eof}) { last; } $self->readChar();
              }
            }
            if ($self->{work} eq "-") {
              # while 
              while ($self->matchClass($self->{peep}, "[-]")) {
                if ($self->{eof}) { last; } $self->readChar();
              }
            }
            if ($self->{work} eq "=") {
              # while 
              while ($self->matchClass($self->{peep}, "[=]")) {
                if ($self->{eof}) { last; } $self->readChar();
              }
            }
            if ((!($self->{work} eq "zero")) && (!($self->{work} eq "escape")) && (!(substr($self->{work}, 0, length("+")) eq "+")) && (!(substr($self->{work}, 0, length("-")) eq "-")) && (!(substr($self->{work}, 0, length("=")) eq "="))) {
              # while 
              while ($self->matchClass($self->{peep}, "[:alpha:]")) {
                if ($self->{eof}) { last; } $self->readChar();
              }
            }
            if ($self->{work} eq "a") {
              # while 
              while ($self->matchClass($self->{peep}, "[-+]")) {
                if ($self->{eof}) { last; } $self->readChar();
              }
              if (($self->{work} eq "a+") || ($self->{work} eq "a-")) {
                ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              }
              if ($self->{work} eq "a") {
                $self->{work} = '';  # clear 
                $self->{work} .= "add"; # add 
              }
            }
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "#"; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "#"; # add 
            $self->replace("#k#", "#clip#");  # replace 
            $self->replace("#K#", "#clop#");  # replace 
            $self->replace("#D#", "#replace#");  # replace 
            $self->replace("#d#", "#clear#");  # replace 
            $self->replace("#t#", "#print#");  # replace 
            $self->replace("#p#", "#pop#");  # replace 
            $self->replace("#P#", "#push#");  # replace 
            $self->replace("#u#", "#unstack#");  # replace 
            $self->replace("#U#", "#stack#");  # replace 
            $self->replace("#G#", "#put#");  # replace 
            $self->replace("#g#", "#get#");  # replace 
            $self->replace("#x#", "#swap#");  # replace 
            $self->replace("#m#", "#mark#");  # replace 
            $self->replace("#M#", "#go#");  # replace 
            $self->replace("#r#", "#read#");  # replace 
            $self->replace("#R#", "#until#");  # replace 
            $self->replace("#w#", "#while#");  # replace 
            $self->replace("#W#", "#whilenot#");  # replace 
            $self->replace("#n#", "#count#");  # replace 
            $self->replace("#c#", "#chars#");  # replace 
            $self->replace("#C#", "#nochars#");  # replace 
            $self->replace("#l#", "#lines#");  # replace 
            $self->replace("#L#", "#nolines#");  # replace 
            $self->replace("#v#", "#unescape#");  # replace 
            $self->replace("#z#", "#delim#");  # replace 
            $self->replace("#S#", "#state#");  # replace 
            $self->replace("#q#", "#quit#");  # replace 
            $self->replace("#s#", "#write#");  # replace 
            $self->replace("#o#", "#nop#");  # replace 
            $self->replace("#rs#", "#restart#");  # replace 
            $self->replace("#rp#", "#reparse#");  # replace 
            $self->{work} =~ s/\X$//; # clip
            $self->{work} =~ s/^\X//; # clop
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            if (($self->{work} eq "ll") || ($self->{work} eq "cc")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* The syntax \""; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "\" for lines or chars"; # add 
              $self->{work} .= "  is no longer valid.\\n"; # add 
              $self->{work} .= "  use 'chars' or 'c' for a character count \\n"; # add 
              $self->{work} .= "  use 'lines' or 'l' for a line count \\n"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              last LEX;
            }
            if (($self->{work} eq "+") || ($self->{work} eq "-")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* This syntax \""; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "\" which were 1 letter abbreviations\\n"; # add 
              $self->{work} .= "  are no longer valid because.\\n"; # add 
              $self->{work} .= "  it is silly to have 1 letter abbrevs for 2 letter commands."; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              last LEX;
            }
            if (($self->{work} eq "a+") || ($self->{work} eq "a-") || ($self->{work} eq "zero") || ($self->{work} eq "++") || ($self->{work} eq "--") || ($self->{work} eq "add") || ($self->{work} eq "clip") || ($self->{work} eq "clop") || ($self->{work} eq "replace") || ($self->{work} eq "upper") || ($self->{work} eq "lower") || ($self->{work} eq "cap") || ($self->{work} eq "clear") || ($self->{work} eq "print") || ($self->{work} eq "state") || ($self->{work} eq "pop") || ($self->{work} eq "push") || ($self->{work} eq "unstack") || ($self->{work} eq "stack") || ($self->{work} eq "put") || ($self->{work} eq "get") || ($self->{work} eq "swap") || ($self->{work} eq "mark") || ($self->{work} eq "go") || ($self->{work} eq "read") || ($self->{work} eq "until") || ($self->{work} eq "while") || ($self->{work} eq "whilenot") || ($self->{work} eq "count") || ($self->{work} eq "zero") || ($self->{work} eq "chars") || ($self->{work} eq "lines") || ($self->{work} eq "nochars") || ($self->{work} eq "nolines") || ($self->{work} eq "escape") || ($self->{work} eq "unescape") || ($self->{work} eq "echar") || ($self->{work} eq "delim") || ($self->{work} eq "quit") || ($self->{work} eq "write") || ($self->{work} eq "nop")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "command*"; # add 
              $self->pushToken();
              last LEX;
            }
            if (($self->{work} eq "parse") || ($self->{work} eq "reparse") || ($self->{work} eq "restart") || ($self->{work} eq "eof") || ($self->{work} eq "EOF") || ($self->{work} eq "==")) {
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "word*"; # add 
              $self->pushToken();
              last LEX;
            }
            if ($self->{work} eq "begin") {
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} .= "*"; # add 
              $self->pushToken();
              last LEX;
            }
            $self->{work} = lc($self->{work});  # lower
            if (($self->{work} eq "add") || ($self->{work} eq "clip") || ($self->{work} eq "clop") || ($self->{work} eq "replace") || ($self->{work} eq "upper") || ($self->{work} eq "lower") || ($self->{work} eq "cap") || ($self->{work} eq "clear") || ($self->{work} eq "print") || ($self->{work} eq "state") || ($self->{work} eq "pop") || ($self->{work} eq "push") || ($self->{work} eq "unstack") || ($self->{work} eq "stack") || ($self->{work} eq "put") || ($self->{work} eq "get") || ($self->{work} eq "swap") || ($self->{work} eq "mark") || ($self->{work} eq "go") || ($self->{work} eq "read") || ($self->{work} eq "until") || ($self->{work} eq "while") || ($self->{work} eq "whilenot") || ($self->{work} eq "count") || ($self->{work} eq "zero") || ($self->{work} eq "chars") || ($self->{work} eq "lines") || ($self->{work} eq "nochars") || ($self->{work} eq "nolines") || ($self->{work} eq "escape") || ($self->{work} eq "unescape") || ($self->{work} eq "echar") || ($self->{work} eq "delim") || ($self->{work} eq "quit") || ($self->{work} eq "write") || ($self->{work} eq "zero") || ($self->{work} eq "++") || ($self->{work} eq "--") || ($self->{work} eq "a+") || ($self->{work} eq "a-") || ($self->{work} eq "nop") || ($self->{work} eq "begin") || ($self->{work} eq "parse") || ($self->{work} eq "reparse") || ($self->{work} eq "restart")) {
              $self->increment();   # ++ 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} = '';  # clear 
              $self->{work} .= "* incorrect command \""; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "\"\\n"; # add 
              $self->{work} .= "- all nom commands and words are lower case \\n"; # add 
              $self->{work} .= "  (except for EOF and abbreviations) \\n"; # add 
              $self->{work} .= "- did you mean '"; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} .= "'?"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              last LEX;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "* unknown word or command \""; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "\""; # add 
            $self->{work} .= "";
            $self->{work} .= "\n";
            $self->{work} .= "\n    - Valid nom commands are: ";
            $self->{work} .= "\n";
            $self->{work} .= "\n    add clip clop replace upper lower cap clear ";
            $self->{work} .= "\n    print state pop push unstack stack put get swap ";
            $self->{work} .= "\n    mark go read until while whilenot ";
            $self->{work} .= "\n    count zero chars lines nochars nolines ";
            $self->{work} .= "\n    escape unescape delim quit write (writefile ?) ";
            $self->{work} .= "\n    zero ++ -- a+ a- nop ";
            $self->{work} .= "\n    ";
            $self->{work} .= "\n    - Valid nom words are ";
            $self->{work} .= "\n";
            $self->{work} .= "\n    parse reparse restart begin eof EOF == ";
            $self->{work} .= "\n";
            $self->{work} .= "\n    see www.nomlang.org/doc/commands/ \\n"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            last LEX;
          }
          if ($self->{work} eq "#") {
            if ($self->{eof}) {
              $self->{work} = '';  # clear 
              last LEX;
            }
            if ($self->{eof}) { last SCRIPT; } $self->readChar(); # read 
            if ($self->matchClass($self->{work}, "[#\n]")) {
              $self->{work} = '';  # clear 
              last LEX;
            }
            if ($self->{work} eq "#*") {
              $self->{work} = '';  # clear 
              $self->{work} .= "line:"; # add 
              $self->{work} .= $self->{linesRead}; # lines 
              $self->{work} .= " char:"; # add 
              $self->{work} .= $self->{charsRead}; # chars 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->readUntil("*#");
              if (!((length("*#") <= length($self->{work})) && (substr($self->{work}, -length("*#")) eq "*#"))) {
                $self->{work} = '';  # clear 
                $self->{work} .= "* unterminated multiline comment #*... \\n  starting at "; # add 
                $self->{work} .= $self->{tape}[$self->{cell}];  # get
                ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
                $self->{work} = '';  # clear 
                $self->{work} .= "nom.error*"; # add 
                $self->pushToken();
                last LEX;
              }
              $self->{work} =~ s/\X$//; # clip
              $self->{work} =~ s/\X$//; # clip
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "comment*"; # add 
              $self->pushToken();
              last LEX;
            }
            $self->{work} = '';  # clear 
            # whilenot   
            while (!$self->matchClass($self->{peep}, "[\n]")) {
              if ($self->{eof}) { last; } $self->readChar();
            }
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "comment*"; # add 
            $self->pushToken();
            last LEX;
          }
          if ($self->{work} eq "\"") {
            $self->{work} = '';  # clear 
            $self->{work} .= "line:"; # add 
            $self->{work} .= $self->{linesRead}; # lines 
            $self->{work} .= " char:"; # add 
            $self->{work} .= $self->{charsRead}; # chars 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->readUntil("\"");
            if ((!((length("\"") <= length($self->{work})) && (substr($self->{work}, -length("\"")) eq "\""))) || ($self->{eof})) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* unterminated quote (\") or incomplete command starting at "; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              last LEX;
            }
            $self->{work} =~ s/\X$//; # clip
            $self->unescapeChar('"');
            $self->replace("\\\\", "\\\\\\\\");  # replace 
            $self->escapeChar('\$');
            $self->escapeChar('\@');
            $self->escapeChar('"');
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "\""; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "\""; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "quoted*"; # add 
            $self->pushToken();
            last LEX;
          }
          if ($self->{work} eq "'") {
            $self->{work} = '';  # clear 
            $self->{work} .= "line:"; # add 
            $self->{work} .= $self->{linesRead}; # lines 
            $self->{work} .= " char:"; # add 
            $self->{work} .= $self->{charsRead}; # chars 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->readUntil("'");
            if ((!((length("'") <= length($self->{work})) && (substr($self->{work}, -length("'")) eq "'"))) || ($self->{eof})) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* unterminated quote (') or incomplete command starting at "; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              last LEX;
            }
            $self->{work} =~ s/\X$//; # clip
            $self->unescapeChar('\'');
            $self->unescapeChar('"');
            $self->replace("\\\\", "\\\\\\\\");  # replace 
            $self->escapeChar('\$');
            $self->escapeChar('\@');
            $self->escapeChar('"');
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "\""; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "\""; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "quoted*"; # add 
            $self->pushToken();
            last LEX;
          }
          if ($self->{work} eq "[") {
            $self->{work} = '';  # clear 
            $self->{work} .= "line:"; # add 
            $self->{work} .= $self->{linesRead}; # lines 
            $self->{work} .= " char:"; # add 
            $self->{work} .= $self->{charsRead}; # chars 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->readUntil("]");
            if ((!((length("]") <= length($self->{work})) && (substr($self->{work}, -length("]")) eq "]"))) || ($self->{eof})) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* unterminated class [...] or incomplete command starting at "; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              last LEX;
            }
            $self->{work} =~ s/\X$//; # clip
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            if ((substr($self->{work}, 0, length(":")) eq ":") && ((length(":") <= length($self->{work})) && (substr($self->{work}, -length(":")) eq ":")) && (!($self->{work} eq ":")) && (!($self->{work} eq "::"))) {
              $self->{work} =~ s/\X$//; # clip
              $self->{work} =~ s/^\X//; # clop
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              if (($self->{work} eq "alnum") || ($self->{work} eq "alpha") || ($self->{work} eq "ascii") || ($self->{work} eq "word") || ($self->{work} eq "blank") || ($self->{work} eq "cntrl") || ($self->{work} eq "digit") || ($self->{work} eq "graph") || ($self->{work} eq "lower") || ($self->{work} eq "print") || ($self->{work} eq "punct") || ($self->{work} eq "space") || ($self->{work} eq "upper") || ($self->{work} eq "xdigit")) {
                $self->{work} = '';  # clear 
                $self->{work} .= "[:"; # add 
                $self->{work} .= $self->{tape}[$self->{cell}];  # get
                $self->{work} .= ":]"; # add 
                ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
                $self->{work} = '';  # clear 
                $self->{work} .= "class*"; # add 
                $self->pushToken();
                last LEX;
              }
              $self->replace(" ", "_");  # replace 
              $self->replace(".", "_");  # replace 
              if (($self->{work} eq "L") || ($self->{work} eq "Letter") || ($self->{work} eq "Ll") || ($self->{work} eq "Lowercase_Letter") || ($self->{work} eq "Lu") || ($self->{work} eq "Uppercase_Letter") || ($self->{work} eq "Lt") || ($self->{work} eq "Titlecase_Letter") || ($self->{work} eq "L&") || ($self->{work} eq "Cased_Letter") || ($self->{work} eq "Lm") || ($self->{work} eq "Modifier_Letter") || ($self->{work} eq "Lo") || ($self->{work} eq "Other_Letter") || ($self->{work} eq "M") || ($self->{work} eq "Mark") || ($self->{work} eq "Mn") || ($self->{work} eq "Non_Spacing_Mark") || ($self->{work} eq "Mc") || ($self->{work} eq "Spacing_Combining_Mark") || ($self->{work} eq "Me") || ($self->{work} eq "Enclosing_Mark") || ($self->{work} eq "Z") || ($self->{work} eq "Separator") || ($self->{work} eq "Zs") || ($self->{work} eq "Space_Separator") || ($self->{work} eq "Zl") || ($self->{work} eq "Line_Separator") || ($self->{work} eq "Zp") || ($self->{work} eq "Paragraph_Separator") || ($self->{work} eq "S") || ($self->{work} eq "Symbol") || ($self->{work} eq "Sm") || ($self->{work} eq "Math_Symbol") || ($self->{work} eq "Sc") || ($self->{work} eq "Currency_Symbol") || ($self->{work} eq "Sk") || ($self->{work} eq "Modifier_Symbol") || ($self->{work} eq "So") || ($self->{work} eq "Other_Symbol") || ($self->{work} eq "N") || ($self->{work} eq "Number") || ($self->{work} eq "Nd") || ($self->{work} eq "Decimal_Digit_Number") || ($self->{work} eq "Nl") || ($self->{work} eq "Letter_Number") || ($self->{work} eq "No") || ($self->{work} eq "Other_Number") || ($self->{work} eq "P") || ($self->{work} eq "Punctuation") || ($self->{work} eq "Pd") || ($self->{work} eq "Dash_Punctuation") || ($self->{work} eq "Ps") || ($self->{work} eq "Open_Punctuation") || ($self->{work} eq "Pe") || ($self->{work} eq "Close_Punctuation") || ($self->{work} eq "Pi") || ($self->{work} eq "Initial_Punctuation") || ($self->{work} eq "Pf") || ($self->{work} eq "Final_Punctuation") || ($self->{work} eq "Pc") || ($self->{work} eq "Connector_Punctuation") || ($self->{work} eq "Po") || ($self->{work} eq "Other_Punctuation") || ($self->{work} eq "C") || ($self->{work} eq "Other") || ($self->{work} eq "Cc") || ($self->{work} eq "Control") || ($self->{work} eq "Cf") || ($self->{work} eq "Format") || ($self->{work} eq "Co") || ($self->{work} eq "Private_Use") || ($self->{work} eq "Cs") || ($self->{work} eq "Surrogate") || ($self->{work} eq "Cn") || ($self->{work} eq "Unassigned")) {
                $self->{work} .= ":";
                $self->{work} .= "\n         This nom->perl translator does not currently support unicode character ";
                $self->{work} .= "\n         category names in nom classes. You could try the nom->dart";
                $self->{work} .= "\n         translator if you really need them:";
                $self->{work} .= "\n           nomlang.org/tr/nom.todart.pss \\n"; # add 
                ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
                $self->{work} = '';  # clear 
                $self->{work} .= "nom.error*"; # add 
                $self->pushToken();
                last LEX;
              }
              if (($self->{work} eq "Common") || ($self->{work} eq "Arabic") || ($self->{work} eq "Armenian") || ($self->{work} eq "Bengali") || ($self->{work} eq "Bopomofo") || ($self->{work} eq "Braille") || ($self->{work} eq "Buhid") || ($self->{work} eq "Canadian_Aboriginal") || ($self->{work} eq "Cherokee") || ($self->{work} eq "Cyrillic") || ($self->{work} eq "Devanagari") || ($self->{work} eq "Ethiopic") || ($self->{work} eq "Georgian") || ($self->{work} eq "Greek") || ($self->{work} eq "Gujarati") || ($self->{work} eq "Gurmukhi") || ($self->{work} eq "Han") || ($self->{work} eq "Hangul") || ($self->{work} eq "Hanunoo") || ($self->{work} eq "Hebrew") || ($self->{work} eq "Hiragana") || ($self->{work} eq "Inherited") || ($self->{work} eq "Kannada") || ($self->{work} eq "Katakana") || ($self->{work} eq "Khmer") || ($self->{work} eq "Lao") || ($self->{work} eq "Latin") || ($self->{work} eq "Limbu") || ($self->{work} eq "Malayalam") || ($self->{work} eq "Mongolian") || ($self->{work} eq "Myanmar") || ($self->{work} eq "Ogham") || ($self->{work} eq "Oriya") || ($self->{work} eq "Runic") || ($self->{work} eq "Sinhala") || ($self->{work} eq "Syriac") || ($self->{work} eq "Tagalog") || ($self->{work} eq "Tagbanwa") || ($self->{work} eq "TaiLe") || ($self->{work} eq "Tamil") || ($self->{work} eq "Telugu") || ($self->{work} eq "Thaana") || ($self->{work} eq "Thai") || ($self->{work} eq "Tibetan") || ($self->{work} eq "Yi")) {
                $self->{work} .= ":";
                $self->{work} .= "\n         This nom->perl translator does not currently support unicode script ";
                $self->{work} .= "\n         names in nom classes. You could try the nom->dart";
                $self->{work} .= "\n         translator if you really need them:";
                $self->{work} .= "\n           nomlang.org/tr/nom.todart.pss \\n"; # add 
                ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
                $self->{work} = '';  # clear 
                $self->{work} .= "nom.error*"; # add 
                $self->pushToken();
                last LEX;
              }
              if (($self->{work} eq "InBasic_Latin") || ($self->{work} eq "InLatin-1_Supplement") || ($self->{work} eq "InLatin_Extended-A") || ($self->{work} eq "InLatin_Extended-B") || ($self->{work} eq "InIPA_Extensions") || ($self->{work} eq "InSpacing_Modifier_Letters") || ($self->{work} eq "InCombining_Diacritical_Marks") || ($self->{work} eq "InGreek_and_Coptic") || ($self->{work} eq "InCyrillic") || ($self->{work} eq "InCyrillic_Supplementary") || ($self->{work} eq "InArmenian") || ($self->{work} eq "InHebrew") || ($self->{work} eq "InArabic") || ($self->{work} eq "InSyriac") || ($self->{work} eq "InThaana") || ($self->{work} eq "InDevanagari") || ($self->{work} eq "InBengali") || ($self->{work} eq "InGurmukhi") || ($self->{work} eq "InGujarati") || ($self->{work} eq "InOriya") || ($self->{work} eq "InTamil") || ($self->{work} eq "InTelugu") || ($self->{work} eq "InKannada") || ($self->{work} eq "InMalayalam") || ($self->{work} eq "InSinhala") || ($self->{work} eq "InThai") || ($self->{work} eq "InLao") || ($self->{work} eq "InTibetan") || ($self->{work} eq "InMyanmar") || ($self->{work} eq "InGeorgian") || ($self->{work} eq "InHangul_Jamo") || ($self->{work} eq "InEthiopic") || ($self->{work} eq "InCherokee") || ($self->{work} eq "InUnified_Canadian_Aboriginal_Syllabics") || ($self->{work} eq "InOgham") || ($self->{work} eq "InRunic") || ($self->{work} eq "InTagalog") || ($self->{work} eq "InHanunoo") || ($self->{work} eq "InBuhid") || ($self->{work} eq "InTagbanwa") || ($self->{work} eq "InKhmer") || ($self->{work} eq "InMongolian") || ($self->{work} eq "InLimbu") || ($self->{work} eq "InTai_Le") || ($self->{work} eq "InKhmer_Symbols") || ($self->{work} eq "InPhonetic_Extensions") || ($self->{work} eq "InLatin_Extended_Additional") || ($self->{work} eq "InGreek_Extended") || ($self->{work} eq "InGeneral_Punctuation") || ($self->{work} eq "InSuperscripts_and_Subscripts") || ($self->{work} eq "InCurrency_Symbols") || ($self->{work} eq "InCombining_Diacritical_Marks_for_Symbols") || ($self->{work} eq "InLetterlike_Symbols") || ($self->{work} eq "InNumber_Forms") || ($self->{work} eq "InArrows") || ($self->{work} eq "InMathematical_Operators") || ($self->{work} eq "InMiscellaneous_Technical") || ($self->{work} eq "InControl_Pictures") || ($self->{work} eq "InOptical_Character_Recognition") || ($self->{work} eq "InEnclosed_Alphanumerics") || ($self->{work} eq "InBox_Drawing") || ($self->{work} eq "InBlock_Elements") || ($self->{work} eq "InGeometric_Shapes") || ($self->{work} eq "InMiscellaneous_Symbols") || ($self->{work} eq "InDingbats") || ($self->{work} eq "InMiscellaneous_Mathematical_Symbols-A") || ($self->{work} eq "InSupplemental_Arrows-A") || ($self->{work} eq "InBraille_Patterns") || ($self->{work} eq "InSupplemental_Arrows-B") || ($self->{work} eq "InMiscellaneous_Mathematical_Symbols-B") || ($self->{work} eq "InSupplemental_Mathematical_Operators") || ($self->{work} eq "InMiscellaneous_Symbols_and_Arrows") || ($self->{work} eq "InCJK_Radicals_Supplement") || ($self->{work} eq "InKangxi_Radicals") || ($self->{work} eq "InIdeographic_Description_Characters") || ($self->{work} eq "InCJK_Symbols_and_Punctuation") || ($self->{work} eq "InHiragana") || ($self->{work} eq "InKatakana") || ($self->{work} eq "InBopomofo") || ($self->{work} eq "InHangul_Compatibility_Jamo") || ($self->{work} eq "InKanbun") || ($self->{work} eq "InBopomofo_Extended") || ($self->{work} eq "InKatakana_Phonetic_Extensions") || ($self->{work} eq "InEnclosed_CJK_Letters_and_Months") || ($self->{work} eq "InCJK_Compatibility") || ($self->{work} eq "InCJK_Unified_Ideographs_Extension_A") || ($self->{work} eq "InYijing_Hexagram_Symbols") || ($self->{work} eq "InCJK_Unified_Ideographs") || ($self->{work} eq "InYi_Syllables") || ($self->{work} eq "InYi_Radicals") || ($self->{work} eq "InHangul_Syllables") || ($self->{work} eq "InHigh_Surrogates") || ($self->{work} eq "InHigh_Private_Use_Surrogates") || ($self->{work} eq "InLow_Surrogates") || ($self->{work} eq "InPrivate_Use_Area") || ($self->{work} eq "InCJK_Compatibility_Ideographs") || ($self->{work} eq "InAlphabetic_Presentation_Forms") || ($self->{work} eq "InArabic_Presentation_Forms-A") || ($self->{work} eq "InVariation_Selectors") || ($self->{work} eq "InCombining_Half_Marks") || ($self->{work} eq "InCJK_Compatibility_Forms") || ($self->{work} eq "InSmall_Form_Variants") || ($self->{work} eq "InArabic_Presentation_Forms-B") || ($self->{work} eq "InHalfwidth_and_Fullwidth_Forms") || ($self->{work} eq "InSpecials")) {
                $self->{work} .= ":";
                $self->{work} .= "\n           This nom->perl translator does not currently support unicode block ";
                $self->{work} .= "\n           names in nom class patterns. "; # add 
                ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
                $self->{work} = '';  # clear 
                $self->{work} .= "nom.error*"; # add 
                $self->pushToken();
                last LEX;
              }
              $self->{work} = '';  # clear 
              $self->{work} .= "* Incorrect nom character class\\n"; # add 
              $self->{work} .= " ";
              $self->{work} .= "\n      Character classes are used in tests and the nom while ";
              $self->{work} .= "\n      and whilenot commands";
              $self->{work} .= "\n        eg: [:space:] { while [:space:]; clear; } ";
              $self->{work} .= "\n        or: [:alnum:] { while [:alnum:]; clear; } \\n"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              last LEX;
            }
            $self->escapeChar('"');
            $self->unescapeChar(']');
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "["; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "]"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "class*"; # add 
            $self->pushToken();
            last LEX;
          }
          if (!($self->{work} eq "")) {
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "* strange character found '"; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "'\\n\\n"; # add 
            $self->{work} .= "  see www.nomlang.org/doc/syntax for nom syntax documentation \\n"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            last LEX;
          }
        } # lex block 
        PARSE: 
          while (true) { 
          $self->popToken();
          if ($self->{work} eq "nom.help*") {
            $self->{work} = '';  # clear 
            ($self->{tape}[$self->{cell}], $self->{work}) = ($self->{work}, $self->{tape}[$self->{cell}]);  # swap
            if (($self->{work} eq "commands.shortlist") || ($self->{work} eq "commands") || ($self->{work} eq "all")) {
              ($self->{tape}[$self->{cell}], $self->{work}) = ($self->{work}, $self->{tape}[$self->{cell}]);  # swap
              $self->{work} .= "";
              $self->{work} .= "\n      # 'D' doesn't actually work in compile.pss !";
              $self->{work} .= "\n      nom abbreviations and commands: ";
              $self->{work} .= "\n";
              $self->{work} .= "\n        zero k clip K clop D replace d clear";
              $self->{work} .= "\n        t print p pop P push u unstack U stack G put g get x swap";
              $self->{work} .= "\n        m mark M go r read R until w while W whilenot n count c chars C nochars ";
              $self->{work} .= "\n        l lines L nolines v escape unescape z delim S state q quit s write";
              $self->{work} .= "\n        o nop .rs .restart .rp .reparse";
              $self->{work} .= "\n        (no abbreviations)";
              $self->{work} .= "\n        a+ a- ++ --";
              $self->{work} .= "\n";
              $self->{work} .= "\n          "; # add 
            }
            if (($self->{work} eq "command.add") || ($self->{work} eq "commands") || ($self->{work} eq "all")) {
              ($self->{tape}[$self->{cell}], $self->{work}) = ($self->{work}, $self->{tape}[$self->{cell}]);  # swap
              $self->{work} .= "";
              $self->{work} .= "\n      add command:";
              $self->{work} .= "\n        add text to end of the workspace buffer";
              $self->{work} .= "\n        see: nomlang.org/doc/commands/nom.add.html";
              $self->{work} .= "\n      eg:";
              $self->{work} .= "\n        add ':tag:';     # correct";
              $self->{work} .= "\n        add [:space:];   # incorrect, cannot have class parameter ";
              $self->{work} .= "\n        add;             # incorrect, missing parameter";
              $self->{work} .= "\n          "; # add 
            }
            if (($self->{work} eq "semicolon") || ($self->{work} eq "punctuation") || ($self->{work} eq "all")) {
              ($self->{tape}[$self->{cell}], $self->{work}) = ($self->{work}, $self->{tape}[$self->{cell}]);  # swap
              $self->{work} .= "";
              $self->{work} .= "\n       semicolon:";
              $self->{work} .= "\n         All statements (commands) must end with a semi-colon ";
              $self->{work} .= "\n         except .reparse and .restart (even the last command in";
              $self->{work} .= "\n         the block)";
              $self->{work} .= "\n       eg:";
              $self->{work} .= "\n         clear; .reparse       # correct";
              $self->{work} .= "\n         clear add '.';        # incorrect, clear needs ; ";
              $self->{work} .= "\n         "; # add 
            }
            if (($self->{work} eq "brackets") || ($self->{work} eq "punctuation") || ($self->{work} eq "all")) {
              ($self->{tape}[$self->{cell}], $self->{work}) = ($self->{work}, $self->{tape}[$self->{cell}]);  # swap
              $self->{work} .= "";
              $self->{work} .= "\n      brackets () ";
              $self->{work} .= "\n        are used for tests like (eof) (EOF) (==) ";
              $self->{work} .= "\n        currently (2025) brackets are not used for logical grouping in ";
              $self->{work} .= "\n        tests.";
              $self->{work} .= "\n      examples:";
              $self->{work} .= "\n         (==)                  # correct";
              $self->{work} .= "\n         (==,'abc' { nop; }    # incorrect: unbalanced "; # add 
            }
            if (($self->{work} eq "negation") || ($self->{work} eq "punctuation") || ($self->{work} eq "all")) {
              ($self->{tape}[$self->{cell}], $self->{work}) = ($self->{work}, $self->{tape}[$self->{cell}]);  # swap
              $self->{work} .= "";
              $self->{work} .= "\n      negation operator ! ";
              $self->{work} .= "\n        is used for negating class and equals tests and with the ";
              $self->{work} .= "\n        B and E modifiers. It should precede the test and the ";
              $self->{work} .= "\n        B and E modifiers.";
              $self->{work} .= "\n";
              $self->{work} .= "\n      examples:";
              $self->{work} .= "\n         !(eof) { add '.'; }   # correct, not at end-of-file";
              $self->{work} .= "\n         ![:space:] { clear; } # correct ";
              $self->{work} .= "\n         'abc'! { clear; }     # incorrect: ! must precede test.";
              $self->{work} .= "\n         B!'abc' { clear; }    # incorrect: ! must precede 'B'  "; # add 
            }
            if (($self->{work} eq "modifiers") || ($self->{work} eq "tests") || ($self->{work} eq "all")) {
              ($self->{tape}[$self->{cell}], $self->{work}) = ($self->{work}, $self->{tape}[$self->{cell}]);  # swap
              $self->{work} .= "";
              $self->{work} .= "\n      begins-with 'B' and ends-with 'E' modifiers:";
              $self->{work} .= "\n        are used with quoted text tests and cannot be used with ";
              $self->{work} .= "\n        class tests.";
              $self->{work} .= "\n      eg: ";
              $self->{work} .= "\n        B'abc' { clear; }        # correct ";
              $self->{work} .= "\n        E\"abc\" { clear; }      # correct ";
              $self->{work} .= "\n        B[:alpha:] { clear; }  # incorrect  "; # add 
            }
            if (($self->{work} eq "help") || ($self->{work} eq "help") || ($self->{work} eq "all")) {
              ($self->{tape}[$self->{cell}], $self->{work}) = ($self->{work}, $self->{tape}[$self->{cell}]);  # swap
              $self->{work} .= "";
              $self->{work} .= "\n        help system:";
              $self->{work} .= "\n          categories: tests, commands, punctuation etc";
              $self->{work} .= "\n          type '#:help <command>' in a [nom] script to get help";
              $self->{work} .= "\n          for a particular command or word or category";
              $self->{work} .= "\n        eg:";
              $self->{work} .= "\n          #:help add    # shows help for the add command";
              $self->{work} .= "\n          #:help tests  # shows help nom block tests.";
              $self->{work} .= "\n        "; # add 
            }
            $self->{work} .= "\\n\\n"; # add 
            $self->writeText(); # print  
            last SCRIPT; # quit 
          }
          if ($self->{work} eq "nom.error*") {
            $self->{work} = '';  # clear 
            $self->{work} .= "! Nom syntax:"; # add 
            $self->{work} .= " near line:"; # add 
            $self->{work} .= $self->{linesRead}; # lines 
            $self->{work} .= " char:"; # add 
            $self->{work} .= $self->{charsRead}; # chars 
            $self->{work} .= "\\n"; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "\\n run /eg/nom.syntax.reference.pss for more detailed \\n"; # add 
            $self->{work} .= " syntax checking. See www.nomlang.org/doc for complete-ish \\n"; # add 
            $self->{work} .= " pep and nom documentation. \\n"; # add 
            $self->writeText(); # print  
            $self->{work} = '';  # clear 
            $self->popToken();
            if ($self->{work} eq "nom.help*") {
              $self->pushToken();
              next PARSE;
            }
            last SCRIPT; # quit 
          }
          if ($self->{work} eq "nom.untrapped.error*") {
            $self->{work} = '';  # clear 
            $self->{work} .= "! Nom untrapped error! :"; # add 
            $self->{work} .= " near line:"; # add 
            $self->{work} .= $self->{linesRead}; # lines 
            $self->{work} .= " char:"; # add 
            $self->{work} .= $self->{charsRead}; # chars 
            $self->{work} .= "\\n"; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "\\n run /eg/nom.syntax.reference.pss for more detailed \\n"; # add 
            $self->{work} .= " syntax checking. \\n"; # add 
            $self->writeText(); # print  
            last SCRIPT; # quit 
          }
          $self->popToken();
          if (($self->{work} eq "B*class*") || ($self->{work} eq "E*class*")) {
            $self->{work} = '';  # clear 
            $self->{work} = '';  # clear 
            $self->{work} .= "modifiers"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.help*"; # add 
            $self->pushToken();
            $self->{work} .= "  B or E modifier before class test."; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("}*")) eq "}*") || (substr($self->{work}, 0, length(";*")) eq ";*") || (substr($self->{work}, 0, length(">*")) eq ">*") || (substr($self->{work}, 0, length(")*")) eq ")*")) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* misplaced } or ; or > or ) character?"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("B*")) eq "B*") || (substr($self->{work}, 0, length("E*")) eq "E*")) {
            if ((length("!*") <= length($self->{work})) && (substr($self->{work}, -length("!*")) eq "!*")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "negation"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.help*"; # add 
              $self->pushToken();
              $self->{work} .= "* The negation operator (!) must precede the  \\n"; # add 
              $self->{work} .= "  begins-with (B) or ends-with (E) modifiers \\n"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
          }
          if ((substr($self->{work}, 0, length("B*")) eq "B*") && (!($self->{work} eq "B*")) && (!((length("quoted*") <= length($self->{work})) && (substr($self->{work}, -length("quoted*")) eq "quoted*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* misplaced begin-test modifier 'B' ?"; # add 
            $self->{work} .= "  eg: B'##' { d; add 'heading*'; push; .reparse } "; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("E*")) eq "E*") && (!($self->{work} eq "E*")) && (!((length("quoted*") <= length($self->{work})) && (substr($self->{work}, -length("quoted*")) eq "quoted*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* misplaced end-test modifier 'E' ?"; # add 
            $self->{work} .= "  eg: E'.' { d; add 'phrase*'; push; .reparse } "; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("E*")) eq "E*") && ((length("quoted*") <= length($self->{work})) && (substr($self->{work}, -length("quoted*")) eq "quoted*"))) {
            $self->{work} = '';  # clear 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            if ($self->{work} eq "\"\"") {
              $self->{work} = '';  # clear 
              $self->{work} .= "modifiers"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.help*"; # add 
              $self->pushToken();
              $self->{work} .= "  Empty quote after 'E' modifier "; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "E*quoted*"; # add 
          }
          if ((substr($self->{work}, 0, length("B*")) eq "B*") && ((length("quoted*") <= length($self->{work})) && (substr($self->{work}, -length("quoted*")) eq "quoted*"))) {
            $self->{work} = '';  # clear 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            if ($self->{work} eq "\"\"") {
              $self->{work} = '';  # clear 
              $self->{work} .= "modifiers"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.help*"; # add 
              $self->pushToken();
              $self->{work} .= "  Empty quote after 'B' modifier "; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "B*quoted*"; # add 
          }
          if ((substr($self->{work}, 0, length("!*")) eq "!*") && (!($self->{work} eq "!*")) && (!((length("(*") <= length($self->{work})) && (substr($self->{work}, -length("(*")) eq "(*"))) && (!((length("<*") <= length($self->{work})) && (substr($self->{work}, -length("<*")) eq "<*"))) && (!((length("B*") <= length($self->{work})) && (substr($self->{work}, -length("B*")) eq "B*"))) && (!((length("E*") <= length($self->{work})) && (substr($self->{work}, -length("E*")) eq "E*"))) && (!((length("quoted*") <= length($self->{work})) && (substr($self->{work}, -length("quoted*")) eq "quoted*"))) && (!((length("class*") <= length($self->{work})) && (substr($self->{work}, -length("class*")) eq "class*"))) && (!((length("test*") <= length($self->{work})) && (substr($self->{work}, -length("test*")) eq "test*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* misplaced negation operator (!) ?"; # add 
            $self->{work} .= "  e.g. \\n"; # add 
            $self->{work} .= "   !B'\$#\@' { clear; }   # correct \\n"; # add 
            $self->{work} .= "   !\"xyz\" { clear; }   # correct \\n"; # add 
            $self->{work} .= "   \"abc\"! { clear; }   # incorrect \\n"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length(",*")) eq ",*") && (!((length("(*") <= length($self->{work})) && (substr($self->{work}, -length("(*")) eq "(*"))) && (!((length("<*") <= length($self->{work})) && (substr($self->{work}, -length("<*")) eq "<*"))) && (!((length("!*") <= length($self->{work})) && (substr($self->{work}, -length("!*")) eq "!*"))) && (!((length("B*") <= length($self->{work})) && (substr($self->{work}, -length("B*")) eq "B*"))) && (!((length("E*") <= length($self->{work})) && (substr($self->{work}, -length("E*")) eq "E*"))) && (!((length("quoted*") <= length($self->{work})) && (substr($self->{work}, -length("quoted*")) eq "quoted*"))) && (!((length("class*") <= length($self->{work})) && (substr($self->{work}, -length("class*")) eq "class*"))) && (!((length("test*") <= length($self->{work})) && (substr($self->{work}, -length("test*")) eq "test*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* misplaced comma ?"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length(".*")) eq ".*") && (!((length("(*") <= length($self->{work})) && (substr($self->{work}, -length("(*")) eq "(*"))) && (!((length("<*") <= length($self->{work})) && (substr($self->{work}, -length("<*")) eq "<*"))) && (!((length("!*") <= length($self->{work})) && (substr($self->{work}, -length("!*")) eq "!*"))) && (!((length("B*") <= length($self->{work})) && (substr($self->{work}, -length("B*")) eq "B*"))) && (!((length("E*") <= length($self->{work})) && (substr($self->{work}, -length("E*")) eq "E*"))) && (!((length("quoted*") <= length($self->{work})) && (substr($self->{work}, -length("quoted*")) eq "quoted*"))) && (!((length("class*") <= length($self->{work})) && (substr($self->{work}, -length("class*")) eq "class*"))) && (!((length("test*") <= length($self->{work})) && (substr($self->{work}, -length("test*")) eq "test*"))) && (!((length("word*") <= length($self->{work})) && (substr($self->{work}, -length("word*")) eq "word*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* misplaced dot?"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("{*")) eq "{*") && ((length("}*") <= length($self->{work})) && (substr($self->{work}, -length("}*")) eq "}*"))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* empty block {} "; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("{*")) eq "{*") && (!($self->{work} eq "{*"))) {
            if (((length(">*") <= length($self->{work})) && (substr($self->{work}, -length(">*")) eq ">*")) || ((length(",*") <= length($self->{work})) && (substr($self->{work}, -length(",*")) eq ",*")) || ((length(")*") <= length($self->{work})) && (substr($self->{work}, -length(")*")) eq ")*")) || ((length("{*") <= length($self->{work})) && (substr($self->{work}, -length("{*")) eq "{*")) || ((length("}*") <= length($self->{work})) && (substr($self->{work}, -length("}*")) eq "}*")) || ((length(";*") <= length($self->{work})) && (substr($self->{work}, -length(";*")) eq ";*"))) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* misplaced character '"; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} .= "' ?"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
          }
          if ($self->{eof}) {
            if (($self->{work} eq "{*statement*") || ($self->{work} eq "{*statementset*")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* missing close brace (}) ?\\n"; # add 
              $self->{work} .= "  At "; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= " there is an opening brace ({) which does \\n"; # add 
              $self->{work} .= "  not seem to be matched with a closing brace "; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
          }
          if ((!(substr($self->{work}, 0, length(".*")) eq ".*")) && ((length("word*") <= length($self->{work})) && (substr($self->{work}, -length("word*")) eq "word*")) && (!($self->{work} eq "word*"))) {
            $self->pushToken();
            $self->pushToken();
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->increment();   # ++ 
            if (($self->{work} eq "reparse") || ($self->{work} eq "restart")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* missing dot before reparse/restart ? "; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->popToken();
            $self->popToken();
          }
          if ((substr($self->{work}, 0, length("(*")) eq "(*") && (!($self->{work} eq "(*")) && (!((length("word*") <= length($self->{work})) && (substr($self->{work}, -length("word*")) eq "word*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* strange syntax after '(' "; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq "<*;*") {
            $self->{work} = '';  # clear 
            $self->{work} .= "* '<' used to be an abbreviation for '--' \\n"; # add 
            $self->{work} .= "* but no-longer (mar 2025) since it clashes with <eof> etc "; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("<*")) eq "<*") && (!($self->{work} eq "<*")) && (!((length("word*") <= length($self->{work})) && (substr($self->{work}, -length("word*")) eq "word*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* bad test syntax."; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq ">*;*") {
            $self->{work} = '';  # clear 
            $self->{work} .= "* '>' used to be an abbreviation for '++' \\n"; # add 
            $self->{work} .= "  but no-longer (mar 2025) since it clashes with <eof> etc \\n"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("begin*")) eq "begin*") && (!($self->{work} eq "begin*")) && (!((length("{*") <= length($self->{work})) && (substr($self->{work}, -length("{*")) eq "{*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* begin is always followed by a brace.\\n"; # add 
            $self->{work} .= "   eg: begin { delim '/'; }\\n"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if (((length("begin*") <= length($self->{work})) && (substr($self->{work}, -length("begin*")) eq "begin*")) && (!($self->{work} eq "begin*")) && (!(substr($self->{work}, 0, length("comment*")) eq "comment*"))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* only comments can precede a begin block."; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq "command*}*") {
            $self->{work} = '';  # clear 
            $self->{work} .= "* missing semicolon? "; # add 
            $self->{work} .= "";
            $self->{work} .= "\n     In nom all commands except .reparse and .restart ";
            $self->{work} .= "\n     must be terminated with a semicolon, even the last ";
            $self->{work} .= "\n     command in a block {...} ";
            $self->{work} .= "\n";
            $self->{work} .= "\n     see www.nomlang.org/doc/syntax/ for details \\n"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("command*")) eq "command*") && (!($self->{work} eq "command*")) && (!((length(";*") <= length($self->{work})) && (substr($self->{work}, -length(";*")) eq ";*"))) && (!((length("quoted*") <= length($self->{work})) && (substr($self->{work}, -length("quoted*")) eq "quoted*"))) && (!((length("class*") <= length($self->{work})) && (substr($self->{work}, -length("class*")) eq "class*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* bad command syntax."; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq "command*class*") {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ((!($self->{work} eq "while")) && (!($self->{work} eq "whilenot"))) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* command '"; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "' does not take class argument.\\n"; # add 
              $self->{work} .= "  see www.nomlang/doc/commands/nom."; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= ".html "; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "command*class*"; # add 
          }
          if ($self->{work} eq "command*quoted*") {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ((!($self->{work} eq "add")) && (!($self->{work} eq "replace")) && (!($self->{work} eq "mark")) && (!($self->{work} eq "go")) && (!($self->{work} eq "until")) && (!($self->{work} eq "delim")) && (!($self->{work} eq "escape")) && (!($self->{work} eq "unescape")) && (!($self->{work} eq "echar"))) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* command '"; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "' does not take quoted argument.\\n\\n"; # add 
              $self->{work} .= "  see www.nomlang/doc/commands/nom."; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= ".html "; # add 
              $self->{work} .= "  for details."; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            if (($self->{work} eq "delim") || ($self->{work} eq "echar")) {
              $self->{work} = '';  # clear 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} =~ s/\X$//; # clip
              $self->{work} =~ s/^\X//; # clop
              $self->{work} =~ s/\X$//; # clip
              if (!($self->{work} eq "")) {
                $self->{work} = '';  # clear 
                $self->{work} .= "* multiple char argument to 'delim' or 'echar'. "; # add 
                ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
                $self->{work} = '';  # clear 
                $self->{work} .= "nom.error*"; # add 
                $self->pushToken();
                next PARSE;
              }
            }
            $self->{work} = '';  # clear 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            if ($self->{work} eq "\"\"") {
              $self->{work} = '';  # clear 
              $self->{work} .= "* empty quoted text ('' or \"\") is an error here.\\n\\n"; # add 
              $self->{work} .= "  - The 2nd argument to 'replace' can be an empty quote\\n"; # add 
              $self->{work} .= "    eg: replace 'abc' ''; # replace 'abc' with nothing \\n"; # add 
              $self->{work} .= "  - Also, empty quotes can be used in tests \\n"; # add 
              $self->{work} .= "    eg: '' { add 'xyz'; } !'' { clear; } \\n"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "command*quoted*"; # add 
          }
          if ($self->{work} eq "command*;*") {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if (($self->{work} eq "add") || ($self->{work} eq "replace") || ($self->{work} eq "while") || ($self->{work} eq "whilenot") || ($self->{work} eq "delim") || ($self->{work} eq "escape") || ($self->{work} eq "unescape") || ($self->{work} eq "echar")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* command '"; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "' requires argument."; # add 
              $self->{work} .= "- eg: add 'abc'; while [:alnum:]; escape ']'; "; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "command*;*"; # add 
          }
          if ($self->{eof}) {
            if ((length("command*") <= length($self->{work})) && (substr($self->{work}, -length("command*")) eq "command*")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* unterminated command '"; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "' at end of script"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            if (($self->{work} eq "command*quoted*") || ($self->{work} eq "command*class*")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* unterminated command '"; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "' at end of script"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
          }
          if ((substr($self->{work}, 0, length("quoted*")) eq "quoted*") && (!($self->{work} eq "quoted*")) && (!((length("{*") <= length($self->{work})) && (substr($self->{work}, -length("{*")) eq "{*"))) && (!((length("quoted*") <= length($self->{work})) && (substr($self->{work}, -length("quoted*")) eq "quoted*"))) && (!((length(";*") <= length($self->{work})) && (substr($self->{work}, -length(";*")) eq ";*"))) && (!((length(",*") <= length($self->{work})) && (substr($self->{work}, -length(",*")) eq ",*"))) && (!((length(".*") <= length($self->{work})) && (substr($self->{work}, -length(".*")) eq ".*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= " dubious syntax (eg: missing semicolon ';') after quoted text."; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("class*")) eq "class*") && (!($self->{work} eq "class*")) && (!((length("{*") <= length($self->{work})) && (substr($self->{work}, -length("{*")) eq "{*"))) && (!((length(";*") <= length($self->{work})) && (substr($self->{work}, -length(";*")) eq ";*"))) && (!((length(",*") <= length($self->{work})) && (substr($self->{work}, -length(",*")) eq ",*"))) && (!((length(".*") <= length($self->{work})) && (substr($self->{work}, -length(".*")) eq ".*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "semicolon"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.help*"; # add 
            $self->pushToken();
            $self->{work} = '';  # clear 
            $self->{work} .= "* missing semi-colon after class? "; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("word*")) eq "word*") && (!($self->{work} eq "word*")) && (!((length(")*") <= length($self->{work})) && (substr($self->{work}, -length(")*")) eq ")*"))) && (!((length(">*") <= length($self->{work})) && (substr($self->{work}, -length(">*")) eq ">*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* bad syntax after word."; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("test*")) eq "test*") && (!($self->{work} eq "test*")) && (!((length(",*") <= length($self->{work})) && (substr($self->{work}, -length(",*")) eq ",*"))) && (!((length(".*") <= length($self->{work})) && (substr($self->{work}, -length(".*")) eq ".*"))) && (!((length("{*") <= length($self->{work})) && (substr($self->{work}, -length("{*")) eq "{*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* bad test syntax."; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("ortest*")) eq "ortest*") && (!($self->{work} eq "ortest*")) && ((length(".*") <= length($self->{work})) && (substr($self->{work}, -length(".*")) eq ".*"))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* AND '.' operator in OR test."; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if (($self->{work} eq "ortest*quoted*") || ($self->{work} eq "ortest*test*")) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* missing comma in test?"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("ortest*")) eq "ortest*") && (!($self->{work} eq "ortest*")) && (!((length(",*") <= length($self->{work})) && (substr($self->{work}, -length(",*")) eq ",*"))) && (!((length("{*") <= length($self->{work})) && (substr($self->{work}, -length("{*")) eq "{*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* bad OR test syntax."; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("andtest*")) eq "andtest*") && (!($self->{work} eq "andtest*")) && ((length(",*") <= length($self->{work})) && (substr($self->{work}, -length(",*")) eq ",*"))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* OR ',' operator in AND test."; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if (($self->{work} eq "andtest*quoted*") || ($self->{work} eq "andtest*test*")) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* missing dot in test?"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("andtest*")) eq "andtest*") && (!($self->{work} eq "andtest*")) && (!((length(".*") <= length($self->{work})) && (substr($self->{work}, -length(".*")) eq ".*"))) && (!((length("{*") <= length($self->{work})) && (substr($self->{work}, -length("{*")) eq "{*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* bad AND test syntax."; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{eof}) {
            if (((length("test*") <= length($self->{work})) && (substr($self->{work}, -length("test*")) eq "test*")) || (substr($self->{work}, 0, length("test*")) eq "test*") || ((length("ortest*") <= length($self->{work})) && (substr($self->{work}, -length("ortest*")) eq "ortest*")) || (substr($self->{work}, 0, length("ortest*")) eq "ortest*") || ((length("andtest*") <= length($self->{work})) && (substr($self->{work}, -length("andtest*")) eq "andtest*")) || (substr($self->{work}, 0, length("andtest*")) eq "andtest*")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* test with no block {} at end of script"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
          }
          if ((substr($self->{work}, 0, length("statement*")) eq "statement*") && (!($self->{work} eq "statement*"))) {
            if (((length(",*") <= length($self->{work})) && (substr($self->{work}, -length(",*")) eq ",*")) || ((length("{*") <= length($self->{work})) && (substr($self->{work}, -length("{*")) eq "{*"))) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* misplaced dot/comma/brace ?"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
          }
          if ((substr($self->{work}, 0, length("statementset*")) eq "statementset*") && (!($self->{work} eq "statementset*"))) {
            if (((length(",*") <= length($self->{work})) && (substr($self->{work}, -length(",*")) eq ",*")) || ((length("{*") <= length($self->{work})) && (substr($self->{work}, -length("{*")) eq "{*"))) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* misplaced dot/comma/brace ?"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
          }
          if ($self->{work} eq "command*;*") {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if (($self->{work} eq "add") || ($self->{work} eq "replace") || ($self->{work} eq "while") || ($self->{work} eq "whilenot") || ($self->{work} eq "delim") || ($self->{work} eq "escape") || ($self->{work} eq "unescape") || ($self->{work} eq "echar")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* command '"; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "' requires argument"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "command*;*"; # add 
          }
          $self->popToken();
          if ((substr($self->{work}, 0, length("command*class*")) eq "command*class*") && (!($self->{work} eq "command*class*")) && (!((length(";*") <= length($self->{work})) && (substr($self->{work}, -length(";*")) eq ";*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "semicolon"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.help*"; # add 
            $self->pushToken();
            $self->{work} = '';  # clear 
            $self->{work} .= "* missing semi-colon after statement? "; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("command*quoted*")) eq "command*quoted*") && (!($self->{work} eq "command*quoted*")) && (!((length(";*") <= length($self->{work})) && (substr($self->{work}, -length(";*")) eq ";*"))) && (!((length("quoted*") <= length($self->{work})) && (substr($self->{work}, -length("quoted*")) eq "quoted*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* missing semi-colon after statement? "; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ((substr($self->{work}, 0, length("quoted*quoted*")) eq "quoted*quoted*") && (!((length(";*") <= length($self->{work})) && (substr($self->{work}, -length(";*")) eq ";*")))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* missing comma or dot in test? "; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if (((length("quoted*quoted*") <= length($self->{work})) && (substr($self->{work}, -length("quoted*quoted*")) eq "quoted*quoted*")) && (!(substr($self->{work}, 0, length("command*")) eq "command*"))) {
            $self->{work} = '';  # clear 
            $self->{work} .= "* missing comma or dot in test? "; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq "command*quoted*quoted*") {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if (!($self->{work} eq "replace")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* command '"; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "' does not take 2 quoted arguments.\\n"; # add 
              $self->{work} .= "- The only nom command with 2 quoted arguments is 'replace'."; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "command*quoted*quoted*"; # add 
          }
          $self->popToken();
          if ($self->{work} eq "command*quoted*quoted*;*") {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if (!($self->{work} eq "replace")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* command '"; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "' does not take 2 arguments."; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            if ($self->{work} eq "\"\"") {
              $self->{work} = '';  # clear 
              $self->{work} .= "* empty quoted text '' is an error here."; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "command*quoted*quoted*;*"; # add 
          }
          $self->pushToken();
          $self->pushToken();
          $self->pushToken();
          $self->pushToken();
          $self->popToken();
          $self->popToken();
          if ((substr($self->{work}, 0, length("comment*")) eq "comment*") && (!($self->{work} eq "comment*"))) {
            $self->replace("comment*", "");  # replace 
            $self->pushToken();
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->increment();   # ++ 
            $self->{work} = '';  # clear 
            next PARSE;
          }
          if (((length("comment*") <= length($self->{work})) && (substr($self->{work}, -length("comment*")) eq "comment*")) && (!($self->{work} eq "comment*"))) {
            $self->replace("comment*", "");  # replace 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq ".*word*") {
            $self->{work} = '';  # clear 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            if ($self->{work} eq "restart") {
              $self->{work} = '';  # clear 
              $self->{work} .= "next SCRIPT;"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "statement*"; # add 
              $self->pushToken();
              next PARSE;
            }
            if ($self->{work} eq "reparse") {
              $self->{work} = '';  # clear 
              $self->{work} .= $self->{accumulator}; # count 
              if ((!($self->{work} eq "0")) && (!($self->{work} eq "1"))) {
                $self->{work} = '';  # clear 
                $self->{work} .= "* multiple parse label error?"; # add 
                ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
                $self->{work} = '';  # clear 
                $self->{work} .= "nom.untrapped.error*"; # add 
                $self->pushToken();
                next PARSE;
              }
              if ($self->{work} eq "0") {
                $self->{work} = '';  # clear 
                $self->{work} .= "last LEX;"; # add 
              }
              if ($self->{work} eq "1") {
                $self->{work} = '';  # clear 
                $self->{work} .= "next PARSE;"; # add 
              }
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "statement*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "* invalid statement ."; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.untrapped.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq "word*>*") {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{work} eq "parse") {
              $self->{work} = '';  # clear 
              $self->{work} .= $self->{accumulator}; # count 
              if (!($self->{work} eq "0")) {
                $self->{work} = '';  # clear 
                $self->{work} .= "script error:\\n"; # add 
                $self->{work} .= "  extra parse> label at line "; # add 
                $self->{work} .= $self->{linesRead}; # lines 
                $self->{work} .= ".\\n"; # add 
                $self->writeText(); # print  
                last SCRIPT; # quit 
              }
              $self->{work} = '';  # clear 
              $self->{work} .= "--> parse>"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "parselabel*"; # add 
              $self->pushToken();
              $self->{accumulator} += 1; # a+ 
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "word*>*"; # add 
          }
          if ($self->{work} eq "E*quoted*") {
            $self->{work} = '';  # clear 
            $self->increment();   # ++ 
            $self->{work} .= "(length("; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= ") <= length(\$self->{work})) && "; # add 
            $self->{work} .= "(substr(\$self->{work}, -length("; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= ")) eq "; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= ")"; # add 
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "test*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq "B*quoted*") {
            $self->{work} = '';  # clear 
            $self->{work} .= "substr(\$self->{work}, 0, length("; # add 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= ")) eq "; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "test*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if (($self->{work} eq "comment*statement*") || ($self->{work} eq "statement*comment*") || ($self->{work} eq "statementset*comment*")) {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "\\n"; # add 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "command*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq "comment*comment*") {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "\\n"; # add 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "comment*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq "!*test*") {
            $self->{work} = '';  # clear 
            $self->{work} .= "!("; # add 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            $self->{work} .= ")"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "test*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if (($self->{work} eq ",*quoted*") || ($self->{work} eq ".*quoted*") || ($self->{work} eq "!*quoted*")) {
            $self->pushToken();
            $self->{work} = '';  # clear 
            $self->{work} .= "\$self->{work} eq "; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "test*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if (($self->{work} eq "quoted*,*") || ($self->{work} eq "quoted*.*") || ($self->{work} eq "quoted*{*")) {
            $self->replace("quoted*", "test*");  # replace 
            $self->pushToken();
            $self->pushToken();
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            $self->{work} .= "\$self->{work} eq "; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->increment();   # ++ 
            $self->increment();   # ++ 
            $self->{work} = '';  # clear 
            next PARSE;
          }
          if (($self->{work} eq ",*class*") || ($self->{work} eq ".*class*") || ($self->{work} eq "!*class*")) {
            $self->pushToken();
            $self->{work} = '';  # clear 
            $self->{work} .= "\$self->matchClass(\$self->{work}, \""; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "\")"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "test*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if (($self->{work} eq "class*,*") || ($self->{work} eq "class*.*") || ($self->{work} eq "class*{*")) {
            $self->replace("class*", "test*");  # replace 
            $self->pushToken();
            $self->pushToken();
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            $self->{work} .= "\$self->matchClass(\$self->{work}, \""; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "\")"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->increment();   # ++ 
            $self->increment();   # ++ 
            $self->{work} = '';  # clear 
            next PARSE;
          }
          if ($self->{work} eq "command*;*") {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ((!($self->{work} eq "go")) && (!($self->{work} eq "mark")) && (!($self->{work} eq "until")) && (!($self->{work} eq "clip")) && (!($self->{work} eq "clop")) && (!($self->{work} eq "clear")) && (!($self->{work} eq "upper")) && (!($self->{work} eq "lower")) && (!($self->{work} eq "cap")) && (!($self->{work} eq "print")) && (!($self->{work} eq "pop")) && (!($self->{work} eq "push")) && (!($self->{work} eq "unstack")) && (!($self->{work} eq "stack")) && (!($self->{work} eq "state")) && (!($self->{work} eq "put")) && (!($self->{work} eq "get")) && (!($self->{work} eq "swap")) && (!($self->{work} eq "++")) && (!($self->{work} eq "--")) && (!($self->{work} eq "read")) && (!($self->{work} eq "count")) && (!($self->{work} eq "a+")) && (!($self->{work} eq "a-")) && (!($self->{work} eq "zero")) && (!($self->{work} eq "chars")) && (!($self->{work} eq "lines")) && (!($self->{work} eq "nochars")) && (!($self->{work} eq "nolines")) && (!($self->{work} eq "quit")) && (!($self->{work} eq "write")) && (!($self->{work} eq "nop"))) {
              $self->{work} = '';  # clear 
              $self->{work} .= "  incorrect command syntax?"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.untrapped.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            if ($self->{work} eq "go") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->goToMark(\$self->{tape}[\$self->{cell}]);  # go (tape) "; # add 
            }
            if ($self->{work} eq "mark") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$mark = \$self->{tape}[\$self->{cell}];\\n"; # add 
              $self->{work} .= "\$self->addMark(\$mark);  # mark (tape) "; # add 
            }
            if ($self->{work} eq "until") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$text = \$self->{tape}[\$self->{cell}];\\n"; # add 
              $self->{work} .= "\$self->readUntil(\$text); "; # add 
              $self->{work} .= "# until (tape)"; # add 
            }
            if ($self->{work} eq "clip") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{work} =~ s/\\\\X\$//; # clip"; # add 
            }
            if ($self->{work} eq "clop") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{work} =~ s/^\\\\X//; # clop"; # add 
            }
            if ($self->{work} eq "clear") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{work} = '';  # clear "; # add 
            }
            if ($self->{work} eq "upper") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{work} = uc(\$self->{work});  # upper"; # add 
            }
            if ($self->{work} eq "lower") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{work} = lc(\$self->{work});  # lower"; # add 
            }
            if ($self->{work} eq "cap") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->capitalise(); # cap "; # add 
            }
            if ($self->{work} eq "print") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->writeText(); # print  "; # add 
            }
            if ($self->{work} eq "pop") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->popToken();"; # add 
            }
            if ($self->{work} eq "push") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->pushToken();"; # add 
            }
            if ($self->{work} eq "unstack") {
              $self->{work} = '';  # clear 
              $self->{work} .= "while (\$self->popToken()) { next; }   # unstack "; # add 
            }
            if ($self->{work} eq "stack") {
              $self->{work} = '';  # clear 
              $self->{work} .= "while (\$self->pushToken()) { next; }   # stack "; # add 
            }
            if ($self->{work} eq "state") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->printState();    # state "; # add 
            }
            if ($self->{work} eq "put") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\${\$self->{tape}}[\$self->{cell}] = \$self->{work};   # put "; # add 
            }
            if ($self->{work} eq "get") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{work} .= \$self->{tape}[\$self->{cell}];  # get"; # add 
            }
            if ($self->{work} eq "swap") {
              $self->{work} = '';  # clear 
              $self->{work} .= "(\$self->{tape}[\$self->{cell}], \$self->{work}) = "; # add 
              $self->{work} .= "(\$self->{work}, \$self->{tape}[\$self->{cell}]);  # swap"; # add 
            }
            if ($self->{work} eq "++") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->increment();   # ++ "; # add 
            }
            if ($self->{work} eq "--") {
              $self->{work} = '';  # clear 
              $self->{work} .= "if (\$self->{cell} > 0) { \$self->{cell} -= 1; } # --"; # add 
            }
            if ($self->{work} eq "read") {
              $self->{work} = '';  # clear 
              $self->{work} .= "if (\$self->{eof}) { last SCRIPT; } \$self->readChar(); # read "; # add 
            }
            if ($self->{work} eq "count") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{work} .= \$self->{accumulator}; # count "; # add 
            }
            if ($self->{work} eq "a+") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{accumulator} += 1; # a+ "; # add 
            }
            if ($self->{work} eq "a-") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{accumulator} -= 1; # a- "; # add 
            }
            if ($self->{work} eq "zero") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{accumulator} = 0; # zero "; # add 
            }
            if ($self->{work} eq "chars") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{work} .= \$self->{charsRead}; # chars "; # add 
            }
            if ($self->{work} eq "lines") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{work} .= \$self->{linesRead}; # lines "; # add 
            }
            if ($self->{work} eq "nochars") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{charsRead} = 0; # nochars "; # add 
            }
            if ($self->{work} eq "nolines") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{linesRead} = 0; # nolines "; # add 
            }
            if ($self->{work} eq "quit") {
              $self->{work} = '';  # clear 
              $self->{work} .= "last SCRIPT; # quit "; # add 
            }
            if ($self->{work} eq "write") {
              $self->{work} = '';  # clear 
              $self->{work} .= "open my \$fh, '>:utf8', 'sav.pp';\\n"; # add 
              $self->{work} .= "print \$fh \$self->{work}; close \$fh; # write"; # add 
            }
            if ($self->{work} eq "nop") {
              $self->{work} = '';  # clear 
              $self->{work} .= "# removed nop: does nothing "; # add 
            }
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "statement*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if (($self->{work} eq "statementset*statement*") || ($self->{work} eq "statement*statement*")) {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "\\n"; # add 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "statementset*"; # add 
            $self->pushToken();
            next PARSE;
          }
          $self->popToken();
          if (($self->{work} eq "(*word*)*") || ($self->{work} eq "<*word*>*")) {
            $self->{work} = '';  # clear 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            if ((!($self->{work} eq "eof")) && (!($self->{work} eq "=="))) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* invalid test <> or () ."; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.untrapped.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            if ($self->{work} eq "eof") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{eof}"; # add 
            }
            if ($self->{work} eq "==") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{tape}[\$self->{cell}] eq \$self->{work}"; # add 
            }
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "test*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq "command*quoted*;*") {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ((!($self->{work} eq "mark")) && (!($self->{work} eq "go")) && (!($self->{work} eq "delim")) && (!($self->{work} eq "add")) && (!($self->{work} eq "until")) && (!($self->{work} eq "escape")) && (!($self->{work} eq "unescape")) && (!($self->{work} eq "echar"))) {
              $self->{work} = '';  # clear 
              $self->{work} .= "  superfluous argument or other error?\\n"; # add 
              $self->{work} .= "  (error should have been trapped in error block: check)"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.untrapped.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            if ($self->{work} eq "mark") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->addMark("; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} .= "); # mark "; # add 
            }
            if ($self->{work} eq "go") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->goToMark("; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} .= "); # go "; # add 
            }
            if ($self->{work} eq "delim") {
              $self->{work} = '';  # clear 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} =~ s/\X$//; # clip
              $self->{work} =~ s/^\X//; # clop
              $self->escapeChar('\'');
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{delimiter} = '"; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} .= "'; # delim "; # add 
            }
            if ($self->{work} eq "add") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->{work} .= "; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->replace("\\n", "\";\\n\$self->{work} .= \"\\\\n");  # replace 
              $self->{work} .= "; # add "; # add 
            }
            if ($self->{work} eq "until") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->readUntil("; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->replace("\\n", "\\\\n");  # replace 
              $self->{work} .= ");"; # add 
            }
            if (($self->{work} eq "escape") || ($self->{work} eq "unescape")) {
              $self->{work} = '';  # clear 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} =~ s/\X$//; # clip
              $self->{work} =~ s/^\X//; # clop
              $self->unescapeChar('"');
              $self->escapeChar('\'');
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->"; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "Char"; # add 
              $self->{work} .= "('"; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} .= "');"; # add 
            }
            if ($self->{work} eq "echar") {
              $self->{work} = '';  # clear 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} =~ s/\X$//; # clip
              $self->{work} =~ s/^\X//; # clop
              $self->escapeChar('\'');
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} .= "\$self->{escape} = '"; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} .= "'; # echar "; # add 
            }
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "statement*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq "command*class*;*") {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{work} eq "while") {
              $self->{work} = '';  # clear 
              $self->{work} .= "# while \\n"; # add 
              $self->{work} .= "while (\$self->matchClass(\$self->{peep}, \""; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} .= "\")) {\\n"; # add 
              $self->{work} .= "  if (\$self->{eof}) { last; } \$self->readChar();\\n}"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "statement*"; # add 
              $self->pushToken();
              next PARSE;
            }
            if ($self->{work} eq "whilenot") {
              $self->{work} = '';  # clear 
              $self->{work} .= "# whilenot   \\n"; # add 
              $self->{work} .= "while (!\$self->matchClass(\$self->{peep}, \""; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} .= "\")) {\\n"; # add 
              $self->{work} .= "  if (\$self->{eof}) { last; } \$self->readChar();\\n}"; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "statement*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "*** unchecked error in rule: statement = command class ;"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq "(*test*)*") {
            $self->{work} = '';  # clear 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "test*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if (($self->{work} eq "(*ortest*)*") || ($self->{work} eq "(*andtest*)*")) {
            $self->{work} = '';  # clear 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "test*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if (($self->{work} eq "test*,*test*") || ($self->{work} eq "ortest*,*test*")) {
            if ($self->{work} eq "test*,*test*") {
              $self->{work} = '';  # clear 
              $self->{work} .= "("; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= ")"; # add 
            }
            if ($self->{work} eq "ortest*,*test*") {
              $self->{work} = '';  # clear 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
            }
            $self->{work} .= " || ("; # add 
            $self->increment();   # ++ 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            $self->{work} .= ")"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "ortest*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if (($self->{work} eq "test*.*test*") || ($self->{work} eq "andtest*.*test*")) {
            if ($self->{work} eq "test*.*test*") {
              $self->{work} = '';  # clear 
              $self->{work} .= "("; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= ")"; # add 
            }
            if ($self->{work} eq "andtest*.*test*") {
              $self->{work} = '';  # clear 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
            }
            $self->{work} .= " && ("; # add 
            $self->increment();   # ++ 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            $self->{work} .= ")"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "andtest*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq "{*statement*}*") {
            $self->replace("ment*", "mentset*");  # replace 
          }
          $self->popToken();
          if ($self->{work} eq "command*quoted*quoted*;*") {
            $self->{work} = '';  # clear 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{work} eq "replace") {
              $self->{work} = '';  # clear 
              $self->{work} .= "\$self->replace("; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= ", "; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= ");  # replace "; # add 
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "statement*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "  incorrect command syntax?"; # add 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "nom.untrapped.error*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if (($self->{work} eq "test*{*statementset*}*") || ($self->{work} eq "ortest*{*statementset*}*") || ($self->{work} eq "andtest*{*statementset*}*")) {
            $self->{work} = '';  # clear 
            $self->increment();   # ++ 
            $self->increment();   # ++ 
            $self->{work} .= "\\n"; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->replace("\\n", "\\n  ");  # replace 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            $self->{work} = '';  # clear 
            $self->{work} .= "if ("; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= ") {"; # add 
            $self->increment();   # ++ 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "\\n}"; # add 
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "statement*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{work} eq "begin*{*statementset*}*") {
            $self->{work} = '';  # clear 
            $self->increment();   # ++ 
            $self->increment();   # ++ 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "beginblock*"; # add 
            $self->pushToken();
            next PARSE;
          }
          if ($self->{eof}) {
            if (($self->{work} eq "test*") || ($self->{work} eq "ortest*") || ($self->{work} eq "andtest*") || ($self->{work} eq "begin*")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "* Incomplete script."; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
          }
          $self->pushToken();
          $self->pushToken();
          $self->pushToken();
          $self->pushToken();
          $self->popToken();
          $self->popToken();
          $self->popToken();
          if ($self->{eof}) {
            $self->replace("statement*", "statementset*");  # replace 
            if ($self->{work} eq "statementset*parselabel*statementset*") {
              $self->{work} = '';  # clear 
              $self->{work} .= "    "; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->replace("\\n", "\\n    ");  # replace 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->increment();   # ++ 
              $self->increment();   # ++ 
              $self->{work} .= "    "; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->replace("\\n", "\\n    ");  # replace 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} .= "SCRIPT:\\n"; # add 
              $self->{work} .= "while (true) {\\n"; # add 
              $self->{work} .= "  LEX: { \\n"; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "\\n  } # lex block \\n"; # add 
              $self->{work} .= "  PARSE: \\n"; # add 
              $self->{work} .= "    while (true) { \\n"; # add 
              $self->increment();   # ++ 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->{work} .= "\\n     last PARSE;  # run-once parse loop "; # add 
              $self->{work} .= "\\n   } # parse block "; # add 
              $self->{work} .= "\\n} # nom script loop "; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "script*"; # add 
              $self->pushToken();
              next PARSE;
            }
          }
          $self->pushToken();
          $self->pushToken();
          $self->pushToken();
          $self->popToken();
          $self->popToken();
          if ($self->{eof}) {
            $self->replace("statement*", "statementset*");  # replace 
            if ($self->{work} eq "statementset*parselabel*") {
              $self->{work} = '';  # clear 
              $self->{work} .= "    "; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->replace("\\n", "\\n    ");  # replace 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "SCRIPT:\\n"; # add 
              $self->{work} .= "while (true) {\\n"; # add 
              $self->{work} .= "  LEX: { \\n"; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "\\n  } # lex block \\n"; # add 
              $self->{work} .= "  PARSE: "; # add 
              $self->{work} .= "\\n} # nom script loop "; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "script*"; # add 
              $self->pushToken();
              next PARSE;
            }
            if ($self->{work} eq "parselabel*statementset*") {
              $self->{work} = '';  # clear 
              $self->{work} .= "    "; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              $self->replace("\\n", "\\n    ");  # replace 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "SCRIPT:\\n"; # add 
              $self->{work} .= "while (true) {\\n"; # add 
              $self->{work} .= "  PARSE: \\n"; # add 
              $self->{work} .= "    while (true) { \\n"; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "\\n     last PARSE;  # run-once parse loop "; # add 
              $self->{work} .= "\\n   } # parse block "; # add 
              $self->{work} .= "\\n} # nom script loop "; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "script*"; # add 
              $self->pushToken();
              next PARSE;
            }
            if ($self->{work} eq "beginblock*script*") {
              $self->{work} = '';  # clear 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "\\n"; # add 
              $self->increment();   # ++ 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              if ($self->{cell} > 0) { $self->{cell} -= 1; } # --
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "script*"; # add 
              $self->pushToken();
              next PARSE;
            }
          }
          $self->pushToken();
          $self->pushToken();
          $self->popToken();
          if ($self->{eof}) {
            $self->replace("statement*", "statementset*");  # replace 
            if ($self->{work} eq "statementset*") {
              $self->{work} = '';  # clear 
              $self->{work} .= "  "; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->replace("\\n", "\\n  ");  # replace 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "SCRIPT:\\n"; # add 
              $self->{work} .= "while (true) {\\n"; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              $self->{work} .= "\\n} # nom script loop "; # add 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "script*"; # add 
              $self->pushToken();
              next PARSE;
            }
            if (($self->{work} eq "beginblock*") || ($self->{work} eq "comment*") || ($self->{work} eq "parselabel*")) {
              $self->{work} = '';  # clear 
              $self->{work} .= "script*"; # add 
              $self->pushToken();
              next PARSE;
            }
          }
          $self->pushToken();
          $self->pushToken();
          $self->pushToken();
          $self->pushToken();
          if ($self->{eof}) {
            $self->popToken();
            $self->popToken();
            if ($self->{work} eq "") {
              $self->{work} .= "# empty nom script\\n"; # add 
              $self->writeText(); # print  
              last SCRIPT; # quit 
            }
            if (!($self->{work} eq "script*")) {
              $self->pushToken();
              $self->pushToken();
              while ($self->popToken()) { next; }   # unstack 
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "* script syntax problem: the error was not caught by the \\n"; # add 
              $self->{work} .= "  syntax checker, and should have been.\\n"; # add 
              $self->{work} .= "  The parse stack was: "; # add 
              $self->{work} .= $self->{tape}[$self->{cell}];  # get
              ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
              $self->{work} = '';  # clear 
              $self->{work} .= "nom.error*"; # add 
              $self->pushToken();
              next PARSE;
            }
            $self->{work} = '';  # clear 
            $self->{work} .= "#!/usr/bin/perl \\n"; # add 
            $self->writeText(); # print  
            $self->{work} = '';  # clear 
            $self->{work} .= "\\n"; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->replace("\\n", "\\n      ");  # replace 
            ${$self->{tape}}[$self->{cell}] = $self->{work};   # put 
            $self->{work} = '';  # clear 
            $self->{work} .= "";
            $self->{work} .= "\n";
            $self->{work} .= "\n use strict;";
            $self->{work} .= "\n use warnings;";
            $self->{work} .= "\n use utf8;";
            $self->{work} .= "\n # for unicode character properties.";
            $self->{work} .= "\n # use Unicode::UCD qw(charprop);";
            $self->{work} .= "\n # use IO::File;";
            $self->{work} .= "\n #use IO::BufReader;";
            $self->{work} .= "\n #use IO::BufWriter;";
            $self->{work} .= "\n use Getopt::Long;";
            $self->{work} .= "\n use List::Util;  # for all function";
            $self->{work} .= "\n use Carp; # For croak and confess";
            $self->{work} .= "\n";
            $self->{work} .= "\n package Machine; ";
            $self->{work} .= "\n   use constant { true => 1, false => 0 };";
            $self->{work} .= "\n";
            $self->{work} .= "\n   sub new {";
            $self->{work} .= "\n     # my (\$class) = \@_;";
            $self->{work} .= "\n     my \$class = shift;  # ";
            $self->{work} .= "\n     binmode STDOUT, \":encoding(UTF-8)\";";
            $self->{work} .= "\n";
            $self->{work} .= "\n     my \$self = {";
            $self->{work} .= "\n       accumulator   => 0,       # counter for anything";
            $self->{work} .= "\n       peep          => \"\",      # next char in input stream";
            $self->{work} .= "\n       charsRead     => 0,       # No. of chars read so far init:0";
            $self->{work} .= "\n       linesRead     => 1,       # No. of lines read so far init:1";
            $self->{work} .= "\n       inputBuffer   => [],      # reversed array of input chars/graphemes";
            $self->{work} .= "\n       outputBuffer  => \"\",      # where string output will go";
            $self->{work} .= "\n       inputType    => \"unset\",  # reading from stdin/string/file etc";
            $self->{work} .= "\n       sinkType      => \"stdout\",# ";
            $self->{work} .= "\n       work          => \"\",      # text accumulator";
            $self->{work} .= "\n       stack         => [],      # parse token stack";
            $self->{work} .= "\n       tapeLength    => 100,     # tape initial length";
            $self->{work} .= "\n       tape          => [ map { \"\" } 1..100 ], # array of token attributes";
            $self->{work} .= "\n       marks         => [ map { \"\" } 1..100 ], # tape marks";
            $self->{work} .= "\n       cell          => 0,       # pointer to current cell";
            $self->{work} .= "\n       input         => *STDIN,  # text input stream";
            $self->{work} .= "\n       output        => *STDOUT, #";
            $self->{work} .= "\n       eof           => false,    # end of stream reached? (boolean)";
            $self->{work} .= "\n       escape        => \"\\\\\\\\\",   # char used to \"escape\" others: default \"\\\\\"";
            $self->{work} .= "\n       delimiter     => \"*\",      # push/pop delimiter (default is \"*\")";
            $self->{work} .= "\n     };";
            $self->{work} .= "\n     bless \$self, \$class;";
            $self->{work} .= "\n     return \$self;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   sub fillInputStringBuffer {";
            $self->{work} .= "\n     my (\$self, \$text) = \@_;";
            $self->{work} .= "\n     my \$revtext = reverse \$text;";
            $self->{work} .= "\n     # push onto the array";
            $self->{work} .= "\n     push \@{\$self->{inputBuffer}}, split //, \$revtext;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   sub fillInputBuffer {";
            $self->{work} .= "\n     my \$self = shift;";
            $self->{work} .= "\n     my \$text = shift;";
            $self->{work} .= "\n     # grapheme clusters regex is \\X in perl";
            $self->{work} .= "\n     # the grapheme cluster splitter is making an extra empty char ";
            $self->{work} .= "\n     # in the array";
            $self->{work} .= "\n";
            $self->{work} .= "\n     # not working?";
            $self->{work} .= "\n     # my \@charArray = reverse split(/(\\\\X)/, \$text);";
            $self->{work} .= "\n";
            $self->{work} .= "\n     #my \@graphemes = \$text =~ m/\\X/g;";
            $self->{work} .= "\n     #my \@charArray = reverse(\@graphemes);";
            $self->{work} .= "\n     my \@charArray = reverse split(//, \$text);";
            $self->{work} .= "\n     push (\@{\$self->{inputBuffer}}, \@charArray);";
            $self->{work} .= "\n     # display the input buffer array";
            $self->{work} .= "\n     # print \"[\",join(\", \", \@{\$self->{inputBuffer}}),\"]\";";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # read one character from the input stream and";
            $self->{work} .= "\n   #   update the machine. This reads though an inputBuffer/inputChars";
            $self->{work} .= "\n   #   so as to handle unicode grapheme clusters (which can be more";
            $self->{work} .= "\n   #   than one \"character\").";
            $self->{work} .= "\n   # ";
            $self->{work} .= "\n   sub readChar {";
            $self->{work} .= "\n     my \$self = shift;";
            $self->{work} .= "\n";
            $self->{work} .= "\n     #  this exit code should never be called in a translated script";
            $self->{work} .= "\n     #  because the Machine:parse() method will return just before";
            $self->{work} .= "\n     #  a read() on self.eof But I should keep this here in case";
            $self->{work} .= "\n     #  the machine methods are used outside of a parse() method?";
            $self->{work} .= "\n     if (\$self->{eof}) {";
            $self->{work} .= "\n       # need to return from parse method (i.e break loop) when reading on eof.";
            $self->{work} .= "\n       exit 0; # print(\"eof exit\")";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n";
            $self->{work} .= "\n     my \$result = 0; my \$line = \"\";";
            $self->{work} .= "\n     \$self->{charsRead} += 1;";
            $self->{work} .= "\n     # increment lines";
            $self->{work} .= "\n     if (\$self->{peep} eq \"\\\\n\") { \$self->{linesRead} += 1; }";
            $self->{work} .= "\n     \$self->{work} .= \$self->{peep};";
            $self->{work} .= "\n";
            $self->{work} .= "\n     # fix: it would be better not to have an if else here";
            $self->{work} .= "\n     # stdin.all/string/file all read the whole input stream";
            $self->{work} .= "\n     #    at once into a buffer.";
            $self->{work} .= "\n     my \$inputType = \$self->{inputType};";
            $self->{work} .= "\n     if (\$inputType eq \"stdin\" || \$inputType eq \"string\" || ";
            $self->{work} .= "\n         \$inputType eq \"file\") {";
            $self->{work} .= "\n       if (!\@{\$self->{inputBuffer}}) {";
            $self->{work} .= "\n         \$self->{eof} = true;";
            $self->{work} .= "\n         \$self->{peep} = \"\";";
            $self->{work} .= "\n       } else {";
            $self->{work} .= "\n         \$self->{peep} = \"\";";
            $self->{work} .= "\n         # the inputBuffer is a reversed array. pop() returns the last element";
            $self->{work} .= "\n         my \$char = pop \@{\$self->{inputBuffer}};";
            $self->{work} .= "\n         \$self->{peep} .= \$char if defined \$char;";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n       return;";
            $self->{work} .= "\n     } elsif (\$inputType eq \"stdinstream\") {";
            $self->{work} .= "\n       # read from stdin one line at a time. ";
            $self->{work} .= "\n       # ";
            $self->{work} .= "\n     } elsif (\$inputType eq \"filestream\") {";
            $self->{work} .= "\n       # if (scalar(\@{\$self->{inputBuffer}}) == 0) {";
            $self->{work} .= "\n       if (!\@{\$self->{inputBuffer}}) {";
            $self->{work} .= "\n         my \$bytes = \$self->{input}->getline(\\\\\$line);";
            $self->{work} .= "\n         if (\$bytes > 0) {";
            $self->{work} .= "\n           \$self->fillInputBuffer(\$line);";
            $self->{work} .= "\n         } else {";
            $self->{work} .= "\n           \$self->{eof} = true;";
            $self->{work} .= "\n           \$self->{peep} = \"\";";
            $self->{work} .= "\n         }";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n       if (scalar(\@{\$self->{inputBuffer}}) > 0) {";
            $self->{work} .= "\n         \$self->{peep} = \"\";";
            $self->{work} .= "\n         my \$char = pop \@{\$self->{inputBuffer}};";
            $self->{work} .= "\n         \$self->{peep} .= \$char if defined \$char;";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n       return;";
            $self->{work} .= "\n     } else {";
            $self->{work} .= "\n       print STDERR \"Machine.inputType error \", \$inputType, \" while trying to read input\\\\n\";";
            $self->{work} .= "\n       exit 1;";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n   } # read";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # function Machine:write(output)";
            $self->{work} .= "\n   sub writeText {";
            $self->{work} .= "\n     my \$self = shift;";
            $self->{work} .= "\n     my \$outputType = \$self->{sinkType};";
            $self->{work} .= "\n     if (\$outputType eq \"stdout\") {";
            $self->{work} .= "\n       print \$self->{work};";
            $self->{work} .= "\n     } elsif (\$outputType eq \"file\") {";
            $self->{work} .= "\n       print {\$self->{output}} \$self->{work} or die \"Error writing to file: \$!\";";
            $self->{work} .= "\n     } elsif (\$outputType eq \"string\") {";
            $self->{work} .= "\n       \$self->{outputBuffer} .= \$self->{work};";
            $self->{work} .= "\n     } else {";
            $self->{work} .= "\n       print STDERR \"Machine.sinkType error for type \", \$outputType, \"\\\\n\";";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # increment tape pointer by one";
            $self->{work} .= "\n   sub increment {";
            $self->{work} .= "\n     my (\$self) = \@_;";
            $self->{work} .= "\n     \$self->{cell}++;";
            $self->{work} .= "\n     if (\$self->{cell} >= \$self->{tapeLength}) {";
            $self->{work} .= "\n       for (my \$ii = 1; \$ii <= 50; \$ii++) {";
            $self->{work} .= "\n         push \@{\$self->{tape}}, \"\";";
            $self->{work} .= "\n         push \@{\$self->{marks}}, \"\";";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n       \$self->{tapeLength} += 50;";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # Machine.decrement() is usually compiled inline";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # remove escape char, the char should be a string because it could be";
            $self->{work} .= "\n   # a unicode grapheme cluster (diacritics etc) ";
            $self->{work} .= "\n   sub unescapeChar {";
            $self->{work} .= "\n     my (\$self, \$c) = \@_;";
            $self->{work} .= "\n     # dont unescape chars that are not escaped!";
            $self->{work} .= "\n     my \$countEscapes = 0;";
            $self->{work} .= "\n     my \$s = \"\";";
            $self->{work} .= "\n     # let nextChar = ;";
            $self->{work} .= "\n     return if length(\$self->{work}) == 0;";
            $self->{work} .= "\n";
            $self->{work} .= "\n     for my \$nextChar (split //, \$self->{work}) {";
            $self->{work} .= "\n       if (\$nextChar eq \$c && (\$countEscapes % 2 == 1)) {";
            $self->{work} .= "\n         # assuming that the escape char is only one char?";
            $self->{work} .= "\n         # remove last escape char";
            $self->{work} .= "\n         substr(\$s, -1) = \"\";";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n       if (\$nextChar eq \$self->{escape}) {";
            $self->{work} .= "\n         \$countEscapes++;";
            $self->{work} .= "\n       } else {";
            $self->{work} .= "\n         \$countEscapes = 0;";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n       \$s .= \$nextChar;";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n     \$self->{work} = \$s;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   #  add escape character, dont escape chars that are already escaped!";
            $self->{work} .= "\n   #  this seems not to work when escaping the escape char! which is ";
            $self->{work} .= "\n   #  a substantial problem. I may have to use replace instead for the ";
            $self->{work} .= "\n   #  escape char?";
            $self->{work} .= "\n   #    modify this for grapheme clusters.";
            $self->{work} .= "\n   #   ";
            $self->{work} .= "\n   sub escapeChar {";
            $self->{work} .= "\n     my (\$self, \$c) = \@_;";
            $self->{work} .= "\n     my \$countEscapes = 0;";
            $self->{work} .= "\n     my \$s = \"\";";
            $self->{work} .= "\n     return if length(\$self->{work}) == 0;";
            $self->{work} .= "\n     for my \$nextChar (split //, \$self->{work}) {";
            $self->{work} .= "\n       if (\$nextChar eq \$c && (\$countEscapes % 2 == 0)) {";
            $self->{work} .= "\n         \$s .= \$self->{escape};";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n       if (\$nextChar eq \$self->{escape}) {";
            $self->{work} .= "\n         \$countEscapes++;";
            $self->{work} .= "\n       } else {";
            $self->{work} .= "\n         \$countEscapes = 0;";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n       \$s .= \$nextChar;";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n     \$self->{work} = \$s;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # # a helper to see how many trailing escape chars ";
            $self->{work} .= "\n   sub countEscaped {";
            $self->{work} .= "\n     my (\$self, \$suffix) = \@_;";
            $self->{work} .= "\n     my \$s = \$self->{work};";
            $self->{work} .= "\n     my \$count = 0;";
            $self->{work} .= "\n     if (substr(\$s, -length(\$suffix)) eq \$suffix) {";
            $self->{work} .= "\n       \$s = substr(\$s, 0, length(\$s) - length(\$suffix));";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n     while (substr(\$s, -length(\$self->{escape})) eq \$self->{escape}) {";
            $self->{work} .= "\n       \$count++;";
            $self->{work} .= "\n       \$s = substr(\$s, 0, length(\$s) - length(\$self->{escape}));";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n     return \$count;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   #  reads the input stream until the work end with text. It is";
            $self->{work} .= "\n   #    better to call this readUntil instead of until because some";
            $self->{work} .= "\n   #       languages dont like keywords as methods. Same for read()";
            $self->{work} .= "\n   #       should be readChar() ";
            $self->{work} .= "\n   sub readUntil {";
            $self->{work} .= "\n     my (\$self, \$suffix) = \@_;";
            $self->{work} .= "\n     # read at least one character";
            $self->{work} .= "\n     return if \$self->{eof};";
            $self->{work} .= "\n     \$self->readChar();";
            $self->{work} .= "\n     while (true) {";
            $self->{work} .= "\n       return if \$self->{eof};";
            $self->{work} .= "\n       if (substr(\$self->{work}, -length(\$suffix)) eq \$suffix) {";
            $self->{work} .= "\n         return if \$self->countEscaped(\$suffix) % 2 == 0;";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n       \$self->readChar();";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # pop the first token from the stack into the workspace";
            $self->{work} .= "\n   sub popToken {";
            $self->{work} .= "\n     my \$self = shift;   # a reference to the pep machine";
            $self->{work} .= "\n     if (!\@{\$self->{stack}}) { return false; }";
            $self->{work} .= "\n     \$self->{work} = pop(\@{\$self->{stack}}) . \$self->{work};";
            $self->{work} .= "\n     if (\$self->{cell} > 0) { \$self->{cell} -= 1; }";
            $self->{work} .= "\n     return true;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # push the first token from the workspace to the stack";
            $self->{work} .= "\n   sub pushToken {";
            $self->{work} .= "\n     my \$self = shift;   # a reference to the pep machine";
            $self->{work} .= "\n     # dont increment the tape pointer on an empty push";
            $self->{work} .= "\n     if (length(\$self->{work}) == 0) { return false; }";
            $self->{work} .= "\n";
            $self->{work} .= "\n     # I iterate the workspace buffer chars so that this method";
            $self->{work} .= "\n     # can be easily adapted for grapheme clusters";
            $self->{work} .= "\n     my \$token = \"\";";
            $self->{work} .= "\n     my \$remainder = \"\";";
            $self->{work} .= "\n     my \@chars = split(//, \$self->{work});";
            $self->{work} .= "\n";
            $self->{work} .= "\n     # maybe for grapheme clusters";
            $self->{work} .= "\n     # my \@chars = split(/\\X/, \$self->{work});";
            $self->{work} .= "\n     for (my \$ii = 0; \$ii < scalar(\@chars); \$ii++) {";
            $self->{work} .= "\n       my \$c = \$chars[\$ii];";
            $self->{work} .= "\n       \$token .= \$c;";
            $self->{work} .= "\n       if (\$c eq \$self->{delimiter}) {";
            $self->{work} .= "\n         push \@{\$self->{stack}}, \$token;";
            $self->{work} .= "\n         \$remainder = join \"\", \@chars[\$ii+1 .. \$#chars];";
            $self->{work} .= "\n         \$self->{work} = \"\";";
            $self->{work} .= "\n         \$self->{work} .= \$remainder;";
            $self->{work} .= "\n         \$self->increment();";
            $self->{work} .= "\n         return true;";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n     # push the whole workspace if there is no token delimiter";
            $self->{work} .= "\n     push \@{\$self->{stack}}, \$token;";
            $self->{work} .= "\n     \$self->{work} = \"\";";
            $self->{work} .= "\n     \$self->increment();";
            $self->{work} .= "\n     return true;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # save the workspace to file \"sav.pp\"";
            $self->{work} .= "\n   # we can put this inline?";
            $self->{work} .= "\n   sub writeToFile {";
            $self->{work} .= "\n     my (\$self) = \@_;";
            $self->{work} .= "\n     my \$filename = \"sav.pp\";";
            $self->{work} .= "\n     open my \$fh, \">:utf8\", \$filename or ";
            $self->{work} .= "\n       die \"Could not open file [\$filename] for writing: \$!\";";
            $self->{work} .= "\n     print \$fh \$self->{work};";
            $self->{work} .= "\n     close \$fh;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   sub goToMark {";
            $self->{work} .= "\n     my (\$self, \$mark) = \@_;";
            $self->{work} .= "\n     for (my \$ii = 0; \$ii < \@{\$self->{marks}}; \$ii++) {";
            $self->{work} .= "\n       # print(\"ii:\", \$ii, \" mark:\", \$thismark,\"\\\\n\");";
            $self->{work} .= "\n       if (\$self->{marks}[\$ii] eq \$mark) {";
            $self->{work} .= "\n         \$self->{cell} = \$ii;";
            $self->{work} .= "\n         return;";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n     print \"badmark '\$mark'!\\\\n\";";
            $self->{work} .= "\n     exit 1;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # # remove existing marks with the same name and add new mark ";
            $self->{work} .= "\n   sub addMark {";
            $self->{work} .= "\n     my (\$self, \$newMark) = \@_;";
            $self->{work} .= "\n     # remove existing marks with the same name.";
            $self->{work} .= "\n     for my \$mark (\@{\$self->{marks}}) {";
            $self->{work} .= "\n       if (\$mark eq \$newMark) {";
            $self->{work} .= "\n         \$mark = \"\";";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n     \$self->{marks}[\$self->{cell}] = \$newMark;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # # check if the workspace matches given list class eg [hjk]";
            $self->{work} .= "\n   #    or a range class eg [a-p]. The class string will be \"[a-p]\" ie";
            $self->{work} .= "\n   #    with brackets [:alpha:] may have already been made into something else by the";
            $self->{work} .= "\n   #    compiler.";
            $self->{work} .= "\n   #    fix: for grapheme clusters and more complete classes";
            $self->{work} .= "\n   #   ";
            $self->{work} .= "\n   sub matchClass {";
            $self->{work} .= "\n     my (\$self, \$text, \$class) = \@_;";
            $self->{work} .= "\n     # empty text should never match a class.";
            $self->{work} .= "\n     return false if length(\$text) == 0;";
            $self->{work} .= "\n";
            $self->{work} .= "\n     # a character type class like [:alpha:]";
            $self->{work} .= "\n     # print(\"class: \$class\");";
            $self->{work} .= "\n         ";
            $self->{work} .= "\n     if (\$class =~ /^\\\\[:(.+):\\\\]\$/ && \$class ne \"[:]\" && \$class ne \"[::]\") {";
            $self->{work} .= "\n       my \$charType = \$1;";
            $self->{work} .= "\n       my \@chars = split //, \$text;";
            $self->{work} .= "\n       if (\$charType eq \"alnum\") { return \$text =~ /^\\\\w+\$/; }";
            $self->{work} .= "\n       if (\$charType eq \"alpha\") { return \$text =~ /^[[:alpha:]]+\$/; }";
            $self->{work} .= "\n       if (\$charType eq \"ascii\") { return \$text =~ /^[[:ascii:]]+\$/; }";
            $self->{work} .= "\n       if (\$charType eq \"word\") { return \$text =~ /^[\\\\w_]+\$/; }";
            $self->{work} .= "\n       if (\$charType eq \"blank\") { return \$text =~ /^[\\\\s\\\\t]+\$/; }";
            $self->{work} .= "\n       if (\$charType eq \"control\") { return \$text =~ /^[[:cntrl:]]+\$/; }";
            $self->{work} .= "\n       if (\$charType eq \"cntrl\") { return \$text =~ /^[[:cntrl:]]+\$/; }";
            $self->{work} .= "\n       if (\$charType eq \"digit\") { return \$text =~ /^\\\\d+\$/;}";
            $self->{work} .= "\n       if (\$charType eq \"graph\") { return \$text =~ /^[[:graph:]]+\$/; }";
            $self->{work} .= "\n       if (\$charType eq \"lower\") { return \$text =~ /^[[:lower:]]+\$/; }";
            $self->{work} .= "\n       if (\$charType eq \"upper\") { return \$text =~ /^[[:upper:]]+\$/; }";
            $self->{work} .= "\n       if (\$charType eq \"print\") { return \$text =~ /^[[:print:]]+\$/; ";
            $self->{work} .= "\n         # and not eq \" \"";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n       if (\$charType eq \"punct\") { return \$text =~ /^[[:punct:]]+\$/; }";
            $self->{work} .= "\n       if (\$charType eq \"space\") { return \$text =~ /^\\\\s+\$/; }";
            $self->{work} .= "\n       if (\$charType eq \"xdigit\") { return \$text =~ /^[0-9a-fA-F]+\$/; }";
            $self->{work} .= "\n       print STDERR \"unrecognised char class in translated nom script\\\\n\";";
            $self->{work} .= "\n       print STDERR \"\$charType\\\\n\";";
            $self->{work} .= "\n       exit 1;";
            $self->{work} .= "\n       return false;";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n";
            $self->{work} .= "\n     # get a vector of chars except the first and last which are [ and ]";
            $self->{work} .= "\n     my \@charList = split //, substr(\$class, 1, length(\$class)-2);";
            $self->{work} .= "\n     # is a range class like [a-z]";
            $self->{work} .= "\n     if (scalar(\@charList) == 3 && \$charList[1] eq \"-\") {";
            $self->{work} .= "\n       my (\$start, undef, \$end) = \@charList;";
            $self->{work} .= "\n       my \@chars = split(//, \$text);";
            $self->{work} .= "\n       #print(\"chars: \@chars\");";
            $self->{work} .= "\n       #return all { \$_ ge \$start && \$_ le \$end } \@chars;";
            $self->{work} .= "\n       # modify split for grapheme clusters?";
            $self->{work} .= "\n       for my \$char (split //, \$text) {";
            $self->{work} .= "\n         if (\$char lt \$start || \$char gt \$end) { return false; }";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n       return true;";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n";
            $self->{work} .= "\n     # list class like: [xyzabc]";
            $self->{work} .= "\n     # check if all characters in text are in the class list";
            $self->{work} .= "\n     # my \@textChars = split //, \$text;";
            $self->{work} .= "\n";
            $self->{work} .= "\n     # Create a hash for faster lookup?";
            $self->{work} .= "\n     my %charHash = map { \$_ => 1 } \@charList; ";
            $self->{work} .= "\n     for my \$char (split //, \$text) {";
            $self->{work} .= "\n       return false unless exists \$charHash{\$char};";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n     return true;";
            $self->{work} .= "\n";
            $self->{work} .= "\n     #return all { grep { \$_ eq \$textChars[\$_] } \@charList } 0 .. \$#textChars;";
            $self->{work} .= "\n     #return false;";
            $self->{work} .= "\n     # also must handle eg [:alpha:] This can be done with char methods";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # # a plain text string replace function on the workspace ";
            $self->{work} .= "\n   sub replace {";
            $self->{work} .= "\n     my (\$self, \$old, \$new) = \@_;";
            $self->{work} .= "\n     return if length(\$old) == 0;";
            $self->{work} .= "\n     return if \$old eq \$new;";
            $self->{work} .= "\n     \$old = quotemeta(\$old);";
            $self->{work} .= "\n     \$self->{work} =~ s/\$old/\$new/g;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   #  make the workspace capital case ";
            $self->{work} .= "\n   sub capitalise {";
            $self->{work} .= "\n     my (\$self) = \@_;";
            $self->{work} .= "\n     my \$result = \"\";";
            $self->{work} .= "\n     my \$capitalize_next = 1;";
            $self->{work} .= "\n     for my \$c (split //, \$self->{work}) {";
            $self->{work} .= "\n       if (\$c =~ /[[:alpha:]]/) {";
            $self->{work} .= "\n         if (\$capitalize_next) {";
            $self->{work} .= "\n           \$result .= uc \$c;";
            $self->{work} .= "\n           \$capitalize_next = false;";
            $self->{work} .= "\n         } else {";
            $self->{work} .= "\n           \$result .= lc \$c;";
            $self->{work} .= "\n         }";
            $self->{work} .= "\n       } else {";
            $self->{work} .= "\n         \$result .= \$c;";
            $self->{work} .= "\n         if (\$c eq \"\\\\n\" || \$c eq \" \" || \$c eq \".\" || \$c eq \"?\" || \$c eq \"!\") {";
            $self->{work} .= "\n           \$capitalize_next = true;";
            $self->{work} .= "\n         }";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n     \$self->{work} = \$result;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   #  print the internal state of the pep/nom parsing machine. This";
            $self->{work} .= "\n   #    is handy for debugging ";
            $self->{work} .= "\n   sub printState {";
            $self->{work} .= "\n     my \$self = shift;";
            $self->{work} .= "\n     print ";
            $self->{work} .= "\n       \"\\\\n--------- Machine State ------------- \\\\n\",";
            $self->{work} .= "\n       \"(input buffer:\", join(\",\", \@{\$self->{inputBuffer}}), \")\\\\n\",";
            $self->{work} .= "\n       \"Stack[\", join(\",\", \@{\$self->{stack}}), \"]\", ";
            $self->{work} .= "\n       \" Work[\", \$self->{work}, \"]\",";
            $self->{work} .= "\n       \" Peep[\", \$self->{peep}, \"]\\\\n\",";
            $self->{work} .= "\n       \"Acc:\", \$self->{accumulator},";
            $self->{work} .= "\n       \" EOF:\", \$self->{eof} eq true? \"true\":\"false\", ";
            $self->{work} .= "\n       \" Esc:\", \$self->{escape},";
            $self->{work} .= "\n       \" Delim:\", \$self->{delimiter}, ";
            $self->{work} .= "\n       \" Chars:\", \$self->{charsRead}, \" \";";
            $self->{work} .= "\n     print \"Lines:\", \$self->{linesRead}, \"\\\\n\";";
            $self->{work} .= "\n     print \"-------------- Tape ----------------- \\\\n\";";
            $self->{work} .= "\n     print \"Tape Size: \", \$self->{tapeLength}, \"\\\\n\";";
            $self->{work} .= "\n     my \$start = 0;";
            $self->{work} .= "\n     if (\$self->{cell} > 3) {";
            $self->{work} .= "\n       \$start = \$self->{cell} - 4;";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n     my \$end = \$self->{cell} + 4;";
            $self->{work} .= "\n     for (my \$ii = \$start; \$ii <= \$end; \$ii++) {";
            $self->{work} .= "\n       print \"    \$ii \";";
            $self->{work} .= "\n       if (\$ii == \$self->{cell}) { print \"> [\"; }";
            $self->{work} .= "\n       else { print \"  [\"; }";
            $self->{work} .= "\n       if (defined \$self->{tape}[\$ii]) {";
            $self->{work} .= "\n         print \$self->{tape}[\$ii], \"] (m:\", \$self->{marks}[\$ii], \")\\\\n\";";
            $self->{work} .= "\n       } else {";
            $self->{work} .= "\n         print \"]\\\\n\";";
            $self->{work} .= "\n       }";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # # makes the machine read from a string also needs to prime";
            $self->{work} .= "\n   #    the \"peep\" value. ";
            $self->{work} .= "\n   sub setStringInput {";
            $self->{work} .= "\n     my (\$self, \$text) = \@_;";
            $self->{work} .= "\n     \$self->{inputType} = \"string\";";
            $self->{work} .= "\n     \$self->{inputBuffer} = [];";
            $self->{work} .= "\n     \$self->fillInputBuffer(\$text);";
            $self->{work} .= "\n     # prime the \"peep\" with the 1st char";
            $self->{work} .= "\n     \$self->{peep} = \"\"; \$self->readChar(); \$self->{charsRead} = 0;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # # makes the machine write to a string ";
            $self->{work} .= "\n   sub setStringOutput {";
            $self->{work} .= "\n     my (\$self) = \@_;";
            $self->{work} .= "\n     \$self->{sinkType} = \"string\";";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # # parse/translate from a string and return the translated";
            $self->{work} .= "\n   #    string ";
            $self->{work} .= "\n   sub parseString {";
            $self->{work} .= "\n     my (\$self, \$input) = \@_;";
            $self->{work} .= "\n     \$self->setStringInput(\$input);";
            $self->{work} .= "\n     \$self->{sinkType} = \"string\";";
            $self->{work} .= "\n     \$self->parse();";
            $self->{work} .= "\n     return \$self->{outputBuffer};";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # # makes the machine read from a file stream line by line,";
            $self->{work} .= "\n   #    not from stdin ";
            $self->{work} .= "\n   sub setFileStreamInput {";
            $self->{work} .= "\n     my (\$self, \$filename) = \@_;";
            $self->{work} .= "\n     unless (checkTextFile(\$filename)) { exit 1; }";
            $self->{work} .= "\n     open my \$fh, \"<:utf8\", \$filename or ";
            $self->{work} .= "\n       die \"Cannot open file [\$filename] for reading: \$!\";";
            $self->{work} .= "\n     \$self->{input} = IO::BufReader->new(\$fh);";
            $self->{work} .= "\n     \$self->{inputType} = \"filestream\";";
            $self->{work} .= "\n     # prime the peep, the read() method should refill the";
            $self->{work} .= "\n     # inputChars or inputBuffer if it is empty.";
            $self->{work} .= "\n     \$self->{peep} = \"\"; \$self->readChar(); \$self->{charsRead} = 0;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # # makes the machine read from a file line buffer array";
            $self->{work} .= "\n   #    but this also needs to prime the \"peep\" value ";
            $self->{work} .= "\n   sub setFileInput {";
            $self->{work} .= "\n     my (\$self, \$filename) = \@_;";
            $self->{work} .= "\n     open my \$fh, \"<:utf8\", \$filename or ";
            $self->{work} .= "\n       die \"Could not open file [\$filename] for reading: \$!\";";
            $self->{work} .= "\n     my \$text = do { local \$/ = undef; <\$fh> };";
            $self->{work} .= "\n     close \$fh;";
            $self->{work} .= "\n     # there is an extra newline being added, I dont know where.";
            $self->{work} .= "\n     if (\$text =~ s/\\\\n\$//) {}";
            $self->{work} .= "\n     \$self->{inputType} = \"file\";";
            $self->{work} .= "\n     \$self->{inputBuffer} = [];";
            $self->{work} .= "\n     \$self->fillInputBuffer(\$text);";
            $self->{work} .= "\n     # prime the \"peep\" with the 1st char";
            $self->{work} .= "\n     \$self->{peep} = \"\"; \$self->readChar(); \$self->{charsRead} = 0;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # # makes the machine write to a file not to stdout (the default) ";
            $self->{work} .= "\n   sub setFileOutput {";
            $self->{work} .= "\n     my (\$self, \$filename) = \@_;";
            $self->{work} .= "\n     unless (checkTextFile(\$filename)) { exit 1; }";
            $self->{work} .= "\n     open my \$fh, \">:utf8\", \$filename or ";
            $self->{work} .= "\n       die \"Cannot create file [\$filename] for writing: \$!\";";
            $self->{work} .= "\n     \$self->{output} = IO::BufWriter->new(\$fh);";
            $self->{work} .= "\n     \$self->{sinkType} = \"file\";";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # parse from a file and put result in file";
            $self->{work} .= "\n   sub parseFile {";
            $self->{work} .= "\n     my (\$self, \$inputFile, \$outputFile) = \@_;";
            $self->{work} .= "\n     \$self->setFileInput(\$inputFile);";
            $self->{work} .= "\n     \$self->setFileOutput(\$outputFile);";
            $self->{work} .= "\n     \$self->parse();";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # # parse from any stream, fix handle ";
            $self->{work} .= "\n   # #";
            $self->{work} .= "\n   # sub parseStream {";
            $self->{work} .= "\n   #   my (\$self, \$reader) = \@_;";
            $self->{work} .= "\n   #   # \$self->{input} = \$reader; # Needs proper handling of reader type";
            $self->{work} .= "\n   #   \$self->parse();";
            $self->{work} .= "\n   # }";
            $self->{work} .= "\n   # ";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # # this is the default parsing mode. If no other is selected";
            $self->{work} .= "\n   #    it will be activated when parse() is first called. I activate it when";
            $self->{work} .= "\n   #    parse is 1st called because otherwise it will block if no stdin";
            $self->{work} .= "\n   #    is availabel. It also sets stdout as output ";
            $self->{work} .= "\n   sub setStandardInput {";
            $self->{work} .= "\n     my \$self = shift;";
            $self->{work} .= "\n     \$self->{inputType} = \"stdin\";";
            $self->{work} .= "\n     \$self->{sinkType} = \"stdout\";";
            $self->{work} .= "\n     # for printing wide characters";
            $self->{work} .= "\n     binmode STDOUT, \":encoding(UTF-8)\";";
            $self->{work} .= "\n     # binmode STDERR, \":encoding(UTF-8)\";";
            $self->{work} .= "\n";
            $self->{work} .= "\n     # \$self->{input} = \\*STDIN;";
            $self->{work} .= "\n     # \$self->{output} = \\*STDOUT;";
            $self->{work} .= "\n";
            $self->{work} .= "\n     # read the whole of stdin into the inputBuffer";
            $self->{work} .= "\n     \$self->{inputBuffer} = [];";
            $self->{work} .= "\n     my \$buffer = \"\";";
            $self->{work} .= "\n     #  my \$stdin = join(\"\", <STDIN>);";
            $self->{work} .= "\n     while (<STDIN>) { \$buffer .= \$_; }";
            $self->{work} .= "\n     ";
            $self->{work} .= "\n     # print(\"buffer: [\$buffer]\\\\n\");";
            $self->{work} .= "\n     \$self->fillInputBuffer(\$buffer);";
            $self->{work} .= "\n     # prime the \"peep\" with the 1st char, but this doesnt count as";
            $self->{work} .= "\n     # a character read.";
            $self->{work} .= "\n     \$self->{peep} = \"\"; \$self->readChar(); \$self->{charsRead} = 0;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # This function performs all sorts of magic and shenanigans. ";
            $self->{work} .= "\n   # Creates a new method runScript() and evaluates it, ";
            $self->{work} .= "\n   # thus acting as an interpreter of a scriptfile given to an";
            $self->{work} .= "\n   # -f switch. This method only works when the nom to perl translator has ";
            $self->{work} .= "\n   # been run on itself with:";
            $self->{work} .= "\n   #   >> pep -f translate.perl.pss translate.perl.pss > interp.perl.pl";
            $self->{work} .= "\n   #   >> echo \"read; print; print; clear; \" > test.pss";
            $self->{work} .= "\n   #   >> chmod a+x interp.perl.pl";
            $self->{work} .= "\n   #   >> echo buzz | ./interp.perl.pl -f test.pss";
            $self->{work} .= "\n   #   >> (output should be \"bbuuzz\")";
            $self->{work} .= "\n   # Only those who have achieved";
            $self->{work} .= "\n   # true enlightenment will understand this method.";
            $self->{work} .= "\n   sub interpret {";
            $self->{work} .= "\n     my \$self = shift;          # the parse machine ";
            $self->{work} .= "\n     my \$filename = \"\";";
            $self->{work} .= "\n     # fix using get opts";
            $self->{work} .= "\n     if (\$ARGV[0] eq \"-f\") { \$filename = \$ARGV[1]; }";
            $self->{work} .= "\n     if (\$ARGV[0] =~ /^-f/) { ";
            $self->{work} .= "\n       \$filename = \$ARGV[1]; \$filename =~ s/^..//;";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n     if ((!defined \$filename) || (\$filename eq \"\")) { return; }";
            $self->{work} .= "\n     my \$method = \$self->parseFile(\$filename);";
            $self->{work} .= "\n     # remove everything except the parse method and rename";
            $self->{work} .= "\n     # the method so that it doesnt clash with the existing parse";
            $self->{work} .= "\n     # method";
            $self->{work} .= "\n     \$method =~ s/^.*sub parse \\\\{/sub runScript \\\\{/s;";
            $self->{work} .= "\n     # to debug";
            $self->{work} .= "\n     # print \$method; return;";
            $self->{work} .= "\n     # add this new method to the current class via evaluation";
            $self->{work} .= "\n     eval(\$method);";
            $self->{work} .= "\n     # execute the new method, thus interpreting the script-file ";
            $self->{work} .= "\n     # that was provide";
            $self->{work} .= "\n     \$self->runScript(*STDIN, *STDOUT);";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n";
            $self->{work} .= "\n   # parse and translate the input stdin/file/string ";
            $self->{work} .= "\n   sub parse {";
            $self->{work} .= "\n     my \$self = shift;";
            $self->{work} .= "\n     # some temporary variables";
            $self->{work} .= "\n     my \$text = \"\"; my \$mark = \"\";";
            $self->{work} .= "\n";
            $self->{work} .= "\n     if (\$self->{inputType} eq \"unset\") {";
            $self->{work} .= "\n       \$self->setStandardInput();";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n    ";
            $self->{work} .= "\n     # -----------";
            $self->{work} .= "\n     # translated nom code inserted below";
            $self->{work} .= "\n     # -----------";
            $self->{work} .= "\n     "; # add 
            $self->{work} .= $self->{tape}[$self->{cell}];  # get
            $self->{work} .= "";
            $self->{work} .= "\n";
            $self->{work} .= "\n     # close open files here? yes. use break, not return";
            $self->{work} .= "\n     my \$outputType = \$self->{sinkType};";
            $self->{work} .= "\n     if (\$outputType eq \"file\") {";
            $self->{work} .= "\n       \$self->{output}->flush() or die \"Error flushing output file: \$!\";";
            $self->{work} .= "\n     } elsif (\$outputType eq \"stdout\") {";
            $self->{work} .= "\n       # STDOUT is typically flushed automatically";
            $self->{work} .= "\n     } elsif (\$outputType eq \"string\") {";
            $self->{work} .= "\n       # Output is in the buffer";
            $self->{work} .= "\n     } else {";
            $self->{work} .= "\n       print STDERR \"unsupported output type: \", \$outputType, \"\\\\n\";";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n   } # sub parse";
            $self->{work} .= "\n";
            $self->{work} .= "\n";
            $self->{work} .= "\n sub printHelp {";
            $self->{work} .= "\n   print <<EOF;";
            $self->{work} .= "\n";
            $self->{work} .= "\n   Nom script translated to perl by www.nomlang.org/tr/ script ";
            $self->{work} .= "\n   usage:";
            $self->{work} .= "\n         echo \"..sometext..\" | ./script";
            $self->{work} .= "\n         cat somefile.txt | ./script";
            $self->{work} .= "\n         ./script -f <file>";
            $self->{work} .= "\n         ./script -i <text>";
            $self->{work} .= "\n   options:";
            $self->{work} .= "\n     --file -f <file>";
            $self->{work} .= "\n       run the script with <file> as input (not stdin)";
            $self->{work} .= "\n     --input -i <text>";
            $self->{work} .= "\n       run the script with <text> as input";
            $self->{work} .= "\n     --filetest -F <filename>";
            $self->{work} .= "\n       test the translated script with file input and output";
            $self->{work} .= "\n     --filestream -S <filename>";
            $self->{work} .= "\n       test the translated script with file-stream input";
            $self->{work} .= "\n     --inputtest -I <text>";
            $self->{work} .= "\n       test the translated script with string input and output";
            $self->{work} .= "\n     --help -h";
            $self->{work} .= "\n       show this help";
            $self->{work} .= "\n";
            $self->{work} .= "\nEOF";
            $self->{work} .= "\n";
            $self->{work} .= "\n }";
            $self->{work} .= "\n";
            $self->{work} .= "\n # display a message about a missing argument to the translated";
            $self->{work} .= "\n #    script ";
            $self->{work} .= "\n sub missingArgument {";
            $self->{work} .= "\n   print \"Missing argument.\\\\n\";";
            $self->{work} .= "\n   printHelp();";
            $self->{work} .= "\n   exit 1;";
            $self->{work} .= "\n }";
            $self->{work} .= "\n";
            $self->{work} .= "\n # display a message if an command line option is repeated";
            $self->{work} .= "\n sub duplicateSwitch {";
            $self->{work} .= "\n   print \"Duplicate switch found.\\\\n\";";
            $self->{work} .= "\n   printHelp();";
            $self->{work} .= "\n   exit 1;";
            $self->{work} .= "\n }";
            $self->{work} .= "\n";
            $self->{work} .= "\n sub checkTextFile {";
            $self->{work} .= "\n   my (\$filepath) = \@_;";
            $self->{work} .= "\n   eval {";
            $self->{work} .= "\n     open my \$fh, \"<:utf8\", \$filepath;";
            $self->{work} .= "\n     close \$fh;";
            $self->{work} .= "\n     return true;";
            $self->{work} .= "\n   };";
            $self->{work} .= "\n   if (\$\@) {";
            $self->{work} .= "\n     if (\$\@ =~ /No such file or directory/) {";
            $self->{work} .= "\n       print \"File [\$filepath] not found.\\\\n\";";
            $self->{work} .= "\n     } elsif (\$\@ =~ /Permission denied/) {";
            $self->{work} .= "\n       print \"Permission denied to read file [\$filepath]\\\\n\";";
            $self->{work} .= "\n     } else {";
            $self->{work} .= "\n       print \"Error opening file \$filepath: \$\@\";";
            $self->{work} .= "\n     }";
            $self->{work} .= "\n     return false;";
            $self->{work} .= "\n   }";
            $self->{work} .= "\n   return true;";
            $self->{work} .= "\n }";
            $self->{work} .= "\n";
            $self->{work} .= "\npackage main;";
            $self->{work} .= "\n";
            $self->{work} .= "\n  my \$mm = Machine->new();";
            $self->{work} .= "\n  my \$input = \"\";";
            $self->{work} .= "\n  my \$filename = \"\";";
            $self->{work} .= "\n";
            $self->{work} .= "\n  GetOptions (";
            $self->{work} .= "\n    \"file|f=s\"      => \\\$filename,";
            $self->{work} .= "\n    \"input|i=s\"     => \\\$input,";
            $self->{work} .= "\n    \"filetest|F=s\"  => sub {";
            $self->{work} .= "\n      my (\$opt_name, \$value) = \@_;";
            $self->{work} .= "\n      if (\$value) {";
            $self->{work} .= "\n        if (\$filename ne \"\") { duplicateSwitch(); }";
            $self->{work} .= "\n        if (!checkTextFile(\$value)) { printHelp(); exit 1; }";
            $self->{work} .= "\n        \$mm->parseFile(\$value, \"out.txt\");";
            $self->{work} .= "\n        my \$output = do {";
            $self->{work} .= "\n          local \$/ = undef;";
            $self->{work} .= "\n          open my \$fh, \"<:utf8\", \"out.txt\" or die \"Could not open out.txt: \$!\";";
            $self->{work} .= "\n          <\$fh>;";
            $self->{work} .= "\n        };";
            $self->{work} .= "\n        print \$output;";
            $self->{work} .= "\n        exit 0;";
            $self->{work} .= "\n      } else {";
            $self->{work} .= "\n        missingArgument();";
            $self->{work} .= "\n      }";
            $self->{work} .= "\n    },";
            $self->{work} .= "\n    \"filestream|S=s\" => sub {";
            $self->{work} .= "\n      my (\$opt_name, \$value) = \@_;";
            $self->{work} .= "\n      if (\$value) {";
            $self->{work} .= "\n        if (\$filename ne \"\") { duplicateSwitch(); }";
            $self->{work} .= "\n        if (!checkTextFile(\$value)) { printHelp(); exit 1; }";
            $self->{work} .= "\n        \$mm->setFileStreamInput(\$value);";
            $self->{work} .= "\n      } else {";
            $self->{work} .= "\n        missingArgument();";
            $self->{work} .= "\n      }";
            $self->{work} .= "\n    },";
            $self->{work} .= "\n    \"inputtest|I=s\" => sub {";
            $self->{work} .= "\n      my (\$opt_name, \$value) = \@_;";
            $self->{work} .= "\n      if (\$value) {";
            $self->{work} .= "\n        if (\$input ne \"\") { duplicateSwitch(); }";
            $self->{work} .= "\n        my \$text = \$mm->parseString(\$value);";
            $self->{work} .= "\n        print \$text;";
            $self->{work} .= "\n        exit 0;";
            $self->{work} .= "\n      } else {";
            $self->{work} .= "\n        missingArgument();";
            $self->{work} .= "\n      }";
            $self->{work} .= "\n    },";
            $self->{work} .= "\n    \"help|h\"        => sub { printHelp(); exit 0; },";
            $self->{work} .= "\n  ) or die \"Error in command line arguments\\\\n\";";
            $self->{work} .= "\n";
            $self->{work} .= "\n  if (\$input ne \"\" && \$filename ne \"\") {";
            $self->{work} .= "\n    print <<EOF;";
            $self->{work} .= "\n";
            $self->{work} .= "\n    Either use the --file/--filetest options or the --input/--inputtest";
            $self->{work} .= "\n    options, not both";
            $self->{work} .= "\n";
            $self->{work} .= "\nEOF";
            $self->{work} .= "\n    printHelp();";
            $self->{work} .= "\n    exit 0;";
            $self->{work} .= "\n  }";
            $self->{work} .= "\n";
            $self->{work} .= "\n  \$mm->parse();";
            $self->{work} .= "\n";
            $self->{work} .= "\n  1;";
            $self->{work} .= "\n";
            $self->{work} .= "\n  \\n"; # add 
            $self->writeText(); # print  
            last SCRIPT; # quit 
          }
           last PARSE;  # run-once parse loop 
         } # parse block 
      } # nom script loop 

     # close open files here? yes. use break, not return
     my $outputType = $self->{sinkType};
     if ($outputType eq "file") {
       $self->{output}->flush() or die "Error flushing output file: $!";
     } elsif ($outputType eq "stdout") {
       # STDOUT is typically flushed automatically
     } elsif ($outputType eq "string") {
       # Output is in the buffer
     } else {
       print STDERR "unsupported output type: ", $outputType, "\n";
     }
   } # sub parse


 sub printHelp {
   print <<EOF;

   Nom script translated to perl by www.nomlang.org/tr/ script 
   usage:
         echo "..sometext.." | ./script
         cat somefile.txt | ./script
         ./script -f <file>
         ./script -i <text>
   options:
     --file -f <file>
       run the script with <file> as input (not stdin)
     --input -i <text>
       run the script with <text> as input
     --filetest -F <filename>
       test the translated script with file input and output
     --filestream -S <filename>
       test the translated script with file-stream input
     --inputtest -I <text>
       test the translated script with string input and output
     --help -h
       show this help

EOF

 }

 # display a message about a missing argument to the translated
 #    script 
 sub missingArgument {
   print "Missing argument.\n";
   printHelp();
   exit 1;
 }

 # display a message if an command line option is repeated
 sub duplicateSwitch {
   print "Duplicate switch found.\n";
   printHelp();
   exit 1;
 }

 sub checkTextFile {
   my ($filepath) = @_;
   eval {
     open my $fh, "<:utf8", $filepath;
     close $fh;
     return true;
   };
   if ($@) {
     if ($@ =~ /No such file or directory/) {
       print "File [$filepath] not found.\n";
     } elsif ($@ =~ /Permission denied/) {
       print "Permission denied to read file [$filepath]\n";
     } else {
       print "Error opening file $filepath: $@";
     }
     return false;
   }
   return true;
 }

package main;

  my $mm = Machine->new();
  my $input = "";
  my $filename = "";

  GetOptions (
    "file|f=s"      => $filename,
    "input|i=s"     => $input,
    "filetest|F=s"  => sub {
      my ($opt_name, $value) = @_;
      if ($value) {
        if ($filename ne "") { duplicateSwitch(); }
        if (!checkTextFile($value)) { printHelp(); exit 1; }
        $mm->parseFile($value, "out.txt");
        my $output = do {
          local $/ = undef;
          open my $fh, "<:utf8", "out.txt" or die "Could not open out.txt: $!";
          <$fh>;
        };
        print $output;
        exit 0;
      } else {
        missingArgument();
      }
    },
    "filestream|S=s" => sub {
      my ($opt_name, $value) = @_;
      if ($value) {
        if ($filename ne "") { duplicateSwitch(); }
        if (!checkTextFile($value)) { printHelp(); exit 1; }
        $mm->setFileStreamInput($value);
      } else {
        missingArgument();
      }
    },
    "inputtest|I=s" => sub {
      my ($opt_name, $value) = @_;
      if ($value) {
        if ($input ne "") { duplicateSwitch(); }
        my $text = $mm->parseString($value);
        print $text;
        exit 0;
      } else {
        missingArgument();
      }
    },
    "help|h"        => sub { printHelp(); exit 0; },
  ) or die "Error in command line arguments\n";

  if ($input ne "" && $filename ne "") {
    print <<EOF;

    Either use the --file/--filetest options or the --input/--inputtest
    options, not both

EOF
    printHelp();
    exit 0;
  }

  $mm->parse();

  1;

  
