Last active
August 29, 2015 13:59
-
-
Save sfan5/10993910 to your computer and use it in GitHub Desktop.
does stuff using C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <fstream> | |
#include <sstream> | |
#include <map> | |
#include <list> | |
#include <utility> | |
#include <stdlib.h> // for exit() | |
#include <vector> | |
template <typename T, typename U> class create_map { | |
private: | |
std::map<T, U> m_map; | |
public: | |
create_map(const T& key, const U& val) | |
{ | |
m_map[key] = val; | |
} | |
create_map<T, U>& operator()(const T& key, const U& val) | |
{ | |
m_map[key] = val; | |
return *this; | |
} | |
operator std::map<T, U>() | |
{ | |
return m_map; | |
} | |
}; | |
struct type { | |
const char *pf; // Function name | |
const char *type; // C++ type | |
unsigned int flags; | |
}; | |
class create_st { | |
private: | |
struct type s; | |
public: | |
create_st(const char *pf, const char *type, unsigned int flags) | |
{ | |
s.pf = pf; s.type = type; s.flags = flags; | |
} | |
operator struct type() | |
{ | |
return s; | |
} | |
}; | |
#define FLG_SER 1 // Uses serialize... function instead of write... | |
#define FLG_REF 2 // Passed by reference | |
#define LEX_WHITESPACE 1 // [ \t]+ | |
#define LEX_IDENT 2 // [A-Za-z0-9_]+ | |
#define LEX_TOPEN 3 // [ | |
#define LEX_TCLOSE 4 // ] | |
#define LEX_COPEN 5 // { | |
#define LEX_CCLOSE 6 // } | |
#define LEX_SEMIC 7 // ; | |
static inline const char *lex2human(unsigned int t) | |
{ | |
switch(t) { | |
case LEX_WHITESPACE: | |
return "whitespace"; | |
case LEX_IDENT: | |
return "identifier"; | |
case LEX_TOPEN: | |
return "'['"; | |
case LEX_TCLOSE: | |
return "']'"; | |
case LEX_COPEN: | |
return "'{'"; | |
case LEX_CCLOSE: | |
return "'}'"; | |
case LEX_SEMIC: | |
return "semicolon"; | |
default: | |
return "~ERROR~"; | |
} | |
} | |
struct lex_item { | |
unsigned int type; | |
unsigned int line; | |
unsigned int chri; | |
const char *file; | |
std::string ident_v; // Only when type = LEX_IDENT | |
std::vector<std::string> lines; // Only in first element, contains all the lines of the file this lex item is in | |
}; | |
const std::map<std::string, struct type> types = create_map<std::string, struct type> | |
//name struct type | |
("u64", create_st("U64", "u64", 0)) | |
("u32", create_st("U32", "u32", 0)) | |
("u16", create_st("U16", "u16", 0)) | |
("u8", create_st("U8", "u8", 0)) | |
("s32", create_st("S32", "s32", 0)) | |
("s16", create_st("S16", "s16", 0)) | |
("s8", create_st("S8", "s8", 0)) | |
("v3s32", create_st("V3S32", "v3s32", FLG_REF)) | |
("v3s16", create_st("V3S16", "v3s16", FLG_REF)) | |
("v2s32", create_st("V2S32", "v2s32", FLG_REF)) | |
("v2s16", create_st("V2S16", "v2s16", FLG_REF)) | |
("argb8", create_st("ARGB8", "irr::SColor", FLG_REF)) | |
("f32", create_st("F1000", "float", 0)) | |
("v3f", create_st("V3F1000", "v3f", FLG_REF)) | |
("v2f", create_st("V2F1000", "v2f", FLG_REF)) | |
("string", create_st("String", "std::string", FLG_SER | FLG_REF)) | |
("lstring", create_st("LongString", "std::string", FLG_SER | FLG_REF)) | |
("jstring", create_st("JsonString", "std::string", FLG_SER | FLG_REF)) | |
("wstring", create_st("WideString", "std::wstring", FLG_SER | FLG_REF)) | |
; | |
void writeHeader(std::ofstream &ofs) | |
{ | |
ofs << "#include \"clientserver.h\"\n"; | |
ofs << "#include \"util/serialize.h\"\n"; | |
ofs << "\n"; | |
ofs << "namespace protocol {\n"; | |
ofs << "\n"; | |
} | |
void writeFooter(std::ofstream &ofs) | |
{ | |
ofs << "} // namespace protocol\n"; | |
ofs << "\n"; | |
} | |
void writeFunctionHeader1(std::ostream &os, std::string tag) | |
{ | |
os << "SharedBuffer<u8> create_" << tag << "(\n"; | |
os << "\t\tu16 net_proto_version, // Always\n"; | |
} | |
void writeFunctionHeaderType(std::ostream &os, std::string name, struct type t) | |
{ | |
if(t.flags & FLG_REF) | |
os << "\t\tconst " << t.type << " &" << name << ",\n"; | |
else | |
os << "\t\t" << t.type << " " << name << ",\n"; | |
} | |
void writeFunctionHeader2(std::ostream &os, std::string tag) | |
{ | |
os << ") {\n"; | |
os << "\tstd::ostringstream os(std::ios_base::binary);\n"; | |
os << "\n"; | |
os << "\twriteU16(os, " << tag << ");\n"; | |
} | |
void writeFunctionBody(std::ostream &os, std::string name, struct type t) | |
{ | |
if(t.flags & FLG_SER) | |
os << "\tos << serialize" << t.pf << "(" << name << ");\n"; | |
else | |
os << "\twrite" << t.pf << "(os, " << name << ");\n"; | |
} | |
void writeFunctionFooter(std::ostream &os) | |
{ | |
os << "\n"; | |
os << "\tstd::string s = os.str();\n"; | |
os << "\treturn SharedBuffer<u8>((u8*) s.c_str(), s.size());\n"; | |
os << "}\n"; | |
os << "\n"; | |
} | |
void print_file_err(const char *line, unsigned int lnum, unsigned int chri, const char *fn, const char *err) | |
{ | |
std::cerr << fn << ":" << lnum << ":" << chri << ": " << err << std::endl; | |
std::cerr << "| "; | |
char *p = (char*) line; | |
while(*p) { | |
if(*p == '\t') | |
std::cerr << " "; // Makes sure alignment for tabs is right | |
else | |
std::cerr << *p; | |
p++; | |
} | |
std::cerr << std::endl; | |
std::cerr << "| "; | |
for(int i = 0; i < chri; i++) | |
std::cerr << " "; | |
std::cerr << "^" << std::endl; | |
} | |
#define IDENT_COND ((line[i] >= 'a' && line[i] <= 'z') || (line[i] >= 'A' && line[i] <= 'Z') || (line[i] >= '0' && line[i] <= '9') || line[i] == '_') | |
std::list<struct lex_item> lex(std::ifstream &ifs, const char *fn) | |
{ | |
unsigned int ln = 0; | |
std::list<struct lex_item> out; | |
std::vector<std::string> lines; | |
while(1) { | |
char line[250]; | |
if(ifs.eof()) | |
break; | |
ifs.getline(line, 250); | |
ln++; | |
lines.push_back(std::string(line)); | |
unsigned int i, currtype, starti; | |
i = currtype = 0; | |
std::ostringstream oss; | |
while(1) { | |
unsigned int newtype; | |
if(line[i] == '#' || line[i] == '\0') | |
goto finish; // Finish off the last element... | |
else if(line[i] == ' ' || line[i] == '\t') | |
newtype = LEX_WHITESPACE; | |
else if(IDENT_COND) | |
newtype = LEX_IDENT; | |
else if(line[i] == '[') | |
newtype = LEX_TOPEN; | |
else if(line[i] == ']') | |
newtype = LEX_TCLOSE; | |
else if(line[i] == '{') | |
newtype = LEX_COPEN; | |
else if(line[i] == '}') | |
newtype = LEX_CCLOSE; | |
else if(line[i] == ';') | |
newtype = LEX_SEMIC; | |
else { | |
print_file_err(line, ln, i, fn, "???"); | |
exit(2); | |
} | |
if(currtype == newtype) | |
goto finish_end; | |
finish: | |
if(currtype != 0) { | |
struct lex_item l; | |
l.type = currtype; | |
l.line = ln; | |
l.chri = starti; | |
l.file = fn; | |
if(currtype == LEX_IDENT) { | |
l.ident_v = oss.str(); | |
oss.str(""); // Clear string for ident value | |
} | |
out.push_back(l); | |
} | |
finish_end: | |
if(line[i] == '#' || line[i] == '\0') | |
break; // ...and then exit | |
if(currtype != newtype) { | |
starti = i; // Set the starting index for the new element | |
currtype = newtype; | |
} | |
if(currtype == LEX_IDENT) | |
oss << line[i]; | |
i++; | |
} | |
} | |
out.front().lines = lines; | |
return out; | |
} | |
/*inline std::string int2str(int i) | |
{ | |
std::ostringstream oss; | |
oss << i; | |
return oss.str(); | |
}*/ | |
#define NEXT_EL(lines) \ | |
if(ll.size() == 0) { \ | |
print_file_err(lines[el.line-1].c_str(), el.line, el.chri, el.file, "error: Unexpected EOF"); \ | |
exit(2); \ | |
} \ | |
el = ll.front(); \ | |
ll.pop_front(); | |
#define SKIP(typ) \ | |
while(el.type == typ) { \ | |
NEXT_EL(lines); \ | |
} \ | |
#define EXPECT(typ) \ | |
if(el.type != typ) { \ | |
print_file_err(lines[el.line-1].c_str(), el.line, el.chri, el.file, (std::string("error: Expected ") + lex2human(typ) + " got " + lex2human(el.type)/* + " (" + int2str(__LINE__) + ")"*/).c_str()); \ | |
exit(2); \ | |
} | |
#define FILE_ERR(err) { \ | |
print_file_err(lines[el.line-1].c_str(), el.line, el.chri, el.file, (std::string("error: ") + (err)).c_str()); \ | |
exit(2); \ | |
} | |
#define FILE_WARN(err) \ | |
print_file_err(lines[el.line-1].c_str(), el.line, el.chri, el.file, (std::string("warning: ") + (err)).c_str()); | |
void gen_file(std::list<struct lex_item> ll, std::ofstream &ofs) | |
{ | |
if(ll.size() == 0) | |
return; | |
std::string c_tag, c_type, c_name, c_special1, c_special2; | |
std::ostringstream oss; // Contains the function body | |
struct lex_item el; | |
el = ll.front(); | |
ll.pop_front(); | |
std::vector<std::string> lines = el.lines; | |
while(1) | |
{ | |
SKIP(LEX_WHITESPACE); | |
if(ll.size() == 0) | |
break; | |
newtag: | |
// TOPEN IDENT TCLOSE | [ foobar ] | |
EXPECT(LEX_TOPEN); NEXT_EL(lines); | |
SKIP(LEX_WHITESPACE); | |
EXPECT(LEX_IDENT); | |
c_tag = el.ident_v; | |
NEXT_EL(lines); | |
SKIP(LEX_WHITESPACE); | |
EXPECT(LEX_TCLOSE); NEXT_EL(lines); | |
writeFunctionHeader1(ofs, c_tag); | |
oss.str(""); | |
newcontent: | |
// IDENT IDENT | v2s16 foo; | |
SKIP(LEX_WHITESPACE); | |
EXPECT(LEX_IDENT); | |
c_type = el.ident_v; | |
if(c_type == "list") { | |
// IDENT IDENT IDENT IDENT { <repeating contents> } | list bar u16 SomeCXXType { u8 abc; s32 def; } | |
NEXT_EL(lines); | |
EXPECT(LEX_WHITESPACE); SKIP(LEX_WHITESPACE); | |
EXPECT(LEX_IDENT); | |
c_name = el.ident_v; | |
NEXT_EL(lines); | |
EXPECT(LEX_WHITESPACE); SKIP(LEX_WHITESPACE); | |
EXPECT(LEX_IDENT); | |
c_special1 = el.ident_v; | |
NEXT_EL(lines); | |
EXPECT(LEX_WHITESPACE); SKIP(LEX_WHITESPACE); | |
EXPECT(LEX_IDENT); | |
c_special2 = std::string("std::list<") + el.ident_v + ">"; | |
NEXT_EL(lines); | |
struct type t; | |
t.type = c_special2.c_str(); | |
t.flags = FLG_REF; | |
writeFunctionHeaderType(ofs, c_name, t); | |
SKIP(LEX_WHITESPACE); | |
EXPECT(LEX_COPEN); | |
NEXT_EL(lines); | |
writeFunctionBody(oss, std::string(c_name) + ".size()", types.find(c_special1)->second); | |
oss << "\tfor(" << c_special2 << "::iterator it = " << c_name << ".begin(); it != " << c_name << ".end(); it++) {\n"; | |
while(1) { | |
// IDENT IDENT | v2s16 foo; | |
SKIP(LEX_WHITESPACE); | |
if(el.type == LEX_CCLOSE) | |
break; | |
EXPECT(LEX_IDENT); | |
c_type = el.ident_v; | |
if(types.find(c_type) == types.end()) | |
FILE_ERR((c_type + " does not name a valid type").c_str()); | |
NEXT_EL(lines); | |
EXPECT(LEX_WHITESPACE); SKIP(LEX_WHITESPACE); | |
EXPECT(LEX_IDENT); | |
c_name = el.ident_v; | |
NEXT_EL(lines); | |
oss << "\t"; | |
writeFunctionBody(oss, "it->" + c_name, types.find(c_type)->second); | |
SKIP(LEX_WHITESPACE); | |
EXPECT(LEX_SEMIC); | |
NEXT_EL(lines); | |
} | |
oss << "\t}\n"; | |
SKIP(LEX_WHITESPACE); | |
EXPECT(LEX_CCLOSE); | |
NEXT_EL(lines); | |
} else { | |
if(types.find(c_type) == types.end()) | |
FILE_ERR((c_type + " does not name a valid type").c_str()); | |
NEXT_EL(lines); | |
EXPECT(LEX_WHITESPACE); SKIP(LEX_WHITESPACE); | |
EXPECT(LEX_IDENT); | |
c_name = el.ident_v; | |
NEXT_EL(lines); | |
writeFunctionHeaderType(ofs, c_name, types.find(c_type)->second); | |
writeFunctionBody(oss, c_name, types.find(c_type)->second); | |
} | |
SKIP(LEX_WHITESPACE); | |
EXPECT(LEX_SEMIC); | |
if(ll.size() == 0) { | |
writeFunctionHeader2(ofs, c_tag); // Write the remaining tag to file... | |
ofs << oss.str(); | |
writeFunctionFooter(ofs); | |
break; // ...and break | |
} | |
NEXT_EL(lines); | |
if(el.type == LEX_TOPEN) { | |
writeFunctionHeader2(ofs, c_tag); | |
ofs << oss.str(); | |
writeFunctionFooter(ofs); | |
goto newtag; | |
} else | |
goto newcontent; | |
} | |
} | |
int main(int argc, char *argv[]) | |
{ | |
if(argc <= 2) { | |
std::cerr << "Usage: " << argv[0] << " <input> <output>" << std::endl; | |
return 1; | |
} else { | |
std::ifstream ifs; | |
ifs.open(argv[1]); | |
if(!ifs) { | |
std::cerr << "Failed to open input file!" << std::endl; | |
return 1; | |
} | |
std::ofstream ofs; | |
ofs.open(argv[2]); | |
if(!ofs) { | |
std::cerr << "Failed to open output file!" << std::endl; | |
return 1; | |
} | |
writeHeader(ofs); | |
gen_file(lex(ifs, argv[1]), ofs); | |
writeFooter(ofs); | |
ifs.close(); | |
ofs.close(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#test comment | |
#test comment | |
[ TOCLIENT_INIT ] | |
u8 deployed_block_version; | |
v3s16 player_pos; | |
u64 map_seed; | |
f32 recommended_send_interval; | |
# above stuff was only for testing the parser | |
# here's a packet with everything we can use | |
[TOCLIENT_TEST] | |
u64 a; | |
u32 b; | |
u16 c; | |
u8 d; | |
s32 e; | |
s16 f; | |
s8 g; | |
v3s32 h; | |
v3s16 i; | |
v2s32 j; | |
v2s16 k; | |
argb8 this_is_a_color; | |
f32 this_is_a_float; | |
v3f l; | |
v2f m; | |
string n; | |
lstring longstr; | |
jstring jsonstr; | |
wstring widestr; | |
# here's a packet to test lists | |
[TOCLIENT_LISTTEST] | |
#list <name> <type for length> <C++ type> | |
list a u16 SomeListContainer { | |
# the names here are equivalent to the names in the C++ type | |
v3s16 pos; | |
u8 flags; | |
string name; | |
}; | |
u16 general_settings; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment