// code generated by "translate.go.pss" a pep script
// http://bumble.sf.net/books/pars/tr/


// s.HasPrefix can be used instead of strings.HasPrefix
package main
import (
  "fmt"
  "bufio"  
  "strings"
  "strconv"
  "unicode"
  "io"  
  "os"
  "unicode/utf8"
)

// an alias for Println for brevity
var pr = fmt.Println

  /* a machine for parsing */
  type machine struct {
    SIZE int  // how many elements in stack/tape/marks
    eof bool
    charsRead int
    linesRead int
    escape rune 
    delimiter rune
    counter int
    work string
    stack []string
    cell int
    tape []string
    marks []string
    peep rune
    reader *bufio.Reader
  }

  // there is no special init for structures
  func newMachine(size int) *machine { 
    mm := machine{SIZE: size}
    mm.eof = false     // end of stream reached?
    mm.charsRead = 0   // how many chars already read
    mm.linesRead = 1   // how many lines already read
    mm.escape = '\\'
    mm.delimiter = '*'    // push/pop delimiter (default "*")
    mm.counter = 0        // a counter for anything
    mm.work = ""          // the workspace
    mm.stack = make([]string, 0, mm.SIZE)   // stack for parse tokens 
    mm.cell = 0                             // current tape cell
    // slices not arrays
    mm.tape = make([]string, mm.SIZE, mm.SIZE)  // a list of attribute for tokens 
    mm.marks = make([]string, mm.SIZE, mm.SIZE) // marked tape cells
    // or dont initialse peep until "parse()" calls "setInput()"
    // check! this is not so simple
    mm.reader = bufio.NewReader(os.Stdin)
    var err error
    mm.peep, _, err = mm.reader.ReadRune()
    if err == io.EOF { 
      mm.eof = true 
    } else if err != nil {
      fmt.Fprintln(os.Stderr, "error:", err)
      os.Exit(1)
    }
    return &mm
  }

  // method syntax.
  // func (v * vertex) abs() float64 { ... }
  // multiline strings are ok ?

  func (mm *machine) setInput(newInput string) {
    print("to be implemented")
  }

  // read one utf8 character from the input stream and 
  // update the machine.
  func (mm *machine) read() { 
    var err error
    if mm.eof { os.Exit(0) }
    mm.charsRead += 1
    // increment lines
    if mm.peep == '\n' { mm.linesRead += 1 }
    mm.work += string(mm.peep)
    // check!
    mm.peep, _, err = mm.reader.ReadRune()
    if err == io.EOF { 
      mm.eof = true 
    } else if err != nil {
      fmt.Fprintln(os.Stderr, "error:", err)
      os.Exit(1)
    }
  }

  // remove escape character: trivial method ?
  // check the python code for this, and the c code in machine.interp.c
  // bug. fix.
  func (mm *machine) unescapeChar(c string) {
    // if mm.work = "" { return }
    mm.work = strings.Replace(mm.work, "\\"+c, c, -1)
  }


  /*
  Perl code. Also allows multiple escape chars
  eg: unescape "+-xyz";
  # this walks the string and determines if the given char 
  # is already escaped or not # eg "abcab\cabc"
  # allow multiple chars for escape/unescape
  sub unescapeChar {
    my $self = shift;   # the machine
    my $chars = shift;  # list of chars to escape
    my $cc = "";
    my $result = "";
    my $isEscaped = $false;

    foreach $cc (split(//,$self->{"work"})) {
      if (($isEscaped == $false) && ($cc eq $self->{"escape"})) {
        $isEscaped = $true;
      } else { $isEscaped = $false; }
      # remove the last escape character (usually backslash)
      # this allows multiple chars for escaping
      if (($isEscaped == $true) && (index($chars, $cc) != -1)) {
        $result =~ s/.$//s; 
      }
      $result .= $cc; 
    }
    $self->{"work"} = $result;
  }

  */

  // add escape character : trivial
  func (mm *machine) escapeChar(c string) {
    mm.work = strings.Replace(mm.work, c, "\\"+c, -1)
  }

  /** a helper function to count trailing escapes */
  func (mm *machine) countEscapes(suffix string) int {
    count := 0
    ss := ""
    if strings.HasSuffix(mm.work, suffix) {
      ss = strings.TrimSuffix(mm.work, suffix)
    }
    for (strings.HasSuffix(ss, string(mm.escape))) { 
      ss = strings.TrimSuffix(ss, string(mm.escape))
      count++
    }
    return count
  }

  // reads the input stream until the workspace ends with the
  // given character or text, ignoring escaped characters
  func (mm *machine) until(suffix string) {
    if mm.eof { return; }
    // read at least one character
    mm.read()
    for true { 
      if mm.eof { return; }
      // we need to count the mm.Escape chars preceding suffix
      // if odd, keep reading, if even, stop
      if strings.HasSuffix(mm.work, suffix) {
        if (mm.countEscapes(suffix) % 2 == 0) { return }
      }
      mm.read()
    }
  }  

  /* increment the tape pointer (command ++) and grow the 
     tape and marks arrays if necessary */
  func (mm *machine) increment() { 
    mm.cell++
    if mm.cell >= len(mm.tape) {
      mm.tape = append(mm.tape, "")
      mm.marks = append(mm.marks, "")
      mm.SIZE++
    }
  }

  /* pop the last token from the stack into the workspace */
  func (mm *machine) pop() bool { 
    if len(mm.stack) == 0 { return false }
    // no, get last element of stack
    // a[len(a)-1]
    mm.work = mm.stack[len(mm.stack)-1] + mm.work
    // a = a[:len(a)-1]
    mm.stack = mm.stack[:len(mm.stack)-1]
    if mm.cell > 0 { mm.cell -= 1 }
    return true
  }

  // push the first token from the workspace to the stack 
  func (mm *machine) push() bool { 
    // dont increment the tape pointer on an empty push
    if mm.work == "" { return false }
    // push first token, or else whole string if no delimiter
    aa := strings.SplitN(mm.work, string(mm.delimiter), 2)
    if len(aa) == 1 {
      mm.stack = append(mm.stack, mm.work)
      mm.work = ""
    } else {
      mm.stack = append(mm.stack, aa[0]+string(mm.delimiter))
      mm.work = aa[1]
    }
    mm.increment()
    return true
  }

  // 
  func (mm *machine) printState() { 
    fmt.Printf("Stack %v Work[%s] Peep[%c] \n", mm.stack, mm.work, mm.peep)
    fmt.Printf("Acc:%v Esc:%c Delim:%c Chars:%v", 
      mm.counter, mm.escape, mm.delimiter, mm.charsRead)
    fmt.Printf(" Lines:%v Cell:%v EOF:%v \n", mm.linesRead, mm.cell, mm.eof)
    for ii, vv := range mm.tape {
      fmt.Printf("%v [%s] \n", ii, vv)
      if ii > 4 { return; }
    }
  } 

  func (mm *machine) goToMark(mark string) {
    markFound := false
    for ii := range mm.marks {
      if mm.marks[ii] == mark {
        mm.cell = ii; markFound = true; break
      }
    } 
    if markFound == false {
      fmt.Printf("badmark '%s'", mark)
      os.Exit(1)
    }
  }

  // this is where the actual parsing/compiling code should go
  // so that it can be used by other go classes/objects. Also
  // should have a stream argument.
  func (mm *machine) parse(s string) {
  } 

  /* adapt for clop and clip */
  func trimLastChar(s string) string {
    r, size := utf8.DecodeLastRuneInString(s)
    if r == utf8.RuneError && (size == 0 || size == 1) {
        size = 0
    }
    return s[:len(s)-size]
  }

  func (mm *machine) clip() {
    cc, _ := utf8.DecodeLastRuneInString(mm.work)
    mm.work = strings.TrimSuffix(mm.work, string(cc))  
  }

  func (mm *machine) clop() {
    _, size := utf8.DecodeRuneInString(mm.work) 
    mm.work = mm.work[size:]  
  }

  type fn func(rune) bool
  // eg unicode.IsLetter('x')
  /* check whether the string s only contains runes of type
     determined by the typeFn function */

  func isInClass(typeFn fn, s string) bool {
    if s == "" { return false; }
    for _, rr := range s {
      //if !unicode.IsLetter(rr) {
      if !typeFn(rr) { return false }
    }
    return true
  }

  /* range in format 'a,z' */
  func isInRange(start rune, end rune, s string) bool {
    if s == "" { return false; }
    for _, rr := range s {
      if (rr < start) || (rr > end) { return false }
    }
    return true
  }

  /* list of runes (unicode chars ) */
  func isInList(list string, s string) bool {
    // bug! logic incorrect. should be "onlyContainsAny"
    return strings.ContainsAny(s, list)
  }

func main() {
  // This size needs to be big for some applications. Eg 
  // calculating big palindromes. Really 
  // it should be dynamically allocated.
  var size = 30000
  var mm = newMachine(size);
  var restart = false; 
  // the go compiler complains when modules are imported but
  // not used, also if vars are not used.
  if restart {}; unicode.IsDigit('0'); strconv.Itoa(0);
  for !mm.eof { 
    
    /* lex block */
    for true { 
      // The script lexing phase
      mm.read()             /* read */
      // spaces are actually significant because they cannot occur in
      // decimal numbers, eg: '4. 03' is probably an error
      // make character counter relative to each line for more helpful
      // error messages
      if (isInList("\n", mm.work)) {
        mm.charsRead = 0 /* nochars */
      }
      if (isInClass(unicode.IsSpace, mm.work)) {
        mm.work = ""          // clear
        if (!mm.eof) {
          restart = true; break // restart
        }
        if (mm.eof) {
          break
        }
      }
      // literal token lexing
      // ; is end of an expression/equation this is needed to reduce
      //   comparison operators.
      if (isInList(";", mm.work)) {
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work += "*"
        mm.push();
        break
      }
      // for functions, eg binomial
      if (isInList(",", mm.work)) {
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work += "*"
        mm.push();
        break
      }
      // todo add % as modulus
      if (isInList("<>:!=|&", mm.work)) {
        /* while */
        for isInList("<>:!=|&", string(mm.peep)) {
          if mm.eof { break }
          mm.read()
        }
        mm.tape[mm.cell] = mm.work  /* put */
        // this is use for 'assignment'
        if (mm.work == ":=") {
          mm.work = ""          // clear
          mm.work += "="
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "=*"
          mm.push();
          break
        }
        if (mm.work == "&&") {
          mm.work = ""          // clear
          mm.work += " \\& "
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "op.and*"
          mm.push();
          break
        }
        if (mm.work == "||") {
          mm.work = ""          // clear
          mm.work += " | "
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "op.and*"
          mm.push();
          break
        }
        // for symbols like theta
        if (mm.work == ":") {
          mm.work += "*"
          mm.push();
          break
        }
        //"&&" { clear; add " \\land "; put; clear; add "op.and*"; push; .reparse }
        //"||" { clear; add " \\lor "; put; clear; add "op.and*"; push; .reparse }
        if (mm.work == "<" || mm.work == "<=" || mm.work == ">" || mm.work == ">=" || mm.work == "==" || mm.work == "!=" || mm.work == "<>") {
          // synonyms
          if (mm.work == "==") {
            mm.work = ""          // clear
            mm.work += " = "
          }
          if (mm.work == "<=") {
            mm.work = ""          // clear
            mm.work += " \\leq "
          }
          if (mm.work == ">=") {
            mm.work = ""          // clear
            mm.work += " \\geq "
          }
          if (mm.work == "<>" || mm.work == "!=") {
            mm.work = ""          // clear
            mm.work += " \\neq "
          }
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "op.compare*"
          mm.push();
          break
        }
        mm.work = ""          // clear
        mm.work += "operators"
        mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
        mm.increment()     /* ++ */ 
        
        mm.tape[mm.cell] = mm.work  /* put */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work = ""          // clear
        mm.work += "maths.help*"
        mm.push();
        mm.work += "  unknown operator '"
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "'\n"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "maths.error*"
        mm.push();
        break
      }
      // plus and minus
      if (mm.work == "+" || mm.work == "-") {
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "op.add*"
        mm.push();
      }
      // multiply and divide
      if (mm.work == "*" || mm.work == "/") {
        if (mm.work == "*") {
          mm.work = ""          // clear
          mm.work += " \\times "
        }
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "op.mul*"
        mm.push();
      }
      // to the power of, but what is the lisp power operator ???
      if (mm.work == "^") {
        mm.work = ""          // clear
        mm.work += "^"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "op.power*"
        mm.push();
      }
      // brackets for grouping
      if (mm.work == "(") {
        // it useful to have a line and char for extra
        // opening brackets.
        mm.work = ""          // clear
        mm.work += " near line:"
        mm.work += strconv.Itoa(mm.linesRead) /* lines */
        mm.work += " char:"
        mm.work += strconv.Itoa(mm.charsRead) /* chars */
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "(*"
        mm.push();
      }
      if (mm.work == ")") {
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work += "*"
        mm.push();
      }
      // for decimal number
      if (mm.work == ".") {
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "dot*"
        mm.push();
      }
      if (isInRange('0','9', mm.work)) {
        /* while */
        for isInRange('0','9', string(mm.peep)) {
          if mm.eof { break }
          mm.read()
        }
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "natnum*"
        mm.push();
      }
      // What characters are variable names ?
      if (isInClass(unicode.IsLetter, mm.work)) {
        /* while */
        for isInClass(unicode.IsLetter, string(mm.peep)) {
          if mm.eof { break }
          mm.read()
        }
        mm.tape[mm.cell] = mm.work  /* put */
        // sum is a sigma sum eg \\sum{0,x}
        //"AND" { clear; add " \\land "; put; clear; add "op.and*"; push; .reparse }
        //"OR" { clear; add " \\lor "; put; clear; add "op.or*"; push; .reparse }
        if (mm.work == "AND") {
          mm.work = ""          // clear
          mm.work += " \\& "
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "op.and*"
          mm.push();
          break
        }
        if (mm.work == "OR") {
          mm.work = ""          // clear
          mm.work += " | "
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "op.or*"
          mm.push();
          break
        }
        if (mm.work == "sqrt" || mm.work == "squareroot" || mm.work == "cuberoot" || mm.work == "4throot" || mm.work == "5throot" || mm.work == "nthroot" || mm.work == "tan" || mm.work == "cos" || mm.work == "cosine" || mm.work == "sin" || mm.work == "sine" || mm.work == "sec" || mm.work == "cosec" || mm.work == "cot" || mm.work == "sum" || mm.work == "binomial") {
          // need to take care these replacements wont interfer with
          // each other
          /* replace */
          mm.work = strings.Replace(mm.work, "cosec", "csc", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "cosine", "cos", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "sine", "sin", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "squareroot", "sqrt", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "cuberoot", "sqrt[3]", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "4throot", "sqrt[4]", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "5throot", "sqrt[5]", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "nthroot", "sqrt[n]", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "sum", "sum_", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "binomial", "binom", -1)
          
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "\\"
          mm.work += mm.tape[mm.cell] /* get */
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "function*"
          mm.push();
          break
        }
        mm.work = ""          // clear
        mm.work += "variable*"
        mm.push();
      }
      // a trick to catch bad characters. 
      // better would be a !"text" test
      if (mm.work != "") {
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "characters"
        mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
        mm.increment()     /* ++ */ 
        
        mm.tape[mm.cell] = mm.work  /* put */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work = ""          // clear
        mm.work += "maths.help*"
        mm.push();
        mm.work += "  strange character '"
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "' encountered."
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "maths.error*"
        mm.push();
        break
      }
      break 
    }
    if restart { restart = false; continue; }
    // parse block 
    for true {
      // The parse phase 
      // watch the stack at is parses: very helpful for debugging.
      // Comment out when the script works.fk
      mm.work += "% line "
      mm.work += strconv.Itoa(mm.linesRead) /* lines */
      mm.work += " char "
      mm.work += strconv.Itoa(mm.charsRead) /* chars */
      mm.work += ": "
      fmt.Printf("%s", mm.work)    // print
      mm.work = ""          // clear
      for mm.pop() {}   /* unstack */ 
      fmt.Printf("%s", mm.work)    // print
      for mm.push() {}  /* stack */
      mm.work += "\n"
      fmt.Printf("%s", mm.work)    // print
      mm.work = ""          // clear
      //---------------
      // error analysis
      // we can group all error analysis here to make the script more 
      // organised. This section helps to provide good error messages to
      // the user.
      mm.pop();
      if (mm.work == "maths.error*") {
        // get the parse stack here as well
        mm.work = ""          // clear
        mm.work += "! arithmetic expression syntax:"
        mm.work += " near line:"
        mm.work += strconv.Itoa(mm.linesRead) /* lines */
        mm.work += " char:"
        mm.work += strconv.Itoa(mm.charsRead) /* chars */
        mm.work += "\n"
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "\n"
        // print;
        // add "  The parse stack:";
        // print; --; print; clear;
        fmt.Printf("%s", mm.work)    // print
        // provide help from the maths.help* token if one was 
        // put on the stack. 
        mm.work = ""          // clear
        mm.pop();
        if (mm.work == "maths.help*") {
          mm.push();
          continue
        }
        os.Exit(0)
      }
      // using a parse token to display help
      if (mm.work == "maths.help*") {
        // the topic or category to display help for is in the
        // attribute
        mm.work = ""          // clear
        mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
        // 'brackets' is topic, 'all' is a categories
        if (mm.work == "functions" || mm.work == "all") {
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.work += ""
          mm.work += "\n      functions are predefined words applied to an expression. "
          mm.work += "\n      like 'tan' 'cos' 'sin' 'sqrt' 'cuberoot' '4throot'"
          mm.work += "\n      eg:"
          mm.work += "\n         sqrt (3^4+1)    correct"
          mm.work += "\n         sqrt 5          incorrect "
        }
        if (mm.work == "variables" || mm.work == "all") {
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.work += ""
          mm.work += "\n      variables are any alphabetic name that is not a function"
          mm.work += "\n      such as x abc longVar etc"
          mm.work += "\n      eg:"
          mm.work += "\n         var        correct"
          mm.work += "\n         var.var    incorrect "
        }
        if (mm.work == "characters" || mm.work == "all") {
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.work += ""
          mm.work += "\n      legal characters for expressions "
          mm.work += "\n        arithmetic: ^+-*/"
          mm.work += "\n        comparison: < <= > >= == != <>"
          mm.work += "\n        logic: && || AND OR"
          mm.work += "\n        grouping: ()"
          mm.work += "\n        numbers: [-+0-9.]"
          mm.work += "\n        equations: := ;  (assignment and termination)"
          mm.work += "\n        names: any alphabetic character (for functions and variables)"
          mm.work += "\n        whitespace: is ignored."
          mm.work += "\n      eg:"
          mm.work += "\n         3*size+2^0.5;    correct"
          mm.work += "\n         time := (sin(x) > sin(y));    correct"
          mm.work += "\n         4#+3            incorrect (# is not a recognised operator) "
        }
        if (mm.work == "operators.summary" || mm.work == "operators" || mm.work == "all") {
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.work += ""
          mm.work += "\n      Recognised operators are:"
          mm.work += "\n        comparison: <= < >= > == != <>"
          mm.work += "\n        arithmetic: + - * / ^"
          mm.work += "\n        logic: && || AND OR"
          mm.work += "\n        grouping: ( ) "
        }
        if (mm.work == "assignment.operator" || mm.work == "operators" || mm.work == "all") {
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.work += ""
          mm.work += "\n      The assignment operator is ':=' and the left-hand-side"
          mm.work += "\n      must be a simple variable name. Assignments must end in a "
          mm.work += "\n      semicolon."
          mm.work += "\n      eg:"
          mm.work += "\n         x := y^2+z^2;         correct"
        }
        if (mm.work == "logic.operators" || mm.work == "operators" || mm.work == "all") {
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.work += ""
          mm.work += "\n      The logic operators are && || 'AND' 'OR'"
          mm.work += "\n      AND and OR (uppercase) are synonyms for && and ||"
          mm.work += "\n      eg:"
          mm.work += "\n         && 2*x          incorrect"
        }
        if (mm.work == "compare.operators" || mm.work == "operators" || mm.work == "all") {
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.work += ""
          mm.work += "\n      The comparison operators are <= < >= > == != <>"
          mm.work += "\n      != means not equal to and '<>' is a synonym for that"
          mm.work += "\n      eg:"
          mm.work += "\n         "
          mm.work += "\n         (x==4) AND (x^2 != y)   correct (expression)"
          mm.work += "\n         sqrt(x+y^2) == x+y*3;   correct (equation)"
          mm.work += "\n         == 2*x                  incorrect"
        }
        if (mm.work == "operators" || mm.work == "all") {
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.work += ""
          mm.work += "\n      Operators must be between numbers or expressions. "
          mm.work += "\n      The exception to this are +/- signs which can precede"
          mm.work += "\n      expressions"
          mm.work += "\n      eg:"
          mm.work += "\n         4^3*(3+1)       correct"
          mm.work += "\n         -(4^2) + +3.1   correct"
          mm.work += "\n         /4+3            incorrect "
        }
        if (mm.work == "multiply.and.divide" || mm.work == "operators" || mm.work == "all") {
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.work += ""
          mm.work += "\n      Multiplication is indicated by the asterisk '*' and division"
          mm.work += "\n      by the forward-slash '/' character. These characters must be "
          mm.work += "\n      placed between 2 'expressions' (any combination of operators,"
          mm.work += "\n      variables and functions). The mathematical syntax "
          mm.work += "\n      '4x+3y' is not implemented so far - i.e implicit multiplication "
          mm.work += "\n      (but why not?)"
          mm.work += "\n      eg:"
          mm.work += "\n         4*3/(1.234 ^ 6)   correct"
          mm.work += "\n         -(3+2/)         incorrect (divide with no right expression) "
        }
        if (mm.work == "power.operator" || mm.work == "all") {
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.work += ""
          mm.work += "\n      The power operator is ^ and must occur between 2 numbers "
          mm.work += "\n      or expressions"
          mm.work += "\n      eg:"
          mm.work += "\n         12.345^(1/2)    correct (square root)"
          mm.work += "\n         ^4              incorrect "
        }
        if (mm.work == "brackets" || mm.work == "all") {
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.work += ""
          mm.work += "\n      brackets () are used to group expressions and must be "
          mm.work += "\n      balanced"
          mm.work += "\n      eg: "
          mm.work += "\n        ((5.1+3)*10.0)*6^2      correct "
          mm.work += "\n        (5.1+3)*10.0)*6^2       incorrect (extra close bracket) "
        }
        if (mm.work == "dots" || mm.work == "all") {
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.work += ""
          mm.work += "\n        The dot (.) is only used in positive and negative decimal"
          mm.work += "\n        numbers. I believe that decimals with no leading 0 are not permitted"
          mm.work += "\n        I may change this."
          mm.work += "\n        egs: 5.13 -0.1234 +456.78 0.05"
        }
        if (mm.work == "power" || mm.work == "all") {
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.work += ""
          mm.work += "\n        The power operator is '^' and has greater precedence"
          mm.work += "\n        than all other operators."
          mm.work += "\n        eg: 5/6^2+2 will parse as ((5/(6^2))+2) "
        }
        mm.work += "\n\n"
        fmt.Printf("%s", mm.work)    // print
        os.Exit(0)
      }
      // ----------------
      // 2 token errors
      mm.pop();
      // look for tokens that can't start a sequence
      if (strings.HasPrefix(mm.work, ")*") && mm.work != ")*") {
        mm.work = ""          // clear
        mm.work += "brackets"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "maths.help*"
        mm.push();
        mm.work += "  extra close bracket ) in expression?"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "maths.error*"
        mm.push();
        continue
      }
      // literal token errors
      if (strings.HasPrefix(mm.work, "dot*") && !strings.HasSuffix(mm.work,"natnum*")) {
        mm.work = ""          // clear
        mm.work += "dots"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "maths.help*"
        mm.push();
        mm.work += "  Misplaced dot or incorrect decimal number ? "
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "maths.error*"
        mm.push();
        continue
      }
      if (strings.HasSuffix(mm.work, "dot*") && !strings.HasPrefix(mm.work,"natnum*")) {
        mm.work = ""          // clear
        mm.work += "dots"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "maths.help*"
        mm.push();
        mm.work += "  Misplaced dot (eg .123 is not implemented) ? "
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "maths.error*"
        mm.push();
        continue
      }
      // the not equals test is superfluous but here for clarity
      if (strings.HasPrefix(mm.work, "(*") && mm.work != "(*") {
        if (strings.HasSuffix(mm.work, "op.mul*") || strings.HasSuffix(mm.work, "op.power*") || strings.HasSuffix(mm.work, ")*")) {
          mm.work = ""          // clear
          mm.work += "brackets"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.help*"
          mm.push();
          mm.work += "  misplaced bracket or operator? "
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.error*"
          mm.push();
          continue
        }
      }
      // lits: ().=;:
      // expr* natnum* decnum* op.compare* op.power* op.mul* op.add* sign* 
      // variable* function*
      // op.compare <= >= == != <> 
      // needs more thought
      if (strings.HasPrefix(mm.work, "op.compare*") && mm.work != "op.compare") {
        if (strings.HasSuffix(mm.work, "op.mul*") || strings.HasSuffix(mm.work, "op.power") || strings.HasSuffix(mm.work, ")*") || strings.HasSuffix(mm.work, ".*")) {
          mm.work = ""          // clear
          mm.work += "operators"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.help*"
          mm.push();
          mm.work += "  Misplaced operator ? "
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.error*"
          mm.push();
          continue
        }
      }
      // look for sequences
      if (strings.HasPrefix(mm.work, "op.add*") && mm.work != "op.add") {
        if (strings.HasSuffix(mm.work, "op.mul*") || strings.HasSuffix(mm.work, "op.power") || strings.HasSuffix(mm.work, ")*")) {
          mm.work = ""          // clear
          mm.work += "operators"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.help*"
          mm.push();
          mm.work += "  Misplaced operator ? "
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.error*"
          mm.push();
          continue
        }
      }
      // allow ** as power?
      if (strings.HasPrefix(mm.work, "op.mul*") && mm.work != "op.mul*") {
        if (strings.HasSuffix(mm.work, "op.add") || strings.HasSuffix(mm.work, "op.power") || strings.HasSuffix(mm.work, ")*")) {
          mm.work = ""          // clear
          mm.work += "operators"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.help*"
          mm.push();
          mm.work += "  Misplaced operator ? "
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.error*"
          mm.push();
          continue
        }
      }
      if (strings.HasPrefix(mm.work, "op.power*") && mm.work != "op.power*") {
        if (strings.HasSuffix(mm.work, "op.add") || strings.HasSuffix(mm.work, "op.power*") || strings.HasSuffix(mm.work, "op.power") || strings.HasSuffix(mm.work, ")*")) {
          mm.work = ""          // clear
          mm.work += "power.operator"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.help*"
          mm.push();
          mm.work += "  Misplaced operator or bracket? "
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.error*"
          mm.push();
          continue
        }
      }
      //lits: ().
      // expr* natnum* decnum* op.compare* op.power* op.mul* op.add* sign* 
      // variable* function*
      if (strings.HasPrefix(mm.work, "natnum*") && mm.work != "natnum*") {
        if (strings.HasSuffix(mm.work, "expr*") || strings.HasSuffix(mm.work, "natnum*") || strings.HasSuffix(mm.work, "decnum*") || strings.HasSuffix(mm.work, "(*")) {
          mm.work = ""          // clear
          mm.work += "  missing operator?"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.error*"
          mm.push();
          continue
        }
      }
      if (strings.HasPrefix(mm.work, "decnum*") && mm.work != "decnum*") {
        if (strings.HasSuffix(mm.work, "expr*") || strings.HasSuffix(mm.work, "natnum*") || strings.HasSuffix(mm.work, "decnum*") || strings.HasSuffix(mm.work, "(*")) {
          mm.work = ""          // clear
          mm.work += "  missing operator?"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.error*"
          mm.push();
          continue
        }
      }
      if (strings.HasPrefix(mm.work, "expr*") && mm.work != "expr*") {
        if (strings.HasSuffix(mm.work, "expr*") || strings.HasSuffix(mm.work, "natnum*") || strings.HasSuffix(mm.work, "decnum*") || strings.HasSuffix(mm.work, "(*")) {
          mm.work = ""          // clear
          mm.work += "  missing operator?"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.error*"
          mm.push();
          continue
        }
      }
      //lits: ().
      // expr* natnum* decnum* op.power* op.mul* op.add* sign* 
      // variable function
      if (strings.HasPrefix(mm.work, "variable*") && mm.work != "variable*") {
        if (strings.HasSuffix(mm.work, "variable*") || strings.HasSuffix(mm.work, "function*") || strings.HasSuffix(mm.work, "expr*") || strings.HasSuffix(mm.work, "natnum*") || strings.HasSuffix(mm.work, "decnum*") || strings.HasSuffix(mm.work, "(*") || strings.HasSuffix(mm.work, ".*")) {
          mm.work = ""          // clear
          mm.work += "variables"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.help*"
          mm.push();
          mm.work = ""          // clear
          mm.work += "  misplaced variable name?"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.error*"
          mm.push();
          continue
        }
      }
      if (strings.HasPrefix(mm.work, "function*") && mm.work != "function*" && !strings.HasSuffix(mm.work,"(*")) {
        mm.work = ""          // clear
        mm.work += "functions"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "maths.help*"
        mm.push();
        mm.work = ""          // clear
        mm.work += "  incorrect function syntax?"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "maths.error*"
        mm.push();
        continue
      }
      if (mm.eof) {
        // try to diagnose missing close bracket errors at end of script
        // eg (*expr*
        // we have a line/char number in the open bracket tape cell
        if (strings.HasPrefix(mm.work, "(*")) {
          mm.work = ""          // clear
          mm.work += "* missing close bracket ) ?\n"
          mm.work += "  At "
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += " there is an opening bracket which does \n"
          mm.work += "  not seem to be matched with a closing bracket "
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.error*"
          mm.push();
          continue
        }
        if (strings.HasSuffix(mm.work, "dot*")) {
          // provide dot help with a help parse token
          mm.work = ""          // clear
          mm.work += "dot"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.help*"
          mm.push();
          mm.work = ""          // clear
          mm.work += "  Misplaced dot '.' at end of expression. \n"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.error*"
          mm.push();
          continue
        }
        if (strings.HasSuffix(mm.work, "op.add*") || strings.HasSuffix(mm.work, "op.mul*") || strings.HasSuffix(mm.work, "op.power*")) {
          mm.work = ""          // clear
          mm.work += "operators"
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          mm.increment()     /* ++ */ 
          
          mm.tape[mm.cell] = mm.work  /* put */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          // preserve operator in tape.cell+1
          mm.work = ""          // clear
          mm.work += "maths.help*"
          mm.push();
          mm.work += "  Misplaced operator at '"
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "' end of expression."
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.error*"
          mm.push();
          continue
        }
      }
      // ----------------
      // 3 token errors
      mm.pop();
      // todo expr op.compare followed by ; or ) are errors
      // unterminated comparison 
      mm.push();
      mm.push();
      mm.push();
      // end of error analysis
      // ---------------
      mm.pop();
      // resolve numbers to expressions to simplify grammar rules
      if (mm.work == "decnum*" || mm.work == "variable*") {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "expr*"
        mm.push();
        continue
      }
      // reduce natnum to expression at end of file, no!!!
      if (mm.eof) {
        if (mm.work == "natnum*") {
          // check not preceded by dot (could be decimal)
          mm.pop();
          if (mm.work != "dot*natnum*") {
            /* replace */
            mm.work = strings.Replace(mm.work, "natnum*", "expr*", -1)
            
            mm.push();
            mm.push();
            continue
          }
          mm.push();
        }
      }
      //-----------------
      // 2 token reductions
      mm.pop();
      // eg: (:pi + 2^:pi)/2
      if (mm.work == ":*expr*") {
        mm.work = ""          // clear
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        // mathemtical symbols and greek letters. where there is no capital
        // the roman letter works. eg B Beta
        if (mm.work == "pi" || mm.work == "Pi" || mm.work == "alpha" || mm.work == "beta" || mm.work == "gamma" || mm.work == "Gamma" || mm.work == "delta" || mm.work == "Delta" || mm.work == "epsilon" || mm.work == "eepsilon" || mm.work == "zeta" || mm.work == "eta" || mm.work == "theta" || mm.work == "Theta" || mm.work == "iota" || mm.work == "kappa" || mm.work == "lambda" || mm.work == "Lambda" || mm.work == "mu" || mm.work == "upsilon" || mm.work == "Upsilon" || mm.work == "chi" || mm.work == "psi" || mm.work == "Psi" || mm.work == "omega" || mm.work == "Omega" || mm.work == "nu" || mm.work == "xi" || mm.work == "Xi" || mm.work == "ro" || mm.work == "rro" || mm.work == "sigma" || mm.work == "Sigma" || mm.work == "tau" || mm.work == "theta" || mm.work == "infinity") {
          /* replace */
          mm.work = strings.Replace(mm.work, "ro", "varro", -1)
          
          // a curly ro 
          /* replace */
          mm.work = strings.Replace(mm.work, "eepsilon", "varepsilon", -1)
          
          // a curly e epsilon
          /* replace */
          mm.work = strings.Replace(mm.work, "infinity", "infty", -1)
          
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += " \\"
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += " "
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "variable*"
          mm.push();
          continue
        }
        // a bit of a hack to include +/- as an addition subtraction
        // operator.
        if (mm.work == "plusminus") {
          mm.work = ""          // clear
          mm.work += " \\pm "
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "op.add*"
          mm.push();
          continue
        }
        // save the incorrect symbol name for the error
        // message.
        mm.increment()     /* ++ */ 
        
        mm.tape[mm.cell] = mm.work  /* put */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work = ""          // clear
        mm.work += "symbols"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "maths.help*"
        mm.push();
        mm.work = ""          // clear
        mm.work += "  unknown symbol '"
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "'"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "maths.error*"
        mm.push();
        continue
      }
      // reduce natnums to expressions if not followed by a dot
      // this creatly reduces complexity of parsing rules later
      // already ensured not "natnum*natnum*" in error checks above.
      if (strings.HasPrefix(mm.work, "natnum*") && mm.work != "natnum*" && !strings.HasSuffix(mm.work,"dot*")) {
        /* replace */
        mm.work = strings.Replace(mm.work, "natnum*", "expr*", -1)
        
        mm.push();
        mm.push();
        continue
      }
      if (mm.work == "sign*expr*") {
        mm.work = ""          // clear
        mm.work += " "
        mm.work += mm.tape[mm.cell] /* get */
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work += " "
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "expr*"
        mm.push();
        continue
      }
      // a list of equations
      if (mm.work == "equation*equation*" || mm.work == "equationset*equation*") {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "\n"
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "equationset*"
        mm.push();
        continue
      }
      // There may be an issue with reducing sign*natnum in other
      // cases
      if (mm.eof) {
        if (mm.work == "sign*natnum*") {
          mm.work = ""          // clear
          mm.work += " "
          mm.work += mm.tape[mm.cell] /* get */
          mm.increment()     /* ++ */ 
          
          mm.work += mm.tape[mm.cell] /* get */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.work += " "
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "expr*"
          mm.push();
          continue
        }
      }
      //-----------------
      // 3 tokens
      mm.pop();
      // an equation is just an expression followed by ';'
      // but we need 'lookbehind' here, otherwise partial expressions 
      // will resolve to equations leaving the prefix orphaned so to speak.
      // only 2 tokens, first equation
      // discard the semicolon 
      if (mm.work == "expr*;*") {
        mm.work = ""          // clear
        mm.work += "\\[\n"
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "\n"
        mm.work += "\\]"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "equation*"
        mm.push();
        continue
      }
      if (strings.HasSuffix(mm.work, "expr*;*")) {
        if (strings.HasPrefix(mm.work, "equation*") || strings.HasPrefix(mm.work, "equationset*")) {
          /* replace */
          mm.work = strings.Replace(mm.work, "expr*;*", "equation*", -1)
          
          mm.push();
          mm.push();
          mm.work += "\\[\n"
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "\n"
          mm.work += "\\]"
          mm.tape[mm.cell] = mm.work  /* put */
          // realign tape pointer
          mm.work = ""          // clear
          mm.increment()     /* ++ */ 
          
          continue
        }
      }
      // These are signs at the beginning of the expression
      // only 2 tokens
      if (mm.work == "op.add*natnum*" || mm.work == "op.add*expr*") {
        /* replace */
        mm.work = strings.Replace(mm.work, "op.add*", "sign*", -1)
        
        mm.push();
        mm.push();
        continue
      }
      // +/- at beginning, 3 tokens
      if (strings.HasPrefix(mm.work, "sign*expr*") && mm.work != "sign*expr*") {
        /* replace */
        mm.work = strings.Replace(mm.work, "sign*expr*", "expr*", -1)
        
        mm.push();
        mm.push();
        // need to compose attributes and transfer other attributes
        // compose sign/exp attribute in Lisp syntax
        if mm.cell > 0 { mm.cell-- }  /* -- */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work += " "
        mm.work += mm.tape[mm.cell] /* get */
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += " "
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.increment()     /* ++ */ 
        
        mm.increment()     /* ++ */ 
        
        // transfer invisible token attribute
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.increment()     /* ++ */ 
        
        mm.work = ""          // clear
        continue
      }
      // convert +/- oppadd* token to a sign* token where appropriate
      // If only 2 tokens (not 3) then start of document
      if (strings.HasSuffix(mm.work, "op.add*expr*") && !strings.HasPrefix(mm.work,"expr*")) {
        /* replace */
        mm.work = strings.Replace(mm.work, "op.add*expr*", "sign*expr*", -1)
        
        mm.push();
        mm.push();
        mm.push();
        continue
      }
      if (strings.HasSuffix(mm.work, "op.add*natnum*") && !strings.HasPrefix(mm.work,"expr*")) {
        /* replace */
        mm.work = strings.Replace(mm.work, "op.add*natnum*", "sign*natnum*", -1)
        
        mm.push();
        mm.push();
        mm.push();
        continue
      }
      // we dont need any look ahead here because '^' the power operator
      // has precedence over multiply/divide/add/subtract.
      // precedence. But natnum* only becomes and expr* when it sees 
      // the following token. So need another 4 token rule
      if (mm.work == "expr*op.power*expr*") {
        mm.work = ""          // clear
        // can also remove brackets here. see op.mul divide for example
        mm.work += " "
        mm.work += mm.tape[mm.cell] /* get */
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        mm.increment()     /* ++ */ 
        
        mm.work += "{"
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "}"
        mm.work += " "
        if mm.cell > 0 { mm.cell-- }  /* -- */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "expr*"
        mm.push();
        continue
      }
      // parse positive decimal numbers like 02.345
      if (mm.work == "natnum*dot*natnum*") {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        // or parse to decnum* here to make negation better
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "expr*"
        mm.push();
        continue
      }
      // an interesting trick to parse a 4 token pattern before
      // a 3 token pattern. Be aware about popping nothing (empty stack) 
      if (mm.work == "(*expr*)*") {
        mm.pop();
        // eg: sqrt(4+9)
        if (mm.work == "function*(*expr*)*") {
          mm.work = ""          // clear
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "{"
          mm.increment()     /* ++ */ 
          
          mm.increment()     /* ++ */ 
          
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "}"
          if mm.cell > 0 { mm.cell-- }  /* -- */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "expr*"
          mm.push();
          continue
        }
        // only push if something was popped
        if (mm.work != "(*expr*)*") {
          mm.push();
        }
        mm.work = ""          // clear
        mm.work += "("
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += ")"
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "expr*"
        mm.push();
        continue
      }
      if (mm.eof) {
        // natnums have already been "reduced" to expr* at end of stream 
        if (mm.work == "expr*op.add*expr*") {
          mm.work = ""          // clear
          mm.work += " "
          mm.work += mm.tape[mm.cell] /* get */
          mm.increment()     /* ++ */ 
          
          mm.work += mm.tape[mm.cell] /* get */
          mm.increment()     /* ++ */ 
          
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += " "
          if mm.cell > 0 { mm.cell-- }  /* -- */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "expr*"
          mm.push();
          continue
        }
        // make / into fractions because they look good.
        if (mm.work == "expr*op.mul*expr*") {
          mm.work = ""          // clear
          mm.increment()     /* ++ */ 
          
          mm.work += mm.tape[mm.cell] /* get */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          if (mm.work == "/") {
            // remove brackets from fractions
            mm.work = ""          // clear
            mm.work += mm.tape[mm.cell] /* get */
            if (strings.HasPrefix(mm.work, "(") && strings.HasSuffix(mm.work, ")")) {
              mm.clip()
              mm.clop()
              mm.tape[mm.cell] = mm.work  /* put */
            }
            mm.work = ""          // clear
            mm.increment()     /* ++ */ 
            
            mm.increment()     /* ++ */ 
            
            mm.work += mm.tape[mm.cell] /* get */
            if (strings.HasPrefix(mm.work, "(") && strings.HasSuffix(mm.work, ")")) {
              mm.clip()
              mm.clop()
              mm.tape[mm.cell] = mm.work  /* put */
            }
            if mm.cell > 0 { mm.cell-- }  /* -- */
            if mm.cell > 0 { mm.cell-- }  /* -- */
            mm.work = ""          // clear
            mm.work += "\\frac{"
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += "}"
            mm.increment()     /* ++ */ 
            
            mm.increment()     /* ++ */ 
            
            mm.work += "{"
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += "}"
          }
          if (mm.work == " \\times ") {
            mm.work = ""          // clear
            mm.work += " "
            mm.work += mm.tape[mm.cell] /* get */
            mm.increment()     /* ++ */ 
            
            mm.work += mm.tape[mm.cell] /* get */
            mm.increment()     /* ++ */ 
            
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += " "
          }
          if mm.cell > 0 { mm.cell-- }  /* -- */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "expr*"
          mm.push();
          continue
        }
      }
      //-----------------
      // 4 tokens parse token reductions
      mm.pop();
      // a better lookahead, this will work within another language
      // it only looks for operators with more precedence.
      // reduce comparisons and logic concats to expression, 
      // so we only reduce comparisons 
      // when surrounded by brackets or terminated with ; or ,
      // if this works we can remove several rules below
      // eg: (x^2 != y)  
      if (strings.HasPrefix(mm.work, "expr*op.compare*expr*") || strings.HasPrefix(mm.work, "expr*op.and*expr*") || strings.HasPrefix(mm.work, "expr*op.or*expr*")) {
        if (mm.work != "expr*op.compare*expr*" && mm.work != "expr*op.and*expr*" && mm.work != "expr*op.or*expr*") {
          if (strings.HasSuffix(mm.work, ")*") || strings.HasSuffix(mm.work, ",*") || strings.HasSuffix(mm.work, ";*")) {
            /* replace */
            mm.work = strings.Replace(mm.work, "expr*op.and*expr*", "expr*", -1)
            
            /* replace */
            mm.work = strings.Replace(mm.work, "expr*op.or*expr*", "expr*", -1)
            
            /* replace */
            mm.work = strings.Replace(mm.work, "expr*op.compare*expr*", "expr*", -1)
            
            mm.push();
            mm.push();
            // assemble attribs for new exp token,
            if mm.cell > 0 { mm.cell-- }  /* -- */
            if mm.cell > 0 { mm.cell-- }  /* -- */
            mm.work += " "
            mm.work += mm.tape[mm.cell] /* get */
            mm.increment()     /* ++ */ 
            
            mm.work += mm.tape[mm.cell] /* get */
            mm.increment()     /* ++ */ 
            
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += " "
            if mm.cell > 0 { mm.cell-- }  /* -- */
            if mm.cell > 0 { mm.cell-- }  /* -- */
            mm.tape[mm.cell] = mm.work  /* put */
            // transfer unknown token attrib 
            mm.work = ""          // clear
            mm.increment()     /* ++ */ 
            
            mm.increment()     /* ++ */ 
            
            mm.increment()     /* ++ */ 
            
            mm.work += mm.tape[mm.cell] /* get */
            if mm.cell > 0 { mm.cell-- }  /* -- */
            if mm.cell > 0 { mm.cell-- }  /* -- */
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
            // realign tape pointer 
            mm.increment()     /* ++ */ 
            
            continue
          }
        }
      }
      // for latex eg in sigma sums
      // eg:  ; 
      if (strings.HasPrefix(mm.work, "expr*=*expr*") && mm.work != "expr*=*expr*") {
        if (strings.HasSuffix(mm.work, ")*") || strings.HasSuffix(mm.work, ",*") || strings.HasSuffix(mm.work, ";*")) {
          // check that it is a simple variable name. Slightly tricky because
          // variables are instantly reduced to expressions.
          //clear; 
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          if (!isInClass(unicode.IsLetter, mm.work)) {
            mm.work = ""          // clear
            mm.work += "assignment.operator"
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
            mm.work += "maths.help*"
            mm.push();
            mm.work += "  Left-hand-side of equation not a variable? "
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
            mm.work += "maths.error*"
            mm.push();
            continue
          }
          mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
          /* replace */
          mm.work = strings.Replace(mm.work, "expr*=*expr*", "expr*", -1)
          
          mm.push();
          mm.push();
          // assemble attribs for new exp token,
          if mm.cell > 0 { mm.cell-- }  /* -- */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.work += " "
          mm.work += mm.tape[mm.cell] /* get */
          mm.increment()     /* ++ */ 
          
          mm.work += mm.tape[mm.cell] /* get */
          mm.increment()     /* ++ */ 
          
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += " "
          if mm.cell > 0 { mm.cell-- }  /* -- */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.tape[mm.cell] = mm.work  /* put */
          // transfer unknown token attrib 
          mm.work = ""          // clear
          mm.increment()     /* ++ */ 
          
          mm.increment()     /* ++ */ 
          
          mm.increment()     /* ++ */ 
          
          mm.work += mm.tape[mm.cell] /* get */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          // realign tape pointer 
          mm.increment()     /* ++ */ 
          
          continue
        }
      }
      // op.mul (*/) and op.power (^) have more precedence that +/- 
      if (strings.HasPrefix(mm.work, "expr*op.add*expr*") && mm.work != "expr*op.add*expr*") {
        if (!strings.HasSuffix(mm.work,"op.mul*") && !strings.HasSuffix(mm.work,"op.power*")) {
          /* replace */
          mm.work = strings.Replace(mm.work, "expr*op.add*expr*", "expr*", -1)
          
          mm.push();
          mm.push();
          // assemble attribs for new exp token,
          if mm.cell > 0 { mm.cell-- }  /* -- */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.work += " "
          mm.work += mm.tape[mm.cell] /* get */
          mm.increment()     /* ++ */ 
          
          mm.work += mm.tape[mm.cell] /* get */
          mm.increment()     /* ++ */ 
          
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += " "
          if mm.cell > 0 { mm.cell-- }  /* -- */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.tape[mm.cell] = mm.work  /* put */
          // transfer unknown token attrib 
          mm.work = ""          // clear
          mm.increment()     /* ++ */ 
          
          mm.increment()     /* ++ */ 
          
          mm.increment()     /* ++ */ 
          
          mm.work += mm.tape[mm.cell] /* get */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          // realign tape pointer 
          mm.increment()     /* ++ */ 
          
          continue
        }
      }
      // op.power (^) has more precedence that */
      if (strings.HasPrefix(mm.work, "expr*op.mul*expr*") && mm.work != "expr*op.mul*expr*") {
        if (!strings.HasSuffix(mm.work,"op.power*")) {
          /* replace */
          mm.work = strings.Replace(mm.work, "expr*op.mul*expr*", "expr*", -1)
          
          mm.push();
          mm.push();
          // assemble times or fraction
          mm.work = ""          // clear
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.work += mm.tape[mm.cell] /* get */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          if (mm.work == "/") {
            // remove brackets from fractions
            mm.work = ""          // clear
            mm.work += mm.tape[mm.cell] /* get */
            if (strings.HasPrefix(mm.work, "(") && strings.HasSuffix(mm.work, ")")) {
              mm.clip()
              mm.clop()
              mm.tape[mm.cell] = mm.work  /* put */
            }
            mm.work = ""          // clear
            mm.increment()     /* ++ */ 
            
            mm.increment()     /* ++ */ 
            
            mm.work += mm.tape[mm.cell] /* get */
            if (strings.HasPrefix(mm.work, "(") && strings.HasSuffix(mm.work, ")")) {
              mm.clip()
              mm.clop()
              mm.tape[mm.cell] = mm.work  /* put */
            }
            if mm.cell > 0 { mm.cell-- }  /* -- */
            if mm.cell > 0 { mm.cell-- }  /* -- */
            mm.work = ""          // clear
            mm.work += "\\frac{"
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += "}"
            mm.increment()     /* ++ */ 
            
            mm.increment()     /* ++ */ 
            
            mm.work += "{"
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += "}"
          }
          if (mm.work == " \\times ") {
            mm.work = ""          // clear
            mm.work += " "
            mm.work += mm.tape[mm.cell] /* get */
            mm.increment()     /* ++ */ 
            
            mm.work += mm.tape[mm.cell] /* get */
            mm.increment()     /* ++ */ 
            
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += " "
          }
          if mm.cell > 0 { mm.cell-- }  /* -- */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.increment()     /* ++ */ 
          
          mm.increment()     /* ++ */ 
          
          mm.increment()     /* ++ */ 
          
          mm.work += mm.tape[mm.cell] /* get */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          // realign tape pointer 
          mm.increment()     /* ++ */ 
          
          continue
        }
      }
      // natnum/var/decnum only become expressions when the following
      // token is seen, this is why we need a 'lookahead' rule here. 
      if (strings.HasPrefix(mm.work, "expr*op.power*expr*") && mm.work != "expr*op.power*expr*") {
        /* replace */
        mm.work = strings.Replace(mm.work, "expr*op.power*expr*", "expr*", -1)
        
        mm.push();
        mm.push();
        if mm.cell > 0 { mm.cell-- }  /* -- */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work += " "
        mm.work += mm.tape[mm.cell] /* get */
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += " "
        if mm.cell > 0 { mm.cell-- }  /* -- */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.increment()     /* ++ */ 
        
        mm.increment()     /* ++ */ 
        
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        // realign tape pointer 
        mm.increment()     /* ++ */ 
        
        continue
      }
      //-----------------
      // 5 tokens parse token reductions
      mm.pop();
      //-----------------
      // 6 tokens parse token reductions
      mm.pop();
      // todo: this should be 3 arguments eg sum(0,:infinity,x+y)
      // eg: sum(x=0,100)
      // need to make assignments reduce here
      if (mm.work == "function*(*expr*,*expr*)*") {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        if (mm.work != "\\sum_" && mm.work != "\\binom") {
          mm.work = ""          // clear
          mm.work += "functions"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.help*"
          mm.push();
          mm.work = ""          // clear
          mm.work += "  sum and binom take 2 arguments."
          mm.tape[mm.cell] = mm.work  /* put */
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "maths.error*"
          mm.push();
          continue
        }
        mm.increment()     /* ++ */ 
        
        mm.increment()     /* ++ */ 
        
        mm.work += "{"
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "}"
        // sum has a funny syntax
        if (strings.HasPrefix(mm.work, "\\sum")) {
          mm.work += "^"
        }
        mm.work += "{"
        mm.increment()     /* ++ */ 
        
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "}"
        if mm.cell > 0 { mm.cell-- }  /* -- */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "expr*"
        mm.push();
        continue
      }
      mm.push();
      mm.push();
      mm.push();
      mm.push();
      mm.push();
      mm.push();
      if (mm.eof) {
        mm.pop();
        if (mm.work == "expr*") {
          mm.work = ""          // clear
          mm.work += "\\[\n"
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "\n"
          mm.work += "\\]"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "equation*"
          mm.push();
          continue
        }
        mm.push();
      }
      if (mm.eof) {
        mm.pop();
        mm.pop();
        if (mm.work == "expr*" || mm.work == "equation*" || mm.work == "equationset*") {
          mm.work = ""          // clear
          // create a latex document to display the equation
          mm.work += "\\documentclass{article}\n"
          mm.work += "\\usepackage{amsmath}\n"
          mm.work += "% or \\usepackage{mathtools}\n"
          mm.work += "\\usepackage{xcolor}\n"
          mm.work += "\\usepackage{multicol}\n"
          mm.work += "\\begin{document}\n"
          // turn off page numbers
          mm.work += "\\pagestyle{empty}\n"
          mm.work += "\\huge\n"
          mm.work += "\\color{blue}\n\n"
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "\n"
          mm.work += "\\end{document}\n"
          fmt.Printf("%s", mm.work)    // print
          mm.work = ""          // clear
          os.Exit(0)
        }
        mm.push();
        mm.push();
        mm.work += "No, it doesn't look like a single valid arithmetic \n"
        mm.work += "'in-fix' expression. The parse stack was: "
        fmt.Printf("%s", mm.work)    // print
        mm.work = ""          // clear
        for mm.pop() {}   /* unstack */ 
        mm.work += "\n"
        fmt.Printf("%s", mm.work)    // print
        os.Exit(0)
      }
      break 
    } // parse
    
  }
}


// end of generated 'go' code