--- /dev/null
+PROJECT(gsp)
+
+SUBDIRS(libparser)
+
+OPTION(WITH_GSP "GSP parser / generator Build" OFF)
+
+INCLUDE(CheckIncludeFiles)
+INCLUDE(CheckIncludeFile)
+INCLUDE(CheckTypeSize)
+INCLUDE(CheckFunctionExists)
+INCLUDE(CheckLibraryExists)
+INCLUDE(CheckSymbolExists)
+CHECK_INCLUDE_FILE(unistd.h HAVE_UNISTD_H)
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/gsp_config.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/gsp_config.h)
+
+IF (NOT CMAKE_BUILD_TYPE)
+ SET(CMAKE_BUILD_TYPE Debug)
+ENDIF(NOT CMAKE_BUILD_TYPE)
+
+# Only for Linux not MAC
+IF(APPLE)
+ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG ")
+ELSE(APPLE)
+ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG -std=c++0x")
+ SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++0x")
+ENDIF(APPLE)
+
+
+INCLUDE(${rules_SOURCE_DIR}/flex.cmake)
+INCLUDE_DIRECTORIES(${cmip-lib_BINARY_DIR}/)
+INCLUDE_DIRECTORIES(${asn1_SOURCE_DIR}/)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/rt)
+IF (NOT WIN32)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst ${CMAKE_CURRENT_SOURCE_DIR}/,,$<)\"'")
+ENDIF(NOT WIN32)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
+INCLUDE_DIRECTORIES(${aebutils_SOURCE_DIR}/aeb)
+INCLUDE_DIRECTORIES(${aebutils_SOURCE_DIR}/)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../common/include)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/libparser)
+ADD_DEFINITIONS(-DWITH_ADT_GSP)
+
+IF (WITH_GSP)
+
+IF (NOT CMAKE_CROSSCOMPILING)
+ ADD_EXECUTABLE(gsp
+ main.cpp
+ )
+ #TARGET_LINK_LIBRARIES(gdmo gdmoparser gdmogen)
+ # EXPORT(TARGETS gdmo FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake
+ # NAMESPACE native-)
+ENDIF(NOT CMAKE_CROSSCOMPILING)
+
+
+IF(CMAKE_CROSSCOMPILING)
+ SET(gsp_EXE native-gsp)
+ GET_TARGET_PROPERTY(test ${gsp_EXE} IMPORTED_LOCATION_DEBUG)
+ELSE(CMAKE_CROSSCOMPILING)
+ SET(gsp_EXE ${CMAKE_CURRENT_BINARY_DIR}/gsp)
+ENDIF(CMAKE_CROSSCOMPILING)
+
+#
+# Ok, Add some custom commands
+#
+
+ENDIF(WITH_GSP)
--- /dev/null
+#ifndef GSP_CONFIG_H
+#define GSP_CONFIG_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine HAVE_UNISTD_H 1
+
+/**/
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <cstdio>
+#include <list>
+#include <map>
+#include <set>
+#include <stack>
+#include <algorithm>
+#include <stdio.h>
+// for memset
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#if defined (_WIN32)
+#include <io.h>
+#define access _access_s
+#define F_OK 0
+
+#include <stdlib.h>
+#include <direct.h>
+#define getcwd _getcwd
+#define mkdir _mkdir
+#endif
+
+#endif /*GDMO_CONFIG_H*/
--- /dev/null
+PROJECT(gsplibparser)
+
+
+IF (NOT CMAKE_BUILD_TYPE)
+ SET(CMAKE_BUILD_TYPE Debug)
+ENDIF(NOT CMAKE_BUILD_TYPE)
+
+# Only for Linux not MAC
+IF(APPLE)
+ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG ")
+ELSE(APPLE)
+ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG -std=c++0x")
+ SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++0x")
+ENDIF(APPLE)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../../)
+INCLUDE(${rules_SOURCE_DIR}/flex.cmake)
+
+
+LEXGEN(gsplex.lpp FlexParser.cpp)
+
+ADD_LIBRARY(gspparser
+ parser.cpp
+ lexer.cpp
+ FlexParser.cpp
+ )
+ADD_EXECUTABLE(gsptest
+ gsp_compiler.cpp)
+TARGET_LINK_LIBRARIES(gsptest gspparser)
--- /dev/null
+/*
+ * Copyright (C) 2005 Krzysztof Rzymkowski <rzymek@users.sourceforge.net>
+ * Copyright (C) 2006 Ilya Volynets <ilya@total-knowledge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "dso_code.h"
+#include <servlet/IOError.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#ifdef DEBUG
+#include <iostream> //dbg
+#endif
+
+using namespace std;
+
+dso_code::dso_code(const string& a_filename) : filename(a_filename)
+{
+ load();
+ try {
+ mtime = file_mtime();
+ } catch (...) {
+ unload();
+ throw;
+ }
+}
+
+time_t dso_code::file_mtime()
+{
+ return 0;
+/* struct stat finfo;
+ int status = stat(filename.c_str(),&finfo);
+ if (status == -1)
+ throw servlet::IOError(filename + ": Cannot stat the file");
+ return finfo.st_mtime;*/
+}
+
+void dso_code::load()
+{
+ handle = ::dlopen(filename.c_str(), RTLD_LAZY|RTLD_GLOBAL);
+ if (!handle) {
+ throw std::runtime_error(filename+": Unable to load the library: "+dlerror());
+ }
+
+}
+void dso_code::unload()
+{
+ if (dlclose(handle) != 0)
+ throw std::runtime_error(filename+": unable to dlclose: "+dlerror());
+}
+
+bool dso_code::reload_if_needed(time_t mtime)
+{
+ if (this->mtime != mtime) {
+ unload();
+ load();
+ this->mtime = mtime;
+ return true;
+ }
+ return false;
+}
+
+bool dso_code::reload_if_needed()
+{
+ time_t mtime = file_mtime();
+ return reload_if_needed(mtime);
+}
+
+void* dso_code::call_(const std::string& name)
+{
+ typedef void*(*dso_func_t)();
+ dso_func_t sym = (dso_func_t)dlsym(handle, name.c_str());
+ if (!sym)
+ throw runtime_error(filename+": "+name+": Error getting the symbol: "+dlerror());
+ return sym();
+}
+
+void* dso_code::func_(const std::string& name)
+{
+ void* sym = dlsym(handle, name.c_str());
+ if (!sym)
+ throw runtime_error(filename+": "+name+": Error getting the symbol: "+dlerror());
+ return sym;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2005 Krzysztof Rzymkowski <rzymek@users.sourceforge.net>
+ * Copyright (C) 2006 Ilya Volynets <ilya@total-knowledge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef DSO_CODE_H
+#define DSO_CODE_H
+
+#include <string>
+#include <dlfcn.h>
+#include <time.h>
+
+class dso_code
+{
+ void *handle;
+ time_t mtime; //modification time of the dso file
+ std::string filename;
+
+ void load();
+ void unload();
+ //Returns the mtime of the 'filename'
+ time_t file_mtime();
+ void* call_(const std::string&);
+ void* func_(const std::string&);
+public:
+ dso_code(const std::string& filename);
+ dso_code(const std::string& a_filename, time_t mtime) : filename(a_filename)
+ { load(); this->mtime = mtime; }
+ ~dso_code()
+ { unload(); }
+ bool reload_if_needed(time_t mtime);
+ bool reload_if_needed();
+ bool file_changed()
+ { return file_mtime() > mtime; }
+ template<typename T>
+ T call(const std::string& name)
+ {
+ return reinterpret_cast<T>(call_(name));
+ }
+ template<typename T>
+ T func(const std::string& name)
+ {
+ return reinterpret_cast<T>(func_(name));
+ }
+};
+
+#endif//DSO_CODE_H
+
--- /dev/null
+/*
+ * Copyright (C) 2008-2009 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
+ * Copyright (C) 2005 Krzysztof Rzymkowski <rzymek@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "generator.h"
+#include <stdexcept>
+#include <fstream>
+#include <boost/tokenizer.hpp>
+#include "tokenizer.h"
+#include <servlet/taglib/Generator.h>
+#include <utils/text.h>
+
+namespace cxxsp
+{
+
+using namespace std;
+
+inline string generate_class_name(const string& filename)
+{
+ string class_name = "CspServlet";
+ for (string::size_type i=0;i<filename.size();++i) {
+ if (!isalnum(filename[i]))
+ class_name += '_';
+ else
+ class_name += filename[i];
+ }
+ return class_name;
+}
+
+generator::generator(const string& fileout, const string& filein, const std::string& class_name)
+ : class_name(class_name)
+ , filename(fileout)
+ , filein(filein)
+ , m_abstract(false)
+ , session(false)
+ , isErrorPage(false)
+ , contentType("text/html")
+ , characterEncoding("utf8")
+ , extends("servlet::HttpServlet")
+{
+ generators.head() << "#include <servlet/HttpServlet.h>" << endl;
+}
+
+string generator::escape(const string& s)
+{
+ string res;
+ res.reserve(s.size() + s.size()/3);
+ for (unsigned i=0;i<s.size();++i) {
+ switch (s[i]) {
+ case '\\':
+ res += "\\\\";
+ break;
+ case '\r':
+ res += "\\r";
+ break;
+ case '\n':
+ res += "\\n\"\n\t\"";
+ break;
+ case '"':
+ res += "\\\"";
+ break;
+ default:
+ res += s[i];
+ }
+ }
+ return res;
+}
+
+void generator::data(const string& data, int line, const std::string& fname)
+{
+ if (!data.empty())
+ generators.body() << "#line " << line << " \"" << fname << "\"\n";
+ generators.body() << "\tout.write(\"" << escape(data) << "\", " << data.size() << ");\n";
+}
+
+void generator::decl(const string& data, int line, const std::string& fname)
+{
+ generators.head() << "#line " << line << " \"" << fname << "\"\n";
+ generators.head() << data << endl;
+}
+
+void generator::code(const string& data, int line, const std::string& fname)
+{
+ generators.body() << "#line " << line << " \"" << fname << "\"\n";
+ generators.body() << data << endl;
+}
+
+void generator::expr(const string& data, int line, const std::string& fname)
+{
+ generators.body() << "#line " << line << " \"" << fname << "\"\n";
+ generators.body() << "out << ( " << data << ");\n";
+}
+
+void generator::header(const string& data, int line, const std::string& fname)
+{
+ generators.head() << "#line " << line << " \"" << fname << "\"\n";
+ generators.head() << data << endl;
+}
+
+inline void fill(string &templ, string name, string val)
+{
+ string::size_type pos;
+ const string needle = "{" + name + "}";
+ for (;;) {
+ pos = templ.find(needle);
+ if (pos == string::npos)
+ break;
+ templ.replace(pos, needle.size(), val);
+ }
+}
+
+void generator::libtag_start(int line, const std::string& fname, const string& prefix, const string& name, const attribs_t& attribs)
+{
+ servlet::taglib::Generator& gen = generators.get(prefix,name);
+ generators.body() << endl << "#line " << line << " \"" << fname << "\"\n";
+ gen.doStartTag(attribs);
+ generators.body() << "#line " << line << " \"" << fname << "\"\n";
+}
+
+void generator::libtag_end(int line, const std::string& fname, const string& prefix, const string& name)
+{
+ generators.body() << "#line " << line << " \"" << fname << "\"\n";
+ std::string fullname(prefix);
+ fullname+=':';
+ fullname.append(name);
+ servlet::taglib::Generator& gen = generators.pop(fullname);
+ generators.body() << "#line " << line << " \"" << fname << "\"\n";
+}
+
+
+void generator::directive(const string& name, const attribs_t& attribs)
+{
+ /* include directive is processed by lexer*/
+ if (name == "page") {
+ attribs_t::const_iterator attrib;
+
+ attrib = attribs.find("language");
+ if (attrib != attribs.end())
+ if (attrib->second != "c++")
+ throw runtime_error("Invalid language. Only accepted value is \"c++\"");
+
+ attrib = attribs.find("import");
+ if (attrib != attribs.end()) {
+ tokenizer tok(attrib->second,',');
+ while (!tok.end())
+ generators.head() << "#include <" << tok.next() << ">" << endl;
+ }
+
+ attrib = attribs.find("session");
+ if (attrib != attribs.end())
+ session = (attrib->second == "true");
+
+ attrib = attribs.find("isErrorPage");
+ if (attrib != attribs.end())
+ isErrorPage = (attrib->second == "true");
+
+ attrib = attribs.find("errorPage");
+ if (attrib != attribs.end()) {
+ errorPage = attrib->second;
+ if (errorPage == "this")
+ errorPage = filename;
+ }
+ attrib = attribs.find("contentType");
+ if (attrib != attribs.end())
+ contentType = attrib->second;
+ attrib = attribs.find("characterEncoding");
+ if (attrib != attribs.end())
+ characterEncoding = attrib->second;
+
+ attrib = attribs.find("extends");
+ if (attrib != attribs.end())
+ extends = attrib->second;
+
+ attrib = attribs.find("flags");
+ if (attrib != attribs.end())
+ split_to(attrib->second, flags_);
+
+ attrib = attribs.find("class");
+ if (attrib != attribs.end())
+ if(class_name.empty()) // Make sure it wasn't set on command line
+ class_name=attrib->second;
+
+ // Allows CSP page class to be in a namespace
+ // It's helpful, if, for example, you want to have
+ // Identical class names for multiple CSPs (think themes/skins)
+ attrib = attribs.find("namespace");
+ if (attrib != attribs.end())
+ m_namespace = attrib->second;
+
+ // If abstract is set to "true"
+ // No function is generated, and body stream is discarded
+ attrib = attribs.find("abstract");
+ if (attrib != attribs.end() && attrib->second=="true")
+ m_abstract = true;
+ } else if (name == "taglib") {
+ attribs_t::const_iterator attrib;
+ string prefix,uri;
+
+ attrib = attribs.find("uri");
+ if (attrib != attribs.end()) {
+ uri = attrib->second;
+ } else {
+ throw runtime_error("uri attribute missing from taglib directive");
+ }
+
+ attrib = attribs.find("prefix");
+ if (attrib != attribs.end()) {
+ prefix = attrib->second;
+ } else {
+ throw runtime_error("prefix attribute missing from taglib directive");
+ }
+
+ // If compiletime attribute is set,
+ // we have a preprocessor taglib
+ // Otherwise we have "runtime" taglib,
+ // and container code is generated with
+ // a cppserv-provided generator.
+ attrib = attribs.find("compiletime");
+ if (attrib == attribs.end() || attrib->second!="true") {
+ prefix="cxxsp_runtime_taglib";
+ uri="cxxsp_runtime_taglib.so";
+ }
+
+ try {
+ generators.load(prefix, uri, attribs);
+ } catch (std::exception& e) {
+ std::cerr<<"Unable to load tag lib (prefix="<<prefix<<", uri="<<uri<<")"<<std::endl;
+ throw;
+ }
+ } else {
+ throw runtime_error("Unknown directive: " + name);
+ }
+}
+
+void generator::generate(bool split_def)
+{
+ if(class_name.empty())
+ class_name=generate_class_name(filein);
+ ofstream out_decl, out_def;
+ out_decl.exceptions(ios::badbit | ios::failbit);
+ out_def.exceptions(ios::badbit | ios::failbit);
+ if(split_def)
+ {
+ out_decl.open((filename+".h").c_str());
+ out_def.open((filename+".cpp").c_str());
+ }
+ else
+ {
+ out_decl.open(filename.c_str());
+ }
+ generators.head()<<endl;
+ generators.head().seekg(0);
+ generators.member()<< endl;
+ generators.member().seekg(0);
+ generators.body()<<endl;
+ generators.body().seekg(0);
+
+ // Set file name
+ out_decl<<"#line 1 \"" << filein << "\"\n";
+ if(split_def)
+ {
+ out_def<<"#line 1\"" << filein << "\"\n";
+ //FIXME: use filesystem function, when TR1 is ready
+ string base_name;
+ string::size_type sep = filename.rfind('/');
+ if(sep!=string::npos)
+ base_name=filename.substr(sep+1);
+ else
+ base_name=filename;
+ out_def<<"#include \"" << base_name << ".h\""<<std::endl;
+ out_def<<"#line 1\"" << filein << "\"\n";
+ }
+
+ if (session)
+ out_decl << "#include <memory>\n";
+ out_decl << generators.head().rdbuf() << endl;
+ if(!m_namespace.empty())
+ out_decl << "namespace " << m_namespace << "{"<<std::endl;
+ out_decl << "class " << class_name << ": public " << extends << " {" << endl;
+ out_decl << generators.member().rdbuf() << endl;
+ std::ostream* out;
+ if(split_def)
+ out = &out_def;
+ else
+ out = &out_decl;
+ if(!m_abstract)
+ {
+ out_decl << "public:\n";
+ out_decl << " void doPost(servlet::HttpServletRequest& request, servlet::HttpServletResponse& response) {\n";
+ out_decl << " doGet(request, response);\n";
+ out_decl << " }\n";
+ if(split_def)
+ {
+ out_decl << " void doGet(servlet::HttpServletRequest& request, servlet::HttpServletResponse& response);\n";
+ if(!m_namespace.empty())
+ out_def << "namespace " << m_namespace <<" {" << endl;
+ out_def <<"void " << class_name << "::doGet(servlet::HttpServletRequest& request, servlet::HttpServletResponse& response) {\n";
+ }
+ else
+ {
+ out_decl << " void doGet(servlet::HttpServletRequest& request, servlet::HttpServletResponse& response) {\n";
+ }
+ if (isErrorPage) {
+ *out << " const std::exception* exception = request.hasAttribute(\"csp.exception\") ? \n"
+ << " &request.getAttribute<std::exception>(\"csp.exception\") : \n"
+ << " 0;\n";
+ }
+ if (!errorPage.empty())
+ *out << " try { \n";
+ *out << " std::ostream& out = response.getOutputStream();\n"
+ << " response.setContentType(\"" << escape(contentType) <<"\");\n"
+ << " response.setCharacterEncoding(\"" << escape(characterEncoding) <<"\");\n";
+ if (session)
+ *out << " servlet::HttpSession* session = request.getSession();\n";
+ *out << endl << generators.body().rdbuf() << endl;
+ if (!errorPage.empty()) {
+ *out << " }catch(const std::exception& e) { \n"
+ << " request.setAttribute(\"csp.exception\", e);\n"
+ << " if(exception == 0) /* avoid exception loop */ { "
+ << " request.getRequestDispatcher(\"" << errorPage << "\")->forward(request,response); \n"
+ << " } else {\n"
+ << " throw;"
+ << " }\n"
+ << " }\n";
+ }
+ *out << " }\n";
+ }
+ out_decl << "};\n";
+ if(!m_abstract)
+ *out << "EXPORT_SERVLET(" << class_name << ");" << endl;
+ if(!m_namespace.empty())
+ {
+ out_decl<<'}'<<endl;
+ if(split_def && !m_abstract)
+ out_def<<'}'<<endl;
+ }
+ if(split_def)
+ out_def.close();
+ out_decl.close();
+}
+}
--- /dev/null
+/*
+ * Copyright (C) 2008-2009 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
+ * Copyright (C) 2005 Krzysztof Rzymkowski <rzymek@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef GENERATOR_H
+#define GENERATOR_H
+
+#include <map>
+#include <string>
+#include <vector>
+#include <utility>
+#include <sstream>
+#include <iostream>
+#include "generator_manager.h"
+
+namespace cxxsp
+{
+
+class generator
+{
+ std::string escape(const std::string& s);
+ std::string class_name, m_namespace;
+ std::string filename, filein;
+ bool m_abstract;
+
+ bool session, isErrorPage;
+ std::string errorPage;
+ std::string contentType, characterEncoding, extends;
+ std::vector<std::string> flags_;
+
+ generator_manager generators;
+public:
+ generator(const std::string& fileout, const std::string& filein, const std::string& class_name);
+ typedef servlet::taglib::attribs_t attribs_t;
+
+ void data(const std::string& data, int line, const std::string& fname);
+ void decl(const std::string& data, int line, const std::string& fname);
+ void code(const std::string& data, int line, const std::string& fname);
+ void expr(const std::string& data, int line, const std::string& fname);
+ void header(const std::string& data, int line, const std::string& fname);
+ void libtag_start(int line, const std::string& fname, const std::string& prefix, const std::string& name, const attribs_t& attribs);
+ void libtag_end(int line, const std::string& fname, const std::string& prefix, const std::string& name);
+ void directive(const std::string& name, const attribs_t& attribs);
+
+ void generate(bool split_def);
+ const std::vector<std::string>& flags()
+ { return flags_; }
+ const std::string& className()
+ { return class_name; }
+ const std::string& fileName()
+ { return filename; }
+};
+
+}
+
+#endif//GENERATOR_H
+
--- /dev/null
+/*
+ * Copyright (C) 2008-2009, 2011 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
+ * Copyright (C) 2005 Krzysztof Rzymkowski <rzymek@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "generator_manager.h"
+#include <iostream>
+#include <sstream>
+using namespace std;
+
+void generator_manager::load(const string& prefix, const string& uri, const generator_manager::attribs_t& attribs)
+{
+ if (registry.find(prefix) == registry.end()) {
+ entry e;
+ e.dso = new dso_code(uri);
+ e.taglib = e.dso->func<taglibfactory_t>("create_taglib_"+prefix)(attribs);
+ registry[e.taglib->getPrefix()] = e;
+ }
+}
+
+servlet::taglib::Generator& generator_manager::get(const string& prefix, const string& name)
+{
+ registry_t::iterator r = registry.find(prefix);
+ if (r == registry.end())
+ throw runtime_error("Prefix "+prefix+" not registered");
+ entry& e = r->second;
+ e.dso->reload_if_needed();
+ servlet::taglib::Generator* generator = e.taglib->getTag(name);
+ if(!generators.empty())
+ generator->setParent(generators.top().first);
+ generator->setBuffers(*m_body,*m_head,*m_member);
+ generator->initChildBuffers();
+ m_head = generator->child_header();
+ m_member = generator->child_member();
+ m_body = generator->child_body();
+ generators.push(std::pair<servlet::taglib::Generator*, entry*>(generator, &e));
+ return *generator;
+}
+
+generator_manager::generator_manager()
+ : m_head(&top_head)
+ , m_member(&top_member)
+ , m_body(&top_body)
+{
+}
+
+generator_manager::~generator_manager()
+{
+ if (!generators.empty()) {
+ std::cerr<<"There are still unclosed custom tags: "<<std::endl;
+ while(!generators.empty()) {
+ generators_t::value_type top = generators.top();
+ std::cerr<<"\t"<<top.first->getName()<<std::endl;
+ top.second->taglib->releaseTag(top.first);
+ generators.pop();
+ }
+ }
+
+ for (registry_t::iterator lib = registry.begin(); lib != registry.end(); ++lib) {
+ entry& e = lib->second;
+ delete e.dso;
+ e.dso = NULL;
+ }
+}
+
+servlet::taglib::Generator& generator_manager::pop(const std::string& name)
+{
+ if(generators.empty())
+ throw runtime_error("Closing tag \""+name+"\" which wasn't open");
+ std::pair<servlet::taglib::Generator*, entry*> top = generators.top();
+ if(!top.first)
+ throw runtime_error("Closing tag \""+name+"\" which wasn't open");
+ std::string topname = top.first->getName();
+ if(topname != name) {
+ std::stringstream errmsg;
+ errmsg<< "Closing tag \""<<name<<"\" which wasn't open (current tag: \""<<topname<<"\")";
+ throw std::runtime_error(errmsg.str());
+ }
+ top.first->doEndTag();
+ top.second->taglib->releaseTag(top.first);
+ generators.pop();
+ if(generators.empty())
+ {
+ m_head = &top_head;
+ m_body = &top_body;
+ m_member = &top_member;
+ }
+ else
+ {
+ m_head = generators.top().first->child_header();
+ m_body = generators.top().first->child_body();
+ m_member = generators.top().first->child_member();
+ }
+ return *top.first;
+}
--- /dev/null
+/*
+ * Copyright (C) 2008-2009 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
+ * Copyright (C) 2005 Krzysztof Rzymkowski <rzymek@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef GENERATOR_MANAGER_H
+#define GENERATOR_MANAGER_H
+#include <string>
+#include <stack>
+#include <map>
+#include <string>
+#include <stdexcept>
+#include <servlet/taglib/Generator.h>
+#include <servlet/taglib/Taglib.h>
+#include "dso_code.h"
+#include <memory>
+#include <sstream>
+
+class generator_manager
+{
+ typedef servlet::taglib::attribs_t attribs_t;
+ typedef std::map<std::string, servlet::taglib::Generator*> tags_t;
+ typedef servlet::taglib::Taglib* (*taglibfactory_t)(const attribs_t&);
+
+ struct entry {
+ dso_code* dso;
+ servlet::taglib::Taglib* taglib;
+ };
+
+ typedef std::stack<std::pair<servlet::taglib::Generator*, entry*> > generators_t;
+ generators_t generators;
+
+ typedef std::map<std::string, entry> registry_t;
+ registry_t registry;
+ std::stringstream top_head, top_member, top_body;
+ std::iostream *m_head, *m_member, *m_body;
+public:
+ generator_manager();
+ ~generator_manager();
+ void load(const std::string &prefix, const std::string &uri, const attribs_t& attribs);
+ servlet::taglib::Generator& get(const std::string& prefix, const std::string& name);
+ servlet::taglib::Generator& pop(const std::string&);
+ std::iostream& head() { return *m_head; }
+ std::iostream& member() { return *m_member; }
+ std::iostream& body() { return *m_body; }
+};
+
+
+#endif//GENERATOR_MANAGER_H
+
--- /dev/null
+
+#include "parser.h"
+
+#include <getopt.h>
+
+#include <iostream>
+#include <list>
+//#include <boost/tokenizer.hpp>
+#include <utils/aeb/tokenizer.h>
+
+using namespace std;
+
+void usage(const char* name)
+{
+ std::cerr<<
+ "Usage:\n\t"<<name<<" [--eat-spaces|-e] [--include=path|-I path...] [--split-definition|-s] [--gen-deps|-g] input.csp output[.cpp]"<<std::endl;
+ exit(1);
+}
+
+int main(int argc, char** argv)
+{
+ bool eat_spaces(false), gen_deps(false), split_def(false);
+ std::string class_name;
+ const char *input(0), *output(0), **curfile(&input);
+ static struct option long_opts[] =
+ {
+ // name |has arg|flag|
+ { "eat-spaces", 0, 0, 'e' },
+ { "include", 1, 0, 'I' },
+ { "gen-deps", 0, 0, 'd' },
+ { "split-definition", 0,0, 's' },
+ { "class-name", 1, 0, 'c' },
+ { 0, 0, 0, 0 }
+ };
+ std::list<std::string> search_path;
+ const char* esp = ::getenv("CSP_INCLUDE_PATH");
+ if(esp)
+ {
+ std::string env_search_path(esp);
+#if 0
+ boost::char_separator<char> sep(":","");
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ tokenizer t(env_search_path, sep);
+ for(tokenizer::const_iterator it = t.begin(); it!=t.end(); it++)
+ search_path.push_front(*it);
+#else
+ Tokenizer<std::string> tok(":");
+ std::vector<std::string> t;
+ tok.GetTokens(env_search_path,t);
+ for(std::vector<std::string>::const_iterator it = t.begin(); it!=t.end(); it++)
+ search_path.push_front(*it);
+#endif
+ }
+ for(;;)
+ {
+ int option_index(0);
+ int c = getopt_long(argc, argv, "eI:dsc:", long_opts, &option_index);
+ if(c==-1)
+ break;
+ switch(c)
+ {
+ case 'e':
+ eat_spaces=true;
+ break;
+ case 'I':
+ search_path.push_front(optarg);
+ break;
+ case 'd':
+ gen_deps=true;
+ break;
+ case 's':
+ split_def=true;
+ break;
+ case 'c':
+ class_name = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+ if(argc-optind != 2) {
+ std::cerr<<"Input and/or output file aren't specified"<<std::endl;
+ usage(argv[0]);
+ }
+ input=argv[optind];
+ output=argv[optind+1];
+ cxxsp::parser parser(input, output, class_name, eat_spaces, gen_deps, split_def);
+ for(std::list<std::string>::iterator it = search_path.begin(); it!=search_path.end(); it++)
+ parser.addIncludeDir(*it);
+ if(!parser.parse())
+ return 1;
+ return 0;
+}
--- /dev/null
+/*
+ * FastServerPages - an inline C++ dynamic web pages technology
+ * Copytight (C) 2008-2009 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
+ * Copyright (C) 2003 Krzysztof Rzymkowski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+%option prefix="Cxxsp"
+%option yyclass="cxxsp::lexer"
+%option noyywrap
+%option yylineno
+%option c++
+%option stack
+
+%x HTML_COMMENT
+%x CXXSP_COMMENT
+%x CODE_GENERAL
+%x CODE_EXPR
+%x CODE_DECL
+%x CODE_HEADER
+%x DBL_QUOTE
+%x COMMENT
+%x SPECIAL_TAG
+%x LIBTAG
+
+QUOTE_VALUE ('[^']*')|(\"[^\"]*\")
+ID [a-zA-Z0-9_]+
+
+%{
+ #include "lexer.h"
+
+ /*
+ "<!--" { BEGIN(HTML_COMMENT); save_text(); return CSP_DATA; }
+ <HTML_COMMENT>"-->" { BEGIN(INITIAL); save_text(); return CSP_DATA; }
+ */
+
+%}
+
+%%
+
+
+"<%--" { BEGIN(CXXSP_COMMENT); }
+<CXXSP_COMMENT>{
+ "--%>"\n? { BEGIN(INITIAL); }
+ . /* eat */
+}
+
+"<%" { BEGIN(CODE_GENERAL); return CSP_CODE_START; }
+"<%=" { BEGIN(CODE_EXPR); return CSP_EXPR_START; }
+"<%!" { BEGIN(CODE_DECL); return CSP_DECL_START; }
+"<%#" { BEGIN(CODE_HEADER); return CSP_HEADER_START; }
+
+"<%"[[:space:]]*"@" { BEGIN(SPECIAL_TAG); return CSP_DIRECTIVE_START; }
+
+"<"{ID}":" { BEGIN(LIBTAG); save_text(1,1); return CSP_LIBTAG_START;}
+"</"{ID}":" { BEGIN(LIBTAG); save_text(2,1); return CSP_LIBTAG_STOP; }
+
+<CODE_GENERAL,CODE_EXPR,CODE_DECL,CODE_HEADER>{
+ \" { yy_push_state(DBL_QUOTE); save_text(); return CSP_DATA; }
+ "//"[^\n]*\n /* eat */
+ "/*" { yy_push_state(COMMENT); save_text(); return CSP_DATA; }
+}
+<DBL_QUOTE>\" { yy_pop_state(); save_text(); return CSP_DATA; }
+<COMMENT>"*/" { yy_pop_state(); save_text(); return CSP_DATA; }
+
+<CODE_GENERAL,CODE_DECL,CODE_HEADER>"%>"[[:space:]\n]* { BEGIN(INITIAL); save_text(); return CSP_CODE_END; }
+<CODE_EXPR>"%>" { BEGIN(INITIAL); save_text(); return CSP_CODE_END; }
+
+<SPECIAL_TAG,LIBTAG>{
+ {QUOTE_VALUE} { save_text(1,1); return CSP_VALUE; }
+ [[:space:]]+ /* eat */
+ {ID} { save_text(); return CSP_ID; }
+ "=" { save_text(); return CSP_DATA; }
+}
+<SPECIAL_TAG>"%>"\n? { BEGIN(INITIAL); return CSP_SPECIAL_TAG_CLOSED; }
+<LIBTAG>"/>"\n? { BEGIN(INITIAL); return CSP_LIBTAG_NOBODY_STOP; }
+<LIBTAG>">"\n? { BEGIN(INITIAL); return CSP_SPECIAL_TAG_CLOSED; }
+
+<*>[[:space:]\n]+ { if(YY_START!=CXXSP_COMMENT) {if(m_eat_spaces) save_text(0,YYLeng()-1); else save_text(); return CSP_DATA; }}
+<*>.|\n { if(YY_START!=CXXSP_COMMENT) {save_text(); return CSP_DATA;} }
+<*><<EOF>> { return CSP_EOF; }
+
+
+%%
+
+ int cxxsp::lexer::buffer_size = YY_BUF_SIZE;
+
+ yy_buffer_state* cxxsp::lexer::get_current_buffer() {
+ return YY_CURRENT_BUFFER;
+ }
--- /dev/null
+/*
+ * Copyright (C) 2005 Krzysztof Rzymkowski <rzymek@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "lexer.h"
+#include "parser_error.h"
+//#include <utils/dir.h>
+#include <utils/aeb/sys/directory.h>
+#include <utils/aeb/sys/error.h>
+
+namespace cxxsp
+{
+
+using namespace std;
+
+void lexer::save_text(int start_strip, int end_strip)
+{
+ text.assign(
+ YYText() + start_strip,
+ YYLeng() - start_strip - end_strip
+ );
+}
+
+lexer::lexer(const std::string& fname, bool eat_spaces)
+ : CxxspFlexLexer(open(fname))
+ , fname(fname)
+ , m_eat_spaces(eat_spaces)
+{
+ next_token(); // initialize text & current
+}
+lexer::~lexer()
+{
+ delete in;
+}
+std::istream* lexer::open(const std::string& fname)
+{
+ in = new ifstream();
+ in->exceptions(ios::badbit);
+ in->open(fname.c_str());
+ if (!in->is_open()) {
+ delete in;
+ throw aeb::sys::not_found_error("Cannot open file: " + fname);
+ }
+ return in;
+}
+
+lexer::token lexer::next_token()
+{
+ token prev = current;
+ last = text;
+ text.clear();
+ current = static_cast<token>(yylex());
+ return prev;
+}
+
+std::string token_string(lexer::token token)
+{
+ switch (token) {
+ case lexer::CSP_EOF: return "CSP_EOF";
+ case lexer::CSP_CODE_START: return "CSP_CODE_START";
+ case lexer::CSP_EXPR_START: return "CSP_EXPR_START";
+ case lexer::CSP_DECL_START: return "CSP_DECL_START";
+ case lexer::CSP_HEADER_START: return "CSP_HEADER_START";
+ case lexer::CSP_DIRECTIVE_START: return "CSP_DIRECTIVE_START";
+ case lexer::CSP_LIBTAG_START: return "CSP_LIBTAG_START";
+ case lexer::CSP_LIBTAG_STOP: return "CSP_LIBTAG_STOP";
+ case lexer::CSP_SPECIAL_TAG_CLOSED: return "CSP_SPECIAL_TAG_CLOSED";
+ case lexer::CSP_DATA: return "CSP_DATA";
+ case lexer::CSP_CODE_END: return "CSP_CODE_END";
+ case lexer::CSP_VALUE: return "CSP_VALUE";
+ case lexer::CSP_ID: return "CSP_ID";
+ default: return SSTR(token);
+ }
+}
+} //namespace
+
--- /dev/null
+/*
+ * Copyright (C) 2005 Krzysztof Rzymkowski <rzymek@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LEXER_H
+#define LEXER_H
+
+#include <iostream>
+#include <string>
+//#include <boost/lexical_cast.hpp>
+#include <fstream>
+
+#ifndef yyFlexLexer
+#define yyFlexLexer CxxspFlexLexer
+#include <FlexLexer.h>
+#endif
+
+#define MAX_INCLUDE_DEPTH 100
+
+#ifndef SSTR
+#define SSTR(x) static_cast<std::ostringstream &>( \
+ (std::ostringstream()<<std::dec<<x)).str()
+#endif
+
+namespace cxxsp
+{
+
+class lexer : protected CxxspFlexLexer
+{
+public:
+ enum token {
+ CSP_EOF = 0,
+ CSP_CODE_START = 2,
+ CSP_EXPR_START = 3,
+ CSP_DECL_START = 4,
+ CSP_HEADER_START = 5,
+ CSP_DIRECTIVE_START = 6,
+ CSP_LIBTAG_START = 7,
+ CSP_LIBTAG_STOP = 9,
+ CSP_SPECIAL_TAG_CLOSED = 10,
+ CSP_DATA = 11 ,
+ CSP_CODE_END = 12,
+ CSP_VALUE = 13,
+ CSP_ID = 14,
+ CSP_LIBTAG_NOBODY_STOP=15,
+ };
+private:
+ std::ifstream* in;
+ std::string fname;
+ bool m_eat_spaces;
+
+ std::string text,last;
+
+ token current;
+
+ std::istream* open(const std::string& fname);
+ void save_text(int start_strip=0, int end_strip=0);
+ void emit_line();
+
+ int yylex();
+
+ yy_buffer_state* get_current_buffer();
+ static int buffer_size;
+ void terminate();
+public:
+ lexer(const std::string& fname, bool eat_spaces);
+ ~lexer();
+
+ /* The text of the last token (as returned by next_token()) */
+ std::string last_text()
+ { return last; }
+ token next_token();
+ token peek_token()
+ { return current; }
+
+ int lineno() const {
+ return CxxspFlexLexer::lineno();
+ }
+ const std::string& curfile() const {
+ return fname;
+ }
+ void eat_spaces(bool b) {
+ m_eat_spaces = b;
+ }
+}; //class
+
+std::string token_string(lexer::token token);
+} //namespace
+#endif//LEXER_H
+
--- /dev/null
+/*
+ * Copyright (C) 2008-2009 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
+ * Copyright (C) 2005 Krzysztof Rzymkowski <rzymek@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdexcept>
+#include "parser.h"
+#include "parser_error.h"
+//#include <utils/dir.h>
+#include <utils/aeb/sys/directory.h>
+//directory(...)
+#include <unistd.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+namespace cxxsp
+{
+
+using namespace std;
+
+ parser::parser(const string& a_file_in, const string& a_file_out, const std::string& class_name, bool eat_spaces, bool gen_deps, bool split_def)
+ : lex(0)
+ //, generate(a_file_out, a_file_in, class_name)
+ , file_in(a_file_in)
+ , m_eat_spaces(eat_spaces)
+ , m_gen_deps(gen_deps)
+ , m_split_def(split_def)
+{
+}
+
+parser::~parser()
+{
+ if(lex)
+ delete lex;
+}
+
+string parser::get_data()
+{
+ string data=lex->last_text();
+ while (lex->peek_token() == lexer::CSP_DATA) {
+ lex->next_token();
+ data += lex->last_text();
+ }
+ return data;
+}
+
+void parser::get_token(lexer::token expected)
+{
+ lexer::token got = lex->next_token();
+ if (got != expected)
+ throw parser_error("Unexpected token:"+lex->last_text(),lex->lineno(), got,expected);
+}
+
+void parser::get_token(lexer::token expected1, lexer::token expected2)
+{
+ lexer::token got = lex->next_token();
+ if (got != expected1 && got != expected2)
+ throw parser_error("Unexpected token",lex->lineno(), got,expected1,expected2);
+}
+
+void parser::get_data(const string& expected)
+{
+ string got = get_data();
+ if (expected != got)
+ throw parser_error("Unexpected data. \nGot: '"+ got+"'\nExpected: '"+expected+"'",lex->lineno());
+}
+
+string parser::get_code()
+{
+ stringstream data;
+
+ data << lex->last_text();
+ while (lex->peek_token() != lexer::CSP_CODE_END && lex->peek_token() != lexer::CSP_EOF) {
+ lex->next_token();
+ data << lex->last_text();
+ }
+ lex->next_token(); //eat CSP_CODE_END
+ return data.str();
+}
+
+attribs_t parser::get_tag_attribs()
+{
+ attribs_t attribs;
+ string name,value;
+ lexer::token t;
+ while ((t = lex->peek_token()) != lexer::CSP_SPECIAL_TAG_CLOSED &&
+ t != lexer::CSP_LIBTAG_NOBODY_STOP && t != lexer::CSP_EOF) {
+ get_token(lexer::CSP_ID);
+ name = lex->last_text();
+
+ get_token(lexer::CSP_DATA);
+ get_data("=");
+
+ get_token(lexer::CSP_VALUE,lexer::CSP_ID);
+ value = lex->last_text();
+
+ attribs.insert(std::pair<std::string,std::string>(name,value));
+ }
+ if(t!=lexer::CSP_LIBTAG_NOBODY_STOP)
+ lex->next_token();
+ return attribs;
+}
+
+string parser::relative_path(const string& filename)
+{
+ if (filename.empty())
+ return filename;
+ if (filename[0] == '/') {
+ throw runtime_error("TODO: including relative to web aplication root");
+ } else {
+ //FIXME: do we want to implement some sort of search path
+ // that would include path of _current_ parse file, not
+ // just top-level one?
+ struct stat st;
+ for(list<string>::iterator it = m_search_path.begin(); it!=m_search_path.end(); it++) {
+ string fname = *it+"/"+filename;
+ if(::stat(fname.c_str(), &st)==0) {
+ if(st.st_mode&S_IFREG)
+ return fname;
+ }
+ }
+ }
+ throw runtime_error("File "+filename+" is not found in search path");
+}
+
+bool parser::parse()
+{
+ lex = new lexer(file_in, m_eat_spaces);
+ m_search_path.push_front(directory(file_in));
+ lex_stack.push(lex);
+ try {
+ for (;;) {
+ lexer::token token = lex->next_token();
+ switch (token) {
+ case lexer::CSP_EOF:
+ delete lex;
+ lex=0;
+ lex_stack.pop();
+ m_search_path.pop_front();
+ if (lex_stack.empty()) {
+ if(m_gen_deps) {
+ //std::cout<<outFileName()<<':';
+ for(std::set<std::string>::iterator it = m_deps.begin(); it!=m_deps.end(); it++) {
+ std::cout<<" \\"<<std::endl<<'\t'<<*it;
+ }
+ std::cout<<std::endl;
+ } else {
+ //generate.generate(m_split_def);
+ }
+ return true;
+ }
+ lex=lex_stack.top();
+ break;
+ case lexer::CSP_DATA:
+ std::cout<<"GOT DATA <"<<get_data()<<" >"<<std::endl;
+ //generate.data(get_data(), lex->lineno(), lex->curfile());
+ break;
+ case lexer::CSP_CODE_START:
+ std::cout<<"GOT CODE_START <"<<get_code()<<">"<<std::endl;
+ //generate.code(get_code(), lex->lineno(), lex->curfile());
+ break;
+ case lexer::CSP_EXPR_START:
+ std::cout<<"GOT EXPR_START <"<<get_code()<<">"<<std::endl;
+ //generate.expr(get_code(), lex->lineno(), lex->curfile());
+ break;
+ case lexer::CSP_DECL_START:
+ std::cout<<"GOT DECL_START <"<<get_code()<<">"<<std::endl;
+ //generate.decl(get_code(), lex->lineno(), lex->curfile());
+ break;
+ case lexer::CSP_HEADER_START:
+ std::cout<<"GOT HEADER_START <"<<get_code()<<">"<<std::endl;
+ //generate.header(get_code(), lex->lineno(), lex->curfile());
+ break;
+ case lexer::CSP_DIRECTIVE_START: {
+ get_token(lexer::CSP_ID);
+ string name = lex->last_text();
+ attribs_t attribs = get_tag_attribs();
+
+ if (name == "include")
+ {
+ attribs_t::const_iterator attrib
+ = attribs.find("file");
+ if (attrib != attribs.end()) {
+ std::string path = relative_path(attrib->second);
+ lex=new lexer(path, m_eat_spaces);
+ lex_stack.push(lex);
+ m_search_path.push_front(directory(path));
+ add_dep(path);
+ } else
+ throw parser_error("include directive without file attribute", lex->lineno());
+ } else if (name == "spacing")
+ {
+ attribs_t::const_iterator attrib = attribs.find("preserve");
+ if(attrib == attribs.end())
+ throw parser_error("missing attribute \"preserve\" in spacing directive", lex->lineno());
+ if(attrib->second == "true")
+ lex->eat_spaces(false);
+ else if(attrib->second == "restore")
+ lex->eat_spaces(m_eat_spaces);
+ else
+ lex->eat_spaces(true);
+ } else {
+ std::cout<<"GOT DIRECTIVE_START"<<std::endl;
+ //generate.directive(name, attribs);
+ }
+ break;
+ }
+ case lexer::CSP_LIBTAG_START: {
+ m_cur_libtag_prefix = lex->last_text();
+ get_token(lexer::CSP_ID);
+ m_cur_libtag_name = lex->last_text();
+ attribs_t attr = get_tag_attribs();
+ std::cout<<"GOT LIBTAG_START "<<m_cur_libtag_prefix<<"::"<<m_cur_libtag_name<<std::endl;
+ //generate.libtag_start(lex->lineno(), lex->curfile(), m_cur_libtag_prefix, m_cur_libtag_name, get_tag_attribs());
+ break;
+ }
+ case lexer::CSP_LIBTAG_STOP: {
+ string prefix = lex->last_text();
+ get_token(lexer::CSP_ID);
+ string name = lex->last_text();
+ get_token(lexer::CSP_SPECIAL_TAG_CLOSED);
+ std::cout<<"GOT LIBTAG_STOP"<<std::endl;
+ //generate.libtag_end(lex->lineno(), lex->curfile(), prefix, name);
+ break;
+ }
+ case lexer::CSP_LIBTAG_NOBODY_STOP: {
+ std::cout<<"GOT LIBTAG_NOBODY_STOP"<<std::endl;
+ //generate.libtag_end(lex->lineno(), lex->curfile(), m_cur_libtag_prefix, m_cur_libtag_name);
+ break;
+ }
+ default:
+ throw parser_error("Internal parser error",lex->lineno(), token);
+ }
+ }
+ } catch (std::exception& e) {
+ if(lex)
+ {
+ lex_stack.pop();
+ std::cerr<<lex->curfile()<<": "<<lex->lineno()<<": ";
+ }
+ std::cerr<<"Error: "<<e.what()<<std::endl;
+ while(!lex_stack.empty()) {
+ lex=lex_stack.top();
+ std::cerr<<"In file included from "<<lex->curfile()<<": "<<lex->lineno()<<std::endl;
+ lex_stack.pop();
+ }
+ return false;
+ }
+ return true;
+}
+
+}//namespace
--- /dev/null
+/*
+ * Copyright (C) 2008-2009 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
+ * Copyright (C) 2005 Krzysztof Rzymkowski <rzymek@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef PARSER_H
+#define PARSER_H
+
+#include <fstream>
+#include <string>
+#include <stdexcept>
+#include <vector>
+#include <stack>
+#include <list>
+#include <set>
+#include <map>
+#include "lexer.h"
+// #include "generator.h"
+
+typedef std::multimap<std::string, std::string> attribs_t;
+
+namespace cxxsp
+{
+
+class parser
+{
+ lexer* lex;
+ std::stack<lexer*> lex_stack;
+ //generator generate;
+
+ std::string file_in;
+ bool m_eat_spaces;
+ bool m_gen_deps;
+ bool m_split_def;
+ std::list<std::string> m_search_path;
+ std::set<std::string> m_deps;
+ std::string m_cur_libtag_prefix, m_cur_libtag_name;
+
+ std::string get_data();
+ /* Make the lexer get a next token.
+ If the new token is not one the the 'expected' ones,
+ then throw an exception.
+ */
+ void get_token(lexer::token expected);
+ void get_token(lexer::token expected1, lexer::token expected2);
+
+ /* Get next token. Assert it's CSP_DATA and that
+ text read is equeal to 'expected' */
+ void get_data(const std::string& expected);
+
+ std::string get_code();
+
+ attribs_t get_tag_attribs();
+
+ std::string relative_path(const std::string& filename);
+public:
+ parser(const std::string& file_in, const std::string& file_out, const std::string& class_name, bool eat_spaces, bool gen_deps, bool split_def);
+ ~parser();
+ bool parse();
+#if 0
+ const std::vector<std::string>& flags()
+ { return generate.flags(); }
+
+ const std::string& className()
+ { return generate.className(); }
+
+ const std::string& outFileName()
+ { return generate.fileName(); }
+#endif
+ void addIncludeDir(const std::string& dir)
+ { m_search_path.push_front(dir); }
+
+ void add_dep(const std::string& dep)
+ { m_deps.insert(dep); }
+}; //class
+
+//-------------------------------------------------------------------------
+
+
+} //namespace
+
+#endif//PARSER_H
+
--- /dev/null
+/*
+ * Copyright (C) 2005 Krzysztof Rzymkowski <rzymek@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef PARSER_ERROR_H
+#define PARSER_ERROR_H
+
+#include <stdexcept>
+#include <string>
+#include <sstream>
+#include "lexer.h"
+// #include <boost/lexical_cast.hpp>
+#ifndef SSTR
+#define SSTR(x) static_cast<std::ostringstream &>( \
+ (std::ostringstream()<<std::dec<<x)).str()
+#endif
+namespace cxxsp
+{
+
+class parser_error : public std::runtime_error
+{
+public:
+ parser_error(const std::string& msg, int lineno)
+ : std::runtime_error(msg+"\nLine: "+SSTR(lineno)) { }
+
+ parser_error(const std::string& msg, int lineno, lexer::token token)
+ : std::runtime_error(msg+"\nLine: "+SSTR(lineno)+"\nGot: "+token_string(token)) { }
+
+ parser_error(const std::string& msg, int lineno, lexer::token token,lexer::token exp)
+ : std::runtime_error(msg+"\nLine: "+SSTR(lineno)+"\nGot: "+token_string(token)+". Expected: "+token_string(exp)) { }
+
+ parser_error(const std::string& msg, int lineno, lexer::token token,lexer::token exp1,lexer::token exp2)
+ : std::runtime_error(msg+"\nLine: "+SSTR(lineno)+"\nGot: "+token_string(token)+
+ ". Expected: "+token_string(exp1)+" or "+token_string(exp2)) { }
+
+};
+
+}
+#endif//PARSER_ERROR_H
+
--- /dev/null
+/*
+ * Copyright (C) 2005 Krzysztof Rzymkowski <rzymek@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TOCKENIZER_H
+#define TOCKENIZER_H
+
+#include <string>
+
+class tokenizer
+{
+ const std::string& data;
+ char sep;
+ std::string::size_type start;
+public:
+ tokenizer(const std::string& the_data, char a_sep)
+ : data(the_data)
+ { start = 0; sep = a_sep; }
+ bool end()
+ { return start == std::string::npos; }
+ std::string next() {
+ std::string::size_type begin = start;
+ start = data.find(sep, start);
+ if (std::string::npos == start)
+ return data.substr(begin);
+ return data.substr(begin, start++ - begin);
+ }
+};
+
+#endif//TOCKENIZER_H
+