X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fprogramparser.cpp;h=3b87ea7b58b1a2a16c1a09d3cd6432c53009d73f;hp=c3049dd3649bc5b2d3360b5afa7a4c571787d45c;hb=f141ae14619bfbd51a7e6871c55edbdd17ac3417;hpb=eb6a546dcffc1b67f0a23d8b075fbdc86a2872a0 diff --git a/source/programparser.cpp b/source/programparser.cpp index c3049dd3..3b87ea7b 100644 --- a/source/programparser.cpp +++ b/source/programparser.cpp @@ -1,3 +1,4 @@ +#include #include #include #include "programparser.h" @@ -91,35 +92,26 @@ Module &ProgramParser::parse(IO::Base &io, const string &n) void ProgramParser::parse_source() { - delete module; - module = new Module; - cur_stage = &module->shared; - iter = source.begin(); - current_line = 1; while(1) { - while(RefPtr statement = parse_global_declaration()) - cur_stage->content.body.push_back(statement); - - parse_token(); - string token = parse_token(); - if(token.empty()) + string::size_type slashes = source.find("//////"); + if(slashes==string::npos) break; - else if(token=="vertex") - module->stages.push_back(VERTEX); - else if(token=="geometry") - module->stages.push_back(GEOMETRY); - else if(token=="fragment") - module->stages.push_back(FRAGMENT); - else - throw runtime_error(format("Parse error at '%s': expected stage identifier", token)); - if(cur_stage->type!=SHARED) - module->stages.back().previous = cur_stage; - cur_stage = &module->stages.back(); - - for(; (iter!=source.end() && *iter!='\n'); ++iter) ; + string::size_type newline = source.find('\n', slashes); + string pragma = format("#pragma MSP stage(%s)", source.substr(slashes+6, newline-slashes-6)); + source.replace(slashes, newline-slashes, pragma); } + + delete module; + module = new Module; + cur_stage = &module->shared; + iter = source.begin(); + source_end = source.end(); + current_line = 1; + allow_preprocess = true; + while(RefPtr statement = parse_global_declaration()) + cur_stage->content.body.push_back(statement); } string ProgramParser::format_error(const std::string &message) @@ -154,21 +146,30 @@ const string &ProgramParser::parse_token() string ProgramParser::parse_token_() { - if(!skip_comment_and_whitespace()) - return string(); - - if(isalpha(*iter) || *iter=='_') - return parse_identifier(); - else if(isdigit(*iter)) - return parse_number(); - else - return parse_other(); + while(1) + { + skip_comment_and_whitespace(); + if(iter==source_end) + return string(); + else if(allow_preprocess && *iter=='#') + { + allow_preprocess = false; + SetForScope > clear_tokens(next_tokens, deque()); + preprocess(); + } + else if(isalpha(*iter) || *iter=='_') + return parse_identifier(); + else if(isdigit(*iter)) + return parse_number(); + else + return parse_other(); + } } string ProgramParser::parse_identifier() { string ident; - while(iter!=source.end()) + while(iter!=source_end) { if(isalnum(*iter) || *iter=='_') ident += *iter++; @@ -183,7 +184,7 @@ string ProgramParser::parse_number() { bool accept_sign = false; string number; - while(iter!=source.end()) + while(iter!=source_end) { if(isdigit(*iter) || *iter=='.') number += *iter++; @@ -203,11 +204,11 @@ string ProgramParser::parse_number() string ProgramParser::parse_other() { - if(iter==source.end()) + if(iter==source_end) return string(); string token(1, *iter++); - for(unsigned i=1; (i<3 && iter!=source.end()); ++i) + for(unsigned i=1; (i<3 && iter!=source_end); ++i) { bool matched = false; for(const Operator *j=operators; (!matched && j->type); ++j) @@ -226,11 +227,10 @@ string ProgramParser::parse_other() return token; } -bool ProgramParser::skip_comment_and_whitespace() +void ProgramParser::skip_comment_and_whitespace() { unsigned comment = 0; - unsigned slashes = 0; - while(iter!=source.end()) + while(iter!=source_end) { if(comment==0) { @@ -242,10 +242,7 @@ bool ProgramParser::skip_comment_and_whitespace() else if(comment==1) { if(*iter=='/') - { comment = 2; - slashes = 2; - } else if(*iter=='*') comment = 3; else @@ -259,10 +256,6 @@ bool ProgramParser::skip_comment_and_whitespace() { if(*iter=='\n') comment = 0; - else if(*iter=='/') - ++slashes; - else if(!isspace(*iter) && slashes>=6) - return false; } else if(comment==3 && *iter=='*') comment = 4; @@ -270,17 +263,18 @@ bool ProgramParser::skip_comment_and_whitespace() { if(*iter=='/') comment = 0; - else + else if(*iter!='*') comment = 3; } if(*iter=='\n') + { ++current_line; + allow_preprocess = (comment<3); + } ++iter; } - - return iter!=source.end(); } void ProgramParser::expect(const string &token) @@ -321,7 +315,12 @@ bool ProgramParser::is_interface_qualifier(const string &token) bool ProgramParser::is_sampling_qualifier(const string &token) { - return token=="centroid"; + return (token=="centroid" || token=="sample"); +} + +bool ProgramParser::is_interpolation_qualifier(const string &token) +{ + return (token=="smooth" || token=="flat" || token=="noperspective"); } bool ProgramParser::is_precision_qualifier(const string &token) @@ -331,7 +330,11 @@ bool ProgramParser::is_precision_qualifier(const string &token) bool ProgramParser::is_qualifier(const string &token) { - return (token=="const" || is_interface_qualifier(token) || is_sampling_qualifier(token) || is_precision_qualifier(token)); + return (token=="const" || + is_interface_qualifier(token) || + is_sampling_qualifier(token) || + is_interpolation_qualifier(token) || + is_precision_qualifier(token)); } bool ProgramParser::is_builtin_type(const string &token) @@ -351,9 +354,82 @@ bool ProgramParser::is_identifier(const string &token) return re.match(token); } +void ProgramParser::preprocess() +{ + expect("#"); + + string::const_iterator line_end = iter; + for(; (line_end!=source_end && *line_end!='\n'); ++line_end) ; + SetForScope stop_at_line_end(source_end, line_end); + + string token = peek_token(); + if(token=="pragma") + preprocess_pragma(); + else if(token=="define" || token=="undef" || token=="if" || token=="ifdef" || token=="ifndef" || token=="else" || + token=="elif" || token=="endif" || token=="error" || token=="extension" || token=="version" || token=="line") + throw runtime_error(format_error(format("Unsupported preprocessor directive '%s'", token))); + else if(!token.empty()) + throw runtime_error(format_syntax_error("a preprocessor directive")); + + iter = line_end; +} + +void ProgramParser::preprocess_pragma() +{ + expect("pragma"); + string token = parse_token(); + if(token=="MSP") + preprocess_pragma_msp(); +} + +void ProgramParser::preprocess_pragma_msp() +{ + string token = peek_token(); + if(token=="stage") + preprocess_stage(); + else + throw runtime_error(format_error(format("Unrecognized MSP pragma '%s'", token))); + + token = parse_token(); + if(!token.empty()) + throw runtime_error(format_syntax_error("end of line")); +} + +void ProgramParser::preprocess_stage() +{ + if(!allow_stage_change) + throw runtime_error(format_error("Changing stage not allowed here")); + + expect("stage"); + expect("("); + string token = expect_identifier(); + StageType stage = SHARED; + if(token=="vertex") + stage = VERTEX; + else if(token=="geometry") + stage = GEOMETRY; + else if(token=="fragment") + stage = FRAGMENT; + else + throw runtime_error(format_syntax_error("stage identifier")); + expect(")"); + + if(stage<=cur_stage->type) + throw runtime_error(format_error(format("Stage '%s' not allowed here", token))); + + module->stages.push_back(stage); + + if(cur_stage->type!=SHARED) + module->stages.back().previous = cur_stage; + cur_stage = &module->stages.back(); +} + RefPtr ProgramParser::parse_global_declaration() { + allow_stage_change = true; string token = peek_token(); + allow_stage_change = false; + if(token=="import") return parse_import(); else if(token=="precision") @@ -382,7 +458,7 @@ RefPtr ProgramParser::parse_global_declaration() else if(is_interface_qualifier(token)) { string next = peek_token(1); - if(is_type(next) || is_precision_qualifier(next)) + if(is_type(next) || is_qualifier(next)) return parse_variable_declaration(); else return parse_interface_block(); @@ -651,25 +727,22 @@ RefPtr ProgramParser::parse_variable_declaration() RefPtr var = new VariableDeclaration; string token = peek_token(); - if(is_sampling_qualifier(token)) - { - var->sampling = parse_token(); - token = peek_token(); - if(!is_interface_qualifier(token)) - throw runtime_error(format_syntax_error("an interface qualifier")); - } - - if(is_interface_qualifier(token)) - var->interface = parse_token(); - else if(token=="const") + while(is_qualifier(token)) { - var->constant = true; parse_token(); + if(is_interface_qualifier(token)) + var->interface = token; + else if(is_sampling_qualifier(token)) + var->sampling = token; + else if(is_interpolation_qualifier(token)) + var->interpolation = token; + else if(is_precision_qualifier(token)) + var->precision = token; + else if(token=="const") + var->constant = true; + token = peek_token(); } - if(is_precision_qualifier(token)) - var->precision = parse_token(); - var->type = expect_type(); var->name = expect_identifier(); @@ -703,6 +776,9 @@ RefPtr ProgramParser::parse_function_declaration() expect(","); RefPtr var = new VariableDeclaration; + string token = peek_token(); + if(token=="in" || token=="out" || token=="inout") + var->interface = parse_token(); var->type = expect_type(); var->name = expect_identifier(); func->parameters.push_back(var);