X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fprogramparser.cpp;h=c3049dd3649bc5b2d3360b5afa7a4c571787d45c;hb=eb6a546dcffc1b67f0a23d8b075fbdc86a2872a0;hp=f003a835b56b0352e7abe2387bcaff24792d87ce;hpb=2b073e0a3808f8ece4b93669395e4b812214cf5d;p=libs%2Fgl.git diff --git a/source/programparser.cpp b/source/programparser.cpp index f003a835..c3049dd3 100644 --- a/source/programparser.cpp +++ b/source/programparser.cpp @@ -67,16 +67,18 @@ ProgramParser::~ProgramParser() 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]; @@ -93,9 +95,10 @@ void ProgramParser::parse_source() module = new Module; cur_stage = &module->shared; iter = source.begin(); + current_line = 1; while(1) { - while(Node *statement = parse_global_declaration()) + while(RefPtr statement = parse_global_declaration()) cur_stage->content.body.push_back(statement); parse_token(); @@ -119,23 +122,34 @@ void ProgramParser::parse_source() } } +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_() @@ -260,6 +274,9 @@ bool ProgramParser::skip_comment_and_whitespace() comment = 3; } + if(*iter=='\n') + ++current_line; + ++iter; } @@ -270,14 +287,14 @@ 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)); + 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; } @@ -285,7 +302,7 @@ string ProgramParser::expect_identifier() { 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; } @@ -307,9 +324,14 @@ 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)); + return (token=="const" || is_interface_qualifier(token) || is_sampling_qualifier(token) || is_precision_qualifier(token)); } bool ProgramParser::is_builtin_type(const string &token) @@ -329,22 +351,44 @@ bool ProgramParser::is_identifier(const string &token) return re.match(token); } -Node *ProgramParser::parse_global_declaration() +RefPtr ProgramParser::parse_global_declaration() { string token = peek_token(); - if(token=="layout") - return parse_layout(); + 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_sampling_qualifier(token) || token=="const") - return parse_variable_declaration(); else if(is_interface_qualifier(token)) { - if(is_type(peek_token(1))) + 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)=="(") @@ -355,10 +399,10 @@ Node *ProgramParser::parse_global_declaration() 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")); } -Node *ProgramParser::parse_statement() +RefPtr ProgramParser::parse_statement() { string token = peek_token(); if(token=="if") @@ -369,6 +413,14 @@ Node *ProgramParser::parse_statement() 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()) @@ -377,13 +429,44 @@ Node *ProgramParser::parse_statement() expr->expression = parse_expression(); expect(";"); - return expr.release(); + return expr; } else - throw runtime_error(format("Syntax error at '%s': expected a statement", token)); + throw runtime_error(format_syntax_error("a statement")); } -Layout *ProgramParser::parse_layout() +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("("); @@ -392,7 +475,7 @@ Layout *ProgramParser::parse_layout() { 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(); @@ -407,10 +490,8 @@ Layout *ProgramParser::parse_layout() expect(","); } expect(")"); - layout->interface = parse_token(); - expect(";"); - return layout.release(); + return layout; } void ProgramParser::parse_block(Block &block, bool require_braces) @@ -433,7 +514,7 @@ void ProgramParser::parse_block(Block &block, bool require_braces) expect("}"); } -Expression *ProgramParser::parse_expression(unsigned precedence) +RefPtr ProgramParser::parse_expression(unsigned precedence) { RefPtr left; VariableReference *left_var = 0; @@ -449,22 +530,22 @@ Expression *ProgramParser::parse_expression(unsigned precedence) if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence)) { if(left) - return left.release(); + 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)); - left = parse_function_call(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.release(); + memacc->left = left; parse_token(); memacc->member = expect_identifier(); left = memacc; @@ -474,13 +555,13 @@ Expression *ProgramParser::parse_expression(unsigned precedence) RefPtr unary = new UnaryExpression; unary->oper = parse_token(); unary->prefix = false; - unary->expression = left.release(); + unary->expression = left; left = unary; } else if(oper && oper->type==BINARY) - left = parse_binary(left.release(), oper); + 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 @@ -493,6 +574,12 @@ Expression *ProgramParser::parse_expression(unsigned precedence) 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; @@ -508,19 +595,13 @@ Expression *ProgramParser::parse_expression(unsigned precedence) unary->expression = parse_expression(oper->precedence); left = unary; } - else if(isdigit(token[0])) - { - RefPtr literal = new Literal; - literal->token = parse_token(); - left = literal; - } else - throw runtime_error(format("Parse error at '%s': expected an expression", token)); + throw runtime_error(format_syntax_error("an expression")); } } } -BinaryExpression *ProgramParser::parse_binary(Expression *left, const Operator *oper) +RefPtr ProgramParser::parse_binary(const RefPtr &left, const Operator *oper) { RefPtr binary = (oper->precedence==16 ? new Assignment : new BinaryExpression); binary->left = left; @@ -533,13 +614,13 @@ BinaryExpression *ProgramParser::parse_binary(Expression *left, const Operator * } else binary->right = parse_expression(oper->precedence+(oper->assoc==RIGHT_TO_LEFT)); - return binary.release(); + return binary; } -FunctionCall *ProgramParser::parse_function_call(VariableReference *var) +RefPtr ProgramParser::parse_function_call(const VariableReference &var) { RefPtr call = new FunctionCall; - call->name = var->name; + call->name = var.name; call->constructor = is_type(call->name); expect("("); while(peek_token()!=")") @@ -549,10 +630,10 @@ FunctionCall *ProgramParser::parse_function_call(VariableReference *var) call->arguments.push_back(parse_expression()); } expect(")"); - return call.release(); + return call; } -StructDeclaration *ProgramParser::parse_struct_declaration() +RefPtr ProgramParser::parse_struct_declaration() { expect("struct"); RefPtr strct = new StructDeclaration; @@ -562,10 +643,10 @@ StructDeclaration *ProgramParser::parse_struct_declaration() expect(";"); declared_types.insert(strct->name); - return strct.release(); + return strct; } -VariableDeclaration *ProgramParser::parse_variable_declaration() +RefPtr ProgramParser::parse_variable_declaration() { RefPtr var = new VariableDeclaration; @@ -575,7 +656,7 @@ VariableDeclaration *ProgramParser::parse_variable_declaration() 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)) @@ -586,6 +667,9 @@ VariableDeclaration *ProgramParser::parse_variable_declaration() parse_token(); } + if(is_precision_qualifier(token)) + var->precision = parse_token(); + var->type = expect_type(); var->name = expect_identifier(); @@ -603,10 +687,10 @@ VariableDeclaration *ProgramParser::parse_variable_declaration() var->init_expression = parse_expression(); expect(";"); - return var.release(); + return var; } -FunctionDeclaration *ProgramParser::parse_function_declaration() +RefPtr ProgramParser::parse_function_declaration() { RefPtr func = new FunctionDeclaration; @@ -621,31 +705,31 @@ FunctionDeclaration *ProgramParser::parse_function_declaration() RefPtr var = new VariableDeclaration; var->type = expect_type(); var->name = expect_identifier(); - func->parameters.push_back(var.release()); + func->parameters.push_back(var); } expect(")"); string token = peek_token(); if(token=="{") { - func->definition = true; + func->definition = func.get(); parse_block(func->body, true); } 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.release(); + return func; } -InterfaceBlock *ProgramParser::parse_interface_block() +RefPtr ProgramParser::parse_interface_block() { RefPtr 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)); + throw runtime_error(format_syntax_error("an interface qualifier")); iface->name = expect_identifier(); parse_block(iface->members, true); @@ -660,10 +744,10 @@ InterfaceBlock *ProgramParser::parse_interface_block() expect(";"); } - return iface.release(); + return iface; } -Conditional *ProgramParser::parse_conditional() +RefPtr ProgramParser::parse_conditional() { expect("if"); expect("("); @@ -680,10 +764,10 @@ Conditional *ProgramParser::parse_conditional() parse_block(cond->else_body, false); } - return cond.release(); + return cond; } -Iteration *ProgramParser::parse_iteration() +RefPtr ProgramParser::parse_iteration() { expect("for"); expect("("); @@ -696,7 +780,7 @@ Iteration *ProgramParser::parse_iteration() RefPtr expr = new ExpressionStatement; expr->expression = parse_expression(); expect(";"); - loop->init_statement = expr.release(); + loop->init_statement = expr; } loop->condition = parse_expression(); expect(";"); @@ -705,10 +789,10 @@ Iteration *ProgramParser::parse_iteration() parse_block(loop->body, false); - return loop.release(); + return loop; } -Passthrough *ProgramParser::parse_passthrough() +RefPtr ProgramParser::parse_passthrough() { expect("passthrough"); RefPtr pass = new Passthrough; @@ -719,17 +803,17 @@ Passthrough *ProgramParser::parse_passthrough() expect("]"); } expect(";"); - return pass.release(); + return pass; } -Return *ProgramParser::parse_return() +RefPtr ProgramParser::parse_return() { expect("return"); RefPtr ret = new Return; if(peek_token()!=";") ret->expression = parse_expression(); expect(";"); - return ret.release(); + return ret; } } // namespace GL