diff --git a/.gitignore b/.gitignore
index dc459a3210b50406a6481e3208af3dbb3ee200a3..f1c5785fc48fd53c40be0884e98e02d53f3218c3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,3 +57,10 @@ doc/tech_report.bbl
 doc/tech_report.log
 doc/tech_report.pdf
 doc/tech_report.fdb_latexmk
+examples/user_types/encoded_data_c
+examples/user_types/encoded_data_j
+examples/user_types/example_decoder
+examples/user_types/example_encoder
+doc/tech_report.fls
+examples/dynamic/encoded_data
+examples/dynamic/gen
diff --git a/compiler/2014/C_CodeGen.jrag b/compiler/2014/C_CodeGen.jrag
index b7aae053368fb4659ec23e4d363b7bdf52c083d9..bc9d7626628554a1826c98e8a383f36dad4deadc 100644
--- a/compiler/2014/C_CodeGen.jrag
+++ b/compiler/2014/C_CodeGen.jrag
@@ -1130,11 +1130,39 @@ aspect C_Encoder {
   		    " not declared");
   }
   
+  protected void Decl.C_emitEncoderTypeRegister(C_env env) {
+    env.println("int labcomm"+env.verStr+"_encoder_type_register_" + 
+		env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm"+env.verStr+"_encoder *e");
+    env.unindent();
+    env.println(")");
+    env.println("{");
+    env.indent();
+    env.println("//TODO: add error handling for dependencies");
+
+    C_emitUserTypeDeps(env, null, true); 
+
+    if(!isSampleDecl() || hasDependencies()) {
+      env.println("return labcomm"+env.verStr+"_internal_encoder_type_register(");
+      env.indent();
+      env.println("e,");
+      env.println("&signature_" + env.prefix + getName() + "");
+      env.unindent();
+      env.println(");");
+    } else {
+      env.println("// the type has no dependencies, do nothing");
+      env.println("return 0;");
+    }
+    env.unindent();
+    env.println("}");
+  }
   public void TypeDecl.C_emitEncoderRegisterHandler(C_env env) {
-    // do nothing for type decls
+    C_emitEncoderTypeRegister(env);
   }
   
   public void SampleDecl.C_emitEncoderRegisterHandler(C_env env) {
+    C_emitEncoderTypeRegister(env);
     env.println("int labcomm"+env.verStr+"_encoder_register_" + 
 		env.prefix + getName() + "(");
     env.indent();
@@ -1146,17 +1174,28 @@ aspect C_Encoder {
     C_emitUserTypeDeps(env, null, false); //XXX HERE BE DRAGONS
                                           //currently set to false to turn off
                                           //outputting of code
-    env.println("return labcomm"+env.verStr+"_internal_encoder_register(");
+    env.println("int result = labcomm"+env.verStr+"_internal_encoder_register(");
     env.indent();
     env.println("e,");
     env.println("&signature_" + env.prefix + getName() + ",");
     env.println("(labcomm"+env.verStr+"_encoder_function)encode_" + env.prefix + getName());
     env.unindent();
     env.println(");");
+    env.println("if(result >= 0) {\n");
+    env.indent();
+    env.println("labcomm"+env.verStr+"_encoder_type_register_" + env.prefix + getName()+"(e);");
+    env.println("labcomm"+env.verStr+"_internal_encoder_type_bind(");
+    env.indent();
+    env.println("e,");
+    env.println("&signature_" + env.prefix + getName() + ",");
+    env.println( (hasDependencies() ? "1" : "0")  + ");");
+    env.unindent();
+    env.println("}");
+    env.unindent();
+    env.println("return result;");
     env.unindent();
     env.println("}");
   }
-
 }
 
 aspect C_EncoderIoctl {
@@ -1206,7 +1245,7 @@ aspect C_TypeDependencies {
             t.C_emitUserTypeDeps(env, t.getName(), outputCode);
             if(outputCode) {
                System.out.println("Decl.C_emitUserTypeDeps registering "+t.getName());
-               env.println("labcomm"+env.verStr+"_encoder_register_"+env.prefix + t.getName()+"(e);");
+               env.println("labcomm"+env.verStr+"_encoder_type_register_"+env.prefix + t.getName()+"(e);");
             } else {  // Just output a comment
 	        String refpath = (via == null) ? "directly" : "indirectly via "+via;
 	       env.println(" //Depends ("+refpath+") on "+t.getName() );
@@ -1222,7 +1261,7 @@ aspect C_TypeDependencies {
 
             t.C_emitUserTypeRefs(env, t.getName(), outputCode);
             if(outputCode) {
-               env.println("labcomm"+env.verStr+"_encoder_register_"+env.prefix + t.getName()+"(e);");
+               env.println("labcomm"+env.verStr+"_encoder_type_register_"+env.prefix + t.getName()+"(e);");
             } else {  // Just output a comment
 	        String refpath = (via == null) ? "directly" : "indirectly via "+via;
 	       env.println(" //Is referenced ("+refpath+")  by "+t.getName() );
@@ -1245,14 +1284,15 @@ aspect C_Signature {
   eq TypeDecl.C_DeclTypeString() = "LABCOMM_TYPEDEF";
 
   public void Decl.C_emitSignature(C_env env) {
-    C_emitFlatSignature(env);
-//
-//  if( false && (isReferenced() || isSampleDecl())){ 
-//    Signature signature = getSignature();
-//    signature.C_emitSignature(env, !isSampleDecl());
-//  } else {
-//    env.println("// not emitting signature for "+getName()+isReferenced()+isSampleDecl());  
-//  }
+  if( (isReferenced() || isSampleDecl())){ 
+    Signature signature = getSignature();
+    signature.C_emitSignature(env, !isSampleDecl());
+  } else {
+    env.println("// not emitting signature for "+getName()+isReferenced()+isSampleDecl());  
+  }
+  C_emitFlatSignature(env);
+
+
 //  if(env.versionHasMetaData()) { 
 //    if(isReferenced() || isSampleDecl()){
 //        env.println("(int (*)(void *))labcomm"+env.verStr+"_signature_" + 
@@ -1274,6 +1314,24 @@ aspect C_Signature {
   }
 
   public void Decl.C_emitFlatSignature(C_env env) {
+    C_emitSizeofValue(env);
+    env.println("static struct labcomm"+env.verStr+"_signature " +
+                "signature_" + env.prefix + getName() + " = {");
+    env.indent();
+    env.println("\"" + getName() + "\",");
+    //env.println("sizeof_" + env.prefix + getName() + ",");
+    //HERE BE DRAGONS? do we need sizeof for typedefs?
+    env.println("NULL,");
+    env.println("0,");
+    env.println("NULL,");
+    env.println("0,"); // index
+    env.println("sizeof(signature_tree_" + env.prefix + getName() + "),");
+    env.println("signature_tree_" + env.prefix + getName() + "");
+    env.unindent();
+    env.println(" };");
+    env.println("const struct labcomm"+env.verStr+"_signature " +
+                "*labcomm"+env.verStr+"_signature_" + env.prefix + getName() + 
+                " = &signature_" + env.prefix + getName() + ";");
   }
 
   public void SampleDecl.C_emitFlatSignature(C_env env){
@@ -1304,7 +1362,9 @@ aspect C_Signature {
     env.println("sizeof_" + env.prefix + getName() + ",");
     env.println("sizeof(signature_bytes_" + env.prefix + getName() + "),");
     env.println("signature_bytes_" + env.prefix + getName() + ",");
-    env.println("0");
+    env.println("0,"); // index
+    env.println("sizeof(signature_tree_" + env.prefix + getName() + "),");
+    env.println("signature_tree_" + env.prefix + getName() + "");
     env.unindent();
     env.println(" };");
     env.println("const struct labcomm"+env.verStr+"_signature " +
@@ -1319,28 +1379,29 @@ aspect C_Signature {
     public abstract void SignatureLine.C_emitSignature(C_env env, boolean decl);
 
     public void TypeRefSignatureLine.C_emitSignature(C_env env, boolean isDecl){ 
-      //env.print(getIndentString());
-      //env.println("LABCOMM_SIGDEF_SIGNATURE(labcomm"+env.verStr+"_signature_" + env.prefix + decl.getName() +"),");
+      env.print(getIndentString());
+    //  env.println("LABCOMM_SIGDEF_SIGNATURE(labcomm"+env.verStr+"_signature_" + env.prefix + decl.getName() +"),");
+      env.println("LABCOMM_SIGDEF_SIGNATURE(signature_" + env.prefix + decl.getName() +"),");
     }
 
     public void DataSignatureLine.C_emitSignature(C_env env, boolean decl){ 
-       //   String comment = getComment();
-       //   if (comment != null && comment.length() > 0) {
-       //     env.println(getIndentString() + "// " + comment);
-       //   }
-       //   byte[] data = getData(env.version);
-       //   if (data != null && data.length > 0) {
-       //     env.print(getIndentString());
-       //     env.print("LABCOMM_SIGDEF_BYTES("+data.length+", \"");
-       //     for (int j = 0 ; j < data.length ; j++) {
-       //       byte d = data[j];
-       //       //if(d>='a'&&d<='z' || d>='A'&&d<='Z'|| d>='0'&&d<='9'  )
-       //       //  env.print(""+(char)d);
-       //       //else
-       //       env.print("\\x"+Integer.toHexString(d));
-       //     }
-       //     env.println("\"),");
-       // }
+          String comment = getComment();
+          if (comment != null && comment.length() > 0) {
+            env.println(getIndentString() + "// " + comment);
+          }
+          byte[] data = getData(env.version);
+          if (data != null && data.length > 0) {
+            env.print(getIndentString());
+            env.print("LABCOMM_SIGDEF_BYTES("+data.length+", \"");
+            for (int j = 0 ; j < data.length ; j++) {
+              byte d = data[j];
+              //if(d>='a'&&d<='z' || d>='A'&&d<='Z'|| d>='0'&&d<='9'  )
+              //  env.print(""+(char)d);
+              //else
+              env.print("\\x"+Integer.toHexString(d));
+            }
+            env.println("\"),");
+        }
     }
 //
 //
@@ -1357,18 +1418,18 @@ aspect C_Signature {
 //
 //}
   public void SignatureList.C_emitSignature(C_env env, boolean decl) { 
-//  env.println("static struct labcomm_signature_data signature_tree_" + 
-//  	 env.prefix + parentDecl().getName() + "[] = {");
-//  env.indent();
-//  for (int i = 0 ; i < size() ; i++) {
-//    SignatureLine l = getSignatureLine(i);
-//    l.C_emitSignature(env, decl);
-//  }
-//  
-//  env.println("LABCOMM_SIGDEF_END");
-//  env.println("};");
-//  env.unindent();
-//  env.println();
+  env.println("static struct labcomm_signature_data signature_tree_" + 
+  	 env.prefix + parentDecl().getName() + "[] = {");
+  env.indent();
+  for (int i = 0 ; i < size() ; i++) {
+    SignatureLine l = getSignatureLine(i);
+    l.C_emitSignature(env, decl);
+  }
+  
+  env.println("LABCOMM_SIGDEF_END");
+  env.println("};");
+  env.unindent();
+  env.println();
   }
 
 
@@ -1432,9 +1493,9 @@ aspect C_Constructor {
   }
 
   public void Decl.C_emitConstructor(C_env env) {
-  }
+//  }
 //XXX
-  public void SampleDecl.C_emitConstructor(C_env env) {
+//  public void SampleDecl.C_emitConstructor(C_env env) {
     env.println("labcomm"+env.verStr+"_set_local_index(&signature_" + 
 		env.prefix + getName() + ");");
   }
diff --git a/compiler/2014/FlatSignature.jrag b/compiler/2014/FlatSignature.jrag
index 2a9ca4dd9c48fadfabceecebf215e808d10e0597..b96c119ce386f0a0d2b7e9e2c1edb001050e5f27 100644
--- a/compiler/2014/FlatSignature.jrag
+++ b/compiler/2014/FlatSignature.jrag
@@ -21,9 +21,9 @@ aspect FlatSignature {
     getType().flatSignature(list);
   }
 
-  public void SampleRefType.flatSignature(SignatureList list) {
-    list.addInt(LABCOMM_SAMPLE_REF, "sample");
-  }
+//  public void SampleRefType.flatSignature(SignatureList list) {
+//    list.addInt(LABCOMM_SAMPLE_REF, "sample");
+//  }
 
   public void VoidType.flatSignature(SignatureList list) {
     list.addInt(LABCOMM_STRUCT, "void");
@@ -96,9 +96,9 @@ aspect FlatSignature {
     return getType().signatureComment() + " '" + getName() +"'";
   }
 
-  public String SampleRefType.signatureComment() {
-    return "sample";
-  }
+//  public String SampleRefType.signatureComment() {
+//    return "sample";
+//  }
 
   public String PrimType.signatureComment() {
     return getName();
diff --git a/compiler/2014/Java_CodeGen.jrag b/compiler/2014/Java_CodeGen.jrag
index 478a0ac4222f5cebdff8af2168197784e79543d8..62a59eff2b4d6db81c899e25dfbc817121f70aaa 100644
--- a/compiler/2014/Java_CodeGen.jrag
+++ b/compiler/2014/Java_CodeGen.jrag
@@ -454,10 +454,10 @@ aspect Java_Class {
     env.println();
   }
 
-  //public void TypeDecl.Java_emitSignature(Java_env env) {
-  //  Signature signature = getSignature();
-  //  signature.Java_emitSignature(env, true);
-  //}
+  public void TypeDecl.Java_emitSignature(Java_env env) {
+    Signature signature = getSignature();
+    signature.Java_emitSignature(env, true);
+  }
 
   public void Decl.Java_emitSignature(Java_env env) {
     //always emit the flat signature, as it is needed
@@ -465,10 +465,10 @@ aspect Java_Class {
     //the type_ids of dependent types. Therefore, flat sigs
     //are used for matching
     Java_emitFlatSignature(env);
-    //if(isReferenced() || isSampleDecl()){
-    //  Signature signature = getSignature();
-    //  signature.Java_emitSignature(env, !isSampleDecl());
-    //}
+    if(isReferenced() || (isSampleDecl() && hasDependencies() )){
+      Signature signature = getSignature();
+      signature.Java_emitSignature(env, !isSampleDecl());
+    }
   }
 
   public void Decl.Java_emitFlatSignature(Java_env env){
@@ -497,7 +497,8 @@ aspect Java_Class {
 
   //XXX TODO: refactor: split into a static class ("TypeDefSingleton"?)and a (smaller) dispatcher
   public void Decl.Java_emitDispatcher(Java_env env, boolean isSample) {
-    String genericStr = ""; //env.versionHasMetaData()?"<"+getName()+">":""; 
+    // String genericStr = ""; //env.versionHasMetaData()?"<"+getName()+">":""; 
+    String genericStr = "<"+getName()+">"; 
     env.println("private static Dispatcher dispatcher = new Dispatcher();");
     env.println();
     env.println("public SampleDispatcher getDispatcher() {");
@@ -544,16 +545,20 @@ aspect Java_Class {
     env.println("return "+isSample+";");
     env.unindent();
     env.println("}");
-//    env.println("public boolean hasStaticSignature() {");
-//    env.indent();
-//    env.println("return "+!hasDependencies()+";");
-//    env.unindent();
-//    env.println("}");
+    env.println("public boolean hasDependencies() {");
+    env.indent();
+    env.println("return "+hasDependencies()+";");
+    env.unindent();
+    env.println("}");
     env.println();
     env.println("/** return the flat signature. */");
     env.println("public byte[] getSignature() {");
     env.indent();
-    env.println("return signature;");
+    if(isSample) {
+        env.println("return signature;");
+    } else {
+        env.println("throw new Error(\"a TYPE_DEF has no flat signature\");");
+    }
     env.unindent();
     env.println("}");
     env.println();
@@ -563,15 +568,16 @@ aspect Java_Class {
 //    env.unindent();
 //    env.println("}");
 //    env.println();
-//    env.println("public void encodeSignatureMetadata(Encoder e, int index) throws IOException{");
-//    env.indent();
-//    env.println("e.encodePacked32(Constant.TYPE_DEF);");
-//    env.println("e.encodePacked32(index);");
-//    env.println("e.encodeString(getName());");
-//    env.println("emitSignature(e);");
-//    env.unindent();
-//    env.println("}");
-//    env.println();
+    env.println("public void encodeTypeDef(Encoder e, int index) throws IOException{");
+    env.indent();
+    if(!isSample || hasDependencies()) {
+      env.println("emitSignature(e);");
+    } else {
+      env.println("// the type has no dependencies, do nothing");
+    }
+    env.unindent();
+    env.println("}");
+    env.println();
     env.println("public boolean canDecodeAndHandle() {");
     env.indent();
     env.println("return "+isSample+";");
diff --git a/compiler/2014/LabComm.ast b/compiler/2014/LabComm.ast
index 904cc17eb4fe26462b674394a81df391be9690dd..d3d5e592fc95cb38bf9fd3844d8b3ad2d3cb9081 100644
--- a/compiler/2014/LabComm.ast
+++ b/compiler/2014/LabComm.ast
@@ -1,39 +1,37 @@
 Program ::= Decl*;
 
-//TODO: Add signatures to the abstract grammar, so that
-//they can be extended and refined by more than one aspect.
-//sketch:
-Signature		::= SignatureList FlatSignatureList:SignatureList; 
-SignatureList		::= SignatureLine*;
-abstract SignatureLine 	::= <Indent:int> <Comment:String>; 
-abstract DataSignatureLine : SignatureLine;
-ByteArraySignatureLine : DataSignatureLine ::= <Data:byte[]>;
-IntSignatureLine : DataSignatureLine ::= <Data:int>;
-StringSignatureLine : DataSignatureLine ::= <Data:String>;
-TypeRefSignatureLine   	: SignatureLine ::= Decl;
-
-
-//abstract Decl ::= Type <Name:String>;
-// the signature list be defined as  a non-terminal attribute:
 abstract Decl ::= Type <Name:String> /Signature/;
-TypeDecl : Decl;
+
+TypeDecl   : Decl;
 SampleDecl : Decl;
 
+//Signatures are in the abstract grammar, so that
+//they can be extended and refined by aspects.
+
+Signature                 ::= SignatureList FlatSignatureList:SignatureList; 
+SignatureList             ::= SignatureLine*;
+abstract SignatureLine 	  ::= <Indent:int> <Comment:String>; 
+abstract DataSignatureLine : SignatureLine;
+ByteArraySignatureLine     : DataSignatureLine ::= <Data:byte[]>;
+IntSignatureLine           : DataSignatureLine ::= <Data:int>;
+StringSignatureLine        : DataSignatureLine ::= <Data:String>;
+TypeRefSignatureLine       : SignatureLine     ::= Decl;
+
 Field ::= Type <Name:String>;
 
 abstract Type;
-VoidType          : Type;
-SampleRefType     : Type;
-PrimType          : Type ::= <Name:String> <Token:int>;
-UserType          : Type ::= <Name:String>;
-StructType        : Type ::= Field*;
-ParseArrayType    : Type ::= Type Dim*;
-abstract ArrayType :Type ::= Type Exp*;
-VariableArrayType : ArrayType;
-FixedArrayType    : ArrayType;
+VoidType           : Type;
+//SampleRefType      : Type;
+PrimType           : Type ::= <Name:String> <Token:int>;
+UserType           : Type ::= <Name:String>;
+StructType         : Type ::= Field*;
+ParseArrayType     : Type ::= Type Dim*;
+abstract ArrayType : Type ::= Type Exp*;
+VariableArrayType  : ArrayType;
+FixedArrayType     : ArrayType;
 
 Dim ::= Exp*;
 
 abstract Exp;
 IntegerLiteral : Exp ::= <Value:String>;
-VariableSize : Exp;
+VariableSize   : Exp;
diff --git a/compiler/2014/PrettyPrint.jrag b/compiler/2014/PrettyPrint.jrag
index a7fa877109c55e7ad17f64ab1385f8d9638ad662..3808c952309d375c828023c199472d2e6b9e43de 100644
--- a/compiler/2014/PrettyPrint.jrag
+++ b/compiler/2014/PrettyPrint.jrag
@@ -68,9 +68,9 @@ aspect PrettyPrint {
     out.print("void");
   }
 
-  public void SampleRefType.ppPrefix(PrintStream out) { 
-    out.print("sample");
-  }
+//  public void SampleRefType.ppPrefix(PrintStream out) { 
+//    out.print("sample");
+//  }
 
   public void PrimType.ppPrefix(PrintStream out) { 
     out.print(getName());
diff --git a/compiler/2014/Signature.jrag b/compiler/2014/Signature.jrag
index 5395095487bde26c2df7a19b0ea4f452144995d9..b32e53580aa900e31357333904aeeb115180bcf0 100644
--- a/compiler/2014/Signature.jrag
+++ b/compiler/2014/Signature.jrag
@@ -158,7 +158,6 @@ aspect Signature {
   }
 
   public void TypeDecl.genSigLineForDecl(SignatureList list, boolean decl) {
-     //System.out.println("************ TypeDecl.genSigLine("+decl+").... for "+getName());
     if(decl){
       getType().genSigLineForDecl(list, decl);
     }else{
@@ -167,7 +166,6 @@ aspect Signature {
   }
 
   public void SampleDecl.genSigLineForDecl(SignatureList list, boolean decl) {
-     //System.out.println("************ SampleDecl.genSigLine("+decl+").... for "+getName());
     getType().genSigLineForDecl(list, decl);
   }
 
@@ -176,25 +174,20 @@ aspect Signature {
     list.addInt(0, null);
   }
 
-  public void SampleRefType.genSigLineForDecl(SignatureList list, boolean decl) {
-    list.addInt(LABCOMM_SAMPLE_REF, "sample");
-  }
+//  public void SampleRefType.genSigLineForDecl(SignatureList list, boolean decl) {
+//    list.addInt(LABCOMM_SAMPLE_REF, "sample");
+//  }
   public void PrimType.genSigLineForDecl(SignatureList list, boolean decl) {
     list.addInt(getToken(), null);
   }
 
+  /* For UserType, the decl parameter is ignored, as a UserType
+   * will always be a TypeRef
+   */
   public void UserType.genSigLineForDecl(SignatureList list, boolean decl) {
-    if(decl){
-     //System.out.println("************ UserType.genSigLine("+decl+").... for "+getName());
-      TypeDecl thet=lookupType(getName());
-      //System.out.println("************ thet: "+thet.getName() +":"+thet.getType());
-      thet.genSigLineForDecl(list, decl);
-    }else{
-     //System.out.println("************ UserType.genSigLine("+decl+").... for "+getName());
+      
       TypeDecl thet = lookupType(getName());
-     // System.out.println("************ thet: "+thet.getName() +":"+thet.getType());
       list.addTypeRef(thet, null);
-    }
   }
 
   public void ArrayType.genSigLineForDecl(SignatureList list, boolean decl) {
diff --git a/doc/tech_report.tex b/doc/tech_report.tex
index bb97773e075c356449a1bf874eaf8aa348246703..e0ae1d6df930a48e998c5182c5c00bc34d2f12f6 100644
--- a/doc/tech_report.tex
+++ b/doc/tech_report.tex
@@ -437,6 +437,11 @@ come from two independent number series. To identify which
 \verb+TYPE_DECL+ a particular \verb+SAMPLE_DECL+ corresponds to, the
 \verb+TYPE_BINDING+ packet is used.
 
+For sample types that do not depend on any typedefs, no \verb+TYPE_DECL+
+is sent, and the \verb+TYPE_BINDING+ binds the sample id to the special
+value zero to indicate that the type definition is identical to the
+flattened signature.
+
 \subsection{Example}
 
 The labcomm declaration
@@ -484,6 +489,42 @@ not required to do so. However, if multiple \verb+TYPE_DECL+ packets are
 sent for the same \verb+typedef+, the encoder must use the same
 \verb+type_id+.
 
+\subsection{Decoding in-band type descriptions}
+
+In LabComm, the in-band data descriptions are equivalent to \footnote{in
+the sense that they contain all information needed to recreate} the data
+description source (i.e., the ``.lc-file'').
+%
+As the type declarations (a.k.a. \emph{signatures}) are written before
+sample data on every channel, they can be used to interpret data with
+an unknown (by the receiver) format.
+
+The libraries provide functionality to subscribe to (i.e., register a
+\emph{handler} for) sample and type declarations.
+
+On the low level, the handler receives an instance of the signature
+data structure corresponding to the received declaration.
+
+
+For higher-level processing, the Java library provides the
+\verb+ASTbuilder+ class, which builds an abstract syntax tree in
+the internal representation of the LabComm compiler.
+That enables the user to use the complete functionality of the
+LabComm compiler, e.g. code generation,  on declarations received in a
+LabComm stream. 
+
+
+In combination with on-the-fly compilation and class-loading (or
+linking) that makes it possible to dynamically create handlers for
+previously unknown data types. Thereby, it enables dynamic configuration
+of LabComm endpoints in static languages without the overhead of
+interpreting signatures (at the one-time cost of code generation and
+compilation).
+
+
+
+
+
 
 
 \section{Ideas/Discussion}:
@@ -498,6 +539,177 @@ Java primitive types. However, it is unlikely that the entire range is actually
 way of supporting the common cases is to include run-time checks for overflow in the Java encoders
 and decoders.
 
+\section{Related work}
+  
+Two in-band self-descibing communication protocols are Apache
+Avro\cite{avro} and EDN, the extensible data notation developed for
+Clojure and Datomic\cite{EDN}.
+
+EDN encodes \emph{values} as UTF-8 strings. The documentation says
+``edn is a system for the conveyance of values. It is not a type system,
+and has no schemas.'' That said, it is \emph{extensible} in the sense
+that it has a special \emph{dispatch charachter}, \verb+#+, which can  
+be used to add a \emph{tag} to a value. A tag indicates a semantic
+interpretation of a value, and that allows the reader to support
+handlers for specific tags, enabling functionality similar to that of
+labcomm.
+
+\subsection{Apache Avro}
+
+Apache Avro is similar to LabComm in that it has a textual language
+for declaring data, a binary protocol for transmitting data, and code
+generation for several languages.
+
+Avro is a larger system, including RPC \emph{protocols}, support for
+using different \emph{codecs} for data compression, and \emph{schema
+resolution} to support handling schema evolution and transparent 
+interoperability between different versions of a schema.
+
+\subsubsection*{Data types} 
+
+In the table, the Avro type names are listed, and matched to the
+corresponding LabComm type:
+
+\begin{tabular}{|l|c|c|}
+\hline
+  Type &            Labcomm  &               Avro \\
+  \hline Primitive types \\ \hline
+
+int    &         4 bytes     &           varint  \\
+long   &         8 bytes     &           varint  \\
+float  &         4 bytes     &           4 bytes \\
+long   &         8 bytes     &           8 bytes \\
+string &         varint + utf8[]   &     varint + utf8[] \\ 
+bytes  &         varint + byte[]   &     varint + byte[]\\
+
+  \hline Complex types  \\ \hline
+
+struct/record &  concat of fields     &  concat of fields \\ 
+arrays        &  varIdx[] : elements  &  block[]          \\
+map           &    n/a                &  block[]          \\
+union         &   n/a                 & (varint idx) : value \\
+fixed         &   byte[n]             &  the number of bytes declared in
+the schema\\
+\hline
+\end{tabular}
+
+  where 
+
+\begin{verbatim}  
+  block ::= (varint count) : elem[count]      [*1]
+  count == 0 --> no more blocks
+
+
+[*1] for arrays, count == 0 --> end of array
+     if count < 0, there are |count| elements
+     preceded by a varint block_size to allow
+     fast skipping
+\end{verbatim}  
+
+In maps, keys are strings, and values  according to the schema.
+
+In unions, the index indicates the kind of value and the
+value is encoded according to the schema.
+
+Note that the Avro data type \verb+bytes+ corresponds to the
+LabComm declaration \verb+byte[_]+, i.e. a varaible length byte array.
+
+\subsubsection*{the wire protocol}
+
+\begin{tabular}{|l|c|c|}
+  \hline
+  What & LabComm & Avro \\ \hline
+  Data description & Binary signature & JSON schema \\
+  Signature sent only once pre connection& posible & possible \\
+  Signature sent with each sample & possible & possible \\
+  Data encoding & binary & binary \\
+  \hline
+\end{tabular}
+
+
+Both avro and labcomm use varints when encoding data, similar in that
+they both send a sequence of bytes containing 7 bit chunks (with the
+eight bit signalling more chunks to come), but they differ in range,
+endianness and signedness.
+
+\begin{verbatim}
+                LabComm                 Avro
+                unsigned 32 bit         signed zig-zag coding
+                most significant chunk  least significant chunk
+                first                   first
+
+                0   ->  00               0  ->  00
+                1   ->  01              -1  ->  01
+                2   ->  02               1  ->  02
+                    ...                 -2  ->  03
+                                         2  ->  04
+                                            ...
+                127 ->  7f              -64 ->  7f
+                128 ->  81 00            64 ->  80 01
+                129 ->  81 01           -65 ->  81 01
+                130 ->  81 02            65 ->  82 01
+                    ...                     ...   
+\end{verbatim}
+
+\paragraph{Avro Object Container Files} can be seen as a counterpart
+  to a LabComm channel: 
+Avro includes a simple object container file format. A file has a
+schema, and all objects stored in the file must be written according to
+that schema, using binary encoding. Objects are stored in blocks that
+may be compressed. Syncronization markers are used between blocks to
+permit efficient splitting of files, and enable detection of 
+corrupt blocks.
+
+
+The major difference is the sync markers that LabComm does not have, as
+LabComm assumes that, while the transport may drop packets, there will
+be no bit errors in a received packet. If data integrity is required,
+that is delegated to the reader and writer for the particular transport.
+
+\subsubsection{Fetures not in LabComm} 
+
+Avro has a set of features with no counterpart in LabComm. They include
+
+\paragraph{Codecs.}
+
+Avro has multiple codecs (for compression of the data):
+
+    \begin{verbatim}
+    Required Codecs:
+    - null : The "null" codec simply passes through data uncompressed.
+
+    - deflate : The "deflate" codec writes the data block using the deflate
+                algorithm as specified in RFC 1951, and typically implemented using the
+                zlib library. Note that this format (unlike the "zlib format" in RFC
+                1950) does not have a checksum.
+
+    Optional Codecs
+
+    - snappy:   The "snappy" codec uses Google's Snappy compression library. Each
+                compressed block is followed by the 4-byte, big-endian CRC32 checksum of
+                the uncompressed data in the block.
+
+    \end{verbatim}
+
+  \paragraph{Schema Resolution.} The main objective of LabComm is to
+    ensure correct operation at run-time. Therefore, a LabComm decoder
+    requires the signatures for each handled sample to match exactly.
+
+    Avro, on the other hand, supports the evolution of schemas and
+    provides support for reading data where the ordering of fields
+    differ (but names and types are the same), numerical types differ
+    but can be
+    \emph{promoted} (E.g., \verb+int+ can be promoted to \verb+long+,
+    \verb+float+, or \verb+double+.), and record fields have been added
+    or removed (but are nullable or have default values).
+
+    \paragraph{Schema fingerprints.} Avro defines a \emph{Parsing
+    Canonical Form} to define when two JSON schemas are ``the same''.
+    To reduce the overhead when, e.g., tagging data with the schema
+    there is support for creating a \emph{fingerprint} using 64/128/256
+    bit hashing, in combination with a centralized repository for
+    fingerprint/schema pairs.
+
 \bibliography{refs}{}
 \bibliographystyle{plain}
 
@@ -558,22 +770,23 @@ first.
 
 The built-in data types are encoded as follows:
 \begin{lstlisting}[basicstyle=\footnotesize\ttfamily]
-||Type      ||Encoding/Size                                      ||
-||----------||---------------------------------------------------||
-||boolean   ||  8 bits                                           ||
-||byte      ||  8 bits                                           ||
-||short     || 16 bits                                           ||
-||integer   || 32 bits                                           ||
-||long      || 64 bits                                           ||
-||float     || 32 bits                                           ||
-||double    || 64 bits                                           ||
-||string    || length (varint), followed by UTF8 encoded string  ||
-||array     || each variable index (varint),                     ||
-||          || followed by encoded elements                      ||
-||struct    || concatenation of encoding of each element         ||
-||          || in declaration order                              ||
+||Type       ||Encoding/Size                                      ||
+||-----------||---------------------------------------------------||
+||boolean    ||  8 bits                                           ||
+||byte       ||  8 bits                                           ||
+||short      || 16 bits                                           ||
+||integer    || 32 bits                                           ||
+||long       || 64 bits                                           ||
+||float      || 32 bits                                           ||
+||double     || 64 bits                                           ||
+||sample_ref || 32 bits                                           ||
+||string     || length (varint), followed by UTF8 encoded string  ||
+||array      || each variable index (varint),                     ||
+||           || followed by encoded elements                      ||
+||struct     || concatenation of encoding of each element         ||
+||           || in declaration order                              ||
 \end{lstlisting}
-
+\pagebreak
 \subsection{Protocol grammar}
 \label{sec:ConcreteGrammar}
 \begin{lstlisting}[basicstyle=\footnotesize\ttfamily]
diff --git a/examples/simple/Encoder.java b/examples/simple/Encoder.java
index d70384cee5fe7452d4cb413db3c7c6ef09f9e7a1..15e48582cb1d08b879980b61a76dad86928fea9c 100644
--- a/examples/simple/Encoder.java
+++ b/examples/simple/Encoder.java
@@ -16,12 +16,14 @@ public class Encoder
     throws Exception 
   {
     encoder = new EncoderChannel(out);
+    doavoid.register(encoder);
     theTwoInts.register(encoder);
     IntString.register(encoder);
     TwoArrays.register(encoder);
   }
 
   public void doEncode() throws java.io.IOException {
+
     TwoInts x = new TwoInts();
     x.a = 17;
     x.b = 42;
@@ -35,6 +37,9 @@ public class Encoder
 //    ta.variable = new int[][] {{1,2},{0x11,0x12},{0x21,0x22},{0x31,0x32}};
     ta.variable = new int[][] {{1,2, 3, 4},{0x21,0x22,0x23,0x24}};
 
+    System.out.println("Encoding doavoid");
+    doavoid.encode(encoder);
+
     System.out.println("Encoding theTwoInts, a="+x.a+", b="+x.b);
     theTwoInts.encode(encoder, x);
 
diff --git a/examples/simple/EncoderIS.java b/examples/simple/EncoderIS.java
new file mode 100644
index 0000000000000000000000000000000000000000..4d7fd3a138bf64dcc1022c00409a940d0934da5f
--- /dev/null
+++ b/examples/simple/EncoderIS.java
@@ -0,0 +1,53 @@
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+
+import se.lth.control.labcomm.EncoderChannel;
+
+/**
+ * Simple encoder 
+ */
+public class EncoderIS 
+{
+
+  EncoderChannel encoder;
+
+  public EncoderIS(OutputStream out) 
+    throws Exception 
+  {
+    encoder = new EncoderChannel(out);
+//    doavoid.register(encoder);
+//    theTwoInts.register(encoder);
+    IntString.register(encoder);
+//    TwoArrays.register(encoder);
+  }
+
+  public void doEncodeIS() throws java.io.IOException {
+    IntString a = new IntString();
+    a.x = 17;
+    a.s = "A string";
+
+    IntString b = new IntString();
+    b.x = 9;
+    b.s = "Hej";
+
+    IntString c = new IntString();
+    c.x = 133742;
+    c.s = "Thirteenthirtysevenfourtytwo";
+
+    System.out.println("Encoding IntStrings");
+    IntString.encode(encoder, a);
+    IntString.encode(encoder, b);
+    IntString.encode(encoder, c);
+  }
+
+
+  public static void main(String[] arg) throws Exception {
+    FileOutputStream fos = new FileOutputStream(arg[0]);
+    EncoderIS example = new EncoderIS(fos);
+    example.doEncodeIS();
+    fos.close();
+  }
+
+}
+
diff --git a/examples/simple/example_decoder.c b/examples/simple/example_decoder.c
index 122745d62aebe4ea9831dfbf4280d4f267e40425..107aadae3c237bc263ac359ab9534337ff627884 100644
--- a/examples/simple/example_decoder.c
+++ b/examples/simple/example_decoder.c
@@ -8,6 +8,10 @@
 #include "gen/simple.h"
 #include <stdio.h>
 
+static void handle_simple_doavoid(simple_doavoid *v, void *context) {
+  printf("Got a void.\n");
+}
+
 static void handle_simple_theTwoInts(simple_TwoInts *v,void *context) {
   printf("Got theTwoInts. a=%d, b=%d\n", v->a, v->b);
 }
@@ -69,6 +73,7 @@ int main(int argc, char *argv[]) {
     return 1;
   }
 
+  labcomm_decoder_register_simple_doavoid(decoder, handle_simple_doavoid, context);
   labcomm_decoder_register_simple_theTwoInts(decoder, handle_simple_theTwoInts, context);
   labcomm_decoder_register_simple_anotherTwoInts(decoder, handle_simple_anotherTwoInts, context);
   labcomm_decoder_register_simple_IntString(decoder, handle_simple_IntString, context);
diff --git a/examples/user_types/Decoder.java b/examples/user_types/Decoder.java
index bdb17374517015db59e66c02c3144b9d9bf886bc..29069b1cfb9d456f65b1c0f598f67a17a77e695c 100644
--- a/examples/user_types/Decoder.java
+++ b/examples/user_types/Decoder.java
@@ -1,22 +1,46 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStream;
+import java.io.IOException;
 
 import se.lth.control.labcomm.DecoderChannel;
+import se.lth.control.labcomm.TypeDef;
+import se.lth.control.labcomm.TypeDefParser;
+//import se.lth.control.labcomm.TypeBinding;
 
 public class Decoder
-  implements twoLines.Handler
-
+  implements twoLines.Handler,
+//             TypeDef.Handler,
+//             TypeBinding.Handler,
+             TypeDefParser.TypeDefListener,
+             twoInts.Handler,
+             theFirstInt.Handler,
+             theSecondInt.Handler,
+             doavoid.Handler,
+             intAndRef.Handler
 {
 
-  DecoderChannel decoder;
+  private DecoderChannel decoder;
+  private TypeDefParser tdp;
 
   public Decoder(InputStream in) 
     throws Exception 
   {
     decoder = new DecoderChannel(in);
+    doavoid.register(decoder, this);
+    twoInts.register(decoder, this);
     twoLines.register(decoder, this);
+    theFirstInt.register(decoder, this);
+    theSecondInt.register(decoder, this);
+    intAndRef.register(decoder, this);
+    doavoid.registerSampleRef(decoder);
+    this.tdp = TypeDefParser.registerTypeDefParser(decoder); 
+ //   TypeDef.register(decoder, this);
+ //   TypeBinding.register(decoder, this);
 
+        
+    tdp.addListener(this);
+    
     try {
       System.out.println("Running decoder.");
       decoder.run();
@@ -33,6 +57,48 @@ public class Decoder
     return "Line from "+genPoint(l.start)+" to "+genPoint(l.end);
   }
 
+//  public void handle_TypeDef(TypeDef d) throws java.io.IOException {
+//    System.out.println("Got TypeDef: "+d.getName()+"("+d.getIndex()+")");
+//  }
+//
+//  public void handle_TypeBinding(TypeBinding d) throws java.io.IOException {
+//    System.out.println("Got TypeBinding: "+d.getSampleIndex()+" --> "+d.getTypeIndex()+"");
+//  }
+
+  public void onTypeDef(TypeDefParser.ParsedTypeDef d) {
+    System.out.println("ontype_def: ");
+    System.out.print((d.isSampleDef()?"sample ":"typedef ")+d);
+    System.out.println(" "+d.getName()+";");
+    //for(byte b: d.getSignature()) {
+    //   System.out.print(Integer.toHexString(b)+" ");
+    //}
+    //System.out.println(); 
+    //try {
+    //   tdp.parseSignature(d.getIndex());
+    //} catch(IOException ex) { ex.printStackTrace();}   
+  }
+
+  public void handle_doavoid() throws java.io.IOException {
+    System.out.println("Got a void.");
+  }
+
+  public void handle_twoInts(twoInts d) throws java.io.IOException {
+    System.out.print("Got twoInts: ");
+    System.out.println(d.a +", "+d.b);
+  }
+
+  public void handle_theFirstInt(int d) throws java.io.IOException {
+    System.out.println("Got theFirstInt: "+d);
+  }
+
+  public void handle_theSecondInt(int d) throws java.io.IOException {
+    System.out.println("Got theSecondInt: "+d);
+  }
+
+  public void handle_intAndRef(intAndRef d) throws java.io.IOException {
+    System.out.println("Got intAndRef: "+d.x+", "+d.reference);
+  }
+
   public void handle_twoLines(twoLines d) throws java.io.IOException {
     System.out.print("Got twoLines: ");
     System.out.println("Line l1: "+genLine(d.l1));
diff --git a/examples/user_types/Encoder.java b/examples/user_types/Encoder.java
index aa2f80e9617aa3b47b468f4d46469573743a8bc9..d5687a2ce1d86b9643cddc58921373618b80b7bd 100644
--- a/examples/user_types/Encoder.java
+++ b/examples/user_types/Encoder.java
@@ -16,10 +16,37 @@ public class Encoder
     throws Exception 
   {
     encoder = new EncoderChannel(out);
+    doavoid.register(encoder);
+    twoInts.register(encoder);
     twoLines.register(encoder);
+    theFirstInt.register(encoder);
+    theSecondInt.register(encoder);
+    intAndRef.register(encoder);
+    doavoid.registerSampleRef(encoder);
   }
 
   public void doEncode() throws java.io.IOException {
+    System.out.println("Encoding doavoid");
+    doavoid.encode(encoder);
+      
+    intAndRef iar = new intAndRef();
+    iar.x = 17;
+    iar.reference = doavoid.class;
+
+    System.out.println("Encoding intAndRef");
+    intAndRef.encode(encoder, iar);
+
+    twoInts ti = new twoInts();
+    ti.a = 12;
+    ti.b = 21;
+
+    System.out.println("Encoding twoInts");
+    twoInts.encode(encoder, ti);
+      
+    System.out.println("Encoding the Ints");
+    theFirstInt.encode(encoder, 71);
+    theSecondInt.encode(encoder, 24);
+
     twoLines x = new twoLines();
     line l1 = new line();
     point p11 = new point();
diff --git a/examples/user_types/ExampleDecoder.cs b/examples/user_types/ExampleDecoder.cs
index 1b6bc0d2ae2e96e3e5213afaadddbbf10245f286..95b1fca4e2bf1d0adc4bad67823137b03980163c 100644
--- a/examples/user_types/ExampleDecoder.cs
+++ b/examples/user_types/ExampleDecoder.cs
@@ -7,7 +7,12 @@ using se.lth.control.labcomm;
 
 namespace user_types
 {
-    class Decoder : twoLines.Handler 
+    class Decoder : twoLines.Handler, 
+                    twoInts.Handler, 
+                    theFirstInt.Handler, 
+                    theSecondInt.Handler,
+                    doavoid.Handler,
+                    intAndRef.Handler
     {
         DecoderChannel dec;
 
@@ -15,6 +20,12 @@ namespace user_types
         {
             dec = new DecoderChannel(stream);
             twoLines.register(dec, this);
+            twoInts.register(dec, this);
+            theFirstInt.register(dec, this);
+            theSecondInt.register(dec, this);
+            doavoid.register(dec, this);
+            intAndRef.register(dec, this);
+            doavoid.registerSampleRef(dec);
             try
             {
                 Console.WriteLine("Running decoder.");
@@ -41,6 +52,33 @@ namespace user_types
             Console.WriteLine("Line l2: " + genLine(d.l2));
         }
 
+        public void handle(twoInts d)
+        {
+            Console.WriteLine("Got twoInts: ");
+            Console.WriteLine("a: "+d.a);
+            Console.WriteLine("b: "+d.b);
+        }
+
+        void theFirstInt.Handler.handle(int d)
+        {
+            Console.WriteLine("Got theFirstInt: "+d);
+        }
+
+        void theSecondInt.Handler.handle(int d)
+        {
+            Console.WriteLine("Got theSecondInt: "+d);
+        }
+
+        void doavoid.Handler.handle()
+        {
+            Console.WriteLine("Got a void.");
+        }
+
+        void intAndRef.Handler.handle(intAndRef d)
+        {
+            Console.WriteLine("Got intAndRef: "+d.x+" : "+d.reference);
+        }
+
         static void Main(string[] args)
         {
             new Decoder(new FileStream(args[0], FileMode.Open));
diff --git a/examples/user_types/Makefile b/examples/user_types/Makefile
index 4af38f677bad712cd6a0701411555d2104d65229..7603ffd308aedc0b23d1399d0050c1a257f34c27 100644
--- a/examples/user_types/Makefile
+++ b/examples/user_types/Makefile
@@ -1,15 +1,16 @@
 LCDIR=../..
-LCCJAR=${LCDIR}/compiler/labcomm2014_compiler.jar  # the LabComm compiler
-LCLJAR=${LCDIR}/lib/java/labcomm2014.jar  # the LabComm library
+LCCJAR=${LCDIR}/compiler/labcomm2014_compiler.jar# the LabComm compiler
+LCLJAR=${LCDIR}/lib/java/labcomm2014.jar# the LabComm library
 
 EXECUTABLES=example_encoder example_decoder \
-	    Encoder.class Decoder.class \
+	    Encoder.class Decoder.class TDDecoder.class \
 	    ExampleEncoder.exe ExampleDecoder.exe
+
 include ${LCDIR}/lib/c/os_compat.mk
 
 GENDIR=gen
 
-.PHONY: all cleanbuild clean distclean build run allall buildcs runwcs
+.PHONY: all cleanbuild clean distclean build run allall buildcs runwcs runjastadd
 
 all: cleanbuild run
 
@@ -49,6 +50,7 @@ build :
 	java -jar ${LCDIR}/compiler/labcomm_compiler.jar --java=${GENDIR} --c=${GENDIR}/test.c --h=${GENDIR}/test.h  --python=${GENDIR}/test.py --cs=${GENDIR}/test.cs test.lc 
 
 	javac -cp ${LCDIR}/lib/java/labcomm2014.jar:. ${GENDIR}/*.java Encoder.java Decoder.java
+	javac -cp ${LCDIR}/lib/java/labcomm2014.jar:${LCCJAR}:${GENDIR}:. TDDecoder.java
 
 	${CC} ${CFLAGS} ${LDFLAGS} -Wall -Werror -Wno-unused-function \
 	    -I. -I${LCDIR}/lib/c/2014 -L${LCDIR}/lib/c \
@@ -122,7 +124,7 @@ runwcs: build ExampleEncoder.exe ExampleDecoder.exe
 	@PYTHONPATH=${LCDIR}/lib/python ../wiki_example/example_decoder.py encoded_data_j LabComm2014
 
 	@echo "************ running C# decoder: *****************"
-	@LD_LIBRARY_PATH=${LCDIR}/lib/c/ ./ExampleDecoder.exe encoded_data_j
+	@LD_LIBRARY_PATH=${LCDIR}/lib/c/ mono ./ExampleDecoder.exe encoded_data_j
 
 	@echo "************ running C encoder: *****************"
 	@LD_LIBRARY_PATH=${LCDIR}/lib/c/ ./example_encoder encoded_data_c
@@ -137,7 +139,7 @@ runwcs: build ExampleEncoder.exe ExampleDecoder.exe
 	@PYTHONPATH=${LCDIR}/lib/python ../wiki_example/example_decoder.py encoded_data_c LabComm2014
 
 	@echo "************ running C# decoder: *****************"
-	@./ExampleDecoder.exe encoded_data_c
+	@mono ./ExampleDecoder.exe encoded_data_c
 
 	@echo "************ running python encoder: *****************"
 	@PYTHONPATH=${LCDIR}/lib/python:${GENDIR} ./example_encoder.py encoded_data_p LabComm2014
@@ -152,10 +154,10 @@ runwcs: build ExampleEncoder.exe ExampleDecoder.exe
 	PYTHONPATH=${LCDIR}/lib/python ../wiki_example/example_decoder.py encoded_data_p LabComm2014
 
 	@echo "************ running C# decoder: *****************"
-	@./ExampleDecoder.exe encoded_data_p
+	@mono ./ExampleDecoder.exe encoded_data_p
 
 	@echo "************ running C# encoder: *****************"
-	@./ExampleEncoder.exe encoded_data_cs
+	@mono ./ExampleEncoder.exe encoded_data_cs
 
 	@echo "************ running Java  decoder: *****************"
 	@java -cp .:${LCDIR}/lib/java/labcomm2014.jar:${GENDIR} Decoder encoded_data_cs
@@ -167,8 +169,19 @@ runwcs: build ExampleEncoder.exe ExampleDecoder.exe
 	@PYTHONPATH=${LCDIR}/lib/python ../wiki_example/example_decoder.py encoded_data_cs LabComm2014
 
 	@echo "************ running C# decoder: *****************"
-	@./ExampleDecoder.exe encoded_data_cs
+	@mono ./ExampleDecoder.exe encoded_data_cs
+
+runjastadd: cleanbuild
+	@echo
+	@echo "********************************************"
+	@echo "***   ************ running example with JastAdd unparsing  ***"
+	@echo "********************************************"
+	@echo
+
+	@java -cp .:${LCDIR}/lib/java/labcomm2014.jar:${GENDIR} Encoder encoded_data_j
 
+	@echo "************ running Java  TypeDefdecoder: *****************"
+	java -cp .:${LCDIR}/lib/java/labcomm2014.jar:${LCCJAR}:${GENDIR} TDDecoder encoded_data_j
 
 
 clean:
diff --git a/examples/user_types/TDDecoder.java b/examples/user_types/TDDecoder.java
new file mode 100644
index 0000000000000000000000000000000000000000..6bfdb3ca8f33b5af819472e65a229f4f177e3fd3
--- /dev/null
+++ b/examples/user_types/TDDecoder.java
@@ -0,0 +1,139 @@
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import se.lth.control.labcomm.DecoderChannel;
+import se.lth.control.labcomm.TypeDef;
+import se.lth.control.labcomm.TypeDefParser;
+import se.lth.control.labcomm.ASTbuilder;
+//import se.lth.control.labcomm.TypeBinding;
+
+import se.lth.control.labcomm2014.compiler.Program;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+
+import java.util.Vector;
+import java.util.LinkedList;
+import java.util.Iterator;
+
+
+public class TDDecoder
+  implements twoLines.Handler,
+//             TypeDef.Handler,
+//             TypeBinding.Handler,
+             TypeDefParser.TypeDefListener,
+             twoInts.Handler,
+             theFirstInt.Handler,
+             theSecondInt.Handler,
+             doavoid.Handler,
+             intAndRef.Handler
+{
+
+  private DecoderChannel decoder;
+  private TypeDefParser tdp;
+
+  public TDDecoder(InputStream in) 
+    throws Exception 
+  {
+    decoder = new DecoderChannel(in);
+    twoInts.register(decoder, this);
+    twoLines.register(decoder, this);
+    theFirstInt.register(decoder, this);
+    theSecondInt.register(decoder, this);
+    doavoid.register(decoder, this);
+    intAndRef.register(decoder, this);
+    doavoid.registerSampleRef(decoder);
+    this.tdp = TypeDefParser.registerTypeDefParser(decoder); 
+ //   TypeDef.register(decoder, this);
+ //   TypeBinding.register(decoder, this);
+
+        
+    tdp.addListener(this);
+    
+    try {
+      System.out.println("Running decoder.");
+      decoder.run();
+    } catch (java.io.EOFException e) {
+	System.out.println("Decoder reached end of file.");
+    }
+  }
+
+  private String genPoint(point p) {
+    return "("+p.x.val+", "+p.y.val+")";
+  }
+
+  private String genLine(line l) {
+    return "Line from "+genPoint(l.start)+" to "+genPoint(l.end);
+  }
+
+//  public void handle_TypeDef(TypeDef d) throws java.io.IOException {
+//    System.out.println("Got TypeDef: "+d.getName()+"("+d.getIndex()+")");
+//  }
+//
+//  public void handle_TypeBinding(TypeBinding d) throws java.io.IOException {
+//    System.out.println("Got TypeBinding: "+d.getSampleIndex()+" --> "+d.getTypeIndex()+"");
+//  }
+
+  public void onTypeDef(TypeDefParser.ParsedTypeDef d) {
+    if(d.isSampleDef()){
+        System.out.println("onTypeDef (sample): ");
+        ASTbuilder v = new ASTbuilder();
+        Program p = v.makeProgram((TypeDefParser.ParsedSampleDef) d);
+        try {
+                //FileOutputStream f = new FileOutputStream("/tmp/foopp"+d.getName()+".txt");
+                //PrintStream out = new PrintStream(f);
+                p.pp(System.out);
+                //p.C_genC(System.out, new Vector(), "lcname", "prefix", 2014);
+                //p.J_gen(out, "testpackage", 2014);
+                //out.close();
+        } catch (Throwable e) {
+                System.err.println("Exception: " + e);
+                e.printStackTrace();
+        }
+    }
+    //System.out.println(" "+d.getName()+";");
+    //for(byte b: d.getSignature()) {
+    //   System.out.print(Integer.toHexString(b)+" ");
+    //}
+    //System.out.println(); 
+    //try {
+    //   tdp.parseSignature(d.getIndex());
+    //} catch(IOException ex) { ex.printStackTrace();}   
+  }
+
+  public void handle_twoInts(twoInts d) throws java.io.IOException {
+    System.out.print("Got twoInts: ");
+    System.out.println(d.a +", "+d.b);
+  }
+
+  public void handle_theFirstInt(int d) throws java.io.IOException {
+    System.out.println("Got theFirstInt: "+d);
+  }
+
+  public void handle_theSecondInt(int d) throws java.io.IOException {
+    System.out.println("Got theSecondInt: "+d);
+  }
+
+  public void handle_doavoid() throws java.io.IOException {
+    System.out.println("Got a void.");
+  }
+
+  public void handle_intAndRef(intAndRef d) throws java.io.IOException {
+    System.out.println("Got intAndRef: "+d.x+", "+d.reference);
+  }
+
+  public void handle_twoLines(twoLines d) throws java.io.IOException {
+    System.out.print("Got twoLines: ");
+    System.out.println("Line l1: "+genLine(d.l1));
+    System.out.println("              Line l2: "+genLine(d.l2));
+  }
+
+
+  public static void main(String[] arg) throws Exception {
+    TDDecoder example = new TDDecoder(
+      new FileInputStream(new File(arg[0]))
+    );
+  }
+}
+
diff --git a/examples/user_types/example_decoder.c b/examples/user_types/example_decoder.c
index 1edc52ff2bb0ac37c009d705d0226123d5f67adb..b727f8a47d85007db2bd3c05141c9d5da150ad5a 100644
--- a/examples/user_types/example_decoder.c
+++ b/examples/user_types/example_decoder.c
@@ -8,8 +8,36 @@
 #include "gen/test.h"
 #include <stdio.h>
 
+static void handle_test_doavoid(test_doavoid *v,void *context) {
+  printf("Got a void.\n"); 
+}
+
+static void handle_test_intAndRef(test_intAndRef *v,void *context) {
+  printf("Got intAndRef. (%d : %s) \n", v->x, v->reference->name); 
+}
+
+static void handle_test_twoInts(test_twoInts *v,void *context) {
+  printf("Got twoInts. (%d,%d) \n", v->a, v->b); 
+}
+
+static void handle_test_theFirstInt(int *v,void *context) {
+  printf("Got theFirstInt. (%d) \n", *v); 
+}
+
+static void handle_test_theSecondInt(int *v,void *context) {
+  printf("Got theSecondInt. (%d) \n", *v); 
+}
+
+static void handle_type_def(struct labcomm_raw_type_def *v,void *context) {
+  printf("Got type_def. (0x%x) %s\n", v->index, v->name); 
+}
+
+static void handle_type_binding(struct labcomm_type_binding *v,void *context) {
+  printf("Got type binding. 0x%x --> 0x%x\n", v->sample_index, v->type_index); 
+}
+
 static void handle_test_twoLines(test_twoLines *v,void *context) {
-  printf("Got theTwoInts. (%d,%d) -> (%d,%d), (%d,%d) -> (%d,%d)\n", v->l1.start.x.val, v->l1.start.y.val, 
+  printf("Got twoLines. (%d,%d) -> (%d,%d), (%d,%d) -> (%d,%d)\n", v->l1.start.x.val, v->l1.start.y.val, 
                                                                      v->l1.end.x.val, v->l1.end.y.val,    
                                                                      v->l2.start.x.val, v->l2.start.y.val,
                                                                      v->l2.end.x.val, v->l2.end.y.val);    
@@ -33,7 +61,16 @@ int main(int argc, char *argv[]) {
     return 1;
   }
 
+  labcomm_decoder_register_test_doavoid(decoder, handle_test_doavoid, context);
+  labcomm_decoder_register_test_intAndRef(decoder, handle_test_intAndRef, context);
+  labcomm_decoder_sample_ref_register(decoder,labcomm_signature_test_doavoid );
+
+  labcomm_decoder_register_test_twoInts(decoder, handle_test_twoInts, context);
+  labcomm_decoder_register_test_theFirstInt(decoder, handle_test_theFirstInt, context);
+  labcomm_decoder_register_test_theSecondInt(decoder, handle_test_theSecondInt, context);
   labcomm_decoder_register_test_twoLines(decoder, handle_test_twoLines, context);
+  labcomm_decoder_register_labcomm_type_def(decoder, handle_type_def, context);
+  labcomm_decoder_register_labcomm_type_binding(decoder, handle_type_binding, context);
 
   printf("Decoding:\n");
   labcomm_decoder_run(decoder);
diff --git a/examples/user_types/test.lc b/examples/user_types/test.lc
index d2225394b890937f471e6984a8122aff11b3d51b..75497b4df01e761d47efba7dd95cc7bb1611fcf9 100644
--- a/examples/user_types/test.lc
+++ b/examples/user_types/test.lc
@@ -2,6 +2,16 @@ typedef struct {
   int val;
 } coord;
 
+typedef int anInt;
+
+typedef void avoid;
+sample avoid doavoid;
+
+sample struct {
+  int x;
+  sample reference;
+} intAndRef;
+
 typedef struct {
   coord x;
   coord y;
@@ -23,3 +33,11 @@ sample struct {
   line l2;
   foo  f;
 } twoLines;
+
+sample struct {
+  int a;
+  int b;
+} twoInts;
+
+sample anInt theFirstInt;
+sample anInt theSecondInt;
diff --git a/examples/wiki_example/run b/examples/wiki_example/run
index e3477ea720ff97ebc29ac2339cbcdcae121752ce..276d46b4292c6d0aa635c243713f17fe0ec4f903 100755
--- a/examples/wiki_example/run
+++ b/examples/wiki_example/run
@@ -16,9 +16,9 @@ gcc -Wall -Werror -o example_encoder -I../../lib/c/2014 \
     example.c \
     ../../lib/c/liblabcomm2014.a || exit 1
 
-javac -cp ../../lib/java:. *.java || exit 1
+javac -cp ../../lib/java/labcomm.jar:. *.java || exit 1
 
 # Run through all executables (c->java->Python)
 ./example_encoder one two || exit 1
-java -cp ../../lib/java:. example_decoder_encoder example.encoded example.javaencoded || exit 1
+java -cp ../../lib/java/labcomm.jar:. example_decoder_encoder example.encoded example.javaencoded || exit 1
 PYTHONPATH=../../lib/python ./example_decoder.py example.javaencoded || exit 1
diff --git a/lib/c/2006/labcomm2006.c b/lib/c/2006/labcomm2006.c
index 8f628cfccd6b10dda2635577cfd6c150e7ec4625..ff09b636127ffd0746165b98db2b453d975bad96 100644
--- a/lib/c/2006/labcomm2006.c
+++ b/lib/c/2006/labcomm2006.c
@@ -237,7 +237,7 @@ void *labcomm2006_signature_array_ref(struct labcomm2006_memory *memory,
   }
 }
 
-static int local_index = 0x40;
+static int local_index = LABCOMM_USER;
 
 void labcomm2006_set_local_index(struct labcomm2006_signature *signature)
 {
diff --git a/lib/c/2006/labcomm2006_private.h b/lib/c/2006/labcomm2006_private.h
index 4c3361026bf8e3c83af75fcca44cdebec43453b5..378719ccd2f7eff21df847ffb37cc76ad3838ac9 100644
--- a/lib/c/2006/labcomm2006_private.h
+++ b/lib/c/2006/labcomm2006_private.h
@@ -42,7 +42,7 @@
 #define LABCOMM_SAMPLE   0x02
 #define LABCOMM_ARRAY    0x10
 #define LABCOMM_STRUCT   0x11
-#define LABCOMM_USER     0x80   /* ..0xffffffff */
+#define LABCOMM_USER     0x40   /* ..0xffffffff */
 
 /*
  * Predefined primitive type indices
diff --git a/lib/c/2014/Makefile b/lib/c/2014/Makefile
index 6742429773437384c38c06148fc6af2bd9f78dc5..f5a9f1098233a7f6fcd9766fe5298ebac3ec5a52 100644
--- a/lib/c/2014/Makefile
+++ b/lib/c/2014/Makefile
@@ -20,6 +20,7 @@ OBJS=labcomm$(VERSION).o \
      labcomm$(VERSION)_decoder.o \
      labcomm$(VERSION)_dynamic_buffer_writer.o \
      labcomm$(VERSION)_fd_reader.o \
+	 labcomm$(VERSION)_type_signature.o \
      labcomm$(VERSION)_fd_writer.o \
      labcomm$(VERSION)_pthread_scheduler.o 
 
@@ -29,8 +30,12 @@ ifeq ($(LABCOMM_EXPERIMENTAL),true)
 	    experimental/labcomm_thr_reader_writer.o \
 	    experimental/ThrottleDrv/ethernet_drv.o \
 	    experimental/ThrottleDrv/throttle_drv.o \
-	    experimental/labcomm_udp_reader_writer.o\
-	    experimental/labcomm_sig_parser.o 
+	    experimental/labcomm_udp_reader_writer.o
+endif
+
+# Enable experimental objects by `make LABCOMM_SIG_PARSER=true`
+ifeq ($(LABCOMM_SIG_PARSER),true)
+    OBJS += experimental/labcomm_sig_parser.o 
 endif
 
 LABCOMM_JAR=../../../compiler/labcomm$(LIBVERSION)_compiler.jar
@@ -83,8 +88,8 @@ distclean: clean
 ../liblabcomm$(LIBVERSION).a: $(OBJS)
 	ar -r $@ $^
 
-# Enable experimental objects by `make LABCOMM_EXPERIMENTAL=true`
-ifeq ($(LABCOMM_EXPERIMENTAL),true)
+# Enable sig parser objects by `make LABCOMM_SIG_PARSER=true`
+ifeq ($(LABCOMM_SIG_PARSER),true)
 experimental/test_sig_parser : experimental/labcomm_sig_parser.o experimental/test_sig_parser.c
 endif
 
diff --git a/lib/c/2014/experimental/labcomm_sig_parser.c b/lib/c/2014/experimental/labcomm_sig_parser.c
index 7c4a586717e1944a1d9db016d24fd21fbf4cb3f4..75e9771e53f0fa85df6577b6aee8ef6707ba7609 100644
--- a/lib/c/2014/experimental/labcomm_sig_parser.c
+++ b/lib/c/2014/experimental/labcomm_sig_parser.c
@@ -15,8 +15,6 @@
  * - The RETURN_STRINGS and where/if to allocate strings is to be decided, it
  *   is currently not used
  *
- * - TYPE_DECL is not tested (is it ever sent?)
- *
  * - The dynamic allocation of the parser is not quite dynamic, the sizes are
  *   set through the init function, and are then static.
  *   This should be adapted when allocation is parameterized/user-definable
@@ -66,7 +64,7 @@ static int unpack_varint(unsigned char *buf,
         unsigned char cont = TRUE;
 
         do {
-                char c = buf[idx+i];
+                unsigned char c = buf[idx+i];
                 res = (res << 7) | (c & 0x7f);
                 cont = c & 0x80;
                 i++;
@@ -218,6 +216,7 @@ void getStr(labcomm_sig_parser_t *b, unsigned char *dest, size_t size) {
 	if( size > rem )
 		size = rem;
 	strncpy((char *)dest, (char *)&b->c[b->idx], size);
+    dest[size] = 0;
 	b->idx += size;
 }
 
@@ -271,6 +270,7 @@ static size_t labcomm_sizeof_primitive(unsigned int type)
 			return 2;
 		case TYPE_INTEGER :
 		case TYPE_FLOAT :
+		case TYPE_SAMPLE_REF :
 			return 4;
 		case TYPE_LONG :
 		case TYPE_DOUBLE :
@@ -340,7 +340,65 @@ int encoded_size_parse_sig(struct labcomm_signature *sig, void *sample)
 	return -1;
 }
 
-static int accept_signature(labcomm_sig_parser_t *d)
+static int accept_signature(labcomm_sig_parser_t *d, 
+                            labcomm_type type,
+                            unsigned int start,
+                            unsigned int uid, char *name)
+{
+    get_varint(d); // ignore sig len
+    VERBOSE_PRINTF("\ntype = ");
+    accept_type(d);
+    //printf(" : ");
+    //unsigned int dt = pop(d);
+#ifdef USE_TYPE_AND_SIZE
+    unsigned int type = pop_val(d);
+    unsigned int enc_size = pop_val(d);
+#else
+    pop_val(d); // unsigned int type
+    pop_val(d); // unsigned int enc_size
+#endif
+    if(type != PKG_SAMPLE_DECL) {
+        if(type == PKG_SAMPLE_REF) {
+            INFO_PRINTF("accept_signature: ignoring sample ref\n");
+            return TRUE;
+        } else if (type == PKG_TYPE_DECL) {
+            INFO_PRINTF("accept_signature: ignoring typedef\n");
+            return TRUE;
+        } else {
+            error("decl is neither sample, ref, or typedef???");
+            return FALSE;
+        }
+    }
+    unsigned int end = d->idx;
+    unsigned int len = end-start;
+
+    struct labcomm_signature *newsig = get_sig_t(d, uid);
+//		newsig->type = type;
+    if(len <= d->max_sig_len) {
+        d->signatures_length[uid-LABCOMM_USER] = len;
+        memcpy(d->signatures[uid-LABCOMM_USER], &d->c[start], len);
+        newsig->size = len;
+        newsig->signature = d->signatures[uid-LABCOMM_USER];
+        newsig->name = name;
+    } else {
+        error("sig longer than max length (this ought to be dynamic...)");
+    }
+    VERBOSE_PRINTF("signature for uid %x: %s (start=%x,end=%x,len=%d)\n", uid, get_signature_name(d, uid), start,end, len);
+    INFO_PRINTF("accept_signature: %s\n", newsig->name);
+#ifdef LABCOMM_EXPERIMENTAL_CACHED_ENCODED_SIZE
+    if(! d->current_decl_is_varsize) {
+        newsig->cached_encoded_size = enc_size;
+        newsig->encoded_size = encoded_size_static;
+        INFO_PRINTF(".... is static size = %d\n", enc_size);
+    } else {
+        newsig->cached_encoded_size = -1;
+        newsig->encoded_size = encoded_size_parse_sig;
+        INFO_PRINTF(".... is variable size\n");
+    }
+#endif
+    return TRUE;
+}
+static int accept_decl(labcomm_sig_parser_t *d, labcomm_type type)
 {
 	if(accept_user_id(d)) {
 		unsigned int uid = pop_val(d);
@@ -354,54 +412,24 @@ static int accept_signature(labcomm_sig_parser_t *d)
 		free(str);
 #endif
 		unsigned char lenlen = labcomm_varint_sizeof(nlen);
-        get_varint(d); // ignore sig len
-		VERBOSE_PRINTF("\ntype = ");
-		accept_type(d);
-		//printf(" : ");
-		//unsigned int dt = pop(d);
-#ifdef USE_TYPE_AND_SIZE
-		unsigned int type = pop_val(d);
-		unsigned int enc_size = pop_val(d);
-#else
-		pop_val(d); // unsigned int type
-		pop_val(d); // unsigned int enc_size
-#endif
-		unsigned int end = d->idx;
-		unsigned int len = end-start;
-
-		struct labcomm_signature *newsig = get_sig_t(d, uid);
-//		newsig->type = type;
-		if(len <= d->max_sig_len) {
-			d->signatures_length[uid-LABCOMM_USER] = len;
-			memcpy(d->signatures[uid-LABCOMM_USER], &d->c[start], len);
-			newsig->size = len;
-			newsig->signature = d->signatures[uid-LABCOMM_USER];
-		} else {
-			error("sig longer than max length (this ought to be dynamic...)");
-		}
 
+        if(type != PKG_SAMPLE_DECL) {
+            // don't record typedefs and samplerefs (for now)
+            // to avoid number clashes with sample defs
+            // in the parser struct 
+            return accept_signature(d, type, start, uid, (char *) &d->c[nstart+lenlen]);
+        }
 		if(nlen < d->max_name_len) { // leave 1 byte for terminating NULL
+            char *name;
 			d->signatures_name_length[uid-LABCOMM_USER] = nlen;
 			memcpy(d->signatures_name[uid-LABCOMM_USER], &d->c[nstart+lenlen], nlen);
 			d->signatures_name[uid-LABCOMM_USER][nlen]=0;
-			newsig->name = d->signatures_name[uid-LABCOMM_USER];
+			name = d->signatures_name[uid-LABCOMM_USER];
+            return accept_signature(d, type, start, uid, name);
 		} else {
 			error("sig name longer than max length (this ought to be dynamic...");
+            return FALSE;
 		}
-		VERBOSE_PRINTF("signature for uid %x: %s (start=%x,end=%x, nlen=%d,len=%d)\n", uid, get_signature_name(d, uid), start,end, nlen, len);
-		INFO_PRINTF("SIG: %s\n", newsig->name);
-#ifdef LABCOMM_EXPERIMENTAL_CACHED_ENCODED_SIZE
-		if(! d->current_decl_is_varsize) {
-			newsig->cached_encoded_size = enc_size;
-			newsig->encoded_size = encoded_size_static;
-			INFO_PRINTF(".... is static size = %d\n", enc_size);
-		} else {
-			newsig->cached_encoded_size = -1;
-			newsig->encoded_size = encoded_size_parse_sig;
-			INFO_PRINTF(".... is variable size\n");
-		}
-#endif
-		return TRUE;
 	} else {
 		error("sample_decl with uid < LABCOMM_USER");
 		return FALSE;
@@ -412,7 +440,7 @@ static int accept_signature(labcomm_sig_parser_t *d)
 int accept_packet(labcomm_sig_parser_t *d) {
         size_t nbytes;
         unsigned int type = peek_varint(d, &nbytes) ;
-    if(type == VERSION ) {
+    if(type == PKG_VERSION ) {
 		advancen(d, nbytes);//consume type field
         get_varint(d); //ignore length field
 		VERBOSE_PRINTF("got version.\n");
@@ -422,19 +450,37 @@ int accept_packet(labcomm_sig_parser_t *d) {
             char *str = (char *) pop_ptr(d);
             free(str);
 #endif
-    }else if(type == TYPE_DECL ) {
-		//XXX is this used? If so, is it correct?
+	} else if (type == PKG_SAMPLE_DECL) {
+		d->current_decl_is_varsize = FALSE; // <-- a conveniance flag in labcomm_sig_parser_t
 		advancen(d, nbytes);
+		VERBOSE_PRINTF("sample_decl ");
+        get_varint(d); //ignore length field
+		accept_decl(d, type);
+	} else if (type == PKG_SAMPLE_REF) {
 		d->current_decl_is_varsize = FALSE; // <-- a conveniance flag in labcomm_sig_parser_t
-		VERBOSE_PRINTF("type_decl ");
+		advancen(d, nbytes);
+		VERBOSE_PRINTF("sample_ref ");
         get_varint(d); //ignore length field
-		accept_signature(d);
-	} else if (type == SAMPLE_DECL) {
+		accept_decl(d, type);
+    }else if(type == PKG_TYPE_DECL ) {
 		d->current_decl_is_varsize = FALSE; // <-- a conveniance flag in labcomm_sig_parser_t
+		advancen(d, nbytes);//consume type field
+		VERBOSE_PRINTF("type_decl ");
+        get_varint(d); //ignore length field
+		accept_decl(d, type);
+	} else if (type == PKG_TYPE_BINDING) {
+		VERBOSE_PRINTF("type_binding ");
 		advancen(d, nbytes);
-		VERBOSE_PRINTF("sample_decl ");
         get_varint(d); //ignore length field
-		accept_signature(d);
+#ifdef VERBOSE        
+        int sid = 
+#endif            
+            get_varint(d); //ignore sample id field
+#ifdef VERBOSE        
+        int tid =
+#endif            
+            get_varint(d); //ignore type id field
+		VERBOSE_PRINTF("sid=0x%x, tid=0x%x\n ", sid, tid);
 	} else if(type >= LABCOMM_USER) {
 #ifdef EXIT_WHEN_RECEIVING_DATA
 		printf("*** got sample data, exiting\n");
@@ -447,7 +493,7 @@ int accept_packet(labcomm_sig_parser_t *d) {
         error("got unknown type (<LABCOMM_USER)");
 		exit(1);
 #else
-        int len = get_varint(d); //ignore length field
+        int len = get_varint(d); // length field
         printf("got unknown tag: 0x%x, skipping %d bytes\n",type, len);
         advancen(d, len);
 #endif
@@ -464,13 +510,14 @@ static int accept_user_id(labcomm_sig_parser_t *d){
 		push_val(d, uid);
 		return TRUE;
 	} else {
+        error("uid < LABCOMM_USER");
 		return FALSE;
 	}
 }
 
 static int accept_string(labcomm_sig_parser_t *d){
 	unsigned int len = get_varint(d);
-	unsigned char *str=malloc(len);
+	unsigned char *str=malloc(len+1); // len is without terminating null
 	getStr(d, str, len);
 	VERBOSE_PRINTF("%s", str);
 #ifdef RETURN_STRINGS
@@ -527,6 +574,11 @@ static int accept_type(labcomm_sig_parser_t *d){
 			labcomm_sig_parser_t_set_varsize(d);
 			push_val(d, 0);
 			break;
+		case TYPE_SAMPLE_REF :
+			VERBOSE_PRINTF("sample\n");
+			advancen(d, nbytes);
+			push_val(d,  4);
+			break;
 		case ARRAY_DECL :
 			accept_array_decl(d);
 			pop_val(d); // ignore element type
@@ -537,7 +589,10 @@ static int accept_type(labcomm_sig_parser_t *d){
 			// push(d, pop(d) is a NOP --> leave size on stack
 			break;
 		default :
-			printf("accept_type default (type==%x) should not happen\n", type);
+            //should we distinguish between SAMPLE_DEF and TYPE_DEF here?
+			//printf("accept_type default (type==%x) should not happen\n", type);
+			VERBOSE_PRINTF("user type 0x%x\n",type);
+			advancen(d, nbytes);
 			push_val(d, 0);
 			push_val(d, type);
 			return FALSE;
@@ -601,7 +656,11 @@ static int accept_struct_decl(labcomm_sig_parser_t *d){
 	if(tid == STRUCT_DECL) {
 		advancen(d, nbytes);
 		unsigned int nf = get_varint(d);
-		VERBOSE_PRINTF("%d field struct:\n", nf);
+        if(nf == 0) {
+            VERBOSE_PRINTF("void\n");
+        } else {
+            VERBOSE_PRINTF("%d field struct:\n", nf);
+        }
 		int i;
 #ifdef USE_UNUSED_VARS
 		int numVar=0;
@@ -708,7 +767,7 @@ static int skip_array(labcomm_sig_parser_t *d, unsigned char *sig, int len, int
 
 int skip_struct(labcomm_sig_parser_t *d, unsigned char *sig, unsigned int len, int *pos) {
 	size_t nbytes;
-	unsigned int nFields = unpack_varint(sig,*pos, &nbytes);
+	int nFields = unpack_varint(sig,*pos, &nbytes);
 	*pos += nbytes;
 	unsigned int i;
 	unsigned int skipped=0;
@@ -719,7 +778,7 @@ int skip_struct(labcomm_sig_parser_t *d, unsigned char *sig, unsigned int len, i
 #ifdef DEBUG
 		VERBOSE_PRINTF("field #%d:\n----namelen==%d\n",i,namelen);
 		char name[namelen+1]; //HERE BE DRAGONS. alloca?
-		strncpy(name, sig+*pos+nbytes, namelen);
+		strncpy(name, (const char *)sig+*pos+nbytes, namelen);
 		name[namelen]=0;
 		VERBOSE_PRINTF("----name = %s\n",name);
 #endif
@@ -797,7 +856,7 @@ int skip_type(unsigned int type, labcomm_sig_parser_t *d,
 }
 #else
 int skip_type(unsigned int type, labcomm_sig_parser_t *d,
-		unsigned char *sig, unsigned int len, int *pos)
+		const char *sig, unsigned int len, int *pos)
 {
 	int skipped=0;
 	VERBOSE_PRINTF("skip_type %x\n", type);
@@ -849,7 +908,7 @@ int skip_packed_sample_data(labcomm_sig_parser_t *d, struct labcomm_signature *s
 	unsigned int skipped = 0;	//skipped byte counter
 	while(pos < sig->size) {
 		size_t nbytes;
-		unsigned int type = unpack_varint(sig->signature,pos, &nbytes);
+		int type = unpack_varint(sig->signature,pos, &nbytes);
 		pos+=nbytes;
 		skipped += skip_type(type, d, sig->signature, sig->size, &pos);
 	}
diff --git a/lib/c/2014/experimental/labcomm_sig_parser.h b/lib/c/2014/experimental/labcomm_sig_parser.h
index b40a534ef5461e9b12f79fe3af8053842d4011e4..46a1d1e41ba7e68379437f2e3b3bdd1f563b0b4c 100644
--- a/lib/c/2014/experimental/labcomm_sig_parser.h
+++ b/lib/c/2014/experimental/labcomm_sig_parser.h
@@ -8,14 +8,18 @@
 #ifndef LABCOMM_SIG_PARSER_H
 #define LABCOMM_SIG_PARSER_H
 
+#include "../labcomm.h"
 #include "../labcomm_private.h"
 
-#undef DEBUG 
-#undef QUIET_STACK	   // don't print anything for push/pop
+#define DEBUG 
+#define QUIET_STACK	   // don't print anything for push/pop
 #undef DEBUG_STACK_VERBOSE // dump stack, otherwise just print value of top
 
 #undef QUIET 		//just print type and size when skipping data
-// #undef VERBOSE 		// print in great detail
+#define VERBOSE 		// print in great detail
+
+
+#undef SKIP_BY_PARSING
 
 #undef STATIC_ALLOCATION  //dynamic allocation not completely implemented
 
@@ -24,6 +28,7 @@
 #define MAX_SIGNATURES 16
 #define MAX_NAME_LEN 32 
 #define MAX_SIG_LEN 128
+#define TYPEDEF_BASE MAX_SIGNATURES
 
 #endif
 
@@ -43,21 +48,24 @@ typedef struct {
 	size_t max_signatures;                 // set by init(...)
 	size_t max_name_len;
 	size_t max_sig_len; 
+    // arrays for signatures and typedefs
+    // signatures start at index 0
+    // typedefs start at index MAX_SIGNATURES
 #ifdef STATIC_ALLOCATION
-	struct labcomm_signature sig_ts[MAX_SIGNATURES];
+	struct labcomm_signature sig_ts[2*MAX_SIGNATURES];
 
-	unsigned int signatures_length[MAX_SIGNATURES];
-	unsigned int signatures_name_length[MAX_SIGNATURES];
-	unsigned char signatures_name[MAX_SIGNATURES][MAX_NAME_LEN]; 
-	unsigned char signatures[MAX_SIGNATURES][MAX_SIG_LEN];
+	unsigned int signatures_length[2*MAX_SIGNATURES];
+	unsigned int signatures_name_length[2*MAX_SIGNATURES];
+	unsigned char signatures_name[2*MAX_SIGNATURES][MAX_NAME_LEN]; 
+	unsigned char signatures[2*MAX_SIGNATURES][MAX_SIG_LEN];
 #else
-	struct labcomm_signature *sig_ts;           // [MAX_SIGNATURES]
+	struct labcomm_signature *sig_ts;           // [2*MAX_SIGNATURES]
 
-	unsigned int *signatures_length;       // [MAX_SIGNATURES]
-	unsigned char **signatures;            // [MAX_SIGNATURES][MAX_SIG_LEN];
+	unsigned int *signatures_length;       // [2*MAX_SIGNATURES]
+	unsigned char **signatures;            // [2*MAX_SIGNATURES][MAX_SIG_LEN];
 
-	unsigned int *signatures_name_length;  // [MAX_SIGNATURES]
-	char **signatures_name;       // [MAX_SIGNATURES][MAX_NAME_LEN];
+	unsigned int *signatures_name_length;  // [2*MAX_SIGNATURES]
+	char **signatures_name;       // [2*MAX_SIGNATURES][MAX_NAME_LEN];
 #endif
 
 } labcomm_sig_parser_t;
@@ -104,17 +112,12 @@ int skip_packed_sample_data(labcomm_sig_parser_t *p, struct labcomm_signature *s
 
 #undef RETURN_STRINGS  //  not really tested
 
-#ifndef TRUE
-
-#define FALSE 0
-#define TRUE 1
-
-#endif
-
 typedef enum{
-        VERSION = LABCOMM_VERSION,
-        SAMPLE_DECL = LABCOMM_SAMPLE_DEF,
-        TYPE_DECL = LABCOMM_TYPEDEF,
+        PKG_VERSION = LABCOMM_VERSION,
+        PKG_SAMPLE_DECL = LABCOMM_SAMPLE_DEF,
+        PKG_SAMPLE_REF = LABCOMM_SAMPLE_REF,
+        PKG_TYPE_DECL = LABCOMM_TYPE_DEF,
+        PKG_TYPE_BINDING = LABCOMM_TYPE_BINDING,
 
         ARRAY_DECL = LABCOMM_ARRAY,
         STRUCT_DECL = LABCOMM_STRUCT,
@@ -126,6 +129,7 @@ typedef enum{
         TYPE_LONG  = LABCOMM_LONG,
         TYPE_FLOAT  = LABCOMM_FLOAT,
         TYPE_DOUBLE  = LABCOMM_DOUBLE,
-        TYPE_STRING  = LABCOMM_STRING
+        TYPE_STRING  = LABCOMM_STRING,
+        TYPE_SAMPLE_REF  = LABCOMM_REF
 } labcomm_type ;
 #endif
diff --git a/lib/c/2014/labcomm.c b/lib/c/2014/labcomm.c
index a1994aff1ec08e7356295f4d3dcd6d12408e9446..a01c96bd8018687e8e3356e50ad01c3025d50ba3 100644
--- a/lib/c/2014/labcomm.c
+++ b/lib/c/2014/labcomm.c
@@ -47,19 +47,19 @@
     UNWRAP_ac( __VA_ARGS__) = UNWRAP_ac(__VA_ARGS__)->next;		\
   }
 
-int labcomm_reader_alloc(struct labcomm_reader *r, 
+int labcomm_reader_alloc(struct labcomm_reader *r,
                          struct labcomm_reader_action_context *action_context)
 {
   UNWRAP(alloc, r, action_context);
 }
 
-int labcomm_reader_free(struct labcomm_reader *r, 
+int labcomm_reader_free(struct labcomm_reader *r,
                         struct labcomm_reader_action_context *action_context)
 {
   UNWRAP(free, r, action_context);
 }
 
-int labcomm_reader_start(struct labcomm_reader *r, 
+int labcomm_reader_start(struct labcomm_reader *r,
                          struct labcomm_reader_action_context *action_context,
 			 int local_index, int remote_index,
 			 const struct labcomm_signature *signature,
@@ -68,41 +68,41 @@ int labcomm_reader_start(struct labcomm_reader *r,
   UNWRAP(start, r, action_context, local_index, remote_index, signature, value);
 }
 
-int labcomm_reader_end(struct labcomm_reader *r, 
+int labcomm_reader_end(struct labcomm_reader *r,
                        struct labcomm_reader_action_context *action_context)
 {
   UNWRAP(end, r, action_context);
 }
 
-int labcomm_reader_fill(struct labcomm_reader *r, 
+int labcomm_reader_fill(struct labcomm_reader *r,
                         struct labcomm_reader_action_context *action_context)
 {
   UNWRAP(fill, r, action_context);
 }
 
-int labcomm_reader_ioctl(struct labcomm_reader *r, 
+int labcomm_reader_ioctl(struct labcomm_reader *r,
                          struct labcomm_reader_action_context *action_context,
                          int local_index, int remote_index,
-                         const struct labcomm_signature *signature, 
+                         const struct labcomm_signature *signature,
                          uint32_t ioctl_action, va_list args)
 {
-  UNWRAP(ioctl, r, action_context, 
+  UNWRAP(ioctl, r, action_context,
 	 local_index, remote_index, signature, ioctl_action, args);
 }
 
-int labcomm_writer_alloc(struct labcomm_writer *w, 
+int labcomm_writer_alloc(struct labcomm_writer *w,
                          struct labcomm_writer_action_context *action_context)
 {
   UNWRAP(alloc, w, action_context);
 }
 
-int labcomm_writer_free(struct labcomm_writer *w, 
+int labcomm_writer_free(struct labcomm_writer *w,
                         struct labcomm_writer_action_context *action_context)
 {
   UNWRAP(free, w, action_context);
 }
 
-int labcomm_writer_start(struct labcomm_writer *w, 
+int labcomm_writer_start(struct labcomm_writer *w,
                          struct labcomm_writer_action_context *action_context,
                          int index, const struct labcomm_signature *signature,
                          void *value)
@@ -110,26 +110,26 @@ int labcomm_writer_start(struct labcomm_writer *w,
   UNWRAP(start, w, action_context, index, signature, value);
 }
 
-int labcomm_writer_end(struct labcomm_writer *w, 
+int labcomm_writer_end(struct labcomm_writer *w,
                        struct labcomm_writer_action_context *action_context)
 {
   UNWRAP(end, w, action_context);
-} 
+}
 
-int labcomm_writer_flush(struct labcomm_writer *w, 
+int labcomm_writer_flush(struct labcomm_writer *w,
                          struct labcomm_writer_action_context *action_context)
 {
   UNWRAP(flush, w, action_context);
-} 
+}
 
-int labcomm_writer_ioctl(struct labcomm_writer *w, 
-                         struct labcomm_writer_action_context *action_context, 
-                         int index, 
-                         const struct labcomm_signature *signature, 
+int labcomm_writer_ioctl(struct labcomm_writer *w,
+                         struct labcomm_writer_action_context *action_context,
+                         int index,
+                         const struct labcomm_signature *signature,
                          uint32_t ioctl_action, va_list args)
 {
   UNWRAP(ioctl, w, action_context, index, signature, ioctl_action, args);
-} 
+}
 
 #undef UNWRAP
 #undef UNWRAP_ac
@@ -137,12 +137,12 @@ int labcomm_writer_ioctl(struct labcomm_writer *w,
 
 
 
-static const char *labcomm_error_string[] = { 
+static const char *labcomm_error_string[] = {
 #define LABCOMM_ERROR(name, description) description ,
 #include "labcomm_error.h"
 #undef LABCOMM_ERROR
 };
-static const int labcomm_error_string_count = (sizeof(labcomm_error_string) / 
+static const int labcomm_error_string_count = (sizeof(labcomm_error_string) /
 					       sizeof(labcomm_error_string[0]));
 
 
@@ -175,7 +175,7 @@ void labcomm2014_on_error_fprintf(enum labcomm_error error_id, size_t nbr_va_arg
    fprintf(stderr, "}\n");
 
    va_end(arg_pointer);
- } 
+ }
 #else
  ; // If labcomm can't be compiled with stdio the user will have to make an own error callback functionif he/she needs error reporting.
 #endif
@@ -207,8 +207,8 @@ void *labcomm_signature_array_ref(struct labcomm_memory *memory,
     *first = index;
     *last = index + 1;
     *data = labcomm_memory_alloc(memory, 0, size);
-    if (*data) { 
-      memset(*data, 0, size); 
+    if (*data) {
+      memset(*data, 0, size);
     }
   } else if (index < *first || *last <= index) {
     void *old_data = *data;
@@ -221,8 +221,8 @@ void *labcomm_signature_array_ref(struct labcomm_memory *memory,
     *data = labcomm_memory_alloc(memory, 0, n * size);
     if (*data) {
       memset(*data, 0, n * size);
-      memcpy(*data + (old_first - *first) * size, 
-	     old_data, 
+      memcpy(*data + (old_first - *first) * size,
+	     old_data,
 	     (old_last - old_first) * size);
     }
 //    dump(old_data, size, old_first, old_last);
@@ -236,7 +236,7 @@ void *labcomm_signature_array_ref(struct labcomm_memory *memory,
   }
 }
 
-static int local_index = 0x40;
+static int local_index = LABCOMM_USER;
 
 void labcomm_set_local_index(struct labcomm_signature *signature)
 {
@@ -257,6 +257,11 @@ int labcomm_get_local_index(const struct labcomm_signature *signature)
   return signature->index;
 }
 
+int labcomm_get_local_type_index(const struct labcomm_signature *signature)
+{
+    return labcomm_get_local_index(signature);
+}
+
 int labcomm_internal_sizeof(const struct labcomm_signature *signature,
                             void *v)
 {
diff --git a/lib/c/2014/labcomm.h b/lib/c/2014/labcomm.h
index 4bc6b6cb881f3a16be1780d97adbdeb972dee73c..dd8859e8654e1118e4154609165befc271883420 100644
--- a/lib/c/2014/labcomm.h
+++ b/lib/c/2014/labcomm.h
@@ -39,20 +39,7 @@
 struct labcomm_encoder;
 struct labcomm_decoder;
 
-/*
- * Signature entry
- */
-struct labcomm_signature {
-  char *name;
-  int (*encoded_size)(void *); /* void* refers to sample_data */
-  int size;
-  unsigned char *signature; 
-  int index;
-#ifdef LABCOMM_EXPERIMENTAL_CACHED_ENCODED_SIZE
-  int cached_encoded_size; // -1 if not initialized or type is variable size
-#endif
-};
-
+#include "labcomm_type_signature.h"
 /*
  * Error handling.
  */
@@ -85,9 +72,6 @@ typedef int (*labcomm_handle_new_datatype_callback)(
   struct labcomm_decoder *decoder,
   struct labcomm_signature *sig);
 
-void labcomm_decoder_register_new_datatype_handler(struct labcomm_decoder *d,
-		labcomm_handle_new_datatype_callback on_new_datatype);
-
 /*
  * Dynamic memory handling
  *   lifetime == 0     memory that will live for as long as the 
diff --git a/lib/c/2014/labcomm_decoder.c b/lib/c/2014/labcomm_decoder.c
index 54575ee1eaf7fbb62fecc0dc0427b4696f08cb39..cac035f6cb431e97efad2836dd33f5d86dd3fcb6 100644
--- a/lib/c/2014/labcomm_decoder.c
+++ b/lib/c/2014/labcomm_decoder.c
@@ -26,6 +26,18 @@
 #include "labcomm_ioctl.h"
 #include "labcomm_dynamic_buffer_writer.h"
 
+#ifdef DEBUG
+#define DEBUG_FPRINTF(str, ...) fprintf(str, ##__VA_ARGS__)
+#else
+#define DEBUG_FPRINTF(str, ...)
+#endif
+
+#ifdef DECODER_DEBUG
+#define DECODER_DEBUG_FPRINTF(str, ...) fprintf(str, ##__VA_ARGS__) 
+#else
+#define DECODER_DEBUG_FPRINTF(str, ...)
+#endif
+
 struct sample_entry {
   int remote_index;
   const struct labcomm_signature *signature;
@@ -166,6 +178,21 @@ static int handle_sample_ref(struct labcomm_decoder *d, int remote_index,
   return result;
 }
 
+static int decoder_skip(struct labcomm_decoder *d, int len, int tag)
+{
+  int i;
+  DECODER_DEBUG_FPRINTF(stdout, "got tag 0x%x, skipping %d bytes\n", tag, len);
+  for(i = 0; i <len; i++){
+    DECODER_DEBUG_FPRINTF(stderr, ".");
+    labcomm_read_byte(d->reader);
+    if (d->reader->error < 0) {
+      DECODER_DEBUG_FPRINTF(stderr, "\nerror while skipping: %d\n",  d->reader->error);
+      return d->reader->error;
+    }
+  }
+  DECODER_DEBUG_FPRINTF(stderr, "\n");
+  return tag;
+}
 
 static int decode_sample_def_or_ref(struct labcomm_decoder *d, int kind)
 {
@@ -200,16 +227,21 @@ static int decode_sample_def_or_ref(struct labcomm_decoder *d, int kind)
       goto free_signature_signature;
     }
   }
-  if (kind == LABCOMM_SAMPLE_DEF) {
-    result = handle_sample_def(d, remote_index, &signature);
-  } else if (kind == LABCOMM_SAMPLE_REF) {
-    result = handle_sample_ref(d, remote_index, &signature);
-    if (result == -ENOENT) {
-      /* Dummy value to silently continue */
-      result = LABCOMM_SAMPLE_REF;
-    }
-  } else {
-    result = -EINVAL;
+  switch (kind) {
+    case LABCOMM_SAMPLE_DEF: {
+      result = handle_sample_def(d, remote_index, &signature);
+      break;
+    } 
+    case LABCOMM_SAMPLE_REF: {
+      result = handle_sample_ref(d, remote_index, &signature);
+      if (result == -ENOENT) {
+        /* Dummy value to silently continue */
+        result = LABCOMM_SAMPLE_REF;
+      }
+      break;
+    } 
+    default:
+      result = -EINVAL;
   }
 free_signature_signature:
   labcomm_memory_free(d->memory, 1,  signature.signature);
@@ -249,18 +281,6 @@ static void reader_alloc(struct labcomm_decoder *d)
   }
 }
 
-static int decoder_skip(struct labcomm_decoder *d, int len, int tag)
-{
-  int i;
-  printf("got tag 0x%x, skipping %d bytes\n", tag, len);
-  for(i = 0; i <len; i++){
-    labcomm_read_byte(d->reader);
-    if (d->reader->error < 0) {
-      return d->reader->error;
-    }
-  }
-  return tag;
-}
 /* d        - decoder to read from
    registry - decoder to lookup signatures (registry != d only if
                 nesting decoders, e.g., when decoding pragma)
@@ -368,17 +388,29 @@ int labcomm_decoder_decode_one(struct labcomm_decoder *d)
     }  
     labcomm_memory_free(d->memory, 1,  version);
   } else if (! d->version_ok) {
-    fprintf(stderr, "No VERSION %d %d\n", remote_index, length);
+    DEBUG_FPRINTF(stderr, "No VERSION %d %d\n", remote_index, length);
     result = -ECONNRESET;
   } else if (remote_index == LABCOMM_SAMPLE_DEF) {
     result = decode_sample_def_or_ref(d, LABCOMM_SAMPLE_DEF); 
   } else if (remote_index == LABCOMM_SAMPLE_REF) {
     result = decode_sample_def_or_ref(d, LABCOMM_SAMPLE_REF); 
+  } else if (remote_index == LABCOMM_TYPE_DEF) {
+    result = decode_and_handle(d, d, remote_index);
+    if(result == -ENOENT) { 
+        //No handler for type_defs, skip
+        result = decoder_skip(d, length, remote_index);
+    }
+  } else if (remote_index == LABCOMM_TYPE_BINDING) {
+    result = decode_and_handle(d, d, remote_index);
+    if(result == -ENOENT) { 
+        //No handler for type_bindings, skip
+        result = decoder_skip(d, length, remote_index);
+    }
   } else if (remote_index == LABCOMM_PRAGMA) {
     result = decode_pragma(d, d, length);
   } else if (remote_index < LABCOMM_USER) {
-    fprintf(stderr, "SKIP %d %d\n", remote_index, length);
-    result = remote_index;
+    DECODER_DEBUG_FPRINTF(stderr, "SKIP %d %d\n", remote_index, length);
+    result = decoder_skip(d, length, remote_index);
   } else {
     result = decode_and_handle(d, d, remote_index);
   }
@@ -453,6 +485,133 @@ int labcomm_internal_decoder_ioctl(struct labcomm_decoder *d,
   return result;
 }
 
+#ifndef LABCOMM_NO_TYPEDECL
+//// Code for allowing user code to handle type_defs 
+//// (should perhaps be moved to another file)
+
+static void decode_raw_type_def(
+  struct labcomm_reader *r,
+  void (*handle)(
+    struct labcomm_raw_type_def *v,
+    void *context
+  ),
+  void *context
+)
+{
+  struct labcomm_raw_type_def v;
+  v.index = labcomm_read_packed32(r);
+  if (r->error < 0) { goto out; }
+  v.name  = labcomm_read_string(r);
+  if (r->error < 0) { goto free_name; }
+  v.length = labcomm_read_packed32(r);
+  if (r->error < 0) { goto free_name; }
+  int i;
+  v.signature_data = labcomm_memory_alloc(r->memory, 1, v.length);
+  if(v.signature_data) {
+    for(i=0; i<v.length; i++) {
+      v.signature_data[i] = labcomm_read_byte(r);
+      if (r->error < 0) { goto free_sig; }
+    }  
+    handle(&v, context);
+    }
+free_sig:
+  labcomm_memory_free(r->memory, 1, v.signature_data);
+free_name:
+  labcomm_memory_free(r->memory, 1, v.name);
+out:
+  return;
+}
+int labcomm_decoder_register_labcomm_type_def(
+  struct labcomm_decoder *d,
+  void (*handler)(
+    struct labcomm_raw_type_def *v,
+    void *context
+  ),
+  void *context
+)
+{
+  int tag = LABCOMM_TYPE_DEF;
+  struct sample_entry *entry;
+  int *remote_to_local;
+ 
+  labcomm_scheduler_data_lock(d->scheduler);
+  entry = LABCOMM_SIGNATURE_ARRAY_REF(d->memory,
+				      d->local, struct sample_entry,
+				      tag);
+  if (entry == NULL) { tag = -ENOMEM; goto unlock; }
+  entry->remote_index = tag;
+  entry->signature = NULL;
+  entry->decode = (labcomm_decoder_function) decode_raw_type_def;
+  entry->handler =(labcomm_handler_function) handler;
+  entry->context = context;
+
+  remote_to_local = LABCOMM_SIGNATURE_ARRAY_REF(d->memory,
+                                                    d->remote_to_local, int,
+                                                    tag);
+  *remote_to_local = tag;
+unlock:
+  labcomm_scheduler_data_unlock(d->scheduler);
+
+  return tag;
+}
+
+
+static void decode_type_binding(
+  struct labcomm_reader *r,
+  void (*handle)(
+    struct labcomm_type_binding *v,
+    void *context
+  ),
+  void *context
+)
+{
+  struct labcomm_type_binding v;
+  v.sample_index = labcomm_read_packed32(r);
+  if (r->error < 0) { goto out; }
+  v.type_index = labcomm_read_packed32(r);
+  if (r->error < 0) { goto out; }
+  handle(&v, context);
+out:
+  return;
+}
+
+int labcomm_decoder_register_labcomm_type_binding(
+  struct labcomm_decoder *d,
+  void (*handler)(
+    struct labcomm_type_binding *v,
+    void *context
+  ),
+  void *context
+)
+{
+  int tag = LABCOMM_TYPE_BINDING;
+  struct sample_entry *entry;
+  int *remote_to_local;
+ 
+  labcomm_scheduler_data_lock(d->scheduler);
+  entry = LABCOMM_SIGNATURE_ARRAY_REF(d->memory,
+				      d->local, struct sample_entry,
+				      tag);
+  if (entry == NULL) { tag = -ENOMEM; goto unlock; }
+  entry->remote_index = tag;
+  entry->signature = NULL;
+  entry->decode = (labcomm_decoder_function) decode_type_binding;
+  entry->handler =(labcomm_handler_function) handler;
+  entry->context = context;
+
+  remote_to_local = LABCOMM_SIGNATURE_ARRAY_REF(d->memory,
+                                                    d->remote_to_local, int,
+                                                    tag);
+  *remote_to_local = tag;
+unlock:
+  labcomm_scheduler_data_unlock(d->scheduler);
+
+  return tag;
+}
+
+//// End type_def handling
+#endif
+
 int labcomm_internal_decoder_register(
   struct labcomm_decoder *d,
   const struct labcomm_signature *signature,
diff --git a/lib/c/2014/labcomm_encoder.c b/lib/c/2014/labcomm_encoder.c
index 4085bbd38c30a93af55714f54ead443ebaf563a3..4b71ed03285dfd9dfc1de13f29c4c02705d12794 100644
--- a/lib/c/2014/labcomm_encoder.c
+++ b/lib/c/2014/labcomm_encoder.c
@@ -24,6 +24,10 @@
 #include "labcomm.h"
 #include "labcomm_private.h"
 #include "labcomm_ioctl.h"
+#include "labcomm_dynamic_buffer_writer.h"
+
+//define the following to disable encoding of typedefs
+#undef LABCOMM_WITHOUT_TYPE_DEFS
 
 struct labcomm_encoder {
   struct labcomm_writer *writer;
@@ -32,13 +36,15 @@ struct labcomm_encoder {
   struct labcomm_scheduler *scheduler;
   LABCOMM_SIGNATURE_ARRAY_DEF(registered, int);
   LABCOMM_SIGNATURE_ARRAY_DEF(sample_ref, int);
+  LABCOMM_SIGNATURE_ARRAY_DEF(typedefs, int);
 };
 
-struct labcomm_encoder *labcomm_encoder_new(
+static struct labcomm_encoder *internal_encoder_new(
   struct labcomm_writer *writer,
   struct labcomm_error_handler *error,
   struct labcomm_memory *memory,
-  struct labcomm_scheduler *scheduler)
+  struct labcomm_scheduler *scheduler,
+  labcomm_bool outputVer)
 {
   struct labcomm_encoder *result;
 
@@ -58,25 +64,31 @@ struct labcomm_encoder *labcomm_encoder_new(
     result->scheduler = scheduler;
     LABCOMM_SIGNATURE_ARRAY_INIT(result->registered, int);
     LABCOMM_SIGNATURE_ARRAY_INIT(result->sample_ref, int);
+    LABCOMM_SIGNATURE_ARRAY_INIT(result->typedefs, int);
     labcomm_writer_alloc(result->writer,
 			 result->writer->action_context);
-    labcomm_writer_start(result->writer, 
-                         result->writer->action_context, 
-                         LABCOMM_VERSION, NULL, CURRENT_VERSION);
-    labcomm_write_packed32(result->writer, LABCOMM_VERSION);
-#ifdef LENGTH_INCL_TAG    
-    length = (labcomm_size_packed32(LABCOMM_VERSION) +
-              labcomm_size_string(CURRENT_VERSION));
-#else
-    length = labcomm_size_string(CURRENT_VERSION);
-#endif
-    labcomm_write_packed32(result->writer, length);
-    labcomm_write_string(result->writer, CURRENT_VERSION);
-    labcomm_writer_end(result->writer, result->writer->action_context);
+    if(outputVer) {
+        labcomm_writer_start(result->writer,
+                            result->writer->action_context,
+                            LABCOMM_VERSION, NULL, CURRENT_VERSION);
+        labcomm_write_packed32(result->writer, LABCOMM_VERSION);
+        length = labcomm_size_string(CURRENT_VERSION);
+        labcomm_write_packed32(result->writer, length);
+        labcomm_write_string(result->writer, CURRENT_VERSION);
+        labcomm_writer_end(result->writer, result->writer->action_context);
+    }
   }
   return result;
 }
 
+struct labcomm_encoder *labcomm_encoder_new(
+  struct labcomm_writer *writer,
+  struct labcomm_error_handler *error,
+  struct labcomm_memory *memory,
+  struct labcomm_scheduler *scheduler)
+{
+    return internal_encoder_new(writer,error,memory,scheduler,TRUE);
+}
 void labcomm_encoder_free(struct labcomm_encoder* e)
 {
   struct labcomm_memory *memory = e->memory;
@@ -84,6 +96,7 @@ void labcomm_encoder_free(struct labcomm_encoder* e)
   labcomm_writer_free(e->writer, e->writer->action_context);
   LABCOMM_SIGNATURE_ARRAY_FREE(e->memory, e->registered, int);
   LABCOMM_SIGNATURE_ARRAY_FREE(e->memory, e->sample_ref, int);
+  LABCOMM_SIGNATURE_ARRAY_FREE(e->memory, e->typedefs, int);
   labcomm_memory_free(memory, 0, e);
 }
 
@@ -99,9 +112,10 @@ int labcomm_internal_encoder_register(
   labcomm_scheduler_writer_lock(e->scheduler);
   if (index <= 0) { goto out; }
   done = LABCOMM_SIGNATURE_ARRAY_REF(e->memory, e->registered, int, index);
-  if (*done) { goto out; }
-  *done = 1;	
-  err = labcomm_writer_start(e->writer, e->writer->action_context, 
+  if (*done) {
+      goto out; }
+  *done = 1;
+  err = labcomm_writer_start(e->writer, e->writer->action_context,
 			     index, signature, NULL);
   if (err == -EALREADY) { result = 0; goto out; }
   if (err != 0) { result = err; goto out; }
@@ -139,7 +153,11 @@ int labcomm_internal_encode(
   index = labcomm_get_local_index(signature);
   length = (signature->encoded_size(value));
   labcomm_scheduler_writer_lock(e->scheduler);
-  result = labcomm_writer_start(e->writer, e->writer->action_context, 
+  if (! LABCOMM_SIGNATURE_ARRAY_GET(e->registered, int, index, 0)) {
+    result = -EINVAL;
+    goto no_end;
+  }
+  result = labcomm_writer_start(e->writer, e->writer->action_context,
 				index, signature, value);
   if (result == -EALREADY) { result = 0; goto no_end; }
   if (result != 0) { goto out; }
@@ -167,8 +185,8 @@ int labcomm_encoder_sample_ref_register(
 
   done = LABCOMM_SIGNATURE_ARRAY_REF(e->memory, e->sample_ref, int, index);
   if (*done) { goto out; }
-  *done = 1;	
-  err = labcomm_writer_start(e->writer, e->writer->action_context, 
+  *done = 1;
+  err = labcomm_writer_start(e->writer, e->writer->action_context,
 			     index, signature, NULL);
   if (err == -EALREADY) { result = 0; goto out; }
   if (err != 0) { result = err; goto out; }
@@ -195,20 +213,20 @@ out:
   return result;
 }
 
-int labcomm_encoder_ioctl(struct labcomm_encoder *encoder, 
+int labcomm_encoder_ioctl(struct labcomm_encoder *encoder,
 			  uint32_t action,
 			  ...)
 {
   int result;
   va_list va;
-  
+
   if (LABCOMM_IOC_SIG(action) != LABCOMM_IOC_NOSIG) {
     result = -EINVAL;
     goto out;
   }
-  
+
   va_start(va, action);
-  result = labcomm_writer_ioctl(encoder->writer, 
+  result = labcomm_writer_ioctl(encoder->writer,
 			       encoder->writer->action_context,
 			       0, NULL, action, va);
   va_end(va);
@@ -217,7 +235,7 @@ out:
   return result;
 }
 
-int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder, 
+int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder,
 				   const struct labcomm_signature *signature,
 				   uint32_t action, va_list va)
 {
@@ -225,8 +243,8 @@ int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder,
   int index;
 
   index = labcomm_get_local_index(signature);
-  result = labcomm_writer_ioctl(encoder->writer, 
-				encoder->writer->action_context, 
+  result = labcomm_writer_ioctl(encoder->writer,
+				encoder->writer->action_context,
 				index, signature, action, va);
   return result;
 }
@@ -245,3 +263,136 @@ int labcomm_internal_encoder_signature_to_index(
   return index;
 }
 
+
+/**********************************************************
+ * Start of code related to sending (hierarchical)
+ * typedefs. Define LABCOMM_WITHOUT_TYPEDEFS to disable
+ **********************************************************/
+#ifndef LABCOMM_WITHOUT_TYPE_DEFS
+
+static void write_sig_tree_byte(char b, const struct labcomm_signature *signature,
+                           void *context)
+{
+  struct labcomm_encoder *e = context;
+  if(signature) {
+    labcomm_write_packed32(e->writer, labcomm_get_local_index(signature));
+  }else {
+    if (e->writer->pos >= e->writer->count) {
+     labcomm_writer_flush(e->writer, e->writer->action_context);
+    }
+    e->writer->data[e->writer->pos] = b;
+    e->writer->pos++;
+  }
+}
+
+static void do_write_signature(struct labcomm_encoder * e, 
+                               const struct labcomm_signature *signature, 
+                               unsigned char flatten)
+{
+  map_signature(write_sig_tree_byte, e, signature, flatten);
+}
+
+static void sig_size(char b, const struct labcomm_signature *signature,
+                     void *context)
+{
+  int *result = context;
+  int diff;
+  if(signature) {
+    int idx = labcomm_get_local_index(signature);
+    diff = labcomm_size_packed32(idx);
+  }else {
+    diff = 1;
+  }
+    (*result)+=diff;
+}
+
+static int calc_sig_encoded_size(struct labcomm_encoder *e,
+                                 const struct labcomm_signature *sig)
+{
+  int result=0;
+  map_signature(sig_size, &result, sig, FALSE);
+  return result;
+}
+
+static int internal_reg_type(
+  struct labcomm_encoder *e,
+  const struct labcomm_signature *signature,
+  labcomm_bool flatten)
+{
+  int result = -EINVAL;
+  int index, *done, err;
+
+  index = labcomm_get_local_index(signature);
+  labcomm_scheduler_writer_lock(e->scheduler);
+  if (index <= 0) { goto out; }
+  done = LABCOMM_SIGNATURE_ARRAY_REF(e->memory, e->typedefs, int, index);
+  if (*done) { goto out; }
+  *done = 1;
+  err = labcomm_writer_start(e->writer, e->writer->action_context,
+                 index, signature, NULL);
+  if (err == -EALREADY) { result = 0; goto out; }
+  if (err != 0) { result = err; goto out; }
+
+  int sig_size = calc_sig_encoded_size(e, signature);
+  int len =  labcomm_size_packed32(index) +
+             labcomm_size_string(signature->name) +
+             labcomm_size_packed32(sig_size) +
+              sig_size;
+
+  labcomm_write_packed32(e->writer, LABCOMM_TYPE_DEF);
+  labcomm_write_packed32(e->writer, len);
+  labcomm_write_packed32(e->writer, index);
+  labcomm_write_string(e->writer, signature->name);
+  labcomm_write_packed32(e->writer, sig_size);
+  do_write_signature(e, signature, FALSE);
+
+  labcomm_writer_end(e->writer, e->writer->action_context);
+  result = e->writer->error;
+out:
+  labcomm_scheduler_writer_unlock(e->scheduler);
+  return result;
+}
+#endif
+
+int labcomm_internal_encoder_type_register(
+  struct labcomm_encoder *e,
+  const struct labcomm_signature *signature)
+{
+#ifndef LABCOMM_WITHOUT_TYPE_DEFS
+  return internal_reg_type(e, signature, FALSE);
+#else
+  return 0;
+#endif
+}
+int labcomm_internal_encoder_type_bind(
+  struct labcomm_encoder *e,
+  const struct labcomm_signature *signature,
+  char has_deps)
+{
+#ifndef LABCOMM_WITHOUT_TYPE_DEFS
+  int result = -EINVAL;
+  int err;
+  int sindex = labcomm_get_local_index(signature);
+  int tindex = has_deps ? labcomm_get_local_type_index(signature) : LABCOMM_BIND_SELF;
+  labcomm_scheduler_writer_lock(e->scheduler);
+  if(sindex <= 0 || (has_deps && tindex <= 0)) {goto out;}
+  err = labcomm_writer_start(e->writer, e->writer->action_context,
+			     LABCOMM_TYPE_BINDING, signature, NULL);
+  if (err == -EALREADY) { result = 0; goto out; }
+  if (err != 0) { result = err; goto out; }
+  int length = (labcomm_size_packed32(sindex) +
+                labcomm_size_packed32(tindex));
+  labcomm_write_packed32(e->writer, LABCOMM_TYPE_BINDING);
+  labcomm_write_packed32(e->writer, length);
+  labcomm_write_packed32(e->writer, sindex);
+  labcomm_write_packed32(e->writer, tindex);
+  labcomm_writer_end(e->writer, e->writer->action_context);
+  result = e->writer->error;
+
+out:
+  labcomm_scheduler_writer_unlock(e->scheduler);
+  return result;
+#else
+  return 0;
+#endif
+}
diff --git a/lib/c/2014/labcomm_private.h b/lib/c/2014/labcomm_private.h
index 8ed93ce02c11d33e423be5332481eae6fa6360b2..1cef97dc4cec3abc311e040517d189b2aa10a6e3 100644
--- a/lib/c/2014/labcomm_private.h
+++ b/lib/c/2014/labcomm_private.h
@@ -42,8 +42,8 @@
 #define LABCOMM_VERSION      0x01
 #define LABCOMM_SAMPLE_DEF   0x02
 #define LABCOMM_SAMPLE_REF   0x03
-#define LABCOMM_TYPEDEF      0x04
-#define LABCOMM_TYPEBINDING  0x05
+#define LABCOMM_TYPE_DEF     0x04
+#define LABCOMM_TYPE_BINDING 0x05
 #define LABCOMM_PRAGMA       0x3f
 #define LABCOMM_USER         0x40 /* ..0xffffffff */
 
@@ -66,6 +66,11 @@
 #define LABCOMM_STRING       0x27
 #define LABCOMM_REF          0x28
 
+/* 
+ * other special values
+ */
+
+#define LABCOMM_BIND_SELF    0
 
 /*
  * Macro to automagically call constructors in modules compiled 
@@ -365,6 +370,15 @@ int labcomm_writer_ioctl(struct labcomm_writer *w,
 			 int index, const struct labcomm_signature *signature, 
 			 uint32_t ioctl_action, va_list args);
 
+int labcomm_internal_encoder_type_register(
+  struct labcomm_encoder *e,
+  const struct labcomm_signature *signature);
+
+int labcomm_internal_encoder_type_bind(
+  struct labcomm_encoder *e,
+  const struct labcomm_signature *signature,
+  char has_deps);
+
 int labcomm_internal_encoder_register(
   struct labcomm_encoder *encoder, 
   const struct labcomm_signature *signature, 
@@ -544,4 +558,6 @@ void labcomm_set_local_index(struct labcomm_signature *signature);
 /* Get the local index for a signature */
 int labcomm_get_local_index(const struct labcomm_signature *s);
 
+int labcomm_get_local_type_index(const struct labcomm_signature *s);
+
 #endif
diff --git a/lib/c/2014/labcomm_type_signature.c b/lib/c/2014/labcomm_type_signature.c
new file mode 100644
index 0000000000000000000000000000000000000000..3cb9cc36e266b32977491b049fea0a1141234f6a
--- /dev/null
+++ b/lib/c/2014/labcomm_type_signature.c
@@ -0,0 +1,128 @@
+#include "labcomm.h"
+#include <string.h>   // for memcmp
+#include <stdio.h>   // for debug printf
+
+/* Dump signature bytes on stdout 
+ */
+
+void labcomm_signature_print(struct labcomm_signature_data *signature)
+{
+  struct labcomm_signature_data *p = signature ;
+  while (p->length != -1) {
+    if (p->length) {
+      int i;
+      for ( i = 0 ; i < p->length ; i++) {
+        printf("%02x ", p->u.bytes[i]);
+      }
+    } else if(p->u.signature){
+      labcomm_signature_print(p->u.signature->treedata);
+    } else {
+      printf("neither data nor ref, bailing out.\n");
+      return;
+    }
+    p+=1;
+  }
+  printf("\n");
+}
+static labcomm_bool sig_dump_checked(struct labcomm_signature_data *signature, 
+                            char *buf, int *len, int buflen);
+
+/* buf (out)   : byte array to write signature into
+   len (in/out): input: buf size, out: signature length
+
+   return TRUE if aborted due to overrun
+ */
+labcomm_bool labcomm_signature_dump(struct labcomm_signature_data *signature, 
+                           char *buf, int *len)
+{
+  int buflen = *len;
+  *len = 0;
+  return sig_dump_checked(signature, buf, len, buflen);
+}
+
+/* internal function with bounds checking for buf.
+ * buflen: capacity of buf
+ */
+static labcomm_bool sig_dump_checked(struct labcomm_signature_data *signature, 
+                            char *buf, int *len, int buflen)
+{
+  struct labcomm_signature_data *p = signature;
+  while ( (p->length != -1) && (*len < buflen)) {
+    if (p->length) {
+      int i;
+      for ( i = 0 ; (i < p->length) && (*len < buflen); i++) {
+        *buf++ = p->u.bytes[i];
+        ++*len;
+      }
+    } else if(p->u.signature){
+      int tmplen=*len;
+      //recursing. c.f. dump()
+      sig_dump_checked(p->u.signature->treedata, buf, len, buflen);
+      int inner_len = *len-tmplen;
+      buf += inner_len;
+    } else {
+      //printf("neither data nor ref, bailing out.\n");
+      return TRUE;
+    }
+    p+=1;
+  }
+  return (*len >= buflen);
+}
+
+/* compare signature (flattened, if needed) to other
+   return TRUE if equal
+*/
+labcomm_bool labcomm_signature_cmp( struct labcomm_signature_data *s1,
+                           struct labcomm_signature_data *s2)
+{
+  int buflen=512;
+  char buf1[buflen];
+  int len1=buflen;
+  char buf2[buflen];
+  int len2=buflen;
+  labcomm_bool res1 = labcomm_signature_dump(s1, buf1, &len1);
+  labcomm_bool res2 = labcomm_signature_dump(s2, buf2, &len2);
+  if(res1 || res2) {
+    printf("WARNING: OVERRUN\n");
+    return FALSE;
+  } else {
+    return(len1 == len2 && memcmp(buf1, buf2, len1)==0);
+  }
+}
+/* maps a function f(char b, struct labcomm_signature *s, void *context) 
+ * on each byte (or type ref) in the signature. 
+ *
+ * If flatten, the signature is flattened to a byte array, and the 
+ * second argument to f is always zero.
+ *
+ * Otherwise, when a type ref is encountered, f is called with the first
+ * argument zero and the referenced type as the second argument.
+ *
+ * The context parameter is passed on, unaltered, to f
+ */ 
+void map_signature( void(*f)(char, const struct labcomm_signature *, void *), 
+                    void *context,
+                    const struct labcomm_signature *signature, labcomm_bool flatten)
+{
+  struct labcomm_signature_data* p = signature->treedata;
+  while (p->length != -1) {
+    //fprintf(stderr, "%p %x\n", p, p->length);
+    if (p->length) {
+      int i;
+      for ( i = 0 ; i < p->length ; i++) {
+        (*f)(p->u.bytes[i], 0, context);
+      }
+    } else if (p->u.signature) {
+      if(p->u.signature == 0) printf("p->u.signature == null\n");
+      if(flatten) {
+        map_signature(f, context, p->u.signature, flatten);
+      } else {
+        (*f)(0, p->u.signature, context);
+      }
+    } else {
+      fprintf(stderr, "neither data nor ref, bailing out.\n");
+      return;
+    }
+    p+=1;
+  }
+}
diff --git a/lib/c/2014/labcomm_type_signature.h b/lib/c/2014/labcomm_type_signature.h
new file mode 100644
index 0000000000000000000000000000000000000000..e556589b3c80fc87227d1f7b66e7a72a74d61edb
--- /dev/null
+++ b/lib/c/2014/labcomm_type_signature.h
@@ -0,0 +1,139 @@
+#ifndef LABCOMM_TYPE_SIGNATURE_H
+#define LABCOMM_TYPE_SIGNATURE_H
+
+//XXX move to common.h
+#ifndef labcomm_bool
+#define labcomm_bool char
+#define TRUE 1
+#define FALSE 0
+#endif
+
+/*
+ * Signature entry
+ */
+#ifndef LABCOMM_NO_TYPEDECL
+#ifdef USE_UNIONS
+
+/* Useful for C99 and up (or GCC without -pedantic) */ 
+
+#define LABCOMM_SIGDEF_BYTES_OR_SIGNATURE          \
+  union {                                   \
+    char *bytes;                            \
+    struct labcomm_signature* signature;            \
+  } u;
+
+#define LABCOMM_SIGDEF_BYTES(l, b) { l, .u.bytes=b }
+#define LABCOMM_SIGDEF_SIGNATURE(s) { 0, .u.signature=&s } // addressof, as s is pointing at the sig struct, not directly the the sig_bytes[]
+#define LABCOMM_SIGDEF_END { -1, .u.bytes=0 }
+
+#else
+
+#define LABCOMM_SIGDEF_BYTES_OR_SIGNATURE          \
+  struct {                                  \
+    char *bytes;                            \
+    const struct labcomm_signature *signature;            \
+  } u;
+
+#define LABCOMM_SIGDEF_BYTES(l, b) { l, { b, 0 } }
+#define LABCOMM_SIGDEF_SIGNATURE(s) { 0, { 0, &s } }
+#define LABCOMM_SIGDEF_END { -1, { 0, 0 } }
+
+#endif
+
+struct labcomm_signature_data {
+  int length;
+  LABCOMM_SIGDEF_BYTES_OR_SIGNATURE
+};
+
+#endif
+struct labcomm_signature {
+  char *name;
+  int (*encoded_size)(void *); /* void* refers to sample_data */
+  int size;
+  unsigned char *signature; 
+  int index;
+#ifndef LABCOMM_NO_TYPEDECL
+  int tdsize;
+  struct labcomm_signature_data *treedata;
+#endif  
+#ifdef LABCOMM_EXPERIMENTAL_CACHED_ENCODED_SIZE
+  int cached_encoded_size; // -1 if not initialized or type is variable size
+#endif
+};
+
+/* a struct for "raw" type_defs, to be used as an intermediate representation
+ * between decoder and signature parser
+ */
+
+struct labcomm_raw_type_def {
+    char *name;
+    int index;
+    int length;
+    char *signature_data;
+};
+
+/* a struct for type bindings
+ */
+
+struct labcomm_type_binding {
+    int sample_index;
+    int type_index;
+};
+
+/*
+ * functions
+ */
+
+
+/* register a handler for type_defs and type bindings
+ */
+
+int labcomm_decoder_register_labcomm_type_def(
+  struct labcomm_decoder *d,
+  void (*handler)(
+    struct labcomm_raw_type_def *v,
+    void *context
+  ),
+  void *context
+);
+
+int labcomm_decoder_register_labcomm_type_binding(
+  struct labcomm_decoder *d,
+  void (*handler)(
+    struct labcomm_type_binding *v,
+    void *context
+  ),
+  void *context
+);
+
+/* Dump signature bytes on stdout 
+ */
+
+void labcomm_signature_print(struct labcomm_signature_data *signature);
+
+/* compare signatures (flattened, if needed) to other
+*  return TRUE if equal
+*/
+labcomm_bool labcomm_signature_cmp( struct labcomm_signature_data *s2,
+                           struct labcomm_signature_data *s1);
+
+/* flatten and dump signature to a byte array.
+ * buf (out)   : byte array to write signature into
+ * len (in/out): input: buf size, out: signature length
+ *
+ * return TRUE if aborted due to overrun
+ */
+labcomm_bool labcomm_signature_dump(struct labcomm_signature_data *signature, 
+                           char *buf, int *len);
+
+/* maps function f on each byte in the signature
+ * if flatten, the signature is flattened, and the second argument of
+ * f is always zero
+ * otherwise, when a type ref is encountered, f is called with the first
+ * argument zero and the type ref as the second argument.
+ */ 
+void map_signature( void(*f)(char, const struct labcomm_signature *, void *), 
+                    void *context,
+                    const struct labcomm_signature *signature, labcomm_bool flatten);
+
+#endif
diff --git a/lib/c/2014/test/generated_encoding.lc b/lib/c/2014/test/generated_encoding.lc
index e561abee3d5bacbdd502fed94a013ed829bfe46f..4055562aaa48c83c9e92c7d1f008f13ab0468039 100644
--- a/lib/c/2014/test/generated_encoding.lc
+++ b/lib/c/2014/test/generated_encoding.lc
@@ -1,4 +1,5 @@
-sample void V;
+typedef void v_t;
+sample v_t V;
 sample byte B;
 sample struct {
   int i;
diff --git a/lib/c/2014/test/test_labcomm.c b/lib/c/2014/test/test_labcomm.c
index e37950e612d3ffb38c08bdec4b31c0325cb851a7..c8526776e98ea640a92ac6305dd97d2e87c05f60 100644
--- a/lib/c/2014/test/test_labcomm.c
+++ b/lib/c/2014/test/test_labcomm.c
@@ -30,6 +30,44 @@
 #include "labcomm_default_scheduler.h"
 #include "test/gen/test_sample.h"
 
+static struct labcomm_writer writer;
+
+static struct expect {
+  char *description;
+  int result;
+  int (*trampoline)(struct labcomm_decoder *context);
+  struct labcomm_decoder *context;
+} *expect;
+
+static void check_expect()
+{
+  struct expect *p = expect;
+
+  {
+    int i;
+    for (i = 0 ; i < writer.pos ; i++) {
+      fprintf(stderr, "%02x ", writer.data[i]);
+    }
+    fprintf(stderr, "\n");
+  }
+  if (p && p->trampoline) {
+    int err;
+    
+    expect = p + 1;
+    fprintf(stderr, "Checking '%s' expected=%d ", p->description, p->result);
+    err = p->trampoline(p->context);
+    fprintf(stderr, "actual=%d\n", err);
+    if (p->result >= 0 && p->result != err) {
+      fprintf(stderr, "FAILED\n");
+      exit(1);
+    } else if (err == 0) {
+      fprintf(stderr, "FAILED (unexpected 0)\n");
+      exit(1);
+    }
+    writer.pos = 0;
+  }
+}
+
 static unsigned char buffer[512];
 
 static int writer_alloc(struct labcomm_writer *w, 
@@ -41,6 +79,7 @@ static int writer_alloc(struct labcomm_writer *w,
   
   return 0;
 }
+
 static int writer_start(struct labcomm_writer *w, 
 			 struct labcomm_writer_action_context *action_context,
 			 int index, const struct labcomm_signature *signature,
@@ -48,15 +87,27 @@ static int writer_start(struct labcomm_writer *w,
 {
   return 0;
 }
+
+static int buf_writer_end(
+  struct labcomm_writer *w, 
+  struct labcomm_writer_action_context *action_context)
+{
+  check_expect();
+  return 0;
+}
+
 const struct labcomm_writer_action writer_action = {
   .alloc = writer_alloc,
   .start = writer_start,
+  .end = buf_writer_end,
 };
+
 static struct labcomm_writer_action_context writer_action_context = {
   .next = NULL,
   .action = &writer_action,
   .context = NULL
 }; 
+
 static struct labcomm_writer writer =  {
   .action_context = &writer_action_context,
   .data = buffer,
@@ -76,21 +127,25 @@ static int reader_alloc(struct labcomm_reader *r,
   
   return 0;
 }
+
 static int reader_fill(struct labcomm_reader *r, 
 		       struct labcomm_reader_action_context *action_context)
 {
   r->error = -ENOMEM;
   return r->error;
 }
+
 const struct labcomm_reader_action reader_action = {
   .alloc = reader_alloc,
   .fill = reader_fill,
 };
+
 static struct labcomm_reader_action_context reader_action_context = {
   .next = NULL,
   .action = &reader_action,
   .context = NULL
 }; 
+
 static struct labcomm_reader reader =  {
   .action_context = &reader_action_context,
   .data = buffer,
@@ -106,6 +161,7 @@ static test_sample_test_var encoder_var = {
   .n_2 = 1,
   .a = encoder_data,
 };
+
 static int32_t decoder_data[256];
 static test_sample_test_var decoder_var = {
   .n_0 = 1,
@@ -127,8 +183,9 @@ int test_decode_one(struct labcomm_decoder *decoder)
     reader.pos = 0;
     result = labcomm_decoder_decode_one(decoder); 
     if (result >= 0 ) {
-      fprintf(stderr, "Got result from buffer with bogus length (%d)\n",
-	      result);
+      fprintf(stderr,
+              "Got result from buffer with bogus length (%d, %d != %d)\n",
+	      result, reader.count, writer.pos);
       exit(1);
     }
   }
@@ -137,7 +194,7 @@ int test_decode_one(struct labcomm_decoder *decoder)
   reader.count = writer.pos;
   result = labcomm_decoder_decode_one(decoder);
   if (result < 0) {
-    fprintf(stderr, "Got result from buffer with correct length (%d)\n",
+    fprintf(stderr, "Got no result from buffer with correct length (%d)\n",
 	    result);
     exit(1);
   }
@@ -174,26 +231,35 @@ static void test_encode_decode(struct labcomm_encoder *encoder,
 
 int main(void)
 {
-  int err, i;
-  struct labcomm_encoder *encoder = labcomm_encoder_new(
-    &writer, 
+  int i;
+  struct labcomm_decoder *decoder = labcomm_decoder_new(
+    &reader,
     labcomm_default_error_handler,
     labcomm_default_memory,
     labcomm_default_scheduler);
-  struct labcomm_decoder *decoder = labcomm_decoder_new(
-    &reader,
+  struct expect expect_version[] = {
+    { "Version", 1, test_decode_one, decoder },
+    { 0, 0, 0 }
+  };
+  expect = expect_version;
+  struct labcomm_encoder *encoder = labcomm_encoder_new(
+    &writer, 
     labcomm_default_error_handler,
     labcomm_default_memory,
     labcomm_default_scheduler);
-  err = test_decode_one(decoder);
-  fprintf(stderr, "decode of version -> index %d\n", err);
-  writer.pos = 0;
   labcomm_decoder_register_test_sample_test_var(decoder,
 						handle_test_var, 
 						NULL);
+  struct expect expect_registration[] = {
+    { "Sampledef", -1, test_decode_one, decoder },
+#ifdef SHOULD_THIS_BE_REMOVED
+    { "Typedef", -1, test_decode_one, decoder },
+#endif
+    { "Binding", -1, test_decode_one, decoder },
+    { 0, 0, 0 }
+  };
+  expect = expect_registration;
   labcomm_encoder_register_test_sample_test_var(encoder);
-  err = test_decode_one(decoder);
-  fprintf(stderr, "decode of register -> index %d\n", err);
   test_encode_decode(encoder, decoder, 12, 1, 1);
   if (decoder_var.a[0] != encoder_var.a[0]) {
     fprintf(stderr, "Failed to decode correct value %d != %d\n", 
diff --git a/lib/c/2014/test/test_labcomm_copy.c b/lib/c/2014/test/test_labcomm_copy.c
index 728195582a491be649adcb05c4aaa3c930456f69..9261e666cd723d47ddcc97714b4c374eee55f001 100644
--- a/lib/c/2014/test/test_labcomm_copy.c
+++ b/lib/c/2014/test/test_labcomm_copy.c
@@ -199,6 +199,7 @@ int main(int argc, char **argv)
 
   while (labcomm_decoder_decode_one(decoder) > 0) ;
 
+  printf("cache_s1.i = %d, s1.i = %d\n", cache_s1.i, s1.i);
   assert(cache_s1.i == s1.i);
   puts("S1 copied ok");
 
diff --git a/lib/c/2014/test/test_labcomm_generated_encoding.c b/lib/c/2014/test/test_labcomm_generated_encoding.c
index 58462aa0b4dd62a319ef60004ccf37db05a84a30..11f9d7c32fd492543a9ab017a279c85ec369c413 100644
--- a/lib/c/2014/test/test_labcomm_generated_encoding.c
+++ b/lib/c/2014/test/test_labcomm_generated_encoding.c
@@ -32,8 +32,21 @@
 #define IOCTL_WRITER_ASSERT_BYTES 4096
 #define IOCTL_WRITER_RESET 4097
 
+#define EXPECT(...)							\
+  {									\
+    int expected[] = __VA_ARGS__;					\
+    labcomm_encoder_ioctl(encoder, IOCTL_WRITER_ASSERT_BYTES,		\
+			  __LINE__,					\
+			  sizeof(expected)/sizeof(expected[0]),		\
+			  expected);					\
+  }
+
+#define VARIABLE(i) -(i + 1)
+#define IS_VARIABLE(i) (i < 0)
+
 static unsigned char buffer[128];
 struct labcomm_writer *writer;
+static int seen_variable[1024];
 
 static int buf_writer_alloc(
   struct labcomm_writer *w, 
@@ -96,13 +109,23 @@ static int buf_writer_ioctl(
       int *expected = va_arg(arg, int *);
       int i, mismatch;
 
+      mismatch = 0;
       if (w->pos != count) {
-	fprintf(stderr, "Invalid length encoded %d != %d (%s:%d)\n", 
+	fprintf(stderr, "Invalid length detected %d != %d (%s:%d)\n", 
 		w->pos, count, __FILE__, line);
 	mismatch = 1;
       } 
-      for (mismatch = 0, i = 0 ; i < count ; i++) {
-	if (expected[i] >= 0 && expected[i] != buffer[i]) {
+      for (i = 0 ; i < count ; i++) {
+        if (IS_VARIABLE(expected[i])) {
+          if (seen_variable[VARIABLE(expected[i])] == -1) {
+            seen_variable[VARIABLE(expected[i])] = buffer[i];
+          }
+          if (seen_variable[VARIABLE(expected[i])] != buffer[i]) {
+            fprintf(stderr, "Unexpected variable (%d:  != %d)\n",
+                    seen_variable[VARIABLE(expected[i])], buffer[i]);
+            mismatch = 1;
+          }
+        } else if (expected[i] != buffer[i]) {
 	  mismatch = 1;
 	}
       }
@@ -116,7 +139,7 @@ static int buf_writer_ioctl(
 	printf("\n");
 	for (i = 0 ; i < count ; i++) {
 	  if (expected[i] < 0) {
-	    printf(".. ");
+	    printf("v%d ", VARIABLE(expected[i]));
 	  } else {
 	    printf("%2.2x ", expected[i] );
 	  }
@@ -167,21 +190,18 @@ void dump_encoder(struct labcomm_encoder *encoder)
   printf("\n");
 }
 
-#define EXPECT(...)							\
-  {									\
-    int expected[] = __VA_ARGS__;					\
-    labcomm_encoder_ioctl(encoder, IOCTL_WRITER_ASSERT_BYTES,		\
-			  __LINE__,					\
-			  sizeof(expected)/sizeof(expected[0]),		\
-			  expected);					\
-  }
-
 int main(void)
 {
   generated_encoding_B B = 1;
   generated_encoding_R R;
+  struct labcomm_encoder *encoder;
+  int i;
+
+  for (i = 0 ; i < sizeof(seen_variable)/sizeof(seen_variable[0]) ; i++) {
+    seen_variable[i] = -1;
+  }
 
-  struct labcomm_encoder *encoder = labcomm_encoder_new(
+  encoder = labcomm_encoder_new(
     &buffer_writer, 
     labcomm_default_error_handler,
     labcomm_default_memory,
@@ -193,13 +213,24 @@ int main(void)
   /* Register twice to make sure that only one registration gets encoded */
   labcomm_encoder_register_generated_encoding_V(encoder);
   labcomm_encoder_register_generated_encoding_V(encoder);
-  EXPECT({ 0x02, 0x06, -1, 0x01, 'V', 0x02, 0x11, 0x00 });
+  EXPECT({ 0x02, 0x06, VARIABLE(0), 0x01, 'V', 0x02, 0x11, 0x00,
+           0x04, 0x08, VARIABLE(1), 0x03, 'v', '_', 't', 0x02, 0x11, 0x00,
+           0x04, 0x05, VARIABLE(2), 0x01, 'V', 0x01, VARIABLE(1),
+           0x05, 0x02, VARIABLE(0), VARIABLE(2) });
 
   labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET);
   /* Register twice to make sure that only one registration gets encoded */
   labcomm_encoder_register_generated_encoding_B(encoder);
   labcomm_encoder_register_generated_encoding_B(encoder);
-  EXPECT({0x02, 0x05, -1, 0x01, 'B', 0x01, 0x21});
+  EXPECT({ 0x02, 0x05, VARIABLE(3), 0x01, 'B', 0x01, 0x21,
+           0x05, 0x02, VARIABLE(3), LABCOMM_BIND_SELF });
+
+  labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET);
+  /* Register twice to make sure that only one registration gets encoded */
+  labcomm_encoder_register_generated_encoding_R(encoder);
+  labcomm_encoder_register_generated_encoding_R(encoder);
+  EXPECT({ 0x02, 0x08, VARIABLE(4), 0x01, 'R', 0x04, 0x10, 0x01, 0x04, 0x28,
+           0x05, 0x02, VARIABLE(4), LABCOMM_BIND_SELF });
 
   labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET);
   /* Register twice to make sure that only one registration gets encoded */
@@ -207,7 +238,7 @@ int main(void)
                                       labcomm_signature_generated_encoding_V);
   labcomm_encoder_sample_ref_register(encoder, 
                                       labcomm_signature_generated_encoding_V);
-  EXPECT({0x03, 0x06, -1, 0x01, 'V', 0x02, 0x11, 0x00});
+  EXPECT({0x03, 0x06, VARIABLE(5), 0x01, 'V', 0x02, 0x11, 0x00});
 
   labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET);
   /* Register twice to make sure that only one registration gets encoded */
@@ -215,7 +246,7 @@ int main(void)
                                       labcomm_signature_generated_encoding_B);
   labcomm_encoder_sample_ref_register(encoder, 
                                       labcomm_signature_generated_encoding_B);
-  EXPECT({0x03, 0x05, -1, 0x01, 'B', 0x01, 0x21});
+  EXPECT({0x03, 0x05, VARIABLE(6), 0x01, 'B', 0x01, 0x21});
 
   labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET);
   /* Register twice to make sure that only one registration gets encoded */
@@ -223,16 +254,16 @@ int main(void)
                                       labcomm_signature_generated_encoding_R);
   labcomm_encoder_sample_ref_register(encoder, 
                                       labcomm_signature_generated_encoding_R);
-  EXPECT({0x03, 0x08, -1, 0x01, 'R', 0x04, 0x10, 0x01, 0x04, 0x28});
+  EXPECT({0x03, 0x08, VARIABLE(7), 0x01, 'R', 0x04, 0x10, 0x01, 0x04, 0x28});
 
   labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET);
   // was: labcomm_encode_generated_encoding_V(encoder, &V);
   labcomm_encode_generated_encoding_V(encoder);
-  EXPECT({-1, 0x00 });
+  EXPECT({VARIABLE(10), 0x00 });
 
   labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET);
   labcomm_encode_generated_encoding_B(encoder, &B);
-  EXPECT({-1, 0x01, 1});
+  EXPECT({VARIABLE(20), 0x01, 1});
 
   labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET);
   R.a[0] = labcomm_signature_generated_encoding_V;
@@ -240,10 +271,10 @@ int main(void)
   R.a[2] = labcomm_signature_generated_encoding_UnusedE;
   R.a[3] = labcomm_signature_generated_encoding_R;
   labcomm_encode_generated_encoding_R(encoder, &R);
-  EXPECT({-1, 0x10, 0x00, 0x00, 0x00, -1,
-                    0x00, 0x00, 0x00, -1,
-                    0x00, 0x00, 0x00, 0x00,
-                    0x00, 0x00, 0x00, -1});
+  EXPECT({VARIABLE(4), 0x10, 0x00, 0x00, 0x00, VARIABLE(5),
+                             0x00, 0x00, 0x00, VARIABLE(6),
+                             0x00, 0x00, 0x00, 0x00,
+                             0x00, 0x00, 0x00, VARIABLE(7)});
   return 0;
 }
 
diff --git a/lib/c/Makefile b/lib/c/Makefile
index c2b23ee9f9373497e4e1ae612a99ed1ee903110a..5d36fef53c20424e93bc83107bcf83be9d64f36c 100644
--- a/lib/c/Makefile
+++ b/lib/c/Makefile
@@ -6,8 +6,12 @@ all:
 	for v in $(VERSIONS) ; do $(MAKE) -C $${v} $@ || exit 1 ; done
 
 
+.PHONY: clean
+clean: 
+	for v in $(VERSIONS) ; do $(MAKE) -C $${v} $@ || exit 1 ; done
+
 .PHONY: distclean
-distclean: 
+distclean:
 	for v in $(VERSIONS) ; do $(MAKE) -C $${v} $@ || exit 1 ; done
 	rm -f *.o *.so *.so.1 *.a
 
diff --git a/lib/c/os_compat.mk b/lib/c/os_compat.mk
index 23b66f2faa2e425e1fb0be3eb0f8772cdd972d60..b916df333d7ef6023694e44cecbafccb13bd6685 100644
--- a/lib/c/os_compat.mk
+++ b/lib/c/os_compat.mk
@@ -10,15 +10,18 @@ ifeq ($(UNAME_S),Linux)
   LDLIBS=-llabcomm$(LIBVERSION) -lrt
   MAKESHARED=gcc -o $1 -shared -Wl,-soname,$2 $3 -lc -lrt
 else ifeq ($(UNAME_S),Darwin)
-  CC=$(CROSS_COMPILE)clang
-  LD=$(CROSS_COMPILE)ld
+  #CC=$(CROSS_COMPILE)clang
+  #LD=$(CROSS_COMPILE)ld
+  CC=$(CROSS_COMPILE)gcc
+  LD=$(CROSS_COMPILE)gcc
   CFLAGS=-g -Wall -Werror -O3  -I. -Itest \
 	 -DLABCOMM_COMPAT=\"labcomm_compat_osx.h\" \
-	 -DLABCOMM_OS_DARWIN=1\
-	 -Wno-tautological-compare -Wno-unused-function
-  LDFLAGS=-L..
+	 -DLABCOMM_OS_DARWIN=1
+#	 -Wno-tautological-compare -Wno-unused-function
+  CFLAGS+=-std=c99 
+  LDFLAGS=-L.. 
   LDLIBS=-llabcomm$(LIBVERSION)
-  MAKESHARED=clang -o $1 -shared -Wl,-install_name,$2 $3 -lc
+  MAKESHARED=clang -o $1 -shared -Wl,-install_name,$2 $3 -lc 
 else ifneq ($(findstring CYGWIN,$(UNAME_S)),)
   CC=$(CROSS_COMPILE)gcc
   LD=$(CROSS_COMPILE)ld
diff --git a/lib/csharp/se/lth/control/labcomm/Constant.cs b/lib/csharp/se/lth/control/labcomm/Constant.cs
index 5b247f677c6f5c79c5ce288d3a681f629eec5248..37615448d0cec858190bbb16dd9a465677a8ccbb 100644
--- a/lib/csharp/se/lth/control/labcomm/Constant.cs
+++ b/lib/csharp/se/lth/control/labcomm/Constant.cs
@@ -11,6 +11,7 @@ namespace se.lth.control.labcomm {
     public const int SAMPLE_DEF       = 0x02;
     public const int SAMPLE_REF       = 0x03;
     public const int TYPE_DEF         = 0x04;
+    public const int TYPE_BINDING     = 0x05;
     public const int PRAGMA           = 0x3f;
     public const int FIRST_USER_INDEX = 0x40; /* ..0xffffffff */
 
diff --git a/lib/csharp/se/lth/control/labcomm/DecoderChannel.cs b/lib/csharp/se/lth/control/labcomm/DecoderChannel.cs
index aa8662172f6cd4ed00cafaba7b44dcd5a6aa1287..99e17fbac0f6065f3364c72dddfe1bce78808cb9 100644
--- a/lib/csharp/se/lth/control/labcomm/DecoderChannel.cs
+++ b/lib/csharp/se/lth/control/labcomm/DecoderChannel.cs
@@ -45,6 +45,12 @@ namespace se.lth.control.labcomm {
           ReadBytes(signature, signature_length);
 	  ref_registry.add(index, name, signature);
         } break;
+        case Constant.TYPE_DEF: 
+        case Constant.TYPE_BINDING: {
+            for(int i=0; i<length;i++){
+                decodeByte();
+            }                
+        } break;
         default: {
           DecoderRegistry.Entry e = def_registry.get(tag);
           if (e == null) {
diff --git a/lib/java/Makefile b/lib/java/Makefile
index 6fb82d9891cf44c94511bc6fe73be71fb059169d..c6a483daae99e03c8cebfab5239b40ddeabc5e67 100644
--- a/lib/java/Makefile
+++ b/lib/java/Makefile
@@ -10,28 +10,40 @@ MODULES=Constant \
 	SampleDispatcher \
 	SampleHandler \
 	SampleType \
+	BuiltinType \
+	TypeDef \
+	TypeBinding \
+	ASTbuilder \
+	TypeDefParser \
 	Writer \
 	WriterWrapper
 
 all: labcomm.jar labcomm2014.jar labcomm2006.jar
 
-labcomm.jar: gen/JAVAC
+labcomm.jar: gen/JAVAC osgi-manifest-all.txt
 	echo $@
-	cd gen ; jar cfm ../$@ ../osgi-manifest.txt se/lth/control/labcomm/*.class se/lth/control/labcomm2006/*.class
+	cd gen ; jar cfm ../$@ ../osgi-manifest-all.txt \
+		se/lth/control/labcomm/*.class \
+		se/lth/control/labcomm2006/*.class
 
-labcomm2014.jar: gen/JAVAC
+labcomm2014.jar: gen/JAVAC osgi-manifest-2014.txt
 	echo $@
-	cd gen ; jar cfm ../$@ ../osgi-manifest.txt se/lth/control/labcomm/*.class
+	cd gen ; jar cfm ../$@ ../osgi-manifest-2014.txt \
+		se/lth/control/labcomm/*.class
 
-labcomm2006.jar: gen/JAVAC
+labcomm2006.jar: gen/JAVAC osgi-manifest-2006.txt
 	echo $@
-	cd gen ; jar cfm ../$@ ../osgi-manifest.txt se/lth/control/labcomm2006/*.class
+	cd gen ; jar cfm ../$@ ../osgi-manifest-2006.txt \
+		se/lth/control/labcomm2006/*.class
 
 gen:
 	mkdir gen
 
-gen/JAVAC: $(MODULES:%=se/lth/control/labcomm/%.java) $(MODULES:%=se/lth/control/labcomm2006/%.java) Makefile | gen
-	javac -d gen $(filter %.java, $^)
+gen/JAVAC: $(MODULES:%=se/lth/control/labcomm/%.java) \
+	   $(MODULES:%=se/lth/control/labcomm2006/%.java) \
+	   Makefile | gen
+	javac -cp ../../compiler/labcomm_compiler.jar -d gen \
+		$(filter %.java, $^) 
 	touch $@
 
 
@@ -40,5 +52,5 @@ clean:
 	rm -rf gen
 
 .PHONY: distclean
-distclean:
+distclean: clean
 	rm -rf labcomm.jar labcomm2006.jar labcomm2014.jar
diff --git a/lib/java/osgi-manifest-2006.txt b/lib/java/osgi-manifest-2006.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4ef6bdac0f7ccc0b4fe0c729b46bb81d67d36dce
--- /dev/null
+++ b/lib/java/osgi-manifest-2006.txt
@@ -0,0 +1,7 @@
+Bundle-Description: Provides Labcomm to bundles
+Bundle-ManifestVersion: 2
+Bundle-Name: Labcomm OSGi
+Bundle-SymbolicName: se.lth.control.labcomm2006
+Bundle-Vendor: LTH
+Bundle-Version: 1.0.0
+Export-Package: se.lth.control.labcomm2006;version="1.0.0"
diff --git a/lib/java/osgi-manifest-2014.txt b/lib/java/osgi-manifest-2014.txt
new file mode 100644
index 0000000000000000000000000000000000000000..53d3954c8f022190a5163fedf2421fe8795ab77d
--- /dev/null
+++ b/lib/java/osgi-manifest-2014.txt
@@ -0,0 +1,7 @@
+Bundle-Description: Provides Labcomm 2014 to bundles
+Bundle-ManifestVersion: 2
+Bundle-Name: Labcomm OSGi
+Bundle-SymbolicName: se.lth.control.labcomm2014
+Bundle-Vendor: LTH
+Bundle-Version: 1.0.0
+Export-Package: se.lth.control.labcomm;version="1.0.0"
diff --git a/lib/java/osgi-manifest-all.txt b/lib/java/osgi-manifest-all.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4a691e7fffa1ae585f7c245174645f61f2b605d7
--- /dev/null
+++ b/lib/java/osgi-manifest-all.txt
@@ -0,0 +1,8 @@
+Bundle-Description: Provides Labcomm 2006/2014 to bundles
+Bundle-ManifestVersion: 2
+Bundle-Name: Labcomm OSGi
+Bundle-SymbolicName: se.lth.control.labcomm-all
+Bundle-Vendor: LTH
+Bundle-Version: 1.0.0
+Export-Package: se.lth.control.labcomm2006;version="1.0.0",
+ se.lth.control.labcomm;version="1.0.0"
diff --git a/lib/java/osgi-manifest.txt b/lib/java/osgi-manifest.txt
deleted file mode 100644
index 49ca3d6cd68f2212c9ab0d74a709ed38c6a2c233..0000000000000000000000000000000000000000
--- a/lib/java/osgi-manifest.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-Bundle-Description: Provides Labcomm to bundles
-Bundle-ManifestVersion: 2
-Bundle-Name: Labcomm OSGi
-Bundle-SymbolicName: se.lth.control.labcomm
-Bundle-Vendor: LTH
-Bundle-Version: 1.0.0
-Export-Package: se.lth.control.labcomm;version="1.0.0",se.lth.control.la
- bcomm2006;version="1.0.0"
diff --git a/lib/java/se/lth/control/labcomm/ASTbuilder.java b/lib/java/se/lth/control/labcomm/ASTbuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..73bd171750c722c910a12549f535272eafc3b5a5
--- /dev/null
+++ b/lib/java/se/lth/control/labcomm/ASTbuilder.java
@@ -0,0 +1,177 @@
+package se.lth.control.labcomm;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.EOFException;
+
+import se.lth.control.labcomm.TypeDef;
+import se.lth.control.labcomm.TypeDefParser;
+
+import se.lth.control.labcomm2014.compiler.LabComm;
+import se.lth.control.labcomm2014.compiler.LabCommParser;
+
+import se.lth.control.labcomm2014.compiler.List;
+import se.lth.control.labcomm2014.compiler.Program;
+import se.lth.control.labcomm2014.compiler.Decl;
+import se.lth.control.labcomm2014.compiler.TypeDecl;
+import se.lth.control.labcomm2014.compiler.SampleDecl;
+import se.lth.control.labcomm2014.compiler.Type;
+import se.lth.control.labcomm2014.compiler.VoidType;
+import se.lth.control.labcomm2014.compiler.PrimType;
+import se.lth.control.labcomm2014.compiler.UserType;
+import se.lth.control.labcomm2014.compiler.StructType;
+import se.lth.control.labcomm2014.compiler.Field;
+import se.lth.control.labcomm2014.compiler.ArrayType;
+import se.lth.control.labcomm2014.compiler.VariableArrayType;
+import se.lth.control.labcomm2014.compiler.FixedArrayType;
+import se.lth.control.labcomm2014.compiler.Dim;
+import se.lth.control.labcomm2014.compiler.Exp;
+import se.lth.control.labcomm2014.compiler.IntegerLiteral;
+import se.lth.control.labcomm2014.compiler.VariableSize;
+
+
+/** A class for building a JastAdd AST from the parsed types
+ *  created by a TypeDefParser. This class depends on the LabComm compiler.
+ */
+public class ASTbuilder implements TypeDefParser.ParsedSymbolVisitor {
+
+        private LinkedList<Type> typeStack;
+        private LinkedList<Field> fieldStack;
+
+        public ASTbuilder() {
+            this.typeStack = new LinkedList<Type>();
+            this.fieldStack = new LinkedList<Field>();
+        }
+
+        private void assertStacksEmpty() throws RuntimeException {
+            if(!typeStack.isEmpty()) {
+               throw new RuntimeException("Error: type stack not empty"); 
+            }
+            if(!fieldStack.isEmpty()) {
+               throw new RuntimeException("Error: field stack not empty"); 
+            }
+        }
+
+        public void visit(TypeDefParser.TypeSymbol s){
+            throw new Error("not implemented? needed?");
+
+        }
+        public void visit(TypeDefParser.SampleSymbol s){
+            throw new Error("not implemented? needed?");
+
+        }
+        public void visit(TypeDefParser.NameSymbol s){
+            throw new Error("not implemented? needed?");
+        }
+
+        public void visit(TypeDefParser.PrimitiveType t){
+            typeStack.push(new PrimType(t.getName(), t.getTag()));
+        }
+
+// SampleRefs are currently represented as primitive types,
+// see comment in TypeDefParser
+//        public void visit(TypeDefParser.SampleRefType t){
+//            typeStack.push(new SampleRefType());
+//        }
+
+        public void visit(TypeDefParser.ParsedStructType t){
+            if(t.isVoid()) {
+                typeStack.push(new VoidType());
+            } else {
+                List<Field> tmpF = new List<Field>();
+                for( TypeDefParser.ParsedField f : t.getFields()) {
+                    f.accept(this);
+                    tmpF.add(fieldStack.pop());
+                }
+                typeStack.push(new StructType(tmpF));
+            }
+        }
+        public void visit(TypeDefParser.ParsedField t){
+            t.getType().accept(this);
+            fieldStack.push(new Field(typeStack.pop(),t.getName()));
+
+        }
+        public void visit(TypeDefParser.ArrayType t){
+            boolean isFixed = true;
+            List<Exp> dim = new List<Exp>();
+            for(int i : t.getIdx()) {
+                if(i == 0) {
+                    dim.add(new VariableSize());
+                    isFixed = false;
+                } else {
+                    dim.add(new IntegerLiteral(Integer.toString(i)));
+                }
+            }
+            t.getType().accept(this);
+            if(isFixed) {
+                typeStack.push(new FixedArrayType(typeStack.pop(), dim));
+            } else {
+                typeStack.push(new VariableArrayType(typeStack.pop(), dim));
+            }
+
+        }
+        public void visit(TypeDefParser.ParsedUserType t){
+            typeStack.push(new UserType(t.getName()));
+        }
+
+
+       public Decl makeDecl(TypeDefParser.ParsedTypeDef d) {
+           d.getType().accept(this);
+           Decl result = new TypeDecl(typeStack.pop(), d.getName());
+           return result;
+       }
+
+       private Program createAndCheckProgram(List<Decl> ds) {
+            Program p = new Program(ds);
+            LinkedList errors = new LinkedList();
+            p.errorCheck(errors);
+            if(errors.isEmpty()) {
+                return p;
+            } else {
+                // This should not happen
+                // get errors and throw exception
+                StringBuilder sb = new StringBuilder();
+                for (Iterator iter = errors.iterator(); iter.hasNext(); ) {
+                    String s = (String)iter.next();
+                    sb.append(s);
+                }
+                throw new RuntimeException("Internal error: parsed labcomm declaration has errors: "+sb.toString());
+            }
+       }
+       
+       public Program makeProgram(TypeDefParser.ParsedTypeDef d) {
+           assertStacksEmpty();
+           List<Decl> ds = new List<Decl>();
+
+           ds.add(makeDecl(d));
+           assertStacksEmpty();
+           return createAndCheckProgram(ds);
+       }
+
+       public Decl makeDecl(TypeDefParser.ParsedSampleDef d) {
+           d.getType().accept(this);
+           Decl result = new SampleDecl(typeStack.pop(), d.getName());
+           return result;
+       }
+       public Program makeProgram(TypeDefParser.ParsedSampleDef d) {
+           assertStacksEmpty();
+           List<Decl> ds = new List<Decl>();
+
+           Iterator<TypeDefParser.ParsedTypeDef> it = d.getDepIterator();
+           while(it.hasNext()){
+               ds.add(makeDecl(it.next()));
+           }
+
+           ds.add(makeDecl(d));
+
+           assertStacksEmpty();
+           return createAndCheckProgram(ds);
+       }
+    }
+
diff --git a/lib/java/se/lth/control/labcomm/BuiltinType.java b/lib/java/se/lth/control/labcomm/BuiltinType.java
new file mode 100644
index 0000000000000000000000000000000000000000..adb8cd02f62a536f6291071155dcd6ee4dad3f2c
--- /dev/null
+++ b/lib/java/se/lth/control/labcomm/BuiltinType.java
@@ -0,0 +1,5 @@
+package se.lth.control.labcomm;
+
+public interface BuiltinType extends SampleType{
+
+}
diff --git a/lib/java/se/lth/control/labcomm/Constant.java b/lib/java/se/lth/control/labcomm/Constant.java
index fc52a2805a7089f3537bb379234e3dd680feb0fd..e109b30445c953abbe43347d5ba5a42d26cbb15f 100644
--- a/lib/java/se/lth/control/labcomm/Constant.java
+++ b/lib/java/se/lth/control/labcomm/Constant.java
@@ -35,5 +35,12 @@ public class Constant {
   public static final int FLOAT            = 0x25;
   public static final int DOUBLE           = 0x26;
   public static final int STRING           = 0x27;
+  public static final int SAMPLE           = 0x28;
 
+
+  /*
+   * Other predefined symbols
+   */
+
+  public static final int TYPE_BIND_SELF   = 0x00;
 }
diff --git a/lib/java/se/lth/control/labcomm/DecoderChannel.java b/lib/java/se/lth/control/labcomm/DecoderChannel.java
index dc25d2366ad4752d56660a2628d6f1c1219c396f..05382913ec659d7ed548f585884ecb4a097bcac5 100644
--- a/lib/java/se/lth/control/labcomm/DecoderChannel.java
+++ b/lib/java/se/lth/control/labcomm/DecoderChannel.java
@@ -35,26 +35,57 @@ public class DecoderChannel implements Decoder {
   }	   
 
   private void processTypeDef(int len) throws IOException {
-       System.err.println("Got TypeDef: skipping "+len+" bytes"); 
-       for(int i=0; i<len; i++) {
-           decodeByte();		  
+       try {
+           processSample(Constant.TYPE_DEF);
+      } catch(Exception ex) {
+       int idx = decodePacked32();
+       String name = decodeString(); 
+       int siglen = decodePacked32();
+       for(int i=0; i<siglen; i++) {
+           byte b = decodeByte();		  
        }
+      }
   }
 
   private void processTypeBinding(int len) throws IOException {
-       System.err.println("Got TypeBinding: skipping "+len+" bytes"); 
-       for(int i=0; i<len; i++) {
-           decodeByte();		  
-       }
+      try {
+           processSample(Constant.TYPE_BINDING);
+      } catch(Exception ex) {
+          for(int i=0; i<len; i++) {
+              decodeByte();		  
+          }
+      } 
   }
 
   private void processPragma(int len) throws IOException {
-       System.err.println("Got Pragma: skipping "+len+" bytes"); 
        for(int i=0; i<len; i++) {
            decodeByte();		  
        }
   }
 
+  private void processSample(int tag) throws IOException {
+	  DecoderRegistry.Entry e = def_registry.get(tag);
+	  if (e == null) {
+	    throw new IOException("Unhandled tag " + tag);
+	  }
+	  SampleDispatcher d = e.getDispatcher();
+	  if (d == null) {
+	    throw new IOException("No dispatcher for '" + e.getName() + "'");
+	  }
+	  SampleHandler h = e.getHandler();
+	  if (h == null) {
+	    throw new IOException("No handler for '" + e.getName() +"'");
+	  }
+      try {
+        //XXX why does decodeAndHandle throw Exception and not IOException?
+        d.decodeAndHandle(this, h);
+      } catch (IOException ex) {
+          throw ex;
+      } catch (Exception ex) {
+          ex.printStackTrace();
+      }
+  }	  
+
   public void runOne() throws Exception {
     boolean done = false;
     while (!done) {
@@ -68,37 +99,26 @@ public class DecoderChannel implements Decoder {
 			          version + " != " + Constant.CURRENT_VERSION);
           }
         } break;
-	case Constant.SAMPLE_DEF: {
-          processSampleDef();
-	} break;
-	case Constant.SAMPLE_REF: {
-          processSampleRef();
-	} break;
-	case Constant.TYPE_DEF: {
-          processTypeDef(length);
-	} break;
-	case Constant.TYPE_BINDING: {
-          processTypeBinding(length);
-	} break;
-	case Constant.PRAGMA: {
-          processPragma(length);
-	} break;
-	default: {
-	  DecoderRegistry.Entry e = def_registry.get(tag);
-	  if (e == null) {
-	    throw new IOException("Unhandled tag " + tag);
-	  }
-	  SampleDispatcher d = e.getDispatcher();
-	  if (d == null) {
-	    throw new IOException("No dispatcher for '" + e.getName() + "'");
-	  }
-	  SampleHandler h = e.getHandler();
-	  if (h == null) {
-	    throw new IOException("No handler for '" + e.getName() +"'");
-	  }
-	  d.decodeAndHandle(this, h);
-	  done = true;
-	}
+        case Constant.SAMPLE_DEF: {
+            processSampleDef();
+        } break;
+        case Constant.SAMPLE_REF: {
+            processSampleRef();
+        } break;
+        case Constant.TYPE_DEF: {
+            processTypeDef(length);
+        } break;
+        case Constant.TYPE_BINDING: {
+            processTypeBinding(length);
+        } break;
+        case Constant.PRAGMA: {
+            processPragma(length);
+        } break;
+        default: {
+            processSample(tag);
+            done = true;
+
+        }
       }
     }
   }
@@ -196,5 +216,16 @@ public class DecoderChannel implements Decoder {
 
   }
     
+  /* Package visible methods for use from TypeDefParser */
+
+  String getSampleName(int idx) {
+    DecoderRegistry.Entry e = def_registry.get(idx); 
+    return e.getName();  
+  }
+
+  byte[] getSampleSignature(int idx) {
+    DecoderRegistry.Entry e = def_registry.get(idx); 
+    return e.getSignature();  
+  }
 }
 
diff --git a/lib/java/se/lth/control/labcomm/DecoderRegistry.java b/lib/java/se/lth/control/labcomm/DecoderRegistry.java
index fdf8f591d646dad3680e7fbea48e2dcb9ed2ba15..79a78063a20f1eff1cfef28816b624e8ea326290 100644
--- a/lib/java/se/lth/control/labcomm/DecoderRegistry.java
+++ b/lib/java/se/lth/control/labcomm/DecoderRegistry.java
@@ -51,6 +51,11 @@ public class DecoderRegistry {
       return index;
     }
 
+    // protected, for TypeDefParser...
+    byte[] getSignature() {
+        return signature;
+    }
+
     public void setIndex(int index) throws IOException {
       if (this.index != 0 && this.index != index) {
 	throw new IOException("Index mismatch " + 
@@ -96,6 +101,20 @@ public class DecoderRegistry {
 
   public synchronized void add(SampleDispatcher dispatcher,
 			       SampleHandler handler) throws IOException{
+ //XXX kludge: special handling of predefined types
+    if(dispatcher.getSampleClass() == TypeDef.class){
+      Entry e = new Entry(dispatcher, handler);
+      e.setIndex(Constant.TYPE_DEF);
+      byClass.put(dispatcher.getSampleClass(), e);
+      byIndex.put(Integer.valueOf(Constant.TYPE_DEF), e);
+      //System.out.println("LCDecoderRegistry.add("+e.getName()+", "+e.getIndex()+")");
+    } else if(dispatcher.getSampleClass() == TypeBinding.class){
+      Entry e = new Entry(dispatcher, handler);
+      e.setIndex(Constant.TYPE_BINDING);
+      byClass.put(dispatcher.getSampleClass(), e);
+      byIndex.put(Integer.valueOf(Constant.TYPE_BINDING), e);
+      //System.out.println("LCDecoderRegistry.add("+e.getName()+", "+e.getIndex()+")");
+    } else {
     Entry e = byClass.get(dispatcher.getSampleClass());
     if (e != null) {
       e.check(dispatcher.getName(), dispatcher.getSignature());
@@ -114,6 +133,7 @@ public class DecoderRegistry {
 	byClass.put(dispatcher.getSampleClass(), e);
       }
     }
+   }
   }
 
   public synchronized void add(int index, 
diff --git a/lib/java/se/lth/control/labcomm/Encoder.java b/lib/java/se/lth/control/labcomm/Encoder.java
index 203366e850ec1bcaae73c09c15b1cd1e3b842a12..41901151c2efeab95c24d66ab85caa3e088dfc4f 100644
--- a/lib/java/se/lth/control/labcomm/Encoder.java
+++ b/lib/java/se/lth/control/labcomm/Encoder.java
@@ -6,8 +6,11 @@ public interface Encoder {
 
   public void register(SampleDispatcher dispatcher) throws IOException;
   public void registerSampleRef(SampleDispatcher dispatcher) throws IOException;
-  public void begin(Class<? extends Sample> c) throws IOException;
-  public void end(Class<? extends Sample> c) throws IOException;
+  public void begin(Class<? extends SampleType> c) throws IOException;
+  public void end(Class<? extends SampleType> c) throws IOException;
+
+  public void begin(int t) throws IOException;
+  public int getTypeId(Class<? extends SampleType> c) throws IOException;
 
   public void encodeBoolean(boolean value) throws IOException;
   public void encodeByte(byte value) throws IOException;
diff --git a/lib/java/se/lth/control/labcomm/EncoderChannel.java b/lib/java/se/lth/control/labcomm/EncoderChannel.java
index 08f9c87074c6d675d3cb08fd397d481f708e1726..f429f94e7bf311ed57ae89b8cd7406b43ff07b2c 100644
--- a/lib/java/se/lth/control/labcomm/EncoderChannel.java
+++ b/lib/java/se/lth/control/labcomm/EncoderChannel.java
@@ -10,41 +10,117 @@ public class EncoderChannel implements Encoder {
   private Writer writer;
   private ByteArrayOutputStream bytes = new ByteArrayOutputStream();
   private DataOutputStream data = new DataOutputStream(bytes);
-  private EncoderRegistry def_registry = new EncoderRegistry();
-  private EncoderRegistry ref_registry = new EncoderRegistry();
-  private int current_tag; 
+  private EncoderRegistry sample_def_registry = new EncoderRegistry();
+  private EncoderRegistry sample_ref_registry = new EncoderRegistry();
+  private EncoderRegistry type_def_registry = new EncoderRegistry();
+  private int current_tag;
 
-  public EncoderChannel(Writer writer) throws IOException {
+  private EncoderChannel(Writer writer, boolean emitVersion) throws IOException {
     this.writer = writer;
 
-    begin(Constant.VERSION);
-    encodeString(Constant.CURRENT_VERSION);
-    end(null);
+    if(emitVersion){
+      begin(Constant.VERSION);
+      encodeString(Constant.CURRENT_VERSION);
+      end(null);
+    }
+  }
+  public EncoderChannel(Writer writer) throws IOException {
+      this(writer, true);
   }
 
   public EncoderChannel(OutputStream writer) throws IOException {
-    this(new WriterWrapper(writer));
+    this(new WriterWrapper(writer), true);
   }
 
-  public void register(SampleDispatcher dispatcher) throws IOException {
-    if(dispatcher.getTypeDeclTag() == Constant.SAMPLE_DEF) {
-        int index = def_registry.add(dispatcher);
-        //begin(Constant.SAMPLE_DEF);
+  private EncoderChannel(OutputStream writer, boolean emitVersion) throws IOException {
+    this(new WriterWrapper(writer), emitVersion);
+  }
+  private void bindType(int sampleId, int typeId) throws IOException {
+        begin(Constant.TYPE_BINDING);
+        encodePacked32(sampleId);
+        encodePacked32(typeId);
+        end(null);
+  }
+
+  private void registerSample(SampleDispatcher dispatcher) throws IOException {
+        int index = sample_def_registry.add(dispatcher);
         begin(dispatcher.getTypeDeclTag());
         encodePacked32(index);
         encodeString(dispatcher.getName());
         byte[] signature = dispatcher.getSignature();
         encodePacked32(signature.length);
         for (int i = 0 ; i < signature.length ; i++) {
-        encodeByte(signature[i]);
+            encodeByte(signature[i]);
         }
         end(null);
+        int tindex;
+        if(dispatcher.hasDependencies()){
+            tindex = registerTypeDef(dispatcher);
+        } else {
+            tindex = Constant.TYPE_BIND_SELF;
+        }
+        bindType(index, tindex);
+
+  }
+
+  private static class WrappedEncoder extends EncoderChannel{
+      private Encoder wrapped;
+
+      public WrappedEncoder(Encoder e, OutputStream s, boolean emitVersion) throws IOException {
+          super(s,emitVersion);
+          this.wrapped = e;
+      }
+      public int getTypeId(Class<? extends SampleType> c) throws IOException{
+         return wrapped.getTypeId(c);
+      }
+  }
+
+
+  private int registerTypeDef(SampleDispatcher dispatcher) throws IOException {
+      // check if already registered
+        try {
+            return type_def_registry.getTag(dispatcher);
+        } catch (IOException e) {
+            //otherwise, add to the registry
+            int index = type_def_registry.add(dispatcher);
+            //wrap encoder to get encoded length of signature
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            EncoderChannel wrapped = new WrappedEncoder(this, baos, false);
+            dispatcher.encodeTypeDef(wrapped, index);
+            wrapped.flush();
+            byte b[] = baos.toByteArray();
+
+            begin(Constant.TYPE_DEF);
+            encodePacked32(index);
+            encodeString(dispatcher.getName());
+            encodePacked32(b.length);
+            for(int i = 0; i<b.length; i++) {
+                encodeByte(b[i]);
+            }
+            end(null);
+
+            return index;
+        }
+  }
+
+  public void register(SampleDispatcher dispatcher) throws IOException {
+    switch (dispatcher.getTypeDeclTag())  {
+        case Constant.SAMPLE_DEF: {
+            registerSample(dispatcher);
+            break;
+        }
+        case Constant.TYPE_DEF: {
+            registerTypeDef(dispatcher);
+            break;
+        }
+        default:
+            throw new Error("Unknown typeDeclTag: "+dispatcher.getTypeDeclTag());
     }
   }
 
   public void registerSampleRef(SampleDispatcher dispatcher) throws IOException {
     System.err.println(dispatcher);
-    int index = ref_registry.add(dispatcher);
+    int index = sample_ref_registry.add(dispatcher);
     begin(Constant.SAMPLE_REF);
     encodePacked32(index);
     encodeString(dispatcher.getName());
@@ -56,16 +132,22 @@ public class EncoderChannel implements Encoder {
     end(null);
   }
 
-  private void begin(int tag) {
+  public void begin(int tag) {
     current_tag = tag;
     bytes.reset();
   }
 
-  public void begin(Class<? extends Sample> c) throws IOException {
-    begin(def_registry.getTag(c));
+  public void begin(Class<? extends SampleType> c) throws IOException {
+    begin(sample_def_registry.getTag(c));
   }
 
-  public void end(Class<? extends Sample> c) throws IOException {
+  /* aux. method used to allow nesting encoders to find encoded size */
+  private void flush() throws IOException{
+    data.flush();
+    writer.write(bytes.toByteArray());
+    bytes.reset();
+  }
+  public void end(Class<? extends SampleType> c) throws IOException {
     data.flush();
     WritePacked32(writer, current_tag);
     WritePacked32(writer, bytes.size());
@@ -73,19 +155,26 @@ public class EncoderChannel implements Encoder {
     bytes.reset();
   }
 
+  /**
+   * @return the id of a TYPE_DEF
+   */
+  public int getTypeId(Class<? extends SampleType> c) throws IOException {
+    return type_def_registry.getTag(c);
+  }
+
   private void WritePacked32(Writer s, long value) throws IOException {
     byte[] tmp1 = new byte[5];
     byte[] tmp2 = new byte[1];
     long v = value & 0xffffffff;
     int i;
-    
+
     for (i = 0 ; i == 0 || v != 0 ; i++, v = (v >> 7)) {
       tmp1[i] = (byte)(v & 0x7f | (i!=0?0x80:0x00));
     }
     for (i = i - 1 ; i >= 0 ; i--) {
       tmp2[0] = tmp1[i];
       writer.write(tmp2);
-    }      
+    }
   }
 
   public void encodeBoolean(boolean value) throws IOException{
@@ -117,17 +206,15 @@ public class EncoderChannel implements Encoder {
   }
 
   public void encodeString(String value) throws IOException {
-    //data.writeShort(0); // HACK...
-    //data.writeUTF(value);
-
-    //kludge, to replace above hack with packed length
     ByteArrayOutputStream tmpb = new ByteArrayOutputStream();
     DataOutputStream tmps = new DataOutputStream(tmpb);
 
     tmps.writeUTF(value);
     tmps.flush();
     byte[] tmp = tmpb.toByteArray();
-  
+
+    //the two first bytes written by writeUTF is the length of
+    //the string, so we skip those
     encodePacked32(tmp.length-2);
     for (int i = 2 ; i < tmp.length ; i++) {
       encodeByte(tmp[i]);
@@ -150,8 +237,9 @@ public class EncoderChannel implements Encoder {
   public void encodeSampleRef(Class value) throws IOException {
     int index = 0;
     try {
-      index = ref_registry.getTag(value);
+      index = sample_ref_registry.getTag(value);
     } catch (NullPointerException e) {
+        //we want to return 0 for unregistered ref types
     }
     data.writeInt(index);
   }
diff --git a/lib/java/se/lth/control/labcomm/EncoderRegistry.java b/lib/java/se/lth/control/labcomm/EncoderRegistry.java
index cd0cf72f5f45ed9ccc3cb6ce1902c9c2e37333bf..f990d1813920a0624c557b4a895cae1f64331a69 100644
--- a/lib/java/se/lth/control/labcomm/EncoderRegistry.java
+++ b/lib/java/se/lth/control/labcomm/EncoderRegistry.java
@@ -42,7 +42,11 @@ public class EncoderRegistry {
     return e.getIndex();
   }
   
-  public int getTag(Class<? extends Sample> sample) throws IOException {
+  public int getTag(SampleDispatcher d) throws IOException {
+      return getTag(d.getSampleClass());
+  }
+
+  public int getTag(Class<? extends SampleType> sample) throws IOException {
     Entry e = byClass.get(sample);
     if (e == null) {
       throw new IOException("'" + 
@@ -52,4 +56,8 @@ public class EncoderRegistry {
     return e.index;
   }
 
+  public boolean contains(Class<? extends SampleType> sample) {
+    return byClass.containsKey(sample);
+  }
+
 }
diff --git a/lib/java/se/lth/control/labcomm/Sample.java b/lib/java/se/lth/control/labcomm/Sample.java
index f86f486b4bae2276780f73e24b33d03717c95840..2dd432b878f509538aca71f0b7840ff8fe2513b2 100644
--- a/lib/java/se/lth/control/labcomm/Sample.java
+++ b/lib/java/se/lth/control/labcomm/Sample.java
@@ -1,6 +1,6 @@
 package se.lth.control.labcomm;
 
-public interface Sample {
+public interface Sample extends SampleType {
 
   public SampleDispatcher getDispatcher();
 
diff --git a/lib/java/se/lth/control/labcomm/SampleDispatcher.java b/lib/java/se/lth/control/labcomm/SampleDispatcher.java
index 58e3d1debdb47e31125088cf9bb6502d0ebc74b5..b2ed2fd98658f15461c6a8a60e8f4bb9df39418b 100644
--- a/lib/java/se/lth/control/labcomm/SampleDispatcher.java
+++ b/lib/java/se/lth/control/labcomm/SampleDispatcher.java
@@ -1,8 +1,10 @@
 package se.lth.control.labcomm;
 
-public interface SampleDispatcher {
+import java.io.IOException;
+
+public interface SampleDispatcher <T extends SampleType>{
     
-  public Class getSampleClass();
+  public Class<T> getSampleClass();
     
   public String getName();
 
@@ -11,6 +13,12 @@ public interface SampleDispatcher {
   public void decodeAndHandle(Decoder decoder,
 			      SampleHandler handler) throws Exception;
 
+  /** @return true if the type depends on one or more typedefs
+   */
+  public boolean hasDependencies();
+
+  public void encodeTypeDef(Encoder e, int index) throws IOException;
+
   /** return the tag SAMPLE_DEF or TYPE_DEF, for use
    *  by encoder.register.
    *  TODO: refactor types, moving this to a super-interface
diff --git a/lib/java/se/lth/control/labcomm/TypeBinding.java b/lib/java/se/lth/control/labcomm/TypeBinding.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c0cd41345f1aa20470e0327570eb17413d6e811
--- /dev/null
+++ b/lib/java/se/lth/control/labcomm/TypeBinding.java
@@ -0,0 +1,125 @@
+package se.lth.control.labcomm;
+
+import java.io.IOException;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import se.lth.control.labcomm.Decoder;
+import se.lth.control.labcomm.DecoderChannel;
+import se.lth.control.labcomm.SampleDispatcher;
+import se.lth.control.labcomm.SampleHandler;
+
+public class TypeBinding implements BuiltinType {
+    private int sampleIndex;
+    private int typeIndex;
+
+  public TypeBinding(int sampleIndex, int typeIndex) {
+      this.sampleIndex = sampleIndex;
+      this.typeIndex = typeIndex;
+  }
+
+  public int getSampleIndex() {
+    return sampleIndex;
+  }
+
+  public int getTypeIndex() {
+    return typeIndex;
+  }
+
+  public boolean isSelfBinding() {
+      return typeIndex == Constant.TYPE_BIND_SELF;
+  }
+
+  public interface Handler extends SampleHandler {
+    public void handle_TypeBinding(TypeBinding value) throws Exception;
+  }
+
+  public static void register(Decoder d, Handler h) throws IOException {
+    d.register(Dispatcher.singleton(), h);
+  }
+
+  public static void register(Encoder e) throws IOException {
+    register(e,false);
+  }
+
+  public static void register(Encoder e, boolean sendMetaData) throws IOException {
+    throw new IOException("cannot send TypeDefs");
+  }
+
+ static class Dispatcher implements SampleDispatcher<TypeBinding> {
+
+    private static Dispatcher singleton;
+
+    public synchronized static Dispatcher singleton() {
+      if(singleton==null) singleton=new Dispatcher();
+      return singleton;
+    }
+
+    public Class<TypeBinding> getSampleClass() {
+      return TypeBinding.class;
+    }
+
+    public String getName() {
+      return "TypeBinding";
+    }
+
+    public byte getTypeDeclTag() {
+      throw new Error("Should not be called");
+    }
+
+    public boolean isSample() {
+      throw new Error("Should not be called");
+    }
+    public boolean hasStaticSignature() {
+      throw new Error("Should not be called");
+    }
+
+    public byte[] getSignature() {
+      return null; // not used for matching
+    }
+
+    public void encodeTypeDef(Encoder e, int index) throws IOException{
+      throw new Error("Should not be called");
+    }
+
+    public void decodeAndHandle(Decoder d,
+                                SampleHandler h) throws Exception {
+      ((Handler)h).handle_TypeBinding(TypeBinding.decode(d));
+    }
+
+    public boolean hasDependencies() {
+        return false;
+    }
+  }
+
+  public static void encode(Encoder e, TypeBinding value) throws IOException {
+    throw new Error("Should not be called");
+  }
+
+  /* HERE BE DRAGONS!
+   * This exposes (and relies on the stability of) indices that are
+   * internal to a decoder.
+   *
+   * The SAMPLE_DEF and TYPE_DEF must already have been received for the
+   * indices to be known, so this can be changed to instead return
+   * references to the SampleDispactcher corresponding to the sample type
+   * and the matching TypeDef.
+   *
+   * Sketch:
+   *
+   * SampleDispatcher sd = d.getDispatcherForId(sampleIndex);
+   * TypeDef td = d.getTypeDefForId(typeIndex);
+   *
+   * return new TypeBinding(sd, td);
+   *
+   * assuming that the Decoder keeps a registry for TypeDefs
+   */
+  public static TypeBinding decode(Decoder d) throws IOException {
+    TypeBinding result;
+    int sampleIndex = d.decodePacked32();
+    int typeIndex = d.decodePacked32();
+
+    result = new TypeBinding(sampleIndex, typeIndex);
+    return result;
+  }
+}
+
diff --git a/lib/java/se/lth/control/labcomm/TypeDef.java b/lib/java/se/lth/control/labcomm/TypeDef.java
new file mode 100644
index 0000000000000000000000000000000000000000..067c400e9b0a668ddff6786e231aa4ff3a9f9067
--- /dev/null
+++ b/lib/java/se/lth/control/labcomm/TypeDef.java
@@ -0,0 +1,132 @@
+package se.lth.control.labcomm;
+
+import java.io.IOException;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import se.lth.control.labcomm.Decoder;
+import se.lth.control.labcomm.DecoderChannel;
+import se.lth.control.labcomm.SampleDispatcher;
+import se.lth.control.labcomm.SampleHandler;
+
+public class TypeDef implements BuiltinType {
+    private int index;
+    private String name;
+    private byte signature[];
+
+  public int getIndex() {
+    return index;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public String toString() {
+     return getName();
+  }
+ 
+  public byte[] getSignature() {
+    return signature;
+  }
+
+  public void dump() {
+      System.out.print("=== TypeDef "+getName()+"( "+Integer.toHexString(getIndex())+") : ");
+      for (byte b : signature) {
+        System.out.print(String.format("0x%02X ", b));
+      }
+      System.out.println();
+  }
+  public interface Handler extends SampleHandler {
+    public void handle_TypeDef(TypeDef value) throws Exception;
+  }
+  
+  public static void register(Decoder d, Handler h) throws IOException {
+    d.register(Dispatcher.singleton(), h);
+  }
+  
+  public static void register(Encoder e) throws IOException {
+    register(e,false);
+  }
+  
+  public static void register(Encoder e, boolean sendMetaData) throws IOException {
+    throw new IOException("cannot send TypeDefs");
+  }
+  
+ static class Dispatcher implements SampleDispatcher<TypeDef> {
+    
+    private static Dispatcher singleton;
+    
+    public synchronized static Dispatcher singleton() {
+      if(singleton==null) singleton=new Dispatcher();
+      return singleton;
+    }
+    
+    public Class<TypeDef> getSampleClass() {
+      return TypeDef.class;
+    }
+    
+    public String getName() {
+      return "TypeDef";
+    }
+
+    public byte getTypeDeclTag() {
+      throw new Error("Should not be called");
+    }
+    
+    public boolean isSample() {
+      throw new Error("Should not be called");
+    }
+    public boolean hasStaticSignature() {
+      throw new Error("Should not be called");
+    }
+    
+    /** return the flat signature. Intended use is on decoder side */
+    public byte[] getSignature() {
+      return null; // not used for matching
+    }
+    
+    public void encodeTypeDef(Encoder e, int index) throws IOException{
+      throw new Error("Should not be called");
+    }
+    
+//    public boolean canDecodeAndHandle() {
+//      return true;
+//    }
+    
+    public void decodeAndHandle(Decoder d,
+                                SampleHandler h) throws Exception {
+      ((Handler)h).handle_TypeDef(TypeDef.decode(d));
+    }
+    
+    public boolean hasDependencies() {
+        return false;
+    }
+  }
+  
+  public static void encode(Encoder e, TypeDef value) throws IOException {
+    throw new Error("Should not be called");
+  }
+  
+  protected TypeDef() {
+  }
+
+  public TypeDef(int index, String name, byte sig[]) {
+      this.index = index;
+      this.name = name;
+      this.signature = sig;
+  }
+
+  public static TypeDef decode(Decoder d) throws IOException {
+    TypeDef result;
+    int index = d.decodePacked32();
+    String name = d.decodeString();
+    int siglen= d.decodePacked32();
+    byte sig[] = new byte[siglen];
+    for(int i=0; i<siglen;i++){
+        sig[i] = d.decodeByte();
+    }
+    result = new TypeDef(index, name, sig);
+    return result;
+  }
+}
+
diff --git a/lib/java/se/lth/control/labcomm/TypeDefParser.java b/lib/java/se/lth/control/labcomm/TypeDefParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..a72e96510e6ee1544f42aa39c548b637172c1cbd
--- /dev/null
+++ b/lib/java/se/lth/control/labcomm/TypeDefParser.java
@@ -0,0 +1,663 @@
+package se.lth.control.labcomm;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.EOFException;
+
+import se.lth.control.labcomm.Decoder;
+import se.lth.control.labcomm.DecoderChannel;
+import se.lth.control.labcomm.TypeDef;
+import se.lth.control.labcomm.TypeBinding;
+
+public class TypeDefParser implements TypeDef.Handler, TypeBinding.Handler {
+
+    static class SelfBinding extends TypeDef {
+
+        private int sampleIndex;
+        private Decoder decoder;
+        private byte[] dummy = new byte[0];
+        public String toString() {return "self";} 
+        public String getName() {
+            if(decoder instanceof DecoderChannel) {
+                DecoderChannel dc = (DecoderChannel) decoder;
+                return dc.getSampleName(sampleIndex);
+            } else {
+                return "self";
+            }
+        } 
+        public int getIndex() {return 0;}
+        public byte[] getSignature() {
+            if(decoder instanceof DecoderChannel) {
+                DecoderChannel dc = (DecoderChannel) decoder;
+                return dc.getSampleSignature(sampleIndex);
+            } else {
+                return dummy;
+            }
+        }
+
+        public SelfBinding(int sampleIndex, Decoder decoder) {
+            super();
+            this.sampleIndex = sampleIndex;
+            this.decoder = decoder;
+        }
+    }
+
+    public interface TypeDefListener {
+        void onTypeDef(ParsedTypeDef d);
+    }
+
+    private HashMap<Integer,TypeDef> typeDefs;
+    private HashMap<Integer,Integer> typeBindings;
+    private HashSet<TypeDefListener> listeners;
+    private LinkedList<ParsedSampleDef> sampleDefs;
+    private Decoder decoder;
+
+    protected TypeDefParser(Decoder d) {
+        this.decoder = d;
+        typeDefs = new HashMap<Integer,TypeDef>();
+        typeBindings = new HashMap<Integer,Integer>();
+        listeners = new HashSet<TypeDefListener>();
+        sampleDefs = new LinkedList<ParsedSampleDef>();
+    }
+
+    public void addListener(TypeDefListener l) {
+        listeners.add(l);
+    }
+
+
+    public Iterator<ParsedSampleDef> sampleDefIterator() {
+        return sampleDefs.iterator();
+    }
+
+    public void handle_TypeDef(TypeDef d) throws java.io.IOException {
+        typeDefs.put(d.getIndex(), d);
+    }
+
+    public void handle_TypeBinding(TypeBinding d) throws java.io.IOException {
+        TypeDef td;
+        if(d.isSelfBinding()){
+             td = new SelfBinding(d.getSampleIndex(), decoder);
+        } else {
+            typeBindings.put(d.getSampleIndex(), d.getTypeIndex());
+            td = getTypeDefForIndex(d.getSampleIndex());
+        }
+        ParsedSampleDef result = parseSignature(td);
+
+        sampleDefs.add(result);
+
+        Iterator<TypeDefListener> it = listeners.iterator();
+        while(it.hasNext()){
+            notifyListener(it.next(), result);
+        }
+    }
+
+    private void notifyListener(TypeDefListener l, ParsedTypeDef d) {
+        l.onTypeDef(d);
+        if(d instanceof ParsedSampleDef) {
+            for(ParsedTypeDef dep : ((ParsedSampleDef)d).getDependencies()) {
+                //do we want to change ParseTypeDef to have dependencies,
+                //and do recursion here?
+                //if so, do notifyListener(l, dep);
+                l.onTypeDef(dep);
+            }
+        }
+    }
+
+    private TypeDef getTypeDefForIndex(int sampleIndex) {
+        return typeDefs.get(typeBindings.get(sampleIndex));
+    }
+
+
+    /** Factory method for use by application programs:
+     *  registers a TypeDefParser for handling TypeDef and TypeBinding
+     *  on the Decoder d.
+     *
+     *  @return a new TypeDefParser registered on d
+     */
+    public static TypeDefParser registerTypeDefParser(Decoder d) throws java.io.IOException  {
+
+        TypeDefParser res = new TypeDefParser(d);
+
+        TypeDef.register(d,res);
+        TypeBinding.register(d,res);
+
+        return res;
+    }
+
+    public LinkedList<ParsedSymbol> symbolify() {
+
+        LinkedList<ParsedSymbol> result = new LinkedList<ParsedSymbol>();
+
+        Iterator<ParsedSampleDef> sdi = sampleDefIterator();
+
+        while(sdi.hasNext()) {
+            ParsedSampleDef sd = sdi.next();
+            result.add(new SampleSymbol());
+            result.add(sd.getType());
+            result.add(new NameSymbol(sd.getName()));
+
+            Iterator<ParsedTypeDef> di = sd.getDepIterator();        
+            while(di.hasNext()) {
+                ParsedTypeDef d = di.next();
+                result.add(new TypeSymbol());
+                result.add(d.getType());
+                result.add(new NameSymbol(d.getName()));
+            }
+        }
+        return result;
+    }
+
+    public String symbolString() {
+        Iterator<ParsedSymbol> i = symbolify().iterator();
+
+        StringBuilder sb = new StringBuilder();
+
+        while(i.hasNext()) {
+            sb.append(i.next().toString());
+        }
+        return sb.toString();
+    }
+
+    /* An interface for using Visitor pattern to traverse 
+     * ParsedTypeDefs
+     */
+    public interface ParsedSymbolVisitor {
+        void visit(TypeSymbol s);
+        void visit(SampleSymbol s);
+        void visit(NameSymbol s);
+        void visit(PrimitiveType t);
+        //sampleRefs are sent as primitive types
+        //Put this back if that is changed to SampleRefType
+        //void visit(SampleRefType t);
+        void visit(ParsedStructType t);
+        void visit(ParsedField t);
+        void visit(ArrayType t);
+        void visit(ParsedUserType t);
+    }
+    public abstract class ParsedSymbol{
+        public abstract void accept(ParsedSymbolVisitor v);
+    }
+
+    public class TypeSymbol extends ParsedSymbol {
+        public String toString() {
+            return "typedef ";
+        }
+        public void accept(ParsedSymbolVisitor v){
+            v.visit(this);
+        }
+    }
+
+    public class SampleSymbol extends ParsedSymbol {
+        public String toString() {
+            return "sample ";
+        }
+        public void accept(ParsedSymbolVisitor v){
+            v.visit(this);
+        }
+    }
+
+    public class NameSymbol extends ParsedSymbol {
+        private String name;
+
+        public NameSymbol(String name) {
+            this.name = name;
+        }
+
+        public String toString() { 
+            return name;
+        }
+        public void accept(ParsedSymbolVisitor v){
+            v.visit(this);
+        }
+    }
+
+    public abstract class ParsedType extends ParsedSymbol{
+    }
+
+// SampleRefType currently not sent, se above
+//    public class SampleRefType extends ParsedType {
+//        public void accept(ParsedSymbolVisitor v) {
+//            v.visit(this);
+//        }
+//
+//        public String toString() { 
+//            return "sample";}
+//    }
+
+    public class PrimitiveType extends ParsedType {
+        private final String name;
+        private int tag;
+
+        String getName() {
+            return name;
+        }
+
+        int getTag() {
+            return tag;
+        }
+        PrimitiveType(int tag) {
+            this.tag = tag;
+            switch(tag) {
+                case Constant.BOOLEAN:
+                    this.name = "boolean";
+                    break;
+                case Constant.BYTE:
+                    this.name = "byte";
+                    break;
+                case Constant.SHORT:
+                    this.name = "short";
+                    break;
+                case Constant.INT:
+                    this.name = "int";
+                    break;
+                case Constant.LONG:
+                    this.name = "long";
+                    break;
+                case Constant.FLOAT:
+                    this.name = "float";
+                    break;
+                case Constant.DOUBLE:
+                    this.name = "double";
+                    break;
+                case Constant.STRING:
+                    this.name = "string";
+                    break;
+                case Constant.SAMPLE:
+                    this.name = "sample";
+                    break;
+                default:
+                    this.name = "??? unknown tag 0x"+Integer.toHexString(tag);    
+            }
+        }
+
+        public void accept(ParsedSymbolVisitor v) {
+            v.visit(this);
+        }
+
+        public String toString() { 
+            return name;}
+    }
+
+    public class ParsedStructType extends ParsedType {
+        private ParsedField fields[];
+
+        ParsedStructType(int nParsedFields) {
+            this.fields = new ParsedField[nParsedFields];
+        }
+
+        public ParsedField[] getFields() {
+            return fields;
+        }
+
+        void setParsedField(int idx, ParsedField f) {
+            fields[idx] = f;
+        }
+
+        public boolean isVoid() {
+            return fields.length == 0;
+        }
+
+        public String toString() {
+            if(isVoid()) { //void type is empty struct
+                return "void";
+            } else {
+                StringBuilder sb = new StringBuilder();
+                sb.append("struct {\n");
+                for(ParsedField f : fields) {
+                    sb.append(f.toString());
+                    sb.append(";\n");        
+                }
+                sb.append("}");
+                return sb.toString();
+            }
+        }
+
+        public void accept(ParsedSymbolVisitor v) {
+            v.visit(this);
+        }
+    }
+
+    public class ParsedField extends ParsedSymbol{
+        private ParsedType type;
+        private String name;
+
+        ParsedField(String name, ParsedType type) {
+            this.name = name;
+            this.type = type;
+        }
+
+        public ParsedType getType() {
+            return type;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String toString() {
+            return type.toString() + " " + name;
+        }
+
+        public void accept(ParsedSymbolVisitor v) {
+            v.visit(this);
+        }
+    }
+
+    public class ArrayType extends ParsedType {
+        private int idx[];
+        private ParsedType type;
+
+        ArrayType(int idx[], ParsedType elementType) {
+            this.idx = idx;
+            this.type = elementType;
+        }
+
+        public ParsedType getType() {
+            return type;
+        }
+
+        public int[] getIdx() {
+            return idx;
+        }
+
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(type.toString());
+            for(int i : idx) {
+                sb.append("["+(i>0 ? i : "_")+"]");
+            }
+            return sb.toString();
+        }
+
+        public void accept(ParsedSymbolVisitor v) {
+            v.visit(this);
+        }
+    }
+
+    public class ParsedUserType extends ParsedType {
+        private String name;
+        public String getName() {
+            return name;
+        }
+
+        public String toString() {
+            return name;
+        }
+
+        ParsedUserType(String name) {
+            this.name = name;
+        }
+
+        public void accept(ParsedSymbolVisitor v) {
+            v.visit(this);
+        }
+    }
+
+    public class ParsedTypeDef{
+       private int idx;
+       private String name;
+       private ParsedType type;
+
+       ParsedTypeDef(int idx, String name){
+            this.idx = idx;
+            this.name = name;
+       }
+
+       ParsedTypeDef(int idx, String name, ParsedType type) {
+           this(idx, name);
+           this.type = type;
+       }
+
+       /** To be overridden in ParsedSampleDef
+        */
+       public boolean isSampleDef() {
+           return false;
+       }
+
+       void setType(ParsedType type) {
+           this.type = type;
+       }
+
+       ParsedType getType() {
+           return type;
+       }
+
+       int getIndex() {
+           return idx;
+       }
+
+       public String getName() {
+            return name;
+       }
+
+       public String toString() {
+          return type.toString();
+       }
+
+       public int hashCode() {
+           return name.hashCode();
+       }
+
+       public boolean equals(Object o) {
+            if(! (o instanceof ParsedTypeDef)){
+                return false;
+            } else {
+                ParsedTypeDef other = (ParsedTypeDef) o;
+                return other.idx == idx && other.name.equals(name);
+            }
+       }
+
+       public void accept(ParsedSymbolVisitor v) {
+            type.accept(v);
+       }
+    }
+   
+    public class ParsedSampleDef extends ParsedTypeDef{
+
+        private HashSet<ParsedTypeDef> deps;
+        ParsedSampleDef(ParsedTypeDef td) {
+            super(td.getIndex(), td.getName(), td.getType());
+            this.deps = new HashSet<ParsedTypeDef>();
+        }
+
+        void addDependency(ParsedTypeDef d) {
+            deps.add(d);
+        }
+
+        @Override
+        public boolean isSampleDef() {
+            return true;
+        }
+        private HashSet<ParsedTypeDef> getDependencies() {
+            return deps;
+        }
+
+        Iterator<ParsedTypeDef> getDepIterator() {
+            return deps.iterator();
+        }        
+    }
+
+    private class ParserState {
+        private ByteArrayInputStream bis;
+        private DataInputStream in;
+        private TypeDef current;
+        private ParsedTypeDef currentParsed;
+
+        private LinkedList<TypeDef> typeStack;
+
+        ParsedTypeDef newTypeDef() {
+            currentParsed =new ParsedTypeDef(getCurrentIndex(), getCurrentName());
+            return currentParsed;
+        }
+
+        private ParserState() {
+            typeStack = new LinkedList<TypeDef>();
+        }
+
+        ParserState(int typeIdx) {
+            this();
+            pushType(typeIdx);
+        }
+         
+        ParserState(TypeDef td) {
+            this();
+            pushType(td);
+        }
+         
+        ParserState(byte sig[]) {
+            this();
+            bis= new ByteArrayInputStream(sig);
+            in = new DataInputStream(bis);
+        }
+
+        void pushType(TypeDef td) {
+            if(!typeStack.contains(td)) {
+                typeStack.push(td);
+            }
+        }
+        void pushType(int typeIdx) {
+            if(typeIdx >= 0x40 && !typeStack.contains(typeIdx)) {
+                typeStack.push(typeDefs.get(typeIdx));
+            } 
+        }
+
+        void popType() {
+            TypeDef td2 = typeStack.pop();
+            current = td2;
+            bis =new ByteArrayInputStream(td2.getSignature());
+            in = new DataInputStream(bis);
+        }
+
+        boolean moreTypes() {
+            return !typeStack.isEmpty();
+        }
+
+        int getCurrentIndex() {
+            return current.getIndex();
+        }
+
+        String getCurrentName() {
+            return current.getName();
+        }
+
+        String decodeString() throws IOException {
+            int len = decodePacked32() & 0xffffffff;
+            byte[] chars = new byte[len];
+            for(int i=0; i<len; i++) {
+                chars[i] = in.readByte();
+            }
+            return new String(chars);
+        }
+
+        int decodePacked32() throws IOException {
+            long res=0;
+            byte i=0;
+            boolean cont=true;
+
+            do {
+            byte c = in.readByte();
+            res = (res << 7) | (c & 0x7f);
+            cont = (c & 0x80) != 0;
+            i++;
+            } while(cont);
+
+            return (int) (res & 0xffffffff);
+        }
+    }
+
+    public ParsedSampleDef parseSignature(TypeDef td) throws IOException{
+        ParserState s = new ParserState(td);
+
+        ParsedSampleDef result=null;
+        try {
+            s.popType();
+            result = parseSampleTypeDef(s);
+            while(s.moreTypes()) {
+                s.popType();
+                result.addDependency(parseTypeDef(s));
+            }
+        } catch(java.io.EOFException ex) {
+            System.out.println("EOF: self_binding");
+        }
+        return result;
+    }    
+
+    private ArrayType  parseArray(ParserState in) throws IOException {
+        int numIdx = in.decodePacked32();
+        int idx[] = new int[numIdx];
+        for(int i=0; i<numIdx; i++){
+            idx[i] = in.decodePacked32(); 
+        }
+        int type = in.decodePacked32();
+        ParsedType elementType = lookupType(type, in); 
+        ArrayType result = new ArrayType(idx, elementType);
+        for(int i=0; i<numIdx; i++){
+            idx[i] = in.decodePacked32(); 
+        }
+        return result;
+    }
+
+    private ParsedStructType parseStruct(ParserState in) throws IOException {
+        int numParsedFields = in.decodePacked32();
+        ParsedStructType result = new ParsedStructType(numParsedFields);
+        for(int i=0; i<numParsedFields; i++) {
+            result.setParsedField(i, parseParsedField(in));
+        }
+        return result;
+    }
+
+    private ParsedField parseParsedField(ParserState in) throws IOException {
+        String name = in.decodeString();
+        return new ParsedField(name, parseType(in));
+    }
+
+    private ParsedType lookupType(int tag, ParserState in) {
+        ParsedType result;
+        if(tag >= Constant.FIRST_USER_INDEX) {
+                TypeDef td = typeDefs.get(tag);
+                result = new ParsedUserType(td.getName());
+                in.pushType(tag);
+// sampleRefs are sent as primitive types, see above
+//        } else if(tag == Constant.SAMPLE) {
+//                result = new SampleRefType();       
+        } else {
+                result = new PrimitiveType(tag);
+        }
+        return result;
+    }
+
+    private ParsedSampleDef parseSampleTypeDef(ParserState in) throws IOException {
+        ParsedTypeDef td = parseTypeDef(in);
+        return new ParsedSampleDef(td);
+    }
+    private ParsedTypeDef parseTypeDef(ParserState in) throws IOException {
+        ParsedTypeDef result = in.newTypeDef();
+        result.setType(parseType(in));
+        return result;
+    }
+    private ParsedType parseType(ParserState in) throws IOException {
+        int tag = in.decodePacked32();
+        ParsedType result = null;
+        switch(tag) {
+            case 0:
+                System.out.println("SELF");
+                break;
+            case Constant.ARRAY:
+                result = parseArray(in);
+                break;
+            case Constant.STRUCT:
+                result = parseStruct(in);
+                break;
+            default:
+                result = lookupType(tag, in);
+                break;
+        }    
+        return result;
+    }
+}
diff --git a/lib/java/se/lth/control/labcomm2006/ASTbuilder.java b/lib/java/se/lth/control/labcomm2006/ASTbuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..a65e88738f5ed796591f10a00f63733aa17d8116
--- /dev/null
+++ b/lib/java/se/lth/control/labcomm2006/ASTbuilder.java
@@ -0,0 +1,4 @@
+package se.lth.control.labcomm2006;
+
+public class ASTbuilder {
+}
diff --git a/lib/java/se/lth/control/labcomm2006/BuiltinType.java b/lib/java/se/lth/control/labcomm2006/BuiltinType.java
new file mode 100644
index 0000000000000000000000000000000000000000..ffcdc879cd4c727d112423d498603da897752f3e
--- /dev/null
+++ b/lib/java/se/lth/control/labcomm2006/BuiltinType.java
@@ -0,0 +1,5 @@
+package se.lth.control.labcomm2006;
+
+public interface BuiltinType extends SampleType{
+
+}
diff --git a/lib/java/se/lth/control/labcomm2006/TypeBinding.java b/lib/java/se/lth/control/labcomm2006/TypeBinding.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a15ac99af8f32c711e621d667ee920cf14abd7b
--- /dev/null
+++ b/lib/java/se/lth/control/labcomm2006/TypeBinding.java
@@ -0,0 +1,3 @@
+public class TypeBinding {
+
+}
diff --git a/lib/java/se/lth/control/labcomm2006/TypeDef.java b/lib/java/se/lth/control/labcomm2006/TypeDef.java
new file mode 100644
index 0000000000000000000000000000000000000000..32997dd75bc4b149eef5d885da7b046819e47b2c
--- /dev/null
+++ b/lib/java/se/lth/control/labcomm2006/TypeDef.java
@@ -0,0 +1,3 @@
+public class TypeDef {
+
+}
diff --git a/lib/java/se/lth/control/labcomm2006/TypeDefParser.java b/lib/java/se/lth/control/labcomm2006/TypeDefParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..2890eeec456346dbd786195991afcf1bfd21cdec
--- /dev/null
+++ b/lib/java/se/lth/control/labcomm2006/TypeDefParser.java
@@ -0,0 +1,2 @@
+public class TypeDefParser {
+}
diff --git a/lib/python/labcomm/LabComm.py b/lib/python/labcomm/LabComm.py
index 57172143d4c1716069edae6b971e87881a430ee9..3816c0f834cf6da92928a85cc6ee2caa868988bf 100644
--- a/lib/python/labcomm/LabComm.py
+++ b/lib/python/labcomm/LabComm.py
@@ -175,6 +175,8 @@ DEFAULT_VERSION = "LabComm2014"
 i_VERSION     = 0x01
 i_SAMPLE_DEF  = 0x02
 i_SAMPLE_REF  = 0x03
+i_TYPE_DEF    = 0x04  
+i_TYPE_BINDING= 0x05 
 i_PRAGMA      = 0x3f
 i_USER        = 0x40 # ..0xffffffff
 
@@ -847,6 +849,13 @@ class Decoder(Codec):
         for _ in xrange(length):
             self.decode_byte()
 
+    # kludge, should really check if the index exists in self.version
+    def skip_or_raise(self, length, index):
+        if usePacketLength(self.version):
+            self.skip(length)
+        else:    
+            raise Exception("Invalid type index %d" % index)
+
     def decode(self):
         while True:
             index = self.decode_type_number()
@@ -865,6 +874,18 @@ class Decoder(Codec):
         elif index == i_SAMPLE_REF:
             decl = self.index_to_decl[index].decode_decl(self)
             value = None
+        elif index == i_TYPE_DEF:
+            self.skip_or_raise(length, index) 
+            decl = None
+            value = None
+        elif index == i_TYPE_BINDING:
+            self.skip_or_raise(length, index) 
+            decl = None
+            value = None
+        elif index == i_PRAGMA:
+            self.skip_or_raise(length, index) 
+            decl = None
+            value = None
         elif index < i_USER:
             raise Exception("Invalid type index %d" % index)
         else: