Write a BYTE or Array of bytes in Ada - ada

I'm writing a simple compiler for Brainf*** in Ada, but I'm in serious trouble in the code generation, therefore I am unable to generate a binary file with opcode instructions, correctly because whenever I write the file, it saves hexa decimal value like an integer. ( Integer size )
I made a simple sample of wat I try to make:
With Ada, Ada.Sequential_IO, Ada.Integer_Text_IO;
Use Ada;
procedure main is
type Byte is range -128 .. 127;
for Byte'Size use 16;
package Bin_IO is new Sequential_IO(Integer);
File : Bin_IO.File_Type;
FileName : constant String := "teste.bin";
Num : Byte;
begin
Bin_IO.Create(File => File,
Name => FileName);
Num := 16#FF#;
Bin_IO.Write(File => File,
Item => Num);
Bin_IO.Close(File => File);
end main;
The spected result in file is just FF but, when I open the file in hex editor I have FF00 0000
How I can save the opcode instructions correctly correctly??

Try changing line 9 to:
package Bin_IO is new Sequential_IO(Byte);
It changes the generic package to sequence of bytes.
Bin_IO.Write should now write Bytes instead.

I found functional solution...
I changed the type to Character type, and, I just convert the machine opcode to char type and write in file, that work's very well..., I don't know if that is the best way, but works
With Ada, Ada.Sequential_IO, Ada.Integer_Text_IO;
Use Ada;
procedure main is
package Bin_IO is new Sequential_IO(Character);
File : Bin_IO.File_Type;
FileName : constant String := "teste.bin";
Num : Character;
begin
Bin_IO.Create(File => File,
Name => FileName);
Num := Character'Val(16#97#);
Bin_IO.Write(File => File,
Item => Num);
Bin_IO.Close(File => File);
end main;

Related

How to save Doubly_Linked_Lists text to a file for Ada language? Also how to have not fixed size string input?

I am writing a school project to store string to the doubly linked list, but I don't know how to save the final list to a text file. I also what the user to choose the text file name. Can someone show me how to do that? Also for Ada can I have a not fixed-length string as input? Right now I set the string length to 5 but I really wanted to have a flexible length for the string. Below is my code thank you.
with Ada.Containers.Doubly_Linked_Lists;
with Ada.Text_Io; use Ada.Text_Io;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.IO_Exceptions;
procedure main is
type Command is (A, C, P, E, M);
package Command_IO is new Ada.Text_IO.Enumeration_IO (Command);
package String_List is new Ada.Containers.Doubly_Linked_Lists(Unbounded_String);
use String_List;
Userinput : String(1 .. 5) := (others => ' '); --This string length is 5
InsertLocation : String(1 .. 5) := (others => ' '); --This string length is 5
text : List; -- List is from Doubly_Linked_Lists
F : File_Type;
begin
loop
declare
Cmd : Command;
procedure Print(Position : Cursor) is -- this subprogram print all string from list
begin
Put_Line(To_String(Element(Position)));
--Put_Line("K");
end Print;
begin
Put_Line("*****************************");
Put_Line("*Enter A to add a text *");
Put_Line("*Enter C to insert a text *");
Put_Line("*Enter P the print text list*");
Put_Line("*Enter E the exit program *");
Put_Line("*Enter M to save the list *");
Put_Line("*****************************");
Put_Line(" ");
Put(">> ");
Command_IO.Get (Cmd);
Ada.Text_IO.Skip_Line;
Put_Line ("read " & Cmd'Image); -- ' to sort out the not-fully-Ada-aware syntax highlighting
Put_Line (" " );
case Cmd is
when a =>
Put_Line("Enter a text " );
Put(">> " );
Get(Userinput);
text.Append(To_Unbounded_String(Userinput)); -- if letter is a add it to the doubly link list
Put_line(" " );
when c =>
Put_Line("Enter a text location you want to insert " );
Put(">> " );
Get(Userinput);
Put_Line("Enter a text " );
Put(">> " );
Get(InsertLocation);
text.Insert(Before => text.Find(To_Unbounded_String(Userinput)), New_Item => To_Unbounded_String( InsertLocation ));
when p =>
text.Iterate(Print'access);
Put_line(" " );
when m =>
Put_Line("Save to file");
Create (F, Out_File, "file.txt");
Put_Line (F, "This string will be written to the file file.txt");
Close (F);
when e =>
Put_Line("Program Exit");
exit;
end case;
exception
when Ada.IO_Exceptions.Data_Error =>
Put_Line ("unrecognised command");
Put_Line (" ");
end;
end loop;
end main;
You look like you have all the parts. You can use Text_IO for writing to the file and you can use Unbounded_String to hold strings of any size. For reading in strings of any size, you can use the procedure Get_Line in Text_IO which returns a string of any length or if you really want to use Unbounded_Strings, you can use Ada.Text_IO.Unbounded_IO.Get_Line. I could also optionally suggest looking at Indefinite_Doubly_Linked_List instead of using Unbounded_String, depending on your use case.
For writing to file, just loop over the List and write each element to a file using Text_IO style functions.
Here is some scaffolding showing some of this.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Indefinite_Doubly_Linked_Lists;
use Ada.Containers;
procedure Hello is
package Lists is new Indefinite_Doubly_Linked_Lists(String);
Text : Lists.List;
begin
Put_Line("Hello, world!");
Put_Line("Enter a text:" );
declare
User_Input : String := Get_Line;
begin
Text.Append(New_Item => User_Input);
end;
Put_Line("Enter Text to Insert at:");
declare
Location : String := Get_Line;
begin
Put_Line("Enter New Text:");
declare
User_Input : String := Get_Line;
begin
Text.Insert(Before => Text.Find(Location), New_Item => User_Input);
end;
end;
-- Loop through list and write each element
for Line of Text loop
Put_Line(Line);
-- Write to file here using Text_IO file operations
end loop;
end Hello;
Side note, if you spend more time searching your data than you do creating your list, you can also look at Map packages. Ada has both hashed and ordered maps (with indefinite options as well).
A couple of observations:
(1) Although a String is a fixed-length object, the length can be determined at initialisation:
declare
Str : constant String := Get_Line;
begin
...
You may have to be a bit creative about using the value in Str outside its scope, the declare block. For example, if it’s the name of a file to be opened, the File_Type object to be opened could be in an outer scope.
(2) If you want to read an integer, use Ada.Integer_Text_IO.Get (followed by Skip_Line, because the Get terminates when the number has been read, leaving the rest of the line, including the terminator, in the input buffer)
Looks like you are on the right path.
A couple of points :
you can ask the user to enter a filename (e.g. in a funciton returning String, used to initialise a variable as in Simon's answer. This function could suggest a default which will be used if the user just presses Return. Then you pass that string to the Create call.
Probably the best way to output complex things like lists is to learn Stream I/O. This may be more complex to set up than you need right now, but ultimately it would let you simply "Write" the whole list to file in a single operation. Each data type has 'Read and 'Write attributes, which are procedures you can overload with your own procedures to format the file however you wish. The default 'Write attribute for a list will iterate over the whole List calling each element's own 'Write procedure. (It may also insert information about the List you don't want, that's why it's overloadable...)

Ada: Serial port, String to Stream_element_array

when 'B' |'b' =>
cons.Put_Line("Enter text - less than 20 chars: ");
cons.Get_Line(Item => st,
Last => m);
--buffer_ser'Write(st,m);
ser.Write(Port => S_Port,
Buffer => buffer_ser);
Defined as:
package cons renames gnat.IO;
package ser renames gnat.Serial_Communications;
S_Port : gnat.Serial_Communications.Serial_Port;
buffer_ser: ada.Streams.Stream_Element_Array(1..20);
x : Ada.Streams.Stream_Element_Offset;
m : Integer;
st : string(1..20) := (others => ASCII.NUL);
ComPort : GNAT.Serial_Communications.Port_Name(1..5);
Basically, I needed a very portable application, to operate an old device that overlays a video stream based on serial commands. I decided to try out Ada as I'd been learning it for something else.
How do I convert to a Stream_element_array(1..20) from a String(1..20) in Ada? I've tried the obvious answers, and I'm just totally stuck!
Edited as requested for the person who down voted me...
First we need an MCVE.
with gnat.IO;
with ada.Streams;
with gnat.Serial_Communications;
procedure MCVE is
package cons renames gnat.IO;
package ser renames gnat.Serial_Communications;
S_Port : gnat.Serial_Communications.Serial_Port;
buffer_ser: ada.Streams.Stream_Element_Array(1..20);
x : Ada.Streams.Stream_Element_Offset;
m : Integer;
st : string(1..20) := (others => ASCII.NUL);
ComPort : GNAT.Serial_Communications.Port_Name(1..5);
begin
cons.Put_Line("Enter text - less than 20 chars: ");
cons.Get_Line(Item => st,
Last => m);
--buffer_ser'Write(st,m);
ser.Write(Port => S_Port,
Buffer => buffer_ser);
end MCVE;
it compiles successfully and fails with the error
raised GNAT.SERIAL_COMMUNICATIONS.SERIAL_ERROR : write: port not
opened
A little reading on Streams shows that the answer to the actual question:
How do I convert to a Stream_element_array(1..20)
is : normally, you don't. Streams take care of that for you.
A couple of modifications, respectively:
make S_Port aliased so we can take its access (to allow redirectable stream Writes) and delete unnecessary intermediate variables
actually open the serial port as a Stream
write the string directly to the stream
look like
S_Port : aliased gnat.Serial_Communications.Serial_Port;
-- buffer_ser: ada.Streams.Stream_Element_Array(1..20);
-- x : Ada.Streams.Stream_Element_Offset;
...
gnat.Serial_Communications.Open(S_Port,ComPort);
String'Write(S_Port'access, st(1..m));
--buffer_ser'Write(st,m);
--ser.Write(Port => S_Port, Buffer => buffer_ser);
But using fixed length strings when they aren't appropriate is a bad idea. Let's declare the string to be of the right length and simplify further. This requires a function form of Get_Line, which the Gnat.IO package doesn't provide, so let's use the more portable Ada.Text_IO instead. (And initialise the serial port name, and actually use the renamed packages...)
When we're done, we have something like
with Ada.Text_IO;
with ada.Streams;
with gnat.Serial_Communications;
procedure MCVE is
package cons renames Ada.Text_IO;
package ser renames gnat.Serial_Communications;
S_Port : aliased ser.Serial_Port;
ComPort : ser.Port_Name := "COM1";
begin
ser.Open(S_Port,ComPort);
cons.Put_Line("Enter text : ");
declare
st : String := cons.Get_Line;
begin
String'Write(S_Port'access, st);
end;
end MCVE;

Mapping chunk of shared memory for reading/writing in Ada

I have a chunk (1024 bytes) of shared memory between two processes for which I have an address pointing to. I want to copy some data to this shared memory, and read it on the other process. Coming from a C background, it seems easiest to map a record to this address, and then write to the record, but it does not seem to be copying correctly.
Currently, I am trying to convert the pointer to a pointer-to-record type using an Unchecked Conversion, and copy to the record, but I am seeing differences in the data when I compare the original payload with the one received in the second process.
Is this the proper way of doing this?:
type Payload_Array_Type is array (1..255) of Integer_32;
type Common_Buffer_Type is
record
Size : Integer_32;
Payload : Payload_Array_Type;
end record;
type Common_Buffer_Ptr_Type is access Common_Buffer_Type;
function Convert_Common_Memory_Ptr is new Unchecked_Conversion (
Source => System.Address,
Target => Common_Buffer_Ptr_Type);
Common_Memory_Ptr : System.Address;
procedure Copy_To_Common_Buffer
(
Size : Integer_32;
Payload : Payload_Array_Type
) is
Common_Buffer_Ptr : Common_Buffer_Ptr_Type;
begin
Common_Buffer_Ptr := Convert_Common_Memory_Ptr(Common_Memory_Ptr);
Common_Buffer_Ptr.Size := Size;
Common_Buffer_Ptr.Payload(1..255) := Payload(1..255);
end Copy_To_Common_Buffer;
I would try to do it this way:
procedure Payload is
type Payload_Array_Type is array (1..255) of Integer_32;
type Common_Buffer_Type is record
Size : Integer_32;
Payload : Payload_Array_Type;
end record;
for Common_Buffer_Type use record -- representation clause should be common to both processes
Size at 0 range 0 .. 31;
Payload at 0 range 32 .. 1023;
end record;
for Common_Buffer_Type'Size use 1024; -- check this is also used in the other process.
type Common_Buffer_Ptr_Type is access Common_Buffer_Type;
Common_Memory_Ptr : System.Address; -- assuming this is where the shared object resides with a real address, possibly make it constant
procedure Copy_To_Common_Buffer (Size : in Integer_32;
Payload : in Payload_Array_Type) is
Common_Buffer : Common_Buffer_Type;
for Common_Buffer'Address use Common_Memory_Ptr; -- address overlay
begin
Common_Buffer := (Size => Size,
Payload => Payload);
end Copy_To_Common_Buffer;
begin
Copy_To_Common_Buffer (9,(others => 876));
end Payload;
The type definitions should be common to the two processes, and note I've used a representation clause to specify where the components go.
I've used an address overlay to specify the location of where I'm writing, and written the whole record in one go.
Also look up usage of pragma volatile as #Brian Drummond suggests.

Ada - getting string from text file and store in array

Hi im just wondering how to put data in an array if i loop txt and store it in A_Composite Name.
procedure Main is
type An_Array is array (Natural range <>) of A_Composite;
type A_Composite is
record
Name : Unbounded_String;
end record;
File : Ada.Text_IO.File_Type;
Line_Count : Integer := 0;
begin
Ada.Text_IO.Open (File => File,
Mode => Ada.Text_IO.In_File,
Name => "highscore.txt");
while not Ada.Text_IO.End_Of_File (File) loop
declare
Line :String := Ada.Text_IO.Get_Line (File);
begin
--I want to store Line String to array. but i don't know how to do it
end;
end loop;
Ada.Text_IO.Close (File);
end Main;
Ok, you have an unconstrained array here. This has implications; you see an unconstrained array gains its definite length when the object (general sense, not OOP) is declared or initialized.
As an example, let's look at strings (which are unconstrained arrays of characters) for an example to see how this works:
-- Create a string of 10 asterisks; the initialization takes those bounds.
A : constant string(1..10):= (others => '*');
-- Create a string of 10 asterisks; but determined by the initialization value.
B : constant string := (1..10 => '*');
-- Another way of declaring a string of 10 asterisks.
C : constant string := ('*','*','*','*','*','*','*','*','*','*');
Now, you can get these bounds from a function call; this means that we can use function-calls to return these values recursively.
Function Get_Text return An_Array is
Package Unbounded renames Ada.Strings.Unbounded;
-- You'll actually want the Get_Line that takes a file.
Function Get_Line return Unbounded.Unbounded_String
renames Unbounded.Text_IO.Get_Line;
begin
return (1 => (Name => Get_Line)) & Get_Text;
exception
when End_Error => return ( 1..0 => (Name => Unbounded.Null_Unbounded_String) );
end Get_Text;
So, that's how you'd do it using an unconstrained array.

Function reading from standard input without any "in" parameters

Perhaps this is simple, and I am just missing some basic information, but I can't seem to find the answer anywhere.
I'm writing a Get_Word function for class, here is the relevant section of the spec file my prof wrote:
function Get_Word return Ustring;
-- return a space-separated word from standard input
procedure Fill_Word_List(Wl : in out Ustring_Vector);
-- read a text file from standard in and add all
-- space-separated words to the word list wl
I've written the Get_Word function, and am trying to test it out with this code:
with Ada.Text_IO; use Ada.Text_Io;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure ngramtest is
Name : String(1..80);
File : File_Type;
Size : Natural;
function Get_Word return String is
-- I'm using a strings instead of Unbounded_Strings for testing purposes.
Word : String(1..80) := (others => ' ');
Char : Character;
File : File_Type;
Eol : Boolean;
I : Integer := 1;
begin
--this code below, when uncommented reveals whether or not the file is open.
--if Is_Open(File) then
-- Word := (1..80 => 'y');
--else
-- Word := (1..80 => 'n');
--end if;
loop
Look_Ahead(File, Char, Eol);
if Eol then
exit;
elsif Char = ' ' then
exit;
else
Get (File, Char);
Word(I) := Char;
I := I + 1;
end if;
end loop;
return Word(1..Word'Last);
end Get_Word;
begin
Put ("Enter filename: ");
Get_Line (Name, Size);
Open (File, Mode => In_File, Name => Name(1..Size));
Put (Get_Word);
Close(File);
end ngramtest;
It compiles, but at runtime I get an exception telling me that the file isn't open, and the commented out section returns "nnnnnn..." meaning that the file is not open within the function.
My question is how am I to read from standard input if i'm not allowed to use in parameters in my function? Without them the function won't be able to access files.
Essentially, how can I "Get_Word"?
Sorry if this is simple, but I'm completely lost.
You need to set your "File" variable to standard input:
File : File_Type := Ada.Text_IO.Standard_Input;

Resources