What is the command and syntax for breaking/stopping a program in QBASIC? - qbasic

I am currently writing a QBASIC program that runs an indefinite loop (while loop). However, if a certain condition is met, I want to exit the program. What command do I use, and also what is the syntax.
Thanks

ENDexits program, and clears all variables, which frees up memory.
STOPexits program, but retains the value of all variables, which makes it possible (in certain versions of QB) to continue execution at another point, by choosing Set next statement from the Debugmenu, and then Startfrom the Runmenu. END has the same effect as STOP + choosing Restart from the Runmenu once the program has terminated.
If you have a loop, and want to exit the program from inside it, you may use either
DO
IF condition THEN EXIT DO
LOOP
END
or
DO
IF condition THEN END
LOOP

You're looking for the END or SYSTEM statement. For example:
PRINT "Hello World!"
END
PRINT "This won't be printed."
If you're using regular old QBASIC/QuickBASIC, then you can ignore all of the QB64 details on the linked pages and just use either SYSTEM or END. Both will do the same thing for the most part.1
If you're using FreeBASIC, it's recommended to use END instead of SYSTEM since some things won't get cleaned up properly when you use SYSTEM. See SYSTEM for more information pertaining to FreeBASIC if that's what you're using.
1 The END statement when running the program using QB.EXE /RUN PROGRAM.BAS will print "Press any key to continue" before exiting to the QB/QBASIC environment. The SYSTEM statement when run the same way will simply return you to the DOS shell without any need for a key press. Also, typing SYSTEM in the "Immediate Window" of the QB/QBASIC environment will exit the environment and return to the DOS shell. Otherwise the two statements behave exactly the same in QB/QBASIC, whether for standalone (compiled) programs or .BAS modules.

You can keep any condition according to the need of your program. For eg:
CLS
LET a = 5
WHILE a > 0
PRINT a;
a = a - 1
WEND
END
Here, in the program while wends executes itself until a = 0. This will not run an infinite loop.

The answer is
exit();
to exit the program.

Related

Can script be configured to "exit on unhandled exception"?

Is there a simple way to configure a MATLAB script so that it exits upon encountering an unhandled exception (as opposed to reverting to the REPL)?
The reason for this is that when executing many runs of a script in (unsupervised) batch mode, any script that fails should exit immediately, and not hang indifinitely at (unattended) interactive prompt.
IMPORTANT CLARIFICATION: this script is meant to be executed from the Unix command line, not from the MATLAB interactive prompt. More specifically, the script is to be invoked with
matlab -nodesktop -nosplash -nojvm -r myscript.m
The script should always terminate MATLAB after it has executed all its code, and return a status code reflecting its success (0) or failure (some non-zero integer).
I'm looking for a global setting (or a command-line flag) that can be put into effect without affecting the rest of the code.
IOW, I'm looking for something analogous to the -e flag available in some Unix shells (e.g. bash, zsh), which has the effect of aborting a script immediately whenever the return status of a statement is non-zero (meaning that the statement failed).
I know that I can wrap the entire body of a script with a try-catch, like this (for example):
try
exit_code = 0;
%
% BODY OF SCRIPT
%
catch exc
fprintf(2, 'CAUGHT EXCEPTION:\n');
fprintf(2, '%s(%d): %s\n', exc.stack.file, exc.stack.line, exc.message);
exit_code = 1;
end
exit(exit_code);
...but, as I said above, I'm looking for something simple, with no, or at most minimal, impact on the code.
The default behavior when an unhandled exception occurs is that information about the error will be printed to the command window and control will return to the command window. You should not be getting an interactive prompt from the error unless you've explicitly enabled it with dbstop if error or there is a try/catch with a keyboard command in the catch block. To just get a plain error rather than an interactive prompt you can use dbclear if error to disable this behavior. I would check your startup files to make sure that you don't have dbstop if error in there.
A try/catch pair is really the only way that this can be done. What you can do is wrap your calls to your script with another file and put the call to your script within a try/catch block. This has the added benefit that you don't have to modify the script itself, just the "runner".
Also you won't want to use exit as that completely exits MATLAB.
your_script.m
disp('Doing my thing')
error('Throwing an error!')
calling_script.m
for k = 1:100
try
% Call your other script and hope for no errors!
your_script
catch ME
% Print information about the error and continue
fprintf(2, 'CAUGHT EXCEPTION:\n');
fprintf(2, '%s(%d): %s\n', ME.stack.file, ME.stack.line, ME.message);
end
end
Update
Based upon the clarification that you've provided that you want to run this from the Unix command line, you'll still want to use something similar with a try/catch statement combined with exit. Again, you could do this in an external file as shown above
calling_script.m
code = 0;
try
your_script
catch ME
fprintf(2, 'CAUGHT EXCEPTION:\n');
fprintf(2, '%s(%d): %s\n', ME.stack.file, ME.stack.line, ME.message);
code = 1;
end
exit(code)

Variables may not be used as commands

Using fish shell, I'm writing very simple script that checks the command execution
#!/usr/bin/fish
command
if $status
echo "Oops error"
else
echo "Worked OK"
#...
end
And get the error message:
fish: Variables may not be used as commands. Instead, define a function like “function status; 0 $argv; end”. See the help section for the function command by typing “help function”.
The message looks pretty straight forward but no "defining function like..." nor "help function" helps solving the problem.
There is also a 'test' command, that sounds promising. But docs say it is to be used to check files...
How this simple thing should be done with fish shell?
Heh... And why all documentation is SO misleading?..
P.S. Please, don't write about 'and' command.
Fish's test command currently works exactly like POSIX test (i.e. the one you'll find in bash or similar shells). It has a couple of operations, including "-gt", "-eq", "-lt" to check if a number is bigger, equal or less than another number, respectively.
So if you want to use test, you'll do if test $status -eq 0 (a 0 traditionally denotes success). Otherwise, you can check the return value of a command by putting it in the if clause directly like if command (which will be true if the command returns 0) - that's what fish is trying to do here, which is why it complains about a variable being used in place of a command.

Break out of proprietary toolbox after a given time

I am iterating through a large test matrix in MATLAB and calling second-party proprietary software (running in MATLAB) each time. I cannot edit the software source code. Sometimes, the software hangs, so I want to exit it after a certain amount of time and move on to the next iteration.
In pseudocode, I'm doing this:
for i = 1:n
output(i) = proprietary_software(input(i));
end
How can I skip to the next iteration (and possibly save output(i)='too_long') if the proprietary software is taking too long?
You will need to call Matlab from another instance of Matlab. The other instance of Matlab will run the command and release control to the first instance of Matlab to wait while it either saves the results or reaches a certain time. In this case, it will wait 30 seconds.
You will need 1 additional function. Make sure this function is on the Matlab path.
function proprietary_software_caller(input)
hTic=tic;
output=proprietary_software(input);
hToc=toc(hTic);
if hToc<30
save('outfile.mat','output');
end
exit;
end
You will need to modify your original script this way
[status,firstPID] = str2double(system('for /f "tokens=2 delims=," %F in (''tasklist /nh /fi "imagename eq Matlab.exe" /fo csv) do #echo %~F'')'));
for i = 1:n
inputStr=num2str(input(i));
system(['matlab.exe -nodesktop -r proprietary_software_caller\(',inputStr,'\)&']);
hTic=tic;
hToc=toc(hTic);
while hToc<30 || ~(exist('outfile.mat','file')==2)
hToc=toc(hTic);
end
if hToc>=30
output(i)= 'too_long';
[status,allPIDs]=str2double(system('for /f "tokens=2 delims=," %F in (''tasklist /nh /fi "imagename eq Matlab.exe" /fo csv) do #echo %~F'')'));
allPIDs(allPIDs==firstPID)=[];
for a=1:numel(allPIDs)
[status,cmdout]=system(['taskkill /F /pid ' sprintf('%i',allPIDs(a))]);
end
elseif exist('outfile.mat','file')==2
loadedData=load('outfile.mat');
output(i)=loadedData.output;
delete('outfile.mat');
end
end
I hope this helps.
You are essentially asking for a way to implement a timeout on MATLAB code. This can be surprisingly tricky to implement. The first thing to state is that if the MATLAB code in question cannot terminate itself, either by exiting cleanly or throwing an error, then it is not possible to terminate the code without quitting or killing the MATLAB process in question. For example, throwing an error in an externally created timer does not work; the error is caught.
The first question to ask is therefore:
Can the over-running code be made to terminate itself?
This depends on the cause to the over-run, and also your access to the source code:
If the program gets stuck in an infinite (or very long-running) loop, either in MATLAB code or a mex file for which you have source code, or which calls a user-defined callback each iteration, then you can get this code to terminate itself.
If the program gets stuck inside a MATLAB builtin, or a p-code file or mex file for which you don't have the source code, and doesn't have support for calling a callback regularly, then it won't be possible for you to get the code to terminate itself.
Let's address the first case. The easiest way to get the code to terminate itself is to get it to throw an error, which is caught by the caller, if it exceeds the timeout time. E.g. in the OP's case:
for i = 1:n
tic();
try
output(i) = proprietary_software(input(i));
catch
end
end
with the following code somewhere in the over-running loop, or called in a loop callback or mex file:
assert(toc() < 10, 'Timed out');
Now for the second case. You need to kill this MATLAB process, so it makes sense for this to be a MATLAB process you have spawned from your current MATLAB session. You can do this using a system call similar to this:
system('matlab -nodisplay -r code_to_run()')
While it is possible for a MATLAB process to quit itself in some situations which could be of use here (e.g. a timer function calling quit('force')), the most reliable way of killing a MATLAB process is to do it with a system call, using taskkill (Windows) or kill (Linux/Mac).
A framework using the approach of spawning and killing timed-out MATLAB processes might work like this:
Using system calls, launch one or more new MATLAB processes from your MATLAB session, running the code you want.
Use the file system or a memory mapped file to communicate between the MATLAB processes the function inputs, loop progress, outputs, process ids and timeout times.
Use the original MATLAB process to check the timeout times haven't been reached, or if so to terminate the process in question and instantiate a new one.
Use the original MATLAB process to collect up the function outputs (either from the filesystem or memory mapped file) and exit. Workers should terminate when there is no more work left
I provide a sketch only because a full working implementation of this approach is fairly involved, and in fact it has already been implemented and is publicly available in the batch_job toolbox. In the OP's case, using this toolbox (with a 10 second timeout) you'd call:
output = batch_job(#proprietary_software, input(:)', '-timeout', 10);
Note that for the toolbox to work, its root directory needs to be on your MATLAB path at startup.

Using Expect with Perl and pipe to a file

I'm fairly new to Perl and have been searching the interwebs for documentation for what I'm trying to do. I'm not having any luck.
I have a program that outputs information to stdout with prompts throughout. I need to make a Perl script to pipe that information to a file.
I thought I could use Expect but there seems to be a problem with the pipe after the first prompt.
Here is the part of my code:
# Run program and compare the output to the BASE file
$cmd = "./program arg1 arg2 arg3 arg4 > $outfile";
my $exp = new Expect;
$exp->spawn($cmd);
BAIL_OUT("couldn't create expect object") if (! defined $exp);
$exp->expect(2);
$exp->send("\n");
For this case there is only a single prompt for the user to press "enter". This program is small and very fast - 2 seconds is plenty of time to reach the first prompt.
The output file only contains the first half of the information.
Does anyone have any suggestions on how I can grab the second half as well?
UPDATE:
I've verified that this works with Expect by using a simple script:
spawn ./program arg1 arg2 arg3 arg4
expect "<Return>"
send "\r"
interact
Where "< Return >" is a verbose expression that the Perl script could look for.
Note: I've tried writing my Perl script to expect "< Return >"...it makes no difference.
i.e.
$exp->expect(2, '-re', "<Return>")
Any thoughts?
UPDATE2:
Hazaah! I've found a solution to my problem...completely by accident.
So, I had a mistype in some test code I made...
$exp->expect(2);
$exp->send("\r");
$exp->expect(2);
Note the trailing expect(2)...I accidentally left that in and it worked!
So, I'm trying to understand what is happening. Unix expect does not seem work this way! It appears Expect implemented in Perl "expects" anything...not just prompts?
So, I provided expect another 2 seconds to collect stdout and I am able to get everything.
If anyone can offer some more detailed information as to what is going on here I'd love to understand what is going on.
Try sending \r instead of \n - you're trying to emulate a carriage return, not a newline, and the tty settings might not be translating them.
ALSO:
A suggestion from the Expect docs FAQ section, which seems likely given your accidental solution:
My script fails from time to time without any obvious reason. It
seems that I am sometimes loosing output from the spawned program.
You could be exiting too fast without giving the spawned program
enough time to finish. Try adding $exp->soft_close() to terminate the
program gracefully or do an expect() for 'eof'.
Alternatively, try adding a 'sleep 1' after you spawn() the program.
It could be that pty creation on your system is just slow (but this is
rather improbable if you are using the latest IO-Tty).
Standard unix/tcl expect doesn't exit in interactive mode, which could give your program enough time to finish running.
It's been a while since I've used Expect, but I'm pretty sure you need to provide something for Expect to match the prompt against:
$exp->expect( 2, 'Press enter' );
for example.

How to verify normal termination of R scripts executed from Perl?

I have written a shebang R script and would like to execute it from a Perl script. I currently use system ($my_r_script_path, $r_script_arg1, $r_script_arg2, ...) and my question is how can I verify the R script terminates normally (no errors or warnings).
guess I should make my R script return some true value at the end, only if everything is OK, then catch this value in Perl, but I'm not sure how to do that.
Thanks!
You can set the return value in the command quit(), eg q(status=1). Default is 0, see also ?quit. How to catch that one in Perl, is like catching any other returning value in Perl. It is saved in a special variable $? if I remember right. See also the examples in the perldoc for system, it should be illustrated there.
On a sidenote, I'd just use the R-Perl interface. You can find info and examples here :
http://www.omegahat.org/RSPerl/
Just for completeness :
At the beginning of your script, you can put something like :
options(
warn=2, # This will change all warnings into errors,
# so warnings will also be handled like errors
error= quote({
sink(file="error.txt"); # save the error message in a file
dump.frames();
print(attr(last.dump,"error.message"));
sink();
q("no",status=1,FALSE) # standard way for R to end after errors
})
)
This will save the error message, and break out of the R session without saving, with exit code 1 and without running the .Last.
Still, the R-Perl interface offers a lot more possibilities that are worth checking out if you're going to do this more often.