diff --git a/SQLGeneration.Tests/CommandBuilderTester.cs b/SQLGeneration.Tests/CommandBuilderTester.cs
index d4fbf8b..9b771b8 100644
--- a/SQLGeneration.Tests/CommandBuilderTester.cs
+++ b/SQLGeneration.Tests/CommandBuilderTester.cs
@@ -1038,17 +1038,36 @@ public void TestDelete_WhereClause()
         #region Batch
 
         /// <summary>
-        /// This sees whether we can reproduce multiple insert statements in a batch.
+        /// This sees whether we can reproduce a batch of SQL statements.
+        /// </summary>
+        [TestMethod]
+        public void TestBatch_MixtureOfStatementsWithSemiColons()
+        {
+            string commandText = @"INSERT INTO Table (TestCol) VALUES(';');SELECT 1 UNION ALL SELECT 1;SELECT CASE WHEN Table.Column = 'Adm;in' THEN 'Administ;rator' ELSE 'Us;er' END FROM Table";
+            assertCanReproduce(commandText);
+        }
+
+        /// <summary>
+        /// This sees whether we can reproduce multiple insert statements in a batch using a terminator.
         /// </summary>
         [TestMethod]
         public void TestBatch_MultipleInserts()
         {
-            string commandText = @"INSERT INTO Table VALUES();
-                                   INSERT INTO Table VALUES()";
+            string commandText = @"INSERT INTO Table VALUES();INSERT INTO Table VALUES()";
             assertCanReproduce(commandText);
         }
 
-        #endregion      
+        /// <summary>
+        /// This tests whether the terminator is persisted when we parse and reproduce the sql.
+        /// </summary>
+        [TestMethod]
+        public void TestBatch_TerminatorPersists()
+        {
+            string commandText = @"INSERT INTO Table VALUES();";
+            assertCanReproduce(commandText);
+        }
+
+        #endregion
 
         private void assertCanReproduce(string commandText, CommandBuilderOptions options = null)
         {
diff --git a/SQLGeneration/Builders/BatchBuilder.cs b/SQLGeneration/Builders/BatchBuilder.cs
new file mode 100644
index 0000000..c95230a
--- /dev/null
+++ b/SQLGeneration/Builders/BatchBuilder.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace SQLGeneration.Builders
+{
+
+    /// <summary>
+    /// Builds a string that contains many individual commands seprated by terminators.
+    /// </summary>
+    public class BatchBuilder : ICommand
+    {
+        private readonly IList<ICommand> _commands;
+        private bool _hasTerminator = false;
+
+        /// <summary>
+        /// Initializes a new instance of a BatchBuilder.
+        /// </summary>     
+        /// <param name="commands">The commands to be in the batch.</param>
+        public BatchBuilder(IList<ICommand> commands)
+        {
+            _commands = commands;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of a BatchBuilder.
+        /// </summary>     
+        public BatchBuilder()
+        {
+            _commands = new List<ICommand>();
+        }
+
+        /// <summary>
+        /// Adds the command to the batch.
+        /// </summary>
+        /// <param name="command">The command to add.</param>
+        public void AddCommand(ICommand command)
+        {
+            if (command == null)
+            {
+                throw new ArgumentNullException("command");
+            }
+            _commands.Add(command);
+        }
+
+        /// <summary>
+        /// Removes the command from the batch.
+        /// </summary>
+        /// <param name="command">The command to remove.</param>
+        /// <returns>True if the command was removed; otherwise, false.</returns>
+        public bool RemoveCommand(ICommand command)
+        {
+            if (command == null)
+            {
+                throw new ArgumentNullException("command");
+            }
+            return _commands.Remove(command);
+        }
+
+        /// <summary>
+        /// Gets the command at the specified index.
+        /// </summary>
+        /// <param name="index"></param>
+        /// <returns></returns>
+        public ICommand GetCommand(int index)
+        {
+            return _commands[index];
+        }
+
+        /// <summary>
+        /// Returns the commands as an IEnumerable.
+        /// </summary>
+        /// <returns></returns>
+        public IEnumerable<ICommand> Commands()
+        {
+            return _commands.AsEnumerable();
+        }
+
+        /// <summary>
+        /// Returns whether there is a single command in the batch.
+        /// </summary>
+        /// <returns></returns>
+        public bool IsSingleCommand()
+        {
+            return !(_commands.Count > 1);
+        }
+
+        /// <summary>
+        /// Gets whether this command has a terminator.
+        /// </summary>
+        public bool HasTerminator
+        {
+            get
+            {
+                return _hasTerminator;
+            }
+            set
+            {
+                _hasTerminator = value;
+            }
+        }
+
+        /// <summary>
+        /// Accepts a visitor.
+        /// </summary>
+        /// <param name="visitor"></param>
+        public void Accept(BuilderVisitor visitor)
+        {
+            visitor.VisitBatch(this);
+        }
+    }
+}
diff --git a/SQLGeneration/Builders/BuilderVisitor.cs b/SQLGeneration/Builders/BuilderVisitor.cs
index b36a782..40e25d8 100644
--- a/SQLGeneration/Builders/BuilderVisitor.cs
+++ b/SQLGeneration/Builders/BuilderVisitor.cs
@@ -45,6 +45,14 @@ protected internal virtual void VisitAliasedSource(AliasedSource aliasedSource)
 
         }
 
+        /// <summary>
+        /// Visits a Batch builder.
+        /// </summary>
+        /// <param name="item">The item to visit.</param>
+        protected internal virtual void VisitBatch(BatchBuilder item)
+        {
+        }
+
         /// <summary>
         /// Visits a BetweenFilter builder.
         /// </summary>
diff --git a/SQLGeneration/Builders/CommandOptions.cs b/SQLGeneration/Builders/CommandOptions.cs
index 7f95f5b..95429c3 100644
--- a/SQLGeneration/Builders/CommandOptions.cs
+++ b/SQLGeneration/Builders/CommandOptions.cs
@@ -17,6 +17,7 @@ public CommandOptions()
             VerboseDeleteStatement = true;
             VerboseInnerJoin = true;
             VerboseOuterJoin = true;
+            Terminator = ';';
         }
 
         /// <summary>
@@ -82,5 +83,10 @@ public CommandOptions Clone()
         /// Gets or sets whether columns should be fully qualified within a DELETE statement.
         /// </summary>
         public bool QualifyDeleteColumns { get; set; }
+
+        /// <summary>
+        /// Gets or sets the terminator to be used.
+        /// </summary>
+        public char Terminator { get; set; }
     }
 }
diff --git a/SQLGeneration/Builders/DeleteBuilder.cs b/SQLGeneration/Builders/DeleteBuilder.cs
index f987fa1..e4ac0a2 100644
--- a/SQLGeneration/Builders/DeleteBuilder.cs
+++ b/SQLGeneration/Builders/DeleteBuilder.cs
@@ -11,6 +11,7 @@ public class DeleteBuilder : IFilteredCommand
     {
         private readonly AliasedSource _table;
         private readonly FilterGroup _where;
+        private bool _hasTerminator = false;
 
         /// <summary>
         /// Initializes a new instance of a DeleteBuilder.
@@ -70,6 +71,21 @@ public bool RemoveWhere(IFilter filter)
             return _where.RemoveFilter(filter);
         }
 
+        /// <summary>
+        /// Gets whether this command has a terminator.
+        /// </summary>
+        public bool HasTerminator
+        {
+            get
+            {
+                return _hasTerminator;
+            }
+            set
+            {
+                _hasTerminator = value;
+            }
+        }
+
         void IVisitableBuilder.Accept(BuilderVisitor visitor)
         {
             visitor.VisitDelete(this);
diff --git a/SQLGeneration/Builders/ICommand.cs b/SQLGeneration/Builders/ICommand.cs
index 9b5cd2e..c228602 100644
--- a/SQLGeneration/Builders/ICommand.cs
+++ b/SQLGeneration/Builders/ICommand.cs
@@ -8,5 +8,9 @@ namespace SQLGeneration.Builders
     /// </summary>
     public interface ICommand : IVisitableBuilder
     {
+        /// <summary>
+        /// Gets whether the command has a terminator.
+        /// </summary>
+        bool HasTerminator { get; set; }
     }
 }
diff --git a/SQLGeneration/Builders/InsertBuilder.cs b/SQLGeneration/Builders/InsertBuilder.cs
index 6e02f4e..9f9d73f 100644
--- a/SQLGeneration/Builders/InsertBuilder.cs
+++ b/SQLGeneration/Builders/InsertBuilder.cs
@@ -12,6 +12,7 @@ public class InsertBuilder : ICommand
         private readonly AliasedSource _table;
         private readonly List<Column> _columns;
         private readonly IValueProvider _values;
+        private bool _hasTerminator = false;
 
         /// <summary>
         /// Initializes a new instance of a InsertBuilder.
@@ -85,9 +86,26 @@ public IValueProvider Values
             get { return _values; }
         }
 
+        /// <summary>
+        /// Gets whether this command has a terminator.
+        /// </summary>
+        public bool HasTerminator
+        {
+            get
+            {
+                return _hasTerminator;
+            }
+            set
+            {
+                _hasTerminator = value;
+            }
+        }
+
         void IVisitableBuilder.Accept(BuilderVisitor visitor)
         {
             visitor.VisitInsert(this);
         }
+
+
     }
 }
diff --git a/SQLGeneration/Builders/SelectBuilder.cs b/SQLGeneration/Builders/SelectBuilder.cs
index 0ad2116..6eee0ea 100644
--- a/SQLGeneration/Builders/SelectBuilder.cs
+++ b/SQLGeneration/Builders/SelectBuilder.cs
@@ -17,6 +17,7 @@ public class SelectBuilder : ISelectBuilder, IFilteredCommand
         private readonly List<IGroupByItem> _groupBy;
         private readonly FilterGroup _having;
         private readonly SourceCollection sources;
+        private bool _hasTerminator = false;
 
         /// <summary>
         /// Initializes a new instance of a SelectBuilder.
@@ -371,6 +372,21 @@ bool IValueProvider.IsValueList
             get { return false; }
         }
 
+        /// <summary>
+        /// Gets whether this command has a terminator.
+        /// </summary>
+        public bool HasTerminator
+        {
+            get
+            {
+                return _hasTerminator;
+            }
+            set
+            {
+                _hasTerminator = value;
+            }
+        }
+
         void IVisitableBuilder.Accept(BuilderVisitor visitor)
         {
             visitor.VisitSelect(this);
diff --git a/SQLGeneration/Builders/SelectCombiner.cs b/SQLGeneration/Builders/SelectCombiner.cs
index c0bbd20..6119ee3 100644
--- a/SQLGeneration/Builders/SelectCombiner.cs
+++ b/SQLGeneration/Builders/SelectCombiner.cs
@@ -12,6 +12,7 @@ public abstract class SelectCombiner : ISelectBuilder
         private readonly ISelectBuilder leftHand;
         private readonly ISelectBuilder rightHand;
         private readonly List<OrderBy> orderBy;
+        private bool _hasTerminator = false;
 
         /// <summary>
         /// Initializes a new instance of a SelectCombiner.
@@ -116,6 +117,21 @@ bool IValueProvider.IsValueList
             get { return false; }
         }
 
+        /// <summary>
+        /// Gets whether this command has a terminator.
+        /// </summary>
+        public bool HasTerminator
+        {
+            get
+            {
+                return _hasTerminator;
+            }
+            set
+            {
+                _hasTerminator = value;
+            }
+        }
+
         void IVisitableBuilder.Accept(BuilderVisitor visitor)
         {
             OnAccept(visitor);
diff --git a/SQLGeneration/Builders/UpdateBuilder.cs b/SQLGeneration/Builders/UpdateBuilder.cs
index 0c86457..28a9501 100644
--- a/SQLGeneration/Builders/UpdateBuilder.cs
+++ b/SQLGeneration/Builders/UpdateBuilder.cs
@@ -13,6 +13,7 @@ public class UpdateBuilder : IFilteredCommand
         private readonly AliasedSource _table;
         private readonly IList<Setter> _setters;
         private readonly FilterGroup _where;
+        private bool _hasTerminator = false;
 
         /// <summary>
         /// Initializes a new instance of a UpdateBuilder.
@@ -108,6 +109,21 @@ public bool RemoveWhere(IFilter filter)
             return _where.RemoveFilter(filter);
         }
 
+        /// <summary>
+        /// Gets whether this command has a terminator.
+        /// </summary>
+        public bool HasTerminator
+        {
+            get
+            {
+                return _hasTerminator;
+            }
+            set
+            {
+                _hasTerminator = value;
+            }
+        }
+
         void IVisitableBuilder.Accept(BuilderVisitor visitor)
         {
             visitor.VisitUpdate(this);
diff --git a/SQLGeneration/Generators/CommandBuilder.cs b/SQLGeneration/Generators/CommandBuilder.cs
index 9c6cf67..9c446f7 100644
--- a/SQLGeneration/Generators/CommandBuilder.cs
+++ b/SQLGeneration/Generators/CommandBuilder.cs
@@ -44,8 +44,36 @@ public ICommand GetCommand(string commandText, CommandBuilderOptions options = n
             this.scope = new SourceScope();
             this.options = options ?? new CommandBuilderOptions();
             ITokenSource tokenSource = Grammar.TokenRegistry.CreateTokenSource(commandText);
-            MatchResult result = GetResult(tokenSource);
-            return buildStart(result);
+
+            var batch = new BatchBuilder();
+
+            while (true)
+            {
+                MatchResult result = GetResult(tokenSource);
+                if (result != null && result.IsMatch)
+                {
+                    var command = buildStart(result);
+                    batch.AddCommand(command);
+                }
+                else
+                {
+                    break;
+                }
+            }
+
+            if (batch.IsSingleCommand())
+            {
+                return batch.GetCommand(0);
+            }
+
+            return batch;
+        }
+
+        private void buildTerminator(MatchResult result, ICommand builder)
+        {
+            MatchResult terminator = result.Matches[SqlGrammar.Start.Terminator];
+            builder.HasTerminator = terminator.IsMatch;
+            return;
         }
 
         private ICommand buildStart(MatchResult result)
@@ -53,22 +81,30 @@ private ICommand buildStart(MatchResult result)
             MatchResult select = result.Matches[SqlGrammar.Start.SelectStatement];
             if (select.IsMatch)
             {
-                return buildSelectStatement(select);
+                ICommand command = buildSelectStatement(select);
+                buildTerminator(result, command);
+                return command;
             }
             MatchResult insert = result.Matches[SqlGrammar.Start.InsertStatement];
             if (insert.IsMatch)
             {
-                return buildInsertStatement(insert);
+                ICommand command = buildInsertStatement(insert);
+                buildTerminator(result, command);
+                return command;
             }
             MatchResult update = result.Matches[SqlGrammar.Start.UpdateStatement];
             if (update.IsMatch)
             {
-                return buildUpdateStatement(update);
+                ICommand command = buildUpdateStatement(update);
+                buildTerminator(result, command);
+                return command;
             }
             MatchResult delete = result.Matches[SqlGrammar.Start.DeleteStatement];
             if (delete.IsMatch)
             {
-                return buildDeleteStatement(delete);
+                ICommand command = buildDeleteStatement(delete);
+                buildTerminator(result, command);
+                return command;
             }
             throw new InvalidOperationException();
         }
diff --git a/SQLGeneration/Generators/FormattingVisitor.cs b/SQLGeneration/Generators/FormattingVisitor.cs
index c2e045c..420cdad 100644
--- a/SQLGeneration/Generators/FormattingVisitor.cs
+++ b/SQLGeneration/Generators/FormattingVisitor.cs
@@ -40,10 +40,10 @@ public FormattingVisitor(TextWriter writer, CommandOptions options = null)
         }
 
         private FormattingVisitor(
-            TextWriter writer, 
-            CommandOptions options, 
-            int level, 
-            CommandType commandType, 
+            TextWriter writer,
+            CommandOptions options,
+            int level,
+            CommandType commandType,
             SourceReferenceType sourceType,
             ValueReferenceType projectionType)
         {
@@ -107,6 +107,19 @@ protected internal override void VisitAllColumns(AllColumns item)
             writer.Write("*");
         }
 
+        /// <summary>
+        /// Generates the text for a Batch builder.
+        /// </summary>
+        /// <param name="item">The BatchBuilder to generate the text for.</param>
+        protected internal override void VisitBatch(BatchBuilder item)
+        {
+            foreach (var command in item.Commands())
+            {
+                command.Accept(this);
+            }
+            base.VisitBatch(item);
+        }
+
         /// <summary>
         /// Generates the text for a BetweenFilter builder.
         /// </summary>
@@ -228,6 +241,10 @@ private void visitDelete(DeleteBuilder item)
                 IFilter filterGroup = item.WhereFilterGroup;
                 filterGroup.Accept(forSubCommand().forValueContext(ValueReferenceType.Reference));
             }
+            if (item.HasTerminator)
+            {
+                writer.Write(options.Terminator);
+            }
         }
 
         /// <summary>
@@ -507,6 +524,10 @@ private void visitInsert(InsertBuilder item)
                 writer.Write("VALUES");
             }
             item.Values.Accept(forSubCommand().forValueContext(ValueReferenceType.Reference));
+            if (item.HasTerminator)
+            {
+                writer.Write(options.Terminator);
+            }
         }
 
         /// <summary>
@@ -834,7 +855,7 @@ protected internal override void VisitPrecedingUnboundFrame(PrecedingUnboundFram
             visitUnboundFrame(item);
             writer.Write(" PRECEDING");
         }
-        
+
         /// <summary>
         /// Generates the text for a RightOuterJoin builder.
         /// </summary>
@@ -911,6 +932,10 @@ private void visitSelect(SelectBuilder item)
             {
                 writer.Write(")");
             }
+            if (item.HasTerminator)
+            {
+                writer.Write(options.Terminator);
+            }
         }
 
         /// <summary>
@@ -1010,6 +1035,10 @@ private void visitUpdate(UpdateBuilder item)
                 IVisitableBuilder where = item.WhereFilterGroup;
                 where.Accept(forSubCommand().forValueContext(ValueReferenceType.Reference));
             }
+            if (item.HasTerminator)
+            {
+                writer.Write(options.Terminator);
+            }
         }
 
         /// <summary>
@@ -1214,6 +1243,10 @@ private void visitSelectCombiner(SelectCombiner combiner, string combinerToken)
             {
                 writer.Write(")");
             }
+            if (combiner.HasTerminator)
+            {
+                writer.Write(options.Terminator);
+            }
         }
 
         private void visitBoundFrame(BoundFrame item)
@@ -1312,7 +1345,8 @@ private enum CommandType
             Select,
             Insert,
             Update,
-            Delete
+            Delete,
+            Batch
         }
 
         private enum SourceReferenceType
diff --git a/SQLGeneration/Generators/SqlGenerator.cs b/SQLGeneration/Generators/SqlGenerator.cs
index b5aa2c3..0b5f876 100644
--- a/SQLGeneration/Generators/SqlGenerator.cs
+++ b/SQLGeneration/Generators/SqlGenerator.cs
@@ -39,7 +39,8 @@ protected SqlGrammar Grammar
         protected MatchResult GetResult(ITokenSource tokenSource)
         {
             Parser parser = new Parser(grammar);
-            return parser.Parse(SqlGrammar.Start.Name, tokenSource);
+            var matchedStatement = parser.Parse(SqlGrammar.Start.Name, tokenSource);
+            return matchedStatement;
         }
     }
 }
diff --git a/SQLGeneration/Parsing/Parser.cs b/SQLGeneration/Parsing/Parser.cs
index ee2eccb..0a9a5ca 100644
--- a/SQLGeneration/Parsing/Parser.cs
+++ b/SQLGeneration/Parsing/Parser.cs
@@ -39,13 +39,7 @@ public MatchResult Parse(string expressionType, ITokenSource tokenSource)
 
             Expression expression = grammar.Expression(expressionType);
             ParseAttempt attempt = new ParseAttempt(this, tokenSource);
-            MatchResult result = expression.Match(attempt, String.Empty);
-
-            // check that there are no trailing tokens
-            if (result.IsMatch && attempt.GetToken() != null)
-            {
-                result.IsMatch = false;
-            }
+            MatchResult result = expression.Match(attempt, String.Empty);         
 
             return result;
         }
diff --git a/SQLGeneration/SQLGeneration.csproj b/SQLGeneration/SQLGeneration.csproj
index 73c4a5a..8b4d162 100644
--- a/SQLGeneration/SQLGeneration.csproj
+++ b/SQLGeneration/SQLGeneration.csproj
@@ -46,6 +46,7 @@
     <Compile Include="Builders\AliasedProjection.cs" />
     <Compile Include="Builders\AliasedSource.cs" />
     <Compile Include="Builders\ArithmeticExpression.cs" />
+    <Compile Include="Builders\BatchBuilder.cs" />
     <Compile Include="Builders\BetweenFilter.cs" />
     <Compile Include="Builders\BetweenWindowFrame.cs" />
     <Compile Include="Builders\BuilderVisitor.cs" />