Ada "Compilation Unit Expected" error - compilation

I'm trying to declare a new type so I can pass an array as an argument to a procedure. It looks like this:
type Arr_Type is array(1..1000) of String;
procedure proceed(Arg1: in Arr_Type) is
begin
<program body>
end
Whenever I try and compile this, I receive a "compilation unit expected" error. If I remove the type declaration, I no longer get the error, but I obviously need it and I get an error if I put it anywhere else in the file. I'm a little new to Ada so I'm not entirely sure what's happening here.

A program in Ada has to be divided into compilation unit (procedure, function or package). The type declaration has to be contained in a unit so you could wrap these in a procedure:
procedure Main is
type Arr_Type is array(1..1000) of String;
procedure proceed(Arg1: in Arr_Type) is
begin
<program body>
end proceed;
begin
call to proceed
end Main;
If you already have a program calling proceed but want it on a separate file, you'll need a package instead. Then you create two files - a specification file (.ads) and a body file (.adb):
my_package.ads:
package My_Package is
type Arr_Type is array(1..1000) of String;
procedure proceed(Arg1: in Arr_Type);
end My_Package;
my_package.adb:
package body My_Package is
procedure proceed(Arg1: in Arr_Type) is
begin
<program body>
end Proceed;
end My_Package;
Then you can include this package as usual with with My_Package (and possible use)

Related

Creating a class in Pascal

I'm attempting to create a class in Pascal, I am a bit confused about the declaration and syntax. the main thing is an error I'm getting "Forward declaration not solved Tetromino.Rotate(LongInt)", I read that I need to declare my procedure in the implementation section but I'm not sure where I'm meant to be putting that. also if you notice anything else wrong with my class declaration please tell me.
program Tetris;
{$MODE OBJFPC}
uses crt, sysutils;
type
Tetromino = class
private
TempFace : array [0..15] of char;
public
Face : array[0..15] of char;
//constructor create(); (idk what this is but read somewhere that you need it)
procedure Rotate(rotation : integer);
end;
var
a,b,c,d,e,f,g : tetromino;
begin
ReadKey();
end.
In a program module there is no need for division into interface and implementation. Therefore the error description (to implement the procedure in the implementation section) is a little bit misleading. Still, it indicates that the implementation of the Rotate() procedure is missing.
So, the error is that you have declared a procedure in the Tetromino class, but the implementation of that procedure is missing. You need to implement it somewhere between the class declaration and the begin .. end block of the program.
In a unit module, which has named sections: interface and implementation, you declare classes in the interface section (if those classes are to be accessible from other modules) and implement them in the implementation section.
In the following I outline what you need to do in your program, including the constructor for Tetromino
program Tetris;
{$MODE OBJFPC}
uses crt, sysutils;
type
Tetromino = class
private
TempFace : array [0..15] of char;
public
Face : array[0..15] of char;
constructor create(); (idk what this is but read somewhere that you need it)
procedure Rotate(rotation : integer);
end;
var
a,b,c,d,e,f,g : tetromino;
constructor Tetromino.create;
begin
// constructor (automatically) aquires a block of memory
// to hold members of the class
// to do: initialize member fields of the instance
end;
procedure Tetromino.Rotate(rotation: Integer);
begin
// implementation of the Rotate() method
end;
begin
ReadKey();
end.

Does a VHDL function have to return a value?

I would like to create a function to write a file via the TEXTIO library. This is quite a simple routine to write naturally, but for clarity of code I would prefer to write it as a function.
I know the typical way of writing a function is as follows
Heading type
function my_func(my_arg : my_arg_type) return return_type;
Body type
function my_func(my_arg : my_arg_type) return return_type is
However, if I am not interested in returning anything is there a way to avoid the critical warning -
return type is not specified
No. But, you could use a procedure instead:
procedure my_func (my_arg : my_arg_type) is
You can put a procedure in a package:
package P is
procedure my_func (my_arg : my_arg_type);
end package P;
package body P is
procedure my_func (my_arg : my_arg_type) is
begin
// blah blah blah
end procedure my_func;
end package body P;
SystemVerilog has void functions which have no return type, but this can't be done using VHDL.
No. A function must always return a value of a known type.
You should use a procedure instead.

Assigning procedures to variables and calling them in Pascal

I have a small terminal program which displays a menu. I want to have a function which takes the user's input and an array of procedure names and be able to call the procedure the user chose. I know that I could do that using if or case statements in the main program, but I want to make a unit with the above procedure and a couple of other menu functions, and if this was possible, I could make it call arbitrary procedures. Here's more or less how I would like it to work (I know it's wrong, but so you get a general idea).
program menu;
uses crt;
type procs = array [0..1] of procedure;
procedure call_procs(inp: int; procsy: procs);
begin
writeln(procsy[ord(inp)]); {And call it here.}
end;
var procsx : procs;
begin
procsx[0] := readkey; {I would like to somehow store the procedure here.}
procsx[1] := clrscr;
call_procs(0, procsx);
end.
Is there any way to do something like this? Thank you in advance.
There are a few things wrong with your original code which are not cited in your answer.
You have an array of procedure but you are calling writeln with these procedure calls as arguments as if they were function, which they are not.
readkey is a function, not a procedure, so its type doesn't match the element type of your array
Your assignment of the procedures to the array need to use # to reference the procedure pointer and not actually call the procedure
Not sure what compiler or options you're using, but int isn't the standard Pascal integer type, rather integer is.
As a niggle, since you're already using the integer index of the array, you don't need to use ord.
So the minimal changes to your code to make it basically work would be:
program menu;
uses crt;
type procs = array [0..1] of procedure;
procedure call_procs(inp: integer; procsy: procs);
begin
procsy[inp]; { call the procedure here - removed 'ord' since it's superfluous }
end;
var procsx : procs;
begin
{ procsx[0] := readkey; {- 'readkey' is a function and won't work here }
procsx[1] := #clrscr;
call_procs(1, procsx);
end.
You can create an array of functions that return char which matches the type for readkey:
program menu;
uses crt;
type procs = array [0..1] of function: char;
procedure call_procs(inp: integer; procsy: procs);
begin
writeln(procsy[inp]); { call the function; write out the returned char }
end;
function foo: char;
begin
foo := 'X';
end;
var procsx : procs;
begin
procsx[0] := #readkey;
procsx[1] := #foo;
call_procs(0, procsx);
call_procs(1, procsx);
end.
I figured out how to do this. One can use pointers to a procedure, then create an array of those pointers, and pass them to the procedure I wanted to use. Also, for some reason, it doesn't seem to work with the functions that come with Pascal (such as readkey or clrscr). For this example, one could do this:
program menu;
type
Tprocptr = procedure; {This creates a pointer to procedures.}
Tprocarray = array of Tprocptr;
procedure writeHi;
begin
writeln('Hi!');
end;
procedure writeHello;
begin
writeln('Hello!');
end;
procedure call_proc(inp: integer; procsy: Tprocarray);
{This now calls functions like one would expect.}
begin
procsy[ord(inp)];
end;
var
proclist : Tprocarray;
begin
setlength(proclist, 2);
proclist[0] := #writeHi; {The '#' creates a pointer to those procedures.}
proclist[1] := #writeHello;
call_proc(0, proclist);
end.
This works as expected, calling (in this case) the procedure writeHi, so if you run this program it will output Hi! to the terminal. If you change call_proc(0,proclist) to call_proc(1, proclist), it will call writeHello instead.

Why doesn't calling a function with identical signatures in different units result in compiler error?

Why doesn't this code result in a compiler error? I would have expected error for example 'ambiguous call to "CallMe"'. Is this a bug in the compiler or in the language? This can worked around by using the unit name and a dot in front of the function call but this not shield user code and library code against name collisions. You think that your code did something but it did something else and that's bad.
uses
Unit2, Unit3;
{$R *.lfm}
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(IntToStr(CallMe(5)));
end;
unit Unit2;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
function CallMe(A: Integer) : Integer;
implementation
function CallMe(A: Integer) : Integer;
begin
Result := A * 2;
end;
end.
unit Unit3;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
function CallMe(A: Integer) : Integer;
implementation
function CallMe(A: Integer) : Integer;
begin
Result := A * -1;
end;
end.
From documentation:
If two units declare a variable, constant, type, procedure, or function with the same name, the compiler uses the one from the unit listed last in the uses clause. (To access the identifier from the other unit, you would have to add a qualifier: UnitName.Identifier.)
As said it is by design, the compiler loads symbols from units using a stack based approach, and parses through the stack from last loaded to first loaded to search for a symbol. Preprocessor state is directly merged into the global state though.
Cross unit overloading is an exception though. If you mark both functions with overload; directive, you get an error (bla was the name of the function in the test)
[dcc32 Error] test.dpr: E2251 Ambiguous overloaded call to 'bla'
Unit1.pas(8): Related method: procedure bla;
Unit2.pas(8): Related method: procedure bla;
if you have two different signatures, it will select the best matching one.
cross overloading is a newer feature, but I don't remember exactly when. My guess is D2006.

Why can't I call a function in a constant declaration, that is defined in the same package in ModelSim?

I have a VHDL package that defines a function (forward declaration) and a constant. The constant's value is calculated by that function, whose body is located in the package body.
As of now ModelSim/QuestaSim is the only tool that does not like this code. It needs 2 packages so the body was parsed before the constant declaration.
package test is
function mytest(param : boolean ) return boolean;
constant value : boolean := mytest(TRUE);
end package;
package body test is
function mytest(param : boolean ) return boolean is
begin
return not param;
end function;
end package body;
Is this not allowed in VHDL and other tools use relaxed parsing rules, or is that a ModelSim issue?
With a deferred constant, and assign in package body after mytest function is elaborated, it is possible even in ModelSim:
package test is
function mytest(param : boolean ) return boolean;
constant value : boolean;
end package;
package body test is
function mytest(param : boolean ) return boolean is
begin
return not param;
end function;
constant value : boolean := mytest(TRUE);
end package body;
Handling across different tools appears to be inconsistent, since as you notice ModelSim requires the deferred constant, but Altera Quartus II allows assign of constant before function elaboration, thus without deferred constant.
The VHDL-2008 standards covers subprogram elaboration in:
14.4.2.1 General: ..., it is illegal to call a subprogram before its corresponding body is elaborated.
Effect of subprogram body elaboration is described in:
14.4.2.2 Subprogram declarations, bodies, and instantiations: ... Elaboration of a subprogram body, other than the subprogram body of an uninstantiated subprogram, has no effect other than to establish that the body can, from then on, be used for the execution of calls of the
subprogram.
Alternative way is to suppress this warning by inserting the following lines into modelsim.ini file:
[msg_system]
; Downgrade the following error:
; Error (suppressible): (vcom-1594) Cannot call subprogram before it is elaborated.
; See more on: https://stackoverflow.com/a/29764446/2506522
warning = 1594

Resources