I am trying to see how to test short circuit evaluation in Pascal but not sure if doing it correctly. This is what I have so far.
program shortcircuit;
var
{ local variable definition }
a : integer;
b : integer;
begin
a := 8;
b := 0;
if( (b <> 0) and (a / b) ) then
(* if condition is true then print the following *)
writeln('...' )
end.
It is unclear what your question is, but you should try to provide a program that actually compiles before posting. This will help you answer your own questions.
The first problem you have is that Pascal has no concept of automatically convert to boolean that many C-derived languages do. You must test the inequity with zero explicitly.
I would also add an else clause to print when your test works successfully.
var
{ local variable definition }
a : integer;
b : integer;
begin
a := 8;
b := 0;
if( (b <> 0) and ((a / b) <> 0.0) ) then
(* if condition is true then print the following *)
writeln('fooey' )
else writeln('short circuited')
end.
http://tpcg.io/_HUNS7P
It is possible, should you make some minor modifications to the LHS of the and expression, that the compiler will notice you are hard-coding an attempt to divide by zero and complain.
Finally, Pascal always does short-circuit evaluation by default. You can disable it with a compiler directive, but that is always The Wrong Thing To Do.
For your example (avoiding a divide by zero error), the code will do the correct thing by default.
if (b <> 0) and some_predicate_function( a / b ) then ...
Though if you are just doing a checked divide, you could just make yourself a useful function that defaults to an acceptable value:
function checked_divide( a,b:integer; fooey:double = 0.0 ) : double;
begin
if b <> 0
then result := a / b
else result := fooey
end;
The notion of short-circuit evaluation is not part of the language:
Boolean expressions have the property that their value may be known before the entire expression has been evaluated.
Assume for example, that X = 0.
Then the value of the expression
(x > 0) and (X < 10)
is already known to be false after computation of the first factor, and the second need not be evaluated.
Whether or not the second factor is evaluated is implementation-dependent.
This means that you must assure that the second factor is well defined, independent of the value of the first factor.
[…]
Source:
Jensen, Kathleen; Wirth, Niklaus.
Pascal – user manual and report (4th revised ed.).
p. 32.
doi:10.1007/978‑1‑4612‑4450‑9.
ISBN 978‑0‑387‑97649‑5.
Therefore, you need to consult your compiler’s documentation.
Delphi and the FreePascal Compiler have the {$B+}/{$boolEval on} and {$B‑}/{$boolEval off} (default) compiler directives, disabling and enabling short-circuit evaluation respectively.
The GNU Pascal Compiler recognizes {$B+}/{$B‑} too, plus {$short‑circuit}/{$no‑short‑circuit}.
However, the default is not to guarantee either, I don’t know, maybe for some SIMD optimizations.
Pascal “likes” writing things out.
Because, or if this implementation-dependence is dissatisfying or unwanted, the ISO standard 10206 “Extended Pascal” introduces two other Boolean operators:
A primary, a factor, a term, or a simple‑expression shall be designated an operand.
Except for the and_then and or_else operators, the order of evaluation of the operands of a dyadic operator shall be implementation-dependent.
NOTE —
This means, for example, that the operands may be evaluated in textual order, or in reverse order, or in parallel, or they may not both be evaluated.
6.8.3.3 Boolean operators
[…]
In a term of the form A and_then B, the right operand shall be evaluated if and only if the left operand denotes the value true;
the term shall denote the value false if the left operand denotes the value false;
otherwise, the term shall denote the value denoted by the right operand.
In a simple‑expression of the form A or_else B, the right operand shall be evaluated if and only if the left operand denotes the values false;
the simple-expression shall denote the value true if the left operand denotes the value true;
otherwise, the simple-expression denotes the value denoted by the right operand.
Unfortunately, of the previously mentioned compilers only the GNU Pascal Compiler supports and_then/or_else.
Generally speaking, if you want “short-circuit evaluation”, you have to write it out in Pascal (e. g. a nested if in lieu of and_then).
Experimentally determining your compiler’s behavior.
I am trying to see how to test short circuit evaluation in Pascal but not sure if doing it correctly.
A test design would use Boolean functions with side-effects, particularly writeLns, like so:
program shortCircuitTest(output);
function A: Boolean;
begin
writeLn('A');
A := false;
end;
function B: Boolean;
begin
writeLn('B');
B := true;
end;
{ === MAIN ========= }
begin
if A and B then
begin
writeLn('then branch');
end
else
begin
writeLn('else branch');
end;
end.
However, this is only an indicator.
You really need to consult your compiler’s documentation to know the details.
Related
In pascal programming language i wrote the following code
Program practice;
//**** Function to get back N characters from a P position from a given string
Function get_char(s1:String;n,p :Integer): String;
Var
temp : String;
i : Integer;
Begin
temp:= s1[p];
For i:= p+1 To p+n-1 Do
temp := temp + s1[i];
get_char := temp;
End;
//**** end of the function *****
Var
s1,s2: String;
n,p: Integer;
Begin
Write('Enter the number of char:');
readln(n);
write('Enter the position:' );
readln(p);
write('Enter the string : ');
readln(s1);
write(get_char(s1,n,p));
Readkey;
End.
Know that this function gets back a certain number of characters given by the user from a certain postion in the string .
for example 'hello' with p = 1 and n =2 the result will be 'he' .
Now imagine p is 3 and n =4 then then the output of the function will be 'lloA'.
So my question is what happends in this case or why do we get such a result ? ( please give me details if its related to memory).
When your function reads characters beyond the end of the string, it reads memory content that happens to be in those memory positions, and interpretes that memory content as characters. Memory content beyond the length of a string is not defined, nor predictable. Some compilers add an explicit Char(0) as a terminating character. This zero character is not included in the length of the string.
To prevent wrong return values form your function, you can either,
a) turn range checking on in compiler settings, which will raise runtime errors
b) check that p + n - 1 <= Length(s) and if not, limit reading to Length(s).
Selecting option b gives a freedom to read until the end of any string by passing MaxInt for argument p.
I am seeking help as I am learning this language construct.
Here is what I have:
function int_slv(val,width: integer) return std_logic_vector is
variable R: std_logic_vector(0 to width-1):=(others=>'0')
variable b:integer:= width;
begin
if (b>32) then
b=32;
else
assert 2**bits >val report
"value too big for std_logic_vector"
severity warning
end if;
for i in 0 to b-1 loop
if val ((val/(2**i)) MOD 2 = 1) then
R(i)='1';
end if;
end loop;
return(R);
end int_slv;
In addition to 5 syntax errors, one wrong identifier and a modulo reduction expressions expressed as an element of an array as well as several sets of redundant parentheses, your modified code:
library ieee;
use ieee.std_logic_1164.all;
package int2bv_pkg is
function int_slv (val, width: integer) return std_logic_vector;
end package;
package body int2bv_pkg is
function int_slv (val, width: integer) return std_logic_vector is
variable R: std_logic_vector(0 to width-1):=(others=>'0'); -- added ';'
variable b:integer:= width;
begin
if b > 32 then
b := 32; -- ":=" is used for variable assignment
else
assert 2 ** width > val report -- width not bits
"value too big for std_logic_vector"
severity warning; -- missing semicolon at the end of assertion
end if;
for i in 0 to b - 1 loop
if val/2 ** i MOD 2 = 1 then -- not val (...)
R(i) := '1'; -- ":=" variable assign.
end if;
end loop;
return R; -- parentheses not needed
end int_slv;
end package body int2bv_pkg;
analyzes (compiles). The exponentiation operator "**" is the highest priority, the division operators "/" and "mod" are the same priority and executed in the order they are found (left to right). It's likely worthwhile learning VHDL operator precedence.
You were using "=" for variable assignment when you should have been using ":=" in two places, you were missing two semicolons and were using the identifier bits (which isn't declared in your function) where apparently you meant width.
The modified example analyzes, and hasn't been tested absent a Minimal, Complete and Verifiable example in the question.
Note that a package body is a design unit as is a package declaration. There are various other places in other design units you can introduce a function body.
You could also note the 2 ** 31 is outside the guaranteed range of an integer in VHDL equal to 2147483648, while the INTEGER value range guaranteed to be from -2147483647 to +2147483647 at a minimum.
This implies that were ever you are using a value that derived from an expression equivalent to 2 ** 31 you can incur a range error during execution (either at elaboration or during simulation).
This pretty much says you need a VHDL implementation with a larger INTEGER value range or you need to rethink what you're doing.
As a matter of course there are integer to unsigned and integer to signed functions found in package numeric_std in library IEEE.
The result of such can be type converted to std_logic_vector, and the source code can make great learning aids on how to wend through the limitations VHDL imposes. These to_signed or to_unsigned functions would be capable of dealing with the maximum value an INTEGER can hold and specify the length of the resulting array type while providing zero or sign filling for array lengths greater than the INTEGER's binary value. That utility extends to clipping using length as well.
VHDL -2008 package numeric_std_unsigned contains a function To_StdLogicVector that does what your int_slv function is intended to do although limited to a NATURAL range for the integer type input.
As #user1155120 has already indicated, the VHDL-2008 package numeric_std_unsigned has a builtin to_stdlogicvector. And #user1155120 already pointed out the to_signed and to_unsigned in numeric_std are available as well.
So, to expand on the previous answer, you can do:
constant C : integer := -6817563;
constant C_VEC : std_logic_vector(31 downto 0) := std_logic_vector(to_signed(c, 32));
And this mechanism will accept the full range of integer. You can also use to_unsigned, but this is limited to the range of natural.
The following code, taken from Gnu Pascal test code, will compile nicely in Free Pascal. And I can understand how it works.
var s1 : set of 0..255;
s2 : set of 64..128;
ok : boolean;
procedure p1;
begin
if s1 = s2 then begin
writeln('failed1');
ok := false;
end;
end;
However, I'm slightly curious what the rules are for set compatibility and what you can expect. For example:
program p;
var
a : set of 0..10;
b : set of 20..100;
s : integer;
begin
b := [20];
a := [];
if a = b then
writeln('a')
else
writeln('b');
end.
This prints 'b'. But if I have two empty sets (b := [];) then they are considered equal.
I'm just trying to get my head around how this actually gets implemented.
(What I'm kind of thinking is that the two sets are converted to the union of the ranges, so set of 0..100 are created, and two temporaries from a and b as set of 0..100, and then comparison is done those temporaries).
Sets with integers as base type (the type after the set of) are always compatible.
Your assumption is correct: in general both sets are converted to temporaries with common ranges and then the temporaries are compared. The conversion is done by calls to fpc_varset_load.
If you are interested in more details, the code which decides how to convert the sets, is located in nadd.pas (see 1) starting at line 1593.
The problem
I'm writing a function in a package which converts some values for a testbench. I want to check the if the output exceeds a maximum value, if it does I want to set it to that maximum value. What I tired was the following:
-- vec_in: 0...1023, returns -14...23.5 dB
function conv_dac602_scale (
vec_in : std_logic_vector)
return real is
variable val_in, dB : real := 0.0;
constant lower : real := -14.0;
constant upper : real := 23.5;
begin -- function conv_dac602_scale
val_in := real(to_integer(unsigned(vec_in)));
dB := (lower+(val_in*((upper-lower)/1024.0)));
return dB when dB <= upper else upper; -- this is the important line! (129)
end function conv_dac602_scale;
When I try to compile this I got the following errors:
** Error: myfile.vhd(129): near "when": expecting ';'
** Error: myfile.vhd(260): VHDL Compiler exiting
I then tried assigning it to a variable r first:
...
r := dB when dB <= upper else upper; -- this is the important line! (129)
return r;
end function conv_dac602_scale;
Which did not change the outcome. I know that I can use a simple if/else clause instead, but my question is why I can't use the when clause.
System
Modelsim SE 10.0b, VHDL 2008
The target <= signal when x is a so called concurrent statement, which is designed for easy creation of signal assignments outside a process. You can use it within an architecture, but not inside a process. If and else are designed for sequential statements within a process. In your case, you'll have to use if/else.
Edit:
Seems this only holds true for Vhdl pre 2008. As fru1tbat pointet out, this is valid vhdl 2008 code and the problem is a not supported feature by the Modelsim compiler.
I would reconsider changing the way you call your return, as it looks like your syntax using WHEN is incorrect.
Clarify what you're trying to do with:
return dB when dB <= upper else upper;
That essentially is "return dB when dB is less than or equal to upper, else upper" where upper will not be returned due to the way you make the return statement. You may want to say: ... else return upper
I would prefer an if statement in this case:
if ( dB <= upper) then
return dB;
else
return upper;
end if;
I'm trying to implement the extended euclidean algorithm given in pseudo-code below, in KornShell (ksh).
I am having problems with the lines with ":=" - I don't know what those mean.
I'm also having problems with the multiple return variables.
How can I implement this?
function extended_gcd(a, b)
x := 0 lastx := 1
y := 1 lasty := 0
while b ≠ 0
quotient := a div b
(a, b) := (b, a mod b)
(x, lastx) := (lastx - quotient*x, x)
(y, lasty) := (lasty - quotient*y, y)
return (lastx, lasty)
:= part :
:= is not for shell scripting , for assignments we use simple "=" in scripts ie
var="abcd" ;
:= is available in other tools though , like in make -- where it stands for immediate assignment.
what immediate assignment means is that the variable gets assigned a value the moment its parsed.
there are also other variants available like =? ... etc.
fxn return value part :
its a basic rule that a function can return only a single value.
But iff you are intrested in being able to use multiple variables outside the function body then -- bash/korn/shell in general dont have any specific concept as a local variable .
by default what ever variables you have in a script are global ie available throughout .... but within the scope of the current shell only .
you would need to export the variables to make them available in a child shell.
syntax : export variable_name ;
Also you need to use {} braces to define a function body. ie
fxn_name()
{
var=$1; ## if you want to use a variable
......
....
}
its invokation/call is
fxn_name $arg ;