
// 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
  func (mm *machine) unescapeChar(c string) {
    // if mm.work = "" { return }
    mm.work = strings.Replace(mm.work, "\\"+c, c, -1)
  }

  // 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 {
    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);
  // create a dummy newline so that doc structures work even
// on the first line of the file/stream.
mm.work += "nl*"
mm.push();
for !mm.eof { 
    
    /* lex block */
    for true { 
      mm.read()             /* read */
      if (!isInClass(unicode.IsSpace, mm.work)) {
        // count words per line with the accumulator
        mm.counter++    /* a+ */
        /* whilenot */
        for !isInClass(unicode.IsSpace, string(mm.peep)) {
          if mm.eof { break; }
          mm.read()
        }
        mm.tape[mm.cell] = mm.work  /* put */
        // an image structure delimiter.
        // "[[" { clear; add "*"; push; .reparse }
        // create an image file token for images. If imfile is not 
        // preceded with [[ or followed by ]] or :> or <: or a number
        // (for a width specifier)
        if (strings.HasSuffix(mm.work, ".png") || strings.HasSuffix(mm.work, ".jpg") || strings.HasSuffix(mm.work, ".jpeg") || strings.HasSuffix(mm.work, ".bmp")) {
          mm.work = ""          // clear
          mm.work += "imfile*"
          mm.push();
          break
        }
        mm.work = ""          // clear
        mm.work += "word*"
        mm.push();
        break
      }
      // keep leading space in newline token?
      if (isInList("\n", mm.work)) {
        // set accumulator == 0 so that we can count words 
        // per line (and know which is the first word)
        mm.counter = 0  /* zero */
        mm.charsRead = 0 /* nochars */
        /* while */
        for isInList(" ", string(mm.peep)) {
          if mm.eof { break }
          mm.read()
        }
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "nl*"
        mm.push();
        break
      }
      if (isInList("\r\t ", mm.work)) {
        mm.work = ""          // clear
        if (!mm.eof) {
          restart = true; break // restart
        }
      }
      break 
    }
    if restart { restart = false; continue; }
    // parse block 
    for true {
      // for debugging, add % as a latex comment.
      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
      // -------------
      // 1 token
      mm.pop();
      if (mm.work == "nl*") {
        /* nop eliminated */
      }
      // here we classify words into other tokens
      // we can use accumulator with a+ a- to determine if current
      // word is the first word of the line, or even count number of 
      // words per line. This should simplify grammar items such as
      // nl/---  and nl/star/ etc
      // another advantage, is that we can dispense with tokens such as 
      // ---, >> etc and not have to get rid of them later.
      if (mm.work == "word*") {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        // no numbers in headings!
        if (isInRange('A','Z', mm.work)) {
          mm.work = ""          // clear
          mm.work += "uuword*"
          mm.push();
          continue
        }
        // at least three --- on a newline marks a code block start
        // use 'count;' here to simplify. The token --- probably doesnt
        // need to exist.
        if (strings.HasPrefix(mm.work, "---") && isInList("-", mm.work)) {
          mm.work = ""          // clear
          mm.work += "---*"
          mm.push();
          continue
        }
        // >> on a newline marks a code line start
        if (mm.work == ">>") {
          mm.work += "*"
          mm.push();
          continue
        }
        // subheading marker
        if (strings.HasPrefix(mm.work, "....") && isInList(".", mm.work)) {
          mm.work = ""          // clear
          mm.work += "4dots*"
          mm.push();
          continue
        }
        // dash is used for lists 
        // only make a dash token if it is first word on the line
        if (mm.work == "-") {
          mm.work = ""          // clear
          mm.work += strconv.Itoa(mm.counter) /* count */ 
          if (mm.work == "1") {
            mm.work = ""          // clear
            mm.work += "dash*"
            mm.push();
            continue
          }
          mm.work = ""          // clear
          mm.work += mm.tape[mm.cell] /* get */
        }
        // ordered list start token 
        // only make token if it is first word on the line
        if (mm.work == "o/-" || mm.work == "O/-" || mm.work == "0/-") {
          mm.work = ""          // clear
          mm.work += strconv.Itoa(mm.counter) /* count */ 
          if (mm.work == "1") {
            mm.work = ""          // clear
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work += "olist*"
            mm.push();
            continue
          }
          mm.work = ""          // clear
          mm.work += mm.tape[mm.cell] /* get */
        }
        // unordered list start token 
        if (mm.work == "u/-" || mm.work == "U/-") {
          mm.work = ""          // clear
          mm.work += strconv.Itoa(mm.counter) /* count */ 
          if (mm.work == "1") {
            mm.work = ""          // clear
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work += "ulist*"
            mm.push();
            continue
          }
          mm.work = ""          // clear
          mm.work += mm.tape[mm.cell] /* get */
        }
        // definition/description list start token 
        // need to parse a bit differently because of the desc
        if (mm.work == "d/-" || mm.work == "D/-") {
          mm.work = ""          // clear
          mm.work += strconv.Itoa(mm.counter) /* count */ 
          if (mm.work == "1") {
            mm.work = ""          // clear
            // read description here, but have to escape special
            // verb cant go in here. Special chars will crash this. 
            mm.work += "\n \\item["
            /* whilenot */
            for !isInList("\n:", string(mm.peep)) {
              if mm.eof { break; }
              mm.read()
            }
            mm.work += "]"
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
            mm.work += "dlist*"
            mm.push();
            continue
          }
          mm.work = ""          // clear
          mm.work += mm.tape[mm.cell] /* get */
        }
        // star on newline marks emphasis, list or code description 
        // probably dont need star token.
        if (mm.work == "*") {
          // check that * is 1st 'word' on line using accumulator
          mm.work = ""          // clear
          mm.work += strconv.Itoa(mm.counter) /* count */ 
          if (mm.work != "1") {
            mm.work = ""          // clear
            mm.work += "*"
          }
          if (mm.work == "1") {
            mm.work = ""          // clear
            /* while */
            for isInList(" \t\f", string(mm.peep)) {
              if mm.eof { break }
              mm.read()
            }
            mm.work = ""          // clear
            /* whilenot */
            for !isInList("\n", string(mm.peep)) {
              if mm.eof { break; }
              mm.read()
            }
            mm.work = strings.Title(strings.ToLower(mm.work)) // capital
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
            // this is a trick, because we want special LaTeX chars to
            // be escaped. So, will add \\emph{} after next replace code. 
            mm.work += "::EMPH::"
            mm.work += mm.tape[mm.cell] /* get */
            mm.tape[mm.cell] = mm.work  /* put */
            //add "emline*"; push; .reparse
          }
        }
        // need to escape % # } \ and others
        // & % $ # _ { } ~ ^ \   
        // \textasciitilde, \textasciicircum, and \textbackslash
        /* replace */
        mm.work = strings.Replace(mm.work, "\\", "\\textbackslash ", -1)
        
        /* replace */
        mm.work = strings.Replace(mm.work, "&", "\\&", -1)
        
        /* replace */
        mm.work = strings.Replace(mm.work, "%", "\\%", -1)
        
        /* replace */
        mm.work = strings.Replace(mm.work, "$", "\\$", -1)
        
        /* replace */
        mm.work = strings.Replace(mm.work, "#", "\\#", -1)
        
        /* replace */
        mm.work = strings.Replace(mm.work, "_", "\\_", -1)
        
        /* replace */
        mm.work = strings.Replace(mm.work, "{", "\\{", -1)
        
        /* replace */
        mm.work = strings.Replace(mm.work, "}", "\\}", -1)
        
        /* replace */
        mm.work = strings.Replace(mm.work, "~", "\\textasciitilde", -1)
        
        /* replace */
        mm.work = strings.Replace(mm.work, "^", "\\textasciicircum", -1)
        
        /* replace */
        mm.work = strings.Replace(mm.work, ">", "\\textgreater ", -1)
        
        /* replace */
        mm.work = strings.Replace(mm.work, "<", "\\textless ", -1)
        
        /* replace */
        mm.work = strings.Replace(mm.work, "LaTeX", "\\LaTeX{}", -1)
        
        // now make the emphasis line token, after special chars have 
        // been escaped.
        if (strings.HasPrefix(mm.work, "::EMPH::")) {
          /* replace */
          mm.work = strings.Replace(mm.work, "::EMPH::", " \\emph{", -1)
          
          mm.work += "}"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "emline*"
          mm.push();
          continue
        }
        // If a previous test has matched, then the workspace should
        // be clear, and so none of the following will match.
        // graphical key representations
        if (strings.HasPrefix(mm.work, "[") && strings.HasSuffix(mm.work, "]")) {
          /* replace */
          mm.work = strings.Replace(mm.work, "[esc]", "\\Esc", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "[enter]", "\\Enter", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "[return]", "\\Enter", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "[insert]", "\\Ins", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "[shift]", "\\Shift", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "[delete]", "\\Del", -1)
          
          /* replace */
          mm.work = strings.Replace(mm.work, "[home]", "\\Home", -1)
          
          // keys defined by 'keystroke' package, can make new ones.
          // \Enter \Del  \Ins    \Esc   \Shift  \Ctrl  \Home
          // \End   \PgUp \PgDown \PrtSc \Scroll \Break
        }
        //replace '\\n' "\\textbackslash n";
        //replace '\\f' "\\textbackslash f";
        //replace '\\r' "\\textbackslash r";
        //replace '\\t' "\\textbackslash t";
        mm.tape[mm.cell] = mm.work  /* put */
        // urls, not so important for LaTex (and pdf) output.
        // Dont really need a token because we can render immediately
        // Could maybe render them as footnotes
        if (strings.HasPrefix(mm.work, "http://") || strings.HasPrefix(mm.work, "https://") || strings.HasPrefix(mm.work, "www.") || strings.HasPrefix(mm.work, "ftp://") || strings.HasPrefix(mm.work, "sftp://")) {
          // clear; add "url*"; push; .reparse
          // render as fixed pitch font
          mm.work = ""          // clear
          mm.work += "\\url{"
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "}"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
        }
        // format acronyms as a small capital font, case insensitive
        mm.work = strings.ToLower(mm.work) /* lower */
        if (mm.work == "antlr" || mm.work == "pdf" || mm.work == "json" || mm.work == "ebnf" || mm.work == "bnf" || mm.work == "dns" || mm.work == "html") {
          mm.work = ""          // clear
          mm.work += "\\textsc{\\textbf{"
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "}}"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
        }
        // restore the mixed-case version of the input word
        if (mm.work != "") {
          mm.work = ""          // clear
          mm.work += mm.tape[mm.cell] /* get */
        }
        // filenames, could be elided with quoted filenames
        if (mm.work == "parse>" || mm.work == "print" || mm.work == "pop" || mm.work == "push" || mm.work == "get" || mm.work == "put" || mm.work == ".reparse" || mm.work == ".restart" || mm.work == "add" || mm.work == "sed" || mm.work == "awk" || mm.work == "grep" || mm.work == "pep" || mm.work == "nom" || mm.work == "less" || mm.work == "stdin" || mm.work == "stdout" || mm.work == "bash" || mm.work == "lex" || mm.work == "yacc" || mm.work == "flex" || mm.work == "bison" || mm.work == "lalr" || mm.work == "gnu" || strings.HasSuffix(mm.work, ".h") || strings.HasSuffix(mm.work, ".c") || strings.HasSuffix(mm.work, ".a") || strings.HasSuffix(mm.work, ".txt") || strings.HasSuffix(mm.work, ".doc") || strings.HasSuffix(mm.work, ".py") || strings.HasSuffix(mm.work, ".rb") || strings.HasSuffix(mm.work, ".rs") || strings.HasSuffix(mm.work, ".java") || strings.HasSuffix(mm.work, ".class") || strings.HasSuffix(mm.work, ".tcl") || strings.HasSuffix(mm.work, ".tk") || strings.HasSuffix(mm.work, ".sw") || strings.HasSuffix(mm.work, ".js") || strings.HasSuffix(mm.work, ".go") || strings.HasSuffix(mm.work, ".pp") || strings.HasSuffix(mm.work, ".pss") || strings.HasSuffix(mm.work, ".cpp") || strings.HasSuffix(mm.work, ".pl") || strings.HasSuffix(mm.work, ".html") || strings.HasSuffix(mm.work, ".pdf") || strings.HasSuffix(mm.work, ".tex") || strings.HasSuffix(mm.work, ".sh") || strings.HasSuffix(mm.work, ".css") || strings.HasSuffix(mm.work, ".out") || strings.HasSuffix(mm.work, ".log") || strings.HasSuffix(mm.work, ".png") || strings.HasSuffix(mm.work, ".jpg") || strings.HasSuffix(mm.work, ".jpeg") || strings.HasSuffix(mm.work, ".bmp") || strings.HasSuffix(mm.work, ".mp3") || strings.HasSuffix(mm.work, ".wav") || strings.HasSuffix(mm.work, "aux") || strings.HasSuffix(mm.work, ".tar") || strings.HasSuffix(mm.work, ".gz") || strings.HasSuffix(mm.work, "/")) {
          mm.work = ""          // clear
          mm.work += "\\texttt{"
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "}"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
        }
        // mark up language names
        if (mm.work == "python" || mm.work == "java" || mm.work == "ruby" || mm.work == "perl" || mm.work == "tcl" || mm.work == "rust" || mm.work == "swift" || mm.work == "markdown" || mm.work == "c" || mm.work == "c++") {
          mm.work = ""          // clear
          mm.work += "\\textit{\\texttt{"
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "}}"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
        }
        // paths and directories ? 
        if (strings.HasPrefix(mm.work, "../") && mm.work != "../") {
          mm.work = ""          // clear
          mm.work += "\\texttt{"
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "}"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
        }
        if (strings.HasPrefix(mm.work, "\"") && strings.HasSuffix(mm.work, "\"") && mm.work != "\"\"" && mm.work != "\"") {
          // filenames in quotes
          mm.clip()
          mm.clop()
          mm.tape[mm.cell] = mm.work  /* put */
          // quoted uppercase words in headings
          if (isInRange('A','Z', mm.work)) {
            // add LaTeX curly quotes to the heading word
            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 += "uuword*"
            mm.push();
            continue
          }
          // markup language names
          if (mm.work == "python" || mm.work == "java" || mm.work == "ruby" || mm.work == "perl" || mm.work == "tcl" || mm.work == "rust" || mm.work == "swift" || mm.work == "markdown" || mm.work == "c" || mm.work == "c++" || mm.work == "forth") {
            mm.work = ""          // clear
            mm.work += "``\\textit{\\texttt{"
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += "}}''"
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
          }
          // markup filenames and some unix and pep/nom names as fixed-pitch
          // font. 
          if (mm.work == "pep" || mm.work == "parse>" || mm.work == "print" || mm.work == "pop" || mm.work == "push" || mm.work == "get" || mm.work == "put" || mm.work == ".reparse" || mm.work == ".restart" || mm.work == "add" || mm.work == "sed" || mm.work == "awk" || mm.work == "grep" || mm.work == "pep" || mm.work == "nom" || mm.work == "less" || mm.work == "stdin" || mm.work == "stdout" || mm.work == "bash" || strings.HasSuffix(mm.work, ".h") || strings.HasSuffix(mm.work, ".c") || strings.HasSuffix(mm.work, ".a") || strings.HasSuffix(mm.work, ".txt") || strings.HasSuffix(mm.work, ".doc") || strings.HasSuffix(mm.work, ".py") || strings.HasSuffix(mm.work, ".rb") || strings.HasSuffix(mm.work, ".rs") || strings.HasSuffix(mm.work, ".java") || strings.HasSuffix(mm.work, ".class") || strings.HasSuffix(mm.work, ".tcl") || strings.HasSuffix(mm.work, ".tk") || strings.HasSuffix(mm.work, ".sw") || strings.HasSuffix(mm.work, ".js") || strings.HasSuffix(mm.work, ".go") || strings.HasSuffix(mm.work, ".pp") || strings.HasSuffix(mm.work, ".pss") || strings.HasSuffix(mm.work, ".cpp") || strings.HasSuffix(mm.work, ".pl") || strings.HasSuffix(mm.work, ".html") || strings.HasSuffix(mm.work, ".pdf") || strings.HasSuffix(mm.work, ".tex") || strings.HasSuffix(mm.work, ".sh") || strings.HasSuffix(mm.work, ".css") || strings.HasSuffix(mm.work, ".out") || strings.HasSuffix(mm.work, ".log") || strings.HasSuffix(mm.work, ".png") || strings.HasSuffix(mm.work, ".jpg") || strings.HasSuffix(mm.work, ".jpeg") || strings.HasSuffix(mm.work, ".bmp") || strings.HasSuffix(mm.work, ".mp3") || strings.HasSuffix(mm.work, ".wav") || strings.HasSuffix(mm.work, "aux") || strings.HasSuffix(mm.work, ".tar") || strings.HasSuffix(mm.work, ".gz") || strings.HasSuffix(mm.work, ";")) {
            mm.work = ""          // clear
            mm.work += "``\\texttt{"
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += "}''"
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
          }
          // everything else in quotes (but only words without spaces!)
          if (mm.work != "") {
            mm.work = ""          // clear
            mm.work += "``\\textit{"
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += "}''"
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
          }
        }
        // filenames 
        // crude pattern checking.
        if (strings.HasPrefix(mm.work, "/") && mm.work != "/") {
          mm.clip()
          if (strings.HasSuffix(mm.work, ".")) {
            mm.work = ""          // clear
            mm.work += "\\texttt{"
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += "}"
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
          }
          mm.clip()
          if (strings.HasSuffix(mm.work, ".")) {
            mm.work = ""          // clear
            mm.work += "\\texttt{"
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += "}"
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
          }
          mm.clip()
          if (strings.HasSuffix(mm.work, ".")) {
            mm.work = ""          // clear
            mm.work += "\\texttt{"
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += "}"
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
          }
        }
        // emphasis is *likethis* (only words, not phrases) 
        if (strings.HasPrefix(mm.work, "*") && strings.HasSuffix(mm.work, "*") && mm.work != "**") {
          mm.clip()
          mm.clop()
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "\\textbf{\\emph{"
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "}}"
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
        }
        // && starting a line marks the document title 
        // the document 'title' after && or first heading, & has already 
        // been escaped
        if (mm.work == "\\&\\&") {
          mm.work = ""          // clear
          mm.work += strconv.Itoa(mm.counter) /* count */ 
          if (mm.work == "1") {
            mm.work = ""          // clear
            /* while */
            for isInList(" \t\f", string(mm.peep)) {
              if mm.eof { break }
              mm.read()
            }
            mm.work = ""          // clear
            /* whilenot */
            for !isInList("\n", string(mm.peep)) {
              if mm.eof { break; }
              mm.read()
            }
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
            mm.work += "\\centerline{\\Large \\bf "
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += "} \\medskip \n"
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
          }
        }
        // A quote, starting the line
        if (mm.work == "quote:") {
          mm.work = ""          // clear
          mm.work += strconv.Itoa(mm.counter) /* count */ 
          if (mm.work == "1") {
            // \begin{center}
            //    {\huge \`\`}\textit{$quote}{\huge ''}
            //    \textsc{$quoteauthor}
            //  \end{center}
            mm.work = ""          // clear
            /* while */
            for isInList(" \t\f", string(mm.peep)) {
              if mm.eof { break }
              mm.read()
            }
            mm.work = ""          // clear
            /* whilenot */
            for !isInList("\n", string(mm.peep)) {
              if mm.eof { break; }
              mm.read()
            }
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
            mm.work += "\\begin{center}{\\huge ``}\\textit{"
            mm.work += mm.tape[mm.cell] /* get */
            mm.work += "}{\\huge ''}\\end{center} \n"
            mm.tape[mm.cell] = mm.work  /* put */
            mm.work = ""          // clear
          }
        }
        mm.work = ""          // clear
        mm.work += "word*"
      }
      mm.pop();
      // -------------
      // 2 tokens
      // remove irrelevant image-related tokens by hand-balling to "word*" 
      if (strings.HasSuffix(mm.work, "imfile*") && !strings.HasPrefix(mm.work,"[[*")) {
        /* replace */
        mm.work = strings.Replace(mm.work, "imfile*", "word*", -1)
        
        mm.push();
        mm.push();
        continue
      }
      //--------------------
      // images 
      // standard format is [[*imfile*quote*width*float*]]*
      // A width is "50%" or "200pt"; float is left/right/center
      // imfile is a image file name
      // remove newline and blank line tokens when parsing
      // images. But this is tricky, because we want to preserve
      // them otherwise
      // vanish [[ if possible
      if (strings.HasPrefix(mm.work, "[[*") && mm.work != "[[*" && !strings.HasSuffix(mm.work,"imfile*") && !strings.HasSuffix(mm.work,"float*") && !strings.HasSuffix(mm.work,"quote*") && !strings.HasSuffix(mm.work,"width*")) {
        /* replace */
        mm.work = strings.Replace(mm.work, "[[*", "word*", -1)
        
        mm.push();
        mm.push();
        continue
      }
      // swap image tokens that are out of order, this needs to come 
      // before the empty token creation below.
      if (mm.work == "float*imfile*" || mm.work == "width*imfile*" || mm.work == "quote*imfile*" || mm.work == "width*quote*" || mm.work == "float*quote*" || mm.work == "float*width*") {
        // swap tokens
        mm.increment()     /* ++ */ 
        
        mm.increment()     /* ++ */ 
        
        mm.push();
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.pop();
        mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.push();
        mm.push();
        // now swap attributes
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work, mm.tape[mm.cell] = mm.tape[mm.cell], mm.work  /* swap */
        mm.increment()     /* ++ */ 
        
        mm.tape[mm.cell] = mm.work  /* put */
        mm.increment()     /* ++ */ 
        
        mm.work = ""          // clear
        continue
      }
      // vanish ]] 
      if (strings.HasSuffix(mm.work, "]]*") && mm.work != "]]*" && !strings.HasPrefix(mm.work,"imfile*") && !strings.HasPrefix(mm.work,"float*") && !strings.HasPrefix(mm.work,"quote*") && !strings.HasPrefix(mm.work,"width*")) {
        /* replace */
        mm.work = strings.Replace(mm.work, "]]*", "word*", -1)
        
        mm.push();
        mm.push();
        continue
      }
      // vanish imfiles 
      if (strings.HasPrefix(mm.work, "imfile*") && mm.work != "imfile*" && !strings.HasSuffix(mm.work,"float*") && !strings.HasSuffix(mm.work,"quote*") && !strings.HasSuffix(mm.work,"width*") && !strings.HasSuffix(mm.work,"]]*")) {
        /* replace */
        mm.work = strings.Replace(mm.work, "imfile*", "word*", -1)
        
        mm.push();
        mm.push();
        continue
      }
      // vanish quotes
      if (strings.HasPrefix(mm.work, "quote*") && mm.work != "quote*" && !strings.HasSuffix(mm.work,"float*") && !strings.HasSuffix(mm.work,"width*") && !strings.HasSuffix(mm.work,"]]*")) {
        /* replace */
        mm.work = strings.Replace(mm.work, "quote*", "word*", -1)
        
        mm.push();
        mm.push();
        continue
      }
      // vanish widths
      if (strings.HasPrefix(mm.work, "width*") && mm.work != "width*" && !strings.HasSuffix(mm.work,"float*") && !strings.HasSuffix(mm.work,"]]*")) {
        /* replace */
        mm.work = strings.Replace(mm.work, "width*", "word*", -1)
        
        mm.push();
        mm.push();
        continue
      }
      // vanish floats
      if (strings.HasPrefix(mm.work, "float*") && mm.work != "float*" && !strings.HasSuffix(mm.work,"]]*")) {
        /* replace */
        mm.work = strings.Replace(mm.work, "float*", "word*", -1)
        
        mm.push();
        mm.push();
        continue
      }
      // Add missing attributes here
      if (mm.work == "width*]]*") {
        mm.work = ""          // clear
        mm.work += "width*float*]]*"
        mm.push();
        mm.push();
        mm.push();
        continue
        // also add an appropriate attribute for a center float
      }
      if (mm.work == "quote*]]*") {
        mm.work = ""          // clear
        mm.work += "quote*width*]]*"
        mm.push();
        mm.push();
        mm.push();
        continue
        // also add an appropriate width
      }
      if (mm.work == "imfile*]]*") {
        mm.work = ""          // clear
        mm.work += "imfile*quote*]]*"
        mm.push();
        mm.push();
        mm.push();
        continue
        // also add an a null quote ?
      }
      // how to vanish image tokens when not needed?
      // End image token manipulation
      // ellide text
      if (mm.work == "text*text*" || mm.work == "word*text*" || mm.work == "word*word*" || mm.work == "text*word*" || mm.work == "word*uuword*" || mm.work == "text*uuword*" || mm.work == "uutext*word*" || mm.work == "uuword*word*") {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += " "
        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 += "text*"
        mm.push();
        continue
      }
      // tokenlist:
      // --- >> 4dots codeblock codeline emline nl text uutext uuword word
      // codeblock,
      // remove pesky newline tokens, 4dots handled elsewhere
      // not really working
      if (mm.work == "nl*text*" || mm.work == "nl*word*" || mm.work == "bl*text*" || mm.work == "bl*word*") {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        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 += "text*"
        mm.push();
        continue
      }
      if (mm.work == "nl*dash*") {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        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 += "dash*"
        mm.push();
        continue
      }
      if (mm.work == "nl*emline*" || mm.work == "bl*emline*") {
        mm.work = ""          // clear
        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 += "emline*"
        mm.push();
        continue
      }
      // We are using a dummy nl* token at the start of the doc, so the 
      // codeblock* codeline* etc tokens are not able to be the first token
      // of the document. So we can remove the !"codeblock*". clause.
      // multiline codeblocks with no caption 
      if (strings.HasSuffix(mm.work, "codeblock*") && !strings.HasPrefix(mm.work,"emline*")) {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "\n\n \\begin{tabular}{l}\n  "
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work += " \\end{tabular} \n"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "text*"
        mm.push();
        continue
      }
      // single line code with no caption 
      if (strings.HasSuffix(mm.work, "codeline*") && !strings.HasPrefix(mm.work,"emline*")) {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "\n\n \\begin{tabular}{l}\n  "
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work += " \\end{tabular} \n"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "text*"
        mm.push();
        continue
      }
      // eliminate emline* tokens (not followed by codeblock/line)
      // the logic is slightly different because emline* is significant before
      // other tokens, not after.
      // also, consider emline*text*nl*
      if (strings.HasPrefix(mm.work, "emline*") && !strings.HasSuffix(mm.work,"nl*") && !strings.HasSuffix(mm.work,"codeline*") && !strings.HasSuffix(mm.work,"codeblock*")) {
        /* replace */
        mm.work = strings.Replace(mm.work, "emline*", "text*", -1)
        
        mm.push();
        mm.push();
        // make emline display on its own line, even when not
        // followed by codeline/codeblock. LaTeX will treat a blank line 
        // as a paragraph break, but \newline or \\ could be used.
        if mm.cell > 0 { mm.cell-- }  /* -- */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work += "\n\n"
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "\n\n"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        continue
      }
      // remove insignificant 4dots* tokens, 
      // 4 dots (....) marks a subheading and always comes at the end of 
      // all capitals line. Just replacing the 4dots token with a text
      // token is safer and more logical.
      if (strings.HasSuffix(mm.work, "4dots*") && !strings.HasPrefix(mm.work,"uutext*") && !strings.HasPrefix(mm.work,"uuword*")) {
        /* replace */
        mm.work = strings.Replace(mm.work, "4dots*", "text*", -1)
        
        mm.push();
        mm.push();
        continue
      }
      // remove insignificant ---* tokens
      if (strings.HasSuffix(mm.work, "---*") && !strings.HasPrefix(mm.work,"nl*") && !strings.HasPrefix(mm.work,"bl*")) {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += " "
        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 += "text*"
        mm.push();
        continue
      }
      // remove insignificant >>* tokens
      // lets assume that codelines cant start a document? Or lets
      // generate a dummy nl* token at the start of the document to 
      // make parsing easier.
      // !">>*".E">>*".!B"nl*" {
      if (strings.HasSuffix(mm.work, ">>*") && !strings.HasPrefix(mm.work,"nl*") && !strings.HasPrefix(mm.work,"bl*")) {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += " "
        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 += "text*"
        mm.push();
        continue
      }
      // ellide upper case text 
      if (mm.work == "uuword*uuword*" || mm.work == "uutext*uuword*") {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += " "
        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 += "uutext*"
        mm.push();
        continue
      }
      // a blank line token for terminating lists etc 
      // bl/bl should not happen really
      if (mm.work == "nl*nl*" || mm.work == "bl*nl*" || mm.work == "bl*bl*") {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        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 += "bl*"
        mm.push();
        continue
      }
      // ellide multiple newlines 
      //"nl*nl*" {
      //  clear; get; ++; get; --; put; clear;
      //  add "nl*"; push; .reparse
      //}
      // code line (starts with >>) 
      if (mm.work == "bl*>>*" || mm.work == "nl*>>*") {
        // ignore leading space.
        mm.work = ""          // clear
        /* while */
        for isInList(" \t\f", string(mm.peep)) {
          if mm.eof { break }
          mm.read()
        }
        mm.work = ""          // clear
        // escape | so it doesnt terminate the verb environment.
        // but how to do it? or use lstlisting
        /* whilenot */
        for !isInList("\n", string(mm.peep)) {
          if mm.eof { break; }
          mm.read()
        }
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += " \\verb| "
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += " |\n"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "codeline*"
        mm.push();
        continue
      }
      // code block marker 
      if (mm.work == "bl*---*" || mm.work == "nl*---*") {
        mm.work = ""          // clear
        mm.until(",,,");
        mm.clip()
        mm.clip()
        mm.clip()
        // remove excessive indentation.
        /* replace */
        mm.work = strings.Replace(mm.work, "\n   ", "\n", -1)
        
        mm.tape[mm.cell] = mm.work  /* put */
        /* while */
        for isInList(",", string(mm.peep)) {
          if mm.eof { break }
          mm.read()
        }
        mm.work = ""          // clear
        mm.work += "\n \\begin{lstlisting}[breaklines]"
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "\n \\end{lstlisting} \n"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "codeblock*"
        mm.push();
        continue
      }
      // a code block with its preceding description
      if (mm.work == "emline*codeblock*") {
        mm.work = ""          // clear
        mm.work += "\n\n \\begin{tabular}{l}\n  "
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += " \\\\ "
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work += " \\end{tabular} \n"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "text*"
        mm.push();
        continue
      }
      // a code line with its preceding description
      // add some tabular LaTeX markup here.
      if (mm.work == "emline*codeline*") {
        mm.work = ""          // clear
        mm.work += "\n\n \\begin{tabular}{l}\n  "
        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.work += " \\end{tabular} \n"
        //add " \\end{figure}";
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "text*"
        mm.push();
        continue
      }
      // probably indicates an empty - at the end of a list
      // add a dummy text token
      if (mm.work == "olist*bl*" || mm.work == "ulist*bl*" || mm.work == "dlist*bl*") {
        mm.push();
        mm.work = ""          // clear
        mm.work += "empty"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "\n\n"
        mm.increment()     /* ++ */ 
        
        mm.tape[mm.cell] = mm.work  /* put */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work = ""          // clear
        mm.work += "text*bl*"
        mm.push();
        mm.push();
        continue
      }
      // or use this to terminate the list, and so allow nested lists
      if (mm.work == "olist*dash*" || mm.work == "ulist*dash*" || mm.work == "dlist*dash*") {
        mm.push();
        mm.work = ""          // clear
        mm.work += "empty"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "text*dash*"
        mm.push();
        mm.push();
        continue
      }
      mm.pop();
      // -------------
      // 3 tokens
      if (mm.work == "olist*word*dash*" || mm.work == "ulist*word*dash*" || mm.work == "dlist*word*dash*" || mm.work == "olist*word*bl*" || mm.work == "ulist*word*bl*" || mm.work == "dlist*word*bl*") {
        /* replace */
        mm.work = strings.Replace(mm.work, "word*", "text*", -1)
        
        // or dont reparse
        // push; push; push; .reparse
      }
      // eliminate dashes that are not part of a list
      // eg: ulist*dash* olist*text*dash* dlist*word*dash*
      // the logic is tricky, how do we know there are really 3 tokens 
      // here, and not 2. This is the problem with negative tests.
      // doesnt matter because not altering attributes here.
      if (strings.HasSuffix(mm.work, "dash*")) {
        if (!strings.HasPrefix(mm.work,"ulist*text*") && !strings.HasPrefix(mm.work,"olist*text*") && !strings.HasPrefix(mm.work,"dlist*text*")) {
          /* replace */
          mm.work = strings.Replace(mm.work, "dash*", "text*", -1)
          
          mm.push();
          mm.push();
          mm.push();
          continue
        }
      }
      if (mm.work == "olist*text*dash*") {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "\n \\item "
        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 += "olist*"
        mm.push();
        continue
      }
      // could be ellided, but for readability, no
      if (mm.work == "ulist*text*dash*") {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "\n \\item "
        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 += "ulist*"
        mm.push();
        continue
      }
      // 
      if (mm.work == "dlist*text*dash*") {
        mm.work = ""          // clear
        // already have \item start
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += " "
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        // also, put a \verbatim in [] because text is not escaped??
        mm.work += "\n \\item["
        /* whilenot */
        for !isInList("\n:", string(mm.peep)) {
          if mm.eof { break; }
          mm.read()
        }
        mm.work += "] "
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        mm.work += "dlist*"
        mm.push();
        continue
      }
      // finish off the ordered list, also could finish it off with 
      // ulist*dash* ??
      if (mm.work == "olist*text*bl*") {
        mm.work = ""          // clear
        mm.work += "\n \\begin{enumerate}\n"
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "\n \\item "
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work += "\n \\end{enumerate}\n\n"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        // insert the blankline attribute
        mm.work += "\n\n"
        mm.increment()     /* ++ */ 
        
        mm.tape[mm.cell] = mm.work  /* put */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work = ""          // clear
        mm.work += "text*bl*"
        mm.push();
        mm.push();
        continue
      }
      // finish off the unordered list
      if (mm.work == "ulist*text*bl*") {
        mm.work = ""          // clear
        mm.work += "\n \\begin{itemize}\n"
        mm.work += mm.tape[mm.cell] /* get */
        mm.work += "\n \\item "
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work += "\n \\end{itemize}\n\n"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        // insert the blankline attribute
        mm.work += "\n\n"
        mm.increment()     /* ++ */ 
        
        mm.tape[mm.cell] = mm.work  /* put */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work = ""          // clear
        mm.work += "text*bl*"
        mm.push();
        mm.push();
        continue
      }
      // finish off the description list
      if (mm.work == "dlist*text*bl*") {
        // or check here if it is D/- or d/- for nextline style
        // or use \hfill \\ on each item which also works
        mm.work = ""          // clear
        mm.work += "\n \\begin{description}[style=nextline]\n"
        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.work += "\n \\end{description}\n\n"
        mm.tape[mm.cell] = mm.work  /* put */
        mm.work = ""          // clear
        // insert the blankline attribute
        mm.work += "\n\n"
        mm.increment()     /* ++ */ 
        
        mm.tape[mm.cell] = mm.work  /* put */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work = ""          // clear
        mm.work += "text*bl*"
        mm.push();
        mm.push();
        continue
      }
      // top level headings, all upper case on the line in the source document.
      // dont need a "heading" token because we dont parse the document as a 
      // heirarchy, we just render things as we find them in the stream.
      if (mm.work == "nl*uutext*nl*" || mm.work == "nl*uuword*nl*" || mm.work == "bl*uutext*nl*" || mm.work == "bl*uuword*nl*") {
        mm.work = ""          // clear
        // Check that heading is at least 4 chars
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.clip()
        mm.clip()
        mm.clip()
        if (mm.work == "") {
          mm.work += "nl*text*nl*"
          mm.push();
          mm.push();
          mm.push();
          continue
        }
        mm.work = ""          // clear
        // make headings capital case
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        // capitalise even 1st word in latex curly quotes
        // add "<<heading\n"; print; replace "<<heading\n" "";
        if (strings.HasPrefix(mm.work, "``")) {
          mm.clop()
          mm.clop()
        }
        mm.work = strings.Title(strings.ToLower(mm.work)) // capital
        mm.tape[mm.cell] = mm.work  /* put */
        /* replace */
        mm.work = strings.Replace(mm.work, "''", "", -1)
        
        // add open curly quotes if there before.
        if (mm.work != mm.tape[mm.cell]) {
          mm.work = ""          // clear
          mm.work += "``"
          mm.work += mm.tape[mm.cell] /* get */
        }
        mm.tape[mm.cell] = mm.work  /* put */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        // newline
        mm.work += "\\section{"
        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
        // transfer nl value
        mm.increment()     /* ++ */ 
        
        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
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work += "text*nl*"
        mm.push();
        mm.push();
        continue
      }
      // simple reductions 
      if (mm.work == "nl*text*nl*" || mm.work == "nl*word*nl*" || mm.work == "bl*text*nl*" || mm.work == "bl*word*nl*" || mm.work == "text*text*nl*" || mm.work == "emline*text*nl*") {
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        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.increment()     /* ++ */ 
        
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.tape[mm.cell] = mm.work  /* put */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work = ""          // clear
        // transfer newline value
        mm.work += "text*nl*"
        mm.push();
        mm.push();
        continue
      }
      mm.pop();
      // -------------
      // 4 tokens
      // sub headings, 
      if (mm.work == "nl*uutext*4dots*nl*" || mm.work == "nl*uuword*4dots*nl*" || mm.work == "bl*uutext*4dots*nl*" || mm.work == "bl*uuword*4dots*nl*") {
        mm.work = ""          // clear
        // Check that sub heading text is at least 4 chars ?
        // yes but need to transfer 4dots and nl
        // ++; get; --; clip; clip; clip; 
        // "" { add "nl*text*nl*"; push; push; push; .reparse }
        mm.work = ""          // clear
        // make subheadings capital case
        mm.increment()     /* ++ */ 
        
        mm.work += mm.tape[mm.cell] /* get */
        // capitalise even 1st word in latex curly quotes
        if (strings.HasPrefix(mm.work, "``")) {
          mm.clop()
          mm.clop()
        }
        mm.work = strings.Title(strings.ToLower(mm.work)) // capital
        mm.tape[mm.cell] = mm.work  /* put */
        /* replace */
        mm.work = strings.Replace(mm.work, "''", "", -1)
        
        // add open curly quotes if there before.
        if (mm.work != mm.tape[mm.cell]) {
          mm.work = ""          // clear
          mm.work += "``"
          mm.work += mm.tape[mm.cell] /* get */
        }
        mm.tape[mm.cell] = mm.work  /* put */
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work = ""          // clear
        mm.work += mm.tape[mm.cell] /* get */
        // newline
        mm.work += "\\subsection{"
        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
        // transfer nl value
        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
        if mm.cell > 0 { mm.cell-- }  /* -- */
        mm.work += "text*nl*"
        mm.push();
        mm.push();
        continue
      }
      mm.push();
      mm.push();
      mm.push();
      mm.push();
      if (mm.eof) {
        // or use 'unstack' but does it adjust the tape pointer?
        mm.pop();
        mm.pop();
        mm.pop();
        mm.pop();
        mm.pop();
        mm.pop();
        // "nl*word*","nl*text*" have already been dealt with.
        // we would like "permissive" parsing, because this is just
        // a document format, not code, so will just check for starting
        // text token
        //"text*nl*","text*bl","text*" {
        if (strings.HasPrefix(mm.work, "text*") || strings.HasPrefix(mm.work, "word*")) {
          // show the token parse stack at the top of the document
          mm.increment()     /* ++ */ 
          
          mm.tape[mm.cell] = mm.work  /* put */
          mm.work = ""          // clear
          mm.work += "%% Document parse-stack is: "
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "\n"
          if mm.cell > 0 { mm.cell-- }  /* -- */
          mm.work = ""          // clear
          // make a valid LaTeX document
          mm.work += ""
          mm.work += "\n  %% <start-document>"
          mm.work += "\n  %% -------------------------------------------"
          mm.work += "\n  %%  latex generated by: mark.latex.pss "
          mm.work += "\n  %%   from source file : "
          mm.work += "\n  %%                  on: "
          mm.work += "\n  %% -------------------------------------------"
          mm.work += "\n"
          mm.work += "\n  \\documentclass[a4paper,12pt]{article}"
          mm.work += "\n  \\usepackage[margin=4pt,noheadfoot]{geometry}"
          mm.work += "\n  \\usepackage{color}                   %% to use colours, use 'xcolor' for more"
          mm.work += "\n  \\usepackage{multicol}                %% for multiple columns"
          mm.work += "\n  \\usepackage{keystroke}               %% for keyboard key images"
          mm.work += "\n  \\usepackage[toc]{multitoc}           %% for multi column table of contents"
          mm.work += "\n  \\usepackage{tocloft}                 %% to customize the table of contents"
          mm.work += "\n  \\setcounter{tocdepth}{2}             %% only display 2 levels in the contents"
          mm.work += "\n  \\setlength{\\cftbeforesecskip}{0cm}   %% make the toc more compact"
          mm.work += "\n  \\usepackage{listings}                %% for nice code listings"
          mm.work += "\n  \\usepackage{caption}                 %% "
          mm.work += "\n  \\lstset{"
          mm.work += "\n    captionpos=t,"
          mm.work += "\n    language=bash,"
          mm.work += "\n    basicstyle=\\ttfamily,           %% fixed pitch font"
          mm.work += "\n    xleftmargin=0pt,                %% margin on the left outside the frames"
          mm.work += "\n    framexleftmargin=0pt,"
          mm.work += "\n    framexrightmargin=0pt,"
          mm.work += "\n    framexbottommargin=5pt,"
          mm.work += "\n    framextopmargin=5pt,"
          mm.work += "\n    breaklines=true,                %% break long code lines"
          mm.work += "\n    breakatwhitespace=false,        %% break long code lines anywhere"
          mm.work += "\n    breakindent=10pt,               %% reduce the indent from 20pt to 10"
          mm.work += "\n    postbreak=\\mbox{{\\color{blue}\\small$\\Rightarrow$\\space}},  %% mark with arrow"
          mm.work += "\n    showstringspaces=false,            %% dont show spaces within strings"
          mm.work += "\n    framerule=2pt,                     %% thickness of the frames"
          mm.work += "\n    frame=top,frame=bottom,"
          mm.work += "\n    rulecolor=\\color{lightgrey}, "
          mm.work += "\n    % frame=l"
          mm.work += "\n    % define special comment delimiters '##(' and ')'"
          mm.work += "\n    % moredelim=[s][\\color{grey}\\itshape\\footnotesize\\ttfamily]{~(}{)},"
          mm.work += "\n  }   %% source code settings"
          mm.work += "\n  \\usepackage{graphicx}                %% to include images"
          mm.work += "\n  \\usepackage{fancybox}                %% boxes with rounded corners"
          mm.work += "\n  \\usepackage{wrapfig}                 %% flow text around tables, images"
          mm.work += "\n  \\usepackage{tabularx}                %% change width of tables"
          mm.work += "\n  \\usepackage[table]{xcolor}           %% alternate row colour tables"
          mm.work += "\n  \\usepackage{booktabs}                %% for heavier rules in tables"
          mm.work += "\n  \\usepackage[small,compact]{titlesec} %% sections more compact, less space"
          mm.work += "\n  \\usepackage{enumitem}                %% more compact and better lists"
          mm.work += "\n  \\setlist{noitemsep}                  %% reduce list item spacing"
          mm.work += "\n  \\usepackage{hyperref}     %% make urls into hyperlinks"
          mm.work += "\n  \\hypersetup{              %% add pdftex if only pdf output is required"
          mm.work += "\n     colorlinks=false,       %% set up the colours for the hyperlinks"
          mm.work += "\n     linkcolor=black,        %% internal document links black"
          mm.work += "\n     urlcolor=black,        %% url links black"
          mm.work += "\n     frenchlinks=true,"
          mm.work += "\n     bookmarks=true, pdfpagemode=UseOutlines}"
          mm.work += "\n"
          mm.work += "\n  \\geometry{ left=1.0in,right=1.0in,top=1.0in,bottom=1.0in }"
          mm.work += "\n  %% define some colours to use"
          mm.work += "\n  \\definecolor{lightgrey}{gray}{0.70}"
          mm.work += "\n  \\definecolor{grey}{gray}{0.30}"
          mm.work += "\n"
          mm.work += "\n  %% titlesec: create framed section headings"
          mm.work += "\n  %% \\titleformat{\\section}[frame]{\\normalfont}"
          mm.work += "\n  %%   {\\filleft \\footnotesize \\enspace Section \\thesection\\enspace\\enspace}"
          mm.work += "\n  %%   {3pt} {\\bfseries\\itshape\\filright}"
          mm.work += "\n"
          mm.work += "\n  \\title{The Pep/nom parsing language and machine}"
          mm.work += "\n  \\author{m.j.bishop}"
          mm.work += "\n  \\date{\\today}"
          mm.work += "\n  \\setlength{\\parindent}{0pt}"
          mm.work += "\n  %% \\setlength{\\parskip}{1ex}"
          mm.work += "\n"
          mm.work += "\n  %% label lists with stars"
          mm.work += "\n  \\renewcommand{\\labelitemi}{$\\star$}"
          mm.work += "\n"
          mm.work += "\n  \\parindent=0pt"
          mm.work += "\n  \\parskip=6pt"
          mm.work += "\n  \\begin{document}"
          mm.work += "\n"
          mm.work += "\n  "
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "\n\\end{document} \n"
          mm.work += "\n\n %% Document parsed as text*!\n"
          // show parse-stack at end of doc as well
          mm.increment()     /* ++ */ 
          
          mm.work += " %% Document parse-stack is: "
          mm.work += mm.tape[mm.cell] /* get */
          mm.work += "\n"
          if mm.cell > 0 { mm.cell-- }  /* -- */
          fmt.Printf("%s", mm.work)    // print
          os.Exit(0)
        }
        for mm.push() {}  /* stack */
        mm.work += "Document parsed unusually!\n"
        mm.work += "Stack at 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
        os.Exit(0)
      }
      break 
    } // parse
    
  }
}


// end of generated golang code
