I want to make a list of strings in a Testbench to load different files for example.
I tried:
type tastring ARRAY(iADCCount_C-1 downto 0) of string;
constant Filenames : tastring := ("file.txt",
"anotherfile.txt",
"jetanotherfile.txt");
Its not possible to have variable length strings in an array.
Also:
type tpstring is access string;
type tpastring is ARRAY(iADCCount_C-1 downto 0) of tpstring;
constant Filenames : tpastring := (new string'("file.txt"),
new string'(anotherfile.txt"),
new string'(jetanotherfile.txt"));
Does not work! You cannot make an access type constant. Do I miss something? Is there a way to make a list of Strings without padding them to the same size?
You are almost correct :)
The second code snippet must use a variable, because access types can only be used for objects of kind variable.
type line_vector is array(iADCCount_C-1 downto 0) of line;
variable Filenames : line_vector := (
new string'("file.txt"),
new string'("anotherfile.txt"),
new string'("jetanotherfile.txt")
);
Note 1: added missing " characters.
Note 2: type line is already defined in VHDL.
Note 3: type line_vector will be defined by VHDL-2017.
As an alternative, you can fill all string with character NUL. You might want to implement two functions for sizing the string to the constant's size and to trim the string (remove trailing NUL characters.
See this answer. AFAIK it is impossible to have arrays of variable-length strings.
If you implement custom trim functions as suggested in the answer, try using a fixed spacing character that cannot exist in file names(like ? for windows), as it will also ensure no problems with NUL-characters or other non-prinatbles that can cause hiccoughs with different synthesis tools.
Related
So, I'm coding in Ada for the first time and have to create this pre-populated array of strings, so I can use a random method and call a different value each time.
poolOfWords: constant array(1..50) of string := ("gum","sin","for","cry","lug","bye","fly",
"ugly", "each","from","work","talk","with","self", "pizza","thing","feign","friend",
"elbow","fault", "dirty","budget","spirit","quaint","maiden","escort","pickax",
"example","tension","quinine","kidney","replica","sleeper", "triangle","kangaroo",
"mahogany","sergeant","sequence","moustache","dangerous","scientist",
"different","quiescent", "magistrate","erroneously","loudspeaker",
"phytotoxic","matrimonial","parasympathomimetic","thigmotropism");
But when I try to compile I get this error: "unconstrained element type in array declaration".
I Googled all over internet and couldn't find a solution to that. I even tried to use unbounded_string, but didn't work as well. It works fine when I pre-populate an array of integers, floats, but when it come to strings it's not working.
Can someone help me and explain what's going on and how to solve it? I really don't want to declare the array and then populate each of the 50 indexes one by one.
Your problem stems from the fact that String in Ada is an unconstrained type. This means, roughly, that you need to specify "something" in order to have a usable type. In the case of String you need to specify the string length, since a String is just an array of Character. If you say something like
X : String;
the compiler complains since it does not know the length of X and it does not know how much memory to reserve for X. You need to say something like
X : String(1..6);
or something like
X : String := "foobar";
Note that in the second case you do not need to specify the index range since the compiler is able to deduce it from the fact that you use a 6-Character string to initialize X.
This explains why it is illegal to declare an array of just String. When you declare an array the compiler needs to know the size of every entry (all the entries must share the same size, this makes access to a random entry of the array very efficient). If you declare an array of just String, the compiler would not know how much memory to allocate to every entry since the length is unspecified.
Note that this instead would work (disclaimer: I have not an Ada compiler at hand now, so I cannot check the code)
subtype ZIP_Code is String (1..5);
type ZIP_Code_Array is array(Positive range <>) of ZIP_Code;
since now the compiler knows the size of every entry of a ZIP_Code_Array (5 Character).
In your case, however, the strings have all different sizes. I can see two possible solutions
If the maximum length is known in advance you can use the subtype approach shown above and pad the strings with spaces. It depends on your context if this is a suitable solution or not
The approach that I typically use is to create an array of Unconstrained_String that I initialize as follows
function "+"(X: String) return Unbounded_String
renames To_Unbounded_String;
poolOfWords: constant array(1..50) of Unbounded_String :=
(+"gum",
+"sin",
+"for",
-- and so on...
);
Note the renames that defines the unary + as an alias for To_Unbounded_String. This is just syntactic sugar that allows you to write +"gum" instead of To_Unbounded_String("gum"). Someone cringes at this type of syntactic sugar (and I am not so keen either), but in this case I think it is worth since it makes the code "lighter." It would be nice to have the definition of unary + near its use, just for clarity.
An alternative to the use of Unbounded_String is to use the generic package Bounded_Strings and define poolOfWords as an array of Bounded_String. A Bounded_String can hold strings with variable length, as long as the length is smaller than the bound specified when instantiating the Bounded_Strings package. In order to convert back and forth String you can use the same "rename trick."
My personal preference goes to the Unbounded_String, unless I have some special reason that forces me to use the Bounded_String.
Another option is to use Ada's standard containers. For example:
Package String_Holder is new Ada.Containers.Indefinite_Holders(
"=" => Ada.Strings.Equal_Case_Insensitive,
Element_Type => String
);
Function "+"( Right : String_Holder.Holder ) return String
renames String_Holder.Element;
Function "+"( Right : String ) return String_Holder.Holder
renames String_Holder.To_Holder;
Allows you to store in the holder varying sized values of type String, so you could forego any dependence on Ada.Strings.Unbounded_String and use something like:
poolOfWords: constant array(Positive range <>) of String_Holder.Holder :=
+"gum", +"sin", +"for", +"cry", -- ...
+"Stuff"
);
Function Get_Word(Index : Positive) return String is
(+poolOfWords(Index)) with Pre => Index in poolOfWords'Range;
Alternatively, you could use Ada.Containers.Indefinite_Vectors like so:
Package String_Vector is new Ada.Containers.Indefinite_Vectors(
"=" => Ada.Strings.Equal_Case_Insensitive,
Index_Type => Positive,
Element_Type => String
);
though there is one problem with this in Ada 2012: You can't initialize such a vector directly within the declaration, but can initialize it via function-call:
Function Populate return String_Vector.Vector is
Begin
Return Result : String_Vector.Vector do
Result.Append( "some" );
Result.Append( "data" );
Result.Append( "HERE" );
End Return;
End Populate;
Being able to say X : String_Vectors.Vector := ("this", "that", "the other") is in Ada 2020 .
I know that with tuples sizes of arrays can be defined. Not applicable to float32array which is a class itself though.
Can that somehow be done with float32arrays as well?
I tried const foo: FloatArray32[4] but that casts the type directly to the number.
I also tried to check if types might be compatible:
let foo: [number, number, number, number];
foo = new Float32Array([1, 2, 3, 4]);
But they are not.
Changing all the types in my code to '[number, number, number, number];' (in my case I need a 4 float array for a point coordinate) is a possibility, although I would need to make changes in quite a lot of places in the code.
However, I was wondering if there might be a 'childtype' extending Float32Array type, where the number of the elements of the array can be fixed in the type.
Javascript typed arrays, are in fact, fixed length - see the docs for your example. The constructors in particular:
new Float32Array(); // new in ES2017
new Float32Array(length);
new Float32Array(typedArray);
new Float32Array(object);
new Float32Array(buffer [, byteOffset [, length]]);
all have the length deducible on creation (that new first one creates an empty array with 0 elements. I guess it simplified some edge cases).
I'm not sure how you are determining the type, but as soon as you get an item from your array it will be converted to a number, the only number type available in JS - so looking at your log is misleading here. Take a look at the following static property:
Float32Array.prototype.byteLength
Returns the length (in bytes) of the Float32Array. Fixed at construction time and thus read only.
This is the only thing that counts. If you still don't believe the docs, try logging a cell after you overflow it (easier with int8 - put 200 or something). This is relevant to your example - nothing is being converted to a number. The array object is a view in fixed length numbers - again, run your test with an Int8Array and try to assign 200 to the cell, and read the cell.
This is a view into raw data. If you extract it and make mathematical operations, you are now in JS realm and working with Numbers - but once you assign stuff back, you better make sure the data fits. You cannot get JS/TS to show you something like float32 in your console, but each cell of the array itself does have an exact byte length.
unfortunately, making the length a part of the type is non-trivial within the type system as far as I can tell since the length is a property determined in construction (even if static and read only) and not a part of the type. If you do want something like this a thin wrapper could do the trick:
class vec4 extends Float32Array {
constructor(initial_values? : [number, number, number, number]) {
initial_values? super(initial_values) : super(4);
}
}
would do the trick. If you are willing to give up square brackets you can add index out-of-bound checking in the different methods (you can set in a fixed width array any cell, but it will do nothing, and retrieving it will yield undefined if out of bounds, which may be error prone):
get(index : number) {
if(index > 4 || index < 0) ...
return this.private_data[index];
}
set(index : number, value : number) {
if(index > 4 || index < 0) ...
this.private_data[index] = value;
}
Of course, without LSP in JS/TS the array and your class are still interchangeable, so enforcement is really only done on construction, and only if you do not try to break your own code (let foo : vec4; foo = new Float32Array([1, 2]); etc...).
In the code I inherited, a buffer is passed to a procedure using its start address and length as parameters. This procedure code uses inline assembly language to process the buffer contents.
In a new procedure that uses the same parameters, I want to refer to the buffer as an array but I want to use the same parameters and their types that the existing procedure uses. This is so I don't have to make intrusive modifications to the original code except to use the same calling signature, which is like this:
procedure Push_Buffer(
Source_Address : Address;
Count : Natural);
In this case, the buffer is just an array of machine words. I want to refer to it as an array of machine words, and already have types (Word and Buffer_Type) that are used elsewhere without a problem. (The objects of unconstrained type Buffer_Type have their constraints defined where they are used.)
I would like to refer to the buffer that's being passed by address as an array within my procedure. How would I do this?
Like this (which works with -gnat83, but might not work with a real Ada83 compiler; I don’t have one to check with):
with Text_IO; use Text_IO;
with System;
procedure Push is
type Integers is array (Positive range <>) of Integer;
procedure Push_Buffer (Source_Address : System.Address;
Count : Natural) is
Source : Integers (1 .. Count);
for Source use at Source_Address;
begin
for J in Source'Range loop
Put_Line (Integer'Image (J) & " => " & Integer'Image (Source (J)));
end loop;
end Push_Buffer;
begin
declare
Data : Integers (1 .. 3) := (4, 5, 6);
begin
Push_Buffer (Data'Address, Data'Length);
end;
end Push;
As a side note, probably not relevant to your situation: if there was any question of default initialization of the object whose address you’ve specified (for example, if it’s a structure containing access variables, which are default-initialized to null) you would need to suppress the initialization by writing the declaration as
Source : Integers (1 .. Count);
pragma Import (Ada, Source);
for Source use at Source_Address;
(or something compiler-dependent like that; GNAT says warning: (Ada 83) pragma "Import" is non-standard). See the GNAT Reference Manual 8.15, Address Clauses, about half-way down.
I would use an unconstrained array as the parameter, rather than a System.Address. This ensures that the compiler does not pass the bound information (aka "fat pointers" in gcc and gnat), and should be compatible with a pragma import.
type Unconstrained_Integer_Array is array (Positive) of Integer;
procedure Push_Buffer (Buffer : Unconstrained_Integer_Array;
Length : Natural)
is
begin
for A in 1 .. Length loop
...
end loop;
end Push_Buffer;
We use similar tricks when interfacing with C in the GtkAda bindings
I have an assignment to make a program in C that displays a number (n < 50) of valid, context-free grammar strings using the following context-free grammar:
S -> AA|0
A -> SS|1
I had few concepts of how to do it, but after analyzing them more and more, none of them were right.
For now, I'm planning to make an array and randomly change [..., A, ...] for [..., S, S, ...] or [..., 1, ...] until there are only 0s and 1s and then check whether the same thing was already randomly generated.
I'm still not convinced if that is the right approach, and I still don't know exactly how to do that or where to keep the final words because the basic form will be an array of chars of different length. Also, in C, is a two dimensional array of chars equal to an array of strings?
Does this make any sense, and is it a proper way to do it? Or am I missing something?
You can simply make a random decision every time you need to decide on something. For example:
function A():
if (50% random chance)
return "1"
else
return concat(S(), S())
function S():
if (50% random chance)
return "0"
else
return concat(A(), A())
Calling S() multiple times give me these outputs:
"0"
"00110110100100101111010111111111001111101011100100011000000110101110000110101110
10001000110001111100011000101011000001101111000110110011101010111111111011010011
10000000101111100100011011010000000101000111110010001000101001100110100111111111
1001010011"
"11"
"10010010101111010111101"
All valid strings for your grammar. Note that you may need to tweak a little the random chances. This sample has a high probability to generate very small strings like "11".
Try to think of the context-free grammar as a set of rules that allow you to generate new strings in a language. For example, the first rule:
S -> AA | 0
How could you generate a word S in this language? One way is with a function that generates, at random, either the string "0" or two A words, concatenated.
Similarly, to implement the second rule:
A -> SS | 1
write a function that generates, at random, either "1" or two S words concatenated.
You asked several questions...
Regarding The question: BTW in C, is two dimensional array of chars equal to array of strings?
Yes.
Here are ways to declare arrays of strings, each example shows varying flexibility in terms of usage:
char **ArrayOfStrings; //most flexible declaration -
//pointer to pointer, can use `calloc()` or `malloc()` to create memory for
//any number of strings of any length (all strings will have same length)
or
char *ArrayOfStrings[10]; //somewhat flexible -
//pointer to array of 10 strings, again can use `c(m)alloc()` to allocate memory for
//each string to have any lenth (all strings will have same length)
or
ArrayOfStrings[5][10]; //Not flexible - (but still very useful)
//2 dimensional array of 5 strings, each with space for up to 9 chars + '\0'
//Note: In C, by definition, strings must always be NULL terminated.
Note: Although each of these forms are valid, and very useful when used correctly, It is good to be aware there are differences in the way each will behave in practice. (read the link for a good discussion on that)
Say I have the variable:
Var question : array[1..50] of char;
When I do:
question := 't'; //What is the correct way to change the value?
It returns an error:
Incompatible types: 'array[1..50] of Char' and 'Char'
Note: I want to have a max string size of 50 chars, not 50 different chars.
The reason for this question is that I have a record in another unit(This is just a basic example, not what I actually have written above) In that unit I have a Record, which I can't use the string data type in(Or is there a way? please explain if there is). I just need to know how to give an array of chars a value.
While Delphi strings and arrays of char are related, they are not the same.
Delphi overloads assignment of strings and literals (char and string) to array of chars, but only when the lower array bound is zero.
The following code works for me in D2007 and Delphi XE:
var x : array[0..49] of char;
begin
x:='b'; // char literal
x:='bb'; // string literal
end.
If I change the [0 to [1 it fails. This limitation probably simplifies the language helper that takes care of this, and probably the feature is only meant for dealing with converted C structs where arrays always have lower bound 0.
Are you sure that you can't use string data type in a record?
Anyways...
type
TCharArray = array[Char] of Char;
function StringToArray(Str: string): TCharArray;
begin
FillChar(Result, High(Byte), #0);
Move(Str[1], Result, length(Str));
end;
procedure TestCharArray;
var
question: TCharArray;
begin
question := StringToArray('123');
ShowMessage(PChar(#question));
end;
Also take a look at StrPCopy function.
If you don't need unicode characters, you should just define your string like string[50].
After that you don't need any functions or conversions to work with that string, and it'll be just as easy to read and write it to a file.
Hscores = record
var
_topscore : integer;
_topname : string[50];
end;
I'm pretty sure you can use strings in record types.
This blog entry shows an example: http://delphi.about.com/od/beginners/a/record_type.htm
In order to assign a value to the Char array, you have to index it, like any other array:
question[1] := 't';