X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fprogramparser.cpp;h=f38f39097615c94185c0d4bf7504d70e0dc7d646;hp=c3049dd3649bc5b2d3360b5afa7a4c571787d45c;hb=bfeb6c6404659fffb1222e084b0bd08cccb4e67d;hpb=eb6a546dcffc1b67f0a23d8b075fbdc86a2872a0 diff --git a/source/programparser.cpp b/source/programparser.cpp index c3049dd3..f38f3909 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; @@ -275,12 +268,13 @@ bool ProgramParser::skip_comment_and_whitespace() } if(*iter=='\n') + { ++current_line; + allow_preprocess = (comment<3); + } ++iter; } - - return iter!=source.end(); } void ProgramParser::expect(const string &token) @@ -351,9 +345,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") @@ -703,6 +770,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);