Often this type of notation looks like a nightmare to someone learning assembler but once you get the swing of how it is constructed its a very clear and precise notation.
Here is a simple demo to show how it works.
#IF 0 ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Build with PBCC50
Intel complex addressing mode.
BASE REGISTER --- INDEX --- MULTIPLIER --- DISPLACEMENT
mov esi, address ; ESI as base register
mov edi, 16 ; EDI as the INDEX
mov eax, [esi+edi*4+128]
copy the contents at address + index times 4 + displacement into register EAX
#ENDIF ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
FUNCTION PBmain as LONG
#REGISTER NONE
LOCAL svar as LONG
LOCAL uvar as DWORD
LOCAL parr as DWORD
dim iarr(0 to 9) as LONG ' dimension a 10 item integer array
iarr(0) = 0000
iarr(1) = 1111
iarr(2) = 2222
iarr(3) = 3333
iarr(4) = 4444
iarr(5) = 5555
iarr(6) = 6666
iarr(7) = 7777
iarr(8) = 8888
iarr(9) = 9999
parr = VarPtr(iarr(0)) ' get the address of the first element
! mov esi, parr ' use ESI as the BASE REGISTER
! xor edi, edi ' use EDI as the INDEX REGISTER
' --------------------------------
' read array by altering the INDEX
' --------------------------------
! mov eax, [esi+edi*4] ' get the content of member ZERO in one instruction
! mov uvar, eax
cout ustr(uvar)
! add edi, 6
! mov eax, [esi+edi*4] ' get the content of member SIX in one instruction
! mov uvar, eax
cout ustr(uvar)
' ---------------------------------------
' read array by altering the displacement
' ---------------------------------------
! mov eax, [esi+16] ' get the contents of member 4 in one instruction
! mov uvar, eax
cout ustr(uvar)
! mov eax, [esi+32] ' get the contents of member 8 in one instruction
! mov uvar, eax
cout ustr(uvar)
' -----------------------------------------
' read from a BYTE table in one instruction
' zero extend it to 32 bit and display it
' -----------------------------------------
' Using this notation the location "ctable" is effectively a DISPLACEMENT.
' For it to work it is an OFFSET determined at compile time.
! movzx eax, BYTE PTR ctable[51] ' disassembly >>> movzx eax,byte ptr [401453h]
! mov uvar, eax
cout ustr(uvar)
' setting a register like an INDEX changes the output OPCODE
' EDI becomes the BASE REGISTER and the location "ctable"
' is a DISPLACEMENT added to it.
! mov edi, 66 ' set the INDEX
! movzx eax, BYTE PTR ctable[edi] ' disassembly >>> movzx eax,byte ptr [edi+401420h]
! mov uvar, eax
cout ustr(uvar)
pause
FUNCTION = 0
Exit FUNCTION
#align 4
ctable:
! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
! db 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0 ' numbers
! db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ' upper case
! db 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
! db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ' lower case
! db 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
! db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
End FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
DECLARE FUNCTION cc_out CDECL LIB "MSVCRT.DLL" ALIAS "puts" (BYVAL ptxt AS DWORD) AS DWORD
SUB cout(a$)
' ***** Supported escapes *****
' \0 = ascii zero 0
' \t = tab 9
' \n = newline 10
' \r = carriage return 13
' \q = double quote 34
' \\ = backslash 92
' *****************************
#REGISTER NONE
LOCAL src as DWORD
LOCAL dst as DWORD
LOCAL sln as DWORD
src = StrPtr(a$)
! mov esi, src
! mov edi, src
stlp:
! mov al, [esi]
! add esi, 1
! cmp al, "\"
! jne nxt
' ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤
! cmp BYTE PTR [esi], "n"
! jne lb1
! add esi, 1
! mov BYTE PTR [edi], 10
! add edi, 1
! jmp stlp
lb1:
! cmp BYTE PTR [esi], "r"
! jne lb2
! add esi, 1
! mov BYTE PTR [edi], 13
! add edi, 1
! jmp stlp
lb2:
! cmp BYTE PTR [esi], "t"
! jne lb3
! add esi, 1
! mov BYTE PTR [edi], 9
! add edi, 1
! jmp stlp
lb3:
! cmp BYTE PTR [esi], "0"
! jne lb4
! add esi, 1
! mov BYTE PTR [edi], 0
! add edi, 1
! jmp stlp
lb4:
! cmp BYTE PTR [esi], "\"
! jne lb5
! add esi, 1
! mov BYTE PTR [edi], 92
! add edi, 1
! jmp stlp
lb5:
! cmp BYTE PTR [esi], "q"
! jne lb6
! add esi, 1
! mov BYTE PTR [edi], 34
! add edi, 1
! jmp stlp
lb6:
' ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤
nxt:
! mov [edi], al
! add edi, 1
! test al, al
! jnz stlp
! sub edi, src
! mov sln, edi
cesc$ = left$(a$,sln)
cc_out StrPtr(cesc$)
END SUB
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
MACRO INPUT_HANDLE = -10&
DECLARE FUNCTION kbflush LIB "KERNEL32.DLL" ALIAS "FlushConsoleInputBuffer" ( _
BYVAL hConsoleInput AS DWORD) AS LONG
DECLARE FUNCTION hStdIn LIB "KERNEL32.DLL" ALIAS "GetStdHandle" ( _
BYVAL nStdHandle AS DWORD) AS DWORD
DECLARE FUNCTION SysYield LIB "KERNEL32.DLL" ALIAS "Sleep" ( _
BYVAL msWait AS DWORD) AS LONG
DECLARE FUNCTION keypress CDECL LIB "MSVCRT.DLL" ALIAS "_kbhit" () as DWORD
DECLARE FUNCTION putz CDECL LIB "MSVCRT.DLL" ALIAS "puts" (BYVAL ptxt AS DWORD) AS DWORD
' -------------------------------------------
SUB pause()
txt$ = "Press any key to continue ...."
putz StrPtr(txt$)
kbflush hStdIn(INPUT_HANDLE)
lbl0:
SysYield 20
keypress
! test eax, eax
! jz lbl0
END SUB
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
DECLARE FUNCTION ltoa CDECL LIB "MSVCRT.DLL" ALIAS "_ltoa" ( _
ByVal lval as LONG,ByVal pstr as DWORD,ByVal radix as DWORD) as DWORD
' -------------------------------------------
FUNCTION sstr(ByVal lval as LONG) as STRING
LOCAL astring as ASCIIZ * 32
ltoa(lval,VarPtr(astring),10)
FUNCTION = astring
End FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
DECLARE FUNCTION c_ultoa CDECL LIB "MSVCRT.DLL" ALIAS "_ultoa" ( _
ByVal uint as DWORD,ByVal pstr as DWORD,ByVal radix as DWORD) as DWORD
' -------------------------------------------
FUNCTION ustr(ByVal uint as DWORD) as STRING
LOCAL astring as ASCIIZ * 32
c_ultoa(uint,VarPtr(astring),10)
FUNCTION = astring
End FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
DECLARE FUNCTION c_atoi CDECL LIB "MSVCRT.DLL" ALIAS "atoi" (ByVal ptxt as DWORD) as DWORD
FUNCTION atoi(number$) as DWORD
FUNCTION = c_atoi(StrPtr(number$))
End FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
DECLARE FUNCTION c_atol CDECL LIB "MSVCRT.DLL" ALIAS "atol" (ByVal ptxt as DWORD) as LONG
FUNCTION atol(number$) as LONG
FUNCTION = c_atol(StrPtr(number$))
End FUNCTION
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤