Implement ifdef and ifndef
diff --git a/ast.go b/ast.go
index fe8e21f..7abeeaa 100644
--- a/ast.go
+++ b/ast.go
@@ -92,3 +92,21 @@
 func (ast *IncludeAST) show() {
 	Log("include %s", ast.expr)
 }
+
+type IfAST struct {
+	ASTBase
+	op string
+	lhs string
+	rhs string // Empty if |op| is ifdef or ifndef.
+	trueStmts []AST
+	falseStmts []AST
+}
+
+func (ast *IfAST) eval(ev *Evaluator) {
+	ev.evalIf(ast)
+}
+
+func (ast *IfAST) show() {
+	// TODO
+	Log("if")
+}
diff --git a/eval.go b/eval.go
index 6f092cc..4d4c07f 100644
--- a/eval.go
+++ b/eval.go
@@ -221,6 +221,26 @@
 	}
 }
 
+func (ev *Evaluator) evalIf(ast *IfAST) {
+	var stmts []AST
+	switch ast.op {
+	case "ifdef", "ifndef":
+		value, _ := ev.getVar(ev.evalExpr(ast.lhs))
+		if (value != "") == (ast.op == "ifdef") {
+			stmts = ast.trueStmts
+		} else {
+			stmts = ast.falseStmts
+		}
+	case "ifeq", "ifneq":
+		panic("TODO")
+	default:
+		panic(fmt.Sprintf("unknown if statement: %q", ast.op))
+	}
+	for _, stmt := range stmts {
+		ev.eval(stmt)
+	}
+}
+
 func (ev *Evaluator) eval(ast AST) {
 	ast.eval(ev)
 }
diff --git a/parser.go b/parser.go
index d8bb903..513305b 100644
--- a/parser.go
+++ b/parser.go
@@ -14,6 +14,11 @@
 	stmts []AST
 }
 
+type ifState struct {
+	ast     *IfAST
+	in_else bool
+}
+
 type parser struct {
 	rd       *bufio.Reader
 	mk       Makefile
@@ -23,6 +28,8 @@
 	unBuf    []byte
 	hasUnBuf bool
 	done     bool
+	outStmts *[]AST
+	ifStack  []ifState
 }
 
 func exists(filename string) bool {
@@ -35,10 +42,16 @@
 }
 
 func newParser(rd io.Reader, filename string) *parser {
-	return &parser{
+	p := &parser{
 		rd:       bufio.NewReader(rd),
 		filename: filename,
 	}
+	p.outStmts = &p.mk.stmts
+	return p
+}
+
+func (p* parser) addStatement(ast AST) {
+	*p.outStmts = append(*p.outStmts, ast)
 }
 
 func (p *parser) readLine() []byte {
@@ -131,6 +144,63 @@
 	return ast
 }
 
+func (p *parser) parseIfdef(line string, oplen int) AST {
+	ast := &IfAST{
+		op: line[:oplen],
+		lhs: strings.TrimSpace(line[oplen+1:]),
+	}
+	ast.filename = p.filename
+	ast.lineno = p.lineno
+	p.addStatement(ast)
+	p.ifStack = append(p.ifStack, ifState{ast: ast})
+	p.outStmts = &ast.trueStmts
+	return ast
+}
+
+func (p *parser) parseIfeq(line string, oplen int) AST {
+	ast := &IfAST{
+		op: line[:oplen],
+		lhs: strings.TrimSpace(line[oplen+1:]),
+	}
+	ast.filename = p.filename
+	ast.lineno = p.lineno
+	p.addStatement(ast)
+	p.ifStack = append(p.ifStack, ifState{ast: ast})
+	p.outStmts = &ast.trueStmts
+	return ast
+}
+
+func (p *parser) checkIfStack(curKeyword string) {
+	if len(p.ifStack) == 0 {
+		Error(p.filename, p.lineno, `*** extraneous %q.`, curKeyword)
+	}
+}
+
+func (p *parser) parseElse(line string) {
+	p.checkIfStack("else")
+	state := &p.ifStack[len(p.ifStack)-1]
+	if state.in_else {
+		Error(p.filename, p.lineno, `*** only one "else" per conditional.`)
+	}
+	state.in_else = true
+	p.outStmts = &state.ast.falseStmts
+}
+
+func (p *parser) parseEndif(line string) {
+	p.checkIfStack("endif")
+	p.ifStack = p.ifStack[0:len(p.ifStack)-1]
+	if len(p.ifStack) == 0 {
+		p.outStmts = &p.mk.stmts
+	} else {
+		state := p.ifStack[len(p.ifStack)-1]
+		if state.in_else {
+			p.outStmts = &state.ast.falseStmts
+		} else {
+			p.outStmts = &state.ast.trueStmts
+		}
+	}
+}
+
 func (p *parser) parseLine(line string) AST {
 	stripped := strings.TrimLeft(line, " \t")
 	if strings.HasPrefix(stripped, "include ") {
@@ -139,6 +209,30 @@
 	if strings.HasPrefix(stripped, "-include ") {
 		return p.parseInclude(stripped, len("-include"))
 	}
+	if strings.HasPrefix(stripped, "ifdef ") {
+		p.parseIfdef(stripped, len("ifdef"))
+		return nil
+	}
+	if strings.HasPrefix(stripped, "ifndef ") {
+		p.parseIfdef(stripped, len("ifndef"))
+		return nil
+	}
+	if strings.HasPrefix(stripped, "ifeq ") {
+		p.parseIfeq(stripped, len("ifeq"))
+		return nil
+	}
+	if strings.HasPrefix(stripped, "ifneq ") {
+		p.parseIfeq(stripped, len("ifneq"))
+		return nil
+	}
+	if strings.HasPrefix(stripped, "else") {
+		p.parseElse(stripped)
+		return nil
+	}
+	if strings.HasPrefix(stripped, "endif") {
+		p.parseEndif(stripped)
+		return nil
+	}
 	ast := &RawExprAST{expr: line}
 	ast.filename = p.filename
 	ast.lineno = p.lineno
@@ -171,13 +265,15 @@
 				}
 			}
 			if ast != nil {
-				p.mk.stmts = append(p.mk.stmts, ast)
+				p.addStatement(ast)
 				break
 			}
 		}
 		if ast == nil && len(bytes.TrimSpace(line)) > 0 {
 			ast = p.parseLine(string(line))
-			p.mk.stmts = append(p.mk.stmts, ast)
+			if ast != nil {
+				p.addStatement(ast)
+			}
 		}
 	}
 	return p.mk, nil
diff --git a/runtest.rb b/runtest.rb
index bb4cbd6..fef0a5a 100755
--- a/runtest.rb
+++ b/runtest.rb
@@ -33,6 +33,9 @@
     output = ''
 
     testcases = c.scan(/^test\d*/).sort
+    if testcases.empty?
+      testcases = ['']
+    end
 
     cleanup
     testcases.each do |tc|
diff --git a/test/cond_syntax.mk b/test/cond_syntax.mk
new file mode 100644
index 0000000..e5ba2eb
--- /dev/null
+++ b/test/cond_syntax.mk
@@ -0,0 +1,91 @@
+VAR=var
+VARREF=VAR
+EMPTY=
+UNDEFREF=UNDEFINED
+
+RESULT=
+
+ifdef VAR
+RESULT += PASS
+endif
+
+ifdef VAR
+RESULT += PASS
+else
+RESULT += FAIL
+endif
+ifdef $(VARREF)
+RESULT += PASS
+else
+RESULT += FAIL
+endif
+ifdef UNDEFINED
+RESULT += FAIL
+else
+RESULT += PASS
+endif
+ifdef $(UNDEFREF)
+RESULT += FAIL
+else
+RESULT += PASS
+endif
+ifdef EMPTY
+RESULT += FAIL
+else
+RESULT += PASS
+endif
+
+ifndef VAR
+RESULT += FAIL
+else
+RESULT += PASS
+endif
+ifndef $(VARREF)
+RESULT += FAIL
+else
+RESULT += PASS
+endif
+ifndef UNDEFINED
+RESULT += PASS
+else
+RESULT += FAIL
+endif
+ifndef $(UNDEFREF)
+RESULT += PASS
+else
+RESULT += FAIL
+endif
+
+# TODO: Support ifeq and ifneq
+
+# ifeq ($(VAR),var)
+# RESULT += PASS
+# else
+# RESULT += FAIL
+# endif
+# ifneq ($(VAR),var)
+# RESULT += FAIL
+# else
+# RESULT += PASS
+# endif
+
+# ifeq ($(UNDEFINED),)
+# RESULT += PASS
+# else
+# RESULT += FAIL
+# endif
+# ifeq (,$(UNDEFINED))
+# RESULT += PASS
+# else
+# RESULT += FAIL
+# endif
+
+# TODO: Support?
+# ifeq "$(VAR)" "var"
+# RESULT += PASS
+# else
+# RESULT += FAIL
+# endif
+
+test:
+	echo $(RESULT)
diff --git a/test/err_extra_else.mk b/test/err_extra_else.mk
new file mode 100644
index 0000000..82fec45
--- /dev/null
+++ b/test/err_extra_else.mk
@@ -0,0 +1 @@
+else
diff --git a/test/err_extra_endif.mk b/test/err_extra_endif.mk
new file mode 100644
index 0000000..1467f63
--- /dev/null
+++ b/test/err_extra_endif.mk
@@ -0,0 +1 @@
+endif
diff --git a/test/err_two_else.mk b/test/err_two_else.mk
new file mode 100644
index 0000000..c996fa7
--- /dev/null
+++ b/test/err_two_else.mk
@@ -0,0 +1,4 @@
+ifdef VAR
+else
+else
+endif