%{ #include #include #include #include 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_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) { 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: */