author | Michael Krelin <hacker@klever.net> | 2005-03-30 21:58:44 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2005-03-30 21:58:44 (UTC) |
commit | 5c757590c7561f6d85b3f9011aa0695c4111b379 (patch) (side-by-side diff) | |
tree | e0bf20ca58b3e7bd9cc4eda54db5674ba1d71db0 | |
parent | 3ddbfeafde93d1aab16a710498d86eef4e787406 (diff) | |
download | sitecing-5c757590c7561f6d85b3f9011aa0695c4111b379.zip sitecing-5c757590c7561f6d85b3f9011aa0695c4111b379.tar.gz sitecing-5c757590c7561f6d85b3f9011aa0695c4111b379.tar.bz2 |
1. fixed a bug just introduced, preventing the last skeleton-generated file
from being written.
2. introduced pragma directive and pragma main=class
3. minor changes of no importance
-rw-r--r-- | include/sitecing/sitecing_enflesher.h | 9 | ||||
-rw-r--r-- | include/sitecing/sitecing_parser.h | 8 | ||||
-rw-r--r-- | lib/component_factory.cc | 2 | ||||
-rw-r--r-- | lib/sitecing_enflesher.ll | 8 | ||||
-rw-r--r-- | lib/sitecing_parser.ll | 47 |
5 files changed, 71 insertions, 3 deletions
diff --git a/include/sitecing/sitecing_enflesher.h b/include/sitecing/sitecing_enflesher.h index 8bc43a0..db15bc3 100644 --- a/include/sitecing/sitecing_enflesher.h +++ b/include/sitecing/sitecing_enflesher.h @@ -1,79 +1,88 @@ #ifndef __SITECING_SITECING_ENFLESHER_H #define __SITECING_SITECING_ENFLESHER_H #include <fstream> #include <string> using namespace std; /** * @file * @brief The preprocessed source builder. */ #ifndef sitecing_enflesher_flexlexer_once #define sitecing_enflesher_flexlexer_once #undef yyFlexLexer #define yyFlexLexer sitecing_enflesherFlexLexer #include <FlexLexer.h> #undef yyFlexLexerOnce #endif class sitecing_parser; /** * The enfleshing of the skeleton file according to the in-memory parsed * component source. */ class sitecing_enflesher : public sitecing_enflesherFlexLexer { public: /** * It is time to anchor output with the #line directive. */ bool anchor_time; /** * The file currently being written is supposed to have #line * directives all around the place. */ bool anchoraged; /** * The reference to the parser object containg the parsed source. */ sitecing_parser& parser; /** * The output stream. */ ofstream outs; /** * the outs stream destination file. * @see outs */ string outs_filename; /** * @param p The parser object containing preparsed data. */ sitecing_enflesher(sitecing_parser& p) : parser(p), anchor_time(true) { } /** * Do the job. */ void enflesh(); virtual void LexerOutput(const char *buf,int size); virtual int yylex(); /** * Put a #line anchor into output. */ void anchor(); /** * Close previously opened output stream, rename to the 'correct' * destination filename, if needed, and open new file. * @see outs * @see outs_filename + * @see outs_close */ void outs_open(const string& nfile); + /** + * Close previously opened output stream, and rename to the 'correct' + * destination filename, if needed. + * @see outs_open + * @see outs + * @see outs_filename + */ + void outs_close(); }; #endif /* __SITECING_SITECING_ENFLESHER_H */ diff --git a/include/sitecing/sitecing_parser.h b/include/sitecing/sitecing_parser.h index 22d716f..a8474f3 100644 --- a/include/sitecing/sitecing_parser.h +++ b/include/sitecing/sitecing_parser.h @@ -102,225 +102,233 @@ class sitecing_parser : public sitecing_parserFlexLexer { */ member_variables_t member_variables; /** * @todo TODO: wish I could remember the details -- document me. */ bool have_initializers; /** * Whether the component has a constructor defined. */ bool have_constructor; /** * Member function definition. */ class member_function { public: /** * Return type. */ string type; /** * Function name. */ string name; /** * Arguments declaration. */ string args; /** * Function body. */ string body; /** * @param t type. * @param n name. * @param a arguments. * @param b body. */ member_function(const string& t,const string& n,const string& a,const string& b) : type(t), name(n), args(a), body(b) { } }; /** * The list of member functions. */ typedef list<member_function> member_functions_t; /** * Member functions. */ member_functions_t member_functions; /** * Current mode of operation. */ class modus_operandi { public: /** * The state enumeration. */ enum modus_t { /** * Building the code. */ modus_code = 0, /** * Ready to do the '<<' thing. */ modus_preop, /** * Just made a '<<'. */ modus_postop, /** * Outputting raw output data. */ modus_text, /** * The number of modes. */ modi }; /** * Processing flags enumeration. */ enum { /** * Eat the comments. */ flag_devour_comments = 0x0001, /** * Eat whitespace. */ flag_devour_whitespace = 0x0002 }; /** * The processing mode. */ modus_t modus; /** * The processing flags. */ int flags; /** * Output being built. */ string output; /** * The type for compound modes. */ string _type; /** * The last id encountered. */ string _lastid; /** * The name for compound modes. */ string _name; /** * The argument declaration. Obviously for member functions. */ string _args; /** * @param flags. * @see flags */ modus_operandi(int f = 0) : modus(modus_code), flags(f) { } /** * Change the processing mode. */ void modify(modus_t m); /** * See if we're eating up whitespaces. */ bool devour_whitespace() { return flags&flag_devour_whitespace; } /** * See if we're eating up the comments. */ bool devour_comments() { return flags&flag_devour_comments; } }; /** * The modes stack type. */ typedef list<modus_operandi> modi_operandi; /** * The modes stack. */ modi_operandi modi; /** * Input file name. */ string input_file; /** * Base class name. */ string base_class; /** * Base class header. */ string base_header; /** * Component's basename. * @todo TODO: wish I could remember the details -- document me. */ string component_basename; /** * The skeleton file name. */ string skeleton; /** * The component class name. */ string class_name; /** * Output basename. * @todo TODO: wish I could remember the details -- document me. */ string output_basename; /** * Verbatim declaration part. */ string decl; /** * Verbatim implementation part. */ string impl; /** * The reference to the component factory object. */ component_factory& factory; + /** + * Pragma map type. + */ + typedef map<string,string> pragmas_t; + /** + * Pragma's found in the component. + */ + pragmas_t pragmas; /** * @param f the component factory. */ sitecing_parser(component_factory& f); /** * Preprocess file. * @param in input file name. */ void preprocess(const string& in); virtual void LexerOutput(const char *buf,int size); virtual int yylex(); /** * Retrieve reference to the to of the modes stack. * @return the reference in question. */ modus_operandi& M() { return modi.front(); } /** * Anchor the output with the #line, if we're not in the text output mode. */ void soft_anchor(); /** * Anchor the output with the #line directive, changing to the appropriate output mode if needed. */ void anchor(); }; #endif /* __SITECING_SITECING_PARSER_H */ diff --git a/lib/component_factory.cc b/lib/component_factory.cc index b8f5a16..1253111 100644 --- a/lib/component_factory.cc +++ b/lib/component_factory.cc @@ -130,203 +130,203 @@ namespace sitecing { strip_prefix(dp,root_so); return file_factory::is_uptodate(dst,deps); }catch(utility_no_prefix& unp) { } return true; } void component_factory::build(const string& dst) { string dp = normalize_path(dst,strip_trailing_slash); // sources try { string noro = strip_prefix(dp,root_source); // building the sources is left up to developer return; }catch(utility_no_prefix& unp) { } // .so files try { string noso = strip_suffix(dp,".so"); string noro = strip_prefix(noso,root_so); string o = root_intermediate+noro+".o"; if(access(o.c_str(),R_OK)) throw konforka::exception(CODEPOINT,string("can't access compiled component code (")+o+")"); make_path(dir_name(root_so+noro),0755); file_lock lock_cc(root_intermediate+noro+".o.lock"); file_lock lock_so(root_so+noro+".so.lock"); int stdO = open((root_intermediate+noro+".ld.stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); if(stdO<0) throw konforka::exception(CODEPOINT,"failed to open/create linker stdout"); int stdE = open((root_intermediate+noro+".ld.stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); if(stdE<0) { close(stdO); throw konforka::exception(CODEPOINT,"failed to open/create linker stderr"); } list<string> args; config_options *co_ld_flags = config.lookup_config(noro,config_options::flag_ld_flags); if(co_ld_flags) { args.insert(args.end(),co_ld_flags->ld_flags.begin(),co_ld_flags->ld_flags.end()); } args.push_back("-shared"); args.push_back(o); file_list_t ancestors; get_ancestors(noro,ancestors); for(file_list_t::const_iterator i=ancestors.begin();i!=ancestors.end();++i) { string aso=root_so+*i+".so"; make(aso); args.push_back(aso); } args.push_back("-o"); args.push_back(dp); // TODO: "g++" configurable int rv = execute("g++",args,stdO,stdE); if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) ) // TODO:TODO: linker_error throw compile_error(CODEPOINT,"failed to link component",noro); return; }catch(utility_no_prefix& unp) { throw konforka::exception(CODEPOINT,"component is outside of component root"); }catch(utility_no_suffix& uns) { } // compiler targets for(int cct=0;cct<sizeof(cc_targets)/sizeof(*cc_targets);cct++) { try { string nos = strip_suffix(dp,cc_targets[cct]); string noro = strip_prefix(nos,root_intermediate); string cc = root_intermediate+noro+".cc"; string o = root_intermediate+noro+".o"; if(access(cc.c_str(),R_OK)) throw konforka::exception(CODEPOINT,string("can't access preprocessed component code (")+cc+")"); make_path(dir_name(cc),0755); string pwd = dir_name(root_source+noro); auto_chdir dir_changer(pwd); file_lock lock_source(root_intermediate+noro+".lock"); file_lock lock_cc(root_intermediate+noro+".o.lock"); int stdO = open((root_intermediate+noro+".stdout").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); if(stdO<0) throw konforka::exception(CODEPOINT,"failed to open/create compiler stdout"); int stdE = open((root_intermediate+noro+".stderr").c_str(),O_CREAT|O_TRUNC|O_WRONLY,0664); if(stdE<0) { close(stdO); throw konforka::exception(CODEPOINT,"failed to open/create compiler's stderr"); } list<string> args; config_options *co_cpp_flags = config.lookup_config(noro,config_options::flag_cpp_flags); if(co_cpp_flags) { args.insert(args.end(),co_cpp_flags->cpp_flags.begin(),co_cpp_flags->cpp_flags.end()); } // TODO: maybe move it to separare config option like CoreCPPFLags? args.push_back("-I"+root_intermediate); args.push_back("-I"+root_source); args.push_back("-MD"); args.push_back("-MF"); args.push_back(root_intermediate+noro+".d"); args.push_back("-c"); args.push_back(cc); args.push_back("-o"); args.push_back(o); // TODO: "g++" configurable int rv = execute("g++",args,stdO,stdE); if(! (WIFEXITED(rv) && !WEXITSTATUS(rv)) ) throw compile_error(CODEPOINT,"failed to compile component",noro); return; }catch(utility_no_affix& una) { // do nothing, not a compiler target } } // preprocessor targets for(int ppt=0;ppt<sizeof(pp_targets)/sizeof(*pp_targets);ppt++) { try { string nos = strip_suffix(dp,pp_targets[ppt]); string noro = strip_prefix(nos,root_intermediate); string src = root_source+noro; if(access(src.c_str(),R_OK)) throw konforka::exception(CODEPOINT,string("can't access component source (")+src+")"); make_path(dir_name(root_intermediate+noro),0755); file_lock lock(root_intermediate+noro+".lock"); sitecing_parser parser(*this); config_options *co_skeleton = config.lookup_config(noro,config_options::flag_skeleton); if(co_skeleton) parser.skeleton = co_skeleton->skeleton; static const char *id_chars = "abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ"; parser.class_name = normalize_path(noro,strip_leading_slash|strip_trailing_slash); for(string::size_type illc = parser.class_name.find_first_not_of(id_chars);illc!=string::npos;illc=parser.class_name.find_first_not_of(id_chars,illc)) { string::size_type lc = parser.class_name.find_first_of(id_chars,illc); int n = ((lc==string::npos)?parser.class_name.length():lc)-illc; parser.class_name.replace(illc,n,n,'_'); } parser.class_name = "_SCC_"+parser.class_name; parser.output_basename = nos; parser.component_basename = noro; try { parser.preprocess(src); string sf = root_intermediate+noro+".pp_stamp"; ofstream sfs(sf.c_str(),ios::trunc|ios::out); // touch .pp_stamp }catch(preprocessor_error& pe) { pe.component_name = noro; pe.see(CODEPOINT); throw; } return; }catch(utility_no_affix& una) { // must be a crap from .d file } } cerr << "ignoring build request for " << dp << endl; } int component_factory::execute(const string& cmd, const list<string>& args,int stdo,int stde) { // XXX: is it right that we do stdio/stderr tricks outside of the function? cerr << "executing: " << cmd; vector<const char*> argv(args.size()+2); argv[0]=cmd.c_str(); int an = 1; for(list<string>::const_iterator i=args.begin();i!=args.end();i++) { cerr << " " << *i ; argv[an++] = i->c_str(); } cerr << endl; argv[an++]=NULL; pid_t pid = vfork(); if(pid==-1) { close(stdo); close(stde); throw konforka::exception(CODEPOINT,"failed to vfork()"); } if(!pid) { // child if(dup2(stdo,1)!=1) _exit(-1); if(dup2(stde,2)!=2) _exit(-1); close(0); execvp(cmd.c_str(),(char**)&argv.front()); _exit(-1); } // parent close(stdo); close(stde); int rv; if(waitpid(pid,&rv,0)<0) throw konforka::exception(CODEPOINT,"failed to waitpid()"); return rv; } string component_factory::get_classname(const string& component) { string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".classname"; make(cn); ifstream ifs(cn.c_str()); if(!ifs.good()) throw konforka::exception(CODEPOINT,"failed to access component .classname"); ifs >> cn; return cn; } void component_factory::get_ancestors(const string& component,file_list_t& rv) { string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".ancestors"; make(cn); ifstream ifs(cn.c_str()); if(!ifs.good()) - throw konforka::exception(CODEPOINT,"filed to access component .ancestors"); + throw konforka::exception(CODEPOINT,string("failed to access component '")+component+"' .ancestors"); rv.clear(); while(!ifs.eof()) { string a; ifs >> a; if(!a.empty()) rv.push_back(a); } } } diff --git a/lib/sitecing_enflesher.ll b/lib/sitecing_enflesher.ll index 46489c7..bb667be 100644 --- a/lib/sitecing_enflesher.ll +++ b/lib/sitecing_enflesher.ll @@ -1,254 +1,260 @@ %{ #include <iostream> #include <fstream> #include <cassert> #include <stdexcept> using namespace std; #include "sitecing/sitecing_exception.h" using namespace sitecing; #define sitecing_enflesher_flexlexer_once #include "sitecing/sitecing_enflesher.h" #include "sitecing/sitecing_parser.h" #undef yyFlexLexer #define yyFlexLexer sitecing_enflesherFlexLexer %} %option 8bit c++ verbose noyywrap yyclass="sitecing_enflesher" yylineno prefix="sitecing_enflesher" stack debug ID [A-Za-z_][A-Za-z0-9_]* %% ^\%\%\#[^\n]+\n { string line = yytext; line.erase(0,3); line.erase(line.length()-1); outs_open(parser.output_basename+line); anchor(); anchoraged = true; } ^\%\%[^\n]+\n { string line = yytext; line.erase(0,2); line.erase(line.length()-1); outs_open(parser.output_basename+line); anchoraged = false; } \<\%component_basename\%\> outs << parser.component_basename; anchor_time = true; \<\%impl\%\> outs << parser.impl; anchor_time = true; \<\%member_functions:impl\%\> { for(sitecing_parser::member_functions_t::const_iterator i=parser.member_functions.begin();i!=parser.member_functions.end();i++) { outs << i->type << " " << parser.class_name << "::"; if(i->name.empty()) { outs << parser.class_name << "()"; bool first = true; for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) { if(i->initializer.empty()) continue; if(first) { outs << ":"; first=false; }else{ outs << ","; } if(i->bComponent) { outs << i->name << "(NULL)"; }else { outs << i->name << "(" << i->initializer << ")"; } } }else if(i->name == "~") outs << "~" << parser.class_name << "()"; else outs << i->name << i->args; outs << "{\n" << i->body << "\n}\n"; } anchor_time = true; } \<\%class_name\%\> outs << parser.class_name; anchor_time = true; \<\%baseclass_header\%\> outs << parser.base_header; anchor_time = true; \<\%decl\%\> outs << parser.decl; anchor_time = true; \<\%baseclass_name\%\> outs << parser.base_class; anchor_time = true; \<\%member_variables:decl\%\> { for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) { if(i->bComponent) { if(i->type.empty()) { i->type = parser.factory.get_classname(i->initializer); } if(i->bTypeOnly) { outs << "typedef " << i->type << " " << i->name << ";\n"; }else{ outs << "typedef " << i->type << " __type_" << i->name << ";\nsitecing::so_component __soc_" << i->name << ";\n__type_" << i->name << " *" << i->name << ";\n"; } }else{ outs << i->type << " " << i->name << ";\n"; } } anchor_time = true; } \<\%member_functions:decl\%\> { for(sitecing_parser::member_functions_t::const_iterator i=parser.member_functions.begin();i!=parser.member_functions.end();i++) { (i->name.empty()?outs:outs << "virtual ") << i->type << " "; if(i->name.empty()) { outs << parser.class_name << "()"; }else if(i->name == "~") outs << "~" << parser.class_name << "()"; else outs << i->name << i->args; outs << ";\n"; } anchor_time = true; } \<\%imports:list\%\> { for(sitecing_parser::member_variables_t::const_iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) { if(i->bComponent) outs << i->initializer << endl; } anchor_time = true; } \<\%imports:includes\%\> { for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) { if(i->bComponent) outs << "\n#include \"" << i->initializer << ".h\"\n"; } anchor_time = true; } \<\%imports:import\%\> { for(sitecing_parser::member_variables_t::iterator i=parser.member_variables.begin();i!=parser.member_variables.end();i++) { if(!i->bComponent) continue; if(i->bTypeOnly) continue; outs << "__soc_" << i->name << "=__SCIF->ss->fetch(\"" << i->initializer << "\",__SCIF); " << i->name << "=static_cast<__type_" << i->name << "*>(__soc_" << i->name << ".ac->__the_most_derived_this());\n"; } anchor_time = true; } \<\%base_component\%\> { // TODO: anchor_time = true; } \<\%ancestors:includes\%\> { for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) { outs << "#include \"" << i->path << ".h\"\n"; } anchor_time = true; } \<\%ancestors:component_list\%\> { for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) { outs << i->path << "\n"; } anchor_time = true; } \<\%ancestors:base_clause_part\%\> { for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) { outs << ", virtual public " << parser.factory.get_classname(i->path); } } \<\%ancestors:typedefs\%\> { for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) { outs << "typedef class " << parser.factory.get_classname(i->path) << " " << i->name << ";\n"; } anchor_time = true; } \<\%ancestors:import\%\> { for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) { outs << i->name << "::__do_imports();\n"; } anchor_time = true; } \n { if(anchor_time) anchor(); ECHO; } . ECHO; %% void sitecing_enflesher::LexerOutput(const char *buf,int size) { outs.write(buf,size); } void sitecing_enflesher::enflesh() { ifstream ifs(parser.skeleton.c_str()); if(!ifs.good()) throw preprocessor_error(CODEPOINT,"failed to open skeleton file"); switch_streams(&ifs,NULL); yylex(); + outs_close(); } void sitecing_enflesher::anchor() { if(!anchoraged) return; outs << "\n#line " << lineno() << " \"" << parser.skeleton << "\"\n"; anchor_time = false; } -void sitecing_enflesher::outs_open(const string& nfile) { +void sitecing_enflesher::outs_close() { if(!outs_filename.empty()) { outs.flush(); outs.close(); outs.clear(); /* * compare source and destination files. * * one can also keep a hash for the old one and compute one for the * output while writing, but I'm not sure if it's any better. Surely a * bit less accurate, unless we're going to compare it in case of * difference, anyway. */ bool overwrite = false; struct stat st_s, st_d; string fn_s = outs_filename+".new"; string fn_d = outs_filename; if(stat(fn_d.c_str(),&st_d)) { overwrite = true; }else{ if(stat(fn_s.c_str(),&st_s)) throw preprocessor_error(CODEPOINT,"failed to stat() supposedly created file"); if(st_s.st_size!=st_d.st_size) { overwrite = true; }else{ ifstream i_s(fn_s.c_str(),ios::in); if(!i_s) throw preprocessor_error(CODEPOINT,"failed to open supposedly created file"); ifstream i_d(fn_d.c_str(),ios::in); if(!i_d) throw preprocessor_error(CODEPOINT,"failed to open the old preprocessed source"); off_t remaining = st_s.st_size; char t1[2048]; char t2[sizeof(t1)]; while(remaining) { int rb = remaining; if(rb>sizeof(t1)) rb = sizeof(t1); if(i_s.read(t1,rb).gcount()!=rb) throw preprocessor_error(CODEPOINT,"error reading just created file"); if(i_d.read(t2,rb).gcount()!=rb) throw preprocessor_error(CODEPOINT,"error reading the old preprocessed source"); if(memcmp(t1,t2,rb)) { overwrite = true; break; } remaining -= rb; } } } if(overwrite) { cerr << "renaming '" << fn_s << "'" << endl; if(rename(fn_s.c_str(),fn_d.c_str())) throw preprocessor_error(CODEPOINT,"failed to rename() generated output"); } } + outs_filename.erase(); +} + +void sitecing_enflesher::outs_open(const string& nfile) { + outs_close(); outs_filename = nfile; outs.open((nfile+".new").c_str(),ios::trunc); if(!outs.good()) throw preprocessor_error(CODEPOINT,"failed to write preprocessor output"); } /* * vim:set ft=lex: */ diff --git a/lib/sitecing_parser.ll b/lib/sitecing_parser.ll index 6cb78f3..8ba8673 100644 --- a/lib/sitecing_parser.ll +++ b/lib/sitecing_parser.ll @@ -1,594 +1,639 @@ %{ /* * XXX: I have a strong feeling that this parser should be completely rewritten. */ #include <iostream> #include <fstream> #include <cassert> #include <stdexcept> using namespace std; #include "sitecing/sitecing_util.h" #include "sitecing/sitecing_exception.h" using namespace sitecing; #define sitecing_parser_flexlexer_once #include "sitecing/sitecing_parser.h" #include "sitecing/sitecing_enflesher.h" #undef yyFlexLexer #define yyFlexLexer sitecing_parserFlexLexer %} %x SLASHSTAR_COMMENT SLASHSLASH_COMMENT STRING %x CODELINE CLASSLINE DECLLINE IMPLLINE DECLBLOCK IMPLBLOCK VARLINE VARINIT %x IMPORTLINE IMPORTCOMPONENT %x IMPORTTYPELINE IMPORTTYPECOMPONENT %x DERIVELINE DERIVECOMPONENT %x CONSTRUCTOR DESTRUCTOR CODEMETHODLINE CODEMETHODARGS %x CODEMETHODBLOCK INLINE METHODLINE METHODARGS METHODBLOCK CODEBLOCK OUTPUTBLOCK +%x PRAGMALINE %option 8bit c++ verbose noyywrap yyclass="sitecing_parser" prefix="sitecing_parser" stack yylineno WHITESPACE [ \t] ID [A-Za-z_][A-Za-z0-9_]* NOIDCHAR [^A-Za-z0-9_] %% <INITIAL>{ ^\%\%class{WHITESPACE}+ { // TODO: signal error if we already have class name acquired from source. modi.push_front(modus_operandi(modus_operandi::flag_devour_comments|modus_operandi::flag_devour_whitespace)); BEGIN(CLASSLINE); } ^\%\%decl{WHITESPACE}+ { modi.push_front(modus_operandi(0)); anchor(); BEGIN(DECLLINE); } ^\%\%impl{WHITESPACE}+ { modi.push_front(modus_operandi(0)); anchor(); BEGIN(IMPLLINE); } \<\%decl\> { modi.push_front(modus_operandi(0)); anchor(); BEGIN(DECLBLOCK); } \<\%impl\> { modi.push_front(modus_operandi(0)); anchor(); BEGIN(IMPLBLOCK); } ^\%\%var{WHITESPACE}+ { modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); anchor(); BEGIN(VARLINE); } ^\%\%import{WHITESPACE}+ { modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); BEGIN(IMPORTLINE); } ^\%\%import_type{WHITESPACE}+ { modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); BEGIN(IMPORTTYPELINE); } ^\%\%derive{WHITESPACE}+ { modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); BEGIN(DERIVELINE); } \<\%constructor\> { modi.push_front(modus_operandi()); anchor(); BEGIN(CONSTRUCTOR); } \<\%destructor\> { modi.push_front(modus_operandi()); anchor(); BEGIN(DESTRUCTOR); } \<\%codemethod{WHITESPACE}+ { modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); anchor(); BEGIN(CODEMETHODLINE); } \<\%method{WHITESPACE}+ { modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); anchor(); BEGIN(METHODLINE); } + ^\%\%pragma{WHITESPACE}+ { + modi.push_front(modus_operandi(modus_operandi::flag_devour_comments)); + BEGIN(PRAGMALINE); + } <<EOF>> { assert(modi.size()==1); M().modify(modus_operandi::modus_preop); LexerOutput(";",1); return 0; } } <<EOF>> throw preprocessor_error(CODEPOINT,"unexpected end of file",lineno()); <CODEBLOCK,CODEMETHODBLOCK>{ "<%output>" { anchor(); yy_push_state(OUTPUTBLOCK); } } +<PRAGMALINE>{ + {WHITESPACE}+ { + modus_operandi& m = M(); + if(!m.output.empty()) { + string::size_type eq = m.output.find('='); + if(eq==string::npos) { + pragmas[m.output]=m.output; + }else{ + pragmas[m.output.substr(0,eq)] = m.output.substr(eq+1); + } + m.output.erase(); + } + } + \n { + modus_operandi& m = M(); + if(!m.output.empty()) { + string::size_type eq = m.output.find('='); + if(eq==string::npos) { + pragmas[m.output]=m.output; + }else{ + pragmas[m.output.substr(0,eq)] = m.output.substr(eq+1); + } + m.output.erase(); + } + modi.pop_front(); + BEGIN(INITIAL); + anchor(); + } +} + <METHODLINE>{ {WHITESPACE}+ { modus_operandi& m = modi.front(); if(!m.output.empty()) { if(!m._lastid.empty()) { if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._lastid = m.output; m.output.clear(); } } \* { modus_operandi& m = modi.front(); ECHO; if(!m._lastid.empty()) { if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._lastid = m.output; m.output.clear(); } \( { modus_operandi& m = modi.front(); if(m.output.empty()) { m._name=m._lastid; }else{ if(!m._lastid.empty()) { // XXX: lastid, I believe should never be emtpy... if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._name = m.output; m.output.clear(); } ECHO; BEGIN(METHODARGS); } } <METHODARGS>{ \%\> { modus_operandi& m = modi.front(); m._args = m.output; m.output.clear(); anchor(); BEGIN(METHODBLOCK); } } <INITIAL,METHODBLOCK,OUTPUTBLOCK>{ \<\%{WHITESPACE}+ { M().modify(modus_operandi::modus_postop); anchor(); LexerOutput("(",1); yy_push_state(INLINE); } ^\%{WHITESPACE} { M().modify(modus_operandi::modus_code); anchor(); yy_push_state(CODELINE); } \<\%code\> { M().modify(modus_operandi::modus_code); anchor(); yy_push_state(CODEBLOCK); } "</%output>" { if(YY_START!=OUTPUTBLOCK) throw preprocessor_error(CODEPOINT,"unexpected tag",lineno()); M().modify(modus_operandi::modus_code); anchor(); yy_pop_state(); } } <INLINE>\%\> LexerOutput(")",1); M().modus=modus_operandi::modus_preop; yy_pop_state(); <CODELINE>\n yy_pop_state(); <CODEMETHODLINE>{ {WHITESPACE}+ { modus_operandi& m = modi.front(); if(!m.output.empty()) { if(!m._lastid.empty()) { if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._lastid = m.output; m.output.clear(); } } \* { modus_operandi& m = modi.front(); ECHO; if(!m._lastid.empty()) { if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._lastid = m.output; m.output.clear(); } \( { modus_operandi& m = modi.front(); if(m.output.empty()) { m._name=m._lastid; }else{ if(!m._lastid.empty()) { // XXX: lastid, I believe should never be emtpy... if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._name = m.output; m.output.clear(); } ECHO; BEGIN(CODEMETHODARGS); } } <CODEMETHODARGS>{ \%\> { modus_operandi& m = modi.front(); m._args = m.output; m.output.clear(); m.flags=0; anchor(); BEGIN(CODEMETHODBLOCK); } } <IMPORTLINE>{ {WHITESPACE}+ { } {ID} { if(!modi.front()._name.empty()) throw preprocessor_error(CODEPOINT,"syntax error",lineno()); modi.front()._name = yytext; } \= { modi.front().output.clear(); BEGIN(IMPORTCOMPONENT); } } <IMPORTCOMPONENT>{ {WHITESPACE}+ { } \n { modus_operandi& m = M(); string::size_type t = m.output.find_first_not_of(" \t"); if(t!=string::npos) m.output.erase(0,t); t = m.output.find_last_not_of(" \t;"); if(t!=string::npos) m.output.erase(t+1); if(m.output[0]=='"' && m.output[m.output.length()-1]=='"') { m.output.erase(0,1); m.output.erase(m.output.length()-1); } string c = combine_path(component_basename,m.output); member_variables.push_back(member_variable(m._type,m._name,normalize_path(c,strip_leading_slash),true)); modi.pop_front(); BEGIN(INITIAL); } } <IMPORTTYPELINE>{ {WHITESPACE}+ { } {ID} { if(!modi.front()._name.empty()) throw preprocessor_error(CODEPOINT,"syntax error",lineno()); modi.front()._name = yytext; } \= { modi.front().output.clear(); BEGIN(IMPORTTYPECOMPONENT); } } <IMPORTTYPECOMPONENT>{ {WHITESPACE}+ { } \n { modus_operandi& m = M(); string::size_type t = m.output.find_first_not_of(" \t"); if(t!=string::npos) m.output.erase(0,t); t = m.output.find_last_not_of(" \t;"); if(t!=string::npos) m.output.erase(t+1); if(m.output[0]=='"' && m.output[m.output.length()-1]=='"') { m.output.erase(0,1); m.output.erase(m.output.length()-1); } string c = combine_path(component_basename,m.output); member_variables.push_back(member_variable(m._type,m._name,normalize_path(c,strip_leading_slash),true,true)); modi.pop_front(); BEGIN(INITIAL); } } <DERIVELINE>{ {WHITESPACE}+ { } {ID} { if(!modi.front()._name.empty()) throw preprocessor_error(CODEPOINT,"syntax_error",lineno()); modi.front()._name = yytext; } \= { modi.front().output.clear(); BEGIN(DERIVECOMPONENT); } } <DERIVECOMPONENT>{ {WHITESPACE}+ { } \n { modus_operandi& m = M(); string::size_type t = m.output.find_first_not_of(" \t"); if(t!=string::npos) m.output.erase(0,t); t = m.output.find_last_not_of(" \t;"); if(t!=string::npos) m.output.erase(t+1); if(m.output[0]=='"' && m.output[m.output.length()-1]=='"') { m.output.erase(0,1); m.output.erase(m.output.length()-1); } string c = combine_path(component_basename,m.output); ancestor_classes.push_back(ancestor_class(m._name,normalize_path(c,strip_leading_slash))); modi.pop_front(); BEGIN(INITIAL); } } <VARLINE>{ {WHITESPACE}+ { modus_operandi& m = modi.front(); if(!m.output.empty()) { if(!m._lastid.empty()) { if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._lastid = m.output; m.output.clear(); } } \* { modus_operandi& m = modi.front(); ECHO; if(!m._lastid.empty()) { if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._lastid = m.output; m.output.clear(); } \;|\n|\= { modus_operandi& m = modi.front(); if(m.output.empty()) { m._name=m._lastid; }else{ if(!m._lastid.empty()) { // XXX: lastid should never be emtpy, I believe? if(!m._type.empty()) m._type += ' '; m._type += m._lastid; } m._name=m.output; m.output.clear(); } BEGIN(VARINIT); if(*yytext!='=') unput('\n'); } } <VARINIT>{ \n { modus_operandi& m = modi.front(); string::size_type t = m.output.find_first_not_of(" \t"); if(t!=string::npos) m.output.erase(0,t); t = m.output.find_last_not_of(" \t;"); if(t!=string::npos) m.output.erase(t+1); member_variables.push_back(member_variable(m._type,m._name,m.output)); if(!m.output.empty()) have_initializers=true; modi.pop_front(); BEGIN(INITIAL); } } <DECLLINE>\n { ECHO; decl += modi.front().output; modi.pop_front(); BEGIN(INITIAL); } <IMPLLINE>\n { ECHO; impl += modi.front().output; modi.pop_front(); BEGIN(INITIAL); } <CLASSLINE>\n { class_name = modi.front().output; modi.pop_front(); BEGIN(INITIAL); } -<CLASSLINE,DECLLINE,IMPLLINE,VARLINE,VARINIT,IMPORTLINE,IMPORTCOMPONENT,CODEMETHODLINE,CODEMETHODARGS,INLINE,METHODLINE,METHODARGS,DECLBLOCK,IMPLBLOCK,CONSTRUCTOR,DESTRUCTOR,CODEMETHODBLOCK,CODELINE,CODEBLOCK>{ +<CLASSLINE,DECLLINE,IMPLLINE,VARLINE,VARINIT,IMPORTLINE,IMPORTCOMPONENT,CODEMETHODLINE,CODEMETHODARGS,INLINE,METHODLINE,METHODARGS,DECLBLOCK,IMPLBLOCK,CONSTRUCTOR,DESTRUCTOR,CODEMETHODBLOCK,CODELINE,CODEBLOCK,PRAGMALINE>{ "/*" { yy_push_state(SLASHSTAR_COMMENT); if(!M().devour_comments()) { ECHO; } } "//" { yy_push_state(SLASHSLASH_COMMENT); if(!M().devour_comments()) { ECHO; } } \" { yy_push_state(STRING); ECHO; } \'\\.\' { ECHO; } } <INITIAL,METHODBLOCK,OUTPUTBLOCK>{ \" soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\\"",2); \n soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\n",2); \r soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\r",2); \t soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\t",2); \b soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\b",2); \a soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\a",2); . soft_anchor(); M().modify(modus_operandi::modus_text); ECHO; {WHITESPACE}+ soft_anchor(); M().modify(modus_operandi::modus_text); ECHO; } <DECLBLOCK,IMPLBLOCK,CONSTRUCTOR,DESTRUCTOR,CODEMETHODBLOCK,METHODBLOCK,CODEBLOCK>{ \<\/\%decl\> { if(YY_START!=DECLBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); decl += modi.front().output; modi.pop_front(); BEGIN(INITIAL); } \<\/\%impl\> { if(YY_START!=IMPLBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); impl += modi.front().output; modi.pop_front(); BEGIN(INITIAL); } \<\/\%constructor\> { if(YY_START!=CONSTRUCTOR) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); member_functions.push_back(member_function("","","",modi.front().output)); have_constructor = true; modi.pop_front(); BEGIN(INITIAL); } \<\/\%destructor\> { if(YY_START!=DESTRUCTOR) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); member_functions.push_back(member_function("","~","",modi.front().output)); modi.pop_front(); BEGIN(INITIAL); } \<\/\%codemethod\> { if(YY_START!=CODEMETHODBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); modus_operandi& m = modi.front(); member_functions.push_back(member_function(m._type,m._name,m._args,m.output)); modi.pop_front(); BEGIN(INITIAL); } \<\/%method\> { if(YY_START!=METHODBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); modus_operandi& m = modi.front(); m.modify(modus_operandi::modus_code); member_functions.push_back(member_function(m._type,m._name,m._args,m.output)); modi.pop_front(); BEGIN(INITIAL); } \<\/%code\> { if(YY_START!=CODEBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno()); yy_pop_state(); } \n ECHO; } <SLASHSTAR_COMMENT>{ "*/" { if(!M().devour_comments()) { ECHO; } yy_pop_state(); unput(' '); } \n { if(!M().devour_comments()) { ECHO; } } } <SLASHSLASH_COMMENT>{ \n { if(!M().devour_comments()) { ECHO; } yy_pop_state(); if(YY_START!=CODEBLOCK && YY_START!=CODEMETHODBLOCK && YY_START!=IMPLBLOCK && YY_START!=DECLBLOCK) unput('\n'); } } <SLASHSTAR_COMMENT,SLASHSLASH_COMMENT>. { if(!M().devour_comments()) { ECHO; } } <STRING>{ \\. ECHO; \" ECHO; yy_pop_state(); . ECHO; } {WHITESPACE}+ { if(!(M().flags&modus_operandi::flag_devour_whitespace)) { ECHO; } } %% sitecing_parser::sitecing_parser(component_factory& f) : factory(f), have_initializers(false), have_constructor(false), base_class("sitecing::cgi_component"), base_header("sitecing/cgi_component.h"), skeleton(__SC_DEFAULT_SKELETON) { } void sitecing_parser::preprocess(const string& in) { ifstream ifs(in.c_str(),ios::in); if(!ifs.good()) throw preprocessor_error(CODEPOINT,"failed to open input file"); input_file = in; modi.push_front(modus_operandi(0)); switch_streams(&ifs,NULL); if(yylex()) throw preprocessor_error(CODEPOINT,"unknown error"); + pragmas_t::const_iterator mp = pragmas.find("main"); + if(mp==pragmas.end()) { member_functions.push_back(member_function("void","main","(int _magic,va_list _args)",M().output)); + }else{ + member_functions.push_back( + member_function( + "void","main","(int _magic,va_list _args)", + mp->second+"::main(_magic,_args);" + ) + ); + } if(have_initializers && !have_constructor) member_functions.push_back(member_function("","","","")); sitecing_enflesher enflesher(*this); enflesher.enflesh(); } void sitecing_parser::LexerOutput(const char* buf,int size) { assert(modi.size()); M().output.append(buf,size); } static const char *modus_transitions [sitecing_parser::modus_operandi::modi] [sitecing_parser::modus_operandi::modi] = { // To: // code preop postop text From: { "", "(*(__SCIF->out))", "(*(__SCIF->out))<<", "(*(__SCIF->out))<<\"" }, // code { ";", "", "<<", "<<\"" }, // preop { NULL, NULL, "", "\"" }, // postop { "\";", "\"", "\"<<", "" } // text }; void sitecing_parser::modus_operandi::modify(modus_t m) { const char * x = modus_transitions[modus][m]; assert(x); output += x; modus = m; } void sitecing_parser::soft_anchor() { if(M().modus!=modus_operandi::modus_text) anchor(); } void sitecing_parser::anchor() { if(M().modus==modus_operandi::modus_text) M().modify(modus_operandi::modus_preop); M().output += "\n#line "; char tmp[7]; snprintf(tmp,sizeof(tmp),"%d",lineno()); M().output += tmp; M().output += " \""; M().output += input_file; M().output += "\"\n"; } /* vim:set ft=lex: */ |