X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fglsl%2Fparser.cpp;h=1f0d712467f3b43c2d9990dfa277bb1c46d0ff42;hb=9ec831710f64a62ad5f2e896a55ae82a3519f29e;hp=5ffc2a9b023f284b2837990e06f7a8533955d5fc;hpb=6288c42adde9ee7d39a47de51fa2856cf965dccc;p=libs%2Fgl.git diff --git a/source/glsl/parser.cpp b/source/glsl/parser.cpp index 5ffc2a9b..1f0d7124 100644 --- a/source/glsl/parser.cpp +++ b/source/glsl/parser.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -28,14 +29,14 @@ Parser::~Parser() delete module; } -Module &Parser::parse(const string &s, const string &n, unsigned i) +Module &Parser::parse(const string &s, const string &n, int i) { source = s; parse_source(n, i); return *module; } -Module &Parser::parse(IO::Base &io, const string &n, unsigned i) +Module &Parser::parse(IO::Base &io, const string &n, int i) { source = string(); while(!io.eof()) @@ -48,17 +49,23 @@ Module &Parser::parse(IO::Base &io, const string &n, unsigned i) return *module; } -void Parser::parse_source(const string &name, unsigned index) +void Parser::parse_source(const string &name, int index) { delete module; module = new Module; cur_stage = &module->shared; base_index = index; source_index = index; - source_reference(1, name); + if(index>=0) + source_reference(1, name); tokenizer.begin(name, source); - while(RefPtr statement = parse_global_declaration()) - cur_stage->content.body.push_back(statement); + allow_stage_change = true; + while(!tokenizer.peek_token().empty()) + if(RefPtr statement = parse_with_recovery(&Parser::parse_global_declaration)) + cur_stage->content.body.push_back(statement); + + if(!errors.empty()) + throw invalid_shader_source(join(errors.begin(), errors.end(), "\n")); } void Parser::set_required_version(const Version &ver) @@ -68,7 +75,7 @@ void Parser::set_required_version(const Version &ver) void Parser::source_reference(unsigned index, const string &name) { - if(index<1) + if(index<1 || base_index<0) throw invalid_shader_source(tokenizer.get_location(), "Invalid source reference"); module->source_map.set_name(base_index+index-1, name); @@ -181,11 +188,54 @@ bool Parser::is_identifier(const string &token) return re.match(token); } +template +RefPtr Parser::parse_with_recovery(RefPtr (Parser::*parse_func)()) +{ + tokenizer.clear_progress_mark(); + try + { + return (this->*parse_func)(); + } + catch(const invalid_shader_source &exc) + { + errors.push_back(exc.what()); + } + + if(tokenizer.get_last_token()!=";" || !tokenizer.get_progress_mark()) + { + unsigned scope_level = 0; + while(1) + { + if(tokenizer.peek_token()=="}" && scope_level==0) + { + if(!tokenizer.get_progress_mark()) + tokenizer.parse_token(); + break; + } + + string token = tokenizer.parse_token(); + if(token=="}") + { + --scope_level; + if(scope_level==0) + break; + } + else if(token=="{") + ++scope_level; + else if(token==";" && scope_level==0) + break; + else if(token.empty()) + break; + } + } + + return RefPtr(); +} + RefPtr Parser::parse_global_declaration() { - allow_stage_change = true; string token = tokenizer.peek_token(); - allow_stage_change = false; + SetFlag disallow(allow_stage_change, false); if(token=="import") return parse_import(); @@ -262,6 +312,11 @@ RefPtr Parser::parse_statement() } else if(is_qualifier(token) || is_type(token)) return parse_variable_declaration(); + else if(token==";") + { + tokenizer.parse_token(); + throw invalid_shader_source(tokenizer.get_location(), "Empty statement not allowed"); + } else if(!token.empty()) { RefPtr expr = new ExpressionStatement; @@ -357,7 +412,8 @@ void Parser::parse_block(Block &block, bool require_braces, RefPtr (Parser::* if(have_braces) { while(tokenizer.peek_token()!="}") - block.body.push_back((this->*parse_content)()); + if(RefPtr node = parse_with_recovery(parse_content)) + block.body.push_back(node); } else block.body.push_back((this->*parse_content)());