Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r52643 - in trunk: boost/spirit/home/karma boost/spirit/home/karma/auxiliary boost/spirit/home/lex/detail boost/spirit/home/support boost/spirit/include libs/spirit/example/karma
From: hartmut.kaiser_at_[hidden]
Date: 2009-04-27 20:19:55


Author: hkaiser
Date: 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
New Revision: 52643
URL: http://svn.boost.org/trac/boost/changeset/52643

Log:
Spirit: Added more missing files.
Added:
   trunk/boost/spirit/home/lex/detail/
   trunk/boost/spirit/home/lex/detail/sequence_function.hpp (contents, props changed)
   trunk/boost/spirit/include/karma_generate_attr.hpp (contents, props changed)
   trunk/boost/spirit/include/lex_lexertl.hpp (contents, props changed)
   trunk/boost/spirit/include/lex_static_lexertl.hpp (contents, props changed)
   trunk/boost/spirit/include/qi_parse_attr.hpp (contents, props changed)
   trunk/boost/spirit/include/support_any_if_ns.hpp (contents, props changed)
   trunk/boost/spirit/include/support_attributes.hpp (contents, props changed)
   trunk/boost/spirit/include/support_modify.hpp (contents, props changed)
   trunk/libs/spirit/example/karma/calc2_ast_dump.cpp (contents, props changed)
   trunk/libs/spirit/example/karma/calc2_ast_rpn.cpp (contents, props changed)
Text files modified:
   trunk/boost/spirit/home/karma/auxiliary.hpp | 2 +-
   trunk/boost/spirit/home/karma/auxiliary/eol.hpp | 3 ++-
   trunk/boost/spirit/home/support/common_terminals.hpp | 1 +
   trunk/boost/spirit/home/support/terminal.hpp | 26 ++++++++++++++++++++++++++
   4 files changed, 30 insertions(+), 2 deletions(-)

Modified: trunk/boost/spirit/home/karma/auxiliary.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/auxiliary.hpp (original)
+++ trunk/boost/spirit/home/karma/auxiliary.hpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -6,7 +6,7 @@
 #if !defined(BOOST_SPIRIT_KARMA_AUXILIARY_MAR_26_2007_1225PM)
 #define BOOST_SPIRIT_KARMA_AUXILIARY_MAR_26_2007_1225PM
 
-// #include <boost/spirit/home/karma/auxiliary/confix.hpp>
+#include <boost/spirit/home/karma/auxiliary/confix.hpp>
 #include <boost/spirit/home/karma/auxiliary/eps.hpp>
 #include <boost/spirit/home/karma/auxiliary/eol.hpp>
 #include <boost/spirit/home/karma/auxiliary/lazy.hpp>

Modified: trunk/boost/spirit/home/karma/auxiliary/eol.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/auxiliary/eol.hpp (original)
+++ trunk/boost/spirit/home/karma/auxiliary/eol.hpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -8,10 +8,11 @@
 
 #include <boost/spirit/home/support/common_terminals.hpp>
 #include <boost/spirit/home/support/info.hpp>
+#include <boost/spirit/home/support/unused.hpp>
+#include <boost/spirit/home/support/attributes.hpp>
 #include <boost/spirit/home/karma/domain.hpp>
 #include <boost/spirit/home/karma/meta_compiler.hpp>
 #include <boost/spirit/home/karma/delimit_out.hpp>
-#include <boost/spirit/home/support/unused.hpp>
 #include <boost/spirit/home/karma/detail/generate_to.hpp>
 
 namespace boost { namespace spirit

Added: trunk/boost/spirit/home/lex/detail/sequence_function.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/spirit/home/lex/detail/sequence_function.hpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -0,0 +1,37 @@
+// Copyright (c) 2001-2009 Hartmut Kaiser
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#if !defined(BOOST_SPIRIT_LEX_SEQUENCE_FUNCTION_FEB_28_2007_0249PM)
+#define BOOST_SPIRIT_LEX_SEQUENCE_FUNCTION_FEB_28_2007_0249PM
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once // MS compatible compilers support #pragma once
+#endif
+
+#include <boost/spirit/home/lex/domain.hpp>
+#include <boost/spirit/home/support/unused.hpp>
+
+namespace boost { namespace spirit { namespace lex { namespace detail
+{
+ template <typename LexerDef, typename String>
+ struct sequence_function
+ {
+ sequence_function(LexerDef& def_, String const& state_)
+ : def(def_), state(state_) {}
+
+ template <typename Component>
+ bool operator()(Component const& component) const
+ {
+ component.collect(def, state);
+ return false; // execute for all sequence elements
+ }
+
+ LexerDef& def;
+ String const& state;
+ };
+
+}}}}
+
+#endif

Modified: trunk/boost/spirit/home/support/common_terminals.hpp
==============================================================================
--- trunk/boost/spirit/home/support/common_terminals.hpp (original)
+++ trunk/boost/spirit/home/support/common_terminals.hpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -73,6 +73,7 @@
         ( right_align )
         ( center )
         ( maxwidth )
+ ( confix )
         ( set_state )
         ( in_state )
         ( token )

Modified: trunk/boost/spirit/home/support/terminal.hpp
==============================================================================
--- trunk/boost/spirit/home/support/terminal.hpp (original)
+++ trunk/boost/spirit/home/support/terminal.hpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -386,6 +386,32 @@
               , phoenix::as_actor<A2>::convert(_2));
         }
     };
+
+ ///////////////////////////////////////////////////////////////////////////
+ namespace traits
+ {
+ // Calculate the type of the compound terminal if generated by one of
+ // the spirit::terminal::operator() overloads above
+ template <
+ typename Tag
+ , typename A0 = unused_type
+ , typename A1 = unused_type
+ , typename A2 = unused_type
+ >
+ struct terminal
+ {
+ typedef typename spirit::terminal<Tag>::
+ template result<A0, A1, A2>::type type;
+ };
+
+ // The terminal type itself is passed through without modification
+ template <typename Tag>
+ struct terminal<Tag, unused_type, unused_type, unused_type>
+ {
+ typedef spirit::terminal<Tag> type;
+ };
+ }
+
 }}
 
 // Define a spirit terminal. This macro may be placed in any namespace.

Added: trunk/boost/spirit/include/karma_generate_attr.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/spirit/include/karma_generate_attr.hpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -0,0 +1,12 @@
+/*=============================================================================
+ Copyright (c) 2001-2009 Joel de Guzman
+ Copyright (c) 2001-2009 Hartmut Kaiser
+ http://spirit.sourceforge.net/
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+#ifndef BOOST_SPIRIT_INCLUDE_KARMA_GENERATE_ATTR
+#define BOOST_SPIRIT_INCLUDE_KARMA_GENERATE_ATTR
+#include <boost/spirit/home/karma/generate_attr.hpp>
+#endif

Added: trunk/boost/spirit/include/lex_lexertl.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/spirit/include/lex_lexertl.hpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -0,0 +1,12 @@
+/*=============================================================================
+ Copyright (c) 2001-2009 Joel de Guzman
+ Copyright (c) 2001-2009 Hartmut Kaiser
+ http://spirit.sourceforge.net/
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+#ifndef BOOST_SPIRIT_INCLUDE_LEX_LEXERTL
+#define BOOST_SPIRIT_INCLUDE_LEX_LEXERTL
+#include <boost/spirit/home/lex/lexer_lexertl.hpp>
+#endif

Added: trunk/boost/spirit/include/lex_static_lexertl.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/spirit/include/lex_static_lexertl.hpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -0,0 +1,12 @@
+/*=============================================================================
+ Copyright (c) 2001-2009 Joel de Guzman
+ Copyright (c) 2001-2009 Hartmut Kaiser
+ http://spirit.sourceforge.net/
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+#ifndef BOOST_SPIRIT_INCLUDE_LEX_LEXER_STATIC_LEXERTL
+#define BOOST_SPIRIT_INCLUDE_LEX_LEXER_STATIC_LEXERTL
+#include <boost/spirit/home/lex/lexer_static_lexertl.hpp>
+#endif

Added: trunk/boost/spirit/include/qi_parse_attr.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/spirit/include/qi_parse_attr.hpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -0,0 +1,12 @@
+/*=============================================================================
+ Copyright (c) 2001-2009 Joel de Guzman
+ Copyright (c) 2001-2009 Hartmut Kaiser
+ http://spirit.sourceforge.net/
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+#ifndef BOOST_SPIRIT_INCLUDE_QI_PARSE_ATTR
+#define BOOST_SPIRIT_INCLUDE_QI_PARSE_ATTR
+#include <boost/spirit/home/qi/parse_attr.hpp>
+#endif

Added: trunk/boost/spirit/include/support_any_if_ns.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/spirit/include/support_any_if_ns.hpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -0,0 +1,12 @@
+/*=============================================================================
+ Copyright (c) 2001-2009 Joel de Guzman
+ Copyright (c) 2001-2009 Hartmut Kaiser
+ http://spirit.sourceforge.net/
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+#ifndef BOOST_SPIRIT_INCLUDE_SUPPORT_ANY_IF_NS
+#define BOOST_SPIRIT_INCLUDE_SUPPORT_ANY_IF_NS
+#include <boost/spirit/home/support/algorithm/any_if_ns.hpp>
+#endif

Added: trunk/boost/spirit/include/support_attributes.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/spirit/include/support_attributes.hpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -0,0 +1,12 @@
+/*=============================================================================
+ Copyright (c) 2001-2009 Joel de Guzman
+ Copyright (c) 2001-2009 Hartmut Kaiser
+ http://spirit.sourceforge.net/
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+#ifndef BOOST_SPIRIT_INCLUDE_SUPPORT_ATTRIBUTE_OF
+#define BOOST_SPIRIT_INCLUDE_SUPPORT_ATTRIBUTE_OF
+#include <boost/spirit/home/support/attributes.hpp>
+#endif

Added: trunk/boost/spirit/include/support_modify.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/spirit/include/support_modify.hpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -0,0 +1,12 @@
+/*=============================================================================
+ Copyright (c) 2001-2009 Joel de Guzman
+ Copyright (c) 2001-2009 Hartmut Kaiser
+ http://spirit.sourceforge.net/
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+#ifndef BOOST_SPIRIT_INCLUDE_SUPPORT_MODIFY
+#define BOOST_SPIRIT_INCLUDE_SUPPORT_MODIFY
+#include <boost/spirit/home/support/modify.hpp>
+#endif

Added: trunk/libs/spirit/example/karma/calc2_ast_dump.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/example/karma/calc2_ast_dump.cpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -0,0 +1,166 @@
+/*=============================================================================
+ Copyright (c) 2001-2009 Joel de Guzman
+ Copyright (c) 2001-2009 Hartmut Kaiser
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+///////////////////////////////////////////////////////////////////////////////
+//
+// A Calculator example demonstrating generation of AST which gets dumped into
+// a human readable format afterwards.
+//
+// [ JDG April 28, 2008 ]
+// [ HK April 28, 2008 ]
+//
+///////////////////////////////////////////////////////////////////////////////
+#include <boost/config/warning_disable.hpp>
+#include <boost/spirit/include/qi.hpp>
+#include <boost/spirit/include/karma.hpp>
+
+#include <iostream>
+#include <vector>
+#include <string>
+
+#include "calc2_ast.hpp"
+
+using namespace boost::spirit;
+using namespace boost::spirit::ascii;
+
+///////////////////////////////////////////////////////////////////////////////
+// Our calculator parser grammar
+///////////////////////////////////////////////////////////////////////////////
+template <typename Iterator>
+struct calculator
+ : qi::grammar<Iterator, expression_ast(), space_type>
+{
+ calculator() : calculator::base_type(expression)
+ {
+ expression =
+ term [_val = _1]
+ >> *( ('+' >> term [_val += _1])
+ | ('-' >> term [_val -= _1])
+ )
+ ;
+
+ term =
+ factor [_val = _1]
+ >> *( ('*' >> factor [_val *= _1])
+ | ('/' >> factor [_val /= _1])
+ )
+ ;
+
+ factor =
+ uint_ [_val = _1]
+ | '(' >> expression [_val = _1] >> ')'
+ | ('-' >> factor [_val = neg(_1)])
+ | ('+' >> factor [_val = pos(_1)])
+ ;
+ }
+
+ qi::rule<Iterator, expression_ast(), space_type> expression, term, factor;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Our AST grammar for the generator, this just dumps the AST as a expression
+///////////////////////////////////////////////////////////////////////////////
+template <typename OuputIterator>
+struct dump_ast
+ : karma::grammar<OuputIterator, expression_ast(), space_type>
+{
+ dump_ast() : dump_ast::base_type(ast_node)
+ {
+ ast_node %=
+ int_ [_1 = _int(_val)]
+ | binary_node [_1 = _bin_op(_val)]
+ | unary_node [_1 = _unary_op(_val)]
+ ;
+
+ binary_node =
+ ('(' << ast_node << char_ << ast_node << ')')
+ [
+ _1 = _left(_val), _2 = _op(_val), _3 = _right(_val)
+ ]
+ ;
+
+ unary_node =
+ ('(' << char_ << ast_node << ')')
+ [
+ _1 = _op(_val), _2 = _right(_val)
+ ]
+ ;
+ }
+
+ karma::rule<OuputIterator, expression_ast(), space_type> ast_node;
+ karma::rule<OuputIterator, binary_op(), space_type> binary_node;
+ karma::rule<OuputIterator, unary_op(), space_type> unary_node;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Main program
+///////////////////////////////////////////////////////////////////////////////
+int
+main()
+{
+ std::cout << "/////////////////////////////////////////////////////////\n\n";
+ std::cout << "Dump AST's for simple expressions...\n\n";
+ std::cout << "/////////////////////////////////////////////////////////\n\n";
+ std::cout << "Type an expression...or [q or Q] to quit\n\n";
+
+ // Our parser grammar definitions
+ typedef std::string::const_iterator iterator_type;
+ typedef calculator<iterator_type> calculator;
+
+ calculator calc;
+
+ // Our generator grammar definitions
+ typedef std::back_insert_iterator<std::string> output_iterator_type;
+ typedef dump_ast<output_iterator_type> dump_ast;
+
+ dump_ast ast_grammar;
+
+ std::string str;
+ while (std::getline(std::cin, str))
+ {
+ if (str.empty() || str[0] == 'q' || str[0] == 'Q')
+ break;
+
+ expression_ast ast;
+ std::string::const_iterator iter = str.begin();
+ std::string::const_iterator end = str.end();
+ bool r = qi::phrase_parse(iter, end, calc, space, ast);
+
+ if (r && iter == end)
+ {
+ std::string generated;
+ output_iterator_type outit(generated);
+ r = karma::generate_delimited(outit, ast_grammar, space, ast);
+
+ if (r)
+ {
+ std::cout << "Got AST:" << std::endl << generated
+ << std::endl;
+ std::cout << "-------------------------\n";
+ }
+ else
+ {
+ std::cout << "-------------------------\n";
+ std::cout << "Generating failed\n";
+ std::cout << "-------------------------\n";
+ }
+ }
+ else
+ {
+ std::string rest(iter, end);
+ std::cout << "-------------------------\n";
+ std::cout << "Parsing failed\n";
+ std::cout << "stopped at: \": " << rest << "\"\n";
+ std::cout << "-------------------------\n";
+ }
+ }
+
+ std::cout << "Bye... :-) \n\n";
+ return 0;
+}
+
+

Added: trunk/libs/spirit/example/karma/calc2_ast_rpn.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/example/karma/calc2_ast_rpn.cpp 2009-04-27 20:19:52 EDT (Mon, 27 Apr 2009)
@@ -0,0 +1,170 @@
+/*=============================================================================
+ Copyright (c) 2001-2009 Joel de Guzman
+ Copyright (c) 2001-2009 Hartmut Kaiser
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+///////////////////////////////////////////////////////////////////////////////
+//
+// A Calculator example demonstrating generation of AST which gets dumped into
+// a reverse polish notation afterwards.
+//
+// [ JDG April 28, 2008 ]
+// [ HK April 28, 2008 ]
+//
+///////////////////////////////////////////////////////////////////////////////
+#include <boost/config/warning_disable.hpp>
+#include <boost/spirit/include/qi.hpp>
+#include <boost/spirit/include/karma.hpp>
+
+#include <iostream>
+#include <vector>
+#include <string>
+
+#include "calc2_ast.hpp"
+
+using namespace boost::spirit;
+using namespace boost::spirit::ascii;
+
+///////////////////////////////////////////////////////////////////////////////
+// Our calculator parser grammar
+///////////////////////////////////////////////////////////////////////////////
+template <typename Iterator>
+struct calculator
+ : qi::grammar<Iterator, expression_ast(), space_type>
+{
+ calculator() : calculator::base_type(expression)
+ {
+ expression =
+ term [_val = _1]
+ >> *( ('+' >> term [_val += _1])
+ | ('-' >> term [_val -= _1])
+ )
+ ;
+
+ term =
+ factor [_val = _1]
+ >> *( ('*' >> factor [_val *= _1])
+ | ('/' >> factor [_val /= _1])
+ )
+ ;
+
+ factor =
+ uint_ [_val = _1]
+ | '(' >> expression [_val = _1] >> ')'
+ | ('-' >> factor [_val = neg(_1)])
+ | ('+' >> factor [_val = pos(_1)])
+ ;
+ }
+
+ qi::rule<Iterator, expression_ast(), space_type> expression, term, factor;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Our AST grammar for the generator, this prints the AST in reverse polish
+// notation
+///////////////////////////////////////////////////////////////////////////////
+template <typename OuputIterator>
+struct ast_rpn
+ : karma::grammar<OuputIterator, expression_ast(), space_type>
+{
+ ast_rpn() : ast_rpn::base_type(ast_node)
+ {
+ ast_node %=
+ int_ [_1 = _int(_val)]
+ | binary_node [_1 = _bin_op(_val)]
+ | unary_node [_1 = _unary_op(_val)]
+ ;
+
+ binary_node =
+ (ast_node << ast_node << char_)
+ [
+ _1 = _left(_val), _2 = _right(_val), _3 = _op(_val)
+ ]
+ ;
+
+ unary_node =
+// verbatim [
+ ('(' << ast_node << char_ << ')')
+ [
+ _1 = _right(_val), _2 = _op(_val)
+ ]
+// ]
+ ;
+ }
+
+ karma::rule<OuputIterator, expression_ast(), space_type> ast_node;
+ karma::rule<OuputIterator, binary_op(), space_type> binary_node;
+ karma::rule<OuputIterator, unary_op(), space_type> unary_node;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Main program
+///////////////////////////////////////////////////////////////////////////////
+int
+main()
+{
+ std::cout << "/////////////////////////////////////////////////////////\n\n";
+ std::cout << "RPN generator for simple expressions...\n\n";
+ std::cout << "/////////////////////////////////////////////////////////\n\n";
+ std::cout << "Type an expression...or [q or Q] to quit\n\n";
+
+ // Our parser grammar definitions
+ typedef std::string::const_iterator iterator_type;
+ typedef calculator<iterator_type> calculator;
+
+ calculator calc;
+
+ // Our generator grammar definitions
+ typedef std::back_insert_iterator<std::string> output_iterator_type;
+ typedef ast_rpn<output_iterator_type> ast_rpn;
+
+ ast_rpn ast_grammar;
+
+ std::string str;
+ while (std::getline(std::cin, str))
+ {
+ if (str.empty() || str[0] == 'q' || str[0] == 'Q')
+ break;
+
+ expression_ast ast; // this will hold the generated AST
+
+ std::string::const_iterator iter = str.begin();
+ std::string::const_iterator end = str.end();
+ bool r = qi::phrase_parse(iter, end, calc, space, ast);
+
+ if (r && iter == end)
+ {
+ std::string generated;
+ output_iterator_type outit(generated);
+ r = karma::generate_delimited(outit, ast_grammar, space, ast);
+
+ if (r)
+ {
+ std::cout << "RPN for '" << str << "': \n" << generated
+ << std::endl;
+ std::cout << "-------------------------\n";
+ }
+ else
+ {
+ std::cout << "-------------------------\n";
+ std::cout << "Generating failed\n";
+ std::cout << "-------------------------\n";
+ }
+ }
+ else
+ {
+ std::string rest(iter, end);
+ std::cout << "-------------------------\n";
+ std::cout << "Parsing failed\n";
+ std::cout << "stopped at: \": " << rest << "\"\n";
+ std::cout << "-------------------------\n";
+ }
+ }
+
+ std::cout << "Bye... :-) \n\n";
+ return 0;
+}
+
+


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk