News:

PlayBASIC2DLL V0.99 Revision I Commercial Edition released! - Convert PlayBASIC programs to super fast Machine Code. 

Main Menu

PlayBASIC IDE & Compiler Integration Tutorial

Started by kevin, December 03, 2008, 09:59:38 AM

Previous topic - Next topic

kevin




PlayBASIC IDE & Compiler Integration Tutorial:

Document Revision: V0.03



Q. What is this ?  


      A.  This tutorial (in the form of an FAQ) is designed to help budding IDE developers, create alternative (or adapt existing) IDE'S for use with PlayBASIC V1.63 / V1.64 editions.   Such an IDE would also be useful with early editions of PlayBasicFX.  But only in the short term.




Q.  I want to make an IDE, but where can I get more information ?


      A.  If you want to roll your own IDE for PlayBasic then I suggest heading over the to the IDE Replacement Discussion (login required) thread.    This is the place for all replacement IDE discussions.  





Q. What operations does the IDE need to perform when it sends the source code to the PlayBasic compiler/runtime ?  


      A.   The IDE must prepare a Compiler Project file.  This is a simple text file with a list of properties about the project.  It contains fields about the starting screen size,  the window title etc etc.   As well as the file name of the merged source code.  

           The PB runtime expects the source to be pre-merged into one big chunk prior to compilation.   This includes the pre-parsing of  #Include directives also.

           So the various tabs of source code are output in order, from (left to right in the current IDE)    So if a project has 3 source files.  And they appear in the existing IDE as     Declares.PBA  |  MyFunctions.PBA |  Main.pba     The IDE would export them in that order to a single file.

           So we'd end up with one big chuck of source like this,


    Declares
    ....
    ....
    ....
    ....
    MyFunctions
    ....
    ....
    ....
    ....
    Main
    ....
    ....
    ....


       Once the source is merged, and the compile project file is built, then the IDE launches PlayBasic.exe.   PlayBasic.exe will expect the Full path of the compile Project file,  passed as a parameter.

       The IDE should ideally hibernate until the play basic compiler/runtime thread completes.   If there was a compiler or the runtime error, PB will dump the error message file into the PlayBasic temp folder (located in the users temp folder - see bellow for how to locate it).    If this exists after PB execution is complete, then there was some error.  So you need to load this message,  parse it and display it.  Make sure you delete the temp file also.  
     
       Errors are returned in a labeled text message format. There's three main fields, The Error number, The Line Number and The Error string.   The error string is obviously what caused PB to abort.  The tricky part is going to be the Line Number.   PB will return the Line number within the merged version of the source code.  So you'll have to to keep track of the how this maps back during either your code exporting (when you build the merged version), or you could parse the merged code after the error occurs.  The latter is probably quicker (think about it :) ).  




Q. What Fields are in the Compiler Project file  ?  


   A.  Here's an example of a Compiler Project file.    The file uses a grouped/sectioned format.  There's a handful of sections, but the main one's are <General> & </General>  and the linker pair.    You only need the stuff in General to run a program.  


<General>
source file=Example.source
debugmode = 0
author=Name Of Author
Splash Width=394
Splash Height=145
Splash Time=0
Screen Type=1
Screen Depth=16
Screen Width=800
Screen Height=600
Screen Title=
Exe File=MyProjectsEXEName.exe
Parameters=
</General>


<Watches>
</Watches>

<Linker>
ResourceFile=MyProjectsResourceFile.pbr
LinkDebug=0
LinkVersionInfo=0
</Linker>



 


Q. Where is an example of a Compiler Project file  ?  


     A.    There's one attached to this thread.  Check This out (login required)





Q. How Can I start a 'Compiler Project' file manually ?


     A.   One easy way is to create a short cut to PlayBasic.exe (the compiler/runtime)  then drag this short cut to location of your compiler project file + merged source (like the one the linked above).   In order to pass the project you'll have to edit the short cut, to do this right click on it,  then use the properties.  Change the 'TARGET' field to include the "absolute path of the compiler project file"    Once that's done, when you click on the short cut, it should then compile and run the projects associated source code.  As if it launched from an IDE.


 


Q. What does the 'compiler project' file field do ?


     A.    It lets us bundle up a whole collection of the information and pass it to the compiler / runtime environment easily.   Otherwise we'd have to pass this information through the command line or perhaps a file map.  

    Here's a quick overview of what the fields do.


   <General>

    source file= The name of the merged source file. The file must be in the same folder as the compiler project.

    debugmode = What debug mode should the compiler build the code in 0=none,  1 = trace, 2 =full debug.

    author= Who wrote this program.    (used for building exe's)

    Splash Width= Width of the splash screen in a built EXE  (used for building exe's)

    Splash Height= erm it's obvious :)

    Splash Time=  The time the splash should appear for in milliseconds   (used for building exe's)

    Screen Type=  The default type of Screen the runtime should create.  0 = none (not supported), 1 =windowed, 2 = full screen

    Screen Depth=  The request pixel depth of the screen valid inputs 16,24, & 32

    Screen Width=  Width of the default screen

    Screen Height= erm the screen height maybe

    Screen Title=  The Title of the default window.  NULL is no project title is set
   
    Exe File= The output name of the a built EXE.  (used for building exe's)

    Parameters= Command line parameters this program should start with

   </General>






Q. Why are the PlayBasic IDE Project files different from Compiler Project Formats ?


     A.  They weren't originally.  The original IDE used the same project file format as the compiler.   About a year (or so) into the development,  the author of that IDE vanished.  So Empty kindly offered up a replacement, and as such we have current IDE (PlayWrite)  - Some time later on, we changed the main project format to the more XML styled version we currently use.  If look deep enough in the forums, you can actually find old projects built from the original IDE.   So there's a bit of trivia for ya.

      However, because the compiler doesn't support the IDE project format (it probably should by now),  I'm not terribly familiar with what it houses myself.  But from what i've seen most of it seems pretty self explanatory I would think,  but you're on your own on this one ATM.
 
 
           



Q. How Do I Get Errors Message from the compiler/runtime ?


     A.  Any errors are returned in a  report file is called CompileTimeError.txt




Q. Where does PlayBasic save the current Compiler Error Message ?


     A.  Current editions of PlayBasic (1.63 ->1.64 generation) use the current users TEMP folder.    The file is stored under a Sub folder of PlayBasic\Temp

       ie.    ThisUsersTempDir\PlayBasic\Temp\CompileTimeError.txt





Q. What does the CompileTimeError.txt file look like ?


     A.  Like This.

 Error Report Sample


COMPILE TIME ERROR REPORT
Line Number=6
Error Number=27
Error String=Expecting Equals




Q. What do the Fields in CompileTimeError.txt do ?



 A.    They're pretty straight forward.

Line Number=   The line number (integer) within the merged source code that caused this error

Error Number=  The PB error number (integer) of this event

Error String= The PB error message.


  To parse the errors file, I just read though the file line by line.  To detect if a row is a field, we search for the = chr in the current row.  If it's found this row is possibly a ID field and value.   So we split the Left characters off (which become the field name) and the right characters become the value of this field.

  To resolve the fields we just fall through a select case or if/then block.

  here's a mock up in VB6



Function Parse_Compilers_Errors(ErrorMessage$(), OutputText As TextBox)

       Dim ErrorFormat As Long
       Dim lp As Long
   
         ' 0 is the original error file format
         ErrorFormat = 0

        Dim s As String
        For lp = 0 To UBound(CompileError$())
               s = UCase(ErrorMessage$(lp))
               If (s = "COMPILE TIME ERROR REPORT") Then
                       ErrorFormat = 0
                       Exit For
               End If
        Next
           
       Dim Id$
       Dim V$

       Dim CurrentErrorNumber As Long
       Dim CurrentErrorMessage As String
       
       Dim Divider As String
       
       
       ' -------------------------------------------------------------------------------------------
       ' -------------------------------------------------------------------------------------------
       ' -------------------------------------------------------------------------------------------
       
       If ErrorFormat = 0 Then
                   
           Divider = "="
           
            For lp = 0 To UBound(CompileError$())
               
               s = (ErrorMessage$(lp))
               
               Parse_TokenID_Ang_Value_from_String s$, Id$, V$, Divider
               
               
               Id$ = Replace(Id$, Divider$, "")
               Id$ = Trim(Id$)
               Id$ = UCase(Trim(Id$))
               
               If Id$ = UCase("Line Number") Then
                          Cursor.Y = Val(V)
               End If
               
               If Id$ = UCase("Error Number") Then
                      CurrentErrorNumber = Val(V)
               End If
               
               If Id$ = UCase("Error String") Then
                      CurrentErrorMessage = V
               End If
               
               
            Next
   
       End If
   
       
       ' -------------------------------------------------------------------------------------------
       ' -------------------------------------------------------------------------------------------
       ' -------------------------------------------------------------------------------------------
       If ErrorFormat = 1 Then

          '  Beware, The message format may change.  So that more than one error can be returned in a single pass.  As well as warnings/tips from the compiler.
   
       End If
   
   
       '  Dump the text box
       OutputText.Text = "Error #" + Str$(CurrentErrorNumber) + vbCrLf
       OutputText.Text = OutputText.Text + "Message" + CurrentErrorMessage
       

End Function




  NOTE:  it's possible the error format will change in the future. So it's most like a good idea to query the format as the above example does.    




Q. How Do I locate the Temp folder PlayBasic uses ?


   A.   PlayBASIC calls the API function GetTempPathA in kernel32 to locate the temp path on the current system.  It them users the sub folder of PlayBasic\Temp  to store files.  


  This PlayBASIC code will display the contents of the Pb scratch area and the temp folder.  The compiler stores stat's in the scratch area,  nothing really too useful for the IDE.  Error files are stored in the PlayBasic\Temp folder though.


PlayBASIC Code: [Select]
LinkDll "kernel32"
GetTempPathA(nSize,lpBuffer) alias "GetTempPathA" as integer
EndLinkDll



Function GetTempPath()
// Alloc a bank of 1024 bytes
Size=1024
ThisBank=newbank(Size)
Ptr=GetBankPtr(thisBank)
Status=GetTempPathA(Size,ptr)
if Status
Path$=PeekString(ptr,0) ; peek a null termed string
endif
Deletebank ThisBank
EndFunction path$


//
PBScratchFolder$=GetTempPath()+"PlayBasic\"

// Read this folder
Readdir PbScratchFolder$,"",0,0

// display the files/folders stored in the scratch folder
ShowFiles(PbScratchFolder$,"Compiler Scratch\Stat's Area")

//
PbTempFolder$=PbScratchFolder$+"Temp"
Readdir PbTempFolder$,"",0,0
ShowFiles(PbTempFolder$+"Temp","Compiler\IDE Temp Files")



print "Done"

Sync
waitkey



Function ShowFiles(ThisPath$,Message$)

print Message$
print "================================"

for lp=0 to getdirSize()
fileName$=Getdir$(lp)
select FileType(Thispath$+Filename$)
case 1
ink rgb(255,255,255)
case 2
ink rgb(255,0,0)
endselect
print Filename$
next
ink rgb(255,255,255)


EndFunction







Q. How Do I locate the Application folder PlayBasic uses ?


   A.   PlayBASIC calls the API function SHGetFolderPathA in shell32 to locate the current application data path of the current user.   All file\folders related to PB are stored in the sub folder  ie.  My Local App Dir\PlayBasic.


  This (mock up code) code will display the the Pb application folder.

  The compiler & IDE stores common files in this area.  Such as KeyWord and Version files come to mind.

  PlayBASIC Code
  AppDir$=GetSpecialFolderPath(CSIDL_LOCAL_APPDATA)   See PB Code

  To locate the keywords file you'd  AppDir$ +"PlayBasic\Info\Keywords.txt"
  To locate the keywords file you'd  AppDir$ +"PlayBasic\Info\Version.txt"

 There's also other folders for LOGS and Current Editor preferences.

 



Q. How Do get a List of KeyWords PlayBasic uses ?


   A.  Classic version of the PlayBasic (1.63/164 at the time of writing) have Keyword generation ability from the command line.    So if you call the PlayBasic.exe with the command line parameter of "info"  it'll create a new version file and keywords file.

        See above for how to locate them.




Q. What's in the KeyWord File ?


  A.  Not much.   It's simply a text file with a group of headings, followed by the keywords.  Such as [Directives], [Commands], [Constants], [Operators] and [Stats]  

   Each heading is followed by a number rows of keywords.  There's 1 keyword per row.  Each keyword section is concluded when a NULL row is reached.





Q. How Do I Parse the KeyWord File ?


  A.  Here's an example of how to do it this PB code.  

PlayBASIC Code: [Select]
Constant  CSIDL_LOCAL_APPDATA = $1C          ;{user}\Local App Data Settings _

LinkDll "shell32"
SHGetFolderPath(hWndOwner,nFolder,hToken,dwFlags,pszPath) Alias "SHGetFolderPathA" as integer
EndLinkDll


Function GetSpecialFolderPath(nFolderID)
// Alloc a bank of 1024 bytes for the function to return the path in
Size=1024
ThisBank=newbank(Size)
Ptr=GetBankPtr(thisBank)
Status=SHGetFolderPath(0,nFolderID,0,0,ptr)
if Status=0
// if status is 0 then the function worked
Path$=PeekString(ptr,0) ; peek a null termed string
else
#print "error polling path"
endif
Deletebank ThisBank
EndFunction path$



// Get the location of a Special windows folder
AppDir$=GetSpecialFolderPath(CSIDL_LOCAL_APPDATA)



// Get the Absolute location of the PlayBasic keywords file
KeyWordsFile$=AppDir$+"\PlayBasic\Info\KeyWords.txt"


//
ThisFile=ReadNewFile(KeyWordsFile$)
While Not EndOfFile(ThisFile)
Row$=ReadString$(ThisFile)

// Check if we're reading the Command anme keywords
if Row$="[Commands]"
//
Print "Found Keywords"
Repeat
CommandName$=ReadString$(ThisFile)
#print CommandName$
until CommandName$=""
endif


// Check if we're reading the Constant section
if Row$="[Constants]"
//
Print "Found Constants"
Repeat
CommandName$=ReadString$(ThisFile)
#print CommandName$
until CommandName$=""
endif

EndWhile

print AppDir$
Sync
waitkey


   





Q. Where the Command/Function parameters stored ?


    A.  The KeyWord.txt only stores the command names.   The parameter names are not stored internally.  So they can't be exported from the compiler.   There is a parameter listing though, which is located in a file called KeyWordsHelp.txt.  This file is part of the PlayBasic Help files and can be found in your Playbasic installation.  Eg. C:\Program Files\PlayBasic\Help\KeyWordsHelp.txt

    The file is just text file where each row contains the keyword name,  it's parameters and link to it's associated help page.    The three sections are separated with the pipe chr.  This thing..  |
   
    Here's a sample of the file.


ATan|Value#: Degrees#|help\commands\math\atan.htm
ATanFull|Y, X: Degrees#|help\commands\math\atanfull.htm
AutoCaps$|StringToConvert$: CapitalizedString$|help\commands\strings\autocaps$.htm
AutoCenterSpriteHandle|SpriteIndex, Flag:|help\commands\sprites\autocenterspritehandle.htm
BankQuantity|NumberOfBanks:|help\commands\banks\bankquantity.htm
Bin$|ValueToConvert: ResultString$|help\commands\strings\bin$.htm
BlendBitmapFont|FontIndex, RGB:|help\commands\fonts\blendbitmapfont.htm
BlurImage|ImageIndex, BlurAverage:|help\commands\images\blurimage.htm
Box|X1, Y1, X2, Y2, FillMode:|help\commands\graphics\box.htm



    The parameter field is separated into two halves by the colon : chr.  Inputs parameters are on the left,  Returns are on the right.   Null parameters (input/return) have a null result.    

     Input parameters are separated by the coma chr.




Q. How Do I Parse the KeyWordsHelp.txt  file ?


  A.  This PB example will parse through the entire KeyWord help file, and shows how to get the KeyWord, it's input/return parameters & the associated help file from each row using the SplitToArray function.  Just for fun.  :)


PlayBASIC Code: [Select]
// Read this in Debug/trace mode  -> outs to debug console

DIm Token$(1000)
DIm InputParmTokens$(1000)
DIm ReturnParmTokens$(1000)


// The location of the KeyWord help file
KeyWordsFile$="D:\Play_Basic\PlayBasicClassic\Help\KeyWordsHelp.txt"

// read through it
ThisFile=ReadNewFile(KeyWordsFile$)
While Not EndOfFile(ThisFile)
// parse this row
ParseKeyWord(ReadString$(ThisFile))
EndWhile
CloseFile ThisFile


print "done"

Sync
waitkey
End


Function ParseKeyWord(Row$)

TokenCount=SplitToarray(Row$,"|",Token$(),1)

If TokenCount>0
// Found Something

KeyWord$ =Token$(1)

Parmeter$ =Token$(2)

AssociatedHelpFileLocation$=Token$(3)

// Split Parameter section into Input & return parameters

TokenCount=SplitToarray(Parmeter$,":",Token$(),1)
if TokenCount=2

InputParameters$=Token$(1)
ReturnParameters$=Token$(2)

// split the input parmas in the seperate fields
Params=SplitToArray(InputParameters$,",",InputParmTokens$(),1)
endif

#print KeyWord$
#print "Inputs:"+InputParameters$
for lp=1 to Params
#print InputParmTokens$(lp)
next

#print "Returns:"+ReturnParameters$
#print "Help File:"+AssociatedHelpFileLocation$
#print ""

endif
EndFunction



   


Q. Where the Help Files located ?


    A.  The PlayBasic Help files and can be found in your Playbasic installation.  Eg. C:\Program Files\PlayBasic\Help\Commands\Index.htm

     They're HTML, so to view them you'll need either your own parser or a html view





thaaks

Wow! What a great introduction to the IDE and Compiler interaction!

Now let's see if some "teachable" IDE can be used for PB  ;)

Thanks for this valuable info, Kevin!

Big C.

yes... indeed... a interesting tut... where ist the tut to program a IDE   :P


slayer93

If I didn't have so much work already I would totally try to make an IDE. Although I never been so great with making anything that has a good UI.

Big C.

Hmmm... I should have  a look to purebasic... there are many examples for making window based programs... but I didn't have enough practice (and time)...