unittest
{
	assert( [ "?ABC" ].solve == 4 );		// 追加ケース
	assert( [ "ABC?" ].solve == 4 );		// 追加ケース
	
	assert( [ "A??C" ].solve == 8 );
	assert( [ "ABCBC" ].solve == 3 );
	assert( [ "????C?????B??????A???????" ].solve == 979596887 );
}



import std.conv;
import std.range;
import std.stdio;

void main()
{
	stdin.byLineCopy.solve.writeln;
}

auto solve( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto s = input.front.to!( dchar[] );
	
	// dp[ i文字目 ][ ABCのうちj文字一致した ] = パターン数
	const M = 10L ^^ 9 + 7;
	auto dp = new ModWorld!M[][]( 1 + s.length, 3 );
	auto q = ModWorld!M( 1L );
	foreach( i, c; s )
	{
		dp[ i + 1 ][ 0 ] = dp[ i ][ 0 ];
		dp[ i + 1 ][ 1 ] = dp[ i ][ 1 ];
		dp[ i + 1 ][ 2 ] = dp[ i ][ 2 ];
		
		// ?の場合、ここまでの全パターンが3倍になる
		if( c == '?' )
		{
			dp[ i + 1 ][ 0 ] *= 3;
			dp[ i + 1 ][ 1 ] *= 3;
			dp[ i + 1 ][ 2 ] *= 3;
		}
		
		// 文字がABCと一致しているか判定
		if( c == 'A' || c == '?' ) dp[ i + 1 ][ 0 ] += q;
		if( c == 'B' || c == '?' ) dp[ i + 1 ][ 1 ] += dp[ i ][ 0 ];
		if( c == 'C' || c == '?' ) dp[ i + 1 ][ 2 ] += dp[ i ][ 1 ];
		
		// ?の場合、ここからの全パターンが3倍になる
		if( c == '?' ) q *= 3;
	}
	return dp[ $ - 1 ][ $ - 1 ];
}

// モジュラ整数型（n mod M）
struct ModWorld( long M )
{
	long n;
	
	void opUnary( string OP )() if( OP == "++" ){ this.n = ( this.n + 1 ) % M; }
	void opUnary( string OP )() if( OP == "--" ){ this.n = ( this.n + M - 1 ) % M; }
	void opOpAssign( string OP )( ModWorld r ) if( OP == "+"  ){ this.n = ( this.n + r.n ) % M; }
	void opOpAssign( string OP )( ModWorld r ) if( OP == "-"  ){ this.n = ( this.n + M - r.n ) % M; }
	void opOpAssign( string OP )( ModWorld r ) if( OP == "*"  ){ this.n = ( this.n * r.n ) % M; }
	void opOpAssign( string OP )( ModWorld r ) if( OP == "/"  ){ this *= r ^^ ModWorld( M - 2 ); }
	void opOpAssign( string OP )( ModWorld r ) if( OP == "^^" )
	{
		auto a = this.n;
		this.n = 1L;
		for( auto i = r.n; 0 < i; i >>= 1 )
		{
			if( i & 1 ) this.n = ( this.n * a ) % M;
			a = ( a * a ) % M;
		}
	}
	auto opBinary( string OP )( ModWorld r ){ auto l = this; l.opOpAssign!OP( r ); return l; }
	
	void opAssign( long r ){ this.n = r; }
	void opOpAssign( string OP )( long r ){ this.opOpAssign!OP( ModWorld( r ) ); }
	auto opBinary( string OP )( long r ){ return this.opBinary!OP( ModWorld( r ) ); }
	auto opBinaryRight( string OP )( long l ){ return ModWorld( l ).opBinary!OP( this ); }
	auto opEquals( long r ){ return this.n == r; }
	
	auto toString(){ return this.n.to!string; }
}
