Spin2 Operator Syntax - Page 8 — Parallax Forums

Spin2 Operator Syntax

• Posts: 2,996
Thinking about it more, I agree about having >> be non-arithmetic in the context of Spin and typical usage there. Also, having SAR/SAL makes it very clear that it's not a normal shift.
I have sometimes wished that C would let you more explicitly do shifts and arithmetic shifts. Usually you have to do some casting to get what you want if it's not the defined behavior.

Chip, re: precedence
As others have said, I don't really think about precedence order beyond the basics for the simple math ops. I typically just put in the ( )'s just so it's very clear.
• Posts: 14,020
edited 2017-04-13 07:54
Keep the Spin precedence order, Chip. I concur with your assessment that C's is a bit off.

Thanks,
-Phil

Phil, thanks for thinking about all this. I know this is a bit of a roller coaster.

All of your guys' input has been really helpful here. I think we've maybe got it nailed now.

My only wish, at this point, is that we could do this, but it really flies in the face of convention:
```>>   rotate right
<<   rotate left
->   shift right
<-   shift left
~>   shift arithmetic right
```

That would have been elegant, but >> and << got used for shift a long time ago, even though, graphically, they are ideal for rotates. And they leave nice solutions for shifts: <-, ->, ~>
• Posts: 10,250
With the change back to logical shifts, I'm good.

• Posts: 10,250
cgracey wrote: »
Keep the Spin precedence order, Chip. I concur with your assessment that C's is a bit off.

Thanks,
-Phil

Phil, thanks for thinking about all this. I know this is a bit of a roller coaster.

All of your guys' input has been really helpful here. I think we've maybe got it nailed now.

My only wish, at this point, is that we could do this, but it really flies in the face of convention:
```>>   rotate right
<<   rotate left
->   shift right
<-   shift left
~>   shift arithmetic right
```

That would have been elegant, but >> and << got used for shift a long time ago, even though, graphically, they are ideal for rotate. And they leave nice solutions for shifts: <-, ->, ~>

I'm not opposed, and it's nice. Agreed. But, I also think this is an opportunity missed too.

IMHO, basically everybody will stumble on >> and friends, if we don't leave them as a simple shift. Gets used all the time.

• Posts: 14,020
I agree, Potatohead. It's just fantasy.
• Posts: 18,066
Roy Eltham wrote: »
Thinking about it more, I agree about having >> be non-arithmetic in the context of Spin and typical usage there. Also, having SAR/SAL makes it very clear that it's not a normal shift.
I have sometimes wished that C would let you more explicitly do shifts and arithmetic shifts. Usually you have to do some casting to get what you want if it's not the defined behavior.

Chip, re: precedence
As others have said, I don't really think about precedence order beyond the basics for the simple math ops. I typically just put in the ( )'s just so it's very clear.
SAL is the usually the same as SHL, and many micros don't include SAL.
From wikipedia
Equivalence of arithmetic left shift and multiplication
Arithmetic left shifts are equivalent to multiplication by a (positive, integral) power of the radix (e.g., a multiplication by a power of 2 for binary numbers). Arithmetic left shifts are, with two exceptions, identical in effect to logical left shifts. Exception one is the minor trap that arithmetic shifts may trigger arithmetic overflow whereas logical shifts do not. Obviously, that exception occurs in real world use cases only if a trigger signal for such an overflow is needed by the design it is used for. Exception two is the MSB is preserved. Processors usually do not offer logical and arithmetic left shift operations with a significant difference, if any.

So, IMHO no need for SAL. Otherwise, totally agreed.
• Posts: 18,066
Chip,
Maybe you could use the following descriptions...
```#>		x #> y		x #>= y		binary signed	9, 16	    Greater/Maximum (limit minimum)/Ensure x => y
<#		x <# y		x <#= y		binary signed	9, 16	    Lesser /Minimum (limit maximum)/Ensure x <= y
```
• Posts: 14,020
edited 2017-04-13 08:28
ersmith wrote: »
Looks good, Chip.

Do boolean AND and OR short circuit? That is, in:
```c := 0 AND foo(1)
```
does the foo() function get called? In C it doesn't for &&, but of course does for &.

jmg: boolean AND and binary AND are different, so they should have different operators. If Spin had a boolean type then perhaps we could rely on the compiler to infer which is intended, but with all variables being 32 bit integers this isn't really possible.

We could do it that way. That would really be a compiler thing. In fact, if we do it that way, there's not even a need for the boolean AND/OR, as actual operator routines.
• Posts: 14,020
Cluso99 wrote: »
```#>		x #> y		x #>= y		binary		9, 16	Ensure x => y
<#		x <# y		x <#= y		binary		9, 16	Ensure x <= y
```
Are these signed, as P1 was ??? if yes, then can it be written (and same for other signed operators)
```#>		x #> y		x #>= y		binary signed	9, 16	Ensure x => y
<#		x <# y		x <#= y		binary signed	9, 16	Ensure x <= y
```

So we write
```  min #> x <# max  'limit x between min and max
```
Looks wrong to me, but it is compatible to P1.

The #> and <# are signed. I made a note in the operator list.

I would code that last example as:

x #> min <# max

What you wrote looks like it would work, but it looks strange to me.
• Posts: 18,066
edited 2017-04-13 08:41
Maybe time to revisit these...
```=          assignement operator - in addition to :=
;          for statement terminator
/* ... */  for block/multi-line comments - in addition to {...} and {{...}}
```
• Posts: 14,020
edited 2017-04-13 09:31
Keep the Spin precedence order, Chip. I concur with your assessment that C's is a bit off.

Thanks,
-Phil

I was just now looking at the original Spin precedence list and I see that I wound up replicating it exactly today, without even remembering what the original Spin did. I just thought it through. The only difference is that the OR's and XOR's switched places. I was influenced by looking at C's precedence today. Don't know what is actually better. Kind of seems like XOR should be the highest to me. Someone pointed out that the new way is proper, though.
• Posts: 14,020
Cluso99 wrote: »
Maybe time to revisit these...
```=          assignement operator - in addition to :=
;          for statement terminator
/* ... */  for block/multi-line comments - in addition to {...} and {{...}}
```

And maybe { } for scope, since they wouldn't be needed for comments.
• Posts: 2,996
Chip,
I really wish we had normal MIN and MAX, the limit variants are just odd to me. I just want x := MAX(a,b) where x is assigned the higher of a and b. and vice versa for MIN.

I have never used <# or #> myself, they just look foreign to me, and I have to think a long time about them when I see them in code.

Same for the PASM MIN and MAX instructions, they are just backwards to me. REALLY confusing to use, when I'm so used to MAX and MIN in other CPUs/MCUs, and languages working like I said above.
• Posts: 15,135
Cluso99 wrote: »
Maybe time to revisit these...
```=          assignement operator - in addition to :=
;          for statement terminator
/* ... */  for block/multi-line comments - in addition to {...} and {{...}}
```

• Posts: 15,135
edited 2017-04-13 09:15
cgracey wrote: »
That would have been elegant, but >> and << got used for shift a long time ago, even though, graphically, they are ideal for rotates.

Yes, history did chose another path, which is why the alias coverage is important, as a means to give an explicit way to cover all the bases.
Ideally, the HLL should be able to support all the SHIFTS available in Assembler, and you can see laments from C coders where it lacks that.
The aliases you have already listed SAR, SHL, SHR, ROR, ROL give that coverage & follow established conventions

• Posts: 14,020
edited 2017-04-13 09:25
Roy Eltham wrote: »
Chip,
I really wish we had normal MIN and MAX, the limit variants are just odd to me. I just want x := MAX(a,b) where x is assigned the higher of a and b. and vice versa for MIN.

I have never used <# or #> myself, they just look foreign to me, and I have to think a long time about them when I see them in code.

Same for the PASM MIN and MAX instructions, they are just backwards to me. REALLY confusing to use, when I'm so used to MAX and MIN in other CPUs/MCUs, and languages working like I said above.

I hear you and I think I know the problem. We are doing MIN and MAX with one implied term, in sequence.

Using MIN(x,y) and MAX(x,y) is common in the world, but you can't use them as assignment operators cleanly. Those are 'batch', while ours are 'flow'.

If it wasn't for people's experiential bias, I think the #> and <# way would be seen as better. As those operators execute, I imagine a carpenter doing some trimming as he moves along. With MIN(x,y), I imagine something in each hand being evaluated and one getting kept, while the other gets tossed.

Isn't this nice, though:
```somecalc #> 0 <# 99         'clamp within 0..99
```
Maybe we should just use names, instead:
```somecalc MIN 0 MAX 99       'clamp within 0..99
```
• Posts: 14,020
edited 2017-04-13 09:34
Here is the updated list with SHL and SHR gone, as they are no longer needed. SAR sits where SHR used to:
```Operator	Term Usage	Assign Usage	Type		Prior	Description
-------------------------------------------------------------------------------------------------------------------------
++ (pre)	++x		++x		var prefix	1	Pre-increment
-- (pre)	--x		--x		var prefix	1	Pre-decrement
?? (pre)	??x		??x		var prefix	1	PRNG reverse (var must be long)

++ (post)	x++		x++		var postfix	1	Post-increment
-- (post)	x--		x--		var postfix	1	Post-decrement
?? (post)	x??		x??		var postfix	1	PRNG forward (var must be long)
!! (post)	x!!		x!!		var postfix	1	Post-boolean NOT
!  (post)	x!		x!		var postfix	1	Post-bitwise NOT
\  (post)	x\y		x\y		var postfix	1	Post-set to y

!		!x		!= x		unary		2	Bitwise NOT, 1's complement
-		-x		-= x		unary		2	Negation, 2's complement
ABS		ABS x		ABS= x		unary		2	Absolute value
NCOD		NCOD x		NCOD= x		unary		2	Encode MSB, 31..0
DCOD		DCOD x		DCOD= x		unary		2	Decode, 1<<(x & \$1F)
SQRT		SQRT x		SQRT= x		unary		2	Square root
LOG2		LOG2 x		LOG2= x		unary		2	Unsigned to logarithm-base2
EXP2		EXP2 x		EXP2= x		unary		2	Logarithm-base2 to unsigned

>>		x >> y		x >>= y		binary		3, 16	Shift right, insert 0's
<<		x << y		x <<= y		binary		3, 16	Shift left
SAR		x SAR y		x SAR= y	binary		3, 16	Shift right, insert MSB's
ROR		x ROR y		x ROR= y	binary		3, 16	Rotate right
ROL		x ROL y		x ROL= y	binary		3, 16	Rotate left
REV		x REV y		x REV= y	binary		3, 16	Reverse y LSBs of x and zero-extend
SIGNX		x SIGNX y	x SIGNX= y	binary		3, 16	Sign-extend from bit y

&		x & y		x &= y		binary		4, 16	Bitwise AND
^		x ^ y		x ^= y		binary		5, 16	Bitwise XOR
|		x | y		x |= y		binary		6, 16	Bitwise OR

*		x * y		x *= y		binary		7, 16	Multiply
/		x / y		x /= y		binary		7, 16	Divide, return quotient
MOD		x MOD y		x MOD= y	binary		7, 16	Divide, return remainder
SCAL		x SCAL y	x SCAL= y	binary		7, 16	Scale, unsigned (x * y) >> 32
FRAC		x FRAC y	x FRAC= y	binary		7, 16	Fraction, unsigned {x, 32'b0}/y

+		x + y		x += y		binary		8, 16	Add
-		x - y		x -= y		binary		8, 16	Subtract

MIN		x MIN y		x MIN= y	binary		9, 16	Ensure x => y, signed
MAX		x MAX y		x MAX= y	binary		9, 16	Ensure x <= y, signed

<		x < y		n/a		equality	10	Check less than			(returns 0 or -1)
<=		x <= y		n/a		equality	10	Check less than or equal	(returns 0 or -1)
==		x == y		n/a		equality	10	Check equal			(returns 0 or -1)
<>		x <> y		n/a		equality	10	Check not equal			(returns 0 or -1)
>=		x >= y		n/a		equality	10	Check greater than or equal	(returns 0 or -1)
>		x > y		n/a		equality	10	Check greater than		(returns 0 or -1)

!!, NOT		!!x		!!= x		unary		11	Boolean NOT  (x == 0,            returns 0 or -1)
&&, AND		x && y		x &&= y		binary		12	Boolean AND  (x <> 0 AND y <> 0, returns 0 or -1)
^^, XOR		x ^^ y		x ^^= y		binary		13	Boolean XOR  (x <> 0 XOR y <> 0, returns 0 or -1)
||, OR		x || y		x ||= y		binary		14	Boolean OR   (x <> 0 OR  y <> 0, returns 0 or -1)

? :		x ? y : z	n/a		ternary		15	Choose between y and z

:=		x := y		x := y		assign		16	Set x to y
```

Among the unary and binary operators, the only non-standard, non-alpha operators are #> and <#. I kind of just want to call them MIN and MAX and be done with it... Okay, I just did it.
• Posts: 15,135
Roy Eltham wrote: »
I really wish we had normal MIN and MAX, the limit variants are just odd to me. I just want x := MAX(a,b) where x is assigned the higher of a and b. and vice versa for MIN.

I have never used <# or #> myself, they just look foreign to me, and I have to think a long time about them when I see them in code.

Same for the PASM MIN and MAX instructions, they are just backwards to me. REALLY confusing to use, when I'm so used to MAX and MIN in other CPUs/MCUs, and languages working like I said above.
Agreed, those are backwards, but they are also now established in the field, so a new form is required for the fix, where pfxMAX or MAXsfx mean what the English says. (pfx,sfx = some tbf prefix of suffix)

• Posts: 14,507
Roy Eltham wrote: »
Thinking about it more, I agree about having >> be non-arithmetic in the context of Spin and typical usage there. Also, having SAR/SAL makes it very clear that it's not a normal shift.
I have sometimes wished that C would let you more explicitly do shifts and arithmetic shifts. Usually you have to do some casting to get what you want if it's not the defined behavior.

Chip, re: precedence
As others have said, I don't really think about precedence order beyond the basics for the simple math ops. I typically just put in the ( )'s just so it's very clear.
I also tend to assume that && and || are almost the lowest precedence so you can write expressions like "x >= 0 && x < 10". Other than that, I use parens.
• Posts: 18,066
edited 2017-04-13 11:56
cgracey wrote: »
Here is the updated list with SHL and SHR gone, as they are no longer needed. SAR sits where SHR used to:
```Operator	Term Usage	Assign Usage	Type		Prior	Description
-------------------------------------------------------------------------------------------------------------------------
++ (pre)	++x		++x		var prefix	1	Pre-increment
-- (pre)	--x		--x		var prefix	1	Pre-decrement
?? (pre)	??x		??x		var prefix	1	PRNG reverse (var must be long)

++ (post)	x++		x++		var postfix	1	Post-increment
-- (post)	x--		x--		var postfix	1	Post-decrement
?? (post)	x??		x??		var postfix	1	PRNG forward (var must be long)
!! (post)	x!!		x!!		var postfix	1	Post-boolean NOT
!  (post)	x!		x!		var postfix	1	Post-bitwise NOT
\  (post)	x\y		x\y		var postfix	1	Post-set to y

!		!x		!= x		unary		2	Bitwise NOT, 1's complement
-		-x		-= x		unary		2	Negation, 2's complement
ABS		ABS x		ABS= x		unary		2	Absolute value
NCOD		NCOD x		NCOD= x		unary		2	Encode MSB, 31..0
DCOD		DCOD x		DCOD= x		unary		2	Decode, 1<<(x & \$1F)
SQRT		SQRT x		SQRT= x		unary		2	Square root
LOG2		LOG2 x		LOG2= x		unary		2	Unsigned to logarithm-base2
EXP2		EXP2 x		EXP2= x		unary		2	Logarithm-base2 to unsigned

>>		x >> y		x >>= y		binary		3, 16	Shift right, insert 0's
<<		x << y		x <<= y		binary		3, 16	Shift left
SAR		x SAR y		x SAR= y	binary		3, 16	Shift right, insert MSB's
ROR		x ROR y		x ROR= y	binary		3, 16	Rotate right
ROL		x ROL y		x ROL= y	binary		3, 16	Rotate left
REV		x REV y		x REV= y	binary		3, 16	Reverse y LSBs of x and zero-extend
SIGNX		x SIGNX y	x SIGNX= y	binary		3, 16	Sign-extend from bit y

&		x & y		x &= y		binary		4, 16	Bitwise AND
^		x ^ y		x ^= y		binary		5, 16	Bitwise XOR
|		x | y		x |= y		binary		6, 16	Bitwise OR

*		x * y		x *= y		binary		7, 16	Multiply
/		x / y		x /= y		binary		7, 16	Divide, return quotient
MOD		x MOD y		x MOD= y	binary		7, 16	Divide, return remainder
SCAL		x SCAL y	x SCAL= y	binary		7, 16	Scale, unsigned (x * y) >> 32
FRAC		x FRAC y	x FRAC= y	binary		7, 16	Fraction, unsigned {x, 32'b0}/y

+		x + y		x += y		binary		8, 16	Add
-		x - y		x -= y		binary		8, 16	Subtract

MIN		x MIN y		x MIN= y	binary		9, 16	Ensure x => y, signed
MAX		x MAX y		x MAX= y	binary		9, 16	Ensure x <= y, signed

<		x < y		n/a		equality	10	Check less than			(returns 0 or -1)
<=		x <= y		n/a		equality	10	Check less than or equal	(returns 0 or -1)
==		x == y		n/a		equality	10	Check equal			(returns 0 or -1)
<>		x <> y		n/a		equality	10	Check not equal			(returns 0 or -1)
>=		x >= y		n/a		equality	10	Check greater than or equal	(returns 0 or -1)
>		x > y		n/a		equality	10	Check greater than		(returns 0 or -1)

!!, NOT		!!x		!!= x		unary		11	Boolean NOT  (x == 0,            returns 0 or -1)
&&, AND		x && y		x &&= y		binary		12	Boolean AND  (x <> 0 AND y <> 0, returns 0 or -1)
^^, XOR		x ^^ y		x ^^= y		binary		13	Boolean XOR  (x <> 0 XOR y <> 0, returns 0 or -1)
||, OR		x || y		x ||= y		binary		14	Boolean OR   (x <> 0 OR  y <> 0, returns 0 or -1)

? :		x ? y : z	n/a		ternary		15	Choose between y and z

:=		x := y		x := y		assign		16	Set x to y
```

Among the unary and binary operators, the only non-standard, non-alpha operators are #> and <#. I kind of just want to call them MIN and MAX and be done with it... Okay, I just did it.

I really think you should use MINS and MAXS rather than MIN and MAX to at least be consistent with PASM.
• Posts: 18,066
Here is a limit use from code by Jason Dorie...
```    Elev := 1000 #> Elev <# 2000                        'limit between 1ms..2ms
```
which will now read (assuming MINS/MAXS rather than MIN/MAX)...
```    Elev := 1000 MINS Elev MAXS 2000                        'limit between 1ms..2ms
```
• Posts: 6,347
edited 2017-04-13 13:25
The wording of "Ensure x => y" for the MIN operator seems confusing. It sounds like the value of x is changed to equal the value of y if y is greater than x. The description for "x MIN y" should say exactly what it does, which is "returns the maximum value of x and y". And the description of MAX should be "returns the minimum value of x and y". Of course, those accurate descriptions will make the novice programmer wonder why the operator does the opposite of what the name implies, but I think all of us have wondered that ourselves.

EDIT: I would suggest not having aliases for #> and <#, or if you do want to use MIN and MAX for the aliases then swap them so their use is obvious instead of obfuscating the meaning. Of course, if you do that you would probably need to fix the meaning in assembly as well. Maybe better aliases would be CLIPHI and CLIPLO, or CLPH and CLPL. I think it's better to avoid using the terms MIN and MAX because of the misleading connotation of the operators.
• Posts: 4,195
I always have to look up #> and <# to remember what they mean. Why not something simple like X := LimMax(Y, maxval) or X := LimMax(Y, 100) then you see exactly what the maximum value will be and there is zero confusion about it.
• Posts: 23,514
cgracey wrote:
Isn't this nice, though:
```somecalc #> 0 <# 99         'clamp within 0..99
```
Maybe we should just use names, instead:
```somecalc MIN 0 MAX 99       'clamp within 0..99
```
I've always liked the #> and <# as opposed to MIN and MAX. To me they mean "force greater-than-or-equal" and "force-less-than-or-equal."

To those of you who've never programmed in PBASIC, MIN and MAX there act as limit operators, too, not as traditional MIN and MAX functions. Those mnemonics can be confusing if you're expecting the opposite behavior.

-Phil
• Posts: 23,514
edited 2017-04-13 16:19
cgracey wrote:
And maybe { } for scope, since they wouldn't be needed for comments.
Oh heavens, no! Please keep the indentation.

When I taught C for robotics, the biggest thing that slowed the class down was helping the kids track down unmatched braces. And with braces they were slow to use proper indentation style, which made things even worse. Spin solved both issues with indentation scoping.

So keep it clean, please. We don't need more syntactic gingerbread in Spin.

-Phil
• Posts: 10,250
I don't want the brackets.
• Posts: 14,020
edited 2017-04-13 16:51
I don't enjoy brackets, either. It would be nice to maybe get more than one statement on a line, though. But, I don't like semicolons any more than brackets.
• Posts: 2,996
I think you can keep #> and <# as they are/were, but add MIN and MAX to work the traditional way (so not really as operators).

I have much more of a beef with the PASM MIN/MAX instructions being backwards...
• Posts: 21,230
As much as I am unhappy with white space block delimiting I vote against changing Spin so drastically as to add brace delimiters or "begin", "end" etc. That is going to far.

I also love semicolons, but not in Spin for Pete's sake.

I really hate the practice of stuffing multiple statements on a line separated by semi-colons. I know ace programmers love it. But I'm sure it's just another confusion and makes things harder to read for beginners.

In short I'm all for keeping that syntactic noise out of Spin.