I don't want to use global value it is dangerous for a big program. Code is like this
subroutine has_key(id)
if (true) then
return 1
else
return 0
end if
end subroutine
subroutine main
if(has_key(id))
write(*,*) 'it works!'
end subroutine
how can I do something like this using subroutine. I was thinking of return a flag but I may use a global value. Anyone has idea?
Like this
subroutine test(input, flag)
integer, intent(in) :: input
logical, intent(out) :: flag
flag = input>=0
end subroutine
and
call test(3,myflag)
will set myflag to .true.
Note
that subroutines return values through their argument lists;
the use of the intent clause to tell the compiler what the subroutine can do with its arguments;
my example is very simple and you will probably want to adapt it to your needs.
You could also do it with a function. Say it returns true for even numbers
logical function has_key(id)
integer, intent(in):: id
has_key = mod(id,2) .eq. 0
end function has_key
program main
do ii = 1, 4
if(has_key(ii))
print *, ii, ' has key'
else
print *, ii, ' no key'
end if
end do
end program
Related
A program that loads and processes command-line arguments should be created.
Here comes a few examples on how it should look when you run it (bold text is the text that the user will type):
Terminal prompt % **./my_program**
No arguments given.
Terminal prompt % **./my_program 123**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 10 XYZ 999 Greetings!**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 3 HELLO**
Message: HELLOHELLOHELLO
The program "./my program" is ending.
Terminal prompt % **./my_program 0 Bye**
Message:
The program "./my program" is ending.
This is my code so far:
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
type String is array (Positive) of Character;
N : Integer;
Text : String;
begin
N := Argument_Count;
if N = 0 then
Put_Line("No arguments given.");
elsif N /= 2 then
Put_Line("Wrong number of arguments given.");
elsif N = 2 then
Put("Message: ");
for I in 1 .. N loop
Put(Text);
New_Line;
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
end my_program;
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says
Missing argument for parameter "Item" in call to "Put"
I don't know if I declared my string right because I don't want a string of a specific length. Can anyone come up with something that could help me solve case 4 and 5? It would be nice and highly appreciated
This seems to be a homework or exam question, so I would usually not provide a full answer. But Chris already gave that (with some defects), so here is my suggestion. Compared to Chris's solution, I try to avoid using unnecessary variables, and I favour case statements over if-then-else cascades, and I try to reduce the scope of exception handlers. I prefer to put use clauses in the subprogram so that the context-clause section contains only with clauses. I use the string-multiplying "*" operator from Ada.Strings.Fixed, but that is perhaps an unnecessary refinement.
with Ada.Command_Line;
with Ada.Strings.Fixed;
with Ada.Text_IO;
procedure My_Program
is
use Ada.Strings.Fixed;
use Ada.Text_IO;
begin
case Ada.Command_Line.Argument_Count is
when 0 =>
Put_Line ("No arguments given.");
when 2 =>
begin
Put_Line (
Natural'Value (Ada.Command_Line.Argument(1))
* Ada.Command_Line.Argument(2));
exception
when Constraint_Error =>
Put_Line ("Invalid input for argument 1.");
end;
when others =>
Put_Line ("Wrong amount of arguments given.");
end case;
Put_Line (
"The program """
& Ada.Command_Line.Command_Name
& """ is ending.");
end My_Program;
Note that my version:
Rejects negative first arguments (like "-3").
Outputs the repeated strings on a single line, as was required by the examples given.
Includes the name of the program in the final message, as was also required.
Given the clarification in comments as to the purpose of the program, to print a message n times where n is the first argument, and the message is the second argument, you need to parse the first argument as an integer. This can be done with Integer'Value.
Now, that raises the prospect of the user not running the program with an integer. So we have to handle the possible Constraint_Error exception.
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
argc : Integer;
N : Integer;
begin
argc := Argument_Count;
if argc = 0 then
Put_Line("No arguments given.");
elsif argc /= 2 then
Put_Line("Wrong number of arguments given.");
else
n := Integer'Value(Argument(1));
Put("Message: ");
for I in 1 .. N loop
Put_Line(Argument(2));
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
exception
when Constraint_Error =>
Put_Line("Invalid input for argument 1.");
end my_program;
As an aside, when we've checked in our conditional if argc is zero, and that it doesn't equal two, we don't have to use elsif. The only other possibility is that it is 2.
You say
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says "Missing argument for parameter "Item" in call to "Put". "
which doesn't make sense, because your program as shown doesn't compile. I guess what you mean is "when I try to add the code to handle cases 4 and 5, it doesn't compile".
The reason why it doesn’t compile is hidden in the actual error messages:
leun.adb:24:10: no candidate interpretations match the actuals:
leun.adb:24:10: missing argument for parameter "Item" in call to "put" declared at a-tiinio.ads:97, instance at a-inteio.ads:18
...
leun.adb:24:14: expected type "Standard.Integer"
leun.adb:24:14: found type "String" defined at line 7
leun.adb:24:14: ==> in call to "Put" at a-tiinio.ads:80, instance at a-inteio.
You have at line 7
type String is array (Positive) of Character;
which is both misleading and not what you meant.
It’s ’not what you meant’ because array (Positive) means an array of fixed length from 1 to Positive’Last, which will not fit into your computer’s memory. What you meant is array (Positive range <>).
Even with this correction, it's 'misleading' because although it would be textually the same as the declaration of the standard String in ARM 3.6.3(4), in Ada two different type declarations declare two different types. So, when you write Put(Text); the Put that you meant to call (the second in ARM A.10.7(16)) doesn’t match because it’s expecting a parameter of type Standard.String but Text is of type my_program.String.
Cure for this problem: don’t declare your own String type.
module rev_array;
int array_in[10]={0,1,2,3,4,5,6,7,8,9};
typedef integer array[9:0];
function array reverse(int array_in[10]);
for(int j=$size(array_in)-1,int i=0;j>=0;j--,i++)
begin
reverse[j]=array_in[i];
end
// working for(integer k=0;k<$size(array_in)-1;k++)
// working $display("reverse[%0d]:%0d", k, reverse[k]);
$display("inside function");
endfunction:reverse
initial
begin
reverse(array_in);
for(integer k=0;k<$size(array_in)-1;k++)
begin
$display("reverse[%0d]:%0d", k, reverse[k]);
end
end
endmodule
Error-[IUS] Illegal use of scope
testbench.sv, 22
rev_array, "rev_array.reverse"
Scope cannot be used in this context
Error-[XMRIBS] Illegal bit select
testbench.sv, 22
Error is found in following cross-module reference, illegal bit select on
the target.
Source info: $display("reverse[%0d]:%0d", k, rev_array.reverse[k]);
I am trying to reverse an array and return it in system verilog function, I am able to see the reversed array inside the function by printing it but
when I try to print it using $display outside the function, I think it is
not being returned properly somehow, in the 4th line from end, getting
errorError-[IUS]
your both issues are related to the line where you use reverse function name as an array within $display.
$display("reverse[%0d]:%0d", k, reverse[k]);
--------------------------------^^^^^^^^^^
this is an illegal syntax causing both messages.
your initial block should look like the following.
initial
begin
array result;
result = reverse(array_in);
//^^^^^^^^^^^^^^^^^^^^^^^^^//
for(integer k=0;k<$size(array_in)-1;k++)
begin
$display("reverse[%0d]:%0d", k, result[k]);
// ^^^^^^ //
end
end
call the function and use returned results for display.
module rev_array;
initial
begin
int array_in[10]={0,1,2,3,4,5,6,7,8,9};
typedef integer array[9:0];
function array reverse(int array_in[10]);
array reverse;
for(integer i=0;i<$size(array_in)-1;i++)
begin
for(int j=$size(array_in)-1;j>=0;j--)
begin
reverse[j]=array_in[i];
end
end
return reverse;
endfunction:reverse
reverse(array_in);
for(integer k=0;k<$size(array_in)-1;k++)
begin
$display("reverse[%0d]:%0d", k, reverse[k]);
end
end
endmodule
For the above code, I am getting error
Error-[SE] Syntax error
Following verilog source has syntax error :
"testbench.sv", 7: token is 'function'
function array reverse(int array_in[10]);
I want to return an array named reverse(same name as the function ) which has 10 elements, each element being an integer, what am I doing wrong here ?
You cannot define a function in the middle of a procedural block. Move it to the top level of the module. You have many other problems. Note there is a built-in reverse array method.
In an IML proc I have several martices and several vectors with the names of columns:
proc IML;
mydata1 = {1 2 3, 2 3 4};
mydata2 = {1 2, 2 3};
names1 = {'red' 'green' 'blue'};
names2 = {'black' 'white'};
To assign column names to columns in matrices one can copypaste the mattrib statement enough times:
/* mattrib mydata1 colname=names1;*/
/* mattrib mydata2 colname=names2;*/
However, in my case the number of matrices is defined at execution, thus a do loop is needed. The following code
varNumb=2;
do idx=1 to varNumb;
call symputx ('mydataX', cat('mydata',idx));
call symputx ('namesX', cat('names',idx));
mattrib (symget('mydataX')) colname=(symget('namesX'));
end;
print (mydata1[,'red']) (mydata2[,'white']);
quit;
however produces the "Expecting a name" error on the first symget.
Similar question Loop over names in SAS-IML? offers the macro workaround with symget, what produces an error here.
What is the correct way of using mattrib with symget? Is there other way of making a variable from a string than macro?
Any help would be appreciated.
Thanks,
Alex
EDIT1
The problem is in the symget function. The &-sign resolves the name of the matrix contained in the macro variable, the symget only returns the name of the macro.
proc IML;
mydata1 = {1 2 3};
call symputx ('mydataX', 'mydata1');
mydataNew = (symget('mydataX'));
print (&mydataX);
print (symget("mydataX"));
print mydataNew;
quit;
results in
mydata1 :
1 2 3
mydata1
mydataNew :
mydata1
Any ideas?
EDIT2
Function value solves the symget problem in EDIT1
mydataNew = value(symget('mydataX'));
print (&mydataX);
print (value(symget("mydataX")));
print mydataNew;
The mattrib issue but persists.
SOLVED
Thanks Rick, you have opened my eyes to CALL EXECUTE() statement.
When you use CALL SYMPUTX, you should not use quotes for the second argument. Your statement
call symputx ('mydataX', 'mydata1');
assigns the string 'mydata1' to the macro variable.
In general, trying to use macro variables in SAS/IML loops often results in complicated code. See the article Macros and loops in the SAS/IML language for an indication of the issues caused by trying to combine a macro preprocessor with an interactive language. Because the MATTRIB statement expects a literal value for the matrix name, I recomend that you use CALL EXECUTE rather than macro substitution to execute the MATTRIB statement.
You are also having problems because a macro variable is always a scalar string, whereas the column name is a vector of strings. Use the ROWCAT function to concatenate the vector of names into a single string.
The following statements accomplish your objective without using macro variables:
/* Use CALL EXECUTE to set matrix attributes dynamically.
Requires that matrixName and varNames be defined at main scope */
start SetMattrib;
cmd = "mattrib " + matrixName + " colname={" + varNames + "};";
*print cmd; /* for debugging */
call execute(cmd);
finish;
varNumb=2;
do idx=1 to varNumb;
matrixName = cat('mydata',idx);
varNames = rowcat( value(cat('names',idx)) + " " );
run SetMattrib;
end;
I have a problem with defining default arguments to a function in Octave/Matlab by a previously defined constant. Could someone give me a hint, why in the following code test1(1) displays 1 and 100, while test2(1) fails with error:testarg' undefined near line 1 column 36`? Thank you so much!
testarg = 100
function test1 (arg1=testarg, arg2=100)
disp(arg1)
disp(arg2)
endfunction
function test2 (arg1=testarg, arg2=testarg)
disp(arg1)
disp(arg2)
endfunction
test1(1)
test2(2)
Edit:
Please not that the order of the arguments matters:
function test3 (arg1=100, arg2=testarg)
disp(arg1)
disp(arg2)
endfunction
octave:8> test1(1)
1
100
octave:9>test3(1)
error: `testarg' undefined near line 1 column 32
I've never seen that syntax in Matlab, is it an Octave thing? In general default arguments need to be a constant rather than some other variable that may or may not be in scope or initialised at the time the function is called (feel free to educate me on languages where this isn't the case, of course).
The 'normal' way to do default arguments in regular Matlab is like this:
function test1(arg1, arg2)
if nargin < 2
arg2 = 100;
end
if nargin < 1
arg2 = testarg; % if testarg isn't in scope this still won't work
end
disp(arg1);
disp(arg2);
end
This looks like a bug to me, you should report it to the Octave developers.
In the meanwhile, here is a workaround:
testarg = 100
function test1 (arg1, arg2)
if nargin < 2, arg2 = 100; end
if nargin < 1, arg1 = testarg; end
disp(arg1)
disp(arg2)
endfunction
test1(2)
That said, it is better to be explicit here, and define them as "global variables". If the testarg is intended as a constant, better make it a function that returns said value:
testarg = #() 100;