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 | 49 |
5 files changed, 72 insertions, 4 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 @@ -27,53 +27,62 @@ 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 @@ -246,81 +246,89 @@ class sitecing_parser : public sitecing_parserFlexLexer { */ 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 @@ -274,59 +274,59 @@ namespace sitecing { 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 @@ -134,121 +134,127 @@ ID [A-Za-z_][A-Za-z0-9_]* 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,160 +1,195 @@ %{ /* * 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); } } @@ -361,97 +396,97 @@ NOIDCHAR [^A-Za-z0-9_] 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)); @@ -501,94 +536,104 @@ NOIDCHAR [^A-Za-z0-9_] } } } <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"); - member_functions.push_back(member_function("void","main","(int _magic,va_list _args)",M().output)); + 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: */ |