program development environment
- PDE -
QuickBasic to XBasic
June 1, 1999
The following notes were written by an XBasic programmer who converted a 10,000 line QuickBASIC 4.5 console-mode program to XBasic in two long days of intense work. He added and integrated a GUI in another day with the interactive GuiDesigner built into the XBasic program development environment.
Also see the work-in-progress QuickBasic keywords to XBasic equivalents table in the XBasic web-site.
I made most changes with a "monitored" wildcard replace, which means you view and confirm each replace. I burned myself a few times with unmonitored wildcard replaces. With XBasic, you can do monitored find and replace quickly with the F11 / F12 function keys.
Load your QuickBasic program as a text file, otherwise XBasic will not be able to figure out what's up. After all, XBasic understands XBasic syntax, not QuickBASIC.
Save a new copy of the file you're converting every 5 minutes as a separate file. You should end up with a series of files like prog0000.x, prog0001.x, prog0002.x, ... prog0025.x when you finish. That way if you royally screw up some step you can go back to the most recent good working copy. Doing this saved me hours of work and possibly suicide.
Type .h in the upper text area to get a list of shortcut "dot commands" including find/replace examples. Entering dot commands in the upper text area is often much faster than working pulldown menus.
By the way, most of the find and replace work goes much faster and smoother if you set the find and replace to be case sensitive, which you only need to do once. Just select "Edit" then "Find" and depress the toggle button labeled "Case Sensitive". Hold the shift key down to do reverse find/replace with F11/F12.
Remember, the XBasic programming language is case sensitive. So FOR is a keyword, and for, For, foR, and FoR are all different variables.
If you don't find an equivalent for something fundamental, check the XBasic standard function library. Check the "\xb\doc\library.doc" manual, or better yet, select "Help" + "StandardLibrary" from the menu bar in the main XBasic window. For graphics, read the whole "\xb\doc\graphics.doc" manual first.
step by step process
step 1 : Replace all occurrences of SUB with FUNCTION. You need to monitor this process, otherwise you'll accidentally change all occurrences of GOSUB into GOFUNCTION. A QuickBasic function that does not return an argument is called a SUB, while every XBasic function is called a FUNCTION, whether they return an argument or not. This frees up the SUB keyword for "subroutines" within functions.
step 2 : Go through your entire program and find all subroutines, which means every location your program GOSUBs to. Find the beginning and end of each subroutine and do the following:
|Put a SUB keyword before the subroutine name and remove the trailing colon from the name. For example, if the beginning of a subroutine is a line dothis:, change the line to SUB dothis.|
|Replace the RETURN keyword at the end of the subroutine with END SUB.|
|Find all RETURN keywords within the subroutine and change them to EXIT SUB.|
step 3 : Make sure no RETURN keywords remain in your program.
step 4 : In every context, XBasic functions require parentheses after the function name, even if the function takes no arguments. Find every occurrence of functions that take no arguments and add () after the function name. For example, change funcname to funcname().
step 5 : As I recall, in QuickBASIC you return a value from a function by assigning a value to a variable with the same name as the function. In XBasic, you simply write RETURN (value). In XBasic, a function named a() can contain a variable named a that works just like every other variable in the function and has nothing whatever to do with returning values from the function.
step 6 : XBasic array names are always followed by square brackets, as in array[n] vs array(n). One reason XBasic programs are easier to read is because you can always tell when something is a variable, an array, or a function. So go find all your arrays and change their parentheses to square brackets.
step 7 : Execution of XBasic programs always begins with the first declared function. The PROLOG of XBasic programs is for type declarations, function declarations, and constant declarations - nothing else. If you have any executable code before your first function, put it in an Entry() function and make sure it's the first function declared in the PROLOG.
step 8 : I don't remember the scope rules for QuickBASIC very well any more, but all XBasic variables are automatic and local to the function they're in unless they're declared otherwise after the beginning of the function. If you want to share a variable with another function you need to put the variable in a SHARED statement in both functions, or add a # prefix to the variable name everywhere it appears. XBasic supports the following scopes:
|AUTO||local & automatic - may live in a CPU register|
|AUTOX||local & automatic - never lives in a CPU register|
|STATIC||local & permanent - value retained between function calls|
|SHARED||shared & permanent - share with functions that declare it SHARED|
|EXTERNAL||shared & permanent - shared with static-linked modules that declare it EXTERNAL|
step 9 : Shared constants must be defined in the PROLOG, and have a $$ prefix, as in $$MyConstant. So CONST MyConstant = 32 in QuickBASIC becomes $$MyConstant = 23 in XBasic.
step 10 : Local constants defined within a function must begin with a $ prefix, as in $ThisConstant. So CONST ThisConstant = 11 in QuickBASIC becomes $ThisConstant = 11 in XBasic.
step 11 : In QuickBasic, to convert strings to numbers you write:
value# = VAL (string$) ' VAL returns double precision
In XBasic you can convert strings to any data type you want:
value = SBYTE (string$) ' signed byte (16-bits)
value = UBYTE (string$) ' unsigned byte (16-bits)
value = SSHORT (string$) ' signed short (16-bits)
value = USHORT (string$) ' unsigned short (16-bits)
value = SLONG (string$) ' signed long (32-bits)
value = ULONG (string$) ' unsigned long (32-bits)
value = XLONG (string$) ' native long (signed 32-bits)
value = GIANT (string$) ' signed giant (64-bits)
value = SINGLE (string$) ' 32-bit IEEE floating point
value = DOUBLE (string$) ' 64-bit IEEE floating point
value$ = STRING (string$) ' character string
value$ = STRING$ (string$) ' character string
To exactly duplicate the QuickBasic VAL(), replace it with DOUBLE().
step 12 : To make a string of several of the same character, QuickBASIC has the STRING$() intrinsic. But STRING$() in XBasic converts any data type to a string representation. To generate a series of the same character with XBasic, change STRING$() to the two argument form of CHR$(). For example, change QuickBASIC a$ = STRING$("a",5) to an XBasic a$ = CHR$('a',5).
step 13 : To create formatted strings for printing or other purposes, see FORMAT$().
step 14 : XBasic replaces MID$() on the left side of the assignment operator with STUFF$().
step 15 : By default, XBasic passes function arguments by-value, while QuickBASIC passes function arguments by-reference. To make XBasic pass an argument by-reference, prefix the argument with @, as in a=func(@a,@b,@c$). When called functions do not change an argument, by-value and by-reference are functionally equivalent. Note: pass-by-value is faster for numeric variables and pass-by-reference is faster for string, array and composite variables.
step 16 : The default data type of XBasic variables & arrays is XLONG integer, not SINGLE.
step 17 : Please send additional steps that will help others convert QuickBasic to XBasic. Some steps must be performed after some steps and before others, so please consider this issue carefully and state where your new steps belong.