My program has the following basic structure:
TITLE LDA
.MODEL SMALL
.STACK 200h
.DATA
(data)
.CODE
mov AX,@DATA
mov DS,AX
LDAB PROC
(code)
Five procedures, each with the xxx PROC, RET, xxx ENDP format
ZE: mov AX,4C00h
int 21h
LDAB ENDP
END
When I try to assemble it, I get the error message:
LDA.asm (259) Fatal error A1010: unmatched block nesting: LDAB
All of the procedures function correctly on their own, and in any case that's
apparently not where my problem is. Can someone explain the "unmatched
block nesting" comment to me? Thanks
Michael
Hi Michael, you have one PROC inside another PROC? I could be mistaken but I don't think that is allowed. :)
Mark,
Thanks for the suggestion. Actually, I have about eight programs written so far, all of
which have procedures inside the main procedure, and they all work just fine. In other
words, in the main program I have a number of CALL instructions, each of which invokes
a subroutine with the format I mentioned: PROC......code.....RET..ENDP.
For instance (the smallest subroutine I've written so far)
CRLF PROC ;writes CR, LF to file
mov AH,40h
mov BX,handle
mov CX,2
mov DX,offset buffc
int 21h
jc MB
RET
CRLF ENDP
Hmm, it sounds like the error message is generated if another PROC is encountered before the previous ENDP, i.e.
MyProc1 PROC
mov ax,1
MyProc2 PROC
mov cx,2
ret
ENDP ; two procs, which ENDP to use?
ret 8
ENDP ; hmmm
Could you try altering the code as follows?
MyProc1:
mov ax,1
MyProc2:
mov cx,2
ret
The procedure label defined by the PROC command should in interchangable with a jump label (they are both converted to an offset at compile-time.) I hope this is what you are after, have fun! :U
Hello again,
All of my procedures are in the same format as the example I posted; i.e. no CALLs to another
procedure within the one that's running. I have tried moving all procedures to a point
after the ENDP END for the main procedure, with no success. Is it possible that there's
a number-of-lines limit problem here?
Not trying to muddy the waters, but could there be a problem with the software I'm
using to assemble my programs? It came with Kip Irvine's assembly language book. This
morning I observed, using the CodeView 4.10 that came with it, that a line was skipped
as I was stepping through the program, trying to debug it. Just an ordinary line, something
like mov BX, 12h. It happened again and again. I'm bothered enough to want to go out
and try to find a package of assembly language software....
Thanks again,
Michael
I doubt that the problem has anything to do with line length or the tools. The only way I can find to produce an unmatched block nesting error with code like you seem to be describing is to have an overlap between the procedure definitions, as in Mark's example. IIRC you cannot nest procedures that have a stack frame, and without a stack frame a procedure cannot support parameters or local variables, so under these conditions a procedure is little better than label, so why not just use a label?
Hi, Michael,
I am interested in your suggestion to use a label instead of a procedure. ......except that I don't see how
to implement the return function at the end of the procedure. Could you perhaps illustrate the idea by
showing me how to write the CRLF subroutine I quoted earlier? At the moment I just CALL the procedure
when I need to, and this puts the appropriate return address on the stack, to be used when the RET
instruction is encountered.
Incidentally, by shuffling the order in which the subroutines are called I was able to make the original
program work. However, CodeView insists that there is a "fatal error" in the program; this is why I wonder
if my assembly-language software, including CV, is flaky...
Thanks,
Michael
carlottagp
Your original code should have an "end xxx" directive with an entry label instead of just "end".
You can call or invoke proc from within procs, but if you nest a proc within a proc, the ret instruction will return program flow to the wrong place.
As MichaelW said, it may be appropriate to use simple labels instead of procs in many circumstances if you are not using a stack frame. In this way you will effectively be creating subroutines. For example, the CRLF subroutine could be:
CRLF:
.data
labcrlf db 13,10,'$'
.code
mov ah,9
mov dx,offset labcrlf
int 21h
ret
where you use "call CRLF".
Or better still in my opinoin is a macro:
CRLF MACRO
local labcrlf
.data
labcrlf db 13,10,'$'
.code
mov ah,9
mov dx,offset labcrlf
int 21h
ENDM
where you just use CRLF in your code.
Regards
Chris
ML will let you have nested PROCs:
proc1 proc
mov eax,eax
proc2 proc
ret
proc2 endp
ret
proc1 endp
main proc
call proc1
call proc2
ret
main endp
will compile and link no worries.
With your CRLF proc,
Quote
CRLF PROC ;writes CR, LF to file
mov AH,40h
mov BX,handle
mov CX,2
mov DX,offset buffc
int 21h
jc MB
RET
CRLF ENDP
jumping out of a PROC is as bad as a BASIC GOTO (a PROC is self-contained
and has one exit point (so I have been told :lol))
ChrisLeslie: using your macro 50 times in a program will scatter 50 times "13,10,$"
through your .data :eek
sinsi,
The problem with the nested proc example that you gave is that any code that may exist in proc1 after the proc2 block will not be executed because proc2's "ret" will cause proc1 to return.
Unfortunately that is correct that when using macros that code, and any data, is repeated upon every invocation. I think it depends on the circumstances and one's preferences whether a macro is the best choice.
Regards
Chris
Sorry Chris, bad example since proc2 doesn't need to return if proc1 does.
(Too lazy to actually think up some code that works heh heh.)
On that CRLF macro, maybe something like
CRLF MACRO
IFNDEF str_crlf
.data
str_crlf db 13,10,'$'
ENDIF
.code
mov ah,9
mov dx,offset str_crlf
int 21h
ENDM
would only define it once?
Ahh, IFENDEF. That should be an improvement. I havn't used it yet but it sounds useful.
Chris
Quote from: sinsi on August 17, 2006, 05:36:43 AM
ML will let you have nested PROCs
Yes, but only if the procedures do not have parameters or automatic local variables. If they do, then you will get:
error A2144: cannot nest procedures
Oops :red. We live and learn. In my meagre defense, I have never used nested PROCs in ASM (I think Delphi treats one as a "local" procedure?).
MichaelW, I am curious as to what an "automatic local variable" is. I understand a defined local variable but what's an automatic one?
By automatic local variable I mean a local variable created with the LOCAL directive. MASM will not return an error if a nested procedure has local variables that were created manually. And my statement was not correct. For a nested procedure with LOCAL and no parameters, MASM returns:
error A2012: PROC, MACRO, or macro repeat directive must precede LOCAL
i would need to see all the code to tell you what else might be wrong
mov AX,@DATA
mov DS,AX
LDAB PROC
(code)
Five procedures, each with the xxx PROC, RET, xxx ENDP format
ZE: mov AX,4C00h
int 21h
LDAB ENDP
END
but try aranging you code so it matches below.
mov AX,@DATA
mov DS,AX
LDAB PROC
(code)
ZE: mov AX,4C00h
int 21h
LDAB ENDP
Five procedures, each with the xxx PROC, RET, xxx ENDP format
END
if it doesn't and all the procs have local calls and no far calls try this
mov AX,@DATA
mov DS,AX
LDAB PROC
(code)
{condition to call proc1}
push Offset ReturnFromProc1
push {variables}
jmp Proc1
ReturnFromProc1:; - place this label were you want proc 1 to return to.
ZE: mov AX,4C00h
int 21h
LDAB ENDP
Proc1:; - change from the proc setup to a label. and varialbes will have to be manuall pushed to the stack
pop {variables}
{code}
ret
Five procedures, each with the xxx PROC, RET, xxx ENDP format
END
let me know if theres anything i have to clarify for you.