Initial import from SVN master
authoraebersol <aebersol@hystou.home>
Mon, 20 Dec 2021 21:20:36 +0000 (22:20 +0100)
committeraebersol <aebersol@hystou.home>
Mon, 20 Dec 2021 21:20:36 +0000 (22:20 +0100)
17 files changed:
CMakeLists.txt [new file with mode: 0644]
gsp_config.h.in [new file with mode: 0644]
libparser/CMakeLists.txt [new file with mode: 0644]
libparser/dso_code.cpp [new file with mode: 0644]
libparser/dso_code.h [new file with mode: 0644]
libparser/generator.cpp [new file with mode: 0644]
libparser/generator.h [new file with mode: 0644]
libparser/generator_manager.cpp [new file with mode: 0644]
libparser/generator_manager.h [new file with mode: 0644]
libparser/gsp_compiler.cpp [new file with mode: 0644]
libparser/gsplex.lpp [new file with mode: 0644]
libparser/lexer.cpp [new file with mode: 0644]
libparser/lexer.h [new file with mode: 0644]
libparser/parser.cpp [new file with mode: 0644]
libparser/parser.h [new file with mode: 0644]
libparser/parser_error.h [new file with mode: 0644]
libparser/tokenizer.h [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f10a206
--- /dev/null
@@ -0,0 +1,68 @@
+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)
diff --git a/gsp_config.h.in b/gsp_config.h.in
new file mode 100644 (file)
index 0000000..5727db1
--- /dev/null
@@ -0,0 +1,36 @@
+#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*/
diff --git a/libparser/CMakeLists.txt b/libparser/CMakeLists.txt
new file mode 100644 (file)
index 0000000..08dc394
--- /dev/null
@@ -0,0 +1,31 @@
+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)
diff --git a/libparser/dso_code.cpp b/libparser/dso_code.cpp
new file mode 100644 (file)
index 0000000..a8e9b9f
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *  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;
+}
+
diff --git a/libparser/dso_code.h b/libparser/dso_code.h
new file mode 100644 (file)
index 0000000..1908fd0
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *  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
+
diff --git a/libparser/generator.cpp b/libparser/generator.cpp
new file mode 100644 (file)
index 0000000..d291ae3
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ *  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();
+}
+}
diff --git a/libparser/generator.h b/libparser/generator.h
new file mode 100644 (file)
index 0000000..a01257c
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  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
+
diff --git a/libparser/generator_manager.cpp b/libparser/generator_manager.cpp
new file mode 100644 (file)
index 0000000..e01e8d1
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *  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;
+}
diff --git a/libparser/generator_manager.h b/libparser/generator_manager.h
new file mode 100644 (file)
index 0000000..3f5ec1a
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  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
+
diff --git a/libparser/gsp_compiler.cpp b/libparser/gsp_compiler.cpp
new file mode 100644 (file)
index 0000000..aa94d0f
--- /dev/null
@@ -0,0 +1,94 @@
+
+#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;
+}
diff --git a/libparser/gsplex.lpp b/libparser/gsplex.lpp
new file mode 100644 (file)
index 0000000..66b3822
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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;
+    }
diff --git a/libparser/lexer.cpp b/libparser/lexer.cpp
new file mode 100644 (file)
index 0000000..640ad10
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  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
+
diff --git a/libparser/lexer.h b/libparser/lexer.h
new file mode 100644 (file)
index 0000000..1314356
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ *  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
+
diff --git a/libparser/parser.cpp b/libparser/parser.cpp
new file mode 100644 (file)
index 0000000..eafa037
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ *  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
diff --git a/libparser/parser.h b/libparser/parser.h
new file mode 100644 (file)
index 0000000..9095adb
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *  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
+
diff --git a/libparser/parser_error.h b/libparser/parser_error.h
new file mode 100644 (file)
index 0000000..ef783ff
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  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
+
diff --git a/libparser/tokenizer.h b/libparser/tokenizer.h
new file mode 100644 (file)
index 0000000..d3b58e2
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  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
+