X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fglsl%2Fparser.cpp;h=c6f3f5be3cdd186818cbee6322ad966dff46181d;hb=19a24f859cd7fcf581442319499ae24b3e7385a4;hp=60cc3516b0750db9f131e8a665b135c89d7dab7b;hpb=af00eefb3f7da48ec4038357035980c31cbcb685;p=libs%2Fgl.git diff --git a/source/glsl/parser.cpp b/source/glsl/parser.cpp index 60cc3516..c6f3f5be 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" @@ -17,7 +19,9 @@ Parser::Parser(): { tokenizer.signal_preprocess.connect(sigc::mem_fun(&preprocessor, &Preprocessor::preprocess)); preprocessor.signal_version.connect(sigc::mem_fun(this, &Parser::set_required_version)); + preprocessor.signal_source.connect(sigc::mem_fun(this, &Parser::source_reference)); preprocessor.signal_stage_change.connect(sigc::mem_fun(this, &Parser::stage_change)); + preprocessor.signal_line.connect(sigc::mem_fun(this, &Parser::line_change)); } Parser::~Parser() @@ -25,41 +29,56 @@ 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; - source_index = i; - parse_source(n); + 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(); - source_index = i; while(!io.eof()) { char buffer[4096]; unsigned len = io.read(buffer, sizeof(buffer)); source.append(buffer, len); } - parse_source(n); + parse_source(n, i); return *module; } -void Parser::parse_source(const string &name) +void Parser::parse_source(const string &name, int index) { delete module; module = new Module; cur_stage = &module->shared; + base_index = index; + source_index = index; + 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) { - cur_stage->required_version = ver; + cur_stage->required_features.glsl_version = ver; +} + +void Parser::source_reference(unsigned index, const string &name) +{ + 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); } void Parser::stage_change(Stage::Type stage) @@ -76,6 +95,21 @@ void Parser::stage_change(Stage::Type stage) cur_stage = &module->stages.back(); } +void Parser::line_change(int index, unsigned line) +{ + if(index>0) + source_index = base_index+index-1; + else if(index==0) + source_index = 0; + else + index = source_index; + + string name = module->source_map.get_name(index); + if(name.empty()) + name = format("<%d>", index); + tokenizer.set_location(Location(name, line)); +} + string Parser::expect_type() { string token = tokenizer.parse_token(); @@ -92,6 +126,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); @@ -146,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(); @@ -227,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; @@ -289,10 +379,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; @@ -304,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) @@ -313,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); @@ -356,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; @@ -363,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; @@ -400,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; } @@ -411,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; } @@ -432,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()!=")") { @@ -451,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); @@ -501,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; @@ -529,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(); @@ -550,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(); @@ -575,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; @@ -614,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; } @@ -629,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; }