X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fglsl%2Fparser.cpp;h=d9fdbc4ea998e56d98d2209e6a5d79558511bf34;hb=3f899b1fc2e04f4fe74c99ad3e8ebb900c257214;hp=ec6ce6eb5e28bb060050e25121196e3e262a8f4d;hpb=c0be4e4ae1a8b6ac31ff6b7080e2242c13d947ff;p=libs%2Fgl.git diff --git a/source/glsl/parser.cpp b/source/glsl/parser.cpp index ec6ce6eb..d9fdbc4e 100644 --- a/source/glsl/parser.cpp +++ b/source/glsl/parser.cpp @@ -1,5 +1,7 @@ +#include #include #include +#include #include "glsl_error.h" #include "parser.h" @@ -56,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) @@ -118,6 +125,14 @@ string Parser::expect_identifier() return token; } +int Parser::expect_integer() +{ + string token = tokenizer.parse_token(); + if(!isnumrc(token)) + throw parse_error(tokenizer.get_location(), token, "an integer literal"); + return lexical_cast(token); +} + bool Parser::check(const string &token) { bool result = (tokenizer.peek_token()==token); @@ -172,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(); @@ -253,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; @@ -315,10 +378,18 @@ RefPtr Parser::parse_layout() layout->qualifiers.push_back(Layout::Qualifier()); Layout::Qualifier &qual = layout->qualifiers.back(); - qual.identifier = token; + qual.name = token; - if(check("=")) - qual.value = tokenizer.parse_token(); + if((qual.has_value = check("="))) + { + if(qual.name=="constant_id" && tokenizer.peek_token()=="auto") + { + qual.value = -1; + tokenizer.parse_token(); + } + else + qual.value = expect_integer(); + } if(tokenizer.peek_token()==")") break; @@ -330,7 +401,8 @@ RefPtr Parser::parse_layout() return layout; } -void Parser::parse_block(Block &block, bool require_braces) +template +void Parser::parse_block(Block &block, bool require_braces, RefPtr (Parser::*parse_content)()) { bool have_braces = (require_braces || tokenizer.peek_token()=="{"); if(have_braces) @@ -339,10 +411,11 @@ void Parser::parse_block(Block &block, bool require_braces) if(have_braces) { while(tokenizer.peek_token()!="}") - block.body.push_back(parse_statement()); + if(RefPtr node = parse_with_recovery(parse_content)) + block.body.push_back(node); } else - block.body.push_back(parse_statement()); + block.body.push_back((this->*parse_content)()); block.use_braces = (require_braces || block.body.size()!=1); @@ -477,7 +550,7 @@ RefPtr Parser::parse_struct_declaration() strct->line = tokenizer.get_location().line; strct->name = expect_identifier(); - parse_block(strct->members, true); + parse_block(strct->members, true, &Parser::parse_variable_declaration); tokenizer.expect(";"); declared_types.insert(strct->name); @@ -527,6 +600,18 @@ RefPtr Parser::parse_variable_declaration() return var; } +RefPtr Parser::parse_variable_declaration_with_layout() +{ + RefPtr layout; + if(tokenizer.peek_token()=="layout") + layout = parse_layout(); + + RefPtr var = parse_variable_declaration(); + var->layout = layout; + + return var; +} + RefPtr Parser::parse_function_declaration() { RefPtr func = new FunctionDeclaration; @@ -555,7 +640,7 @@ RefPtr Parser::parse_function_declaration() if(token=="{") { func->definition = func.get(); - parse_block(func->body, true); + parse_block(func->body, true, &Parser::parse_statement); } else if(token==";") tokenizer.parse_token(); @@ -576,7 +661,7 @@ RefPtr Parser::parse_interface_block() throw parse_error(tokenizer.get_location(), iface->interface, "an interface qualifier"); iface->name = expect_identifier(); - parse_block(iface->members, true); + parse_block(iface->members, true, &Parser::parse_variable_declaration_with_layout); if(!check(";")) { iface->instance_name = expect_identifier(); @@ -601,13 +686,13 @@ RefPtr Parser::parse_conditional() cond->condition = parse_expression(); tokenizer.expect(")"); - parse_block(cond->body, false); + parse_block(cond->body, false, &Parser::parse_statement); string token = tokenizer.peek_token(); if(token=="else") { tokenizer.parse_token(); - parse_block(cond->else_body, false); + parse_block(cond->else_body, false, &Parser::parse_statement); } return cond; @@ -640,7 +725,7 @@ RefPtr Parser::parse_for() loop->loop_expression = parse_expression(); tokenizer.expect(")"); - parse_block(loop->body, false); + parse_block(loop->body, false, &Parser::parse_statement); return loop; } @@ -655,7 +740,7 @@ RefPtr Parser::parse_while() loop->condition = parse_expression(); tokenizer.expect(")"); - parse_block(loop->body, false); + parse_block(loop->body, false, &Parser::parse_statement); return loop; }