From: Mikko Rasa Date: Sun, 14 Feb 2021 17:56:15 +0000 (+0200) Subject: Follow the GLSL syntax rules more closely X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=c1ec86d6b9ceb6c71f787fed3b2ea6c75457a474;p=libs%2Fgl.git Follow the GLSL syntax rules more closely Fix a bug which allowed preprocessor directives anywhere on a line, reject characters which are not allowed in GLSL, and parse numeric literals more robustly. --- diff --git a/source/glsl/glsl_error.cpp b/source/glsl/glsl_error.cpp index ea8e9306..aff897ca 100644 --- a/source/glsl/glsl_error.cpp +++ b/source/glsl/glsl_error.cpp @@ -11,6 +11,10 @@ invalid_shader_source::invalid_shader_source(const Location &loc, const string & runtime_error(format("%s:%d: %s", loc.name, loc.line, message)) { } +syntax_error::syntax_error(const Location &loc, const string &token, const string &message): + invalid_shader_source(loc, "Syntax error near '%s': %s", token, message) +{ } + parse_error::parse_error(const Location &loc, const string &token, const string &expected): invalid_shader_source(loc, "Parse error at '%s': expected %s", token, expected) { } diff --git a/source/glsl/glsl_error.h b/source/glsl/glsl_error.h index 63c49bbd..1ae521ca 100644 --- a/source/glsl/glsl_error.h +++ b/source/glsl/glsl_error.h @@ -23,6 +23,13 @@ public: virtual ~invalid_shader_source() throw() { } }; +class syntax_error: public invalid_shader_source +{ +public: + syntax_error(const Location &, const std::string &, const std::string &); + virtual ~syntax_error() throw() { } +}; + class parse_error: public invalid_shader_source { public: diff --git a/source/glsl/preprocessor.cpp b/source/glsl/preprocessor.cpp index 3c190221..bf2d4b4d 100644 --- a/source/glsl/preprocessor.cpp +++ b/source/glsl/preprocessor.cpp @@ -14,8 +14,6 @@ Preprocessor::Preprocessor(Tokenizer &t): void Preprocessor::preprocess() { - tokenizer.expect("#"); - string token = tokenizer.peek_token(); if(token=="pragma") preprocess_pragma(); diff --git a/source/glsl/tokenizer.cpp b/source/glsl/tokenizer.cpp index be432143..e73afd52 100644 --- a/source/glsl/tokenizer.cpp +++ b/source/glsl/tokenizer.cpp @@ -61,17 +61,21 @@ string Tokenizer::parse_token_() while(1) { skip_comment_and_whitespace(); + bool allow_preproc = allow_preprocess; + allow_preprocess = false; if(iter==source_end) return string(); - else if(allow_preprocess && *iter=='#') + else if(allow_preproc && *iter=='#') { - allow_preprocess = false; + ++iter; preprocess(); } else if(isalpha(*iter) || *iter=='_') return parse_identifier(); else if(isdigit(*iter)) return parse_number(); + else if(*iter=='"' || *iter=='#' || *iter=='$' || *iter=='\'' || *iter=='@' || *iter=='\\' || *iter=='`') + throw syntax_error(location, string(1, *iter), "Invalid character in source"); else return parse_other(); } @@ -106,23 +110,45 @@ string Tokenizer::parse_identifier() string Tokenizer::parse_number() { - bool accept_sign = false; + bool got_fract = false; string number; while(iter!=source_end) { - if(isdigit(*iter) || *iter=='.') + if(isdigit(*iter)) number += *iter++; - else if(*iter=='e' || *iter=='E') + else if(!got_fract && *iter=='.') { number += *iter++; - accept_sign = true; + got_fract = true; } - else if(accept_sign && (*iter=='+' || *iter=='-')) - number += *iter++; else break; } + bool require_digit = false; + if(iter!=source_end && (*iter=='e' || *iter=='E')) + { + number += *iter++; + if(iter!=source_end && (*iter=='-' || *iter=='+')) + number += *iter++; + require_digit = true; + while(iter!=source_end) + { + if(isdigit(*iter)) + { + number += *iter++; + require_digit = false; + } + else + break; + } + } + + if(require_digit) + throw syntax_error(location, number, "Incomplete numeric literal"); + else if(isalnum(*iter) || *iter=='_') + throw syntax_error(location, number, "Garbage at end of numeric literal"); + return number; }