1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

ON BREAK doesn't always work

Discussion in 'Support' started by vefatica, Oct 6, 2012.

  1. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,792
    Likes Received:
    29
    I have a BTM which starts like this.
    Code:
    setlocal
    setarray b[9]
    on break ( unsetarray b & echo Quitting! & quit )
    
    There are no other ON commands. The body is nested inside 9 DO loops.
    In the first run below, when I pressed Ctrl-C, it quit with no message and without unsetting the array (as evidenced by the error when it was restarted). After restarting (the second run below) the first Ctrl-C resulted in the array being unset and the message being echoed but the BTM didn't quit; The second Ctrl-C got it to quit (but with an error because the array had been unset by the first Ctrl-C). The behavior is erratic. The BTM is attached. It plays all possible games of tic-tac-toe and calculates the fraction which end in a win (with occasional progress reports). Well, the server won't let me upload it (A server error occurred. Please try again later.) neither as a BTM nor as a ZIP. Rex, I'll email it to you.
    Code:
    v:\> ttt.btm
    15:12:01
    8 / 10 = 0.8
    37 / 50 = 0.74
    101 / 130 = 0.7769230769
    129 / 170 = 0.7588235294
    ^C
     
    v:\> ttt.btm
    TCC: V:\ttt.btm [2]  Array variable is already defined "b"
    15:12:21
    8 / 10 = 0.8
    37 / 50 = 0.74
    101 / 130 = 0.7769230769
    129 / 170 = 0.7588235294
    158 / 210 = 0.7523809524
    185 / 250 = 0.74
    ^C
    Quitting!
    236 / 310 = 0.7612903226
    236 / 320 = 0.7375
    236 / 330 = 0.7151515152
    236 / 340 = 0.6941176471
    236 / 350 = 0.6742857143
    236 / 360 = 0.6555555556
    236 / 370 = 0.6378378378
    236 / 380 = 0.6210526316
    236 / 390 = 0.6051282051
    236 / 400 = 0.59
    236 / 410 = 0.5756097561
    ^C
    TCC: V:\ttt.btm [26]  Not an array variable "b"
    Quitting!
     
    v:\>
    Here's another (on another machine) where it took many attempts before it quit, each time unsetting the array (or trying to) and echoing the message ... except for the last when neither the error message nor the "Quitting" message appeared.
    Code:
    v:\> \\zz\h$\Workplace\ttt.btm
    15:23:02
    8 / 10 = 0.8
    37 / 50 = 0.74
    101 / 130 = 0.7769230769
    129 / 170 = 0.7588235294
    158 / 210 = 0.7523809524
    185 / 250 = 0.74
    252 / 330 = 0.7636363636
    ^C
    Quitting!
    270 / 360 = 0.75
    270 / 370 = 0.7297297297
    270 / 380 = 0.7105263158
    270 / 390 = 0.6923076923
    270 / 400 = 0.675
    270 / 410 = 0.6585365854
    270 / 420 = 0.6428571429
    270 / 430 = 0.6279069767
    270 / 440 = 0.6136363636
    270 / 450 = 0.6
    270 / 460 = 0.5869565217
    270 / 470 = 0.5744680851
    ^C
    TCC: \\zz\h$\Workplace\ttt.btm [74]  Not an array variable "b"
    Quitting!
    270 / 480 = 0.5625
    270 / 490 = 0.5510204082
    270 / 500 = 0.54
    270 / 510 = 0.5294117647
    270 / 520 = 0.5192307692
    270 / 530 = 0.5094339623
    270 / 540 = 0.5
    270 / 550 = 0.4909090909
    270 / 560 = 0.4821428571
    270 / 570 = 0.4736842105
    ^C
    TCC: \\zz\h$\Workplace\ttt.btm [78]  Not an array variable "b"
    Quitting!
    270 / 580 = 0.4655172414
    270 / 590 = 0.4576271186
    270 / 600 = 0.45
    270 / 610 = 0.4426229508
    ^C
    TCC: \\zz\h$\Workplace\ttt.btm [80]  Not an array variable "b"
    Quitting!
    270 / 620 = 0.435483871
    270 / 630 = 0.4285714286
    270 / 640 = 0.421875
    ^C
    TCC: \\zz\h$\Workplace\ttt.btm [79]  Not an array variable "b"
    Quitting!
    270 / 650 = 0.4153846154
    270 / 660 = 0.4090909091
    270 / 670 = 0.4029850746
    ^C
     
    v:\>
     
  2. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,792
    Likes Received:
    29
    P.S. If I put the ON BREAK command in the inner loop the behavior is the same, erratic. If I put the ON BREAK inside the ":win" subroutine, TCC disappears when I press Ctrl-C, and leaves this GPF file.
    Code:
    TCC  14.02.39
    Module=g:\tc14\TakeCmd.dll
    Address=1007E47C
    Exception=C0000005
    EAX=3090FC28  EBX=76EDAAD7  ECX=00000000  EDX=00000000
    ESI=3090E199  EDI=058E7648  EBP=00BFC83C  ESP=00BEC7B8
    CS=0000001B  DS=00000023  ES=00000023  SS=00000023
    Flags=00010206
     
    Stack:
    1 : TakeCmd.dll 00000001:0007d47c
    2 : TakeCmd.dll 00000001:0009164d
    3 : TakeCmd.dll 00000001:000913be
     
  3. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,732
    Likes Received:
    81
    The problem isn't with ON BREAK. Because you've nested your DO loops so deeply, the parser has to unwind a couple dozen levels before it can even determine that you've done a QUIT. (A QUIT just sets the batch file pointer to the end; it does not immediately terminate the batch file.)

    A DO causes a recursive entry into the parser; nested DO's double that (at least -- it could be more depending on what else you're doing, like command grouping). So depending on where you were in your DO hierarchy, the parser may have to execute a *lot* more DO statements before it reaches a point where the QUIT could take effect.
     
  4. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,792
    Likes Received:
    29
    I thought I posted a simple example with just a single DO. Here it is again. It won't QUIT if the break happens in a subroutine.
    Code:
    v:\> type simplified.btm
     on break ( echo Quitting at line %_batchline & quit )
     do i=1 to 1000000
     set a=%@exec[gosub foo]
     enddo
     quit
     
    :foo
    if 1==1 set b=b
    if 1==1 set b=b
    if 1==1 set b=b
    if 1==1 set b=b
    if 1==1 set b=b
    if 1==1 set b=b
    return 1
     
    v:\> simplified.btm
    ^C
    Quitting at line 8
    ^C
    Quitting at line 12
    ^C
    Quitting at line 12
    ^C
    Quitting at line 8
    ^C
    Quitting at line 3
     
    v:\>
     
  5. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,792
    Likes Received:
    29
    Something is definitely screwy. I ran the BTM below several times. Every time it ended when I pressed Ctrl-C. The 4th time it neither echoed "bye" nor unset the array!
    Code:
    v:\> type crazy.btm
    echo %_time
    setarray b[9]
    set brk=0
    on break ( set brk=1 )
    do i=1 to 1000
    do j=1 to 1000
            if %brk == 1 goto goner
    enddo
    enddo
     
    :goner
    echo bye
    unsetarray b
    quit
    Code:
    v:\> crazy.btm
    23:30:46
    ^C
    bye
     
    v:\> crazy.btm
    23:30:48
    ^C
    bye
     
    v:\> crazy.btm
    23:30:50
    ^C
    bye
     
    v:\> crazy.btm
    23:30:52
    ^C
     
    v:\> crazy.btm
    23:30:57
    TCC: V:\crazy.btm [2]  Array variable is already defined "b"
    ^C
    bye
     
    v:\>
     
  6. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,732
    Likes Received:
    81
    I can't imagine what you're trying to do with the @EXEC (which doesn't add anything other than a LOT of overhead). The ON BREAK works fine without the @EXEC, so your problem with QUIT seems unrelated to DO (or ON BREAK, for that matter).

    There does seem to be an issue with executing QUIT from inside an @EXEC function, though that fortunately doesn't seem to be something that users are typically going to want to do. I'll take a look at it but it's not likely to be something that I'm going to want to rewrite the parser for.
     
  7. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,732
    Likes Received:
    81
    The parser is saving the global variables (including the current batch file state -- offset, line number, name, etc.) before running @EXEC / @EXECSTR / @EXECARRAY. So the QUIT inside @EXEC sets the offset to the end of the file, and the variable expansion sets it back to its previous position when @EXEC returns.

    Changing this is going to have a very far-ranging impact, so I think I'm going to need a better argument than your (contrived?) example. Can you think of a convincing argument why anyone would need to be doing @EXEC[quit] ?
     
  8. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,792
    Likes Received:
    29
    How about my last example (not involving a subroutine) in which ON BREAK doesn't always behave the same. Below, sometimes it executes the commands after the label "goner" and sometimes it doesn't.
    Code:
    v:\> type crazy.btm
    echo %_time
    setarray b[9]
    set brk=0
    on break ( set brk=1 )
    do i=1 to 1000000
            if %brk == 1 goto goner
    enddo
     
    :goner
    echo bye
    unsetarray b
    quit
    v:\>
    Code:
    v:\> crazy.btm
    14:33:52
    ^C
    bye
     
    v:\> crazy.btm
    14:33:54
    ^C                    <======= no "bye"; array not unset
     
    v:\> crazy.btm
    14:33:56
    TCC: V:\crazy.btm [2]  Array variable is already defined "b"
    ^C
    bye
     
    v:\> crazy.btm
    14:33:57
    ^C                    <======= no "bye"; array not unset
     
    v:\> crazy.btm
    14:33:59
    TCC: V:\crazy.btm [2]  Array variable is already defined "b"
    ^C                    <======= no "bye"; array not unset
     
    v:\> crazy.btm
    14:34:01
    TCC: V:\crazy.btm [2]  Array variable is already defined "b"
    ^C
    bye
     
    v:\> crazy.btm
    14:34:03
    ^C
    bye
     
    v:\>
     
  9. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,732
    Likes Received:
    81
    Not reproducible here.
     
  10. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,792
    Likes Received:
    29
    I can only suppose you didn't try hard enough. Here's the same BTM on another machine.
    Code:
    echo %_time
    setarray b[9]
    set brk=0
    on break ( set brk=1 )
    do i=1 to 1000000
            if %brk == 1 goto goner
    enddo
     
    :goner
    echo bye
    unsetarray b
    quit
    Code:
    v:\> crazy.btm
    20:12:59
    ^C
    bye
     
    v:\> crazy.btm
    20:13:02
    ^C
     
    v:\> crazy.btm
    20:13:06
    TCC: V:\crazy.btm [2]  Array variable is already defined "b"
    ^C
    bye
     
    v:\> crazy.btm
    20:13:09
    ^C
    bye
     
    v:\> crazy.btm
    20:13:12
    ^C
    bye
     
    v:\> crazy.btm
    20:13:15
    ^C
     
    v:\> crazy.btm
    20:13:18
    TCC: V:\crazy.btm [2]  Array variable is already defined "b"
    ^C
    bye
     
    v:\>
     
  11. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,732
    Likes Received:
    81
    I ran it 100 times on each of three different machines. Cannot reproduce it.
     
  12. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,792
    Likes Received:
    29
    Well, I'm not making it up. Do you have any idea what's happening on my two machines?
     
  13. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,732
    Likes Received:
    81
    I don't have the slightest idea. Does it happen without any plugins loaded?

    Can you reproduce it with anything other than DO -- i.e., FOR?
     
  14. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,792
    Likes Received:
    29
    I discovered it with no plugins loaded and almost all my testing was with no plugins. It does not do it (50-60 tries) if I replace DO with FOR in the most recently posted BTMfile. It also doesn't do it if I replace the DO loop with
    Code:
    :label
    if %brk == 1 goto goner
    goto label
    
    Is there another CtrlHandler hanging around ... doing something other than the GOTO? That's what it seems like.

    Even with DO, this (a plugin workaround) works (as long as I remember to press Ctrl-q).
    Code:
    if %_inkey == @17 goto goner
    So it really seems to deal with the CtrlHandler.
     
  15. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,732
    Likes Received:
    81
    No; there's only one CtrlHandler in TCC.
     
  16. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,792
    Likes Received:
    29
    Well I dunno! The batch file sometimes ends with no evidence that the GOTO happened.
     
  17. JohnQSmith

    Joined:
    Jan 19, 2011
    Messages:
    560
    Likes Received:
    8
    Sounds like the parser needs to be improved. What's the maximum level of nested loops? Documentation under "Limits" says "no limit", which means it should be able to handle an infinite number (allowing for memory, of course).

    There doesn't need to be a "convincing argument". If someone can think of it and do it, even if "contrived", then it either needs to be fixed or an exception needs the be thrown and caught. It like what George Carlin said...
    Why does it always sound as if you are putting the blame on the user?

    It's like going to the doctor and telling him "Doc, it hurts when I move my arm like this." So the doctor says "Then don't move your arm like that."
     
  18. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,792
    Likes Received:
    29
    In Rex's defence, I was using @EXEC[GOSUB ... ] only because I remembered doing that a long time ago and had forgotten that I could simply GOSUB and then look at _?. I deserve to be scolded for that. But changing that in my original BTM left me with all the same ON BREAK problems.
     
  19. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,732
    Likes Received:
    81
    The ON BREAK issue doesn't have anything to do with the parser or the maximum level of nested DO loops. The problem is with using QUIT embedded deeply within DO loops -- QUIT does *not* immediately exit the batch file, it simply sets the read pointer to the end of the file, so that the next read will terminate it. But when you're deep within nested DO's, the parser isn't reading from the batch file, it's executing the already-read DO blocks, so it's not going to see the QUIT until it finishes the DO loops.
     
  20. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,792
    Likes Received:
    29
    That simply does not seem to be the case. Using "on break ( set brk=1 )" I put these two statements inside the 9 nested DO loops
    Code:
    if %_inkey == @17 (echo Ctrl-q! & unsetarray b & quit)
    if %brk == 1 (echo Break! & unsetarray b & quit)
    
    Pressing Ctrl-q works every time (completely and immediately) while pressing Ctrl-c often does not echo the message or unset the array. I could/have done the same thing with "INKEY /P /W0 /X" and with the same results as the plugin _INKEY.
    Code:
    v:\> ttt.btm
    14:45:12
    8 / 10 = 0.8000000000          (202.0 min)
    37 / 50 = 0.7400000000          (202.6 min)
    Ctrl-q!
     
    v:\> ttt.btm
    14:45:17
    8 / 10 = 0.8000000000          (201.4 min)
    Ctrl-q!
     
    v:\> ttt.btm
    14:45:21
    8 / 10 = 0.8000000000          (201.4 min)
    ^C                        <====================no message; array not unset
     
    v:\> ttt.btm
    TCC: V:\ttt.btm [2]  Array variable is already defined "b"
    14:45:26
    8 / 10 = 0.8000000000          (200.8 min)
    37 / 50 = 0.7400000000          (202.3 min)
    ^C                        <====================message; array unset
    Break!
     
    v:\> ttt.btm
    14:45:30
    8 / 10 = 0.8000000000          (202.6 min)
    37 / 50 = 0.7400000000          (202.7 min)
    ^C                        <====================no message; array not unset
     
    v:\> ttt.btm
    TCC: V:\ttt.btm [2]  Array variable is already defined "b"
    14:45:34
    (and so on)
     
  21. dcantor

    Joined:
    May 29, 2008
    Messages:
    505
    Likes Received:
    3
    So it needs a QUIT and a LEAVE? Is there some way to effect that like IF condition (QUIT & LEAVE) ?
    Would that first set the pointer to the EOF and then exit the DO-loop?
     
  22. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,792
    Likes Received:
    29
    Note that in my last post, the BTM ends when I press Ctrl-C .. but apparently (sometimes) **NOT** because I said
    Code:
    if %brk == 1 (echo Break! & unsetarray b & quit)
    If it were executing **MY** "QUIT" I'd expect to see the message and that the array be unset.
     
  23. samintz

    samintz Scott Mintz

    Joined:
    May 20, 2008
    Messages:
    1,178
    Likes Received:
    11
    I ran Vince's CRAZY.BTM file and got pretty much the same results as he did.
    Code:
    echo %_time
    setarray b[9]
    set brk=0
    on break ( set brk=1 )
    do i=1 to 1000000
            if %brk == 1 goto goner
    enddo
     
    :goner
    echo bye
    unsetarray b
    quit
    
    And this is my output:
    Code:
    crazy
    16:11:34
    ^C
    bye
     
    [R:\LNX] crazy
    16:11:41
    ^C
     
    [R:\LNX] crazy
    16:11:54
    TCC: R:\LNX\crazy.btm [2]  Array variable is already defined "b"
    ^C
     
    [R:\LNX] crazy
    16:11:59
    TCC: R:\LNX\crazy.btm [2]  Array variable is already defined "b"
    ^C
    bye
     
    [R:\LNX] crazy
    16:12:16
    ^C
     
    [R:\LNX] crazy
    16:12:21
    TCC: R:\LNX\crazy.btm [2]  Array variable is already defined "b"
    ^C
     
    [R:\LNX] crazy
    16:12:25
    TCC: R:\LNX\crazy.btm [2]  Array variable is already defined "b"
    ^C
    bye
    
     
  24. samintz

    samintz Scott Mintz

    Joined:
    May 20, 2008
    Messages:
    1,178
    Likes Received:
    11
    Note that replacing "goto goner" with "leave" makes no difference. I get the same behavior.
     

Share This Page