Final set of changes by Fred before 1.4beta3
diff --git a/Demo/parser/Makefile b/Demo/parser/Makefile
index 648bf6e..d71e811 100644
--- a/Demo/parser/Makefile
+++ b/Demo/parser/Makefile
@@ -3,6 +3,10 @@
 
 #  Use a new name for this; the included file uses 'clean' already....
 clean-parser:
-	rm -f *.log *.aux *.dvi *.pyc
+	rm -f *.log *.aux *.dvi *.pyc *.ps
+
+dist:
+	(cd ../..; \
+	 tar cf - `cat Demo/parser/FILES` | gzip >parsermodule-1.4.tar.gz)
 
 include ../../Doc/Makefile
diff --git a/Demo/parser/README b/Demo/parser/README
index 03696c3..3d775aa 100644
--- a/Demo/parser/README
+++ b/Demo/parser/README
@@ -4,12 +4,29 @@
 Files:
 ------
 
+	FILES	     -- list of files associated with the parser module.
+
+	README	     -- this file.
+
 	example.py   --	module that uses the `parser' module to extract
 			information from the parse tree of Python source
 			code.
 
+	docstring.py -- sample source file containing only a module docstring.
+
+	simple.py    -- sample source containing a "short form" definition.
+
 	source.py    --	sample source code used to demonstrate ability to
 			handle nested constructs easily using the functions
 			and classes in example.py.
 
+	pprint.py    -- function to pretty-print Python values.
+
+	test_parser.py  program to put the parser module through it's paces.
+
+	parser.tex   -- LaTex driver file for formatting the parser module
+			documentation separately from the library reference.
+
+	Makefile     -- `make' rule set to format the parser module manual.
+
 Enjoy!
diff --git a/Demo/parser/example.py b/Demo/parser/example.py
index c428aff..363f5bb 100644
--- a/Demo/parser/example.py
+++ b/Demo/parser/example.py
@@ -1,6 +1,8 @@
 """Simple code to extract class & function docstrings from a module.
 
-
+This code is used as an example in the library reference manual in the
+section on using the parser module.  Refer to the manual for a thorough
+discussion of the operation of this code.
 """
 
 import symbol
@@ -23,12 +25,35 @@
     return ModuleInfo(tup, basename)
 
 
-class DefnInfo:
+class SuiteInfoBase:
     _docstring = ''
     _name = ''
 
-    def __init__(self, tree):
-	self._name = tree[2][1]
+    def __init__(self, tree = None):
+	self._class_info = {}
+	self._function_info = {}
+	if tree:
+	    self._extract_info(tree)
+
+    def _extract_info(self, tree):
+	# extract docstring
+	if len(tree) == 2:
+	    found, vars = match(DOCSTRING_STMT_PATTERN[1], tree[1])
+	else:
+	    found, vars = match(DOCSTRING_STMT_PATTERN, tree[3])
+	if found:
+	    self._docstring = eval(vars['docstring'])
+	# discover inner definitions
+	for node in tree[1:]:
+	    found, vars = match(COMPOUND_STMT_PATTERN, node)
+	    if found:
+		cstmt = vars['compound']
+		if cstmt[0] == symbol.funcdef:
+		    name = cstmt[2][1]
+		    self._function_info[name] = FunctionInfo(cstmt)
+		elif cstmt[0] == symbol.classdef:
+		    name = cstmt[2][1]
+		    self._class_info[name] = ClassInfo(cstmt)
 
     def get_docstring(self):
 	return self._docstring
@@ -36,38 +61,21 @@
     def get_name(self):
 	return self._name
 
-class SuiteInfoBase(DefnInfo):
-    def __init__(self):
-	self._class_info = {}
-	self._function_info = {}
-
     def get_class_names(self):
 	return self._class_info.keys()
 
     def get_class_info(self, name):
 	return self._class_info[name]
 
-    def _extract_info(self, tree):
-	if len(tree) >= 4:
-	    found, vars = match(DOCSTRING_STMT_PATTERN, tree[3])
-	    if found:
-		self._docstring = eval(vars['docstring'])
-	for node in tree[1:]:
-	    if (node[0] == symbol.stmt
-		and node[1][0] == symbol.compound_stmt):
-		if node[1][1][0] == symbol.funcdef:
-		    name = node[1][1][2][1]
-		    self._function_info[name] = \
-					      FunctionInfo(node[1][1])
-		elif node[1][1][0] == symbol.classdef:
-		    name = node[1][1][2][1]
-		    self._class_info[name] = ClassInfo(node[1][1])
+    def __getitem__(self, name):
+	try:
+	    return self._class_info[name]
+	except KeyError:
+	    return self._function_info[name]
 
 
-class SuiteInfo(SuiteInfoBase):
-    def __init__(self, tree):
-	SuiteInfoBase.__init__(self)
-	self._extract_info(tree)
+class SuiteFuncInfo:
+    #  Mixin class providing access to function names and info.
 
     def get_function_names(self):
 	return self._function_info.keys()
@@ -76,23 +84,16 @@
 	return self._function_info[name]
 
 
-class FunctionInfo(SuiteInfo):
-    def __init__(self, tree):
-	DefnInfo.__init__(self, tree)
-	suite = tree[-1]
-	if len(suite) >= 4:
-	    found, vars = match(DOCSTRING_STMT_PATTERN, suite[3])
-	    if found:
-		self._docstring = eval(vars['docstring'])
-	SuiteInfoBase.__init__(self)
-	self._extract_info(suite)
+class FunctionInfo(SuiteInfoBase, SuiteFuncInfo):
+    def __init__(self, tree = None):
+	self._name = tree[2][1]
+	SuiteInfoBase.__init__(self, tree and tree[-1] or None)
 
 
 class ClassInfo(SuiteInfoBase):
-    def __init__(self, tree):
-	SuiteInfoBase.__init__(self)
-	DefnInfo.__init__(self, tree)
-	self._extract_info(tree[-1])
+    def __init__(self, tree = None):
+	self._name = tree[2][1]
+	SuiteInfoBase.__init__(self, tree and tree[-1] or None)
 
     def get_method_names(self):
 	return self._function_info.keys()
@@ -101,19 +102,40 @@
 	return self._function_info[name]
 
 
-class ModuleInfo(SuiteInfo):
-    def __init__(self, tree, name="<string>"):
+class ModuleInfo(SuiteInfoBase, SuiteFuncInfo):
+    def __init__(self, tree = None, name = "<string>"):
 	self._name = name
-	SuiteInfo.__init__(self, tree)
-	found, vars = match(DOCSTRING_STMT_PATTERN, tree[1])
-	if found:
-	    self._docstring = vars["docstring"]
+	SuiteInfoBase.__init__(self, tree)
+	if tree:
+	    found, vars = match(DOCSTRING_STMT_PATTERN, tree[1])
+	    if found:
+		self._docstring = vars["docstring"]
 
 
 from types import ListType, TupleType
 
 def match(pattern, data, vars=None):
-    """
+    """Match `data' to `pattern', with variable extraction.
+
+    pattern
+	Pattern to match against, possibly containing variables.
+
+    data
+	Data to be checked and against which variables are extracted.
+
+    vars
+	Dictionary of variables which have already been found.  If not
+	provided, an empty dictionary is created.
+
+    The `pattern' value may contain variables of the form ['varname'] which
+    are allowed to match anything.  The value that is matched is returned as
+    part of a dictionary which maps 'varname' to the matched value.  'varname'
+    is not required to be a string object, but using strings makes patterns
+    and the code which uses them more readable.
+
+    This function returns two values: a boolean indicating whether a match
+    was found and a dictionary mapping variable names to their associated
+    values.
     """
     if vars is None:
 	vars = {}
@@ -131,6 +153,15 @@
     return same, vars
 
 
+#  This pattern identifies compound statements, allowing them to be readily
+#  differentiated from simple statements.
+#
+COMPOUND_STMT_PATTERN = (
+    symbol.stmt,
+    (symbol.compound_stmt, ['compound'])
+    )
+
+
 #  This pattern will match a 'stmt' node which *might* represent a docstring;
 #  docstrings require that the statement which provides the docstring be the
 #  first statement in the class or function, which this pattern does not check.
diff --git a/Demo/parser/pprint.py b/Demo/parser/pprint.py
index c4b8158..36d1888 100644
--- a/Demo/parser/pprint.py
+++ b/Demo/parser/pprint.py
@@ -1,7 +1,7 @@
 #  pprint.py
 #
 #  Author:	Fred L. Drake, Jr.
-#		fdrake@vt.edu
+#		fdrake@cnri.reston.va.us, fdrake@intr.net
 #
 #  This is a simple little module I wrote to make life easier.  I didn't
 #  see anything quite like it in the library, though I may have overlooked
@@ -9,35 +9,29 @@
 #  tuples with fairly non-descriptive content.  This is modelled very much
 #  after Lisp/Scheme - style pretty-printing of lists.  If you find it
 #  useful, thank small children who sleep at night.
-#
 
 """Support to pretty-print lists, tuples, & dictionaries recursively.
-Very simple, but at least somewhat useful, especially in debugging
-data structures.
+Very simple, but useful, especially in debugging data structures.
 
-INDENT_PER_LEVEL	--  Amount of indentation to use for each new
-			    recursive level.  The default is 1.  This
-			    must be a non-negative integer, and may be
-			    set by the caller before calling pprint().
+Constants
+---------
 
-MAX_WIDTH		--  Maximum width of the display.  This is only
-			    used if the representation *can* be kept
-			    less than MAX_WIDTH characters wide.  May
-			    be set by the user before calling pprint().
+INDENT_PER_LEVEL
+    Amount of indentation to use for each new recursive level.  The
+    default is 1.  This must be a non-negative integer, and may be set
+    by the caller before calling pprint().
 
-TAB_WIDTH		--  The width represented by a single tab.  This
-			    value is typically 8, but 4 is the default
-			    under MacOS.  Can be changed by the user if
-			    desired, but is probably not a good idea.
+MAX_WIDTH
+    Maximum width of the display.  This is only used if the
+    representation *can* be kept less than MAX_WIDTH characters wide.
+    May be set by the user before calling pprint().
 
-pprint(seq [, stream])	--  The pretty-printer.  This takes a Python
-			    object (presumably a sequence, but that
-			    doesn't matter) and an optional output
-			    stream.  See the function documentation
-			    for details.
+TAB_WIDTH
+    The width represented by a single tab.  This value is typically 8,
+    but 4 is the default under MacOS.  Can be changed by the user if
+    desired, but is probably not a good idea.
 """
 
-
 INDENT_PER_LEVEL = 1
 
 MAX_WIDTH = 80
@@ -46,46 +40,45 @@
 TAB_WIDTH = (os.name == 'mac' and 4) or 8
 del os
 
+from types import DictType, ListType, TupleType
 
 
 def _indentation(cols):
-    "Create tabbed indentation string COLS columns wide."
+    """Create tabbed indentation string.
 
-    #  This is used to reduce the byte-count for the output, allowing
-    #  files created using this module to use as little external storage
-    #  as possible.  This is primarily intended to minimize impact on
-    #  a user's quota when storing resource files, or for creating output
-    #  intended for transmission.
-
+    cols
+	Width of the indentation, in columns.
+    """
     return ((cols / TAB_WIDTH) * '\t') + ((cols % TAB_WIDTH) * ' ')
 
 
-
 def pprint(seq, stream = None, indent = 0, allowance = 0):
     """Pretty-print a list, tuple, or dictionary.
 
-    pprint(seq [, stream]) ==> None
+    seq
+	List, tuple, or dictionary object to be pretty-printed.  Other
+	object types are permitted by are not specially interpreted.
 
-    If STREAM is provided, output is written to that stream, otherwise
-    sys.stdout is used.  Indentation is done according to
-    INDENT_PER_LEVEL, which may be set to any non-negative integer
-    before calling this function.  The output written on the stream is
-    a perfectly valid representation of the Python object passed in,
-    with indentation to suite human-readable interpretation.  The
-    output can be used as input without error, given readable
-    representations of all sequence elements are available via repr().
-    Output is restricted to MAX_WIDTH columns where possible.  The
-    STREAM parameter must support the write() method with a single
-    parameter, which will always be a string.  The output stream may be
-    a StringIO.StringIO object if the result is needed as a string.
+    stream
+	Output stream.  If not provided, `sys.stdout' is used.  This
+	parameter must support the `write()' method with a single
+	parameter, which will always be a string.  It may be a
+	`StringIO.StringIO' object if the result is needed as a
+	string.
+
+    Indentation is done according to `INDENT_PER_LEVEL', which may be
+    set to any non-negative integer before calling this function.  The
+    output written on the stream is a perfectly valid representation
+    of the Python object passed in, with indentation to assist
+    human-readable interpretation.  The output can be used as input
+    without error, given readable representations of all elements are
+    available via `repr()'.  Output is restricted to `MAX_WIDTH'
+    columns where possible.
     """
-
     if stream is None:
 	import sys
 	stream = sys.stdout
 
-    from types import DictType, ListType, TupleType
-
     rep = `seq`
     typ = type(seq)
     sepLines = len(rep) > (MAX_WIDTH - 1 - indent - allowance)
@@ -140,4 +133,4 @@
 
 
 #
-#  end of pprint.py
+#  end of file
diff --git a/Demo/parser/simple.py b/Demo/parser/simple.py
new file mode 100644
index 0000000..184e2fe
--- /dev/null
+++ b/Demo/parser/simple.py
@@ -0,0 +1 @@
+def f(): "maybe a docstring"