// $Id: code_gen.cc,v 1.9.2.1 1999/07/29 04:41:26 greear Exp $ // $Revision: 1.9.2.1 $ $Author: greear $ $Date: 1999/07/29 04:41:26 $ // //ScryMUD Server Code //Copyright (C) 1998 Ben Greear // //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; either version 2 //of the License, or (at your option) any later version. // //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. // // To contact the Author, Ben Greear: greear@cyberhighway.net, (preferred) // greearb@agcs.com // #include <stdio.h> #include <string2.h> #include <string.h> #include "code_gen.h" #include <fstream.h> #include <PtrArray.h> LogStream mudlog("/tmp/code_gen.log", 65535); int __node_cnt; int __list_cnt; int __cell_cnt; char* header = "// //ScryMUD Server Code //Copyright (C) 1998 Ben Greear // // NOTE: This code was autogenerated by the code_gen.cc program. If you // need to make modifications, do it there! --BLG // //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; either version 2 //of the License, or (at your option) any later version. // //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. // // To contact the Author, Ben Greear: greear@cyberhighway.net, (preferred) // greearb@agcs.com // // // NOTE: This code was autogenerated by the code_gen.cc program. If you // need to make modifications, do it there! --BLG "; int core_dump(const char* msg) { cerr << "ERROR: " << msg << endl; exit(1); } LanguageEntry::LanguageEntry(const LanguageEntry& src) : enum_name(src.enum_name) { Cell<LVPair*> cll(src.vals); LVPair* ptr; while ((ptr = cll.next())) { vals.append(new LVPair(*ptr)); } }//copy constructor void LanguageEntry::clear() { enum_name = ""; clear_ptr_list(vals); }//clear int LanguageEntry::read(ifstream& dafile) { char junk[200]; String tmp_lang(50); String tmp_val; clear(); // Grab comments, if there are any. while (TRUE) { dafile >> enum_name; if (!dafile) return -1; //EOF if (enum_name.charAt(0) == '#') { dafile.getline(junk, 200); } else { break; } }//while dafile >> tmp_lang; //Language type while (tmp_lang != "~") { if (!dafile) return -1; //EOF tmp_val.Clear(); if (tmp_val.readToken('\"', dafile, TRUE) < 0) { cerr << "ERROR: trying to read token: -:" << tmp_val << ":- Exiting." << endl; exit(2); }//if vals.append(new LVPair(tmp_lang, tmp_val)); dafile >> tmp_lang; }//while return 0; }//read String LanguageEntry::getConstArray() const { String retval(500); String translations[NUM_LANGUAGES]; /* enum LanguageE { English, Spanish, Portugues, Italian, LastLanguage }; */ retval = " {\n "; int slen; // NOTE: To add a new language, modify the while loop below // to contain the ones you want to support. Then make additions // to the translation.spec file. Cell<LVPair*> cll(vals); LVPair* ptr; int found_one; while ((ptr = cll.next())) { slen = ptr->lang.Strlen(); found_one = FALSE; for (int i = 0; i<NUM_LANGUAGES; i++) { if (strncasecmp(ptr->lang, languages[i], slen) == 0) { translations[i] = ptr->val; found_one = TRUE; break; } } if (!found_one) { cerr << "WARNING: Unknown language: -:" << ptr->lang << ":-" << endl; } }//while for (int i = 0; i<NUM_LANGUAGES; i++) { if (translations[i].Strlen()) { retval += translations[i]; if ((i + 1) != NUM_LANGUAGES) retval += ",\n "; else retval += "\n"; } else { if ((i + 1) != NUM_LANGUAGES) retval += "NULL,\n "; else retval += "NULL\n"; }//else }//for retval += " }"; return retval; }//getConstArray void GenCmdInput::clear() { for (int i = 0; i<ALIASES_ARRAY_LEN; i++) { aliases[i].Clear(); } help.Clear(); cmd.Clear(); } void GenCmdInput::print() { cout << "ALIAS: "; for (int i = 0; i<ALIASES_ARRAY_LEN; i++) { if (aliases[i].Strlen()) { cout << "[" << aliases[i] << "] "; } } cout << "\nHELP: [" << help << "]\n"; cout << "CMD: [" << cmd << "]\n"; } int GenCmdInput::read(ifstream& dafile) { clear(); char ch_buf[200]; String tmp; int idx = 0; while (TRUE) { dafile >> tmp; if ((tmp.Strlen() == 0) || (tmp == "~")) { // first was a ~, so we are at EOF return -1; } if ((tmp == "#") || (tmp.charAt(0) == '#')) { dafile.getline(ch_buf, 199); continue; } else { break; } }//while, read and junk comments // no comments allowed within entries. while (tmp != "~") { //cout << "In while loop, tmp -:" << tmp << ":- idx: " << idx << endl; aliases[idx] = tmp; idx++; dafile >> tmp; } //cout << "Done with while loop, idx: " << idx << endl; if (idx > 1) { // last one is the help //cout << "Using last one for help.." << endl; help = aliases[idx - 1]; aliases[idx - 1].Clear(); } else if (idx == 1) { //cout << "Using first one for help." << endl; help = aliases[0]; //default to the first one is the help too } else { return -1; //all done, I spose! } // junk the first, it's the end of the line of aliases cmd.Getline(dafile, 200); cmd.Getline(dafile, 200); return 0; }//read int main(int argc, char** argv) { const char* usage = "code_gen -[CL] [input_file_name ...] [out.cc] [out.h]\n"; if (argc < 5) { cerr << usage << endl; cerr << "ERROR: argc should be >= 5, but was: " << argc << endl; exit(1); } if (strcasecmp(argv[1], "-C") == 0) { // Then create some commands return code_gen_commands(argv, argc); } else if (strcasecmp(argv[1], "-L") == 0) { // Create the language array and code return code_gen_language(argv, argc); } else { cerr << usage << endl; exit(1); } }//main int code_gen_language(char** argv, int argc) { // First, lets parse the incomming file and make sure it's OK. PtrArray<LanguageEntry> language_entries; LanguageEntry le; ofstream of_cc(argv[argc - 2]); if (!of_cc) { cerr << "ERROR: could not open output .cc file." << endl; exit(1); } ofstream of_h(argv[argc - 1]); if (!of_h) { cerr << "ERROR: could not open output .h file." << endl; exit(1); } int cnt = 0; for (int i = 2; i<(argc - 2); i++) { ifstream input_file(argv[i]); if (!input_file) { cerr << "ERROR: could not open input_file: " << argv[i] << endl; exit(1); } else { cout << "Processing spec file: " << argv[i] << endl; } // If there is a read or parse error, the program will exit // inside the le.read() call. while (le.read(input_file) >= 0) { cnt++; language_entries.appendShallowCopy(new LanguageEntry(le)); } }//for // If we got to here, then we were able to parse and read the file. //First, get the headers out of the way of_h << header; // NOTE: If you change the language enum below, you will need to // modify the LanguageEntry code, especially the NUM_LANGUAGES #define // and the getConstArray() method. --BEN of_h << " #ifndef __INCLUDE_AUTOGEN_LANGUAGE_H__ #define __INCLUDE_AUTOGEN_LANGUAGE_H__ #include <string2.h> // I expect this may grow. enum LanguageE {\n"; for (int j = 0; j<NUM_LANGUAGES; j++) { of_h << " " << languages[j] << "," << endl; } of_h <<" LastLanguage\n};\n\n"; // If the ENUM above changes, change this 3 to be equal to // the number of languages. of_h << "#define LS_PER_ENTRY " << NUM_LANGUAGES << " /* same as LastLanguage */" << endl; of_h << "#define LS_ENTRIES " << cnt << " /* Number of Translation groupings */\n\n"; of_h << "extern const char* language_strings[LS_ENTRIES][LS_PER_ENTRY];\n"; of_h << "\nenum CSentryE {\n"; for (int i = 0; i<cnt; i++) { of_h << " " << language_entries[i]->getEnumName(); if ((i + 1) != cnt) of_h << "," << endl; else of_h << endl; } of_h << "};//CSentryE enum\n\n"; of_h << " class CSHandler { public: static const char* getString(CSentryE which_string, LanguageE language); }; #endif\n"; of_h << flush; // Done with .h file, lets start on the .cc file of_cc << header; of_cc << " #include \"lang_strings.h\" const char* language_strings[LS_ENTRIES][LS_PER_ENTRY] = {\n"; for (int i = 0; i<cnt; i++) { of_cc << " /* " << language_entries[i]->getEnumName() << " */" << endl; of_cc << language_entries[i]->getConstArray(); if ((i + 1) != cnt) of_cc << ",\n\n"; else of_cc << endl; }//for of_cc << "}; //language_strings\n\n"; of_cc << " const char* CSHandler::getString(CSentryE which_string, LanguageE language) { const char* retval = language_strings[(int)(which_string)][(int)(language)]; if (retval) { return retval; } else { // Default to English... // TODO: Be smarter here, ie Portuguese defaults to Spanish?? return language_strings[(int)(which_string)][0]; }//else }//getString\n\n"; of_cc << flush; return 0; }//code_gen_language int code_gen_commands(char** argv, int argc) { String buf(200); String tmp(200); String cmd_enum(1000); String cmd_instantiations(10000); String exe_cmds(5000); String cmd_array(1000); // add the starting stuff. cmd_enum.Append("enum CmdId {\n"); cmd_instantiations.Append("#define ADD_NEW_CMD cmds_collection.addCmdSpecifierNoCreate void initCmdsCollection() { \n"); exe_cmds.Append("//Add a few #defines to cut down on the huge file size!\n\n"); exe_cmds.Append(" #define CODE_GEN_EXE_HEADER \ String& str1, String& str2, String& str3, String& str4, \ String& str5, int i, int j, int k, int l, int m, int n,\ int& is_dead, critter& pc, critter* c_script_owner, \ room* r_script_owner, String* cooked_strs, int* cooked_ints, \ int do_sub, int sanity, int was_ordered \n"); // Hopefully, a smart compiler will get rid of this test. It's // here to keep the compiler from complaining about un-used variables. // --BLG exe_cmds.Append(" #define CODE_GEN_VAR_TEST_IF \ 1 || &str1 || &str2 || &str3 || &str4 || &str5 || i || j || k || l \ || m || n || is_dead || &pc ||c_script_owner || r_script_owner \ || cooked_strs || cooked_ints || do_sub || sanity || was_ordered\n\n"); exe_cmds.Append(" class ExeCmd { public: virtual int execute(CODE_GEN_EXE_HEADER) = 0; //pure virtual };\n"); cmd_array.Append("void initCmdsArray() {\n"); ofstream of_cc(argv[argc - 2]); if (!of_cc) { cerr << "ERROR: could not open output .cc file." << endl; exit(1); } ofstream of_h(argv[argc - 1]); if (!of_h) { cerr << "ERROR: could not open output .h file." << endl; exit(1); } //TODO: Never tested w/two spec files...I fear blowup!! --BEN int cmd_count = 0; int done_exe_already = FALSE; for (int i = 2; i<(argc - 2); i++) { ifstream input_file(argv[i]); if (!input_file) { cerr << "ERROR: could not open input_file: " << argv[i] << endl; exit(1); } else { cout << "Processing spec file: " << argv[i] << endl; } GenCmdInput cmd_input; while (input_file) { if (cmd_input.read(input_file) == -1) { // all done break; } // debugging //cmd_input.print(); if (cmd_input.help.charAt(0) != '*') { // help only // create the commands, and the enum, and the ExeCmds Sprintf(tmp, " ci_%S,\n", &(cmd_input.aliases[0])); cmd_enum.Append(tmp); } done_exe_already = FALSE; for (int i = 0; i<ALIASES_ARRAY_LEN; i++) { if (cmd_input.aliases[i].Strlen() == 0) break; if (cmd_input.help.charAt(0) == '*') { // help only Sprintf(tmp, " ADD_NEW_CMD(new CmdSpecifier(\"%S\", %i, ci_HELP_ONLY, \"%s\"));\n", &(cmd_input.aliases[i]), cmd_input.aliases[i].Strlen(), ((const char*)(cmd_input.help)) + 1); //move past * cmd_instantiations.Append(tmp); } else { Sprintf(tmp, " ADD_NEW_CMD(new CmdSpecifier(\"%S\", %i, ci_%S, \"%S\"));\n", &(cmd_input.aliases[i]), cmd_input.aliases[i].Strlen(), &(cmd_input.aliases[0]), &(cmd_input.help)); cmd_instantiations.Append(tmp); if (!done_exe_already) { cmd_count++; Sprintf(tmp, " class ExeCmd_%S : public ExeCmd { public: int execute(CODE_GEN_EXE_HEADER) { if (CODE_GEN_VAR_TEST_IF) { %S } else return 0; }//execute };//ExeCmd\n", &(cmd_input.aliases[0]), &(cmd_input.cmd)); exe_cmds.Append(tmp); // Now, lets add the code that will place this in an array. Sprintf(tmp, " exe_cmd_array[(int)(ci_%S)] = new ExeCmd_%S;\n", &(cmd_input.aliases[0]), &(cmd_input.aliases[0])); cmd_array.Append(tmp); done_exe_already = TRUE; }//if not done_exe_already }//else }//for }//while }//for all spec files // Now, have read everything in..lets put the code together. of_h << header; of_h << " #ifndef __INCLUDE_AUTOGEN_CMD_H__ #define __INCLUDE_AUTOGEN_CMD_H__ #include \"ar_skll.h\" #include \"cr_skll.h\" #include \"social2.h\" #include \"ez_skll.h\" #include \"dam_skll.h\" #include \"misc.h\" #include \"misc2.h\" #include \"commands.h\" #include \"command2.h\" #include \"command3.h\" #include \"command4.h\" #include \"command5.h\" #include \"spells.h\" #include \"skills.h\" #include \"olc.h\" #include \"olc2.h\" #include \"socials.h\" #include \"classes.h\" #include \"wep_skll.h\" #include \"parse.h\" #include \"script.h\"\n\n"; of_cc << header; of_cc << "#include \"code_gen.h\"\n"; of_cc << "#include \"parse.h\"\n"; // Terminate the constructs. cmd_enum.Append(" ci_HELP_ONLY,\n"); cmd_enum.Append(" ci_UNKNOWN,\n"); cmd_enum.Append(" ci_MAX_VALUE\n};\n\n"); cmd_instantiations.Append("}// initCmdsCollection\n\n"); // exe_cmds should be fine cmd_array.Append("}//End of ExeCmd array assignment\n\n"); // Lets do the .h file first. Assume #includes already done. of_h << "class ExeCmd; //foward declaration\n\n"; of_h << "\nextern ExeCmd* exe_cmd_array[" << cmd_count + 1 << "];\n\n"; of_h << cmd_enum << endl; of_h << exe_cmds << endl; of_h << "\n\n#endif"; // Now, the .cc file of_cc << "ExeCmd* exe_cmd_array[" << cmd_count + 1 << "];\n\n"; of_cc << cmd_instantiations << endl; of_cc << cmd_array << endl; return 0; }//code_gen_commands