First commit from BOOST_REVIEW branch spirit.sf.net
[SVN r17111]
145
example/fundamental/calc/grouping_calc.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Full calculator example
|
||||
// [ demonstrating grouping parser ]
|
||||
//
|
||||
// [ Hartmut Kaiser 10/7/2002 ]
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//#define BOOST_SPIRIT_DEBUG // define this, if debug output is required
|
||||
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/attribute.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
using namespace phoenix;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our calculator grammar using phoenix and grouping to do the semantics
|
||||
//
|
||||
// Note: The top rule propagates the expression result (value) upwards
|
||||
// to the calculator grammar self.val closure member which is
|
||||
// then visible outside the grammar (i.e. since self.val is the
|
||||
// member1 of the closure, it becomes the attribute passed by
|
||||
// the calculator to an attached semantic action. See the
|
||||
// driver code that uses the calculator below).
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
struct calc_closure : boost::spirit::closure<calc_closure, double>
|
||||
{
|
||||
member1 val;
|
||||
};
|
||||
|
||||
struct calculator : public grammar<calculator, calc_closure::context_t>
|
||||
{
|
||||
template <typename ScannerT>
|
||||
struct definition
|
||||
{
|
||||
definition(calculator const& self)
|
||||
{
|
||||
top = addsub_expr[self.val = arg1];
|
||||
|
||||
addsub_expr
|
||||
= group_d[muldiv_expr >> '+' >> muldiv_expr]
|
||||
[
|
||||
addsub_expr.val = arg1 + arg3
|
||||
]
|
||||
| group_d[muldiv_expr >> '-' >> muldiv_expr]
|
||||
[
|
||||
addsub_expr.val = arg1 - arg3
|
||||
]
|
||||
;
|
||||
|
||||
muldiv_expr
|
||||
= group_d[factor >> '*' >> factor]
|
||||
[
|
||||
muldiv_expr.val = arg1 * arg3
|
||||
]
|
||||
| group_d[factor >> '/' >> factor]
|
||||
[
|
||||
muldiv_expr.val = arg1 / arg3
|
||||
]
|
||||
| factor
|
||||
[
|
||||
muldiv_expr.val = arg1
|
||||
]
|
||||
;
|
||||
|
||||
factor
|
||||
= ureal_p[factor.val = arg1]
|
||||
| '(' >> addsub_expr[factor.val = arg1] >> ')'
|
||||
| '+' >> addsub_expr[factor.val = arg1]
|
||||
| '-' >> addsub_expr[factor.val = -arg1]
|
||||
;
|
||||
|
||||
BOOST_SPIRIT_DEBUG_NODE(top);
|
||||
BOOST_SPIRIT_DEBUG_NODE(addsub_expr);
|
||||
BOOST_SPIRIT_DEBUG_NODE(muldiv_expr);
|
||||
BOOST_SPIRIT_DEBUG_NODE(factor);
|
||||
}
|
||||
|
||||
typedef rule<ScannerT, calc_closure::context_t> rule_t;
|
||||
rule_t addsub_expr, muldiv_expr, factor;
|
||||
rule<ScannerT> top;
|
||||
|
||||
rule<ScannerT> const&
|
||||
start() const { return top; }
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\tExpression parser using Phoenix and grouping...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "Type an expression...or [q or Q] to quit\n\n";
|
||||
|
||||
calculator calc; // Our parser
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
double n = 0;
|
||||
parse_info<> info = parse(str.c_str(), calc[var(n) = arg1], space_p);
|
||||
|
||||
// calc[var(n) = arg1] invokes the calculator and extracts
|
||||
// the result of the computation. See calculator grammar
|
||||
// note above.
|
||||
|
||||
if (info.full)
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << "result = " << n << endl;
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "stopped at: \": " << info.stop << "\"\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
185
example/fundamental/calc/parse_tree_calc1.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
#include "boost/spirit/core.hpp"
|
||||
#include "boost/spirit/tree/parse_tree.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <stack>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
// This example shows how to use a parse tree
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
// Here's some typedefs to simplify things
|
||||
typedef char const* iterator_t;
|
||||
typedef tree_match<iterator_t> parse_tree_match_t;
|
||||
typedef parse_tree_match_t::const_tree_iterator iter_t;
|
||||
|
||||
typedef pt_match_policy<iterator_t> match_policy_t;
|
||||
typedef scanner_policies<iteration_policy, match_policy_t, action_policy> scanner_policy_t;
|
||||
typedef scanner<iterator_t, scanner_policy_t> scanner_t;
|
||||
typedef rule<scanner_t> rule_t;
|
||||
|
||||
// grammar rules
|
||||
rule_t expression, term, factor, integer;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Here's the function prototypes that we'll use. One function for each
|
||||
// grammar rule.
|
||||
long evaluate(const tree_parse_info<>& info);
|
||||
long eval_expression(iter_t const& i);
|
||||
long eval_term(iter_t const& i);
|
||||
long eval_factor(iter_t const& i);
|
||||
long eval_integer(iter_t const& i);
|
||||
|
||||
long evaluate(const tree_parse_info<>& info)
|
||||
{
|
||||
return eval_expression(info.trees.begin());
|
||||
}
|
||||
|
||||
// i should be pointing to a node created by the expression rule
|
||||
long eval_expression(iter_t const& i)
|
||||
{
|
||||
parser_id id = i->value.id();
|
||||
assert(id == parser_id(&expression)); // check the id
|
||||
|
||||
// first child points to a term, so call eval_term on it
|
||||
iter_t chi = i->children.begin();
|
||||
long lhs = eval_term(chi);
|
||||
for (++chi; chi != i->children.end(); ++chi)
|
||||
{
|
||||
// next node points to the operator. The text of the operator is
|
||||
// stored in value (a vector<char>)
|
||||
char op = *(chi->value.begin());
|
||||
++chi;
|
||||
long rhs = eval_term(chi);
|
||||
if (op == '+')
|
||||
lhs += rhs;
|
||||
else if (op == '-')
|
||||
lhs -= rhs;
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
long eval_term(iter_t const& i)
|
||||
{
|
||||
parser_id id = i->value.id();
|
||||
assert(id == parser_id(&term));
|
||||
|
||||
iter_t chi = i->children.begin();
|
||||
long lhs = eval_factor(chi);
|
||||
for (++chi; chi != i->children.end(); ++chi)
|
||||
{
|
||||
char op = *(chi->value.begin());
|
||||
++chi;
|
||||
long rhs = eval_factor(chi);
|
||||
if (op == '*')
|
||||
lhs *= rhs;
|
||||
else if (op == '/')
|
||||
lhs /= rhs;
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
long eval_factor(iter_t const& i)
|
||||
{
|
||||
parser_id id = i->value.id();
|
||||
assert(id == parser_id(&factor));
|
||||
|
||||
iter_t chi = i->children.begin();
|
||||
id = chi->value.id();
|
||||
if (id == parser_id(&integer))
|
||||
return eval_integer(chi->children.begin());
|
||||
else if (*(chi->value.begin()) == '(')
|
||||
{
|
||||
++chi;
|
||||
return eval_expression(chi);
|
||||
}
|
||||
else if (*(chi->value.begin()) == '-')
|
||||
{
|
||||
++chi;
|
||||
return -eval_factor(chi);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
long eval_integer(iter_t const& i)
|
||||
{
|
||||
// extract integer (not always delimited by '\0')
|
||||
string integer(i->value.begin(), i->value.end());
|
||||
|
||||
return strtol(integer.c_str(), 0, 10);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
|
||||
// Start grammar definition
|
||||
integer = lexeme_d[ token_node_d[ (!ch_p('-') >> +digit_p) ] ];
|
||||
factor = integer
|
||||
| '(' >> expression >> ')'
|
||||
| ('-' >> factor);
|
||||
term = factor >>
|
||||
*( ('*' >> factor)
|
||||
| ('/' >> factor)
|
||||
);
|
||||
expression = term >>
|
||||
*( ('+' >> term)
|
||||
| ('-' >> term)
|
||||
);
|
||||
// End grammar definition
|
||||
|
||||
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tThe simplest working calculator...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "Type an expression...or [q or Q] to quit\n\n";
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
const char* first = str.c_str();
|
||||
|
||||
tree_parse_info<> info = pt_parse(first, expression);
|
||||
|
||||
if (info.full)
|
||||
{
|
||||
#if defined(BOOST_SPIRIT_DUMP_PARSETREE_AS_XML)
|
||||
// dump parse tree as XML
|
||||
std::map<parser_id, std::string> rule_names;
|
||||
rule_names[&integer] = "integer";
|
||||
rule_names[&factor] = "factor";
|
||||
rule_names[&term] = "term";
|
||||
rule_names[&expression] = "expression";
|
||||
tree_to_xml(cout, info.trees, first, rule_names);
|
||||
#endif
|
||||
|
||||
// print the result
|
||||
cout << "parsing succeeded\n";
|
||||
cout << "result = " << evaluate(info) << "\n\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "parsing failed\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
124
example/fundamental/calc/phoenix_calc.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Full calculator example
|
||||
// [ demonstrating phoenix ]
|
||||
//
|
||||
// [ JDG 6/29/2002 ]
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/attribute.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
using namespace phoenix;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our calculator grammar using phoenix to do the semantics
|
||||
//
|
||||
// Note: The top rule propagates the expression result (value) upwards
|
||||
// to the calculator grammar self.val closure member which is
|
||||
// then visible outside the grammar (i.e. since self.val is the
|
||||
// member1 of the closure, it becomes the attribute passed by
|
||||
// the calculator to an attached semantic action. See the
|
||||
// driver code that uses the calculator below).
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
struct calc_closure : boost::spirit::closure<calc_closure, double>
|
||||
{
|
||||
member1 val;
|
||||
};
|
||||
|
||||
struct calculator : public grammar<calculator, calc_closure::context_t>
|
||||
{
|
||||
template <typename ScannerT>
|
||||
struct definition
|
||||
{
|
||||
definition(calculator const& self)
|
||||
{
|
||||
top = expression[self.val = arg1];
|
||||
|
||||
expression
|
||||
= term[expression.val = arg1]
|
||||
>> *( ('+' >> term[expression.val += arg1])
|
||||
| ('-' >> term[expression.val -= arg1])
|
||||
)
|
||||
;
|
||||
|
||||
term
|
||||
= factor[term.val = arg1]
|
||||
>> *( ('*' >> factor[term.val *= arg1])
|
||||
| ('/' >> factor[term.val /= arg1])
|
||||
)
|
||||
;
|
||||
|
||||
factor
|
||||
= ureal_p[factor.val = arg1]
|
||||
| '(' >> expression[factor.val = arg1] >> ')'
|
||||
| ('-' >> factor[factor.val = -arg1])
|
||||
| ('+' >> factor[factor.val = arg1])
|
||||
;
|
||||
}
|
||||
|
||||
typedef rule<ScannerT, calc_closure::context_t> rule_t;
|
||||
rule_t expression, term, factor;
|
||||
rule<ScannerT> top;
|
||||
|
||||
rule<ScannerT> const&
|
||||
start() const { return top; }
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tExpression parser using Phoenix...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "Type an expression...or [q or Q] to quit\n\n";
|
||||
|
||||
calculator calc; // Our parser
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
double n = 0;
|
||||
parse_info<> info = parse(str.c_str(), calc[var(n) = arg1], space_p);
|
||||
|
||||
// calc[var(n) = arg1] invokes the calculator and extracts
|
||||
// the result of the computation. See calculator grammar
|
||||
// note above.
|
||||
|
||||
if (info.full)
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << "result = " << n << endl;
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "stopped at: \": " << info.stop << "\"\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
134
example/fundamental/calc/phoenix_subrule_calc.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Full calculator example
|
||||
// [ demonstrating phoenix and subrules ]
|
||||
//
|
||||
// [ Hartmut Kaiser 10/8/2002 ]
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//#define BOOST_SPIRIT_DEBUG // define this for debug output
|
||||
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/attribute.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
using namespace phoenix;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our calculator grammar using phoenix to do the semantics and subrule's
|
||||
// as it's working horses
|
||||
//
|
||||
// Note: The top rule propagates the expression result (value) upwards
|
||||
// to the calculator grammar self.val closure member which is
|
||||
// then visible outside the grammar (i.e. since self.val is the
|
||||
// member1 of the closure, it becomes the attribute passed by
|
||||
// the calculator to an attached semantic action. See the
|
||||
// driver code that uses the calculator below).
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
struct calc_closure : boost::spirit::closure<calc_closure, double>
|
||||
{
|
||||
member1 val;
|
||||
};
|
||||
|
||||
struct calculator : public grammar<calculator, calc_closure::context_t>
|
||||
{
|
||||
template <typename ScannerT>
|
||||
struct definition
|
||||
{
|
||||
definition(calculator const& self)
|
||||
{
|
||||
top = (
|
||||
expression =
|
||||
term[self.val = arg1]
|
||||
>> *( ('+' >> term[self.val += arg1])
|
||||
| ('-' >> term[self.val -= arg1])
|
||||
)
|
||||
,
|
||||
|
||||
term =
|
||||
factor[term.val = arg1]
|
||||
>> *( ('*' >> factor[term.val *= arg1])
|
||||
| ('/' >> factor[term.val /= arg1])
|
||||
)
|
||||
,
|
||||
|
||||
factor
|
||||
= ureal_p[factor.val = arg1]
|
||||
| '(' >> expression[factor.val = arg1] >> ')'
|
||||
| ('-' >> factor[factor.val = -arg1])
|
||||
| ('+' >> factor[factor.val = arg1])
|
||||
);
|
||||
|
||||
BOOST_SPIRIT_DEBUG_NODE(top);
|
||||
BOOST_SPIRIT_DEBUG_NODE(expression);
|
||||
BOOST_SPIRIT_DEBUG_NODE(term);
|
||||
BOOST_SPIRIT_DEBUG_NODE(factor);
|
||||
}
|
||||
|
||||
subrule<0, calc_closure::context_t> expression;
|
||||
subrule<1, calc_closure::context_t> term;
|
||||
subrule<2, calc_closure::context_t> factor;
|
||||
|
||||
rule<ScannerT> top;
|
||||
|
||||
rule<ScannerT> const&
|
||||
start() const { return top; }
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tExpression parser using Phoenix...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "Type an expression...or [q or Q] to quit\n\n";
|
||||
|
||||
calculator calc; // Our parser
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
double n = 0;
|
||||
parse_info<> info = parse(str.c_str(), calc[var(n) = arg1], space_p);
|
||||
|
||||
// calc[var(n) = arg1] invokes the calculator and extracts
|
||||
// the result of the computation. See calculator grammar
|
||||
// note above.
|
||||
|
||||
if (info.full)
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << "result = " << n << endl;
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "stopped at: \": " << info.stop << "\"\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
88
example/fundamental/calc/primitive_calc.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// A primitive calculator that knows how to add and subtract.
|
||||
// [ demonstrating phoenix ]
|
||||
//
|
||||
// [ JDG 6/28/2002 ]
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/phoenix/primitives.hpp>
|
||||
#include <boost/phoenix/operators.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
using namespace phoenix;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our primitive calculator
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename IteratorT>
|
||||
bool primitive_calc(IteratorT first, IteratorT last, double& n)
|
||||
{
|
||||
return parse(first, last,
|
||||
|
||||
// Begin grammar
|
||||
(
|
||||
real_p[var(n) = arg1]
|
||||
>> *( ('+' >> real_p[var(n) += arg1])
|
||||
| ('-' >> real_p[var(n) -= arg1])
|
||||
)
|
||||
)
|
||||
,
|
||||
// End grammar
|
||||
|
||||
space_p).full;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tA primitive calculator...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
|
||||
cout << "Give me a list of numbers to be added or subtracted.\n";
|
||||
cout << "Example: 1 + 10 + 3 - 4 + 9\n";
|
||||
cout << "The result is computed using Phoenix.\n";
|
||||
cout << "Type [q or Q] to quit\n\n";
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
double n;
|
||||
if (primitive_calc(str.begin(), str.end(), n))
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << str << " Parses OK: " << endl;
|
||||
|
||||
cout << "result = " << n;
|
||||
cout << "\n-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
154
example/fundamental/calc/rpn_calc.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This sample shows, how to use Phoenix for implementing a
|
||||
// simple (RPN style) calculator [ demonstrating phoenix ]
|
||||
//
|
||||
// [ HKaiser 2001 ]
|
||||
// [ JDG 6/29/2002 ]
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/attribute.hpp>
|
||||
#include <boost/phoenix/functions.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
using namespace phoenix;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our RPN calculator grammar using phoenix to do the semantics
|
||||
// The class 'RPNCalculator' implements a polish reverse notation
|
||||
// calculator which is equivalent to the following YACC description.
|
||||
//
|
||||
// exp:
|
||||
// NUM { $$ = $1; }
|
||||
// | exp exp '+' { $$ = $1 + $2; }
|
||||
// | exp exp '-' { $$ = $1 - $2; }
|
||||
// | exp exp '*' { $$ = $1 * $2; }
|
||||
// | exp exp '/' { $$ = $1 / $2; }
|
||||
// | exp exp '^' { $$ = pow ($1, $2); } /* Exponentiation */
|
||||
// | exp 'n' { $$ = -$1; } /* Unary minus */
|
||||
// ;
|
||||
//
|
||||
// The different notation results from the requirement of LL parsers not to
|
||||
// allow left recursion in their grammar (would lead to endless recursion).
|
||||
// Therefore the left recursion in the YACC script before is transformated
|
||||
// into iteration. To some, this is less intuitive, but once you get used
|
||||
// to it, it's very easy to follow.
|
||||
//
|
||||
// Note: The top rule propagates the expression result (value) upwards
|
||||
// to the calculator grammar self.val closure member which is
|
||||
// then visible outside the grammar (i.e. since self.val is the
|
||||
// member1 of the closure, it becomes the attribute passed by
|
||||
// the calculator to an attached semantic action. See the
|
||||
// driver code that uses the calculator below).
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
struct pow_
|
||||
{
|
||||
template <typename X, typename Y>
|
||||
struct result { typedef X type; };
|
||||
|
||||
template <typename X, typename Y>
|
||||
X operator()(X x, Y y) const
|
||||
{
|
||||
using namespace std;
|
||||
return pow(x, y);
|
||||
}
|
||||
};
|
||||
|
||||
// Notice how power(x, y) is lazily implemented using Phoenix function.
|
||||
function<pow_> power;
|
||||
|
||||
struct calc_closure : boost::spirit::closure<calc_closure, double, double>
|
||||
{
|
||||
member1 x;
|
||||
member2 y;
|
||||
};
|
||||
|
||||
struct calculator : public grammar<calculator, calc_closure::context_t>
|
||||
{
|
||||
template <typename ScannerT>
|
||||
struct definition {
|
||||
|
||||
definition(calculator const& self)
|
||||
{
|
||||
top = expr [self.x = arg1];
|
||||
expr =
|
||||
real_p [expr.x = arg1]
|
||||
>> *(
|
||||
expr [expr.y = arg1]
|
||||
>> (
|
||||
ch_p('+') [expr.x += expr.y]
|
||||
| ch_p('-') [expr.x -= expr.y]
|
||||
| ch_p('*') [expr.x *= expr.y]
|
||||
| ch_p('/') [expr.x /= expr.y]
|
||||
| ch_p('^') [expr.x = power(expr.x, expr.y)]
|
||||
)
|
||||
| ch_p('n') [expr.x = -expr.x]
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
typedef rule<ScannerT, calc_closure::context_t> rule_t;
|
||||
rule_t expr;
|
||||
rule<ScannerT> top;
|
||||
|
||||
rule<ScannerT> const&
|
||||
start() const { return top; }
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tExpression parser using Phoenix...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "Type an expression...or [q or Q] to quit\n\n";
|
||||
|
||||
calculator calc; // Our parser
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
double n = 0;
|
||||
parse_info<> info = parse(str.c_str(), calc[var(n) = arg1], space_p);
|
||||
|
||||
// calc[var(n) = arg1] invokes the calculator and extracts
|
||||
// the result of the computation. See calculator grammar
|
||||
// note above.
|
||||
|
||||
if (info.full)
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << "result = " << n << endl;
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "stopped at: \": " << info.stop << "\"\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
132
example/fundamental/calc/subrule_calc.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This calculator example demontrates the use of subrules.
|
||||
//
|
||||
// [ JDG 4/11/2002 ]
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//#define BOOST_SPIRIT_DEBUG // define this for debug output
|
||||
|
||||
#include "boost/spirit/core.hpp"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Semantic actions
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
namespace {
|
||||
|
||||
void do_int(char const* str, char const* end)
|
||||
{
|
||||
string s(str, end);
|
||||
cout << "PUSH(" << s << ')' << endl;
|
||||
}
|
||||
|
||||
void do_add(char const*, char const*) { cout << "ADD\n"; }
|
||||
void do_subt(char const*, char const*) { cout << "SUBTRACT\n"; }
|
||||
void do_mult(char const*, char const*) { cout << "MULTIPLY\n"; }
|
||||
void do_div(char const*, char const*) { cout << "DIVIDE\n"; }
|
||||
void do_neg(char const*, char const*) { cout << "NEGATE\n"; }
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our calculator grammar (using subrules)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
struct calculator : public grammar<calculator> {
|
||||
|
||||
template <typename ScannerT>
|
||||
struct definition {
|
||||
|
||||
definition(calculator const& /*self*/)
|
||||
{
|
||||
first = (
|
||||
|
||||
expression =
|
||||
term
|
||||
>> *( ('+' >> term)[&do_add]
|
||||
| ('-' >> term)[&do_subt]
|
||||
)
|
||||
,
|
||||
|
||||
term =
|
||||
factor
|
||||
>> *( ('*' >> factor)[&do_mult]
|
||||
| ('/' >> factor)[&do_div]
|
||||
)
|
||||
,
|
||||
|
||||
factor
|
||||
= lexeme_d[(+digit_p)[&do_int]]
|
||||
| '(' >> expression >> ')'
|
||||
| ('-' >> factor)[&do_neg]
|
||||
| ('+' >> factor)
|
||||
);
|
||||
|
||||
BOOST_SPIRIT_DEBUG_NODE(first);
|
||||
BOOST_SPIRIT_DEBUG_NODE(expression);
|
||||
BOOST_SPIRIT_DEBUG_NODE(term);
|
||||
BOOST_SPIRIT_DEBUG_NODE(factor);
|
||||
}
|
||||
|
||||
subrule<0> expression;
|
||||
subrule<1> term;
|
||||
subrule<2> factor;
|
||||
|
||||
rule<ScannerT> first;
|
||||
rule<ScannerT> const&
|
||||
start() const { return first; }
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tA calculator using subrules...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "Type an expression...or [q or Q] to quit\n\n";
|
||||
|
||||
calculator calc; // Our parser
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
parse_info<> info = parse(str.c_str(), calc, space_p);
|
||||
|
||||
if (info.full)
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "stopped at: \": " << info.stop << "\"\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
61
example/fundamental/calc/tree_calc_grammar.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef BOOST_SPIRIT_TREE_CALC_GRAMMAR_HPP_
|
||||
#define BOOST_SPIRIT_TREE_CALC_GRAMMAR_HPP_
|
||||
|
||||
using namespace boost::spirit;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our calculator grammar
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
struct calculator : public grammar<calculator>
|
||||
{
|
||||
static const int integerID = 1;
|
||||
static const int factorID = 2;
|
||||
static const int termID = 3;
|
||||
static const int expressionID = 4;
|
||||
|
||||
template <typename ScannerT>
|
||||
struct definition
|
||||
{
|
||||
definition(calculator const& /*self*/)
|
||||
{
|
||||
// Start grammar definition
|
||||
integer = leaf_node_d[ lexeme_d[
|
||||
(!ch_p('-') >> +digit_p)
|
||||
] ];
|
||||
|
||||
factor = integer
|
||||
| inner_node_d[ch_p('(') >> expression >> ch_p(')')]
|
||||
| (root_node_d[ch_p('-')] >> factor);
|
||||
|
||||
term = factor >>
|
||||
*( (root_node_d[ch_p('*')] >> factor)
|
||||
| (root_node_d[ch_p('/')] >> factor)
|
||||
);
|
||||
|
||||
expression = term >>
|
||||
*( (root_node_d[ch_p('+')] >> term)
|
||||
| (root_node_d[ch_p('-')] >> term)
|
||||
);
|
||||
// End grammar definition
|
||||
|
||||
// turn on the debugging info.
|
||||
BOOST_SPIRIT_DEBUG_RULE(integer);
|
||||
BOOST_SPIRIT_DEBUG_RULE(factor);
|
||||
BOOST_SPIRIT_DEBUG_RULE(term);
|
||||
BOOST_SPIRIT_DEBUG_RULE(expression);
|
||||
}
|
||||
|
||||
rule<ScannerT, parser_context, parser_tag<expressionID> > expression;
|
||||
rule<ScannerT, parser_context, parser_tag<termID> > term;
|
||||
rule<ScannerT, parser_context, parser_tag<factorID> > factor;
|
||||
rule<ScannerT, parser_context, parser_tag<integerID> > integer;
|
||||
|
||||
rule<ScannerT, parser_context, parser_tag<expressionID> > const&
|
||||
start() const { return expression; }
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
266
example/fundamental/calc/vmachine_calc.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The calculator using a simple virtual machine and compiler.
|
||||
//
|
||||
// Ported to v1.5 from the original v1.0 code by JDG
|
||||
// [ JDG 9/18/2002 ]
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The VMachine
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
enum ByteCodes
|
||||
{
|
||||
OP_NEG, // negate the top stack entry
|
||||
OP_ADD, // add top two stack entries
|
||||
OP_SUB, // subtract top two stack entries
|
||||
OP_MUL, // multiply top two stack entries
|
||||
OP_DIV, // divide top two stack entries
|
||||
OP_INT, // push constant integer into the stack
|
||||
OP_RET // return from the interpreter
|
||||
};
|
||||
|
||||
class vmachine
|
||||
{
|
||||
public:
|
||||
vmachine(unsigned stackSize = 1024)
|
||||
: stack(new int[stackSize]),
|
||||
stackPtr(stack) {}
|
||||
~vmachine() { delete [] stack; }
|
||||
int top() const { return stackPtr[-1]; };
|
||||
void execute(int code[]);
|
||||
|
||||
private:
|
||||
|
||||
int* stack;
|
||||
int* stackPtr;
|
||||
};
|
||||
|
||||
void
|
||||
vmachine::execute(int code[])
|
||||
{
|
||||
int const* pc = code;
|
||||
bool running = true;
|
||||
|
||||
while (running)
|
||||
{
|
||||
switch (*pc++)
|
||||
{
|
||||
case OP_NEG:
|
||||
stackPtr[-1] = -stackPtr[-1];
|
||||
break;
|
||||
|
||||
case OP_ADD:
|
||||
stackPtr--;
|
||||
stackPtr[-1] += stackPtr[0];
|
||||
break;
|
||||
|
||||
case OP_SUB:
|
||||
stackPtr--;
|
||||
stackPtr[-1] -= stackPtr[0];
|
||||
break;
|
||||
|
||||
case OP_MUL:
|
||||
stackPtr--;
|
||||
stackPtr[-1] *= stackPtr[0];
|
||||
break;
|
||||
|
||||
case OP_DIV:
|
||||
stackPtr--;
|
||||
stackPtr[-1] /= stackPtr[0];
|
||||
break;
|
||||
|
||||
case OP_INT:
|
||||
// Check stack overflow here!
|
||||
*stackPtr++ = *pc++;
|
||||
break;
|
||||
|
||||
case OP_RET:
|
||||
running = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The Compiler
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
struct push_int
|
||||
{
|
||||
push_int(vector<int>& code_)
|
||||
: code(code_) {}
|
||||
|
||||
void operator()(char const* str, char const* /*end*/) const
|
||||
{
|
||||
using namespace std;
|
||||
int n = strtol(str, 0, 10);
|
||||
code.push_back(OP_INT);
|
||||
code.push_back(n);
|
||||
cout << "push\t" << int(n) << endl;
|
||||
}
|
||||
|
||||
vector<int>& code;
|
||||
};
|
||||
|
||||
struct push_op
|
||||
{
|
||||
push_op(int op_, vector<int>& code_)
|
||||
: op(op_), code(code_) {}
|
||||
|
||||
void operator()(char const*, char const*) const
|
||||
{
|
||||
code.push_back(op);
|
||||
|
||||
switch (op) {
|
||||
|
||||
case OP_NEG:
|
||||
cout << "neg\n";
|
||||
break;
|
||||
|
||||
case OP_ADD:
|
||||
cout << "add\n";
|
||||
break;
|
||||
|
||||
case OP_SUB:
|
||||
cout << "sub\n";
|
||||
break;
|
||||
|
||||
case OP_MUL:
|
||||
cout << "mul\n";
|
||||
break;
|
||||
|
||||
case OP_DIV:
|
||||
cout << "div\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int op;
|
||||
vector<int>& code;
|
||||
};
|
||||
|
||||
template <typename GrammarT>
|
||||
static bool
|
||||
compile(GrammarT const& calc, char const* expr)
|
||||
{
|
||||
cout << "\n/////////////////////////////////////////////////////////\n\n";
|
||||
|
||||
parse_info<char const*>
|
||||
result = parse(expr, calc, space_p);
|
||||
|
||||
if (result.full)
|
||||
{
|
||||
cout << "\t\t" << expr << " Parses OK\n\n\n";
|
||||
calc.code.push_back(OP_RET);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "\t\t" << expr << " Fails parsing\n";
|
||||
cout << "\t\t";
|
||||
for (int i = 0; i < (result.stop - expr); i++)
|
||||
cout << " ";
|
||||
cout << "^--Here\n\n\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our calculator grammar
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
struct calculator : public grammar<calculator>
|
||||
{
|
||||
calculator(vector<int>& code_)
|
||||
: code(code_) {}
|
||||
|
||||
template <typename ScannerT>
|
||||
struct definition
|
||||
{
|
||||
definition(calculator const& self)
|
||||
{
|
||||
integer =
|
||||
lexeme_d[ (+digit_p)[push_int(self.code)] ]
|
||||
;
|
||||
|
||||
factor =
|
||||
integer
|
||||
| '(' >> expression >> ')'
|
||||
| ('-' >> factor)[push_op(OP_NEG, self.code)]
|
||||
| ('+' >> factor)
|
||||
;
|
||||
|
||||
term =
|
||||
factor
|
||||
>> *( ('*' >> factor)[push_op(OP_MUL, self.code)]
|
||||
| ('/' >> factor)[push_op(OP_DIV, self.code)]
|
||||
)
|
||||
;
|
||||
|
||||
expression =
|
||||
term
|
||||
>> *( ('+' >> term)[push_op(OP_ADD, self.code)]
|
||||
| ('-' >> term)[push_op(OP_SUB, self.code)]
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
rule<ScannerT> expression, term, factor, integer;
|
||||
|
||||
rule<ScannerT> const&
|
||||
start() const { return expression; }
|
||||
};
|
||||
|
||||
vector<int>& code;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tA simple virtual machine...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "Type an expression...or [q or Q] to quit\n\n";
|
||||
|
||||
vmachine mach; // Our virtual machine
|
||||
vector<int> code; // Our VM code
|
||||
calculator calc(code); // Our parser
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
code.clear();
|
||||
if (compile(calc, str.c_str()))
|
||||
{
|
||||
mach.execute(&*code.begin());
|
||||
cout << "\n\nresult = " << mach.top() << "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
230
example/fundamental/comments.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This example shows:
|
||||
// 1. Parsing of different comment styles
|
||||
// parsing C/C++-style comment
|
||||
// parsing C++-style comment
|
||||
// parsing PASCAL-style comment
|
||||
// 2. Parsing tagged data with the help of the confix_parser
|
||||
// 3. Parsing tagged data with the help of the confix_parser but the semantic
|
||||
// action is directly attached to the body sequence parser
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/utility/confix.hpp>
|
||||
#include <boost/spirit/utility/chset.hpp>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// used namespaces
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// actor called after successfully matching a single character
|
||||
class actor_string
|
||||
{
|
||||
public:
|
||||
actor_string(std::string &rstr) :
|
||||
matched(rstr)
|
||||
{
|
||||
}
|
||||
|
||||
void operator() (const char *pbegin, const char *pend) const
|
||||
{
|
||||
matched += std::string(pbegin, pend-pbegin);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string &matched;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// actor called after successfully matching a C++-comment
|
||||
void actor_cpp (const char *pfirst, const char *plast)
|
||||
{
|
||||
cout << "Parsing C++-comment" <<endl;
|
||||
cout << "Matched (" << plast-pfirst << ") characters: ";
|
||||
|
||||
char cbbuffer[128];
|
||||
|
||||
strncpy(cbbuffer, pfirst, plast-pfirst);
|
||||
cbbuffer[plast-pfirst] = '\0';
|
||||
|
||||
cout << "\"" << cbbuffer << "\"" << endl;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// main entry point
|
||||
int main ()
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 1. Parsing different comment styles
|
||||
// parsing C/C++-style comments (non-nested!)
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char const* pCComment = "/* This is a /* nested */ C-comment */";
|
||||
|
||||
rule<> cpp_comment;
|
||||
|
||||
cpp_comment =
|
||||
comment_p("/*", "*/") // rule for C-comments
|
||||
| comment_p("//") // rule for C++ comments
|
||||
;
|
||||
|
||||
std::string comment_c;
|
||||
parse_info<> result;
|
||||
|
||||
result = parse (pCComment, cpp_comment[actor_string(comment_c)]);
|
||||
if (result.hit)
|
||||
{
|
||||
cout << "Parsed C-comment successfully!" << endl;
|
||||
cout << "Matched (" << (int)comment_c.size() << ") characters: ";
|
||||
cout << "\"" << comment_c << "\"" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Failed to parse C/C++-comment!" << endl;
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
// parsing C++-style comment
|
||||
char const* pCPPComment = "// This is a C++-comment\n";
|
||||
std::string comment_cpp;
|
||||
|
||||
result = parse (pCPPComment, cpp_comment[&actor_cpp]);
|
||||
if (result.hit)
|
||||
cout << "Parsed C++-comment successfully!" << endl;
|
||||
else
|
||||
cout << "Failed to parse C++-comment!" << endl;
|
||||
|
||||
cout << endl;
|
||||
|
||||
|
||||
// parsing PASCAL-style comment (nested!)
|
||||
char const* pPComment = "{ This is a (* nested *) PASCAL-comment }";
|
||||
|
||||
rule<> pascal_comment;
|
||||
|
||||
pascal_comment = // in PASCAL we have two comment styles
|
||||
comment_nest_p('{', '}') // both may be nested
|
||||
| comment_nest_p("(*", "*)")
|
||||
;
|
||||
|
||||
std::string comment_pascal;
|
||||
|
||||
result = parse (pPComment, pascal_comment[actor_string(comment_pascal)]);
|
||||
if (result.hit)
|
||||
{
|
||||
cout << "Parsed PASCAL-comment successfully!" << endl;
|
||||
cout << "Matched (" << (int)comment_pascal.size() << ") characters: ";
|
||||
cout << "\"" << comment_pascal << "\"" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Failed to parse PASCAL-comment!" << endl;
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 2. Parsing tagged data with the help of the confix parser
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string body;
|
||||
rule<> open_tag, html_tag, close_tag, body_text;
|
||||
|
||||
open_tag =
|
||||
str_p("<b>")
|
||||
;
|
||||
|
||||
body_text =
|
||||
anychar_p
|
||||
;
|
||||
|
||||
close_tag =
|
||||
str_p("</b>")
|
||||
;
|
||||
|
||||
html_tag =
|
||||
confix_p (open_tag, (*body_text)[actor_string(body)], close_tag)
|
||||
;
|
||||
|
||||
char const* pTag = "<b>Body text</b>";
|
||||
|
||||
result = parse (pTag, html_tag);
|
||||
if (result.hit)
|
||||
{
|
||||
cout << "Parsed HTML snippet \"<b>Body text</b>\" successfully "
|
||||
"(with re-attached actor)!" << endl;
|
||||
cout << "Found body (" << (int)body.size() << " characters): ";
|
||||
cout << "\"" << body << "\"" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Failed to parse HTML snippet (with re-attached actor)!"
|
||||
<< endl;
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 3. Parsing tagged data with the help of the confix_parser but the
|
||||
// semantic action is directly attached to the body sequence parser
|
||||
// (see comment in confix.hpp) and out of the usage of the 'direct()'
|
||||
// construction function no automatic refactoring takes place.
|
||||
//
|
||||
// As you can see, for successful parsing it is required to refactor the
|
||||
// confix parser by hand. To see, how it fails, you can try the following:
|
||||
//
|
||||
// html_tag_direct =
|
||||
// confix_p.direct(
|
||||
// str_p("<b>"),
|
||||
// (*body_text)[actor_string(bodydirect)],
|
||||
// str_p("</b>")
|
||||
// )
|
||||
// ;
|
||||
//
|
||||
// Here the *body_text parser eats up all the input up to the end of the
|
||||
// input sequence.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
rule<> html_tag_direct;
|
||||
std::string bodydirect;
|
||||
|
||||
html_tag_direct =
|
||||
confix_p.direct(
|
||||
str_p("<b>"),
|
||||
(*(body_text - str_p("</b>")))[actor_string(bodydirect)],
|
||||
str_p("</b>")
|
||||
)
|
||||
;
|
||||
|
||||
char const* pTagDirect = "<b>Body text</b>";
|
||||
|
||||
result = parse (pTagDirect, html_tag_direct);
|
||||
if (result.hit)
|
||||
{
|
||||
cout << "Parsed HTML snippet \"<b>Body text</b>\" successfully "
|
||||
"(with direct actor)!" << endl;
|
||||
cout << "Found body (" << (int)bodydirect.size() << " characters): ";
|
||||
cout << "\"" << bodydirect << "\"" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Failed to parse HTML snippet (with direct actor)!" << endl;
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
95
example/fundamental/complex_number.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// A complex number micro parser (using subrules)
|
||||
//
|
||||
// [ JDG 5/10/2002 ]
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <iostream>
|
||||
#include <complex>
|
||||
#include <string>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our complex number micro parser
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
parse_complex(char const* str, complex<double>& c)
|
||||
{
|
||||
double rN = 0.0;
|
||||
double iN = 0.0;
|
||||
|
||||
subrule<0> first;
|
||||
subrule<1> r;
|
||||
subrule<2> i;
|
||||
|
||||
if (parse(str,
|
||||
|
||||
// Begin grammar
|
||||
(
|
||||
first = '(' >> r >> !(',' >> i) >> ')' | r,
|
||||
r = real_p[assign(rN)],
|
||||
i = real_p[assign(iN)]
|
||||
)
|
||||
,
|
||||
// End grammar
|
||||
|
||||
space_p).full)
|
||||
{
|
||||
c = complex<double>(rN, iN);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tA complex number micro parser for Spirit...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
|
||||
cout << "Give me a complex number of the form r or (r) or (r,i) \n";
|
||||
cout << "Type [q or Q] to quit\n\n";
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
complex<double> c;
|
||||
if (parse_complex(str.c_str(), c))
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << str << " Parses OK: " << c << endl;
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
170
example/fundamental/dynamic_parser.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// A parser based on dynamic parser statements that parses a decimal integer
|
||||
//
|
||||
// [ JCAB 7/26/2002 ]
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/spirit/utility/dynamic_parser.hpp>
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/utility/functor_parser.hpp>
|
||||
//#include <boost/lambda/lambda.hpp>
|
||||
//#include <boost/phoenix/primitives.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace local
|
||||
{
|
||||
template <typename T>
|
||||
struct var_wrapper
|
||||
: public boost::reference_wrapper<T>
|
||||
{
|
||||
explicit inline var_wrapper(T& t)
|
||||
: boost::reference_wrapper<T>(t)
|
||||
{}
|
||||
|
||||
inline T& operator()() const { return get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline var_wrapper<T>
|
||||
var(T& t)
|
||||
{
|
||||
return var_wrapper<T>(t);
|
||||
}
|
||||
} // namespace local
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our parser functor
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
struct number_parser {
|
||||
typedef int result_t;
|
||||
template <typename ScannerT>
|
||||
int
|
||||
operator()(ScannerT const& scan, result_t& result) const {
|
||||
if (scan.at_end()) {
|
||||
return -1;
|
||||
}
|
||||
char ch = *scan;
|
||||
if (ch < '0' || ch > '9') {
|
||||
return -1;
|
||||
}
|
||||
result = 0;
|
||||
int len = 0;
|
||||
do {
|
||||
result = result*10 + int(ch - '0');
|
||||
++len;
|
||||
++scan;
|
||||
} while (!scan.at_end() && (ch = *scan, ch >= '0' && ch <= '9'));
|
||||
return len;
|
||||
}
|
||||
};
|
||||
|
||||
functor_parser<number_parser> number_parser_p;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our number parser function
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
parse_numbers(char const* str, std::vector<int>& n, bool many)
|
||||
{
|
||||
return parse(str,
|
||||
lexeme_d[number_parser_p[append(n)]] >>
|
||||
|
||||
/////////////////////////
|
||||
// functors as condition
|
||||
if_p(local::var(many)) [
|
||||
//if_p (phoenix::var(many)) [
|
||||
//if_p (boost::lambda::var(many)) [
|
||||
|
||||
/////////////////////////
|
||||
// parser as condition
|
||||
//if_p (boost::spirit::ch_p(',')) [
|
||||
|
||||
*(',' >> lexeme_d[number_parser_p[append(n)]])
|
||||
] .else_p [
|
||||
epsilon_p
|
||||
],
|
||||
space_p
|
||||
).full;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tA number parser implemented as a functor for Spirit...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
|
||||
cout << "Give me an integer number command\n";
|
||||
cout << "Commands:\n";
|
||||
cout << " A <num> --> parses a single number\n";
|
||||
cout << " B <num>, <num>, ... --> parses a series of numbers "
|
||||
"separated by commas\n";
|
||||
cout << " Q --> quit\n\n";
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q') {
|
||||
break;
|
||||
} else if (str[0] == 'a' || str[0] == 'A') {
|
||||
std::vector<int> n;
|
||||
if (parse_numbers(str.c_str()+1, n, false))
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << str << " Parses OK: " << n[0] << endl;
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
} else if (str[0] == 'b' || str[0] == 'B') {
|
||||
std::vector<int> n;
|
||||
if (parse_numbers(str.c_str()+1, n, true))
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
int size = n.size();
|
||||
cout << str << " Parses OK: " << size
|
||||
<< " number(s): " << n[0];
|
||||
for (int i = 1; i < size; ++i) {
|
||||
cout << ", " << n[i];
|
||||
}
|
||||
cout << endl;
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
} else {
|
||||
cout << "-------------------------\n";
|
||||
cout << "Unrecognized command!!";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
94
example/fundamental/file_parser.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// A parser that echoes a file
|
||||
//
|
||||
// [ JMW 8/05/2002 ]
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/iterator/file_iterator.hpp>
|
||||
#include <iostream>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using namespace boost::spirit;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Types
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef char CharT;
|
||||
typedef file_iterator <CharT> IteratorT;
|
||||
typedef scanner <IteratorT> ScannerT;
|
||||
typedef rule <ScannerT> RuleT;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Actions
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Echo (IteratorT const & rBegin, IteratorT const & rEnd)
|
||||
{
|
||||
while (rBegin < rEnd)
|
||||
{
|
||||
std::cout << *rBegin++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int main (int argc, char * argv [])
|
||||
{
|
||||
if (2 > argc)
|
||||
{
|
||||
std::cout << "Must specify a filename!\n";
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create a file iterator for this file
|
||||
IteratorT _Start (argv [1]);
|
||||
|
||||
if (!_Start)
|
||||
{
|
||||
std::cout << "Unable to open file!\n";
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create an EOF iterator
|
||||
IteratorT _End = _Start.make_end ();
|
||||
|
||||
// A simple rule
|
||||
RuleT _Rule = *(anychar_p);
|
||||
|
||||
// Parse
|
||||
parse_info <IteratorT> _Info = parse (
|
||||
_Start,
|
||||
_End,
|
||||
_Rule [&Echo]
|
||||
);
|
||||
|
||||
// This really shouldn't fail...
|
||||
if (_Info.full)
|
||||
{
|
||||
std::cout << "Parse succeeded!\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Parse failed!\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
152
example/fundamental/functor_parser.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// An functor parser that parses a decimal integer
|
||||
//
|
||||
// [ JCAB 7/20/2002 ]
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/utility/functor_parser.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our parser functor
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
struct number_parser
|
||||
{
|
||||
typedef int result_t;
|
||||
template <typename ScannerT>
|
||||
int
|
||||
operator()(ScannerT const& scan, result_t& result) const
|
||||
{
|
||||
if (scan.at_end())
|
||||
return -1;
|
||||
|
||||
char ch = *scan;
|
||||
if (ch < '0' || ch > '9')
|
||||
return -1;
|
||||
|
||||
result = 0;
|
||||
int len = 0;
|
||||
|
||||
do
|
||||
{
|
||||
result = result*10 + int(ch - '0');
|
||||
++len;
|
||||
++scan;
|
||||
} while (!scan.at_end() && (ch = *scan, ch >= '0' && ch <= '9'));
|
||||
|
||||
return len;
|
||||
}
|
||||
};
|
||||
|
||||
functor_parser<number_parser> number_parser_p;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our number parser functions
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
parse_number(char const* str, int& n)
|
||||
{
|
||||
return parse(str, lexeme_d[number_parser_p[assign(n)]], space_p).full;
|
||||
}
|
||||
|
||||
bool
|
||||
parse_numbers(char const* str, std::vector<int>& n)
|
||||
{
|
||||
return
|
||||
parse(
|
||||
str,
|
||||
lexeme_d[number_parser_p[append(n)]]
|
||||
>> *(',' >> lexeme_d[number_parser_p[append(n)]]),
|
||||
space_p
|
||||
).full;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tA number parser implemented as a functor for Spirit...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
|
||||
cout << "Give me an integer number command\n";
|
||||
cout << "Commands:\n";
|
||||
cout << " A <num> --> parses a single number\n";
|
||||
cout << " B <num>, <num>, ... --> parses a series of numbers ";
|
||||
cout << "separated by commas\n";
|
||||
cout << " Q --> quit\n\n";
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
else if (str[0] == 'a' || str[0] == 'A')
|
||||
{
|
||||
int n;
|
||||
if (parse_number(str.c_str()+1, n))
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << str << " Parses OK: " << n << endl;
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
else if (str[0] == 'b' || str[0] == 'B')
|
||||
{
|
||||
std::vector<int> n;
|
||||
if (parse_numbers(str.c_str()+1, n))
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
int size = n.size();
|
||||
cout << str << " Parses OK: " << size << " number(s): " << n[0];
|
||||
for (int i = 1; i < size; ++i) {
|
||||
cout << ", " << n[i];
|
||||
}
|
||||
cout << endl;
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Unrecognized command!!";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
228
example/fundamental/list_parser.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// This sample shows the usage of the list_p utility parser
|
||||
// 1. parsing a simple ',' delimited list w/o item formatting
|
||||
// 2. parsing a CSV list (comma separated values - strings, integers or reals)
|
||||
// 3. parsing a token list (token separated values - strings, integers or
|
||||
// reals)
|
||||
// with an action parser directly attached to the item part of the list_p
|
||||
// generated parser
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/utility/confix.hpp>
|
||||
#include <boost/spirit/utility/lists.hpp>
|
||||
#include <boost/spirit/utility/escape_char.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// actor, attached to the list_p parser
|
||||
class list_actor
|
||||
{
|
||||
public:
|
||||
list_actor (std::vector<std::string> &vec_) : vec(vec_) {}
|
||||
|
||||
// The following operator() is called by the action parser generated by
|
||||
// attaching this actor to a list_p generated list parser.
|
||||
|
||||
template <typename ActionIterT>
|
||||
void operator() (ActionIterT const &first, ActionIterT const &last) const
|
||||
{
|
||||
vec.push_back(std::string(first, last-first));
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> &vec;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// main entry point
|
||||
int main ()
|
||||
{
|
||||
// 1. parsing a simple ',' delimited list w/o item formatting
|
||||
char const* plist_wo_item = "element1,element2,element3";
|
||||
rule<> list_wo_item;
|
||||
std::vector<std::string> vec_list;
|
||||
|
||||
list_wo_item =
|
||||
list_p[append(vec_list)]
|
||||
;
|
||||
|
||||
parse_info<> result = parse (plist_wo_item, list_wo_item);
|
||||
|
||||
cout << "-----------------------------------------------------------------"
|
||||
<< endl;
|
||||
|
||||
if (result.hit)
|
||||
{
|
||||
cout
|
||||
<< "Parsing simple list" << endl
|
||||
<< "\t" << plist_wo_item << endl
|
||||
<< "Parsed successfully!" << endl << endl;
|
||||
|
||||
cout
|
||||
<< "Actor was called " << (int)vec_list.size()
|
||||
<< " times: " << endl;
|
||||
|
||||
cout
|
||||
<< "Results got from the list parser:" << endl;
|
||||
for (std::vector<std::string>::iterator it = vec_list.begin();
|
||||
it != vec_list.end(); ++it)
|
||||
{
|
||||
cout << *it << endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Failed to parse simple list!" << endl;
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
|
||||
// 2. parsing a CSV list (comma separated values - strings, integers or
|
||||
// reals)
|
||||
char const *plist_csv = "\"string\",\"string with an embedded \\\"\","
|
||||
"12345,0.12345e4";
|
||||
rule<> list_csv, list_csv_item;
|
||||
std::vector<std::string> vec_item;
|
||||
|
||||
vec_list.clear();
|
||||
|
||||
list_csv_item =
|
||||
confix_p('\"', *c_escape_ch_p, '\"')
|
||||
| longest_d[real_p | int_p]
|
||||
;
|
||||
|
||||
list_csv =
|
||||
list_p(
|
||||
list_csv_item[append(vec_item)],
|
||||
','
|
||||
)[append(vec_list)]
|
||||
;
|
||||
|
||||
result = parse (plist_csv, list_csv);
|
||||
|
||||
cout << "-----------------------------------------------------------------"
|
||||
<< endl;
|
||||
if (result.hit)
|
||||
{
|
||||
cout
|
||||
<< "Parsing CSV list (comma separated values) " << endl
|
||||
<< "\t" << plist_csv << endl
|
||||
<< "Parsed successfully!" << endl << endl;
|
||||
|
||||
if (result.full)
|
||||
{
|
||||
cout << "Matched " << (int)vec_list.size() <<
|
||||
" list elements (full list): " << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Matched " << (int)vec_list.size() <<
|
||||
" list elements: " << endl;
|
||||
}
|
||||
|
||||
cout << "The list parser matched:" << endl;
|
||||
for (std::vector<std::string>::iterator itl = vec_list.begin();
|
||||
itl != vec_list.end(); ++itl)
|
||||
{
|
||||
cout << *itl << endl;
|
||||
}
|
||||
|
||||
cout << endl << "Item(s) got directly from the item parser:" << endl;
|
||||
for (std::vector<std::string>::iterator it = vec_item.begin();
|
||||
it != vec_item.end(); ++it)
|
||||
{
|
||||
cout << *it << endl;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Failed to parse CSV list!" << endl;
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
|
||||
// 3. parsing a token list (token separated values - strings, integers or
|
||||
// reals) with an action parser directly attached to the item part of the
|
||||
// list_p generated parser
|
||||
char const *plist_csv_direct = "\"string\"<par>\"string with an embedded "
|
||||
"\\\"\"<par>12345<par>0.12345e4";
|
||||
rule<> list_csv_direct, list_csv_direct_item;
|
||||
|
||||
vec_list.clear();
|
||||
vec_item.clear();
|
||||
|
||||
// Note: the list parser is here generated through the list_p.direct()
|
||||
// generator function. This inhibits re-attachment of the item_actor_direct
|
||||
// during parser construction (see: comment in utility/lists.hpp)
|
||||
list_csv_direct_item =
|
||||
confix_p('\"', *c_escape_ch_p, '\"')
|
||||
| longest_d[real_p | int_p]
|
||||
;
|
||||
|
||||
list_csv_direct =
|
||||
list_p.direct(
|
||||
(*list_csv_direct_item)[list_actor(vec_item)],
|
||||
"<par>"
|
||||
)[list_actor(vec_list)]
|
||||
;
|
||||
|
||||
result = parse (plist_csv_direct, list_csv_direct);
|
||||
|
||||
cout << "-----------------------------------------------------------------"
|
||||
<< endl;
|
||||
if (result.hit)
|
||||
{
|
||||
cout
|
||||
<< "Parsing CSV list (comma separated values)" << endl
|
||||
<< "The list parser was generated with 'list_p.direct()'" << endl
|
||||
<< "\t" << plist_csv_direct << endl
|
||||
<< "Parsed successfully!" << endl << endl;
|
||||
|
||||
if (result.full)
|
||||
{
|
||||
cout << "Matched " << vec_list.size() <<
|
||||
" list elements (full list): " << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Matched " << vec_list.size() <<
|
||||
" list elements: " << endl;
|
||||
}
|
||||
|
||||
cout << "The list parser matched:" << endl;
|
||||
for (std::vector<std::string>::iterator itl = vec_list.begin();
|
||||
itl != vec_list.end(); ++itl)
|
||||
{
|
||||
cout << *itl << endl;
|
||||
}
|
||||
|
||||
cout << endl << "Items got directly from the item parser:" << endl;
|
||||
for (std::vector<std::string>::iterator it = vec_item.begin();
|
||||
it != vec_item.end(); ++it)
|
||||
{
|
||||
cout << *it << endl;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Failed to parse CSV list!" << endl;
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
106
example/fundamental/matching_tags.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// HTML/XML like tag matching grammar
|
||||
// { demonstrates phoenix and closures and parametric parsers ]
|
||||
//
|
||||
// [ JDG 6/30/2002 ]
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
#include "boost/spirit/core.hpp"
|
||||
#include "boost/spirit/attribute.hpp"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
using namespace phoenix;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// HTML/XML like tag matching grammar
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
struct tags_closure : boost::spirit::closure<tags_closure, string> {
|
||||
|
||||
member1 tag;
|
||||
};
|
||||
|
||||
struct tags : public grammar<tags> {
|
||||
|
||||
template <typename ScannerT>
|
||||
struct definition {
|
||||
|
||||
definition(tags const& /*self*/)
|
||||
{
|
||||
element = start_tag >> *element >> end_tag;
|
||||
|
||||
start_tag =
|
||||
'<'
|
||||
>> lexeme_d
|
||||
[
|
||||
(+alpha_p)
|
||||
[
|
||||
// construct string from arg1 and arg2 lazily
|
||||
// and assign to element.tag
|
||||
|
||||
element.tag = construct_<string>(arg1, arg2)
|
||||
]
|
||||
]
|
||||
>> '>';
|
||||
|
||||
end_tag = "</" >> fstr_p(element.tag) >> '>';
|
||||
}
|
||||
|
||||
rule<ScannerT, tags_closure::context_t> element;
|
||||
rule<ScannerT> start_tag, end_tag;
|
||||
|
||||
rule<ScannerT, tags_closure::context_t> const&
|
||||
start() const { return element; }
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tHTML/XML like tag matching parser demo \n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "Type an HTML/XML like nested tag input...or [q or Q] to quit\n\n";
|
||||
cout << "Example: <html><head></head><body></body></html>\n\n";
|
||||
|
||||
tags p; // Our parser
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
parse_info<> info = parse(str.c_str(), p, space_p);
|
||||
|
||||
if (info.full)
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "stopped at: \": " << info.stop << "\"\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
83
example/fundamental/number_list.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// A parser for a comma separated list of numbers
|
||||
//
|
||||
// [ JDG 5/10/2002 ]
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our comma separated list parser
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
parse_numbers(char const* str, vector<double>& v)
|
||||
{
|
||||
return parse(str,
|
||||
|
||||
// Begin grammar
|
||||
(
|
||||
real_p[append(v)] >> *(',' >> real_p[append(v)])
|
||||
)
|
||||
,
|
||||
// End grammar
|
||||
|
||||
space_p).full;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tA comma separated list parser for Spirit...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
|
||||
cout << "Give me a comma separated list of numbers.\n";
|
||||
cout << "The numbers will be inserted in a vector of numbers\n";
|
||||
cout << "Type [q or Q] to quit\n\n";
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
vector<double> v;
|
||||
if (parse_numbers(str.c_str(), v))
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << str << " Parses OK: " << endl;
|
||||
|
||||
for (vector<double>::size_type i = 0; i < v.size(); ++i)
|
||||
cout << i << ": " << v[i] << endl;
|
||||
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
208
example/fundamental/parameters.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// This sample show the usage of parser parameters.
|
||||
//
|
||||
// Parser parameters are used to pass some values from the outer parsing scope
|
||||
// to the next inner scope. They can be imagined as the opposite to the return
|
||||
// value paradigm, which returns some value from the inner to the next outer
|
||||
// scope.
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
#if defined(_MSC_VER) /*&& !defined(__COMO__)*/
|
||||
#pragma warning(disable: 4244)
|
||||
#pragma warning(disable: 4355)
|
||||
#endif // defined(_MSC_VER) && !defined(__COMO__)
|
||||
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/symbols/symbols.hpp>
|
||||
|
||||
#include <boost/phoenix/tuples.hpp>
|
||||
#include <boost/phoenix/tuple_helpers.hpp>
|
||||
#include <boost/phoenix/primitives.hpp>
|
||||
#include <boost/spirit/attribute/closure.hpp>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// used namespaces
|
||||
using namespace boost::spirit;
|
||||
using namespace phoenix;
|
||||
using namespace std;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Helper class for encapsulation of the type for the parsed variable names
|
||||
class declaration_type
|
||||
{
|
||||
public:
|
||||
enum vartype {
|
||||
vartype_unknown = 0, // unknown variable type
|
||||
vartype_int = 1, // 'int'
|
||||
vartype_real = 2 // 'real'
|
||||
};
|
||||
|
||||
declaration_type() : type(vartype_unknown)
|
||||
{
|
||||
}
|
||||
template <typename ItT>
|
||||
declaration_type(ItT const &first, ItT const &last)
|
||||
{
|
||||
init(string(first, last-first-1));
|
||||
}
|
||||
declaration_type(declaration_type const &type_) : type(type_.type)
|
||||
{
|
||||
}
|
||||
declaration_type(string const &type_) : type(vartype_unknown)
|
||||
{
|
||||
init(type_);
|
||||
}
|
||||
|
||||
// access to the variable type
|
||||
operator vartype const &() const { return type; }
|
||||
operator string ()
|
||||
{
|
||||
switch(type) {
|
||||
default:
|
||||
case vartype_unknown: break;
|
||||
case vartype_int: return string("int");
|
||||
case vartype_real: return string("real");
|
||||
}
|
||||
return string ("unknown");
|
||||
}
|
||||
|
||||
void swap(declaration_type &s) { std::swap(type, s.type); }
|
||||
|
||||
protected:
|
||||
void init (string const &type_)
|
||||
{
|
||||
if (type_ == "int")
|
||||
type = vartype_int;
|
||||
else if (type_ == "real")
|
||||
type = vartype_real;
|
||||
else
|
||||
type = vartype_unknown;
|
||||
}
|
||||
|
||||
private:
|
||||
vartype type;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// used closure type
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
struct var_decl_closure : boost::spirit::closure<var_decl_closure, declaration_type>
|
||||
{
|
||||
member1 val;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// symbols_with_data
|
||||
//
|
||||
// Helper class for inserting an item with data into a symbol table
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T, typename InitT>
|
||||
class symbols_with_data
|
||||
{
|
||||
public:
|
||||
typedef
|
||||
symbol_inserter<T, boost::spirit::impl::tst<T, char> >
|
||||
symbol_inserter_t;
|
||||
|
||||
symbols_with_data(symbol_inserter_t const &add_, InitT const &data_) :
|
||||
add(add_), data(as_actor<InitT>::convert(data_))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename IteratorT>
|
||||
symbol_inserter_t const &
|
||||
operator()(IteratorT const &first_, IteratorT const &last) const
|
||||
{
|
||||
IteratorT first = first_;
|
||||
return add(first, last, data());
|
||||
}
|
||||
|
||||
private:
|
||||
symbol_inserter_t const &add;
|
||||
typename as_actor<InitT>::type data;
|
||||
};
|
||||
|
||||
template <typename T, typename CharT, typename InitT>
|
||||
inline
|
||||
symbols_with_data<T, InitT>
|
||||
symbols_gen(symbol_inserter<T, boost::spirit::impl::tst<T, CharT> > const &add_,
|
||||
InitT const &data_)
|
||||
{
|
||||
return symbols_with_data<T, InitT>(add_, data_);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The var_decl_list grammar parses variable declaration list
|
||||
|
||||
struct var_decl_list :
|
||||
public grammar<var_decl_list, var_decl_closure::context_t>
|
||||
{
|
||||
template <typename ScannerT>
|
||||
struct definition
|
||||
{
|
||||
definition(var_decl_list const &self)
|
||||
{
|
||||
// pass variable type returned from 'type' to list closure member 0
|
||||
decl = type[self.val = arg1] >> +space_p >> list(self.val);
|
||||
|
||||
// m0 to access arg 0 of list --> passing variable type down to ident
|
||||
list = ident(list.val) >> *(',' >> ident(list.val));
|
||||
|
||||
// store identifier and type into the symbol table
|
||||
ident = (*alnum_p)[symbols_gen(symtab.add, ident.val)];
|
||||
|
||||
// the type of the decl is returned in type's closure member 0
|
||||
type =
|
||||
str_p("int")[type.val = construct_<string>(arg1, arg2)]
|
||||
| str_p("real")[type.val = construct_<string>(arg1, arg2)]
|
||||
;
|
||||
|
||||
BOOST_SPIRIT_DEBUG_RULE(decl);
|
||||
BOOST_SPIRIT_DEBUG_RULE(list);
|
||||
BOOST_SPIRIT_DEBUG_RULE(ident);
|
||||
BOOST_SPIRIT_DEBUG_RULE(type);
|
||||
}
|
||||
|
||||
rule<ScannerT> const&
|
||||
start() const { return decl; }
|
||||
|
||||
private:
|
||||
typedef rule<ScannerT, var_decl_closure::context_t> rule_t;
|
||||
rule_t type;
|
||||
rule_t list;
|
||||
rule_t ident;
|
||||
symbols<declaration_type> symtab;
|
||||
|
||||
rule<ScannerT> decl; // start rule
|
||||
};
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// main entry point
|
||||
int main()
|
||||
{
|
||||
var_decl_list decl;
|
||||
declaration_type type;
|
||||
char const *pbegin = "int var1";
|
||||
|
||||
if (parse (pbegin, decl[assign(type)]).full) {
|
||||
cout << endl
|
||||
<< "Parsed variable declarations successfully!" << endl
|
||||
<< "Detected type: " << declaration_type::vartype(type)
|
||||
<< " (" << string(type) << ")"
|
||||
<< endl;
|
||||
} else {
|
||||
cout << endl
|
||||
<< "Parsing the input stream failed!"
|
||||
<< endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
180
example/fundamental/polynomial.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
//
|
||||
// A very simple parser grammar .
|
||||
// This parser parses a simple polynomial expression ( of the form
|
||||
// aX^2 + bX^3 + ... ) .
|
||||
//
|
||||
// Written by: Andy Elvey
|
||||
// Slightly modified by Dan Nuffer
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the copyright holder be held liable for
|
||||
// any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute
|
||||
// it freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must
|
||||
// not claim that you wrote the original software. If you use this
|
||||
// software in a product, an acknowledgment in the product documentation
|
||||
// would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must
|
||||
// not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
// Uses: The Spirit parser framework, which was written by
|
||||
// Joel de Guzman isis-tech.n3.net
|
||||
//
|
||||
|
||||
//#define BOOST_SPIRIT_DEBUG ///$$$ DEFINE THIS WHEN DEBUGGING $$$///
|
||||
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
using namespace boost::spirit;
|
||||
using namespace std;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//----------------------------------------------------------------------------
|
||||
// Start grammar definition
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
struct polynomial_grammar :
|
||||
public grammar<polynomial_grammar>
|
||||
{
|
||||
template <typename ScannerT>
|
||||
struct definition
|
||||
{
|
||||
typedef rule<ScannerT> rule_t;
|
||||
|
||||
rule_t program, stmts, term, constant, sign, var, caret;
|
||||
rule_t IDENT, STRING_LITERAL, VAR;
|
||||
|
||||
definition(polynomial_grammar const&)
|
||||
{
|
||||
//-----------------------------------------------------------------
|
||||
// OPERATORS
|
||||
//-----------------------------------------------------------------
|
||||
chlit<> PLUS('+');
|
||||
chlit<> MINUS('-');
|
||||
chlit<> CARET('^');
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// TOKENS
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
|
||||
IDENT =
|
||||
nocase_d
|
||||
[
|
||||
lexeme_d
|
||||
[
|
||||
(alpha_p >> *(alnum_p | '_'))
|
||||
]
|
||||
]
|
||||
;
|
||||
|
||||
STRING_LITERAL =
|
||||
lexeme_d
|
||||
[
|
||||
ch_p('\'')
|
||||
>> +(
|
||||
str_p("\'\'")
|
||||
| anychar_p - ch_p('\'')
|
||||
)
|
||||
>> ch_p('\'')
|
||||
]
|
||||
;
|
||||
|
||||
VAR = nocase_d[ lexeme_d[ alpha_p ] ] ;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// RULES
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
// Now - the actual BNF grammar for the parser
|
||||
|
||||
program =
|
||||
+(stmts)
|
||||
;
|
||||
|
||||
stmts =
|
||||
( term | constant )
|
||||
;
|
||||
|
||||
term =
|
||||
+(
|
||||
!(sign)
|
||||
>> !(uint_p)
|
||||
>> VAR
|
||||
>> !(CARET)
|
||||
>> !(uint_p)
|
||||
)
|
||||
; // e.g. 3x^2
|
||||
|
||||
constant =
|
||||
!(sign) >> +(uint_p)
|
||||
;
|
||||
|
||||
sign =
|
||||
( PLUS | MINUS )
|
||||
;
|
||||
|
||||
var =
|
||||
VAR
|
||||
;
|
||||
|
||||
caret =
|
||||
CARET
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
rule_t const& start() const
|
||||
{
|
||||
return program;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
main(int /*argc*/, char* /*argv[]*/)
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\t A polynomial parser...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "Type a polynomial (e.g. 3a^4 + 7a^5 - 8a^3 - 4a - 5) or\n"
|
||||
<< "[q or Q] to quit\n\n";
|
||||
|
||||
|
||||
polynomial_grammar g;
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
if (parse(str.c_str(), g, space_p).full)
|
||||
{
|
||||
cout << "parsing succeeded\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "parsing failed\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
16
example/fundamental/position_iterator/Makefile.am
Normal file
@@ -0,0 +1,16 @@
|
||||
EXTRA_PROGRAMS = position_iterator
|
||||
|
||||
all: $(EXTRA_PROGRAMS)
|
||||
|
||||
position_iterator_SOURCES = position_iterator.cpp
|
||||
|
||||
EXTRA_DIST = \
|
||||
position_iterator.err1 \
|
||||
position_iterator.err2 \
|
||||
position_iterator.err3 \
|
||||
position_iterator.ok
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
CLEANFILES = $(EXTRA_PROGRAMS)
|
||||
|
||||
164
example/fundamental/position_iterator/position_iterator.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// A parser for a comma separated list of numbers,
|
||||
// with positional error reporting
|
||||
//
|
||||
// [ JCAB 9/28/2002 ]
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/iterator/position_iterator.hpp>
|
||||
#include <boost/spirit/utility/functor_parser.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our error reporting parsers
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
std::ostream& operator<<(std::ostream& out, file_position const& lc)
|
||||
{
|
||||
return out <<
|
||||
"\nFile:\t" << lc.file <<
|
||||
"\nLine:\t" << lc.line <<
|
||||
"\nCol:\t" << lc.column << endl;
|
||||
}
|
||||
|
||||
struct error_report_parser {
|
||||
char const* eol_msg;
|
||||
char const* msg;
|
||||
|
||||
error_report_parser(char const* eol_msg_, char const* msg_):
|
||||
eol_msg(eol_msg_),
|
||||
msg (msg_)
|
||||
{}
|
||||
|
||||
typedef nil_t result_t;
|
||||
|
||||
template <typename ScannerT>
|
||||
int
|
||||
operator()(ScannerT const& scan, result_t& /*result*/) const
|
||||
{
|
||||
if (scan.at_end()) {
|
||||
if (eol_msg) {
|
||||
file_position fpos = scan.first.get_position();
|
||||
cerr << fpos << eol_msg << endl;
|
||||
}
|
||||
} else {
|
||||
if (msg) {
|
||||
file_position fpos = scan.first.get_position();
|
||||
cerr << fpos << msg << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return -1; // Fail.
|
||||
}
|
||||
|
||||
};
|
||||
typedef functor_parser<error_report_parser> error_report_p;
|
||||
|
||||
error_report_p
|
||||
error_badnumber_or_eol =
|
||||
error_report_parser(
|
||||
"Expecting a number, but found the end of the file\n",
|
||||
"Expecting a number, but found something else\n"
|
||||
);
|
||||
|
||||
error_report_p
|
||||
error_badnumber =
|
||||
error_report_parser(
|
||||
0,
|
||||
"Expecting a number, but found something else\n"
|
||||
);
|
||||
|
||||
error_report_p
|
||||
error_comma =
|
||||
error_report_parser(
|
||||
0,
|
||||
"Expecting a comma, but found something else\n"
|
||||
);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our comma separated list parser
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
parse_numbers(char const* filename, char const* str, vector<double>& v)
|
||||
{
|
||||
typedef position_iterator<char const*> iterator_t;
|
||||
iterator_t begin(str, str + strlen(str), filename);
|
||||
iterator_t end;
|
||||
begin.set_tabchars(8);
|
||||
return parse(begin, end,
|
||||
|
||||
// Begin grammar
|
||||
(
|
||||
(real_p[append(v)] | error_badnumber)
|
||||
>> *(
|
||||
(',' | error_comma)
|
||||
>> (real_p[append(v)] | error_badnumber_or_eol)
|
||||
)
|
||||
)
|
||||
,
|
||||
// End grammar
|
||||
|
||||
space_p).full;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\tAn error-reporting parser for Spirit...\n\n";
|
||||
cout << "Parses a comma separated list of numbers from a file.\n";
|
||||
cout << "The numbers will be inserted in a vector of numbers\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
|
||||
char str[65536];
|
||||
char const* filename;
|
||||
|
||||
if (argc > 1) {
|
||||
filename = argv[1];
|
||||
ifstream file(filename);
|
||||
file.get(str, sizeof(str), '\0');
|
||||
} else {
|
||||
filename = "<cin>";
|
||||
cin.get(str, sizeof(str), '\0');
|
||||
}
|
||||
|
||||
vector<double> v;
|
||||
if (parse_numbers(filename, str, v))
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << str << " Parses OK: " << endl;
|
||||
|
||||
for (vector<double>::size_type i = 0; i < v.size(); ++i)
|
||||
cout << i << ": " << v[i] << endl;
|
||||
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
0, 1,2 , 3 a,4
|
||||
,5,
|
||||
6
|
||||
,
|
||||
7
|
||||
|
||||
|
||||
,08
|
||||
@@ -0,0 +1,8 @@
|
||||
0, 1,2 , 3 ,4
|
||||
,5,
|
||||
6
|
||||
,
|
||||
7
|
||||
|
||||
|
||||
,
|
||||
@@ -0,0 +1,8 @@
|
||||
0, 1,2 , a3 ,4
|
||||
,5,
|
||||
6
|
||||
,
|
||||
7
|
||||
|
||||
|
||||
,08
|
||||
@@ -0,0 +1,8 @@
|
||||
0, 1,2 , 3 ,4
|
||||
,5,
|
||||
6
|
||||
,
|
||||
7
|
||||
|
||||
|
||||
,08
|
||||
205
example/fundamental/refactoring.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// This example shows the usage of the refactoring parser family parsers
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "boost/spirit/core.hpp"
|
||||
#include "boost/spirit/utility/refactoring.hpp"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// used namespaces
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// actor, used by the refactor_action_p test
|
||||
struct refactor_action_actor
|
||||
{
|
||||
refactor_action_actor (std::string &str_) : str(str_) {}
|
||||
|
||||
template <typename IteratorT>
|
||||
void operator() (IteratorT const &first, IteratorT const &last) const
|
||||
{
|
||||
str = std::string(first, last-first);
|
||||
}
|
||||
|
||||
std::string &str;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// main entry point
|
||||
int main()
|
||||
{
|
||||
parse_info<> result;
|
||||
char const *test_string = "Some string followed by a newline\n";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 1. Testing the refactor_unary_d parser
|
||||
//
|
||||
// The following test should successfully parse the test string, because the
|
||||
//
|
||||
// refactor_unary_d[
|
||||
// *anychar_p - '\n'
|
||||
// ]
|
||||
//
|
||||
// is refactored into
|
||||
//
|
||||
// *(anychar_p - '\n').
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
result = parse(test_string, refactor_unary_d[*anychar_p - '\n'] >> '\n');
|
||||
|
||||
if (result.full)
|
||||
{
|
||||
cout << "Successfully refactored an unary!" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Failed to refactor an unary!" << endl;
|
||||
}
|
||||
|
||||
// Parsing the same test string without refactoring fails, because the
|
||||
// *anychar_p eats up all the input up to the end of the input string.
|
||||
|
||||
result = parse(test_string, (*anychar_p - '\n') >> '\n');
|
||||
|
||||
if (result.full)
|
||||
{
|
||||
cout
|
||||
<< "Successfully parsed test string (should not happen)!"
|
||||
<< endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout
|
||||
<< "Correctly failed parsing the test string (without refactoring)!"
|
||||
<< endl;
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 2. Testing the refactor_action_d parser
|
||||
//
|
||||
// The following test should successfully parse the test string, because the
|
||||
//
|
||||
// refactor_action_d[
|
||||
// (*(anychar_p - '$'))[refactor_action_actor(str)] >> '$'
|
||||
// ]
|
||||
//
|
||||
// is refactored into
|
||||
//
|
||||
// (*(anychar_p - '$') >> '$')[refactor_action_actor(str)].
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string str;
|
||||
char const *test_string2 = "Some test string ending with a $";
|
||||
|
||||
result =
|
||||
parse(test_string2,
|
||||
refactor_action_d[
|
||||
(*(anychar_p - '$'))[refactor_action_actor(str)] >> '$'
|
||||
]
|
||||
);
|
||||
|
||||
if (result.full && str == std::string(test_string2))
|
||||
{
|
||||
cout << "Successfully refactored an action!" << endl;
|
||||
cout << "Parsed: \"" << str << "\"" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Failed to refactor an action!" << endl;
|
||||
}
|
||||
|
||||
// Parsing the same test string without refactoring fails, because the
|
||||
// the attached actor gets called only for the first part of the string
|
||||
// (without the '$')
|
||||
|
||||
result =
|
||||
parse(test_string2,
|
||||
(*(anychar_p - '$'))[refactor_action_actor(str)] >> '$'
|
||||
);
|
||||
|
||||
if (result.full && str == std::string(test_string2))
|
||||
{
|
||||
cout << "Successfully parsed test string!" << endl;
|
||||
cout << "Parsed: \"" << str << "\"" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout
|
||||
<< "Correctly failed parsing the test string (without refactoring)!"
|
||||
<< endl;
|
||||
cout << "Parsed instead: \"" << str << "\"" << endl;
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 3. Testing the refactor_action_d parser with an embedded (nested)
|
||||
// refactor_unary_p parser
|
||||
//
|
||||
// The following test should successfully parse the test string, because the
|
||||
//
|
||||
// refactor_action_unary_d[
|
||||
// ((*anychar_p)[refactor_action_actor(str)] - '$')
|
||||
// ] >> '$'
|
||||
//
|
||||
// is refactored into
|
||||
//
|
||||
// (*(anychar_p - '$'))[refactor_action_actor(str)] >> '$'.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const refactor_action_gen<refactor_unary_gen<> > refactor_action_unary_d =
|
||||
refactor_action_gen<refactor_unary_gen<> >(refactor_unary_d);
|
||||
|
||||
result =
|
||||
parse(test_string2,
|
||||
refactor_action_unary_d[
|
||||
((*anychar_p)[refactor_action_actor(str)] - '$')
|
||||
] >> '$'
|
||||
);
|
||||
|
||||
if (result.full)
|
||||
{
|
||||
cout
|
||||
<< "Successfully refactored an action attached to an unary!"
|
||||
<< endl;
|
||||
cout << "Parsed: \"" << str << "\"" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Failed to refactor an action!" << endl;
|
||||
}
|
||||
|
||||
// Parsing the same test string without refactoring fails, because the
|
||||
// anychar_p eats up all the input up to the end of the string
|
||||
|
||||
result =
|
||||
parse(test_string2,
|
||||
((*anychar_p)[refactor_action_actor(str)] - '$') >> '$'
|
||||
);
|
||||
|
||||
if (result.full)
|
||||
{
|
||||
cout << "Successfully parsed test string!" << endl;
|
||||
cout << "Parsed: \"" << str << "\"" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout
|
||||
<< "Correctly failed parsing the test string (without refactoring)!"
|
||||
<< endl;
|
||||
cout << "Parsed instead: \"" << str << "\"" << endl;
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
169
example/fundamental/regex_convert.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// vim:ts=4:sw=4:et
|
||||
//
|
||||
// Demonstrate regular expression parsers for match based text conversion
|
||||
//
|
||||
// This sample requires an installed version of the boost regex library
|
||||
// (http://www.boost.org) The sample was tested with boost V1.29.0
|
||||
//
|
||||
// Note: - there is no error handling in this example
|
||||
// - this program isn't particularly useful
|
||||
//
|
||||
// This example shows one way build a kind of filter program.
|
||||
// It reads input from std::cin and uses a grammar and actions
|
||||
// to print out a modified version of the input.
|
||||
//
|
||||
// [ Martin Wille, 10/18/2002 ]
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <streambuf>
|
||||
#include <sstream>
|
||||
#include <deque>
|
||||
#include <iterator>
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/spirit/core.hpp>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The following header must be included, if regular expression support is
|
||||
// required for Spirit.
|
||||
//
|
||||
// The BOOST_SPIRIT_NO_REGEX_LIB PP constant should be defined, if you're using the
|
||||
// Boost.Regex library from one translation unit only. Otherwise you have to
|
||||
// link with the Boost.Regex library as defined in the related documentation
|
||||
// (see. http://www.boost.org).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define BOOST_SPIRIT_NO_REGEX_LIB
|
||||
#include <boost/spirit/utility/regex.hpp>
|
||||
|
||||
using namespace boost::spirit;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
long triple(long val)
|
||||
{
|
||||
return 3*val;
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// actions
|
||||
//
|
||||
struct emit_constant
|
||||
{
|
||||
emit_constant(string const &text)
|
||||
: msg(text)
|
||||
{}
|
||||
|
||||
template<typename Iterator>
|
||||
void operator()(Iterator b, Iterator e) const
|
||||
{
|
||||
cout.rdbuf()->sputn(msg.data(), msg.size());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
string msg;
|
||||
};
|
||||
|
||||
void
|
||||
copy_unmodified(char letter)
|
||||
{
|
||||
cout.rdbuf()->sputc(letter);
|
||||
}
|
||||
|
||||
struct emit_modified_subscript
|
||||
{
|
||||
emit_modified_subscript(boost::function<long (long)> const &f)
|
||||
: modifier(f)
|
||||
{}
|
||||
|
||||
template<typename Iterator>
|
||||
void operator()(Iterator b, Iterator e) const
|
||||
{
|
||||
string tmp(b+1,e-1);
|
||||
long val = strtol(tmp.c_str(),0, 0);
|
||||
ostringstream os;
|
||||
os << modifier(val);
|
||||
tmp = os.str();
|
||||
cout.rdbuf()->sputc('[');
|
||||
cout.rdbuf()->sputn(tmp.c_str(), tmp.size());
|
||||
cout.rdbuf()->sputc(']');
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
boost::function<long (long)> modifier;
|
||||
};
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// The grammar 'conversion_grammar' serves as a working horse for match based
|
||||
// text conversion. It does the following:
|
||||
//
|
||||
// - converts the word "class" into the word "struct"
|
||||
// - multiplies any integer number enclosed in square brackets with 3
|
||||
// - any other input is simply copied to the output
|
||||
|
||||
struct conversion_grammar
|
||||
: grammar<conversion_grammar>
|
||||
{
|
||||
template<class ScannerT>
|
||||
struct definition
|
||||
{
|
||||
typedef ScannerT scanner_t;
|
||||
|
||||
definition(conversion_grammar const &)
|
||||
{
|
||||
static const char expr[] = "\\[\\d+\\]";
|
||||
first = (
|
||||
/////////////////////////////////////////////////////////////
|
||||
// note that "fallback" is the last alternative here !
|
||||
top = *(class2struct || subscript || fallback),
|
||||
/////////////////////////////////////////////////////////////
|
||||
// replace any occurrance of "class" by "struct"
|
||||
class2struct = str_p("class") [emit_constant("struct")],
|
||||
/////////////////////////////////////////////////////////////
|
||||
// if the input maches "[some_number]"
|
||||
// "some_number" is multiplied by 3 before printing
|
||||
subscript = regex_p(expr) [emit_modified_subscript(&triple)],
|
||||
/////////////////////////////////////////////////////////////
|
||||
// if nothing else can be done with the input
|
||||
// then it will be printed without modifications
|
||||
fallback = anychar_p [©_unmodified]
|
||||
);
|
||||
}
|
||||
|
||||
rule<scanner_t> const & start() { return first; }
|
||||
|
||||
private:
|
||||
|
||||
subrule<0> top;
|
||||
subrule<1> class2struct;
|
||||
subrule<2> subscript;
|
||||
subrule<3> fallback;
|
||||
rule<scanner_t> first;
|
||||
};
|
||||
};
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
// this would print "struct foo {}; foo bar[9];":
|
||||
// parse("class foo {}; foo bar[3];", conversion_grammar());
|
||||
|
||||
// Note: the regular expression parser contained in the
|
||||
// grammar requires a bidirectional iterator. Therefore,
|
||||
// we cannot use sdt::istreambuf_iterator as one would
|
||||
// do with other Spirit parsers.
|
||||
istreambuf_iterator<char> input_iterator(cin);
|
||||
std::deque<char> input(input_iterator, istreambuf_iterator<char>());
|
||||
|
||||
parse(input.begin(), input.end(), conversion_grammar());
|
||||
return 0;
|
||||
}
|
||||
|
||||
79
example/fundamental/regular_expression.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Demonstrate regular expression parser objects
|
||||
//
|
||||
// This sample requires an installed version of the boost regex library
|
||||
// (http://www.boost.org) The sample was tested with boost V1.28.0
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/spirit/core.hpp>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The following header must be included, if regular expression support is
|
||||
// required for Spirit.
|
||||
//
|
||||
// The BOOST_SPIRIT_NO_REGEX_LIB PP constant should be defined, if you're using the
|
||||
// Boost.Regex library from one translation unit only. Otherwise you have to
|
||||
// link with the Boost.Regex library as defined in the related documentation
|
||||
// (see. http://www.boost.org).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define BOOST_SPIRIT_NO_REGEX_LIB
|
||||
#include <boost/spirit/utility/regex.hpp>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// used namespaces
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// main entry point
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
const char *ptest = "123 E 456";
|
||||
const char *prx = "[1-9]+[[:space:]]*E[[:space:]]*";
|
||||
|
||||
cout << "Parse " << ptest << " against regular expression: " << prx
|
||||
<< endl;
|
||||
|
||||
// 1. direct use of rxlit<>
|
||||
rxstrlit<> regexpr(prx);
|
||||
parse_info<> result;
|
||||
string str;
|
||||
|
||||
result = parse (ptest, regexpr[assign(str)]);
|
||||
if (result.hit)
|
||||
{
|
||||
cout << "Parsed regular expression successfully!" << endl;
|
||||
cout << "Matched (" << (int)result.length << ") characters: ";
|
||||
cout << "\"" << str << "\"" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Failed to parse regular expression!" << endl;
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
// 2. use of regex_p predefined parser object
|
||||
result = parse (ptest, regex_p(prx)[assign(str)]);
|
||||
if (result.hit)
|
||||
{
|
||||
cout << "Parsed regular expression successfully!" << endl;
|
||||
cout << "Matched (" << (int)result.length << ") characters: ";
|
||||
cout << "\"" << str << "\"" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Failed to parse regular expression!" << endl;
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
263
example/fundamental/rfc821.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RFC821-compliant SMTP e-mail address parser
|
||||
// ===========================================
|
||||
// Martijn W. van der Lee (martijn@v-d-l.com)
|
||||
// Ported to Spirit v1.5 [ JDG 9/17/2002 ]
|
||||
//
|
||||
// This is an example for using Spirit to verify RFC821-compliant e-mail
|
||||
// addresses.
|
||||
//
|
||||
// Although the author has taken utmost care to check the correctness of this
|
||||
// code we can make no guarantees whatsoever. Use at your own risk.
|
||||
//
|
||||
// Please report any corrections or problems with the implementation of RFC821
|
||||
// to spirit.sourceforge.net and/or the author and/or the spirit mailing list.
|
||||
//
|
||||
// What this example demonstrates:
|
||||
// - Conversion of BNF to Spirit code.
|
||||
// - How to use exceptions for implementing semantics.
|
||||
//
|
||||
// --------------------------------------------------- original RFC821 BNF ---
|
||||
//
|
||||
// <reverse-path> ::= <path>
|
||||
// <forward-path> ::= <path>
|
||||
// <path> ::= "<" [ <a-d-l> ":" ] <mailbox> ">"
|
||||
// <a-d-l> ::= <at-domain> | <at-domain> "," <a-d-l>
|
||||
// <at-domain> ::= "@" <domain>
|
||||
// <domain> ::= <element> | <element> "." <domain>
|
||||
// <element> ::= <name> | "#" <number> | "[" <dotnum> "]"
|
||||
// <mailbox> ::= <local-part> "@" <domain>
|
||||
// <local-part> ::= <dot-string> | <quoted-string>
|
||||
// <name> ::= <a> <ldh-str> <let-dig>
|
||||
// <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
|
||||
// <let-dig> ::= <a> | <d>
|
||||
// <let-dig-hyp> ::= <a> | <d> | "-"
|
||||
// <dot-string> ::= <string> | <string> "." <dot-string>
|
||||
// <string> ::= <char> | <char> <string>
|
||||
// <quoted-string> ::= """ <qtext> """
|
||||
// <qtext> ::= "\" <x> | "\" <x> <qtext> | <q> | <q> <qtext>
|
||||
// <char> ::= <c> | "\" <x>
|
||||
// <dotnum> ::= <snum> "." <snum> "." <snum> "." <snum>
|
||||
// <number> ::= <d> | <d> <number>
|
||||
// <CRLF> ::= <CR> <LF>
|
||||
// <CR> ::= the carriage return character (ASCII code 13)
|
||||
// <LF> ::= the line feed character (ASCII code 10)
|
||||
// <SP> ::= the space character (ASCII code 32)
|
||||
// <snum> ::= one, two, or three digits representing a decimal
|
||||
// integer value in the range 0 through 255
|
||||
// <a> ::= any one of the 52 alphabetic characters A through Z
|
||||
// in upper case and a through z in lower case
|
||||
// <c> ::= any one of the 128 ASCII characters, but not any
|
||||
// <special> or <SP>
|
||||
// <d> ::= any one of the ten digits 0 through 9
|
||||
// <q> ::= any one of the 128 ASCII characters except <CR>,
|
||||
// <LF>, quote ("), or backslash (\)
|
||||
// <x> ::= any one of the 128 ASCII characters (no exceptions)
|
||||
// <special> ::= "<" | ">" | "(" | ")" | "[" | "]" | "\" | "."
|
||||
// | "," | ";" | ":" | "@" """ | the control
|
||||
// characters (ASCII codes 0 through 31 inclusive and
|
||||
// 127)
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/utility/loops.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// My grammar
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
struct rfc821 : public grammar<rfc821>
|
||||
{
|
||||
template <typename ScannerT>
|
||||
struct definition
|
||||
{
|
||||
definition(rfc821 const& /*self*/)
|
||||
{
|
||||
range<>
|
||||
ascii(char(0x01), char(0x7F))
|
||||
;
|
||||
|
||||
e_path
|
||||
= lexeme_d
|
||||
[
|
||||
'<'
|
||||
>> !(e_a_d_l >> ':')
|
||||
>> e_mailbox
|
||||
>> '>'
|
||||
]
|
||||
;
|
||||
|
||||
e_a_d_l
|
||||
= e_at_domain
|
||||
>> *(',' >> e_at_domain)
|
||||
;
|
||||
|
||||
e_mailbox
|
||||
= e_local_part
|
||||
>> e_at_domain
|
||||
;
|
||||
|
||||
e_at_domain
|
||||
= '@'
|
||||
>> e_domain
|
||||
;
|
||||
|
||||
e_domain
|
||||
= e_element
|
||||
>> *('.' >> e_element)
|
||||
;
|
||||
|
||||
e_element
|
||||
= e_name
|
||||
| '#' >> +digit_p
|
||||
| '[' >> e_dotnum >> ']';
|
||||
|
||||
e_local_part
|
||||
= e_dot_string
|
||||
| e_quoted_string
|
||||
;
|
||||
|
||||
e_dot_string
|
||||
= +e_char
|
||||
>> *('.' >> +e_char)
|
||||
;
|
||||
|
||||
e_quoted_string
|
||||
= '\"'
|
||||
>> e_qtext
|
||||
>> '\"'
|
||||
;
|
||||
|
||||
e_qtext
|
||||
= +(e_q | ('\\' >> ascii));
|
||||
|
||||
// e_name forces domain-name parts to be 2 characters minimum, RFC0821
|
||||
// is a bit unclear about this. Could also be 1 or 3.
|
||||
e_name
|
||||
= alpha_p
|
||||
>> +e_alnum_hyp
|
||||
;
|
||||
|
||||
e_char
|
||||
= e_c
|
||||
| ('\\' >> ascii)
|
||||
;
|
||||
|
||||
e_crlf
|
||||
= ch_p('\r')
|
||||
>> '\n'
|
||||
;
|
||||
|
||||
e_c
|
||||
= ascii - e_special - ' '
|
||||
;
|
||||
|
||||
e_q
|
||||
= ascii - '\\' - '\r' - '\n' - '\"'
|
||||
;
|
||||
|
||||
e_alnum_hyp
|
||||
= *ch_p('-')
|
||||
>> alnum_p
|
||||
;
|
||||
|
||||
e_dotnum
|
||||
= e_snum
|
||||
>> repeat_p(3)['.' >> e_snum]
|
||||
;
|
||||
|
||||
uint_parser<unsigned, 10, 1, 3> uint3_p; // 3 digit unsigned
|
||||
|
||||
e_snum
|
||||
= max_limit_d(255u)[uint3_p]; // 0-255!
|
||||
|
||||
e_special
|
||||
= ch_p('<') | '>' | '(' | ')' | '[' | ']'
|
||||
| '\\' | '.' | ',' | ';' | ':' | '@' | '\"'
|
||||
| cntrl_p;
|
||||
}
|
||||
|
||||
rule<ScannerT>
|
||||
e_path, e_a_d_l, e_mailbox, e_at_domain, e_domain, e_element,
|
||||
e_local_part, e_dot_string, e_quoted_string, e_qtext, e_name,
|
||||
e_char, e_crlf, e_c, e_q, e_alnum_hyp, e_dotnum, e_snum,
|
||||
e_special
|
||||
;
|
||||
|
||||
rule<ScannerT> const&
|
||||
start() const { return e_path; }
|
||||
};
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
struct check
|
||||
{
|
||||
char address[32];
|
||||
bool prediction;
|
||||
};
|
||||
|
||||
check checks[] =
|
||||
{
|
||||
// 12345678901234567890123456789012
|
||||
{"<user@server.com>", true},
|
||||
{"<user\\@@server.com>", true},
|
||||
{"<user\\\\@server.com>", true},
|
||||
{"<@serv2.com:user@server.com>", true},
|
||||
{"<user@#1234>", true},
|
||||
{"<user@mail.[12.34.56.255]>", true},
|
||||
{"<user@[255.0.0.0].#123.com>", true},
|
||||
{"<\"user name\"@server.com>", true},
|
||||
{"diddledoo", false},
|
||||
{"<polka@dot...dot>", false}
|
||||
};
|
||||
|
||||
// Header
|
||||
cout << "E-mail validation based on RFC821" << endl
|
||||
<< "---------------------------------" << endl;
|
||||
|
||||
// Tests
|
||||
int failed = 0;
|
||||
unsigned i;
|
||||
rfc821 g;
|
||||
|
||||
for (i = 0; i < sizeof(checks) / sizeof(check); ++i)
|
||||
{
|
||||
// This parser is an implicit lexeme. Passing in a
|
||||
// space_p or any skipper will not work unless the
|
||||
// grammar is explicitly wrapped inside a lexeme_d
|
||||
|
||||
const bool success = parse(checks[i].address, g).full;
|
||||
|
||||
cout << "Test " << (int)i
|
||||
<< " \"" << checks[i].address << "\" should "
|
||||
<< (checks[i].prediction? "" : "not") << " match. Result: "
|
||||
<< (success == checks[i].prediction? "success" : "failure")
|
||||
<< endl;
|
||||
|
||||
if (success != checks[i].prediction)
|
||||
++failed;
|
||||
}
|
||||
|
||||
// Footer
|
||||
cout << "---------------------------------" << endl;
|
||||
cout << failed << " test failed";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
180
example/fundamental/roman_numerals.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// A Roman Numerals Parser (demonstrating the symbol table)
|
||||
//
|
||||
// [ JDG 8/22/2002 ]
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/symbols/symbols.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Parse roman hundreds (100..900) numerals using the symbol table.
|
||||
// Notice that the data associated with each slot is passed
|
||||
// to attached semantic actions.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
struct hundreds : symbols<unsigned>
|
||||
{
|
||||
hundreds()
|
||||
{
|
||||
add
|
||||
("C" , 100)
|
||||
("CC" , 200)
|
||||
("CCC" , 300)
|
||||
("CD" , 400)
|
||||
("D" , 500)
|
||||
("DC" , 600)
|
||||
("DCC" , 700)
|
||||
("DCCC" , 800)
|
||||
("CM" , 900)
|
||||
;
|
||||
}
|
||||
|
||||
} hundreds_p;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Parse roman tens (10..90) numerals using the symbol table.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
struct tens : symbols<unsigned>
|
||||
{
|
||||
tens()
|
||||
{
|
||||
add
|
||||
("X" , 10)
|
||||
("XX" , 20)
|
||||
("XXX" , 30)
|
||||
("XL" , 40)
|
||||
("L" , 50)
|
||||
("LX" , 60)
|
||||
("LXX" , 70)
|
||||
("LXXX" , 80)
|
||||
("XC" , 90)
|
||||
;
|
||||
}
|
||||
|
||||
} tens_p;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Parse roman ones (1..9) numerals using the symbol table.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
struct ones : symbols<unsigned>
|
||||
{
|
||||
ones()
|
||||
{
|
||||
add
|
||||
("I" , 1)
|
||||
("II" , 2)
|
||||
("III" , 3)
|
||||
("IV" , 4)
|
||||
("V" , 5)
|
||||
("VI" , 6)
|
||||
("VII" , 7)
|
||||
("VIII" , 8)
|
||||
("IX" , 9)
|
||||
;
|
||||
}
|
||||
|
||||
} ones_p;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Semantic actions
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
struct add_1000
|
||||
{
|
||||
add_1000(unsigned& r_) : r(r_) {}
|
||||
void operator()(char) const { r += 1000; }
|
||||
unsigned& r;
|
||||
};
|
||||
|
||||
struct add_roman
|
||||
{
|
||||
add_roman(unsigned& r_) : r(r_) {}
|
||||
void operator()(unsigned n) const { r += n; }
|
||||
unsigned& r;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// roman (numerals) grammar
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
struct roman : public grammar<roman>
|
||||
{
|
||||
template <typename ScannerT>
|
||||
struct definition
|
||||
{
|
||||
definition(roman const& self)
|
||||
{
|
||||
first
|
||||
= +ch_p('M') [add_1000(self.r)]
|
||||
|| hundreds_p [add_roman(self.r)]
|
||||
|| tens_p [add_roman(self.r)]
|
||||
|| ones_p [add_roman(self.r)];
|
||||
|
||||
// Note the use of the || operator. The expression
|
||||
// a || b reads match a or b and in sequence. Try
|
||||
// defining the roman numerals grammar in YACC or
|
||||
// PCCTS. Spirit rules! :-)
|
||||
}
|
||||
|
||||
rule<ScannerT> first;
|
||||
rule<ScannerT> const&
|
||||
start() const { return first; }
|
||||
};
|
||||
|
||||
roman(unsigned& r_) : r(r_) {}
|
||||
unsigned& r;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main driver code
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tRoman Numerals Parser\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "Type a Roman Numeral ...or [q or Q] to quit\n\n";
|
||||
|
||||
// Start grammar definition
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
unsigned n = 0;
|
||||
roman roman_p(n);
|
||||
if (parse(str.c_str(), roman_p).full)
|
||||
{
|
||||
cout << "parsing succeeded\n";
|
||||
cout << "result = " << n << "\n\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "parsing failed\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
117
example/fundamental/spirit_bind.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Demonstrates use of boost::bind and spirit
|
||||
//
|
||||
// [ JDG 9/29/2002 ]
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
using namespace boost;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our comma separated list parser
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class list_parser
|
||||
{
|
||||
public:
|
||||
|
||||
typedef list_parser self_t;
|
||||
|
||||
bool
|
||||
parse(char const* str)
|
||||
{
|
||||
return boost::spirit::parse(str,
|
||||
|
||||
// Begin grammar
|
||||
(
|
||||
real_p
|
||||
[
|
||||
bind(&self_t::add, this, _1)
|
||||
]
|
||||
|
||||
>> *( ','
|
||||
>> real_p
|
||||
[
|
||||
bind(&self_t::add, this, _1)
|
||||
]
|
||||
)
|
||||
)
|
||||
,
|
||||
// End grammar
|
||||
|
||||
space_p).full;
|
||||
}
|
||||
|
||||
void
|
||||
add(double n)
|
||||
{
|
||||
v.push_back(n);
|
||||
}
|
||||
|
||||
void
|
||||
print() const
|
||||
{
|
||||
for (vector<double>::size_type i = 0; i < v.size(); ++i)
|
||||
cout << i << ": " << v[i] << endl;
|
||||
}
|
||||
|
||||
vector<double> v;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\tA comma separated list parser for Spirit...\n";
|
||||
cout << "\tDemonstrates use of boost::bind and spirit\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
|
||||
cout << "Give me a comma separated list of numbers.\n";
|
||||
cout << "The numbers will be inserted in a vector of numbers\n";
|
||||
cout << "Type [q or Q] to quit\n\n";
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
list_parser lp;
|
||||
if (lp.parse(str.c_str()))
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << str << " Parses OK: " << endl;
|
||||
|
||||
lp.print();
|
||||
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
84
example/fundamental/sum.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// A parser for summing a list of numbers.
|
||||
// [ demonstrating phoenix ]
|
||||
//
|
||||
// [ JDG 6/28/2002 ]
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/phoenix/primitives.hpp>
|
||||
#include <boost/phoenix/operators.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace boost::spirit;
|
||||
using namespace phoenix;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Our adder
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename IteratorT>
|
||||
bool adder(IteratorT first, IteratorT last, double& n)
|
||||
{
|
||||
return parse(first, last,
|
||||
|
||||
// Begin grammar
|
||||
(
|
||||
real_p[var(n) = arg1] >> *real_p[var(n) += arg1]
|
||||
)
|
||||
,
|
||||
// End grammar
|
||||
|
||||
space_p).full;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Main program
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
cout << "\t\tA parser for summing a list of numbers...\n\n";
|
||||
cout << "/////////////////////////////////////////////////////////\n\n";
|
||||
|
||||
cout << "Give me a space separated list of numbers.\n";
|
||||
cout << "The numbers are added using Phoenix.\n";
|
||||
cout << "Type [q or Q] to quit\n\n";
|
||||
|
||||
string str;
|
||||
while (getline(cin, str))
|
||||
{
|
||||
if (str[0] == 'q' || str[0] == 'Q')
|
||||
break;
|
||||
|
||||
double n;
|
||||
if (adder(str.begin(), str.end(), n))
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing succeeded\n";
|
||||
cout << str << " Parses OK: " << endl;
|
||||
|
||||
cout << "sum = " << n;
|
||||
cout << "\n-------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "-------------------------\n";
|
||||
cout << "Parsing failed\n";
|
||||
cout << "-------------------------\n";
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Bye... :-) \n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
196
index.html
Normal file
@@ -0,0 +1,196 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Spirit v1.5</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<link rel="stylesheet" href="doc/theme/style.css" type="text/css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<table width="100%" border="0" background="doc/theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
<h1></h1>
|
||||
</td>
|
||||
<td width="85%"> <font face="Verdana, Arial, Helvetica, sans-serif"><b><font size="6">Spirit
|
||||
v1.5 </font></b></font></td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="doc/theme/spirit.gif" width="112" height="48" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table width="75%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="table_title">Table of Contents</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><a href="doc/preface.html">Preface</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><a href="doc/introduction.html">Introduction</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><a href="doc/quick_start.html">Quick Start</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><a href="doc/basic_concepts.html">Basic Concepts</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><a href="doc/organization.html">Organization</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><b><font face="Geneva, Arial, Helvetica, san-serif">Core</font></b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/primitives.html">Primitives</a> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/operators.html">Operators</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/numerics.html">Numerics</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/rule.html">The Rule</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/directives.html">Directives</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/scanner.html">The Scanner and Parsing</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/grammar.html">The Grammar</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/subrules.html">Subrules</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/semantic_actions.html">Semantic Actions</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/indepth_the_parser.html">In-depth: The
|
||||
Parser</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/indepth_the_scanner.html">In-depth:
|
||||
The Scanner</a> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><b>Attribute</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/parametric_parsers.html">Parametric
|
||||
Parsers</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/functional.html">Functional</a><a href="doc/parametric_parsers.html"></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/closures.html">Closures</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><b>Utility</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/escape_char_parser.html">Escape Character
|
||||
Parsers</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/loops.html">Loop Parsers</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/character_sets.html">Character Set Parser</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/confix.html">Confix and Comment Parsers</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/list_parsers.html">List Parsers</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/functor_parser.html">Functor Parser</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/refactoring.html">Refactoring Parsers</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/regular_expression_parser.html">Regular
|
||||
Expression Parser</a> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><b>Symbols</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/symbols.html">The Symbol Table</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="table_cells"><b>Trees</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/trees.html">Parse Trees and ASTs</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><b>Iterator</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/multi_pass.html">Multi Pass </a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/file_iterator.html">File Iterator</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1"><a href="doc/position_iterator.html">Position Iterator
|
||||
</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><a href="doc/debugging.html">Debugging</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><a href="doc/error_handling.html">Error Handling</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><a href="doc/acknowledgments.html">Acknowledgments</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0"><a href="doc/references.html">References</a> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table width="50%" border="0" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<div align="center"><font size="2" color="#666666">Copyright © 1998-2002
|
||||
Joel de Guzman</font><font size="2"><br>
|
||||
<br>
|
||||
Portions of this document: <br>
|
||||
<font color="#666666">Copyright © 2001-2002 Hartmut Kaiser<br>
|
||||
Copyright © 2001-2002 Daniel C. Nuffer<br>
|
||||
Copyright © 2002 Chris Uzdavinis<br>
|
||||
Copyright © 2002 Jeff Westfahl<br>
|
||||
Copyright © 2002 Juan Carlos Arevalo-Baeza<br>
|
||||
<br>
|
||||
</font> </font></div>
|
||||
<p><font size="2"> <font color="#666666">Permission to copy, use, modify,
|
||||
sell and distribute this document is granted provided this copyright notice
|
||||
appears in all copies. This document is provided "as is" without
|
||||
express or implied warranty, and with no claim as to its suitability for
|
||||
any purpose. </font> </font></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table width="35%" border="0" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<div align="center"><font size="2">Spirit is hosted by <a href="http://sourceforge.net">SourceForge</a></font><br>
|
||||
<font size="2"><a href="http://spirit.sourceforge.net/">http://spirit.sourceforge.net/
|
||||
</a></font> <br>
|
||||
<br>
|
||||
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.php?group_id=28447" width="88" height="31" border="0" alt="SourceForge Logo"></a></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<p> </p>
|
||||
</body>
|
||||
</html>
|
||||
4
phoenix/Makefile.am
Normal file
@@ -0,0 +1,4 @@
|
||||
SUBDIRS = doc example test
|
||||
EXTRA_DIST = index.html
|
||||
html_DATA = $(EXTRA_DIST)
|
||||
htmldir = $(prefix)/libs/phoenix
|
||||
5
phoenix/doc/Makefile.am
Normal file
@@ -0,0 +1,5 @@
|
||||
#This file generated by Makefileamgen.sh
|
||||
SUBDIRS = theme
|
||||
EXTRA_DIST = actors.html actors_revisited.html adaptable_closures.html architecture.html arguments.html basic_concepts.html binders.html composites.html composites_revisited.html efficiency.html functions.html inside_phoenix.html interfacing.html introduction.html lazy_construction_and_conversions.html lazy_functions.html operators.html operators_revisited.html organization.html phoenix_users_manual.txt place_holders.html polymorphic_functions.html preface.html primitives.html quick_start.html references.html statements.html tuples.html values.html variables.html wrap_up.html
|
||||
html_DATA = $(EXTRA_DIST)
|
||||
htmldir = $(prefix)/libs/spirit/doc
|
||||
89
phoenix/doc/actors.html
Normal file
@@ -0,0 +1,89 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Actors</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="organization.html">
|
||||
<link rel="next" href="primitives.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Actors</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="organization.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="primitives.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Actors are functors. Actors are the main driving force behind the framework. An actor can accept 0 to N arguments (where N is a predefined maximum). In an abstract point of view, an actor is the metaphor of a function declaration. The actor has no function body at all, which means that it does not know how to perform any function at all.</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/note.gif">
|
||||
an actor is the metaphor of a function declaration </td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
The actor is a template class though, and its sole template parameter fills in the missing function body and does the actual function evaluation. The actor class derives from its template argument. Here's the simplified actor class declaration:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>BaseT</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>actor </span><span class=special>: </span><span class=keyword>public </span><span class=identifier>BaseT </span><span class=special>{ </span><span class=comment>/*...*/ </span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
To avoid being overwhelmed in details, the following is a brief overview of what an actor is. First, imagine an actor as a non- lazy function that accepts 0..N arguments:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>actor</span><span class=special>(</span><span class=identifier>a0</span><span class=special>, </span><span class=identifier>a1</span><span class=special>, </span><span class=special>... </span><span class=identifier>aN</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Not knowing what to do with the arguments passed in, the actor forwards the arguments received from the client (caller) onto its base class BaseT. It is the base class that does the actual operation, finally returning a result. In essence, the actor's base class is the metaphor of the function body. The sequence of events that transpire is outlined informally as follows:</p>
|
||||
<p>
|
||||
1) actor is called, passing in N arguments:</p>
|
||||
<p>
|
||||
client --> actor(a0, a1, ... aN)</p>
|
||||
<p>
|
||||
2) actor forwards the arguments to its base:</p>
|
||||
<p>
|
||||
--> actor's base(a0, a1, ... aN)</p>
|
||||
<p>
|
||||
3) actor's base does some computation and returns a result back to the actor, and finally, the actor returns this back to the client:</p>
|
||||
<p>
|
||||
actor's base operation --> return result --> actor --> client</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/note.gif">
|
||||
In essence, the actor's base class is the metaphor of the function body </td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
For further details, we shall see more in-depth information later as we move on to the more technical side of the framework.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="organization.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="primitives.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
142
phoenix/doc/actors_revisited.html
Normal file
@@ -0,0 +1,142 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Actors revisited</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="tuples.html">
|
||||
<link rel="next" href="composites_revisited.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Actors revisited</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="tuples.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="composites_revisited.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
This class is a protocol class for all actors. This class is essentially an interface contract. The actor class does not really know how how to act on anything but instead relies on the template parameter BaseT (from which the actor will derive from) to do the actual action. The template class actor is declared as:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>BaseT</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>actor </span><span class=special>: </span><span class=keyword>public </span><span class=identifier>BaseT </span><span class=special>{
|
||||
|
||||
</span><span class=identifier>actor</span><span class=special>();
|
||||
</span><span class=identifier>actor</span><span class=special>(</span><span class=identifier>BaseT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>base</span><span class=special>);
|
||||
|
||||
</span><span class=comment>/*...member functions...*/
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/lens.gif">
|
||||
<b>Curiously Recurring Template Pattern Inverse</b><br><br>Notice that actor derives from its template argument BaseT. This is the inverse of the curiously recurring template pattern (CRTP). With the CRTP, the actor is an abstract class with a DerivedT template parameter that is assumed to be its parametric subclass. This pattern however, "parametric base class pattern" (PBCP) for lack of a name, inverses the inheritance and makes actor a concrete class. Anyway, be it CRTP or PBCP, actor is a protocol class and either BaseT or DerivedT will have to conform to its protocol. Both CRTP and PBCP techniques has its pros and cons, of which is outside the scope of this document. CRTP should really be renamed "parametric subclass pattern (PSCP), but again, that's another story. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
An actor is a functor that is capable of accepting arguments up to a predefined maximum. It is up to the base class to do the actual processing or possibly to limit the arity (no. of arguments) passed in. Upon invocation of the functor through a supplied operator(), the actor funnels the arguments passed in by the client into a tuple and calls the base class' eval member function.</p>
|
||||
<p>
|
||||
Schematically:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>arg0 </span><span class=special>---------|
|
||||
</span><span class=identifier>arg1 </span><span class=special>---------|
|
||||
</span><span class=identifier>arg3 </span><span class=special>---------|---> </span><span class=identifier>tupled_args </span><span class=special>---> </span><span class=identifier>base</span><span class=special>.</span><span class=identifier>eval
|
||||
</span><span class=special>... </span><span class=special>|
|
||||
</span><span class=identifier>argN </span><span class=special>---------|
|
||||
|
||||
</span><span class=identifier>actor</span><span class=special>::</span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>arg0</span><span class=special>, </span><span class=identifier>arg1</span><span class=special>... </span><span class=identifier>argN</span><span class=special>)
|
||||
</span><span class=special>---> </span><span class=identifier>BaseT</span><span class=special>::</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>tupled_args</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Actor base classes from which this class inherits from are expected to have a corresponding member function eval compatible with the conceptual Interface:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>>
|
||||
</span><span class=identifier>actor_return_type
|
||||
</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>TupleT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>args</span><span class=special>) </span><span class=keyword>const</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
where args are the actual arguments passed in by the client funneled into a tuple (see tuple for details).</p>
|
||||
<p>
|
||||
The actor_return_type can be anything. Base classes are free to return any type, even argument dependent types (types that are deduced from the types of the arguments). After evaluating the parameters and doing some computations or actions, the eval member function concludes by returning something back to the client. To do this, the forwarding function (the actor's operator()) needs to know the return type of the eval member function that it is calling. For this purpose, actor base classes are required to provide a nested template class:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>result</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
This auxiliary class provides the result type information returned by the eval member function of a base actor class. The nested template class result should have a typedef 'type' that reflects the return type of its member function eval. It is basically a type computer that answers the question "given arguments packed into a TupleT type, what will be the result type of the eval member function of ActorT?".</p>
|
||||
<p>
|
||||
There is a global template class actor_result declared in namespace phoenix scope that queries the actor's result type given a tuple. Here is the class actor_result's declaration:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>ActorT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>actor_result </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>ActorT</span><span class=special>::</span><span class=keyword>template </span><span class=identifier>result</span><span class=special><</span><span class=identifier>TupleT</span><span class=special>>::</span><span class=identifier>type </span><span class=identifier>type</span><span class=special>;
|
||||
</span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>remove_reference</span><span class=special><</span><span class=identifier>type</span><span class=special>>::</span><span class=identifier>type </span><span class=identifier>plain_type</span><span class=special>;
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<ul><li>type is the actual return type</li><li>plain_type is the return type stripped from references.</li></ul><p>
|
||||
Given an actor type ActorT and a TupleT, we can get the actor's return type this way:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special><</span><span class=identifier>ActorT</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>>::</span><span class=identifier>type
|
||||
</span><span class=identifier>actor_return_type</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
where actor_return_type is the actual type returned by ActorT's eval member function given some arguments packed in a TupleT.</p>
|
||||
<p>
|
||||
For reference, here's a typical actor::operator() that accepts two (2) arguments:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>BaseT</span><span class=special>>
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>T1</span><span class=special>>
|
||||
</span><span class=keyword>inline </span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special><</span><span class=identifier>BaseT</span><span class=special>, </span><span class=identifier>tuple</span><span class=special><</span><span class=identifier>T0</span><span class=special>&, </span><span class=identifier>T1</span><span class=special>&> </span><span class=special>>::</span><span class=identifier>type
|
||||
</span><span class=identifier>actor</span><span class=special><</span><span class=identifier>BaseT</span><span class=special>>::</span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>T0</span><span class=special>& </span><span class=identifier>_0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>& </span><span class=identifier>_1</span><span class=special>) </span><span class=keyword>const
|
||||
</span><span class=special>{
|
||||
</span><span class=keyword>return </span><span class=identifier>BaseT</span><span class=special>::</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>tuple</span><span class=special><</span><span class=identifier>T0</span><span class=special>&, </span><span class=identifier>T1</span><span class=special>&>(</span><span class=identifier>_0</span><span class=special>, </span><span class=identifier>_1</span><span class=special>));
|
||||
</span><span class=special>}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/lens.gif">
|
||||
<b>Forwarding Function Problem</b><br><br>_0 and _1 are references. Hence the arguments cannot accept non-const temporaries and literal constants. This is a current C++ language issue known as the "forwarding function problem" that is currently being discussed. The problem is that given an arbitrary function f, using current C++ language rules, one cannot create a forwarding function f' that transparently assumes the arguments of f. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="tuples.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="composites_revisited.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
135
phoenix/doc/adaptable_closures.html
Normal file
@@ -0,0 +1,135 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Adaptable closures</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="binders.html">
|
||||
<link rel="next" href="lazy_construction_and_conversions.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Adaptable closures</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="binders.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="lazy_construction_and_conversions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
The framework will not be complete without some form of closures support. Closures encapsulate a stack frame where local variables are created upon entering a function and destructed upon exiting. Closures provide an environment for local variables to reside. Closures can hold heterogeneous types.</p>
|
||||
<p>
|
||||
Phoenix closures are true hardware stack based. Closures enable true reentrancy in lambda functions. A closure provides access to a function stack frame where local variables reside. Modeled after Pascal nested stack frames, closures can be nested just like nested functions where code in inner closures may access local variables from in-scope outer closures (accessing inner scopes from outer scopes is an error and will cause a run-time assertion failure).</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/lens.gif">
|
||||
<b>Spirit Closures</b><br><br><a href="http://spirit.sourceforge.net">
|
||||
Spirit</a> uses Phoenix closures to allow parameter passing (inherited and synthetic attributes, in parsing parlance) upstream and downstream in a parse traversal (see <a href="../../spirit/index.html">
|
||||
Spirit v1.5</a> documentation). </td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
There are three (3) interacting classes:</p>
|
||||
<p>
|
||||
<b>1) closure:</b></p>
|
||||
<p>
|
||||
At the point of declaration, a closure does not yet create a stack frame nor instantiate any variables. A closure declaration declares the types and names of the local variables. The closure class is meant to be subclassed. It is the responsibility of a closure subclass to supply the names for each of the local variable in the closure. Example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>my_closure </span><span class=special>: </span><span class=identifier>closure</span><span class=special><</span><span class=keyword>int</span><span class=special>, </span><span class=identifier>string</span><span class=special>, </span><span class=keyword>double</span><span class=special>> </span><span class=special>{
|
||||
|
||||
</span><span class=identifier>member1 </span><span class=identifier>num</span><span class=special>; </span><span class=comment>// names the 1st (int) local variable
|
||||
</span><span class=identifier>member2 </span><span class=identifier>message</span><span class=special>; </span><span class=comment>// names the 2nd (string) local variable
|
||||
</span><span class=identifier>member3 </span><span class=identifier>real</span><span class=special>; </span><span class=comment>// names the 3rd (double) local variable
|
||||
</span><span class=special>};
|
||||
|
||||
</span><span class=identifier>my_closure </span><span class=identifier>clos</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Now that we have a closure 'clos', its local variables can be accessed lazily using the dot notation. Each qualified local variable can be used just like any primitive actor (see primitives). Examples:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>clos</span><span class=special>.</span><span class=identifier>num </span><span class=special>= </span><span class=number>30
|
||||
</span><span class=identifier>clos</span><span class=special>.</span><span class=identifier>message </span><span class=special>= </span><span class=identifier>arg1
|
||||
</span><span class=identifier>clos</span><span class=special>.</span><span class=identifier>real </span><span class=special>= </span><span class=identifier>clos</span><span class=special>.</span><span class=identifier>num </span><span class=special>* </span><span class=number>1e6
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
The examples above are lazily evaluated. As usual, these expressions return composite actors that will be evaluated through a second function call invocation (see operators). Each of the members (clos.xxx) is an actor. As such, applying the operator() will reveal its identity:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>clos</span><span class=special>.</span><span class=identifier>num</span><span class=special>() </span><span class=comment>// will return the current value of clos.num
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/note.gif">
|
||||
<b>Acknowledgement:</b><br><br><b>Juan Carlos Arevalo-Baeza</b> (JCAB) introduced and initilally implemented the closure member names that uses the dot notation and <b>Martin Wille</b> who improved multi thread safety using <a href="http://www.boost.org">
|
||||
Boost</a> Threads. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
<b>2) closure_member</b></p>
|
||||
<p>
|
||||
The named local variables of closure 'clos' above are actually closure members. The closure_member class is an actor and conforms to its conceptual interface. member1..memberN are predefined typedefs that correspond to each of the listed types in the closure template parameters.</p>
|
||||
<p>
|
||||
<b>3) closure_frame</b></p>
|
||||
<p>
|
||||
When a closure member is finally evaluated, it should refer to an actual instance of the variable in the hardware stack. Without doing so, the process is not complete and the evaluated member will result to an assertion failure. Remember that the closure is just a declaration. The local variables that a closure refers to must still be instantiated.</p>
|
||||
<p>
|
||||
The closure_frame class does the actual instantiation of the local variables and links these variables with the closure and all its members. There can be multiple instances of closure_frames typically situated in the stack inside a function. Each closure_frame instance initiates a stack frame with a new set of closure local variables. Example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>void </span><span class=identifier>foo</span><span class=special>()
|
||||
</span><span class=special>{
|
||||
</span><span class=identifier>closure_frame</span><span class=special><</span><span class=identifier>my_closure</span><span class=special>> </span><span class=identifier>frame</span><span class=special>(</span><span class=identifier>clos</span><span class=special>);
|
||||
</span><span class=comment>/* do something */
|
||||
</span><span class=special>}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
where 'clos' is an instance of our closure 'my_closure' above. Take note that the usage above precludes locally declared classes. If my_closure is a locally declared type, we can still use its self_type as a paramater to closure_frame:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>closure_frame</span><span class=special><</span><span class=identifier>my_closure</span><span class=special>::</span><span class=identifier>self_type</span><span class=special>> </span><span class=identifier>frame</span><span class=special>(</span><span class=identifier>clos</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Upon instantiation, the closure_frame links the local variables to the closure. The previous link to another closure_frame instance created before is saved. Upon destruction, the closure_frame unlinks itself from the closure and relinks the preceding closure_frame prior to this instance.</p>
|
||||
<p>
|
||||
The local variables in the closure 'clos' above is default constructed in the stack inside function 'foo'. Once 'foo' is exited, all of these local variables are destructed. In some cases, default construction is not desirable and we need to initialize the local closure variables with some values. This can be done by passing in the initializers in a compatible tuple. A compatible tuple is one with the same number of elements as the destination and where each element from the destination can be constructed from each corresponding element in the source. Example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>tuple</span><span class=special><</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>char </span><span class=keyword>const</span><span class=special>*, </span><span class=keyword>int</span><span class=special>> </span><span class=identifier>init</span><span class=special>(</span><span class=number>123</span><span class=special>, </span><span class=string>"Hello"</span><span class=special>, </span><span class=number>1000</span><span class=special>);
|
||||
</span><span class=identifier>closure_frame</span><span class=special><</span><span class=identifier>my_closure</span><span class=special>> </span><span class=identifier>frame</span><span class=special>(</span><span class=identifier>clos</span><span class=special>, </span><span class=identifier>init</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Here now, our closure_frame's variables are initialized with int: 123, char const*: "Hello" and int: 1000.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="binders.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="lazy_construction_and_conversions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
51
phoenix/doc/architecture.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Architecture</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="basic_concepts.html">
|
||||
<link rel="next" href="lazy_functions.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Architecture</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="basic_concepts.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="lazy_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Care and attention to detail was given, painstakingly, to the design and implementation of Phoenix. The overall design of the framework is well structured and clean. In this chapter, we shall see the main concepts behind the framework and gain introductory insights regarding its design.</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/lens.gif">
|
||||
<b>Macros</b><br><br>Implementation wise, not a single macro was used. Macros cause more trouble than its worth, regardless if they are used only in the implementation. A very early version of the framework did use macros to generate redundant code. The experience was to say the least, painful. 1) The code is so much more difficult to read 2) Compile errors take you in the middle of nowhere in a meaningless macro invocation without the slightest clue whatsoever what went wrong. The bottom line is: Macros are plain ugly. Exclamation point! No to macros. Period. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="basic_concepts.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="lazy_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
95
phoenix/doc/arguments.html
Normal file
@@ -0,0 +1,95 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Arguments</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="primitives.html">
|
||||
<link rel="next" href="values.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Arguments</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="primitives.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="values.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
The most basic primitive is the argument placeholder. For the sake of explanation, we used the '?' in our introductory examples to represent unknown arguments or argument place holders. Later on, we introduced the notion of positional argument place holders.</p>
|
||||
<p>
|
||||
We use an object of a special class argument<N> to represent the Nth function argument. The argument placeholder acts as an imaginary data-bin where a function argument will be placed.</p>
|
||||
<p>
|
||||
There are a couple of predefined instances of argument<N> named arg1..argN (where N is a predefined maximum). When appropriate, we can of course define our own argument<N> names. For example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>actor</span><span class=special><</span><span class=identifier>argument</span><span class=special><</span><span class=number>0</span><span class=special>> </span><span class=special>> </span><span class=identifier>first_param</span><span class=special>; </span><span class=comment>// note zero based index
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Take note that it should be wrapped inside an actor to be useful. first_param can now be used as a parameter to a lazy function:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus</span><span class=special>(</span><span class=identifier>first_param</span><span class=special>, </span><span class=number>6</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
which is equivalent to:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=number>6</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Here are some sample preset definitions of arg1..N</p>
|
||||
<code><pre>
|
||||
<span class=identifier>actor</span><span class=special><</span><span class=identifier>argument</span><span class=special><</span><span class=number>0</span><span class=special>> </span><span class=special>> </span><span class=keyword>const </span><span class=identifier>arg1 </span><span class=special>= </span><span class=identifier>argument</span><span class=special><</span><span class=number>0</span><span class=special>>();
|
||||
</span><span class=identifier>actor</span><span class=special><</span><span class=identifier>argument</span><span class=special><</span><span class=number>1</span><span class=special>> </span><span class=special>> </span><span class=keyword>const </span><span class=identifier>arg2 </span><span class=special>= </span><span class=identifier>argument</span><span class=special><</span><span class=number>1</span><span class=special>>();
|
||||
</span><span class=identifier>actor</span><span class=special><</span><span class=identifier>argument</span><span class=special><</span><span class=number>2</span><span class=special>> </span><span class=special>> </span><span class=keyword>const </span><span class=identifier>arg3 </span><span class=special>= </span><span class=identifier>argument</span><span class=special><</span><span class=number>2</span><span class=special>>();
|
||||
</span><span class=special>...
|
||||
</span><span class=identifier>actor</span><span class=special><</span><span class=identifier>argument</span><span class=special><</span><span class=identifier>N</span><span class=special>> </span><span class=special>> </span><span class=keyword>const </span><span class=identifier>argN </span><span class=special>= </span><span class=identifier>argument</span><span class=special><</span><span class=identifier>N</span><span class=special>>();
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
An argument is in itself an actor base class. As such, arguments can be evaluated through the actor's operator(). An argument as an actor base class selects the Nth argument from the arguments passed in by the client (see actor).</p>
|
||||
<p>
|
||||
For example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>char </span><span class=identifier>c </span><span class=special>= </span><span class=literal>'A'</span><span class=special>;
|
||||
</span><span class=keyword>int </span><span class=identifier>i </span><span class=special>= </span><span class=number>123</span><span class=special>;
|
||||
</span><span class=keyword>const </span><span class=keyword>char</span><span class=special>* </span><span class=identifier>s </span><span class=special>= </span><span class=string>"Hello World"</span><span class=special>;
|
||||
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>arg1</span><span class=special>(</span><span class=identifier>c</span><span class=special>) </span><span class=special><< </span><span class=literal>' '</span><span class=special>; </span><span class=comment>// Get the 1st argument of unnamed_f(c)
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>arg1</span><span class=special>(</span><span class=identifier>i</span><span class=special>, </span><span class=identifier>s</span><span class=special>) </span><span class=special><< </span><span class=literal>' '</span><span class=special>; </span><span class=comment>// Get the 1st argument of unnamed_f(i, s)
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>arg2</span><span class=special>(</span><span class=identifier>i</span><span class=special>, </span><span class=identifier>s</span><span class=special>) </span><span class=special><< </span><span class=literal>' '</span><span class=special>; </span><span class=comment>// Get the 2nd argument of unnamed_f(i, s)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
will print out "A 123 Hello World"</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="primitives.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="values.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
102
phoenix/doc/basic_concepts.html
Normal file
@@ -0,0 +1,102 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Basic Concepts</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="quick_start.html">
|
||||
<link rel="next" href="architecture.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Basic Concepts</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="quick_start.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="architecture.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Everything is a function (class actor) in the Phoenix framework that can be evaluated as f(a..n), where n is the function's arity, or number of arguments that the function expects. Operators are also functions. For example, a + b is just a function with arity == 2 (or binary). a + b is the same as plus(a, b), a + b + c is the same as plus(a, plus(b, c)). plus(a, plus(b, c)) is a ternary function (arity == 3).</p>
|
||||
<p>
|
||||
Amusingly, even functions return functions. We shall see what this means in a short while.</p>
|
||||
<p>
|
||||
Currying, named after the famous Logician <a href="http://www.haskell.org">
|
||||
Haskell</a> Curry, is one of the important mechanisms in the programming discipline known as functional programming (or FP). There's much theory surrounding the concepts behind it, however, in the most simplest term, it is safe to assume that "currying" a function is more or less like partially evaluating a function. Take a simple pseudo C++ function:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus</span><span class=special>(</span><span class=identifier>x</span><span class=special>, </span><span class=identifier>y</span><span class=special>) </span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>x </span><span class=special>+ </span><span class=identifier>y</span><span class=special>; </span><span class=special>}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
for example. Fully evaluating the function 'plus' above is done by supplying the arguments for x and y. For example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus</span><span class=special>(</span><span class=number>3</span><span class=special>, </span><span class=number>2</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
will give us 5. On the other hand, partial evaluation can be thought of as calling the function without supplying all the arguments. Here's an imaginary (non-C++) example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus</span><span class=special>(?, </span><span class=number>6</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
What does this mean and what is the function's result? First, the question mark proclaims that we don't have this argument yet, let this be supplied later. We have the second argument though, which is 6. Now, while the fully evaluated function plus(3, 2) results to the actual computed value 5, the partially evaluated function plus(?, 6) results to another (unnamed) function (A higher order function. In FP, the unnamed function is called a lambda function), this time, the lambda function expects one less argument:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus</span><span class=special>(</span><span class=number>3</span><span class=special>, </span><span class=number>2</span><span class=special>) </span><span class=special>--> </span><span class=number>5
|
||||
</span><span class=identifier>plus</span><span class=special>(?, </span><span class=number>6</span><span class=special>) </span><span class=special>--> </span><span class=identifier>unnamed_f_x_plus_6</span><span class=special>(</span><span class=identifier>x</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
now, we can use unnamed_f_x_plus_6, which is the result of the expression plus(?, 6) just like a function with one argument. Thus:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus</span><span class=special>(?, </span><span class=number>6</span><span class=special>)(</span><span class=number>3</span><span class=special>) </span><span class=special>--> </span><span class=number>9
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
This can be understood as:</p>
|
||||
<code><pre>
|
||||
<span class=special>| </span><span class=identifier>plus</span><span class=special>(?, </span><span class=number>6</span><span class=special>) </span><span class=special>| </span><span class=special>(</span><span class=number>3</span><span class=special>) </span><span class=special>|
|
||||
</span><span class=special>|</span><span class=identifier>_____f1_____</span><span class=special>| </span><span class=special>|
|
||||
</span><span class=special>|</span><span class=identifier>_____f2___________</span><span class=special>|
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<ul><li>f1 is the result of partially evaluating plus(?, 6)</li><li>f2 is the result of the fully evaluated function passing 3 where f1 has the ? placeholder, thus plus(3, 6)</li></ul><p>
|
||||
The same can be done with operators. For instance, the above example is equivalent to:</p>
|
||||
<code><pre>
|
||||
<span class=number>3 </span><span class=special>+ </span><span class=number>2 </span><span class=special>--> </span><span class=number>5
|
||||
</span><span class=special>? </span><span class=special>+ </span><span class=number>6 </span><span class=special>--> </span><span class=identifier>unnamed_f_x_plus_6</span><span class=special>(</span><span class=identifier>x</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Obviously, partially evaluating the plus function as we see above cannot be done directly in C++ where we are expected to supply all the arguments that a function expects. Simply, currying the function plus is not possible in straight C++. That's where the Phoenix framework comes in. The framework provides the facilities to do partial function evaluation.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="quick_start.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="architecture.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
222
phoenix/doc/binders.html
Normal file
@@ -0,0 +1,222 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Binders</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="statements.html">
|
||||
<link rel="next" href="adaptable_closures.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Binders</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="statements.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="adaptable_closures.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
There are times when it is desireable to bind a simple functor, function, member function or member variable for deferred evaluation. This can be done through the binding facilities provided below. There are template classes:</p>
|
||||
<ol><li>function_ptr ( function pointer binder )</li><li>functor ( functor pointer binder )</li><li>member_function_ptr ( member function pointer binder )</li><li>member_var_ptr ( member variable pointer binder )</li></ol><p>
|
||||
These template classes are specialized lazy function classes for functors, function pointers, member function pointers and member variable pointers, respectively. These are subclasses of the lazy- function class (see functions). Each of these has a corresponding overloaded bind(x) function. Each bind(x) function generates a suitable binder object.</p>
|
||||
<p>
|
||||
Example, given a function foo:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>void </span><span class=identifier>foo_</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>n</span><span class=special>) </span><span class=special>{ </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>n </span><span class=special><< </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>; </span><span class=special>}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Here's how the function foo is bound:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>bind</span><span class=special>(&</span><span class=identifier>foo_</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
This bind expression results to a lazy-function (see functions) that is lazily evaluated. This bind expression is also equivalent to:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>function_ptr</span><span class=special><</span><span class=keyword>void</span><span class=special>, </span><span class=keyword>int</span><span class=special>> </span><span class=identifier>foo </span><span class=special>= </span><span class=special>&</span><span class=identifier>foo_</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
The template parameter of the function_ptr is the return and argument types of actual signature of the function to be bound read from left to right. Examples:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>void </span><span class=identifier>foo_</span><span class=special>(</span><span class=keyword>int</span><span class=special>); </span><span class=special>---> </span><span class=identifier>function_ptr</span><span class=special><</span><span class=keyword>void</span><span class=special>, </span><span class=keyword>int</span><span class=special>>
|
||||
</span><span class=keyword>int </span><span class=identifier>bar_</span><span class=special>(</span><span class=keyword>double</span><span class=special>, </span><span class=keyword>int</span><span class=special>); </span><span class=special>---> </span><span class=identifier>function_ptr</span><span class=special><</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>double</span><span class=special>, </span><span class=keyword>int</span><span class=special>>
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Either bind(&foo_) and its equivalent foo can now be used in the same way a lazy function (see functions) is used:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>bind</span><span class=special>(&</span><span class=identifier>foo_</span><span class=special>)(</span><span class=identifier>arg1</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
or</p>
|
||||
<code><pre>
|
||||
<span class=identifier>foo</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
The latter, of course, follows C/C++ function call syntax and is much easier to understand. This is now a full-fledged lazy function that can finally be evaluated by another function call invocation. A second function call will invoke the actual foo function:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>int </span><span class=identifier>i </span><span class=special>= </span><span class=number>4</span><span class=special>;
|
||||
</span><span class=identifier>foo</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>)(</span><span class=identifier>i</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
will print out "4".</p>
|
||||
<p>
|
||||
Binding functors and member functions can be done similarly. Here's how to bind a functor (e.g. std::plus<int>):</p>
|
||||
<code><pre>
|
||||
<span class=identifier>bind</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>plus</span><span class=special><</span><span class=keyword>int</span><span class=special>>())
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
or</p>
|
||||
<code><pre>
|
||||
<span class=identifier>functor</span><span class=special><</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>plus</span><span class=special><</span><span class=keyword>int</span><span class=special>> </span><span class=special>> </span><span class=identifier>plus</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Again, these are full-fledged lazy functions. In this case, unlike the first example, expect 2 arguments (std::plus<int> needs two arguments lhs and rhs). Either or both of which can be lazily bound:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg2</span><span class=special>) </span><span class=comment>// arg1 + arg2
|
||||
</span><span class=identifier>plus</span><span class=special>(</span><span class=number>100</span><span class=special>, </span><span class=identifier>arg1</span><span class=special>) </span><span class=comment>// 100 + arg1
|
||||
</span><span class=identifier>plus</span><span class=special>(</span><span class=number>100</span><span class=special>, </span><span class=number>200</span><span class=special>) </span><span class=comment>// 300
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
A bound member function takes in a pointer or reference to an object as the first argument. For instance, given:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>xyz </span><span class=special>{ </span><span class=keyword>void </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>int</span><span class=special>) </span><span class=keyword>const</span><span class=special>; </span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
xyz's foo member function can be bound as:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>bind</span><span class=special>(&</span><span class=identifier>xyz</span><span class=special>::</span><span class=identifier>foo</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
or</p>
|
||||
<p>
|
||||
member_function_ptr<void, xyz, int> xyz_foo = &xyz::foo;</p>
|
||||
<p>
|
||||
The template parameter of the member_function_ptr is the return, class and argument types of actual signature of the function to be bound, read from left to right:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>void </span><span class=identifier>xyz</span><span class=special>::</span><span class=identifier>foo_</span><span class=special>(</span><span class=keyword>int</span><span class=special>); </span><span class=special>---> </span><span class=identifier>member_function_ptr</span><span class=special><</span><span class=keyword>void</span><span class=special>, </span><span class=identifier>xyz</span><span class=special>, </span><span class=keyword>int</span><span class=special>>
|
||||
</span><span class=keyword>int </span><span class=identifier>abc</span><span class=special>::</span><span class=identifier>bar_</span><span class=special>(</span><span class=keyword>double</span><span class=special>, </span><span class=keyword>char</span><span class=special>); </span><span class=special>---> </span><span class=identifier>member_function_ptr</span><span class=special><</span><span class=keyword>int</span><span class=special>, </span><span class=identifier>abc</span><span class=special>, </span><span class=keyword>int</span><span class=special>, </span><span class=keyword>double</span><span class=special>, </span><span class=keyword>char</span><span class=special>>
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Take note that a member_function_ptr lazy-function expects the first argument to be a pointer or reference to an object. Both the object (reference or pointer) and the arguments can be lazily bound. Examples:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>xyz </span><span class=identifier>obj</span><span class=special>;
|
||||
</span><span class=identifier>xyz_foo</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg2</span><span class=special>) </span><span class=comment>// arg1.foo(arg2)
|
||||
</span><span class=identifier>xyz_foo</span><span class=special>(</span><span class=identifier>obj</span><span class=special>, </span><span class=identifier>arg1</span><span class=special>) </span><span class=comment>// obj.foo(arg1)
|
||||
</span><span class=identifier>xyz_foo</span><span class=special>(</span><span class=identifier>obj</span><span class=special>, </span><span class=number>100</span><span class=special>) </span><span class=comment>// obj.foo(100)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Be reminded that var(obj) must be used to call non-const member functions. For example, if xyz was declared as:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>xyz </span><span class=special>{ </span><span class=keyword>void </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>int</span><span class=special>); </span><span class=special>}; </span><span class=comment>// note non-const member function
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
the pointer or reference to the object must also be non-const since lazily bound arguments are stored as const value by default (see variable class in primitives).</p>
|
||||
<code><pre>
|
||||
<span class=identifier>xyz_foo</span><span class=special>(</span><span class=identifier>var</span><span class=special>(</span><span class=identifier>obj</span><span class=special>), </span><span class=number>100</span><span class=special>) </span><span class=comment>// obj.foo(100)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
arg1..argN are already implicitly mutable. There is no need to wrap arg1..argN in a var. It is an error to do so:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>var</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>) </span><span class=comment>// ERROR! arg1 is already mutable
|
||||
</span><span class=identifier>var</span><span class=special>(</span><span class=identifier>arg2</span><span class=special>) </span><span class=comment>// ERROR! arg2 is already mutable
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Finally, member variables can be bound much like member functions. For instance, given:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>xyz </span><span class=special>{ </span><span class=keyword>int </span><span class=identifier>v</span><span class=special>; </span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
xyz::v can be bound as:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>bind</span><span class=special>(&</span><span class=identifier>xyz</span><span class=special>::</span><span class=identifier>v</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
or</p>
|
||||
<code><pre>
|
||||
<span class=identifier>member_var_ptr</span><span class=special><</span><span class=keyword>int</span><span class=special>, </span><span class=identifier>xyz</span><span class=special>> </span><span class=identifier>xyz_v </span><span class=special>= </span><span class=special>&</span><span class=identifier>xyz</span><span class=special>::</span><span class=identifier>v</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
The template parameter of the member_var_ptr is the type of the variable followed by the class:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>int </span><span class=identifier>xyz</span><span class=special>::</span><span class=identifier>v</span><span class=special>; </span><span class=special>---> </span><span class=identifier>member_var_ptr</span><span class=special><</span><span class=keyword>int</span><span class=special>, </span><span class=identifier>xyz</span><span class=special>>
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Just like the member_function_ptr, member_var_ptr also expects the first argument to be a pointer or reference to an object. Both the object (reference or pointer) and the arguments can be lazily bound. Like member function binders, var(obj) must be used to access non-const member variables. Examples:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>xyz </span><span class=identifier>obj</span><span class=special>;
|
||||
</span><span class=identifier>xyz_v</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>) </span><span class=comment>// arg1.v (const& access)
|
||||
</span><span class=identifier>xyz_v</span><span class=special>(</span><span class=identifier>obj</span><span class=special>) </span><span class=comment>// obj.v (const& access)
|
||||
|
||||
</span><span class=identifier>xyz_v</span><span class=special>(</span><span class=identifier>var</span><span class=special>(</span><span class=identifier>obj</span><span class=special>))() </span><span class=special>= </span><span class=number>3 </span><span class=comment>// obj.v = 3 (non-const& access)
|
||||
</span><span class=identifier>xyz_v</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>)(</span><span class=identifier>obj</span><span class=special>) </span><span class=special>= </span><span class=number>4 </span><span class=comment>// obj.v = 4 (non-const& access)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Be reminded once more that binders are monomorphic. This layer is provided only for compatibility with existing code such as prewritten STL functors and legacy APIs. Rather than binding functions or functors, the preferred method is to write true generic and polymorphic lazy-functions (see functions). However, since most of the time we are dealing with adaptation of exisiting code, binders are indeed indespensible.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="statements.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="adaptable_closures.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
71
phoenix/doc/composites.html
Normal file
@@ -0,0 +1,71 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Composites</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="variables.html">
|
||||
<link rel="next" href="functions.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Composites</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="variables.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Actors may be combined in a multitude of ways to form composites. Composites are actors that are composed of zero or more actors. Composition is hierarchical. An element of the composite can be a primitive or again another composite. The flexibility to arbitrarily compose hierarchical structures allows us to form intricate constructions that model complex functions, statements and expressions.</p>
|
||||
<p>
|
||||
A composite is more or less a tuple of 0..N actors plus an operation object (some specialized composites have implied operations, i.e. the composite itself implies the operation). The composite class is declared informally as:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><
|
||||
</span><span class=keyword>typename </span><span class=identifier>OperationT</span><span class=special>,
|
||||
</span><span class=keyword>typename </span><span class=identifier>A0 </span><span class=special>= </span><span class=identifier>nil_t</span><span class=special>,
|
||||
</span><span class=keyword>typename </span><span class=identifier>A1 </span><span class=special>= </span><span class=identifier>nil_t</span><span class=special>,
|
||||
</span><span class=keyword>typename </span><span class=identifier>A2 </span><span class=special>= </span><span class=identifier>nil_t</span><span class=special>,
|
||||
</span><span class=special>...
|
||||
</span><span class=keyword>typename </span><span class=identifier>AN </span><span class=special>= </span><span class=identifier>nil_t
|
||||
</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>composite </span><span class=special>{
|
||||
|
||||
</span><span class=identifier>OperationT </span><span class=identifier>op</span><span class=special>; </span><span class=comment>// operation
|
||||
</span><span class=identifier>A0 </span><span class=identifier>a0</span><span class=special>; </span><span class=identifier>A1 </span><span class=identifier>a1</span><span class=special>; </span><span class=special>... </span><span class=identifier>AN </span><span class=identifier>an</span><span class=special>; </span><span class=comment>// actors
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
This can be recursive. As mentioned, each of the actors A0..AN can in turn be another composite since a composite is itself an actor superclass and conforms to its expected conceptual interface. Composite specializations are provided to handle different numbers of actors from zero (0) to a predefined maximum.</p>
|
||||
<p>
|
||||
Except for specialized composites, like the actor and unlike the primitives, the composite is a protocol class. A composite does not really know how to perform anything. The actual operation is handled by its actors and finally its operation 'op'. After it has received the arguments passed in by the actor (see actor), all of the arguments are broadcasted to all of the composite's actors for preprocessing. Each of the composite's actors in turn returns a result. These results are then transfered to the composite's operation 'op'.</p>
|
||||
<p>
|
||||
If this may seem confusing at first, don't fret. Further details will be provided later for those who are inclined to learn more about the framework inside out. However, such information is not at all required to use the framework. After all, composites are not created directly. Instead, some facilities are provided for the generation of composites. These generators are the front-ends. We have seen the var(x), the val(x) and the const_ref(x). These are really generators that create primitives. Likewise, we also have generators that create composites.</p>
|
||||
<p>
|
||||
Just think of composites as your backbone. You don't really have to scrutinize it to use it; it simply works. The composite is indeed the backbone of the Phoenix framework.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="variables.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
111
phoenix/doc/composites_revisited.html
Normal file
@@ -0,0 +1,111 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Composites revisited</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="actors_revisited.html">
|
||||
<link rel="next" href="operators_revisited.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Composites revisited</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="actors_revisited.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="operators_revisited.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
A composite is an actor base class composed of zero or more actors (see actor) and an operation. A composite is itself an actor superclass and conforms to its expected conceptual interface. Its eval member function un-funnels the tupled actual arguments by invoking each of the actors' eval member function. The results of each are then passed on as arguments to the operation. Specializations are provided for composites that handle different numbers of actors from zero to N, where N is a predefined maximum.</p>
|
||||
<p>
|
||||
Schematically:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>actor0</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>tupled_args</span><span class=special>) </span><span class=special>--> </span><span class=identifier>arg0 </span><span class=special>--> </span><span class=special>|
|
||||
</span><span class=identifier>actor1</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>tupled_args</span><span class=special>) </span><span class=special>--> </span><span class=identifier>arg1 </span><span class=special>--> </span><span class=special>|
|
||||
</span><span class=identifier>actor2</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>tupled_args</span><span class=special>) </span><span class=special>--> </span><span class=identifier>arg3 </span><span class=special>--> </span><span class=special>| </span><span class=special>--> </span><span class=identifier>operation</span><span class=special>(</span><span class=identifier>arg0</span><span class=special>...</span><span class=identifier>argN</span><span class=special>)
|
||||
</span><span class=special>... </span><span class=special>|
|
||||
</span><span class=identifier>actorN</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>tupled_args</span><span class=special>) </span><span class=special>--> </span><span class=identifier>argN </span><span class=special>--> </span><span class=special>|
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Here's a typical example of the composite's eval member function for a 2-actor composite:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>>
|
||||
</span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special><</span><span class=identifier>self_t</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>>::</span><span class=identifier>type
|
||||
</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>TupleT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>args</span><span class=special>) </span><span class=keyword>const
|
||||
</span><span class=special>{
|
||||
</span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special><</span><span class=identifier>A0</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>>::</span><span class=identifier>type </span><span class=identifier>r0 </span><span class=special>= </span><span class=identifier>a0</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>);
|
||||
</span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special><</span><span class=identifier>A1</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>>::</span><span class=identifier>type </span><span class=identifier>r1 </span><span class=special>= </span><span class=identifier>a1</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>);
|
||||
</span><span class=keyword>return </span><span class=identifier>op</span><span class=special>(</span><span class=identifier>r0</span><span class=special>, </span><span class=identifier>r1</span><span class=special>);
|
||||
</span><span class=special>}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
where self_t is the composite's 'self' type, TupleT 'args' is the tuple-packed arguments passed to the actor (see actor) and op is the operation associated with the composite. r0 and r1 are the actual arguments un-funneled from 'args' and pre-processed by the composite's actors which are then passed on to the operation 'op'.</p>
|
||||
<p>
|
||||
The operation can be any suitable functor that can accept the arguments passed in by the composite. The operation is expected to have a member operator() that carries out the actual operation. There should be a one to one correspondence between actors of the composite and the arguments of the operation's member operator().</p>
|
||||
<p>
|
||||
The operation is also expected to have a nested template class result<T0...TN>. The nested template class result should have a typedef 'type' that reflects the return type of its member operator(). This is essentially a type computer that answers the metaprogramming question "Given arguments of type T0...TN, what will be your operator()'s return type?". There is a special case for operations that accept no arguments. Such nullary operations are only required to define a typedef result_type that reflects the return type of its operator().</p>
|
||||
<p>
|
||||
Here's a view on what happens when the eval function is called:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>tupled </span><span class=identifier>arguments</span><span class=special>: </span><span class=identifier>args
|
||||
</span><span class=special>|
|
||||
</span><span class=special>+-------+-------+-------+-------+
|
||||
</span><span class=special>| </span><span class=special>| </span><span class=special>| </span><span class=special>| </span><span class=special>|
|
||||
</span><span class=special>| </span><span class=special>| </span><span class=special>| </span><span class=special>| </span><span class=special>|
|
||||
</span><span class=identifier>actors</span><span class=special>: </span><span class=identifier>actor0 </span><span class=identifier>actor1 </span><span class=identifier>actor2 </span><span class=identifier>actor3</span><span class=special>..</span><span class=identifier>actorN
|
||||
</span><span class=special>| </span><span class=special>| </span><span class=special>| </span><span class=special>| </span><span class=special>|
|
||||
</span><span class=special>| </span><span class=special>| </span><span class=special>| </span><span class=special>| </span><span class=special>|
|
||||
</span><span class=identifier>operation</span><span class=special>: </span><span class=identifier>op</span><span class=special>( </span><span class=identifier>arg0</span><span class=special>, </span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg2</span><span class=special>, </span><span class=identifier>arg3</span><span class=special>,...</span><span class=identifier>argN </span><span class=special>)
|
||||
</span><span class=special>|
|
||||
</span><span class=special>|
|
||||
</span><span class=identifier>returns</span><span class=special>: </span><span class=special>+---> </span><span class=identifier>operation</span><span class=special>::</span><span class=identifier>result</span><span class=special><</span><span class=identifier>T0</span><span class=special>...</span><span class=identifier>TN</span><span class=special>>::</span><span class=identifier>type
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Here's an example of a simple operation that squares a number:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>square </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>ArgT</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{ </span><span class=keyword>typedef </span><span class=identifier>ArgT </span><span class=identifier>type</span><span class=special>; </span><span class=special>};
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>ArgT</span><span class=special>>
|
||||
</span><span class=identifier>ArgT </span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>ArgT </span><span class=identifier>n</span><span class=special>) </span><span class=keyword>const </span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>n </span><span class=special>* </span><span class=identifier>n</span><span class=special>; </span><span class=special>}
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
This is a perfect example of a polymorphic functor discussed before in the section on functions. As we can see, operations are polymorphic. Its arguments and return type are not fixed to a particular type. The example above for example, can handle any ArgT type as long as it has a multiplication operator.</p>
|
||||
<p>
|
||||
Composites are not created directly. Instead, there are meta- programs provided that indirectly create composites. See operators, binders and functions for examples.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="actors_revisited.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="operators_revisited.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
60
phoenix/doc/efficiency.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Efficiency</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="lazy_construction_and_conversions.html">
|
||||
<link rel="next" href="inside_phoenix.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Efficiency</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="lazy_construction_and_conversions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="inside_phoenix.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Now this is important. Operators that form expressions and statements, while truly expressive, should be used judiciously and sparingly. While aggressive compiler optimizations and inline code helps a lot to produce tighter and faster code, lazy operators and statements will always have more overhead compared to lazy- functions and bound simple functors especially when the logic gets to be quite complex. It is not only run-time code that hits a penalty, complex expressions involving lazy-operators and lazy- functions are also much more difficult to parse and compile by the host C++ compiler and results in much longer compile times.</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/bulb.gif">
|
||||
<b>Lambda vs. Offline Functions</b><br><br>The best way to use the framework is to write generic off-line lazy functions (see functions) then call these functions lazily using straight-forward inline lazy-operators and lazy-statements. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
While it is indeed satisfying to impress others with quite esoteric uses of operator overloading and generative programming as can be done by lazy-operators and lazy-statements, these tools are meant to be used for the right job. That said, caveat-emptor.</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/note.gif">
|
||||
need benchmarks, benchmarks, and more benchmarks </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="lazy_construction_and_conversions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="inside_phoenix.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
109
phoenix/doc/functions.html
Normal file
@@ -0,0 +1,109 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Functions</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="composites.html">
|
||||
<link rel="next" href="operators.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Functions</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="composites.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="operators.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<a name="lazy_functions"></a><h2>Lazy functions</h2><p>
|
||||
This class provides a mechanism for lazily evaluating functions. Syntactically, a lazy function looks like an ordinary C/C++ function. The function call looks familiar and feels the same as ordinary C++ functions. However, unlike ordinary functions, the actual function execution is deferred. For example here are sample factorial function calls:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>factorial</span><span class=special>(</span><span class=number>4</span><span class=special>)
|
||||
</span><span class=identifier>factorial</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>)
|
||||
</span><span class=identifier>factorial</span><span class=special>(</span><span class=identifier>arg1 </span><span class=special>* </span><span class=number>6 </span><span class=special>/ </span><span class=identifier>factorial</span><span class=special>(</span><span class=identifier>var</span><span class=special>(</span><span class=identifier>i</span><span class=special>)))
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
These functions are automatically lazily bound unlike ordinary function pointers or functor objects that need to be explicitly bound through the bind function (see binders).</p>
|
||||
<p>
|
||||
A lazy function works in conjunction with a user defined functor (as usual with a member operator()). Only special forms of functor objects are allowed. This is required to enable true polymorphism (STL style monomorphic functors and function pointers can still be used through the bind facility (see binders)).</p>
|
||||
<p>
|
||||
This special functor is expected to have a nested template class result<T0...TN> (where N is the number of arguments of its member operator()). The nested template class result should have a typedef 'type' that reflects the return type of its member operator(). This is essentially a type computer that answers the metaprogramming question "Given arguments of type T0...TN, what will be the functor operator()'s return type?".</p>
|
||||
<p>
|
||||
There is a special case for functors that accept no arguments. Such nullary functors are only required to define a typedef result_type that reflects the return type of its operator().</p>
|
||||
<p>
|
||||
Here's an example of a simple functor that computes the factorial of a number:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>factorial_impl </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>Arg</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{ </span><span class=keyword>typedef </span><span class=identifier>Arg </span><span class=identifier>type</span><span class=special>; </span><span class=special>};
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>Arg</span><span class=special>>
|
||||
</span><span class=identifier>Arg </span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>Arg </span><span class=identifier>n</span><span class=special>) </span><span class=keyword>const
|
||||
</span><span class=special>{ </span><span class=keyword>return </span><span class=special>(</span><span class=identifier>n </span><span class=special><= </span><span class=number>0</span><span class=special>) </span><span class=special>? </span><span class=number>1 </span><span class=special>: </span><span class=identifier>n </span><span class=special>* </span><span class=keyword>this</span><span class=special>-></span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>n</span><span class=special>-</span><span class=number>1</span><span class=special>); </span><span class=special>}
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
As can be seen, the functor is polymorphic. Its arguments and return type are not fixed to a particular type. The example above for example, can handle any type as long as it can carry out the required operations (i.e. <=, * and -).</p>
|
||||
<p>
|
||||
We can now declare and instantiate a lazy 'factorial' function:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>function</span><span class=special><</span><span class=identifier>factorial_impl</span><span class=special>> </span><span class=identifier>factorial</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Invoking a lazy function 'factorial' does not immediately execute the functor factorial_impl. Instead, a composite object is created and returned to the caller. Example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>factorial</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
does nothing more than return a composite. A second function call will invoke the actual factorial function. Example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>int </span><span class=identifier>i </span><span class=special>= </span><span class=number>4</span><span class=special>;
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>factorial</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>)(</span><span class=identifier>i</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
will print out "24".</p>
|
||||
<p>
|
||||
Take note that in certain cases (e.g. for functors with state), an instance of the functor may be passed on to the constructor. Example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>function</span><span class=special><</span><span class=identifier>factorial_impl</span><span class=special>> </span><span class=identifier>factorial</span><span class=special>(</span><span class=identifier>ftor</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
where ftor is an instance of factorial_impl (this is not necessary in this case since factorial is a simple stateless functor). Take care though when using functors with state because the functors are taken in by value. It is best to keep the data manipulated by a functor outside the functor itself and keep a reference to this data inside the functor. Also, it is best to keep functors as small as possible.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="composites.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="operators.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
45
phoenix/doc/inside_phoenix.html
Normal file
@@ -0,0 +1,45 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Inside Phoenix</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="efficiency.html">
|
||||
<link rel="next" href="tuples.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Inside Phoenix</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="efficiency.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="tuples.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
This chapter explains in more detail how the framework operates. The information henceforth should not be necessary to those who are interested in just using the framework. However, a microscopic view might prove to be beneficial to more advanced programmers. But then again, it is really hard to classify what it means to be an "advanced programmer". Is knowledge of the C++ language as a language lawyer a prerequisite? Perhaps, but also perhaps not. As always, the information presented will always assume a friendly tone. Perhaps the prerequisite here is that the reader should have an "advanced imagination" <img src="theme/smiley.gif">
|
||||
and a decent knowledge of C++ language rules.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="efficiency.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="tuples.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
462
phoenix/doc/interfacing.html
Normal file
@@ -0,0 +1,462 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Interfacing</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="operators_revisited.html">
|
||||
<link rel="next" href="wrap_up.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Interfacing</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="operators_revisited.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="wrap_up.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
The modular design of Phoenix makes it extremely extensible. We have seen that layer upon layer, the whole framework is built on solid foundation. There are only a few simple well designed concepts that are laid out like bricks. Overall the framework is designed to be extended. Everything above the composite and primitives can in fact be considered just as extensions to the framework. This modular design was inherited from the <a href="http://spirit.sourceforge.net">
|
||||
Spirit</a> inline parser framework.</p>
|
||||
<p>
|
||||
Extension is non-intrusive. And, whenever a component or module is extended, the new extension automatically becomes a first class citizen and is automatically recognized by all modules and components in the framework. There are a multitude of ways in which a module is extended.</p>
|
||||
<p>
|
||||
1) Write and deploy a new primitive:</p>
|
||||
<p>
|
||||
So far we have presented only a few primitives 1) arguments 2) values and 3) variables. For the sake of illustration, let us write a simple primitive extension. Let us call it static_int. It shall be parameterized by an integer value. It is like a static version of the the value<int> class, but since it is static, holds no data at all. The integer is encoded in its type. Here is the complete class (sample5.cpp):</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>int </span><span class=identifier>N</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>static_int </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{ </span><span class=keyword>typedef </span><span class=keyword>int </span><span class=identifier>type</span><span class=special>; </span><span class=special>};
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>>
|
||||
</span><span class=keyword>int </span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>TupleT </span><span class=keyword>const</span><span class=special>&) </span><span class=keyword>const </span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>N</span><span class=special>; </span><span class=special>}
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
That's it. Done! Now we can use this as it is already a full- fledged Phoenix citizen due to interface conformance. Let us write a suitable generator to make it easier to use our static_int. Remember that it should be wrapped as an actor before it can be used. Let us call our generator int_const:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>int </span><span class=identifier>N</span><span class=special>>
|
||||
</span><span class=identifier>phoenix</span><span class=special>::</span><span class=identifier>actor</span><span class=special><</span><span class=identifier>static_int</span><span class=special><</span><span class=identifier>N</span><span class=special>> </span><span class=special>>
|
||||
</span><span class=identifier>int_const</span><span class=special>()
|
||||
</span><span class=special>{
|
||||
</span><span class=keyword>return </span><span class=identifier>static_int</span><span class=special><</span><span class=identifier>N</span><span class=special>>();
|
||||
</span><span class=special>}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Now we are done. Let's use it:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>cout </span><span class=special><< </span><span class=special>(</span><span class=identifier>int_const</span><span class=special><</span><span class=number>5</span><span class=special>>() </span><span class=special>+ </span><span class=identifier>int_const</span><span class=special><</span><span class=number>6</span><span class=special>>())() </span><span class=special><< </span><span class=identifier>endl</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Prints out "11". There are lots of things you can do with this form of extension. For instance, data type casts come to mind. Example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>lazy_cast</span><span class=special><</span><span class=identifier>T</span><span class=special>>(</span><span class=identifier>some_lazy_expression</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
2) Write and deploy a new composite:</p>
|
||||
<p>
|
||||
This is more complicated than our first example (writing a primitive). Nevertheless, once you get the basics, writing a composite is almost mechanical and boring (read: easy <img src="theme/smiley.gif">
|
||||
. Check out statements.hpp. All the lazy statements are written in terms of the composite interface.</p>
|
||||
<p>
|
||||
Ok, let's get on with it. Recall that the if_ else_ lazy statement (and all statements for that matter) return void. What's missing, and will surely be useful, is something like C/C++'s "cond ? a : b" expression. It is really unfortunate that C++ fell short of allowing this to be overloaded. Sigh. Anyway here's the code (sample6.cpp):</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>CondT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TrueT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>FalseT</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>if_else_composite </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=identifier>if_else_composite</span><span class=special><</span><span class=identifier>CondT</span><span class=special>, </span><span class=identifier>TrueT</span><span class=special>, </span><span class=identifier>FalseT</span><span class=special>> </span><span class=identifier>self_t</span><span class=special>;
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>higher_rank</span><span class=special><
|
||||
</span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special><</span><span class=identifier>TrueT</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>>::</span><span class=identifier>plain_type</span><span class=special>,
|
||||
</span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special><</span><span class=identifier>FalseT</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>>::</span><span class=identifier>plain_type
|
||||
</span><span class=special>>::</span><span class=identifier>type </span><span class=identifier>type</span><span class=special>;
|
||||
</span><span class=special>};
|
||||
|
||||
</span><span class=identifier>if_else_composite</span><span class=special>(
|
||||
</span><span class=identifier>CondT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>cond_</span><span class=special>, </span><span class=identifier>TrueT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>true__</span><span class=special>, </span><span class=identifier>FalseT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>false__</span><span class=special>)
|
||||
</span><span class=special>: </span><span class=identifier>cond</span><span class=special>(</span><span class=identifier>cond_</span><span class=special>), </span><span class=identifier>true_</span><span class=special>(</span><span class=identifier>true__</span><span class=special>), </span><span class=identifier>false_</span><span class=special>(</span><span class=identifier>false__</span><span class=special>) </span><span class=special>{}
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>>
|
||||
</span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special><</span><span class=identifier>self_t</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>>::</span><span class=identifier>type
|
||||
</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>TupleT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>args</span><span class=special>) </span><span class=keyword>const
|
||||
</span><span class=special>{
|
||||
</span><span class=keyword>return </span><span class=identifier>cond</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>) </span><span class=special>? </span><span class=identifier>true_</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>) </span><span class=special>: </span><span class=identifier>false_</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>);
|
||||
</span><span class=special>}
|
||||
|
||||
</span><span class=identifier>CondT </span><span class=identifier>cond</span><span class=special>; </span><span class=identifier>TrueT </span><span class=identifier>true_</span><span class=special>; </span><span class=identifier>FalseT </span><span class=identifier>false_</span><span class=special>; </span><span class=comment>// actors
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Ok, this is quite a mouthfull. Let's digest this piecemeal.</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>CondT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TrueT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>FalseT</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>if_else_composite </span><span class=special>{
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
This is basically a specialized composite that has 3 actors. It has no operation since it is implied. The 3 actors are cond (condition of type CondT) true_ (the true branch of type TrueT), false_ the (false branch or type FalseT).</p>
|
||||
<code><pre>
|
||||
<span class=keyword>typedef </span><span class=identifier>if_else_composite</span><span class=special><</span><span class=identifier>CondT</span><span class=special>, </span><span class=identifier>TrueT</span><span class=special>, </span><span class=identifier>FalseT</span><span class=special>> </span><span class=identifier>self_t</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
self_t is a typedef that declares its own type: "What am I?"</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>higher_rank</span><span class=special><
|
||||
</span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special><</span><span class=identifier>TrueT</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>>::</span><span class=identifier>plain_type</span><span class=special>,
|
||||
</span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special><</span><span class=identifier>FalseT</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>>::</span><span class=identifier>plain_type
|
||||
</span><span class=special>>::</span><span class=identifier>type </span><span class=identifier>type</span><span class=special>;
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
We have seen result before. For actor base-classes such as composites and primitives, the parameter is a TupleT, i.e. the tupled arguments passed in from the actor.</p>
|
||||
<p>
|
||||
So given some arguments, what will be our return type? TrueT and FalseT are also actors remember? So first, we should ask them "What are your *plain* (stripped from references) return types?"</p>
|
||||
<p>
|
||||
Knowing that, our task is then to know which type has a higher rank (recall rank<T> and higher_rank<T0, T1>). Why do we have to do this? We are emulating the behavior of the "cond ? a : b" expression. In C/C++, the type of this expression is the one (a or b) with the higher rank. For example, if a is an int and b is a double, the result should be a double.</p>
|
||||
<p>
|
||||
Following this, finally, we have a return type typedef'd by result<TupleT>::type.</p>
|
||||
<code><pre>
|
||||
<span class=identifier>if_else_composite</span><span class=special>(
|
||||
</span><span class=identifier>CondT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>cond_</span><span class=special>, </span><span class=identifier>TrueT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>true__</span><span class=special>, </span><span class=identifier>FalseT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>false__</span><span class=special>)
|
||||
</span><span class=special>: </span><span class=identifier>cond</span><span class=special>(</span><span class=identifier>cond_</span><span class=special>), </span><span class=identifier>true_</span><span class=special>(</span><span class=identifier>true__</span><span class=special>), </span><span class=identifier>false_</span><span class=special>(</span><span class=identifier>false__</span><span class=special>) </span><span class=special>{}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
This is our constructor. We just stuff the constructor arguments into our member variables.</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>TupleT</span><span class=special>>
|
||||
</span><span class=keyword>typename </span><span class=identifier>actor_result</span><span class=special><</span><span class=identifier>self_t</span><span class=special>, </span><span class=identifier>TupleT</span><span class=special>>::</span><span class=identifier>type
|
||||
</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>TupleT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>args</span><span class=special>) </span><span class=keyword>const
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Now, here is our main eval member function. Given a self_t, our type, and the TupleT, the return type deduction is almost canonical. Just ask actor_result, it'll surely know.</p>
|
||||
<code><pre>
|
||||
<span class=special>{
|
||||
</span><span class=keyword>return </span><span class=identifier>cond</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>) </span><span class=special>? </span><span class=identifier>true_</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>) </span><span class=special>: </span><span class=identifier>false_</span><span class=special>.</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>args</span><span class=special>);
|
||||
</span><span class=special>}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
We pass the tupled args to all of our actors: cond, args and args appropriately. Notice how this expression reflects the C/C++ version almost to the letter.</p>
|
||||
<p>
|
||||
Well that's it. Now let's write a generator for this composite:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>CondT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TrueT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>FalseT</span><span class=special>>
|
||||
</span><span class=identifier>actor</span><span class=special><</span><span class=identifier>if_else_composite</span><span class=special><
|
||||
</span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>CondT</span><span class=special>>::</span><span class=identifier>type</span><span class=special>,
|
||||
</span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>TrueT</span><span class=special>>::</span><span class=identifier>type</span><span class=special>,
|
||||
</span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>FalseT</span><span class=special>>::</span><span class=identifier>type</span><span class=special>> </span><span class=special>>
|
||||
</span><span class=identifier>if_else_</span><span class=special>(</span><span class=identifier>CondT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>cond</span><span class=special>, </span><span class=identifier>TrueT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>true_</span><span class=special>, </span><span class=identifier>FalseT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>false_</span><span class=special>)
|
||||
</span><span class=special>{
|
||||
</span><span class=keyword>typedef </span><span class=identifier>if_else_composite</span><span class=special><
|
||||
</span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>CondT</span><span class=special>>::</span><span class=identifier>type</span><span class=special>,
|
||||
</span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>TrueT</span><span class=special>>::</span><span class=identifier>type</span><span class=special>,
|
||||
</span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>FalseT</span><span class=special>>::</span><span class=identifier>type</span><span class=special>>
|
||||
</span><span class=identifier>result</span><span class=special>;
|
||||
|
||||
</span><span class=keyword>return </span><span class=identifier>result</span><span class=special>(
|
||||
</span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>CondT</span><span class=special>>::</span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>cond</span><span class=special>),
|
||||
</span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>TrueT</span><span class=special>>::</span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>true_</span><span class=special>),
|
||||
</span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>FalseT</span><span class=special>>::</span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>false_</span><span class=special>));
|
||||
</span><span class=special>}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Now this should be trivial to explain. I hope. Again, let's digest this piecemeal.</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>CondT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TrueT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>FalseT</span><span class=special>>
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Again, there are three elements involved: The CondT condition 'cond', the TrueT true branch 'true_, and the FalseT false branch 'false_'.</p>
|
||||
<code><pre>
|
||||
<span class=identifier>actor</span><span class=special><</span><span class=identifier>if_else_composite</span><span class=special><
|
||||
</span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>CondT</span><span class=special>>::</span><span class=identifier>type</span><span class=special>,
|
||||
</span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>TrueT</span><span class=special>>::</span><span class=identifier>type</span><span class=special>,
|
||||
</span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>FalseT</span><span class=special>>::</span><span class=identifier>type</span><span class=special>> </span><span class=special>>
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
This is our target. We want to generate this actor. Now, given our arguments (cond, true_ and false_), we are not really sure if they are really actors. What if the user passes the boolean true as the cond? Surely, that has to be converted to an actor<value<bool> >, otherwise Phoenix will go berzerk and will not be able to accommodate this alien.</p>
|
||||
<code><pre>
|
||||
<span class=identifier>as_actor</span><span class=special><</span><span class=identifier>T</span><span class=special>>::</span><span class=identifier>type
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
is just what we need. This type computer converts from an arbitrary type T to a full-fledged actor citizen.</p>
|
||||
<code><pre>
|
||||
<span class=identifier>if_else_</span><span class=special>(</span><span class=identifier>CondT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>cond</span><span class=special>, </span><span class=identifier>TrueT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>true_</span><span class=special>, </span><span class=identifier>FalseT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>false_</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
These are the arguments to our generator 'if_else_'.</p>
|
||||
<code><pre>
|
||||
<span class=keyword>typedef </span><span class=identifier>if_else_composite</span><span class=special><
|
||||
</span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>CondT</span><span class=special>>::</span><span class=identifier>type</span><span class=special>,
|
||||
</span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>TrueT</span><span class=special>>::</span><span class=identifier>type</span><span class=special>,
|
||||
</span><span class=keyword>typename </span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>FalseT</span><span class=special>>::</span><span class=identifier>type</span><span class=special>>
|
||||
</span><span class=identifier>result</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Same as before, this is our target return type, this time stripped off the actor. That's OK because the actor<T> has a constructor that takes in a BaseT object: 'result' in this case.</p>
|
||||
<code><pre>
|
||||
<span class=keyword>return </span><span class=identifier>result</span><span class=special>(
|
||||
</span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>CondT</span><span class=special>>::</span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>cond</span><span class=special>),
|
||||
</span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>TrueT</span><span class=special>>::</span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>true_</span><span class=special>),
|
||||
</span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>FalseT</span><span class=special>>::</span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>false_</span><span class=special>));
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Finally, we construct and return our result. Notice how we called the as_actor<T>::convert static function to do the conversion from T to a full-fledged actor for each of the arguments.</p>
|
||||
<p>
|
||||
At last. Now we can use our brand new composite and its generator:</p>
|
||||
<code><pre>
|
||||
<span class=comment>// Print all contents of an STL container c and
|
||||
// prefix " is odd" or " is even" appropriately.
|
||||
|
||||
</span><span class=identifier>for_each</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),
|
||||
</span><span class=identifier>cout
|
||||
</span><span class=special><< </span><span class=identifier>arg1
|
||||
</span><span class=special><< </span><span class=identifier>if_else_</span><span class=special>(</span><span class=identifier>arg1 </span><span class=special>% </span><span class=number>2 </span><span class=special>== </span><span class=number>1</span><span class=special>, </span><span class=string>" is odd"</span><span class=special>, </span><span class=string>" is even"</span><span class=special>)
|
||||
</span><span class=special><< </span><span class=identifier>val</span><span class=special>(</span><span class=literal>'\n'</span><span class=special>)
|
||||
</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
3) Write an as_actor<T> converter for a specific type:</p>
|
||||
<p>
|
||||
By default, an unknown type T is converted to an actor<value<T> >. Say we just wrote a special primitive my_lazy_class following example 1. Whenever we have an object of type my_class, we want to convert this to a my_lazy_class automatically.</p>
|
||||
<p>
|
||||
as_actor<T> is Phoenix's type converter. All facilities that need to convert from an unknown type to an actor passes through this class. Specializing as_actor<T> for my_class is just what we need. For example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><>
|
||||
</span><span class=keyword>struct </span><span class=identifier>as_actor</span><span class=special><</span><span class=identifier>my_class</span><span class=special>> </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=identifier>actor</span><span class=special><</span><span class=identifier>my_lazy_class</span><span class=special>> </span><span class=identifier>type</span><span class=special>;
|
||||
</span><span class=keyword>static </span><span class=identifier>type </span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>my_class </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>x</span><span class=special>)
|
||||
</span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>my_lazy_class</span><span class=special>(</span><span class=identifier>x</span><span class=special>); </span><span class=special>}
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
For reference, here is the main is_actor<T> interface:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>T</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>as_actor </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=special>??? </span><span class=identifier>type</span><span class=special>;
|
||||
</span><span class=keyword>static </span><span class=identifier>type </span><span class=identifier>convert</span><span class=special>(</span><span class=identifier>T </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>x</span><span class=special>);
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
where ??? is the actor type returned by the static convert function. By default, this is:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>typedef </span><span class=identifier>value</span><span class=special><</span><span class=identifier>T</span><span class=special>> </span><span class=identifier>type</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
4) Write a specialized overloaded operator for a specific type:</p>
|
||||
<p>
|
||||
Consider the handling of operator << std::ostream such as cout. When we see an expression such as:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>cout </span><span class=special><< </span><span class=string>"Hello World\n"
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
the operator overload actually takes in cout by reference, modifies it and returns the same cout again by reference. This does not conform to the standard behavior of the shift left operator for built-in ints.</p>
|
||||
<p>
|
||||
In such cases, we can provide a specialized overload for this to work as a lazy-operator in expressions such as "cout << arg1 << arg2;" where the operatior behavior deviates from the standard operator:</p>
|
||||
<ol><li>std::ostream is taken as the LHS by reference</li><li>std::ostream is converted to an actor<variable<std::ostream> > instead of the default actor<value<std::ostream> >.</li></ol><p>
|
||||
We supply a special overload then (see special_ops.hpp):</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>BaseT</span><span class=special>>
|
||||
</span><span class=identifier>actor</span><span class=special><</span><span class=identifier>composite</span><span class=special><
|
||||
</span><span class=identifier>shift_l_op</span><span class=special>, </span><span class=comment>// an operator tag
|
||||
</span><span class=identifier>variable</span><span class=special><</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>>, </span><span class=comment>// an actor LHS
|
||||
</span><span class=identifier>actor</span><span class=special><</span><span class=identifier>BaseT</span><span class=special>>, </span><span class=comment>// an actor RHS
|
||||
</span><span class=special>> </span><span class=special>>
|
||||
</span><span class=keyword>operator</span><span class=special><<(
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>& </span><span class=identifier>_0</span><span class=special>, </span><span class=comment>// LHS argument
|
||||
</span><span class=identifier>actor</span><span class=special><</span><span class=identifier>BaseT</span><span class=special>> </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>_1</span><span class=special>) </span><span class=comment>// RHS argument
|
||||
</span><span class=special>{
|
||||
</span><span class=keyword>return </span><span class=identifier>actor</span><span class=special><</span><span class=identifier>composite</span><span class=special><
|
||||
</span><span class=identifier>shift_l_op</span><span class=special>, </span><span class=comment>// an operator tag
|
||||
</span><span class=identifier>variable</span><span class=special><</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>>, </span><span class=comment>// an actor LHS
|
||||
</span><span class=identifier>actor</span><span class=special><</span><span class=identifier>BaseT</span><span class=special>>, </span><span class=comment>// an actor RHS
|
||||
</span><span class=special>> </span><span class=special>>(</span><span class=identifier>var</span><span class=special>(</span><span class=identifier>_0</span><span class=special>), </span><span class=identifier>_1</span><span class=special>); </span><span class=comment>// construct 'em
|
||||
</span><span class=special>}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Take note that the std::ostream reference is converted to a actor<variable<std::ostream> > instead of the default actor<value<std::ostream> > which is not appropriate in this case.</p>
|
||||
<p>
|
||||
This is not yet complete. Take note also that a specialization for binary_operator also needs to be written (see no. 6).</p>
|
||||
<p>
|
||||
5) Specialize a rank<T> for a specific type or group of types:</p>
|
||||
<p>
|
||||
Scenario: We have a set of more specialized numeric classes with higher precision than the built-in types. We have integer, floating and rational classes. All of the classes allow type promotions from the built-ins. These classes have all the pertinent operators implemented along with a couple of mixed type operators whenever appropriate. The operators conform to the canonical behavior of the built-in types. We want to enable Phoenix support for our numeric classes.</p>
|
||||
<p>
|
||||
Solution: Write rank specializations for our numeric types. This is trivial and straightforward:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><> </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special><</span><span class=identifier>integer</span><span class=special>> </span><span class=special>{ </span><span class=keyword>static </span><span class=keyword>int </span><span class=keyword>const </span><span class=identifier>value </span><span class=special>= </span><span class=number>10000</span><span class=special>; </span><span class=special>};
|
||||
</span><span class=keyword>template </span><span class=special><> </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special><</span><span class=identifier>floating</span><span class=special>> </span><span class=special>{ </span><span class=keyword>static </span><span class=keyword>int </span><span class=keyword>const </span><span class=identifier>value </span><span class=special>= </span><span class=number>10020</span><span class=special>; </span><span class=special>};
|
||||
</span><span class=keyword>template </span><span class=special><> </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special><</span><span class=identifier>rational</span><span class=special>> </span><span class=special>{ </span><span class=keyword>static </span><span class=keyword>int </span><span class=keyword>const </span><span class=identifier>value </span><span class=special>= </span><span class=number>10030</span><span class=special>; </span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Now, whenever there are mixed-type operations such as a + b where a is a primitive built-in int and b is our rational class, the correct promotion will be applied, and the result will be a rational. The type with the higher rank will win.</p>
|
||||
<p>
|
||||
6) Specialize a unary_operator<TagT, T> or binary_operator<TagT, T0, T1> for a specific type:</p>
|
||||
<p>
|
||||
Scenario: We have a non-STL conforming iterator named my_iterator. Fortunately, its ++ operator works as expected. Unfortunately, when applying the dereference operator *p, it returns an object of type my_class but does not follow STL's convention that iterator classes have a typedef named reference.</p>
|
||||
<p>
|
||||
Solution, write a unary_operator specialization for our non- standard class:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><>
|
||||
</span><span class=keyword>struct </span><span class=identifier>unary_operator</span><span class=special><</span><span class=identifier>dereference_op</span><span class=special>, </span><span class=identifier>my_iterator</span><span class=special>> </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=identifier>my_class </span><span class=identifier>result_type</span><span class=special>;
|
||||
</span><span class=keyword>static </span><span class=identifier>result_type </span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>my_iterator </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>iter</span><span class=special>)
|
||||
</span><span class=special>{ </span><span class=keyword>return </span><span class=special>*</span><span class=identifier>iter</span><span class=special>; </span><span class=special>}
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Scenario: We have a legacy bigint implementation that we use for cryptography. The class design is totally brain-dead and disobeys all the rules. For example, its + operator is destructive and actually applies the += semantics for efficiency (yes, there are such brain-dead beasts!).</p>
|
||||
<p>
|
||||
Solution: write a binary_operator specialization for our non- standard class:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><>
|
||||
</span><span class=keyword>struct </span><span class=identifier>binary_operator</span><span class=special><</span><span class=identifier>plus_op</span><span class=special>, </span><span class=identifier>bigint</span><span class=special>, </span><span class=identifier>bigint</span><span class=special>> </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=identifier>bigint</span><span class=special>& </span><span class=identifier>result_type</span><span class=special>;
|
||||
</span><span class=keyword>static </span><span class=identifier>result_type </span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>bigint</span><span class=special>& </span><span class=identifier>lhs</span><span class=special>, </span><span class=identifier>bigint </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>rhs</span><span class=special>)
|
||||
</span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>lhs </span><span class=special>+ </span><span class=identifier>rhs</span><span class=special>; </span><span class=special>}
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Going back to our example in no. 4, we also need to write a binary_operator<TagT, T0, T1> specialization for ostreams because the << operator for ostreams deviate from the normal behavior.</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>T1</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>binary_operator</span><span class=special><</span><span class=identifier>shift_l_op</span><span class=special>, </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>, </span><span class=identifier>T1</span><span class=special>> </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>& </span><span class=identifier>result_type</span><span class=special>;
|
||||
</span><span class=keyword>static </span><span class=identifier>result_type </span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>ostream</span><span class=special>& </span><span class=identifier>out</span><span class=special>, </span><span class=identifier>T1 </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>rhs</span><span class=special>)
|
||||
</span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>out </span><span class=special><< </span><span class=identifier>rhs</span><span class=special>; </span><span class=special>}
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
7) Simply write a lazy-function.</p>
|
||||
<p>
|
||||
Consider this:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>if_else_func </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>CondT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TrueT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>FalseT</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>higher_rank</span><span class=special><</span><span class=identifier>TrueT</span><span class=special>, </span><span class=identifier>FalseT</span><span class=special>>::</span><span class=identifier>type </span><span class=identifier>type</span><span class=special>;
|
||||
</span><span class=special>};
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>CondT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>TrueT</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>FalseT</span><span class=special>>
|
||||
</span><span class=keyword>typename </span><span class=identifier>higher_rank</span><span class=special><</span><span class=identifier>TrueT</span><span class=special>, </span><span class=identifier>FalseT</span><span class=special>>::</span><span class=identifier>type
|
||||
</span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>CondT </span><span class=identifier>cond</span><span class=special>, </span><span class=identifier>TrueT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>t</span><span class=special>, </span><span class=identifier>FalseT </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>f</span><span class=special>) </span><span class=keyword>const
|
||||
</span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>cond </span><span class=special>? </span><span class=identifier>t </span><span class=special>: </span><span class=identifier>f</span><span class=special>; </span><span class=special>}
|
||||
</span><span class=special>};
|
||||
|
||||
</span><span class=identifier>function</span><span class=special><</span><span class=identifier>if_else_func</span><span class=special>> </span><span class=identifier>if_else_</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
And this corresponding usage:</p>
|
||||
<code><pre>
|
||||
<span class=comment>// Print all contents of an STL container c and
|
||||
// prefix " is odd" or " is even" appropriately.
|
||||
|
||||
</span><span class=identifier>for_each</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),
|
||||
</span><span class=identifier>cout
|
||||
</span><span class=special><< </span><span class=identifier>arg1
|
||||
</span><span class=special><< </span><span class=identifier>if_else_</span><span class=special>(</span><span class=identifier>arg1 </span><span class=special>% </span><span class=number>2 </span><span class=special>== </span><span class=number>1</span><span class=special>, </span><span class=string>" is odd"</span><span class=special>, </span><span class=string>" is even"</span><span class=special>)
|
||||
</span><span class=special><< </span><span class=identifier>val</span><span class=special>(</span><span class=literal>'\n'</span><span class=special>)
|
||||
</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
What the $%^!? If we can do this, why on earth did we go to all the trouble twisting our brains inside out with the if_else_ composite in no. 2? Hey, not so fast, there's a slight difference that justifies the if_else_ composite: It is not apparent in the example, but the composite version of the if_else_ evaluates either the true or the false branch, **but not both**. The lazy-function version above always eagerly evaluates all its arguments before the function is called. Thus, if we are to adhere strongly to C/C++ semantics, we need the composite version.</p>
|
||||
<p>
|
||||
Besides, I need to show an example... Hmmm, so what's the point of no. 7 then? Well, in most cases, a lazy-function will suffice. These beasts are quite powerful, you know.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="operators_revisited.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="wrap_up.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
53
phoenix/doc/introduction.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Introduction</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="preface.html">
|
||||
<link rel="next" href="quick_start.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Introduction</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="preface.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="quick_start.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<a name="the_phoenix_framework_v1_0"></a><h1>The Phoenix Framework v1.0</h1><a name="preliminary_draft"></a><h4>Preliminary Draft</h4><p>
|
||||
February 2001, Joel de Guzman</p>
|
||||
<p>
|
||||
Functional programming (or FP) is gaining momentum as more programmers discover its power. In its purest form, the paradigms set forth seem to be too detached from what most programmers are already accustomed to. In the point of view of the C or Pascal imperative programmer, for instance, FP techniques and concepts are quite esoteric at first glance. Learning a pure FP language such as <a href="http://www.haskell.org">
|
||||
Haskell</a> for example requires a significant quantum leap.</p>
|
||||
<p>
|
||||
FP can be taken as a methodology that is not at all tied to a specific language. FP as a programming discipline can be applied to many programming languages. In the realm of C++ for instance, we are seeing more FP techniques being applied. C++ is sufficiently rich to support at least some of the most important facets of FP such as higher order functions. C++ deservedly regards itself as a multiparadigm programming language. It is not only procedural; it is not only object oriented; stealthily beneath the core of the standard C++ library, a closer look into STL gives us a glimpse of a truly FP paradigm already in place. It is obvious that the authors of STL knows and practices FP. In the near future, we shall see more FP trickle down into the mainstream. Surely.</p>
|
||||
<p>
|
||||
The truth is, although FP is rich in concepts new and alien to the typical C++ programmer, we need not shift the paradigm in its entirety wholesale; but rather in small pieces at a time. In fact, most of the FP techniques can coexist quite well with the standard object oriented and imperative programming paradigms. When we are using STL algorithms and functors for example, we are already doing FP.</p>
|
||||
<p>
|
||||
Phoenix extends the concepts of FP to C++ much further. In a nutshell, the framework opens up FP techniques such as Lambda (unnamed functions) and Currying (partial function evaluation).</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="preface.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="quick_start.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
75
phoenix/doc/lazy_construction_and_conversions.html
Normal file
@@ -0,0 +1,75 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Lazy Construction and Conversions</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="adaptable_closures.html">
|
||||
<link rel="next" href="efficiency.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Lazy Construction and Conversions</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="adaptable_closures.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="efficiency.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<a name="lazy_c___casts"></a><h2>Lazy C++ Casts</h2><p>
|
||||
The set of lazy C++ cast template classes and functions provide a way of lazily casting certain type to another during parsing. The lazy C++ templates are (syntactically) used very much like the well known C++ casts:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>A </span><span class=special>*</span><span class=identifier>a </span><span class=special>= </span><span class=identifier>static_cast_</span><span class=special><</span><span class=identifier>A </span><span class=special>*>(</span><span class=identifier>_a_lambda_expression_</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
These casts parallel the ones in the C++ language. Take note however that the <i>lazy</i> versions have a trailing underscore.</p>
|
||||
<ul><li>static_cast_<T>(lambda_expression)</li><li>dynamic_cast_<T>(lambda_expression)</li><li>const_cast_<T>(lambda_expression)</li><li>reinterpret_cast_<T>(lambda_expression)</li></ul><table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/note.gif">
|
||||
<b>Acknowledgement:</b><br><br><b>Hartmut Kaiser</b> implemented the lazy casts and constructors based on his original work on <a href="http://spirit.sourceforge.net">
|
||||
Spirit</a> SE "semantic expressions" (the precursor of Phoenix). </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a name="lazy_object_construction"></a><h2>Lazy object construction</h2><p>
|
||||
A set of lazy constructor template classes and functions provide a way of lazily constructing an object of a type from an arbitrary set of lazy arguments in the form of lambda expressions. The construct_ templates are (syntactically) used very much like the well known C++ casts:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>A </span><span class=identifier>a </span><span class=special>= </span><span class=identifier>construct_</span><span class=special><</span><span class=identifier>A</span><span class=special>>(</span><span class=identifier>lambda_arg1</span><span class=special>, </span><span class=identifier>lambda_arg2</span><span class=special>, </span><span class=special>..., </span><span class=identifier>lambda_argN</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
where the given parameters are become the parameters to the contructor of the object of type A. (This implies, that type A is expected to have a constructor with a corresponsing set of parameter types.)</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/bulb.gif">
|
||||
The ultimate maximum number of actual parameters is limited by the preprocessor constant PHOENIX_CONSTRUCT_LIMIT. Note though, that this limit should not be greater than PHOENIX_LIMIT. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="adaptable_closures.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="efficiency.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
124
phoenix/doc/lazy_functions.html
Normal file
@@ -0,0 +1,124 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Lazy functions</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="architecture.html">
|
||||
<link rel="next" href="place_holders.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Lazy functions</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="architecture.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="place_holders.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
When currying or partial function evaluation takes place, supplying N actual arguments to a function that expects M arguments where N < M will result in a higher order function with M-N arguments. Technically, when N == M, the function has all the arguments needed to do a full evaluation:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus</span><span class=special>(</span><span class=number>3</span><span class=special>, </span><span class=number>2</span><span class=special>) </span><span class=identifier>full </span><span class=identifier>evaluation
|
||||
</span><span class=identifier>plus</span><span class=special>(?, </span><span class=number>6</span><span class=special>) </span><span class=identifier>partial </span><span class=identifier>evaluation
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/note.gif">
|
||||
Lazy functions are subsets of partial function evaluation or currying </td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Now, we shall revisit the concept of lazy functions introduced before in passing. That is, the first function invocation will not really "fully evaluate" the function regardless if all or some of the arguments are supplied. A second function invocation will always be needed to perform the actual evaluation. At the point in the second call, the caller is expected to supply all arguments that are still missing. Still vague? To clarify, a partially evaluated function:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>f</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=special>?, </span><span class=special>?)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
results to an unnamed function unnamed_f(a, b) that expects the two (2) more arguments that are still missing when the first function, f, is invoked. Since unnamed_f(a, b) is already a second level evaluation, all arguments must be supplied when it is called and the result is finally evaluated. Example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>f</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=special>?, </span><span class=special>?) </span><span class=special>---> </span><span class=identifier>unnamed_f</span><span class=special>(</span><span class=identifier>a</span><span class=special>, </span><span class=identifier>b</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
then</p>
|
||||
<code><pre>
|
||||
<span class=identifier>unnamed_f</span><span class=special>(</span><span class=number>2</span><span class=special>, </span><span class=number>3</span><span class=special>) </span><span class=special>---> </span><span class=identifier>evaluate_and_return_value_for </span><span class=identifier>f</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>, </span><span class=number>3</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
This function call sequence can be concatenated:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>f</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=special>?, </span><span class=special>?)(</span><span class=number>2</span><span class=special>, </span><span class=number>3</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
The second level function unnamed_f is not curryable. All of its still missing arguments must be supplied when it is called.</p>
|
||||
<p>
|
||||
As mentioned, even though we have all the arguments in the first call, the function is not yet evaluated (thus lazy). For example, a function call:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>f</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>, </span><span class=number>3</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
remember that the first function invocation will not really evaluate the function even if all the arguments are fully supplied. Thus:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>f</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>, </span><span class=number>3</span><span class=special>) </span><span class=special>---> </span><span class=identifier>unnamed_f</span><span class=special>()
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/note.gif">
|
||||
<b>Generators</b><br><br>In FP, unnamed_f() is a generator; a function that has no arguments but returns a result. Not to be confused with Phoenix generators to be discussed later. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Then:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>unnamed_f</span><span class=special>() </span><span class=special>---> </span><span class=identifier>evaluate_and_return_value_for </span><span class=identifier>f</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>, </span><span class=number>3</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
This function call sequence can be concatenated as:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>f</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>, </span><span class=number>3</span><span class=special>)()
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Lambda (unnamed) functions and currying (partial function evaluation) can also be applied to operators. However, unlike lazy functions, operators are fully evaluated once all the arguments are known and supplied, unless some sort of intervention is applied to coerce the operator expression to be lazily evaluated. We shall see more details on this and how this is done later.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="architecture.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="place_holders.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
116
phoenix/doc/operators.html
Normal file
@@ -0,0 +1,116 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Operators</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="functions.html">
|
||||
<link rel="next" href="statements.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Operators</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="statements.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<a name="lazy_operators"></a><h2>Lazy operators</h2><p>
|
||||
This facility provides a mechanism for lazily evaluating operators. Syntactically, a lazy operator looks and feels like an ordinary C/C++ infix, prefix or postfix operator. The operator application looks the same. However, unlike ordinary operators, the actual operator execution is deferred. Samples:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>arg1 </span><span class=special>+ </span><span class=identifier>arg2
|
||||
</span><span class=number>1 </span><span class=special>+ </span><span class=identifier>arg1 </span><span class=special>* </span><span class=identifier>arg2
|
||||
</span><span class=number>1 </span><span class=special>/ </span><span class=special>-</span><span class=identifier>arg1
|
||||
</span><span class=identifier>arg1 </span><span class=special>< </span><span class=number>150
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
We have seen the lazy operators in action (see sample2.cpp) above. Let's go back and examine it a little bit further:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>find_if</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(), </span><span class=identifier>arg1 </span><span class=special>% </span><span class=number>2 </span><span class=special>== </span><span class=number>1</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Through operator overloading, the expression "arg1 % 2 == 1" actually generates a composite. This composite object is passed on to STL's find_if function. In the viewpoint of STL, the composite is simply a functor expecting a single argument, the container's element. For each element in the container 'c', the element is passed on as an argument (arg1) to the composite (functor). The composite (functor) checks if this is an odd value based on the expression "arg1 % 2 == 1" where arg1 is iteratively replaced by the container's element.</p>
|
||||
<p>
|
||||
A set of classes implement all the C++ free operators. Like lazy functions (see functions), lazy operators are not immediately executed when invoked. Instead, a composite (see composite) object is created and returned to the caller. Example:</p>
|
||||
<code><pre>
|
||||
<span class=special>(</span><span class=identifier>arg1 </span><span class=special>+ </span><span class=identifier>arg2</span><span class=special>) </span><span class=special>* </span><span class=identifier>arg3
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
does nothing more than return a composite. A second function call will evaluate the actual operators. Example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>int </span><span class=identifier>i </span><span class=special>= </span><span class=number>4</span><span class=special>, </span><span class=identifier>j </span><span class=special>= </span><span class=number>5</span><span class=special>, </span><span class=identifier>k </span><span class=special>= </span><span class=number>6</span><span class=special>;
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=special>((</span><span class=identifier>arg1 </span><span class=special>+ </span><span class=identifier>arg2</span><span class=special>) </span><span class=special>* </span><span class=identifier>arg3</span><span class=special>)(</span><span class=identifier>i</span><span class=special>, </span><span class=identifier>j</span><span class=special>, </span><span class=identifier>k</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
will print out "54".</p>
|
||||
<p>
|
||||
Arbitrarily complex expressions can be lazily evaluated following three simple rules:</p>
|
||||
<ol><li>Lazy evaluated binary operators apply when *at least* one of the operands is an actor object (see actor, primitives and composite). Consequently, if one of the operands is not an actor object, it is implicitly converted, by default, to an object of type actor<value<T> > (where T is the original type of the operand).</li><li>Lazy evaluated unary operators apply only to operands which are actor objects.</li><li>The result of a lazy operator is a composite actor object that can in turn apply to rule 1.</li></ol><p>
|
||||
Example:</p>
|
||||
<code><pre>
|
||||
<span class=special>-(</span><span class=identifier>arg1 </span><span class=special>+ </span><span class=number>3 </span><span class=special>+ </span><span class=number>6</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<ol><li>Following rule 1, lazy evaluation is triggered since arg1 is an instance of an actor<argument<N> > class (see primitives).</li><li>The immediate right operand <3> is implicitly converted to an actor<value<int> >. Still following rule 1.</li><li>The result of this "arg1 + 3" expression is a composite object, following rule 3.</li><li>Now since "arg1 + 3" is a composite, following rule 1 again, its right operand <6> is implicitly converted to an actor<value<int> >.</li><li>Continuing, the result of "arg1 + 3" ... "+ 6" is again another composite. Rule 3.</li><li>The expression "arg1 + 3 + 6" being a composite, is the operand of the unary operator -. Following rule 2, the result is an actor object.</li><li>Folowing rule 3, the whole thing "-(arg1 + 3 + 6)" is a composite.</li></ol><p>
|
||||
Lazy-operator application is highly contagious. In most cases, a single argN actor infects all its immediate neighbors within a group (first level or parenthesized expression).</p>
|
||||
<p>
|
||||
Take note that although at least one of the operands must be a valid actor class in order for lazy evaluation to take effect, if this is not the case and we still want to lazily evaluate an expression, we can use var(x), val(x) or const_ref(x) to transform the operand into a valid action object (see primitives). Example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>val</span><span class=special>(</span><span class=number>1</span><span class=special>) </span><span class=special><< </span><span class=number>3</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Supported operators:</p>
|
||||
<p>
|
||||
Unary operators:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>prefix</span><span class=special>: </span><span class=special>~, </span><span class=special>!, </span><span class=special>-, </span><span class=special>+, </span><span class=special>++, </span><span class=special>--, </span><span class=special>& </span><span class=special>(</span><span class=identifier>reference</span><span class=special>), </span><span class=special>* </span><span class=special>(</span><span class=identifier>dereference</span><span class=special>)
|
||||
</span><span class=identifier>postfix</span><span class=special>: </span><span class=special>++, </span><span class=special>--
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Binary operators:</p>
|
||||
<code><pre>
|
||||
<span class=special>=, </span><span class=special>[], </span><span class=special>+=, </span><span class=special>-=, </span><span class=special>*=, </span><span class=special>/=, </span><span class=special>%=, </span><span class=special>&=, </span><span class=special>|=, </span><span class=special>^=, </span><span class=special><<=, </span><span class=special>>>=
|
||||
</span><span class=special>+, </span><span class=special>-, </span><span class=special>*, </span><span class=special>/, </span><span class=special>%, </span><span class=special>&, </span><span class=special>|, </span><span class=special>^, </span><span class=special><<, </span><span class=special>>>
|
||||
</span><span class=special>==, </span><span class=special>!=, </span><span class=special><, </span><span class=special>>, </span><span class=special><=, </span><span class=special>>=
|
||||
</span><span class=special>&&, </span><span class=special>||
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="statements.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
217
phoenix/doc/operators_revisited.html
Normal file
@@ -0,0 +1,217 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Operators revisited</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="composites_revisited.html">
|
||||
<link rel="next" href="interfacing.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Operators revisited</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="composites_revisited.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="interfacing.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Each C++ operator has a special tag type associated with it. For example the binary + operator has a plus_op tag type associated with it. This operator tag is used to specialize either:</p>
|
||||
<ol><li>unary_operator<TagT, T0></li><li>binary_operator<TagT, T0, T1></li></ol><p>
|
||||
template classes (see unary_operator and binary_operator below). Specializations of these unary_operator and binary_operator are the actual workhorses that implement the operations. The behavior of each lazy operator depends on these unary_operator and binary_operator specializations.</p>
|
||||
<p>
|
||||
Preset specializations conform to the canonical operator rules modeled by the behavior of integers and pointers:</p>
|
||||
<ul><li>Prefix -, + and ~ accept constant arguments and return an object by value.</li><li>The ! accept constant arguments and returns a boolean result.</li><li>The & (address-of), * (dereference) both return a reference to an object.</li><li>Prefix ++ returns a reference to its mutable argument after it is incremented.</li><li>Postfix ++ returns the mutable argument by value before it is incremented.</li><li>The += and its family accept mutable right hand side (rhs) operand and return a reference to the rhs operand.</li><li>Infix + and its family accept constant arguments and return an object by value.</li><li>The == and its family accept constant arguments and return a boolean result.</li><li>Operators && and || accept constant arguments and return a boolean result and are short circuit evaluated as expected.</li></ul><a name="special_operators_and_extensibility"></a><h2>Special operators and extensibility</h2><p>
|
||||
It is of course possible to override the standard operator behavior when appropriate. For example, the behavior of std::cout does not conform to the canonocal shift left operator << (i.e. the rhs std::cout is a mutable reference). Odd balls such as this are placed in special_ops.hpp. There you will find specializations for various classes found in the standard lib.</p>
|
||||
<p>
|
||||
The library is meant to be extensible. Users may implement their own specializations to allow other libraries to be adapted to be partial-function-evaluation savvy. Later on, in the section "Interfacing (to applications, libraries and frameworks)", discussion will be focused on interfacing and extending the framework.</p>
|
||||
<a name="operator_tags"></a><h2>Operator tags</h2><p>
|
||||
Each C++ operator has a corresponding tag type. This is used as a means for specializing the unary_operator and binary_operator (see below). The tag also serves as the lazy operator type compatible with a composite as an operation (see composite). Here are two examples of operator tags:</p>
|
||||
<p>
|
||||
Unary example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>negative_op </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>unary_operator</span><span class=special><</span><span class=identifier>negative_op</span><span class=special>, </span><span class=identifier>T0</span><span class=special>>
|
||||
</span><span class=special>::</span><span class=identifier>result_type </span><span class=identifier>type</span><span class=special>;
|
||||
</span><span class=special>};
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>>
|
||||
</span><span class=keyword>typename </span><span class=identifier>unary_operator</span><span class=special><</span><span class=identifier>negative_op</span><span class=special>, </span><span class=identifier>T0</span><span class=special>>::</span><span class=identifier>result_type
|
||||
</span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>T0</span><span class=special>& </span><span class=identifier>_0</span><span class=special>) </span><span class=keyword>const
|
||||
</span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>unary_operator</span><span class=special><</span><span class=identifier>negative_op</span><span class=special>, </span><span class=identifier>T0</span><span class=special>>::</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>_0</span><span class=special>); </span><span class=special>}
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Binary example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>plus_op </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>T1</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>binary_operator</span><span class=special><</span><span class=identifier>plus_op</span><span class=special>, </span><span class=identifier>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>>
|
||||
</span><span class=special>::</span><span class=identifier>result_type </span><span class=identifier>type</span><span class=special>;
|
||||
</span><span class=special>};
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>T1</span><span class=special>>
|
||||
</span><span class=keyword>typename </span><span class=identifier>binary_operator</span><span class=special><</span><span class=identifier>plus_op</span><span class=special>, </span><span class=identifier>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>>::</span><span class=identifier>result_type
|
||||
</span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>T0</span><span class=special>& </span><span class=identifier>_0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>& </span><span class=identifier>_1</span><span class=special>) </span><span class=keyword>const
|
||||
</span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>binary_operator</span><span class=special><</span><span class=identifier>plus_op</span><span class=special>, </span><span class=identifier>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>>::</span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>_0</span><span class=special>, </span><span class=identifier>_1</span><span class=special>); </span><span class=special>}
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Notice that these are again perfect examples of a composite operation. This style of specialized function is ubiquitous in the framework. We shall see how the unary_operator<negative_op, T0> and the binary_operator<plus_op, T0, T1> template classes, work in a short while.</p>
|
||||
<p>
|
||||
Here are the complete list of operator tags:</p>
|
||||
<code><pre>
|
||||
<span class=comment>// Unary operator tags
|
||||
|
||||
</span><span class=keyword>struct </span><span class=identifier>negative_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>positive_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>logical_not_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>invert_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>reference_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>dereference_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>pre_incr_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>pre_decr_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>post_incr_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>post_decr_op</span><span class=special>;
|
||||
|
||||
</span><span class=comment>// Binary operator tags
|
||||
|
||||
</span><span class=keyword>struct </span><span class=identifier>assign_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>index_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>plus_assign_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>minus_assign_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>times_assign_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>divide_assign_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>mod_assign_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>and_assign_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>or_assign_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>xor_assign_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>shift_l_assign_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>shift_r_assign_op</span><span class=special>;
|
||||
|
||||
</span><span class=keyword>struct </span><span class=identifier>plus_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>minus_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>times_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>divide_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>mod_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>and_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>or_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>xor_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>shift_l_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>shift_r_op</span><span class=special>;
|
||||
|
||||
</span><span class=keyword>struct </span><span class=identifier>eq_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>not_eq_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>lt_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>lt_eq_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>gt_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>gt_eq_op</span><span class=special>;
|
||||
</span><span class=keyword>struct </span><span class=identifier>logical_and_op</span><span class=special>; </span><span class=keyword>struct </span><span class=identifier>logical_or_op</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<a name="unary_operator"></a><h3>unary_operator</h3><p>
|
||||
The unary_operator class implements most of the C++ unary operators. Each specialization is basically a simple static eval function plus a result_type typedef that determines the return type of the eval function.</p>
|
||||
<p>
|
||||
TagT is one of the unary operator tags above and T is the data type (argument) involved in the operation. Here is an example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>T</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>unary_operator</span><span class=special><</span><span class=identifier>negative_op</span><span class=special>, </span><span class=identifier>T</span><span class=special>> </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=identifier>T </span><span class=keyword>const </span><span class=identifier>result_type</span><span class=special>;
|
||||
</span><span class=keyword>static </span><span class=identifier>result_type </span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>T </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>v</span><span class=special>)
|
||||
</span><span class=special>{ </span><span class=keyword>return </span><span class=special>-</span><span class=identifier>v</span><span class=special>; </span><span class=special>}
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
This example is exactly what was being referred to by the first example we saw in the section on operator tags.</p>
|
||||
<p>
|
||||
Only the behavior of C/C++ built-in types are taken into account in the specializations provided in operator.hpp. For user-defined types, these specializations may still be used provided that the operator overloads of such types adhere to the standard behavior of built-in types.</p>
|
||||
<p>
|
||||
A separate special_ops.hpp file implements more STL savvy specializations. Other more specialized unary_operator implementations may be defined by the client for specific unary operator tags/data types.</p>
|
||||
<a name="binary_operator"></a><h3>binary_operator</h3><p>
|
||||
The binary_operator class implements most of the C++ binary operators. Each specialization is basically a simple static eval function plus a result_type typedef that determines the return type of the eval function.</p>
|
||||
<p>
|
||||
TagT is one of the binary operator tags above T0 and T1 are the (arguments') data types involved in the operation. Here is an example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>T0</span><span class=special>, </span><span class=keyword>typename </span><span class=identifier>T1</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>binary_operator</span><span class=special><</span><span class=identifier>plus_op</span><span class=special>, </span><span class=identifier>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>> </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>typedef </span><span class=keyword>typename </span><span class=identifier>higher_rank</span><span class=special><</span><span class=identifier>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>>::</span><span class=identifier>type </span><span class=keyword>const </span><span class=identifier>result_type</span><span class=special>;
|
||||
</span><span class=keyword>static </span><span class=identifier>result_type </span><span class=identifier>eval</span><span class=special>(</span><span class=identifier>T0 </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>lhs</span><span class=special>, </span><span class=identifier>T1 </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>rhs</span><span class=special>)
|
||||
</span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>lhs </span><span class=special>+ </span><span class=identifier>rhs</span><span class=special>; </span><span class=special>}
|
||||
</span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
This example is exactly what was being referred to by the second example we saw in the section on operator tags. higher_rank<T0, T1> is a type computer. We shall see how this works in a short while, pardon the forward information.</p>
|
||||
<p>
|
||||
Only the behavior of C/C++ built-in types are taken into account in the specializations provided in operator.hpp. For user-defined types, these specializations may still be used provided that the operator overloads of such types adhere to the standard behavior of built-in types.</p>
|
||||
<p>
|
||||
A separate special_ops.hpp file implements more STL savvy specializations. Other more specialized unary_operator implementations may be defined by the client for specific unary operator tags/data types.</p>
|
||||
<p>
|
||||
All binary_operator except the logical_and_op and logical_or_op have an eval static function that carries out the actual operation. The logical_and_op and logical_or_op d are special because these two operators are short-circuit evaluated.</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/lens.gif">
|
||||
<b>Short Circuiting || and &&</b><br><br>The logical_and_op and logical_or_op are special due to the C/C++ short circuiting rule, i.e. a || b and a && b are short circuit evaluated. A forwarding operation cannot be used because all function arguments are evaluated before a function is called. logical_and_op and logical_or_op are specialized composites with implied operations. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a name="rank"></a><h2>rank</h2><p>
|
||||
rank<T> class has a static int constant 'value' that defines the absolute rank of a type. rank<T> is used to choose the result type of binary operators such as +. The type with the higher rank wins and is used as the operator's return type. A generic user defined type has a very high rank and always wins when compared against a user defined type. If this is not desireable, one can write a rank specialization for the type. Here are some predefined examples:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>template </span><span class=special><> </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special><</span><span class=keyword>char</span><span class=special>> </span><span class=special>{ </span><span class=keyword>static </span><span class=keyword>int </span><span class=keyword>const </span><span class=identifier>value </span><span class=special>= </span><span class=number>20</span><span class=special>; </span><span class=special>};
|
||||
</span><span class=keyword>template </span><span class=special><> </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special><</span><span class=keyword>signed </span><span class=keyword>char</span><span class=special>> </span><span class=special>{ </span><span class=keyword>static </span><span class=keyword>int </span><span class=keyword>const </span><span class=identifier>value </span><span class=special>= </span><span class=number>20</span><span class=special>; </span><span class=special>};
|
||||
</span><span class=keyword>template </span><span class=special><> </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special><</span><span class=keyword>unsigned </span><span class=keyword>char</span><span class=special>> </span><span class=special>{ </span><span class=keyword>static </span><span class=keyword>int </span><span class=keyword>const </span><span class=identifier>value </span><span class=special>= </span><span class=number>30</span><span class=special>; </span><span class=special>};
|
||||
</span><span class=keyword>template </span><span class=special><> </span><span class=keyword>struct </span><span class=identifier>rank</span><span class=special><</span><span class=keyword>wchar_t</span><span class=special>> </span><span class=special>{ </span><span class=keyword>static </span><span class=keyword>int </span><span class=keyword>const </span><span class=identifier>value </span><span class=special>= </span><span class=number>40</span><span class=special>; </span><span class=special>};
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Take note that ranks 0..9999 are reserved by the framework.</p>
|
||||
<p>
|
||||
A template type computer higher_rank<T0, T1> chooses the type (T0 or T1) with the higher rank. We saw in the binary_operator for plus_op how it was used. Specifically:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>higher_rank</span><span class=special><</span><span class=identifier>T0</span><span class=special>, </span><span class=identifier>T1</span><span class=special>>::</span><span class=identifier>type
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
returns either T0 or T1 depending on which has a higher rank. In some operator applications such as a + b, the result is actually the one with the higher rank. For example if a is of type int and b is of type double, the result will be of type double. This facility can also be quite useful for evaluating some functions. For instance if we have a sum(a, b, c, d, e) function, we can call this type computer to get the type with the highest rank:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>higher_rank</span><span class=special><</span><span class=identifier>TA</span><span class=special>,
|
||||
</span><span class=identifier>higher_rank</span><span class=special><</span><span class=identifier>TB</span><span class=special>,
|
||||
</span><span class=identifier>higher_rank</span><span class=special><</span><span class=identifier>TC</span><span class=special>,
|
||||
</span><span class=identifier>higher_rank</span><span class=special><</span><span class=identifier>TD</span><span class=special>, </span><span class=identifier>TE</span><span class=special>>::</span><span class=identifier>type
|
||||
</span><span class=special>>::</span><span class=identifier>type
|
||||
</span><span class=special>>::</span><span class=identifier>type
|
||||
</span><span class=special>>::</span><span class=identifier>type
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/alert.gif">
|
||||
When used within templates, be sure to use 'typename' appropriately. See binary_operator<plus_op, T0, T1> above. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="composites_revisited.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="interfacing.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
73
phoenix/doc/organization.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Organization</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="polymorphic_functions.html">
|
||||
<link rel="next" href="actors.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Organization</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="polymorphic_functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="actors.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
The framework is organized in five (5) layers.</p>
|
||||
<code><pre>
|
||||
<span class=special>+-----------+
|
||||
</span><span class=special>| </span><span class=identifier>binders </span><span class=special>|
|
||||
</span><span class=special>+-----------+-----------+------------+
|
||||
</span><span class=special>| </span><span class=identifier>functions </span><span class=special>| </span><span class=identifier>operators </span><span class=special>| </span><span class=identifier>statements </span><span class=special>|
|
||||
</span><span class=special>+------------+-----------+-----------+------------+
|
||||
</span><span class=special>| </span><span class=identifier>primitives </span><span class=special>| </span><span class=identifier>composite </span><span class=special>|
|
||||
</span><span class=special>+------------+------------------------------------+
|
||||
</span><span class=special>| </span><span class=identifier>actor </span><span class=special>|
|
||||
</span><span class=special>+-------------------------------------------------+
|
||||
</span><span class=special>| </span><span class=identifier>tuples </span><span class=special>|
|
||||
</span><span class=special>+-------------------------------------------------+
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
The lowest level is the tuples library. Knowledge of tuples is not at all required in order to use the framework. In a nutshell, this small sub-library provides a mechanism for bundling heterogeneous types together. This is an implementation detail. Yet, in itself, it is quite useful in other applications as well. A more detailed explanation will be given later.</p>
|
||||
<p>
|
||||
Actors are the main concept behind the framework. Lazy functions are abstracted as actors which are actually polymorphic functors. There are only 2 kinds of actors:</p>
|
||||
<ol><li>primitives</li><li>composites.</li></ol><p>
|
||||
Composites are composed of zero or more actors. Each actor in a composite can again be another composite. Primitives are atomic units and are not decomposable.</p>
|
||||
<p>
|
||||
(lazy) functions, (lazy) operators and (lazy) statements are built on top of composites. To put it more accurately, a lazy function (lazy operators and statements are just specialized forms of lazy functions) has two stages:</p>
|
||||
<ol><li>(lazy) partial evaluation [ front-end ]</li><li>final evaluation [ back-end ]</li></ol><p>
|
||||
The first stage is handled by a set of generator functions, generator functors and generator operator overloads. These are your front ends (in the client's perspective). These generators create the actors that can be passed on just like any other function pointer or functor object. The second stage, the actual function call, can be invoked or executed anytime just like any other function. These are the back-ends (often, the final invocation is never actually seen by the client).</p>
|
||||
<p>
|
||||
Binders, built on top of functions, create lazy functions from simple monomorphic (STL like) functors, function pointers, member function pointers or member variable pointers for deferred evaluation (variables are accessed through a function call that returns a reference to the data. These binders are built on top of (lazy) functions.</p>
|
||||
<p>
|
||||
The framework's architecture is completely orthogonal. The relationship between the layers is totally acyclic. Lower layers do not depend nor know the existence of higher layers. Modules in a layer do not depend on other modules in the same layer. This means for example that the client can completely discard binders if she does not need it; or perhaps take out lazy-operators and lazy-statements and just use lazy-functions, which is desireable in a pure FP application.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="polymorphic_functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="actors.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
1723
phoenix/doc/phoenix_users_manual.txt
Normal file
112
phoenix/doc/place_holders.html
Normal file
@@ -0,0 +1,112 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Place holders</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="lazy_functions.html">
|
||||
<link rel="next" href="polymorphic_functions.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Place holders</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="lazy_functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="polymorphic_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
So far, apart from the quick start appetizer, we presented some examples of lazy functions using the ? symbol to act as a placeholder for yet unsupplied arguments. While this is understandable and simple, it is not adequate when we are dealing with complex composition of functions in addition to binary infix, unary prefix and postfix operators.</p>
|
||||
<p>
|
||||
When an arbitrarily complex function composition has M-N = U unsupplied arguments, the ? symbol maps this onto the actual non- lazy function taking U arguments. For example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>f1</span><span class=special>(</span><span class=identifier>f2</span><span class=special>(?, </span><span class=number>2</span><span class=special>), </span><span class=identifier>f3</span><span class=special>(?, </span><span class=identifier>f4</span><span class=special>(?))) </span><span class=special>--> </span><span class=identifier>unnamed_f</span><span class=special>(</span><span class=identifier>a</span><span class=special>, </span><span class=identifier>b</span><span class=special>, </span><span class=identifier>c</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Since there is only 1 supplied argument (N) and we are expecting 4 arguments (M), hence U = 3.</p>
|
||||
<p>
|
||||
It might not be immediately apparent how mapping takes place. It can naively be read from left to right; the first ? in our example maps to a, the second to b, and the last ? maps to c. Yet for even more complex compositions possibly with operators added in the mix, this becomes rather confusing. Also, this is not so flexible: in many occassions, we want to map two or more unknown arguments to a single place-holder.</p>
|
||||
<p>
|
||||
To avoid confusion, rather than using the ? as a symbol for unsupplied arguments, we use a more meaningful and precise representation. This is realized by supplying a numeric representation of the actual argument position (1 to N) in the resulting (right hand) function. Here's our revised example using this scheme:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>f1</span><span class=special>(</span><span class=identifier>f2</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=number>2</span><span class=special>), </span><span class=identifier>f3</span><span class=special>(</span><span class=identifier>arg2</span><span class=special>, </span><span class=identifier>f4</span><span class=special>(</span><span class=identifier>arg3</span><span class=special>))) </span><span class=special>--> </span><span class=identifier>unnamed_f</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg2</span><span class=special>, </span><span class=identifier>arg3</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Now, arg1, arg2 and arg3 are used as placeholders instead of ?. Take note that with this revised scheme, we can now map two or more unsupplied arguments to a single actual argument. Example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>f1</span><span class=special>(</span><span class=identifier>f2</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=number>2</span><span class=special>), </span><span class=identifier>f3</span><span class=special>(</span><span class=identifier>arg2</span><span class=special>, </span><span class=identifier>f4</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>))) </span><span class=special>--> </span><span class=identifier>unnamed_f</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg2</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Notice how we mapped the leftmost and the rightmost unnamed argument to arg1. Consequently, the resulting (right hand) function now expects only two arguments (arg1 and arg2) instead of three. Here are some interesting snippets where this might be useful:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg1</span><span class=special>) </span><span class=special>--> </span><span class=identifier>mult_2</span><span class=special>(</span><span class=identifier>x</span><span class=special>)
|
||||
</span><span class=identifier>mult</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg1</span><span class=special>) </span><span class=special>--> </span><span class=identifier>square</span><span class=special>(</span><span class=identifier>x</span><span class=special>)
|
||||
</span><span class=identifier>mult</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>mult</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg1</span><span class=special>)) </span><span class=special>--> </span><span class=identifier>cube</span><span class=special>(</span><span class=identifier>x</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<a name="extra_arguments"></a><h2>Extra arguments</h2><p>
|
||||
In C and C++, a function can have extra arguments that are not at all used by the function body itself. For instance, call-back functions may provide much more information than is actually needed at once. These extra arguments are just ignored.</p>
|
||||
<p>
|
||||
Phoenix also allows extra arguments to be passed. For example, recall our original add function:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>add</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg2</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
We know now that partially evaluating this function results to a function that expects 2 arguments. However, the framework is a bit more lenient and allows the caller to supply more arguments than is actually required. Thus, our partially evaluated plus(arg1, arg2) function actually allows 2 *or more* arguments to be passed in. For instance, with:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>add</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg2</span><span class=special>)(</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>, </span><span class=number>3</span><span class=special>)
|
||||
|
||||
</span><span class=identifier>the </span><span class=identifier>third </span><span class=identifier>argument </span><span class=literal>'3' </span><span class=identifier>is </span><span class=identifier>merely </span><span class=identifier>ignored</span><span class=special>.
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Taking this further, in-between arguments may even be ignored. Example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>add</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg5</span><span class=special>)(</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>, </span><span class=number>3</span><span class=special>, </span><span class=number>4</span><span class=special>, </span><span class=number>5</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Here, arguments 2, 3, and 4 are ignored. The function add just takes in the first argument (arg1) and the fifth argument (arg5). The result is of course six (6).</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/lens.gif">
|
||||
<b>Strict Arity</b><br><br>There are a few reasons why enforcing strict arity is not desireable. A case in point is the callback function. Typical callback functions provide more information than is actually needed. Lambda functions are often used as callbacks. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="lazy_functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="polymorphic_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
54
phoenix/doc/polymorphic_functions.html
Normal file
@@ -0,0 +1,54 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Polymorphic functions</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="place_holders.html">
|
||||
<link rel="next" href="organization.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Polymorphic functions</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="place_holders.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="organization.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
We've seen the examples and we are already aware that lazy functions are polymorphic. This is important and is reiterated over and over again. Monomorphic functions are passe and simply lacks the horse power in this day and age of generic programming.</p>
|
||||
<p>
|
||||
The framework provides facilities for defining truly polymorphic functions (in <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a> jargon, these are called rank-2 polymorphic functoids). For instance, the plus example above can apply to integers, floating points, user defined complex numbers or even strings. Example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>add</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>arg2</span><span class=special>)(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>(</span><span class=string>"Hello"</span><span class=special>), </span><span class=string>" World"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
evaluates to std::string("Hello World"). The observant reader might notice that this function call in fact takes in heterogeneous arguments of types arg1 = std::string and arg2 = char const*. add still works in this context precisely because the C++ standard library allows the expression a + b where a is a std::string and b is a char const*.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="place_holders.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="organization.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
114
phoenix/doc/preface.html
Normal file
@@ -0,0 +1,114 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Preface</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="next" href="introduction.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Preface</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><img src="theme/l_arr_disabled.gif" border="0"></td>
|
||||
<td width="20"><a href="introduction.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<blockquote><p><i>Functional programming is so called because a program consists entirely of functions. The main program itself is written as a function which receives the program's input as its argument and delivers the program's output as its result. Typically the main function is defined in terms of other functions, which in turn are defined in terms of still more functions until at the bottom level the functions are language primitives.</i></p></blockquote><blockquote><p><b><i>John Hughes</i></b>-- <i>Why Functional Programming Matters</i></p></blockquote><a name="influences_and_related_work"></a><h2>Influences and Related Work</h2><p>
|
||||
The design and implementation of Phoenix is highly influenced by <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a> by Yannis Smaragdakis and Brian McNamara and the (<a href="http://www.boost.org">
|
||||
Boost</a> Lambda Library) <a href="http://www.boost.org/libs/lambda/doc/index.html">
|
||||
BLL</a> by Jaakko Järvi and Gary Powell. Phoenix is a blend of <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a> and <a href="http://www.boost.org/libs/lambda/doc/index.html">
|
||||
BLL</a> using the implementation techniques used in the <a href="http://spirit.sourceforge.net">
|
||||
Spirit</a> inline parser.</p>
|
||||
<p>
|
||||
Is Phoenix better than <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a> or <a href="http://www.boost.org/libs/lambda/doc/index.html">
|
||||
BLL</a>? Well, there are concepts found in Phoenix that are not found in either library. <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a> has rank-2 polymorphic functions (<a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a> jargon) which Phoenix also has, <a href="http://www.boost.org/libs/lambda/doc/index.html">
|
||||
BLL</a> has syntactic sugared operators which <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a> lack, that Phoenix also has.</p>
|
||||
<p>
|
||||
Phoenix inherits <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a>'s rank-2 polymorphic functions. Rank-2 polymorphic functions are higher order functions that can accept polymorphic arguments. <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a> is the first library to enable higher order polymorphic functions. Before <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a>, polymorphic functions couldn't be used as arguments to other functions.</p>
|
||||
<p>
|
||||
What really motivated the author to write Phoenix is the lack of access to a true stack-frame with local variables (closures) in all C++ FP libraries in existence so far. When emulating functions in the form of functors, the most basic ingredient is missing: local variables and a stack. Current FP libraries emulate closures using state variables in functors. In more evolved FP applications, this "poor man's closure" is simply inadequate.</p>
|
||||
<p>
|
||||
Perhaps <a href="http://www.boost.org/libs/lambda/doc/index.html">
|
||||
BLL</a> does not need this at all since unnamed lambda functions cannot call itself anyway; at least not directly. <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a> arguably does not need this since it is purely functional without side-effects, thus there is no need to destructively write to a variable. The highly recursive nature of the <a href="http://spirit.sourceforge.net">
|
||||
Spirit</a> framework from which Phoenix is a derivative work necessitated true reentrant closures. Later on, Phoenix will inherit the <a href="http://spirit.sourceforge.net">
|
||||
Spirit</a> framework's true closures which implement access to true hardware stack based local variables.</p>
|
||||
<p>
|
||||
Phoenix is also extremely modular by design. One can extract and use only a small subset of the full framework, literally tearing the framework into small pieces, without fear that the pieces won't work anymore. For instance, one can use only the <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a> style programming layer with rank-2 polymorphic functions without the sugared operators.</p>
|
||||
<p>
|
||||
Emphasis is given to make Phoenix much more portable to current generation C++ compilers such as Borland and MSVC. Borland for example chokes on both <a href="http://www.boost.org/libs/lambda/doc/index.html">
|
||||
BLL</a> and <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a> code. Forget MSVC support in <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a> and <a href="http://www.boost.org/libs/lambda/doc/index.html">
|
||||
BLL</a>. On the other hand, although Phoenix is not yet ported to MSVC, Phoenix uses the same tried and true implementation techniques used by the <a href="http://spirit.sourceforge.net">
|
||||
Spirit</a> framework. Since <a href="http://spirit.sourceforge.net">
|
||||
Spirit</a> has been ported to MSVC by Bruce Florman (v1.1) and by Raghav Satish (v1.3), it is very likely that Phoenix will also be ported to MSVC.</p>
|
||||
<p>
|
||||
Finally, and most importantly though, Phoenix is intended, hopefully, to be much more easier to use. The focus of Phoenix (and <a href="http://spirit.sourceforge.net">
|
||||
Spirit</a> for that matter), is the typical practicing programmer in the field rather than the gurus and high priests. Think of Phoenix as the C++ FP library for the rest of us <img src="theme/smiley.gif">
|
||||
</p>
|
||||
<a name="how_to_use_this_manual"></a><h2>How to use this manual</h2><p>
|
||||
The Phoenix framework is organized in logical modules. This documentation provides a user's guide and reference for each module in the framework. A simple and clear code example is worth a hundred lines of documentation; therefore, the user's guide is presented with abundant examples annotated and explained in step-wise manner. The user's guide is based on examples. Lots of them.</p>
|
||||
<p>
|
||||
As much as possible, forward information (i.e. citing a specific piece of information that has not yet been discussed) is avoided in the user's manual portion of each module. In many cases, though, it is unavoidable that advanced but related topics not be interspersed with the normal flow of discussion. To alleviate this problem, topics categorized as "advanced" may be skipped at first reading.</p>
|
||||
<p>
|
||||
Some icons are used to mark certain topics indicative of their relevance. These icons precede some text to indicate:</p>
|
||||
<table width="90%" border="0" align="center"> <tr>
|
||||
<td class="table_title" colspan="12">
|
||||
Icons </td>
|
||||
</tr>
|
||||
<tr><tr><td class="table_cells"><img src="theme/note.gif">
|
||||
</td><td class="table_cells"><b>Note</b></td><td class="table_cells">Information provided is moderately important and should be noted by the reader.</td></tr><td class="table_cells"><img src="theme/alert.gif">
|
||||
</td><td class="table_cells"><b>Alert</b></td><td class="table_cells">Information provided is of utmost importance.</td></tr><td class="table_cells"><img src="theme/lens.gif">
|
||||
</td><td class="table_cells"><b>Detail</b></td><td class="table_cells">Information provided is auxiliary but will give the reader a deeper insight into a specific topic. May be skipped.</td></tr></tr><td class="table_cells"><img src="theme/bulb.gif">
|
||||
</td><td class="table_cells"><b>Tip</b></td><td class="table_cells"> A potentially useful and helpful piece of information.</td></tr></table>
|
||||
<p>
|
||||
This documentation is automatically generated by <a href="http://spirit.sourceforge.net">
|
||||
Spirit</a> QuickDoc documentation tool. QuickDoc is part of the <a href="http://spirit.sourceforge.net">
|
||||
Spirit</a> distribution [ See libs/spirit/example/application/quickdoc/ ].</p>
|
||||
<a name="support"></a><h2>Support</h2><p>
|
||||
Please direct all questions to <a href="http://spirit.sourceforge.net">
|
||||
Spirit</a>'s mailing list. You can subscribe to the <a href="https://lists.sourceforge.net/lists/listinfo/spirit-general">
|
||||
Spirit Mailing List</a>. The mailing list has a searchable archive. A search link to this archive is provided in <a href="http://spirit.sourceforge.net">
|
||||
Spirit</a>'s home page. You may also read and post messages to the mailing list through an <a href="news://news.gmane.org/gmane.comp.spirit.general">
|
||||
NNTP news portal</a> (thanks to www.gmane.org). The news group mirrors the mailing list. Here are two links to the archives: via <a href="http://news.gmane.org/thread.php?group=gmane.comp.spirit.general">
|
||||
gmane</a>, via <a href="http://www.geocrawler.com/lists/3/SourceForge/12837/0/">
|
||||
geocrawler</a>.</p>
|
||||
<p>
|
||||
<b><i>To my dear daughter Phoenix</i></b><br><b>Joel de Guzman</b><br>September 2002<br></p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><img src="theme/l_arr_disabled.gif" border="0"></td>
|
||||
<td width="20"><a href="introduction.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
44
phoenix/doc/primitives.html
Normal file
@@ -0,0 +1,44 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Primitives</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="actors.html">
|
||||
<link rel="next" href="arguments.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Primitives</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="actors.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="arguments.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Actors are composed to create more complex actors in a tree-like hierarchy. The primitives are atomic entities that are like the leaves in the tree. Phoenix is extensible. New primitives can be put into action anytime. Right out of the box, there are only a few primitives. This chapter shall deal with these preset primitives.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="actors.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="arguments.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
104
phoenix/doc/quick_start.html
Normal file
@@ -0,0 +1,104 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Quick start</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="introduction.html">
|
||||
<link rel="next" href="basic_concepts.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Quick start</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="introduction.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="basic_concepts.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
To get a first glimpse on what the Phoenix framework offers, let us start with an example. We want to find the first odd number in an STL container.</p>
|
||||
<p>
|
||||
1) Normally we use a functor or a function pointer and pass that in to STL's find_if generic function (sample1.cpp):</p>
|
||||
<p>
|
||||
Write a function:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>bool
|
||||
</span><span class=identifier>is_odd</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>arg1</span><span class=special>)
|
||||
</span><span class=special>{
|
||||
</span><span class=keyword>return </span><span class=identifier>arg1 </span><span class=special>% </span><span class=number>2 </span><span class=special>== </span><span class=number>1</span><span class=special>;
|
||||
</span><span class=special>}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Pass a pointer to the function to STL's find_if generic function:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>find_if</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(), </span><span class=special>&</span><span class=identifier>is_odd</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
2) Using Phoenix, the same can be achieved directly with a one- liner (sample2.cpp):</p>
|
||||
<code><pre>
|
||||
<span class=identifier>find_if</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(), </span><span class=identifier>arg1 </span><span class=special>% </span><span class=number>2 </span><span class=special>== </span><span class=number>1</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
The expression "arg1 % 2 == 1" automagically creates a functor with the expected behavior. In FP, this unnamed function is called a lambda function. Unlike 1, the function pointer version, which is monomorphic (expects and works only with a fixed type int argument), the Phoenix version is completely polymorphic and works with any container (of ints, of doubles, of complex, etc.) as long as its elements can handle the "arg1 % 2 == 1" expression.</p>
|
||||
<p>
|
||||
3) Write a polymorphic functor using Phoenix (sample3.cpp)</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>is_odd_ </span><span class=special>{
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>ArgT</span><span class=special>>
|
||||
</span><span class=keyword>struct </span><span class=identifier>result </span><span class=special>{ </span><span class=keyword>typedef </span><span class=keyword>bool </span><span class=identifier>type</span><span class=special>; </span><span class=special>};
|
||||
|
||||
</span><span class=keyword>template </span><span class=special><</span><span class=keyword>typename </span><span class=identifier>ArgT</span><span class=special>>
|
||||
</span><span class=keyword>bool </span><span class=keyword>operator</span><span class=special>()(</span><span class=identifier>ArgT </span><span class=identifier>arg1</span><span class=special>) </span><span class=keyword>const
|
||||
</span><span class=special>{ </span><span class=keyword>return </span><span class=identifier>arg1 </span><span class=special>% </span><span class=number>2 </span><span class=special>== </span><span class=number>1</span><span class=special>; </span><span class=special>}
|
||||
</span><span class=special>};
|
||||
|
||||
</span><span class=identifier>function</span><span class=special><</span><span class=identifier>is_odd_</span><span class=special>> </span><span class=identifier>is_odd</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Call the lazy is_odd function:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>find_if</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(), </span><span class=identifier>is_odd</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>))
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
is_odd_ is the actual functor. It has been proxied in function<is_odd_> by is_odd (note no trailing underscore) which makes it a lazy function. is_odd_::operator() is the main function body. is_odd_::result is a type computer that answers the question "What should be our return type given an argument of type ArgT?".</p>
|
||||
<p>
|
||||
Like 2, and unlike 1, function pointers or plain C++ functors, is_odd is a true lazy, polymorphic functor (rank-2 polymorphic functoid, in <a href="http://www.cc.gatech.edu/~yannis/fc++/">
|
||||
FC++</a> jargon). The Phoenix functor version is fully polymorphic and works with any container (of ints, of doubles, of complex, etc.) as long as its elements can handle the "arg1 % 2 == 1" expression. However, unlike 2, this is more efficient and has less overhead especially when dealing with much more complex functions.</p>
|
||||
<p>
|
||||
This is just the tip of the iceberg. There are more nifty things you can do with the framework. There are quite interesting concepts such as rank-2 polymorphic lazy functions, lazy statements, binders etc; enough to whet the appetite of anyone wishing to squeeze more power from C++.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="introduction.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="basic_concepts.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
63
phoenix/doc/references.html
Normal file
@@ -0,0 +1,63 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>References</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="wrap_up.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>References</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="wrap_up.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Why Functional Programming Matters, John Hughes...</p>
|
||||
<p>
|
||||
The Lambda Library, Jaakko Jarvi</p>
|
||||
<p>
|
||||
Functional Programming in C++, Brian McNamara and Yannis Smaragdakis</p>
|
||||
<p>
|
||||
Side-effects and partial function application in C++, Jaakko Jarvi and Gary Powell</p>
|
||||
<p>
|
||||
<a href="http://spirit.sourceforge.net">
|
||||
Spirit</a> v1.2, Joel de Guzman</p>
|
||||
<p>
|
||||
C++ static polymorphism patterns ???</p>
|
||||
<p>
|
||||
A Gentle Introduction to <a href="http://www.haskell.org">
|
||||
Haskell</a>, Who??</p>
|
||||
<p>
|
||||
Large scale software design, John Lackos</p>
|
||||
<p>
|
||||
Design Patterns, GOF</p>
|
||||
<p>
|
||||
More???</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="wrap_up.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
258
phoenix/doc/statements.html
Normal file
@@ -0,0 +1,258 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Statements</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="operators.html">
|
||||
<link rel="next" href="binders.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Statements</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="operators.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="binders.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<a name="lazy_statements"></a><h2>Lazy statements</h2><p>
|
||||
The primitives and composite building blocks presented before are sufficiently powerful to construct quite elaborate structures and facilities. We have presented lazy-functions and lazy-operators. How about lazy-statements? First, an appetizer:</p>
|
||||
<p>
|
||||
Print all odd-numbered contents of an STL container using std::for_each (sample4.cpp):</p>
|
||||
<code><pre>
|
||||
<span class=identifier>for_each</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),
|
||||
</span><span class=identifier>if_</span><span class=special>(</span><span class=identifier>arg1 </span><span class=special>% </span><span class=number>2 </span><span class=special>== </span><span class=number>1</span><span class=special>)
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>arg1 </span><span class=special><< </span><span class=literal>' '
|
||||
</span><span class=special>]
|
||||
</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Huh? Is that valid C++? Read on...</p>
|
||||
<p>
|
||||
Yes, it is valid C++. The sample code above is as close as you can get to the syntax of C++. This stylized C++ syntax differs from actual C++ code. First, the if has a trailing underscore. Second, the block uses square brackets [] instead of the familiar curly braces {}.</p>
|
||||
<p>
|
||||
Here are more examples with annotations. The code almost speaks for itself.</p>
|
||||
<p>
|
||||
<b>1) block statement:</b></p>
|
||||
<code><pre>
|
||||
<span class=identifier>statement</span><span class=special>,
|
||||
</span><span class=identifier>statement</span><span class=special>,
|
||||
</span><span class=special>....
|
||||
</span><span class=identifier>statement
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Basically, these are comma separated statements. Take note that unlike the C/C++ semicolon, the comma is a separator put *in-between* statements. This is like Pascal's semicolon separator, rather than C/C++'s semicolon terminator. For example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>statement</span><span class=special>,
|
||||
</span><span class=identifier>statement</span><span class=special>,
|
||||
</span><span class=identifier>statement</span><span class=special>, </span><span class=comment>// ERROR!
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Is an error. The last statement should not have a comma. Block statements can be grouped using the parentheses. Again, the last statement in a group should not have a trailing comma.</p>
|
||||
<code><pre>
|
||||
<span class=identifier>statement</span><span class=special>,
|
||||
</span><span class=identifier>statement</span><span class=special>,
|
||||
</span><span class=special>(
|
||||
</span><span class=identifier>statement</span><span class=special>,
|
||||
</span><span class=identifier>statement
|
||||
</span><span class=special>),
|
||||
</span><span class=identifier>statement
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Outside the square brackets, block statements should be grouped. For example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>for_each</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),
|
||||
</span><span class=special>(
|
||||
</span><span class=identifier>do_this</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>),
|
||||
</span><span class=identifier>do_that</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>)
|
||||
</span><span class=special>)
|
||||
</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
<b>2) if_ statement:</b></p>
|
||||
<p>
|
||||
We have seen the if_ statement. The syntax is:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>if_</span><span class=special>(</span><span class=identifier>conditional_expression</span><span class=special>)
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>sequenced_statements
|
||||
</span><span class=special>]
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
<b>3) if_ else_ statement:</b></p>
|
||||
<p>
|
||||
The syntax is</p>
|
||||
<code><pre>
|
||||
<span class=identifier>if_</span><span class=special>(</span><span class=identifier>conditional_expression</span><span class=special>)
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>sequenced_statements
|
||||
</span><span class=special>]
|
||||
</span><span class=special>.</span><span class=identifier>else_
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>sequenced_statements
|
||||
</span><span class=special>]
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Take note that else has a prefix dot and a trailing underscore: .else_</p>
|
||||
<p>
|
||||
Example: This code prints out all the elements and appends " > 5", " == 5" or " < 5" depending on the element's actual value:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>for_each</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),
|
||||
</span><span class=identifier>if_</span><span class=special>(</span><span class=identifier>arg1 </span><span class=special>> </span><span class=number>5</span><span class=special>)
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>arg1 </span><span class=special><< </span><span class=string>" > 5\n"
|
||||
</span><span class=special>]
|
||||
</span><span class=special>.</span><span class=identifier>else_
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>if_</span><span class=special>(</span><span class=identifier>arg1 </span><span class=special>== </span><span class=number>5</span><span class=special>)
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>arg1 </span><span class=special><< </span><span class=string>" == 5\n"
|
||||
</span><span class=special>]
|
||||
</span><span class=special>.</span><span class=identifier>else_
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>arg1 </span><span class=special><< </span><span class=string>" < 5\n"
|
||||
</span><span class=special>]
|
||||
</span><span class=special>]
|
||||
</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Notice how the if_ else_ statement is nested.</p>
|
||||
<p>
|
||||
<b>4) while_ statement:</b></p>
|
||||
<p>
|
||||
The syntax is:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>while_</span><span class=special>(</span><span class=identifier>conditional_expression</span><span class=special>)
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>sequenced_statements
|
||||
</span><span class=special>]
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Example: This code decrements each element until it reaches zero and prints out the number at each step. A newline terminates the printout of each value.</p>
|
||||
<code><pre>
|
||||
<span class=identifier>for_each</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),
|
||||
</span><span class=special>(
|
||||
</span><span class=identifier>while_</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>--)
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>arg1 </span><span class=special><< </span><span class=string>", "
|
||||
</span><span class=special>],
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>val</span><span class=special>(</span><span class=string>"\n"</span><span class=special>)
|
||||
</span><span class=special>)
|
||||
</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
<b>5) do_ while_ statement:</b></p>
|
||||
<p>
|
||||
The syntax is:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>do_
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>sequenced_statements
|
||||
</span><span class=special>]
|
||||
</span><span class=special>.</span><span class=identifier>while_</span><span class=special>(</span><span class=identifier>conditional_expression</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Again, take note that while has a prefix dot and a trailing underscore: .while_</p>
|
||||
<p>
|
||||
Example: This code is almost the same as the previous example above with a slight twist in logic.</p>
|
||||
<code><pre>
|
||||
<span class=identifier>for_each</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),
|
||||
</span><span class=special>(
|
||||
</span><span class=identifier>do_
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>arg1 </span><span class=special><< </span><span class=string>", "
|
||||
</span><span class=special>]
|
||||
</span><span class=special>.</span><span class=identifier>while_</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>--),
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>val</span><span class=special>(</span><span class=string>"\n"</span><span class=special>)
|
||||
</span><span class=special>)
|
||||
</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
<b>6) for_ statement:</b></p>
|
||||
<p>
|
||||
The syntax is:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>for_</span><span class=special>(</span><span class=identifier>init_statement</span><span class=special>, </span><span class=identifier>conditional_expression</span><span class=special>, </span><span class=identifier>step_statement</span><span class=special>)
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>sequenced_statements
|
||||
</span><span class=special>]
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
It is again almost similar to C++ for statement. Take note that the init_statement, conditional_expression and step_statement are separated by the comma instead of the semi- colon and each must be present (i.e. for_(,,) is invalid).</p>
|
||||
<p>
|
||||
Example: This code prints each element N times where N is the element's value. A newline terminates the printout of each value.</p>
|
||||
<code><pre>
|
||||
<span class=keyword>int </span><span class=identifier>iii</span><span class=special>;
|
||||
</span><span class=identifier>for_each</span><span class=special>(</span><span class=identifier>c</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(), </span><span class=identifier>c</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),
|
||||
</span><span class=special>(
|
||||
</span><span class=identifier>for_</span><span class=special>(</span><span class=identifier>var</span><span class=special>(</span><span class=identifier>iii</span><span class=special>) </span><span class=special>= </span><span class=number>0</span><span class=special>, </span><span class=identifier>var</span><span class=special>(</span><span class=identifier>iii</span><span class=special>) </span><span class=special>< </span><span class=identifier>arg1</span><span class=special>, </span><span class=special>++</span><span class=identifier>var</span><span class=special>(</span><span class=identifier>iii</span><span class=special>))
|
||||
</span><span class=special>[
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>arg1 </span><span class=special><< </span><span class=string>", "
|
||||
</span><span class=special>],
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>val</span><span class=special>(</span><span class=string>"\n"</span><span class=special>)
|
||||
</span><span class=special>)
|
||||
</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
As before, all these are lazily evaluated. The result of such statements are in fact composites that are passed on to STL's for_each function. In the viewpoint of for_each, what was passed is just a functor, no more, no less.</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/note.gif">
|
||||
Unlike lazy functions and lazy operators, lazy statements always return void. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="operators.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="binders.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
4
phoenix/doc/theme/Makefile.am
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
#This file generated by Makefileamgen.sh
|
||||
EXTRA_DIST = alert.gif arrow.gif bkd.gif bkd2.gif bulb.gif bullet.gif l_arr.gif l_arr_disabled.gif lens.gif note.gif r_arr.gif r_arr_disabled.gif smiley.gif spirit.gif style.css u_arr.gif
|
||||
html_DATA = $(EXTRA_DIST)
|
||||
htmldir = $(prefix)/libs/spirit/theme
|
||||
BIN
phoenix/doc/theme/Thumbs.db
vendored
Normal file
BIN
phoenix/doc/theme/alert.gif
vendored
Normal file
|
After Width: | Height: | Size: 577 B |
BIN
phoenix/doc/theme/arrow.gif
vendored
Normal file
|
After Width: | Height: | Size: 70 B |
BIN
phoenix/doc/theme/bkd.gif
vendored
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
phoenix/doc/theme/bkd2.gif
vendored
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
phoenix/doc/theme/bulb.gif
vendored
Normal file
|
After Width: | Height: | Size: 944 B |
BIN
phoenix/doc/theme/bullet.gif
vendored
Normal file
|
After Width: | Height: | Size: 152 B |
BIN
phoenix/doc/theme/l_arr.gif
vendored
Normal file
|
After Width: | Height: | Size: 147 B |
BIN
phoenix/doc/theme/l_arr_disabled.gif
vendored
Normal file
|
After Width: | Height: | Size: 91 B |
BIN
phoenix/doc/theme/lens.gif
vendored
Normal file
|
After Width: | Height: | Size: 897 B |
BIN
phoenix/doc/theme/note.gif
vendored
Normal file
|
After Width: | Height: | Size: 151 B |
BIN
phoenix/doc/theme/r_arr.gif
vendored
Normal file
|
After Width: | Height: | Size: 147 B |
BIN
phoenix/doc/theme/r_arr_disabled.gif
vendored
Normal file
|
After Width: | Height: | Size: 91 B |
BIN
phoenix/doc/theme/smiley.gif
vendored
Normal file
|
After Width: | Height: | Size: 879 B |
BIN
phoenix/doc/theme/spirit.gif
vendored
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
170
phoenix/doc/theme/style.css
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
body
|
||||
{
|
||||
background-image: url(bkd.gif);
|
||||
background-color: #FFFFFF;
|
||||
margin: 1em 2em 1em 2em;
|
||||
}
|
||||
|
||||
h1 { font-family: Verdana, Arial, Helvetica, sans-serif; font-weight: bold; text-align: left; }
|
||||
h2 { font: 140% sans-serif; font-weight: bold; text-align: left; }
|
||||
h3 { font: 120% sans-serif; font-weight: bold; text-align: left; }
|
||||
h4 { font: bold 100% sans-serif; font-weight: bold; text-align: left; }
|
||||
h5 { font: italic 100% sans-serif; font-weight: bold; text-align: left; }
|
||||
h6 { font: small-caps 100% sans-serif; font-weight: bold; text-align: left; }
|
||||
|
||||
pre
|
||||
{
|
||||
border-top: gray 1pt solid;
|
||||
border-right: gray 1pt solid;
|
||||
border-left: gray 1pt solid;
|
||||
border-bottom: gray 1pt solid;
|
||||
|
||||
padding-top: 2pt;
|
||||
padding-right: 2pt;
|
||||
padding-left: 2pt;
|
||||
padding-bottom: 2pt;
|
||||
|
||||
display: block;
|
||||
font-family: "courier new", courier, mono;
|
||||
background-color: #eeeeee; font-size: small
|
||||
}
|
||||
|
||||
code
|
||||
{
|
||||
font-family: "Courier New", Courier, mono;
|
||||
font-size: small
|
||||
}
|
||||
|
||||
tt
|
||||
{
|
||||
display: inline;
|
||||
font-family: "Courier New", Courier, mono;
|
||||
color: #000099;
|
||||
font-size: small
|
||||
}
|
||||
|
||||
p
|
||||
{
|
||||
text-align: justify;
|
||||
font-family: Georgia, "Times New Roman", Times, serif
|
||||
}
|
||||
|
||||
ul
|
||||
{
|
||||
list-style-image: url(bullet.gif);
|
||||
font-family: Georgia, "Times New Roman", Times, serif
|
||||
}
|
||||
|
||||
ol
|
||||
{
|
||||
font-family: Georgia, "Times New Roman", Times, serif
|
||||
}
|
||||
|
||||
a
|
||||
{
|
||||
font-weight: bold;
|
||||
color: #003366;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover { color: #8080FF; }
|
||||
|
||||
.literal { color: #666666; font-style: italic}
|
||||
.keyword { color: #000099}
|
||||
.identifier {}
|
||||
.comment { font-style: italic; color: #990000}
|
||||
.special { color: #800040}
|
||||
.preprocessor { color: #FF0000}
|
||||
.string { font-style: italic; color: #666666}
|
||||
.copyright { color: #666666; font-size: small}
|
||||
.white_bkd { background-color: #FFFFFF}
|
||||
.dk_grey_bkd { background-color: #999999}
|
||||
.quotes { color: #666666; font-style: italic; font-weight: bold}
|
||||
|
||||
.note_box
|
||||
{
|
||||
display: block;
|
||||
|
||||
border-top: gray 1pt solid;
|
||||
border-right: gray 1pt solid;
|
||||
border-left: gray 1pt solid;
|
||||
border-bottom: gray 1pt solid;
|
||||
|
||||
padding-right: 12pt;
|
||||
padding-left: 12pt;
|
||||
padding-bottom: 12pt;
|
||||
padding-top: 12pt;
|
||||
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
background-color: #E2E9EF;
|
||||
font-size: small; text-align: justify
|
||||
}
|
||||
|
||||
.table_title
|
||||
{
|
||||
background-color: #648CCA;
|
||||
|
||||
font-family: Verdana, Arial, Helvetica, sans-serif; color: #FFFFFF;
|
||||
font-weight: bold
|
||||
; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px
|
||||
}
|
||||
|
||||
.table_cells
|
||||
{
|
||||
background-color: #E2E9EF;
|
||||
|
||||
font-family: Geneva, Arial, Helvetica, san-serif;
|
||||
font-size: small
|
||||
; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px
|
||||
}
|
||||
|
||||
.toc
|
||||
{
|
||||
DISPLAY: block;
|
||||
background-color: #E2E9EF
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
|
||||
border-top: gray 1pt solid;
|
||||
border-left: gray 1pt solid;
|
||||
border-bottom: gray 1pt solid;
|
||||
border-right: gray 1pt solid;
|
||||
|
||||
padding-top: 24pt;
|
||||
padding-right: 24pt;
|
||||
padding-left: 24pt;
|
||||
padding-bottom: 24pt;
|
||||
}
|
||||
|
||||
.toc_title
|
||||
{
|
||||
background-color: #648CCA;
|
||||
padding-top: 4px;
|
||||
padding-right: 4px;
|
||||
padding-bottom: 4px;
|
||||
padding-left: 4px;
|
||||
font-family: Geneva, Arial, Helvetica, san-serif;
|
||||
color: #FFFFFF;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
.toc_cells
|
||||
{
|
||||
background-color: #E2E9EF;
|
||||
padding-top: 4px;
|
||||
padding-right: 4px;
|
||||
padding-bottom: 4px;
|
||||
padding-left: 4px;
|
||||
font-family: Geneva, Arial, Helvetica, san-serif;
|
||||
font-size: small
|
||||
}
|
||||
|
||||
div.logo
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
|
||||
.toc_cells_L0 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
||||
.toc_cells_L1 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 44px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
||||
.toc_cells_L2 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 88px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
||||
.toc_cells_L3 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 122px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
||||
.toc_cells_L4 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 166px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
||||
BIN
phoenix/doc/theme/u_arr.gif
vendored
Normal file
|
After Width: | Height: | Size: 170 B |
112
phoenix/doc/tuples.html
Normal file
@@ -0,0 +1,112 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Tuples</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="inside_phoenix.html">
|
||||
<link rel="next" href="actors_revisited.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Tuples</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="inside_phoenix.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="actors_revisited.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Tuples are the most basic infrastructure that the framework builds with. This sub-library provides a mechanism to bundle objects of arbitrary types in a single structure. Tuples hold heterogeneous types up to a predefined maximum.</p>
|
||||
<p>
|
||||
Only the most basic functionality needed are provided. This is a straight-forward and extremely lean and mean library. Unlike other recursive list-like tuple implementations, this tuple library implementation uses simple structs similar to std::pair with specialization for 0 to N tuple elements, where N is a predefined constant. There are only 4 tuple operations to learn:</p>
|
||||
<p>
|
||||
1) Construction</p>
|
||||
<p>
|
||||
Here are examples on how to construct tuples:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>typedef </span><span class=identifier>tuple</span><span class=special><</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>char</span><span class=special>> </span><span class=identifier>t1_t</span><span class=special>;
|
||||
</span><span class=keyword>typedef </span><span class=identifier>tuple</span><span class=special><</span><span class=keyword>int</span><span class=special>, </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>, </span><span class=keyword>double</span><span class=special>> </span><span class=identifier>t2_t</span><span class=special>;
|
||||
|
||||
</span><span class=comment>// this tuple has an int and char members
|
||||
</span><span class=identifier>t1_t </span><span class=identifier>t1</span><span class=special>(</span><span class=number>3</span><span class=special>, </span><span class=literal>'c'</span><span class=special>);
|
||||
|
||||
</span><span class=comment>// this tuple has an int, std::string and double members
|
||||
</span><span class=identifier>t2_t </span><span class=identifier>t2</span><span class=special>(</span><span class=number>3</span><span class=special>, </span><span class=string>"hello"</span><span class=special>, </span><span class=number>3.14</span><span class=special>);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
2) Member access</p>
|
||||
<p>
|
||||
A member in a tuple can be accessed using the tuple's [] operator by specifying the Nth tuple_index. Here are some examples:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>tuple_index</span><span class=special><</span><span class=number>0</span><span class=special>> </span><span class=identifier>ix0</span><span class=special>; </span><span class=comment>// 0th index == 1st item
|
||||
</span><span class=identifier>tuple_index</span><span class=special><</span><span class=number>1</span><span class=special>> </span><span class=identifier>ix1</span><span class=special>; </span><span class=comment>// 1st index == 2nd item
|
||||
</span><span class=identifier>tuple_index</span><span class=special><</span><span class=number>2</span><span class=special>> </span><span class=identifier>ix2</span><span class=special>; </span><span class=comment>// 2nd index == 3rd item
|
||||
|
||||
// Note zero based indexing. 0 = 1st item, 1 = 2nd item
|
||||
|
||||
</span><span class=identifier>t1</span><span class=special>[</span><span class=identifier>ix0</span><span class=special>] </span><span class=special>= </span><span class=number>33</span><span class=special>; </span><span class=comment>// sets the int member of the tuple t1
|
||||
</span><span class=identifier>t2</span><span class=special>[</span><span class=identifier>ix2</span><span class=special>] </span><span class=special>= </span><span class=number>6e6</span><span class=special>; </span><span class=comment>// sets the double member of the tuple t2
|
||||
</span><span class=identifier>t1</span><span class=special>[</span><span class=identifier>ix1</span><span class=special>] </span><span class=special>= </span><span class=literal>'a'</span><span class=special>; </span><span class=comment>// sets the char member of the tuple t1
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Access to out of bound indexes returns a nil_t value.</p>
|
||||
<p>
|
||||
3) Member type inquiry</p>
|
||||
<p>
|
||||
The type of an individual member can be queried. Example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>tuple_element</span><span class=special><</span><span class=number>1</span><span class=special>, </span><span class=identifier>t2_t</span><span class=special>>::</span><span class=identifier>type
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Refers to the type of the second member (again note zero based indexing, hence 0 = 1st item, 1 = 2nd item) of the tuple.</p>
|
||||
<p>
|
||||
Access to out of bound indexes returns a nil_t type.</p>
|
||||
<p>
|
||||
4) Tuple length</p>
|
||||
<p>
|
||||
The number of elements in a tuple can be queried. Example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>int </span><span class=identifier>n </span><span class=special>= </span><span class=identifier>t1</span><span class=special>.</span><span class=identifier>length</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
gets the number of elements in tuple t1.</p>
|
||||
<p>
|
||||
length is a static constant. Thus, TupleT::length also works. Example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>int </span><span class=identifier>n </span><span class=special>= </span><span class=identifier>t1_t</span><span class=special>::</span><span class=identifier>length</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="inside_phoenix.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="actors_revisited.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
74
phoenix/doc/values.html
Normal file
@@ -0,0 +1,74 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Values</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="arguments.html">
|
||||
<link rel="next" href="variables.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Values</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="arguments.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="variables.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Whenever we see a constant in a curryable-function such as the plus above, an actor<value<T> > (where T is the type of the constant) is, by default, automatically created for us. For instance, the example plus above is actually equivalent to:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>actor</span><span class=special><</span><span class=identifier>value</span><span class=special><</span><span class=keyword>int</span><span class=special>> </span><span class=special>>(</span><span class=identifier>value</span><span class=special><</span><span class=keyword>int</span><span class=special>>(</span><span class=number>6</span><span class=special>)))
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
A nifty shortcut is the val(v) utility function. The expression above is also equivalent to:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=identifier>val</span><span class=special>(</span><span class=number>6</span><span class=special>))
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
actor<value<int> >(value<int>(6)) is implicitly created behind the scenes, so there's really no need to explicitly type everything but:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus</span><span class=special>(</span><span class=identifier>arg1</span><span class=special>, </span><span class=number>6</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
There are situations though, as we'll see later on, where we might want to explicily write val(x).</p>
|
||||
<p>
|
||||
Like arguments, values are also actors. As such, values can be evaluated through the actor's operator(). Such invocation gives the value's identity. Example:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>cout </span><span class=special><< </span><span class=identifier>val</span><span class=special>(</span><span class=number>3</span><span class=special>)() </span><span class=special><< </span><span class=identifier>val</span><span class=special>(</span><span class=string>"Hello World"</span><span class=special>)();
|
||||
|
||||
</span><span class=identifier>prints </span><span class=identifier>out </span><span class=string>"3 Hello World"</span><span class=special>.
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="arguments.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="variables.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
91
phoenix/doc/variables.html
Normal file
@@ -0,0 +1,91 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Variables</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="values.html">
|
||||
<link rel="next" href="composites.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Variables</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="values.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="composites.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Values are immutable constants which cannot be modified at all. Attempting to do so will result in a compile time error. When we want the function to modify the parameter, we use a variable instead. For instance, imagine a curryable (lazy) function plus_assign:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus_assign</span><span class=special>(</span><span class=identifier>x</span><span class=special>, </span><span class=identifier>y</span><span class=special>) </span><span class=special>{ </span><span class=identifier>x </span><span class=special>+= </span><span class=identifier>y</span><span class=special>; </span><span class=special>}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Here, we want the first function argument x to be mutable. Obviously, we cannot write:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus_assign</span><span class=special>(</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>) </span><span class=comment>// error first argument is immutable
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
In C++, we can pass in a reference to a variable as the first argument in our example above. Yet, by default, the Phoenix framework forces arguments passed to curryable functions to be constant immutable values. To achive our intent, we use the variable<T> class. This is similar to the value<T> class above but instead holds a reference to a variable instead. For example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>int </span><span class=identifier>i_</span><span class=special>;
|
||||
</span><span class=identifier>actor</span><span class=special><</span><span class=identifier>variable</span><span class=special><</span><span class=keyword>int</span><span class=special>> </span><span class=special>> </span><span class=identifier>i </span><span class=special>= </span><span class=identifier>i_</span><span class=special>;
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
now, we can use our actor<variable<int> > 'i' as argument to the plus_assign lazy function:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus_assign</span><span class=special>(</span><span class=identifier>i</span><span class=special>, </span><span class=number>2</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
A shortcut is the var(v) utility function. The expression above is also equivalent to:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>plus_assign</span><span class=special>(</span><span class=identifier>var</span><span class=special>(</span><span class=identifier>i_</span><span class=special>), </span><span class=number>2</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
Lazy variables are actors. As such, variables can be evaluated through the actor's operator(). Such invocation gives the variables's identity. Example:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>int </span><span class=identifier>i </span><span class=special>= </span><span class=number>3</span><span class=special>;
|
||||
</span><span class=keyword>char </span><span class=keyword>const</span><span class=special>* </span><span class=identifier>s </span><span class=special>= </span><span class=string>"Hello World"</span><span class=special>;
|
||||
</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>var</span><span class=special>(</span><span class=identifier>i</span><span class=special>)() </span><span class=special><< </span><span class=identifier>var</span><span class=special>(</span><span class=identifier>s</span><span class=special>)();
|
||||
</span></pre></code>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
prints out "3 Hello World"</p>
|
||||
<p>
|
||||
Finally, another free function const_ref(cv) may also be used. const_ref(cv) creates an actor<variable<T const&> > object where the data is referenced using a constant reference. This is similar to value<T> but when the data to be passed as argument to a function is heavy and expensive to copy by value, the const_ref(cv) offers a low overhead alternative.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="values.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="composites.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
54
phoenix/doc/wrap_up.html
Normal file
@@ -0,0 +1,54 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Wrap up</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="interfacing.html">
|
||||
<link rel="next" href="references.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Wrap up</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="interfacing.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="references.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Sooner or later more FP techniques become standard practice as people find the true value of this programming discipline outside the academe and into the mainstream. In as much as the structured programming of the 70s and object oriented programming in the 80s and generic programming in the 90s shaped our thoughts towards a more robust sense of software engineering, FP will certainly be a paradigm that will catapult us towards more powerful software design and engineering onward into the new millenium.</p>
|
||||
<p>
|
||||
Let me quote Doug Gregor of <a href="http://www.boost.org">
|
||||
Boost</a>.org. About functional style programming libraries:</p>
|
||||
<blockquote><p><i>They're gaining acceptance, but are somewhat stunted by the ubiquitousness of broken compilers. The C++ community is moving deeper into the so-called "STL-style" programming paradigm, which brings many aspects of functional programming into the fold. Look at, for instance, the <a href="http://spirit.sourceforge.net">
|
||||
Spirit</a> parser to see how such function objects can be used to build Yacc-like grammars with semantic actions that can build abstract syntax trees on the fly. This type of functional composition is gaining momentum.</i></p></blockquote><p>
|
||||
Indeed. Phoenix is another attempt to introduce more FP techniques into the mainstream. Not only is it a tool that will make life easier for the programmer. In its own right, the actual design of the framework itself is a model of true C++ FP in action. The framework is designed and structured in a strict but clear and well mannered FP sense. By all means, use the framework as a tool. But for those who want to learn more about FP in C++, don't stop there, I invite you to take a closer look at the design of the framework itself.</p>
|
||||
<p>
|
||||
The whole framework is rather small and comprises of only a couple of header files. There are no object files to link against. Unlike most FP libraries in C++, Phoenix is portable to more C++ compilers in existence. Currently it works on Borland 5.5.1, Comeau 4.24, G++ 2.95.2, G++ 3.03, G++ 3.1, Intel 5.0, Intel 6.0, Code Warrior 7.2 and perhaps soon, to MSVC.</p>
|
||||
<p>
|
||||
So there you have it. Have fun! See you in the FP world.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="interfacing.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="references.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
73
phoenix/example/Jamfile
Normal file
@@ -0,0 +1,73 @@
|
||||
#
|
||||
# Phoenix examples boost-jam file
|
||||
# Joel de Guzman [Sept 27, 2002]
|
||||
#
|
||||
|
||||
subproject libs/phoenix/example ;
|
||||
|
||||
unit-test sample1
|
||||
: fundamental/sample1.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
unit-test sample2
|
||||
: fundamental/sample2.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
unit-test sample3
|
||||
: fundamental/sample3.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
unit-test sample4
|
||||
: fundamental/sample4.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
unit-test sample5
|
||||
: fundamental/sample5.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
unit-test sample6
|
||||
: fundamental/sample6.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
unit-test sample7
|
||||
: fundamental/sample7.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
unit-test sample8
|
||||
: fundamental/sample8.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
unit-test sample9
|
||||
: fundamental/sample9.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
unit-test sample10
|
||||
: fundamental/sample10.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
unit-test closures
|
||||
: fundamental/closures.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
3
phoenix/example/Makefile.am
Normal file
@@ -0,0 +1,3 @@
|
||||
SUBDIRS = fundamental
|
||||
|
||||
EXTRA_DIST = Jamfile
|
||||
59
phoenix/example/fundamental/closures.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
#define PHOENIX_LIMIT 15
|
||||
#include "boost/spirit/phoenix/operators.hpp"
|
||||
#include "boost/spirit/phoenix/primitives.hpp"
|
||||
#include "boost/spirit/phoenix/composite.hpp"
|
||||
#include "boost/spirit/phoenix/special_ops.hpp"
|
||||
#include "boost/spirit/phoenix/statements.hpp"
|
||||
#include "boost/spirit/phoenix/functions.hpp"
|
||||
#include "boost/spirit/phoenix/closures.hpp"
|
||||
|
||||
//////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace phoenix;
|
||||
|
||||
//////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
struct my_closure : closure<int, string, double> {
|
||||
|
||||
member1 num;
|
||||
member2 message;
|
||||
member3 real;
|
||||
};
|
||||
|
||||
my_closure clos;
|
||||
|
||||
{ // First stack frame
|
||||
closure_frame<my_closure::self_t> frame(clos);
|
||||
(clos.num = 123)();
|
||||
(clos.num += 456)();
|
||||
(clos.real = clos.num / 56.5)();
|
||||
(clos.message = "Hello " + string("World "))();
|
||||
|
||||
{ // Second stack frame
|
||||
closure_frame<my_closure::self_t> frame(clos);
|
||||
(clos.num = 987)();
|
||||
(clos.message = "Abracadabra ")();
|
||||
(clos.real = clos.num * 1e30)();
|
||||
|
||||
{ // Third stack frame
|
||||
tuple<int, char const*, double> init(-1, "Direct Init ", 3.14);
|
||||
closure_frame<my_closure::self_t> frame(clos, init);
|
||||
|
||||
(cout << clos.message << clos.num << ", " << clos.real << '\n')();
|
||||
}
|
||||
|
||||
(cout << clos.message << clos.num << ", " << clos.real << '\n')();
|
||||
}
|
||||
|
||||
(cout << clos.message << clos.num << ", " << clos.real << '\n')();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
517
phoenix/example/fundamental/sample10.cpp
Normal file
@@ -0,0 +1,517 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#define PHOENIX_LIMIT 5
|
||||
#include "boost/spirit/phoenix/operators.hpp"
|
||||
#include "boost/spirit/phoenix/primitives.hpp"
|
||||
#include "boost/spirit/phoenix/composite.hpp"
|
||||
#include "boost/spirit/phoenix/special_ops.hpp"
|
||||
#include "boost/spirit/phoenix/statements.hpp"
|
||||
#include "boost/spirit/phoenix/functions.hpp"
|
||||
|
||||
namespace phoenix {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// local_tuple
|
||||
//
|
||||
// This *is a* tuple like the one we see in TupleT in any actor
|
||||
// base class' eval member function. local_tuple should look and
|
||||
// feel the same as a tupled-args, that's why it is derived from
|
||||
// TupleArgsT. It has an added member, locs which is another tuple
|
||||
// where the local variables will be stored. locs is mutable to
|
||||
// allow read-write access to our locals regardless of
|
||||
// local_tuple's constness (The eval member function accepts it as
|
||||
// a const argument).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename TupleArgsT, typename TupleLocsT>
|
||||
struct local_tuple : public TupleArgsT {
|
||||
|
||||
local_tuple(TupleArgsT const& args, TupleLocsT const& locs_)
|
||||
: TupleArgsT(args), locs(locs_) {}
|
||||
|
||||
mutable TupleLocsT locs;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// local_var_result
|
||||
//
|
||||
// This is a return type computer. Given a constant integer N, a
|
||||
// parent index and a tuple, get the Nth local variable type. The
|
||||
// parent index is an integer specifying which parent scope to
|
||||
// access; 0==current scope, 1==parent scope, 2==parent's parent
|
||||
// scope etc.
|
||||
//
|
||||
// This is a metaprogram with partial specializations. There is a
|
||||
// general case, a special case for local_tuples and a terminating
|
||||
// special case for local_tuples.
|
||||
//
|
||||
// General case: If TupleT is not really a local_tuple, we just return nil_t.
|
||||
//
|
||||
// local_tuples case:
|
||||
// Parent index is 0: We get the Nth local variable.
|
||||
// Otherwise: We subclass from local_tuples<N, Parent-1, TupleArgsT>
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <int N, int Parent, typename TupleT>
|
||||
struct local_var_result {
|
||||
|
||||
typedef nil_t type;
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <int N, int Parent, typename TupleArgsT, typename TupleLocsT>
|
||||
struct local_var_result<N, Parent, local_tuple<TupleArgsT, TupleLocsT> >
|
||||
: public local_var_result<N, Parent-1, TupleArgsT> {};
|
||||
|
||||
//////////////////////////////////
|
||||
template <int N, typename TupleArgsT, typename TupleLocsT>
|
||||
struct local_var_result<N, 0, local_tuple<TupleArgsT, TupleLocsT> > {
|
||||
|
||||
typedef typename tuple_element<N, TupleLocsT>::type& type;
|
||||
|
||||
static type get(local_tuple<TupleArgsT, TupleLocsT> const& tuple)
|
||||
{ return tuple.locs[tuple_index<N>()]; }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// local_var
|
||||
//
|
||||
// This class looks so curiously like the argument class. local_var
|
||||
// provides access to the Nth local variable packed in the tuple
|
||||
// duo local_tuple above. Parent specifies the Nth parent scope.
|
||||
// 0==current scope, 1==parent scope, 2==parent's parent scope etc.
|
||||
// The member function parent<N>() may be called to provide access
|
||||
// to outer scopes.
|
||||
//
|
||||
// Note that the member function eval expects a local_tuple
|
||||
// argument. Otherwise there will be acompile-time error. local_var
|
||||
// primitives only work within the context of a context_composite
|
||||
// (see below).
|
||||
//
|
||||
// Provided are some predefined local_var actors for 0..N local
|
||||
// variable access: lvar1..locN.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <int N, int Parent = 0>
|
||||
struct local_var {
|
||||
|
||||
typedef local_var<N, Parent> self_t;
|
||||
|
||||
template <typename TupleT>
|
||||
struct result {
|
||||
|
||||
typedef typename local_var_result<N, Parent, TupleT>::type type;
|
||||
};
|
||||
|
||||
template <typename TupleT>
|
||||
typename actor_result<self_t, TupleT>::type
|
||||
eval(TupleT const& tuple) const
|
||||
{
|
||||
return local_var_result<N, Parent, TupleT>::get(tuple);
|
||||
}
|
||||
|
||||
template <int PIndex>
|
||||
actor<local_var<N, Parent+PIndex> >
|
||||
parent() const
|
||||
{
|
||||
return local_var<N, Parent+PIndex>();
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
namespace locals {
|
||||
|
||||
actor<local_var<0> > const result = local_var<0>();
|
||||
actor<local_var<1> > const lvar1 = local_var<1>();
|
||||
actor<local_var<2> > const lvar2 = local_var<2>();
|
||||
actor<local_var<3> > const lvar3 = local_var<3>();
|
||||
actor<local_var<4> > const lvar4 = local_var<4>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <int N, int Parent, typename TupleT>
|
||||
struct local_func_result {
|
||||
|
||||
typedef nil_t type;
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <int N, int Parent, typename TupleArgsT, typename TupleLocsT>
|
||||
struct local_func_result<N, Parent, local_tuple<TupleArgsT, TupleLocsT> >
|
||||
: public local_func_result<N, Parent-1, TupleArgsT> {};
|
||||
|
||||
//////////////////////////////////
|
||||
template <int N, typename TupleArgsT, typename TupleLocsT>
|
||||
struct local_func_result<N, 0, local_tuple<TupleArgsT, TupleLocsT> > {
|
||||
|
||||
typedef typename actor_result<
|
||||
typename tuple_element<N, TupleLocsT>::type,
|
||||
local_tuple<TupleArgsT, TupleLocsT>
|
||||
>::type type;
|
||||
|
||||
template <typename ArgsT>
|
||||
static type eval(local_tuple<ArgsT, TupleLocsT> const& tuple)
|
||||
{ return tuple.locs[tuple_index<N>()].eval(tuple); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <
|
||||
int N, int Parent,
|
||||
typename A0 = nil_t,
|
||||
typename A1 = nil_t,
|
||||
typename A2 = nil_t,
|
||||
typename A3 = nil_t,
|
||||
typename A4 = nil_t
|
||||
>
|
||||
struct local_function_actor;
|
||||
|
||||
//////////////////////////////////
|
||||
template <int N, int Parent>
|
||||
struct local_function_base {
|
||||
|
||||
template <typename TupleT>
|
||||
struct result {
|
||||
|
||||
typedef typename local_func_result<N, Parent, TupleT>::type type;
|
||||
};
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <int N, int Parent>
|
||||
struct local_function_actor<N, Parent, nil_t, nil_t, nil_t, nil_t, nil_t>
|
||||
: public local_function_base<N, Parent> {
|
||||
|
||||
template <typename TupleArgsT, typename TupleLocsT>
|
||||
typename local_func_result<
|
||||
N, Parent, local_tuple<TupleArgsT, TupleLocsT> >::type
|
||||
eval(local_tuple<TupleArgsT, TupleLocsT> const& args) const
|
||||
{
|
||||
typedef local_tuple<TupleArgsT, TupleLocsT> local_tuple_t;
|
||||
typedef tuple<> tuple_t;
|
||||
tuple_t local_args;
|
||||
|
||||
local_tuple<tuple_t, TupleLocsT> local_context(local_args, args.locs);
|
||||
return local_func_result<
|
||||
N, Parent, local_tuple_t>
|
||||
::eval(local_context);
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <int N, int Parent,
|
||||
typename A0>
|
||||
struct local_function_actor<N, Parent, A0, nil_t, nil_t, nil_t, nil_t>
|
||||
: public local_function_base<N, Parent> {
|
||||
|
||||
local_function_actor(
|
||||
A0 const& _0)
|
||||
: a0(_0) {}
|
||||
|
||||
template <typename TupleArgsT, typename TupleLocsT>
|
||||
typename local_func_result<
|
||||
N, Parent, local_tuple<TupleArgsT, TupleLocsT> >::type
|
||||
eval(local_tuple<TupleArgsT, TupleLocsT> const& args) const
|
||||
{
|
||||
typedef local_tuple<TupleArgsT, TupleLocsT> local_tuple_t;
|
||||
typename actor_result<A0, local_tuple_t>::type r0 = a0.eval(args);
|
||||
|
||||
typedef tuple<
|
||||
typename actor_result<A0, local_tuple_t>::type
|
||||
> tuple_t;
|
||||
tuple_t local_args(r0);
|
||||
|
||||
local_tuple<tuple_t, TupleLocsT> local_context(local_args, args.locs);
|
||||
return local_func_result<
|
||||
N, Parent, local_tuple_t>
|
||||
::eval(local_context);
|
||||
}
|
||||
|
||||
A0 a0; // actors
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
template <
|
||||
int N, int Parent,
|
||||
typename T0 = nil_t,
|
||||
typename T1 = nil_t,
|
||||
typename T2 = nil_t,
|
||||
typename T3 = nil_t,
|
||||
typename T4 = nil_t
|
||||
>
|
||||
struct make_local_function_actor {
|
||||
|
||||
typedef local_function_actor<
|
||||
N, Parent,
|
||||
typename as_actor<T0>::type,
|
||||
typename as_actor<T1>::type,
|
||||
typename as_actor<T2>::type,
|
||||
typename as_actor<T3>::type,
|
||||
typename as_actor<T4>::type
|
||||
> composite_type;
|
||||
|
||||
typedef actor<composite_type> type;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <int N, int Parent = 0>
|
||||
struct local_function {
|
||||
|
||||
actor<local_function_actor<N, Parent> >
|
||||
operator()() const
|
||||
{
|
||||
return local_function_actor<N, Parent>();
|
||||
}
|
||||
|
||||
template <typename T0>
|
||||
typename impl::make_local_function_actor<N, Parent, T0>::type
|
||||
operator()(T0 const& _0) const
|
||||
{
|
||||
return impl::make_local_function_actor<N, Parent, T0>::composite_type(_0);
|
||||
}
|
||||
|
||||
template <int PIndex>
|
||||
local_function<N, Parent+PIndex>
|
||||
parent() const
|
||||
{
|
||||
return local_function<N, Parent+PIndex>();
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
namespace locals {
|
||||
|
||||
local_function<1> const lfun1 = local_function<1>();
|
||||
local_function<2> const lfun2 = local_function<2>();
|
||||
local_function<3> const lfun3 = local_function<3>();
|
||||
local_function<4> const lfun4 = local_function<4>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// context_composite
|
||||
//
|
||||
// This class encapsulates an actor and some local variable
|
||||
// initializers packed in a tuple.
|
||||
//
|
||||
// context_composite is just like a proxy and delegates the actual
|
||||
// evaluation to the actor. The actor does the actual work. In the
|
||||
// eval member function, before invoking the embedded actor's eval
|
||||
// member function, we first stuff an instance of our locals and
|
||||
// bundle both 'args' and 'locals' in a local_tuple. This
|
||||
// local_tuple instance is created in the stack initializing it
|
||||
// with our locals member. We then pass this local_tuple instance
|
||||
// as an argument to the actor's eval member function.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename ActorT, typename LocsT>
|
||||
struct context_composite {
|
||||
|
||||
typedef context_composite<ActorT, LocsT> self_t;
|
||||
|
||||
template <typename TupleT>
|
||||
struct result { typedef typename tuple_element<0, LocsT>::type type; };
|
||||
|
||||
context_composite(ActorT const& actor_, LocsT const& locals_)
|
||||
: actor(actor_), locals(locals_) {}
|
||||
|
||||
template <typename TupleT>
|
||||
typename tuple_element<0, LocsT>::type
|
||||
eval(TupleT const& args) const
|
||||
{
|
||||
local_tuple<TupleT, LocsT> local_context(args, locals);
|
||||
actor.eval(local_context);
|
||||
return local_context.locs[tuple_index<0>()];
|
||||
}
|
||||
|
||||
ActorT actor;
|
||||
LocsT locals;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// context_gen
|
||||
//
|
||||
// At construction time, this class is given some local var-
|
||||
// initializers packed in a tuple. We just store this for later.
|
||||
// The operator[] of this class creates the actual context_composite
|
||||
// given an actor. This is responsible for the construct
|
||||
// context<types>[actor].
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename LocsT>
|
||||
struct context_gen {
|
||||
|
||||
context_gen(LocsT const& locals_)
|
||||
: locals(locals_) {}
|
||||
|
||||
template <typename ActorT>
|
||||
actor<context_composite<typename as_actor<ActorT>::type, LocsT> >
|
||||
operator[](ActorT const& actor)
|
||||
{
|
||||
return context_composite<typename as_actor<ActorT>::type, LocsT>
|
||||
(as_actor<ActorT>::convert(actor), locals);
|
||||
}
|
||||
|
||||
LocsT locals;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Front end generator functions. These generators are overloaded for
|
||||
// 1..N local variables. context<T0,... TN>(i0,...iN) generate
|
||||
// context_gen objects (see above).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T0>
|
||||
inline context_gen<tuple<T0> >
|
||||
context()
|
||||
{
|
||||
typedef tuple<T0> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0()));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1>
|
||||
inline context_gen<tuple<T0, T1> >
|
||||
context(
|
||||
T1 const& _1 = T1()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0(), _1));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1, typename T2>
|
||||
inline context_gen<tuple<T0, T1, T2> >
|
||||
context(
|
||||
T1 const& _1 = T1(),
|
||||
T2 const& _2 = T2()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1, T2> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0(), _1, _2));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
inline context_gen<tuple<T0, T1, T2, T3> >
|
||||
context(
|
||||
T1 const& _1 = T1(),
|
||||
T2 const& _2 = T2(),
|
||||
T3 const& _3 = T3()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1, T2, T3> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0(), _1, _2, _3));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1, typename T2, typename T3, typename T4>
|
||||
inline context_gen<tuple<T0, T1, T2, T3, T4> >
|
||||
context(
|
||||
T1 const& _1 = T1(),
|
||||
T2 const& _2 = T2(),
|
||||
T3 const& _3 = T3(),
|
||||
T4 const& _4 = T4()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1, T2, T3, T4> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0(), _1, _2, _3, _4));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace phoenix;
|
||||
using namespace phoenix::locals;
|
||||
|
||||
//////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
int _10 = 10;
|
||||
|
||||
#ifndef __BORLANDC__
|
||||
|
||||
context<nil_t>
|
||||
(
|
||||
1000, // lvar1: local int variable
|
||||
cout << arg1 << '\n', // lfun2: local function w/ 1 argument (arg1)
|
||||
lvar1 * 2, // lfun3: local function that accesses local variable lvar1
|
||||
lfun2(2 * arg1) // lfun4: local function that calls local function lfun2
|
||||
)
|
||||
[
|
||||
lfun2(arg1 + 2000),
|
||||
lfun2(val(5000) * 2),
|
||||
lfun2(lvar1 + lfun3()),
|
||||
lfun4(55),
|
||||
cout << lvar1 << '\n',
|
||||
cout << lfun3() << '\n',
|
||||
cout << val("bye bye\n")
|
||||
]
|
||||
|
||||
(_10);
|
||||
|
||||
#else // Borland does not like local variables w/ local functions
|
||||
// we can have local variables (see sample 7..9) *OR*
|
||||
// local functions (this: sample 10) but not both
|
||||
// Sigh... Borland :-{
|
||||
|
||||
context<nil_t>
|
||||
(
|
||||
12345,
|
||||
cout << arg1 << '\n'
|
||||
)
|
||||
[
|
||||
lfun2(arg1 + 687),
|
||||
lfun2(val(9999) * 2),
|
||||
cout << val("bye bye\n")
|
||||
]
|
||||
|
||||
(_10);
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
phoenix/example/fundamental/sample2.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include "boost/spirit/phoenix/operators.hpp"
|
||||
#include "boost/spirit/phoenix/primitives.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace phoenix;
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
int init[] = { 2, 10, 4, 5, 1, 6, 8, 3, 9, 7 };
|
||||
vector<int> c(init, init + 10);
|
||||
typedef vector<int>::iterator iterator;
|
||||
|
||||
// Find the first odd number in container c
|
||||
iterator it = find_if(c.begin(), c.end(), arg1 % 2 == 1);
|
||||
|
||||
if (it != c.end())
|
||||
cout << *it; // if found, print the result
|
||||
return 0;
|
||||
}
|
||||
35
phoenix/example/fundamental/sample3.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include "boost/spirit/phoenix/functions.hpp"
|
||||
#include "boost/spirit/phoenix/primitives.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace phoenix;
|
||||
|
||||
struct is_odd_ {
|
||||
|
||||
template <typename ArgT>
|
||||
struct result { typedef bool type; };
|
||||
|
||||
template <typename ArgT>
|
||||
bool operator()(ArgT arg1) const
|
||||
{ return arg1 % 2 == 1; }
|
||||
};
|
||||
|
||||
function<is_odd_> is_odd;
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
int init[] = { 2, 10, 4, 5, 1, 6, 8, 3, 9, 7 };
|
||||
vector<int> c(init, init + 10);
|
||||
typedef vector<int>::iterator iterator;
|
||||
|
||||
// Find the first odd number in container c
|
||||
iterator it = find_if(c.begin(), c.end(), is_odd(arg1));
|
||||
|
||||
if (it != c.end())
|
||||
cout << *it; // if found, print the result
|
||||
return 0;
|
||||
}
|
||||
28
phoenix/example/fundamental/sample4.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include "boost/spirit/phoenix/operators.hpp"
|
||||
#include "boost/spirit/phoenix/primitives.hpp"
|
||||
#include "boost/spirit/phoenix/statements.hpp"
|
||||
#include "boost/spirit/phoenix/special_ops.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace phoenix;
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
int init[] = { 2, 10, 4, 5, 1, 6, 8, 3, 9, 7 };
|
||||
vector<int> c(init, init + 10);
|
||||
typedef vector<int>::iterator iterator;
|
||||
|
||||
// Print all odd contents of an stl container c
|
||||
for_each(c.begin(), c.end(),
|
||||
if_(arg1 % 2 == 1)
|
||||
[
|
||||
cout << arg1 << ' '
|
||||
]
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
35
phoenix/example/fundamental/sample5.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include "boost/spirit/phoenix/operators.hpp"
|
||||
#include "boost/spirit/phoenix/primitives.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace phoenix;
|
||||
|
||||
//////////////////////////////////
|
||||
template <int N>
|
||||
struct static_int {
|
||||
|
||||
template <typename TupleT>
|
||||
struct result { typedef int type; };
|
||||
|
||||
template <typename TupleT>
|
||||
int eval(TupleT const&) const { return N; }
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <int N>
|
||||
phoenix::actor<static_int<N> >
|
||||
int_const()
|
||||
{
|
||||
return static_int<N>();
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
cout << (int_const<5>() + int_const<6>())() << endl;
|
||||
return 0;
|
||||
}
|
||||
80
phoenix/example/fundamental/sample6.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include "boost/spirit/phoenix/operators.hpp"
|
||||
#include "boost/spirit/phoenix/primitives.hpp"
|
||||
#include "boost/spirit/phoenix/composite.hpp"
|
||||
#include "boost/spirit/phoenix/special_ops.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace phoenix;
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename CondT, typename TrueT, typename FalseT>
|
||||
struct if_else_composite {
|
||||
|
||||
typedef if_else_composite<CondT, TrueT, FalseT> self_t;
|
||||
|
||||
template <typename TupleT>
|
||||
struct result {
|
||||
|
||||
typedef typename higher_rank<
|
||||
typename actor_result<TrueT, TupleT>::plain_type,
|
||||
typename actor_result<FalseT, TupleT>::plain_type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
if_else_composite(
|
||||
CondT const& cond_, TrueT const& true__, FalseT const& false__)
|
||||
: cond(cond_), true_(true__), false_(false__) {}
|
||||
|
||||
template <typename TupleT>
|
||||
typename actor_result<self_t, TupleT>::type
|
||||
eval(TupleT const& args) const
|
||||
{
|
||||
return cond.eval(args) ? true_.eval(args) : false_.eval(args);
|
||||
}
|
||||
|
||||
CondT cond; TrueT true_; FalseT false_; // actors
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename CondT, typename TrueT, typename FalseT>
|
||||
inline actor<if_else_composite<
|
||||
typename as_actor<CondT>::type,
|
||||
typename as_actor<TrueT>::type,
|
||||
typename as_actor<FalseT>::type> >
|
||||
if_else_(CondT const& cond, TrueT const& true_, FalseT const& false_)
|
||||
{
|
||||
typedef if_else_composite<
|
||||
typename as_actor<CondT>::type,
|
||||
typename as_actor<TrueT>::type,
|
||||
typename as_actor<FalseT>::type>
|
||||
result;
|
||||
|
||||
return result(
|
||||
as_actor<CondT>::convert(cond),
|
||||
as_actor<TrueT>::convert(true_),
|
||||
as_actor<FalseT>::convert(false_));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
int init[] = { 2, 10, 4, 5, 1, 6, 8, 3, 9, 7 };
|
||||
vector<int> c(init, init + 10);
|
||||
typedef vector<int>::iterator iterator;
|
||||
|
||||
// Print all contents of an stl container c and
|
||||
// prefix " is odd" or " is even" appropriately.
|
||||
|
||||
for_each(c.begin(), c.end(),
|
||||
cout
|
||||
<< arg1
|
||||
<< if_else_(arg1 % 2 == 1, " is odd", " is even")
|
||||
<< val('\n')
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
267
phoenix/example/fundamental/sample7.cpp
Normal file
@@ -0,0 +1,267 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#define PHOENIX_LIMIT 5
|
||||
#include "boost/spirit/phoenix/operators.hpp"
|
||||
#include "boost/spirit/phoenix/primitives.hpp"
|
||||
#include "boost/spirit/phoenix/composite.hpp"
|
||||
#include "boost/spirit/phoenix/special_ops.hpp"
|
||||
#include "boost/spirit/phoenix/statements.hpp"
|
||||
|
||||
namespace phoenix {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// local_tuple
|
||||
//
|
||||
// This *is a* tuple like the one we see in TupleT in any actor
|
||||
// base class' eval member function. local_tuple should look and
|
||||
// feel the same as a tupled-args, that's why it is derived from
|
||||
// TupleArgsT. It has an added member, locs which is another tuple
|
||||
// where the local variables will be stored. locs is mutable to
|
||||
// allow read-write access to our locals regardless of
|
||||
// local_tuple's constness (The eval member function accepts it as
|
||||
// a const argument).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename TupleArgsT, typename TupleLocsT>
|
||||
struct local_tuple : public TupleArgsT {
|
||||
|
||||
typedef TupleLocsT local_vars_t;
|
||||
|
||||
local_tuple(TupleArgsT const& args, TupleLocsT const& locs_)
|
||||
: TupleArgsT(args), locs(locs_) {}
|
||||
|
||||
mutable TupleLocsT locs;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// local_var_result
|
||||
//
|
||||
// This is a return type computer. Given a constant integer N and a
|
||||
// tuple, get the Nth local variable type. If TupleT is not really
|
||||
// a local_tuple, we just return nil_t. Otherwise we get the Nth
|
||||
// local variable type.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <int N, typename TupleT>
|
||||
struct local_var_result {
|
||||
|
||||
typedef nil_t type;
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <int N, typename TupleArgsT, typename TupleLocsT>
|
||||
struct local_var_result<N, local_tuple<TupleArgsT, TupleLocsT> > {
|
||||
|
||||
typedef typename tuple_element<N, TupleLocsT>::type& type;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// local_var
|
||||
//
|
||||
// This class looks so curiously like the argument class. local_var
|
||||
// provides access to the Nth local variable packed in the tuple
|
||||
// duo local_tuple above. Note that the member function eval
|
||||
// expects a local_tuple argument. Otherwise the expression
|
||||
// 'tuple.locs' will fail (compile-time error). local_var
|
||||
// primitives only work within the context of a locals_composite
|
||||
// (see below).
|
||||
//
|
||||
// Provided are some predefined local_var actors for 0..N local
|
||||
// variable access: loc1..locN.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <int N>
|
||||
struct local_var {
|
||||
|
||||
template <typename TupleT>
|
||||
struct result {
|
||||
|
||||
typedef typename local_var_result<N, TupleT>::type type;
|
||||
};
|
||||
|
||||
template <typename TupleT>
|
||||
typename local_var_result<N, TupleT>::type
|
||||
eval(TupleT const& tuple) const
|
||||
{
|
||||
return tuple.locs[tuple_index<N>()];
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
actor<local_var<0> > const loc1 = local_var<0>();
|
||||
actor<local_var<1> > const loc2 = local_var<1>();
|
||||
actor<local_var<2> > const loc3 = local_var<2>();
|
||||
actor<local_var<3> > const loc4 = local_var<3>();
|
||||
actor<local_var<4> > const loc5 = local_var<4>();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// locals_composite
|
||||
//
|
||||
// This class encapsulates an actor and some local variable
|
||||
// initializers packed in a tuple.
|
||||
//
|
||||
// locals_composite is just like a proxy and delegates the actual
|
||||
// evaluation to the actor. The actor does the actual work. In the
|
||||
// eval member function, before invoking the embedded actor's eval
|
||||
// member function, we first stuff an instance of our locals and
|
||||
// bundle both 'args' and 'locals' in a local_tuple. This
|
||||
// local_tuple instance is created in the stack initializing it
|
||||
// with our locals member. We then pass this local_tuple instance
|
||||
// as an argument to the actor's eval member function.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename ActorT, typename LocsT>
|
||||
struct locals_composite {
|
||||
|
||||
typedef locals_composite<ActorT, LocsT> self_t;
|
||||
|
||||
template <typename TupleT>
|
||||
struct result { typedef typename actor_result<ActorT, TupleT>::type type; };
|
||||
|
||||
locals_composite(ActorT const& actor_, LocsT const& locals_)
|
||||
: actor(actor_), locals(locals_) {}
|
||||
|
||||
template <typename TupleT>
|
||||
typename actor_result<ActorT, TupleT>::type
|
||||
eval(TupleT const& args) const
|
||||
{
|
||||
actor.eval(local_tuple<TupleT, LocsT>(args, locals));
|
||||
}
|
||||
|
||||
ActorT actor;
|
||||
LocsT locals;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// locals_gen
|
||||
//
|
||||
// At construction time, this class is given some local var-
|
||||
// initializers packed in a tuple. We just store this for later.
|
||||
// The operator[] of this class creates the actual locals_composite
|
||||
// given an actor. This is responsible for the construct
|
||||
// locals<types>[actor].
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename LocsT>
|
||||
struct locals_gen {
|
||||
|
||||
locals_gen(LocsT const& locals_)
|
||||
: locals(locals_) {}
|
||||
|
||||
template <typename ActorT>
|
||||
actor<locals_composite<typename as_actor<ActorT>::type, LocsT> >
|
||||
operator[](ActorT const& actor)
|
||||
{
|
||||
return locals_composite<typename as_actor<ActorT>::type, LocsT>
|
||||
(as_actor<ActorT>::convert(actor), locals);
|
||||
}
|
||||
|
||||
LocsT locals;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Front end generator functions. These generators are overloaded for
|
||||
// 1..N local variables. locals<T0,... TN>(i0,...iN) generate locals_gen
|
||||
// objects (see above).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T0>
|
||||
inline locals_gen<tuple<T0> >
|
||||
locals(
|
||||
T0 const& _0 = T0()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0> tuple_t;
|
||||
return locals_gen<tuple_t>(tuple_t(_0));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1>
|
||||
inline locals_gen<tuple<T0, T1> >
|
||||
locals(
|
||||
T0 const& _0 = T0(),
|
||||
T1 const& _1 = T1()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1> tuple_t;
|
||||
return locals_gen<tuple_t>(tuple_t(_0, _1));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1, typename T2>
|
||||
inline locals_gen<tuple<T0, T1, T2> >
|
||||
locals(
|
||||
T0 const& _0 = T0(),
|
||||
T1 const& _1 = T1(),
|
||||
T2 const& _2 = T2()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1, T2> tuple_t;
|
||||
return locals_gen<tuple_t>(tuple_t(_0, _1, _2));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
inline locals_gen<tuple<T0, T1, T2, T3> >
|
||||
locals(
|
||||
T0 const& _0 = T0(),
|
||||
T1 const& _1 = T1(),
|
||||
T2 const& _2 = T2(),
|
||||
T3 const& _3 = T3()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1, T2, T3> tuple_t;
|
||||
return locals_gen<tuple_t>(tuple_t(_0, _1, _2, _3));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1, typename T2, typename T3, typename T4>
|
||||
inline locals_gen<tuple<T0, T1, T2, T3, T4> >
|
||||
locals(
|
||||
T0 const& _0 = T0(),
|
||||
T1 const& _1 = T1(),
|
||||
T2 const& _2 = T2(),
|
||||
T3 const& _3 = T3(),
|
||||
T4 const& _4 = T4()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1, T2, T3> tuple_t;
|
||||
return locals_gen<tuple_t>(tuple_t(_0, _1, _2, _3, _4));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace phoenix;
|
||||
|
||||
//////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
int init[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
||||
vector<int> c(init, init + 10);
|
||||
typedef vector<int>::iterator iterator;
|
||||
|
||||
for_each(c.begin(), c.end(),
|
||||
locals<int, char const*>(0, "...That's all\n")
|
||||
[
|
||||
for_(loc1 = 0, loc1 < arg1, ++loc1)
|
||||
[
|
||||
cout << loc1 << ", "
|
||||
],
|
||||
cout << loc2
|
||||
]
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
276
phoenix/example/fundamental/sample8.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#define PHOENIX_LIMIT 5
|
||||
#include "boost/spirit/phoenix/operators.hpp"
|
||||
#include "boost/spirit/phoenix/primitives.hpp"
|
||||
#include "boost/spirit/phoenix/composite.hpp"
|
||||
#include "boost/spirit/phoenix/special_ops.hpp"
|
||||
#include "boost/spirit/phoenix/statements.hpp"
|
||||
|
||||
namespace phoenix {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// local_tuple
|
||||
//
|
||||
// This *is a* tuple like the one we see in TupleT in any actor
|
||||
// base class' eval member function. local_tuple should look and
|
||||
// feel the same as a tupled-args, that's why it is derived from
|
||||
// TupleArgsT. It has an added member, locs which is another tuple
|
||||
// where the local variables will be stored. locs is mutable to
|
||||
// allow read-write access to our locals regardless of
|
||||
// local_tuple's constness (The eval member function accepts it as
|
||||
// a const argument).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename TupleArgsT, typename TupleLocsT>
|
||||
struct local_tuple : public TupleArgsT {
|
||||
|
||||
typedef TupleLocsT local_vars_t;
|
||||
|
||||
local_tuple(TupleArgsT const& args, TupleLocsT const& locs_)
|
||||
: TupleArgsT(args), locs(locs_) {}
|
||||
|
||||
mutable TupleLocsT locs;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// local_var_result
|
||||
//
|
||||
// This is a return type computer. Given a constant integer N and a
|
||||
// tuple, get the Nth local variable type. If TupleT is not really
|
||||
// a local_tuple, we just return nil_t. Otherwise we get the Nth
|
||||
// local variable type.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <int N, typename TupleT>
|
||||
struct local_var_result {
|
||||
|
||||
typedef nil_t type;
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <int N, typename TupleArgsT, typename TupleLocsT>
|
||||
struct local_var_result<N, local_tuple<TupleArgsT, TupleLocsT> > {
|
||||
|
||||
typedef typename tuple_element<N, TupleLocsT>::type& type;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// local_var
|
||||
//
|
||||
// This class looks so curiously like the argument class. local_var
|
||||
// provides access to the Nth local variable packed in the tuple
|
||||
// duo local_tuple above. Note that the member function eval
|
||||
// expects a local_tuple argument. Otherwise the expression
|
||||
// 'tuple.locs' will fail (compile-time error). local_var
|
||||
// primitives only work within the context of a context_composite
|
||||
// (see below).
|
||||
//
|
||||
// Provided are some predefined local_var actors for 0..N local
|
||||
// variable access: loc1..locN.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <int N>
|
||||
struct local_var {
|
||||
|
||||
template <typename TupleT>
|
||||
struct result {
|
||||
|
||||
typedef typename local_var_result<N, TupleT>::type type;
|
||||
};
|
||||
|
||||
template <typename TupleT>
|
||||
typename local_var_result<N, TupleT>::type
|
||||
eval(TupleT const& tuple) const
|
||||
{
|
||||
return tuple.locs[tuple_index<N>()];
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
namespace locals {
|
||||
|
||||
actor<local_var<0> > const result = local_var<0>();
|
||||
actor<local_var<1> > const loc1 = local_var<1>();
|
||||
actor<local_var<2> > const loc2 = local_var<2>();
|
||||
actor<local_var<3> > const loc3 = local_var<3>();
|
||||
actor<local_var<4> > const loc4 = local_var<4>();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// context_composite
|
||||
//
|
||||
// This class encapsulates an actor and some local variable
|
||||
// initializers packed in a tuple.
|
||||
//
|
||||
// context_composite is just like a proxy and delegates the actual
|
||||
// evaluation to the actor. The actor does the actual work. In the
|
||||
// eval member function, before invoking the embedded actor's eval
|
||||
// member function, we first stuff an instance of our locals and
|
||||
// bundle both 'args' and 'locals' in a local_tuple. This
|
||||
// local_tuple instance is created in the stack initializing it
|
||||
// with our locals member. We then pass this local_tuple instance
|
||||
// as an argument to the actor's eval member function.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename ActorT, typename LocsT>
|
||||
struct context_composite {
|
||||
|
||||
typedef context_composite<ActorT, LocsT> self_t;
|
||||
|
||||
template <typename TupleT>
|
||||
struct result { typedef typename tuple_element<0, LocsT>::type type; };
|
||||
|
||||
context_composite(ActorT const& actor_, LocsT const& locals_)
|
||||
: actor(actor_), locals(locals_) {}
|
||||
|
||||
template <typename TupleT>
|
||||
typename tuple_element<0, LocsT>::type
|
||||
eval(TupleT const& args) const
|
||||
{
|
||||
local_tuple<TupleT, LocsT> local_context(args, locals);
|
||||
actor.eval(local_context);
|
||||
return local_context.locs[tuple_index<0>()];
|
||||
}
|
||||
|
||||
ActorT actor;
|
||||
LocsT locals;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// context_gen
|
||||
//
|
||||
// At construction time, this class is given some local var-
|
||||
// initializers packed in a tuple. We just store this for later.
|
||||
// The operator[] of this class creates the actual context_composite
|
||||
// given an actor. This is responsible for the construct
|
||||
// context<types>[actor].
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename LocsT>
|
||||
struct context_gen {
|
||||
|
||||
context_gen(LocsT const& locals_)
|
||||
: locals(locals_) {}
|
||||
|
||||
template <typename ActorT>
|
||||
actor<context_composite<typename as_actor<ActorT>::type, LocsT> >
|
||||
operator[](ActorT const& actor)
|
||||
{
|
||||
return context_composite<typename as_actor<ActorT>::type, LocsT>
|
||||
(as_actor<ActorT>::convert(actor), locals);
|
||||
}
|
||||
|
||||
LocsT locals;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Front end generator functions. These generators are overloaded for
|
||||
// 1..N local variables. context<T0,... TN>(i0,...iN) generate context_gen
|
||||
// objects (see above).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T0>
|
||||
inline context_gen<tuple<T0> >
|
||||
context()
|
||||
{
|
||||
typedef tuple<T0> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0()));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1>
|
||||
inline context_gen<tuple<T0, T1> >
|
||||
context(
|
||||
T1 const& _1 = T1()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0(), _1));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1, typename T2>
|
||||
inline context_gen<tuple<T0, T1, T2> >
|
||||
context(
|
||||
T1 const& _1 = T1(),
|
||||
T2 const& _2 = T2()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1, T2> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0(), _1, _2));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
inline context_gen<tuple<T0, T1, T2, T3> >
|
||||
context(
|
||||
T1 const& _1 = T1(),
|
||||
T2 const& _2 = T2(),
|
||||
T3 const& _3 = T3()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1, T2, T3> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0(), _1, _2, _3));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1, typename T2, typename T3, typename T4>
|
||||
inline context_gen<tuple<T0, T1, T2, T3, T4> >
|
||||
context(
|
||||
T1 const& _1 = T1(),
|
||||
T2 const& _2 = T2(),
|
||||
T3 const& _3 = T3(),
|
||||
T4 const& _4 = T4()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1, T2, T3> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0(), _1, _2, _3, _4));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace phoenix;
|
||||
using namespace phoenix::locals;
|
||||
|
||||
//////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
int init[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
||||
vector<int> c(init, init + 10);
|
||||
typedef vector<int>::iterator iterator;
|
||||
|
||||
// find the first element > 5, print each element
|
||||
// as we traverse the container c. Print the result
|
||||
// if one is found.
|
||||
|
||||
find_if(c.begin(), c.end(),
|
||||
context<bool>()
|
||||
[
|
||||
cout << arg1,
|
||||
result = arg1 > 5,
|
||||
if_(!result)
|
||||
[
|
||||
cout << val(", ")
|
||||
]
|
||||
.else_
|
||||
[
|
||||
cout << val(" found result == ") << arg1
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
303
phoenix/example/fundamental/sample9.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#define PHOENIX_LIMIT 5
|
||||
#include "boost/spirit/phoenix/operators.hpp"
|
||||
#include "boost/spirit/phoenix/primitives.hpp"
|
||||
#include "boost/spirit/phoenix/composite.hpp"
|
||||
#include "boost/spirit/phoenix/special_ops.hpp"
|
||||
#include "boost/spirit/phoenix/statements.hpp"
|
||||
|
||||
namespace phoenix {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// local_tuple
|
||||
//
|
||||
// This *is a* tuple like the one we see in TupleT in any actor
|
||||
// base class' eval member function. local_tuple should look and
|
||||
// feel the same as a tupled-args, that's why it is derived from
|
||||
// TupleArgsT. It has an added member, locs which is another tuple
|
||||
// where the local variables will be stored. locs is mutable to
|
||||
// allow read-write access to our locals regardless of
|
||||
// local_tuple's constness (The eval member function accepts it as
|
||||
// a const argument).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename TupleArgsT, typename TupleLocsT>
|
||||
struct local_tuple : public TupleArgsT {
|
||||
|
||||
typedef TupleLocsT local_vars_t;
|
||||
typedef TupleArgsT parent_t;
|
||||
|
||||
local_tuple(TupleArgsT const& args, TupleLocsT const& locs_)
|
||||
: TupleArgsT(args), locs(locs_) {}
|
||||
|
||||
TupleArgsT& parent() { return *this; }
|
||||
TupleArgsT const& parent() const { return *this; }
|
||||
|
||||
mutable TupleLocsT locs;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// local_var_result
|
||||
//
|
||||
// This is a return type computer. Given a constant integer N, a
|
||||
// parent index and a tuple, get the Nth local variable type. The
|
||||
// parent index is an integer specifying which parent scope to
|
||||
// access; 0==current scope, 1==parent scope, 2==parent's parent
|
||||
// scope.
|
||||
//
|
||||
// This is a metaprogram with partial specializations. There is a
|
||||
// general case, a special case for local_tuples and a terminating
|
||||
// special case for local_tuples.
|
||||
//
|
||||
// General case: If TupleT is not really a local_tuple, we just return nil_t.
|
||||
//
|
||||
// local_tuples case:
|
||||
// Parent index is 0: We get the Nth local variable.
|
||||
// Otherwise: We subclass from local_tuples<N, Parent-1, TupleArgsT>
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <int N, int Parent, typename TupleT>
|
||||
struct local_var_result {
|
||||
|
||||
typedef nil_t type;
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <int N, int Parent, typename TupleArgsT, typename TupleLocsT>
|
||||
struct local_var_result<N, Parent, local_tuple<TupleArgsT, TupleLocsT> >
|
||||
: public local_var_result<N, Parent-1, TupleArgsT> {};
|
||||
|
||||
//////////////////////////////////
|
||||
template <int N, typename TupleArgsT, typename TupleLocsT>
|
||||
struct local_var_result<N, 0, local_tuple<TupleArgsT, TupleLocsT> > {
|
||||
|
||||
typedef typename tuple_element<
|
||||
N, TupleLocsT
|
||||
>::type& type;
|
||||
|
||||
static type get(local_tuple<TupleArgsT, TupleLocsT> const& tuple)
|
||||
{ return tuple.locs[tuple_index<N>()]; }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// local_var
|
||||
//
|
||||
// This class looks so curiously like the argument class. local_var
|
||||
// provides access to the Nth local variable packed in the tuple
|
||||
// duo local_tuple above. Parent specifies the Nth parent scope.
|
||||
// 0==current scope, 1==parent scope, 2==parent's parent scope. The
|
||||
// member function parent<N>() may be called to provide access to
|
||||
// outer scopes.
|
||||
//
|
||||
// Note that the member function eval expects a local_tuple
|
||||
// argument. Otherwise there will be acompile-time error. local_var
|
||||
// primitives only work within the context of a context_composite
|
||||
// (see below).
|
||||
//
|
||||
// Provided are some predefined local_var actors for 0..N local
|
||||
// variable access: loc1..locN.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <int N, int Parent = 0>
|
||||
struct local_var {
|
||||
|
||||
template <typename TupleT>
|
||||
struct result {
|
||||
|
||||
typedef typename local_var_result<N, Parent, TupleT>::type type;
|
||||
};
|
||||
|
||||
template <typename TupleT>
|
||||
typename local_var_result<N, Parent, TupleT>::type
|
||||
eval(TupleT const& tuple) const
|
||||
{
|
||||
return local_var_result<N, Parent, TupleT>::get(tuple);
|
||||
}
|
||||
|
||||
template <int PIndex>
|
||||
actor<local_var<N, Parent+PIndex> >
|
||||
parent() const
|
||||
{
|
||||
return local_var<N, Parent+PIndex>();
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
namespace locals {
|
||||
|
||||
actor<local_var<0> > const result = local_var<0>();
|
||||
actor<local_var<1> > const loc1 = local_var<1>();
|
||||
actor<local_var<2> > const loc2 = local_var<2>();
|
||||
actor<local_var<3> > const loc3 = local_var<3>();
|
||||
actor<local_var<4> > const loc4 = local_var<4>();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// context_composite
|
||||
//
|
||||
// This class encapsulates an actor and some local variable
|
||||
// initializers packed in a tuple.
|
||||
//
|
||||
// context_composite is just like a proxy and delegates the actual
|
||||
// evaluation to the actor. The actor does the actual work. In the
|
||||
// eval member function, before invoking the embedded actor's eval
|
||||
// member function, we first stuff an instance of our locals and
|
||||
// bundle both 'args' and 'locals' in a local_tuple. This
|
||||
// local_tuple instance is created in the stack initializing it
|
||||
// with our locals member. We then pass this local_tuple instance
|
||||
// as an argument to the actor's eval member function.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename ActorT, typename LocsT>
|
||||
struct context_composite {
|
||||
|
||||
typedef context_composite<ActorT, LocsT> self_t;
|
||||
|
||||
template <typename TupleT>
|
||||
struct result { typedef typename tuple_element<0, LocsT>::type type; };
|
||||
|
||||
context_composite(ActorT const& actor_, LocsT const& locals_)
|
||||
: actor(actor_), locals(locals_) {}
|
||||
|
||||
template <typename TupleT>
|
||||
typename tuple_element<0, LocsT>::type
|
||||
eval(TupleT const& args) const
|
||||
{
|
||||
local_tuple<TupleT, LocsT> local_context(args, locals);
|
||||
actor.eval(local_context);
|
||||
return local_context.locs[tuple_index<0>()];
|
||||
}
|
||||
|
||||
ActorT actor;
|
||||
LocsT locals;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// context_gen
|
||||
//
|
||||
// At construction time, this class is given some local var-
|
||||
// initializers packed in a tuple. We just store this for later.
|
||||
// The operator[] of this class creates the actual context_composite
|
||||
// given an actor. This is responsible for the construct
|
||||
// context<types>[actor].
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename LocsT>
|
||||
struct context_gen {
|
||||
|
||||
context_gen(LocsT const& locals_)
|
||||
: locals(locals_) {}
|
||||
|
||||
template <typename ActorT>
|
||||
actor<context_composite<typename as_actor<ActorT>::type, LocsT> >
|
||||
operator[](ActorT const& actor)
|
||||
{
|
||||
return context_composite<typename as_actor<ActorT>::type, LocsT>
|
||||
(as_actor<ActorT>::convert(actor), locals);
|
||||
}
|
||||
|
||||
LocsT locals;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Front end generator functions. These generators are overloaded for
|
||||
// 1..N local variables. context<T0,... TN>(i0,...iN) generate context_gen
|
||||
// objects (see above).
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T0>
|
||||
inline context_gen<tuple<T0> >
|
||||
context()
|
||||
{
|
||||
typedef tuple<T0> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0()));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1>
|
||||
inline context_gen<tuple<T0, T1> >
|
||||
context(
|
||||
T1 const& _1 = T1()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0(), _1));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1, typename T2>
|
||||
inline context_gen<tuple<T0, T1, T2> >
|
||||
context(
|
||||
T1 const& _1 = T1(),
|
||||
T2 const& _2 = T2()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1, T2> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0(), _1, _2));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
inline context_gen<tuple<T0, T1, T2, T3> >
|
||||
context(
|
||||
T1 const& _1 = T1(),
|
||||
T2 const& _2 = T2(),
|
||||
T3 const& _3 = T3()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1, T2, T3> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0(), _1, _2, _3));
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename T0, typename T1, typename T2, typename T3, typename T4>
|
||||
inline context_gen<tuple<T0, T1, T2, T3, T4> >
|
||||
context(
|
||||
T1 const& _1 = T1(),
|
||||
T2 const& _2 = T2(),
|
||||
T3 const& _3 = T3(),
|
||||
T4 const& _4 = T4()
|
||||
)
|
||||
{
|
||||
typedef tuple<T0, T1, T2, T3> tuple_t;
|
||||
return context_gen<tuple_t>(tuple_t(T0(), _1, _2, _3, _4));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
using namespace std;
|
||||
using namespace phoenix;
|
||||
using namespace phoenix::locals;
|
||||
|
||||
//////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
context<nil_t>(1)
|
||||
[
|
||||
cout << loc1 << '\n',
|
||||
context<nil_t>(2)
|
||||
[
|
||||
cout << loc1.parent<1>() << ' ' << loc1 << '\n',
|
||||
context<nil_t>(3)
|
||||
[
|
||||
cout << loc1.parent<2>() << ' ' << loc1.parent<1>() << ' ' << loc1 << '\n'
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
();
|
||||
|
||||
return 0;
|
||||
}
|
||||
182
phoenix/index.html
Normal file
@@ -0,0 +1,182 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Phoenix v1.0</title>
|
||||
<link rel="stylesheet" href="doc/theme/style.css" type="text/css">
|
||||
<link rel="next" href="preface.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="doc/theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Phoenix v1.0</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="doc/theme/spirit.gif" align="right" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="toc_title">Table of contents</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/preface.html">Preface</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/introduction.html">Introduction</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/quick_start.html">Quick start</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/basic_concepts.html">Basic Concepts</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/architecture.html">Architecture</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/lazy_functions.html">Lazy functions</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/place_holders.html">Place holders</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/polymorphic_functions.html">Polymorphic functions</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/organization.html">Organization</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/actors.html">Actors</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/primitives.html">Primitives</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/arguments.html">Arguments</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/values.html">Values</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/variables.html">Variables</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/composites.html">Composites</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/functions.html">Functions</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/operators.html">Operators</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/statements.html">Statements</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/binders.html">Binders</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/adaptable_closures.html">Adaptable closures</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/lazy_construction_and_conversions.html">Lazy Construction and Conversions</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/efficiency.html">Efficiency</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/inside_phoenix.html">Inside Phoenix</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/tuples.html">Tuples</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/actors_revisited.html">Actors revisited</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/composites_revisited.html">Composites revisited</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/operators_revisited.html">Operators revisited</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/interfacing.html">Interfacing</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/wrap_up.html">Wrap up</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L0">
|
||||
<a href="doc/references.html">References</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2001-2002 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
86
phoenix/test/Jamfile
Normal file
@@ -0,0 +1,86 @@
|
||||
#
|
||||
# Phoenix examples boost-jam file
|
||||
# Joel de Guzman [Sept 27, 2002]
|
||||
#
|
||||
|
||||
subproject libs/phoenix/test ;
|
||||
|
||||
unit-test binary_tests
|
||||
: binary_tests.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
unit-test binders_tests
|
||||
: binders_tests.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
unit-test functors_tests
|
||||
: functors_tests.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
unit-test iostream_tests
|
||||
: iostream_tests.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
|
||||
unit-test mixed_binary_tests
|
||||
: mixed_binary_tests.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
|
||||
unit-test more_expressions_tests
|
||||
: more_expressions_tests.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
|
||||
unit-test primitives_tests
|
||||
: primitives_tests.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
|
||||
unit-test statements_tests
|
||||
: statements_tests.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
|
||||
unit-test stl_tests
|
||||
: stl_tests.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
|
||||
unit-test tuples_tests
|
||||
: tuples_tests.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
|
||||
unit-test unary_tests
|
||||
: unary_tests.cpp
|
||||
: <sysinclude>$(BOOST_ROOT)
|
||||
:
|
||||
;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
23
phoenix/test/Makefile.am
Normal file
@@ -0,0 +1,23 @@
|
||||
check_PROGRAMS = binary_tests binders_tests functors_tests iostream_tests \
|
||||
mixed_binary_tests more_expressions_tests primitives_tests statements_tests \
|
||||
stl_tests tuples_tests unary_tests
|
||||
|
||||
binary_tests_SOURCES = binary_tests.cpp
|
||||
binders_tests_SOURCES = binders_tests.cpp
|
||||
functors_tests_SOURCES = functors_tests.cpp
|
||||
iostream_tests_SOURCES = iostream_tests.cpp
|
||||
mixed_binary_tests_SOURCES = mixed_binary_tests.cpp
|
||||
more_expressions_tests_SOURCES = more_expressions_tests.cpp
|
||||
primitives_tests_SOURCES = primitives_tests.cpp
|
||||
statements_tests_SOURCES = statements_tests.cpp
|
||||
stl_tests_SOURCES = stl_tests.cpp
|
||||
tuples_tests_SOURCES = tuples_tests.cpp
|
||||
unary_tests_SOURCES = unary_tests.cpp
|
||||
|
||||
EXTRA_DIST = \
|
||||
runtest.sh \
|
||||
Jamfile
|
||||
|
||||
INCLUDES = -I$(top_srcdir)
|
||||
|
||||
TESTS = runtest.sh
|
||||
94
phoenix/test/binary_tests.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
|
||||
#ifdef __GNUC__ // Darn these relops!
|
||||
#ifndef __SGI_STL_INTERNAL_RELOPS
|
||||
#define __SGI_STL_INTERNAL_RELOPS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
#define PHOENIX_LIMIT 15
|
||||
#include "boost/spirit/phoenix/primitives.hpp"
|
||||
#include "boost/spirit/phoenix/operators.hpp"
|
||||
|
||||
using namespace phoenix;
|
||||
using namespace std;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
main()
|
||||
{
|
||||
int i2 = 2, i3 = 3, i = 5;
|
||||
const char* world = " world";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Binary operators
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
assert((var(i) = var(i))() == 5);
|
||||
assert((var(i) = 3)() == 3);
|
||||
assert(i == 3);
|
||||
i = 5;
|
||||
int x, y, z;
|
||||
(var(x) = var(y) = var(z) = 10)();
|
||||
assert(x == 10 && y == 10 && z == 10);
|
||||
assert((val(world)[3])() == world[3]);
|
||||
|
||||
assert((var(i) += 5)() == 10);
|
||||
assert((var(i) -= 5)() == 5);
|
||||
assert((var(i) *= 5)() == 25);
|
||||
assert((var(i) /= 5)() == 5);
|
||||
assert((var(i) %= 2)() == 1);
|
||||
|
||||
assert((var(i) <<= 3)() == 8);
|
||||
assert((var(i) >>= 1)() == 4);
|
||||
assert((var(i) |= 0xFF)() == 0xFF);
|
||||
assert((var(i) &= 0xF0)() == 0xF0);
|
||||
assert((var(i) ^= 0xFFFFFFFF)() == int(0xFFFFFF0F));
|
||||
|
||||
assert((val(5) == val(5))());
|
||||
assert((val(5) == 5)());
|
||||
|
||||
assert((arg1 + arg2)(i2, i3) == i2 + i3);
|
||||
assert((arg1 - arg2)(i2, i3) == i2 - i3);
|
||||
assert((arg1 * arg2)(i2, i3) == i2 * i3);
|
||||
assert((arg1 / arg2)(i2, i3) == i2 / i3);
|
||||
assert((arg1 % arg2)(i2, i3) == i2 % i3);
|
||||
assert((arg1 & arg2)(i2, i3) == i2 & i3);
|
||||
assert((arg1 | arg2)(i2, i3) == i2 | i3);
|
||||
assert((arg1 ^ arg2)(i2, i3) == i2 ^ i3);
|
||||
assert((arg1 << arg2)(i2, i3) == i2 << i3);
|
||||
assert((arg1 >> arg2)(i2, i3) == i2 >> i3);
|
||||
|
||||
assert((val(5) != val(6))());
|
||||
assert((val(5) < val(6))());
|
||||
assert(!(val(5) > val(6))());
|
||||
assert((val(5) < val(6))());
|
||||
assert((val(5) <= val(6))());
|
||||
assert((val(5) <= val(5))());
|
||||
assert((val(7) >= val(6))());
|
||||
assert((val(7) >= val(7))());
|
||||
|
||||
assert((val(false) && val(false))() == false);
|
||||
assert((val(true) && val(false))() == false);
|
||||
assert((val(false) && val(true))() == false);
|
||||
assert((val(true) && val(true))() == true);
|
||||
|
||||
assert((val(false) || val(false))() == false);
|
||||
assert((val(true) || val(false))() == true);
|
||||
assert((val(false) || val(true))() == true);
|
||||
assert((val(true) || val(true))() == true);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// End asserts
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
cout << "///////////////////////////////////////////////////////////////////////////////\n";
|
||||
cout << "\t\tTests concluded\n";
|
||||
cout << "\t\tSUCCESS!!!\n";
|
||||
cout << "///////////////////////////////////////////////////////////////////////////////\n";
|
||||
}
|
||||