DDL
Hosting the DDL
and
API programmatic interaction
class System.DDL.ManagedDDLEngine
Method System.DDL.ManagedDDLEngine::ClearErrors
Method System.DDL.ManagedDDLEngine::CloseDataFile
Method System.DDL.ManagedDDLEngine::Dispose
Method System.DDL.ManagedDDLEngine::GetErrors.
Method System.DDL.ManagedDDLEngine::GetValue.
Method System.DDL.ManagedDDLEngine::GetValues.
Method System.DDL.ManagedDDLEngine::InterpretData
Method System.DDL.ManagedDDLEngine::List
Method System.DDL.ManagedDDLEngine::LoadSourceFile
Method System.DDL.ManagedDDLEngine::OpenDataFile
Method System.DDL.ManagedDDLEngine::Seek
Method System.DDL.ManagedDDLEngine::Tell
Path Naming Conventions: Summary
The DDL is a language whose sole purpose is to read data from complex file/data formats. As a developer you would use the DDL by writing a script that defines your data format and then using the DDL to interpret the data file that you provide. You can do this using any of the DDL hosting programs provided to you such as the DDL Console.
However you may want to write applications that use the data in your data file. This means that you will have to communicate with the DDL. The DDL is designed to be hoisted by applications, which means that your application will run the DDL interpreter as a part of it.
You application can thus programmatically interact with the DDL using the simple API that it exposes. The DDL is made available to the .Net world as a Managed C++ mixed mode assembly called System.DDL.dll, which is also the namespace in which the DDL API resides.
To host the DDL you need to refer to this assembly in your application and using need to include the namespace System.DDL in your application.
csc /r:System.DDL.dll <rest of the compilation parameters>
And inside your application you need to say the equivalent of the C# using statement:
using System.DDL;
Having done this much you are already clear with your first steps to hosting the DDL.
Note:
The DDL project homepage is http://ddl.sscli.net .
You can mail the authors at spark@sscli.net and dolly@sscli.net
This has been tested with the Microsofts .Net framework 1.0 and should be upward compatible. It however may not work with pure CLI implementations like Rotor and others. This is because pure CLI implementations do not clearly support mixed mode assemblies with need to operate both in the unmanaged c++ runtime as well as the managed .net runtime in parallel. This ability is a difficult hack by Microsoft to enable such a mixed mode operation.
In the future versions of the DDL the intention is to move to a fully managed C++ code base that can be loaded by Rotor and other CLI implementations. And also hope that competing .Net implementations also are capable of supporting complex mixed mode assemblies.
The API is the set functions exposed by the DDL that enable you to programmatically interact with the DDL. This is the reference document to the API. You can also see examples of the usage of this API in any of the sample DDL applications that are provided. We would recommend the DDL-Console application as it is a very simple example.
This class represents the DDL engine or the interpreter of the language. This is the heart or CLR of the language.
To interact with the DDL you create an instance of this class and interact with them.
The following is a listing of the members of the
|
ManagedDDLEngine Constructor |
This is default constructor of the class |
|
Clear the internal Error list |
|
|
Closes the data file, if open |
|
|
Cleans up unmanaged resources |
|
|
Gets the list of internal errors |
|
|
Get the value of a member in the current scope |
|
|
Get the values of a list of members |
|
|
Maps the init structure to data file |
|
|
Get the list of the members in the current path |
|
|
Loads a DDL script file into the interpreter |
|
|
Open a data file for the source file that has been loaded. |
|
|
Change the internal path |
|
|
Returns the current internal path |
Prototype:
void ClearErrors();
This clears the internal errors.
This called when the user has got an exception generated due to some method call and the user wants to clear the internal errors before proceeding. Unless internal errors are cleared, all subsequent calls will generated exceptions.
Refer:
GetErrors , DDLException
Prototype:
void CloseDataFile();
This closes the internal data file opened.
Calling the Dispose() method will also do this for you as well as other clean ups. It is recommended that you use the Dispose method
Refer:
Prototype:
void Dispose();
This cleans up unmanaged resources that are held by the DDL.
ManagedDDLEngine implements the IDisposable interface.
Refer:
System::IDisposable
Prototype:
System.Collections.ArrayList GetErrors();
This returns the list of internal errors as an ArrayList.
Each internal error is represented as an instance of the type struct System.DDL.ErrorInfo.
Refer:
ErrorInfo, ClearErrors, DDLException
Prototype:
double GetValue(string name,int instance);
double GetValue(string name);
Reads the value of a data member when given its name.
This applies only to primitive types and expression types. If the member is an array type then you specify the array instance you wish to read. All values are returned as double irrespective of the type they represent.
Calling GetValue on a struct instance will return 0.
GetValue can read values of members in the current path only. To change the current path, refer to the Seek method.
If there has been a read failure an exception will be thrown of type DDLException. You are expected to call GetErrors and ClearErrors as appropriate in the case of an error.
Refer:
Prototype:
void GetValues(System.Collections.ArrayList member_info);
Reads the values of a list of data members.
The ArrayList should contain members of type MemberInfo. The value read will be populated into the Value member of the MemberInfo structure. This method cannot be used to read array types. If the MemberInfo refers to a array type then the value of the 0th instance of the array is read. Read structure types will return 0.
GetValues can read values of members in the current path only. To change the current path, refer to the Seek method.
If there has been a read failure an exception will be thrown of type DDLException. You are expected to call GetErrors and ClearErrors as appropriate in the case of an error.
Refer:
Seek, GetValue, MemberInfo, DDLException
Prototype:
void InterpretData();
This is used to map the source file to the data file during the initialization phase.
This should be called after the source file is loaded and the data file is opened. You can refer to the documentation of the LoadSourceFile for an example of the DDL initialization sequence.
If there has been a failure an exception will be thrown of type DDLException. You are expected to call GetErrors and ClearErrors as appropriate in the case of an error.
Refer:
LoadSourceFile, OpenDataFile, DDLException
Prototype:
System.Collections.ArrayList List();
This function returns an ArrayList containing information about all the members in the current location.
Each member of the ArrayList is of MemberInfo type and will be filled with the information of a member. This methods will list the member that actually exist in the instance of the current structure after resolving information such as when-blocks, array sizes, offset address calculation etc.
The successful execution of this method indicates that the structure instance could be successfully resolved.
If there has been a failure an exception will be thrown of type DDLException. You are expected to call GetErrors and ClearErrors as appropriate in the case of an error.
Refer:
MemberInfo, Seek, DDLException
Prototype:
void LoadSourceFile(string fn);
This function is used to load the source DDL script into a ManagedDDLEngine instance.
This is typically the first function you would call after creating a DDL instance. On calling this method the source file is opened, read and parsed. Most lexical and parsing related errors are typically related at this phase. Semantic errors such as invalid identifiers in expressions are usually reported only during runtime.
If there has been a failure an exception will be thrown of type DDLException. You are expected to call GetErrors and ClearErrors as appropriate in the case of an error.
Example of DDL initialization:
void Open()
{
if(m!=null)
m.Dispose();
Console.Write("DDL Source File: ");
string src = Console.ReadLine();
Console.Write("Data File: ");
string data = Console.ReadLine();
try
{
//this is how you intiialise the DDL
m = new ManagedDDLEngine();
m.LoadSourceFile(src);
m.OpenDataFile(data);
m.InterpretData();
}
catch(DDLException e)
{
Console.WriteLine("DDL Exception:\n{0}:{1}",e.DDLErrorType,e.DDLMessage);
}
catch(Exception e)
{
Console.WriteLine("Generic Exception:");
Console.WriteLine(e.Message);
}
}
Refer:
OpenDataFile, InterpretData, DDLException
Prototype:
void LoadSourceFile(string fn);
This function is used to open the data file that will be used by a ManagedDDLEngine instance.
This data file is from where the DDLwill read information. The data file can only be open after the source file is loaded. Refer to the documentation of LoadSourceFile for an example of the DDL initialization.
If there has been a failure an exception will be thrown of type DDLException. You are expected to call GetErrors and ClearErrors as appropriate in the case of an error.
Refer:
LoadSourceFile, InterpretData, DDLException
Prototype:
void Seek(string path);
This is used to change paths within the DDL.
A path refers to the current structure instance that the DDL is referencing. You could read up the on the concept of the DDL path in this document. On successful change of path the tell method will return the same path as was requested. Also methods like List will return members of the new path.
You can execute a GetValue or GetValues on a member(s) only after changing to the path in which it resides.
If there has been a failure an exception will be thrown of type DDLException. You are expected to call GetErrors and ClearErrors as appropriate in the case of an error.
Refer:
Tell, List, GetValue, DDLException
Prototype:
string Tell();
Tell return the current path of the DDL.
This is useful as method to check if a path change was successful. Tell always returns absolute paths.
If there has been a failure an exception will be thrown of type DDLException. You are expected to call GetErrors and ClearErrors as appropriate in the case of an error.
Refer:
This is the exception type generated by the DDL when an operation causes entries to be added to the internal error list. This exception contains information about the first entry in the internal error list. You must use ManagedDDLEngine::GetErrors to access the other errors.
|
string DDLMessage |
Represents the human readable error message |
|
ErrorType DDLErrorType |
Indicates the type of the error |
This structure represents member information for any kind of valid data member or expression that can be held by the DDL script.
|
string Name |
Represents the name of the member |
|
int Length |
If the member is an array type, Length indicates the number of instance in the array |
|
MemberTypes Type |
Indicates the type of the Member |
|
int Size |
Indicates the size of the member in bits (this will be 0 for expression types) |
|
int offset |
The offset address (in bits) from the base address of the structure |
|
double Value |
If filled, will indicate the value of the member, as read from the data file |
ErrorInfo holds information about an internal DDL error.
|
string Message |
A readable string indicating the error |
|
ErrorType Type |
The type of the error |
This enumeration indicates the type of the data member.
|
i1 i32 |
Indicates a primitive data types of the corresponding number of bits |
|
ExpressionType |
Indicates that the member is a simply an expression and uses no data space of its own |
|
StructType |
Indicates that the member is an instance of another structure The structure name itself is currently not available |
This holds the enumeration of the kinds of errors that are generated by the DDL
|
DDLError |
Is an error caused in the DDL due to logic or invalid input |
|
DDLWarning |
A non critical message, which can often be ignored |
|
LexerError |
Is an error generated in the lexical analysis phase in the DDL. Indicates an issue in your source file. |
|
LexerWarning |
Message from the Lex phase |
|
ParserError |
Is an error generated in the parse phase in the DDL. Indicates an issue in your source file. |
|
ParserWarning |
Message from the DDLs parser. |
After you initialize the DDL engine you are at the path . (dot) by default. . (dot) represents the root. In this conrtext the root is synonymous with saying the first structure instance created by the DDL or the init structure. This is the parent of all structure instances in the DDL.
A path represents a structure instance. A root or the default path represents the first structure instance created by your DDL which is your init structure.
The contents of a path represent the members that exist in the structure instance that is represented by the path. In the default path the members indicate the members of the init structure.
Now any structure can contain members that are instances of other structures. To be able to access these we must change our path to indicate the other structure. You can change paths using the ManagedDDLEngine::Seek() method.
For example in the init structure contained 2 members one of which was a 16 bit type named a and the other an instance of a structure type called Test which is named x. Let all structures of type Test contain two members a and b that are 16 bit types.
So the content of path . will be a and x. If we change path to .x we will have access to the member of instance x, i.e. this path will have members a and b
The fully qualified names of all the types in this example are
.a
.x.a
.x.b
You can think of this hierarchical structure to be similar to that is object oriented programming or to traversing a directory tree.
When you are changing path through an array instance, you can indicate the instance you ant to change to by appending a : (colon) followed by the instance number. For example to represent the 3rd member into an array of structures named arr you can say arr:3
· The root is represented as . (dot). This is synonymous with the first init-structure instance.
· A path location represents a structure instance.
· You change paths into structure instance, you cannot change the path to reflect a primitive data instance or a expressions instance.
·
To access any member structure that is part of the init structure
the path would be:
.<member name>
In general to access a member under any current path
(denoted as <path>), you would use:
<path>.<member name>
·
In general a path will look like
.<structure instance name>.<structure instance
name>
· Dot (.) is used as the path separator. This is akin to accessing a member of an object in most languages.
· Seek(.) would take the user back to the root.
· Relative paths dont start with a dot.
· Absolute paths are paths from the root and the start with a dot.
·
If a member is an array type then an instance would be
represented as
<member name>:<index>
· If a member type is referred to without any index specification then it represent the 0th entry in the array.
· Tell() always returns absolute paths
|
. |
Root |
|
.abc |
Represents members abc under the root. abc would be an instance of some structure type |
|
.abc.cde |
Cde would be a structure instance that is a member of abc |
|
.xy:2 |
The path represents the second instance of the array type xy. Each element of xy is of some structure type. |
|
.xy:2.abc |
Referring to structure type member abc of the second instance xy. |
|
.xy.abc |
Referring to structure type member abc of the 0th instance xy. |