module(0)
{ }
-void ProgramCompiler::compile(const string &source)
+void ProgramCompiler::compile(const string &source, const string &src_name)
{
resources = 0;
- module = &parser.parse(source);
+ module = &parser.parse(source, src_name);
process();
}
-void ProgramCompiler::compile(IO::Base &io, Resources *res)
+void ProgramCompiler::compile(IO::Base &io, Resources *res, const string &src_name)
{
resources = res;
- module = &parser.parse(io);
+ module = &parser.parse(io, src_name);
process();
}
+void ProgramCompiler::compile(IO::Base &io, const string &src_name)
+{
+ compile(io, 0, src_name);
+}
+
void ProgramCompiler::add_shaders(Program &program)
{
if(!module)
Module *ProgramCompiler::create_builtins_module()
{
ProgramParser parser;
- Module *module = new Module(parser.parse(builtins_src));
+ Module *module = new Module(parser.parse(builtins_src, "<builtin>"));
for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
{
VariableResolver resolver;
if(!io)
throw runtime_error(format("module %s not found", name));
ProgramParser import_parser;
- Module &imported_module = import_parser.parse(*io);
+ Module &imported_module = import_parser.parse(*io, fn);
inject_block(module->shared.content, imported_module.shared.content);
apply<DeclarationCombiner>(module->shared);
delete module;
}
-Module &ProgramParser::parse(const string &s)
+Module &ProgramParser::parse(const string &s, const string &n)
{
source = s;
+ source_name = n;
parse_source();
return *module;
}
-Module &ProgramParser::parse(IO::Base &io)
+Module &ProgramParser::parse(IO::Base &io, const string &n)
{
source = string();
+ source_name = n;
while(!io.eof())
{
char buffer[4096];
module = new Module;
cur_stage = &module->shared;
iter = source.begin();
+ current_line = 1;
while(1)
{
while(RefPtr<Node> statement = parse_global_declaration())
}
}
+string ProgramParser::format_error(const std::string &message)
+{
+ string location = format("%s:%d: ", source_name, current_line);
+ return location+message;
+}
+
+string ProgramParser::format_syntax_error(const std::string &expected)
+{
+ return format_error(format("Syntax error at '%s': expected %s", last_token, expected));
+}
+
const string &ProgramParser::peek_token(unsigned index)
{
while(next_tokens.size()<=index)
next_tokens.push_back(parse_token_());
- return next_tokens[index];
+ return (last_token = next_tokens[index]);
}
-string ProgramParser::parse_token()
+const string &ProgramParser::parse_token()
{
if(!next_tokens.empty())
{
- string token = next_tokens.front();
+ last_token = next_tokens.front();
next_tokens.pop_front();
- return token;
+ return last_token;
}
- return parse_token_();
+ return (last_token = parse_token_());
}
string ProgramParser::parse_token_()
comment = 3;
}
+ if(*iter=='\n')
+ ++current_line;
+
++iter;
}
{
string parsed = parse_token();
if(parsed!=token)
- throw runtime_error(format("Parse error at '%s': expected '%s'", parsed, token));
+ throw runtime_error(format_syntax_error(format("'%s'", token)));
}
string ProgramParser::expect_type()
{
string token = parse_token();
if(!is_type(token))
- throw runtime_error(format("Parse error at '%s': expected a type", token));
+ throw runtime_error(format_syntax_error("a type"));
return token;
}
{
string token = parse_token();
if(!is_identifier(token))
- throw runtime_error(format("Parse error at '%s': expected an identifier", token));
+ throw runtime_error(format_syntax_error("an identifier"));
return token;
}
else if(token.empty())
return 0;
else
- throw runtime_error(format("Syntax error at '%s': expected a global declaration", token));
+ throw runtime_error(format_syntax_error("a global declaration"));
}
RefPtr<Node> ProgramParser::parse_statement()
return expr;
}
else
- throw runtime_error(format("Syntax error at '%s': expected a statement", token));
+ throw runtime_error(format_syntax_error("a statement"));
}
RefPtr<Import> ProgramParser::parse_import()
{
if(cur_stage->type!=SHARED)
- throw runtime_error("Imports are only allowed in the shared section");
+ throw runtime_error(format_error("Imports are only allowed in the shared section"));
expect("import");
RefPtr<Import> import = new Import;
precision->precision = parse_token();
if(!is_precision_qualifier(precision->precision))
- throw runtime_error(format("Parse error at '%s': expected a precision qualifier", precision->precision));
+ throw runtime_error(format_syntax_error("a precision qualifier"));
precision->type = parse_token();
// Not entirely accurate; only float, int and sampler types are allowed
if(!is_builtin_type(precision->type))
- throw runtime_error(format("Parse error at '%s': expected a builtin type", precision->type));
+ throw runtime_error(format_syntax_error("a builtin type"));
expect(";");
{
string token = parse_token();
if(token==")")
- throw runtime_error(format("Parse error at '%s': expected layout qualifier id", token));
+ throw runtime_error(format_syntax_error("a layout qualifier name"));
layout->qualifiers.push_back(Layout::Qualifier());
Layout::Qualifier &qual = layout->qualifiers.back();
if(left)
return left;
else
- throw runtime_error(format("Parse error at '%s': expected an expression", token));
+ throw runtime_error(format_syntax_error("an expression"));
}
else if(left)
{
if(token=="(")
{
if(!left_var)
- throw runtime_error(format("Parse error at '%s': function name must be an identifier", token));
+ throw runtime_error(format_error("Syntax error before '(': function name must be an identifier"));
left = parse_function_call(*left_var);
}
else if(token==".")
else if(oper && oper->type==BINARY)
left = parse_binary(left, oper);
else
- throw runtime_error(format("Parse error at '%s': expected an operator", token));
+ throw runtime_error(format_syntax_error("an operator"));
left_var = 0;
}
else
left = unary;
}
else
- throw runtime_error(format("Parse error at '%s': expected an expression", token));
+ throw runtime_error(format_syntax_error("an expression"));
}
}
}
var->sampling = parse_token();
token = peek_token();
if(!is_interface_qualifier(token))
- throw runtime_error(format("Parse error at '%s': expected an interface qualifier", token));
+ throw runtime_error(format_syntax_error("an interface qualifier"));
}
if(is_interface_qualifier(token))
else if(token==";")
parse_token();
else
- throw runtime_error(format("Parse error at '%s': expected '{' or ';'", token));
+ throw runtime_error(format_syntax_error("'{' or ';'"));
return func;
}
iface->interface = parse_token();
if(!is_interface_qualifier(iface->interface))
- throw runtime_error(format("Parse error at '%s': expected an interface qualifier", iface->interface));
+ throw runtime_error(format_syntax_error("an interface qualifier"));
iface->name = expect_identifier();
parse_block(iface->members, true);
};
std::string source;
+ std::string source_name;
+ unsigned current_line;
std::string::const_iterator iter;
+ std::string last_token;
std::deque<std::string> next_tokens;
ProgramSyntax::Module *module;
ProgramSyntax::Stage *cur_stage;
ProgramParser();
~ProgramParser();
- ProgramSyntax::Module &parse(const std::string &);
- ProgramSyntax::Module &parse(IO::Base &);
+ ProgramSyntax::Module &parse(const std::string &, const std::string &);
+ ProgramSyntax::Module &parse(IO::Base &, const std::string &);
private:
void parse_source();
+ std::string format_error(const std::string &);
+ std::string format_syntax_error(const std::string &);
+
const std::string &peek_token(unsigned = 0);
- std::string parse_token();
+ const std::string &parse_token();
std::string parse_token_();
std::string parse_identifier();
std::string parse_number();