Up to Main Index                           Up to Journal for October, 2013

                    JOURNAL FOR TUESDAY 22ND OCTOBER, 2013
______________________________________________________________________________

SUBJECT: The good, the bad and the parsed
   DATE: Wed 23 Oct 23:40:14 BST 2013

Right now the parsers are getting real big and real ugly. So I've been playing
with a few ways of restructuring and rewriting the parsers.

Now normally things would go quite and not a lot would seem to be happening.
This is mainly due to the fact that I write a lot of little test programs as I
try different things out - usually after an 'experiment' the code is just
deleted again.

This time I thought it might be interesting to see the 'experiment' that seems
to be the most promising:


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8 - - - -


  package main

  import (
    "bufio"
    "fmt"
    "os"
    "strings"
  )

  var Prompt = "> "

  func main() {

    r := bufio.NewScanner(os.Stdin)
    s := Init()

    for ; s.next != nil; s.next() {
      if s.needInput {
        s.buffer = append(s.buffer, Prompt)
        fmt.Print(strings.Join(s.buffer, "\n"))
        s.buffer = s.buffer[:0]

        if r.Scan() {
          s.input = r.Text()
          s.needInput = false
        }
      }
    }
    if len(s.buffer) > 0 {
      fmt.Println(strings.Join(s.buffer, "\n"))
    }

  }

  type state struct {
    input     string
    needInput bool
    next      func()
    name      string
    password  string
    buffer    []string
  }

  func Init() (s *state) {
    s = &state{}
    s.next = s.welcome
    return
  }

  func (s *state) welcome() {
    s.buffer = append(s.buffer, "Welcome.")
    s.next = s.needName
  }

  func (s *state) needName() {
    s.buffer = append(s.buffer, "What is your name?")
    s.next = s.checkName
    s.needInput = true
  }

  func (s *state) checkName() {
    if s.input == "" {
      s.next = s.needName
    } else {
      s.name = s.input
      s.next = s.needPassword
    }
  }

  func (s *state) needPassword() {
    s.buffer = append(s.buffer, "What is your password? (Enter to try again)")
    s.next = s.checkPassword
    s.needInput = true
  }

  func (s *state) checkPassword() {
    if s.input == "" {
      s.next = s.needName
    } else {
      s.password = s.input
      s.next = s.end
    }
  }

  func (s *state) end() {
    msg := fmt.Sprintf(
      "Hi %s, won't tell anyone your password is '%s' ;)", s.name, s.password,
    )
    s.buffer = append(s.buffer, msg)
    s.next = nil
  }


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->8 - - - -


If you want to run and play around with the above code just save it to a file,
say experiment1.go and then just run it using 'go run experiment1.go'.

It should say welcome, ask for a name and keep asking if you just hit enter.
Once it has a name it asks for a password, just hitting enter goes back to
asking for a name again - without the initial greeting. Once it has a name and
password it displays a message and exits. So it actually does quite a bit.

You can ignore most of the main function as it is emulating the networking
code by reading from the command line, although notice that the main for loop
definition is the main 'state' driver:


  for ; cs.next != nil; cs.next() {
    :
    :
    :
  }


This will 'run' the next state until the next state is nil. This replaces the
ever growing select statements in the login parser. Output messages are
batched up in the buffer and sent all together just before asking for input.

Now this may look like a lot of effort and maybe a little overkill. However
the simple login parser is already large and ugly. There is also the
unreleased menu parser and the to be written account creation/character
creation parsers will get more complicated still. So the simpler and more
straight forward the parsers are the simpler maintenance will be and the
simpler it will be for others to extend the parsers.

--
Diddymus


  Up to Main Index                           Up to Journal for October, 2013