Index: /branches/pyyaml3000/tests/test_syck.py
===================================================================
--- /branches/pyyaml3000/tests/test_syck.py	(revision 52)
+++ /branches/pyyaml3000/tests/test_syck.py	(revision 52)
@@ -0,0 +1,30 @@
+
+import test_appliance
+
+class TestSyck(test_appliance.TestAppliance):
+
+    def _testSyckOnTokenTests(self, test_name, data_filename, tokens_filename):
+        try:
+            syck.parse(file(data_filename, 'rb'))
+        except:
+            print
+            print "DATA:"
+            print file(data_filename, 'rb').read()
+            raise
+
+    def _testSyckOnCanonicalTests(self, test_name, data_filename, canonical_filename):
+        try:
+            syck.parse(file(data_filename, 'rb'))
+        except:
+            print
+            print "DATA:"
+            print file(data_filename, 'rb').read()
+            raise
+
+try:
+    import syck
+    #TestSyck.add_tests('testSyckOnTokenTests', '.data', '.tokens')
+    #TestSyck.add_tests('testSyckOnCanonicalTests', '.data', '.canonical')
+except ImportError:
+    pass
+
Index: /branches/pyyaml3000/tests/test_errors.py
===================================================================
--- /branches/pyyaml3000/tests/test_errors.py	(revision 51)
+++ /branches/pyyaml3000/tests/test_errors.py	(revision 52)
@@ -3,6 +3,7 @@
 
 from yaml.error import YAMLError
-from yaml.reader import Reader
-from yaml.scanner import Scanner
+from yaml.reader import *
+from yaml.scanner import *
+from yaml.parser import *
 
 class TestErrors(test_appliance.TestAppliance):
@@ -17,12 +18,29 @@
 
     def _load(self, filename):
-        reader = Reader(file(filename, 'rb'))
-        scanner = Scanner(reader)
-        return list(scanner)
+        try:
+            reader = Reader(file(filename, 'rb'))
+            scanner = Scanner(reader)
+            parser = Parser(scanner)
+            return list(parser)
+        except YAMLError, exc:
+        #except ScannerError, exc:
+        #except ParserError, exc:
+            #print '.'*70
+            #print "%s:" % exc.__class__.__name__, exc
+            raise
 
     def _load_string(self, filename):
-        reader = Reader(file(filename, 'rb').read())
-        scanner = Scanner(reader)
-        return list(scanner)
+        try:
+            reader = Reader(file(filename, 'rb').read())
+            scanner = Scanner(reader)
+            parser = Parser(scanner)
+            return list(parser)
+        except YAMLError, exc:
+        #except ScannerError, exc:
+        #except ParserError, exc:
+            #print '.'*70
+            #print "%s:" % filename
+            #print "%s:" % exc.__class__.__name__, exc
+            raise
 
 TestErrors.add_tests('testErrors', '.error-message')
Index: /branches/pyyaml3000/tests/test_yaml.py
===================================================================
--- /branches/pyyaml3000/tests/test_yaml.py	(revision 47)
+++ /branches/pyyaml3000/tests/test_yaml.py	(revision 52)
@@ -8,4 +8,5 @@
 from test_structure import *
 from test_errors import *
+from test_syck import *
 
 def main(module='__main__'):
Index: /branches/pyyaml3000/tests/data/invalid-anchor-2.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-anchor-2.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-anchor-2.error-message	(revision 52)
@@ -0,0 +1,8 @@
+---
+- [
+    &correct foo,
+    *correct,
+    *correct]   # still correct
+- *correct: still correct
+- &correct-or-not[foo, bar]
+
Index: /branches/pyyaml3000/tests/data/no-block-collection-end.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/no-block-collection-end.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/no-block-collection-end.error-message	(revision 52)
@@ -0,0 +1,3 @@
+- foo
+- bar
+baz: bar
Index: /branches/pyyaml3000/tests/data/invalid-uri.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-uri.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-uri.error-message	(revision 52)
@@ -0,0 +1,1 @@
+--- !foo!   bar
Index: /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-2.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-2.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-2.error-message	(revision 52)
@@ -0,0 +1,2 @@
+%YAML   1e-5
+---
Index: /branches/pyyaml3000/tests/data/no-node-1.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/no-node-1.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/no-node-1.error-message	(revision 52)
@@ -0,0 +1,1 @@
+- !foo ]
Index: /branches/pyyaml3000/tests/data/no-block-mapping-end.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/no-block-mapping-end.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/no-block-mapping-end.error-message	(revision 52)
@@ -0,0 +1,1 @@
+foo: "bar" "baz"
Index: /branches/pyyaml3000/tests/data/invalid-anchor-1.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-anchor-1.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-anchor-1.error-message	(revision 52)
@@ -0,0 +1,1 @@
+--- &?  foo # we allow only ascii and numeric characters in anchor names.
Index: /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-1.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-1.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-1.error-message	(revision 52)
@@ -0,0 +1,3 @@
+# No version at all.
+%YAML
+---
Index: /branches/pyyaml3000/tests/data/undefined-tag-handle.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/undefined-tag-handle.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/undefined-tag-handle.error-message	(revision 52)
@@ -0,0 +1,1 @@
+--- !foo!bar    baz
Index: /branches/pyyaml3000/tests/data/no-document-start.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/no-document-start.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/no-document-start.error-message	(revision 52)
@@ -0,0 +1,3 @@
+%YAML   1.1
+# no ---
+foo: bar
Index: /branches/pyyaml3000/tests/data/no-flow-sequence-end.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/no-flow-sequence-end.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/no-flow-sequence-end.error-message	(revision 52)
@@ -0,0 +1,1 @@
+[foo, bar}
Index: /branches/pyyaml3000/tests/data/invalid-tag-handle-2.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-tag-handle-2.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-tag-handle-2.error-message	(revision 52)
@@ -0,0 +1,2 @@
+%TAG    !foo    bar
+---
Index: /branches/pyyaml3000/tests/data/no-flow-mapping-end.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/no-flow-mapping-end.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/no-flow-mapping-end.error-message	(revision 52)
@@ -0,0 +1,1 @@
+{ foo: bar ]
Index: /branches/pyyaml3000/tests/data/invalid-directive-name-2.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-directive-name-2.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-directive-name-2.error-message	(revision 52)
@@ -0,0 +1,2 @@
+%invalid-characters:in-directive name
+---
Index: /branches/pyyaml3000/tests/data/invalid-yaml-version.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-yaml-version.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-yaml-version.error-message	(revision 52)
@@ -0,0 +1,2 @@
+%YAML   2.0
+--- foo
Index: /branches/pyyaml3000/tests/data/invalid-tag-handle-1.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-tag-handle-1.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-tag-handle-1.error-message	(revision 52)
@@ -0,0 +1,2 @@
+%TAG    foo bar
+---
Index: /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-6.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-6.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-6.error-message	(revision 52)
@@ -0,0 +1,2 @@
+%YAML 123.C
+---
Index: /branches/pyyaml3000/tests/data/invalid-directive-name-1.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-directive-name-1.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-directive-name-1.error-message	(revision 52)
@@ -0,0 +1,2 @@
+%   # no name at all
+---
Index: /branches/pyyaml3000/tests/data/duplicate-yaml-directive.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/duplicate-yaml-directive.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/duplicate-yaml-directive.error-message	(revision 52)
@@ -0,0 +1,3 @@
+%YAML   1.1
+%YAML   1.1
+--- foo
Index: /branches/pyyaml3000/tests/data/duplicate-tag-directive.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/duplicate-tag-directive.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/duplicate-tag-directive.error-message	(revision 52)
@@ -0,0 +1,3 @@
+%TAG    !foo!   bar
+%TAG    !foo!   baz
+--- foo
Index: /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-5.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-5.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-5.error-message	(revision 52)
@@ -0,0 +1,2 @@
+%YAML A.0
+---
Index: /branches/pyyaml3000/tests/data/invalid-directive-line.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-directive-line.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-directive-line.error-message	(revision 52)
@@ -0,0 +1,2 @@
+%YAML   1.1 ?   # extra symbol
+---
Index: /branches/pyyaml3000/tests/data/invalid-uri-escapes-3.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-uri-escapes-3.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-uri-escapes-3.error-message	(revision 52)
@@ -0,0 +1,1 @@
+--- !<foo%d0%af%d0%af%d0bar> baz
Index: /branches/pyyaml3000/tests/data/unclosed-bracket.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/unclosed-bracket.error-message	(revision 47)
+++ /branches/pyyaml3000/tests/data/unclosed-bracket.error-message	(revision 52)
@@ -1,5 +1,6 @@
 test:
     - [ foo: bar
-    - baz
-"we could have detected the unclosed bracket on the above line, but this would forbid such syntax as": {
-}
+# comment the rest of the stream to let the scanner detect the problem.
+#    - baz
+#"we could have detected the unclosed bracket on the above line, but this would forbid such syntax as": {
+#}
Index: /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-4.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-4.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-4.error-message	(revision 52)
@@ -0,0 +1,2 @@
+%YAML 1.132.435
+---
Index: /branches/pyyaml3000/tests/data/invalid-tag-2.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-tag-2.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-tag-2.error-message	(revision 52)
@@ -0,0 +1,1 @@
+- !prefix!foo#bar baz
Index: /branches/pyyaml3000/tests/data/invalid-uri-escapes-2.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-uri-escapes-2.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-uri-escapes-2.error-message	(revision 52)
@@ -0,0 +1,1 @@
+--- !<%FF> foo
Index: /branches/pyyaml3000/tests/data/invalid-tag-directive-prefix.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-tag-directive-prefix.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-tag-directive-prefix.error-message	(revision 52)
@@ -0,0 +1,2 @@
+%TAG    !   tag:zz.com/foo#bar  # '#' is not allowed in URLs
+---
Index: /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-3.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-3.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-yaml-directive-version-3.error-message	(revision 52)
@@ -0,0 +1,2 @@
+%YAML 1.
+---
Index: /branches/pyyaml3000/tests/data/invalid-tag-1.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-tag-1.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-tag-1.error-message	(revision 52)
@@ -0,0 +1,1 @@
+- !<foo#bar> baz
Index: /branches/pyyaml3000/tests/data/no-node-2.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/no-node-2.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/no-node-2.error-message	(revision 52)
@@ -0,0 +1,1 @@
+- [ !foo } ]
Index: /branches/pyyaml3000/tests/data/invalid-uri-escapes-1.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-uri-escapes-1.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-uri-escapes-1.error-message	(revision 52)
@@ -0,0 +1,1 @@
+--- !<tag:%x?y> foo
Index: /branches/pyyaml3000/tests/data/invalid-tag-directive-handle.error-message
===================================================================
--- /branches/pyyaml3000/tests/data/invalid-tag-directive-handle.error-message	(revision 52)
+++ /branches/pyyaml3000/tests/data/invalid-tag-directive-handle.error-message	(revision 52)
@@ -0,0 +1,2 @@
+%TAG !!! !!!
+---
Index: /branches/pyyaml3000/lib/yaml/reader.py
===================================================================
--- /branches/pyyaml3000/lib/yaml/reader.py	(revision 48)
+++ /branches/pyyaml3000/lib/yaml/reader.py	(revision 52)
@@ -16,7 +16,7 @@
 #   reader.line, stream.column - the line and the column of the current character.
 
-__all__ = ['Marker', 'Reader', 'ReaderError']
-
-from error import YAMLError
+__all__ = ['Reader', 'ReaderError']
+
+from error import YAMLError, Marker
 
 import codecs, re
@@ -56,44 +56,4 @@
                 data = data[:-count-1]
         return codecs.utf_8_decode(data, errors)
-
-class Marker:
-
-    def __init__(self, name, line, column, buffer, pointer):
-        self.name = name
-        self.line = line
-        self.column = column
-        self.buffer = buffer
-        self.pointer = pointer
-
-    def get_snippet(self, indent=4, max_length=75):
-        if self.buffer is None:
-            return None
-        head = ''
-        start = self.pointer
-        while start > 0 and self.buffer[start-1] not in u'\0\r\n\x85\u2028\u2029':
-            start -= 1
-            if self.pointer-start > max_length/2-1:
-                head = ' ... '
-                start += 5
-                break
-        tail = ''
-        end = self.pointer
-        while end < len(self.buffer) and self.buffer[end] not in u'\0\r\n\x85\u2028\u2029':
-            end += 1
-            if end-self.pointer > max_length/2-1:
-                tail = ' ... '
-                end -= 5
-                break
-        snippet = self.buffer[start:end].encode('utf-8')
-        return ' '*indent + head + snippet + tail + '\n'  \
-                + ' '*(indent+self.pointer-start+len(head)) + '^'
-
-    def __str__(self):
-        snippet = self.get_snippet()
-        where = "  in \"%s\", line %d, column %d"   \
-                % (self.name, self.line+1, self.column+1)
-        if snippet is not None:
-            where += ":\n"+snippet
-        return where
 
 class ReaderError(YAMLError):
Index: /branches/pyyaml3000/lib/yaml/tokens.py
===================================================================
--- /branches/pyyaml3000/lib/yaml/tokens.py	(revision 51)
+++ /branches/pyyaml3000/lib/yaml/tokens.py	(revision 52)
@@ -36,5 +36,5 @@
 
 class BlockMappingStartToken(Token):
-    id = '<block mapping end>'
+    id = '<block mapping start>'
 
 class BlockEndToken(Token):
Index: /branches/pyyaml3000/lib/yaml/error.py
===================================================================
--- /branches/pyyaml3000/lib/yaml/error.py	(revision 45)
+++ /branches/pyyaml3000/lib/yaml/error.py	(revision 52)
@@ -1,4 +1,79 @@
+
+__all__ = ['Marker', 'YAMLError', 'MarkedYAMLError']
+
+class Marker:
+
+    def __init__(self, name, line, column, buffer, pointer):
+        self.name = name
+        self.line = line
+        self.column = column
+        self.buffer = buffer
+        self.pointer = pointer
+
+    def get_snippet(self, indent=4, max_length=75):
+        if self.buffer is None:
+            return None
+        head = ''
+        start = self.pointer
+        while start > 0 and self.buffer[start-1] not in u'\0\r\n\x85\u2028\u2029':
+            start -= 1
+            if self.pointer-start > max_length/2-1:
+                head = ' ... '
+                start += 5
+                break
+        tail = ''
+        end = self.pointer
+        while end < len(self.buffer) and self.buffer[end] not in u'\0\r\n\x85\u2028\u2029':
+            end += 1
+            if end-self.pointer > max_length/2-1:
+                tail = ' ... '
+                end -= 5
+                break
+        snippet = self.buffer[start:end].encode('utf-8')
+        return ' '*indent + head + snippet + tail + '\n'  \
+                + ' '*(indent+self.pointer-start+len(head)) + '^'
+
+    def __str__(self):
+        snippet = self.get_snippet()
+        where = "  in \"%s\", line %d, column %d"   \
+                % (self.name, self.line+1, self.column+1)
+        if snippet is not None:
+            where += ":\n"+snippet
+        return where
 
 class YAMLError(Exception):
     pass
 
+class MarkedYAMLError(YAMLError):
+
+    def __init__(self, context=None, context_marker=None,
+            problem=None, problem_marker=None):
+        self.context = context
+        self.context_marker = context_marker
+        self.problem = problem
+        self.problem_marker = problem_marker
+
+    def __str__(self):
+        lines = []
+        #for (place, marker) in [(self.context, self.context_marker),
+        #                        (self.problem, self.problem_marker)]:
+        #    if place is not None:
+        #        lines.append(place)
+        #        if marker is not None:
+        #            lines.append(str(marker))
+        if self.context is not None:
+            lines.append(self.context)
+            if self.context_marker is not None  \
+                and (self.problem is None or self.problem_marker is None
+                        or self.context_marker.name != self.problem_marker.name
+                        or self.context_marker.line != self.problem_marker.line
+                        or self.context_marker.column != self.problem_marker.column):
+                lines.append(str(self.context_marker))
+        if self.problem is not None:
+            lines.append(self.problem)
+            if self.problem_marker is not None:
+                lines.append(str(self.problem_marker))
+        return '\n'.join(lines)
+
+
+
Index: /branches/pyyaml3000/lib/yaml/scanner.py
===================================================================
--- /branches/pyyaml3000/lib/yaml/scanner.py	(revision 51)
+++ /branches/pyyaml3000/lib/yaml/scanner.py	(revision 52)
@@ -11,33 +11,9 @@
 __all__ = ['Scanner', 'ScannerError']
 
-from error import YAMLError
+from error import MarkedYAMLError
 from tokens import *
 
-class ScannerError(YAMLError):
-    # ScannerError: while reading a quoted string
-    #         in '...', line 5, column 10:
-    # key: "valu\?e"
-    #      ^
-    # got unknown quote character '?'
-    #         in '...', line 5, column 15:
-    # key: "valu\?e"
-    #            ^
-
-    def __init__(self, context=None, context_marker=None,
-            problem=None, problem_marker=None):
-        self.context = context
-        self.context_marker = context_marker
-        self.problem = problem
-        self.problem_marker = problem_marker
-
-    def __str__(self):
-        lines = []
-        for (place, marker) in [(self.context, self.context_marker),
-                                (self.problem, self.problem_marker)]:
-            if place is not None:
-                lines.append(place)
-                if marker is not None:
-                    lines.append(str(marker))
-        return '\n'.join(lines)
+class ScannerError(MarkedYAMLError):
+    pass
 
 class SimpleKey:
@@ -197,4 +173,8 @@
         if ch == u'.' and self.check_document_end():
             return self.fetch_document_end()
+
+        # TODO: support for BOM within a stream.
+        #if ch == u'\uFEFF':
+        #    return self.fetch_bom()    <-- issue BOMToken
 
         # Note: the order of the following checks is NOT significant.
@@ -750,4 +730,16 @@
         # specification requires. Any such mark will be considered as a part
         # of the document.
+        #
+        # TODO: We need to make tab handling rules more sane. A good rule is
+        #   Tabs cannot precede tokens
+        #   BLOCK-SEQUENCE-START, BLOCK-MAPPING-START, BLOCK-END,
+        #   KEY(block), VALUE(block), BLOCK-ENTRY
+        # So the checking code is
+        #   if <TAB>:
+        #       self.allow_simple_keys = False
+        # We also need to add the check for `allow_simple_keys == True` to
+        # `unwind_indent` before issuing BLOCK-END.
+        # Scanners for block, flow, and plain scalars need to be modified.
+
         if self.reader.index == 0 and self.reader.peek() == u'\uFEFF':
             self.reader.forward()
@@ -794,11 +786,11 @@
         if not length:
             raise ScannerError("while scanning a directive", start_marker,
-                    "expected directive name, but found %r" % ch.encode('utf-8'),
-                    self.reader.get_marker())
+                    "expected alphabetic or numeric character, but found %r"
+                    % ch.encode('utf-8'), self.reader.get_marker())
         value = self.reader.prefix(length)
         self.reader.forward(length)
         ch = self.reader.peek()
         if ch not in u'\0 \r\n\x85\u2028\u2029':
-            raise ScannerError("while scanning a directive" % name, start_marker,
+            raise ScannerError("while scanning a directive", start_marker,
                     "expected alphabetic or numeric character, but found %r"
                     % ch.encode('utf-8'), self.reader.get_marker())
@@ -812,5 +804,6 @@
         if self.reader.peek() != '.':
             raise ScannerError("while scanning a directive", start_marker,
-                    "expected a digit or '.', but found %r" % ch.encode('utf-8'),
+                    "expected a digit or '.', but found %r"
+                    % self.reader.peek().encode('utf-8'),
                     self.reader.get_marker())
         self.reader.forward()
@@ -818,5 +811,6 @@
         if self.reader.peek() not in u'\0 \r\n\x85\u2028\u2029':
             raise ScannerError("while scanning a directive", start_marker,
-                    "expected a digit or ' ', but found %r" % ch.encode('utf-8'),
+                    "expected a digit or ' ', but found %r"
+                    % self.reader.peek().encode('utf-8'),
                     self.reader.get_marker())
         return (major, minor)
@@ -849,5 +843,6 @@
         # See the specification for details.
         value = self.scan_tag_handle('directive', start_marker)
-        if self.reader.peek() != u' ':
+        ch = self.reader.peek()
+        if ch != u' ':
             raise ScannerError("while scanning a directive", start_marker,
                     "expected ' ', but found %r" % ch.encode('utf-8'),
@@ -903,6 +898,6 @@
         if not length:
             raise ScannerError("while scanning an %s" % name, start_marker,
-                    "expected anchor name, but found %r" % ch.encode('utf-8'),
-                    self.reader.get_marker())
+                    "expected alphabetic or numeric character, but found %r"
+                    % ch.encode('utf-8'), self.reader.get_marker())
         value = self.reader.prefix(length)
         self.reader.forward(length)
@@ -924,6 +919,6 @@
             suffix = self.scan_tag_uri('tag', start_marker)
             if self.reader.peek() != u'>':
-                raise ScannerError("while parsing a tag", start_marking,
-                        "expected '>', but got %r" % self.reader.peek().encode('utf-8'),
+                raise ScannerError("while parsing a tag", start_marker,
+                        "expected '>', but found %r" % self.reader.peek().encode('utf-8'),
                         self.reader.get_marker())
             self.reader.forward()
@@ -1310,5 +1305,6 @@
         # For some strange reasons, the specification does not allow '_' in
         # tag handles. I have allowed it anyway.
-        if self.reader.peek() != u'!':
+        ch = self.reader.peek()
+        if ch != u'!':
             raise ScannerError("while scanning a %s" % name, start_marker,
                     "expected '!', but found %r" % ch.encode('utf-8'),
Index: /branches/pyyaml3000/lib/yaml/parser.py
===================================================================
--- /branches/pyyaml3000/lib/yaml/parser.py	(revision 51)
+++ /branches/pyyaml3000/lib/yaml/parser.py	(revision 52)
@@ -21,5 +21,8 @@
 # flow_sequence_entry   ::= flow_node | KEY flow_node? (VALUE flow_node?)?
 # flow_mapping_entry    ::= flow_node | KEY flow_node? (VALUE flow_node?)?
-#
+
+# TODO: support for BOM within a stream.
+# stream ::= (BOM? implicit_document)? (BOM? explicit_document)* STREAM-END
+
 # Note that there is a slight deviation from the specification. We require a
 # non-empty node content if ANCHOR or TAG is specified. This disallow such
@@ -59,26 +62,10 @@
 # flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
 
-from error import YAMLError
+from error import MarkedYAMLError
 from tokens import *
 from events import *
 
-class ParserError(YAMLError):
-
-    def __init__(self, context=None, context_marker=None,
-            problem=None, problem_marker=None):
-        self.context = context
-        self.context_marker = context_marker
-        self.problem = problem
-        self.problem_marker = problem_marker
-
-    def __str__(self):
-        lines = []
-        for (place, marker) in [(self.context, self.context_marker),
-                                (self.problem, self.problem_marker)]:
-            if place is not None:
-                lines.append(place)
-                if marker is not None:
-                    lines.append(str(marker))
-        return '\n'.join(lines)
+class ParserError(MarkedYAMLError):
+    pass
 
 class Parser:
@@ -169,10 +156,10 @@
                 if self.yaml_version is not None:
                     raise ParserError(None, None,
-                            "found duplicate YAML directive", token.start_marker())
+                            "found duplicate YAML directive", token.start_marker)
                 major, minor = token.value
                 if major != 1:
                     raise ParserError(None, None,
                             "found incompatible YAML document (version 1.* is required)",
-                            token.start_marker())
+                            token.start_marker)
                 self.yaml_version = token.value
             elif token.name == u'TAG':
@@ -181,5 +168,5 @@
                     raise ParserError(None, None,
                             "duplicate tag handle %r" % handle.encode('utf-8'),
-                            token.start_marker())
+                            token.start_marker)
                 self.tag_handles[handle] = prefix
         for key in self.DEFAULT_TAGS:
@@ -394,8 +381,4 @@
             if self.scanner.check(FlowEntryToken):
                 self.scanner.get()
-        if not self.scanner.check(FlowSequenceEndToken):
-            token = self.scanner.peek()
-            raise ParserError("while scanning a flow sequence", start_marker,
-                    "expected ']', but found %r" % token.id, token.start_marker)
         token = self.scanner.get()
         yield CollectionEndEvent(token.start_marker, token.end_marker)
