#include #include #include #include int main(int argc, const char** argv) { unsigned i; const char* slang_fn = NULL; const char* vs_asm_fn = NULL; const char* ps_asm_fn = NULL; const char* vs_out_fn = NULL; const char* ps_out_fn = NULL; bool verbose = false; for (i = 1; i < argc - 1; i++) { if(!strcmp(argv[i], "--slang")) slang_fn = argv[++i]; else if(!strcmp(argv[i], "--vsource")) vs_asm_fn = argv[++i]; else if(!strcmp(argv[i], "--psource")) ps_asm_fn = argv[++i]; else if(!strcmp(argv[i], "--vsh")) vs_out_fn = argv[++i]; else if(!strcmp(argv[i], "--psh")) ps_out_fn = argv[++i]; else if(!strcmp(argv[i], "--verbose")) verbose = true; } if(!slang_fn || !vs_out_fn || !ps_out_fn || (!vs_asm_fn && ps_asm_fn) || (vs_asm_fn && !ps_asm_fn)) { printf("Usage :\n"); printf("%s --slang --vsh --psh \n", argv[0]); printf("%s --slang --vsource --psource --vsh --psh \n", argv[0]); } std::string slang; { std::ifstream fs(slang_fn); std::stringstream ss; ss << fs.rdbuf(); slang = ss.str(); } std::string slang_grammar; { std::ifstream fs("grammar.txt"); std::stringstream ss; ss << fs.rdbuf(); slang_grammar = ss.str(); } peg::parser parser; parser.log = [&](size_t ln, size_t col, const std::string &msg) { std::cout << "Error parsing grammar:" << ln << ":" << col << ": " << msg << std::endl; }; if (!parser.load_grammar(slang_grammar.c_str())) { std::cout << "Failed to load grammar" << std::endl; return 1; } parser.log = [&](size_t ln, size_t col, const std::string &msg) { std::cout << slang_fn << ":" << ln << ":" << col << ": " << msg << std::endl; }; parser.enable_ast(); std::shared_ptr ast; if (!parser.parse_n(slang.c_str(), slang.size(), ast)) { std::cout << "Error parsing slang file: " << slang_fn << std::endl; return 1; } ast = peg::AstOptimizer(false).optimize(ast); if(verbose) std::cout << peg::ast_to_s(ast) << std::flush; if (ast->name != "Program") { std::cout << "Expected root node to be Program, not" << ast->name << std::endl; return 1; } std::stringstream common; std::stringstream vs; std::stringstream ps; std::stringstream* out = &common; common << "#version 150\n"; common << "#define float2 vec2\n"; common << "#define float3 vec3\n"; common << "#define float4 vec4\n"; for (std::shared_ptr &node : ast->nodes) { if (node->name == "Version") { /* do nothing */ } else if (node->name == "UniformBlock") { int location = 0; int binding = 0; int set = 0; int std_val = 0; bool push_constant = false; std::string struct_name; std::string name; struct member_type { std::string type; std::string name; }; std::vector members; for (std::shared_ptr &child : node->nodes) { if (child->name == "Layout") { for (std::shared_ptr &layout : child->nodes) { if (layout->name == "PushConstant") push_constant = true; else if (layout->name == "Location") location = std::stoul(layout->token); else if (layout->name == "Binding") binding = std::stoul(layout->token); else if (layout->name == "Set") set = std::stoul(layout->token); else if (layout->name == "Std") std_val = std::stoul(layout->token); } } else if (child->name == "StructName") struct_name = child->token; else if (child->name == "Name") name = child->token; else if (child->name == "Member") { member_type new_member; for (std::shared_ptr &member : child->nodes) { if (member->name == "Type") new_member.type = member->token; else if (member->name == "Name") new_member.name = member->token; } members.push_back(new_member); } } #if 0 *out << "layout(location = " << (push_constant? "1" : "0"); if(std_val) *out << ", std" << std_val; *out << ") "; #else if(std_val) *out << "layout(std" << std_val << ") "; #endif *out << "uniform " << struct_name << "\n{\n"; for (member_type &member : members) *out << " " << member.type << " " << member.name << ";\n"; *out << "}" << name << ";"; } else if (node->name == "Declaration") { int location = 0; int binding = 0; int set = 0; std::string qualifier; std::string type; std::string name; int array_size = 0; bool has_layout = false; for (std::shared_ptr &child : node->nodes) { if (child->name == "Layout") { has_layout = true; for (std::shared_ptr &layout : child->nodes) { if (layout->name == "Location") location = std::stoul(layout->token); else if (layout->name == "Binding") binding = std::stoul(layout->token); else if (layout->name == "Set") set = std::stoul(layout->token); } } else if (child->name == "Qualifier") qualifier = child->token; else if (child->name == "Type") type = child->token; else if (child->name == "Name") name = child->token; else if (child->name == "ArraySize") array_size = std::stoul(child->token); } if(has_layout && type != "sampler2D") *out << "layout(location = " << location << ") "; *out << qualifier << " " << type << " " << name; if(array_size) *out << "[" << array_size << "]"; *out << ";"; } else if (node->name == "ConstArray") { std::string type; std::string name; int array_size = 0; std::vector>* array; for (std::shared_ptr &child : node->nodes) { if (child->name == "Type") type = child->token; else if (child->name == "Name") name = child->token; else if (child->name == "ArraySize") array_size = std::stoul(child->token); else if (child->name == "Array") array = &child->nodes; } *out << type << " " << name; if(array_size) *out << "[" << array_size << "]"; *out << " = " << type; if(array_size) *out << "[" << array_size << "]"; *out << "("; for (std::shared_ptr &item : *array) { if(array_size) *out << type << "("; *out << item->token; if(array_size) *out << ")"; if(item != array->back()) *out << ", "; } *out << ");"; } else if (node->name == "Stage") { std::string stage = node->token; std::transform(stage.begin(), stage.end(), stage.begin(), ::toupper); if(stage == "VERTEX") out = &vs; else out = &ps; } else if (node->name == "Indent") *out << node->token; else if (node->name == "Line") *out << node->token << std::endl; else std::cout << "Unexcpected node " << node->name << std::endl; } { std::ofstream fs(vs_out_fn); fs << common.str(); fs << vs.str(); } { std::ofstream fs(ps_out_fn); fs << common.str(); fs << ps.str(); } return 0; }