Recursion towers of Hanoi program in ADA.
So far I think I have most of it down, my problem is being in my solve function.
I think I have the algorithm fine, but I am not sure how to implement it into the function, all examples I see of using this are using the function inside itself such as:
Example
My errors are:
hanoi.adb:23:09: cannot use function "solve" in a procedure call
hanoi.adb:27:09: cannot use function "solve" in a procedure call
hanoi.adb:59:15: missing ")"
Here is my code so far.
with ada.text_io, ada.command_line;
use ada.text_io, ada.command_line;
procedure hanoi is
Argument_Error : EXCEPTION;
max_disks, min_disks : integer := 3;
moves : integer := 0;
verbose_bool : boolean;
function solve (N: in integer; from, to, using: in character) return integer is
begin
if N = 1 then
if verbose_bool = true then
put("Move disk " & integer'image(N) & " from " & character'image(from) & " to " & character'image(to));
end if;
else
solve(N - 1, 'A', 'B', 'C');
if verbose_bool = true then
put("Move disk " & integer'image(N) & " from " & character'image(from) & " to " & character'image(to));
end if;
solve(N - 1, 'B', 'C', 'A');
end if;
moves := (2 ** min_disks) - 1;
return moves;
end solve;
begin
while min_disks /= max_disks loop
IF Argument_Count > 1 THEN
if Argument_Count = 1 then
min_disks := integer'value("Argument(1)");
elsif Argument_Count = 2 then
min_disks := integer'value("Argument(1)");
max_disks := integer'value("Argument(2)");
elsif Argument_Count = 3 then
min_disks := integer'value("Argument(1)");
max_disks := integer'value("Argument(2)");
if argument(3) = "v" or argument(3) = "V" then
verbose_bool := true; -- if argument is V or v it is true
end if;
END IF;
END IF;
IF Argument_Count > 3 THEN
RAISE argument_error;
END IF;
if (max_disks > 0) then
solve (N: integer; from, to, using : character);
END IF;
min_disks := min_disks + 1;
end loop;
EXCEPTION
WHEN Name_Error =>
Put_Line("Please re-enter your arguments, check to see if you entered integers and characters. Max of 3 arguments.");
WHEN OTHERS =>
Put_Line("Please try to not break the program again, thank you.");
end hanoi;
Functions return values, procedures do not, and you've defined Solve as a function.
Ada requires that you do something with a function's returned value, which you're not doing here. (You can't ignore the returned result as is done in other programming languages.)
As the error message states, your syntax is that of making a procedure call, i.e. invoking a procedure, but you've supplied the name of a function.
If the value being returned from a function is meaningful, then act on it in accordance with its purpose. If it is not providing any meaningful functionality, eliminate it and define Solve as a procedure.
As an aside, you may want to re-factor your display code into a nested subprogram. In the outline below, procedure Print can access the parameters of procedure Solve.
procedure Solve (N: in Integer; From, To, Using: in Character) is
procedure Print is
begin
if Verbose then
...
end if;
end Print;
begin
if N = 1 then
Print;
else
Solve (N - 1, 'A', 'B', 'C');
Print;
Solve (N - 1, 'B', 'C', 'A');
end if;
end Solve;
In addition to Marc's comment about the call to Solve's not being a proper Ada function reference, the syntax you have is that of a specification and not that of a invocation of Solve. You had it right in Solve's body just not in the initial invocation:
if (max_disks > 0) then
solve (N: integer; from, to, using : character);
END IF;
Related
Xilinx is inferring a latch for a VHDL code i've written. I've looked up the possible causes for this and found that it's often due to incomplete if or case statements. I've gone through and made sure to include else and when others statements, but i'm still receiving the warning. I believe this is also affecting another project i'm working on so i'd like to understand why this is the case.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity state_machine is
port(trig, en: in std_logic; cstate,nstate: out std_logic_vector(0 to 2));
end state_machine;
architecture Behavioral of state_machine is
signal cstate_s,nstate_s: std_logic_vector(0 to 2);
begin
cstate <= cstate_s;
nstate <= nstate_s;
process(en, cstate_s)
begin
if en = '1' then
nstate_s <= "111";
if cstate_s = "111" then
nstate_s <= "011";
elsif cstate_s = "011" then
nstate_s <= "100";
elsif cstate_s = "100" then
nstate_s <= "101";
elsif cstate_s = "101" then
nstate_s <= "110";
elsif cstate_s = "110" then
nstate_s <= "111";
else
null;
end if;
else
null;
end if;
end process;
process(trig, nstate_s)
begin
if rising_edge(trig) then
cstate_s <= nstate_s;
else
null;
end if;
end process;
end Behavioral;
WARNING:Xst:737 - Found 3-bit latch for signal . Latches may
be generated from incomplete case or if statements. We do not
recommend the use of latches in FPGA/CPLD designs, as they may lead to
timing problems.
For there to be no latches synthesised when a combinational process is synthesised, there must be no path between begin and end process; where all the outputs of the process are not assigned. This is called complete assignment. An output of the process is any signal assigned anywhere within it.
You have such paths. When any path with your null statements are executed, the output of your first process (nstate_s) is not assigned to. Therefore, you will get latches synthesised. There is no point in just having a null statement. If you genuinely don't care what value is assigned to your outputs in these paths, assign the outputs to '-', which means don't care in VHDL.
By the way (assuming trig is a clock), your second process is not combinational (it is sequential) and so you don't need to obey complete assignment; your else branch is unnecessary.
I have this code in one modules:
PROCEDURE Get (File: IN Ada.Text_IO.File_Type; Item : OUT Rational) IS
N: Integer;
D: Integer;
Dummy: Character;
BEGIN -- Get
LOOP
BEGIN
Ada.Integer_Text_IO.Get(File => File, Item => N);
Ada.Text_IO.Get (File => File, Item => Dummy);
Ada.Integer_Text_IO.Get(File => File, Item => D);
Item := N/D;
if Dummy /= '/' then
........;
end if;
EXIT;
EXCEPTION
when other =>
Ada.Text_IO.Put_Line(" here is exception ");
END;
END LOOP;
END Get;
What is differences with this second code.
The main of my question is if I don't put raise in body of statement of exception what is happen?
PROCEDURE Get (File: IN Ada.Text_IO.File_Type; Item : OUT Rational) IS
N: Integer;
D: Integer;
Dummy: Character;
BEGIN -- Get
LOOP
BEGIN
Ada.Integer_Text_IO.Get(File => File, Item => N);
Ada.Text_IO.Get (File => File, Item => Dummy);
Ada.Integer_Text_IO.Get(File => File, Item => D);
Item := N/D;
if Dummy /= '/' then
........;
end if;
EXIT;
EXCEPTION
when other =>
Ada.Text_IO.Put_Line(" here is exception ");
**raise;**
END;
END LOOP;
END Get;
The main of my question is if I don't put raise in body of statement of exception what is happen???
Thank you very much.
The only difference between both code modules is that the exception (if any is raised during execution of Get) is reraised, i.e. the exception is propagated to the caller of Get.
Whether this is the desired behaviour depends on your needs, i.e. does the caller of Get need to know that an exception occurred?
In your example several kinds of exceptions may occur, e.g.
not reading the correct/expected input (the file to read from does not start with a number)
trying to read from a file that has not been opened
reading D as 0 (thus resulting in a division by 0)
All of these are handled in the same manner by printing "here is exception". The first implementation of Get then silently returns control to the caller (who will not know that anything strange happened). The second implementation, however, will inform the caller by reraising the exception.
For more information see the Ada LRM ยง11.3 (Raise Statements).
I have created a function with one procedure....
Func1[n_] := Table[a[i], {i, n}]
which returns
Func1[5]
{a[1], a[2], a[3], a[4], a[5]}
I also have created a function with a few parameters or with a few arguments, few variables!
Func1[x_, y_, z_] := (x + y)*z - 1
which returns
Func1[5, 2, 3]
20
But what about if I want to create a function with a several procedure which returns whatever I want?
I already know that when one procedure is done I have to type " ; " at the end of this procedure!
Like in for loops we do....
For[k = 2, k < 3, k++,
S := Table[a[i], {i, n}];
B := Dimensions[S][[1]]];
]
So I need to create a function with a several procedure!
How to do it?
Please help me!
A couple of examples here. Remember to use lower-case initial letters to avoid conflicting with built-in functions which all start with a capital letter.
s[n_] := Table[a[i], {i, n}]
b[s_] := Dimensions[s][[1]]
For[k = 2, k < 3, k++,
x = s[k];
Print[b[x]]]
2
For[k = 2, k < 3, k++,
Print[b[s[k]]]]
2
Use parentheses for grouping.
For example
set$s$b[n_Integer] := ($s = Table[a[i], {i, n}];
$b = Dimensions[$s][[1]];)
Now, after executing, e.g.,
set$s$b[5]
one will get
$s
{a[1], a[2], a[3], a[4], a[5]}
$b
5
However, making use of modularity might be a better design choice in situations where the execution of several procedures is needed.
I am writing a LCD controller for an FPGA and am having a really weird (for me at least) problem. The state machine that's supposed to output the needed bits to the screen misbehaves and gets the output pins "stuck" in an old state, while it clearly has moved on to later states.
Here is the relevant parts of the state machine:
PROCESS (clk)
VARIABLE count: INTEGER RANGE 0 TO clk_divider; -- clk_divider is a generic positive.
BEGIN
IF (clk'EVENT AND clk = '1') THEN
count := count + 1;
IF (count = clk_divider) THEN
EAUX <= NOT EAUX;
count := 0;
END IF;
END IF;
END PROCESS;
....
PROCESS (EAUX)
BEGIN
IF (EAUX'EVENT AND EAUX = '1') THEN
pr_state <= nx_state;
END IF;
END PROCESS;
....
PROCESS (pr_state)
BEGIN
CASE pr_state IS
WHEN EntryMode => --6=1,7=Cursor increment/decrement, 8=Display shift on/off
RSs <='0';
DB(7 DOWNTO 0) := "00000110";
nx_state <= WriteData;
WHEN WriteData => --Write data to LCD:
RSs <='1';
YLED <= '1';
DB(7 DOWNTO 0) := "01011111";
i := i + 1;
IF (i < chars) THEN
nx_state <= WriteData;
ELSE
i := 0;
nx_state <= ReturnHome;
END IF;
WHEN ReturnHome => --Return cursor
RSs <='0';
YLED <= '1';
DB(7 DOWNTO 0) := "01011111";
nx_state <= WriteData;
END CASE;
END PROCESS;
Where the bits in the variable DB is assigned to the signal DBOUT:
DBOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0) -- In entity
SHARED VARIABLE DB : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000"; -- In Architecture
DBOUT <= DB;
DBOUT is outputted (in the .ucf-file) as:
NET "DBOUT(0)" LOC = P10;
NET "DBOUT(1)" LOC = P11;
NET "DBOUT(2)" LOC = P12;
NET "DBOUT(3)" LOC = P13;
NET "DBOUT(4)" LOC = P15;
NET "DBOUT(5)" LOC = P16;
NET "DBOUT(6)" LOC = P18;
NET "DBOUT(7)" LOC = P19;
Using an oscilloscope on the pins I can see that it is clearly stuck outputting the "EntryMode" bits and the "RSs" is set at low, while the YLED (the internal led on the FPGA) is on (it's off at all other states). The really weird thing is (and this took a real long time to find) is that if I change the EntryMode bits from
"00000110"
to
"00000100"
it successfully passes the state and outputs the correct bits. It might be true for other changes as well, but I don't really feel like testing that too much. Any help or tips would be highly appreciated!
UPDATE:
After popular request I explicitly put YLED to low in all the early states and switched (back) DB to be a signal. The result is that I can't reach the later states at all, or at least stay in them (even when fiddling with the magic bits, which I guess is a good thing) as the YLED only stays on for a split second after booting the FPGA.
There is a complete example, including theory, state machine, and VHDL code on pages 279-290 of "Finite State Machines in Hardware: Theory and Design...", by Volnei Pedroni, MIT Press, Dec. 2013.
I have a very good DirectMySQL unit, which is ready to be used and i want it to be a TDataset descendant so i can use it with QuickReport, i just want MySQL Query with DirectMySQL which descendant from TDataset.
Everything was ok until i tried to access a big table with 10.000 rows and more. It was unstable, the error was unpredictable and not always shown but it likely happened after you played with other tables.
It happened in GetFieldData(Field: TField; Buffer: Pointer): boolean; which used to get the field value from MySQL rows.
Here's the code,
function TMySQLQuery.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
var
I, CT: Integer;
Row: TMySQL_Row;
TBuf: PChar;
FD: PMySQL_FieldDef;
begin
UpdateCursorPos; ------------> This code is after i got the error but no result
Resync([]); ------------> This code is after i got the error but no result
Result := false;
Row := oRecordset.CurrentRow;
I := Field.FieldNo-1;
FD := oRecordset.FieldDef(I);
if Not Assigned(FD) then
FD := oRecordset.FieldDef(I);
TBuf := PP(Row)[i];
Try
CT := MySQLWriteFieldData(fd.field_type, fd.length, fd.decimals, TBuf, PChar(Buffer));
Result := Buffer <> nil;
Finally
Row := nil; ------------> This code is after i got the error but no result
FD := nil; ------------> This code is after i got the error but no result
TBuf := nil; ------------> This code is after i got the error but no result
Buffer := nil; ------------> This code is after i got the error but no result
End;
end;
{
These codes below are to translate the data type
from MySQL Data type to a TDataset data type
and move mysql row (TBuf) to TDataset buffer to display.
And error always comes up from this function
when moving mysql row to buffer.
}
function TMySQLQuery.MySQLWriteFieldData(AType: byte;
ASize: Integer; ADec: cardinal; Source, Dest: PChar): Integer;
var
VI: Integer;
VF: Double;
VD: TDateTime;
begin
Result := MySQLDataSize(AType, ASize, ADec);
case AType of
FIELD_TYPE_TINY, FIELD_TYPE_SHORT, FIELD_TYPE_LONG, FIELD_TYPE_LONGLONG,
FIELD_TYPE_INT24:
begin
if Source <> '' then
VI := StrToInt(Source)
else
VI := 0;
Move(VI, Dest^, Result);
end;
FIELD_TYPE_DECIMAL, FIELD_TYPE_NEWDECIMAL:
begin
if source <> '' then
VF := internalStrToCurr(Source)
else
VF := 0;
Move(VF, Dest^, Result);
end;
FIELD_TYPE_FLOAT, FIELD_TYPE_DOUBLE:
begin
if Source <> '' then
VF := InternalStrToFloat(Source)
else
VF := 0;
Move(VF, Dest^, Result);
end;
FIELD_TYPE_TIMESTAMP:
begin
if Source <> '' then
VD := InternalStrToTimeStamp(Source)
else
VD := 0;
Move(VD, Dest^, Result);
end;
FIELD_TYPE_DATETIME:
begin
if Source <> '' then
VD := InternalStrToDateTime(Source)
else
VD := 0;
Move(VD, Dest^, Result);
end;
FIELD_TYPE_DATE:
begin
if Source <> '' then
VD := InternalStrToDate(Source)
else
VD := 0;
Move(VD, Dest^, Result);
end;
FIELD_TYPE_TIME:
begin
if Source <> '' then
VD := InternalStrToTime(Source)
else
VD := 0;
Move(VD, Dest^, Result);
end;
FIELD_TYPE_STRING, FIELD_TYPE_VAR_STRING,
FIELD_TYPE_ENUM, FIELD_TYPE_SET:
begin
if Source = nil then
Dest^ := #0
else
Move(Source^, Dest^, Result);
end;
Else
Result := 0;
Raise EMySQLError.Create( 'Write field data - Unknown type field' );
end;
end;
My guess for now is it's memory related problem.
I am stacked. Anyone could help?
I also need TDataset documentation which list availlable descendant function and how to use it, or how to descendant from TDataset. anyone have them? I am lack of this kind of doumentation.
GetFieldData cannot have UpdateCursorPos and Resync calls. Otherwise you may get unpredicatable errors.
FD := oRecordset.FieldDef(I) ... FD := oRecordset.FieldDef(I); - looks strange. Second assigment is not needed.
finally ... end with local variables reset is not needed.
I have no idea what returns MySQLDataSize. For example, MySQLDataSize may return size in Delphi data type representation units, or may return length of data returned by MySQL. But depending on that MySQLWriteFieldData may be correct or may be not.
I dont know how DirectMySQL works. If it uses raw TCP/IP to talk to MySQL, then the problem may be there. For example, it incorrectly handles a sequence of packets.
And finally - what are the errors you are getting ? What is your Delphi version ? What is your MySQL client and server versions ?
And so on ....
IOW, that will be really hard to say, what is wrong. To do so, I for example, will need to get all sources, sit at Delphi IDE debugger and analyze many details of what is going on - sorry, no time :)
It's solved now by adding #0 at the end of the line... Thanks so much to all who replied to my problem.