Improving PBASIC: Request for Comments

Back at the end of last month, there was a Simplifying PBasic thread going in the General Forum. I mentioned I was going to enhance my BASIC Stamp Preprocessor to add a block IF capability (IF … ELSEIF … ELSE … ENDIF).

Here is my proposed syntax:


'{$IF condition 1}
  statement block 1
'{$ELSEIF condition 2}
  statement block 2

...

'{$ELSE}
  statement block n
'{$ENDIF}

Which the preprocessor would translate to:


if (condition 1) then Label1
if (condition 2) then Label2
...

  statement block n
  goto EndIfLabel

Label1:
  statement block 1
  goto EndIfLabel

Label2:
  statement block 2
  goto EndIfLabel

...

EndIfLabel:

Where Label1, Label2, EndIfLabel are labels generated by the preprocessor.

My intention is to allow nested $IF … $ENDIFs – although I haven’t worked out just how I’m going to implement that yet. I may end up disallowing nesting if implementation becomes too hairy – or at least not supporting it in the initial implementation(s).

What do y’all think?

FYI: I chose the '{$directive parameter} format to match the '{$Stamp } directive format since I needed to parse it anyway to get the list project files.

This sounds great.

As to nesting if-elseif-else structures, please try to make this work. There are many situations where this is needed and it would be a bother to be able to us the new structures in one place but not in another. Isn’t this a sort of natural recursion application?

To me, one of the biggest issues is generating goto labels that are easy enough to follow that folks that edit the resulting code directly see something that is editible.

How about this format $IF $IFLABEL (optional) $ELSEIF $ELSE $ENDIF

My thoughts would be that if you provided a label, then the label would be used as a basename for the various goto labels in Pbasic, if not, you get what you get.

As to what I mean by a common subroutine, I don’t mean jumping to a new program slot and jumping back – the way Pbasic handles jumps would add a lot of bother and overhead to any such systems. What I do mean is something like the header file, where I could define a subroutine one time and the pre-processor would add the code to the appropriate files for the approriate programming slots.

An input subroutine is a good example. I often end up calling the input subroutine from at least 2 programming slots and sometimes from 3. If I change the variables that the master CPU sends me (perhaps I want delta_t rather that packet_num), I need to change the subrountine in all 3 places or else I get the dreaded “PBasic Error LED of Death” to light up on the Operator Interface and I am dead in the water.

Finally, what about text editing? How do you make your master file that the pre-processor processes? Has anybody made the leap to CodeWright? It is a very good program for C coding and other serious coding projects. One nice thing about CodeWrightt is that it knows the various keywords of the language you are using. It can be set up to show Constants in one color, variables in another, keywords in yet anther, etc. Has anybody taught CodeWright the Pbasic language? Do tell.

Joe J.

*Originally posted by Joe Johnson *
As to nesting if-elseif-else structures, please try to make this work. There are many situations where this is needed and it would be a bother to be able to us the new structures in one place but not in another. Isn’t this a sort of natural recursion application?

You’re right. This is a natural for recursion – and that’s what I had in mind. I think I should be able to do it without too much trouble, but you never know for sure until you get in there an get your fingernails dirty.:cool:

**To me, one of the biggest issues is generating goto labels that are easy enough to follow that folks that edit the resulting code directly see something that is editible.

How about this format $IF $IFLABEL (optional) $ELSEIF $ELSE $ENDIF

My thoughts would be that if you provided a label, then the label would be used as a basename for the various goto labels in Pbasic, if not, you get what you get.
**

I like your idea of allowing the user to provide labels, but $IFLABEL just doesn’t have “sex appeal” for me.:eek: How about if I just take a look at the next non-blank, non-comment line, and if it’s a label, I will use it instead of generating a label? Something like:


'{$IF condition 1}
Label1:
  statement block 1
'{$ELSEIF condition 2}
Label2:
  statement block 2

...

'{$ELSE}
LabelN:
  statement block n
'{$ENDIF}
EndIfLabel:

**As to what I mean by a common subroutine, I don’t mean jumping to a new program slot and jumping back – the way Pbasic handles jumps would add a lot of bother and overhead to any such systems. What I do mean is something like the header file, where I could define a subroutine one time and the pre-processor would add the code to the appropriate files for the approriate programming slots. **

It sounds like the include file concept satisfies this requirement. Nicht Wahr?

An input subroutine is a good example. I often end up calling the input subroutine from at least 2 programming slots and sometimes from 3. If I change the variables that the master CPU sends me (perhaps I want delta_t rather that packet_num), I need to change the subrountine in all 3 places or else I get the dreaded “PBasic Error LED of Death” to light up on the Operator Interface and I am dead in the water.

:confused: When you say “If I change the variables that the master CPU sends me”, you don’t mean that you have figured out a way to read different data at different times during a match, do you? That might be a nice feature, but the only way I can envision it being done is with a robot controller restart.

Finally, what about text editing? How do you make your master file that the pre-processor processes? Has anybody made the leap to CodeWright? It is a very good program for C coding and other serious coding projects. One nice thing about CodeWrightt is that it knows the various keywords of the language you are using. It can be set up to show Constants in one color, variables in another, keywords in yet anther, etc. Has anybody taught CodeWright the Pbasic language? Do tell.

I’ve never used CodeWright, but it does sound nifty.:cool: I use the StampW editor. Typically, I start out everything at the preprocessor’s GUI. I launch StampW from there. After I have finished editing, I exit back to the preprocessor GUI, and have it preprocess the project. After the project has been preprocessed, it gives you the option of launching the editor so you can download the program or continue editing it.

*Originally posted by Joe Johnson *
**Has anybody made the leap to CodeWright? It is a very good program for C coding and other serious coding projects. One nice thing about CodeWrightt is that it knows the various keywords of the language you are using. It can be set up to show Constants in one color, variables in another, keywords in yet anther, etc. **

We use CodeWright at work so that Borland C++Builder doesn’t do funky things to our code. It has a lot of handy features.

The structure of the PIC code (was this what Microchip and Scenix were sqabbling over) would make it easy to construct a CASE statement.

CASE x OF
~~0 : y = 3;
~~6 : y = 7
~~1…5 : y = 4
ELSE y = 0;

~~~~~~~~BTFSC  ZERO
~~~~~~~~GOTO   YIS3
~~~~~~~~MOVLW  .6
~~~~~~~~SUBWF  X,w
~~~~~~~~BTFSC  ZERO
~~~~~~~~GOTO   YIS7
~~~~~~~~BTFSC  CARRY    'PIC CODES NOT            ~~~~~~~~~~~~~~~~~~~~~~~~'  HANDY:BTFSS? 
~~~~~~~~GOTO   YIS0
~~~~~~~~MOVLW  .4
~~~~~~~~MOVWF  Y
~~~~~~~~GOTO   ENDCASE
YIS3    MOVLW  .3
~~~~~~~~MOVWF  Y
~~~~~~~~GOTO   ENDCASE
YIS7    MOVLW  .7
~~~~~~~~MOVWF  Y
~~~~~~~~GOTO   ENDCASE
YIS0    MOVLW  .0
~~~~~~~~MOVWF  Y
ENDCASE

And yes, a special case could zero Y differently.
Another alternate would be the table of RETLWs, as in the PBASIC lookup/down instructions.:)

BTW is there an option available to NOT delete leading spaces when this BB program edits a post ?

[BTW is there an option available to NOT delete leading spaces when this BB program edits a post ? [/b]

Use the “PHP” formatting option…it uses the PRE tag so that any spaces are kept as typed…the deleting of spaces, unfortunately, is a quirk of standard HTML and not of this board in particular…

*Originally posted by Lloyd Burns *
**The structure of the PIC code (was this what Microchip and Scenix were sqabbling over) would make it easy to construct a CASE statement.

CASE x OF
~~0 : y = 3;
~~6 : y = 7
~~1…5 : y = 4
ELSE y = 0;
**

Do we really need a CASE statement language element? It seems to me that it wouldn’t add much value to the language beyond what we already have with the PBASIC BRANCH statement.

BTW Lloyd, I don’t think we have access to PIC assembly language without breaking the seal and voiding the warranty. :slight_smile:

*Originally posted by gwross *
**

BTW Lloyd, I don’t think we have access to PIC assembly language without breaking the seal and voiding the warranty. :slight_smile: **

But you don’t have access to IF … THEN … ELSE either unless you modify the Parallax token machine. My reply supposed that Parallax was changing PBASIC, and a case statement would take care of the else easily.

Maybe a modification to the preprocessor could make euther statement available.

Personally, I think PBASIC is just one of the givens we work with, and I don’t see that changing soon. In Nicholas Wirth can feel strongly about typing, PBASIC can feel strongly about unsigned integers.:slight_smile:

Small step toward signed math:

The main reason I want to use signed math is I want my division to work out properly. In 2’s complement math, adds, subtracts, and multiplies take care of themselves (mostly). It is the divide operation that give folks the hassles.

How about if you could tag a part of an expression that may be of unknown sign and then the code could get the math right.

For example:
PWMoutput = (error term) * FeedbackGain >> FeedbackScaling + $7F MAX $FE + $8000 MIN $8000 - $8000

If would be nice if I could flag (error term) as signed for the purposes of the division “>> FeedbackScaling”

The pre-processor could then put in the right IFs, Tests, Gotos, etc. that are typically required to get the division to work right.

It would also be nice to an automatic way to make sure that the results are within the right range for an 8 bit PWM output, eliminating the need for all the MAX’s & MIN’s and $8000’s

Just a thought.

Joe J.

Coincidentally, I got frustrated with PBASIC last year, so one night when I was bored I wrote a PBASIC preprocessor. It has nested If-then-else constructs, as well as do-while loops. I meant to post it here, but I never got around to it. You can take a look at it if you want. The source code is at:

http://www.cis.ohio-state.edu/~kiracofe/epbc-src.tgz

A linux binary is available at

http://www.cis.ohio-state.edu/~kiracofe/epbc-bin.tgz

It’s written in straightforward C++, so it should compile in MS Visual C++ although I’ve never tried it. Note that you’ll need lex if you want to modify the lexer. If there is interest, I’ll try to get some Windows binaries available. Just e-mail me at [email protected].

As far as the structure of the compiler goes, it’s pretty straightforward. I use lex to tokenize the input stream. I wrote the parser myself instead of using yacc (or bison or whatever) b/c the language was so simple, I figured this would be easier. Everything is implemented using C++ virtual functions. This makes the writing of nested constructs very easy. (e.g. we can call a function to output a statement without having to worry about what kind of statement it is, since each statement class knows how to “output itself”). Once you understand the BNF of the language (included in the README), the structure of the code should make sense, I hope…

If you have any comments, questions, or suggestions, let me know…

I went ahead and make some Windows binaries.
It’s all command-line only stuff still. If someone
wants to whip up a GUI, be my guest.

http://www.cis.ohio-state.edu/~kiracofe/epbc-win-bin.zip

I’m getting pretty close with my BASIC Stamp preprocessor. I have implemented almost all the planned features. If anyone would like to help me beat it up, e-mail me, and I’ll send you the program.

Finally, I have posted the preprocessor in the white papers area.

Sorry it took so long. My computer crashed just before the new year, and I had to reconstruct a lot of what I had done – losing a lot of momentum in the process.:frowning:

Here is the description I posted along with the program:

PRECIS:

A BASIC Stamp Preprocessor which simplifies coding for the BASIC Stamp 2 SX/E/P by providing an include file capability, and enabling structured programming constructs.

INTRODUCTION:
Here is the preprocessor I promised way back when. Sorry it took so long. (My computer crashed back at the end of December, and I had to reconstruct a lot of my work.)

I wrote this program to make programming our robot easier. It started when we first got the robot controller with the BASIC Stamp2 SX, and I needed to define the program data area identically in all the project programs. The original incarnation was limited to inserting an include file, and had a command line interface.

Last year, I added the graphical user interface, and this year, the structured programming capabilities.

INSTALLATION:

Copy the program to your hard disk. (That’s all!)

USE:
Run the program. It brings up a Windows Explorer like interface. From there, navigate to where your robot programs are stored (or where you want them to be.)

Assuming you already have a program file, find the file you want to edit (or preprocess) in the file list, and press Ctrl-P to preprocess the file or Ctrl-E to launch the BASIC Stamp Editor to edit the file.

To create and edit a new file from the GUI, type the name of the file you want created into the file name edit box, and press Ctrl-E.

The GUI also allows you to rename (Ctrl-N) and delete (Ctrl-D) files.

DIRECTIVE SYNTAX:

All directives appear within curly braces.

All directives are case insensitive. (i.e. $Include and $INCLUDE are equivalent.)

The $Stamp directive is required by the Stamp editor to be within a comment (i.e. preceded by an apostrophe.) All other directives MAY be preceded by apostrophes, although it is not recommended because of the fact that if you forget to preprocess your program, StampW will accept it as syntactically correct, but the program will not run correctly when downloaded to your robot.

The left brace introducing a preprocessor directive must be the first non-blank character on the line (other than an optional label and the optional apostrophe), and the directive (along with its parameters, if any) must be alone inside the braces. Comments may follow the closing brace.

PREPROCESSOR DIRECTIVES:

{$Stamp processor, file2, file3, …, file8}
Tells the BASIC Stamp editor the version of the Stamp processor the program will run on, and the program files that belong to the project. (The processor parameter is ignored by the preprocessor. Consult the StampW documentation for the $STAMP directive syntax.) The preprocessor uses the file list to determine which files to preprocess.

{$Include file_name}
Inserts file_name (after preprocessing it) into the program file being processed.

{$StampPPDate}
Causes the preprocessor to insert a DATA statement containing the date and time the file was preprocessed (StampPPDate DATA 24, “Mon Mar 19 21:16:40 2001”)
When your program starts up, you can display the date the project was preprocessed with the following commands:
stringLength VAR byte
theIndex VAR byte
TheChar VAR byte
debug CLS 'Clear the debug screen
'Print out the source file timestamp:
read StampPPDate, stringLength
for theIndex=1 to stringLength
read StampPPDate+theIndex, theChar
debug theChar
next
debug CR

{$StampProjectPrefix prefix_string}
Specifies to the preprocessor the output file name prefix. By default, the preprocessor prefixes the output file names with the date in the format yyyy.mm.dd. Output files may be directed to another directory by including a directory path in the prefix string.

{$If if_condition}
if_block
{$ElseIf else_condition}
elseif_block
{$Else}
else_block
{$EndIf}
Causes the preprocessor to generate PBASIC code which, when run, will execute if_block if if_condition is true, elseif_block if else_condition is true, and else_block if none of the above are true. (Both the $ElseIf and $Else directives with their accompanying blocks are optional.)

{$While while_condition}
while_block
{$EndWhile}
Causes the preprocessor to generate PBASIC code that will repeatedly execute while_block as long as while_condition is true.

{$Repeat }
repeat_block
{$Until until_condition}
Causes the preprocessor to generate PBASIC code which will repeatedly execute repeat_block until until_condition is true.

Notes:
The preprocessor requires labels in order to generate code for many of the directives. If labels are not provided, the preprocessor will generate them. The generated labels are of the format SPPLnnnn. You may find the generated code more readable if you provide meaningful labels for these directives.

I can’t wait.

Joe J.

Greg,

Could you give some examples on how to use labels?

Thanks.

It might be nice to have a slot directive that allows you to start the code for a different programming slot in the same file.

Typical directives:
To start a new slot (slot number assigned by the preprossor – we refernence them by name):
{$SlotStart slotname}

To end a slot (perhaps not required, either the file ends or a new slot begins:
{$SlotEnd}

To run another slot (preprocessor resolves the slotname to the required number)
{Run slotname}

Along with this I would say it would be nice to have “global” include directives and “local” include directives.

This would let us have some code (say the declarations of variables, constants, etc.) included in all programming slots and then but then we could include special code in specific programming slots.

I know I am asking a lot, but you asked for feedback.

Joe J.

*Originally posted by GreenDice *
**Greg,

Could you give some examples on how to use labels?

Thanks. **

Sure. Sorry for the oversight.


AppleTest:      {$if X = Apple}
                  debug "X is an apple", cr
OrangeTest:     {$elseif X = Orange}
                  debug "X is an orange", cr
MangoTest:      {$elseif X = Mango}
                  debug "X is an mango", cr
NoneOfTheAbove: {$else}
                  debug "X must be a banana", cr
EndFruitTest:   {$endif}

*Originally posted by Joe Johnson *
**It might be nice to have a slot directive that allows you to start the code for a different programming slot in the same file.

Typical directives:
To start a new slot (slot number assigned by the preprossor – we refernence them by name):
{$SlotStart slotname}

To end a slot (perhaps not required, either the file ends or a new slot begins:
{$SlotEnd}

To run another slot (preprocessor resolves the slotname to the required number)
{Run slotname}
**

I think I like it. Let me stew on it a bit.

**Along with this I would say it would be nice to have “global” include directives and “local” include directives.

This would let us have some code (say the declarations of variables, constants, etc.) included in all programming slots and then but then we could include special code in specific programming slots.
**

If I’m understanding what you need, then you can already do this with multiple include files. You’re not restricted to a single $Include directive per file. Simply $Include the global data file in all your project files, and $Include the special code files only where you need them.

**I know I am asking a lot, but you asked for feedback.

Joe J. **

Yes, I did, and I appreciate it all.:slight_smile:

I’m thinking about adding another directive similar to the $Slot directive suggested by Dr. Joe.

$Slot demarks a section of a preprocessor source file to be output as a separate BASIC Stamp program which is loaded into one of the suplemental program slots.

The new directive would identify a portion of a file which can be $Included in any of your $Slot output files.

I’m proposing $IncludeSource for the directive name. The syntax would be {$IncludeSource symbolic_name}. The source file lines between the $IncludeSource and a subsequent $EndIncludeSource directive can then be $Included using symbolic_name.

Example:


{$Stamp bs2sx}

{$IncludeSource dataIncludes}
' Your data definitions go here
.
.
.
{$EndIncludeSource}

{$Include dataIncludes} ' Insert the data definitions from above

'Your program initialization goes here
.
.
.
'Now run the main control loop
{$Run MainLoop}



{$Slot MainLoop}
{$Include dataIncludes} ' Insert the data definitions from above

' Read inputs and process them
.
.
.
'When you run out of program space, split your program, and 
'continue in the next program slot.
{$Run NextSlot}



{$Slot NextSlot}

{$Include dataIncludes} ' Insert the data definitions from above
'Do some more processing...

'Finally, output your data via the serout command, and go back to 
'the beginning of the control loop.

serout ...

{$Run MainLoop}

From my understanding of the original posted question, you want to avoid typing multiple “IF” statements.

http://parallaxinc.com/downloads/Documentation/Basic%20Stamps/BASIC%20Stamp%20Manual%20v2.0.pdf

That’s a link to the manual for the Basic Stamp, look up the “Branch” code. (Pages 85 & 86)

~Excerpt from Basic Stamp Manual~
**Explanation:\B]
The BRANCH instruction is useful when you want to write something like this:
IF value = 0 THEN case_0 ’ value =0: go to label “case_0”
IF value = 1 THEN case_1 ’ value =1: go to label “case_1”
IF value = 2 THEN case_2 ’ value =2: go to label “case_2”

 You can use BRANCH to organize this into a single statement:
      BRANCH value, [case_0, case_1, case_2]**