QBasic: how to run a program from within another program? - qbasic

I have made two different programs in QBasic and they both are saved in different .bas files, i.e one is 1.bas and the other 2.bas.
How to open program 1.bas while I am in program 2.bas, without closing it?
Program 1 should run inside program 2 for some time, and when it ends I should again be in program 2. Is there any way to do that?
I would like to know if there is a syntax for this that works in QBasic and/or QB64.

In Qbasic you can use CHAIN command to pass control to another .BAS file and when it is finished it will return to the first .BAS file. You can combine it with COMMON to also share variables between the two programs.
You could also use RUN but in QBasic you can't pass variables (not sure but I think the control will not return). And in QB64 it is possible to pass variables using RUN
See the standard COM1_EX.BAS and COM2_EX.BAS as an example, contents of COM1_EX.BAS:
' == COM1_EX.BAS - COMMON statement programming example ==
DIM Values(1 TO 50)
COMMON Values(), NumValues
PRINT "Enter values one per line. Type 'END' to quit."
NumValues = 0
DO
INPUT "-> ", N$
IF I >= 50 OR UCASE$(N$) = "END" THEN EXIT DO
NumValues = NumValues + 1
Values(NumValues) = VAL(N$)
LOOP
PRINT "Leaving COM1_EX.BAS to chain to COM2_EX.BAS"
PRINT "Press any key to chain... "
DO WHILE INKEY$ = ""
LOOP
CHAIN "com2_ex"
contents of COM2_EX.BAS:
' == COM2_EX.BAS - COMMON statement programming example ==
' Notice that the variables Values() and NumValues from COM1_EX
' will be called X() and N here in COM2_EX
DIM X(1 TO 50)
COMMON X(), N
PRINT
PRINT "Now executing file com2_ex.bas, reached through a CHAIN command"
IF N > 0 THEN
Sum = 0
FOR I = 1 TO N
Sum = Sum + X(I)
NEXT I
PRINT "The average of the values is"; Sum / N
END IF

I get zero for average sum. It does not pass the array values

Formerly, I used the Qbasic "Join" command successfully for my lengthy Structural programs but it never returned to the original program. In Structural Designing, you have to create a Member Matrix,Property Matrix,Do some Matrix Multiplications, and Load Matrix. Using another program to Inverse for the resulting Matrix. The "Chain" command in any Basic software does not work at all. There ought to be a command to run one program and go to execute another program and return the values/Text it created. As I am running Win 10, 64 bit and I'm not a Comp. expert,

Related

How to get a script to give a value to an input prompt?

I have a collection of smaller scripts foo1, foo2, etc. and a script master.m that runs them all, like this:
% master.m
run foo1
run foo2
Let's say foo1 calls for input somewhere by saying a = input('Gimme a number\n');.
I thought that if I put the value(s) I wanted on new lines after the run command that they would be entered as input, but they don't. I've also tried enclosing them as a string, i.e. '5'. That doesn't work either.
Is their another function I should use? I looked at the help file for input, but there's no output function. Presumably there's something like write or writetostdio somewhere.
How do I give user input to a script that is being called by another script without touching the keyboard? Can I put the values I want to input in the master.m file?
EDIT:
Because there's some confusion, I'll try to clear it up.
The scripts foo1 and foo2 will NOT be passing values back and forth. Every script will be run independently. Instead, I'm trying to test a program for a range of user behaviours (which are responses to prompts via input in foo1). These are normally typed on the keyboard, but I want my master.m file to tell foo1 what the user inputs are.
Sorry if this is confusing, but hopefully that clears it up.
Modifying existing code to accommodate both manual input and testing inputs is trivial:
function foo1(niterations)
if nargin == 0
niterations = round(input('How many iterations? '));
end
for ii = 1:numel(niterations)
% Run the thing
fprintf('Running some random program with %d iterations! Yay!\n', niterations(ii));
end
end
Using this approach we can do:
>> foo1
How many iterations? 2
Running some random program with 2 iterations! Yay!
or
>> foo1(2)
Running some random program with 2 iterations! Yay!
or
>> foo1([1, 3, 5, 7, 9])
Running some random program with 1 iterations! Yay!
Running some random program with 3 iterations! Yay!
Running some random program with 5 iterations! Yay!
Running some random program with 7 iterations! Yay!
Running some random program with 9 iterations! Yay!
This is far more logical than trying to pipe things from text files, use evalin to poof things into workspaces, or whatever automagical approach is required to accommodate using scripts in this fashion.
Ok, this is a bit ugly... but might be a work-around if for some reason foo1.m etc. have to remain as scripts.
The idea is to replace each instance of input with a newly defined function myInput which checks if a variable PROMPT_VALUE has been set in the base work-space; and returns that if so, and otherwise passes through to the built-in input. For example:
% myInput.m
function [ valueOut ] = myInput( promptString )
W = evalin('caller','whos'); %or 'base'
doesPVexist = ismember('PROMPT_VALUE',[W(:).name]);
if doesPVexist
valueOut = evalin('caller', 'PROMPT_VALUE');
else
valueOut = input(promptString);
end
end
Assuming we have the following sub-scripts:
% foo1.m
a = myInput('Number to double: ');
disp(2*a);
% foo2.m
b = myInput('Number to halve: ');
disp(b/2);
We can test the approach as follows:
% master.m
clearvars;
PROMPT_VALUE=5;
run foo1.m;
PROMPT_VALUE=3;
run foo2.m
If you run this as-is it will take the PROMPT_VALUE as inputs to each of the subscripts (returning 10, and 1.5). If those lines are commented out it will look for input from the user.

calling an external program in matlab in a loop

I have installed Matlab 2014 in Ubuntu. My problem:
I build several input files for another program, Quantum Espresso, in Matlab. Now I should pass these files to Quantum Espresso using matlab command line. Now I know I can do this using Linux Terminal, but my way of solving my problem has reached the point that my only option is 'calling Quantum Espresso from matlab'. One single call is actually easy:
! installation/folder/espresso-5.3.0/bin/pw.x < inputfile > outputfile
The problem is I have several input files named like 1name.in 1name.in ... . So this repeated calls should be done in a loop. But how?
I have tried:
the shell script for looping though the files. I added that extra '!' to each line of the script but it doesn't work.
I also tried to write a loop like this :
for i = 1:N
prefix = int2str(i);
fuloutname = [prefix 'name' '.' 'out'];
fulinname = [prefix 'name' '.' 'in'];
! adress/espresso-5.3.0/bin/pw.x < fulinname > fuloutname ;
end
In which 'N' in number of my input files. Clearly running this means you are passing a file nemaed 'fulinname' not 1name.in and will result in an output file named 'fuloutname'
I also tried to do it as you normally load various files in a loop but it also did not work
Please help me.
You should use the unix function:
for i = 1:N
prefix = int2str(i);
fuloutname = [prefix 'name' '.' 'out'];
fulinname = [prefix 'name' '.' 'in'];
mycommand = ['adress/espresso-5.3.0/bin/pw.x < ',fulinname,' > ',fuloutname];
unix(mycommand);
%system(mycommand); %will give you the same, result and this function is cross-platform
end

Control flow within an eval function in Matlab

If I include a continue as a parameter of an eval() instruction, it does not work as expected. For example, when executing the following code:
listParam = {'a','b','c'};
a = 17;
b = NaN;
c = 4;
for ii=1:numel(listParam),
eval(['if isnan(',listParam{ii},'), continue; end']);
disp(['The parameter ', listParam{ii}, ' is not a NaN.']);
end
It will prompt the error:
Error: A CONTINUE may only be used within a FOR or WHILE loop.
Anybody knows why?
Note: I know that I should avoid eval() and the previous example could be refactored in a much better coding; but I found a weird behaviour and I am curious what is happening.
The expression you pass to eval must be a valid matlab expression on it's own, any surrounding code is not considered. This means each continue must be surrounded by a loop. Either put the surrounding for within your eval or put the continue outside.
As #Daniel has pointed out, eval is called by the script, while it is not directly controlled by the for loop. You can think it as: the continue in eval would move the program counter to the head of the code inside eval, but not that of the for loop; this of course would fail, as Matlab does not allow jumping between lines.
A continue can only appear directly inside a for or while loop. However, you can hack the code like this:
for ii=1:numel(listParam),
eval(['if isnan(',listParam{ii},'), x=1; else, x=0; end']);
if x
continue;
end
disp(['The parameter ', listParam{ii}, ' is not a NaN.']);
end
Strangely, x happens to appear in the script's stack. However, this is far from a good piece of code. Never use this method.
Edit: about the "control" scope of eval.
I'm not talking about the variable scope / workspace of eval. Hints can be found in several documentations like this and this. In short, eval uses the "current" workspace.
However, I found the following things interesting:
Running continue directly in eval
for ii = 1:2
eval('continue')
ii+10
end
This simply fails, as shown in the question. The error is Error: A CONTINUE may only be used within a FOR or WHILE loop. which means the continue inside eval cannot find any loop (the for loop).
Calling a separate script in a for loop
for ii = 1:2
foo
ii+10
end
while script foo.m is
ii
continue
First of all, in foo.m Mlint gives a red-line warning, which usually indicates an error that can stop the code from running, saying that CONTINUE is only valid in a FOR or WHILE loop. But pressing F5 on foo.m does not have any problem - in fact running a single continue anywhere does not crash the code.
Running the main script gives output
ii =
1
ii =
2
>>
....so foo.m catches the for loop?
eval('foo') - I really don't understand Matlab
for ii = 1:2
eval('foo')
ii+10
end
The result surprised me a bit.
ii =
1
ans =
11
ii =
2
ans =
12
>>
Thought: eval runs the code in an independent control flow, but shares its workspace with the current one. It is (something but not exactly) like an isolated world model, in which (here in Matlab) different pieces of code can interact with the same set of variables, but cannot interact with each other in the sense of control flow.
Unfortunately, I was unable to find any existing resources as reference to prove this idea.
This does not change my solution: in any case, try to avoid using eval.

How to use command line arguments in Fortran?

GCC version 4.6
The Problem: To find a way to feed in parameters to the executable, say a.out, from the command line - more specifically feed in an array of double precision numbers.
Attempt: Using the READ(*,*) command, which is older in the standard:
Program test.f -
PROGRAM MAIN
REAL(8) :: A,B
READ(*,*) A,B
PRINT*, A+B, COMMAND_ARGUMENT_COUNT()
END PROGRAM MAIN
The execution -
$ gfortran test.f
$ ./a.out 3.D0 1.D0
This did not work. On a bit of soul-searching, found that
$./a.out
3.d0,1.d0
4.0000000000000000 0
does work, but the second line is an input prompt, and the objective of getting this done in one-line is not achieved. Also the COMMAND_ARGUMENT_COUNT() shows that the numbers fed into the input prompt don't really count as 'command line arguments', unlike PERL.
If you want to get the arguments fed to your program on the command line, use the (since Fortran 2003) standard intrinsic subroutine GET_COMMAND_ARGUMENT. Something like this might work
PROGRAM MAIN
REAL(8) :: A,B
integer :: num_args, ix
character(len=12), dimension(:), allocatable :: args
num_args = command_argument_count()
allocate(args(num_args)) ! I've omitted checking the return status of the allocation
do ix = 1, num_args
call get_command_argument(ix,args(ix))
! now parse the argument as you wish
end do
PRINT*, A+B, COMMAND_ARGUMENT_COUNT()
END PROGRAM MAIN
Note:
The second argument to the subroutine get_command_argument is a character variable which you'll have to parse to turn into a real (or whatever). Note also that I've allowed only 12 characters in each element of the args array, you may want to fiddle around with that.
As you've already figured out read isn't used for reading command line arguments in Fortran programs.
Since you want to read an array of real numbers, you might be better off using the approach you've already figured out, that is reading them from the terminal after the program has started, it's up to you.
The easiest way is to use a library. There is FLAP or f90getopt available. Both are open source and licensed under free licenses.
The latter is written by Mark Gates and me, just one module and can be learned in minutes but contains all what is needed to parse GNU- and POSIX-like command-line options. The first is more sophisticated and can be used even in closed-source projects. Check them out.
Furthermore libraries at https://fortranwiki.org/fortran/show/Command-line+arguments
What READ (*,*) does is that it reads from the standard input. For example, the characters entered using the keyboard.
As the question shows COMMAND_ARGUMENT_COUNT() can be used to get the number of the command line arguments.
The accepted answer by High Performance Mark show how to retrieve the individual command line arguments separated by blanks as individual character strings using GET_COMMAND_ARGUMENT(). One can also get the whole command line using GET_COMMAND(). One then has to somehow parse that character-based information into the data in your program.
I very simple cases you just need the program requires, for example, two numbers, so you read one number from arg 1 and another form arg 2. That is simple. Or you can read a triplet of numbers from a single argument if they are comma-separated like 1,2,3 using a simple read(arg,*) nums(1:3).
For general complicated command line parsing one uses libraries such as those mentioned in the answer by Hani. You have set them up so that the library knows the expected syntax of the command line arguments and the data it should fill with the values.
There is a middle ground, that is still relatively simple, but one already have multiple arguments, that correspond to Fortran variables in the program, that may or may not be present. In that case one can use the namelist for the syntax and for the parsing.
Here is an example, the man point is the namelist /cmd/ name, point, flag:
implicit none
real :: point(3)
logical :: flag
character(256) :: name
character(1024) :: command_line
call read_command_line
call parse_command_line
print *, point
print *, "'",trim(name),"'"
print *, flag
contains
subroutine read_command_line
integer :: exenamelength
integer :: io, io2
command_line = ""
call get_command(command = command_line,status = io)
if (io==0) then
call get_command_argument(0,length = exenamelength,status = io2)
if (io2==0) then
command_line = "&cmd "//adjustl(trim(command_line(exenamelength+1:)))//" /"
else
command_line = "&cmd "//adjustl(trim(command_line))//" /"
end if
else
write(*,*) io,"Error getting command line."
end if
end subroutine
subroutine parse_command_line
character(256) :: msg
namelist /cmd/ name, point, flag
integer :: io
if (len_trim(command_line)>0) then
msg = ''
read(command_line,nml = cmd,iostat = io,iomsg = msg)
if (io/=0) then
error stop "Error parsing the command line or cmd.conf " // msg
end if
end if
end subroutine
end
Usage in bash:
> ./command flag=T name=\"data.txt\" point=1.0,2.0,3.0
1.00000000 2.00000000 3.00000000
'data.txt'
T
or
> ./command flag=T name='"data.txt"' point=1.0,2.0,3.0
1.00000000 2.00000000 3.00000000
'data.txt'
T
Escaping the quotes for the string is unfortunately necessary, because bash eats the first quotes.

In perl, what is the difference between $DB::single = 1 and 2?

What is the difference between putting $DB::single=1 and $DB::single=2 in your code? Both seem to have the identical effect of halting execution at the statement following the assignment when I do a 'c' on the perl debugger command line.
perldebug says that a value of 1 is equivalent to having just pressed 's' to get to the next statement, and 2 is the same as 'n', but what difference does it make how you got to the statement?
From perldebug:
If you set $DB::single to 2, it's equivalent to having just typed the n command (which executes over subroutine calls), whereas a value of 1 means the s command (which enters subroutine calls).
That much you know already.
From a user point of view, I'm pretty sure there is no difference. I base this on an examination of the actual DB.pm source code.
Let's follow this logically. You may want to refer to the source code. I've simplified some of the code to remove unnecessary detail but you should be able to get the idea from my descriptions.
When you are executing code in the debugger, there are (at least) two important variables, running and single. The combination of these is what decides whether code is run:
running single description
------- ------ -----------
0 ? not running
1 0 running flat-out
1 1 single stepping, execute into function
1 2 single stepping, execute over function
The DB() function is executed for every single line, and it contains the following snippet which will stop the running if single has been set (it always executes the current line regardless):
if ($DB::single) {
$DB::single = 0;
$running = 0;
}
That's why, if you set the variable in your Perl code, it will break (by break, I mean "stop running the code", not "damage somehow") the debugger at the next line.
When running is 0, the DB() function enters this little loop:
# Now sit in an event loop until something sets $running
do {
$c->idle; # call client event loop; must not block
} until $running;
In other words, it waits on a user command which sets running back to 1. This can be done by one of the following three functions:
sub next {
$DB::single = 2;
$running = 1;
}
sub step {
$DB::single = 1;
$running = 1;
}
sub cont {
$DB::single = 0;
$running = 1;
}
You can see that these three commands set up a different combination of single and running which will be used while executing the next Perl line (see the earlier table to see what these combinations mean).
The ability to use either 1 or 2 in your Perl code is a direct result of the fact that you're using a sneaky but clever trick to break execution from your Perl code itself, by setting a variable that would normally be set by a debugger command.
That's why it's not the value that matters so much as the fact you're forcing the debugger into a particular state.