Ada83 Unchecked Conversion of Record in Declaration - ada

I want to declare a constant as a 16 bit integer of type Word and assign a value to it. To support portability between Big and Little Endian platforms, I can't safely use an assignment like this one:
Special_Value : Constant Word := 16#1234#;
because the byte order might be misinterpreted.
So I use a record like this:
Type Double_Byte Is Record
Byte_1 : Byte; -- most significant byte
Byte_0 : Byte; -- least significant byte
End Record;
For Double_Byte Use Record
Byte_1 At 0 Range 0..7;
Byte_0 At 0 Range 8..15;
End Record;
However, in some cases, I have a large number of pre-configuration assignments that look like this:
Value_1 : Constant Word := 15#1234#;
This is very readable by a person, but endian issues cause it to be misunderstood a number of ways (including in the debugger, for example).
Because I have many lines where I do this, I tried the following because it is fairly compact as source code. It is working, but I'm not sure why, or what part of the Ada Reference Manual covers this concept:
Value_1 : Constant Word := DByte_To_Word((Byte_1 => 16#12#,
Byte_0 => 16#34#));
where DByte_To_Word is defined as
Function DByte_To_Word Is New Unchecked_Conversion(Double_Byte, Word);
I think I have seen something in the ARM that allows me to do this, but not the way I described above. I can't find it and I don't know what I would be searching for.

There’s nothing unusual about your call to DByte_To_Word; (Byte_1 => 16#12#, Byte_0 => 16#34#) is a perfectly legitimate record aggregate of type Double_Byte, see LRM83 4.3.1.
But! But! it’s true that, on a big-endian machine, the first (lowest-addressed) byte of your Word will contain 16#12#, whereas on a little-endian machine it will contain 16#34#. The CPU takes care of all of that; if you print the value of Special_Value you will get 16#1234# (or 0x1234) no matter which endianness the computer implements.
The only time you’ll encounter endianness issues is when you’re copying binary data from one endianness to another, via the network, or a file.
If your debugger gets confused about this, you need a better debugger!

Related

Ada program to detect an end of line

I was assigned this task as my homework. I have a file which contains lines of text of varying lengths. The program is supposed to write the data onto the screen in precisely the same order in which it is written in the file, yet it fails to do so. To achieve the desired result I tried reading only one character per iteration so as to detect new line characters. What am I doing wrong?
WITH Ada.Text_IO;
WITH Ada.Characters.Latin_1;
USE Ada.Text_IO;
PROCEDURE ASCII_artwork IS
File : File_Type;
c : Character;
BEGIN
Open(File, In_File, "Winnie_The_Pooh.txt");
WHILE NOT End_Of_File(File) LOOP
Get(File, C);
IF (C = Ada.Characters.Latin_1.LF) THEN Put_Line(" "); ELSE
Put(C);
END IF;
END LOOP;
Close(File);
END ASCII_Artwork;
For each file, the Ada runtime maintains a fictitious "cursor". This is not the typical file position cursor (index), but one that indicates the position on a page, line, etc. (see also RM A.10 (7)). This is somewhat of an inheritance from the early versions of Ada.
Get stems from this same era and is expected to update the location of this cursor when some particular control characters are being read (e.g. an end-of-line mark). If Get reads such such a control character, it will only use it to update the cursor (internally) and then continue to read a next character (see also RM A.10.7 (3)). You'll therefore never detect an end-of-line mark when using Get.
This behavior, however, has some uncomfortable consequence: if a file ends with a sequence of control characters, then Get will keep reading those characters and hit the end of the file causing an End_Error exception.
You can, of course, catch this exception and handle it, but such a construct is dubious as having a sequence of control characters at the end of a file is actually not such an abnormal case (and hence dubious if worth an exception). As a programmer, however, you cannot change this behavior: it's defined by the language and the language will not be changed because it has been decided to keep Ada (highly) backwards compatible (which in itself is understandable given its field of application).
Hence, in your case, if you want stick to a character-by-character processing approach, I would suggest to move away from Get and instead use (for example) streams to perform I/O as in the example below.
main.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Text_IO.Text_Streams; use Ada.Text_IO.Text_Streams;
procedure ASCII_artwork IS
File : File_Type;
Input : Stream_Access;
Output : Stream_Access;
C : Character;
begin
Open (File, In_File, "Winnie_The_Pooh.txt");
Input := Stream (File);
Output := Stream (Standard_Output);
while not End_Of_File (File) loop
Character'Read (Input, C);
Character'Write (Output, C);
end loop;
Close(File);
end ASCII_Artwork;
Output is as expected (i.e. the content of this the file at ascii-art.de).
NOTE: Check the source code of the GNAT runtime to actually see how Get works internally (focus on the loop at the end).
As explained by DeeDee, text inputs are buffered linewise in Ada. The idea is to be able to read two integers on the same line. For consistency sake (the designers of Ada are picky on that...), Get(File, C) does the same. It is not practical in your case. Fortunately, Ada 95 has introduced Get_Immediate, to solve precisely that issue.
Otherwise, as suggested by Frédéric, you could use the function Get_Line to absorb Winnie_The_Pooh.txt line by line seamlessly. By the way, the Get_Line method will convert the different end-of-line conventions automatically.
Line terminators in Ada.Text_IO are a concept, not a character or sequence of characters in the file. (Although most commonly used file systems implement them as characters or sequences of characters in the file, there exist file systems that do not.) Line terminators must therefore be manipulated using the operations in the package. For reading, End_Of_Line checks to see if the cursor is at a line terminator, Skip_Line skips the next line terminator, and Get_Line may skip a line terminator. For writing, New_Line and Put_Line write line terminators.
For your problem, the canonical solution is to use the Get_Line function to read lines, and Put_Line to output the lines read.

Lua Alien - Pointer Arithmetic and Dereferencing

My goal is to call Windows' GetModuleInformation function to get a MODULEINFO struct back. This is all working fine. The problem comes as a result of me wanting to do pointer arithmetic and dereferences on the LPVOID lpBaseOfDll which is part of the MODULEINFO.
Here is my code to call the function in Lua:
require "luarocks.require"
require "alien"
sizeofMODULEINFO = 12 --Gotten from sizeof(MODULEINFO) from Visual Studio
MODULEINFO = alien.defstruct{
{"lpBaseOfDll", "pointer"}; --Does this need to be a buffer? If so, how?
{"SizeOfImage", "ulong"};
{"EntryPoint", "pointer"};
}
local GetModuleInformation = alien.Kernel32.K32GetModuleInformation
GetModuleInformation:types{ret = "int", abi = "stdcall", "long", "pointer", "pointer", "ulong"}
local GetModuleHandle = alien.Kernel32.GetModuleHandleA
GetModuleHandle:types{ret = "pointer", abi = "stdcall", "pointer"}
local GetCurrentProcess = alien.Kernel32.GetCurrentProcess
GetCurrentProcess:types{ret = "long", abi = "stdcall"}
local mod = MODULEINFO:new() --Create struct (needs buffer?)
local currentProcess = GetCurrentProcess()
local moduleHandle = GetModuleHandle("myModule.dll")
local success = GetModuleInformation(currentProcess, moduleHandle, mod(), sizeofMODULEINFO)
if success == 0 then --If there is an error, exit
return 0
end
local dataPtr = mod.lpBaseOfDll
--Now how do I do pointer arithmetic and/or dereference "dataPtr"?
At this point, mod.SizeOfImage seems to be giving me the correct values that I am expecting, so I know the functions are being called and the struct is being populated. However, I cannot seem to do pointer arithmetic on mod.lpBaseOfDll because it is a UserData.
The only information in the Alien Documentation that may address what I'm trying to do are these:
Pointer Unpacking
Alien also provides three convenience functions that let you
dereference a pointer and convert the value to a Lua type:
alien.tostring takes a userdata (usually returned from a function that has a pointer return value), casts it to char*, and returns a Lua
string. You can supply an optional size argument (if you don’t Alien
calls strlen on the buffer first).
alien.toint takes a userdata, casts it to int*, dereferences it and returns it as a number. If you pass it a number it assumes the
userdata is an array with this number of elements.
alien.toshort, alien.tolong, alien.tofloat, and alien.todouble are like alien.toint, but works with with the respective typecasts.
Unsigned versions are also available.
My issue with those, is I would need to go byte-by-byte, and there is no alien.tochar function. Also, and more importantly, this still doesn't solve the problem of me being able to get elements outside of the base address.
Buffers
After making a buffer you can pass it in place of any argument of
string or pointer type.
...
You can also pass a buffer or other userdata to the new method of your
struct type, and in this case this will be the backing store of the
struct instance you are creating. This is useful for unpacking a
foreign struct that a C function returned.
These seem to suggest I can use an alien.buffer as the argument of MODULEINFO's LPVOID lpBaseOfDll. And buffers are described as byte arrays, which can be indexed using this notation: buf[1], buf[2], etc. Additionally, buffers go by bytes, so this would ideally solve all problems. (If I am understanding this correctly).
Unfortunately, I can not find any examples of this anywhere (not in the docs, stackoverflow, Google, etc), so I am have no idea how to do this. I've tried a few variations of syntax, but nearly every one gives a runtime error (others simply does not work as expected).
Any insight on how I might be able to go byte-by-byte (C char-by-char) across the mod.lpBaseOfDll through dereferences and pointer arithmetic?
I need to go byte-by-byte, and there is no alien.tochar function.
Sounds like alien.tostring has you covered:
alien.tostring takes a userdata (usually returned from a function that has a pointer return value), casts it to char*, and returns a Lua string. You can supply an optional size argument (if you don’t Alien calls strlen on the buffer first).
Lua strings can contain arbitrary byte values, including 0 (i.e. they aren't null-terminated like C strings), so as long as you pass a size argument to alien.tostring you can get back data as a byte buffer, aka Lua string, and do whatever you please with the bytes.
It sounds like you can't tell it to start at an arbitrary offset from the given pointer address. The easiest way to tell for sure, if the documentation doesn't tell you, is to look at the source. It would probably be trivial to add an offset parameter.

LLVM converting a Constant to a Value

I am using custom LLVM pass where if I encounter a store to
where the compiler converts the value to a Constant; e.g. there is an explicit store:
X[gidx] = 10;
Then LLVM will generate this error:
aoc: ../../../Instructions.cpp:1056: void llvm::StoreInst::AssertOK(): Assertion `getOperand(0)->getType() == cast<PointerType>(getOperand(1)->getType())->getElementType() && "Ptr must be a pointer to Val type!"' failed.
The inheritance order goes as: Value<-User<-Constant, so this shouldn't be an issue, but it is. Using an a cast on the ConstantInt or ConstantFP has no effect on this error.
So I've tried this bloated solution:
Value *new_value;
if(isa<ConstantInt>(old_value) || isa<ConstantFP>(old_value)){
Instruction *allocInst = builder.CreateAlloca(old_value->getType());
builder.CreateStore(old_value, allocInst);
new_value = builder.CreateLoad(allocResultInst);
}
However this solution creates its own register errors when different type are involved, so I'd like to avoid it.
Does anyone know how to convert a Constant to a Value? It must be a simple issue that I'm not seeing. I'm developing on Ubuntu 12.04, LLVM 3, AMD gpu, OpenCL kernels.
Thanks ahead of time.
EDIT:
The original code that produces the first error listed is simply:
builder.CreateStore(old_value, store_addr);
EDIT2:
This old_value is declared as
Value *old_value = current_instruction->getOperand(0);
So I'm grabbing the value to be stored, in this case "10" from the first code line.
You didn't provide the code that caused this first assertion, but its wording is pretty clear: you are trying to create a store where the value operand and the pointer operand do not agree on their types. It would be useful for the question if you'd provide the code that generated that error.
Your second, so-called "bloated" solution, is the correct way to store old_value into the stack and then load it again. You write:
However this solution creates its own register errors when different type are involved
These "register errors" are the real issue you should be addressing.
In any case, the whole premise of "converting a constant to a value" is flawed - as you have correctly observed, all constants are values. There's no point storing a value into the stack with the sole purpose of loading it again, and indeed the standard LLVM pass "mem2reg" will completely remove such a sequence, replacing all uses of the load with the original value.

The use of IN OUT in Ada

Given below is some code in ada
with TYPE_VECT_B; use TYPE_VECT_B;
Package TEST01 is
procedure TEST01
( In_State : IN VECT_B ;
Out_State : IN OUT VECT_B );
function TEST02
( In_State : IN VECT_B ) return Boolean ;
end TEST01;
The TYPE_VECT_B package specification and body is also defined below
Package TYPE_VECT_B is
type VECT_B is array (INTEGER range <>) OF BOOLEAN ;
rounded_data : float ;
count : integer ;
trace : integer ;
end TYPE_VECT_B;
Package BODY TYPE_VECT_B is
begin
null;
end TYPE_VECT_B;
What does the variable In_State and Out_State actually mean? I think In_State means input variable. I just get confused to what actually Out_State means?
An in parameter can be read but not written by the subprogram. in is the default. Prior to Ada 2012, functions were only allowed to have in parameters. The actual parameter is an expression.
An out parameter implies that the previous value is of no interest. The subprogram is expected to write to the parameter. After writing to the parameter, the subprogram can read back what it has written. On exit the actual parameter receives the value written to it (there are complications in this area!). The actual parameter must be a variable.
An in out parameter is like an out parameter except that the previous value is of interest and can be read by the subprogram before assignment. For example,
procedure Add (V : Integer; To : in out Integer; Limited_To : Integer)
is
begin
-- Check that the result wont be too large. This involves reading
-- the initial value of the 'in out' parameter To, which would be
-- wrong if To was a mere 'out' parameter (it would be
-- uninitialized).
if To + V > Limited_To then
To := Limited_To;
else
To := To + V;
end if;
end Add;
Basically, every parameter to a function or procedure has a direction to it. The options are in, out, in out (both), or access. If you don't see one of those, then it defaults to in.
in means data can go into the subroutine from the caller (via the parameter). You are allowed to read from in parameters inside the routine. out means data can come out of the routine that way, and thus you are allowed to assign values to the parameter inside the routine. In general, how the compiler accomplishes the data passing is up to the compiler, which is in accord with Ada's general philosophy of allowing you to specify what you want done, not how you want it done.
access is a special case, and is roughly like putting a "*" in your parameter definition in Cish languages.
The next question folks usually have is "if I pass something large as an in parameter, is it going to push all that data on the stack or something?" The answer is "no", unless your compiler writers are unconsionably stupid. Every Ada compiler I know of under the hood passes objects larger than fit in a machine register by reference. It is the compiler, not the details of your parameter passing mechanisim, that enforces not writing data back out of the routine. Again, you tell Ada what you want done, it figures out the most efficient way to do it.

address representation in ada

I have pasted a code below which is in Ada language.I need some clarification on some implementations.
C : character;
Char : character;
type Myarr_Type is array (character range 'A'..'K') of character;
Myarr : Myarr_Type := ('A','B','C','D','E','F','G','H','I','J','K');
Next_Address := Myarr'address --'
Last_Address := Next_Address + Storage_Offset'(40); --'
return P2 + Storage_Offset'(4); --'
Last_Address := Next_Address + Storage_Offset'(4); --'
Now my doubt is 1) what does P2 + Storage_Offset'(4) actually mean.Does that mean that its returning the address of the next element in the array which is 'B'.Storage_Offset'(4) in Ada --does this mean 4 bits or 4 bytes of memory. 2) If i assume that Last_Address points to last element of the array which is 'K', how does the arithmentic Storage_Offset'(40) satisfies the actual implementation?
Please get back to me if u need any more clarifications.
Please assume that the function does not exist.
As a matter of fact,i have some ada file and my job is to convert them to C files.Since i am a beginner in ada,i faced a lot of issues with that.Please pardon in case of any confusion
Thanks
Maddy
Storage_Offset is a special integeral type in package System.Storage_Elements that can be added to objects of type System.Address. What exactly the units of Address and Storage_Offset are is implementation defined, but probably just about every implementation in existence uses bytes. So Next_Address + Storage_Offset'(4) means "the address four bytes past whatever Next_Address refers to."
You talked a bit about Ada porting. In 99% of cases, that is a very stupid idea (the %1 being when you need to port to a platform that has no Ada compiler). I'd say the same thing no matter what language you are porting. It's a fool's game. The best outcome you can hope for when porting code is that after a ton of effort it works as well as it did before. With coding the best case never happens.
Ada can interface to C just fine, so it would be far smarter to keep unchanged code in Ada and only "port" stuff you need to change.
If you come across any tasking code, protected types, or custom streams you will be in a world of hurt. Those things don't really have easy C analogs.
If your bosses really have a boner for C or something, I'd suggest looking into Sofcheck's AdaMagic, which provides a service to transform Ada code to ANSI C. Back in the day (two owners prior) they used to claim that it produced maintainable C code. Either way, it will probably be far cheaper than having an inexperienced (in Ada) developer try to do it all by hand.
my_func(int P1,int P2)
{
return P2 + Storage_Offset'(4);
}
Well, this is a C function whose body is written in Ada. There is no "+" operator taking an Integer and a Storage_Offset; perhaps you're looking for
function "+"(Left : Address; Right : Storage_Offset)
return Address;
and perhaps you meant to call my_func(something, Next_Address)?
In that case, the expression will return the address of whatever is 4 Storage_Elements, ie bytes, after Myarr('A').
Myarr_Type is an array of Character, which with any normal compiler on any common architecture is going to be a standard 8-bit byte. So Myarr_Type objects will be 11 bytes long, not 44, and Myarr('A')'Address + 4 will be the address of Myarr('E').
If you want the address of the last element of Myarr, try
Myarr (Myarr'Last)'Address

Resources