Regarding Macro substitution

In my top_tb I have the following code

 axi32_intf   s_axi_fw_if ( .clk( axi_clk ) , .rst_n( rst ) );
 ...................................
 xam_intf     xam_if ( .ACLK( axi_clk ) , ARESET_N( rst ) );

`connect_axi32_intf_to_xam_intf(  s_axi_fw_if , xam_if )

The definition for macro `connect_axi32_intf_to_xam_intf is as follows ::

 `define connect_axi32_intf_to_xam_intf( intf1 , intf2 ) \
  assign ``intf1``.arvalid  = ``intf2``.ARVALID ; \
  assign ``intf1``.arvid    = ``intf2``.ARID ; \
  assign ``intf1``.araddr   = ``intf2``.ARADDR ; \
  assign ``intf1``.arlen    = ``intf2``.ARLEN ; \
  assign ``intf1``.arburst  = ``intf2``.ARBURST ; \
  assign ``intf2``.arready  = ``intf2``.ARREADY ; \
  ...............................

I am aware that the macro replaces intf1 and intf2 by the actual arguments s_axi_fw_if and xam_if respectively via the 1st `` on both LHS and RHS

[A] What is the use of 2nd `` , why can’t we simply write as

  assign ``intf1.arvalid  = ``intf2.ARVALID ; \

instead of

  assign ``intf1``.arvalid  = ``intf2``.ARVALID ; \

[B] Without the macro, is it possible to achieve the same signal assignment using ‘bind’ construct ?

[C] Are macros also called as pre-processor compiler directives ? i.e before start of compilation stage the compiler replaces the macros with the respective definition

There is no need for any ``'s here. They are a token merging operator, not quotes. You use them when you want to merge a macro argument with other text to create a new identifier. (and yes this only works inside a macro as a pre-processor compiler directive.

 `define connect_axi32_intf_to_xam_intf( intf1 , intf2 ) \
  assign intf1``_if.arvalid  = intf2``_if.ARVALID ; \

Then you can leave off if _if when invoking the macro

`connect_axi32_intf_to_xam_intf(s_axi_fw , xam)

The only only other way of connecting signals inside interfaces together is through port connections like you have done with clk and rst