diff --git a/src/grammar/parse_tree.rs b/src/grammar/parse_tree.rs
index f3722bb..de66eb8 100644
--- a/src/grammar/parse_tree.rs
+++ b/src/grammar/parse_tree.rs
@@ -198,7 +198,7 @@ impl Display for Symbol {
             Symbol::Nonterminal(ref s) =>
                 write!(fmt, "{}", s),
             Symbol::Macro(ref m) =>
-                write!(fmt, "{}<{}>", m.name, Sep(", ", &m.args)),
+                write!(fmt, "{}", m),
             Symbol::Plus(ref s) =>
                 write!(fmt, "{}+", s),
             Symbol::Question(ref s) =>
@@ -213,6 +213,18 @@ impl Display for Symbol {
     }
 }
 
+impl MacroSymbol {
+    pub fn canonical_form(&self) -> String {
+        format!("{}", self)
+    }
+}
+
+impl Display for MacroSymbol {
+    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
+        write!(fmt, "{}<{}>", self.name, Sep(", ", &self.args))
+    }
+}
+
 struct Sep<S>(&'static str, S);
 
 impl<'a,S:Display> Display for Sep<&'a Vec<S>> {
diff --git a/src/main.rs b/src/main.rs
index 31f326c..768fb9d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,9 +3,10 @@ extern crate rusty_peg;
 
 extern crate regex;
 
-mod intern;
-mod parser;
 mod grammar;
+mod intern;
+mod normalize;
+mod parser;
 
 fn main() {
     println!("Hello, world!");
diff --git a/src/normalize/macro_expand.rs b/src/normalize/macro_expand.rs
index 938dab9..06a0d94 100644
--- a/src/normalize/macro_expand.rs
+++ b/src/normalize/macro_expand.rs
@@ -1,7 +1,8 @@
-use std::collections::HashMap;
+use std::collections::HashSet;
+use intern::{intern, InternedString};
 use grammar::parse_tree::{Grammar, GrammarItem, MacroSymbol, Symbol};
 
-pub fn expand_macros(input: pt::Grammar) {
+pub fn expand_macros(input: Grammar) {
     let Grammar { type_name, items } = input;
     let mut expander = MacroExpander::new();
 }
@@ -12,8 +13,8 @@ struct MacroExpander {
 }
 
 impl MacroExpander {
-    fn new(items: Vec<GrammarItem>) -> MacroExpander {
-        MacroExpander { items: items, expansion_stack: Vec::new(), expansion_set: HashSet::new() }
+    fn new() -> MacroExpander {
+        MacroExpander { expansion_stack: Vec::new(), expansion_set: HashSet::new() }
     }
 
     fn expand(&mut self, items: &mut Vec<GrammarItem>) {
@@ -22,7 +23,7 @@ impl MacroExpander {
             // Find any macro uses in items added since last round and
             // replace them in place with the expanded version:
             for item in &mut items[counter..] {
-                self.replace(item);
+                self.replace_item(item);
             }
             counter = items.len();
 
@@ -33,7 +34,7 @@ impl MacroExpander {
     fn replace_item(&mut self, item: &mut GrammarItem) {
         match *item {
             GrammarItem::TokenType(..) => { }
-            GrammarItem::Nonterminal(ref data) => {
+            GrammarItem::Nonterminal(ref mut data) => {
                 // Ignore macro definitions. They will be expanded in
                 // due course.
                 if !data.args.is_empty() {
@@ -41,31 +42,31 @@ impl MacroExpander {
                 }
 
                 for alternative in &mut data.alternatives {
-                    self.replace_symbol(&mut alternative.symbol);
+                    self.replace_symbols(&mut alternative.expr);
                 }
             }
         }
     }
 
+    fn replace_symbols(&mut self, symbols: &mut [Symbol]) {
+        for symbol in symbols {
+            self.replace_symbol(symbol);
+        }
+    }
+
     fn replace_symbol(&mut self, symbol: &mut Symbol) {
         let key;
 
         match *symbol {
-            Symbol::Macro(ref mut macro) => {
-                for sym in &mut macro.args {
-                    self.replace(sym);
-                }
-
-                key = symbol.canonical_form();
-                if self.expansion_set.insert(key) {
-                    self.expansion_stack.push(macro.clone());
-                }
-            }
-            Symbol::Expr(ref mut syms) => {
-                for sym in syms {
+            Symbol::Macro(ref mut m) => {
+                for sym in &mut m.args {
                     self.replace_symbol(sym);
                 }
-                return;
+
+                key = intern(&m.canonical_form());
+                if self.expansion_set.insert(key) {
+                    self.expansion_stack.push(m.clone());
+                }
             }
             Symbol::Terminal(_) |
             Symbol::Nonterminal(_) => {
@@ -79,9 +80,13 @@ impl MacroExpander {
                 self.replace_symbol(sym);
                 return;
             }
+            Symbol::Expr(ref mut syms) => {
+                self.replace_symbols(syms);
+                return;
+            }
         }
 
         // we only get here if this is a macro expansion
-        *symbol = Symbol::Nonterminal(intern(key));
+        *symbol = Symbol::Nonterminal(key);
     }
 }
diff --git a/src/normalize/mod.rs b/src/normalize/mod.rs
index b227358..4280ca0 100644
--- a/src/normalize/mod.rs
+++ b/src/normalize/mod.rs
@@ -6,9 +6,6 @@
 
 use grammar::parse_tree as pt;
 
-pub fn normalize(input: pt::Grammar) -> Result<pt::Grammar> {
-}
-
 // These are executed *IN ORDER*:
 
 // Expands macros
@@ -22,7 +19,7 @@ pub fn normalize(input: pt::Grammar) -> Result<pt::Grammar> {
 //
 // AFTER THIS POINT: No more macros, macro references, or guarded
 // alternatives, though type indirections may occur.
-// mod macro_expand;
+mod macro_expand;
 
 // Computes types where the user omitted them (or
 // from macro byproducts).