X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fglsl%2Fparser.cpp;h=b09d2b5550b47c321fba2a69feedc4d7c36f0293;hb=e195322eb1251f2eb0d6dfb8c2dc0fff02e5fcfc;hp=4b6bd7ed08992271f5ba73318a253b8a4ec2d6ab;hpb=ffdb126a55467245da08a9e6f5669f86e1899bb0;p=libs%2Fgl.git diff --git a/source/glsl/parser.cpp b/source/glsl/parser.cpp index 4b6bd7ed..b09d2b55 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); - tokenizer.begin(name, source); - while(RefPtr statement = parse_global_declaration()) - cur_stage->content.body.push_back(statement); + if(index>=0) + source_reference(1, name); + tokenizer.begin(source, name); + 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; @@ -327,7 +382,15 @@ RefPtr Parser::parse_layout() qual.name = token; if((qual.has_value = check("="))) - qual.value = expect_integer(); + { + 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; @@ -339,7 +402,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) @@ -348,10 +412,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); @@ -391,6 +456,7 @@ RefPtr Parser::parse_expression(unsigned precedence) { RefPtr memacc = new MemberAccess; memacc->left = left; + memacc->oper = oper; tokenizer.parse_token(); memacc->member = expect_identifier(); left = memacc; @@ -398,13 +464,13 @@ RefPtr Parser::parse_expression(unsigned precedence) else if(oper && oper->type==Operator::POSTFIX) { RefPtr unary = new UnaryExpression; - unary->oper = tokenizer.parse_token(); - unary->prefix = false; + unary->oper = oper; + tokenizer.parse_token(); unary->expression = left; left = unary; } else if(oper && oper->type==Operator::BINARY) - left = parse_binary(left, oper); + left = parse_binary(left, *oper); else throw parse_error(tokenizer.get_location(), token, "an operator"); left_var = 0; @@ -435,8 +501,8 @@ RefPtr Parser::parse_expression(unsigned precedence) else if(oper && oper->type==Operator::PREFIX) { RefPtr unary = new UnaryExpression; - unary->oper = tokenizer.parse_token(); - unary->prefix = true; + unary->oper = oper; + tokenizer.parse_token(); unary->expression = parse_expression(oper->precedence); left = unary; } @@ -446,19 +512,19 @@ RefPtr Parser::parse_expression(unsigned precedence) } } -RefPtr Parser::parse_binary(const RefPtr &left, const Operator *oper) +RefPtr Parser::parse_binary(const RefPtr &left, const Operator &oper) { - RefPtr binary = (oper->precedence==16 ? new Assignment : new BinaryExpression); + RefPtr binary = (oper.precedence==16 ? new Assignment : new BinaryExpression); binary->left = left; - binary->oper = tokenizer.parse_token(); - if(binary->oper=="[") + binary->oper = &oper; + tokenizer.expect(oper.token); + if(oper.token[0]=='[') { binary->right = parse_expression(); tokenizer.expect("]"); - binary->after = "]"; } else - binary->right = parse_expression(oper->precedence+(oper->assoc==Operator::RIGHT_TO_LEFT)); + binary->right = parse_expression(oper.precedence+(oper.assoc==Operator::RIGHT_TO_LEFT)); return binary; } @@ -467,6 +533,7 @@ RefPtr Parser::parse_function_call(const VariableReference &var) RefPtr call = new FunctionCall; call->name = var.name; call->constructor = is_type(call->name); + call->oper = &Operator::get_operator("(", Operator::POSTFIX); tokenizer.expect("("); while(tokenizer.peek_token()!=")") { @@ -486,7 +553,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); @@ -536,6 +603,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; @@ -564,7 +643,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(); @@ -585,7 +664,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(); @@ -610,13 +689,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; @@ -649,7 +728,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; } @@ -664,7 +743,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; }