An address is just a standardized way to encode an output script. They aren't part of the Bitcoin protocol, and only a few standard scripts have an associated address. As of now these are P2PKH, P2SH, P2WPKH, P2WSH and P2TR.
I won't go into exact details on how to convert each of these scripts into an address, but I'll give helpful links.
P2PKH (Pay to Public Key Hash)
A P2PKH output scripts looks like this:
OP_DUP OP_HASH160 OP_PUSHBYTES_20 <key_hash> OP_EQUALVERIFY OP_CHECKSIG
<key_hash> part is a 160-bit hash (SHA-256 then RIPEMD-160) of a public key. The address always starts with a
1. More details here.
P2SH (Pay to Script Hash)
A P2SH output script looks like this:
OP_HASH160 OP_PUSHBYTES_20 <script_hash> OP_EQUAL
<script_hash> part is a 160-bit hash of a redeem script. The address always starts with a
3 and is constructed similarly to P2PKH. More details in BIP13.
P2WPKH (Pay to Witness Public Key Hash)
A P2WPKH output script looks like this:
OP_0 OP_PUSHBYTES_20 <key_hash>
As in P2PKH,
<key_hash> is a 160-bit hash of a public key. The address always starts with
bc1q. More details in BIP173.
P2WSH (Pay to Witness Script Hash)
A P2WSH output script looks like this:
OP_0 OP_PUSHBYTES_32 <script_hash>
<script_hash> part is a 256-bit hash (double SHA-256) of a redeem script. As with P2WPKH the address always starts with
bc1q and is also specified in BIP173.
P2TR (Pay to Taproot)
A P2TR output script looks like this:
OP_1 OP_PUSHBYTES_32 <key>
<key> part is a BIP340 public key. The address always starts with
bc1p. More details in BIP350.