flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > My Master Macro File

Author
Thread Post new topic Reply to topic
alwaysnub



Joined: 30 Mar 2013
Posts: 26
alwaysnub 14 Apr 2013, 05:07
While working on my master macro file i noticed that fasm ver 1.70.03 does not have .break or .continue in its IF macro file, might be something to consider adding.

Anyways here is my master macro code.
If you have any comments, suggestions or if you find any bugs please post.

Code:
;Condition operators are,
; = (equal), < (less), > (greater), <= (less or equal), >= (greater or equal), <> (not equal).

macro USE_16
{
    USE16
    Bit_Mode equ 16
}

macro USE_32
{
    USE32
    Bit_Mode equ 32
}

macro USE_64
{
    USE64
    Bit_Mode equ 64
}

macro .while [arg]
{
    local ..while
    __WHILE equ ..while
    local ..endw
    __ENDW equ ..endw
    __WHILE:
    .break equ JMP __ENDW
    if ~ arg eq
        JMPCOND __ENDW,arg
    end if
    .continue equ JMP __WHILE
}

macro .endw
{
    JMP __WHILE
    __ENDW:
    restore .continue
    restore .break
    restore __ENDW
    restore __WHILE
}

macro .if [arg]
{
    __IF equ
    local ..endif
    __ENDIF equ ..endif
    local ..else
    __ELSE equ ..else
    JMPCOND __ELSE,arg
}

macro .else
{
    JMP __ENDIF
    __ELSE:
    restore __IF
    __IF equ ,
}

macro .elseif [arg]
{
    JMP __ENDIF
    __ELSE:
    restore __ELSE
    local ..else
    __ELSE equ ..else
    JMPCOND __ELSE,arg
}

macro .endif
{
    if __IF eq
        __ELSE:
    end if
    __ENDIF:
    restore __ELSE
    restore __ENDIF
    restore __IF
}

macro JMPCOND label,arg
{
    v2loop equ 0
    CurrentLoop equ 0
    JMPCONDITION equ JN
    AssembleCode equ FALSE
    asmCode equ

    irps symb,arg
    \{
         match =0, CurrentLoop
         \\{
               v1 equ symb
               rept 1 v2loopX:v2loop+1 \\\{ v2loop equ v2loopX \\\}
         \\}
         match ==, symb
         \\{
               JMPCONDITION equ JMPCONDITION\\\#E
               rept 1 v2loopX:v2loop+1 \\\{ v2loop equ v2loopX \\\}
         \\}
         match =>, symb
         \\{
               JMPCONDITION equ JMPCONDITION\\\#G
               rept 1 v2loopX:v2loop+1 \\\{ v2loop equ v2loopX \\\}
               match =JN\\\#L\\\#G, JMPCONDITION \\\{ JMPCONDITION equ JE \\\}
         \\}
         match =<, symb
         \\{
               JMPCONDITION equ JMPCONDITION\\\#L
               rept 1 v2loopX:v2loop+1 \\\{ v2loop equ v2loopX \\\}
         \\}
         match v2loopX, v2loop
         \\{
               match =v2loopX, CurrentLoop
               \\\{
                      v2 equ symb
               \\\}
         \\}
         match =TRUE, AssembleCode
         \\{
               asmCode equ asmCode\symb
         \\}
         match =:, symb
         \\{
               AssembleCode equ TRUE
         \\}
         rept 1 CrrtLoopX:CurrentLoop+1 \\{ CurrentLoop equ CrrtLoopX \\}
    \}

    match JMPx, JMPCONDITION \{ JMPCONDITION equ JMPx \}
    asmCode
    CMP v1,v2
    JMPCONDITION label
}

macro PROC ProcName,[arg] ;Define procedure.
{
    common
    ProcName:

    match =16, Bit_Mode
    \{
         PUSH BP
         MOV BP,SP
         ParamOffset equ 4
         bpReg equ BP
    \}
    match =32, Bit_Mode
    \{
         PUSH EBP
         MOV EBP,ESP
         ParamOffset equ 8
         bpReg equ EBP
    \}
    match =64, Bit_Mode
    \{
         PUSH RBP
         MOV RBP,RSP
         ParamOffset equ 16
         bpReg equ RBP
    \}

    ParamNamesToFix equ

    forward
    match argName:argType, arg
    \{
         match =WORD, argType
         \\{
               ParamNamesToFix equ ParamNamesToFix\argName
               argName equ bpReg+ParamOffset
               rept 1 PrmOffsetX:ParamOffset+2 \\\{ ParamOffset equ PrmOffsetX \\\}
         \\}
         match =DWORD, argType
         \\{
               ParamNamesToFix equ ParamNamesToFix\argName
               argName equ bpReg+ParamOffset
               rept 1 PrmOffsetX:ParamOffset+4 \\\{ ParamOffset equ PrmOffsetX \\\}
         \\}
         match =QWORD, argType
         \\{
               ParamNamesToFix equ ParamNamesToFix\argName
               argName equ bpReg+ParamOffset
               rept 1 PrmOffsetX:ParamOffset+8 \\\{ ParamOffset equ PrmOffsetX \\\}
         \\}
    \}
}

macro ENDP ;End procedure.
{
    match =16, Bit_Mode
    \{
         POP BP
         RET ParamOffset-4
    \}
    match =32, Bit_Mode
    \{
         POP EBP
         RET ParamOffset-8
    \}
    match =64, Bit_Mode
    \{
         POP RBP
         RET ParamOffset-16
    \}
    match Params, ParamNamesToFix
    \{
         irps argName, Params
         \\{
               restore argName
         \\}
    \}
}

macro PCALL ProcName,[arg] ;Directly call procedure.
{
    common
    if ~ arg eq
        reverse
        PUSH arg
        common
    end if
    CALL ProcName
}

macro PICALL ProcPointer,[arg] ;Indirectly call procedure.
{
    common
    if ~ arg eq
        reverse
        PUSH arg
        common
    end if
    CALL [ProcPointer]
}    


Example usage:

Code:
USE_16
ORG 0

PCALL MyFunction, WORD AX, WORD BX

PROC MyFunction, Var1:WORD, Var2:WORD
MOV AX,WORD [Var1]
.while AX < 10 : INC AX
.if AX < 5
.continue
.endif
.if AX > 5
.break ;break before we get to 10, because we can lol
.endif
.endw
ENDP    


Last edited by alwaysnub on 14 Apr 2013, 16:44; edited 1 time in total
Post 14 Apr 2013, 05:07
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 14 Apr 2013, 11:51
alwaysnub,

Those USE_X macroinstructions can be defined in a batch:
Code:
irps bit_mode, 16 32 64 {
  macro USE_#bit_mode \{
    USE#bit_mode
    Bit_Mode equ bit_mode
  \}
}    
I prefer this way because it clearly shows that there is no difference between them (except bit_mode).

You may use rept for calculations more often: rept 1 .ParamOffset:Bit_Mode/4 { ParamOffset equ .ParamOffset } can replace all those ParamOffset equ X in PROC macro. Moreover, you may move definition of ParamOffset in USE_X macros altogether (since PROC depends on Bit_Mode being defined, and those macros are only ones that do so).

ENDP macro could use bpReg that is defined in PROC macro to shorten its definition (rept could be used too, see previous paragraph).

While it's perfectly sane to mix preprocessor's and assembler's directive (sometimes it is unavoidable, and it saves a lot of backslashing), you must exactly understand what happens. Your indenting in PCALL macro, for example, may be misleading:
Code:
macro PCALL ProcName,[arg] ;Directly call procedure.
{
    common
        if ~ arg eq
    reverse
            PUSH arg
    common
        end if
        CALL ProcName
}    
It may be better to do that all in preprocessor:
Code:
macro pcall name, [arg] {
common
  match args, arg \{; "if ~ arg eq"
    irp \arg, args \\{ \\reverse push \arg \\}
  \}
  call name
}    
Delegation is powerful technique:
Code:
macro PICALL ProcPointer,[arg] ;Indirectly call procedure.
{ common PCALL [ProcPointer], arg }    
Not only it shows crucial difference between them, it also saves copying changes from one to another.

It may be better to split second argument of JMPCOND (namely arg; I mean ":" delimiter) before main loop, than to collect instruction symbol-wise inside that loop. Also JMPCOND macro name may lead to wrong conclusion that in result it will jump if condition is met (while doing just opposite). Anyway, proper matchbox can simplify it:
Code:
macro convert op, cc, target, expr {
  match v1 op v2, expr \{
    cmp v1, v2
    j#cc target
    restore DONE
    DONE equ YES
  \}
}
macro JMP!COND target, [expr*] {
common
  DONE equ NO
  convert =<==, g, target, expr
  convert >==, l, target, expr
  convert =<>, e, target, expr
  match =NO, DONE \{
    convert =<, ge, target, expr
    convert >, le, target, expr
    convert ==, ne, target, expr
  \}
  restore DONE
}    
You may use support macro to increment symbolic constant (it saves some backslashing):
Code:
struc equ! expr {
  rept 1 value:expr \{
    restore .
    . equ value
  \}
}
macro increment name { name equ! name+1 }    
And last, but not least: test your example before posting! It's missing comma between Var1:WORD and Var2:WORD in PROC macro invocation. It also highlights suboptimal performance of .break/.continue equs (due to their simplicity): jcc over single jmp. You may make them macros that optionally will accept condition on which to break/continue.
Post 14 Apr 2013, 11:51
View user's profile Send private message Reply with quote
alwaysnub



Joined: 30 Mar 2013
Posts: 26
alwaysnub 15 Apr 2013, 04:53
Quote:
Those USE_X macroinstructions can be defined in a batch:
I prefer this way because it clearly shows that there is no difference between them (except bit_mode).


Yea, and its saves space.
I also noticed while playing around if i define the macros as USE16, USE32 or USE64, it will override their original operation, i think this is a good aproach because one does not have to worry about typing USE_16 instead of USE16.

Quote:
test your example before posting! It's missing comma between Var1:WORD and Var2:WORD in PROC macro invocation.


... Surprised my bad

Here is the updated file based on baldr suggestions:

Code:
;Condition operators are, 
; = (equal), < (less), > (greater), <= (less or equal), >= (greater or equal), <> (not equal).

irps Bits, 16 32 64
{
    macro USE#Bits
    \{
         USE#Bits
         Bit_Mode equ Bits
    \}
}

struc equ! expr
{
    rept 1 newExpr:expr
    \{
         restore .
         . equ newExpr
    \}
}

macro equ_increment Name,Increment { Name equ! Name+Increment }

macro .if [arg]
{
    __IF equ
    local ..endif
    __ENDIF equ ..endif
    local ..else
    __ELSE equ ..else
    JMP!COND __ELSE,arg
}

macro .else
{
    JMP __ENDIF
    __ELSE:
    restore __IF
    __IF equ ,
}

macro .elseif [arg]
{
    JMP __ENDIF
    __ELSE:
    restore __ELSE
    local ..else
    __ELSE equ ..else
    JMP!COND __ELSE,arg
}

macro .endif
{
    if __IF eq
        __ELSE:
    end if
    __ENDIF:
    restore __ELSE
    restore __ENDIF
    restore __IF
}

macro .while [arg]
{
    local ..while
    __WHILE equ ..while
    local ..endw
    __ENDW equ ..endw
    __WHILE:
    .break equ JMP __ENDW
    if ~ arg eq
        JMP!COND __ENDW,arg
    end if
    .continue equ JMP __WHILE
}

macro .breakif [arg] { JMPCOND __ENDW,arg }

macro .continueif [arg] { JMPCOND __WHILE,arg }

macro .endw
{
    JMP __WHILE
    __ENDW:
    restore .continue
    restore .break
    restore __ENDW
    restore __WHILE
}

macro JccMatchBox op, CC, label, expr
{
    match v1 op v2, expr
    \{
         CMP v1,v2
         J#CC label
         restore DONE
         DONE equ YES
    \}
}

macro JMP!COND label,arg
{
    DONE equ NO
    JccExpr equ arg

    match JccArg:PreInstruction, arg
    \{
         PreInstruction
         restore JccExpr
         JccExpr equ JccArg
    \}

    JccMatchBox =<==, G, label, JccExpr
    JccMatchBox >==, L, label, JccExpr
    JccMatchBox =<>, E, label, JccExpr
    match =NO, DONE
    \{
         JccMatchBox =<, GE, label, JccExpr
         JccMatchBox >, LE, label, JccExpr
         JccMatchBox ==, NE, label, JccExpr
    \}
    restore JccExpr
    restore DONE
}

macro JMPCOND label,arg
{
    DONE equ NO
    JccExpr equ arg

    match JccArg:PreInstruction, arg
    \{
         PreInstruction
         restore JccExpr
         JccExpr equ JccArg
    \}

    JccMatchBox =<==, LE, label, JccExpr
    JccMatchBox >==, GE, label, JccExpr
    JccMatchBox =<>, NE, label, JccExpr
    match =NO, DONE
    \{
         JccMatchBox =<, L, label, JccExpr
         JccMatchBox >, G, label, JccExpr
         JccMatchBox ==, E, label, JccExpr
    \}
    restore JccExpr
    restore DONE
}

macro PROC ProcName,[arg]
{
    common
    ProcName:

    match =16, Bit_Mode
    \{
         PUSH BP
         MOV BP,SP
         bpReg equ BP
    \}
    match =32, Bit_Mode
    \{
         PUSH EBP
         MOV EBP,ESP
         bpReg equ EBP
    \}
    match =64, Bit_Mode
    \{
         PUSH RBP
         MOV RBP,RSP
         bpReg equ RBP
    \}

    ParamNamesToFix equ
    rept 1 PrmOffsetX:Bit_Mode/4 \{ ParamOffset equ PrmOffsetX \}

    forward
    match argName:argType, arg
    \{
         match =WORD, argType
         \\{
               ParamNamesToFix equ ParamNamesToFix\argName
               argName equ bpReg+ParamOffset
               equ_increment ParamOffset,2
         \\}
         match =DWORD, argType
         \\{
               ParamNamesToFix equ ParamNamesToFix\argName
               argName equ bpReg+ParamOffset
               equ_increment ParamOffset,4
         \\}
         match =QWORD, argType
         \\{
               ParamNamesToFix equ ParamNamesToFix\argName
               argName equ bpReg+ParamOffset
               equ_increment ParamOffset,8
         \\}
    \}
}

macro ENDP
{
    POP bpReg
    rept 1 PrmOffsetX:Bit_Mode/4 \{ RET ParamOffset-PrmOffsetX \}

    restore bpReg
    restore ParamOffset

    match Params, ParamNamesToFix
    \{
         irps argName, Params
         \\{
               restore argName
         \\}
    \}
}

macro PCALL ProcName,[arg]
{
    common
    match args, arg
    \{
         irp \arg, args \\{ \\reverse PUSH \arg \\}
    \}
    CALL ProcName
}

macro PICALL ProcPointer,[arg] { PCALL [ProcPointer],arg }    


Example usage:

Code:
USE16
ORG 0

PCALL MyFunction2, WORD BX, WORD 0

PROC MyFunction, Var1:WORD, Var2:WORD
MOV AX,WORD [Var2]
.while AX < 10 : INC AX
.continueif AX < 6
.breakif AX > 6
.endw
ENDP

PROC MyFunction2, Var2:WORD, Var1:WORD
MOV AX,WORD [Var2]
.while
.if AX > 111
.break
.else
.continue
.endif
.endw
ENDP    
Post 15 Apr 2013, 04:53
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 15 Apr 2013, 06:55
alwaysnub wrote:
I also noticed while playing around if i define the macros as USE16, USE32 or USE64, it will override their original operation, i think this is a good aproach because one does not have to worry about typing USE_16 instead of USE16.
There is one subtlety: preprocessor symbols (e.g. macro names) are case-sensitive, while assembler directives aren't. Thus one can use use16 Wink to have original directive behavior, and USE16 to invoke your macro.

That recurring restore/equ combo encourages wrapping it in macro (struc macro, to be exact, — then you can write symbol reequ value).

local and restore preprocessor directives accept multiple arguments.

Multiple matches at start of PROC macro can be reduced to something like this:
Code:
match bit_mode, Bit_Mode {
  match head/=bit_mode bp sp/tail, //16 bp sp/32 ebp esp/64 rbp rsp// \{
    push bp
    mov bp, sp
    bpReg equ bp
  \}
}    

Matches inside match argName:argType, arg block are different only in equ_increment's second argument. You may define symbolic constants like sizeof.WORD equ 2, then use equ_increment ParamOffset, sizeof.#argType, with proper backslashing. BTW, there is no need of backslash before argName in that blocks.

Make more use of equ! macro (hint: search for rept 1 outside of it).
Post 15 Apr 2013, 06:55
View user's profile Send private message Reply with quote
alwaysnub



Joined: 30 Mar 2013
Posts: 26
alwaysnub 16 Apr 2013, 03:11
Quote:
There is one subtlety: preprocessor symbols (e.g. macro names) are case-sensitive, while assembler directives aren't. Thus one can use use16 to have original directive behavior, and USE16 to invoke your macro.


oh... I did not notice that, in that case i made it more likely to mess up. lol
Ether way, both ways work, people will just have to watch what they type. Razz

Here is the updated file:

Code:
irps Bits, 16 32 64
{
    macro USE#Bits
    \{
         use#Bits
         Bit_Mode equ Bits
    \}
}

sizeof.BYTE equ 1
sizeof.WORD equ 2
sizeof.DWORD equ 4
sizeof.QWORD equ 8

struc reequ value
{
    restore .
    . equ value
}

struc equ! expr
{
    rept 1 newExpr:expr
    \{
         restore .
         . equ newExpr
    \}
}

macro equ_increment Name,Increment { Name equ! Name+Increment }
macro equ_decrement Name,Decrement { Name equ! Name-Decrement }

macro .if [arg]
{
    __IF equ
    local ..endif
    __ENDIF equ ..endif
    local ..else
    __ELSE equ ..else
    JMP!COND __ELSE,arg
}

macro .else
{
    JMP __ENDIF
    __ELSE:
    __IF reequ ,
}

macro .elseif [arg]
{
    JMP __ENDIF
    __ELSE:
    restore __ELSE
    local ..else
    __ELSE equ ..else
    JMP!COND __ELSE,arg
}

macro .endif
{
    if __IF eq
        __ELSE:
    end if
    __ENDIF:
    restore __ELSE
    restore __ENDIF
    restore __IF
}

macro .while [arg]
{
    local ..while
    __WHILE equ ..while
    local ..endw
    __ENDW equ ..endw
    __WHILE:
    .break equ JMP __ENDW
    if ~ arg eq
        JMP!COND __ENDW,arg
    end if
    .continue equ JMP __WHILE
}

macro .breakif [arg] { JMPCOND __ENDW,arg }

macro .continueif [arg] { JMPCOND __WHILE,arg }

macro .endw
{
    JMP __WHILE
    __ENDW:
    restore .continue
    restore .break
    restore __ENDW
    restore __WHILE
}

macro JccMatchBox op, CC, label, expr
{
    match v1 op v2, expr
    \{
         CMP v1,v2
         J#CC label
         DONE reequ YES
    \}
}

macro JMP!COND label,arg
{
    DONE equ NO
    JccExpr equ arg

    match JccArg:PreInstruction, arg
    \{
         PreInstruction
         JccExpr reequ JccArg
    \}

    JccMatchBox =<==, G, label, JccExpr
    JccMatchBox >==, L, label, JccExpr
    JccMatchBox =<>, E, label, JccExpr
    match =NO, DONE
    \{
         JccMatchBox =<, GE, label, JccExpr
         JccMatchBox >, LE, label, JccExpr
         JccMatchBox ==, NE, label, JccExpr
    \}
    restore JccExpr
    restore DONE
}

macro JMPCOND label,arg
{
    DONE equ NO
    JccExpr equ arg

    match JccArg:PreInstruction, arg
    \{
         PreInstruction
         JccExpr reequ JccArg
    \}

    JccMatchBox =<==, LE, label, JccExpr
    JccMatchBox >==, GE, label, JccExpr
    JccMatchBox =<>, NE, label, JccExpr
    match =NO, DONE
    \{
         JccMatchBox =<, L, label, JccExpr
         JccMatchBox >, G, label, JccExpr
         JccMatchBox ==, E, label, JccExpr
    \}
    restore JccExpr
    restore DONE
}

macro PROC ProcName,[arg]
{
    common
    ProcName:

    match Bits, Bit_Mode
    \{
         match Head/=Bits BP SP/Tail, //16 BP SP/32 EBP ESP/64 RBP RSP//
         \\{
               PUSH BP
               MOV BP,SP
               bpReg equ BP
         \\}
    \}

    ParamNamesToFix equ
    ParamOffset equ! Bit_Mode/4

    forward
    match argName:argType, arg
    \{
         ParamNamesToFix equ ParamNamesToFix\argName
         argName equ bpReg+ParamOffset
         equ_increment ParamOffset,sizeof.\#argType
    \}
}

macro ENDP
{
    POP bpReg
    RET ParamOffset-Bit_Mode/4

    restore bpReg
    restore ParamOffset

    match Params, ParamNamesToFix
    \{
         irps argName, Params
         \\{
               restore argName
         \\}
    \}
}

macro PCALL ProcName,[arg]
{
    common
    match args, arg
    \{
         irp \arg, args \\{ \\reverse PUSH \arg \\}
    \}
    CALL ProcName
}

macro PICALL ProcPointer,[arg] { PCALL [ProcPointer],arg }    


I wont be posting any more updates. If baldr or someone has suggestions, then you'll have to make the changes based on what they say. Unless a bug is found i think the macro file is great for all os and non-os projects as it is.
Post 16 Apr 2013, 03:11
View user's profile Send private message Reply with quote
alwaysnub



Joined: 30 Mar 2013
Posts: 26
alwaysnub 17 Apr 2013, 01:35
NOTE: FOUND A BUG!

Posting updated file because of bad code.

notes about bug:
The name PreInstruction in JMP!COND is misleading, its an instruction that gets executed after every loop. however, it was being executed once befor the loop ever started.

Code:
irps Bits, 16 32 64
{
    macro USE_#Bits
    \{
         use#Bits
         Bit_Mode equ Bits
    \}
}

sizeof.BYTE equ 1
sizeof.WORD equ 2
sizeof.DWORD equ 4
sizeof.QWORD equ 8

struc reequ value
{
    restore .
    . equ value
}

struc equ! expr
{
    rept 1 newExpr:expr
    \{
         restore .
         . equ newExpr
    \}
}

macro equ_increment Name,Increment { Name equ! Name+Increment }
macro equ_decrement Name,Decrement { Name equ! Name-Decrement }

macro .if [arg]
{
    __IF equ
    local ..endif
    __ENDIF equ ..endif
    local ..else
    __ELSE equ ..else
    JMP!COND __ELSE,arg
}

macro .else
{
    JMP __ENDIF
    __ELSE:
    __IF reequ ,
}

macro .elseif [arg]
{
    JMP __ENDIF
    __ELSE:
    restore __ELSE
    local ..else
    __ELSE equ ..else
    JMP!COND __ELSE,arg
}

macro .endif
{
    if __IF eq
        __ELSE:
    end if
    __ENDIF:
    restore __ELSE
    restore __ENDIF
    restore __IF
}

macro .while [arg]
{
    local ..while
    __WHILE equ ..while
    local ..endw
    __ENDW equ ..endw
    __WHILE:
    JccExpr equ arg
    if ~ arg eq
        match JccArg:AfterInstruction, arg
        \{
             local ..over
             __OVER equ ..over
             JMP __OVER
             restore __WHILE
             local ..while
             __WHILE equ ..while
             __WHILE:
             AfterInstruction
             __OVER:
             JccExpr reequ JccArg
             restore __OVER
        \}
        JMP!COND __ENDW,JccExpr
    end if
    .break equ JMP __ENDW
    .continue equ JMP __WHILE
}

macro .breakif [arg] { JMPCOND __ENDW,arg }

macro .continueif [arg] { JMPCOND __WHILE,arg }

macro .endw
{
    JMP __WHILE
    __ENDW:
    restore JccExpr
    restore .continue
    restore .break
    restore __ENDW
    restore __WHILE
}

macro JccMatchBox op, CC, label, expr
{
    match v1 op v2, expr
    \{
         CMP v1,v2
         J#CC label
         DONE reequ YES
    \}
}

macro JMP!COND label,arg
{
    DONE equ NO
    JccMatchBox =<==, G, label, arg
    JccMatchBox >==, L, label, arg
    JccMatchBox =<>, E, label, arg
    match =NO, DONE
    \{
         JccMatchBox =<, GE, label, arg
         JccMatchBox >, LE, label, arg
         JccMatchBox ==, NE, label, arg
    \}
    restore DONE
}

macro JMPCOND label,arg
{
    DONE equ NO
    JccMatchBox =<==, LE, label, arg
    JccMatchBox >==, GE, label, arg
    JccMatchBox =<>, NE, label, arg
    match =NO, DONE
    \{
         JccMatchBox =<, L, label, arg
         JccMatchBox >, G, label, arg
         JccMatchBox ==, E, label, arg
    \}
    restore DONE
}

macro PROC ProcName,[arg]
{
    common
    ProcName:

    match Bits, Bit_Mode
    \{
         match Head/=Bits BP SP/Tail, //16 BP SP/32 EBP ESP/64 RBP RSP//
         \\{
               PUSH BP
               MOV BP,SP
               bpReg equ BP
         \\}
    \}

    ParamNamesToFix equ
    ParamOffset equ! Bit_Mode/4

    forward
    match argName:argType, arg
    \{
         ParamNamesToFix equ ParamNamesToFix\argName
         argName equ bpReg+ParamOffset
         equ_increment ParamOffset,sizeof.\#argType
    \}
}

macro ENDP
{
    POP bpReg
    RET ParamOffset-Bit_Mode/4

    restore bpReg
    restore ParamOffset

    match Params, ParamNamesToFix
    \{
         irps argName, Params
         \\{
               restore argName
         \\}
    \}
}

macro PCALL ProcName,[arg]
{
    common
    match args, arg
    \{
         irp \arg, args \\{ \\reverse PUSH \arg \\}
    \}
    CALL ProcName
}

macro PICALL ProcPointer,[arg] { PCALL [ProcPointer],arg }    
Post 17 Apr 2013, 01:35
View user's profile Send private message Reply with quote
uart777



Joined: 17 Jan 2012
Posts: 369
uart777 18 Apr 2013, 06:51
Just some notes:

Your procedures (PROC) are always inserted in the executable even if unused. If my library did this, minimal example would be 170K+! In LANGUAGE.INC>"function", notice the "if used name" (ProcName:) at the beginning and the "end if" in "endf". In JMP!COND:
Code:
JccMatchBox =<==, G, label, JccExpr 
JccMatchBox =<>, E, label, JccExpr 
JccMatchBox =<, GE, label, JccExpr    
Should be:
Code:
JccMatchBox <==, G, label, JccExpr 
JccMatchBox <>, E, label, JccExpr 
JccMatchBox <, GE, label, JccExpr    
Not technically an error, but = and , are the only special operators that need to be preceded with = (match literally). Also, "JccMatchBox" is a long name. In big projects with 100s-1,000s of ".if"s, shorter names (example: "?JC") will result in faster preprocessing.

"call" can be redefined and extended to accept parameters:
Code:

macro pushr [p] {
common
if ~p eq
 reverse pushd p
common
end if
}  

macro call f, [p] {
common pushr p
call f
}

macro callp f, [p] { common call [f], p }    
Post 18 Apr 2013, 06:51
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.