--- /dev/null
+#include <msp/strings/format.h>
+#include <msp/strings/utils.h>
+#include "error.h"
+#include "program.h"
+#include "programcompiler.h"
+#include "shader.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+using namespace ProgramSyntax;
+
+ProgramCompiler::ProgramCompiler():
+ module(0)
+{ }
+
+void ProgramCompiler::compile(const string &source)
+{
+ module = &parser.parse(source);
+}
+
+void ProgramCompiler::compile(IO::Base &io)
+{
+ module = &parser.parse(io);
+}
+
+void ProgramCompiler::add_shaders(Program &program)
+{
+ if(!module)
+ throw invalid_operation("ProgramCompiler::add_shaders");
+
+ string global_source = "#version 150\n"+format_context(module->global_context);
+ if(module->vertex_context.present)
+ program.attach_shader_owned(new VertexShader(global_source+"\n"+format_context(module->vertex_context)));
+ if(module->geometry_context.present)
+ program.attach_shader_owned(new GeometryShader(global_source+"\n"+format_context(module->geometry_context)));
+ if(module->fragment_context.present)
+ program.attach_shader_owned(new FragmentShader(global_source+"\n"+format_context(module->fragment_context)));
+
+ program.bind_attribute(VERTEX4, "vertex");
+ program.bind_attribute(NORMAL3, "normal");
+ program.bind_attribute(COLOR4_FLOAT, "color");
+ program.bind_attribute(TEXCOORD4, "texcoord");
+}
+
+string ProgramCompiler::format_context(Context &context)
+{
+ Formatter formatter;
+ context.content.visit(formatter);
+ return formatter.formatted;
+}
+
+
+ProgramCompiler::Formatter::Formatter():
+ indent(0),
+ parameter_list(false),
+ else_if(false)
+{ }
+
+string ProgramCompiler::Formatter::format_expression(Expression &expr)
+{
+ return join(expr.tokens.begin(), expr.tokens.end(), string());
+}
+
+void ProgramCompiler::Formatter::visit(ExpressionStatement &expr)
+{
+ formatted += format("%s;", format_expression(expr.expression));
+}
+
+void ProgramCompiler::Formatter::visit(Block &block)
+{
+ if(block.use_braces)
+ {
+ if(else_if)
+ {
+ formatted += '\n';
+ else_if = false;
+ }
+ formatted += format("%s{\n", string(indent*2, ' '));
+ }
+
+ bool change_indent = (!formatted.empty() && !else_if);
+ indent += change_indent;
+ string spaces(indent*2, ' ');
+ for(vector<Node *>::const_iterator i=block.body.begin(); i!=block.body.end(); ++i)
+ {
+ if(i!=block.body.begin())
+ formatted += '\n';
+ if(!else_if)
+ formatted += spaces;
+ (*i)->visit(*this);
+ }
+ indent -= change_indent;
+
+ if(block.use_braces)
+ formatted += format("\n%s}", string(indent*2, ' '));
+}
+
+void ProgramCompiler::Formatter::visit(Layout &layout)
+{
+ formatted += "layout(";
+ for(vector<Layout::Qualifier>::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i)
+ {
+ if(i!=layout.qualifiers.begin())
+ formatted += ", ";
+ formatted += i->identifier;
+ if(!i->value.empty())
+ formatted += format("=%s", i->value);
+ }
+ formatted += format(") %s;", layout.interface);
+}
+
+void ProgramCompiler::Formatter::visit(StructDeclaration &strct)
+{
+ formatted += format("struct %s\n", strct.name);
+ strct.members.visit(*this);
+ formatted += ';';
+}
+
+void ProgramCompiler::Formatter::visit(VariableDeclaration &var)
+{
+ if(var.constant)
+ formatted += "const ";
+ if(!var.sampling.empty())
+ formatted += format("%s ", var.sampling);
+ if(!var.interface.empty())
+ formatted += format("%s ", var.interface);
+ formatted += format("%s %s", var.type, var.name);
+ if(var.array)
+ formatted += format("[%s]", format_expression(var.array_size));
+ if(!var.init_expression.empty())
+ formatted += format(" = %s", format_expression(var.init_expression));
+ if(!parameter_list)
+ formatted += ';';
+}
+
+void ProgramCompiler::Formatter::visit(InterfaceBlock &iface)
+{
+ formatted += format("%s %s\n", iface.interface, iface.name);
+ iface.members.visit(*this);
+ formatted += ';';
+}
+
+void ProgramCompiler::Formatter::visit(FunctionDeclaration &func)
+{
+ formatted += format("%s %s(", func.return_type, func.name);
+ parameter_list = true;
+ for(vector<VariableDeclaration *>::const_iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
+ {
+ if(i!=func.parameters.begin())
+ formatted += ", ";
+ (*i)->visit(*this);
+ }
+ parameter_list = false;
+ formatted += ')';
+ if(func.definition)
+ {
+ formatted += '\n';
+ func.body.visit(*this);
+ }
+ else
+ formatted += ';';
+}
+
+void ProgramCompiler::Formatter::visit(Conditional &cond)
+{
+ if(else_if)
+ {
+ formatted += ' ';
+ else_if = false;
+ }
+ formatted += format("if(%s)\n", format_expression(cond.condition));
+ cond.body.visit(*this);
+ if(!cond.else_body.body.empty())
+ {
+ formatted += format("\n%selse", string(indent*2, ' '));
+ else_if = true;
+ cond.else_body.visit(*this);
+ else_if = false;
+ }
+}
+
+void ProgramCompiler::Formatter::visit(Iteration &iter)
+{
+ formatted += "for(";
+ iter.init_statement->visit(*this);
+ formatted += format(" %s; %s)\n", format_expression(iter.condition), format_expression(iter.loop_expression));
+ iter.body.visit(*this);
+}
+
+void ProgramCompiler::Formatter::visit(Return &ret)
+{
+ formatted += format("return %s;", format_expression(ret.expression));
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_PROGRAMCOMPILER_H_
+#define MSP_GL_PROGRAMCOMPILER_H_
+
+#include "programparser.h"
+#include "programsyntax.h"
+
+namespace Msp {
+namespace GL {
+
+class Program;
+
+class ProgramCompiler
+{
+public:
+ struct Formatter: ProgramSyntax::NodeVisitor
+ {
+ std::string formatted;
+ unsigned indent;
+ bool parameter_list;
+ bool else_if;
+
+ Formatter();
+
+ std::string format_expression(ProgramSyntax::Expression &);
+ virtual void visit(ProgramSyntax::Block &);
+ virtual void visit(ProgramSyntax::ExpressionStatement &);
+ virtual void visit(ProgramSyntax::Layout &);
+ virtual void visit(ProgramSyntax::StructDeclaration &);
+ virtual void visit(ProgramSyntax::VariableDeclaration &);
+ virtual void visit(ProgramSyntax::InterfaceBlock &);
+ virtual void visit(ProgramSyntax::FunctionDeclaration &);
+ virtual void visit(ProgramSyntax::Conditional &);
+ virtual void visit(ProgramSyntax::Iteration &);
+ virtual void visit(ProgramSyntax::Return &);
+ };
+
+private:
+ ProgramParser parser;
+ ProgramSyntax::Module *module;
+
+public:
+ ProgramCompiler();
+
+ void compile(const std::string &);
+ void compile(IO::Base &);
+ void add_shaders(Program &);
+
+private:
+ std::string format_context(ProgramSyntax::Context &);
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
--- /dev/null
+#include <msp/strings/format.h>
+#include <msp/strings/regex.h>
+#include "programparser.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+using namespace ProgramSyntax;
+
+Module &ProgramParser::parse(const string &s)
+{
+ source = s;
+ parse_source(main_module);
+ return main_module;
+}
+
+Module &ProgramParser::parse(IO::Base &io)
+{
+ source = string();
+ while(!io.eof())
+ {
+ char buffer[4096];
+ unsigned len = io.read(buffer, sizeof(buffer));
+ source.append(buffer, len);
+ }
+ parse_source(main_module);
+ return main_module;
+}
+
+void ProgramParser::parse_source(Module &module)
+{
+ cur_module = &module;
+ iter = source.begin();
+ Context *cur_context = &module.global_context;
+ while(1)
+ {
+ while(Node *statement = parse_global_declaration())
+ cur_context->content.body.push_back(statement);
+ cur_context->present = !cur_context->content.body.empty();
+
+ parse_token();
+ string token = parse_token();
+ if(token.empty())
+ break;
+ else if(token=="global")
+ cur_context = &module.global_context;
+ else if(token=="vertex")
+ cur_context = &module.vertex_context;
+ else if(token=="geometry")
+ cur_context = &module.geometry_context;
+ else if(token=="fragment")
+ cur_context = &module.fragment_context;
+ else
+ throw runtime_error(format("Parse error at '%s': expected context identifier", token));
+
+ for(; (iter!=source.end() && *iter!='\n'); ++iter) ;
+ }
+}
+
+const string &ProgramParser::peek_token(unsigned index)
+{
+ while(next_tokens.size()<=index)
+ next_tokens.push_back(parse_token_());
+ return next_tokens[index];
+}
+
+string ProgramParser::parse_token()
+{
+ if(!next_tokens.empty())
+ {
+ string token = next_tokens.front();
+ next_tokens.pop_front();
+ return token;
+ }
+
+ return parse_token_();
+}
+
+string ProgramParser::parse_token_()
+{
+ if(!skip_comment_and_whitespace())
+ return string();
+
+ if(isalpha(*iter) || *iter=='_')
+ return parse_identifier();
+ else if(isdigit(*iter))
+ return parse_number();
+ else
+ return parse_other();
+}
+
+string ProgramParser::parse_identifier()
+{
+ string ident;
+ while(iter!=source.end())
+ {
+ if(isalnum(*iter) || *iter=='_')
+ ident += *iter++;
+ else
+ break;
+ }
+
+ return ident;
+}
+
+string ProgramParser::parse_number()
+{
+ bool accept_sign = false;
+ string number;
+ while(iter!=source.end())
+ {
+ if(isdigit(*iter) || *iter=='.')
+ number += *iter++;
+ else if(*iter=='e' || *iter=='E')
+ {
+ number += *iter++;
+ accept_sign = true;
+ }
+ else if(accept_sign && (*iter=='+' || *iter=='-'))
+ number += *iter++;
+ else
+ break;
+ }
+
+ return number;
+}
+
+string ProgramParser::parse_other()
+{
+ string token;
+ while(iter!=source.end())
+ {
+ if(isalnum(*iter) || *iter=='_' || isspace(*iter))
+ break;
+ token += *iter++;
+ if(*iter==';' || *iter=='(' || *iter==')' || *iter=='[' || *iter==']')
+ break;
+ }
+
+ return token;
+}
+
+bool ProgramParser::skip_comment_and_whitespace()
+{
+ unsigned comment = 0;
+ unsigned slashes = 0;
+ while(iter!=source.end())
+ {
+ //IO::print("%d '%c'\n", comment, *iter);
+ if(comment==0)
+ {
+ if(*iter=='/')
+ comment = 1;
+ else if(!isspace(*iter))
+ break;
+ }
+ else if(comment==1)
+ {
+ if(*iter=='/')
+ {
+ comment = 2;
+ slashes = 2;
+ }
+ else if(*iter=='*')
+ comment = 3;
+ else
+ {
+ comment = 0;
+ --iter;
+ break;
+ }
+ }
+ else if(comment==2)
+ {
+ if(*iter=='\n')
+ comment = 0;
+ else if(*iter=='/')
+ ++slashes;
+ else if(!isspace(*iter) && slashes>=6)
+ return false;
+ }
+ else if(comment==3 && *iter=='*')
+ comment = 4;
+ else if(comment==4)
+ {
+ if(*iter=='/')
+ comment = 0;
+ else
+ comment = 3;
+ }
+
+ ++iter;
+ }
+
+ return iter!=source.end();
+}
+
+void ProgramParser::expect(const string &token)
+{
+ string parsed = parse_token();
+ if(parsed!=token)
+ throw runtime_error(format("Parse error at '%s': expected '%s'", parsed, 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));
+ return token;
+}
+
+string ProgramParser::expect_identifier()
+{
+ static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$");
+ string token = parse_token();
+ if(!re.match(token))
+ throw runtime_error(format("Parse error at '%s': expected an identifier", token));
+ return token;
+}
+
+bool ProgramParser::check(const string &token)
+{
+ bool result = (peek_token()==token);
+ if(result)
+ parse_token();
+ return result;
+}
+
+bool ProgramParser::is_interface_qualifier(const string &token)
+{
+ return (token=="uniform" || token=="in" || token=="out");
+}
+
+bool ProgramParser::is_sampling_qualifier(const string &token)
+{
+ return token=="centroid";
+}
+
+bool ProgramParser::is_qualifier(const string &token)
+{
+ return (token=="const" || is_interface_qualifier(token) || is_sampling_qualifier(token));
+}
+
+bool ProgramParser::is_builtin_type(const string &token)
+{
+ static Regex re("^(void|float|int|bool|[ib]?vec[234]|mat[234](x[234])?|sampler((1D|2D)(Array)?(Shadow)?|Cube(Shadow)?|3D))$");
+ return re.match(token);
+}
+
+bool ProgramParser::is_type(const string &token)
+{
+ return is_builtin_type(token) || cur_module->structs.count(token);
+}
+
+Node *ProgramParser::parse_global_declaration()
+{
+ string token = peek_token();
+ if(token=="layout")
+ return parse_layout();
+ else if(token=="struct")
+ return parse_struct_declaration();
+ else if(is_sampling_qualifier(token) || token=="const")
+ return parse_variable_declaration();
+ else if(is_interface_qualifier(token))
+ {
+ if(is_type(peek_token(1)))
+ return parse_variable_declaration();
+ else
+ return parse_interface_block();
+ }
+ else if(is_type(token))
+ {
+ if(peek_token(2)=="(")
+ return parse_function_declaration();
+ else
+ return parse_variable_declaration();
+ }
+ else if(token.empty())
+ return 0;
+ else
+ throw runtime_error(format("Syntax error at '%s': expected a global declaration", token));
+}
+
+Node *ProgramParser::parse_statement()
+{
+ string token = peek_token();
+ if(token=="if")
+ return parse_conditional();
+ else if(token=="for")
+ return parse_iteration();
+ else if(token=="return")
+ return parse_return();
+ else if(is_qualifier(token) || is_type(token))
+ return parse_variable_declaration();
+ else if(!token.empty())
+ {
+ RefPtr<ExpressionStatement> expr = new ExpressionStatement;
+ parse_expression(expr->expression);
+ expect(";");
+
+ return expr.release();
+ }
+ else
+ throw runtime_error(format("Syntax error at '%s': expected a statement", token));
+}
+
+Layout *ProgramParser::parse_layout()
+{
+ expect("layout");
+ expect("(");
+ RefPtr<Layout> layout = new Layout;
+ while(1)
+ {
+ string token = parse_token();
+ if(token==")")
+ throw runtime_error(format("Parse error at '%s': expected layout qualifier id", token));
+
+ layout->qualifiers.push_back(Layout::Qualifier());
+ Layout::Qualifier &qual = layout->qualifiers.back();
+ qual.identifier = token;
+
+ if(check("="))
+ qual.value = parse_token();
+
+ if(peek_token()==")")
+ break;
+
+ expect(",");
+ }
+ expect(")");
+ layout->interface = parse_token();
+ expect(";");
+
+ return layout.release();
+}
+
+void ProgramParser::parse_block(Block &block, bool require_braces)
+{
+ bool have_braces = (require_braces || peek_token()=="{");
+ if(have_braces)
+ expect("{");
+
+ while(1)
+ {
+ string token = peek_token();
+ if(token=="}")
+ break;
+
+ block.body.push_back(parse_statement());
+ if(!have_braces)
+ break;
+ }
+
+ block.use_braces = (require_braces || block.body.size()!=1);
+
+ if(have_braces)
+ expect("}");
+}
+
+void ProgramParser::parse_expression(Expression &expr)
+{
+ unsigned nesting_level = 0;
+ while(iter!=source.end())
+ {
+ string token = peek_token();
+ if(token=="(" || token=="[")
+ ++nesting_level;
+ else if(token==")" || token=="]")
+ {
+ if(!nesting_level)
+ break;
+ --nesting_level;
+ }
+ else if(token==";")
+ break;
+
+ parse_token();
+ expr.tokens.push_back(token);
+ }
+}
+
+StructDeclaration *ProgramParser::parse_struct_declaration()
+{
+ expect("struct");
+ RefPtr<StructDeclaration> strct = new StructDeclaration;
+
+ strct->name = expect_identifier();
+ parse_block(strct->members, true);
+ expect(";");
+
+ cur_module->structs[strct->name] = strct.get();
+ return strct.release();
+}
+
+VariableDeclaration *ProgramParser::parse_variable_declaration()
+{
+ RefPtr<VariableDeclaration> var = new VariableDeclaration;
+
+ string token = peek_token();
+ if(is_sampling_qualifier(token))
+ {
+ 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));
+ }
+
+ if(is_interface_qualifier(token))
+ var->interface = parse_token();
+ else if(token=="const")
+ {
+ var->constant = true;
+ parse_token();
+ }
+
+ var->type = expect_type();
+ var->name = expect_identifier();
+
+ if(check("["))
+ {
+ var->array = true;
+ if(!check("]"))
+ {
+ parse_expression(var->array_size);
+ expect("]");
+ }
+ }
+
+ if(check("="))
+ parse_expression(var->init_expression);
+
+ expect(";");
+ return var.release();
+}
+
+FunctionDeclaration *ProgramParser::parse_function_declaration()
+{
+ RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
+
+ func->return_type = expect_type();
+ func->name = expect_identifier();
+ parse_function_parameter_list(*func);
+
+ string token = peek_token();
+ if(token=="{")
+ {
+ func->definition = true;
+ parse_block(func->body, true);
+ }
+ else if(token==";")
+ parse_token();
+ else
+ throw runtime_error(format("Parse error at '%s': expected '{' or ';'", token));
+
+ return func.release();
+}
+
+void ProgramParser::parse_function_parameter_list(FunctionDeclaration &func)
+{
+ expect("(");
+ while(1)
+ {
+ string token = peek_token();
+ if(token==")")
+ break;
+ else if(!func.parameters.empty())
+ expect(",");
+
+ RefPtr<VariableDeclaration> var = new VariableDeclaration;
+ var->type = expect_type();
+ var->name = expect_identifier();
+ func.parameters.push_back(var.release());
+ }
+ expect(")");
+}
+
+InterfaceBlock *ProgramParser::parse_interface_block()
+{
+ RefPtr<InterfaceBlock> iface = new InterfaceBlock;
+
+ iface->interface = parse_token();
+ if(!is_interface_qualifier(iface->interface))
+ throw runtime_error(format("Parse error at '%s': expected an interface qualifier", iface->interface));
+
+ iface->name = expect_identifier();
+ parse_block(iface->members, true);
+ expect(";");
+
+ return iface.release();
+}
+
+Conditional *ProgramParser::parse_conditional()
+{
+ expect("if");
+ expect("(");
+ RefPtr<Conditional> cond = new Conditional;
+ parse_expression(cond->condition);
+ expect(")");
+
+ parse_block(cond->body, false);
+
+ string token = peek_token();
+ if(token=="else")
+ {
+ parse_token();
+ parse_block(cond->else_body, false);
+ }
+
+ return cond.release();
+}
+
+Iteration *ProgramParser::parse_iteration()
+{
+ expect("for");
+ expect("(");
+ RefPtr<Iteration> loop = new Iteration;
+ string token = peek_token();
+ if(is_type(token))
+ loop->init_statement = parse_statement();
+ else
+ {
+ RefPtr<ExpressionStatement> expr = new ExpressionStatement;
+ parse_expression(expr->expression);
+ expect(";");
+ loop->init_statement = expr.release();
+ }
+ parse_expression(loop->condition);
+ expect(";");
+ parse_expression(loop->loop_expression);
+ expect(")");
+
+ parse_block(loop->body, false);
+
+ return loop.release();
+}
+
+Return *ProgramParser::parse_return()
+{
+ expect("return");
+ RefPtr<Return> ret = new Return;
+ parse_expression(ret->expression);
+ expect(";");
+ return ret.release();
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_PROGRAMPARSER_H_
+#define MSP_GL_PROGRAMPARSER_H_
+
+#include <deque>
+#include <map>
+#include <string>
+#include <msp/io/base.h>
+#include "programsyntax.h"
+
+namespace Msp {
+namespace GL {
+
+class ProgramParser
+{
+private:
+ std::string source;
+ std::string::const_iterator iter;
+ std::deque<std::string> next_tokens;
+ ProgramSyntax::Module main_module;
+ ProgramSyntax::Module *cur_module;
+
+public:
+ ProgramSyntax::Module &parse(const std::string &);
+ ProgramSyntax::Module &parse(IO::Base &);
+
+private:
+ void parse_source(ProgramSyntax::Module &);
+
+ const std::string &peek_token(unsigned = 0);
+ std::string parse_token();
+ std::string parse_token_();
+ std::string parse_identifier();
+ std::string parse_number();
+ std::string parse_other();
+ bool skip_comment_and_whitespace();
+ void expect(const std::string &);
+ std::string expect_type();
+ std::string expect_identifier();
+ bool check(const std::string &);
+
+ static bool is_interface_qualifier(const std::string &);
+ static bool is_sampling_qualifier(const std::string &);
+ static bool is_qualifier(const std::string &);
+ static bool is_builtin_type(const std::string &);
+ bool is_type(const std::string &);
+
+ ProgramSyntax::Node *parse_global_declaration();
+ ProgramSyntax::Node *parse_statement();
+ ProgramSyntax::Layout *parse_layout();
+ void parse_block(ProgramSyntax::Block &, bool);
+ void parse_expression(ProgramSyntax::Expression &);
+ ProgramSyntax::StructDeclaration *parse_struct_declaration();
+ ProgramSyntax::VariableDeclaration *parse_variable_declaration();
+ ProgramSyntax::FunctionDeclaration *parse_function_declaration();
+ void parse_function_parameter_list(ProgramSyntax::FunctionDeclaration &);
+ ProgramSyntax::InterfaceBlock *parse_interface_block();
+ ProgramSyntax::Conditional *parse_conditional();
+ ProgramSyntax::Iteration *parse_iteration();
+ ProgramSyntax::Return *parse_return();
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
--- /dev/null
+#include "programsyntax.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+namespace ProgramSyntax {
+
+Block::Block():
+ use_braces(false)
+{ }
+
+Block::~Block()
+{
+ for(vector<Node *>::iterator i=body.begin(); i!=body.end(); ++i)
+ delete *i;
+}
+
+void Block::visit(NodeVisitor &visitor)
+{
+ visitor.visit(*this);
+}
+
+
+void ExpressionStatement::visit(NodeVisitor &visitor)
+{
+ visitor.visit(*this);
+}
+
+
+void Layout::visit(NodeVisitor &visitor)
+{
+ visitor.visit(*this);
+}
+
+
+StructDeclaration::StructDeclaration()
+{
+ members.use_braces = true;
+}
+
+void StructDeclaration::visit(NodeVisitor &visitor)
+{
+ visitor.visit(*this);
+}
+
+
+VariableDeclaration::VariableDeclaration():
+ constant(false),
+ array(false)
+{ }
+
+void VariableDeclaration::visit(NodeVisitor &visitor)
+{
+ visitor.visit(*this);
+}
+
+
+InterfaceBlock::InterfaceBlock()
+{
+ members.use_braces = true;
+}
+
+void InterfaceBlock::visit(NodeVisitor &visitor)
+{
+ visitor.visit(*this);
+}
+
+
+FunctionDeclaration::FunctionDeclaration():
+ definition(false)
+{ }
+
+FunctionDeclaration::~FunctionDeclaration()
+{
+ for(vector<VariableDeclaration *>::iterator i=parameters.begin(); i!=parameters.end(); ++i)
+ delete *i;
+}
+
+void FunctionDeclaration::visit(NodeVisitor &visitor)
+{
+ visitor.visit(*this);
+}
+
+
+void Conditional::visit(NodeVisitor &visitor)
+{
+ visitor.visit(*this);
+}
+
+
+void Return::visit(NodeVisitor &visitor)
+{
+ visitor.visit(*this);
+}
+
+
+Iteration::Iteration():
+ init_statement(0)
+{ }
+
+Iteration::~Iteration()
+{
+ delete init_statement;
+}
+
+void Iteration::visit(NodeVisitor &visitor)
+{
+ visitor.visit(*this);
+}
+
+
+Context::Context(ContextType t):
+ type(t),
+ present(false)
+{ }
+
+
+Module::Module():
+ global_context(GLOBAL),
+ vertex_context(VERTEX),
+ geometry_context(GEOMETRY),
+ fragment_context(FRAGMENT)
+{ }
+
+} // namespace ProgramSyntax
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_PROGRAMSYNTAX_H_
+#define MSP_GL_PROGRAMSYNTAX_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace Msp {
+namespace GL {
+namespace ProgramSyntax {
+
+struct NodeVisitor;
+
+struct Node
+{
+ virtual ~Node() { }
+
+ virtual void visit(NodeVisitor &) = 0;
+};
+
+struct Block: Node
+{
+ std::vector<Node *> body;
+ bool use_braces;
+
+ Block();
+ virtual ~Block();
+
+ virtual void visit(NodeVisitor &);
+};
+
+struct Expression
+{
+ std::vector<std::string> tokens;
+
+ bool empty() const { return tokens.empty(); }
+};
+
+struct ExpressionStatement: Node
+{
+ Expression expression;
+
+ virtual void visit(NodeVisitor &);
+};
+
+struct Layout: Node
+{
+ struct Qualifier
+ {
+ std::string identifier;
+ std::string value;
+ };
+
+ std::vector<Qualifier> qualifiers;
+ std::string interface;
+
+ virtual void visit(NodeVisitor &);
+};
+
+struct StructDeclaration: Node
+{
+ std::string name;
+ Block members;
+
+ StructDeclaration();
+
+ virtual void visit(NodeVisitor &);
+};
+
+struct VariableDeclaration: Node
+{
+ bool constant;
+ std::string sampling;
+ std::string interface;
+ std::string type;
+ std::string name;
+ bool array;
+ Expression array_size;
+ Expression init_expression;
+
+ VariableDeclaration();
+
+ virtual void visit(NodeVisitor &);
+};
+
+struct InterfaceBlock: Node
+{
+ std::string interface;
+ std::string name;
+ Block members;
+
+ InterfaceBlock();
+
+ virtual void visit(NodeVisitor &);
+};
+
+struct FunctionDeclaration: Node
+{
+ std::string return_type;
+ std::string name;
+ std::vector<VariableDeclaration *> parameters;
+ bool definition;
+ Block body;
+
+ FunctionDeclaration();
+ ~FunctionDeclaration();
+
+ virtual void visit(NodeVisitor &);
+};
+
+struct Conditional: Node
+{
+ Expression condition;
+ Block body;
+ Block else_body;
+
+ virtual void visit(NodeVisitor &);
+};
+
+struct Iteration: Node
+{
+ Node *init_statement;
+ Expression condition;
+ Expression loop_expression;
+ Block body;
+
+ Iteration();
+ virtual ~Iteration();
+
+ virtual void visit(NodeVisitor &);
+};
+
+struct Return: Node
+{
+ Expression expression;
+
+ virtual void visit(NodeVisitor &);
+};
+
+struct NodeVisitor
+{
+ virtual ~NodeVisitor() { }
+
+ virtual void visit(Block &) { }
+ virtual void visit(ExpressionStatement &) { }
+ virtual void visit(Layout &) { }
+ virtual void visit(StructDeclaration &) { }
+ virtual void visit(VariableDeclaration &) { }
+ virtual void visit(InterfaceBlock &) { }
+ virtual void visit(FunctionDeclaration &) { }
+ virtual void visit(Conditional &) { }
+ virtual void visit(Iteration &) { }
+ virtual void visit(Return &) { }
+};
+
+enum ContextType
+{
+ GLOBAL,
+ VERTEX,
+ GEOMETRY,
+ FRAGMENT
+};
+
+struct Context
+{
+ ContextType type;
+ bool present;
+ ProgramSyntax::Block content;
+
+ Context(ContextType);
+};
+
+struct Module
+{
+ Context global_context;
+ Context vertex_context;
+ Context geometry_context;
+ Context fragment_context;
+ std::map<std::string, StructDeclaration *> structs;
+
+ Module();
+};
+
+} // namespace ProgramSyntax
+} // namespace GL
+} // namespace Msp
+
+#endif