PDA

View Full Version : Rexx builtin function module



Robert Hodge
12-06-2013, 15:22
I am interested in developing a thinBasic module to implement as many Rexx builtin functions as possible. The goal is to simplify porting of Rexx scripts to thinBasic.

For example, a Rexx TRANSLATE function, with one operand, does what UCASE$ does, while a call to TRANSLATE(STR,NEW,OLD) is essentially what REPLACE$(STR,OLD,NEW) does. The net result is that porting of Rexx code is pretty hard, even though functionally thinBasic is quite comparable.

My current problem is that the documentation for creating a module is pretty limited. The thinBasic doc for the Module SDK is all blank.

Is there some "prototype" or sample module I could look at for an idea how to go about doing this? Is there documentation laying around that never got into the official docs?

Any help in this area would be appreciated.

ReneMiner
12-06-2013, 16:14
I can give you a small hint to find a few more information on some undocumented SDK-stuff.
Check the attachement, maybe it helps.

Petr Schreiber
12-06-2013, 18:07
Hi Quatras9,

the module developement is relatively simple and should allow you what you need.

First step
The sample ThinBasic module and header files are included in ThinBasic/SDK folder. There is a ZIP file you need to extract and it will give you module example in multiple languages.

Hint
Make sure you have examined the SDK sample, then the following will make more sense.

What do you need to implement your Translate function? I will give example in PowerBASIC, but it can be applied to other languages as well.

Your function in DLL could look like this:


Function Translate() As String
Local sStr, sNew, sOld As String
Local nParams As Long
If thinBasic_CheckOpenParens_Mandatory() Then
thinBasic_ParseString sStr
nParams += 1
If thinBasic_CheckComma_Optional() Then
thinBasic_ParseString sNew
nParams += 1
If thinBasic_CheckComma_Mandatory() Then
thinBasic_ParseString sOld
nParams += 1
End If
End If

If thinBasic_CheckCloseParens_Mandatory() Then
If thinBasic_ErrorFree() Then

Select Case nParams
Case 1
Function = UCase$(sStr)
Case 2
Function = ... something else
Case 3
Replace sOld With sNew In sStr
Function = sStr

End Select

End If
End If

End If

End Function


Then you need to register the function to become visible for thinBASIC - this is done in LoadLibrary function of DLL:


thinBasic_LoadSymbol "Translate", %thinBasic_ReturnString, CODEPTR(Translate), %thinBasic_ForceOverWrite


Alternative
In case the functions are not very performance demanding, you could reimplement them directly using ThinBASIC, store them in one file, for example REXX.tBasicU and reuse in projects.

Sample:


Function Translate( sStr As String, Optional sNew As String, sOld As String) As String
Select Case Function_CParams
Case 1
Return UCase$(sStr)

Case 3
Return Replace$(sStr, sOld, sNew)

Case Else
MsgBox 0, "This function can only take 1 or 3 params"
End Select
End Function



Petr

Robert Hodge
12-06-2013, 18:36
Thanks, that's a big help.

Rexx tends to define a lot of functions with optional parameters. It would seem that I would need to deal with "optional" vs. "mandatory" commas, right parens, etc. to handle all the variant ways these functions can be used.

For example, I can have TRANSLATE(STR) or TRANSLATE(STR,NEW,OLD). So, I will get to a point after STR where I will either have a comma or a right paren. I will have to check for one or the other.

Now, if I check for a right paren and it's not there, am I supposed to do a "put back" when the thinBasic_Check... function returns FALSE? Or do I just keep trying other "Check" functions until one succeeds? --> [I see now what I need; never mind this sentence.]

If I have a syntax error, where I don't find a comma OR a right paren, what then? Do these modules just "stop" and let the thinBasic core detect a syntax error, or is there some way I can convey the fact that they were in my module and I found an unrecoverable syntax error, so that the message produced is more meaningful?

In the thinCore.INC, there are a number of variants of the 'check' functions, like
thinBasic_CheckComma
thinBasic_CheckComma_Mandatory
thinBasic_CheckComma_Optional

What is the difference between thinBasic_CheckComma_Optional and thinBasic_CheckComma (%true,%true) ?

What happens if I use a Mandatory version and the thing isn't there?

If I use an Optional version, and the token in question isn't there, does an automatic putback occur implicitly ?

Based on what is documented in thinCore.INC, it seems that thinBasic implements a recursive-descent parser. Is that the case?

zlatkoAB
12-06-2013, 21:24
Hi...
Hey that is a really interesting thing, i really like rexx but i never fined time or energy or
enough enthusiasm to do something.
A year ago i have use little bit Reginald REXX to test some GUI stuff with rexx cod.
This can be interesting to me especially if would be open source...

good luck
Aurel

ErosOlmi
12-06-2013, 21:57
Hi quatras9,

hope to reply to all of your question from top to bottom:

regarding parsing functions related to comma or open or close parens I suggest to use the "*_Mandatory" or "*_Optional" version.
The "*_Optional" version will automatically putback to parsed token in case it is not the one searched.
The "*_Mandatory" version will automatically generate a runtime error if the token is not the one expected and script will stop execution.
The "parameter" version with 2 parameters (example thinBasic_CheckComma(p1, p2) ) is the first version developed when I started thinBasic. You can use it but is more complex and creates not so readable code.
Regarding runtime errors, thinBasic has a lot of internal checking when parsing and many automatica runtime errors will be fired if any inconsistencies will be identified. But regarding what is the syntax of a command, if it has optional or mandatory parameters, it is up to you (the programmer) to decide how it must be using the many parsing functions thinBasic gives you in SDK. If, at any time, you want to fire a runtime error, just use thinBasic_RunTimeError function.
yes, all internal expression parsing functions are implemented using recursive descendant parser techniques plus some trick developed by me


Just one last advice: all thinBasic strings used in SDK are BSTR strings, dynamic strings. I suppose you are developing using PowerBasic so you should already be on the same line.

In the above post, Petr Schreiber gave you exactly an example on how to develop a function into a thinBasic module.
If you need something more complete, I can give you the full source code (Power Basic 9.x or 10.x) of a complete module implementing the above TRANSLATE function. In any case you can already find a complete example into SDK.

Ciao
Eros

Robert Hodge
12-06-2013, 22:08
Hi...
Hey that is a really interesting thing, i really like rexx but i never fined time or energy or
enough enthusiasm to do something.
A year ago i have use little bit Reginald REXX to test some GUI stuff with rexx cod.
This can be interesting to me especially if would be open source...

good luck
Aurel

The Rexx I have used the most, recently, is oo Rexx (http://www.oorexx.org/). It's a real nice implementation. My interest in Rexx at the moment is because I am trying to port some Rexx ISPF scripts to thinBasic for use with the text editor SPFLite. (www.spflite.com). We are about to release a new version with macro support, and are using thinBasic as the macro engine. The scripts I am trying to port are from TSO/ISPF Rexx and from old Tritus SPF. thinBasic is actually pretty close to Rexx in capabilities, but there is a good bit of syntax differences to overcome, and then there's the 7,000 lines of Rexx I am dealing with ...

Robert Hodge
12-06-2013, 22:14
Eros,

Thanks so much for your reply, it was very helpful.

If you were willing to pass along the source of a working module, that would be extremely helpful. As you may be aware, I'm working with George Deluca on SPFLite, and this is part of that effort. His code in written in PB, so I would end up doing the same. (Although my language of choice is C++, that's what he uses, so he gets to call the shots!)

Regards,

Robert

ErosOlmi
12-06-2013, 23:41
Attached to this post a complete thinBasic module that implements a new keyword named Rexx_Translate
I just implemented it partially, complete as needed

Check inside "thinRexx.bas" for detailed comments.

Compile using PB9x or PB10x

Use thinBAsic script example "thinRexx_Example.tbasic" to test the new module.

Hope this can help as a starting point of a great Rexx module

Ciao
Eros

Robert Hodge
14-06-2013, 16:23
Thanks so much, Eros, the thinRexx module is exactly the framework I need to get started. It has pretty much everything I need.

There is one area of modules I don't know if you handle or not, so here's my question.

A module is fine for introducing functions, subs and constants into the namespace. But, suppose you want to inject a new keyword into the namespace? For example, in Rexx, the DO statement is very general purpose, and it does by itself what basic does with DO, FOR, WHILE, UNTIL, REPEAT, LOOP, etc. It's not possible to make a one-for-one translation, but some automated assists are conceivably possible.

For example, in Rexx, an indexed loop that decrements is done with

do i = 10 to 1 by -1
...
end

whereas basic does it with


for i = 10 to 1 step -1
...
next

I can't envision any way to automated the closures. Basic has LOOP, NEXT, and (repeat) UNTIL whereas Rexx just has END. (Automating Basic to Rexx would actually be easier, BTW).

But, the keyword BY in used in Rexx only for DO statements, so that BY -> STEP is a safe conversion. It would be interesting if I could do something like this:


USES "thinRexx"
DIM I AS LONG
FOR I = 10 TO 1 BY -1
...
NEXT

Here, 'BY' would get converted to 'STEP' the same as if I had written this:


USES "thinRexx"
ALIAS STEP AS BY
DIM I AS LONG
FOR I = 10 TO 1 BY -1
...
NEXT

The problem, of course, is that (a) you don't have any API to define aliases in a module, and (b) even if you did, I don't think the USES processing time is the time when you handle pending alias definitions. Is that a fair assessment?

Mainly, I'd be interested in your assessment of this issue. Could such a thing (module-defined aliases) conceivably fit into your architecture?

ErosOlmi
16-06-2013, 11:04
ALIAS command exists as script command but doesn't exist as SDK function.
I think I can easily add a new SDK function but even if you will be able to ALIAS thinBasic main flow control keywords you will not be able to change they syntax
FOR will remain FOR and DO will remain DO even if you alias them
And you will not able to ALIAS FOR into DO because DO already exists. ALIAS can create "new" aliases.

Ciao
Eros

Robert Hodge
16-06-2013, 16:10
Right, I understand that if you had an SDK function that was the equivalent of the ALIAS statement, it could not replace (or remove!) existing keywords, but only add new ones that were different spellings of existing ones. That would be enough.

I believe that, along with the existing ability to define string and numeric constants should be enough.

For constants, does the SDK require you to put the prefix character on the names? For example, the sample code has these two lines,

'thinBasic_AddEquate "%MyNumericEquate", "" , 1
'thinBasic_AddEquate "$MyStringEquate", "ABC" , 0

Is the % and $ required, or is this just a convention? If I want an equate without these, can you determine which is intended, like this?

'thinBasic_AddEquate "MyNumericEquate", "" , 1 ' a number, because "" means there is no string
'thinBasic_AddEquate "MyStringEquate", "ABC" , 0 ' a string, because "ABC" present

I haven't run across any docs or comments that explain if you could do that or not.

ErosOlmi
16-06-2013, 22:55
It is possible to avoid % or $ specifying the 3rd parameter but looking at the code of "thinBasic_AddEquate" I see there can be a bug.

I will open an bug case and fix for the next update.
So for the moment use $ or %