X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fprogramparser.cpp;h=83a2879f4feeaa92ba5e947149b45064b134ae44;hp=c3049dd3649bc5b2d3360b5afa7a4c571787d45c;hb=HEAD;hpb=eb6a546dcffc1b67f0a23d8b075fbdc86a2872a0 diff --git a/source/programparser.cpp b/source/programparser.cpp deleted file mode 100644 index c3049dd3..00000000 --- a/source/programparser.cpp +++ /dev/null @@ -1,820 +0,0 @@ -#include -#include -#include "programparser.h" - -using namespace std; - -namespace Msp { -namespace GL { - -using namespace ProgramSyntax; - -ProgramParser::Operator ProgramParser::operators[] = -{ - { "[", 2, BINARY, LEFT_TO_RIGHT }, - { "(", 2, BINARY, LEFT_TO_RIGHT }, - { ".", 2, BINARY, LEFT_TO_RIGHT }, - { "++", 2, POSTFIX, LEFT_TO_RIGHT }, - { "--", 2, POSTFIX, LEFT_TO_RIGHT }, - { "++", 3, PREFIX, RIGHT_TO_LEFT }, - { "--", 3, PREFIX, RIGHT_TO_LEFT }, - { "+", 3, PREFIX, RIGHT_TO_LEFT }, - { "-", 3, PREFIX, RIGHT_TO_LEFT }, - { "~", 3, PREFIX, RIGHT_TO_LEFT }, - { "!", 3, PREFIX, RIGHT_TO_LEFT }, - { "*", 4, BINARY, LEFT_TO_RIGHT }, - { "/", 4, BINARY, LEFT_TO_RIGHT }, - { "%", 4, BINARY, LEFT_TO_RIGHT }, - { "+", 5, BINARY, LEFT_TO_RIGHT }, - { "-", 5, BINARY, LEFT_TO_RIGHT }, - { "<<", 6, BINARY, LEFT_TO_RIGHT }, - { ">>", 6, BINARY, LEFT_TO_RIGHT }, - { "<", 7, BINARY, LEFT_TO_RIGHT }, - { ">", 7, BINARY, LEFT_TO_RIGHT }, - { "<=", 7, BINARY, LEFT_TO_RIGHT }, - { ">=", 7, BINARY, LEFT_TO_RIGHT }, - { "==", 8, BINARY, LEFT_TO_RIGHT }, - { "!=", 8, BINARY, LEFT_TO_RIGHT }, - { "&", 9, BINARY, LEFT_TO_RIGHT }, - { "^", 10, BINARY, LEFT_TO_RIGHT }, - { "|", 11, BINARY, LEFT_TO_RIGHT }, - { "&&", 12, BINARY, LEFT_TO_RIGHT }, - { "^^", 13, BINARY, LEFT_TO_RIGHT }, - { "||", 14, BINARY, LEFT_TO_RIGHT }, - { "?", 15, BINARY, RIGHT_TO_LEFT }, - { ":", 15, BINARY, RIGHT_TO_LEFT }, - { "=", 16, BINARY, RIGHT_TO_LEFT }, - { "+=", 16, BINARY, RIGHT_TO_LEFT }, - { "-=", 16, BINARY, RIGHT_TO_LEFT }, - { "*=", 16, BINARY, RIGHT_TO_LEFT }, - { "/=", 16, BINARY, RIGHT_TO_LEFT }, - { "%=", 16, BINARY, RIGHT_TO_LEFT }, - { "<<=", 16, BINARY, RIGHT_TO_LEFT }, - { ">>=", 16, BINARY, RIGHT_TO_LEFT }, - { "&=", 16, BINARY, RIGHT_TO_LEFT }, - { "^=", 16, BINARY, RIGHT_TO_LEFT }, - { "|=", 16, BINARY, RIGHT_TO_LEFT }, - { ",", 17, BINARY, LEFT_TO_RIGHT }, - { { 0 }, 18, NO_OPERATOR, LEFT_TO_RIGHT } -}; - -ProgramParser::ProgramParser(): - module(0) -{ } - -ProgramParser::~ProgramParser() -{ - delete module; -} - -Module &ProgramParser::parse(const string &s, const string &n) -{ - source = s; - source_name = n; - parse_source(); - return *module; -} - -Module &ProgramParser::parse(IO::Base &io, const string &n) -{ - source = string(); - source_name = n; - while(!io.eof()) - { - char buffer[4096]; - unsigned len = io.read(buffer, sizeof(buffer)); - source.append(buffer, len); - } - parse_source(); - return *module; -} - -void ProgramParser::parse_source() -{ - delete module; - module = new Module; - cur_stage = &module->shared; - iter = source.begin(); - current_line = 1; - while(1) - { - while(RefPtr statement = parse_global_declaration()) - cur_stage->content.body.push_back(statement); - - parse_token(); - string token = parse_token(); - if(token.empty()) - break; - else if(token=="vertex") - module->stages.push_back(VERTEX); - else if(token=="geometry") - module->stages.push_back(GEOMETRY); - else if(token=="fragment") - module->stages.push_back(FRAGMENT); - else - throw runtime_error(format("Parse error at '%s': expected stage identifier", token)); - - if(cur_stage->type!=SHARED) - module->stages.back().previous = cur_stage; - cur_stage = &module->stages.back(); - - for(; (iter!=source.end() && *iter!='\n'); ++iter) ; - } -} - -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 (last_token = next_tokens[index]); -} - -const string &ProgramParser::parse_token() -{ - if(!next_tokens.empty()) - { - last_token = next_tokens.front(); - next_tokens.pop_front(); - return last_token; - } - - return (last_token = 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() -{ - if(iter==source.end()) - return string(); - - string token(1, *iter++); - for(unsigned i=1; (i<3 && iter!=source.end()); ++i) - { - bool matched = false; - for(const Operator *j=operators; (!matched && j->type); ++j) - { - matched = (j->token[i]==*iter); - for(unsigned k=0; (matched && ktoken[k]); ++k) - matched = (j->token[k]==token[k]); - } - - if(!matched) - break; - - token += *iter++; - } - - return token; -} - -bool ProgramParser::skip_comment_and_whitespace() -{ - unsigned comment = 0; - unsigned slashes = 0; - while(iter!=source.end()) - { - 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; - } - - if(*iter=='\n') - ++current_line; - - ++iter; - } - - return iter!=source.end(); -} - -void ProgramParser::expect(const string &token) -{ - string parsed = parse_token(); - if(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_syntax_error("a type")); - return token; -} - -string ProgramParser::expect_identifier() -{ - string token = parse_token(); - if(!is_identifier(token)) - throw runtime_error(format_syntax_error("an identifier")); - 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_precision_qualifier(const string &token) -{ - return (token=="highp" || token=="mediump" || token=="lowp"); -} - -bool ProgramParser::is_qualifier(const string &token) -{ - return (token=="const" || is_interface_qualifier(token) || is_sampling_qualifier(token) || is_precision_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) || declared_types.count(token); -} - -bool ProgramParser::is_identifier(const string &token) -{ - static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$"); - return re.match(token); -} - -RefPtr ProgramParser::parse_global_declaration() -{ - string token = peek_token(); - if(token=="import") - return parse_import(); - else if(token=="precision") - return parse_precision(); - else if(token=="layout") - { - RefPtr layout = parse_layout(); - token = peek_token(); - if(is_interface_qualifier(token) && peek_token(1)==";") - { - RefPtr iface_lo = new InterfaceLayout; - iface_lo->layout.qualifiers = layout->qualifiers; - iface_lo->interface = parse_token(); - expect(";"); - return iface_lo; - } - else - { - RefPtr var = parse_variable_declaration(); - var->layout = layout; - return var; - } - } - else if(token=="struct") - return parse_struct_declaration(); - else if(is_interface_qualifier(token)) - { - string next = peek_token(1); - if(is_type(next) || is_precision_qualifier(next)) - return parse_variable_declaration(); - else - return parse_interface_block(); - } - else if(is_qualifier(token)) - return parse_variable_declaration(); - 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("a global declaration")); -} - -RefPtr ProgramParser::parse_statement() -{ - string token = peek_token(); - if(token=="if") - return parse_conditional(); - else if(token=="for") - return parse_iteration(); - else if(token=="passthrough") - return parse_passthrough(); - else if(token=="return") - return parse_return(); - else if(token=="break" || token=="continue" || token=="discard") - { - RefPtr jump = new Jump; - jump->keyword = parse_token(); - expect(";"); - - return jump; - } - else if(is_qualifier(token) || is_type(token)) - return parse_variable_declaration(); - else if(!token.empty()) - { - RefPtr expr = new ExpressionStatement; - expr->expression = parse_expression(); - expect(";"); - - return expr; - } - else - throw runtime_error(format_syntax_error("a statement")); -} - -RefPtr ProgramParser::parse_import() -{ - if(cur_stage->type!=SHARED) - throw runtime_error(format_error("Imports are only allowed in the shared section")); - - expect("import"); - RefPtr import = new Import; - import->module = parse_token(); - expect(";"); - return import; -} - -RefPtr ProgramParser::parse_precision() -{ - expect("precision"); - RefPtr precision = new Precision; - - precision->precision = parse_token(); - if(!is_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_syntax_error("a builtin type")); - - expect(";"); - - return precision; -} - -RefPtr ProgramParser::parse_layout() -{ - expect("layout"); - expect("("); - RefPtr layout = new Layout; - while(1) - { - string token = parse_token(); - if(token==")") - throw runtime_error(format_syntax_error("a layout qualifier name")); - - 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(")"); - - return layout; -} - -void ProgramParser::parse_block(Block &block, bool require_braces) -{ - bool have_braces = (require_braces || peek_token()=="{"); - if(have_braces) - expect("{"); - - if(have_braces) - { - while(peek_token()!="}") - block.body.push_back(parse_statement()); - } - else - block.body.push_back(parse_statement()); - - block.use_braces = (require_braces || block.body.size()!=1); - - if(have_braces) - expect("}"); -} - -RefPtr ProgramParser::parse_expression(unsigned precedence) -{ - RefPtr left; - VariableReference *left_var = 0; - while(1) - { - string token = peek_token(); - - const Operator *oper = 0; - for(Operator *i=operators; (!oper && i->type); ++i) - if(token==i->token && (!left || i->type!=PREFIX) && (left || i->type!=POSTFIX)) - oper = i; - - if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence)) - { - if(left) - return left; - else - throw runtime_error(format_syntax_error("an expression")); - } - else if(left) - { - if(token=="(") - { - if(!left_var) - throw runtime_error(format_error("Syntax error before '(': function name must be an identifier")); - left = parse_function_call(*left_var); - } - else if(token==".") - { - RefPtr memacc = new MemberAccess; - memacc->left = left; - parse_token(); - memacc->member = expect_identifier(); - left = memacc; - } - else if(oper && oper->type==POSTFIX) - { - RefPtr unary = new UnaryExpression; - unary->oper = parse_token(); - unary->prefix = false; - unary->expression = left; - left = unary; - } - else if(oper && oper->type==BINARY) - left = parse_binary(left, oper); - else - throw runtime_error(format_syntax_error("an operator")); - left_var = 0; - } - else - { - if(token=="(") - { - parse_token(); - RefPtr parexpr = new ParenthesizedExpression; - parexpr->expression = parse_expression(); - expect(")"); - left = parexpr; - } - else if(isdigit(token[0]) || token=="true" || token=="false") - { - RefPtr literal = new Literal; - literal->token = parse_token(); - left = literal; - } - else if(is_identifier(token)) - { - RefPtr var = new VariableReference; - var->name = expect_identifier(); - left = var; - left_var = var.get(); - } - else if(oper && oper->type==PREFIX) - { - RefPtr unary = new UnaryExpression; - unary->oper = parse_token(); - unary->prefix = true; - unary->expression = parse_expression(oper->precedence); - left = unary; - } - else - throw runtime_error(format_syntax_error("an expression")); - } - } -} - -RefPtr ProgramParser::parse_binary(const RefPtr &left, const Operator *oper) -{ - RefPtr binary = (oper->precedence==16 ? new Assignment : new BinaryExpression); - binary->left = left; - binary->oper = parse_token(); - if(binary->oper=="[") - { - binary->right = parse_expression(); - expect("]"); - binary->after = "]"; - } - else - binary->right = parse_expression(oper->precedence+(oper->assoc==RIGHT_TO_LEFT)); - return binary; -} - -RefPtr ProgramParser::parse_function_call(const VariableReference &var) -{ - RefPtr call = new FunctionCall; - call->name = var.name; - call->constructor = is_type(call->name); - expect("("); - while(peek_token()!=")") - { - if(!call->arguments.empty()) - expect(","); - call->arguments.push_back(parse_expression()); - } - expect(")"); - return call; -} - -RefPtr ProgramParser::parse_struct_declaration() -{ - expect("struct"); - RefPtr strct = new StructDeclaration; - - strct->name = expect_identifier(); - parse_block(strct->members, true); - expect(";"); - - declared_types.insert(strct->name); - return strct; -} - -RefPtr ProgramParser::parse_variable_declaration() -{ - RefPtr 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_syntax_error("an interface qualifier")); - } - - if(is_interface_qualifier(token)) - var->interface = parse_token(); - else if(token=="const") - { - var->constant = true; - parse_token(); - } - - if(is_precision_qualifier(token)) - var->precision = parse_token(); - - var->type = expect_type(); - var->name = expect_identifier(); - - if(check("[")) - { - var->array = true; - if(!check("]")) - { - var->array_size = parse_expression(); - expect("]"); - } - } - - if(check("=")) - var->init_expression = parse_expression(); - - expect(";"); - return var; -} - -RefPtr ProgramParser::parse_function_declaration() -{ - RefPtr func = new FunctionDeclaration; - - func->return_type = expect_type(); - func->name = expect_identifier(); - expect("("); - while(peek_token()!=")") - { - if(!func->parameters.empty()) - expect(","); - - RefPtr var = new VariableDeclaration; - var->type = expect_type(); - var->name = expect_identifier(); - func->parameters.push_back(var); - } - expect(")"); - - string token = peek_token(); - if(token=="{") - { - func->definition = func.get(); - parse_block(func->body, true); - } - else if(token==";") - parse_token(); - else - throw runtime_error(format_syntax_error("'{' or ';'")); - - return func; -} - -RefPtr ProgramParser::parse_interface_block() -{ - RefPtr iface = new InterfaceBlock; - - iface->interface = parse_token(); - if(!is_interface_qualifier(iface->interface)) - throw runtime_error(format_syntax_error("an interface qualifier")); - - iface->name = expect_identifier(); - parse_block(iface->members, true); - if(!check(";")) - { - iface->instance_name = expect_identifier(); - if(check("[")) - { - iface->array = true; - expect("]"); - } - expect(";"); - } - - return iface; -} - -RefPtr ProgramParser::parse_conditional() -{ - expect("if"); - expect("("); - RefPtr cond = new Conditional; - cond->condition = parse_expression(); - expect(")"); - - parse_block(cond->body, false); - - string token = peek_token(); - if(token=="else") - { - parse_token(); - parse_block(cond->else_body, false); - } - - return cond; -} - -RefPtr ProgramParser::parse_iteration() -{ - expect("for"); - expect("("); - RefPtr loop = new Iteration; - string token = peek_token(); - if(is_type(token)) - loop->init_statement = parse_statement(); - else - { - RefPtr expr = new ExpressionStatement; - expr->expression = parse_expression(); - expect(";"); - loop->init_statement = expr; - } - loop->condition = parse_expression(); - expect(";"); - loop->loop_expression = parse_expression(); - expect(")"); - - parse_block(loop->body, false); - - return loop; -} - -RefPtr ProgramParser::parse_passthrough() -{ - expect("passthrough"); - RefPtr pass = new Passthrough; - if(cur_stage->type==GEOMETRY) - { - expect("["); - pass->subscript = parse_expression(); - expect("]"); - } - expect(";"); - return pass; -} - -RefPtr ProgramParser::parse_return() -{ - expect("return"); - RefPtr ret = new Return; - if(peek_token()!=";") - ret->expression = parse_expression(); - expect(";"); - return ret; -} - -} // namespace GL -} // namespace Msp