these last weeks I have been trying to learn the ADA language, to do it I made an exercise to reverse a string using recursion, however when I compile it with GNATProve it gives me several errors which I have not been able to solve, it would be of great help if you could guide me on how to solve them using Preconditions and Postconditions.
My code:
function String_Reverse(Str:String) return String with
Pre => Str'Length > 0 ,
Post => String_Reverse'Result'Length <= Str'Length;
function String_Reverse (Str : String) return String is
Result : String (Str'Range);
begin
if Str'Length = 1 then
Result := Str;
else
Result :=
String_Reverse (Str (Str'First + 1 .. Str'Last)) &
Str (Str'First);
end if;
return Result;
end String_Reverse;
Errors:
dth113.adb:18:69: low: range check might fail
18>| String_Reverse (Str (Str'First + 1 .. Str'Last)) &
19 | Str (Str'First);
reason for check: result of concatenation must fit in the target type of the assignment
possible fix: precondition of subprogram at line 8 should mention Str
8 | function String_Reverse(Str:String) return String with
| ^ here
dth113.adb:18:69: medium: length check might fail
18>| String_Reverse (Str (Str'First + 1 .. Str'Last)) &
19 | Str (Str'First);
reason for check: array must be of the appropriate length
possible fix: precondition of subprogram at line 8 should mention Str
8 | function String_Reverse(Str:String) return String with
| ^ here
I'm tried using Preconditons and Postconditions about the input Str length
Gnatprove appears to have some difficulty with concatenating arrays.
This below proves, using subtypes rather than pre- and post-conditions. Proving that the result is actually the reverse of the input string might be trickier!
Spec:
pragma SPARK_Mode;
function String_Reverse (Str : String) return String with
Pre => Str'Length > 0,
Post => String_Reverse'Result'Length = Str'Length;
Body:
pragma SPARK_Mode;
function String_Reverse (Str : String) return String is
subtype Result_String is String (Str'Range);
Result : Result_String;
begin
if Str'Length = 1 then
Result := Str;
else
declare
subtype Part_String is String (1 .. Str'Length - 1);
Reversed_Part : constant Part_String
:= String_Reverse (Str (Str'First + 1 .. Str'Last));
begin
Result := Reversed_Part & Str (Str'First);
end;
end if;
return Result;
end String_Reverse;
With a minor change you could handle zero-length strings as well.
Your program keeps appending the bulk of the string to your result. This makes a string much larger than the initial string parameter. You cannot fix this with improved preconditions or post conditions.
See the difference between your solution and the Reverse_String function shown below. In the solution below the size of the returned string cannot be the size of the function string in parameter because it is building the reversed string with each recursion and the size of the string cannot be determined until all recursions complete.
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
function Reverse_String(S : in String; Idx : Positive) return String is
begin
if Idx < S'Last then
return Reverse_String(S, Idx + 1) & S(Idx);
else
return S(Idx) & "";
end if;
end Reverse_String;
S1 : String := "Hello World";
s2 : String := "1234567890";
N1 : Integer := 12345;
N3 : Integer;
begin
Put_Line(S1 & " : " & Reverse_String(S1, 1));
Put_Line(S2 & " : " & Reverse_String(S2, 1));
N3 := Integer'Value(Reverse_String(N1'Image, 1));
Put_Line(N1'Image & " : " & N3'Image);
end Main;
This version of Reverse_String keeps incrementing the index of the input string and concatenating that character at the end of all the characters yet to reverse.
The Reverse_String's else clause appends an empty string to the last character so that it is viewed by the compiler as a string and not a character because S(Idx) is a single character and is not a string, but concatenating S(Idx) with an empty string results in a string.
Here is another implementation
function String_Reverse (Str : String) return String is
Result : String (Str'Range) := Str;
begin
for I in reverse Str'Range loop
Result(Str'Last - I + Result'First) := Str(I);
end loop;
return Result;
end String_Reverse;
SPARK seems to be happier with expression functions than with regular functions in many cases. I don't know if it will make a difference, but you could try rewriting the body of your function as
function String_Reverse (Str : String) return String is
(if Str'Length = 1 then
Str
else
String_Reverse (Str (Str'First + 1 .. Str'Last) ) & Str (Str'First) );
(I hope I've got the parentheses balanced.)
Typically one allows null strings, and the function becomes something like
function Reversed (S : in String) return String with
Post => Reversed'Result'Length = S'Length;
function Reversed (S : in String) return String is
(if S'Length = 0 then ""
else Reversed (S (S'first + 1 .. S'Last) & S (S'First) );
(Hint: "Ada" is a woman's name, not an acronym. GNATProve is a static-analysis tool, not a compiler.)
Related
I would like to convert a float value to a String and created the following short example:
with Ada.Text_IO;
procedure Example is
A : constant Float := -1.234;
B : constant Float := 123_456.789;
C : constant Float := 987.654_321;
package Float_IO is new Ada.Text_IO.Float_IO (Num => Float);
String_Float_A : String := " ";
String_Float_B : String := " ";
String_Float_C : String := " ";
begin
Ada.Text_IO.Put_Line (Float'Image (A));
Ada.Text_IO.Put_Line (Float'Image (B));
Ada.Text_IO.Put_Line (Float'Image (C));
Float_IO.Put
(To => String_Float_A,
Item => A,
Aft => 2,
Exp => 0);
Float_IO.Put
(To => String_Float_B,
Item => B,
Aft => 2,
Exp => 0);
Float_IO.Put
(To => String_Float_C,
Item => C,
Aft => 2,
Exp => 0);
Ada.Text_IO.Put_Line (String_Float_A);
Ada.Text_IO.Put_Line (String_Float_B);
Ada.Text_IO.Put_Line (String_Float_C);
end Example;
My problem: I need to create the string variables before the call of the procedure Put with a sufficient length. How can this be done dynamically at runtime? Basically I need to figure out the number of digits before the dot. Then a sufficient string length would be: 1 (sign) + Number_Of_Dots + 1 (decimal separator) + Aft.
The number of digits before the dot of a decimal number can be computed calculating 1 plus the integer part of the common logarithm (base 10) of
the integer part of the number.
In Ada:
N := Integer (Float'Floor (Log (Float'Floor (abs X), 10.0))) + 1;
Your program must be with'ed with Ada.Numerics.Elementary_Functions.
You must add a space for the minus sign if the number is negative.
This formula does not work if the integer part is 0, but then N is obviously 1.
Your example uses Float, perhaps as a proxy for some more specific real type. If your actual data is better modeled as a decimal fixed point type, discussed here, don't overlook the convenience of Edited Output for Decimal Types, discussed here. The example below uses the string "+Z_ZZZ_ZZ9.99" to construct a picture of the desired output Image.
Console:
- 1.23
+ 123,456.79
+ 987.65
+1,000,000.00
Code:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Text_IO.Editing; use Ada.Text_IO.Editing;
procedure Editing is
type Number is delta 0.000_001 digits 12;
type Numbers is array (Positive range <>) of Number;
package Number_Output is new Decimal_Output (Number);
Format_String : constant String := "+Z_ZZZ_ZZ9.99";
Format : constant Picture := To_Picture (Format_String);
Values : constant Numbers :=
(-1.234, 123_456.789, 987.654_321, Number'Last);
begin
for Value of Values loop
Put_Line (Number_Output.Image (Value, Format));
end loop;
end Editing;
You could make a function to do the job, something like this:
with Ada.Text_IO;
with Ada.Strings.Fixed;
procedure Marcello_Float is
function Image (Item : Float;
Aft : Ada.Text_IO.Field := Float'Digits - 1;
Exp : Ada.Text_IO.Field := 3) return String
is
package Float_IO is new Ada.Text_IO.Float_IO (Float);
Result : String (1 .. 128);
begin
Float_IO.Put (To => Result,
Item => Item,
Aft => Aft,
Exp => Exp);
return Ada.Strings.Fixed.Trim (Result,
Side => Ada.Strings.Both);
end Image;
A : constant Float := -1.234;
B : constant Float := 123_456.789;
C : constant Float := 987.654_321;
A_Image : constant String := Image (A, Aft => 2, Exp => 0);
B_Image : constant String := Image (B, Aft => 2, Exp => 0);
C_Image : constant String := Image (C, Aft => 2, Exp => 0);
use Ada.Text_IO;
begin
Put_Line (A'Image & " => " & A_Image);
Put_Line (B'Image & " => " & B_Image);
Put_Line (C'Image & " => " & C_Image);
end Marcello_Float;
I made Result ridiculously long. I recognise that to calculate an exact size would in fact answer your original question; just being lazy.
I'm working to implement a prime decomposition function in Ada. I need to return a Vector from calc_prime_numbers. I'm trying to store that vector in Y. However, whenever I compile, the compiler is saying prime.adb:40:07: subtype mark required in this context. I'm not sure what that means. What does subtype required mean? How do I fix it?
with Ada.Text_IO, Ada.Integer_Text_IO, Ada.Containers.Vectors;
use Ada.Text_IO, Ada.Integer_Text_IO, Ada.Containers;
procedure Prime is
package Integer_Vectors is new Vectors(Natural, Integer);
function Is_Prime(I : Integer) return Boolean is
J : Integer := 2;
begin
for J in 2 .. I-1 loop
if I mod J = 0 then
return False;
end if;
end loop;
return True;
end Is_Prime;
function calc_prime_numbers(n : Integer) return Integer_Vectors.Vector is
i : Integer := 0;
m : Integer;
Numbers : Integer_Vectors.Vector;
begin
m := n + 1;
while (true) loop
i:=i + 1;
if Is_Prime(i) then
Integer_Vectors.Append(Numbers, i);
Put(Integer'Image(i) & " + ");
end if;
if i = m then
exit;
end if;
end loop;
New_Line;
return Numbers;
end calc_prime_numbers;
X : Integer;
Y : Integer_Vectors; — line 40
begin
while (true) loop
Get(X);
if Is_Prime(X) then
Put(Integer'Image(X) & " is prime.");
else
Put(Integer'Image(X) & " is not prime.");
end if;
New_Line;
Y := calc_prime_numbers(X); — line 40
end loop;
end Prime;
Your line number in the error message don't match the code you pasted, and you don't indicate where line 40 is, so I'll have to guess:
you instantiate a package called Integer_Vectors. Later you declare a variable Y : Integer_Vectors;. So the compiler complains because it expects a type for the variable whereas you provided the name of a package.
Case #1:
module try;
string inp = "my_var";
initial begin
$display("Here we go!");
case (inp)
"my_var" : $display("my_var");
default : $display("default");
endcase
end
endmodule
Output is my_var
Case #2
module try;
string inp = "my_var";
initial begin
$display("Here we go!");
case (inp)
"*var*" : $display("*var*");
default : $display("default");
endcase
end
endmodule
Output is default.
Is it possible to get a hit with wildcard search in a case statement?
SystemVerilog does not have any string regular expression matching methods built into the standard. The UVM has a package that has a uvm_re_match() function. You can import the UVM package to get access to this function even if you do not use any other UVM testbench features. Some simulators, such as ModelSim/Questa have these routines built in as an extension to SystemVerilog so that you can do
module try;
string inp = "my_var";
initial begin
$display("Here we go!");
case (1)
inp.match("*var*") : $display("*var*");
default : $display("default");
endcase
end
endmodule
I found a work-around :
function string match(string s1,s2);
int l1,l2;
l1 = s1.len();
l2 = s2.len();
match = 0 ;
if( l2 > l1 )
return 0;
for(int i = 0;i < l1 - l2 + 1; i ++)
if( s1.substr(i,i+l2 -1) == s2)
return s2;
endfunction
module try;
string target_id = "abc.def.ddr4_0";
string inp = "ddr4_0";
string processed_inp;
initial begin
$display("Here we go!");
for(int i=0;i<2;i++) begin
if (i == 1)begin
inp = "ddr4_1";
target_id = "abc.def.ddr4_1";
end
processed_inp = match(target_id, inp);
$display("input to case = %0s", processed_inp);
case (processed_inp)
"ddr4_0" : $display("ddr4_0 captured!");
"ddr4_1" : $display("ddr4_1 captured!");
default : $display("default");
endcase
end
end
endmodule
Output:
Here we go!
input to case = ddr4_0
ddr4_0 captured!
input to case = ddr4_1
ddr4_1 captured!
PS : Found this solution on the www.
Cannot find the link right now. Will post the reference soon.
This store procedure is returning this error however i cant see find the problem:
Error(20,1): PLS-00103: Encountered the symbol "END" when expecting
one of the following: . ( * # % & = - + ; < / > at in is mod
remainder not rem <> or != or ~= >= <= <> and or
like like2 like4 likec between || multiset member submultiset
create or replace procedure SP_CurrancyOfProject(V_AssyId number) as
temp number := 0;
begin
Select Scope_ID
into Temp
from tbl_Revisions
where Assy_U_ID = V_AssyId;
Select Project_ID
into temp
from tbl_Scope
Where Scope_U_ID = temp;
Select Currancy_Multipier
into temp
from tbl_Currancy
where Project_ID = temp;
return temp;
end;
You Cannot return value from a procedure.
you should use FUNCTION to return the value.
create or replace FUNCTION FN_CurrancyOfProject(V_AssyId number) RETURN NUMBER
as
temp NUMBER := 0;
BEGIN
-- YOUR CODE LOGIC for substituting temp variable.
return temp;
END;
This code basically takes a mathematical expression and evaluates it.
The following code i have written in VB.net shamelessly taken from here : Expression Evaluation
which has been written in Java.
Public Function evaluate(expression As [String]) As Integer
Dim tokens As Char() = expression.ToCharArray()
' Stack for numbers: 'values'
Dim values As New Stack(Of UInteger)()
' Stack for Operators: 'ops'
Dim ops As New Stack(Of Char)()
For i As Integer = 0 To tokens.Length - 1
' Current token is a whitespace, skip it
If tokens(i) = " "c Then
Continue For
End If
' Current token is a number, push it to stack for numbers
If tokens(i) >= "0"c AndAlso tokens(i) <= "9"c Then
Dim sbuf As New StringBuilder(100)
'Dim sbuf As New String("", 128)
' There may be more than one digits in number
If i < tokens.Length AndAlso tokens(i) >= "0"c AndAlso tokens(i) <= "9"c Then
sbuf.Append(tokens(System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)))
End If
If sbuf Is Nothing AndAlso sbuf.ToString().Equals("") Then
Else
Dim intgr As Integer
Dim accpt As Boolean = Integer.TryParse(sbuf.ToString(), intgr)
If accpt = True Then
values.Push([Integer].Parse(sbuf.ToString()))
Else
Dim space As String = " "
values.Push(space)
End If
End If
' Current token is an opening brace, push it to 'ops'
ElseIf tokens(i) = "("c Then
ops.Push(tokens(i))
' Closing brace encountered, solve entire brace
ElseIf tokens(i) = ")"c Then
While ops.Peek() <> "("c
values.Push(applyOp(ops.Pop(), values.Pop(), values.Pop()))
End While
ops.Pop()
' Current token is an operator.
ElseIf tokens(i) = "+"c OrElse tokens(i) = "-"c OrElse tokens(i) = "*"c OrElse tokens(i) = "/"c Then
' While top of 'ops' has same or greater precedence to current
' token, which is an operator. Apply operator on top of 'ops'
' to top two elements in values stack
While Not ops.Count = 0 AndAlso hasPrecedence(tokens(i), ops.Peek())
values.Push(applyOp(ops.Pop(), values.Pop(), values.Pop()))
End While
' Push current token to 'ops'.
ops.Push(tokens(i))
End If
Next
' Entire expression has been parsed at this point, apply remaining
' ops to remaining values
While Not ops.Count = 0
values.Push(applyOp(ops.Pop(), values.Pop(), values.Pop()))
End While
' Top of 'values' contains result, return it
Return values.Pop()
End Function
Public Function hasPrecedence(op1 As Char, op2 As Char) As [Boolean]
If op2 = "("c OrElse op2 = ")"c Then
Return False
End If
If (op1 = "*"c OrElse op1 = "/"c) AndAlso (op2 = "+"c OrElse op2 = "-"c) Then
Return False
Else
Return True
End If
End Function
' A utility method to apply an operator 'op' on operands 'a'
' and 'b'. Return the result.
Public Function applyOp(op As Char, b As Integer, a As Integer) As Integer
Select Case op
Case "+"c
Return a + b
Case "-"c
Return a - b
Case "*"c
Return a * b
Case "/"c
If b = 0 Then
'Throw New UnsupportedOperationException("Cannot divide by zero")
End If
Return a \ b
End Select
Return 0
End Function
this is how im using the code :
formula = "10 + 2 * 6"
Dim result As Double = evaluate(formula)
and i keep getting this following error:
Unhandled exception at line 885, column 13 in http:**** DEDOM5KzzVKtsL1tWZwgsquruscgqkpS5bZnMu2kotJDD8R38OukKT4TyG0z97U1A8ZC8o0wLOdVNYqHqQLlZ9egcY6AKpKRjQWMa4aBQG1Hz8t_HRmdQ39BUIKoCWPik5bv4Ej6LauiiQptjuzBMLowwYrLGpq6dAhVvZcB-4b-mV24vCqXJ3jbeKi0&t=6119e399
0x800a139e - Microsoft JScript runtime error: Sys.WebForms.PageRequestManagerServerErrorException: Conversion from string " " to type 'UInteger' is not valid.
Im a beginner but i think that the error is occurring because its not able to covert space into integer.How to deal with the spaces??
Any help is much appreciated:).
VB.NET is strongly-typed, so you simply cannot push anything other than integers onto a Stack(Of Integer). Therefore this code:
Dim space As String = " "
values.Push(space)
will always fail at runtime. (By the way, you want to set Option Explicit On and Option Strict On at the top of every module. If you do that, the line above will already be marked as an error at build time).
I haven't tried executing your code, but why would you need to save the spaces if what you're building is an expression evaluator? It doesn't seem to add anything to the evaluation. Perhaps if you simply don't add the spaces to the stack it will work anyway.