News:

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

Main Menu

Code Conversion Tools (Convert Amos To PlayBASIC)

Started by kevin, March 28, 2013, 07:39:10 PM

Previous topic - Next topic

kevin


 
 
Amos To PlayBASIC (Work In Progress Blog)




Release Builds



    See Amos TO PlayBASIC V0.27 (initial release - 14th May 2013)


 
BLOG






 Code Conversion Tools

      Programming has enough little annoying problems as it is, let alone trying to move code around between languages.   Bizarrely the problem hasn't really improved that much since when I started programming back in 1982, at least then there was a good reason, like.. you know... assembly :)  -  Today,  there's lots of conversion tools between main stream languages, but there's just so many languages out there, lots and lots of legacy code just ends up sitting around doing nothing.

      I dunno about anybody else, but I try to hang onto my legacy source codes in one big retro collection.   The oldest stuff dates back to the mid 90's (don't really have any my 8bit stuff ;( ).. Anyway,  it's mostly AMOS and 68k Assembly from the Amiga days.  The asm isn't much use, but a lot of legacy BASIC code can be.   The trouble with languages like Amos, is that the source code files are tokenized, so you either need AMOS to view them, or a conversion tool.



 Converting AMOS & AMOS PRO BASIC to PlayBASIC

      Those with a long memories might recall I've had a few tinkers with writing translation programs over the years,  even getting a 'mock up' translator to produce actually working conversion  of some simple AMOS programs (and a few other dialects) programs.     While the Amos convertor worked (to a point) it's basically a brute force solution, since the translator is working in string level making it potentially very hit and miss.          

      Normally when parsing code, you'd translate the text stream into a tokenized state, then decipher what's going on from the tokens.    But for AMOS programs, it makes sense to load the tokenized source code and decode that directly.    I'd looked at doing this before and got a fair way into it, only to find a tool that already did most of it.    Today though, i've dragged out my old source and cut'n'pasted a new project from it's ashes.    Only took a few hours to get it a reasonable translation of a real world binary Amos program.  

      What you have to remember though, is that AMOS is huge language and I have absolutely NO intention of building a one stop shop convertor.    Rather,  the objective is make the tool able to spit out a reasonable translation that a programmer can then use as a basis for the PlayBASIC version. Meaning the program LOGIC should be in tact, but the of course there's no easy way of mapping the AMOS command set to PlayBASIC without writing an abstraction layer..   Which is possible for simple programs (since that's how the previous test worked) but pretty unrealistic for medium to large AMOS programs.


 What's Working?

        The loader supports about 90% of low level primary token types that AMOS uses, what's missing is the command set declarations.  Basically each command name has a numeric token, in some situations that have two or more variations.    When you combine  that with programs can use external command sets that plug into it, then the dark clouds of doom are soon circling over head.     To combat this, i've make declaration tables external..  So yes, you can improve the quality of the translation by working out what token is what...  :)  

         At this point the program is basically just spiting out a text file that represents the original AMOS source code (it only knows about 50 commands).   While I'll probably leave that in,  What I want to do is post process this into something that's more PlayBASIC Friendly.    


kevin

#1
   Amos Tokens Into Generic Tokens, then Source Code Out

      Been having another play with conversion program this morning, the thinking has always been to try and break whatever the input stream is (in this case AMOS) down into a simplified intermediate form, then run a bunch of translator parses over the intermediate stage before dumping the token it out as text.      In the previous session, the loader was merely skimming through the Amos code, sticking the text fragments together and dumping it all out to the debug console.    This is fine if all you want is a text version of the original code.   But I want to translate the core of it directly to PlayBASIC.

       To tackle this means introducing an intermediate step, where we create a representation of the input code in typed tokens, much like how the syntax highlighter works.   Once in this form, we can skim through the program and make the known syntax modifications to code.    For example, AMOS has an ADD operator, which is much like the INC operator in PB (it has that also).   Now since PlayBASIC doesn't have an  ADD,  then we'd need the translation parser to catch these cases in the intermediate code.    The parser just  rips out the old tokens and replaces them with equivalent PlayBASIC syntax.  

        So this AMOS code.
              ADD Score, 100

        could be replaced with,
 
               Score=Score+100
        or
               Score+=100


    This simple example shows is the real beauty of having an intermediate stage, as it not only allows for some simple pattern matching of the input tokens, but we can rearrange them without any great fuss.   Much much easier than trying to do this in string level..  


    Collisions

    When you move code between BASIC dialects keyword collisions are pretty common.   A collision is where a 'variable' or array name, command name that's legal in one language just happens to be reserved word in the target language.   Bellow is an example AMOS program (view as is), but syntax highlighted as PlayBASIC code.

           
PlayBASIC Code: [Select]
  Set Buffer 50 

` *=-------------------------------------------------------------------=*
`
` AGE - ANIMATION - PLANAR DOT RENDERING (Brute Force)
`
` By
`
` By Kevin Picone
`
` Last Updated - 10th, Apr, 2012
`
` (c) Copyright 1997/98/1999/2000- 2012, Kevin Picone
`
` www.UnderwareDesign.com
`
` *=-------------------------------------------------------------------=*
`

` Sorry but AMOSPRO seems to require absolute include paths ??
` SO, YOU'LL HAVE TO TWEAK THE PATHS IN ORDER TO RUN
` THE DEMOS FROM AMOS/AMOSPRO correctly on your machine

` To make the pathing less annoying, here we store the 'root path'
` in a variable APPPATH$ .. Then use this through our program.


apppath$ ="Dh0:/AGE_V102/"

` Set the location of the AGE lib..
age_library_path$ =apppath$ +"Includes/Asm/Age.lib"

` Include the AGE wrapper into your AMOS project
Include "Dh0:/AGE_V102/INCLUDES/AMOS/AGE_V085.AMOS"



` *=-----------------------------------------------------------------=*
`
` >> ALLOC AGE RESOURCE TABLEs <<
`
` *=-----------------------------------------------------------------=*

scrns =15
cops =15
blkdatas =10
banks =11



fonts =12
filecachesize =50000
dcachesize =10000

age_alloc_resources[scrns , cops , blkdatas , banks , fonts , filecachesize , dcachesize ]


` -----------------------------------
` Create our LOWRES / INTERLEAVED AGE screen in Chip Memory '
` -----------------------------------
type =age_lowres
` TYPE=TYPE+AGE_INTERLEAVED
type =type +age_planar

age_open_screen [0 , 320 , 256 , 8 , type ]
age_open_screen [1 , 320 , 256 , 8 , type ]

current_buffer =0



` -----------------------------------
` Load IFF into this a temp screen.
` -----------------------------------

file$ =apppath$ +"GFXFILES/PICTURES/TREE.IFF"

age_open_screen [3 , 320 , 256 , 8 , type ]
age_load_iff_to_screen [file$ , 3 ]

` copy the palette from the backdrop picture in the chip buffers

age_screen_copy_palette [3 , 0 ]
age_screen_copy_palette [3 , 1 ]


` -----------------------------------
` Create standard / simple copper list for viewing our screens.
` -----------------------------------
age_create_copper [0 , 0 , 3 , 8 ]
age_create_copper [1 , 1 , 3 , 8 ]


` -----------------------------------
` Set copper to view our AGE screen
` -----------------------------------
Doke $00DFF096 , $00000180 : REM Kill Bitplane + copper DMA

age_wait_top_of_frame

age_show_copper [1 -current_buffer ]

Doke $00DFF096 , $00008180 : REM restore Bitplane + copper DMA


` -----------------------------------
` Direct ALL RENDERING To OUR Screen
` -----------------------------------
age_set_screen [current_buffer ]


` -----------------------------------
` Load a Font
` -----------------------------------


fonts$ =apppath$ +"gfxfiles/fonts/"

age_load_font [fonts$ +"Alex8.font" , 2 ]

age_set_font [2 ]



Degree


` CReate a bank to store our queue version


` Init the star queue (buffers)

width =320
height =256
pixel_spacing =4

size =width *height

count =(width /pixel_spacing )*(height /pixel_spacing )

age_create_bank [1 , (size +2 )*6 ]


age_get_bank_ptr [1 ]
queue_pointer =Param


queue_dot_layer [width , height , pixel_spacing , queue_pointer ]
Login required to view complete source code



  If you look closely you'll notice there's a few collision in this simple.   So the logic was translated, the code wouldn't compile in PB because of the collisions.    

  The solution is to skim through the known Variables in the input code and cross match them with PB or whatever the target is.   If there's a collision, the input variable gets renamed.  Hopefully the renamed version doesn't collide with some other variable also.   It's a matter of searching the variable table.

  Another change is that AMOS allows spaces in built in commands, where PB doesn't.   I think generally what it'll do is replace the spaces with underscores and add prefixs to the AMOS functions.    This allows  the programmer to write 'emulations' of the Amos function set in PB then include them, which is exactly how I got my test code work originally.        

  Anyway,  something to think about..    

kevin

#2
   Amos To PlayBASIC - Up and running

      In the previous session, I'd been building up an intermediate representation of the input program.     The next thing on the to do list, was write some conversion routines to skim through the token buffers and shuffle the fragments around.   The parsers don't have to understand the input stream, they're just pattern matching the sequences of tokens,  so when key tokens are found, it compares the following ones with a pattern, if there's the assumptions match, it rearrange them, if not, it continues on.   So the process  really couldn't be much easier

      So far there's four skims over the buffers.  The first looks at converting the Procedure declarations and procedure calls into FUNCTIONS.  AMOS can't actually return values from procedures within an expression.  Rather anything following the "End Proc" statement is resolved and the answer is put into a global variable called either Param, Param# or Param$  This makes the translation a bit clunky, as the parameter s after the end proc statement need to be evaluate into our 'global', in order to get working result.

      Ie. AMOS EXAMPLE

    addthings[10,200]
    print param

procedure AddThings[A,B]

End Proc [A+B]      



      Ie. Equivalent code in PB

PlayBASIC Code: [Select]
     global Param,Param#,Param$

addthings[10,200]
print param

Function AddThings(A,B)
param = (A+B)
EndFunction





     The second pass looks at declaration statements, focusing on DIM statement.  Amos PRO allows arrays to be stacked within the declaration,  PB doesn't support this,  so the parser runs through and inserts DIMs between them.   Dead simple and functionality the same.    The third pass looks at math operators,  focusing on INC,DEC and ADD functions.  One of the larger differences is the AMOS has a number of Operator styled commands found in really old school BASIC from yesterday year,  where PB doesn't generally support this in favor of functional design.    Yes... PB has an INC/DEC statements, but they're limited to operating upon variables.  In AMOS it's viable to go,  INC MyArray(Index),  Do this is PB and nothing will happen to the array, the operation is being executed on the register.     So these expressions need to be reformatted into ++ and += and -= statements in order to be functionally the same.      The last pass looks at loop and compare operations.   But they're pretty much identical...  
 
     Here's a sample of our AMOS test input code which the PlayBASIC conversion  bellow it.



  `  --------------------------------------------------------
  `  This test program for AMOS TO PlayBASIC conversion
  `  --------------------------------------------------------

  stuff =5

  DIM stuff(100 ) , cool(50 ) , testarray(10  , 10 +f ) , cool2(1  , 2  , 3 )

  PRINT "Hello World"

  Add index  , 5
  Add stuff(10 ) , 10  : Add cool2(1  , 2  , 3 ) , 12345

  Add index  , 1  : Inc index

  Dec index
  Dec cool2(1  , 2  , 3 ) : Inc cool2(1  , 2  , 3 ) : Add helloworld  , Cos(45 )

  Inc index
  Inc stuff(10 )
  Inc stuff(10 )

  PRINT stuff(10 )

  a# =10
  b# =2.3

  PRINT "casting integer"
  PRINT a *b#

  test2[100  , 100 ] : test2[20  , 20 ]

  test3[10  , 100  , "1000" ]

  testroutine

  testroutine  : testroutine

   PRINT Param

 Input a$


   a =10
   b =5
   WHILE a >b
       PRINT a
       Dec a
   WEND

   IF a =b THENPRINT "A=B"
   IF a =b
       PRINT "A ='s B"
   End If



   IF a <>b
      PRINT "option 1"
Else If a =b
   PRINT "option 2"
  End If





Procedure TESTROUTINE
    Shared stuff()
    PRINT stuff(10 )
End Proc


Procedure TEST2[a  , b ]
    PRINT "2 input params"
End Proc


Procedure TEST3[a  , b#  , c$ ]
    result =a +b# +Val(c$ )
End Proc[result ]



   

PlayBASIC Code: [Select]
   `  -------------------------------------------------------- 
` This test program for AMOS TO PlayBASIC conversion
` --------------------------------------------------------

stuff =5

DIM stuff(100 ) : DIM cool(50 ) : DIM testarray(10 , 10 +f ) : DIM cool2(1 , 2 , 3 )

PRINT "Hello World"

index +=5
stuff(10 )+=10 : cool2(1 , 2 , 3 )+=12345

index +=1 : index ++

index --
cool2(1 , 2 , 3 )-- : cool2(1 , 2 , 3 )++ : helloworld +=Cos(45 )

index ++
stuff(10 )++
stuff(10 )++

PRINT stuff(10 )

a# =10
b# =2.3

PRINT "casting integer"
PRINT a *b#

test2(100 , 100 ) : test2(20 , 20 )

test3(10 , 100 , "1000" )

testroutine()

testroutine() : testroutine()

PRINT Param

Input a$


a =10
b =5
WHILE a >b
PRINT a
a --
EndWhile

IF a =b THENPRINT "A=B"
IF a =b
PRINT "A ='s B"
EndIf



IF a <>b
PRINT "option 1"
ElseIf a =b
PRINT "option 2"
EndIf





Function TESTROUTINE()
Shared stuff()
PRINT stuff(10 )
EndFunction


Function TEST2(a , b )
PRINT "2 input params"
EndFunction


Function TEST3(a , b# , c$ )
result =a +b# +Val(c$ )
_EXITFUNCTIONHERE: Param =(result )
EndFunction





      Even though this is a simple AMOS program, the PB conversion doesn't quite run as yet, but 99% of tedious changes are made for you.  The bigger the code base the more time saving we'll get.    The conversion is pretty quick also, being able to load the original AMOS file,  build the token view, export that to text, run the conversion pass and export that out as text, with an  Average conversion time of  20 milliseconds.



     C64 BASIC Tokens

      Been looking at C64 BASIC as another possible legacy conversion source and it seems like a likely enough candidate.    The only problem being is you've have to emulate the C64 graphics hardware in order to run them without massive changes.  But you could pull the logic out easy enough.
   
      C64 Basic Program Format




kevin

#3
  Amos To PlayBASIC - Parameter Fixing & Rearranging Expressions

      Messing around with the translation layer this morning and hit upon a few situations where the parameters and operations need to be rearranged in order to create something evenly remotely meaningful in the output code.   I pretty much knew that was going to occur, so been mulling over a few quick and easy solutions.     What i'd originally envisaged is building some type of programmable expression modifying engine.  Where the input and out actions can be defined externally.  This would enable the convertor greater customization and potentially open the way for translation many dialects of BASIC  to PB.      But obviously that's wayyyyy more effort than I'm prepared to put in up front.   I do think that some type of ambiguous translator would be very useful tool though.    

      To show the problem, imagine we have some other BASIC (in this case AMOS) which includes an Instring function, but it's called Instr.  Now even though they're the same in Amos + PB,  just imagine they're not.  Changing the function names is trivial, but lets say that in AMOS the parameters are the in reverse order, making them NEEDLE, HAYSTACK, where PB needs them in HAYSTACK, NEEDLE form. 

      So our input code might look like this,  

      POs=Instr("World", "Hello World")

      But we need this,

      POs=Instr("Hello World","World" )


     If they're simple literals, like in this case, that's easy, just swap them.  But this doesn't work when either side is an expression.    Remember the convertor doesn't even try to understand the program on a whole, it's really just a series of reactions to known circumstances.    Could throw an expression parser into it, but then it needs to type aware. Could short cut it a little since AMOS can't return values from user functions, but  I'm not too keen on that.     The current simpler approach revolves around building some functions to remap parameters (as groups of tokens) within such expressions.    The initial version isn't as flexible as it needs to be, but ideally if parameters knowingly require swapping, it'll skim that section and make the best educated guess it can.   If it's not a positive match (ie gets lost) it just does nothing and moves on.    

     The worker functions in the translation layer are all generic, they don't care what the input language is.  So hopefully once a few of these translator tidbits are put in place, it'll become more obvious as to how to externalize the process, or at very least large chunks of it.    I can imagine using such the frame work to convert legacy PlayBASIC V1.00 programs into it's successor for example..   :)


kevin


    Amos To PlayBASIC - Expression remapping cont..

           Been out on the mountain bike most of the afternoon, but wrote 95% of the remapping functions the other day.   Just needed the last little function so the user can nominate the output order.   The process is multi pass, it skims the expression and finds the likely parameters, then moves the tokens from the line array to a temp buffers, remaps them and the result written back to the original array.

           Given the limited number of built in conversion methods, the results thus far are pretty reasonable, and more importantly but library is all pretty painless to use.  Now that there's a good collection of operator functions, some type of dumb action script seems quite viable, and that's really what I'm mainly interested in.   


kevin

#5
Amos To PlayBASIC - Operator Remapping

       Each time i fire it up, the solution keeps improving, and only really big stumbling block has been the expression order remapping stuff, but that's now up and running.  So far, it's only used when dealing with the ROL/ROR operators.   Which present another little challenge, since  PlayBASIC has these are functions, so the parameters need remapping completely into expressions to get something meaningful in the output.     But it all seems to eb fitting together nicely for once.   The remapping pass leaves us with the tokens run that represent each parameter, so just needed to insert the requires param back into the expression in front of the current pointer..  

       Which just means that when it sees AMOS code like this

       Ror.l  1, Variable

       we get this fragment back..  

       Variable=Ror32(Variable,1)
   
       Provided the parameters make sense, the output should make sense..   should, but it's probably possible they won't either :)


     
  Sample Conversion

        Bellow we have today's translation of the standard AMOS sample  code.   What's missing is mapping of the String function to native versions.    But you can wrap (make functions in Pb that do what the Amos version does), which works fine..





  `  --------------------------------------------------------
  `  This test program for AMOS TO PlayBASIC conversion
  `  --------------------------------------------------------

  stuff =5

  DIM stuff(100 ) , cool(50 ) , testarray(10  , 10 +f ) , cool2(1  , 2  , 3 )

  PRINT "Hello World"

  Add index  , 5
  Add stuff(10 ) , 10  : Add cool2(1  , 2  , 3 ) , 12345

  Add index  , 1  : Inc index

  Dec index
  Dec cool2(1  , 2  , 3 ) : Inc cool2(1  , 2  , 3 ) : Add helloworld  , Cos(45 )

  Inc index
  Inc stuff(10 )
  Inc stuff(10 )

  PRINT stuff(10 )

  a# =10
  b# =2.3

  PRINT "casting integer"
  PRINT a *b#

  test2[100  , 100 ] : test2[20  , 20 ]

  test3[10  , 100  , "1000" ]

  testroutine

  testroutine  : testroutine

   PRINT Param




   a =10
   b =5
   WHILE a >b
       PRINT a
       Dec a
   WEND

   IF a =b THEN PRINT "A=B"
   IF a =b
       PRINT "A ='s B"
   End If



   IF a <>b
      PRINT "option 1"
   Else If a =b
      PRINT "option 2"
    End If



    Wait Key



Procedure TESTROUTINE
 `    Shared STUFF()
 `    Print STUFF(10)
End Proc


Procedure TEST2[a  , b ]
    PRINT "2 input params"
End Proc


Procedure TEST3[a  , b#  , c$ ]
    result =a +b# +Val(c$ )
End Proc[result ]



     s$ ="Hello World"
     number$ ="666"

     PRINT s$

     PRINT Upper$(s$ )
     PRINT Lower$(s$ )

     PRINT Left$(s$  , 5 )
     PRINT Right$(s$  , 5 )
     PRINT Str$(12345 )+s$
     PRINT Val(number$ )


     PRINT String$(s$  , 5 )
     PRINT Space$(10 )+s$
       PRINT Flip$(s$ )
     PRINT Repeat$(s$  , 5 )

     PRINT Instr(s$  , "World" )
     PRINT Instr(s$  , "World"  , 2 )

     PRINT String$(""  , 10 )+"nothing"


     a =255
     DIM memory(10 )


     Ror.b(Cos(100 )+Sin(45 )) , ggggg
    Ror.l cool +45 +Cos(450 ) , a

Ror.l 5  , a
    b =123456

     Ror.w a  , c  : b =22222
       Ror.b $0000FFFF  , c








   Rol.b 3  , c



     PRINT Bin$(a )


  Wait Key




       Becomes,


PlayBASIC Code: [Select]
   `  -------------------------------------------------------- 
` This test program for AMOS TO PlayBASIC conversion
` --------------------------------------------------------

stuff =5

DIM stuff(100 ) : DIM cool(50 ) : DIM testarray(10 , 10 +f ) : DIM cool2(1 , 2 , 3 )

PRINT "Hello World"

index +=5
stuff(10 )+=10 : cool2(1 , 2 , 3 )+=12345

index +=1 : index ++

index --
cool2(1 , 2 , 3 )-- : cool2(1 , 2 , 3 )++ : helloworld +=Cos(45 )

index ++
stuff(10 )++
stuff(10 )++

PRINT stuff(10 )

a# =10
b# =2.3

PRINT "casting integer"
PRINT a *b#

test2(100 , 100 ) : test2(20 , 20 )

test3(10 , 100 , "1000" )

testroutine()

testroutine() : testroutine()

PRINT Param




a =10
b =5
WHILE a >b
PRINT a
a --
EndWhile

IF a =b THEN PRINT "A=B"
IF a =b
PRINT "A ='s B"
EndIf



IF a <>b
PRINT "option 1"
ElseIf a =b
PRINT "option 2"
EndIf



WaitKey



Function TESTROUTINE()
` Shared STUFF()
` Print STUFF(10)
EndFunction


Function TEST2(a , b )
PRINT "2 input params"
EndFunction


Function TEST3(a , b# , c$ )
result =a +b# +Val(c$ )
_EXITFUNCTIONHERE: Param =(result )
EndFunction



s$ ="Hello World"
number$ ="666"

PRINT s$

PRINT Upper$(s$ )
PRINT Lower$(s$ )

PRINT Left$(s$ , 5 )
PRINT Right$(s$ , 5 )
PRINT Str$(12345 )+s$
PRINT Val(number$ )


PRINT String$(s$ , 5 )
PRINT Space$(10 )+s$
PRINT Flip$(s$ )
PRINT Repeat$(s$ , 5 )

PRINT Instr(s$ , "World" )
PRINT Instr(s$ , "World" , 2 )

PRINT String$("" , 10 )+"nothing"


a =255
DIM memory(10 )


ggggg = ROR8(ggggg , (Cos(100 )+Sin(45 )))
a = ROR32(a , cool +45 +Cos(450 ))

a = ROR32(a , 5 )
b =123456

c = ROR16(c , a ) : b =22222
c = ROR8(c , $0000FFFF )








c = ROL8(c , 3 )



PRINT Bin$(a )


WaitKey






               
    PlayBASIC AMOS WRAPPER

       The following is an example of what emulation of the AMOS functions might look like in PlayBASIC.    If you cut and paste this into the top of the above code, the example compiles and runs.   There's a few differences like the AMOS defaults to radians, so trig functions like COS/SIN will behave differently, and the you'd need to manually SYNC the buffer at some point.    But it works...  

PlayBASIC Code: [Select]
   `  -------------------------------------------------------- 
` PLAYBASIC AMOS COMMAND SET WRAPPER MOCK UP
` --------------------------------------------------------

Global Param,Param#,Param$

psub String$(s$,Count)
s$=make$(left$(a$,1),Count)
EndPsub s$

psub Space$(Count)
s$=make$(" ",Count)
EndPsub s$

psub Repeat$(s$,Count)
s$=make$(s$,Count)
EndPsub s$

Psub Instr(Heystack$,Needle$,Pos=1)
result=instring(Heystack$,Needle$,Pos)
EndPsub result







     

kevin

#6
  Amos To PlayBASIC - Extension Support ?

     For a 2D focused language,  AMOS was more than big enough language on it's own, but one of the more interesting additions is the extension support.   These allowed 3rd party developers to build native command sets (in assembly) which could plug directly into the core language.   From what I can pick up about the format, they're pretty particular, namely requiring the code being assembled PC relative.   This would allow native code to the cut'n'pasted into compiled exe's without needing to relocate it.  Without that it'd simply fail.  

     Extensions present an annoying little problem for the convertor, being that in order to export Amos source code to text accurately,  we need to know what extensions the programmer had installed (in their installation of the AMOS) at that time.   Since AMOS source code files don't seem to include this information, making it pretty much impossible to automate.    Knowing this up front,  I've been planning on letting the user select a command mapping for each extension slot.   Unfortunately since slots are limited, extensions can clash. Meaning getting a really good translation from source codes that are extension  dependent, will no doubt take a bit fiddling..   Can't do much about that.


Exporting Command Sets From Extensions

     Since extensions are structured and thankfully include a list of commands internally, it should be possible to skim through them and drag out at least a list of the command keywords and hopefully the token ID's/offset also.  So in theory, you run the tool over some binary extension and it spits out a text file for the convertor.   The Amos To PlayBASIC convertor mapping files are just text files full of  token = name declarations.   So each line has a declaration, with the number token value and the string representation of the command name.    

  Example Command Mapping fragment.  



;----------------------------
; SCREEN
;----------------------------
$04FE,Set Buffer
$09EA,Screen Open
$0A04,Screen Close
$0AAE,Screen Hide
$0C6E,Screen
$09A8,Screen Copy

$00000A18,Screen Display
$00000B58,Screen Width
$00000B74,Screen Height
$00000A5E,Screen Colour
$00000A90,Screen To Back
$00000A72,Screen TO Front



     So when the token in the input stream is value $00000A18  we just spit out the "Screen Display"  text in it's place in the output.  The convertor doesn't try to understand the input code at all.  The translator just traps the known core stuff and tweaks that, command sets are beyond the scope so it hasn't got a clue about them.    

     To make the declarations currently,  I'm just converting my existing programs, then skimming through looking for any unknown tags in the output.    If you run WinUAE with AMOS in the emulator, it's relatively easy to build up a mapping.    I've only bothered to do the stuff that's in my own programs, so you're more than likely to find missing token declarations in your AMOS programs also.    But the quality can be improved upon  by editing the command set mapping files.  

     Anyway, if I can get the extension parsing to work, then that will about do.  Just need to slap an interface on it and that'll do.  



     Amos Extension Links

     * AMOS Pro Extension - Basic Layout (Assembly overview)



kevin

 Amos To PlayBASIC - Cont..

       After a few days away from the project, I'm back adding support for loading extensions declarations into the Amos decoder.   The only extension I appear to have installed, is something called Jwindows which is a way to use Amos to create OS legal apps with AGA chipset support.   The main program that uses it is the G3D editor, which was useful when testing the command set mapping support.    The G3d code is around 400K of Amos code for the GUI frontend and the conversion seems pretty accurate now.    You can't actually port that particular program, since all the rendering code is actually done in assembly.    But you can pull all the logic out it and that's the point. 

      Leading up to last weekend, i'd been looking at decoding the extension command tables directly from the Amos Extensions themselves, with some pretty mixed results.    Found a few resources online about the file format, but there seems to be some sketchy data sections in the few that i've found anyway.  Where it's getting some of the commands names out of a couple, but gets completely lost of others.   I'm sure it'd doable, but beyond the scope of the project as it stands now. 

      Another thing i've messing around with this afternoon is batching the conversion.  If all your projects use the same extensions (or none of them), then getting it to just convert an entire folder of old Amos projects seems a lot easier to me.   This works, but you get the odd project where it hangs the parser.   Not too sure what the cause of that is at the moment,  but it will happen on some files for sure (Amos files can have machine code embedded within them, the convertor doesn't have a clue about that).     So if the decoder hits something oddly unique in your Amos source code file and there's no decoder to handle it built in, then it'll more than likely die..

     
         
   
Conversion Quality ?

       The conversion passes haven't really changed since the last update.  For me, I tended to use AMOS to build tables / data conversion/ algorithm proofs mainly.  Which tend to be pretty small Amos programs.     These seem to to convert really well.  Where as programs that are bound to the behavior of Amos command sets won't, without some serious abstraction layer work from You!  -  It's possible to doing something like that, but in a throw away freebie..  that's never going to happen !

       


ATLUS

#8
Kevin maybe you some day create PlayBasic mod. In which it will be possible to use C++ syntax (PlayCPP())?

kevin

QuoteKevin maybe you some day create PlayBasic mod. In which it will be possible to use C++ syntax (PlayCPP())?

  why would you want that ?


ATLUS

#10
Because i think cpp syntax better than basic, and it has more potential.

And line - ;
block's zone - {...}

kevin

Quote from: ATLUS on April 17, 2013, 08:23:17 AM
Because i think cpp syntax better than basic, and it has more potential.

And line - ;
block's zone - {...}

  The idea of having a C++ edition of PB makes absolutely no sense. 



kevin


  Amos To PlayBASIC - Expression Remapping Cont..

     Been away on a cycling weekend since late last week and still sore some days later, but ya get that.   Firing this up tonight and been dropping in some generalize expression remapping.   Picking through some of the example program in AMOS and there seems to be handful of situations where the input code has to be rearranged to make some useful in the output.   The only ones that need radically changes to made them work are implicit statements such as the roll operators, or the Read/Input  statements.   This type of syntax is common in many traditional dialects of BASIC.

     Sometime last week I added a set of functions to help with rewriting expressions at token level, but even though they're fairly high level, these have been wrapped into even simpler interfaces.  The new interfaces makes it easier to create a behavior tables.   So when the convert pass hits a command/function name token it searches the table and reacts accordingly.   So there's handle for mapping operators to function calls,  standard function and command calls. Only thing left to wedge in is support for expression where the remapper has to remove the parameter. 

      Ie. Statements like this,

         Input #1, Variable$


       Would need to be rearranged into,

         Variable$=ReadString$(1)
   

        This shouldn't be too much trouble, since I've already got a solver for converting the math operators to function calls, here it just needs to remove the inserted result field.   The coolest thing about the convertor thus far is that once the Amos file is loader,  the process is largely generic.    Which has been one of my personal  bug bears with writing convertors over the years. 

       

  Batching Performance..
   
         Dropped batch support into the program last week also, but was running into the odd program that would hang the conversion.  One program that would hang it, wasn't actually an Amos encoded source code file, it was some Amos code saved out as text with the extension .AMOS.  The other one turned out to have machine code chunks embedded in the binary, which obvious can't be decoded.   Unless you're willing to write a 68K disassembler..         

         Performance wise the convertor is actually pretty quick, averaging around 250 milliseconds for the 480K G3D source code.  Where the program is loaded/decoded,  dumped to straight text, converted to PB and dumped out as text again.   The text folder has about 180 programs in it ATM,  and conversion averages at about 40 seconds.



kevin

#13
  Amos To PlayBASIC - Front End

      The conversion engine has progressed to a point where it's more than a little useful, it's not perfect, but it's able to handle  a good percentage of my personal AMOS programs, and thus good of Amos code on the internet (there's lots & lots of it BTW).      In my programs there's still the odd Amos opcode that it doesn't understand, but those can be tweaked in the external token declarations.   Meaning the community will be able to improve the conversion results by tweaking the keywords.   I wouldn't bother asking me to do it for you, that won't be happening !

      Tonight's little task has been to jam the conversion engine includes into the standard tool template.  The template is a just a project with same old menu / scrolling console system that's used in the last few throw away apps.    For this one, I think we can get away with just dumping the output to the console.  Which is how I've been testing it previously but from from debugger console.   So only real difference is the conversion is the #print statements turn to console prints.

      The tool only has two modes at this point, those being convert file and convert path.   it does need some switches to toggle stuff on/off like recursive conversion so you can point it an a folder and it'll do all of them.    So the only GUI stuff it needs is a setting dialogs, but should be able to cut'n'paste most, if not all it from some of the other tools.   Was tempted to build in complete in Flexi, but figured with the existing stock pile of code it'd be less effort to jam everything together.  

      Only drama i've been having so far is a strange crash when loading the token def's, not exactly sure what the cause is, so will have to suss it out later.  Anyway, bellow we can see the standard (in not familiar) shot of the tool..  I can't imagine it looking much different in the final,  although unlike some of the other PB tools this one actually requires PlayBASIC installation to work.

kevin

#14
    Amos To PlayBASIC - Extension Mapping

         Things are back up and rolling again after the crashing dramas of last week.  Which seemed fairly trivial initially but turned out to be a right pain to track down, ultimately turning out to be an overflow with fragment searcher.   It's funny how such a simple issue would create all sorts of odd behaviors in the program afterwards.  The  overflow was writing data into/over other structures, making it die in all sorts of strange ways.   But since that's been fixed it's all running perfectly.  

         Prior to the problems,  I'd been wedging the conversion routines into the stock template,  so tonight i've continued hooking the various parts of the interface up to conversion engine.   So far there's only going to be two settings pages, one with general properties such as 'recursive folder scanning' & output to console flags.    The other is to allow the user to create extension mappings.  

        The Extension remapping window is a bit more work, but seemed like nothing a good old cut'n' paste session couldn't fix.     The bulk of the gui code was initially cut from the 'Play-Pic2Map',  I had  figured making a new window would just be a cut'n'paste with some replaces,  but it turns out that the gadget code was all hooked back to the parent structures, meaning to make a second/third windows, you end up with double/triple the code.  Not a fan of that, so converted all the common stuff like the gadget drawing routines into generic functions.   It's still a bit of a mess, but it's a lot less code than it was and things can be reused between windows..      

        Amos programs can have something like 26 extensions libraries plugged in. I'm pretty limited in terms of what gadgets I actually render though, so i've gone with display the list as an array of Text messages with a 'Load" button to replace any one of them.   There's only 10 per page, so added a tree of option buttons to page through them.   Pretty simple, but easy to use.  When the user clicks the LOAD button they'll be prompted with a windows dialog,  where hopefully they select the extension they want.   As with anything GUI related, the back end has to idiot proof then users selection.    In this case scanning the file to see if it actually is a extension mapping file.   Not a huge task, but one of those little things that users never think twice about, that programmers can't avoid..  

        Anyway, here's a bit of a piccy of current progress.   Will probably let the user load/save their mappings as will.