// ident '.' ident
        MemberReferenceExpression ParseMemberRef(BVE5RouteFileLexer lexer, BVE5Language.Ast.Expression parent)
        {
            Token token = lexer.Current;
            Debug.Assert(token.Literal == ".", "Really meant a member reference?");
            lexer.Advance();

            token = lexer.Current;
            Identifier ident = null;
            if(token.Kind == TokenKind.Identifier){
                ident = ParseIdent(lexer);
            }else{
                AddError(ErrorCode.SyntaxError, token.Line, token.Column, "Unexpected token: " + token.Kind);
                if(enable_strict_parsing)
                    return null;
            }

            token = lexer.Current;
            return AstNode.MakeMemRef(parent, ident, parent.StartLocation, token.StartLoc);
        }
        // expr '(' [arguments] ')'
        Expression ParseInvokeExpr(BVE5RouteFileLexer lexer, BVE5Language.Ast.Expression callTarget)
        {
            if(has_error_reported) return callTarget;

            Token token = lexer.Current;
            Debug.Assert(token.Literal == "(", "Really meant an invoke expression?");
            lexer.Advance();
            token = lexer.Current;
            var args = new List<BVE5Language.Ast.Expression>();

            while(token.Kind != TokenKind.EOF && token.Literal != ")"){
                args.Add(ParseRValueExpression(lexer));

                token = lexer.Current;
                if(token.Literal == ","){
                    lexer.Advance();
                    token = lexer.Current;
                }
            }

            if(token.Kind == TokenKind.EOF){
                AddError(ErrorCode.UnexpectedEOF, token.Line, token.Column, "Unexpected EOF!");
                if(enable_strict_parsing)
                    return null;
            }else if(token.Literal != ")"){
                AddError(ErrorCode.SyntaxError, token.Line, token.Column, "Missing ')'");
                if(enable_strict_parsing)
                    return null;
            }else{
                lexer.Advance();
                token = lexer.Current;
            }

            return AstNode.MakeInvoke(callTarget, args, callTarget.StartLocation, token.StartLoc);    //token should be pointing to a closing parenthesis token
        }
        // expr '(' [arguments] ')'
        private InvocationExpression ParseInvokeExpr(BVE5RouteFileLexer lexer, BVE5Language.Ast.Expression callTarget)
        {
            Debug.Assert(lexer.Current.Literal == "(", "Really meant an invoke expression?");
            lexer.Advance();
            Token token = lexer.Current;
            var args = new List<BVE5Language.Ast.Expression>();

            while(token.Kind != TokenKind.EOF && token.Literal != ")"){
                args.Add(ParseArgument(lexer));

                token = lexer.Current;
                if(token.Literal == ","){
                    lexer.Advance();
                    token = lexer.Current;
                }
            }

            if(token.Kind == TokenKind.EOF)
                throw new BVE5ParserException(token.Line, token.Column, "Unexpected EOF!");

            lexer.Advance();
            return AstNode.MakeInvoke(callTarget, args, callTarget.StartLocation, token.EndLoc);
        }
        // ident '.' ident
        private MemberReferenceExpression ParseMemberRef(BVE5RouteFileLexer lexer, BVE5Language.Ast.Expression parent)
        {
            Debug.Assert(lexer.Current.Literal == ".", "Really meant a member reference?");
            lexer.Advance();
            Token token = lexer.Current;
            if(token.Kind != TokenKind.Identifier)
                throw new BVE5ParserException(token.Line, token.Column, "Unexpected token: " + token.Kind);

            Identifier ident = ParseIdent(lexer);
            return AstNode.MakeMemRef(parent, ident, parent.StartLocation, ident.EndLocation);
        }
        // ident '[' ident ']'
        private IndexerExpression ParseIndexExpr(BVE5RouteFileLexer lexer, BVE5Language.Ast.Expression target)
        {
            Debug.Assert(lexer.Current.Literal == "[", "Really meant an index reference?");
            lexer.Advance();
            Token token = lexer.Current;
            if(token.Kind != TokenKind.Identifier)
                throw new BVE5ParserException(token.Line, token.Column, "Unexpected token: " + token.Kind);

            Identifier ident = ParseIdent(lexer);
            token = lexer.Current;
            if(token.Literal != "]")
                throw new BVE5ParserException(token.Line, token.Column, "Expected ']' but got " + token.Literal);

            lexer.Advance();
            return AstNode.MakeIndexExpr(target, ident, target.StartLocation, token.EndLoc);
        }