Migrating BASIC Programs to Delphi

 

Author: J. W. Rider (mailto:development@jwrider.com)

http://www.jwrider.com

 

 

Overview

Spoken and written languages can exercise a strong influence over the way that all people think.  Likewise, programming languages can constrain the way that software developers approach their craft.  Migrating programs from one language to another is not so much an operation of semantics and syntax translations as it is an issue of  rethinking how one programmer thought about a problem in one programming language for another.

 

Delphi provides a very straight-forward approach to translating the visual aspects of  other MS Windows programming languages.  However, complex programs will require significant non-visual conversions, and conversion efforts may find direct translation to be somewhat cumbersome until programmers start thinking about problems in terms of Delphi rather than some other language.

 

This secret to migrating BASIC programs to Delphi is to migrate BASIC programmers to Object Pascal.

 

A Very High-Level Language Comparison

 

Programming languages are all alike (kind of)

As far as programming languages go, the modern versions of BASIC are relatively similar to standard Pascal. Both languages contain ways of organizing memory to represent information in the form of named variables, to perform operations on the variables by storing into them the results of expressions, and to organize the operations in a modular and structured fashion.  Elementary arithmetic operations like addition, subtraction, multiplication and division are handled almost identically.  There are some cosmetic differences where BASIC includes type information for variables with a single character suffix, a feature that doesn't exist in Pascal. 

 

Language-specific features favor designed use

Beyond those cosmetic differences lay some more intrinsic differences.  BASIC is designed to formulate expressions easily.  Pascal is designed to make compilation efficient.  In order to formulate expressions easily, BASIC programs become sequences of statements that get executed a line at a time.  (Sometimes, it is easy to forget that the original BASICs were intended to be interpreted rather than compiled.  Executing statements a line at a time was much easier for interpreters.)  In order to compile efficiently, Pascal programs become a nested combination of control structures that get executed a statement at a time.  Of course, modern BASICs have adopted similar control structures in a way that complements the classic versions of BASIC; the execution of statements a line at a time is not lost.

 

Think language efficiency

It is this business about arranging the program to make compilation efficient that is the biggest obstacle in getting BASIC programmers to rethink their code in Pascal.  Indeed, it affects programmers in many languages that were designed to be mainly interpreted.  The syntactic rules for Pascal can seem a little confusing for the programmer who has a handle on BASIC.  For instance, the necessity of using the colon/equals operator (":=") rather than the simpler equals operator ("=") for assignments can seem a little distant at first glance.   Furthermore, there is the business with semi-colons because it looks to the line-oriented BASIC programmer that sometimes the semi-colons need to be put at the end of  lines and sometimes the semi-colons shouldn't be put at the end of them.

 

BASIC programmers already know about different languages

These syntactic "pecularities" turn out to be not particularly hard for migrating programmers to accept.  As a language, BASIC itself has evolved and been adapted to new environments and applications.  Each generation has provided a additional set of syntactic peculiarities of their own with which programmers would have to come to grips.   Even under MS Windows, several dialects of BASIC are thriving:  MicroSoft's VisualBasic, CA's Realizer, PowerSoft's PowerBuilder, and Borland's ReportSmith all show how the BASIC language can be changed to make  the language useful. 

 

You have to shift gears for higher performance

However, when you are trying to get sheer performance out of  a system, compilation down to native machine code is hard to beat, and that is where Object Pascal has a ready-made advantage.  However, programmers are going to need to shift gears in order to make the best use of this advantage.  The shifting of gears involves thinking about how to arrange program components to be more efficient and improve performance.  In the long run, the programmer who masters the skill of "thinking" in Pascal will discover that skill carries well to other programming languages.

 

 

An Example for Trimming Strings

Later in this paper, a comparison is made to distinguish between features in BASIC and corresponding features in Object Pascal.  Sometimes, there just isn't any corresponding feature.  For instance, some BASICs  have an RTRIM$() function that accepts a string expression as an argument and returns a string value that is the same as the string argument except that all trailing spaces have been removed; i.e., the string is right-trimmed.  This particular feature is easily emulated in Object Pascal by taking advantage of  the knowledge of how strings are stored in memory and a couple of other "tricks":

 

function RTrim( S:string): string;  { Right trim string function }

 

Note: You can't use the dollar sign as a part of the function name.  In BASIC, the dollar sign serves the same purpose as the ":string" following the end parenthesis, and is an intrinsic part of the name.  In Pascal, only alphanumerics and underscores can be used for identifiers, and the type must be explicitly stated when the identifier is defined.  This kind of Pascal string is limited to a maximum length of 255 characters. 

 

var i:integer;

begin

 

   for i :=  length(s) downto 1 do  { start looking at the last character }

                                    { and move back until all of the }

                                    { characters have been examined.}

 

Note: The "for" clause is not an Object Pascal statement by itself.  It must be combined with some kind of action statement to be complete.  Don't put a semicolon between the "do" and the body of the loop.  Since there is no "begin" following the "do", a single statement (in this case, a conditional statement) forms the body of the loop.

 

      { if the character being examined is a space, ignore it, and }

      { check the next character }

 

      if s[i]<>' ' then begin       { aha.  We've found the last }

                                    { non-blank character in the string. }

 

Note: The "begin" indicates that more than one statement will be executed if the "if" expression is true.  Indentation is somewhat a matter of personal taste.  The author has a preference for locating the "begin" on the same line as any prefixed clauses.  This is, by no means, conventional wisdom. 

 

         s[0] := char(i); { this "trick" shortens the string. }

         result := s;     { set the string return value }

         exit;            { return to the function caller.}

         end;             { end of block, end of if, and end for }

 

Note: The semicolon before the "end" is optional.  Again, it's a matter of personal preference as to whether you insert strictly optional semicolons.  The semicolon after the "end" is not optional.

 

      { if we get to this point, it means that the whole string }

      { was composed of blanks, so we return a string of length zero. }

 

   result := '';          { yet another optional semi-colon }

 

end; { end of function }

 

That  does the job, and you can use that in most places that you might have used the BASIC RTRIM$()

function.  However, it's not particularly efficient for a Pascal implementation.  An unknown number of characters are being moved when the function is called and when the return value is set.  Sure, it's limited to 255 characters, but it's the mind set for efficient and high-performing programming that we're trying to establish.  The way to do that is to avoid slow and wasteful practices. 

 

For instance, less stack space will be used by the code if the string is passed by reference as var parameter and modify the string in place.  Of course, if we really wanted to use the name RTrim to indicate a right trimming function, another name will be needed so that we can tell the difference between the function and procedure.  For instance, in the following example, the name is prefixed with an underscore to create a new name:

 

procedure _RTrim( var S: string); { Right trim the string variable S, }

                                  { in place }

var i: integer;

begin

    for i := length(s) downto 1 do

        if s[i] <> ' ' then begin { if isn't a space char }

            s[0] := char(i);

            exit;

            end;

    { String is all blanks; get rid of them all }

     S:= ''; { an empty string}

end;

 

 

Which is hardly distinguishable from the function defined as RTrim earlier.  Of course, it is hardly efficient to have two routines do basically the same thing.  Instead, have the less efficient code call the more efficient code:

 

function RTrim( S:string):string;  { right trim string function }

begin

    _RTrim(S);  { call the faster and more efficient procedure }

                { that modifies the local string variable in place }

    result :=  S;  { return the string value }

end;

 

This approach let's the migrating programmer have it both ways.  An RTRIM$() like function is available for use in string expressions.  On the other hand, more speed and efficiency are available readily whenever the programmer needs to tighten code. 

 

 

 


A Feature-by-Feature Language Comparison

 

In the section that follows, BASIC features are compared with features in Object Pascal that do much the same thing.  Where there might be some ambiguity, the interpretation of MS VisualBasic is followed.  There are six general categories:

 

1. OK.  The BASIC feature can be used in Object Pascal without significant changes.  Object Pascal may have additional uses of the same feature, and may even have more efficient features that can be used, but the programmer isn't going to have to change gears when dealing with the feature.

 

2. Renamed.  Object Pascal has a feature that does something equivalent to the BASIC feature, but in Object Pascal the feature is called something else. 

 

3. Similar.  The feature in Object Pascal does something along the same lines as the BASIC feature, but there is a signficant difference in the behavior. 

 

4. Different.  The named feature exists in Object Pascal, but means something unrelated to how it would be used in BASIC.

 

5. Not used.  The BASIC feature doesn't  correspond to anything available in Object Pascal.  Sometimes the effect can be minor.  For instance, a missing function can be created.  Other times, the code will need to be reworked in order to duplicate the behavior.

 

BASIC Feature             Comparable Usage in Object Pascal

 

Operators

 

Note: Operator precedence is different with Object Pascal from BASIC.

 

& (ampersand)                  To concatenate strings use the Concat function or the + operator.

 

* (asterisk)                        OK.  Object Pascal uses a similar scheme for mixed-precision arithmetic.  Also used for set intersection.

 

+ (plus)                               OK. Also used for string concatenation and set union.

 

- (minus)                            OK. Also used for set difference.

 

/ (slash)                               Similar.  Object Pascal always returns a floating point result.

 

\ (backslash)                      To divide two integers, use the div operator.  For mixed floating point operands, translate a\b into round(a) div round(b).

 

^ (caret)                             The easiest translation of a^b is exp( b * ln(a)) as long as a>0.   a^2 should be translated as sqr(a).  Polynomial expressions should not expressed as powers.  Instead use Horner's method. 

 

<                                           OK.

 

<=                                        OK.  Object Pascal also uses this to mean "subset of" in comparing sets.

 

>                                           OK.

 

>=                                        OK.  Object Pascal also uses this to mean "superset of" in comparing sets.

 

=                                           Similar.  For testing equality, the operator is the same.  For assignment, Object Pascal uses := rather than = .

 

<>                                        OK.

 

AND                                    OK.

 

EQV                                    For logical equivalence, use = .  For bitwise equivalence a EQV b, use not (a xor b).

 

IMP                                     For logical implication, use <=.  For bitwise implication a IMP b, use (not a) or b.

 

IS                                         Different.  In Object Pascal, the Is operator checks the ancestry of a class variable instance.  (In VB, a similar feature is the TYPEOF .... IS .... clause available in the IF...THEN....ELSE... statement.)  To check if two such instances reference the same object, use =.

 

LIKE                                   Not used.

 

MOD                                   Similar.  Can have integer operands only.

 

NOT                                    OK.

 

OR                                       OK.

 

Functions

 

Note:  In BASIC, the same name may be used for both a function and a statement,

and the two forms may work differently.  In Object Pascal, a single name can be used as

either a function or a procedure, but not both (at least, within the same scope).

 

ABS                                     OK.

 

ASC                                     Translate asc(s) as ord(s[1]) as long as length(s)>0.

 

ATN                                     Called ArcTan.

 

CHOOSE                           Not used.

 

CHR                                    OK.

 

COMMAND                      Object Pascal uses the ParamStr to return separate components from the command line.  See also, GetArgStr . 

 

COS                                     OK.

 

CURDIR                             Use GetCurDir function or GetDir procedure.

 

CVDATE                            Not used.

 

CCUR, CDBL, CINT, CLNG, CSNG, CSTR, CVAR

                                             In most cases, it is not necessary to do any conversion of types whatsoever.

 

DATE                                  Use GetDate procedure.

 

DATEADD, DATEDIFF, DATEPART, DATESERIAL, DATEVALUE

                                             Not used.

 

DAY, HOUR, MINUTE, MONTH, SECOND

                                             Not used.

 

DDB, FV, IPMT, IRR, MIRR, NPER, NPV, PMT, PPMT, PV, RATE, SLN, SYD

                                             Not used.

 

Derived Math Functions.              Not automatically defined in Object Pascal either.

 

DIR                                      Use FindFirst and FindNext.

 

ENVIRON                          Use GetEnv, GetEnvVar, or EnvStr.

 

EOF                                    OK. Object Pascal uses file variables instead of file handle numbers.

 

ERR, ERL                          Not used.

 

ERROR                              Not used.

 

EXP                                     OK.

 

FILEATTR                         Use GetFAttr procedure or FileGetAttr function.

 

FILEDATETIME              Use GetFTime procedure or FileGetDate function.

 

FILELEN                           Use FileSize function.

 

FORMAT                           Similar. See SysUtils.Format.

 

FREEFILE                        Not used.  Object Pascal uses file variables instead of file handle numbers.

 

GETATTR                          Use GetFAttr procedure or FileGetAttr function.

 

HEX                                    Use IntToHex function.

 

IIF                                       Not used.

 

INPUT                                Different.  In Object Pascal, Input is a predefined text file variable that is the default source for Read and ReadLn statements.  For transferring information from a file to variables, use Read or ReadLn.  Object Pascal  interprets then incoming character stream more in the fashion of the INPUT function than the INPUT statement.

 

INPUTBOX                       Similar.

 

INSTR                                 The Pos function is used to search for the existence, of one string within another.

 

INT, FIX                             Similar.  The Object Pascal Int function rounds in the same way  that FIX does.  There is no FIX in Object Pascal.

 

ISDATE, ISEMPTY, ISNULL, ISNUMERIC

                                             Not used.

 

LBOUND                           Use Low.

 

LCASE                                Not used.

 

LEFT                                  For LEFT$(x,n), use System.Copy(x,1,n).

 

LEN                                     For strings, called Length.  For variables, called SizeOf.

 

LOC                                    Use FilePos.

 

LOF                                    Use FileSize.

 

LOG                                    Called Ln.

 

LTRIM, RTRIM, TRIM  Not used.

 

MID                                     Called Copy. For MID$(s,a,b), use System.Copy(s,a,b).

 

NOW                                   Use GetDate.

 

OCT                                    Not used.

 

PARTITION                      Not used.

 

RGB                                    Not used.

 

RIGHT                               Not used.

 

RND                                    Use Random to return a random number between 0 and 1.  Random(n) returns a random integer between 0 and n-1, inclusive.

 

SEEK                                  Different.  In Object Pascal, Seek positions a file to a given record number.  To find the location of the current position in a file, use FilePos.

 

SGN                                    Not used.

 

SIN                                      OK.

 

SPACE                                Not used.

 

SPC                                     Translate SPC(x) as a width qualifier for an empty string.

 

SQR                                     Different.  In Object Pascal, Sqr returns the square of a number.  To find the square root, use Sqrt.

 

STR                                     Similar. A procedure rather than a function.

 

STRCOMP                        Similar. In Object Pascal, StrComp compares pchars vice string expressions.  Object Pascal does not support different compare modes.

 

STRING                             Different.  In Object Pascal, String is a reserved word.  There is no facility for creating a string of all the same character.

 

SWITCH                             Not used.

 

TAB                                     Not used.

 

TAN                                     To get the tangent of x, use sin(x)/cos(x).

 

TIME                                  Use GetTime.

 

TIMER                               Not used.

 

TIMESERIAL, TIMEVALUE

                                             Not used.

 

UBOUND                           Use High.

 

UCASE                               UpCase will raise a single character to upper case.

 

VAL                                     Similar.  In Object Pascal, Val is a procedure rather than a function.

 

VARTYPE                          Not used.

 

Statements

 

Object Pascal distinguishes between statements (which organize code together)

and procedures (which are executed).  BASIC includes a number of statements

that would be called procedures in Object Pascal.

 

 

BEEP                                  Not used.

 

CALL                                  Not used.  Procedures are always called when they are referenced.  Arguments must be enclosed in parentheses.

 

CHDIR                               OK. In Object Pascal, the ChDir procedure also changes the drive. 

 

CHDRIVE                          Not used.  Translate CHDRIVE "D" as ChDir('D:').

 

CLOSE                               Used to close a file.  Object Pascal uses file variables rather than file handle numbers.

 

CONST                               Almost identical in both Object Pascal and VB.  Object Pascal does permit the use of string concatenation, and reference of some library functions in evaluating the expression.  For GLOBAL CONST, simply define the constant in the interface of a shared unit.  Object Pascal also has "typed constants" which provides  a mechanism for initializing variables at compile-time.

 

DATE                                  Use SetDate procedure.

 

DECLARE                         Not used.

 

DEFxxxx                             Never used.  The types of variables must be declared individually.

 

DIM                                     Use Var.

 

DO...LOOP                        Use While...do begin... end or Repeat ... Until  ....  For EXIT DO, use Break.

 

ELSE                                   OK.  Object Pascal does not use ELSEIF,  but Else If  has same effect.

 

END                                    Different.  For END FUNCTION, END IF, END SELECT, END SUB, or END TYPE, simply use End.  To terminate a program, use Halt.

 

ERASE                                Different.  The Object Pascal Erase is used to kill external files. To free memory used by arrays, use the Dispose or FreeMem procedures.

 

ERR                                    Not used.

 

ERROR                              Use RunError.

 

EXIT                                   Similar.  For EXIT SUB or EXIT FUNCTION, simply use Exit.  For EXIT DO or EXIT FOR, use Break.

 

FILECOPY                        Substitutes are available.

 

FOR...NEXT                      Similar.  The counter must be a local or global ordinal variable.  Object Pascal does not use the STEP clause.  DownTo replaces To to iterate in the opposite direction.  Object Pascal does not use the NEXT statement.  For EXIT FOR, use Break.

 

FUNCTION                       Similar.  STATIC and PRIVATE are not used.  To make local variables static, convert them to typed constants. To make a function private, declare the function in the  implementation of a unit rather than in the interface. For EXIT FUNCTION, use Exit.  For END FUNCTION, use End.  Object Pascal supports nested functions and procedures.  Functions and procedures can be declared within another function or procedure.

 

GET                                    Use Seek and Read or Seek and BlockRead.

 

GLOBAL                           To make variables global, place their declaration in the interface of a common unit.

 

GOSUB...RETURN          Not used.

 

GOTO                                 OK, but frowned upon by structured programming purists.  Labels must be declared in a Label declaration.

 

IF...THEN...ELSE...          Similar. There is no ELSEIF, but Else If does the same thing.  Only a single statement is permitted after the Then or Else, but the statement may be a compound statement delimited by Begin and End.

 

INPUT                                Different.  In Object Pascal, Input is a predefined text file variable that is the default source for Read and ReadLn statements.  For transferring information from a file to variables, use Read or ReadLn.  Object Pascal interprets then incoming character stream more in the fashion of the INPUT function than the INPUT statement.

 

KILL                                   Use DeleteFile or Erase.

 

LET                                     Not used.

 

LINE INPUT                     Use ReadLn.

 

LOCK, UNLOCK             Not used.

 

LSET                                   Not used.

 

MID                                     Not used.

 

MKDIR                               OK. A procedure rather than a statement.  See also, CreateDir.

 

MSGBOX                          Similar.

 

NAME                                 Use Rename.

 

NEXT                                  In Object Pascal, For loops iterate on a single statement, which may be a compound (Begin...End) statement.

 

ON ERROR                       Use Object Pascal exception handling instead.

 

ON...GOSUB, ON...GOTO

                                             Not used.

 

OPEN                                 To open a file, use Assign to associate the name of a file with a file variable.  To append to a text file, use Append.  To open an existing file, use Reset. To overwrite an existing file or create a new one, use Rewrite.  For binary files, specify the record length with Reset or Rewrite.  Modify the FileMode variable to change the access and lock modes.

 

OPTION BASE                 Not used.

 

OPTION COMPARE      Not used.

 

OPTION EXPLICIT        Always explicitly declare identifiers.

 

PRINT                                Use Write or WriteLn to print to file or device.  Object Pascal uses file variables rather than file handle numbers. SPC and TAB have no meaning.  WriteLn forces the next output to begin at the start of the next line.

 

PRIVATE                           Different.  In Object Pascal, Private is a directive for specifying visibility of object and class members.  To make procedures and functions accessible only from within the unit in which they are declared, declare the procedure or function in the implementation of the unit in which declared.

 

PUT                                     Use Seek with Read or Seek with BlockRead.

 

RANDOMIZE                   Does not take an argument.

 

REDIM                               To allocate dynamic variables, use New or GetMem.  For REDIM PRESERVE, allocate memory for the new variable and copy the old values to the new memory, and erase the old variable with Dispose or FreeMem.  A ReAllocMem function is also available.

 

REM                                   Comments are enclosed between { and } or between  (* and *).

 

RESET                                Different.  In Object Pascal, Reset is used to open an existing file.  There is no facility for closing all opened files automatically.

 

RESUME                           Not used.

 

RMDIR                               OK. A procedure rather than a statement.

 

RSET                                   Not used.

 

SEEK                                  OK. Object Pascal uses file variables rather than file handle numbers.

 

SELECT CASE                 Use Case...Of....

 

SET                                      Different.  In Object Pascal, a Set is a structured collection of unique ordinal values.  To assign a class variable,  use assignment (:=).

 

SETATTR                           Use SetFAttr.

 

SHELL                               Use WinExec.

 

STATIC                               To make persistent variables, declare them as "typed constants".

 

STEP                                   Not used.

 

STOP                                  Use Halt.

 

SUB                                     Use Procedure.

 

TIME                                  Use SetTime.

 

TYPE                                  Similar.  Users can define many other kinds of types  in Object Pascal.  The VB user-defined type corresponds to the Object Pascal Record.

 

Types

 

ANY                                     Typechecking of arguments is suppressed by simply omitting the type (i.e., using "untyped VAR parameters").

 

AS                                        Different.  In Object Pascal, As is used in conjunction with typecasting of classes.  To separate an identifier from its type, Object Pascal uses a  : (colon).

 

BYVAL                               To pass an argument by value, don't use Var or  Const in parameter declaration.  To pass an argument  by reference, Var needs to be placed in front of the parameter declaration.

 

CURRENCY                      Not used.

 

DATE                                  NA.

 

DOUBLE                           OK.

 

EMPTY                              Not used.

 

FALSE                                Is a predefined identifier rather than a reserved word.  Ord(False) is 0.

 

INTEGER                          OK.

 

LONG                                 Use LongInt.

 

ME                                      Use Self.

 

NEW                                   Similar.  In Object Pascal, New is an executable procedure or function that cannot be referenced in a variable declaration.

 

NULL                                  Not used.

 

SINGLE                             OK.

 

STRING                             Similar. Object Pascal strings are limited to 255 chars.  Object Pascal pchar  variables may contain up to 64k chars.

 

TRUE                                  Is a predefined identifier rather than a reserved word.  Ord(True) is 1 (positive) rather than negative (-1).

 

VARIANT                           Not used.