Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2014-02

Incomplete docs on operator precedence / Question about actual precedence

28 messages · 8 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Martin Frb

http://www.freepascal.org/docs-html/ref/refch12.html#x120-13000012

lists

Show quoted text 13 lines
Table 12.1: Precedence of operators Operator Precedence Category ------------------------------------------------------------------------ ------------------------------------------------------------------------ ------------------------------------------------------------------------ Not, @ Highest (first) Unary operators * / div mod and shl shr as << >> Second Multiplying operators + - or xor Third Adding operators = < > <= >= in is Lowest (Last) relational operators

This does not include:
^ deref
- unary minus
. accessing a member of a class/record (not unary)

Assuming they are in the "Highest" group, then they have same precedence as "@".
In an expression containing a mix, I would assume a left to right order.

However this does not compile (project1.lpr(6,10) Error: Illegal qualifier)
   {$T+}  var i: integer
   if @i^ = 0 then ;

If left to right had taken place, then the above would be equal to

   if (@i)^ = 0 then ;

And that compiles.

So it appears that ^ takes precedence over @ ? Or is this a bug?

It also appears that the "." takes precedence over @ @Object.Foo
is equal to
@(Object.Foo)
well otherwise it could not compile

Reply by email

Martin Frb
to Martin Frb
Martin Frb wrote 22 lines
http://www.freepascal.org/docs-html/ref/refch12.html#x120-13000012 lists > Table 12.1: Precedence of operators > > Operator Precedence Category > ------------------------------------------------------------------------ > > ------------------------------------------------------------------------ > > ------------------------------------------------------------------------ > Not, @ Highest (first) Unary operators > * / div mod and shl shr as << >> Second Multiplying operators > + - or xor Third Adding operators > = < > <= >= in is Lowest (Last) relational operators > This does not include: ^ deref - unary minus . accessing a member of a class/record (not unary)

Further, it appears that ^ has a higher precedence than unary -

program Project1;
operator - (a: PInteger) b: PInteger;
begin
   b := PInteger(-Integer(a));
end;
var
   p: PInteger;
   i: Integer;
begin
   i:= 99;
   ;
//  p:= ;   // if enabled, next line will crash
   writeln( -p^ ); // writes -99
   readln;
end.

Reply by email

Hans-Peter Diettrich
to Martin Frb: Further, it appears that ^ has a higher precedence than unary - program Project1;…
Further, it appears that ^ has a higher precedence than unary -

IMO pointer/address arithmetic (should) follows its own rules. Unary - and @ should not be applicable to addresses. @ also is restricted to arguments which *do* have an address, i.e. not applicable to arithmetic expressions or properties.

Applicable binary operators depend on the type of both arguments, e.g. it's valid to subtract addresses (yielding an ordinal value), but adding addresses should be disallowed, while adding an ordinal value to an pointer is okay (yealding another address).

// p:= ; // if enabled, next line will crash

This should not compile, unary - is not applicable to addresses.

writeln( -p^ ); // writes -99

Here ^ must take precedence, applied to an pointer/address.

"p+i^" is questionable, the only valid interpretation is (p+i)^.

IOW applicable operators and precedence depend on the type of the argument(s).

DoDi

Reply by email

Sven Barth
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote
> // p:= ; // if enabled, next line will crash This should not compile, unary - is not applicable to addresses.

It compiles, because Martin has defined a operator overload for PInteger (look at his code). And as long as no internal operator is defined (as you said: unary minus is not defined for pointers) the compiler will allow that overload.

Regards,
Sven

Reply by email

Sven Barth
to Michael Van Canneyt: To my knowledge, the . and ^ are not considered operators, they are "part of the…
Michael Van Canneyt wrote
As for unary minus: this is the same as a binary minus in arithmatic expressions.

Not quite. Take this example:

=== code begin ===

program toppriotest;
{$mode objfpc}
{$modeswitch advancedrecords}
type
   TTest = record
     i: Longint;
     class operator * (aLeft, aRight: TTest): TTest;
     class operator - (aOther: TTest): TTest;
     class operator - (aLeft, aRight: TTest): TTest;
   end;
class operator TTest. * (aLeft, aRight: TTest): TTest;
begin
   Writeln(aLeft.i, ' * ', aRight.i);
   Result.i := aLeft.i * aRight.i;
end;
class operator TTest. - (aOther: TTest): TTest;
begin
   Writeln('- ', aOther.i);
   Result.i := - aOther.i;
end;
class operator TTest. - (aLeft, aRight: TTest): TTest;
begin
   Writeln(aLeft.i, ' - ', aRight.i);
   Result.i := aLeft.i - aRight.i;
end;
var
   t1, t2: TTest;
begin
   t1.i := 42;
   t2.i := 21;
   Writeln((-t1).i);
   Writeln((t1 * t2).i);
   Writeln((t1 - t2).i);
   Writeln((t1 * -t2).i);
   Writeln((-t1 * t2).i);
   Writeln((t1 - t2 * -t1).i);
   Writeln((t1 - -t2).i);
   Readln;
end.

=== code end ===

Will result in this output:

=== output begin ===

- 42
-42
42 * 21
882
42 - 21
21
- 21
42 * -21
-882
- 42
-42 * 21
-882
- 42
21 * -42
42 - -882
924
- 21
42 - -21
63

=== output end ===

So unary minus (and also unary plus which is a valid operator as well!) binds stronger than multiplication.

Regards,
Sven

Reply by email

Michael Van Canneyt
to Sven Barth
Sven Barth wrote 9 lines
Am 03.02.2014 08:58, schrieb Michael Van Canneyt: > As for unary minus: this is the same as a binary minus in arithmatic > expressions. Not quite. Take this example: === output end === So unary minus (and also unary plus which is a valid operator as well!) binds stronger than multiplication.

Then that is an anomaly introduced by operator overloading.

In math, -2^2 = -4

Michael.

Reply by email

Sven Barth
to Michael Van Canneyt
Michael Van Canneyt wrote 17 lines
On Mon, 3 Feb 2014, Sven Barth wrote: > Am 03.02.2014 08:58, schrieb Michael Van Canneyt: >> As for unary minus: this is the same as a binary minus in arithmatic >> expressions. > > Not quite. Take this example: > === output end === > > So unary minus (and also unary plus which is a valid operator as > well!) binds stronger than multiplication. Then that is an anomaly introduced by operator overloading. In math, -2^2 = -4

Yes and the same is true in FPC with operator overloading. If you add a ** operator overload (which uses Trunc(Power(aLeft.i, aRight.i)) ) and have this expression: -t1 ** t2 with t1.i = 2 and t2.i = 2 the result will be -4 as well.

Please keep in mind that -2^2 is (-2) * (-2).

Regards,
Sven

Reply by email

Michael Van Canneyt
to Sven Barth
Sven Barth wrote 24 lines
Am 03.02.2014 12:04, schrieb Michael Van Canneyt: > > > On Mon, 3 Feb 2014, Sven Barth wrote: > >> Am 03.02.2014 08:58, schrieb Michael Van Canneyt: >>> As for unary minus: this is the same as a binary minus in arithmatic >>> expressions. >> >> Not quite. Take this example: >> === output end === >> >> So unary minus (and also unary plus which is a valid operator as well!) >> binds stronger than multiplication. > > Then that is an anomaly introduced by operator overloading. > > In math, -2^2 = -4 Yes and the same is true in FPC with operator overloading. If you add a ** operator overload (which uses Trunc(Power(aLeft.i, aRight.i)) ) and have this expression: -t1 ** t2 with t1.i = 2 and t2.i = 2 the result will be -4 as well. Please keep in mind that -2^2 is (-2) * (-2).

? Not in math:

-2^2 = - (2^2)

Michael.

Reply by email

Tomas Hajny
to Sven Barth: Yes and the same is true in FPC with operator overloading. If you add a ** operator…
Sven Barth wrote 21 lines
Am 03.02.2014 12:04, schrieb Michael Van Canneyt: > On Mon, 3 Feb 2014, Sven Barth wrote: >> Am 03.02.2014 08:58, schrieb Michael Van Canneyt: >>> As for unary minus: this is the same as a binary minus in arithmatic >>> expressions. >> >> Not quite. Take this example: >> === output end === >> >> So unary minus (and also unary plus which is a valid operator as >> well!) binds stronger than multiplication. > > Then that is an anomaly introduced by operator overloading. > > In math, -2^2 = -4 Yes and the same is true in FPC with operator overloading. If you add a ** operator overload (which uses Trunc(Power(aLeft.i, aRight.i)) ) and have this expression: -t1 ** t2 with t1.i = 2 and t2.i = 2 the result will be -4 as well. Please keep in mind that -2^2 is (-2) * (-2).

? -2^2 = -(2^2) = -4 (-2)*(-2) ?

Also in FPC:
---
uses
Math;
begin
WriteLn (-2**2);
end.
===
...gives "-4".

Tomas

Reply by email

Michael Van Canneyt
to Tomas Hajny
Tomas Hajny wrote 34 lines
On Mon, February 3, 2014 12:10, Sven Barth wrote: > Am 03.02.2014 12:04, schrieb Michael Van Canneyt: >> On Mon, 3 Feb 2014, Sven Barth wrote: >>> Am 03.02.2014 08:58, schrieb Michael Van Canneyt: >>>> As for unary minus: this is the same as a binary minus in arithmatic >>>> expressions. >>> >>> Not quite. Take this example: >>> === output end === >>> >>> So unary minus (and also unary plus which is a valid operator as >>> well!) binds stronger than multiplication. >> >> Then that is an anomaly introduced by operator overloading. >> >> In math, -2^2 = -4 > Yes and the same is true in FPC with operator overloading. If you add a > ** operator overload (which uses Trunc(Power(aLeft.i, aRight.i)) ) and > have this expression: -t1 ** t2 with t1.i = 2 and t2.i = 2 the result > will be -4 as well. > > Please keep in mind that -2^2 is (-2) * (-2). ? -2^2 = -(2^2) = -4 (-2)*(-2) ? Also in FPC: --- uses Math; begin WriteLn (-2**2); end. === ...gives "-4".

I was already wondering whether all my education had gone for naught :D

Michael.

Reply by email

Martin Frb
to Michael Van Canneyt: To my knowledge, the . and ^ are not considered operators, they are "part of the…
Michael Van Canneyt wrote 11 lines
On Mon, 3 Feb 2014, Martin Frb wrote: > This does not include: > ^ deref > - unary minus > . accessing a member of a class/record (not unary) To my knowledge, the . and ^ are not considered operators, they are "part of the identifier".

Ok, so they are evaluated before everything else.

Curious though (I can see that the "." is not an operator (it was not what got me started anyway), but the ^ ?
It is the same kind (just reverse) of the @, so why is one an operator, and the other not?

The reason I did get to that, is because I have to reproduce the behaviour (for fpdebug).
And when scanning/evaluating a pascal expression/statement, it works well to handle the "." (and also []()^) as operator. So that is haw the "." ended on the list.

Reply by email

Michael Van Canneyt
to Martin Frb
Martin Frb wrote 19 lines
On 03/02/2014 07:58, Michael Van Canneyt wrote: > > > On Mon, 3 Feb 2014, Martin Frb wrote: > >> This does not include: >> ^ deref >> - unary minus >> . accessing a member of a class/record (not unary) > > To my knowledge, the . and ^ are not considered operators, they are "part > of the identifier". Ok, so they are evaluated before everything else. Curious though (I can see that the "." is not an operator (it was not what got me started anyway), but the ^ ? It is the same kind (just reverse) of the @, so why is one an operator, and the other not?

There is a substantial difference in semantics:
You can take the address of anything.
But you cannot dereference anything except a pointer.

If it was up to me, @ would not have been in the operator list either, but Borland considered it so...

Michael.

Reply by email

Jonas Maebe
to Martin Frb: Ok, so they are evaluated before everything else. Curious though (I can see that the "."…
Martin Frb wrote 5 lines
The reason I did get to that, is because I have to reproduce the behaviour (for fpdebug). And when scanning/evaluating a pascal expression/statement, it works well to handle the "." (and also []()^) as operator. So that is haw the "." ended on the list.

Can't you use fcl-passrc (http://wiki.freepascal.org/fcl-passrc ) instead of scanning/parsing everything yourself? Or does it only support complete source files?

Jonas

Reply by email

Martin Frb
to Sven Barth: Not quite. Take this example: === code begin === program toppriotest; {$mode objfpc}…
Sven Barth wrote
So unary minus (and also unary plus which is a valid operator as well!) binds stronger than multiplication.

Just using -al

c := -a *b;
c := (-a) *b;
c := -(a *b);

The unary - is applied first. Though it makes no difference to the result.

However with the overloaded operators, it may make a difference....

# [22] c := -a *b;
movl U_P$PROJECT1_A,%eax
negl %eax
movl U_P$PROJECT1_B,%edx
imull %edx,%eax
movl %eax,U_P$PROJECT1_C
.Ll8:
# [23] c := (-a) *b;
movl U_P$PROJECT1_A,%eax
negl %eax
movl U_P$PROJECT1_B,%edx
imull %edx,%eax
movl %eax,U_P$PROJECT1_C
.Ll9:
# [24] c := -(a *b);
movl U_P$PROJECT1_A,%eax
movl U_P$PROJECT1_B,%edx
imull %edx,%eax
negl %eax
movl %eax,U_P$PROJECT1_C

Reply by email

Martin Frb
to Jonas Maebe: Can't you use fcl-passrc (http://wiki.freepascal.org/fcl-passrc ) instead of…
Jonas Maebe wrote 13 lines
On 03 Feb 2014, at 14:28, Martin Frb wrote: > The reason I did get to that, is because I have to reproduce the > behaviour (for fpdebug). > And when scanning/evaluating a pascal expression/statement, it works > well to handle the "." (and also []()^) as operator. So that is haw > the "." ended on the list. Can't you use fcl-passrc (http://wiki.freepascal.org/fcl-passrc ) instead of scanning/parsing everything yourself? Or does it only support complete source files?

The example only shows how to parse a full file.

All I need is to parse any of the following
SomeValue
SomeType
SomeFoo + Bar[1]
Bar(Abc).xyz^ // Bar may be a class, or a function

At the time of parsing nothing else is known, the types / values can be looked up during parsing.

This are only right hand site expressions. This are NOT full pascal statements (since the result := part is not there) They may result in a value, or a type. (or be invalid)

I already have the parser (that part was rather simple). And it returns a structure of objects, that can deal with the rest of the work (getting type/value and evaluate).

Reply by email

Martin Frb
to Martin Frb
Martin Frb wrote 22 lines
On 03/02/2014 13:47, Jonas Maebe wrote: > > On 03 Feb 2014, at 14:28, Martin Frb wrote: > >> The reason I did get to that, is because I have to reproduce the >> behaviour (for fpdebug). >> And when scanning/evaluating a pascal expression/statement, it works >> well to handle the "." (and also []()^) as operator. So that is haw >> the "." ended on the list. > > Can't you use fcl-passrc (http://wiki.freepascal.org/fcl-passrc ) > instead of scanning/parsing everything yourself? Or does it only > support complete source files? > The example only shows how to parse a full file. All I need is to parse any of the following SomeValue SomeType SomeFoo + Bar[1] Bar(Abc).xyz^ // Bar may be a class, or a function

Also on top of that, I need the ability to parse "none pascal" add ons (so they can never conflict with any identifier)
%EAX + 1

Reply by email

Sven Barth
to Michael Van Canneyt: ? Not in math: -2^2 = - (2^2) Michael.
Michael Van Canneyt wrote 32 lines
On Mon, 3 Feb 2014, Sven Barth wrote: > Am 03.02.2014 12:04, schrieb Michael Van Canneyt: >> >> >> On Mon, 3 Feb 2014, Sven Barth wrote: >> >>> Am 03.02.2014 08:58, schrieb Michael Van Canneyt: >>>> As for unary minus: this is the same as a binary minus in >>>> arithmatic expressions. >>> >>> Not quite. Take this example: >>> === output end === >>> >>> So unary minus (and also unary plus which is a valid operator as >>> well!) binds stronger than multiplication. >> >> Then that is an anomaly introduced by operator overloading. >> >> In math, -2^2 = -4 > Yes and the same is true in FPC with operator overloading. If you add > a ** operator overload (which uses Trunc(Power(aLeft.i, aRight.i)) ) > and have this expression: -t1 ** t2 with t1.i = 2 and t2.i = 2 the > result will be -4 as well. > > Please keep in mind that -2^2 is (-2) * (-2). ? Not in math: -2^2 = - (2^2)

Eh, yes, sorry. It should have been - (2 * 2) of course *blush*

Nevertheless FPC provides the correct operator precedence (no matter whether overloading is used or not, because that is done at a different level of the parser):
- power
- unary plus/minus
- product/divison
- addition/substraction

Regards,
Sven

Reply by email

Sven Barth
to Martin Frb: Just using -al c := -a *b; c := (-a) *b; c := -(a *b); The unary - is applied first.…
Martin Frb wrote 15 lines
On 03/02/2014 10:48, Sven Barth wrote: > > So unary minus (and also unary plus which is a valid operator as > well!) binds stronger than multiplication. Just using -al c := -a *b; c := (-a) *b; c := -(a *b); The unary - is applied first. Though it makes no difference to the result. However with the overloaded operators, it may make a difference....

FPC uses the unary operator first as the parsing of operators is done at a different part than the resolution to overloaded operators. Only exception is mode ISO (or more precisely modeswitch ISOLikeUnaryMinus) where the unary operator has the same precedence as the binary one (don't know though whether the unary plus is respected here as well...)

Regards,
Sven

Reply by email

Martin Frb
to Sven Barth: Eh, yes, sorry. It should have been - (2 * 2) of course *blush* Nevertheless FPC provides…
Michael Van Canneyt wrote
As for unary minus: this is the same as a binary minus in arithmatic expressions.
Sven Barth wrote 7 lines
Nevertheless FPC provides the correct operator precedence (no matter whether overloading is used or not, because that is done at a different level of the parser): - power - unary plus/minus - product/divison - addition/substraction

Sven's explanation seems to fit the current implementation.

Is that also the intended result (mode fpc).

And should that be added to the docs?

Michael Van Canneyt wrote
To my knowledge, the . and ^ are not considered operators, they are "part of the identifier".

Only doc I found on it is:
http://www.freepascal.org/docs-html/ref/refse15.html#x46-530003.4

It does not state if or if not it is an operator. And also give no indication on its precedence, or if it is applied before or after operators.

This is not so much about he -a^ (which is a (very) constructed case), but about @a^ which is possible (not doing much so)

So if {$T-}
a : pinteger;
@a^ gives an untyped pointer (same as "pointer(a)" ? / but shorter) But only because it is @(a^) and not (@a)^ . The second would only compile wit {$T+}

Reply by email

Dmitry Boyarintsev
to Martin Frb
Martin Frb wrote 12 lines
It does not state if or if not it is an operator. And also give no indication on its precedence, or if it is applied before or after operators. This is not so much about he -a^ (which is a (very) constructed case), but about @a^ which is possible (not doing much so) So if {$T-} a : pinteger; @a^ gives an untyped pointer (same as "pointer(a)" ? / but shorter) But only because it is @(a^) and not (@a)^ . The second would only compile wit {$T+}

Both still both expressions are parsed the same (not if $T is enabled or not).
If you treat ^ as a part of identified, you'll be able to parse the expression.

thanks,
Dmitry

Reply by email

Martin Frb
to Dmitry Boyarintsev
Dmitry Boyarintsev wrote 21 lines
On Mon, Feb 3, 2014 at 10:25 AM, Martin Frb < > wrote: It does not state if or if not it is an operator. And also give no indication on its precedence, or if it is applied before or after operators. This is not so much about he -a^ (which is a (very) constructed case), but about @a^ which is possible (not doing much so) So if {$T-} a : pinteger; @a^ gives an untyped pointer (same as "pointer(a)" ? / but shorter) But only because it is @(a^) and not (@a)^ . The second would only compile wit {$T+} Both still both expressions are parsed the same (not if $T is enabled or not). If you treat ^ as a part of identified, you'll be able to parse the expression.

Parsed yes, but if it comes to evaluation, then you get {$T-} (@a)^ "cant dereference an untyped pointer" or similar

@a^ always works. All I was asking is if the documentation should state it more clearly that ^ is (As part of the identifier) done before ^

Being picky:
http://www.freepascal.org/docs-html/ref/refse15.html#x46-530003.4

Show quoted text 5 lines
The expression BP^ is known as the dereferencing of BP. The result is of type Buffer

If "BP^" is a single identifier, then where in this expression is the action coming from? ("dereferencing" describes an action) Also "result" used for a single identifier seems strange. (so that is correct)

If on the other hand BP is the operator, and ^ is added to the operator (becoming a part of it), then what is ^ on its own? (more specific, than a token, please)

Reply by email

Martin Frb
to Martin Frb
Martin Frb wrote
@a^ always works. All I was asking is if the documentation should state it more clearly that ^ is (As part of the identifier) done before ^

done before @

of course.

For the rest, I am happy, never mind, if it is an operator or not.

Reply by email

Dmitry Boyarintsev
to Martin Frb: Parsed yes, but if it comes to evaluation, then you get {$T-} (@a)^ "cant dereference an…
Martin Frb wrote 6 lines
Parsed yes, but if it comes to evaluation, then you get {$T-} (@a)^ "cant dereference an untyped pointer" or similar @a^ always works. All I was asking is if the documentation should state it more clearly that ^ is (As part of the identifier) done before ^

(debugger) evaluation is different from the compilation. Compiled units doesn't contain the information about compiler directives used (..or are they in .ppu?)

If one unit is compiled with $T+ and another with $T- would you make the evaluator unit specific? I doubt that.
Despite of $T there are many syntax difference for each $mode using in FPC. And each unit might be using it's own {$mode}.

I'm assuming you'll need just assume some set of the directives for your evaluator (i.e. it's always in $mode delphi, and always $T+)

thanks,
Dmitry

Reply by email

Martin Frb
to Martin Frb: Sven's explanation seems to fit the current implementation. Is that also the intended…
Martin Frb wrote 9 lines
On 03/02/2014 14:37, Sven Barth wrote: > Nevertheless FPC provides the correct operator precedence (no matter > whether overloading is used or not, because that is done at a > different level of the parser): > - power > - unary plus/minus > - product/divison > - addition/substraction

By the way, where does ** stand against @ ? ("**" is not in the precedence table on the docs)

@invalue**2

Besides, that this again is not possible (except overloaded) because it is either
pinteger**2
@(expression result has no address)

But
1) For which error should it go
2) on overload, what would it do?

Reply by email

Sven Barth
to Martin Frb
Martin Frb wrote 13 lines
On 03/02/2014 15:25, Martin Frb wrote: > On 03/02/2014 14:37, Sven Barth wrote: >> Nevertheless FPC provides the correct operator precedence (no matter >> whether overloading is used or not, because that is done at a >> different level of the parser): >> - power >> - unary plus/minus >> - product/divison >> - addition/substraction > By the way, where does ** stand against @ ? ("**" is not in the precedence table on the docs)

@ always binds stronger than any arithmetic, set, whatever operators (in the compiler it's implemented as expecting a single factor (maybe with round brackets), so "@(x - y)" (or any other operator) should not work either no matter what overloads are available (again, parsing and resolving operators are different steps)).

Regards,
Sven

Reply by email