Listing 1 Two macros, to push labels onto the stack. ?@StackPtr equ 0 ;;Initialize stack pointer ?@LabelCount equ 0 ;;Initialize label counter macro ?@SetStack adr, val ;;Set a stack element ?@StackData&adr equ val ;;Store the current label count endm macro ?@PushLabel ?@SetStack %?@StackPtr, %?@LabelCount ;;Store the current label count ?@StackPtr equ %(?@StackPtr+1) ;;Increment the stack pointer ?@LabelCount equ %(?@LabelCount+1) ;;Increment the label count endm> Listing 2 Popping to the ?@ReturnData label. macro ?@GetStack adr ?@ReturnData equ %?@StackData&adr ;;Retrieve the data endm macro ?@DecErr lbl ;;Print "stack empty" error display "Stack empty before ??@&lbl" err "Stack empty!" ;;Force assembler error too endm macro ?@PopData if ?@StackPtr ?@StackPtr equ %(?@StackPtr-1) ;;Decrement the stack pointer ?@GetStack %?@StackPtr ;;Retrieve the data else ?@DecErr %?@LabelCount endif endm Listing 3 Creating a new label with the macro ?@NumLabel. macro ?@NumLabel val %macs ;;Enable macro expansions in listing ??@&val: ;;Only the label appears in the listing %nomacs ;;Disable macro expansions in listing. endm macro ?@PutLabel ;;Create label from ?@LabelCount ?@NumLabel %?@LabelCount endm macro ?@PopLabel ;;Create label from value on stack ?@PopData ;;Assign value on stack to ?@ReturnData ?@NumLabel %?@ReturnData ;;Make a label from ?@ReturnData endm Listing 4 An example of Turbo Assembler's string-processing directives. macro ?@JumpOp op, adr %macs ;;Enable macro expansions in listing op ??@&adr ;;Only list the jump opcode %nomacs ;;Disable macro expansions in listing. endm macro ?@JumpFalse flags, label ?@instr instr , ;;?@instr = position of Œn' in string if ?@instr eq 1 ;;'n' is first character if true ?@ncnd substr ,2 ;; = without leading Œn' else ?@ncnd catstr , ;; = with leading Œn' endif ?@jcnd catstr ,?@ncnd ;; = with leading Œj' ?@JumpOp %?@jcnd, label endm Listing 5 The remaining intermediate macros. macro ?@PeekData StkOfs ;;Peek at offset-relative stack data ?@GetStack %(?@StackPtr+StkOfs) endm macro ?@PutData StkOfs, NewData ;;Replace offset-relative stack data ?@SetStack %(?@StackPtr+StkOfs), NewData endm macro ?@PeekLabel StkOfs ;;Create label from offset-relative stack data ?@PeekData StkOfs ?@NumLabel %?@ReturnData endm ; ?@StackPtr-1 holds "IfBeg" label jumped to by "OrIf" code ; ?@StackPtr-2 holds "ElseBeg" label in case "IfBeg" condition is false ; ?@StackPtr-3 holds "IfEnd" label, exit address for "IfBeg" code macro IfBeg flags ?@PushLabel ;;"IfEnd" label ?@JumpFalse flags, %?@LabelCount ?@PushLabel ;;"ElseBeg" label ?@PutLabel ;;"OrIf" jumps here ?@PushLabel ;;"IfBeg" label for "OrIf" endm macro OrIf flags ?@PeekData -1 ;;Jump to this label if flags match condition ifb ?@JumpOp jmp, %?@ReturnData ;;Unconditional jump if no flags else ?@JumpOp j&flags %?@ReturnData ;;Conditional jump back to "IfBeg" endif endm macro ElseBeg type ?@PeekData -3 ;;"IfEnd" address ifb ?@JumpOp , %?@ReturnData else ?@JumpOp , %?@ReturnData endif ?@PeekLabel -2 ;;"ElseBeg" address ?@PutData -2, 0fffffh ;;Invalidate "ElseBeg" label endm macro IfEnd ?@PopData ;;Drop "IfBeg" label ?@PeekData -1 ;;"ElseBeg" label if ?@ReturnData eq 0fffffh ;;"ElseBeg" block if eq ?@PopData ;;Drop "ElseBeg" label ?@PopLabel ;;Exit address for "IfBeg" code else ?@PopLabel ;;No "ElseBeg" code, put "ElseBeg" label here ?@PopData ;;Drop "IfEnd" label endif endm Listing 6 The executable code produced in Listing 5. IfBeg z jnz ??@1 ??@2: ;"If" code done if condition was true ElseBeg jmp ??@0 ;End of "IfBeg" code, exit ??@1: Orif nc ;Also do "IfBeg" code if condition matches jnc ??@2 ;"Else" code if all preceding conditions were false IfEnd ??@0: ;Exit Listing 7 The while conditional structure. ; WhileBeg ; condition test ;;Set CPU flags for condition test ; WhileDo ; code ;;Do this while condition is true ; WhileEnd ; macro WhileBeg ?@PushLabel ;;"WhileEnd" label ?@PutLabel ;;"WhileDo" contiues here ?@PushLabel ;;"WhileBeg" label endm macro WhileDo flags ?@PeekData -2 ;;"WhileEnd" label ?@JumpFalse flags, %?@ReturnData ;;Quit if condition doesn't match endm macro WhileEnd ?@PopData ;;"WhileBeg" label ?@JumpOp jmp, %?@ReturnData ;;Back to condition test ?@PopLabel ;;"WhileEnd" label endm Listing 8 Additional diagnostic macros help locate syntax and nesting errors. macro ?@CheckErr val, sp, lbl ;;Stack not empty error display "Unterminated conditional before ??@&val" display "&sp value(s) on stack" display "Last label pushed to stack is ??@&lbl" err "Stack not empty!" ;;Force assembler error too endm macro CheckNest ;;Error message if not properly nested if ?@StackPtr ne 0 ?@PeekData -1 ;;Get topmost value on stack ?@CheckErr %?@LabelCount, %?@StackPtr, %?@ReturnData endif endm Listing 9 Reference segments like this will reside somewhere in your code. segment InitBeg assume cs:InitGrp, ds:@data, es: nothing, ss:nothing public Initialize label Initialize far ;Entry point cli ;Clear interrupt flag pusha ;Push all registers ends segment InitEnd assume cs:InitGrp, ds:@data, es: nothing, ss:nothing popa ;Pop all registers sti ;Set interrupt flag retf ;Return from initialization ends segment InitCode assume cs:InitGrp, ds:@data, es: nothing, ss:nothing ;Module-specific initialization code ;Code is in-line somewhere between "InitBeg" and "InitEnd" ends