X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fglsl%2Fparser.cpp;h=d9fdbc4ea998e56d98d2209e6a5d79558511bf34;hb=7b73b63df12b3ace4231842aa291d6e1d7b3f948;hp=5ffc2a9b023f284b2837990e06f7a8533955d5fc;hpb=30465dd3b9f55ec42c4b19c3c2077eede7237a26;p=libs%2Fgl.git diff --git a/source/glsl/parser.cpp b/source/glsl/parser.cpp index 5ffc2a9b..d9fdbc4e 100644 --- a/source/glsl/parser.cpp +++ b/source/glsl/parser.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -57,8 +58,13 @@ void Parser::parse_source(const string &name, unsigned index) source_index = index; 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) @@ -181,11 +187,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 +311,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 +411,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)());