Basic language elements
This topic includes information about the following basic language elements:
- Character set
- Data types
- Statements
- Preprocessor and compiler directives
- Identifiers
- Textual literals
- Variables
- Variable references
Character set
The basic unit of Synergy DBL is the ASCII character. (Appendix B: ASCII Character Set contains the complete ASCII character set.) ASCII characters are combined into sequences that represent the elements of Synergy DBL. Certain characters, called delimiters, separate adjacent language elements in a statement. Note that identifier names and keywords are case insensitive in DBL.
This documentation refers to the following ASCII character subsets:
Numeric |
0, 1, 2, 3, 4, 5, 6, 7, 8, and 9 |
Alphabetic |
Uppercase characters A through Z and lowercase characters a through z |
Alphanumeric |
Both numeric and alphabetical characters |
Alpha |
All ASCII characters except the nonprintable characters (for example, carriage return, line feed, and form feed) |
Data types
Synergy DBL supports all of the data types listed in Data types.
Statements
Synergy DBL provides six types of statements:
- Declarative
Declarative statements declare the variables and definitions that the routine can access. Many, but not all, declarative statements appear in the data division or class definition of your program. The declared variables can be local to the routine, global to the routine, or used to exchange data with other routines.
- Data manipulation
Data manipulation statements directly change data.
- File manipulation
File manipulation statements access records within a file or group of files.
- Control
When a routine is being executed, control begins with the statement that follows the PROC statement and flows sequentially to each successive statement. Control statements alter the order of execution by directing control to another statement, transferring control to another routine, ending processing of the current routine, or returning control to a referencing routine. This type of statement is used to create loops and internal functions within a program.
- Input/output
Input/output statements control the exchange of data between the executing program and the input/output devices attached to the computer system. Such devices include printers, terminals, mass storage devices (like disks and floppies), and any other data transmission devices attached to your computer system.
- Interprogram communication
Interprogram communication statements pass and obtain data from interactive processes.
In this documentation, we refer to the statement name as a “keyword.” See Synergy DBL Statements for information about individual statements.
Preprocessor and compiler directives
Preprocessor directives are instructions for the preprocessor and are implemented before any code is compiled. Compiler directive statements instruct the Synergy compiler and are evaluated only when a program is compiled. Directives are not included in the resulting executable program. See Types of directives and syntax for more information.
Identifiers
Identifiers are used as names for namespaces, classes, methods, subroutines, functions, parameters, records, fields, and properties. Identifiers begin with an alpha character (or an underscore in Synergy .NET), optionally followed by a sequence of alphanumeric characters, underscores (_), and dollar signs ($) that identify a statement, variable, or routine to the compiler. For example, Read, a10, namelast, and TAX$RATE_single are all valid identifiers. Destructor method identifiers prefix a tilde (~) to the name of the class.
Identifiers are not case sensitive. For example, NAME_FIRST is the same as name_first and NAME_first.
An identifier section is one of the sections in a nested identifier which may include namespace, class, or member name. For example, the following identifier has three identifier sections:
mynamespace.myclass.myfield
The maximum length of an identifier section is 30 characters on Windows and Unix and 31 characters on OpenVMS.
All identifiers within a scope, such as classes and structures in a namespace or member identifiers in a class, must be distinct, independent of kind, except where the names are identical and resolved via overloading, such as two routines with the same name but different parameters. A scope is defined to be the smallest of one of the following groupings that has the identifier declared as one of its members, not including inherited members:
- Namespace
- Class
- Structure
- Record
- Group
- CATCH block
- Local data block
Thus, you cannot have two fields with the same name, or a field and a method with the same name in the same class, but you can have two methods with the same name in the same class if their method signatures are different. A field name and a property in the same class can have the same name as long as the case is different.
You can’t have two classes with the same name or a class and structure with the same name in the same namespace.
Two method signatures are considered to match if their identifier, number of arguments, and argument types match exactly. Two subroutine or function signatures are considered a match if their identifiers match exactly.
Keywords
Keywords (like READ, END, and .DEFINE) have predefined meanings in Synergy DBL and identify statements and compiler directives. They must be spelled exactly as documented.
Replacement identifiers
A replacement identifier defines a text string that is to be substituted for the identifier throughout the program. A replacement identifier is defined by the .DEFINE statement.
Variable names
Variable names are identifiers that refer to data records, groups, and fields. A variable name can have a maximum of 30 characters. Although variable names appear in a program listing exactly as you typed them, the compiler translates the names to uppercase. For example, the compiler recognizes both of the following identifiers as the identifier ABCDE:
aBcdE
abcDe
Statement labels
You can label any statement in the procedure division with a symbolic name. Several of the program control statements can reference this label, enabling you to transfer control to a specific statement during program execution. For example, you might use a label to transfer control to an error-trapping routine or when using a CALL statement.
The statement label must be the first nonblank item in the statement, followed by a comma and must be unique within the routine. A statement label can have a maximum of 30 characters on Windows and Unix and 31 characters on OpenVMS.
Here’s an example:
call lbl02 ;Unlabeled, references label lbl02 . . . lbl02, ;Labeled incr flg return
Routine names
Routine names identify which main routine, external subroutine, or function is being referenced. Like all other identifiers, a routine name can have a maximum of 30 characters on Windows and Unix and 31 characters on OpenVMS.
To call a global routine from within a class that contains a routine of the same name, include ^global as part of the routine name path. For example,
xcall ^global.sub1()
Data reference operation names
A data reference operation name identifies a data reference operation. See Data reference operations for more information.
Textual literals
A textual literal is either a sequence of characters enclosed between matching delimiters (single or double quotation marks) or a sequence of numeric characters, which may be preceded by a plus or minus sign. A literal represents a specific value that is defined at compile time and cannot be changed during execution.
In Synergy .NET, a literal or literal cast as type object or passed to a parameter of type object has its type changed from a Synergy literal type to the corresponding .NET literal type, and then it is boxed. (For example, “abc” is type string, and 10 is @int.) If you want a Synergy literal type instead, cast the literal as the desired Synergy type (@a or @i).
An alpha literal is a sequence of characters enclosed in matching single or double quotation marks. An alpha literal can be up to 255 characters long.
Here are some examples of alpha literals:
- 'This is an ALPHA literal'
- "as is this one ........."
If an alpha literal contains either a single or double quotation mark and you’re using the same character as the delimiter, you must use two successive characters to represent a single embedded mark. The examples below illustrate embedded delimiters: two successive quotation marks are required to specify one quotation mark within the literal.
- "An" "is embedded"
- "quotation mark at end"""
If the embedded character is different from the ones delimiting the literal, you don’t need to double the embedded character (as shown in the examples below).
- "An ' is embedded"
- ' "Quotation marks are present"...'
Sometimes it’s more convenient to split an alpha literal into smaller physical parts. For example, you might do this if you’re using the literal to initialize an entire record and you want to append comments to each field. The Synergy compiler concatenates several alpha literals if they are separated only by blanks and tabs. (If sections of the alpha literal are on continuation lines, each line must begin with the continuation character [&].)
For example:
"This is " "an alpha " "literal"
and
"This is " &"an alpha " &"literal"
are functionally the single alpha literal
"This is an alpha literal"
The blanks and tabs between the separate alpha literals are not part of the concatenated literal. (See Continuation lines for a warning about splitting alpha literals across two or more physical lines.)
Alpha literals are case sensitive.
Decimal literals
A decimal literal is any consecutive sequence of numeric characters, which may be preceded by a plus (+) or minus (–) sign. A decimal literal can consist of a maximum of 28 digits. The compiler strips nonsignificant leading zeros to a minimum of one digit. For example, the literal 00003 is stored as 3. The literal 000 is stored as 0.
Here are some examples of decimal literals:
- 273949830000000000
- 1
- -391
Implied-decimal literals
An implied-decimal literal is a sequence of not more than 56 numeric characters, which may be preceded by a plus or minus sign. A maximum of 28 digits can appear before the decimal point, and a maximum of 28 can occur after it. The decimal point cannot be the first or the last character in an implied-decimal literal; at least one leading and trailing digit must appear before and after the decimal point.
Here are some examples:
- 1234.567
- 123456789012345678.0123456789
- +18.10
- 0.928456989
- -518.0
The compiler strips nonsignificant leading and/or trailing zeros prior to processing.
Integer literals
You cannot explicitly write an actual integer literal in a source line in the same way that you can specify alpha, decimal, and implied-decimal literals. However, if you include a decimal literal in an arithmetic expression with an integer variable, the compiler builds an integer literal into the code.
You can also use %INTEGER with a numeric literal argument to create an integer literal. |
Error literals
An error literal has the format $ERR_mnemonic, where mnemonic is an error identification mnemonic. One error literal is defined for every trappable runtime error. (For example, $ERR_DIVIDE specifies the “Divide by zero” error.)
The entire error literal is treated as a decimal literal, and you can use error literals with ONERROR statements, in I/O error lists, and anywhere else in your program that you can use decimal literals. Here’s an example:
onerror($ERR_IOFAIL, $ERR_DIGIT) proc_err1, ($ERR_EOF) proc_err2 read(CHN, data, rec_id) [$ERR_IOFAIL=proc_err1]
The Synergy Errors tab contains a complete list of Synergy DBL error mnemonics, numbers, and messages.
Variables
A variable is an identifier that refers to a data location in your program. Before using a variable in statements in the procedure division, you must first define it in the data division. The data division statement that defines the name and data type of the variable also determines the characteristics of the variable’s data area: size, possible initial values, and position relative to the other variables.
Shared variables (common records, global records, and global literals) can be declared by any routine in a program and can be accessed by any routine in a program. A shared variable name must be unique. Variables that are not shared are local to the routine in which they are declared.
A path uniquely references a named record or a field within a data structure (as specified by the RECORD or GROUP statement). Variable path specifications have the following format:
[struct_name.][struct_name….]field_name
Paths have the following characteristics:
- The path can contain any number of data structure names as long as it creates a unique variable reference. Use a period (without any spaces) as the delimiter between data structure names or between a structure name and the field name. Let’s use the following group as an example:
record a group b fld ,a2 group c nam ,a20 city ,a10 endgroup endgroup
You can reference the field city with the following paths:
city a.city b.city c.city a.b.city a.c.city b.c.city a.b.c.city
Note that you don’t have to use the whole path name to reference a field.
- You can use the same field name more than once in GROUP and named RECORD statements. However, when you reference a non-unique field, make sure the path specification is unique. For example, for the following data area:
record inhouse accnt ,d5 name ,a30 address ,a40 zip ,d10 record client accnt ,[100]d5 group customer ,[100]a name ,a30 group bldg ,a group address ,a street ,a4 zip ,d10 endgroup endgroup group contact ,a name ,a30 group address ,a street ,a40 zip ,d10 endgroup endgroup endgroup
the following paths are valid:
contact.name contact.address.street customer[5].bldg.address.street client.accnt inhouse.accnt inhouse.name
while the following paths are invalid because they are not unique:
name customer[1].name address.street accnt
If you specify one of these paths, the compiler generates a “Path specification is ambiguous” error (AMBIGUOUS).
- If you do not define structures with unique paths to all fields, you may end up with fields that you cannot access directly. For example, the fields in the first address group in the following group specification can never be accessed directly:
group customer ,a name ,a30 group address ,a street ,a40 zip ,d10 endgroup group contact ,a name ,a30 group address ,a street ,a40 zip ,d10 endgroup endgroup endgroup
Because partial path names can access fields, the second address group’s street field can be referenced in any of the following ways:
customer.contact.address.street customer.contact.street contact.street
The path specification
customer.address.street
generates a “Path specification is ambiguous” compiler error, because it could reference either the first address group or the second. The only way to reference the data in the first address group is by ranging. See Ranged references for information.
- If no other delimiters are present, the period character in a valid path specification takes precedence over any logical or Boolean operator. For example, if your group looks like this:
group var1 ,a group and ,d4 var2 ,d4 endgroup endgroup
and you reference it with the following path:
var1.and.var2
the Synergy compiler interprets this reference as a path, not a Boolean expression. (To use it as a Boolean expression, add a space before and after the .AND. operator.)
- The data type of the variable reference is the data type of the rightmost element in the path.
Object paths
You can refer to the current instance of a class within the class using the this keyword. For example,
this.mymethod()
Path specifications that contain classes are resolved in the following order:
- Local variables
- Local class members
- Inherited class members (moving up the inheritance chain)
- Local namespaces
- Imported namespaces
Real arrays
When referencing a real array, you must specify each declared dimension. For example, if you declare a variable as follows:
record brk ,[3,4]d1
the references brk[1,2] and brk[2,2] are valid because each dimension is referenced.
In contrast, brk[1] is not valid, and the compiler generates an “Incorrect number of dimensions” error (INVNUMDIM), because it specifies only one of the two dimensions.
The reference brk[ ], however, is valid and refers to the entire scope, or contents, of the dimensioned array as a single element. The maximum size of a scope reference is 65,535. If the array is larger than 65,535 bytes, the scope size is modulo 65,535.
If your dimension specification is larger than the declared size of its corresponding array dimension, you can reference outside the defined area up to the end of the data area, except for class data fields and when -qstrict or -qcheck is specified. We recommend using -qcheck in all development environments and -qstrict for all production builds.
Here’s an example that references a real array:
record demo alpha ,[3,2]d2 , 12 ,34, & 56 ,78, & 98 ,76 beta ,[2,4]a3, "JOE" ,"JIM" ,"TED" ,"SAM", & "LOU" ,"NED" ,"BOB" ,"DAN"
Data is referenced as follows:
Variable reference |
Data obtained |
---|---|
alpha[1,2] |
34 |
alpha[3,1] |
98 |
alpha[3] |
INVNUMDIM error |
alpha[3,3] |
JO |
alpha[4,1] |
JO |
alpha[ ] |
123456789876 |
beta[ ] |
JOEJIMTEDSAMLOUNEDBOBDAN |
beta[1,3] |
TED |
beta[2,4] |
DAN |
Variable references
You can specify variables in a simple, subscripted, or ranged form. Each form is described below. (This information also applies to all Synergex array classes: Synergex.SynergyDE.Collections.ArrayList, System.Collections.ArrayList, and System.Array.)
Simple references
A simple reference consists of the name of a data area, without any subscripting or range specifications. If it’s not defined as an array, the reference refers to the entire data area. Otherwise, the simple reference refers to the first element of the array or the element of the array at the specific index specified inside square brackets ([]) next to the variable name (i.e., variable_name[indexer]). In Synergy .NET, you can also use the square bracket format to access the indexer of any class that has an integer indexer method.
Here are some examples of simple references:
- amount
- a_result
- Y73
- days[m,l]
- cust[i,j].name
- var[]
- HELP
Subscripted references
A subscripted reference refers to an individual element within a list of like elements. The variable name is followed by the subscript value, which is enclosed in parentheses. The subscript value can be any numeric expression greater than zero and defines which element in the list is being accessed. For example, a subscript value of 1 represents the first element in the list.
Any variable reference can be subscripted, provided the data area is accessible to the routine. If the data area is inaccessible, or if the subscript value is less than one, an “Invalid subscript specified” error ($ERR_SUBSCR) is generated. Note that you cannot subscript beyond the defined size of class data fields and records or when the -qcheck compiler option is specified.
To understand how subscripted variables work, consider the following example.
Assume the following data division statements:
record demo alpha ,3d4, 3, 9876, 4321 beta ,a6, "ABCDEF" gamma ,d3, 545 delta ,4a2, "LM", "NP", "RS" ,"TV" episilon ,3d3.2, 6.75, 1.23, 8.00 group theta ,[3]a one ,d3, 123 two ,a3, "abc" endgroup
Data is allocated as follows (shaded boxes are not part of the data space):
Variable |
Data area (characters) |
|||||
---|---|---|---|---|---|---|
alpha(1) |
0 |
0 |
0 |
3 |
|
|
alpha(2) |
9 |
8 |
7 |
6 |
|
|
alpha(3) |
4 |
3 |
2 |
1 |
|
|
beta |
A |
B |
C |
D |
E |
F |
gamma |
5 |
4 |
5 |
|
|
|
delta(1) |
L |
M |
|
|
|
|
delta(2) |
N |
P |
|
|
|
|
delta(3) |
R |
S |
|
|
|
|
delta(4) |
T |
V |
|
|
|
|
epsilon(1) |
6 |
7 |
5 |
|
|
|
epsilon(2) |
1 |
2 |
3 |
|
|
|
epsilon(3) |
8 |
0 |
0 |
|
|
|
theta[1].one |
1 |
2 |
3 |
|
|
|
theta[1].two |
a |
b |
c |
|
|
|
theta[2].one |
1 |
2 |
3 |
|
|
|
theta[2].two |
a |
b |
c |
|
|
|
theta[3].one |
1 |
2 |
3 |
|
|
|
theta[3].two |
a |
b |
c |
|
|
|
Here are some sample variable references:
Variable reference |
Data obtained |
Explanation |
---|---|---|
demo |
000398764321ABCDEF545LMNPRSTV675123800123abc123abc123abc |
Refers to the entire data area. |
alpha |
0003 |
Refers to the first element of the array. |
alpha(1) |
0003 |
Refers to the first element of the array. |
alpha(3) |
4321 |
Refers to the third element of the array. |
alpha(4) |
ABCD |
Refers to the fourth group of four characters after the beginning of alpha’s data area (because a single alpha data item is four characters). |
alpha(5) |
EF54 |
Refers to the fifth group of four characters after the beginning of alpha’s data area. |
beta(2) |
545LMN |
Refers to the second group of six characters after the beginning beta’s data area (because a single beta data item is six characters). |
gamma |
PRS |
Refers to the third group of three characters after the beginning of gamma’s data area (because the variable alpha(1) has a value of 3 and a single gamma data item is three characters). |
delta(4) |
TV |
Refers to the fourth element of the array. |
delta(-3) |
$ERR_SUBSCR |
The subscript value is less than one. |
epsilon(3) |
8.00 |
Refers to the third element of the array. (The decimal point is shown here for clarity; it is not stored in the data area.) |
epsilon(4) |
123 |
Refers to the fourth group of three characters after the beginning of epsilon’s data area. |
theta[1].two(2) |
123 |
Refers to the second set of three characters after the first array element in the group. |
theta[3].two(2) |
$ERR_SUBSCR |
Refers to data outside of the data area accessible to the program. |
Alpha(4) and alpha(5) are both valid references because they don’t extend beyond the total data space allocated by the data division statements. Theta[3].two(2), on the other hand, attempts to refer past the end of the data area, which is not possible.
Notice that beta and gamma can be subscripted even though they are simple variable references.
A ranged reference is a variable reference followed by a range specification, either in absolute or relative form, that is enclosed in parentheses. In either case, the specification indicates starting and ending character positions relative to the beginning of the variable’s data space. The ranged variable’s value is the sequence of characters between the starting and ending positions, inclusive. If the range in a variable reference goes beyond the first variable, Synergy DBL continues to the next variable to obtain data.
You can range real arrays. Here’s an example:
brk[1,2](1,23)
You cannot range subscripted arrays. The following generates an error:
array(4)(1,23)
If the variable being ranged is implied-decimal, it is interpreted as decimal. Note that you cannot range beyond the defined size of class data fields and records or when the -qcheck compiler option is specified.
Absolute ranging
The absolute form of a range specification indicates the starting and ending positions of a character sequence using two numeric expressions separated by a comma.
Absolute ranging has the following format:
variable(start_pos,end_pos)
Here’s an example:
record abs alpha ,d8, 10203405 beta ,a13, "ABCDEFGHIJKLM" gamma ,[3,2]a3, "ABC", "DEF", & "GHI", "JKL", & "MNO", "PQR" group theta ,[3]a one ,d3, 123 two ,a3, "abc" endgroup
Variable reference |
Data obtained |
---|---|
alpha(2,4) |
020 |
alpha(8,13) |
5ABCDE |
beta(3,6) |
CDEF |
beta(alpha(2,3),alpha(7,8)) |
BCDE |
beta(alpha(2,3)+2,5) |
DE |
beta(13,14) |
MA |
gamma[1,2](2,3) |
EF |
gamma[2,2](3,6) |
LMNO |
alpha(6,3) |
$ERR_SUBSCR |
theta[1].two(2,8) |
bc123ab |
Note that the ability to access characters that extend past (or in front of) the specified field has been deprecated. For backward compatibility, the Synergy Runtime will continue to support this type of access. However, we recommend that you compile and run with -qcheck and make the appropriate changes to avoid future memory access violations.
The relative form of a range specification indicates the starting or ending character position and length of a character sequence range using two numeric expressions separated by a colon. The value that is referenced depends on the sign of the length. For positive lengths, the specified position is the starting point, and the value is the character sequence of the specified length that begins at that position. For negative lengths, the position is the ending point, and the value is the character sequence that begins the specified number of characters before that position.
Relative ranging has the following format:
variable(position:length)
Here’s an example of a data division:
record abs alpha ,d8, 10203405 beta ,a13, "ABCDEFGHIJKLM" gamma ,[3,2]a3, "ABC", "DEF", & "GHI", "JKL", & "MNO", "PQR" group theta ,[3]a one ,d3, 123 two ,a3, "abc" endgroup
Variable reference |
Data obtained |
---|---|
alpha(3:1) |
2 |
alpha(3:2) |
20 |
alpha(6:-2) |
34 |
beta(13:2) |
MA |
gamma[1,2](1:2) |
DE |
gamma[1,1](1:12) |
ABCDEFGHIJKL |
gamma[3,2](1:12) |
PQR123abc123 |
beta(2:-15) |
$ERR_SUBSCR |
theta[2].one(3:10) |
3abc123abc |
Note that the ability to access characters that extend past (or in front of) the specified field is deprecated. For backward compatibility, the Synergy Runtime will continue to support this type of access. However, we recommend that you compile and run with -qcheck and make the appropriate changes to avoid future memory access violations.