Basic Syntax

Top  Previous  Next

Basic Syntax

 

Statements

A statement consists of a single verb and any arguments or parameters suitable for that verb.  Multiple statements can be placed on a single line by separating them with a semicolon (;).  Statements can be preceded by a label, which consists of a label name followed by a colon.  Label names must follow the same naming conventions as numeric variables.

 

Variables

There are two types of variables in Business Basic: string and numeric.  Variables that end in a "$" character are treated as string variables.  They can hold any amount of text data, limited only by system memory.  Numeric variables can contain any number or integer.  UnForm sets precision to 10, so that up to 10 digits to the right of the decimal are maintained accurately.

 

Variable names can be up to 127 letters, digits, and underscore characters, and must start with a letter.  Variables can’t start with "fn" and should not start with "uf".

 

work$, account01$, and cust_name$ are valid string variables.

cust-name$ is invalid.

amount, period_12,  and six are valid numeric variables.

 

Arrays

Arrays can be defined for both string and numeric variables.  Arrays must be defined to a fixed number of elements with a DIM statement, and array elements can then be referenced as variables.  Arrays can contain up to three dimensions.

 

dim amount[12]  defines a 13-element array, a[0] … a[12].

dim x$[1:6,1:20] defines a 2-dimensional string array.  The first dimension ranges from 1 to 6, the second from 1 to 20.  x$[2,20] would be a valid element in this array.

 

Arrays can be re-dimensioned with the REDIM statement.  When an array is re-dimmed, all its existing elements are retained as long as they are part of the new array dimensions.

 

You can get the first and last indexes of an array with a DIM() function.  These examples assume a string array named array$.

 

dim(read min(array$)) is the lowest index, typically 0
dim(read max(array$)) is the highest index
dim(read max(array$,2)) is the highest index of the second dimension of the array

 

 

Associative Arrays

The language also supports arrays that use string keys rather than indexes.  Both text and numeric values can be stored this way.  There is no DIM statement required to define such an array.  Simply start using the array syntax with string keys, such as:

 

states$["CA"]="California"
state$="CA"
desc$="My state is "+states$[state$]

 

If an array key is used that doesn't exist, it is treated as null or 0.  An associated array can be cleared with a dim statement and the base variable, such as "dim states$".  Beware of using a reference to an array element.  This will create an element if it doesn't exist, which is likely not the intention:

 

 if states$[state$]>"" then found=1

 

If state$ is null or otherwise doesn't exist in the array, a null array entry will be created for it.

 

In addition to a key, associative array elements have a 1-based index.  You can get the number of elements in the array with: dim(read num(array$)).  For example:

 

first=1,last=dim(read num(a$))

for i=first to last

 b$+=a$[i]+$0a$

next i

 

You can find the array index of a given key.  This statement will set position to the index number of the array element "mykey".  If that key isn't found, position will be set to 0.  This is useful for determining if a key exists in an array.

 

 position=dim(index a$["mykey"])

 

Likewise, you can find the key of a given index (note this will produce an error 42 if the index value is out of range):

 

 keyval$=dim(key a$[2])

 

You can remove a key from an array:

 

position_dropped=dim(drop a$["mykey"])

 

 

Other Uses of DIM

The dim statement can be used to initialize strings to a specified length.  Dim a$(12), for example, will set a$ to 12 spaces.
 
The dim statement can be used to initialize a string template.  Dim state$:"id:c(2*),name:c(20*),taxrate:n(4*)" creates a string template with variables state.id$, state.name$, and state.taxrate.  The above template describes state.id$ as a variable-length character field, with a suggested length of 2, a second character field, state.name$, and a numeric field, state.taxrate.

 

There are additional capabilities in string templates, but those are beyond what is generally used in UnForm coding.  Details about those additional features can be found in the pxplus documentation at pvxplus.com.

 

 

Functions

Many functions are available in Business Basic.  Most will be familiar to a Basic programmer.  Functions consist of a word, an opening parenthesis, one or more arguments, and a closing parenthesis.  The function returns a string or numeric result, which is typically used as part of an expression, or in an assignment.  Wherever a string or numeric value can be used, a string or numeric function can be used.  In addition to internal Business Basic functions, UnForm also provides some functions that perform tasks typical to print stream environment in which it runs.

 

String and numeric representation

Strings are made up of concatenated bytes.  They can be represented as literals inside double quotes, such as "Name:", or as hexadecimal strings inside "$" delimiters, such as $1B45$ for Escape-E.  They can also be made up of combinations of literals, hex strings, string variables, and functions that return string values.  These values are combined using the "+" operator to concatenate each string together.  For example, a string containing quotes could be constructed one of these ways: chr(34)+"some text"+chr(34); or $22$+"some text"+$22$, or quote$+"some text"+quote$.  Since chr(34) and $22$ both represent a quote character, and it would be possible for the variable quote$ to contain the same, all these expressions can represent the same string.

 

Substrings can be derived from a string variable with the syntax stringvar(start [,length]).  For example, if account$ is "01-567", then account$(4,3) would return the value "567".  Substrings references with positions that aren't in the string result in errors, so care must be used.  To avoid the possible errors, the mid() function can be used.

 

Numbers can be represented as integers or decimal numbers, or, like strings, can be represented as expressions containing literal numbers, numeric variables, and numeric functions.  With numbers, there are more operators available to produce the expressions.  A literal number is just a series of digits, with an optional decimal point and an optional leading minus sign.  1995.99 and -100.433 are valid numbers.  Other punctuation, such as thousands separators or currency symbols, are invalid in a number though they can be added when a number is formatted as a string for output.

 

Operators

Business Basic has the following standard operators:

 

+        concatenate strings or add numbers, depending on context

-        subtraction

*        multiplication

/        division

^        exponentiation

=        testing for equality, or assignment, depending on context

>        testing for greater than

>=        testing for greater than or equal to

<        testing for less than

<=        testing for less than or equal to

<>        testing for inequality

()        controlling precedence

and        combining expressions with logical "and" in conditions

or        combining expressions with "or" in conditions

 

+=        appends right-side value to a string or adds to a number

-=        subtracts right-side value from a number

*=        multiplies a number by right-side number

/=        divides a number by right-side number

++var, var++, --var, var-- increments or decrements a numeric variable by 1, either before or after an operation, depending on the position of the ++ or -- operators.

 

 

If Then Else

The structure of IF…THEN…ELSE        statements are simple and unblocked.  The IF must be followed by an expression to test.  The expression can be simple or complex, and must resolve to a single Boolean or numeric result.  For numeric results, a 0 is considered false, and anything else is considered true.  Once resolved, if true the THEN clause is executed, otherwise the ELSE clause, if present, is executed.

 

Both the THEN clause and the ELSE clause can contain any statements, including nested IF statements.  A closing END_IF after a THEN or ELSE clause will terminate the conditional nature of statements following it.

 

Here are some examples of  IF statements:

 

if amount < 0 then text$="Credit Balance"

if x$="A" then desc$="Acme Rental" else if x$="S" then desc$="Smith & Sons" else desc$="N/A"

if testmode then dummy$=set(1,1,10,"Test Mode") end_if; goto exitsub

 

UnForm’s code block parser also supports blocked if-then-else syntax, like this (optional elements indicated in square brackets):

 

 If condition [then][:]

         Statement1

         Statement2

 [else

         Statement1

         Statement2

         … ]

 End if

 

The key elements are the condition "if condition" line and the closing "end if".  The structures can be nested, with additional if statements inside the if or else sections.  The trailing colon on the IF line is optional.

 

 

While Wend Loops

One of Business Basic's looping structures is the WHILE..WEND loop.  At the top of the loop is a while condition statement, where the condition is evaluated like an IF clause.  As long as the condition is true, or returns a non-zero value, the statements up until the closing wend statement are repeated.  To escape the loop, you can use the BREAK verb, the EXITTO label verb, or set variables such that the condition is false before executing the wend verb.  To iterate the loop from within, use the CONTINUE verb.

 

Here is a simple WHILE…WEND syntax that substitutes (") with (') in a string:

 

x=pos($22$=work$)

while x > 0

work$(x,1)="'"

x=pos($22$=work$)

wend

 

For Next Loops

Another commonly used loop structure is the FOR…NEXT loop.

 

The most common FOR statement identifies a variable, a start value, an end value, and an optional step value.  The variable is set to the start value; the loop statements are executed until a NEXT statement is encountered; the variable is incremented by the step value; and, until the end value is exceeded, the loop statements are repeated.  To exit the loop before the end value is reached, use the BREAK verb or the EXITTO label verb.  To iterate the loop from within, use the CONTINUE verb.  Here is an example that would perform the same substitution shown above (though more slowly):

 

for i=1 to len(work$)

 if work$(i,1)=$22$ then work$(i,1)="'"

next i

 

Another construct parses a string into delimited segments and runs the loop code for each segment.  The delimiter is always the last character of the string.  For example, many UnForm values are linefeed delimited lists.  A linefeed can be represented as hexadecimal $0a$, so you could use a loop like this:

 

result$=""

for item$ from items$+$0a$

if item$="" continue

if mid(item$,1,1)="*" result$+=item$+$0a$

next

 

A final construct loops over the indexes of an array, either numeric for standard arrays or string for associative arrays.  This code would convert an associative array into a tab-separated-values string.

 

result$=""

for k$ index states$[all]

result$+=k$+$09$+states$[k$]+$0a$

next

 

Switch/End Switch

The switch statement provides a concise logical testing capability, replacing potentially a large set of 'if' statements.  The switch statement sets a test value, either a variable or expression.  Inside the body of the switch are case statements, which can name one or more comma-separated values to compare with the test value.  If there is a match, the code below executes until there is a break statement.  There can be any number of case statements to test any number of possible conditions.  There can also be a default statement, which matches any test value, and can be thought of is an 'else' statement.   The switch can test either string or numeric values, though the internal case statements must match the switch value type.

 

switch lcs(state$)

case "az"

 name$="Arizona"

 break

 

case "ca"

 name$="California"; break

 

default

 name$="unknown"

 break

end switch

 

File Handling

Business Basic has very powerful facilities for handling files.  Not only are there intrinsic keyed file types, but also text files and pipes can be used.

 

If the application with which UnForm is integrated is written in ProvideX, then full native access to the data files is available.

 

If UnForm is working with a non-Business Basic application (e.g. C, Cobol, Informix, Oracle, etc.), there are additional means to obtain data, via ODBC, pipes, or command lines.  There are high level functions to work with external data sources, such as sqlconnect() and sqlexec(), and objects, such as http, textfile, inifile, or binfile.

 

Below are comments about directly working with files.

 

 

Opening Files

 

File access is performed through an open file channel.  The OPEN statement opens the file on a numeric channel in preparation for later file access.  Open(99)"customers.dat" opens the named file on channel 99.  Channel numbers can range from 1 to 32767, though the operating system will typically impose a limit on the number of simultaneous channels that can be opened.  Channel numbers must be unique.  Once opened, that channel number is no longer available until closed.  To avoid conflicts with channel numbers, it is common to use a special function that returns an available channel number, UNT.  Here is a typical syntax:

 

cust=unt

open(cust)"customers.dat"

 

After that, file access verbs can use the cust variable to access the "customers.dat" file.

 

To open a pipe channel, you could do the following:

 

faxlist=unt

open(faxlist)"|sqlexec 'select cust,faxnum from customers'"

read(faxlist)line1$

 

labelprt=unt

open(labelprt)">lp –dlabels"

print(labelprt)"To: "+name$

print(labelprt)"    "+address1$

 

Reading Files

 

There are two verbs used for reading channels: READ, and READ RECORD.  The READ verb understands line and field separators, whereas the READ RECORD verb reads blocks of a specified size or whole records, in the case of intrinsic keyed file types.  The READ verbs accept several options, including "key=string", "ind=index", "err=linelabel", "end=linelabel", and others.  Full details can be found in the language reference manuals.  Labels can be actual labels in code (label:), or a symbolic label, such as *next, *break, or *continue.  UnForm also recognizes err=next as a synonym for err=*next.

 

To read from an intrinsic keyed file (ProvideX files only), you might use one of these:

 

read(cust,key=custkey$,err=next)*,name$,*,*,*,*,faxnum$

 

read record(cust,key=custkey$,err=next)custrec$

name$=custrec$(7,30),faxnum$=custrec$(112,10)

 

To read from a pipe or a text file, you may not use a key= clause, so you just read sequentially through the file:

 

read(faxlist,end=done)cust$,faxnum$

 

 

Writing files

 

You probably would not want to write to your application files, but you may well want to write to external devices or log files.  Writing is performed with these verbs: WRITE or WRITE RECORD and PRINT.  Each uses a channel number and arguments to print.  PRINT terminate its values with a line-feed character ($0A$), unless a comma follows the last argument.  WRITE RECORD will write a single string variable without any termination so it is suitable for binary or blocked output.  WRITE terminates values with an internal field separator, normally $8A$, which is not useful when writing files that will be used by other applications, but which is recognized by READ.

 

print (logfile)"Customer: "+custname$+" printed on "+date(0,tim:"%D-%M-%Y:%Hz:%mz")

dim block$(128); block$(1)=custname$,block$(31)=str(amount:"000000.00"); write record(log)block$