X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fprogramparser.cpp;h=da3ee0b99f5c383b5f9475676dd2d7b3eeb8c3ff;hb=0ab875bdc9fbf84ecfce883b188410bb45882447;hp=1981f474eb679794fc66b495666f621d93ad2c57;hpb=6e6ee01b68056b23c6709d7f60396710dd7623b9;p=libs%2Fgl.git diff --git a/source/programparser.cpp b/source/programparser.cpp index 1981f474..da3ee0b9 100644 --- a/source/programparser.cpp +++ b/source/programparser.cpp @@ -9,11 +9,69 @@ 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) { source = s; - parse_source(main_module); - return main_module; + parse_source(); + return *module; } Module &ProgramParser::parse(IO::Base &io) @@ -25,35 +83,37 @@ Module &ProgramParser::parse(IO::Base &io) 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; + delete module; + module = new Module; + cur_stage = &module->shared; 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(); + 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=="global") - cur_context = &module.global_context; else if(token=="vertex") - cur_context = &module.vertex_context; + module->stages.push_back(VERTEX); else if(token=="geometry") - cur_context = &module.geometry_context; + module->stages.push_back(GEOMETRY); else if(token=="fragment") - cur_context = &module.fragment_context; + module->stages.push_back(FRAGMENT); else - throw runtime_error(format("Parse error at '%s': expected context identifier", token)); + 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) ; } @@ -129,14 +189,24 @@ 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; @@ -148,7 +218,6 @@ bool ProgramParser::skip_comment_and_whitespace() unsigned slashes = 0; while(iter!=source.end()) { - //IO::print("%d '%c'\n", comment, *iter); if(comment==0) { if(*iter=='/') @@ -214,9 +283,8 @@ string ProgramParser::expect_type() string ProgramParser::expect_identifier() { - static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$"); string token = parse_token(); - if(!re.match(token)) + if(!is_identifier(token)) throw runtime_error(format("Parse error at '%s': expected an identifier", token)); return token; } @@ -252,14 +320,39 @@ 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); } -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=="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") @@ -284,13 +377,15 @@ Node *ProgramParser::parse_global_declaration() throw runtime_error(format("Syntax error at '%s': expected a global declaration", token)); } -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(is_qualifier(token) || is_type(token)) @@ -298,16 +393,28 @@ Node *ProgramParser::parse_statement() 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)); } -Layout *ProgramParser::parse_layout() +RefPtr ProgramParser::parse_import() +{ + if(cur_stage->type!=SHARED) + throw runtime_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_layout() { expect("layout"); expect("("); @@ -331,10 +438,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 +448,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 +462,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("Parse error at '%s': expected an expression", token)); } - else if(token==";") - break; + 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); + } + 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("Parse error at '%s': expected an operator", token)); + 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("Parse error at '%s': expected an expression", token)); + } + } +} - 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; +} + +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; } -StructDeclaration *ProgramParser::parse_struct_declaration() +RefPtr ProgramParser::parse_struct_declaration() { expect("struct"); RefPtr strct = new StructDeclaration; @@ -391,11 +590,11 @@ 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; @@ -424,30 +623,41 @@ 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; + 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==";") @@ -455,29 +665,10 @@ FunctionDeclaration *ProgramParser::parse_function_declaration() 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 var = new VariableDeclaration; - var->type = expect_type(); - var->name = expect_identifier(); - func.parameters.push_back(var.release()); - } - expect(")"); + return func; } -InterfaceBlock *ProgramParser::parse_interface_block() +RefPtr ProgramParser::parse_interface_block() { RefPtr iface = new InterfaceBlock; @@ -487,17 +678,26 @@ InterfaceBlock *ProgramParser::parse_interface_block() 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 +709,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 +723,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