Handle dots in keys
diff --git a/lexer.go b/lexer.go
index 5efbf6b..5dfff38 100644
--- a/lexer.go
+++ b/lexer.go
@@ -169,10 +169,6 @@
 			return lexEqual
 		}
 
-		if isAlphanumeric(next) {
-			return lexKey
-		}
-
 		if isSpace(next) {
 			l.ignore()
 		}
@@ -181,6 +177,10 @@
 			return lexRvalue
 		}
 
+		if isKeyChar(next) {
+			return lexKey
+		}
+
 		if l.next() == eof {
 			break
 		}
diff --git a/lexer_test.go b/lexer_test.go
index 6436378..8582520 100644
--- a/lexer_test.go
+++ b/lexer_test.go
@@ -121,6 +121,14 @@
 		token{tokenEOF, ""},
 	})
 }
+func TestKeyWithSymbolsAndEqual(t *testing.T) {
+	testFlow(t, "~!@#$^&*()_+-`1234567890[]\\|/?><.,;:' = 5", []token{
+		token{tokenKey, "~!@#$^&*()_+-`1234567890[]\\|/?><.,;:'"},
+		token{tokenEqual, "="},
+		token{tokenInteger, "5"},
+		token{tokenEOF, ""},
+	})
+}
 
 func TestKeyEqualStringEscape(t *testing.T) {
 	testFlow(t, "foo = \"hello\\\"\"", []token{
diff --git a/parser.go b/parser.go
index 6328d12..672bb35 100644
--- a/parser.go
+++ b/parser.go
@@ -6,6 +6,7 @@
 	"fmt"
 	"reflect"
 	"strconv"
+	"strings"
 	"time"
 )
 
@@ -13,7 +14,7 @@
 	flow          chan token
 	tree          *TomlTree
 	tokensBuffer  []token
-	currentGroup  string
+	currentGroup  []string
 	seenGroupKeys []string
 }
 
@@ -96,7 +97,7 @@
 	p.seenGroupKeys = append(p.seenGroupKeys, key.val)
 	p.tree.createSubTree(key.val)
 	p.assume(tokenRightBracket)
-	p.currentGroup = key.val
+	p.currentGroup = strings.Split(key.val, ".")
 	return parseStart(p)
 }
 
@@ -104,14 +105,17 @@
 	key := p.getToken()
 	p.assume(tokenEqual)
 	value := parseRvalue(p)
-	final_key := key.val
-	if p.currentGroup != "" {
-		final_key = p.currentGroup + "." + key.val
+	var final_key []string
+	if len(p.currentGroup) > 0 {
+		final_key = p.currentGroup
+	} else {
+		final_key = make([]string, 0)
 	}
-	if p.tree.Get(final_key) != nil {
-		panic(fmt.Sprintf("the following key was defined twice: %s", final_key))
+	final_key = append(final_key, key.val)
+	if p.tree.GetPath(final_key) != nil {
+		panic(fmt.Sprintf("the following key was defined twice: %s", strings.Join(final_key, ".")))
 	}
-	p.tree.Set(final_key, value)
+	p.tree.SetPath(final_key, value)
 	return parseStart(p)
 }
 
@@ -182,8 +186,6 @@
 			panic("unterminated array")
 		}
 		if follow.typ != tokenRightBracket && follow.typ != tokenComma {
-			fmt.Println(follow.typ)
-			fmt.Println(follow.val)
 			panic("missing comma")
 		}
 		if follow.typ == tokenComma {
@@ -199,7 +201,7 @@
 		flow:          flow,
 		tree:          &result,
 		tokensBuffer:  make([]token, 0),
-		currentGroup:  "",
+		currentGroup:  make([]string, 0),
 		seenGroupKeys: make([]string, 0),
 	}
 	parser.run()
diff --git a/toml.go b/toml.go
index e1a137f..dbf8ae8 100644
--- a/toml.go
+++ b/toml.go
@@ -42,8 +42,11 @@
 // Key is a dot-separated path (e.g. a.b.c).
 // Returns nil if the path does not exist in the tree.
 func (t *TomlTree) Get(key string) interface{} {
+	return t.GetPath(strings.Split(key, "."))
+}
+
+func (t *TomlTree) GetPath(keys []string) interface{} {
 	subtree := t
-	keys := strings.Split(key, ".")
 	for _, intermediate_key := range keys[:len(keys)-1] {
 		_, exists := (*subtree)[intermediate_key]
 		if !exists {
@@ -67,8 +70,11 @@
 // Key is a dot-separated path (e.g. a.b.c).
 // Creates all necessary intermediates trees, if needed.
 func (t *TomlTree) Set(key string, value interface{}) {
+	t.SetPath(strings.Split(key, "."), value)
+}
+
+func (t *TomlTree) SetPath(keys []string, value interface{}) {
 	subtree := t
-	keys := strings.Split(key, ".")
 	for _, intermediate_key := range keys[:len(keys)-1] {
 		_, exists := (*subtree)[intermediate_key]
 		if !exists {