From: Mikko Rasa Date: Sat, 20 Feb 2021 12:59:44 +0000 (+0200) Subject: Recognize the #line directive in the GLSL parser X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=1083ad1;p=libs%2Fgl.git Recognize the #line directive in the GLSL parser Also add a new pragma to specify source names. --- diff --git a/source/glsl/parser.cpp b/source/glsl/parser.cpp index eee62129..7044a8c3 100644 --- a/source/glsl/parser.cpp +++ b/source/glsl/parser.cpp @@ -17,7 +17,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() @@ -50,8 +52,9 @@ void Parser::parse_source(const string &name, unsigned index) delete module; module = new Module; cur_stage = &module->shared; + base_index = index; source_index = index; - module->source_map.set_name(source_index, name); + source_reference(1, name); tokenizer.begin(name, source); while(RefPtr statement = parse_global_declaration()) cur_stage->content.body.push_back(statement); @@ -62,6 +65,14 @@ void Parser::set_required_version(const Version &ver) cur_stage->required_version = ver; } +void Parser::source_reference(unsigned index, const string &name) +{ + if(index<1) + 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) { if(!allow_stage_change) @@ -76,6 +87,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(); diff --git a/source/glsl/parser.h b/source/glsl/parser.h index 58b14b50..cdb57ebc 100644 --- a/source/glsl/parser.h +++ b/source/glsl/parser.h @@ -16,6 +16,7 @@ class Parser { private: std::string source; + unsigned base_index; unsigned source_index; Tokenizer tokenizer; Preprocessor preprocessor; @@ -34,7 +35,9 @@ public: private: void parse_source(const std::string &, unsigned); void set_required_version(const Version &); + void source_reference(unsigned, const std::string &); void stage_change(Stage::Type); + void line_change(int, unsigned); std::string expect_type(); std::string expect_identifier(); diff --git a/source/glsl/preprocessor.cpp b/source/glsl/preprocessor.cpp index 354b2a7a..ea6dd6de 100644 --- a/source/glsl/preprocessor.cpp +++ b/source/glsl/preprocessor.cpp @@ -1,3 +1,4 @@ +#include #include "glsl_error.h" #include "preprocessor.h" #include "tokenizer.h" @@ -19,8 +20,10 @@ void Preprocessor::preprocess() preprocess_pragma(); else if(token=="version") preprocess_version(); + else if(token=="line") + preprocess_line(); else if(token=="define" || token=="undef" || token=="if" || token=="ifdef" || token=="ifndef" || token=="else" || - token=="elif" || token=="endif" || token=="error" || token=="extension" || token=="line") + token=="elif" || token=="endif" || token=="error" || token=="extension") throw invalid_shader_source(tokenizer.get_location(), "Unsupported preprocessor directive '%s'", token); else if(!token.empty()) throw parse_error(tokenizer.get_location(), token, "a preprocessor directive"); @@ -38,6 +41,23 @@ void Preprocessor::preprocess_version() throw parse_error(tokenizer.get_location(), token, "end of line"); } +void Preprocessor::preprocess_line() +{ + tokenizer.expect("line"); + unsigned line_number = lexical_cast(tokenizer.parse_token()); + + int source_index = -1; + string token = tokenizer.parse_token(); + if(!token.empty()) + source_index = lexical_cast(token); + + token = tokenizer.parse_token(); + if(!token.empty()) + throw parse_error(tokenizer.get_location(), token, "end of line"); + + signal_line.emit(source_index, line_number); +} + void Preprocessor::preprocess_pragma() { tokenizer.expect("pragma"); @@ -51,6 +71,8 @@ void Preprocessor::preprocess_pragma_msp() string token = tokenizer.peek_token(); if(token=="stage") preprocess_stage(); + else if(token=="source") + preprocess_source(); else throw invalid_shader_source(tokenizer.get_location(), "Unrecognized MSP pragma '%s'", token); @@ -78,6 +100,21 @@ void Preprocessor::preprocess_stage() signal_stage_change.emit(stage); } +void Preprocessor::preprocess_source() +{ + tokenizer.expect("source"); + tokenizer.expect("("); + unsigned source_index = lexical_cast(tokenizer.parse_token()); + tokenizer.expect(","); + string filename = tokenizer.parse_token(); + if(filename[0]!='"') + throw parse_error(tokenizer.get_location(), filename, "a string literal"); + filename = c_unescape(filename.substr(1, filename.size()-2)); + tokenizer.expect(")"); + + signal_source.emit(source_index, filename); +} + } // namespace SL } // namespace GL } // namespace Msp diff --git a/source/glsl/preprocessor.h b/source/glsl/preprocessor.h index d812a3fa..5f6430c7 100644 --- a/source/glsl/preprocessor.h +++ b/source/glsl/preprocessor.h @@ -14,7 +14,9 @@ class Preprocessor { public: sigc::signal signal_version; + sigc::signal signal_source; sigc::signal signal_stage_change; + sigc::signal signal_line; private: Tokenizer &tokenizer; @@ -25,9 +27,11 @@ public: void preprocess(); private: void preprocess_version(); + void preprocess_line(); void preprocess_pragma(); void preprocess_pragma_msp(); void preprocess_stage(); + void preprocess_source(); }; } // namespace SL diff --git a/source/glsl/sourcemap.cpp b/source/glsl/sourcemap.cpp index e74f1b67..9b341fe4 100644 --- a/source/glsl/sourcemap.cpp +++ b/source/glsl/sourcemap.cpp @@ -29,6 +29,16 @@ void SourceMap::set_name(unsigned i, const std::string &n) source_names[i] = n; } +const string &SourceMap::get_name(unsigned i) const +{ + i -= base_index; + if(i next_tokens; @@ -37,12 +41,14 @@ public: const std::string &peek_token(unsigned = 0); const std::string &parse_token(); void expect(const std::string &); + void set_location(const Location &); const Location &get_location() const { return location; } private: std::string parse_token_(); void preprocess(); std::string parse_identifier(); std::string parse_number(); + std::string parse_string(); std::string parse_other(); void skip_comment_and_whitespace(); };