parser.go version 2...!
diff --git a/parser.go b/parser.go
index 12dffe3..4c9232d 100644
--- a/parser.go
+++ b/parser.go
@@ -2,6 +2,7 @@
 
 import (
 	"bufio"
+	"bytes"
 	"errors"
 	"io"
 	"os"
@@ -13,10 +14,13 @@
 }
 
 type parser struct {
-	rd     *bufio.Reader
-	mk     Makefile
-	lineno int
-	done   bool
+	rd         *bufio.Reader
+	mk         Makefile
+	lineno     int
+	elineno    int // lineno == elineno unless there is trailing '\'.
+	un_buf     []byte
+	has_un_buf bool
+	done       bool
 }
 
 func exists(filename string) bool {
@@ -42,6 +46,49 @@
 	}
 }
 
+func (p *parser) readLine() []byte {
+	if p.has_un_buf {
+		p.has_un_buf = false
+		return p.un_buf
+	}
+
+	p.lineno = p.elineno
+	line, err := p.rd.ReadBytes('\n')
+	p.lineno++
+	if err == io.EOF {
+		p.done = true
+	} else if err != nil {
+		panic(err)
+	}
+
+	if len(line) > 0 {
+		line = line[0 : len(line)-1]
+	}
+
+	// TODO: Handle \\ at the end of the line?
+	for len(line) > 0 && line[len(line)-1] == '\\' {
+		line = line[:len(line)-1]
+		nline := p.readLine()
+		p.elineno++
+		line = append(line, nline...)
+	}
+
+	index := bytes.IndexByte(line, '#')
+	if index >= 0 {
+		line = line[:index]
+	}
+
+	return line
+}
+
+func (p *parser) unreadLine(line []byte) {
+	if p.has_un_buf {
+		panic("unreadLine twice!")
+	}
+	p.un_buf = line
+	p.has_un_buf = true
+}
+
 func (p *parser) readByte() (byte, error) {
 	ch, err := p.rd.ReadByte()
 	if err != nil {
@@ -163,29 +210,70 @@
 }
 
 func (p *parser) parse() (Makefile, error) {
-	for {
-		tok, err := p.getNextToken()
-		Log("tok=%s", tok)
-		if err == io.EOF {
-			return p.mk, nil
-		} else if err != nil {
-			return p.mk, err
+	for !p.done {
+		line := p.readLine()
+
+		for i, ch := range line {
+			switch ch {
+			case ':':
+				// TODO: Handle := and ::=.
+				lhs := string(bytes.TrimSpace(line[:i]))
+				rhs := string(bytes.TrimSpace(line[i+1:]))
+				ast := &RuleAST{
+					lhs: lhs,
+					rhs: rhs,
+				}
+				ast.lineno = p.lineno
+				for {
+					line := p.readLine()
+					if len(line) == 0 {
+						break
+					} else if line[0] == '\t' {
+						ast.cmds = append(ast.cmds, string(bytes.TrimSpace(line)))
+					} else {
+						p.unreadLine(line)
+						break
+					}
+				}
+				p.mk.stmts = append(p.mk.stmts, ast)
+			case '=':
+				lhs := string(bytes.TrimSpace(line[:i]))
+				rhs := string(bytes.TrimSpace(line[i+1:]))
+				ast := &AssignAST{
+					lhs: lhs,
+					rhs: rhs,
+				}
+				ast.lineno = p.lineno
+				p.mk.stmts = append(p.mk.stmts, ast)
+			case '?':
+				panic("TODO")
+			}
 		}
-		switch tok {
-		default:
-			ntok, err := p.getNextToken()
-			if err != nil {
+
+		/*
+			tok, err := p.getNextToken()
+			Log("tok=%s", tok)
+			if err == io.EOF {
+				return p.mk, nil
+			} else if err != nil {
 				return p.mk, err
 			}
-			switch ntok {
-			case "=":
-				ast := p.parseAssign(tok)
-				p.mk.stmts = append(p.mk.stmts, ast)
-			case ":":
-				ast := p.parseRule(tok)
-				p.mk.stmts = append(p.mk.stmts, ast)
+			switch tok {
+			default:
+				ntok, err := p.getNextToken()
+				if err != nil {
+					return p.mk, err
+				}
+				switch ntok {
+				case "=":
+					ast := p.parseAssign(tok)
+					p.mk.stmts = append(p.mk.stmts, ast)
+				case ":":
+					ast := p.parseRule(tok)
+					p.mk.stmts = append(p.mk.stmts, ast)
+				}
 			}
-		}
+		*/
 	}
 	return p.mk, nil
 }