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)
{ }
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:
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();
}
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;
}