System Verilog function that takes any number of strings as an argument? - verilog

I want to have a SystemVerilog function that can accept any number of string arguments, this function is essentially a wrapper around the in-built $display as such I want users to be able to call the function in the same way, passing any number of strings into myfunc() as follows:
myfunc(stringVar1, "literalString", stringVar2, stringVarN, intVarToConvertToString);
My current implementation is to just have a single string arg and use the SystemVerilog concatenation operator to concatenate all the strings I wish to pass; e.g.
myfunc({stringVar1, "literalString", stringVar2, stringVarN, intVarToConvertToString});
however when I try to pass in a numeric type like int as a concatenated string, it isn't being converted into a string representation of its value correctly, and the � character is printed in its place. I have also tried to perform an explicit string cast on the non-string types being concatenated but to no avail.
I know that if I got all of the arguments to my function separately I can then just pass them directly to $display which does correctly convert the number types to their string representation to display them. Does anyone know how I would do this in System Verilog?

If you want to convert an integer's value into a string representation, or more specifically, a "string" of ASCII digits, you need to use a formatting function, like $sformatf("%d",intVarToConvertToString) to convert a value to a decimal representation, or you can combine the concatenation and formatting into a single expression.
myfunc($sformat("%s%s%s%d",{stringVar1, "literalString"}, stringVar2, stringVarN, intVarToConvertToString);

The concat operator {} converts its contents in a stream of bits.
There are no variable arguments in verilog/system verilog functions.
There is no way to wrap variable args in a $display.
So your best bet is using dynamic or associative arrays of strings or queues.
The following is an example of a possible use of an associative array:
package pkg;
function void multstr(string args[int]);
for(int i = 0; i < args.num; i++) begin
$display("arg%0d: %s", i, args[i]);
end
endfunction
endpackage
module testme();
string strings[int];
initial begin
strings[0] = "hello ";
strings[1] = "world";
pkg::multstr(strings);
end
endmodule

Create a function with a dynamic array port like this:
module tb ();
// function arg is a dynamic array of strings
function void printStrings(string mystrings[]);
foreach(mystrings[i])
$display("",mystrings[i]);
endfunction
// dynamic array of string
string names [];
initial
begin
names = new[2];
names = '{"bob","joe"};
printStrings(names);
$display("-----");
// make the d-array 1 bigger
names = new[names.size() + 1](names);
names = '{"bob","joe","bill"};
printStrings(names);
end
endmodule
Which produces
bob
joe
-----
bob
joe
bill
The same thing could be done using a queue as a function port rather than a d-array.

Related

Ada - How do I split a string in two parts?

If I create a subprogram of type function that for instance orders you to type a string of a particular length and you type Overflow, it's supposed to type the last half of the string, so in this case it would be flow. But on the other end if I type an odd number of characters like Stack it's supposed to type the last half of the string + the middle letter, so in this case it would be "ack".
Let me make it clearer (text in bold is user input):
Type a string that's not longer than 7 characters: Candy
The other half of the string is: ndy
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
function Split_String (S : in String) return String is
begin
Mid := 1 + (S'Length / 2);
return S(Mid .. S'Last);
end Split_String;
S : String(1 .. 7);
I : Integer;
begin
Put("Type a string that's no longer than 7 characters: ");
Get_Line(S, I);
Put(Split_String(S));
end Split;
Let me tell you how I've been thinking. So I do a Get_Line to see how many characters the string contains. I then put I in my subprogram to determine if its evenly dividable by two or not. If it's dividable by two, the rest should be 0, thus it'll mean that typing out the other half of the string + THE MIDDLE CHARACTER is not needed. If in all the other cases, it's not dividable by two I have to type out the other half of the string + the middle character. But now I stumbled upon a big problem in my main program. I don't know how type out the other half of a string. If a string contains 4 words I can just type out Put(S(3 .. 4); but the thing is that I don't know a general formula for this. Help is appreciated! :) Have a good day!
You need a more general approach to your problem. Also, try to understand how Get_Line works for you.
For example, if you declare an input string with a large size such as
Input : String (1..1024);
You will have a string large enough to work with any likely input values.
Next, you need a variable to indicate how many characters were actually read by Get_Line.
Length : Natural;
The data returned by Get_Line will then be in the slice of the input string designated as
Input (1 .. Length);
Pass that slice to your function to return the second half of the string.
function last_half(S : string) return string;
last_half(Input(1..Length));
Now all you need is to calculate the last half of the string passed to the function last_half. The function will output a slice of the string passed to it. To find the first index of the last half of the input string you must perform the calculation
mid : Positive := 1 + (S'length / 2);
Then simply return the string S(mid .. S'Last).
It appears that the goal of this exercise is to learn how to use array slices. Concentrate on how slices work for you in the problem and the solution will be very simple.
One possible solution is
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
Input : String (1 .. 1_024);
Length : Natural;
function last_half (S : in String) return String is
Mid : Positive := 1 + (S'Length / 2);
begin
return S (Mid .. S'Last);
end last_half;
begin
Put ("Enter a string: ");
Get_Line (Input, Length);
Put_Line (Input (1 .. Length) & " : " & last_half (Input (1 .. Length)));
end Main;
Study how the solution uses array slices on the return value of Get_Line and on the parameter for the function last_half and on its return statement. It is also important to remember that the type String is defined as an unbounded array of character. This means that every slice of a string is also a string.
type String is array ( Positive range <> ) of Character;
Aside from being an untidy mess, your latest code edit (as of 20:11 GMT on 15 Nov 2021) doesn’t even compile. Please don’t show us code like this! (unless, of course, that’s the problem).
I’d like to strongly suggest this alternate way of inputting strings:
declare
S : constant String := Get_Line;
begin
-- do things with S, which is exactly as long as
-- the input you typed: no undefined characters at
-- the end to confuse the result, no need to worry
-- about overrunning an input buffer
end;
With this change, and obvious syntactic changes, your current code will do what you want.

Reading a comma-separated string (not text file) in Matlab

I want to read a string in Matlab (not an external text file) which has numerical values separated by commas, such as
a = {'1,2,3'}
and I'd like to store it in a vector as numbers. Is there any function which does that? I only find processes and functions used to do that with text files.
I think you're looking for sscanf
A = sscanf(str,formatSpec) reads data from str, converts it according
to the format specified by formatSpec, and returns the results in an
array. str is either a character array or a string scalar.
You can try the str2num function:
vec = str2num('1,2,3')
If you have to use the cell a, per your example, it would be: vec=str2num(a{1})
There are some security warnings in the documentation to consider so be cognizant of how your code is being employed.
Another, more flexible, option is textscan. It can handle strings as well as file handles.
Here's an example:
cellResult = textscan('1,2,3', '%f','delimiter',',');
vec = cellResult{1};
I will use the eval function to "evaluate" the vector. If that is the structure, I will also use the cell2mat to get the '1,2,3' text (this can be approached by other methods too.
% Generate the variable "a" that contains the "vector"
a = {'1,2,3'};
% Generate the vector using the eval function
myVector = eval(['[' cell2mat(a) ']']);
Let me know if this solution works for you

Properly write into string in Matlab (efficient and preserving escape characters)

I have an abstract class Writer which allows clients to write into something. Could be the screen, could be a file. Now, I try to create a derived class to write into a string.
I have two problems with the denoted line in method write(...):
It's probably very inefficient. Is there something like a string buffer in Matlab?
It writes escape sequences like \n plain into the string, instead of taking their actual meaning.
How can I get the denoted line properly?
Code:
classdef StringTextWriter < Writer
properties
str;
end
methods
function this = StringTextWriter()
% Init the write-target which is a string in our case.
% (Other Writer classes would maybe open a file.)
this.str = '';
end
function write(this, val)
% Write to writer target.
% (Other Writer classes would maybe use fprinf here for file write.)
% ?????????????????????????????
this.str = [this.str val]; % How to do this properly?
% ?????????????????????????????
end
end
end
To answer your questions point by point:
The closest notion to a string buffer would be a string cell. Instead of:
str = '';
str = [strbuf, 'abc\n'];
str = [strbuf, 'def\n'];
str = [strbuf, 'ghi\n'];
%// and so on...
one may use
strbuf = {};
strbuf{end+1} = 'abc\n';
strbuf{end+1} = 'def\n';
strbuf{end+1} = 'ghi\n';
%// and so on...
str = sprintf([strbuf{:}]); %// careful about percent signs and single quotes in string
the drawback being that you have to reconstruct the string every time you ask for it. This can be alleviated by setting a modified flag every time you add strings to the end of strbuf, resetting it every time you concatenate the strings, and memoizing the result of concatenation in the last line (rebuild if modified, or last result if not).
Further improvement can be achieved by choosing a better strategy for growing the strbuf cell array; probably this would be effective if you have a lot of write method calls.
The escape sequences are really linked to the <?>printf family and not to the string literals, so MATLAB in general doesn't care about them, but sprintf in particular might.

Ada string comparison

I am new to Ada and currently trying to write a simple program involving an if-else if statement. The code is as follows:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Year_Codes is
Year : String(1..9) := " ";
CharsRead : Natural;
function YearCode(Name : in String) return Integer is
begin
if(Name = "freshman")then
return 1;
elsif(Name = "sophomore")then
return 2;
elsif(Name = "junior")then
return 3;
elsif(Name = "senior")then
return 4;
else
return 0;
end if;
end YearCode;
begin
Put("Enter your academic year: "); -- Prompt for input
Get_Line(Year, CharsRead); -- Input
Put( YearCode(Year) ); -- Convert and output
New_Line;
end Year_Codes;
I am getting 0 for every answer. Any input on what I am doing wrong?
The "=" operation on strings compares the entire strings. If the user's input is "freshman", the value of Name will be "freshman ", not "freshman". Read the documentation for the Get_Line procedure.
You should probably pass YearCode a slice of the Year string, not the entire string; CharsRead tells you what that slice should be.
Specifically, the call should be:
Put( YearCode(Year(Year'First..CharsRead)) );
Here's a case-insensitive version using attributes:
function YearCode(Name : in String) return Integer is
Type Class is (Freshman, Sophmore, Junior, Senior);
begin
Return 1 + Class'Pos(Class'Value(Name));
exception
When CONSTRAINT_ERROR => Return 0;
end YearCode;
With that extra character in your buffer, it looks to me like you are thinking of strings in C terms. You need to stop that. Of everything in the language, string handling is the most different between Ada and C.
While C strings are null terminated, Ada strings are not. Instead, an Ada string is assumed to be the size of the string array object. Its a simple difference, but it has enormous consequences in how you handle strings.
I go into this a bit in my answer to How to I build a string from other strings in Ada? The basic gist is that in Ada you always try to build perfectly-sized string objects on the fly.
Sadly, Text_IO input is one place that has traditionally made that really hard, due to its string buffer-based input. In that case, you are forced to use an overly large string object as a buffer, and use the returned value as the end of the defined area of the buffer, as Keith showed.
However, if you have a new version of the compiler, you can use the function version of Get_Line to fix that. Simply change your middle two lines to:
Put( YearCode(Get_Line) );

Understanding the string represented data type in Matlab

I have a String like '12,23,43,erogol,bla,3.4' and I want to parse it and see which type of values are in this string. For example if I give that string to function I expect to have a vector like output=["integer,integer,integer,string,string,double"] as the return of the function.
How could I do it in matlab ?
This can be done very easily using regular expressions.
input = '-12,12,0,erogol,bla,3.4,-3.4';
First replace the strings with 'string'.
Next catch the doubles
Finally catch the integers:
Example:
output = regexprep(input, '[a-zA-Z]*', 'string');
output = regexprep(output, '[-]*[0-9]*[.][0-9]*', 'double');
output = regexprep(output, '[-]*[0-9]*', 'integer');
Output now contains `integer,integer,integer,string,string,double,double'
Which you can split into a cell array using:
varTypes = regexp(output, ',', 'split');

Resources