The MASM Forum Archive 2004 to 2012

Miscellaneous Forums => 16 bit DOS Programming => Topic started by: carlottagp on August 10, 2006, 08:49:49 PM

Title: Unmatched block nesting
Post by: carlottagp on August 10, 2006, 08:49:49 PM
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








Title: Re: Unmatched block nesting
Post by: Mark Jones on August 11, 2006, 03:07:57 PM
Hi Michael, you have one PROC inside another PROC? I could be mistaken but I don't think that is allowed. :)
Title: Re: Unmatched block nesting
Post by: carlottagp on August 12, 2006, 05:38:11 PM
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

Title: Re: Unmatched block nesting
Post by: Mark Jones on August 12, 2006, 07:46:17 PM
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
Title: Re: Unmatched block nesting
Post by: carlottagp on August 12, 2006, 10:31:41 PM
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
Title: Re: Unmatched block nesting
Post by: MichaelW on August 15, 2006, 12:47:00 PM
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?

Title: Re: Unmatched block nesting
Post by: carlottagp on August 15, 2006, 09:54:57 PM
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
Title: Re: Unmatched block nesting
Post by: ChrisLeslie on August 15, 2006, 10:48:33 PM
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
Title: Re: Unmatched block nesting
Post by: sinsi on August 17, 2006, 05:36:43 AM
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
Title: Re: Unmatched block nesting
Post by: ChrisLeslie on August 17, 2006, 11:48:50 PM
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
Title: Re: Unmatched block nesting
Post by: sinsi on August 18, 2006, 11:28:02 AM
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?
Title: Re: Unmatched block nesting
Post by: ChrisLeslie on August 19, 2006, 06:37:06 AM
Ahh, IFENDEF. That should be an improvement. I havn't used it yet but it sounds useful.

Chris
Title: Re: Unmatched block nesting
Post by: MichaelW on August 21, 2006, 03:08:42 PM
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
Title: Re: Unmatched block nesting
Post by: sinsi on August 21, 2006, 03:27:37 PM
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?
Title: Re: Unmatched block nesting
Post by: MichaelW on September 01, 2006, 04:16:41 PM
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
Title: Re: Unmatched block nesting
Post by: ninjarider on September 03, 2006, 04:06:52 PM
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.