Spin2 Operator Syntax — Parallax Forums

# Spin2 Operator Syntax

edited 2017-04-03 16:02
Here is what I've got, so far. I'm not sure how this aligns with other languages, but it's open for review so we can maximize the sweet spot:
```Op	Example		Type		Description
-----------------------------------------------------------------------------
NOT	NOT x		unary		Boolean NOT (0 = -1, non-0 = 0)
!	!x		unary		Bitwise NOT, 1's complement
-	-x		unary		Negation, 2's complement
||	||x		unary		Absolute value
>|	>|x		unary		Encode MSB, 0..31
|<	|<x		unary		Decode, 1 shl (x & \$1F)
~	~x		unary		Sign-extend from bit 7
~~	~~x		unary		Sign-extend from bit 15
SQRT	SQRT x		unary		Square root
LOG	LOG x		unary		Unsigned to logarithm
EXP	EXP x		unary		Logarithm to unsigned

AND	x AND y		binary		Boolean AND (x <> 0 AND y <> 0, returns 0 or -1)
OR	x OR y		binary		Boolean OR (x <> 0 OR y <> 0, returns 0 or -1)
&	x & y		binary		Bitwise AND
|	x | y		binary		Bitwise OR
^	x ^ y		binary		Bitwise XOR
>>	x >> y		binary		Shift right
<<	x << y		binary		Shift left
~>	x ~> y		binary		Shift arithmetic right
<~	x <~ y		binary		Shift arithmetic left
->	x -> y		binary		Rotate right
<-	x <- y		binary		Rotate left
><	x >< y		binary		Reverse y LSBs of x and zero-extend
#>	x #> y		binary		Ensure x => y
<#	x <# y		binary		Ensure x <= y
+	x + y		binary		Add
-	x - y		binary		Subtract
*	x * y		binary		Multiply
/	x / y		binary		Divide, return quotient
//	x // y		binary		Divide, return remainder
**	x ** y		binary		Scale, unsigned (x * y) >> 32
*/	x */ y		binary		Fraction, unsigned {x, 32'b0}/y

<	x < y		equality	Check less than,		returns 0 or -1
=<, <=	x <= y		equality	Check equal or less than,	returns 0 or -1
==	x == y		equality	Check equal,			returns 0 or -1
<>	x <> y		equality	Check not equal,		returns 0 or -1
=>, >=	x => y		equality	Check equal or greater than,	returns 0 or -1
>	x > y		equality	Check greater than,		returns 0 or -1
```

The equality operators can no longer be used as assignment modifiers (i.e. "x >= y" assigns x>y to x). This allows both versions of =>/>= and =</<=.

The idea here is that any of the "unary" operators could also be used alone with a variable to modify the variable.

Any of the "binary" operators could be used after a variable and then followed with an "=" to create a self-modifying assignment (i.e. x += 3).

• edited 2017-04-03 16:36
No pre/post increment/decrement?

edit: I'm not arguing that they should be added. Just confirming that they weren't accidentally left off the list.
• I would treat LOG, EXP, SQRT, and maybe NOT as functions: i.e. require the parens.

-Phil
• Seairth wrote: »
No pre/post increment/decrement?

edit: I'm not arguing that they should be added. Just confirming that they weren't accidentally left off the list.

I just didn't list those. We'll get to them.
• I would treat LOG, EXP, SQRT, and maybe NOT as functions: i.e. require the parens.

-Phil

That thought occurred to me, too, but I'm not sure what I think about it.
• I really like the change to the equality operators...
• You might want to add != as a synonym for <>. However, I'm not really crazy about these synonyms. I think you're better off just changing to the C-like syntax rather than supporting both. Having both will make code harder to read for very little benefit.
• edited 2017-04-03 17:52
I just checked and "!=" gives an error in P1 Spin.

So, that's better than <= where it gives no error but doesn't do what you might think...

BTW: Noticed Lua uses "~=", which I think is slightly worse than "<>"
• This looks fine to me, Chip. Just add the != to be <>, like David Betz said and I'll be happy.
It resolves my main gripe with the Spin1 operators (the <= and >= ones).
• The Spin 2 operators have been under discussion recently elsewhere here.

There is a chorus of calls to harmonize the Spin 2 operators with other common languages, C/C++, C#, Java, Javascript, Perl etc....

This makes a lot of sense as it removes a lot of confusion for those coming to Spin from other languages. There is no particular reason why Spin operators should be different. Given the other huge changes to Spin/PASM that break all pre-existing code now is the time to harmonize the operators.

Of course Spin is syntactically very different from those other languages, but those differences are more obvious. The operator confusion is, well, confusing.

Personally I think all the other "non-standard" operators should have a function style syntax, MAX(), ROT(), etc. Makes things much more readable.

• Heater brings up a good point. I agree that the non-standard operators should use the function like syntax, every time I see <~ and the like I have to look them up.
So, while I said I was happy in the last message, I think I would be happier with the additional change Heater suggests.
• edited 2017-04-03 18:28
I agree about using function syntax for the "non-standard" operators. This would also allow a bit more flexibility in a few cases, such as with the sign-extension operator. Now you could provide the actual bit to extend, making it both more flexible and easier to read.

My only concern with this, though, is that you now have reserved function names. While it might not be an issue with Spin 2, you potentially cause conflicts if you and more reserved function names in Spin 3 (and so on). So... what if Spin 2 (and beyond) used a different syntax for these functions. For instance, would it be okay to have something like:
```x := {extend y, 7}
```

This would serve two purposes:

* Ensure that new functions could be added without conflicts
* Make it it obvious which functions are intrinsic to the interpreter

(edit: don't get fixated on the use of braces. I just used those because it wasn't parentheses. In reality, braces won't work because they're already used for comment blocks.)
• I'd suggest changing <- to something else because that's a parsing ambiguity.

"if x<-5" *should* evaluate identically to "if x < -5", but it doesn't.

Maybe <<< and >>> instead? Those to me read much more like "special shifts" than <- and ->.

I'm with David on supporting one or the other for the inequality ops - supporting both is worse.

I'm torn on sign extension - in C, the ~ operator is binary not, so to me, "~1" means "0xFE" (as a byte). I like the compactness of the sign extension operators, but find them hard to read. In C that's typically done just by type casting. For example, to sign extend something you'd do this:
```  int x = 0xff;
x = (signed char)x;   // sign extend from 8 to 32
x = (signed short)x;  // sign extend from 16 to 32
```

It could be done shorter as builtin functions:
```  int x = 0xff;
x = s8(x);   // sign extend from 8 to 32
x = s16(x);  // sign extend from 16 to 32
```

That would allow making ! be logical not, which is how most languages do it, though Python uses "not", so there's less consensus here.

For #> and <#, if you're supporting built-in functions, maybe max() and min() ? I always found the syntax of these really hard to read. x = max(x, 0), or x = min(x, 10) is pretty normal.
• JasonDorie wrote: »
I'd suggest changing <- to something else because that's a parsing ambiguity.

"if x<-5" *should* evaluate identically to "if x < -5", but it doesn't.

You know, that one surprises me. The docs say that negate has precedence over rotate-left.
• Seairth wrote:
x := {extend y, 7}

That looks more like lambda notation, e.g. Lisp.

-Phil
• Seairth wrote:
x := {extend y, 7}

That looks more like lambda notation, e.g. Lisp.

-Phil

Yeah, I thought about that when I was typing it. I was just looking for something that wasn't x(y). I suppose you could do x{y}, but that looks weird (to me, at least). Suggestions welcome!
• We have a little problem with the shift right operator ">>".

Languages like C will produce different bit patterns in the result depending on the type of thing being shifted. Signed integers get the sign bit propagated down. Unsigned shifts zeros into the top.

Spin only has signed LONGs so there is a problem there.

Javascript gets around this, yes it can deal with 32 bit integers, by providing:

>>, Shift right propagating the sign bit down from bit 31. (Signed)

>>>, Shift right filling the top with zero bits. (Unsigned)

This is the way to go in Spin I think.
• Seairth wrote: »
JasonDorie wrote: »
"if x<-5" *should* evaluate identically to "if x < -5", but it doesn't.

You know, that one surprises me. The docs say that negate has precedence over rotate-left.

It'd be worth testing that, just to be sure. I know I've been bitten by a number of these in the past, but it's possible that this particular case isn't one of them. That said, the fact that "x <- 5" isn't necessarily the same as "x<-5" is just as bad.
• I would treat LOG, EXP, SQRT, and maybe NOT as functions: i.e. require the parens.

Yes, I agree with this approach. Expressions are easier to scan that way.

JasonDorie wrote: »
I'd suggest changing <- to something else because that's a parsing ambiguity.
"if x<-5" *should* evaluate identically to "if x < -5", but it doesn't.
Yes, that is simply broken.
Heater. wrote: »
Personally I think all the other "non-standard" operators should have a function style syntax, MAX(), ROT(), etc. Makes things much more readable.
Yes, I'll find a list of how others that use function syntax manage this already.

• edited 2017-04-03 21:31
cgracey wrote: »
Here is what I've got, so far. I'm not sure how this aligns with other languages, but it's open for review so we can maximize the sweet spot:

Below is a collection of other languages added in the fName, Op Use columns.

In most cases there is an easy alignment, and I think the BSR, BSL can be used, along with SAR,SAL
You may need to add BSL for symmetry, if PASM has the equivalent ?

I'm not sure if Spin LOG is natural, or base 10 ?, but others have both LOG() and LN()

Comments is another area, and the // as comment EOL is now pretty much universal.
I've found cases where both (* *) and /* */ are also allowed/tolerated for block comments.
Allowing nested comments is also a good language idea.

```Op      Example     fName   Op  Use           Type       Description
-------------------##########################-------------------------------------------------
NOT     NOT x       NOT         OUT:=NOT IN   unary      Boolean NOT (0 = -1, non-0 = 0)
||      ||x         ABS         ABS(n)        unary      Absolute value
>|      >|x         BSR?                      unary      Encode MSB, 0..31
BSL?                                 Encode LSB, 0..31   bsf (Bit Scan Forward) and bsr (Bit Scan Reverse)
|<      |<x         1 SHL x                   unary      Decode, 1 shl (x & \$1F)

SQRT    SQRT x      SQRT        SQRT(Re)      unary      Square root
LOG     LOG x       LOG         LOG(Re) b10   unary      Unsigned to logarithm
LN          LN(Re)  nl    unary      Unsigned to logarithm
EXP     EXP x       EXP         EXP(Re) nl    unary      Logarithm to unsigned

AND     x AND y     AND     &                 binary     Boolean AND (x <> 0 AND y <> 0, returns 0 or -1)
OR      x OR y      OR                        binary     Boolean OR (x <> 0 OR y <> 0, returns 0 or -1)
&       x & y       &                         binary     Bitwise AND
|       x | y                                 binary     Bitwise OR
^       x ^ y       XOR                       binary     Bitwise XOR
>>      x >> y      SHR                 0in   binary     Shift right
<<      x << y      SHL                 0in   binary     Shift left
~>      x ~> y      SAR                       binary     Shift arithmetic right
<~      x <~ y      SAL                       binary     Shift arithmetic left
->      x -> y      ROR                       binary     Rotate right
<-      x <- y      ROL                       binary     Rotate left
//      x // y       MOD   -    n MOD m       binary     Divide, return remainder
EXPT  **
<       x < y        LT    <                  equality   Check less than,                returns 0 or -1
=<, <=  x <= y       LE    <=                 equality   Check equal or less than,       returns 0 or -1
==      x == y       EQ    =                  equality   Check equal,                    returns 0 or -1
<>      x <> y       NE    <>                 equality   Check not equal,                returns 0 or -1
=>, >=  x => y       GE    >=                 equality   Check equal or greater than,    returns 0 or -1
>       x > y        GT    >                  equality   Check greater than,             returns 0 or -1
Assign               :=        n := m
Unused               ~ !
Used                 % \$ @
Others               MAX        MAX(A,B,C)
MIN        MIN(A,B,C)
Comment EOL          //
Comment Block        /* txt */
Comment Block        (* txt *)

Trigonometric functions : SIN COS TAN ASIN ACOS ATAN  Radians

Appendix:
6.6.4.3 Bit Scanning: BSF and BSR (asm notes)

The bsf (Bit Scan Forward) and bsr (Bit Scan Reverse) instructions search for the first or last set bit in a 16 or 32 bit quantity.
The general form of these instructions is
bsf	dest, source
bsr	dest, source
Bsf locates the first set bit in the source operand, searching from bit zero though the H.O. bit.
Bsr locates the first set bit searching from the H.O. bit down to the L.O. bit.
If these instructions locate a one, they clear the zero flag and store the bit index (0..31) into the destination operand.
If the source operand is zero, these instructions set the zero flag and store an indeterminate value into the destination operand.
```

• heater wrote:
>> Shift right propagating the sign bit down from bit 31. (Signed)

>>>, Shift right filling the top with zero bits. (Unsigned)

This is the way to go in Spin I think.
No. The way Spin does it now is fine: ~> for signed, >> for unsigned. (Although I do wish the standard for -> and ~> were reversed, but that ship has sailed.)

-Phil
• The way Spin does it is indeed fine.

Any combination of weird symbols that gets the job done is as good as any other.

My point is that there is no particular reason to use a different combination of weird symbols than millions of other programmers around the world use. Especially if one might want to attract those people into the fold and make their life easy.

Hmm...Having said that. "~>" is not fine at all. The "~" is often taken as a "NOT". The ">" is a obviously "greater than". So at first glance it looks like a "not greater than".

It's just awful.

• edited 2017-04-03 23:48
No. The way Spin does it now is fine: ~> for signed, >> for unsigned. (Although I do wish the standard for -> and ~> were reversed, but that ship has sailed.)
Heater. wrote: »
Hmm...Having said that. "~>" is not fine at all. The "~" is often taken as a "NOT". The ">" is a obviously "greater than". So at first glance it looks like a "not greater than". It's just awful.

To me, all of this "It's just awful" & "Although I do wish" teeth gnashing is readily solved by merely adding the word operators SHR,SHL,ASR,ASL
No conflicts there, so those can co-exist even without a mode switch. Looks like BSR and BSL can also be added.

• edited 2017-04-03 23:55
jmg,
Whilst we are at it let's use ADD for addition, SUB for subtraction, etc. No need for those pesky weird operator symbols at all ! • Heater. wrote: »
jmg,
Whilst we are at it let's use ADD for addition, SUB for subtraction, etc. No need for those pesky weird operator symbols at all ! hehe - What is the saying - 'many a true word is spoken in jest' ?

I have one example in front of me that does include ADD() as an alias for +.

Yes, at first glance that seems silly, but then they allow ADD,SUB as a graphical element in the graphical entry schemes, and ADD,SUB also works for records like Time types.
All makes good sense, when you see the real examples in front of you.

The key point here is they are aliases, so you are perfectly free to use + and -, like we always have.

• What language are you looking at?

Going from "x + y" to "ADD(x, y)" is not just an alias. It's a total syntactic rearrangement.

Or do you mean "x ADD y" ?

We could do that is C++ with some #defines and operator overloading.

Too weird.
• edited 2017-04-04 00:49
jmg wrote: »
All makes good sense, when you see the real examples in front of you.

Not to mention the symmetry with PASM.

(edit: further, given Parallax's educational leanings, wouldn't the removal of all operators, except maybe assignment, be better? Operators are comparatively opaque and can often get novices, and sometimes experts, in trouble without even knowing it.)
• You mean we should write:
```x = MUL(ADD(a, b), ADD(c, d))
```
```x = (a + b) * (c + d)
```
No thanks.
• Heater. wrote: »
You mean we should write:
```x = MUL(ADD(a, b), ADD(c, d))
```
```x = (a + b) * (c + d)
```
No thanks.

No, no, your first expression should be:
```(set! x (mul (add a b) (add c d) ))
```
S expressions all the way .

• edited 2017-04-04 01:56
Heater. wrote: »
You mean we should write:
```x = MUL(ADD(a, b), ADD(c, d))
```
```x = (a + b) * (c + d)
```
No thanks.

It's the normal syntax in Spin for float expressions:
```x := f.FMUL(f.FADD(a, b), f.FADD(c, d))
```
• @eric,

Ha! Yes. Let's turn SPIN into LISP. Or Scheme perhaps.

@Ariba
It's the normal syntax in Spin for float expressions:
Is it?

That is not in the manual.