DDL

Hosting the DDL

and

API – programmatic interaction

 

Hosting the DDL. 2

Notes on CLI compatibility. 2

The DDL API 2

class System.DDL.ManagedDDLEngine. 2

Public Constructors. 3

Public Methods. 3

Method System.DDL.ManagedDDLEngine::ClearErrors. 3

Method System.DDL.ManagedDDLEngine::CloseDataFile. 3

Method System.DDL.ManagedDDLEngine::Dispose. 3

Method System.DDL.ManagedDDLEngine::GetErrors. 4

Method System.DDL.ManagedDDLEngine::GetValue. 4

Method System.DDL.ManagedDDLEngine::GetValues. 4

Method System.DDL.ManagedDDLEngine::InterpretData. 5

Method System.DDL.ManagedDDLEngine::List 5

Method System.DDL.ManagedDDLEngine::LoadSourceFile. 5

Method System.DDL.ManagedDDLEngine::OpenDataFile. 6

Method System.DDL.ManagedDDLEngine::Seek. 6

Method System.DDL.ManagedDDLEngine::Tell 7

class System.DDL.DDLException. 7

Public Members. 7

struct System.DDL.MemberInfo. 7

Public Members. 7

struct System.DDL.ErrorInfo. 8

Public Members. 8

enum System.DDL.MemberTypes. 8

Members. 8

enum System.DDL.ErrorTypes. 8

Members. 8

The Concept of Path. 8

Arrays in the Path. 9

Path Naming Conventions: Summary. 9

Examples. 9


Hosting the DDL

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

 

 

Notes on CLI compatibility

This has been tested with the Microsoft’s .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 DDL API

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.

 

class System.DDL.ManagedDDLEngine

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

 

Public Constructors

ManagedDDLEngine Constructor

This is default constructor of the class

 

Public Methods

ClearErrors

Clear the internal Error list

CloseDataFile

Closes the data file, if open

Dispose

Cleans up unmanaged resources

GetErrors

Gets the list of internal errors

GetValue

Get the value of a member in the current scope

GetValues

Get the values of a list of members

InterpretData

Maps the init structure to data file

List

Get the list of the members in the current path

LoadSourceFile

Loads a DDL script file into the interpreter

OpenDataFile

Open a data file for the source file that has been loaded.

Seek

Change the internal path

Tell

Returns the current internal path

 

 

Method System.DDL.ManagedDDLEngine::ClearErrors

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

 

Method System.DDL.ManagedDDLEngine::CloseDataFile

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:

Dispose

 

Method System.DDL.ManagedDDLEngine::Dispose

Prototype:

void  Dispose();

 

This cleans up unmanaged resources that are held by the DDL.

 

ManagedDDLEngine implements the IDisposable interface.

 

Refer:

System::IDisposable

 

Method System.DDL.ManagedDDLEngine::GetErrors

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

 

Method System.DDL.ManagedDDLEngine::GetValue

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:

Seek, GetValues, DDLException

 

Method System.DDL.ManagedDDLEngine::GetValues

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

 

Method System.DDL.ManagedDDLEngine::InterpretData

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

 

Method System.DDL.ManagedDDLEngine::List

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

 

Method System.DDL.ManagedDDLEngine::LoadSourceFile

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

 

Method System.DDL.ManagedDDLEngine::OpenDataFile

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

 

Method System.DDL.ManagedDDLEngine::Seek

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

 

Method System.DDL.ManagedDDLEngine::Tell

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:

Seek, DDLException

 

class System.DDL.DDLException

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.

 

Public Members

string DDLMessage

Represents the human readable error message

ErrorType DDLErrorType

Indicates the type of the error

 

 

struct System.DDL.MemberInfo

This structure represents member information for any kind of valid data member or expression that can be held by the DDL script.

 

Public Members

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

 

struct System.DDL.ErrorInfo

ErrorInfo holds information about an internal DDL error.

Public Members

string Message

A readable string indicating the error

ErrorType Type

The type of the error

 

 

enum System.DDL.MemberTypes

This enumeration indicates the type of the data member.

Members

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

 

enum System.DDL.ErrorTypes

This holds the enumeration of the kinds of errors that are generated by the DDL

 

Members

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 DDL’s parser.

 

The Concept of Path

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.

Arrays in the Path

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’

 

Path Naming Conventions: Summary

·         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 don’t 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

 

Examples

.

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.