[Assorted-commits] SF.net SVN: assorted:[1224] clamp
Brought to you by:
yangzhang
From: <yan...@us...> - 2009-02-23 02:48:07
|
Revision: 1224 http://assorted.svn.sourceforge.net/assorted/?rev=1224&view=rev Author: yangzhang Date: 2009-02-23 02:47:54 +0000 (Mon, 23 Feb 2009) Log Message: ----------- carrying clamp forward! Added Paths: ----------- clamp/ clamp/trunk/ clamp/trunk/doc/ clamp/trunk/doc/index.html clamp/trunk/doc/readme.txt clamp/trunk/src/ 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 Added: clamp/trunk/doc/index.html =================================================================== --- clamp/trunk/doc/index.html (rev 0) +++ clamp/trunk/doc/index.html 2009-02-23 02:47:54 UTC (rev 1224) @@ -0,0 +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> \ No newline at end of file Added: clamp/trunk/doc/readme.txt =================================================================== --- clamp/trunk/doc/readme.txt (rev 0) +++ clamp/trunk/doc/readme.txt 2009-02-23 02:47:54 UTC (rev 1224) @@ -0,0 +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... Added: clamp/trunk/src/CodeGen.cc =================================================================== --- clamp/trunk/src/CodeGen.cc (rev 0) +++ clamp/trunk/src/CodeGen.cc 2009-02-23 02:47:54 UTC (rev 1224) @@ -0,0 +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); + } + } + } +} Added: clamp/trunk/src/CodeGen.hh =================================================================== --- clamp/trunk/src/CodeGen.hh (rev 0) +++ clamp/trunk/src/CodeGen.hh 2009-02-23 02:47:54 UTC (rev 1224) @@ -0,0 +1,110 @@ +// -*- mode:c++ -*- +// +// Header file CodeGen.hh +// +// Copyright (c) 2002 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 +// +// version: $Id: CodeGen.hh,v 1.9 2003/09/30 22:42:56 Raoul Exp $ +// + +#ifndef CodeGen_rmg_20020211_included +#define CodeGen_rmg_20020211_included + +#include "clamp_support.hh" + +#include <stdio.h> +#include <stack> +#include <memory> +#include <fstream> +#include <map> +#include <sstream> +#include "boost/smart_ptr.hpp" + +namespace clamp +{ + class CodeGen + { + public: + CodeGen (); + + public: + void lambdaType (FILE *, std::auto_ptr<lambdaT>); + std::auto_ptr<stringT> lambdaTypeName (std::auto_ptr<lambdaT>); + + public: + bool braceMatch (int pos); + bool startLambda (FILE *&, int openBracePos, std::auto_ptr<lambdaT>); + bool endLambda (FILE *&); + + public: + bool contextRef (FILE *, std::auto_ptr<stringT>, bool byRef = false); + + public: + void spitItOut (); + + private: + struct LambdaContext { + FILE *mPrevFile; + int mOpenBracePos; + boost::shared_ptr<lambdaT> mLamp; + int mLambdaNumber; + + static int sContextCount; + + LambdaContext (FILE *, int, std::auto_ptr<lambdaT>); + }; + + private: + std::stack<LambdaContext> mStack; + + private: + int mLambdaCount; + + private: + std::ofstream mImplStream; + + private: + // + // Store lambda expressions for deferred processing, grouping + // by context and parameter list size (i.e. ccount and pcount) + // + typedef std::pair<unsigned, unsigned> LambdaType; + typedef std::list<LambdaContext> LambdaList; + + struct LambdaGroup + { + // Lambda functions that share the same implementation template + LambdaList mLambdaList; + boost::shared_ptr<std::stringstream> mImplStream; + + LambdaGroup (); + }; + + typedef std::map<LambdaType, LambdaGroup> LambdaMap; + + LambdaMap mLambdaMap; + + private: + std::ostringstream mGeneratorStream; + + private: + LambdaMap::iterator lambdaGroup (int ccount, int pcount); + // Get the lambda group for the given number of parameters (starting + // a new group if necessary) + }; +} + +#endif // CodeGen_rmg_20020211_included Added: clamp/trunk/src/Makefile =================================================================== --- clamp/trunk/src/Makefile (rev 0) +++ clamp/trunk/src/Makefile 2009-02-23 02:47:54 UTC (rev 1224) @@ -0,0 +1,70 @@ +# -*- mode:makefile -*- +# +# GNU Makefile for clamp +# +# 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/ 6 rmg File creation +# +# version: $Id: Makefile,v 1.16.1.4 2003/09/30 22:10:19 Raoul Exp $ +# + +all: clamp test eg curry + +# +# You might have to uncomment and adjust some of the following bits and +# pieces, depending on your set-up: CXX, CC, LEX and -I ...boost... +# + +LEX := flex + +CXXFLAGS = -g -Wall -Wno-unused -I d:/CVS/boost/boost +# Use -Wno-unused because lex.yy.c contains some unused labels and functions + +LFLAGS = +YFLAGS = -v -d + +LDLIBS = -lstdc++ + +clamp.tab.h: clamp.cc + mv y.tab.h clamp.tab.h + +lex.yy.cc: clamplex.lex clamp.tab.h + $(LEX) $(LFLAGS) clamplex.lex + mv lex.yy.c lex.yy.cc + +clamplex.o: lex.yy.cc clamp.tab.h clamp_support.hh + $(COMPILE.cc) lex.yy.cc -o clamplex.o + +clamp_support.o: clamp_support.cc clamp_support.hh + +clamplex: clamplex.o + $(LINK.c) -o clamplex $? + +clamp.cc: clamp.y + $(YACC.y) $? + mv -f y.tab.c clamp.cc + +clamp.o: clamp.cc clamp_support.hh clamplex.h CodeGen.hh + +clamp: LDLIBS := $(LDLIBS) -lfl +clamp: clamp.o clamplex.o clamp_support.o CodeGen.o + +clean: + -rm *.o *.exe clamp.cc y.output clamp.tab.h lex.yy.cc lambda*.clamp_h + +.PRECIOUS: %.cc + +%.cc: %.clamp clamp + ./clamp <$< >$@ Added: clamp/trunk/src/clamp.y =================================================================== --- clamp/trunk/src/clamp.y (rev 0) +++ clamp/trunk/src/clamp.y 2009-02-23 02:47:54 UTC (rev 1224) @@ -0,0 +1,410 @@ +/* -*- mode:c -*- + * + * Bison module clamp.y + * + * 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/ 7 rmg File creation + * + * $Id: clamp.y,v 1.31 2003/09/30 22:06:25 Raoul Exp $ + */ + +%{ +#define YYDEBUG 1 + +#include "clamp_support.hh" +#include "clamplex.h" +#include "CodeGen.hh" + +#include <iostream> +#include <stdio.h> +#include <malloc.h> +#include <set> + + using namespace clamp; + + CodeGen *gGenPtr = 0; + + extern FILE *yyin; + + const char *clamp_parser_rcsid = "$Id: clamp.y,v 1.31 2003/09/30 22:06:25 Raoul Exp $"; + + %} + +%union { + int tokval; + stringT *strval; + paramListT *plist; + lambdaT *lambda; + bool flag; +} + +%token <tokval> TOK_LAMBDA +%token <tokval> TOK_NEW_LAMBDA +%token <tokval> TOK_CONTEXT +%token <tokval> TOK_CONTEXT_REF +%token <tokval> TOK_GENERIC +%token <tokval> TOK_WHITESPACE +%token <tokval> TOK_SCOPE + +%token <tokval> TOK_TYPE_KEYWORD +%token <tokval> TOK_TYPENAME +%token <tokval> TOK_CV_QUAL + +%type <strval> name genericexpr genericexpropt genericid simple_generic +%type <strval> typeid typeidopt basictype cvqualopt typename +%type <strval> name_opt indirect_sym +%type <plist> decls decl_list decl +%type <lambda> lambda_start lambda_type +%type <flag> ctxorref +/* no type for context, statements, lambda_def_start, lambda */ + +%expect 5 + +%% + +input: /* empty */ +| input lambda +; + +lambda: lambda_type { + gGenPtr->lambdaType (yyout, std::auto_ptr<lambdaT>($1)); + + // We read a lookahead token in lambda mode, and it wasn't + // a left brace - put the char back and let the lexer reprocess + // it in the INITIAL start condition + resume_initial = 1; + yyclearin; + lexer_reprocess_last (); +} +| lambda_def_start statements '}' { + if (!gGenPtr->endLambda (yyout)) + { + YYABORT; + } +} +; + +lambda_def_start: lambda_type '{' { + resume_initial = 1; + + if (!gGenPtr->startLambda (yyout, openbraces, std::auto_ptr<lambdaT>($1))) + { + YYABORT; + } +} +; + +lambda_type: lambda_start + | lambda_start '(' decls ')' { + if (plistInitialisers ($3)) + { + yywarning ("default parameters ignored"); + } + + $$ = shiftlambda ($1, $3); // Adjust to explicit-context lambda + } +; + +lambda_start: TOK_LAMBDA typeidopt '(' decls ')' { + $$ = makelambda (0, $2, 0, $4); // Assume implicit context variant +} +| TOK_NEW_LAMBDA typeidopt '(' decls ')' { + $$ = makelambda (0, $2, 0, $4, true); // Assume implicit context variant +} +; + +decls: /* empty */ { $$ = 0; } + | decl_list +; + +decl_list: decl + | decl_list ',' decl { + $$ = appendplist ($1, $3); +} +; + +decl: typeid name_opt { + $$ = makeplist ($1, $2, 0); +} + | typeid name_opt '=' genericexpr { + $$ = makeplist ($1, $2, $4); +} +; + +typeidopt: /* empty */ { $$ = makestr ("void"); } +| typeid +; + +typeid: cvqualopt basictype { $$ = appendstr ($1, $2); } +| typeid cvqualopt indirect_sym cvqualopt { $$ = appendstr ($1, $2, $3, $4);} +| cvqualopt genericid cvqualopt { $$ = appendstr ($1, $2, $3); } +| typename genericid { $$ = appendstr ($1, $2); } +| lambda_type { + $$ = gGenPtr->lambdaTypeName (std::auto_ptr<lambdaT>($1)).release(); +} +; + +indirect_sym: '*' { $$ = makestr (yytext); } +| '&' { $$ = makestr (yytext); } +; + +basictype: TOK_TYPE_KEYWORD { $$ = makestr (yytext); } +| basictype TOK_TYPE_KEYWORD { $$ = appendstr ($1, makestr (yytext)); } +; + +cvqualopt: /* empty */ { $$ = 0; } +| cvqualopt TOK_CV_QUAL { $$ = appendstr ($1, makestr (yytext)); } +; + +typename: TOK_TYPENAME { $$ = makestr (yytext); }; + +name_opt: /* empty */ { $$ = 0; } +| name +; + +name: TOK_GENERIC { $$ = makestr (yytext); } +; + +genericid: simple_generic { $$ = $1; } +| simple_generic TOK_SCOPE simple_generic { + $$ = appendstr ($1, makestr ("::"), $3); +} +; + +simple_generic: TOK_GENERIC { $$ = makestr (yytext); } +; + +statements: /* empty */ +| statements context +| statements lambda +; + +context: ctxorref '(' genericexpr ')' { + if (!gGenPtr->contextRef (yyout, std::auto_ptr<stringT> ($3), $1)) + { + YYABORT; + } + + resume_initial = 1; +} +; + +ctxorref: TOK_CONTEXT { $$ = false; } +| TOK_CONTEXT_REF { $$ = true; } +; + +genericexpr: TOK_GENERIC { $$ = makestr (yytext); } +| genericexpropt '(' genericexpropt ')' genericexpropt { + $$ = appendstr ($1, makestr ("("), $3, makestr (")"), $5); +} +| indirect_sym genericexpropt { $$ = appendstr ($1, $2); } +/* + Note - indirect_sym should actually require a genericexpr + (i.e. it's not optional). Unfortunately, that creates a + reduce/reduce conflict, since the parser can reduce the "X" + in "indirect_sym X" with either genericexpr or genericexpropt +*/ +; + +genericexpropt: { $$ = 0; } + | genericexpr +; + +%% + +namespace +{ + struct BlockInfo + { + BlockInfo *prev; + BlockInfo *next; + void *caller; + std::size_t size; + }; + + struct Stats + { + std::size_t blocks; + std::size_t bytes; + }; + + Stats gAlloc = {0}; + Stats gDealloc = {0}; + + BlockInfo *first = 0; +} + +#ifdef TRACK_MEMORY +void *operator new (std::size_t size) throw (std::bad_alloc) +{ + ++gAlloc.blocks; + gAlloc.bytes += size; + + BlockInfo *myPtr + = static_cast<BlockInfo *> (malloc (size + sizeof(*myPtr))); + + if (first) + { + first->prev = myPtr; + } + + myPtr->next = first; + myPtr->prev = 0; + myPtr->caller = __builtin_return_address (1); + first = myPtr; + + myPtr->size = size; + + return myPtr + 1; +} + +void operator delete (void *ptr) throw () +{ + if (ptr) + { + BlockInfo *myPtr = static_cast<BlockInfo *> (ptr); + --myPtr; + + ++gDealloc.blocks; + gDealloc.bytes += myPtr->size; + + if (myPtr->next) + { + myPtr->next->prev = myPtr->prev; + } + + if (myPtr->prev) + { + myPtr->prev->next = myPtr->next; + } + + else + { + first = myPtr->next; + } + + free (myPtr); + } +} + +void *operator new[] (std::size_t size) throw (std::bad_alloc) +{ + return operator new (size); +} + +void operator delete[] (void *ptr) throw () +{ + return operator delete (ptr); +} +#endif // TRACK_MEMORY + +extern "C" { + int yyerror (const char *s) + { + fflush (yyout); + fflush (stdout); + + fprintf (stderr + , "\nclamp: %s on line %d with token %s\n" + , s + , yylineno + , yytext); + + return 0; + } + + int yywarning (const char *s) + { + fflush (yyout); + fflush (stdout); + + fprintf (stderr + , "clamp: %s on line %d\n" + , s + , yylineno); + + return 0; + } +} + +bool parserBraceMatch (int pos) +{ + return gGenPtr->braceMatch (pos); +} + +int main (int argc, char *argv[]) +{ + int result; + + if (argc > 1) + { + yyin = fopen (argv[1], "r"); + + if (!yyin) + { + perror ("fopen"); + + return 1; + } + + ++argv; + --argc; + } + + yydebug = argc - 1; + + printf ("#include \"lambda_impl.clamp_h\"\n"); + + gGenPtr = new CodeGen; + + result = yyparse(); + + if (result == 0) + { + gGenPtr->spitItOut (); + } + + else + { + fprintf (stderr, "yyparse returned %d\n", result); + } + + delete gGenPtr; + + if (gAlloc.blocks != gDealloc.blocks) + { + using namespace std; + + fprintf (stderr + , "Memory leak detected. Dumping still allocated blocks:\n"); + + fflush (stderr); + + BlockInfo *scan = first; + + while (scan) + { + std::cerr + << "Address " << static_cast<void *>(scan) + << " size " << scan->size + << " caller " << scan->caller + << "\n"; + + scan = scan->next; + } + } + + return result; +} Added: clamp/trunk/src/clamp_support.cc =================================================================== --- clamp/trunk/src/clamp_support.cc (rev 0) +++ clamp/trunk/src/clamp_support.cc 2009-02-23 02:47:54 UTC (rev 1224) @@ -0,0 +1,241 @@ +// -*- mode:c++ -*- +// +// Module clamp_support.cc +// +// Copyright (c) 2002 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 non-commercial purposes +// 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/10 rmg File creation +// +// version: $Id: clamp_support.cc,v 1.11 2002/09/16 17:09:45 Raoul Exp $ +// + +#include "clamp_support.hh" +#include <iostream> +// #include <ostream> + +using namespace std; + +namespace clamp +{ + lambdaT::lambdaT () + : ret_type (0) + , context (0) + , params (0) + , explicitContext (false) + , onHeap (false) + { + } + + template<typename T> + void safeAssign (auto_ptr<T> &to, T *from, bool force = false) + { + if (from || force) + { + to.reset (from); + } + } + + lambdaT *makelambda (lambdaT *lamp + , stringT *typestr + , paramListT *ctx + , paramListT *params + , bool onh) + { + if (lamp == 0) + { + lamp = new lambdaT; + } + + safeAssign (lamp->ret_type, typestr); + safeAssign (lamp->context, ctx); + safeAssign (lamp->params, params); + lamp->onHeap = onh; + + return lamp; + } + + lambdaT *shiftlambda (lambdaT *lamp + , paramListT *params) + { + // Release should be safe because it is only called if lamp is + // already non-null, in which case makelambda guarantees no-throw + lambdaT *result + = makelambda (lamp, 0, lamp ? lamp->params.release() : 0, params); + + result->explicitContext = true; + + return result; + } + + paramListT *appendplist (paramListT *front, paramListT *back) + { + if (front) + { + if (back) + { + front->splice (front->end(), *back); + delete back; + } + } + + else if (back) + { + front = back; + } + + return front; + } + + paramListT *makeplist (stringT *type, stringT *name, stringT *i) + { + auto_ptr<paramListT> listp (new paramListT); + + listp->push_back (boost::shared_ptr<paramT> (new paramT (type, name, i))); + + return listp.release(); + } + + bool plistInitialisers (const paramListT *list) + { + bool foundInit = false; + + if (list) + { + for (paramListT::const_iterator iter = list->begin() + ; (iter != list->end()) && (!foundInit) + ; ++iter) + { + foundInit = (*iter)->initialiser.get(); + } + } + + return foundInit; + } + + stringT *appendstr (stringT *s1, stringT *s2) + { + if (s1) + { + if (s2) + { + s1->append (" "); + s1->append (*s2); + + delete s2; + } + } + + else if (s2) + { + s1 = s2; + } + + return s1; + } + + stringT *appendstr (stringT *s1, stringT *s2, stringT *s3) + { + return appendstr (appendstr (s1, s2), s3); + } + + stringT *appendstr (stringT *s1, stringT *s2, stringT *s3, stringT *s4) + { + return appendstr (appendstr (s1, s2, s3), s4); + } + + stringT *appendstr (stringT *s1 + , stringT *s2 + , stringT *s3 + , stringT *s4 + , stringT *s5) + { + return appendstr (appendstr (s1, s2, s3, s4), s5); + } + + stringT *makestr (const char *cstr) + { + if (cstr) + { + return new stringT (cstr); + } + + else + { + return 0; + } + } + + stringT *makestr (const char *cstr, int length) + { + if (cstr) + { + return new stringT (cstr, length); + } + + else + { + return 0; + } + } + + std::ostream &operator<< (std::ostream &strm, const lambdaT &lam) + { + strm + << "lambdaT returning " + << lam.ret_type.get() + << " from"; + + if (lam.explicitContext) + { + strm + << " context " + << lam.context.get() + << " and"; + } + + strm + << " params " + << lam.params.get(); + + return strm; + } + + std::ostream &operator<< (std::ostream &strm, const paramT &p) + { + return strm + << "(type " + << p.type.get() + << " with name " + << p.name.get() + << ")"; + } + + std::ostream &operator<< (std::ostream &strm, const paramListT &pList) + { + for (paramListT::const_iterator iter = pList.begin() + ; iter != pList.end() + ; ++iter) + { + if (iter != pList.begin()) + { + strm << ", "; + } + + strm << iter->get(); + } + + return strm; + } +} Added: clamp/trunk/src/clamp_support.hh =================================================================== --- clamp/trunk/src/clamp_support.hh (rev 0) +++ clamp/trunk/src/clamp_support.hh 2009-02-23 02:47:54 UTC (rev 1224) @@ -0,0 +1,116 @@ +// -*- mode:c++ -*- +// +// Header file clamp_support.hh +// +// 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/ 7 rmg File creation +// +// version: $Id: clamp_support.hh,v 1.14 2003/09/30 22:06:22 Raoul Exp $ +// + +#ifndef clamp_support_rmg_20020207_included +#define clamp_support_rmg_20020207_included + +#include <string> +#include <list> +#include <memory> +#include <iosfwd> +#include "boost/smart_ptr.hpp" + +namespace clamp +{ + typedef std::string stringT; + + struct paramT + { + boost::shared_ptr<stringT> type; + boost::shared_ptr<stringT> name; + boost::shared_ptr<stringT> initialiser; + int ctx_param_num; + bool byReference; + + paramT (stringT *t, stringT *n, stringT *i, int ctx = 0, bool ref = false) + : type (t) + , name (n) + , initialiser (i) + , ctx_param_num (ctx) + , byReference (ref) + { + } + }; + + typedef std::list<boost::shared_ptr<paramT> > paramListT; + + struct lambdaT + { + std::auto_ptr<stringT> ret_type; + std::auto_ptr<paramListT> context; + std::auto_ptr<paramListT> params; + bool explicitContext; + bool onHeap; + + lambdaT (); + }; + + lambdaT *makelambda (lambdaT *lamp + , stringT *typestr + , paramListT *ctx + , paramListT *params + , bool onHeap = false); + + // + // Convert an implicit-context lambda into an explicit-context version + // by shifting the misplaced params into the correct context slot + // and adding the given parameters + // + lambdaT *shiftlambda (lambdaT *lamp + , paramListT *params); + + paramListT *makeplist (stringT *type, stringT *name, stringT *init); + + paramListT *appendplist (paramListT *front, paramListT *back); + + // Check if the plist contains any initialisers + bool plistInitialisers (const paramListT *); + + stringT *makestr (const char *cstr); + stringT *makestr (const char *cstr, int length); + + stringT *appendstr (stringT *, stringT *); + stringT *appendstr (stringT *, stringT *, stringT *); + stringT *appendstr (stringT *, stringT *, stringT *, stringT *); + stringT *appendstr (stringT *, stringT *, stringT *, stringT *, stringT *); + + /* + template<typename T> + std::ostream &operator<< (std::ostream &strm, const T *tptr) + { + if (tptr) + { + return strm << *tptr; + } + + else + { + return strm << "(null)"; + } + } + */ + + std::ostream &operator<< (std::ostream &, const lambdaT &); + std::ostream &operator<< (std::ostream &, const paramListT &); +} + +#endif // clamp_support_rmg_20020207_included Added: clamp/trunk/src/clamplex.h =================================================================== --- clamp/trunk/src/clamplex.h (rev 0) +++ clamp/trunk/src/clamplex.h 2009-02-23 02:47:54 UTC (rev 1224) @@ -0,0 +1,40 @@ +/* -*- mode:c -*- + * + * Header file clamplex.h + * + * Copyright (c) 2002 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/10 rmg File creation + */ + +#ifndef clamplex_rmg_20020210_included +#define clamplex_rmg_20020210_included + +#include <stdio.h> + +extern int resume_initial; +extern int openbraces; +extern void lexer_reprocess_last (); + +extern "C" { + int yyerror (const char *); + int yywarning (const char *); + int yylex (); + + extern char *yytext; + extern FILE *yyout; + extern int yylineno; +} + +#endif // clamplex_rmg_20020210_included Added: clamp/trunk/src/clamplex.lex =================================================================== --- clamp/trunk/src/clamplex.lex (rev 0) +++ clamp/trunk/src/clamplex.lex 2009-02-23 02:47:54 UTC (rev 1224) @@ -0,0 +1,192 @@ +/* -*- mode:c -*- + * + * Flex module clamplex.lex + * + * Copyright (c) 2002 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/ 6 rmg File creation + * + * version: $Id: clamplex.lex,v 1.13 2002/11/18 17:04:00 Raoul Exp $ + */ + +%{ + +#include <stdio.h> +#include "clamp_support.hh" + + using namespace clamp; + +#include "clamp.tab.h" + + int resume_initial = 0; + + int openbraces = 0; + + extern "C" { int yylex (); } + + extern bool parserBraceMatch (int); +%} + +%option nomain + +%x stringlit +%x charlit +%x comment +%x lambda +%x lambda_def +%x context + +FSLASH \/ +BSLASH \\ +DQUOTE \" +SQUOTE \' +STAR \* +LBRACE \{ +RBRACE \} +COLON \: + +%option yylineno + +%% + if (resume_initial) + { + BEGIN (INITIAL); + resume_initial = 0; + } + +<INITIAL>{ + {FSLASH}{FSLASH}.*\n ECHO; + + {DQUOTE} { + ECHO; + BEGIN(stringlit); + } + + {SQUOTE} { + ECHO; + BEGIN(charlit); + } + + {FSLASH}{STAR} { + ECHO; + BEGIN(comment); + } + + new[ \t\n][ \t\n]*lambda { + BEGIN(lambda); + return TOK_NEW_LAMBDA; + } + + lambda { + BEGIN(lambda); + return TOK_LAMBDA; + } + + __ctx[ \t\n]* { + BEGIN (context); + return TOK_CONTEXT; + } + + __ref[ \t\n]* { + BEGIN (context); + return TOK_CONTEXT_REF; + } + + {LBRACE} { + ECHO; + ++openbraces; + } + + {RBRACE} { + if (parserBraceMatch (openbraces--)) + { + return '}'; + } + + else + { + ECHO; + } + } +} + +<stringlit>{ + [^\"\\]* ECHO; + {BSLASH}. ECHO; + {DQUOTE} { + ECHO; + BEGIN(INITIAL); + } +} + +<charlit>{ + [^\'\\]* ECHO; + {BSLASH}. ECHO; + {SQUOTE} { + ECHO; + BEGIN(INITIAL); + } +} + +<comment>{ + {STAR}{FSLASH} { + ECHO; + BEGIN(INITIAL); + } +} + +<lambda>{ + const | + volatile return TOK_CV_QUAL; + + char | + int | + short | + long | + signed | + unsigned | + float | + double return TOK_TYPE_KEYWORD; + + typename return TOK_TYPENAME; + + lambda return TOK_LAMBDA; + + [^()*&,{}= \t\n]* return TOK_GENERIC; + + [ \t\n]* /* ignore whitespace */ + + {LBRACE} { + ++openbraces; + return yytext[... [truncated message content] |