[Assorted-commits] SF.net SVN: assorted:[1225] clamp/trunk
Brought to you by:
yangzhang
From: <yan...@us...> - 2009-02-23 04:37:38
|
Revision: 1225 http://assorted.svn.sourceforge.net/assorted/?rev=1225&view=rev Author: yangzhang Date: 2009-02-23 04:37:33 +0000 (Mon, 23 Feb 2009) Log Message: ----------- dos2unix Modified Paths: -------------- clamp/trunk/doc/index.html clamp/trunk/doc/readme.txt clamp/trunk/src/CodeGen.cc clamp/trunk/src/CodeGen.hh clamp/trunk/src/Makefile clamp/trunk/src/clamp.y clamp/trunk/src/clamp_support.cc clamp/trunk/src/clamp_support.hh clamp/trunk/src/clamplex.h clamp/trunk/src/clamplex.lex clamp/trunk/src/curry.clamp clamp/trunk/src/eg.clamp clamp/trunk/src/home_page_examples.clamp clamp/trunk/src/test.clamp Modified: clamp/trunk/doc/index.html =================================================================== --- clamp/trunk/doc/index.html 2009-02-23 02:47:54 UTC (rev 1224) +++ clamp/trunk/doc/index.html 2009-02-23 04:37:33 UTC (rev 1225) @@ -1,489 +1,489 @@ -<html> -<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> -<meta name="Author" content="Raoul Gough"> - -<title>Project page for clamp - the C++ lambda preprocessor</title> - -<!-- $Id: index.html,v 1.14 2003/09/30 22:04:44 Raoul Exp $ --> - -<STYLE> -<!-- - -font.terminal { - font-family: arial, sans-serif; - font-weight: normal; - text-align: left; - vertical-align: top; -} - -font.nonterminal { - font-family: arial, sans-serif; - font-weight: normal; - font-style: italic; - text-align: left; - vertical-align: top; -} - -font.code { - font-family: courier, monotype; - font-weight: normal; - text-align: left; - vertical-align: middle; -} - ---> -</STYLE> - - -<body> - -<table width="100%"> - <tr> - <td colspan=2> -<a name="intro"> -<h1> -C++ lambda preprocessor -</h1> - </td> - </tr> - <tr> - <td bgcolor="lightblue" valign="top"> - <font size="-1"> - -<b> -Directory -</b> -<br> -<a href="#why">Why clamp?</a><br> -<a href="#detail">What it does</a><br> -<a href="#internal">How it works</a><br> -<a href="#grammar">Grammar</a><br> -<a href="#porting">Portability</a><br> -<a href="#contact">Contact info</a><br> -<a href="clamp_053_src.tar.gz">Source download</a> -<a href="clamp_053_exe.tar.gz">Windows executable</a> -<a href="../index.html">Author's home page</a> - - </font> - </td> - <td> - -The C++ lambda preprocessor (clamp) converts C++ code containing -lambda expressions into ordinary C++ code. Here's a simple example: - -<p> -<font class="code"> -vector<int> v;<br> -// ... <br> -std::for_each (v.begin(), v.end()<br> - - - , <b>lambda</b> (int &p) {<br> - - - if (p == 5) p = 0;<br> - - - } ); -</font> - -<p> -This example uses the standard algorithm <font -class="code">for_each</font> to apply an anonymous function to each -element of a vector. The anonymous function accepts an integer -parameter by reference, and resets the value to zero if it is -currently five (a simple, but not very useful example). The -preprocessor replaces the entire lambda expression in its output, so -that the C++ compiler ends up seeing something like the following: - -<p> -<font class="code"> -std::for_each (v.begin(), v.end()<br> - - , lambda_generator_1<void, int &>::generate () ); -</font> - -<p> -The exact nature of the template <font -class="code">lambda_generator_1</font> is beyond the scope of this -introduction, except to say that its <font -class="code">generate()</font> member function returns a function -object by value. The function object has, in this case, a member -function <font class="code">void operator()(int &)</font> -which <font class="code">for_each</font> applies to each element of -the vector. Some people would probably prefer to use the standard -<font class="code">transform</font> algorithm for this example, as in: - -<p> -<font class="code"> -std::transform (v.begin(), v.end(), v.begin()<br> - - - , lambda int (int p) {<br> - - - return (p == 5) ? 0 : p;<br> - - - } ); -</font> - -<p> -This example shows an anonymous function that returns a value, in this -case int. Rather than hard-wiring a value into the function body, it -is also possible to include contextual information in the function -object. For instance: - -<p> -<font class="code"> -void reset (std::vector<int> &v, int val) {<br> - -std::transform (v.begin(), v.end(), v.begin()<br> - - - , lambda int (int p) {<br> - - - return (p == <b>__ctx</b>(val)) ? 0 : p;<br> - - - } );<br> -} -</font> - -<p> -The <font class="code">__ctx</font> expression is an example of -context information bound by value. The clamp preprocessor also -supports reference semantics for contextual information via <font -class="code">__ref</font> expressions. For example: - -<p> -<font class="code"> -int sum = 0;<br> -std::for_each (v.begin(), v.end()<br> - - -, lambda (int p) { <b>__ref</b>(sum) += p; });<br> -</font> - -<p> -This, of course, calculates the sum of elements in the vector. - -<p> -Getting into some more complicated examples, it is possible to name -the type of the function object generated by a lambda expression by -simply omitting the function body. You have to do this, for instance, -if you want to use an anonymous function generated by a lambda -expression as a function parameter or return value. For example, the -type of the expression from the previous example: - -<p> -<font class="code"> -lambda (int p) { __ref(sum) += p; } -</font> - -<p> -can be referred to in the code as "<font class="code">lambda (int &) -(int)</font>". The first pair of brackets contains the context binding -(or closure) parameters, and the second pair contains the function -parameters. The closure parameter list is optional for context-less -functions, as is the return type for functions returning <font -class="code">void</font>, such as this one. Putting all of that -together, here's a templated function that returns a function object: - -<p> -<font class="code"> -template<typename T><br> -lambda bool (T) (const T &)<br> -match (const T &target) {<br> - return lambda bool (const T &candidate) {<br> - return candidate == __ctx(target);<br> - };<br> -}<br> -<p> -// Use a generated comparison object<br> -std::vector<int>::iterator<br> - i = find_if (v.begin(), v.end(), match (7));<br> -</font> -<p> -This <font class="code">find_if</font> example returns an iterator to -the first 7 in the vector (or <font class="code">v.end()</font>, if -none) using an instantiation of the <font class="code">match</font> -template with an <font class="code">int</font> parameter. For a vector -of strings, you could do the following: - -<p> -<font class="code"> -std::vector<std::string>::iterator<br> - i = find_if (v.begin(), v.end()<br> - - -, match (std::string("hello")));<br> -</font> - -<h2> -<a name="why"> -Why a preprocessor? -</h2> - -I wrote the preprocessor just for fun. There doesn't seem to be any -way to achieve real lambda expressions in pure C++, since it won't let -you insert a function definition in the middle of an expression. The -limits of what pure C++ allows are pretty well exhausted by the <a -href="http://www.boost.org/libs/lambda/doc/">boost lambda library</a>. - -<p> -Lambda expressions simplify some coding tasks, so it would be nice to -have them in C++. In the time it takes you to extract that one-liner -into a named function, I bet you could write <i>two</i> lambda -expressions for sure. Not to mention cases which require a named class -that contains context information. - -<h2> -<a name="detail"> -What it does -</h2> -<p> - -clamp scans its input for lambda expressions, passing any plain C++ -through unchanged. When it encounters a lambda expression, it extracts -the function body into a separate file. It also generates a class -template with a suitable <font class="code">operator()</font> and -(where necessary) member variables to store any context binding. This -class template also goes into a separate file. The whole lambda -expression is then replaced in the output by a single constructor -call, which creates an object of the templated class. - -<p> -The first line of the output is always a #include directive, which -drags in the generated templates and (indirectly) the function bodies. -The generated templates do not refer explicitly to any types used in -the original lambda expressions, which is how it can be included -before any user code. The actual types are only bound at the point of -use. Because of this, the clamp parser doesn't have to know what scope -a lambda expression appears in, or where the required types are -defined. This also makes including lambda expressions in templated -code a breeze, since the type binding is done within the template -scope where the expression was originally used. - -<h2> -<a name="internal"> -How it works -</h2> -<p> - -<p> -The clamp preprocessor consists of a lexical analyser (lexer) written -in flex, a parser written in bison and a code generator in plain C++. - -<p> -The clamp parser mostly tries to ignore everything in the input file, -letting the lexer copy input to output. When the lexer encounters the -<font class="code">lambda</font> keyword, it enters a different mode -("start condition" in flex terminology) in which is behaves like a -normal lexer and supplies tokens to the parser. The parser does some -messy stuff redirecting output and resetting the lexer mode as -necessary. - -<p> -Note: clamp is actually pretty dumb. It performs purely syntactic -transformations on the input, without really understanding scope, -types or variables. This will no doubt result in some incomprehensible -errors from the C++ compiler if something goes wrong. This is also the -reason that clamp requires the <font class="code">__ctx</font> and -<font class="code">__ref</font> keywords, since it wouldn't otherwise -be able to tell that an expression relies on surrounding context -information. - -<h2> -<a name="grammar"> -Grammar -</h2> -<p> -clamp introduces three keywords: <font -class="code">lambda, __ctx</font> and <font class="code">__ref</font>. -The parser recognises more or less the following grammar: - -<p> -<font size="-1"> - -<font class="nonterminal"> -lambda-expression: -<br> -lambda-decl -lambda-body<sub>opt</sub> -</font> - -<p> -<font class="nonterminal"> -lambda-decl: -<br> -</font> -<font class="terminal"> -lambda -</font> -<font class="nonterminal"> -return-type<sub>opt</sub> -param-list<sub>opt</sub> -param-list -</font> - -<p> -<font class="nonterminal"> -return-type: -<br> -type-id -</font> - -<p> -<font class="nonterminal"> -param-list: -<br> -</font> -<font class="terminal"> -( ) -</font> -<font class="nonterminal"> -<br> -</font> -<font class="terminal"> -( -</font> -<font class="nonterminal"> -parameter -</font> -<font class="terminal"> -) -</font> -<font class="nonterminal"> -<br> -</font> -<font class="terminal"> -( -</font> -<font class="nonterminal"> -parameter -</font> -<font class="terminal"> -, -</font> -<font class="nonterminal"> -... -</font> -<font class="terminal"> -) -</font> - -<p> -<font class="nonterminal"> -parameter: -<br> -type-id -identifier<sub>opt</sub> -initialiser<sub>opt</sub> -</font> - -<p> -<font class="nonterminal"> -initialiser: -<br> - - -</font> -<font class="terminal"> -= -</font> -<font class="nonterminal"> -expression -</font> - -<p> -<font class="nonterminal"> -lambda-body: -<br> - - -</font> -<font class="terminal"> -{ -</font> -<font class="nonterminal"> -statement<sub>opt</sub> ... -</font> -<font class="terminal"> -} -</font> - -<p> - -</font> - -where <font class="nonterminal">statement</font> represents any valid C++ -statement, possibly making use of the following extended expressions: - -<font size="-1"> -<p> -<font class="nonterminal"> -extended-expression: -<br> -lambda-expression -<br> -</font> -<font class="terminal"> -__ctx ( -</font> -<font class="nonterminal"> -expression -</font> -<font class="terminal"> -) -</font> -<font class="nonterminal"> -<br> -</font> -<font class="terminal"> -__ref ( -</font> -<font class="nonterminal"> -expression -</font> -<font class="terminal"> -) -</font> - -</font> - -<h2> -<a name="porting"> -Portability -</h2> -I wrote clamp using the following tools: g++ 2.95.3-5 with -boost 1.25.1, flex 2.5.4, bision 1.28 and -gnu make 3.79.1, all under Cygwin on Windows 2000. The -preprocessor builds successfully with g++ 3.1, but the code that it -generates causes an internal compiler error when taking the address of -a member function. This is probably fixed in later versions of g++. - -<p> -The preprocessor itself <i>might</i> build with yacc and/or -traditional Unix make (maybe) with any reasonable C++ compiler. The -lexer probably won't compile with plain lex, because (according to the -flex manual), lex doesn't support exclusive start conditions. - -<a name="contact"> -<h2> -Contact information -</h2> -This page and clamp itself are Copyright (C) 2002, 2003 by Raoul Gough -and may be used and distributed free of charge. Please send any -clamp-related comments to <a -href="mailto:Rao...@ya...">Rao...@ya...</a>. It -might be a good idea to include the word "clamp" in the subject line, -because that email address attracts a bit of spam. - - </td> - </tr> -</table> - -</body> +<html> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<meta name="Author" content="Raoul Gough"> + +<title>Project page for clamp - the C++ lambda preprocessor</title> + +<!-- $Id: index.html,v 1.14 2003/09/30 22:04:44 Raoul Exp $ --> + +<STYLE> +<!-- + +font.terminal { + font-family: arial, sans-serif; + font-weight: normal; + text-align: left; + vertical-align: top; +} + +font.nonterminal { + font-family: arial, sans-serif; + font-weight: normal; + font-style: italic; + text-align: left; + vertical-align: top; +} + +font.code { + font-family: courier, monotype; + font-weight: normal; + text-align: left; + vertical-align: middle; +} + +--> +</STYLE> + + +<body> + +<table width="100%"> + <tr> + <td colspan=2> +<a name="intro"> +<h1> +C++ lambda preprocessor +</h1> + </td> + </tr> + <tr> + <td bgcolor="lightblue" valign="top"> + <font size="-1"> + +<b> +Directory +</b> +<br> +<a href="#why">Why clamp?</a><br> +<a href="#detail">What it does</a><br> +<a href="#internal">How it works</a><br> +<a href="#grammar">Grammar</a><br> +<a href="#porting">Portability</a><br> +<a href="#contact">Contact info</a><br> +<a href="clamp_053_src.tar.gz">Source download</a> +<a href="clamp_053_exe.tar.gz">Windows executable</a> +<a href="../index.html">Author's home page</a> + + </font> + </td> + <td> + +The C++ lambda preprocessor (clamp) converts C++ code containing +lambda expressions into ordinary C++ code. Here's a simple example: + +<p> +<font class="code"> +vector<int> v;<br> +// ... <br> +std::for_each (v.begin(), v.end()<br> + + + , <b>lambda</b> (int &p) {<br> + + + if (p == 5) p = 0;<br> + + + } ); +</font> + +<p> +This example uses the standard algorithm <font +class="code">for_each</font> to apply an anonymous function to each +element of a vector. The anonymous function accepts an integer +parameter by reference, and resets the value to zero if it is +currently five (a simple, but not very useful example). The +preprocessor replaces the entire lambda expression in its output, so +that the C++ compiler ends up seeing something like the following: + +<p> +<font class="code"> +std::for_each (v.begin(), v.end()<br> + + , lambda_generator_1<void, int &>::generate () ); +</font> + +<p> +The exact nature of the template <font +class="code">lambda_generator_1</font> is beyond the scope of this +introduction, except to say that its <font +class="code">generate()</font> member function returns a function +object by value. The function object has, in this case, a member +function <font class="code">void operator()(int &)</font> +which <font class="code">for_each</font> applies to each element of +the vector. Some people would probably prefer to use the standard +<font class="code">transform</font> algorithm for this example, as in: + +<p> +<font class="code"> +std::transform (v.begin(), v.end(), v.begin()<br> + + + , lambda int (int p) {<br> + + + return (p == 5) ? 0 : p;<br> + + + } ); +</font> + +<p> +This example shows an anonymous function that returns a value, in this +case int. Rather than hard-wiring a value into the function body, it +is also possible to include contextual information in the function +object. For instance: + +<p> +<font class="code"> +void reset (std::vector<int> &v, int val) {<br> + +std::transform (v.begin(), v.end(), v.begin()<br> + + + , lambda int (int p) {<br> + + + return (p == <b>__ctx</b>(val)) ? 0 : p;<br> + + + } );<br> +} +</font> + +<p> +The <font class="code">__ctx</font> expression is an example of +context information bound by value. The clamp preprocessor also +supports reference semantics for contextual information via <font +class="code">__ref</font> expressions. For example: + +<p> +<font class="code"> +int sum = 0;<br> +std::for_each (v.begin(), v.end()<br> + + +, lambda (int p) { <b>__ref</b>(sum) += p; });<br> +</font> + +<p> +This, of course, calculates the sum of elements in the vector. + +<p> +Getting into some more complicated examples, it is possible to name +the type of the function object generated by a lambda expression by +simply omitting the function body. You have to do this, for instance, +if you want to use an anonymous function generated by a lambda +expression as a function parameter or return value. For example, the +type of the expression from the previous example: + +<p> +<font class="code"> +lambda (int p) { __ref(sum) += p; } +</font> + +<p> +can be referred to in the code as "<font class="code">lambda (int &) +(int)</font>". The first pair of brackets contains the context binding +(or closure) parameters, and the second pair contains the function +parameters. The closure parameter list is optional for context-less +functions, as is the return type for functions returning <font +class="code">void</font>, such as this one. Putting all of that +together, here's a templated function that returns a function object: + +<p> +<font class="code"> +template<typename T><br> +lambda bool (T) (const T &)<br> +match (const T &target) {<br> + return lambda bool (const T &candidate) {<br> + return candidate == __ctx(target);<br> + };<br> +}<br> +<p> +// Use a generated comparison object<br> +std::vector<int>::iterator<br> + i = find_if (v.begin(), v.end(), match (7));<br> +</font> +<p> +This <font class="code">find_if</font> example returns an iterator to +the first 7 in the vector (or <font class="code">v.end()</font>, if +none) using an instantiation of the <font class="code">match</font> +template with an <font class="code">int</font> parameter. For a vector +of strings, you could do the following: + +<p> +<font class="code"> +std::vector<std::string>::iterator<br> + i = find_if (v.begin(), v.end()<br> + + +, match (std::string("hello")));<br> +</font> + +<h2> +<a name="why"> +Why a preprocessor? +</h2> + +I wrote the preprocessor just for fun. There doesn't seem to be any +way to achieve real lambda expressions in pure C++, since it won't let +you insert a function definition in the middle of an expression. The +limits of what pure C++ allows are pretty well exhausted by the <a +href="http://www.boost.org/libs/lambda/doc/">boost lambda library</a>. + +<p> +Lambda expressions simplify some coding tasks, so it would be nice to +have them in C++. In the time it takes you to extract that one-liner +into a named function, I bet you could write <i>two</i> lambda +expressions for sure. Not to mention cases which require a named class +that contains context information. + +<h2> +<a name="detail"> +What it does +</h2> +<p> + +clamp scans its input for lambda expressions, passing any plain C++ +through unchanged. When it encounters a lambda expression, it extracts +the function body into a separate file. It also generates a class +template with a suitable <font class="code">operator()</font> and +(where necessary) member variables to store any context binding. This +class template also goes into a separate file. The whole lambda +expression is then replaced in the output by a single constructor +call, which creates an object of the templated class. + +<p> +The first line of the output is always a #include directive, which +drags in the generated templates and (indirectly) the function bodies. +The generated templates do not refer explicitly to any types used in +the original lambda expressions, which is how it can be included +before any user code. The actual types are only bound at the point of +use. Because of this, the clamp parser doesn't have to know what scope +a lambda expression appears in, or where the required types are +defined. This also makes including lambda expressions in templated +code a breeze, since the type binding is done within the template +scope where the expression was originally used. + +<h2> +<a name="internal"> +How it works +</h2> +<p> + +<p> +The clamp preprocessor consists of a lexical analyser (lexer) written +in flex, a parser written in bison and a code generator in plain C++. + +<p> +The clamp parser mostly tries to ignore everything in the input file, +letting the lexer copy input to output. When the lexer encounters the +<font class="code">lambda</font> keyword, it enters a different mode +("start condition" in flex terminology) in which is behaves like a +normal lexer and supplies tokens to the parser. The parser does some +messy stuff redirecting output and resetting the lexer mode as +necessary. + +<p> +Note: clamp is actually pretty dumb. It performs purely syntactic +transformations on the input, without really understanding scope, +types or variables. This will no doubt result in some incomprehensible +errors from the C++ compiler if something goes wrong. This is also the +reason that clamp requires the <font class="code">__ctx</font> and +<font class="code">__ref</font> keywords, since it wouldn't otherwise +be able to tell that an expression relies on surrounding context +information. + +<h2> +<a name="grammar"> +Grammar +</h2> +<p> +clamp introduces three keywords: <font +class="code">lambda, __ctx</font> and <font class="code">__ref</font>. +The parser recognises more or less the following grammar: + +<p> +<font size="-1"> + +<font class="nonterminal"> +lambda-expression: +<br> +lambda-decl +lambda-body<sub>opt</sub> +</font> + +<p> +<font class="nonterminal"> +lambda-decl: +<br> +</font> +<font class="terminal"> +lambda +</font> +<font class="nonterminal"> +return-type<sub>opt</sub> +param-list<sub>opt</sub> +param-list +</font> + +<p> +<font class="nonterminal"> +return-type: +<br> +type-id +</font> + +<p> +<font class="nonterminal"> +param-list: +<br> +</font> +<font class="terminal"> +( ) +</font> +<font class="nonterminal"> +<br> +</font> +<font class="terminal"> +( +</font> +<font class="nonterminal"> +parameter +</font> +<font class="terminal"> +) +</font> +<font class="nonterminal"> +<br> +</font> +<font class="terminal"> +( +</font> +<font class="nonterminal"> +parameter +</font> +<font class="terminal"> +, +</font> +<font class="nonterminal"> +... +</font> +<font class="terminal"> +) +</font> + +<p> +<font class="nonterminal"> +parameter: +<br> +type-id +identifier<sub>opt</sub> +initialiser<sub>opt</sub> +</font> + +<p> +<font class="nonterminal"> +initialiser: +<br> + + +</font> +<font class="terminal"> += +</font> +<font class="nonterminal"> +expression +</font> + +<p> +<font class="nonterminal"> +lambda-body: +<br> + + +</font> +<font class="terminal"> +{ +</font> +<font class="nonterminal"> +statement<sub>opt</sub> ... +</font> +<font class="terminal"> +} +</font> + +<p> + +</font> + +where <font class="nonterminal">statement</font> represents any valid C++ +statement, possibly making use of the following extended expressions: + +<font size="-1"> +<p> +<font class="nonterminal"> +extended-expression: +<br> +lambda-expression +<br> +</font> +<font class="terminal"> +__ctx ( +</font> +<font class="nonterminal"> +expression +</font> +<font class="terminal"> +) +</font> +<font class="nonterminal"> +<br> +</font> +<font class="terminal"> +__ref ( +</font> +<font class="nonterminal"> +expression +</font> +<font class="terminal"> +) +</font> + +</font> + +<h2> +<a name="porting"> +Portability +</h2> +I wrote clamp using the following tools: g++ 2.95.3-5 with +boost 1.25.1, flex 2.5.4, bision 1.28 and +gnu make 3.79.1, all under Cygwin on Windows 2000. The +preprocessor builds successfully with g++ 3.1, but the code that it +generates causes an internal compiler error when taking the address of +a member function. This is probably fixed in later versions of g++. + +<p> +The preprocessor itself <i>might</i> build with yacc and/or +traditional Unix make (maybe) with any reasonable C++ compiler. The +lexer probably won't compile with plain lex, because (according to the +flex manual), lex doesn't support exclusive start conditions. + +<a name="contact"> +<h2> +Contact information +</h2> +This page and clamp itself are Copyright (C) 2002, 2003 by Raoul Gough +and may be used and distributed free of charge. Please send any +clamp-related comments to <a +href="mailto:Rao...@ya...">Rao...@ya...</a>. It +might be a good idea to include the word "clamp" in the subject line, +because that email address attracts a bit of spam. + + </td> + </tr> +</table> + +</body> </html> \ No newline at end of file Modified: clamp/trunk/doc/readme.txt =================================================================== --- clamp/trunk/doc/readme.txt 2009-02-23 02:47:54 UTC (rev 1224) +++ clamp/trunk/doc/readme.txt 2009-02-23 04:37:33 UTC (rev 1225) @@ -1,19 +1,19 @@ - -clamp release 0.53 -================== - -clamp is Copyright (c) 2002, 2003 by Raoul M. Gough and licensed for -use and distribution without fee. Please refer to the disclaimer and -license details in the source code. - -To compile the clamp preprocessor, you will need to have the boost -smart_ptr library installed. Also requires bison (although yacc might -work) and flex. You can also download a pre-built windows executable -from the web site where you got this tarball. The supplied make file -works under GNU make, and should be able to build executables directly -from .clamp input files. You might have to adjust the compiler defines -at the top of the makefile to suit your system (e.g. add a suitable -I -to the CXXFLAGS). - -Limited help is provided in index.html. Please send any comments or -requests to Rao...@ya... + +clamp release 0.53 +================== + +clamp is Copyright (c) 2002, 2003 by Raoul M. Gough and licensed for +use and distribution without fee. Please refer to the disclaimer and +license details in the source code. + +To compile the clamp preprocessor, you will need to have the boost +smart_ptr library installed. Also requires bison (although yacc might +work) and flex. You can also download a pre-built windows executable +from the web site where you got this tarball. The supplied make file +works under GNU make, and should be able to build executables directly +from .clamp input files. You might have to adjust the compiler defines +at the top of the makefile to suit your system (e.g. add a suitable -I +to the CXXFLAGS). + +Limited help is provided in index.html. Please send any comments or +requests to Rao...@ya... Modified: clamp/trunk/src/CodeGen.cc =================================================================== --- clamp/trunk/src/CodeGen.cc 2009-02-23 02:47:54 UTC (rev 1224) +++ clamp/trunk/src/CodeGen.cc 2009-02-23 04:37:33 UTC (rev 1225) @@ -1,862 +1,862 @@ -// -*- mode:c++ -*- -// -// Module CodeGen.cc -// -// Copyright (c) 2002, 2003 Raoul M. Gough -// -// This material is provided "as is", with absolutely no warranty expressed -// or implied. Any use is at your own risk. -// -// Permission to use or copy this software for any purpose is hereby granted -// without fee, provided the above notices are retained on all copies. -// Permission to modify the code and to distribute modified code is granted, -// provided the above notices are retained, and a notice that the code was -// modified is included with the above copyright notice. -// -// History -// ======= -// 2002/ 2/11 rmg File creation -// - -#include "CodeGen.hh" - -#include <climits> -#include <sstream> -#include <cassert> -#include <iostream> - -extern const char *clamp_parser_rcsid; -const char *clamp_codegen_rcsid = "$Id: CodeGen.cc,v 1.20 2003/09/30 22:43:05 Raoul Exp $"; - -using namespace std; - -namespace -{ - using namespace clamp; - - unsigned count (paramListT *pListp) - { - if (pListp) - { - return pListp->size(); - } - - else - { - return 0; - } - } - - void initList (std::ostream &strm, paramListT *pListp, bool first = true) - { - if (pListp) - { - for (paramListT::const_iterator iter = pListp->begin() - ; iter != pListp->end() - ; ++iter) - { - if (iter->get()->initialiser.get()) - { - if (!first) - { - strm << ", "; - } - - strm << *iter->get()->initialiser; - - first = false; - } - - else if (iter->get()->type.get()) - { - if (!first) - { - strm << ", "; - } - - // Default initialize - strm << "(" << *iter->get()->type << ")0"; - - first = false; - } - } - } - } - - void typeList (std::ostream &strm, paramListT *pListp, bool first = true) - { - if (pListp) - { - for (paramListT::const_iterator iter = pListp->begin() - ; iter != pListp->end() - ; ++iter) - { - if (iter->get()->type.get()) - { - if (!first) - { - strm << ", "; - } - - strm << *iter->get()->type; - - first = false; - } - } - } - } -} - -namespace clamp -{ - //////////////////////////////////////////////////////////////////////// - // Constructors - //////////////////////////////////////////////////////////////////////// - - CodeGen::CodeGen () - : mStack () - , mLambdaCount (0) - , mImplStream ("lambda_impl.clamp_h") - , mLambdaMap () - , mGeneratorStream () - { - } - - CodeGen::LambdaContext::LambdaContext (FILE *f - , int b - , std::auto_ptr<lambdaT> lamp) - : mPrevFile (f) - , mOpenBracePos (b) - , mLamp (lamp.release()) - , mLambdaNumber (++sContextCount) - { - } - - CodeGen::LambdaGroup::LambdaGroup () - : mLambdaList () - , mImplStream (new stringstream) - { - } - - void implTemplateName (ostream &strm, int ccount, int pcount) - { - strm - << "lambda_template_" - << ccount - << "_" - << pcount; - } - - void tList (ostream &strm, int start, int end, bool first = true) - { - for (int count = start; count <= end; ++count) - { - if (!first) - { - strm << ", "; - } - - strm << "T" << count; - - first = false; - } - } - - void implFunctionVar (ostream &strm, int ccount, int pcount, const char *n) - { - strm << "T1 ("; - - if (ccount > 0) - { - // Implementation via pointer to member function - implTemplateName (strm, ccount, pcount); - strm << "::"; - } - // else implementation via pointer to ordinary function - - strm << "*" << n << ") ("; - tList (strm, 2 + ccount, 1 + ccount + pcount); - strm << ")"; - } - - void implInstance (ostream &strm, lambdaT const &lam) - { - unsigned ccount = count (lam.context.get()); - unsigned pcount = count (lam.params.get()); - - implTemplateName (strm, ccount, pcount); - - strm - << "<" - << *lam.ret_type; - - typeList (strm, lam.context.get(), false); - typeList (strm, lam.params.get(), false); - - strm << "> "; - } - - std::auto_ptr<stringT> CodeGen::lambdaTypeName (std::auto_ptr<lambdaT> lamp) - { - lambdaGroup (count (lamp->context.get()), count (lamp->params.get())); - // Make sure we've recorded the existance of this lambda group - - std::ostringstream temp; - - implInstance (temp, *lamp); - - return std::auto_ptr<stringT> (new stringT (temp.str())); - } - - void CodeGen::lambdaType (FILE *outFile, std::auto_ptr<lambdaT> lamp) - { - fprintf (outFile, "%s", lambdaTypeName (lamp)->c_str()); - } - - bool CodeGen::braceMatch (int pos) - { - return (!mStack.empty()) && (mStack.top().mOpenBracePos == pos); - } - - std::string contextVarExpression (paramT const &ctxParam) - { - std::stringstream result; - - result << "mContext" << ctxParam.ctx_param_num; - - return result.str(); - } - - int CodeGen::LambdaContext::sContextCount = 0; - - stringT bodyFileName (int count) - { - char name[PATH_MAX]; - sprintf (name, "lambda_body_%d.clamp_h", count); - return stringT (name); - } - - void explicitConstructor (ostream &strm, int id, const lambdaT &lam) - { - if (lam.onHeap) - { - strm << "new "; - } - - implInstance (strm, lam); - strm << "(&"; - implInstance (strm, lam); - strm << "::fn" << id; - initList (strm, lam.context.get(), false); - strm << ")"; - } - - void typenameList (ostream &strm - , unsigned start - , unsigned end - , bool first = true) - { - for (unsigned count = start; count <= end; ++count) - { - if (!first) - { - strm << ", "; - } - - strm << "typename T" << count; - - first = false; - } - } - - void implTemplateDecl (ostream &strm, unsigned templateParams) - { - strm - << "template <"; - - typenameList (strm, 1, templateParams); - - strm << ">"; - } - - void startExplicitImpl (ostream &strm, unsigned ccount, unsigned pcount) - { - implTemplateDecl (strm, ccount + pcount + 1); - - strm << "\nstruct "; - - implTemplateName (strm, ccount, pcount); - - strm << "\n{\n "; - - implFunctionVar (strm, ccount, pcount, "mFn"); - - strm << ";"; - - for (unsigned count = 1; count <= ccount; ++count) - { - strm << "\n T" << count + 1 << " mContext" << count << ";"; - } - - strm << "\n\n typedef T1 result_type;"; - - for (unsigned count = 1; count <= ccount; ++count) - { - strm - << "\n typedef T" << count + 1 - << " context_type_" << count - << ";"; - } - - for (unsigned count = 1; count <= pcount; ++count) - { - strm - << "\n typedef T" << count + ccount + 1 - << " argument_type_" << count - << ";"; - } - - // Additional typedefs in special cases for standard binder compatability - if (pcount == 1) - { - strm - << "\n typedef T" << ccount + 2 - << " argument_type;"; - } - - else if (pcount == 2) - { - strm - << "\n typedef T" << ccount + 2 - << " first_argument_type;\n typedef T" << ccount + 3 - << " second_argument_type;"; - } - - strm << "\n\n // Constructor\n "; - - implTemplateName (strm, ccount, pcount); - - strm << " ("; - - implFunctionVar (strm, ccount, pcount, "fn"); - - for (unsigned count = 1; count <= ccount; ++count) - { - strm << ", T" << count + 1 << " c" << count; - } - - strm << ")\n : mFn (fn)"; - - for (unsigned count = 1; count <= ccount; ++count) - { - strm << "\n , mContext" << count << " (c" << count << ")"; - } - - strm - << "\n { }\n" - << "\n // Forwarding function" - << "\n T1 operator() ("; - - for (unsigned count = 1; count <= pcount; ++count) - { - if (count != 1) - { - strm << ", "; - } - - strm << "T" << count + ccount + 1 << " p" << count; - } - - strm << ")\n {\n return ("; - - if (ccount > 0) - { - // Have closure parameters - use pointer to member syntax - strm << "this->"; - } - // else static function - - strm << "*mFn)("; - - for (unsigned count = 1; count <= pcount; ++count) - { - if (count != 1) - { - strm << ", "; - } - - strm << "p" << count; - } - - strm << ");\n }\n"; - } - - void declareMemberFn (ostream &strm - , int id - , unsigned ccount - , unsigned pcount) - { - strm << "\n "; - - if (ccount == 0) - { - strm << "static "; - } - - strm << "T1 fn" << id << " ("; - - tList (strm, 2 + ccount, 1 + ccount + pcount); - - strm << ");\n"; - } - - void defineMemberFn (ostream &strm - , int id - , unsigned ccount - , unsigned pcount - , const lambdaT &lam) - { - implTemplateDecl (strm, ccount + pcount + 1); - - strm << "\nT1 "; - - implTemplateName (strm, ccount, pcount); - - strm << "<"; - - tList (strm, 1, 1 + ccount + pcount); - - strm << ">::fn" << id << " ("; - - if (lam.params.get()) - { - unsigned count = 1; - - for (paramListT::const_iterator iter = lam.params->begin() - ; iter != lam.params->end() - ; ++iter) - { - if (count != 1) - { - strm << ", "; - } - - strm << "T" << count + ccount + 1; - - const stringT *name = iter->get()->name.get(); - - if (name) - { - strm - << " " << *name; - } - - ++count; - } - } - - strm << ")\n{"; - - if (lam.explicitContext && lam.context.get()) - { - // Context parameters require renaming - unsigned count = 1; - - for (paramListT::const_iterator iter = lam.context->begin() - ; iter != lam.context->end() - ; ++iter) - { - const stringT *name = iter->get()->name.get(); - - if (name) - { - strm - << "\n#define " << *name - << " mContext" - << count; - } - - ++count; - } - } - - strm - << "\n#include \"" - << bodyFileName (id) - << "\""; - - if (lam.explicitContext && lam.context.get()) - { - unsigned count = 1; - - for (paramListT::const_iterator iter = lam.context->begin() - ; iter != lam.context->end() - ; ++iter) - { - const stringT *name = iter->get()->name.get(); - - if (name) - { - strm - << "\n#undef " << *name; - } - - ++count; - } - } - - strm << "\n}\n"; - } - - void implicitConstructor (ostream &strm, int id, const lambdaT &lam) - { - strm - << "lambda_generator_" - << id - << "<" - << *lam.ret_type; - - typeList (strm, lam.params.get(), false); - - strm << ">::generate ("; - - initList (strm, lam.context.get()); - - strm <<")"; - } - - void implicitTemplateInstance (ostream &strm - , const lambdaT &lam - , unsigned ccount - , unsigned pcount) - { - implTemplateName (strm, ccount, pcount); - - strm << " <T1"; - - if (ccount) - { - paramListT::const_iterator iter = lam.context->begin(); - - for (unsigned count = 1; count <= ccount; ++count) - { - strm << ", T" << count + 1; - - if ((*iter)->byReference) - { - strm << " &"; - } - - ++iter; - } - } - - tList (strm, 2 + ccount, 1 + ccount + pcount, false); - - strm << ">"; - } - - void writeGenerator (ostream &strm, int id, const lambdaT &lam) - { - unsigned ccount = count (lam.context.get()); - unsigned pcount = count (lam.params.get()); - - strm << "\ntemplate <"; - - typenameList (strm, 1, 1); - typenameList (strm, 2 + ccount, 1 + ccount + pcount, false); - - strm - << ">\nstruct lambda_generator_" << id - << "\n{"; - - if (ccount >= 1) - { - strm << "\n template <"; - - typenameList (strm, 2, 1 + ccount); - - strm << ">"; - } - - strm << "\n static "; - - implicitTemplateInstance (strm, lam, ccount, pcount); - - if (lam.onHeap) - { - strm << " *"; - } - - strm << "\n generate ("; - - if (ccount) - { - paramListT::const_iterator iter = lam.context->begin(); - - for (unsigned count = 1; count <= ccount; ++count) - { - if (count != 1) - { - strm << ", "; - } - - strm << "T" << count + 1 << " "; - - if ((*iter)->byReference) - { - strm << "&"; // Accept parameter by reference - } - - strm << "p" << count; - - ++iter; - } - } - - strm << ")\n {\n return "; - - if (lam.onHeap) - { - strm << "new "; - } - - implicitTemplateInstance (strm, lam, ccount, pcount); - - strm << " (&"; - implicitTemplateInstance (strm, lam, ccount, pcount); - strm << "::fn" << id; - - if (ccount) - { - unsigned count = 0; - - for (paramListT::const_iterator iter = lam.context->begin() - ; iter != lam.context->end() - ; ++iter) - { - ++count; - - strm << ", " << "p" << count; - } - } - - strm << ");\n }\n};\n"; - } - - struct MatchInitialiser - { - const stringT &mTarget; - bool mByRef; - - MatchInitialiser (const stringT &target - , bool byRef) - : mTarget (target) - , mByRef (byRef) - { - } - - bool operator() (const boost::shared_ptr<paramT> &pp) - { - return (mTarget == (*pp->initialiser)) && (mByRef == pp->byReference); - } - }; - - bool CodeGen::contextRef (FILE *outFile - , std::auto_ptr<stringT> strp - , bool byRef) - { - // Handles context by value and by reference - - lambdaT &lam (*mStack.top().mLamp); - - if (lam.explicitContext) - { - cerr - << "__ctx or __ref expression in lambda with explicit context\n"; - - return false; - } - - if (!lam.context.get()) - { - lam.context.reset (new paramListT); - } - - paramListT &context (*lam.context); - - paramListT::iterator param; - - param = std::find_if (context.begin() - , context.end() - , MatchInitialiser (*strp, byRef)); - - if (param == context.end()) - { - int ccount = context.size() + 1; - - char newName[128]; - - sprintf (newName, "mContext%d", ccount); - - char pseudoType[128]; - - sprintf (pseudoType, "T%d", ccount); - - boost::shared_ptr<paramT> - newParamPtr (new paramT (makestr(pseudoType) - , makestr (newName) - , strp.release() - , ccount - , byRef)); - - context.push_back (newParamPtr); - - param = context.end(); - --param; - } - - fprintf (outFile, "%s", contextVarExpression (**param).c_str()); - - return true; - } - - bool CodeGen::startLambda (FILE *&f - , int openBracePos - , std::auto_ptr<lambdaT> lamp) - { - mStack.push (LambdaContext (f, openBracePos, lamp)); - - string newName (bodyFileName (++mLambdaCount)); - - f = fopen (newName.c_str(), "w+"); - - if (!f) - { - cerr - << "Failed to create new body file " - << newName - << "\n"; - - f = mStack.top().mPrevFile; - mStack.pop (); - - return false; - } - - return true; - } - - CodeGen::LambdaMap::iterator CodeGen::lambdaGroup (int ccount, int pcount) - { - LambdaType typeId (ccount, pcount); - - LambdaMap::iterator mapIter = mLambdaMap.find (typeId); - - if (mapIter == mLambdaMap.end()) - { - pair<LambdaMap::iterator, bool> inserted - = mLambdaMap.insert (std::make_pair (typeId, LambdaGroup())); - - assert (inserted.second); - - mapIter = inserted.first; - - startExplicitImpl (*mapIter->second.mImplStream, ccount, pcount); - } - - return mapIter; - } - - bool CodeGen::endLambda (FILE *&f) - { - fprintf (f, "\n"); // Ensure newline termination - fclose (f); - f = mStack.top().mPrevFile; - - LambdaContext &ctx (mStack.top()); - - int ccount = count (ctx.mLamp->context.get()); - int pcount = count (ctx.mLamp->params.get()); - - LambdaMap::iterator mapIter = lambdaGroup (ccount, pcount); - - mapIter->second.mLambdaList.push_back (ctx); - - declareMemberFn (*mapIter->second.mImplStream - , ctx.mLambdaNumber - , ccount - , pcount); - - std::ostringstream temp; - - if (ctx.mLamp->explicitContext) - { - explicitConstructor (temp, ctx.mLambdaNumber, *ctx.mLamp); - } - - else - { - writeGenerator (mGeneratorStream, ctx.mLambdaNumber, *ctx.mLamp); - implicitConstructor (temp, ctx.mLambdaNumber, *ctx.mLamp); - } - - fprintf (f, "%s", temp.str().c_str()); - - mStack.pop(); - return true; - } - - void CodeGen::spitItOut () - { - mImplStream - << "//" - << "\n// clamp generated lambda templates" - << "\n// parser " << clamp_parser_rcsid - << "\n// code generator " << clamp_codegen_rcsid - << "\n//\n\n" - ; - - for (LambdaMap::const_iterator iter = mLambdaMap.begin() - ; iter != mLambdaMap.end() - ; ++iter) - { - mImplStream - << iter->second.mImplStream->rdbuf() - << "\nprivate:\n "; - - // Make the assignment operator private, since it wouldn't - // handle any reference member variables - - implTemplateName (mImplStream, iter->first.first, iter->first.second); - - mImplStream << " operator= ("; - - implTemplateName (mImplStream, iter->first.first, iter->first.second); - - mImplStream - << " const &);\n" - << "};\n"; - } - - mImplStream << "\n" << mGeneratorStream.str() << "\n"; - - for (LambdaMap::const_iterator group = mLambdaMap.begin() - ; group != mLambdaMap.end() - ; ++group) - { - const LambdaList &list (group->second.mLambdaList); - - for (LambdaList::const_iterator iter = list.begin() - ; iter != list.end() - ; ++iter) - { - defineMemberFn (mImplStream - , iter->mLambdaNumber - , group->first.first - , group->first.second - , *iter->mLamp); - } - } - } -} +// -*- mode:c++ -*- +// +// Module CodeGen.cc +// +// Copyright (c) 2002, 2003 Raoul M. Gough +// +// This material is provided "as is", with absolutely no warranty expressed +// or implied. Any use is at your own risk. +// +// Permission to use or copy this software for any purpose is hereby granted +// without fee, provided the above notices are retained on all copies. +// Permission to modify the code and to distribute modified code is granted, +// provided the above notices are retained, and a notice that the code was +// modified is included with the above copyright notice. +// +// History +// ======= +// 2002/ 2/11 rmg File creation +// + +#include "CodeGen.hh" + +#include <climits> +#include <sstream> +#include <cassert> +#include <iostream> + +extern const char *clamp_parser_rcsid; +const char *clamp_codegen_rcsid = "$Id: CodeGen.cc,v 1.20 2003/09/30 22:43:05 Raoul Exp $"; + +using namespace std; + +namespace +{ + using namespace clamp; + + unsigned count (paramListT *pListp) + { + if (pListp) + { + return pListp->size(); + } + + else + { + return 0; + } + } + + void initList (std::ostream &strm, paramListT *pListp, bool first = true) + { + if (pListp) + { + for (paramListT::const_iterator iter = pListp->begin() + ; iter != pListp->end() + ; ++iter) + { + if (iter->get()->initialiser.get()) + { + if (!first) + { + strm << ", "; + } + + strm << *iter->get()->initialiser; + + first = false; + } + + else if (iter->get()->type.get()) + { + if (!first) + { + strm << ", "; + } + + // Default initialize + strm << "(" << *iter->get()->type << ")0"; + + first = false; + } + } + } + } + + void typeList (std::ostream &strm, paramListT *pListp, bool first = true) + { + if (pListp) + { + for (paramListT::const_iterator iter = pListp->begin() + ; iter != pListp->end() + ; ++iter) + { + if (iter->get()->type.get()) + { + if (!first) + { + strm << ", "; + } + + strm << *iter->get()->type; + + first = false; + } + } + } + } +} + +namespace clamp +{ + //////////////////////////////////////////////////////////////////////// + // Constructors + //////////////////////////////////////////////////////////////////////// + + CodeGen::CodeGen () + : mStack () + , mLambdaCount (0) + , mImplStream ("lambda_impl.clamp_h") + , mLambdaMap () + , mGeneratorStream () + { + } + + CodeGen::LambdaContext::LambdaContext (FILE *f + , int b + , std::auto_ptr<lambdaT> lamp) + : mPrevFile (f) + , mOpenBracePos (b) + , mLamp (lamp.release()) + , mLambdaNumber (++sContextCount) + { + } + + CodeGen::LambdaGroup::LambdaGroup () + : mLambdaList () + , mImplStream (new stringstream) + { + } + + void implTemplateName (ostream &strm, int ccount, int pcount) + { + strm + << "lambda_template_" + << ccount + << "_" + << pcount; + } + + void tList (ostream &strm, int start, int end, bool first = true) + { + for (int count = start; count <= end; ++count) + { + if (!first) + { + strm << ", "; + } + + strm << "T" << count; + + first = false; + } + } + + void implFunctionVar (ostream &strm, int ccount, int pcount, const char *n) + { + strm << "T1 ("; + + if (ccount > 0) + { + // Implementation via pointer to member function + implTemplateName (strm, ccount, pcount); + strm << "::"; + } + // else implementation via pointer to ordinary function + + strm << "*" << n << ") ("; + tList (strm, 2 + ccount, 1 + ccount + pcount); + strm << ")"; + } + + void implInstance (ostream &strm, lambdaT const &lam) + { + unsigned ccount = count (lam.context.get()); + unsigned pcount = count (lam.params.get()); + + implTemplateName (strm, ccount, pcount); + + strm + << "<" + << *lam.ret_type; + + typeList (strm, lam.context.get(), false); + typeList (strm, lam.params.get(), false); + + strm << "> "; + } + + std::auto_ptr<stringT> CodeGen::lambdaTypeName (std::auto_ptr<lambdaT> lamp) + { + lambdaGroup (count (lamp->context.get()), count (lamp->params.get())); + // Make sure we've recorded the existance of this lambda group + + std::ostringstream temp; + + implInstance (temp, *lamp); + + return std::auto_ptr<stringT> (new stringT (temp.str())); + } + + void CodeGen::lambdaType (FILE *outFile, std::auto_ptr<lambdaT> lamp) + { + fprintf (outFile, "%s", lambdaTypeName (lamp)->c_str()); + } + + bool CodeGen::braceMatch (int pos) + { + return (!mStack.empty()) && (mStack.top().mOpenBracePos == pos); + } + + std::string contextVarExpression (paramT const &ctxParam) + { + std::stringstream result; + + result << "mContext" << ctxParam.ctx_param_num; + + return result.str(); + } + + int CodeGen::LambdaContext::sContextCount = 0; + + stringT bodyFileName (int count) + { + char name[PATH_MAX]; + sprintf (name, "lambda_body_%d.clamp_h", count); + return stringT (name); + } + + void explicitConstructor (ostream &strm, int id, const lambdaT &lam) + { + if (lam.onHeap) + { + strm << "new "; + } + + implInstance (strm, lam); + strm << "(&"; + implInstance (strm, lam); + strm << "::fn" << id; + initList (strm, lam.context.get(), false); + strm << ")"; + } + + void typenameList (ostream &strm + , unsigned start + , unsigned end + , bool first = true) + { + for (unsigned count = start; count <= end; ++count) + { + if (!first) + { + strm << ", "; + } + + strm << "typename T" << count; + + first = false; + } + } + + void implTemplateDecl (ostream &strm, unsigned templateParams) + { + strm + << "template <"; + + typenameList (strm, 1, templateParams); + + strm << ">"; + } + + void startExplicitImpl (ostream &strm, unsigned ccount, unsigned pcount) + { + implTemplateDecl (strm, ccount + pcount + 1); + + strm << "\nstruct "; + + implTemplateName (strm, ccount, pcount); + + strm << "\n{\n "; + + implFunctionVar (strm, ccount, pcount, "mFn"); + + strm << ";"; + + for (unsigned count = 1; count <= ccount; ++count) + { + strm << "\n T" << count + 1 << " mContext" << count << ";"; + } + + strm << "\n\n typedef T1 result_type;"; + + for (unsigned count = 1; count <= ccount; ++count) + { + strm + << "\n typedef T" << count + 1 + << " context_type_" << count + << ";"; + } + + for (unsigned count = 1; count <= pcount; ++count) + { + strm + << "\n typedef T" << count + ccount + 1 + << " argument_type_" << count + << ";"; + } + + // Additional typedefs in special cases for standard binder compatability + if (pcount == 1) + { + strm + << "\n typedef T" << ccount + 2 + << " argument_type;"; + } + + else if (pcount == 2) + { + strm + << "\n typedef T" << ccount + 2 + << " first_argument_type;\n typedef T" << ccount + 3 + << " second_argument_type;"; + } + + strm << "\n\n // Constructor\n "; + + implTemplateName (strm, ccount, pcount); + + strm << " ("; + + implFunctionVar (strm, ccount, pcount, "fn"); + + for (unsigned count = 1; count <= ccount; ++count) + { + strm << ", T" << count + 1 << " c" << count; + } + + strm << ")\n : mFn (fn)"; + + for (unsigned count = 1; count <= ccount; ++count) + { + strm << "\n , mContext" << count << " (c" << count << ")"; + } + + strm + << "\n { }\n" + << "\n // Forwarding function" + << "\n T1 operator() ("; + + for (unsigned count = 1; count <= pcount; ++count) + { + if (count != 1) + { + strm << ", "; + } + + strm << "T" << count + ccount + 1 << " p" << count; + } + + strm << ")\n {\n return ("; + + if (ccount > 0) + { + // Have closure parameters - use pointer to member syntax + strm << "this->"; + } + // else static function + + strm << "*mFn)("; + + for (unsigned count = 1; count <= pcount; ++count) + { + if (count != 1) + { + strm << ", "; + } + + strm << "p" << count; + } + + strm << ");\n }\n"; + } + + void declareMemberFn (ostream &strm + , int id + , unsigned ccount + , unsigned pcount) + { + strm << "\n "; + + if (ccount == 0) + { + strm << "static "; + } + + strm << "T1 fn" << id << " ("; + + tList (strm, 2 + ccount, 1 + ccount + pcount); + + strm << ");\n"; + } + + void defineMemberFn (ostream &strm + , int id + , unsigned ccount + , unsigned pcount + , const lambdaT &lam) + { + implTemplateDecl (strm, ccount + pcount + 1); + + strm << "\nT1 "; + + implTemplateName (strm, ccount, pcount); + + strm << "<"; + + tList (strm, 1, 1 + ccount + pcount); + + strm << ">::fn" << id << " ("; + + if (lam.params.get()) + { + unsigned count = 1; + + for (paramListT::const_iterator iter = lam.params->begin() + ; iter != lam.params->end() + ; ++iter) + { + if (count != 1) + { + strm << ", "; + } + + strm << "T" << count + ccount + 1; + + const stringT *name = iter->get()->name.get(); + + if (name) + { + strm + << " " << *name; + } + + ++count; + } + } + + strm << ")\n{"; + + if (lam.explicitContext && lam.context.get()) + { + // Context parameters require renaming + unsigned count = 1; + + for (paramListT::const_iterator iter = lam.context->begin() + ; iter != lam.context->end() + ; ++iter) + { + const stringT *name = iter->get()->name.get(); + + if (name) + { + strm + << "\n#define " << *name + << " mContext" + << count; + } + + ++count; + } + } + + strm + << "\n#include \"" + << bodyFileName (id) + << "\""; + + if (lam.explicitContext && lam.context.get()) + { + unsigned count = 1; + + for (paramListT::const_iterator iter = lam.context->begin() + ; iter != lam.context->end() + ; ++iter) + { + const stringT *name = iter->get()->name.get(); + + if (name) + { + strm + << "\n#undef " << *name; + } + + ++count; + } + } + + strm << "\n}\n"; + } + + void implicitConstructor (ostream &strm, int id, const lambdaT &lam) + { + strm + << "lambda_generator_" + << id + << "<" + << *lam.ret_type; + + typeList (strm, lam.params.get(), false); + + strm << ">::generate ("; + + initList (strm, lam.context.get()); + + strm <<")"; + } + + void implicitTemplateInstance (ostream &strm + , const lambdaT &lam + , unsigned ccount + , unsigned pcount) + { + implTemplateName (strm, ccount, pcount); + + strm ... [truncated message content] |