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