]> git.tdb.fi Git - libs/gl.git/commitdiff
Follow the GLSL syntax rules more closely
authorMikko Rasa <tdb@tdb.fi>
Sun, 14 Feb 2021 17:56:15 +0000 (19:56 +0200)
committerMikko Rasa <tdb@tdb.fi>
Sun, 14 Feb 2021 17:56:15 +0000 (19:56 +0200)
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.

source/glsl/glsl_error.cpp
source/glsl/glsl_error.h
source/glsl/preprocessor.cpp
source/glsl/tokenizer.cpp

index ea8e93064403d89c4ce5a3cb1fcc9947c3a58492..aff897ca012c73b249bd63fc12fe5e3e9cfa9299 100644 (file)
@@ -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)
 { }
index 63c49bbd9112d95f521369d43577603958e17589..1ae521cae8b05a9085a5195ab2182104e28ffe3f 100644 (file)
@@ -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:
index 3c190221952ab7758fdbbc984c071abb41d39c8f..bf2d4b4de0c2b226fcbb90becd48047b9c93946b 100644 (file)
@@ -14,8 +14,6 @@ Preprocessor::Preprocessor(Tokenizer &t):
 
 void Preprocessor::preprocess()
 {
-       tokenizer.expect("#");
-
        string token = tokenizer.peek_token();
        if(token=="pragma")
                preprocess_pragma();
index be432143d34e2c6f21c570287bb2ac483c2515a3..e73afd5273add2dec2f907f223b2b1e5421b9f9d 100644 (file)
@@ -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;
 }