PBASIC language syntax

Does anyone know of an online or downloadable complete PBASIC syntax description? I know there is a help file that comes with editor from Parallax, but it leaves a bit to the imagination. For one thing,it doesn’t give a complete list of operators.

I’d like the “definitive reference” for the version of the language that the 2.5 system from Parallax processes, but the specific question for anybody who can answer:

can I express this in one line:

if (bytevarX = 254) then
bitvarY = 1
else
bitvarY = 0
end

In some languages I could do this by
bitvarY = (bytevarX = 254)
but not this one.

Yeah, I know, end is supposed to be endif. Just a little bit of old pl/i syntax leaking out my fingers…

Thanks

Taking advantage of integer math, might this work:

bitvarY = bytevarX/254

The BASIC Stamp Manual v2.0 (from Parallax):

Duh… thanks Justin. I already had this manual, but somehow had misplaced it and forgotten that it existed. When I went to download it, of course that’s when I found it…
Bill

Unfortunately, the PBASIC tokenizer will not accept things like myVar=(p1_y>127), etc with the exception of predicates in IF statements. Ie, you can do IF myVar=(p1_y>127) THEN doStuff, but the = will be interpreted as equality, not assignment. Someone please correct me if I’m wrong on this…

As for the integer math, that only works assuming that bytevarX will never be bigger than the value you are testing for. If it could be, then the behavior is rather sporadic. For example. bitVarY=5/10 will assign the value 0 to bitVarY since the lowest-order bit of 5/10 (= 10b) is zero, wheras 5/15 (=11b) will assign it the value 1.

You can, however, express what you want on one line:

IF (bytevarX = 254) THEN bitvarY = 1 ELSE bitvarY = 0

–Rob

*Originally posted by rbayer *
Someone please correct me if I’m wrong on this…

I believe you are already correct. No correction necessary.:wink:

The manual (Basic_Stamp_Manual_V2-0.pdf, pg 153) says you should not use bitwise operators in IF statements, but when used with awareness of how the bit variables are handled, they seem to work. Can anyone clarify whether what’s safe WRT this?

For example

'(note all variables in these code snippets are single bits)
b1 var bit
b2 var bit

if (b1 & b2) then

appears to behave equivalently to

if (b1=1) and (b2=1) then

And produces smaller code, which is the goal of this question.

Also…

though it’s understandable if unfortunate that you don’t get what you might expect when you code

if (~b1) then

since ~b1 will always evaluate to %11111111111111x and therefore always be true regardless of the value of the bit stored in b1.

Seems like

if (b1 & ~b2) then

Will give the expected and desired result since the leading zeros in b1 will mask off the leading ones in b2, and the result will depend only on the logical & of the single variable bits. Again, this produces smaller code than does

if (b1=1) and (b2=0) then

Any feedback?

Bill

*Originally posted by WizardOfAz *
**The manual (Basic_Stamp_Manual_V2-0.pdf, pg 153) says you should not use bitwise operators in IF statements, but when used with awareness of how the bit variables are handled, they seem to work. Can anyone clarify whether what’s safe WRT this?
**

As you said, as long as you understand how bit ops work, you should be fine. However, there are many, many caveats regarding bitwise stuff, so be very careful. Here’s some examples:

5 AND 2 will evaluate to true, while
5 & 2 will be false, since 101b & 10b = 000b.

5 AND NOT 2 will evaluate to false, while
5 & ~2 will be true, since 101b & 111111101b=101b=5

Also, as far as I know, the exact value of =, >, <, etc is not officially defined except for the fact that it is zero for false and non-zero for true. Thus, things like:
(5>2) & (3<10)
could evaluate to either true or false, depending on how >, < get evaluated.

In summary, if you know what you’re doing and you’re only working with bit-sized variables, you can probably get by with the bitwise stuff. Otherwise, I would HIGHLY recommend using the more correct logical operators. It will make your code easier to maintain, easier to understand, and probably more correct.

–Rob

P.S. If anyone knows for sure what =, >, etc evaluate to, I would greatly appreciate knowing in order to fix up RoboEmu. I’m going with the assumption of either 0 or 1 for now, but it could be changed very easily.

*Originally posted by rbayer *
**P.S. If anyone knows for sure what =, >, etc evaluate to, I would greatly appreciate knowing in order to fix up RoboEmu. I’m going with the assumption of either 0 or 1 for now, but it could be changed very easily. **

I just tried this code:

'{$STAMP BS2sx}
'{$PBASIC 2.5}

if (1 = 1) = $ffff then
  debug "(1 = 1) = $ffff.", cr
else
  debug "(1 = 1) <> $ffff!", cr
endif

end

It prints out

(1 = 1) = $ffff.

I think we already knew that false conditions evaluate to 0. Now I would surmise that TRUE = ~FALSE.

*Originally posted by gwross ***
I think we already knew that false conditions evaluate to 0. Now I would surmise that TRUE = ~FALSE. **

THANK YOU! I’ll try to get this into RoboEmu as soon as I get the chance to look at the code again. And yes, even though I have literally zero free time at this point, I do still plan on working towards 2.0 sometime in the not-to-distant future.

–Rob

A slightly related issue to this one is to avoid all the if tests to decide if a result is positive or negative before dividing.

This used to be a real coding headache before this year’s if then else, but it can still be a cause for ugly code if you have to test 3 or 4 or more expressions to see if they are positive or negative before using them.

This is a pretty ugly work around but it can be the least ugly option at times.

The idea is to shift right until you have the “sign bit” then subract this twice this number from one. The result is 1 if the expression was positive and -1 if the expression is negative.

It looks like this:

PwmArm = 127 + (1 - (ArmPot - ArmDesired >> 15 << 1)) * (ABS (ArmPot - ArmDesired) * ARM_GAIN)

If there are a lot of tests that you have to do to see if this quantity is positive and this other quantity is negative and yet anther quantity is positive then you end up with 8 SLIGHTLY different expressions for PwmArm which can drive you nuts. It is very difficult to get all the signs correct in 8 different expressions.

For what it is worth.

Joe J.

P.S. For those who want to do “swerve” (a.k.a. crab steering), this method is very very useful – the adjustment to gas and steering angle are complicated enough without having to debug spagetti code.

Oh yeah, I forgot to answer the basic question from this tread.

If you want to accomplish the equiv. of (Var = XXX) you can do this:

bitvarY = (bytevarX = 254)

You can do this:

bitvarY = 1 - (- ABS(bytevarX - 254) >> 15 )

Again, this is ugly but it accomplishes the result you want without an IF statement.

If you are looking to minize code size you may want to try NCD

bitvarY = 1 - (- NCD(bytevarX - 254) >> 15)

Another hack to try would be to use bitwize XOR for your compare test – thinking about it, this may be the fastest and tightest way to do it;

bitvarY = 1 - ( - (bytevarX ^ 254) >> 15)

Yet another thing to try is the Pbasic’s normal truncation and the REV function rather than the “-” sign and the “>> 15” business. The whole purpose of these things is to take advantage of all numbers but zero have a negative with a 1 in the high order bit of a 16 bit number.

You can get t this bit in an expression using the following as well:

bitvarY = ( - (bytevarX ^ 254) REV 16)

The above also reverses the sense of bitvarY. It becomes 1 in they are different and 0 if they are equal.

This brings up another simplification. Changing bitvarY to the opposite sense (bytevarX <> 254) makes the test a bit easier to implement as all the “1 -” s from the above expressions disappear.

Hope this helps.

Joe J.

*Originally posted by rbayer *
**As for the integer math, that only works assuming that bytevarX will never be bigger than the value you are testing for. If it could be, then the behavior is rather sporadic. For example. bitVarY=5/10 will assign the value 0 to bitVarY since the lowest-order bit of 5/10 (= 10b) is zero, wheras 5/15 (=11b) will assign it the value 1.
**

What about this:


bitVar = byteVAR / a MAX 1 'byteVar >= a
bitVar = a / (byteVAR MIN 1) MAX 1 'byteVar <= a
bitVar = (byteVAR / a) * (a / (byteVAR MIN 1) ) MAX 1 'byteVar == a (doesn't work for a=0)

Albeit, that fix makes it more bloated than helpful for the equality test. Here’s an option I just thought of for an equality test (don’t you just love bit fidling?)


bitVar = 0 ** (byteVAR - a) 'byteVar == a

If byteVAR == a, it will end up being 0^0, which is usually defined as one (although, I can’t confirm the stamp will return 1). Otherwise, it will return 0. There is the case if byteVAR is less than a, then we have 0 ^ (- k), and that is a division by zero error (or maybe the stamp just returns 0?). You could fix that with a MIN statement though. I don’t know how fast MIN and MAX statements are, so there is the highly likely chance that all this is futile, and Dr. Joe’s way is much faster :smiley:

Stephen

The ** op is not exponentiation. It is just muplication, but returns the high-order 16-bits instead of the normal low-order 16. Combined with the normal * op, you can get the full 32-bit result that could come from multiplying two 16-bit numbers. As far as I know, PBASIC doesn’t have an exponentiation op.

–Rob

*Originally posted by rbayer *
**The ** op is not exponentiation. It is just muplication, but returns the high-order 16-bits instead of the normal low-order 16. Combined with the normal * op, you can get the full 32-bit result that could come from multiplying two 16-bit numbers. As far as I know, PBASIC doesn’t have an exponentiation op.

–Rob **

d’oh … I’m thinking in Perl. Sorry about that. The only sort of exponention op I know of is DCD, which is just 2^n (or 1 << n), where n is the argument. Hmm … I can pull something out of my failed code …


bitVAR = DCD (byteVAR - a) - 1  MAX 1 '!(byteVAR == a)

That just reverses the logic (0 if they are equal, 1 if they are not). I don’t know the error handling if DCD’s argument is over 15, so the statement may need another MAX. Of course, it’s past the realm of usefulness I suppose.

Stephen