The following provides a complete specification for the Object Description Language (ODL), the language used to encode data labels for the Planetary Data System (PDS) and other NASA data systems. This standard contains a formal definition of the grammar of the ODL and describes the semantics of the language. PDS specific implementation notes and standards are referenced in separate sections of this chapter.
/* File Format and Length */
RECORD_TYPE = FIXED_LENGTH
RECORD_BYTES = 800
FILE_RECORDS = 860
/* pointer to First Record of Major Objects in File */
^IMAGE = 40
^IMAGE_HISTOGRAM = 840
^ENGINEERING_TABLE = 842
/* Image Description */
SPACECRAFT_NAME = VOYAGER_2
TARGET_NAME = IO
IMAGE_ID = "0514J2-00"'
IMAGE_TIME = 1979-07-08T05:19:11
INSTRUMENT_NAME = NARROW_ANGLE_CAMERA
EXPOSURE_DURATION = 1.9200 <SECONDS>
NOTE = "Routine multispectral longitude
coverage, 1 of 7 frames"
/* Description of the Objects Contained in the File */
OBJECT = IMAGE
LINES = 800
LINE_SAMPLES = 800
SAMPLE_TYPE = UNSIGNED_INTEGER
SAMPLE_BITS = 8
END_OBJECT = IMAGE
OBJECT = IMAGE_HISTOGRAM
ITEMS = 25
ITEM_TYPE = INTEGER
ITEM_BITS = 32
END_OBJECT = IMAGE_HISTOGRAM
OBJECT = ANCILLARY_TABLE
^STRUCTURE = "TABLE. FMT"
END_OBJECT = ANCILLARY_TABLE
END
defined_element ::= definition
where the definition is composed from the following components:
units_expression
Whenever the name of a syntactic category is used outside of the formal BNF specification, spaces take the place of underscores (for example, units expression).
object
Special characters used as syntactic elements also appear in boldface type.
The ODL character set is partitioned into letters, digits, special characters, spacing characters, format effectors and other characters:
character :: = letter | digit | special_character |
spacing_character | format_effector |
other_character
The letters are the uppercase letters A - Z and the lowercase letters a - z. The ODL is case-insensitive, meaning that lower case letters are treated as identical to their upper-case equivalent. Thus the following identifiers are equivalent:
The digits are 0, 1,2,3,4, 5, 6,7,8,9.
The following special characters are used in the ODL:
Symbol Name Usage
= Equals The equals sign equates an attribute or pointer to a value.
{ } Braces Braces enclose an unordered set of values.
( ) Parentheses Parentheses enclose an ordered sequence of values.
+ Plus The plus sign indicates a positive numeric value.
- Minus The minus sign indicates a negative numeric value.
< > Angle brackets Angle brackets enclose a units expression associated with a numeric value.
. Period The period is the decimal place in real numbers.
" Quotation Marks Quotation marks denote the beginning and end of a text string value.
' Apostrophe Apostrophes mark the beginning and end of a literal value.
_ Underscore The underscore separates words within an identifier.
, Comma The comma separates the individual values in a set or sequence.
/ Slant The slant character indicates division in units expressions. The slant is also
part of the comment delimiter.
* Asterisk The asterisk indicates multiplication in units expressions. Two asterisks in a
row indicate exponentiation in units expressions. The asterisk is also part of
the comment delimiter.
: Colon The colon separates hours, minutes and seconds within a time value.
# Sharp The sharp delimits the digits in an integer number value expressed in based
notation.
& Ampersand The ampersand denotes continuation of a statement onto another line.
^ Circumflex The circumflex indicates that a value is to be interpreted as a pointer.
Two characters, called the spacing characters, separate lexical elements of the language and can be used to format characters on a line:
Space
Horizontal Tabulation
The following ISO characters are format effectors, used to separate ODL encoded statements into lines:
Carriage Return
Line Feed
Form Feed
Vertical Tabulation
The spacing characters and format effectors are discussed further in Section 12.4.1 below. There are other characters in the ISO 646 character set that are not required to write ODL statements and labels. These characters may, however, appear within text strings and quoted symbolic literals:
$ % ; ? @ [ ]' | ~
The category of other characters also includes the ASCII control characters except for horizontal tabulation, carriage return, line feed, form feed and vertical tabulation (e.g., the control characters that serve as spacing characters or format effectors). As with the printing characters in this category, the control characters in this category can appear within a text String or symbolic literal. The handling of control characters within text strings and symbolic literals is discussed in Section 12.3.5 below.
integer :: = [sign] unsigned_integer
unsigned_integer :: = [digit] +
sign ::= + | -
Examples of Decimal Integers
0
123
+440
-150000
A based integer may optionally include a number sign. An unsigned based integer number is assumed to be positive.
based_integer :: = radix # [sign] [extended_digit] + #
extended_digit :: = digit | letter
radix :: = unsigned_integer
Examples of Based Integers
2#1001011#
8#113#
10#75#
16#4B#
16#+48#
16#-4B#
All but the last example above are equivalent to the decimal integer number 75. The final example is the hexadecimal representation of -75 decimal.
real :: = [sign] unscaled_real | [sign] scaled_real
unscaled_real :: = unsigned_integer.[unsigned_integer]|.unsigned_integer
scaled_real :: = unscaled_real exponent
exponent :: = E integer | e integer
Note that the letter E in the exponent of a real number may appear in either upper or lower case.Examples of Real Numbers
0.0
123.
+1234.56
-.9981
-1.E-3
31459e1
(For information regarding PDS specific use of dates and times, see the Date/Time chapter in this document.)
date_time_value :: = date | time | date_time
The following rules apply to date values:
Software for writing ODL shall always output full four-digit year numbers so that the labels will be valid into the next century.
Times in ODL may be specified with unlimited precision (for example, to nanoseconds). The actual precision with which times can be represented by label reading/writing software is determined by the software implementers, based upon limitations of the hardware on which the software is implemented. Developers of label reading/writing software should document the precision to which times can be represented.
Software for writing ODL shall not output local time values, since a label may be read in a time zone other than where it was written. Use either the UTC or zoned time format instead.
date :: = year_doy | year_month_day year_doy :: = year - doy year_month_day :: = year - month - day year :: = unsigned_integer month :: = unsigned_integer day :: = unsigned_integer doy :: = unsigned_integerExamples of Dates
1990-07-04
90-158
2001-001
time :: = local_time | utc_time | zoned_time
local time :: = hour_min_sec
utc_time :: = hour_min_sec Z
zoned_time :: = hour_min_sec zone_offset
hour_min_sec :: = hour: minute [:second]
zone_offset :: = sign hour [: minute]
hour :: = unsigned_integer
minute :: = unsigned_integer
second :: = unsigned_integer | unscaled_real
Note that either an integral or a fractional number of seconds can be specified in a time.Examples of Times
12:00
15:24:12Z
01:10:39.457591+07
A date and time can be specified together using the format below. Either of the two date formats can be combined with any time format - UTC, zoned or local.
date_time::=date T time
The letter T separating the date from the time can be specified in either upper or lower case. Note that because this is a lexical element that spaces may not appear within a date, within a time or before or after the letter T. Examples of Date/Times
1990-07-04T12:00
90-15:24:12Z
2001-001T01:10:39.457591+7
quoted_text: :="[character]*"
The empty string -- a quoted text string with no characters within the delimiters -- is allowed.A quoted text string may not contain the quotation mark, which is reserved to be the text string delimiter. A quoted text string may contain format effectors, hence it may span multiple lines in a label: the lexical element begins with the opening quotation mark and extends to the closing quotation mark, even if the closing mark is on a following line. The rules for interpreting the characters within a text string, including format effectors, are given in the section on string values in Section 12.5.
quoted-symbol ::= '[character]+'
A symbol string may not contain any of the following characters:
Identifiers are composed of letters, digits, and underscores. Underscores are used to separate "words" in an identifier. The first character of an identifier must be a letter. The last character cannot be an underscore.
identifier ::= letter [letter | digit | _letter | _digit]*
Because ODL is not case sensitive, lower case characters in an identifier can be converted to their upper case equivalent upon input to simplify comparisons and parsing.Examples of Identifiers
VOYAGER VOYAGER_2 BLUE_FILTER USA_NASA_PDS_1_0007 SHOT_1_RANGE_TO_SURFACE
end end_group end_object
group object begin_object
As can be seen in the sections above, many lexical elements incorporate special characters. Examples are the decimal point in real numbers and the quotation marks that delimit a text string. Some special characters are lexical elements in their own right. These so-called delimiters appear within the syntax descriptions in the following section. The following single characters are delimiters unless they appear within one of the lexical elements described above or within a text or symbol string.
= The equals sign is the assignment operator.
, The comma separates the elements of an array or a set
* The asterisk serves as the multiplication operator in unit expressions.
/ The slant serves as the division operator within units expressions.
^ The circumflex denotes a pointer to an object.
<> The angle brackets enclose units expressions.
() The parentheses enclose the elements of a sequence.
{} The braces enclose the elements of a set.
The following two-character sequence is a lexical element.
** Two adjacent asterisks are the exponentiation sign within units
expressions.
label ::= [statement]*
end
The body of a label is built from four types of statements:
statement :: = attribute_assignment_statement |
pointer_statement |
object_statement |
group_statement
Each of the four types of statements is discussed below
FILTERS = {RED, GREEN, BLUE}
FILTERS = {RED,
GREEN
BLUE}
NOTE = "All good men come to the /* Example of incorrect comment*/
aid of their party"
Any characters on a line following a comment are ignored.In some computer systems files are divided into records. Software for writing and reading ODL-encoded labels in record-oriented files should adhere to the following rules:
assignment_statement :: = attribute_identifier = value
The syntax and semantics of values are given in Section 12.5.Examples of Assignments Statements
RECORD_BYTES = 800
TARGET = JUPITER
FIELD_OF_VIEW = (0.25 <DEG>, 3.00 <DEG>)
FILTERS = {RED,
GREEN,
BLUE}
pointer_statement :: = ^object_identifier = value
As with the attribute assignment statement, the value may be a scalar value, an ordered sequence of values, or an unordered set of values.A common use of pointer statements is to reference a file containing an auxiliary label. For example:
^STRUCTURE = "TABLE.FMT"
is a pointer statement that points to a file name TABLE.FMT that contains a description of the structure of the ancillary table from our sample label. Another use of the pointer statement is to indicate the position of an object within another object. This is often used to indicate the position of major objects within a file. The following examples are from our sample label:
^ IMAGE = 40
^IMAGE_HISTOGRAM = 840
^ENGINEERING_TABLE = 842
The first pointer statement above indicates that the image is located starting at the 40th record from the beginning of the file. If an integer value is used to indicate the relative position of an object, the units of measurement of position are determined by the nature of the object. For files, the default unit of measurement is records. Alternatively, a units expression can be specified for the integer value to indicate explicitly the units of measurement for the position. For example, the pointer
^IMAGE = 10200 <BYTES>
indicates that the image starts 10,200 bytes from the beginning of the file.The object pointers above reference locations in the same files as the label. Pointers may also reference either byte or record locations in data files which are detached, or separate, from the label file:
^IMAGE = ("IMAGE.DAT", 10)
^HEADER = ("IMAGE.DAT", 512 <BYTES>)
The format of the OBJECT statement is:
object_statement :: = object = object_identifier
[statement ]*
end_object[=object_identifier]
The object identifier gives a name to the particular object being described. For example, in a file containing images of several planets, the image object descriptions might be named VENUS_IMAGE, JUPITER_IMAGE, etc. The object identifier at the end of the OBJECT statement is optional, but if it appears it must match the name given at the beginning of the OBJECT statement.
The GROUP statement is also used to group related attributes of an object. For example, if two attributes of an image object are the time at which the camera shutter opened and closed, then the two attributes might be grouped as follows:
GROUP = SHUTTER_TIMES START = 12:30:42.177 STOP = 14:01:29.265 END_GROUP = SHUTTER_TIMESThe format of the group statement is as follows:
group_statement :: = group = group_identifier
[statement]*
end_group[= group_identifier]
The group identifier gives a name to the particular group, as shown in the example for shutter times above. The object identifier at the end of the GROUP statement is optional, but if it appears it must match the name given at the beginning of the GROUP statement. Groups may be nested within other groups. There is no limit to the depth to which groups can be nested.
value :: = scalar_value | sequence_value | set_value
A scalar value consists of a single lexical element:
scalar_value ::=numeric_value |
date_time_value |
text_string_value |
symbol_value |
The format and use of each of these scalar values is discussed in the sections below.
numeric_value :: = integer [units_expression] |
based_integer [units_expression] |
real [units_expression]
units_expression :: = < units_factor [mult_op units_factor]* >
units_factor :: = units_identifier [exp_op integer]
mult_op :: = * | /
exp_op :: = **
A units expression is always enclosed within angle brackets. The expression may consist of a single units identifier like KM (for kilometers), or SEC (for seconds). Examples are the distance 1.341E6 <KM> and the time 1.024 <SEC>. More complex units can also be represented; for example, the velocity 3.471 <KM/SEC> or the acceleration 0.414 < KM/SEC/SEC>. There is often more than one way to represent a unit of measure. For example:
text_string_value :: = quoted_text
"To be or not to be"
and
"To be or
not to be"
are the same.
"The planet Jupiter is very big"
and
"The planet Jupi-
ter is very big"
are the same.
The PDS defines a set of format specifiers that can be used in text strings to indicate the formatting of the string on output. These specifiers can be used to indicate where explicit line breaks should be placed, and so on. The format specifiers are:
"This is the first line \n and this is the second line."
on output will print as:
This is the first line
and this is the second line.
Note that these format specifiers have meaning only when a text string is printed, and not when the string is read in or stored.
symbolic-value :: = identifier | quoted_symbol
The following statements assign attributes to symbolic values specified by identifiers:
TARGET = I0
SPACECRAFT = VOYAGER_2
The apostrophes must be used if the symbolic value does not have the proper format for a identifier or if it contains characters not allowed in an identifier. For example, the value 'FILTER_+_7' must be enclosed within apostrophes, since this would not be a legal ODL identifier. Similarly, the symbolic value 'U13-A4B' must be in apostrophes because it contains a special character (the dash) not allowed in an identifier. There is no harm in putting a legal identifier within apostrophes; for example:
SPACECRAFT = 'VOYAGER_2'
is equivalent to the last example above.Symbolic values may not contain format effectors, i.e., may not cross a line boundary.
SPACECRAFT = VOYAGER_2
SPACECRAFT = 'Voyager_2'
are equivalent.
sequence_value :: = sequence_1D | sequence_2D sequence_1D :: = (scalar_value [, scalar_value]*) sequence_2D :: = ([sequence _1D] +)A sequence may have any kind of scalar value for its members. It is not required that all the members of the sequence be of the same kind of scalar value. Thus a sequence may represent a heterogeneous record. Each member of a two dimensional sequence is a one-dimensional sequence. This can be used, for example, to represent a table of values. The order in which members of a sequence appear must be preserved. There is no upper limit on the number of values in a sequence.
set_value :: = {[scalar_value [, scalar_value]*} | {}
Note that the empty set is allowed: The empty set is denoted by opening and closing brackets with nothing except optional spacing characters or format effectors between them.The order in which the members appear in the set is not significant and the order need not be preserved when a set is read and manipulated. There is no upper limit on the number of values in a set.
The ODL uses the ISO 646 character set (the American version of the ISO 646 standard is ASCII). The ODL character set is partitioned as follows:
character : : = letter | digit | special_character |
spacing_character | format_effector |
other_character
letter : : = A-Z | a-z
digit : : = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8| 9
special_character : : = - { | } | ( | ) | + | - | . | " | ' | = |
_ | , | / | * | : | # | & | ^ | < | >
spacing_character : : = space | horizontal tabulation
format_effector : : = carriage return | line feed |
form feed | vertical tabulation
other_character :: = ! | $ | % | ; | ? | @ | [ | ] | ` | ~ |
vertical bar | other control characters
Lexical Elements (12.3)
integer : : = [sign] unsigned_integer
unsigned_integer : : = [digit]+
sign : : = + | -
based_integer : : = radix # [sign] [extended_digit]+ #
extended_digit : : = digit | letter
radix : : = unsigned_integer
real : : = [sign] unscaled_real | [sign] scaled_real
unscaled_real : : = unsigned_integer.[unsigned_integer] |
. unsigned_integer
scaled_real : : = unscaled_real exponent
exponent : : = E integer | e integer
date : : = year_day | year_month_day
year_day : : = year - day
year_month_day : : = year - month - day
year : : = unsigned_integer
month : : = unsigned_integer
day : : = unsigned_integer
time : : = local_time | utc_time | zoned_time
local_time : : = hour_min_sec
utc_time : : = hour_min_sec Z
zoned_time : : = hour_min_sec zone_offset
hour_min_sec : : = hour : minute [ : second]
zone_offset : : = sign hour [ : minute]
hour : : = unsigned_integer
minute : : = unsigned_integer
second : : = unsigned_integer | unscaled_real
date_time : : = date T time
quoted_text : : = "[character]*"e;
quoted_symbol : : = '[character]+'
identifier : : = letter [letter | digit | _letter | _ digit ]*
Statements (12.4)
label : : = [statement]*
end
statement : : = assignment_stmt | pointer_stmt |
object_stmt | group_stmt
assignment_stmt : : = attribute_identifier = value
pointer_stmt : : = ^ object_identifier = value
object_stmt : : = object = object_identifier
[statement]*
end_object [= object_identifier]
group_stmt : : = group = group_identifier
[statement]*
end_group [= group_identifier]
Values (12.5)
value : : = scalar_value | sequence_value | set_value
scalar_value : : = numeric_value | date_time_value
text_string_value | symbolic_value
numeric_value : : = integer [units_expression] |
based_integer [units_expression] |
real [units_expression]
units_expression : : = <units_factor[mult_op units_factor]* >
units_factor : : = units_identifier [exp_op integer]
mult_op : : = * | /
exp_op : : = **
date_time_value : : = date | time | date_time
text_string_value : : = quoted_text
symbolic_value : : = identifier | quoted_symbol
sequence_value : : = sequence_lD | sequence_2D
sequence_1D : : = (scalar_value [, scalar_value]*)
sequence_2D : : = ([sequence_lD]+)
set_value : : = { scalar_value [,scalar_value]* } | { }
range_value :: = integer..integer
This notation is not allowed in ODL Version 2. A parser may still recognize the 'double-dot' range notation. On output, a range shall be encoded as a two value sequence, with the low-value of the range being the first element of the sequence and the high-value being the second element of the sequence.
The individual values in sets and sequences could be separated by a comma or by a spacing character. In Version 2, a comma is required. A parser can allow spacing characters between values as well as commas. Software that writes ODL should place commas between all values in a sequence or set.
In Version 1 of the ODL the circumflex character (^) was used as the exponentiation operator in units expressions rather than the two-asterisk sequence (**). Parsers may still allow the circumflex to appear within units expressions as an exponentiation operator. Software for writing ODL should use only the ** notation.
date :: = year / month / day_of_month | year / day_of_year
date_time :: = date - time zone
zone :: = < identifier>
The definition of time in ODL Version 0 was a subset of ODL Version 2; therefore parsers that handle Version 2 time formats will also handle Version 0 times. Software for writing ODL must output dates and date-times in the Version 2 format only.
Some organizations which deal with the PDS have accepted PVL as their standard language for product labels. Largely because PVL is a superset of ODL, some PVL constructs are not supported by the PDS. In addition, some ODL constructs may be interpreted differently by PVL software.
The ODL/PVL usage standard defines restrictions on the use of ODL/PVL in archive quality data sets. These restrictions are intended to ensure the compatibility of PVL with the Object Description Language (ODL) and existing software.