X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fprogramparser.cpp;h=3b87ea7b58b1a2a16c1a09d3cd6432c53009d73f;hp=1981f474eb679794fc66b495666f621d93ad2c57;hb=20af6dd2f04caa224d8cae00befc97d010a1ed08;hpb=6e6ee01b68056b23c6709d7f60396710dd7623b9 diff --git a/source/programparser.cpp b/source/programparser.cpp index 1981f474..3b87ea7b 100644 --- a/source/programparser.cpp +++ b/source/programparser.cpp @@ -1,3 +1,4 @@ +#include #include #include #include "programparser.h" @@ -9,92 +10,166 @@ namespace GL { using namespace ProgramSyntax; -Module &ProgramParser::parse(const string &s) +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; - parse_source(main_module); - return main_module; + 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]; unsigned len = io.read(buffer, sizeof(buffer)); source.append(buffer, len); } - parse_source(main_module); - return main_module; + parse_source(); + return *module; } -void ProgramParser::parse_source(Module &module) +void ProgramParser::parse_source() { - 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()) + string::size_type slashes = source.find("//////"); + if(slashes==string::npos) 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) ; + string::size_type newline = source.find('\n', slashes); + string pragma = format("#pragma MSP stage(%s)", source.substr(slashes+6, newline-slashes-6)); + source.replace(slashes, newline-slashes, pragma); } + + delete module; + module = new Module; + cur_stage = &module->shared; + iter = source.begin(); + source_end = source.end(); + current_line = 1; + allow_preprocess = true; + while(RefPtr statement = parse_global_declaration()) + cur_stage->content.body.push_back(statement); +} + +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_() { - 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(); + while(1) + { + skip_comment_and_whitespace(); + if(iter==source_end) + return string(); + else if(allow_preprocess && *iter=='#') + { + allow_preprocess = false; + SetForScope > clear_tokens(next_tokens, deque()); + preprocess(); + } + else 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()) + while(iter!=source_end) { if(isalnum(*iter) || *iter=='_') ident += *iter++; @@ -109,7 +184,7 @@ string ProgramParser::parse_number() { bool accept_sign = false; string number; - while(iter!=source.end()) + while(iter!=source_end) { if(isdigit(*iter) || *iter=='.') number += *iter++; @@ -129,26 +204,34 @@ string ProgramParser::parse_number() string ProgramParser::parse_other() { - string token; - while(iter!=source.end()) + if(iter==source_end) + return string(); + + string token(1, *iter++); + for(unsigned i=1; (i<3 && iter!=source_end); ++i) { - if(isalnum(*iter) || *iter=='_' || isspace(*iter)) + 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++; - if(*iter==';' || *iter=='(' || *iter==')' || *iter=='[' || *iter==']') - break; } return token; } -bool ProgramParser::skip_comment_and_whitespace() +void ProgramParser::skip_comment_and_whitespace() { unsigned comment = 0; - unsigned slashes = 0; - while(iter!=source.end()) + while(iter!=source_end) { - //IO::print("%d '%c'\n", comment, *iter); if(comment==0) { if(*iter=='/') @@ -159,10 +242,7 @@ bool ProgramParser::skip_comment_and_whitespace() else if(comment==1) { if(*iter=='/') - { comment = 2; - slashes = 2; - } else if(*iter=='*') comment = 3; else @@ -176,10 +256,6 @@ bool ProgramParser::skip_comment_and_whitespace() { if(*iter=='\n') comment = 0; - else if(*iter=='/') - ++slashes; - else if(!isspace(*iter) && slashes>=6) - return false; } else if(comment==3 && *iter=='*') comment = 4; @@ -187,37 +263,40 @@ bool ProgramParser::skip_comment_and_whitespace() { if(*iter=='/') comment = 0; - else + else if(*iter!='*') comment = 3; } + if(*iter=='\n') + { + ++current_line; + allow_preprocess = (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)); + 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 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)); + if(!is_identifier(token)) + throw runtime_error(format_syntax_error("an identifier")); return token; } @@ -236,12 +315,26 @@ bool ProgramParser::is_interface_qualifier(const string &token) bool ProgramParser::is_sampling_qualifier(const string &token) { - return token=="centroid"; + return (token=="centroid" || token=="sample"); +} + +bool ProgramParser::is_interpolation_qualifier(const string &token) +{ + return (token=="smooth" || token=="flat" || token=="noperspective"); +} + +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_interpolation_qualifier(token) || + is_precision_qualifier(token)); } bool ProgramParser::is_builtin_type(const string &token) @@ -252,25 +345,126 @@ bool ProgramParser::is_builtin_type(const string &token) bool ProgramParser::is_type(const string &token) { - return is_builtin_type(token) || cur_module->structs.count(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); +} + +void ProgramParser::preprocess() +{ + expect("#"); + + string::const_iterator line_end = iter; + for(; (line_end!=source_end && *line_end!='\n'); ++line_end) ; + SetForScope stop_at_line_end(source_end, line_end); + + string token = peek_token(); + if(token=="pragma") + preprocess_pragma(); + else if(token=="define" || token=="undef" || token=="if" || token=="ifdef" || token=="ifndef" || token=="else" || + token=="elif" || token=="endif" || token=="error" || token=="extension" || token=="version" || token=="line") + throw runtime_error(format_error(format("Unsupported preprocessor directive '%s'", token))); + else if(!token.empty()) + throw runtime_error(format_syntax_error("a preprocessor directive")); + + iter = line_end; +} + +void ProgramParser::preprocess_pragma() +{ + expect("pragma"); + string token = parse_token(); + if(token=="MSP") + preprocess_pragma_msp(); +} + +void ProgramParser::preprocess_pragma_msp() +{ + string token = peek_token(); + if(token=="stage") + preprocess_stage(); + else + throw runtime_error(format_error(format("Unrecognized MSP pragma '%s'", token))); + + token = parse_token(); + if(!token.empty()) + throw runtime_error(format_syntax_error("end of line")); +} + +void ProgramParser::preprocess_stage() +{ + if(!allow_stage_change) + throw runtime_error(format_error("Changing stage not allowed here")); + + expect("stage"); + expect("("); + string token = expect_identifier(); + StageType stage = SHARED; + if(token=="vertex") + stage = VERTEX; + else if(token=="geometry") + stage = GEOMETRY; + else if(token=="fragment") + stage = FRAGMENT; + else + throw runtime_error(format_syntax_error("stage identifier")); + expect(")"); + + if(stage<=cur_stage->type) + throw runtime_error(format_error(format("Stage '%s' not allowed here", token))); + + module->stages.push_back(stage); + + if(cur_stage->type!=SHARED) + module->stages.back().previous = cur_stage; + cur_stage = &module->stages.back(); } -Node *ProgramParser::parse_global_declaration() +RefPtr ProgramParser::parse_global_declaration() { + allow_stage_change = true; string token = peek_token(); - if(token=="layout") - return parse_layout(); + allow_stage_change = false; + + 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_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)=="(") @@ -281,33 +475,74 @@ 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") 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; - parse_expression(expr->expression); + 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")); +} + +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; } -Layout *ProgramParser::parse_layout() +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("("); @@ -316,7 +551,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(); @@ -331,10 +566,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) @@ -343,16 +576,13 @@ void ProgramParser::parse_block(Block &block, bool require_braces) if(have_braces) expect("{"); - while(1) + if(have_braces) { - string token = peek_token(); - if(token=="}") - break; - - block.body.push_back(parse_statement()); - if(!have_braces) - break; + 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); @@ -360,29 +590,126 @@ void ProgramParser::parse_block(Block &block, bool require_braces) expect("}"); } -void ProgramParser::parse_expression(Expression &expr) +RefPtr ProgramParser::parse_expression(unsigned precedence) { - unsigned nesting_level = 0; - while(iter!=source.end()) + RefPtr left; + VariableReference *left_var = 0; + while(1) { string token = peek_token(); - if(token=="(" || token=="[") - ++nesting_level; - else if(token==")" || 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(!nesting_level) - break; - --nesting_level; + if(left) + return left; + else + throw runtime_error(format_syntax_error("an expression")); } - else if(token==";") - break; + 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")); + } + } +} - parse_token(); - expr.tokens.push_back(token); +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; } -StructDeclaration *ProgramParser::parse_struct_declaration() +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; @@ -391,29 +718,29 @@ StructDeclaration *ProgramParser::parse_struct_declaration() parse_block(strct->members, true); expect(";"); - cur_module->structs[strct->name] = strct.get(); - return strct.release(); + declared_types.insert(strct->name); + return strct; } -VariableDeclaration *ProgramParser::parse_variable_declaration() +RefPtr ProgramParser::parse_variable_declaration() { RefPtr var = new VariableDeclaration; string token = peek_token(); - if(is_sampling_qualifier(token)) + while(is_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(); + if(is_interface_qualifier(token)) + var->interface = token; + else if(is_sampling_qualifier(token)) + var->sampling = token; + else if(is_interpolation_qualifier(token)) + var->interpolation = token; + else if(is_precision_qualifier(token)) + var->precision = token; + else if(token=="const") + var->constant = true; + token = peek_token(); } var->type = expect_type(); @@ -424,80 +751,84 @@ VariableDeclaration *ProgramParser::parse_variable_declaration() var->array = true; if(!check("]")) { - parse_expression(var->array_size); + var->array_size = parse_expression(); expect("]"); } } if(check("=")) - parse_expression(var->init_expression); + 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; func->return_type = expect_type(); func->name = expect_identifier(); - parse_function_parameter_list(*func); + expect("("); + while(peek_token()!=")") + { + if(!func->parameters.empty()) + expect(","); + + RefPtr var = new VariableDeclaration; + string token = peek_token(); + if(token=="in" || token=="out" || token=="inout") + var->interface = parse_token(); + var->type = expect_type(); + var->name = expect_identifier(); + 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; } -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 var = new VariableDeclaration; - var->type = expect_type(); - var->name = expect_identifier(); - func.parameters.push_back(var.release()); - } - expect(")"); -} - -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); - expect(";"); + if(!check(";")) + { + iface->instance_name = expect_identifier(); + if(check("[")) + { + iface->array = true; + expect("]"); + } + expect(";"); + } - return iface.release(); + return iface; } -Conditional *ProgramParser::parse_conditional() +RefPtr ProgramParser::parse_conditional() { expect("if"); expect("("); RefPtr cond = new Conditional; - parse_expression(cond->condition); + cond->condition = parse_expression(); expect(")"); parse_block(cond->body, false); @@ -509,10 +840,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("("); @@ -523,27 +854,42 @@ Iteration *ProgramParser::parse_iteration() else { RefPtr expr = new ExpressionStatement; - parse_expression(expr->expression); + expr->expression = parse_expression(); expect(";"); - loop->init_statement = expr.release(); + loop->init_statement = expr; } - parse_expression(loop->condition); + loop->condition = parse_expression(); expect(";"); - parse_expression(loop->loop_expression); + loop->loop_expression = parse_expression(); expect(")"); parse_block(loop->body, false); - return loop.release(); + 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; } -Return *ProgramParser::parse_return() +RefPtr ProgramParser::parse_return() { expect("return"); RefPtr ret = new Return; - parse_expression(ret->expression); + if(peek_token()!=";") + ret->expression = parse_expression(); expect(";"); - return ret.release(); + return ret; } } // namespace GL