From: aebersol Date: Mon, 20 Dec 2021 21:20:36 +0000 (+0100) Subject: Initial import from SVN X-Git-Url: https://git.ebersold.fr/?a=commitdiff_plain;h=70fec5d1a2b248cb4d2cf3a6a470e0b31ad66b29;p=parser%2Fgsp.git Initial import from SVN --- 70fec5d1a2b248cb4d2cf3a6a470e0b31ad66b29 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f10a206 --- /dev/null +++ b/CMakeLists.txt @@ -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 index 0000000..5727db1 --- /dev/null +++ b/gsp_config.h.in @@ -0,0 +1,36 @@ +#ifndef GSP_CONFIG_H +#define GSP_CONFIG_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H 1 + +/**/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// for memset +#include +#include +#include +#if defined(HAVE_UNISTD_H) +#include +#endif +#if defined (_WIN32) +#include +#define access _access_s +#define F_OK 0 + +#include +#include +#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 index 0000000..08dc394 --- /dev/null +++ b/libparser/CMakeLists.txt @@ -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 index 0000000..a8e9b9f --- /dev/null +++ b/libparser/dso_code.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2005 Krzysztof Rzymkowski + * Copyright (C) 2006 Ilya Volynets + * + * 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 +#include +#include +#include +#ifdef DEBUG +#include //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 index 0000000..1908fd0 --- /dev/null +++ b/libparser/dso_code.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2005 Krzysztof Rzymkowski + * Copyright (C) 2006 Ilya Volynets + * + * 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 +#include +#include + +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 + T call(const std::string& name) + { + return reinterpret_cast(call_(name)); + } + template + T func(const std::string& name) + { + return reinterpret_cast(func_(name)); + } +}; + +#endif//DSO_CODE_H + diff --git a/libparser/generator.cpp b/libparser/generator.cpp new file mode 100644 index 0000000..d291ae3 --- /dev/null +++ b/libparser/generator.cpp @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2008-2009 Ilya A. Volynets-Evenbakh + * Copyright (C) 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "generator.h" +#include +#include +#include +#include "tokenizer.h" +#include +#include + +namespace cxxsp +{ + +using namespace std; + +inline string generate_class_name(const string& filename) +{ + string class_name = "CspServlet"; + for (string::size_type i=0;i" << endl; +} + +string generator::escape(const string& s) +{ + string res; + res.reserve(s.size() + s.size()/3); + for (unsigned i=0;isecond != "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="<\n"; + out_decl << generators.head().rdbuf() << endl; + if(!m_namespace.empty()) + out_decl << "namespace " << m_namespace << "{"<(\"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<<'}'< + * Copyright (C) 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef GENERATOR_H +#define GENERATOR_H + +#include +#include +#include +#include +#include +#include +#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 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& 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 index 0000000..e01e8d1 --- /dev/null +++ b/libparser/generator_manager.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2008-2009, 2011 Ilya A. Volynets-Evenbakh + * Copyright (C) 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "generator_manager.h" +#include +#include +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("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(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: "<getName()<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 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 \""<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 index 0000000..3f5ec1a --- /dev/null +++ b/libparser/generator_manager.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008-2009 Ilya A. Volynets-Evenbakh + * Copyright (C) 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef GENERATOR_MANAGER_H +#define GENERATOR_MANAGER_H +#include +#include +#include +#include +#include +#include +#include +#include "dso_code.h" +#include +#include + +class generator_manager +{ + typedef servlet::taglib::attribs_t attribs_t; + typedef std::map tags_t; + typedef servlet::taglib::Taglib* (*taglibfactory_t)(const attribs_t&); + + struct entry { + dso_code* dso; + servlet::taglib::Taglib* taglib; + }; + + typedef std::stack > generators_t; + generators_t generators; + + typedef std::map 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 index 0000000..aa94d0f --- /dev/null +++ b/libparser/gsp_compiler.cpp @@ -0,0 +1,94 @@ + +#include "parser.h" + +#include + +#include +#include +//#include +#include + +using namespace std; + +void usage(const char* name) +{ + std::cerr<< + "Usage:\n\t"< search_path; + const char* esp = ::getenv("CSP_INCLUDE_PATH"); + if(esp) + { + std::string env_search_path(esp); +#if 0 + boost::char_separator sep(":",""); + typedef boost::tokenizer > 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 tok(":"); + std::vector t; + tok.GetTokens(env_search_path,t); + for(std::vector::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"<::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 index 0000000..66b3822 --- /dev/null +++ b/libparser/gsplex.lpp @@ -0,0 +1,103 @@ +/* + * FastServerPages - an inline C++ dynamic web pages technology + * Copytight (C) 2008-2009 Ilya A. Volynets-Evenbakh + * 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(INITIAL); save_text(); return CSP_DATA; } + */ + +%} + +%% + + +"<%--" { BEGIN(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;} +"{ + \" { yy_push_state(DBL_QUOTE); save_text(); return CSP_DATA; } + "//"[^\n]*\n /* eat */ + "/*" { yy_push_state(COMMENT); save_text(); return CSP_DATA; } +} +\" { yy_pop_state(); save_text(); return CSP_DATA; } +"*/" { yy_pop_state(); save_text(); return CSP_DATA; } + +"%>"[[:space:]\n]* { BEGIN(INITIAL); save_text(); return CSP_CODE_END; } +"%>" { BEGIN(INITIAL); save_text(); return CSP_CODE_END; } + +{ + {QUOTE_VALUE} { save_text(1,1); return CSP_VALUE; } + [[:space:]]+ /* eat */ + {ID} { save_text(); return CSP_ID; } + "=" { save_text(); return CSP_DATA; } +} +"%>"\n? { BEGIN(INITIAL); return CSP_SPECIAL_TAG_CLOSED; } +"/>"\n? { BEGIN(INITIAL); return CSP_LIBTAG_NOBODY_STOP; } +">"\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;} } +<*><> { 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 index 0000000..640ad10 --- /dev/null +++ b/libparser/lexer.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "lexer.h" +#include "parser_error.h" +//#include +#include +#include + +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(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 index 0000000..1314356 --- /dev/null +++ b/libparser/lexer.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LEXER_H +#define LEXER_H + +#include +#include +//#include +#include + +#ifndef yyFlexLexer +#define yyFlexLexer CxxspFlexLexer +#include +#endif + +#define MAX_INCLUDE_DEPTH 100 + +#ifndef SSTR +#define SSTR(x) static_cast( \ + (std::ostringstream()< + * Copyright (C) 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "parser.h" +#include "parser_error.h" +//#include +#include +//directory(...) +#include +#include +#include + +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(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::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<::iterator it = m_deps.begin(); it!=m_deps.end(); it++) { + std::cout<<" \\"<"<lineno(), lex->curfile()); + break; + case lexer::CSP_CODE_START: + std::cout<<"GOT CODE_START <"<"<lineno(), lex->curfile()); + break; + case lexer::CSP_EXPR_START: + std::cout<<"GOT EXPR_START <"<"<lineno(), lex->curfile()); + break; + case lexer::CSP_DECL_START: + std::cout<<"GOT DECL_START <"<"<lineno(), lex->curfile()); + break; + case lexer::CSP_HEADER_START: + std::cout<<"GOT HEADER_START <"<"<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"<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 "<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"<lineno(), lex->curfile(), prefix, name); + break; + } + case lexer::CSP_LIBTAG_NOBODY_STOP: { + std::cout<<"GOT LIBTAG_NOBODY_STOP"<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<curfile()<<": "<lineno()<<": "; + } + std::cerr<<"Error: "<curfile()<<": "<lineno()< + * Copyright (C) 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PARSER_H +#define PARSER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "lexer.h" +// #include "generator.h" + +typedef std::multimap attribs_t; + +namespace cxxsp +{ + +class parser +{ + lexer* lex; + std::stack lex_stack; + //generator generate; + + std::string file_in; + bool m_eat_spaces; + bool m_gen_deps; + bool m_split_def; + std::list m_search_path; + std::set 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& 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 index 0000000..ef783ff --- /dev/null +++ b/libparser/parser_error.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PARSER_ERROR_H +#define PARSER_ERROR_H + +#include +#include +#include +#include "lexer.h" +// #include +#ifndef SSTR +#define SSTR(x) static_cast( \ + (std::ostringstream()< + * + * 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 + +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 +