X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fprogramparser.cpp;h=c6cdfd06246f1c14683919fcfec637b8adf85058;hb=a36992487d018d8801ead6980b362b00a2f5f5c5;hp=1981f474eb679794fc66b495666f621d93ad2c57;hpb=6e6ee01b68056b23c6709d7f60396710dd7623b9;p=libs%2Fgl.git diff --git a/source/programparser.cpp b/source/programparser.cpp index 1981f474..c6cdfd06 100644 --- a/source/programparser.cpp +++ b/source/programparser.cpp @@ -9,6 +9,55 @@ 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 } +}; + Module &ProgramParser::parse(const string &s) { source = s; @@ -129,14 +178,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; @@ -214,9 +273,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,7 +310,13 @@ 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() @@ -298,7 +362,7 @@ Node *ProgramParser::parse_statement() else if(!token.empty()) { RefPtr expr = new ExpressionStatement; - parse_expression(expr->expression); + expr->expression = parse_expression(); expect(";"); return expr.release(); @@ -343,16 +407,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,26 +421,124 @@ void ProgramParser::parse_block(Block &block, bool require_braces) expect("}"); } -void ProgramParser::parse_expression(Expression &expr) +Expression *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.release(); + 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.release(); + 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.release(); + left = unary; + } + else if(oper && oper->type==BINARY) + left = parse_binary(left.release(), 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(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 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)); + } + } +} - parse_token(); - expr.tokens.push_back(token); +BinaryExpression *ProgramParser::parse_binary(Expression *left, const Operator *oper) +{ + RefPtr binary = 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)); + binary->assignment = (oper->precedence==16); + return binary.release(); +} + +FunctionCall *ProgramParser::parse_function_call(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.release(); } StructDeclaration *ProgramParser::parse_struct_declaration() @@ -391,7 +550,7 @@ StructDeclaration *ProgramParser::parse_struct_declaration() parse_block(strct->members, true); expect(";"); - cur_module->structs[strct->name] = strct.get(); + declared_types.insert(strct->name); return strct.release(); } @@ -424,13 +583,13 @@ 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(); @@ -461,12 +620,9 @@ FunctionDeclaration *ProgramParser::parse_function_declaration() void ProgramParser::parse_function_parameter_list(FunctionDeclaration &func) { expect("("); - while(1) + while(peek_token()!=")") { - string token = peek_token(); - if(token==")") - break; - else if(!func.parameters.empty()) + if(!func.parameters.empty()) expect(","); RefPtr var = new VariableDeclaration; @@ -497,7 +653,7 @@ Conditional *ProgramParser::parse_conditional() expect("if"); expect("("); RefPtr cond = new Conditional; - parse_expression(cond->condition); + cond->condition = parse_expression(); expect(")"); parse_block(cond->body, false); @@ -523,13 +679,13 @@ Iteration *ProgramParser::parse_iteration() else { RefPtr expr = new ExpressionStatement; - parse_expression(expr->expression); + expr->expression = parse_expression(); expect(";"); loop->init_statement = expr.release(); } - 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); @@ -541,7 +697,7 @@ Return *ProgramParser::parse_return() { expect("return"); RefPtr ret = new Return; - parse_expression(ret->expression); + ret->expression = parse_expression(); expect(";"); return ret.release(); }