From 095f296a3eb9c0776258075b1067170360de2e97 Mon Sep 17 00:00:00 2001
From: Anders Blomdell <anders.blomdell@control.lth.se>
Date: Tue, 25 Nov 2014 18:03:17 +0100
Subject: [PATCH] First stab at separating compiler for different versions

---
 .gitignore                                |    1 +
 compiler/{ => 2006}/ArrayTypeRewrite.jrag |    0
 compiler/{ => 2006}/CS_CodeGen.jrag       |    0
 compiler/{ => 2006}/C_CodeGen.jrag        |    0
 compiler/{ => 2006}/DeclNames.jrag        |    0
 compiler/{ => 2006}/ErrorCheck.jrag       |    0
 compiler/{ => 2006}/FlatSignature.jrag    |    0
 compiler/{ => 2006}/Java_CodeGen.jrag     |    0
 compiler/{ => 2006}/LabComm.ast           |    0
 compiler/2006/LabComm.java                |  404 +++++
 compiler/{ => 2006}/LabCommParser.parser  |    3 +-
 compiler/{ => 2006}/LabCommScanner.flex   |    4 +-
 compiler/{ => 2006}/LabCommTokens.jrag    |    0
 compiler/{ => 2006}/NameAnalysis.jrag     |    0
 compiler/{ => 2006}/PrettyPrint.jrag      |    0
 compiler/{ => 2006}/Python_CodeGen.jrag   |    0
 compiler/{ => 2006}/RAPID_CodeGen.jrag    |    0
 compiler/{ => 2006}/Signature.jrag        |    2 +-
 compiler/{ => 2006}/TypeCheck.jrag        |    0
 compiler/{ => 2006}/TypeReferences.jrag   |    0
 compiler/{ => 2006}/Version.jrag          |    0
 compiler/2014/ArrayTypeRewrite.jrag       |   43 +
 compiler/2014/CS_CodeGen.jrag             |  971 ++++++++++++
 compiler/2014/C_CodeGen.jrag              | 1694 +++++++++++++++++++++
 compiler/2014/DeclNames.jrag              |   14 +
 compiler/2014/ErrorCheck.jrag             |   31 +
 compiler/2014/FlatSignature.jrag          |  123 ++
 compiler/2014/Java_CodeGen.jrag           | 1056 +++++++++++++
 compiler/2014/LabComm.ast                 |   39 +
 compiler/2014/LabComm.java                |  404 +++++
 compiler/2014/LabCommParser.parser        |  133 ++
 compiler/2014/LabCommScanner.flex         |   87 ++
 compiler/2014/LabCommTokens.jrag          |   21 +
 compiler/2014/NameAnalysis.jrag           |   67 +
 compiler/2014/PrettyPrint.jrag            |  117 ++
 compiler/2014/Python_CodeGen.jrag         |  232 +++
 compiler/2014/RAPID_CodeGen.jrag          |  369 +++++
 compiler/2014/Signature.jrag              |  236 +++
 compiler/2014/TypeCheck.jrag              |   36 +
 compiler/2014/TypeReferences.jrag         |   46 +
 compiler/2014/Version.jrag                |   15 +
 compiler/LabComm.java                     |  417 +----
 compiler/build.xml                        |  135 +-
 compiler/cs_codegen.patch                 |   34 -
 compiler/java_array_encode.patch          |   24 -
 45 files changed, 6260 insertions(+), 498 deletions(-)
 rename compiler/{ => 2006}/ArrayTypeRewrite.jrag (100%)
 rename compiler/{ => 2006}/CS_CodeGen.jrag (100%)
 rename compiler/{ => 2006}/C_CodeGen.jrag (100%)
 rename compiler/{ => 2006}/DeclNames.jrag (100%)
 rename compiler/{ => 2006}/ErrorCheck.jrag (100%)
 rename compiler/{ => 2006}/FlatSignature.jrag (100%)
 rename compiler/{ => 2006}/Java_CodeGen.jrag (100%)
 rename compiler/{ => 2006}/LabComm.ast (100%)
 create mode 100644 compiler/2006/LabComm.java
 rename compiler/{ => 2006}/LabCommParser.parser (97%)
 rename compiler/{ => 2006}/LabCommScanner.flex (96%)
 rename compiler/{ => 2006}/LabCommTokens.jrag (100%)
 rename compiler/{ => 2006}/NameAnalysis.jrag (100%)
 rename compiler/{ => 2006}/PrettyPrint.jrag (100%)
 rename compiler/{ => 2006}/Python_CodeGen.jrag (100%)
 rename compiler/{ => 2006}/RAPID_CodeGen.jrag (100%)
 rename compiler/{ => 2006}/Signature.jrag (99%)
 rename compiler/{ => 2006}/TypeCheck.jrag (100%)
 rename compiler/{ => 2006}/TypeReferences.jrag (100%)
 rename compiler/{ => 2006}/Version.jrag (100%)
 create mode 100644 compiler/2014/ArrayTypeRewrite.jrag
 create mode 100644 compiler/2014/CS_CodeGen.jrag
 create mode 100644 compiler/2014/C_CodeGen.jrag
 create mode 100644 compiler/2014/DeclNames.jrag
 create mode 100644 compiler/2014/ErrorCheck.jrag
 create mode 100644 compiler/2014/FlatSignature.jrag
 create mode 100644 compiler/2014/Java_CodeGen.jrag
 create mode 100644 compiler/2014/LabComm.ast
 create mode 100644 compiler/2014/LabComm.java
 create mode 100644 compiler/2014/LabCommParser.parser
 create mode 100644 compiler/2014/LabCommScanner.flex
 create mode 100644 compiler/2014/LabCommTokens.jrag
 create mode 100644 compiler/2014/NameAnalysis.jrag
 create mode 100644 compiler/2014/PrettyPrint.jrag
 create mode 100644 compiler/2014/Python_CodeGen.jrag
 create mode 100644 compiler/2014/RAPID_CodeGen.jrag
 create mode 100644 compiler/2014/Signature.jrag
 create mode 100644 compiler/2014/TypeCheck.jrag
 create mode 100644 compiler/2014/TypeReferences.jrag
 create mode 100644 compiler/2014/Version.jrag
 delete mode 100644 compiler/cs_codegen.patch
 delete mode 100644 compiler/java_array_encode.patch

diff --git a/.gitignore b/.gitignore
index 19ab6d0..24cebf1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+*~
 *.class
 *.o
 lib/c/liblabcomm.a
diff --git a/compiler/ArrayTypeRewrite.jrag b/compiler/2006/ArrayTypeRewrite.jrag
similarity index 100%
rename from compiler/ArrayTypeRewrite.jrag
rename to compiler/2006/ArrayTypeRewrite.jrag
diff --git a/compiler/CS_CodeGen.jrag b/compiler/2006/CS_CodeGen.jrag
similarity index 100%
rename from compiler/CS_CodeGen.jrag
rename to compiler/2006/CS_CodeGen.jrag
diff --git a/compiler/C_CodeGen.jrag b/compiler/2006/C_CodeGen.jrag
similarity index 100%
rename from compiler/C_CodeGen.jrag
rename to compiler/2006/C_CodeGen.jrag
diff --git a/compiler/DeclNames.jrag b/compiler/2006/DeclNames.jrag
similarity index 100%
rename from compiler/DeclNames.jrag
rename to compiler/2006/DeclNames.jrag
diff --git a/compiler/ErrorCheck.jrag b/compiler/2006/ErrorCheck.jrag
similarity index 100%
rename from compiler/ErrorCheck.jrag
rename to compiler/2006/ErrorCheck.jrag
diff --git a/compiler/FlatSignature.jrag b/compiler/2006/FlatSignature.jrag
similarity index 100%
rename from compiler/FlatSignature.jrag
rename to compiler/2006/FlatSignature.jrag
diff --git a/compiler/Java_CodeGen.jrag b/compiler/2006/Java_CodeGen.jrag
similarity index 100%
rename from compiler/Java_CodeGen.jrag
rename to compiler/2006/Java_CodeGen.jrag
diff --git a/compiler/LabComm.ast b/compiler/2006/LabComm.ast
similarity index 100%
rename from compiler/LabComm.ast
rename to compiler/2006/LabComm.ast
diff --git a/compiler/2006/LabComm.java b/compiler/2006/LabComm.java
new file mode 100644
index 0000000..58234a5
--- /dev/null
+++ b/compiler/2006/LabComm.java
@@ -0,0 +1,404 @@
+package se.lth.control.labcomm2006.compiler;
+
+import java.io.*;
+import java.util.*;
+
+public class LabComm {
+
+  private static void println(String s) {
+    System.out.println(s);
+  }
+
+  private static void print_help() {
+    println("\n Usage: java -jar labcom.jar [options*] FILE");
+    println("");
+    println(" --help                  Shows this help text");
+    println(" -v                      Be verbose");
+    println(" --ver=VERSION           Generate code for labcomm VERSION (=2006 or 2013)");
+    println("[ C options ]");
+    println(" -C                      Generates C/H code in FILE.[ch]");
+    println(" --cprefix=PREFIX        Prefixes C types with PREFIX");
+    println(" --cinclude=FILE         Include FILE in generated .c");
+    println(" --c=CFILE               Generates C code in CFILE");
+    println(" --h=HFILE               Generates H code in HFILE");
+    println("[ C# options]");
+    println(" --cs                    Generates C# code in FILE.cs");
+    println(" --cs=CSFILE             Generates C# code in CSFILE");
+    println(" --csnamespace=NAMESPACE Place C# classes in NAMESPACE");
+    println("[ Java options ]");
+    println(" --java=JDIR             Generates Java files in JDIR");
+    println(" --javapackage=PACKAGE   Place Java classes in PACKAGE");
+    println("[ Python options ]");
+    println(" -P                      Generates Python code in FILE.py");
+    println(" --python=PFILE          Generates Python code in PFILE");
+    println("[ RAPID options ]");
+    println(" --rapid                 Generates RAPID code in FILE.sys");
+    println("[ Misc options ]");
+    println(" --pretty=PFILE          Pretty prints to PFILE");
+    println(" --typeinfo=TIFILE       Generates typeinfo in TIFILE");
+  }
+    
+  /** To be cleaned up.
+   */
+  private static void checkVersion(int v) {
+     if(! (v == 2006 || v == 2013) ) {
+	System.err.println(" Unknown version: " + v);
+	System.err.println(" Supported versions: 2006, 2013 ");
+	System.exit(2);
+     }
+  }
+
+  private static void genH(Program p, String hName, 
+			   Vector cIncludes, String coreName, String prefix, int ver) {
+    try {
+      FileOutputStream f;
+      PrintStream out;
+      
+      f = new FileOutputStream(hName);
+      out = new PrintStream(f);
+      p.C_genH(out, cIncludes, coreName, prefix, ver);
+      out.close();
+    } catch (IOException e) {
+      System.err.println("IOException: " + hName + " " + e);
+    }
+  }
+
+  private static void genC(Program p, String cName, 
+			   Vector cIncludes, String coreName, String prefix, int ver) {
+    try {
+      FileOutputStream f;
+      PrintStream out;
+
+      f = new FileOutputStream(cName);
+      out = new PrintStream(f);
+      p.C_genC(out, cIncludes, coreName, prefix, ver);
+      out.close();
+    } catch (IOException e) {
+      System.err.println("IOException: " + cName + " " + e);
+    }
+  }
+
+  private static void genCS(Program p, String csName, String csNamespace, int ver) {
+//      throw new Error("C# generation currently disabled");
+    try {
+      p.CS_gen(csName, csNamespace, ver);
+    } catch (IOException e) {
+      System.err.println("IOException: " + csName + " " + 
+			 csNamespace + " " + e);
+    }
+  }
+
+  private static void genJava(Program p,  String dirName, String packageName, int ver) {
+    try {
+      p.J_gen(dirName, packageName, ver);
+    } catch (IOException e) {
+      System.err.println("IOException: " + dirName + " " + 
+			 packageName + " " + e);
+    }
+  }
+
+  private static void genPython(Program p, String filename, String prefix, int ver) {
+    try {
+      FileOutputStream f;
+      PrintStream out;
+
+      f = new FileOutputStream(filename);
+      out = new PrintStream(f);
+      p.Python_gen(out, prefix, ver);
+      out.close();
+    } catch (IOException e) {
+      System.err.println("IOException: " + filename + " " + e);
+    }
+  }
+
+  private static void genRAPID(Program p, String filename, String prefix, int ver) {
+    try {
+      p.RAPID_gen(filename, prefix, ver);
+    } catch (IOException e) {
+      System.err.println("IOException: " + filename + " " + e);
+    }
+  }
+
+  /** Helper class to contain command line options 
+      and their associated behaviour
+   **/
+  private static class Opts {
+    final String[] args;
+    String coreName = null;
+    String prefix = null;
+    boolean verbose = false;
+    int ver = 2013; //Version 2013 as default
+    String cFile = null;
+    String hFile = null;
+    Vector cIncludes = new Vector();
+    String cPrefix; // gets default value (prefix) in processFilename
+    String csFile = null;
+    String csNamespace = null;
+    String javaDir = null;
+    String javaPackage = "";
+    String pythonFile = null;
+    String prettyFile = null;
+    String typeinfoFile = null;
+    String rapidFile = null;
+    String fileName = null;
+
+   Opts(String[] args) {
+     this.args = args;
+   }
+
+    private static String getCoreName(String s) {
+      int i = s.lastIndexOf('.');
+      return s.substring(0, i > 0 ? i : s.length());
+    }
+  
+    private static String getFileName(String s) {
+      return s.substring(s.lastIndexOf('/') + 1, s.length());
+    }
+  
+    private static String getBaseName(String s) {
+      s = getFileName(s);
+      int i = s.lastIndexOf('.');
+      return s.substring(0, i > 0 ? i : s.length());
+    }
+  
+    private static String getPrefix(String s) {
+      return s.substring(s.lastIndexOf('/') + 1, s.length());
+    }
+  
+    boolean processFilename(){
+      // Scan for first non-option
+      for (int i = 0 ; i < args.length ; i++) {
+        if (! args[i].startsWith("-")) {
+  	fileName = args[i];
+  	break;
+        }
+      }
+      if (fileName != null) {
+        coreName = getBaseName(fileName);
+        prefix = getPrefix(coreName);
+       cPrefix = prefix;
+      }
+      return fileName != null;
+    }
+    
+    void processArgs(){
+      for (int i = 0 ; i < args.length ; i++) {
+        if (fileName == null ||
+  	  args[i].equals("-help") || 
+  	  args[i].equals("-h") || 
+  	  args[i].equals("--help")) {
+  	print_help();
+  	System.exit(0);
+        } else if (args[i].equals("-v")) {
+  	verbose=true;
+        } else if (args[i].startsWith("--ver=")) {
+          ver = Integer.parseInt(args[i].substring(6));
+          checkVersion(ver);
+        } else if (args[i].equals("-C")) {
+  	cFile = coreName + ".c";
+  	hFile = coreName + ".h";
+        } else if (args[i].startsWith("--cinclude=")) {
+  	cIncludes.add(args[i].substring(11));
+        } else if (args[i].startsWith("--cprefix=")) {
+  	cPrefix = args[i].substring(10);
+        } else if (args[i].startsWith("--c=")) {
+  	cFile = args[i].substring(4);
+        } else if (args[i].startsWith("--h=")) {
+  	hFile = args[i].substring(4);
+        } else if (args[i].equals("--cs")) {
+  	csFile = coreName + ".cs";
+        } else if (args[i].startsWith("--cs=")) {
+  	csFile = args[i].substring(5);
+        } else if (args[i].startsWith("--csnamespace=")) {
+  	csNamespace = args[i].substring(14);
+        } else if (args[i].startsWith("--java=")) {
+  	javaDir = args[i].substring(7);
+        } else if (args[i].startsWith("--javapackage=")) {
+  	javaPackage = args[i].substring(14);
+        } else if (args[i].equals("-P")) {
+  	pythonFile = coreName + ".py";
+        } else if (args[i].startsWith("--python=")) {
+  	pythonFile = args[i].substring(9);
+        } else if (args[i].startsWith("--pretty=")) {
+  	prettyFile = args[i].substring(9);
+        } else if (args[i].startsWith("--typeinfo=")) {
+  	typeinfoFile = args[i].substring(11);
+        } else if (args[i].equals("--rapid")) {
+  	rapidFile = coreName + ".sys";
+        } else if (i == args.length - 1) {
+  	fileName = args[i];
+        } else {
+  	System.err.println(" Unknown argument " + args[i]);
+  	print_help();
+  	System.exit(2);
+        }
+      }
+     if(prefix==null){
+  	System.err.println("   WARNING! prefix==null");
+        prefix="";
+     }
+   }
+
+   Program parseFile(){
+     Program ast = null;
+     try {
+       // Check for errors
+       LabCommScanner scanner = new LabCommScanner(
+                                  new FileReader(fileName));
+       LabCommParser parser = new LabCommParser();
+       Program p = (Program)parser.parse(scanner);
+       Collection errors = new LinkedList();
+       p.errorCheck(errors);
+         
+       if (errors.isEmpty()) {
+         ast = p;
+       } else {
+         for (Iterator iter = errors.iterator(); iter.hasNext(); ) {
+           String s = (String)iter.next();
+           System.out.println(s);
+         }
+       }
+     } catch (FileNotFoundException e) {
+       System.err.println("Could not find file: " + fileName);
+     } catch (IOException e) {
+       System.err.println("IOException: " + fileName + " " + e);
+     } catch (beaver.Parser.Exception e) {
+       System.err.println(e.getMessage());
+     }
+     return ast;
+   }
+
+   boolean generateC(Program ast) {
+     boolean wroteFile = false; 
+     Vector hIncludes = new Vector(cIncludes);
+     if (hFile != null) {
+       cIncludes.add(hFile);
+     }
+     if (cFile != null) {
+       printStatus("C: " , cFile);
+       genC(ast, cFile, cIncludes, coreName, cPrefix, ver);
+       wroteFile = true;
+     }
+     if (hFile != null) {
+       printStatus("H: " , hFile);
+       genH(ast, hFile, hIncludes, coreName, cPrefix, ver);
+       wroteFile = true;
+     }
+     return wroteFile;
+   }
+  
+   boolean generateCS(Program ast) {
+     boolean wroteFile = false; 
+     if (csFile != null) {
+       printStatus("C#: " , csFile); 
+       genCS(ast, csFile, csNamespace, ver);
+       wroteFile = true;
+     }
+     return wroteFile;
+   }
+  
+   boolean generateJava(Program ast) {
+     boolean wroteFile = false; 
+     if (javaDir != null) {
+       printStatus("Java: " , javaDir);
+       genJava(ast, javaDir, javaPackage, ver);
+       wroteFile = true;
+     }
+     return wroteFile;
+   }
+  
+   boolean generatePython(Program ast) {
+     boolean wroteFile = false; 
+     if (pythonFile != null) {
+       printStatus("Python: " , pythonFile); 
+       genPython(ast, pythonFile, prefix, ver);
+       wroteFile = true;
+     }
+     return wroteFile;
+   }
+  
+   boolean generateRAPID(Program ast) {
+     boolean wroteFile = false; 
+     if (rapidFile != null) {
+       printStatus("RAPID: " , rapidFile);
+       genRAPID(ast, rapidFile, coreName, ver);
+       wroteFile = true;
+     }
+     return wroteFile;
+   }
+   boolean generatePrettyPrint(Program ast) {
+     boolean wroteFile = false; 
+     if (prettyFile != null) {
+       printStatus("Pretty: " , prettyFile); 
+       try {
+         FileOutputStream f = new FileOutputStream(prettyFile);
+         PrintStream out = new PrintStream(f);
+         ast.pp(out);
+         out.close();
+         wroteFile = true;
+       } catch (IOException e) {
+         System.err.println("IOException: " + prettyFile + " " + e);
+       } 
+     }
+     return wroteFile;
+   }
+  
+   boolean generateTypeinfo(Program ast) {
+     boolean wroteFile = false; 
+     if (typeinfoFile != null) {
+       printStatus("TypeInfo: " , typeinfoFile); 
+       try {
+         FileOutputStream f = new FileOutputStream(typeinfoFile);
+         PrintStream out = new PrintStream(f);
+         ast.C_info(out, cPrefix, ver);
+         ast.Java_info(out, ver);
+         ast.CS_info(out, csNamespace, ver);
+         wroteFile = true;
+       } catch (IOException e) {
+         System.err.println("IOException: " + typeinfoFile + " " + e);
+       }
+     }
+     return wroteFile;
+    }
+
+    private void printStatus(String kind, String filename){
+       if (verbose) { 
+         System.err.println("Generating "+kind+": " + filename); 
+       }
+    }
+  }
+
+
+  public static void main(String[] args) {
+    Opts opts = new Opts(args);
+    if(!opts.processFilename()) {
+      print_help();
+      System.exit(1);
+    } else {
+      opts.processArgs();
+      Program ast =  opts.parseFile();
+
+      if (ast != null) {
+	
+	boolean fileWritten = false;
+
+        fileWritten |= opts.generateC(ast);
+        fileWritten |= opts.generateCS(ast);
+        fileWritten |= opts.generateJava(ast);
+        fileWritten |= opts.generatePython(ast);
+        fileWritten |= opts.generateRAPID(ast);
+        fileWritten |= opts.generatePrettyPrint(ast);
+        fileWritten |= opts.generateTypeinfo(ast);
+
+        // if no output to files, prettyprint on stdout
+	if (!fileWritten) {
+	  ast.pp(System.out);
+	}
+      } else {
+          // Catch-all for compilation errors
+          System.err.println("Error in specification");
+          System.exit(3);
+      }
+    }
+  } 
+}
diff --git a/compiler/LabCommParser.parser b/compiler/2006/LabCommParser.parser
similarity index 97%
rename from compiler/LabCommParser.parser
rename to compiler/2006/LabCommParser.parser
index f326d63..e1fb352 100644
--- a/compiler/LabCommParser.parser
+++ b/compiler/2006/LabCommParser.parser
@@ -1,5 +1,6 @@
 %header {:
- package AST;
+package se.lth.control.labcomm2006.compiler;
+import se.lth.control.labcomm2006.compiler.*;
 :};
 %embed {:
   public static class SourceError extends Error {
diff --git a/compiler/LabCommScanner.flex b/compiler/2006/LabCommScanner.flex
similarity index 96%
rename from compiler/LabCommScanner.flex
rename to compiler/2006/LabCommScanner.flex
index 4bb82d3..685f824 100644
--- a/compiler/LabCommScanner.flex
+++ b/compiler/2006/LabCommScanner.flex
@@ -1,8 +1,8 @@
-package AST;
+package se.lth.control.labcomm2006.compiler;
 
 import beaver.Symbol;
 import beaver.Scanner;
-import AST.LabCommParser.Terminals;
+import se.lth.control.labcomm2006.compiler.LabCommParser.Terminals;
 
 %%
 
diff --git a/compiler/LabCommTokens.jrag b/compiler/2006/LabCommTokens.jrag
similarity index 100%
rename from compiler/LabCommTokens.jrag
rename to compiler/2006/LabCommTokens.jrag
diff --git a/compiler/NameAnalysis.jrag b/compiler/2006/NameAnalysis.jrag
similarity index 100%
rename from compiler/NameAnalysis.jrag
rename to compiler/2006/NameAnalysis.jrag
diff --git a/compiler/PrettyPrint.jrag b/compiler/2006/PrettyPrint.jrag
similarity index 100%
rename from compiler/PrettyPrint.jrag
rename to compiler/2006/PrettyPrint.jrag
diff --git a/compiler/Python_CodeGen.jrag b/compiler/2006/Python_CodeGen.jrag
similarity index 100%
rename from compiler/Python_CodeGen.jrag
rename to compiler/2006/Python_CodeGen.jrag
diff --git a/compiler/RAPID_CodeGen.jrag b/compiler/2006/RAPID_CodeGen.jrag
similarity index 100%
rename from compiler/RAPID_CodeGen.jrag
rename to compiler/2006/RAPID_CodeGen.jrag
diff --git a/compiler/Signature.jrag b/compiler/2006/Signature.jrag
similarity index 99%
rename from compiler/Signature.jrag
rename to compiler/2006/Signature.jrag
index d542d43..5395095 100644
--- a/compiler/Signature.jrag
+++ b/compiler/2006/Signature.jrag
@@ -76,7 +76,7 @@ aspect Signature {
 	    }
 	    //add(data, comment);
         break;
-        case 2013:             // Use new encoding with varints
+        case 2014:             // Use new encoding with varints
 	    byte[] tmp = new byte[5];
  	    long v = value & 0xffffffff;
             int i, j;
diff --git a/compiler/TypeCheck.jrag b/compiler/2006/TypeCheck.jrag
similarity index 100%
rename from compiler/TypeCheck.jrag
rename to compiler/2006/TypeCheck.jrag
diff --git a/compiler/TypeReferences.jrag b/compiler/2006/TypeReferences.jrag
similarity index 100%
rename from compiler/TypeReferences.jrag
rename to compiler/2006/TypeReferences.jrag
diff --git a/compiler/Version.jrag b/compiler/2006/Version.jrag
similarity index 100%
rename from compiler/Version.jrag
rename to compiler/2006/Version.jrag
diff --git a/compiler/2014/ArrayTypeRewrite.jrag b/compiler/2014/ArrayTypeRewrite.jrag
new file mode 100644
index 0000000..28e3c79
--- /dev/null
+++ b/compiler/2014/ArrayTypeRewrite.jrag
@@ -0,0 +1,43 @@
+aspect ArrayRewrite {
+
+  syn boolean Dim.isVariable() {
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      if (getExp(i) instanceof VariableSize) {
+	return true;
+      }	
+    }
+    return false;
+  }
+
+  rewrite ParseArrayType {
+    when (! getDim(0).isVariable()) 
+    to FixedArrayType  { 
+      if (getNumDim() == 1) {
+        return new FixedArrayType(getType(), 
+				  getDim(0).getExpList());
+      } else {
+        List l = new List();
+        for (int i = 1 ; i < getNumDim() ; i++) {
+	  l.add(getDim(i));
+        }
+        return new FixedArrayType(new ParseArrayType(getType(), l), 
+				  getDim(0).getExpList());
+      }
+    }
+    when (getDim(0).isVariable()) 
+    to VariableArrayType  { 
+      if (getNumDim() == 1) {
+        return new VariableArrayType(getType(), 
+				     getDim(0).getExpList());
+      } else {
+        List l = new List();
+        for (int i = 1 ; i < getNumDim() ; i++) {
+	  l.add(getDim(i));
+        }
+        return new VariableArrayType(new ParseArrayType(getType(), l), 
+				     getDim(0).getExpList());
+      }
+    }
+  }
+
+}
diff --git a/compiler/2014/CS_CodeGen.jrag b/compiler/2014/CS_CodeGen.jrag
new file mode 100644
index 0000000..e1da497
--- /dev/null
+++ b/compiler/2014/CS_CodeGen.jrag
@@ -0,0 +1,971 @@
+import java.io.*;
+import java.util.*;
+
+aspect CS_CodeGenEnv {
+
+  // Environment wrapper for CS-code generation
+  // handles indentation, file writing, 
+
+  public class CS_env {
+
+    public final int version;
+    public final String verStr;
+    private int indent;
+    private int depth;
+    private CS_printer printer;
+    private HashMap unique = new HashMap();
+
+    final private static class CS_printer {
+      
+      private boolean newline = true;
+      private File file;
+      private PrintStream out;
+      private IOException exception;
+      
+
+      public CS_printer(File f) {
+  	file = f;
+        File parentFile = f.getParentFile();
+        if(parentFile != null) {
+            parentFile.mkdirs();
+        }
+      }
+
+     public CS_printer(PrintStream out) {
+        this.out = out;
+      }
+
+      public void close() throws IOException {
+	if (out != null) {
+  	  out.close();
+        }
+	if (exception != null) {
+	  throw exception;
+        }
+      }
+
+      public PrintStream getPrintStream() {
+	return(out);
+      }
+
+      public void checkOpen() {
+	if (out == null && exception == null) {
+          try {
+    	    out = new PrintStream(new FileOutputStream(file));
+          } catch (IOException e) {
+	    exception = e;
+          }
+        }
+      }
+
+      public void print(CS_env env, String s) {
+	checkOpen();
+        if (newline) {
+          newline = false;
+          for (int i = 0 ; i < env.indent ; i++) {
+            out.print("  ");
+          }
+        }
+        out.print(s);
+      }
+
+      public void println(CS_env env, String s) {
+	checkOpen();
+        print(env, s);
+        out.println();
+        newline = true;
+      }
+    }
+
+    private CS_env(int indent, CS_printer printer, int version) {
+      this.version = version;
+      this.indent = indent;
+      this.printer = printer;
+      this.verStr = LabCommVersion.versionString(version);
+    }
+
+    public CS_env(File f, int version) {
+      this(0, new CS_printer(f), version);
+    }
+
+    public CS_env(PrintStream out, int version) {
+      this(0, new CS_printer(out), version);
+    }
+
+    public void close() throws IOException {
+      printer.close();
+    }
+
+    public PrintStream getPrintStream() {
+      return printer.getPrintStream();
+    }
+    public void indent(int amount) {
+      indent += amount;
+    }
+
+    public void indent() {
+      indent(1);
+    }
+
+    public void unindent(int amount) {
+      indent -= amount;
+      if (indent < 0) {
+        throw new Error("Negative indent level");
+      }
+    }
+
+    public void unindent() {
+      unindent(1);
+    }
+
+    public void print(String s) {
+      printer.print(this, s);
+    }
+
+    public void println(String s) {
+      printer.println(this, s);
+    }
+
+    public void println() {
+      printer.println(this, "");
+    }
+
+    public int getDepth() {
+      return depth;
+    }
+
+    public String print_for_begin(String limit) {
+      print("for (int i_" + depth + " = 0 ; ");
+      print("i_" + depth + " < " + limit + " ; ");
+      println("i_" + depth + "++) {");
+      indent();
+      depth++;
+      return "i_" + (depth - 1);
+    }
+
+    public void print_for_end() {
+      depth--;
+      unindent();
+      println("}");
+    }
+
+    public void print_block_begin() {
+      println("{");
+      indent();
+    }
+
+    public void print_block_end() {
+      unindent();
+      println("}");
+    }
+
+    public String getUnique(Object o) {
+      String result = (String)unique.get(o);
+      if (result == null) {
+   	result = "_" + (unique.size() + 1) + "_";
+      }
+      unique.put(o, result);
+      return result;
+    }
+
+  }
+
+}
+
+aspect CS_StructName {
+
+  inh int Decl.CS_Depth();
+  inh int Type.CS_Depth();
+  eq Program.getDecl(int i).CS_Depth() = 0;
+  eq StructType.getField(int i).CS_Depth() = CS_Depth() + 1;
+
+  inh String Type.CS_structName();
+  eq Program.getDecl(int i).CS_structName() = getDecl(i).getName();
+  eq StructType.getField(int i).CS_structName() {
+    if (CS_Depth() == 0) {
+      return "struct_" + getField(i).getName();
+    } else {
+      return CS_structName() + "_" + getField(i).getName();
+    }
+  }
+}
+
+aspect CS_Void {
+
+  syn boolean Decl.CS_isVoid() = getType().CS_isVoid();
+  syn boolean UserType.CS_isVoid() = decl().CS_isVoid();
+  syn boolean Type.CS_isVoid() = false;
+  syn boolean VoidType.CS_isVoid() = true;
+
+}
+
+aspect CS_CodeGen {
+
+  public void Program.CS_gen(String file, 
+			     String namespace, int version) throws IOException {
+    // Registration class
+    CS_env env = new CS_env(new File(file), version);
+    if (namespace != null && namespace.length() > 0) {
+      env.println("namespace " + namespace + "{");
+      env.indent();
+    }
+    env.println("using System;");
+    env.println("using se.lth.control.labcomm;");
+    for (int i = 0; i < getNumDecl(); i++) {
+      Decl d = getDecl(i);
+      try {
+        d.CS_emitClass(env);
+      } catch (Error e) {
+	System.err.println(d.getName());
+	throw e;
+      }
+    }
+    if (namespace != null && namespace.length() > 0) {
+      env.unindent();
+      env.println("}");
+    }
+  }
+
+}
+
+aspect CS_Register {
+
+  public void Program.CS_emitTypeRegister(CS_env env) {
+  }
+
+  public void Decl.CS_emitTypeRegister(CS_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".CS_emitTypeRegister(CS_env env)" + 
+		    " not declared");
+  }
+
+  public void SampleDecl.CS_emitTypeRegister(CS_env env) {
+    env.println(getName() + ".register(c);");
+  }
+
+  public void TypeDecl.CS_emitTypeRegister(CS_env env) {
+    // TODO
+  }
+
+}
+
+aspect CS_Class {
+
+  public void Decl.CS_emitClass(CS_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".CS_emitClass(CS_env env)" + 
+		    " not declared");
+  }
+
+  public void Decl.CS_emitDeclPP(CS_env env){
+	env.println("/* ");
+	pp(env.getPrintStream());
+	
+	CS_emitUserTypeDeps(env,null,false);
+	CS_emitUserTypeRefs(env,null,false);
+	env.println("*/");
+  
+  }
+  
+  public void Decl.CS_emitUserTypeDeps(CS_env env, String via, boolean outputCode){
+	Iterator<Decl> it = type_dependencies().iterator();
+	while(it.hasNext()) {
+	    Decl t = it.next();
+
+	    t.CS_emitUserTypeDeps(env, t.getName(), outputCode);
+	    if( outputCode && t.getType().isUserType() ) {
+	       env.println(t.getName()+".register(e);");
+	    } else {  // Just output a comment
+		String refpath = (via == null) ? "directly" : "indirectly via "+via;
+	       env.println(" //Depends ("+refpath+") on "+t.getName() );
+	    }
+	}
+  }
+  
+  public void Decl.CS_emitUserTypeRefs(CS_env env, String via, boolean outputCode){
+     if( isReferenced() ) {
+        Iterator<Decl> it = type_references().iterator();
+        while(it.hasNext()) {
+            Decl t = it.next();
+
+            t.CS_emitUserTypeRefs(env, t.getName(), outputCode);
+            if(outputCode) {
+               env.println(t.getName()+".register(e);");
+            } else {  // Just output a comment
+	        String refpath = (via == null) ? "directly" : "indirectly via "+via;
+	       env.println(" //Is referenced ("+refpath+")  by "+t.getName() );
+            }
+        }
+    }
+  }
+  
+  public void Decl.CS_emitRegisterEncoder(CS_env env) {
+    env.println("public static void register(Encoder e){");
+    env.indent();
+    env.println("e.register(dispatcher);");
+    env.unindent();
+    env.println("}");
+    env.println("public static void registerSampleRef(Encoder e) {");
+    env.indent();
+    env.println("e.registerSampleRef(dispatcher);");
+    env.unindent();
+    env.println("}");
+    env.println();
+  }
+  
+  public void Decl.CS_emitRegisterDecoder(CS_env env) {
+    env.println("public static void register(Decoder d, Handler h) {");
+    env.indent();
+    env.println("d.register(dispatcher, h);");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public static void registerSampleRef(Decoder d) {");
+    env.indent();
+    env.println("d.registerSampleRef(dispatcher);");
+    env.unindent();
+    env.println("}");
+    env.println();
+  }
+    
+  public void TypeDecl.CS_emitClass(CS_env env) {
+    if (getType().CS_needInstance()) {
+      // Hackish prettyprint preamble
+      env.println("/* ");
+      pp(env.getPrintStream());
+      env.println("*/");
+      env.println();
+      env.println("public class " + getName() + " : SampleType {");
+      env.println();
+      env.indent();
+      getType().CS_emitInstance(env);
+      if( isReferenced()) {
+        CS_emitRegisterEncoder(env);
+	CS_emitDispatcher(env,false);
+      }
+      CS_emitSignature(env);
+      CS_emitEncoder(env);
+      CS_emitDecoder(env);
+      env.unindent();
+      env.println("}");
+    }
+  }
+
+  public void SampleDecl.CS_emitClass(CS_env env) {
+    env.println("/* ");
+    pp(env.getPrintStream());
+    env.println("*/");
+    env.println();
+    env.println("public class " + getName() + " : Sample {");
+    env.println();
+    env.indent();
+    getType().CS_emitInstance(env);
+    env.println("public interface Handler : SampleHandler {");
+    env.print("  void handle(");
+    if (!isVoid()) {
+      getType().CS_emitType(env);
+      env.print(" value");
+    }
+    env.println(");");
+    env.println("}");
+    env.println();
+    CS_emitDispatcher(env,true);
+    CS_emitRegisterEncoder(env);
+    CS_emitRegisterDecoder(env);
+    CS_emitEncoder(env);
+    CS_emitDecoder(env);
+    CS_emitSignature(env);
+
+    env.println("}");
+  }
+
+  public void Decl.CS_emitSignature(CS_env env) {
+    CS_emitFlatSignature(env);
+//    if(isReferenced() || isSampleDecl()){
+//      Signature signature = getSignature();
+//      signature.CS_emitSignature(env, !isSampleDecl());
+//    }
+  }
+
+  public void Decl.CS_emitFlatSignature(CS_env env){
+    env.println("private static byte[] signature = new byte[] {");
+    env.indent();
+    SignatureList signature = flatSignature(env.version);
+    for (int i = 0 ; i < signature.size() ; i++) {
+      String comment = signature.getComment(i);
+      if (comment != null) {
+        env.println(signature.getIndent(i) + "// " + comment);
+      }
+      byte[] data = signature.getData(i, env.version);
+      if (data != null) {
+        env.print(signature.getIndent(i));
+        for (int j = 0 ; j < data.length ; j++) {
+          //env.print(data[j] + ", ");
+          env.print(String.format("0x%02X, ", data[j])) ;
+        }
+        env.println();
+      }
+    }
+    env.unindent();
+    env.println("};");
+    env.println();
+  }
+
+  //XXX TODO: refactor: split into a static class ("TypeDefSingleton"?)and a (smaller) dispatcher
+  public void Decl.CS_emitDispatcher(CS_env env, boolean isSample) {
+    String genericStr = ""; //env.versionHasMetaData()?"<"+getName()+">":""; 
+    env.println("private static Dispatcher dispatcher = new Dispatcher();");
+    env.println();
+    env.println("public SampleDispatcher getDispatcher() {");
+    env.indent();
+    env.println("return dispatcher;");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("private class Dispatcher : SampleDispatcher{");
+    env.indent();
+    env.println();
+    env.println("public Type getSampleClass() {");
+    env.indent();
+    env.println("return typeof(" + getName() + ");");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public String getName() {");
+    env.indent();
+    env.println("return \"" + getName() + "\";");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public byte getTypeDeclTag() {");
+    env.indent();
+    if(isSample) {
+      env.println("return Constant.SAMPLE_DEF;");
+    } else {
+      env.println("return Constant.TYPE_DEF;");
+    }
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public bool isSample() {");
+    env.indent();
+    env.println("return "+isSample+";");
+    env.unindent();
+    env.println("}");
+    env.println("/** return the flat signature. */");
+    env.println("public byte[] getSignature() {");
+    env.indent();
+    env.println("return signature;");
+    env.unindent();
+    env.println("}");
+    env.println();
+//    env.println("public void encodeSignature(Encoder e) throws IOException{");
+//    env.indent();
+//    env.println("emitSignature(e);");
+//    env.unindent();
+//    env.println("}");
+//    env.println();
+//  env.println("public void encodeSignatureMetadata(Encoder e, int index){");
+//  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 bool canDecodeAndHandle() {");
+    env.indent();
+    env.println("return "+isSample+";");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public void decodeAndHandle(Decoder d,");
+    env.println("                            SampleHandler h) {");
+    env.indent();
+    if( isSample) {
+        if (isVoid()) {
+          env.println(getName() + ".decode(d);");
+          env.println("((Handler)h).handle();");
+        } else {
+          env.println("((Handler)h).handle(" + getName() + ".decode(d));");
+        }
+    } else {
+        env.println("throw new Exception(\"A typedef has no handler, the corresponding method on the sample class should be called.\");");
+    }
+    env.unindent();
+    env.println("}");
+    env.println("");
+    env.unindent();
+    env.println("}");
+    env.println("");
+
+ } //TODO, fix above method
+  
+  public void TypeDecl.CS_emitEncoder(CS_env env) {
+    env.print("public static void encode(Encoder e");
+    if (!isVoid()) {
+      env.print(", ");
+      getType().CS_emitType(env);
+      env.print(" value");
+    }
+    env.println(") {");
+    env.indent();
+    getType().CS_emitEncoder(env, "value");
+    env.unindent();
+    env.println("}");
+    env.println();
+  }
+
+  public void SampleDecl.CS_emitEncoder(CS_env env) {
+    env.print("public static void encode(Encoder e");
+    if (!isVoid()) {
+      env.print(", ");
+      getType().CS_emitType(env);
+      env.print(" value");
+    }
+    env.println(") {");
+    env.indent();
+    env.println("e.begin(typeof(" + getName() + "));");
+    getType().CS_emitEncoder(env, "value");
+    env.println("e.end(typeof(" + getName() + "));");
+    env.unindent();
+    env.println("}");
+    env.println();
+  }
+
+  public void Type.CS_emitEncoder(CS_env env, String name) {
+    throw new Error(this.getClass().getName() + 
+		    ".CS_emitEncoder(CS_env env, String name)" + 
+		    " not declared");
+  }
+
+  public void VoidType.CS_emitEncoder(CS_env env, String name) {
+  }
+
+  public void PrimType.CS_emitEncoder(CS_env env, String name) {
+    switch (getToken()) {
+      case LABCOMM_BOOLEAN: { env.print("e.encodeBoolean"); } break;
+      case LABCOMM_BYTE: { env.print("e.encodeByte"); } break;
+      case LABCOMM_SHORT: { env.print("e.encodeShort"); } break;
+      case LABCOMM_INT: { env.print("e.encodeInt"); } break;
+      case LABCOMM_LONG: { env.print("e.encodeLong"); } break;
+      case LABCOMM_FLOAT: { env.print("e.encodeFloat"); } break;
+      case LABCOMM_DOUBLE: { env.print("e.encodeDouble"); } break;
+      case LABCOMM_STRING: { env.print("e.encodeString"); } break;
+      case LABCOMM_SAMPLE: { env.print("e.encodeSampleRef"); } break;
+    }
+    env.println("(" + name + ");");
+  }
+
+  public void ArrayType.CS_emitEncoder(CS_env env, String name) {
+    env.print_block_begin();
+    int baseDepth = env.getDepth();
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      String limit = getExp(i).CS_emitEncoder(env, 
+					      name + ".GetLength(" + i + ")");
+      env.println("int i_" + (baseDepth + i) + "_max = " + limit + ";");
+    }
+    String index = null;
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      String limit = "i_" + (baseDepth + i) + "_max";
+      if (i == 0) {
+        index = env.print_for_begin(limit);
+      } else {
+        index = index + ", " + env.print_for_begin(limit);
+      }
+    }
+    getType().CS_emitEncoder(env, name + "[" + index + "]");
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      env.print_for_end();
+    }
+    env.print_block_end();
+  }
+  
+  public String Exp.CS_emitEncoder(CS_env env, String name) {
+    throw new Error(this.getClass().getName() + 
+		    ".CS_emitEncoder(CS_env env, String name)" + 
+		    " not declared");
+  }
+
+  public String IntegerLiteral.CS_emitEncoder(CS_env env, String name) {
+    return getValue();
+  }
+
+  public String VariableSize.CS_emitEncoder(CS_env env, String name) {
+    env.println("e.encodePacked32(" + name + ");");
+    return name;
+  }
+
+  public void StructType.CS_emitEncoder(CS_env env, String name) {
+    for (int i = 0 ; i < getNumField() ; i++) {
+      Field f = getField(i);
+      f.getType().CS_emitEncoder(env, name + "." + f.getName());
+    }
+  }
+
+  public void UserType.CS_emitEncoder(CS_env env, String name) {
+    if (CS_needInstance()) {
+      env.println(getName() + ".encode(e, " + name + ");");
+    } else {
+      decl().getType().CS_emitEncoder(env, name);
+    }
+  }
+
+  public void Decl.CS_emitDecoder(CS_env env) {
+    env.print("public static ");
+    getType().CS_emitType(env);
+    env.println(" decode(Decoder d) {");
+    env.indent();
+    if (!isVoid()) {
+      getType().CS_emitType(env);
+      env.println(" result;");
+      getType().CS_emitDecoder(env, "result");
+      env.println("return result;");
+    }
+    env.unindent();
+    env.println("}");
+    env.println();
+  }
+
+  public void Type.CS_emitDecoder(CS_env env, String name) {
+    throw new Error(this.getClass().getName() + 
+		    ".CS_emitDecoder(CS_env env, String name)" + 
+		    " not declared");
+  }
+
+  public void VoidType.CS_emitDecoder(CS_env env, String name) {
+  }
+
+  public void PrimType.CS_emitDecoder(CS_env env, String name) {
+    env.print(name + " = ");
+    switch (getToken()) {
+      case LABCOMM_BOOLEAN: { env.println("d.decodeBoolean();"); } break;
+      case LABCOMM_BYTE: { env.println("d.decodeByte();"); } break;
+      case LABCOMM_SHORT: { env.println("d.decodeShort();"); } break;
+      case LABCOMM_INT: { env.println("d.decodeInt();"); } break;
+      case LABCOMM_LONG: { env.println("d.decodeLong();"); } break;
+      case LABCOMM_FLOAT: { env.println("d.decodeFloat();"); } break;
+      case LABCOMM_DOUBLE: { env.println("d.decodeDouble();"); } break;
+      case LABCOMM_STRING: { env.println("d.decodeString();"); } break;
+      case LABCOMM_SAMPLE: { env.println("d.decodeSampleRef();"); } break;
+      default: {
+        throw new Error("PrimType.CS_emitDecoder(CS_env env, String name)" + 
+                        " unknown token type");
+      }
+    }
+  }
+
+  public void ArrayType.CS_emitDecoder(CS_env env, String name) {
+    env.println("{");
+    env.indent();
+    int baseDepth = env.getDepth();
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      env.print("int i_" + (baseDepth + i) + "_max = ");
+      getExp(i).CS_emitDecoder(env);
+      env.println(";");
+    }
+    env.print(name + " = new "); 
+    getType().CS_emitTypePrefix(env);
+    env.print("[");
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      if (i > 0) {
+	env.print(", ");
+      }
+      env.print("i_" + (baseDepth + i) + "_max");
+    }
+    env.print("]");
+    getType().CS_emitTypeSuffix(env);
+    env.println(";");
+    
+    String index = null;
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      String limit = "i_" + (baseDepth + i) + "_max";
+      if (i == 0) {
+        index = env.print_for_begin(limit);
+      } else {
+        index = index + ", " + env.print_for_begin(limit);
+      }
+    }
+    getType().CS_emitDecoder(env, name + "[" + index + "]");
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      env.print_for_end();
+    }
+    env.unindent();
+    env.println("}");
+  }
+
+  public void Exp.CS_emitDecoder(CS_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".CS_emitDecoder(CS_env env)" + 
+		    " not declared");
+  }
+
+  public void IntegerLiteral.CS_emitDecoder(CS_env env) {
+    env.print(getValue());
+  }
+
+  public void VariableSize.CS_emitDecoder(CS_env env) {
+    env.print("d.decodePacked32()");
+  }
+
+  public void StructType.CS_emitDecoder(CS_env env, String name) {
+    env.print(name + " = new ");
+    CS_emitType(env);
+    env.println("();");
+    for (int i = 0 ; i < getNumField() ; i++) {
+      Field f = getField(i);
+      f.getType().CS_emitDecoder(env, name + "." + f.getName());
+    }
+  }
+
+  public void UserType.CS_emitDecoder(CS_env env, String name) {
+    if (CS_needInstance()) {
+      env.println(name + " = " + getName() + ".decode(d);");
+    } else {
+      decl().getType().CS_emitDecoder(env, name);
+    }
+  }
+
+  public void Type.CS_emitTypePrefix(CS_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".CS_emitTypePrefix(CS_env env)" + 
+		    " not declared");
+  }
+
+  public void PrimType.CS_emitTypePrefix(CS_env env) {
+    switch (getToken()) {
+      case LABCOMM_STRING: { env.print("String"); } break;
+      case LABCOMM_SAMPLE: { env.print("Type"); } break;
+      default: { env.print(getName()); } break;
+    }
+  }
+
+  public void UserType.CS_emitTypePrefix(CS_env env) {
+    if (CS_needInstance()) {
+      env.print(getName());
+    } else {
+      decl().getType().CS_emitTypePrefix(env);
+    } 
+  }
+
+  public void ArrayType.CS_emitTypePrefix(CS_env env){
+    getType().CS_emitTypePrefix(env);
+  }
+
+  public void StructType.CS_emitTypePrefix(CS_env env){
+    env.print(CS_structName());
+  }
+
+  public void Type.CS_emitTypeSuffix(CS_env env) {
+  }
+
+  public void UserType.CS_emitTypeSuffix(CS_env env) {
+    if (! CS_needInstance()) {
+      decl().getType().CS_emitTypeSuffix(env);
+    } 
+  }
+
+  public void ArrayType.CS_emitTypeSuffix(CS_env env){
+    env.print("[");
+    for (int i = 1 ; i < getNumExp() ; i++) {
+      env.print(",");
+    }
+    env.print("]");
+    getType().CS_emitTypeSuffix(env);
+  }
+
+  public boolean Type.CS_needInstance() {
+    throw new Error(this.getClass().getName() + 
+		    ".CS_needInstance()" + 
+		    " not declared");
+  }
+
+  public boolean VoidType.CS_needInstance() {
+    return false;
+  }
+
+  public boolean PrimType.CS_needInstance() {
+    return false;
+  }
+
+  public boolean UserType.CS_needInstance() {
+    return decl().getType().CS_needInstance();
+  }
+
+  public boolean StructType.CS_needInstance() {
+    return true;
+  }
+
+  public boolean ArrayType.CS_needInstance() {
+    return getType().CS_needInstance();
+  }
+
+  public boolean Type.CS_isPrimitive() {
+    return false;
+  }
+
+  public boolean PrimType.CS_isPrimitive() {
+    return true;
+  }
+
+  public void Type.CS_emitInstance(CS_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".CS_emitInstance(CS_env env)" + 
+		    " not declared");
+  }
+
+  public void VoidType.CS_emitInstance(CS_env env) {
+  }
+
+  public void PrimType.CS_emitInstance(CS_env env) {
+  }
+
+  public void ArrayType.CS_emitInstance(CS_env env) {
+    getType().CS_emitInstance(env);
+  }
+
+  public void StructType.CS_emitInstance(CS_env env) {
+    if (CS_Depth() > 0) {
+      env.println("public class " + CS_structName() + " {");
+      env.indent();
+    }
+    for (int i = 0 ; i < getNumField() ; i++) {
+      getField(i).getType().CS_emitInstance(env);
+    }
+    for (int i = 0 ; i < getNumField() ; i++) {
+      getField(i).CS_emitField(env);
+    }
+    if (CS_Depth() > 0) {
+      env.unindent();
+      env.println("}");
+    }
+    env.println();
+  }
+
+  public void UserType.CS_emitInstance(CS_env env) {
+  }
+
+  public void Field.CS_emitField(CS_env env) {
+    env.print("public ");
+    getType().CS_emitType(env);
+    env.println(" " + getName() + ";");    
+  }
+
+  public void Type.CS_emitType(CS_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".CS_emitType(CS_env env)" + 
+		    " not declared");
+  }
+
+  public void VoidType.CS_emitType(CS_env env) {
+    env.print("void");
+  }
+
+  public void PrimType.CS_emitType(CS_env env) {
+    switch (getToken()) {
+      case LABCOMM_STRING: { env.print("String"); } break;
+      case LABCOMM_BOOLEAN: { env.print("bool"); } break;
+      case LABCOMM_SAMPLE: { env.print("Type"); } break;
+      default: { env.print(getName()); } break;
+    }
+  }
+
+  public void UserType.CS_emitType(CS_env env) {
+    decl().getType().CS_emitType(env);
+  }
+
+  public void ArrayType.CS_emitType(CS_env env){
+    getType().CS_emitTypePrefix(env);
+    env.print("[");
+    for (int i = 1 ; i < getNumExp() ; i++) {
+      env.print(",");
+    }
+    env.print("]");
+    getType().CS_emitTypeSuffix(env);
+  }
+
+  public void StructType.CS_emitType(CS_env env){
+    env.print(CS_structName());
+  }
+
+}
+
+aspect CS_Signature {
+    public void Signature.CS_emitSignature(CS_env env, boolean decl){
+ 
+      SignatureList sl = getSignatureList();
+      sl.CS_emitSignature(env, decl);
+    }
+
+    public abstract void SignatureLine.CS_emitSignature(CS_env env, boolean decl);
+
+    public void TypeRefSignatureLine.CS_emitSignature(CS_env env, boolean isDecl){
+      env.print(getIndentString());
+      env.println("e.encodePacked32(e.getTypeId( typeof("+decl.getName()+")));");
+    }
+
+    public void DataSignatureLine.CS_emitSignature(CS_env env, boolean decl){
+        byte[] data = getData(env.version);
+          if (data != null) {
+              env.print(getIndentString());
+              for (int j = 0 ; j < data.length ; j++) {
+                  //env.print("e.encodeByte((byte)"+data[j]+");");
+                  env.print("e.encodeByte((byte)"+ String.format("0x%02X ", data[j]) +"); ");
+              }
+              env.println();
+          }
+  }
+    public void SignatureList.CS_emitSignature(CS_env env, boolean decl) {
+      env.println("private static void emitSignature(Encoder e){");
+      env.indent();
+      for (int i = 0 ; i < size() ; i++) {
+        String comment = getComment(i);
+        if (comment != null && comment.length() > 0) {
+            env.println(getIndent(i) + "// " + comment);
+        }
+        SignatureLine l = getSignatureLine(i);
+        l.CS_emitSignature(env, decl);
+      }
+      env.println("}");
+      env.unindent();
+  }
+
+}
+
+aspect CS_Info {
+
+  public void Program.CS_info(PrintStream out, String namespace, int version) {
+    CS_env env = new CS_env(out, version);
+    if (namespace == null) {
+      namespace = ""; 
+    } else {
+      namespace = namespace + "."; 
+    }
+    for (int i = 0; i < getNumDecl(); i++) {
+      getDecl(i).CS_info(env, namespace);
+    }
+  }
+
+  public void Decl.CS_info(CS_env env, String namespace) {
+    throw new Error(this.getClass().getName() + 
+		    ".CS_info(CS_env env)" + 
+		    " not declared");
+  }
+
+  public void TypeDecl.CS_info(CS_env env, String namespace) {
+    env.print(";C#;typedef;" + namespace + getName() + ";");
+    getType().CS_emitType(env) ;
+    env.print(";not_applicable_for_C#");
+    env.println();
+  }
+
+  public void SampleDecl.CS_info(CS_env env, String namespace) {
+    env.print(";C#;sample;" + namespace + getName() + ";");
+    getType().CS_emitType(env);
+    env.print(";not_applicable_for_C#");
+    env.println();
+  }
+
+}
+
diff --git a/compiler/2014/C_CodeGen.jrag b/compiler/2014/C_CodeGen.jrag
new file mode 100644
index 0000000..0beef11
--- /dev/null
+++ b/compiler/2014/C_CodeGen.jrag
@@ -0,0 +1,1694 @@
+import java.util.Vector;
+
+aspect C_CodeGenEnv {
+
+  // Environment wrapper for C-code generation
+  // handles qualid nesting, indentation, file writing and
+  // prefix propagation
+
+  public class C_env {
+
+    final private static class C_printer {
+      
+      private boolean newline = true;
+      private PrintStream out;
+
+      public C_printer(PrintStream out) {
+	this.out = out;
+      }
+
+      public void print(C_env env, String s) {
+	if (newline) {
+	  newline = false;
+	  for (int i = 0 ; i < env.indent ; i++) {
+	    out.print("  ");
+	  }
+	}
+	out.print(s);
+      }
+      public void println(C_env env, String s) {
+	print(env, s);
+	out.println();
+	newline = true;
+      }
+    }
+
+    public final int version; //labcomm version (2006 or 2014)
+    public final String verStr; // version suffix to append (currently _2006 and empty string)
+
+    public final String qualid;
+    public final String lcName;
+    public final String rawPrefix;
+    public final String prefix;
+    private int indent;
+    public final int depth;
+    private C_printer printer;
+    public final int nestedLevel;
+    private boolean rootIsPointer;
+    private int rootLevel;
+
+    public boolean versionHasMetaData() {
+      return version != 2006;
+    }
+
+    private C_env(String qualid, String lcName, String rawPrefix, 
+		  int indent, int depth, C_printer printer,
+                  int nestedLevel, int version)
+    {
+      this.version = version;
+      this.verStr = LabCommVersion.versionString(version);
+      this.qualid = qualid;
+      this.lcName = lcName;
+      this.rawPrefix = rawPrefix;
+      if (rawPrefix == null) {
+        System.err.println("WARNING: prefix==null");
+        this.prefix = ""; 
+      } else if (rawPrefix.equals("")) {
+        this.prefix = rawPrefix;
+      } else {
+        this.prefix = rawPrefix + "_";
+      }
+      this.indent = indent;
+      this.depth = depth;
+      this.printer = printer;
+      this.nestedLevel = nestedLevel;
+    }
+
+    public C_env(String qualid, String lcName, String rawPrefix,
+		 PrintStream out, int version)
+    {
+      this(qualid, lcName, rawPrefix, 0, 0, new C_printer(out), 0, version);
+    }
+
+    public C_env(String qualid, String lcName, String rawPrefix,
+		 int indent, int depth, C_printer printer, int version) {
+            this(qualid, lcName, rawPrefix, indent, depth, printer, 0, version);
+    }
+
+    public C_env nestArray(String suffix) {
+      return new C_env(qualid + suffix, lcName, rawPrefix,
+		       indent, depth + 1, printer, nestedLevel + 1, version);
+    }
+
+    public C_env nestStruct(String suffix) {
+      return new C_env(qualid + suffix, lcName, rawPrefix, 
+		       indent, depth, printer, nestedLevel + 1, version);
+    }
+
+    public void indent() {
+      indent++;
+    }
+
+    public void unindent() {
+      indent--;
+    }
+
+    public String prefix() {
+      return rawPrefix;
+    }
+
+    public void print(String s) {
+      printer.print(this, s);
+    }
+
+    public void println() {
+      printer.println(this, "");
+    }
+
+    public void println(String s) {
+      printer.println(this, s);
+    }
+
+    public C_env setPointer() {
+      rootIsPointer = true;
+      rootLevel = nestedLevel;
+      return this;
+    }
+
+    public String memberAccessor() {
+      return (rootIsPointer && (nestedLevel == rootLevel)) ? "->" : ".";
+    }
+
+    public String accessor() {
+      return (rootIsPointer && (nestedLevel == rootLevel)) ? "*" : "";
+    }
+  }
+
+  public C_env ArrayType.C_Nest(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_Nest(C_env env)" + 
+		    " not declared");
+  }
+
+  public C_env FixedArrayType.C_Nest(C_env env) {
+    String index = env.memberAccessor() + "a";
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      index += "[i_" + env.depth + "_" + i + "]";
+    }
+    return env.nestArray(index);
+  }
+
+  public C_env VariableArrayType.C_Nest(C_env env) {
+    return env.nestArray(env.memberAccessor() + "a[i_" + env.depth + "]");
+  }
+
+
+}
+
+aspect C_IsDynamic {
+  
+  // Determine if a type has dynamically allocated data
+  syn boolean Decl.C_isDynamic() = getType().C_isDynamic();
+  syn boolean Type.C_isDynamic() = false;
+  syn boolean PrimType.C_isDynamic() = getToken() == LABCOMM_STRING;
+  syn boolean UserType.C_isDynamic() = 
+    lookupType(getName()).getType().C_isDynamic();
+  syn boolean StructType.C_isDynamic() {
+    for (int i = 0 ; i < getNumField() ; i++) {
+      if (getField(i).getType().C_isDynamic()) {
+	return true;
+      }
+    }
+    return false;
+  }
+  syn boolean FixedArrayType.C_isDynamic() = getType().C_isDynamic();
+  syn boolean VariableArrayType.C_isDynamic() = true;
+}
+
+aspect C_CodeGen {
+
+  public void Program.C_genH(PrintStream out, Vector includes, 
+			     String lcName, String prefix, int version) {
+    C_env env = new C_env("", lcName, prefix, out, version);
+
+    // Hackish prettyprint preamble
+    out.println("/* LabComm declarations:");
+    pp(out);
+    out.println("*/");
+    env.println("");
+    env.println("");
+    env.println("#ifndef __LABCOMM_" + env.lcName + "_H__"); 
+    env.println("#define __LABCOMM_" + env.lcName + "_H__");
+    env.println("");
+
+    // Include
+    env.println("#include \"labcomm"+env.verStr+".h\"");
+    for (int i = 0 ; i < includes.size() ; i++) {
+      env.println("#include \"" + includes.get(i) + "\"");
+    }
+    env.println("");
+
+    C_emitH(env);
+
+    env.println("#endif");
+  }
+
+  public void Program.C_genC(PrintStream out, Vector includes, 
+			     String lcName, String prefix, int version) {
+    C_env env = new C_env("", lcName, prefix, out, version);
+
+    // Include
+    env.println("#include \"labcomm"+env.verStr+".h\"");
+    env.println("#include \"labcomm"+env.verStr+"_private.h\"");
+    for (int i = 0 ; i < includes.size() ; i++) {
+      env.println("#include \"" + includes.get(i) + "\"");
+    }
+    env.println("");
+    
+    // Method Implementations
+    C_emitC(env);
+  }
+
+  public void Program.C_emitH(C_env env) {
+    for (int i = 0; i < getNumDecl(); i++) {
+      getDecl(i).C_emitType(env);
+      getDecl(i).C_emitDecoderDeclaration(env);
+      getDecl(i).C_emitEncoderDeclaration(env);
+      getDecl(i).C_emitSizeofDeclaration(env);
+      getDecl(i).C_emitCopyDeclaration(env);
+      getDecl(i).C_emitCopyDeallocationDeclaration(env);
+      env.println("");
+    }
+    C_emitConstructorDeclaration(env);
+    C_emitForAll(env);
+  }
+
+  public void Program.C_emitC(C_env env) {
+    for (int i = 0; i < getNumDecl(); i++) {
+      getDecl(i).C_emitSignature(env);
+      getDecl(i).C_emitDecoder(env);
+      getDecl(i).C_emitDecoderRegisterHandler(env);
+      getDecl(i).C_emitDecoderIoctl(env);
+      getDecl(i).C_emitEncoder(env);
+      getDecl(i).C_emitEncoderRegisterHandler(env);
+      getDecl(i).C_emitEncoderIoctl(env);
+      getDecl(i).C_emitSizeof(env);
+      getDecl(i).C_emitCopy(env);
+      getDecl(i).C_emitCopyDeallocation(env);
+    }
+    C_emitConstructor(env);
+  }
+ 
+}
+
+aspect C_Common {
+
+  public void ArrayType.C_emitLoopVariables(C_env env) {
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      env.println("int i_" + env.depth + "_" + i + ";");
+    }
+  }
+
+}
+
+aspect C_Type {
+
+  public void Decl.C_emitType(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitType(C_env env)" + 
+		    " not declared");
+  }
+
+  public void TypeDecl.C_emitType(C_env env) {
+    env.println("#ifndef PREDEFINED_" + env.prefix + getName());
+    env.print("typedef ");
+    getType().C_emitType(env, env.prefix + getName());
+    env.println(";");
+    env.println("#endif");
+  }
+
+  public void SampleDecl.C_emitType(C_env env) {
+    env.println("#ifndef PREDEFINED_" + env.prefix + getName());
+    env.print("typedef ");
+    getType().C_emitType(env, env.prefix + getName());
+    env.println(";");
+    env.println("#endif");
+    env.println("extern const struct labcomm"+env.verStr+"_signature " +
+                "*labcomm"+env.verStr+"_signature_" + env.prefix + getName() + 
+                ";");
+  }
+
+  public void Type.C_emitType(C_env env, String name) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitType(C_env env, String name)" + 
+		    " not declared");
+  }
+
+  public void VoidType.C_emitType(C_env env, String name) {
+    env.print("char " + name);
+  }
+
+  public void PrimType.C_emitType(C_env env, String name) {
+    switch (getToken()) {
+      case LABCOMM_BOOLEAN: { env.print("uint8_t"); } break;
+      case LABCOMM_BYTE: { env.print("uint8_t"); } break;
+      case LABCOMM_SHORT: { env.print("int16_t"); } break;
+      case LABCOMM_INT: { env.print("int32_t"); } break;
+      case LABCOMM_LONG: { env.print("int64_t"); } break;
+      case LABCOMM_FLOAT: { env.print("float"); } break;
+      case LABCOMM_DOUBLE: { env.print("double"); } break;
+      case LABCOMM_STRING: { env.print("char*"); } break;
+      case LABCOMM_SAMPLE: { 
+        env.print("const struct labcomm_signature *"); 
+      } break;
+    }
+    env.print(" " + name);
+  }
+
+  public void UserType.C_emitType(C_env env, String name) {
+    env.print(env.prefix + getName() + " " + name);
+  }
+
+  public void StructType.C_emitType(C_env env, String name) {
+    env.println("struct {");
+    env.indent();
+    for (int i = 0 ; i < getNumField() ; i++) {
+      getField(i).C_emitType(env);
+      env.println(";");
+    }
+    env.unindent();
+    env.print("} " + name);
+  }
+
+  public void Field.C_emitType(C_env env) {
+    getType().C_emitType(env, getName());
+  }
+
+  public void FixedArrayType.C_emitType(C_env env, String name) {
+    env.println("struct {");
+    env.indent();
+    StringBuffer index = new StringBuffer("a");
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      index.append("[" + getExp(i).C_getValue() + "]");
+    }
+    getType().C_emitType(env, index.toString());
+    env.println(";");
+    env.unindent();
+    env.print("} " + name);
+  }
+
+  public void VariableArrayType.C_emitType(C_env env, String name) {
+    env.println("struct {");
+    env.indent();
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      if (getExp(i) instanceof VariableSize) {
+	env.println("int n_" + i + ";");
+      } else {
+	env.println("// n_" + i + "=" + getExp(i).C_getValue());
+      }
+    }
+    getType().C_emitType(env, "*a");
+    env.println(";");
+    env.unindent();
+    env.print("} " + name);
+  }
+
+  public String Exp.C_getValue() {
+   throw new Error(this.getClass().getName() + 
+		    ".C_getValue()" + 
+		    " not declared");
+  }
+
+  public String IntegerLiteral.C_getValue() {
+    return getValue();
+  }
+
+}
+
+aspect C_Declarations {
+
+  public void Decl.C_emitDecoderDeclaration(C_env env) {
+  }
+
+  public void SampleDecl.C_emitDecoderDeclaration(C_env env) {
+    env.println("int labcomm"+env.verStr+"_decoder_register_" + 
+		env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm"+env.verStr+"_decoder *d,");
+    env.println("void (*handler)(");
+    env.indent();
+    env.println(env.prefix + getName() + " *v,");
+    env.println("void *context");
+    env.unindent();
+    env.println("),");
+    env.println("void *context");
+    env.unindent();
+    env.println(");");
+
+    env.println("int labcomm"+env.verStr+"_decoder_ioctl_" + env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm"+env.verStr+"_decoder *d,");
+    env.println("int ioctl_action,");
+    env.println("...");
+    env.unindent();
+    env.println(");");
+  }
+  
+  public void Decl.C_emitEncoderDeclaration(C_env env) {
+  }
+//
+  public void SampleDecl.C_emitEncoderDeclaration(C_env env) {
+    env.println("int labcomm"+env.verStr+"_encoder_register_" + 
+		env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm"+env.verStr+"_encoder *e);");
+    env.unindent();
+
+    env.println("int labcomm"+env.verStr+"_encode_" + env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm"+env.verStr+"_encoder *e");
+    if(!isVoid() ) {
+        env.println(", "+env.prefix + getName() + " *v");
+    }
+    env.unindent();
+    env.println(");");
+
+    env.println("int labcomm"+env.verStr+"_encoder_ioctl_" + env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm"+env.verStr+"_encoder *e,");
+    env.println("int ioctl_action,");
+    env.println("...");
+    env.unindent();
+    env.println(");");
+  }
+
+}
+
+aspect C_Limit {
+
+  public String Exp.C_getLimit(C_env env, int i) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitDecoderLimit(C_env env, int i)" + 
+		    " not declared");
+  }
+
+  public String IntegerLiteral.C_getLimit(C_env env, int i) {
+    return getValue();
+  }
+
+  public String VariableSize.C_getLimit(C_env env, int i) {
+    return env.qualid + env.memberAccessor() + "n_" + i;
+  }
+  
+}
+
+aspect C_Index {
+
+  public void ArrayType.C_emitCalcIndex(C_env env) {
+  }
+
+  public void VariableArrayType.C_emitCalcIndex(C_env env) {
+    env.print("int i_" + env.depth + " = ");
+
+    String i_prefix = "i_" + env.depth + "_";
+    String expr = i_prefix + "0";
+    for (int i = 1 ; i < getNumExp() ; i++) {
+      expr = "(" + expr + ") * " +
+	getExp(i).C_getLimit(env, i) + " + " + 
+	i_prefix + i;
+    }
+    env.println(expr + ";");
+  }
+
+}
+
+aspect C_Decoder {
+
+  public void Decl.C_emitDecoder(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitDecoder(C_env env)" + 
+		    " not declared");
+  }
+
+  public void TypeDecl.C_emitDecoder(C_env env) {
+  }
+
+  public void SampleDecl.C_emitDecoder(C_env env) {
+    env = env.nestStruct("v");
+    env.println("static void decode_" + env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm"+env.verStr+"_reader *r,");
+    env.println("void (*handle)(");
+    env.indent();
+    env.println(env.prefix + getName() + " *v,");
+    env.println("void *context");
+    env.unindent();
+    env.println("),");
+    env.println("void *context");
+    env.unindent();
+    env.println(")");
+    env.println("{");
+    env.indent();
+    env.println(env.prefix + getName() + " v;");
+    getType().C_emitDecoder(env);
+    env.println("handle(&v, context);");
+    if (C_isDynamic()) {
+      env.println("{");
+      env.indent();
+      getType().C_emitDecoderDeallocation(env);
+      env.unindent();
+      env.println("}");
+    }
+    env.unindent();
+    env.println("}");
+  }
+
+  public void Type.C_emitDecoder(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitDecoder(C_env env)" + 
+		    " not declared");
+  }
+
+  public void VoidType.C_emitDecoder(C_env env) {
+  }
+
+  public void PrimType.C_emitDecoder(C_env env) {
+    env.print(env.qualid + " = ");
+    switch (getToken()) {
+      case LABCOMM_SAMPLE: { 
+        env.println("labcomm_internal_decoder_index_to_signature(" +
+                    "r->decoder, labcomm"+env.verStr+"_read_int(r));");
+      } break;
+      default: {
+        env.println("labcomm"+env.verStr+"_read_" + getName() + "(r);");
+      }; break;
+    }
+  }
+
+  public void UserType.C_emitDecoder(C_env env) {
+    lookupType(getName()).getType().C_emitDecoder(env);
+  }
+
+  public void StructType.C_emitDecoder(C_env env) {
+    for (int i = 0 ; i < getNumField() ; i++) {
+      getField(i).C_emitDecoder(env);
+    }
+  }
+
+  public void ArrayType.C_emitDecoder(C_env env) {
+    C_emitDecoderDecodeLimit(env);
+    C_emitDecoderArrayAllocate(env);
+    env.println("{");
+    env.indent();
+    C_emitLoopVariables(env);
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      String iterator = "i_" + env.depth + "_" + i;
+      env.println("for (" + iterator + " = 0" +
+		  " ; " +
+		  iterator + " < " + getExp(i).C_getLimit(env, i) +
+		  " ; " +
+		  iterator + "++) {");
+      env.indent();
+    }
+    C_emitCalcIndex(env);
+    getType().C_emitDecoder(C_Nest(env));
+    for (int i = getNumExp() - 1 ; i >= 0 ; i--) {
+      env.unindent();
+      env.println("}");
+    }
+    env.unindent();
+    env.println("}");
+  }
+
+  public void Field.C_emitDecoder(C_env env) {
+    getType().C_emitDecoder(env.nestStruct("." + getName()));
+  }
+
+  public void Exp.C_emitDecoderDecodeLimit(C_env env, int i) {
+  }
+
+  public void VariableSize.C_emitDecoderDecodeLimit(C_env env, int i) {
+    env.println(env.qualid + ".n_" + i + " = labcomm"+env.verStr+"_read_packed32(r);");
+  }
+
+  public void ArrayType.C_emitDecoderDecodeLimit(C_env env) {
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      getExp(i).C_emitDecoderDecodeLimit(env, i);
+    }
+  }
+
+  public void ArrayType.C_emitDecoderArrayAllocate(C_env env) {
+  }
+
+  public void VariableArrayType.C_emitDecoderArrayAllocate(C_env env) {
+    env.print(env.qualid + 
+              ".a = labcomm"+env.verStr+"_memory_alloc(r->memory, 1, sizeof(" + 
+	      env.qualid + ".a[0])");
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      env.print(" * " + getExp(i).C_getLimit(env, i));
+    }
+    env.println(");");
+  }
+
+  // Code for deallocation of dynamically allocated data 
+
+  public void Type.C_emitDecoderDeallocation(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitDecoderDeallocation(C_env env)" + 
+		    " not declared");
+  }
+
+  public void PrimType.C_emitDecoderDeallocation(C_env env) {
+    if (C_isDynamic()) {
+      env.println("labcomm"+env.verStr+"_memory_free(r->memory, 1, " + 
+                  env.qualid + ");");
+    }
+  }
+
+  public void UserType.C_emitDecoderDeallocation(C_env env) {
+    if (C_isDynamic()) {
+      lookupType(getName()).getType().C_emitDecoderDeallocation(env);
+    }
+  }
+
+  public void StructType.C_emitDecoderDeallocation(C_env env) {
+    if (C_isDynamic()) {
+      for (int i = 0 ; i < getNumField() ; i++) {
+	getField(i).C_emitDecoderDeallocation(env);
+      }
+    }
+  }
+
+  public void ArrayType.C_emitDecoderDeallocation(C_env env) {
+    if (getType().C_isDynamic()) {
+      env.println("{");
+      env.indent();
+      C_emitLoopVariables(env);
+      for (int i = 0 ; i < getNumExp() ; i++) {
+	String iterator = "i_" + env.depth + "_" + i;
+	env.println("for (" + iterator + " = 0" +
+		    " ; " +
+		    iterator + " < " + getExp(i).C_getLimit(env, i) +
+		    " ; " +
+		    iterator + "++) {");
+	env.indent();
+      }
+      C_emitCalcIndex(env);
+      getType().C_emitDecoderDeallocation(C_Nest(env));
+      for (int i = 0 ; i < getNumExp() ; i++) {
+	env.unindent();
+	env.println("}");
+      }
+      env.unindent();
+      env.println("}");
+    }
+  }
+
+  public void VariableArrayType.C_emitDecoderDeallocation(C_env env) {
+    super.C_emitDecoderDeallocation(env);
+    env.println("labcomm"+env.verStr+"_memory_free(r->memory, 1, " + 
+                env.qualid + ".a);");
+  }
+
+  public void Field.C_emitDecoderDeallocation(C_env env) {
+    getType().C_emitDecoderDeallocation(env.nestStruct("." + getName()));
+  }
+
+  public void Decl.C_emitDecoderRegisterHandler(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitDecoderRegisterHandler(C_env env)" + 
+		    " not declared");
+  }
+
+  public void TypeDecl.C_emitDecoderRegisterHandler(C_env env) {
+  }
+
+  public void SampleDecl.C_emitDecoderRegisterHandler(C_env env) {
+    env.println("int labcomm"+env.verStr+"_decoder_register_" + 
+		env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm"+env.verStr+"_decoder *d,");
+    env.println("void (*handler)(");
+    env.indent();
+    env.println(env.prefix + getName() + " *v,");
+    env.println("void *context");
+    env.unindent();
+    env.println("),");
+    env.println("void *context");
+    env.unindent();
+    env.println(")");
+    env.println("{");
+    env.indent();
+    env.println("return labcomm"+env.verStr+"_internal_decoder_register(");
+    env.indent();
+    env.println("d,");
+    env.println("&signature_" + env.prefix + getName() + ",");
+    env.println("(labcomm"+env.verStr+"_decoder_function)decode_" + env.prefix + getName() + ",");
+    env.println("(labcomm"+env.verStr+"_handler_function)handler,");
+    env.println("context");
+    env.unindent();
+    env.println(");");
+    env.unindent();
+    env.println("}");
+  }
+
+}
+
+aspect C_copy {
+
+  private void SampleDecl.C_emitCopyFunctionParam(C_env env, String src,
+						  String dst)
+  {
+    env.println("void labcomm" + env.verStr + "_copy_" +
+                env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm" + env.verStr + "_memory *mem,");
+    env.println(env.prefix + getName() + " *" + dst + ",");
+    env.println(env.prefix + getName() + " *" + src);
+    env.unindent();
+    env.print(")");
+  }
+
+  public void Decl.C_emitCopyDeclaration(C_env env) {
+  }
+
+  public void SampleDecl.C_emitCopyDeclaration(C_env env) {
+    C_emitCopyFunctionParam(env, "src", "dst");
+    env.println(";");
+  }
+
+  public void Decl.C_emitCopy(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitCopy(C_env env)" + 
+		    " not declared");
+  }
+
+  public void TypeDecl.C_emitCopy(C_env env) {
+  }
+
+  public void SampleDecl.C_emitCopy(C_env env) {
+    final String dst = "dst";
+    final String src = "src";
+    C_env env_src = env.nestStruct(src).setPointer();
+    C_env env_dst = env.nestStruct(dst).setPointer();
+
+    C_emitCopyFunctionParam(env_src, src, dst);
+    env_src.println("");
+    env_src.println("{");
+    env_src.indent();
+    getType().C_emitCopy(env_src, env_dst);
+    env_src.unindent();
+    env_src.println("}");
+  }
+
+  public void Type.C_emitCopy(C_env env_src, C_env env_dst) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitCopy(C_env env)" + 
+		    " not declared");
+  }
+
+  public void VoidType.C_emitCopy(C_env env_src, C_env env_dst) {
+  }
+
+  public void PrimType.C_emitCopy(C_env env_src, C_env env_dst) {
+    if (C_isDynamic()) {
+      env_src.println(String.format(
+	  "%s%s = labcomm%s_memory_alloc(mem, 1, strlen(%s%s)+1);",
+	  env_dst.accessor(), env_dst.qualid,
+          env_src.verStr,
+	  env_src.accessor(), env_src.qualid));
+      env_src.println(String.format(
+	  "memcpy(%s%s, %s%s, strlen(%s%s)+1);",
+	  env_dst.accessor(), env_dst.qualid,
+	  env_src.accessor(), env_src.qualid,
+	  env_src.accessor(), env_src.qualid));
+    } else {
+      env_src.println(env_dst.accessor() + env_dst.qualid + " = " +
+		      env_src.accessor() + env_src.qualid + ";");
+    }
+  }
+
+  public void UserType.C_emitCopy(C_env env_src, C_env env_dst) {
+    lookupType(getName()).getType().C_emitCopy(env_src, env_dst);
+  }
+
+  public void StructType.C_emitCopy(C_env env_src, C_env env_dst) {
+    for (int i = 0 ; i < getNumField() ; i++) {
+      getField(i).C_emitCopy(env_src, env_dst);
+    }
+  }
+
+  public void ArrayType.C_emitCopy(C_env env_src, C_env env_dst) {
+    C_emitCopyDecodeLimit(env_src, env_dst);
+    C_emitCopyArrayAllocate(env_src, env_dst);
+    env_src.println("{");
+    env_src.indent();
+    C_emitLoopVariables(env_src);
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      String iterator = "i_" + env_src.depth + "_" + i;
+      env_src.println("for (" + iterator + " = 0" +
+		  " ; " +
+		  iterator + " < " + getExp(i).C_getLimit(env_src, i) +
+		  " ; " +
+		  iterator + "++) {");
+      env_src.indent();
+    }
+    C_emitCalcIndex(env_src);
+    getType().C_emitCopy(C_Nest(env_src), C_Nest(env_dst));
+    for (int i = getNumExp() - 1 ; i >= 0 ; i--) {
+      env_src.unindent();
+      env_src.println("}");
+    }
+    env_src.unindent();
+    env_src.println("}");
+  }
+
+  public void Field.C_emitCopy(C_env env_src, C_env env_dst) {
+    String fnam = env_src.memberAccessor() + getName();
+    getType().C_emitCopy(env_src.nestStruct(fnam), env_dst.nestStruct(fnam));
+  }
+
+  public void Exp.C_emitCopyDecodeLimit(C_env env_src, C_env env_dst, int i) {
+    // Ordinary array has no length-member.
+  }
+
+  public void VariableSize.C_emitCopyDecodeLimit(C_env env_src, C_env env_dst, int i) {
+    String src = env_src.qualid + env_src.memberAccessor() + "n_" + i;
+    String dst = env_dst.qualid + env_dst.memberAccessor() + "n_" + i;
+    env_src.println(dst + " = " + src + ";");
+  }
+
+  public void ArrayType.C_emitCopyDecodeLimit(C_env env_src, C_env env_dst) {
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      getExp(i).C_emitCopyDecodeLimit(env_src, env_dst, i);
+    }
+  }
+
+  public void ArrayType.C_emitCopyArrayAllocate(C_env env_src, C_env env_dst) {
+  }
+
+  public void VariableArrayType.C_emitCopyArrayAllocate(C_env env_src,
+							C_env env_dst)
+  {
+    env_src.print(env_dst.qualid + env_dst.memberAccessor() +
+                  "a = labcomm" + env_src.verStr +
+                  "_memory_alloc(mem, 1, sizeof(" +
+		  env_src.qualid + env_src.memberAccessor() + "a[0])");
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      env_src.print(" * " + getExp(i).C_getLimit(env_src, i));
+    }
+    env_dst.println(");");
+  }
+
+  // Code for deallocation of dynamically allocated data in a copy.
+
+  private void SampleDecl.C_emitCopyDeallocationFunctionParam(C_env env,
+							      String par)
+  {
+    env.println("void labcomm" + env.verStr + "_copy_free_" +
+                env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm" + env.verStr + "_memory *mem,");
+    env.println(env.prefix + getName() + " *" + par);
+    env.unindent();
+    env.print(")");
+  }
+
+  public void Decl.C_emitCopyDeallocationDeclaration(C_env env) {
+  }
+
+  public void SampleDecl.C_emitCopyDeallocationDeclaration(C_env env) {
+    C_emitCopyDeallocationFunctionParam(env, "c");
+    env.println(";");
+  }
+
+  public void Decl.C_emitCopyDeallocation(C_env env) {
+    throw new Error(this.getClass().getName() +
+		    ".C_emitCopy(C_env env)" +
+		    " not declared");
+  }
+
+  public void TypeDecl.C_emitCopyDeallocation(C_env env) {
+  }
+
+  public void SampleDecl.C_emitCopyDeallocation(C_env env) {
+    String par = "par";
+    env = env.nestStruct(par).setPointer();
+
+    C_emitCopyDeallocationFunctionParam(env, par);
+    env.println("");
+    env.println("{");
+    env.indent();
+    getType().C_emitCopyDeallocation(env);
+    env.unindent();
+    env.println("}");
+  }
+
+  public void Type.C_emitCopyDeallocation(C_env env) {
+    throw new Error(this.getClass().getName() +
+  		    ".C_emitCopyDeallocation(C_env env)" +
+  		    " not declared");
+  }
+
+  public void VoidType.C_emitCopyDeallocation(C_env env) {
+  }
+
+  public void PrimType.C_emitCopyDeallocation(C_env env) {
+    if (C_isDynamic()) {
+      env.println("labcomm" + env.verStr + "_memory_free(mem, 1, " +
+                  env.accessor() + env.qualid + ");");
+    }
+  }
+
+  public void UserType.C_emitCopyDeallocation(C_env env) {
+    if (C_isDynamic()) {
+      lookupType(getName()).getType().C_emitCopyDeallocation(env);
+    }
+  }
+
+  public void StructType.C_emitCopyDeallocation(C_env env) {
+    if (C_isDynamic()) {
+      for (int i = 0 ; i < getNumField() ; i++) {
+  	getField(i).C_emitCopyDeallocation(env);
+      }
+    }
+  }
+
+  public void ArrayType.C_emitCopyDeallocation(C_env env) {
+    if (getType().C_isDynamic()) {
+      env.println("{");
+      env.indent();
+      C_emitLoopVariables(env);
+      for (int i = 0 ; i < getNumExp() ; i++) {
+  	String iterator = "i_" + env.depth + "_" + i;
+  	env.println("for (" + iterator + " = 0" +
+  		    " ; " +
+  		    iterator + " < " + getExp(i).C_getLimit(env, i) +
+  		    " ; " +
+  		    iterator + "++) {");
+  	env.indent();
+      }
+      C_emitCalcIndex(env);
+      getType().C_emitCopyDeallocation(C_Nest(env));
+      for (int i = 0 ; i < getNumExp() ; i++) {
+  	env.unindent();
+  	env.println("}");
+      }
+      env.unindent();
+      env.println("}");
+    }
+  }
+
+  public void VariableArrayType.C_emitCopyDeallocation(C_env env) {
+    super.C_emitCopyDeallocation(env);
+    env.println("labcomm" + env.verStr + "_memory_free(mem, 1, " +
+                env.qualid + env.memberAccessor() + "a);");
+  }
+
+  public void Field.C_emitCopyDeallocation(C_env env) {
+    getType().C_emitCopyDeallocation(env.nestStruct(env.memberAccessor()
+						    + getName()));
+  }
+}
+
+aspect C_DecoderIoctl {
+
+  public void Decl.C_emitDecoderIoctl(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitDecoderIoctl(C_env env)" + 
+		    " not declared");
+  }
+
+  public void TypeDecl.C_emitDecoderIoctl(C_env env) {
+  }
+
+  public void SampleDecl.C_emitDecoderIoctl(C_env env) {
+    env.println("int labcomm"+env.verStr+"_decoder_ioctl_" + env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm"+env.verStr+"_decoder *d,");
+    env.println("int ioctl_action,");
+    env.println("...");
+    env.unindent();
+    env.println(")");
+    env.println("{");
+    env.indent();
+    env.println("int result;");
+    env.println("va_list va;");
+    env.println("va_start(va, ioctl_action);");
+    env.println("result = labcomm"+env.verStr+"_internal_decoder_ioctl(");
+    env.indent();
+    env.println("d, &signature_" + env.prefix + getName() + ", ");
+    env.println("ioctl_action, va);");
+    env.unindent();
+    env.println("va_end(va);");
+    env.println("return result;");
+    env.unindent();
+    env.println("}");
+  }
+}
+
+
+aspect C_Encoder {
+
+  public void Decl.C_emitEncoder(C_env env) {
+    throw new Error(this.getClass().getName() + 
+        ".C_emitEncoder()" + 
+        " not declared");
+  }
+
+  public void TypeDecl.C_emitEncoder(C_env env) {
+    // do nothing for type decls
+  }
+
+  public void SampleDecl.C_emitEncoder(C_env env) {
+    env = env.nestStruct("(*v)");
+    env.println("static int encode_" + env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm"+env.verStr+"_writer *w");
+    if(!isVoid() ) {
+        env.println(", "+env.prefix + getName() + " *v");
+    }
+    env.unindent();
+    env.println(")");
+    env.println("{");
+    env.indent();
+    env.println("int result = 0;");
+    getType().C_emitEncoder(env);
+    env.println("return result;");
+    env.unindent();
+    env.println("}");
+
+    // Typesafe encode wrapper
+    env.println("int labcomm"+env.verStr+"_encode_" + env.prefix + getName() + "(");
+    env.println("struct labcomm"+env.verStr+"_encoder *e");
+    if(!isVoid() ) {
+        env.println(", "+env.prefix + getName() + " *v");
+    }
+    env.unindent();
+    env.println(")");
+    env.println("{");
+    env.indent();
+    env.println("return labcomm"+env.verStr+"_internal_encode(e, &signature_" + 
+		env.prefix + getName() + 
+		", (labcomm"+env.verStr+"_encoder_function)encode_" + 
+                env.prefix + getName() +
+		(!isVoid()?", v":", NULL")+");");
+    env.unindent();
+    env.println("}");
+  }
+
+  public void Type.C_emitEncoder(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitEncoder(C_env env)" + 
+		    " not declared");
+  }
+
+  public void VoidType.C_emitEncoder(C_env env) {
+    env.println("result = 0;");
+  }
+
+  public void PrimType.C_emitEncoder(C_env env) {
+    env.print("result = ");
+    switch (getToken()) {
+      case LABCOMM_SAMPLE: { 
+        env.println("labcomm"+env.verStr+"_write_int(w, " + 
+                    "labcomm_internal_encoder_signature_to_index(w->encoder, " +
+                    env.qualid + "));");
+      } break;
+      default: {
+        env.println("labcomm"+env.verStr+"_write_" + getName() + 
+                    "(w, " + env.qualid + ");");
+      } break;
+    }
+    env.println("if (result != 0) { return result; }");
+  }
+
+  public void UserType.C_emitEncoder(C_env env) {
+    decl().getType().C_emitEncoder(env);
+  }
+
+  public void StructType.C_emitEncoder(C_env env) {
+    for (int i = 0 ; i < getNumField() ; i++) {
+      getField(i).C_emitEncoder(env);
+    }
+  }
+
+  public void ArrayType.C_emitEncoder(C_env env) {
+    C_emitEncoderEncodeLimit(env);
+    env.println("{");
+    env.indent();
+    C_emitLoopVariables(env);
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      String iterator = "i_" + env.depth + "_" + i;
+      env.println("for (" + iterator + " = 0" +
+		  " ; " +
+		  iterator + " < " + getExp(i).C_getLimit(env, i) +
+		  " ; " +
+		  iterator + "++) {");
+      env.indent();
+    }
+    C_emitCalcIndex(env);
+    getType().C_emitEncoder(C_Nest(env));
+    for (int i = getNumExp() - 1 ; i >= 0 ; i--) {
+      env.unindent();
+      env.println("}");
+    }
+    env.unindent();
+    env.println("}");
+  }
+
+  public void Field.C_emitEncoder(C_env env) {
+    getType().C_emitEncoder(env.nestStruct("." + getName()));
+  }
+
+  public void Exp.C_emitEncoderEncodeLimit(C_env env, int i) {
+  }
+
+  public void VariableSize.C_emitEncoderEncodeLimit(C_env env, int i) {
+    env.println("labcomm"+env.verStr+"_write_packed32(w, " + env.qualid + ".n_" + i + ");");
+  }
+
+  public void ArrayType.C_emitEncoderEncodeLimit(C_env env) {
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      getExp(i).C_emitEncoderEncodeLimit(env, i);
+    }
+  }
+
+  public void Decl.C_emitEncoderRegisterHandler(C_env env) {
+    throw new Error(this.getClass().getName() + 
+  		    ".C_emitEncoderRegisterHandler(C_env env)" + 
+  		    " not declared");
+  }
+  
+  public void TypeDecl.C_emitEncoderRegisterHandler(C_env env) {
+    // do nothing for type decls
+  }
+  
+  public void SampleDecl.C_emitEncoderRegisterHandler(C_env env) {
+    env.println("int labcomm"+env.verStr+"_encoder_register_" + 
+		env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm"+env.verStr+"_encoder *e");
+    env.unindent();
+    env.println(")");
+    env.println("{");
+    env.indent();
+    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.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.unindent();
+    env.println("}");
+  }
+
+}
+
+aspect C_EncoderIoctl {
+
+  public void Decl.C_emitEncoderIoctl(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitEncoderIoctl()" + 
+		    " not declared");
+  }
+
+  public void TypeDecl.C_emitEncoderIoctl(C_env env) {
+  }
+
+  public void SampleDecl.C_emitEncoderIoctl(C_env env) {
+    env.println("int labcomm"+env.verStr+"_encoder_ioctl_" + env.prefix + getName() + "(");
+    env.indent();
+    env.println("struct labcomm"+env.verStr+"_encoder *e,");
+    env.println("int ioctl_action,");
+    env.println("...");
+    env.unindent();
+    env.println(")");
+    env.println("{");
+    env.indent();
+    env.println("int result;");
+    env.println("va_list va;");
+    env.println("va_start(va, ioctl_action);");
+    env.println("result = labcomm"+env.verStr+"_internal_encoder_ioctl(");
+    env.indent();
+    env.println("e, &signature_" + env.prefix + getName() + ", ");
+    env.println("ioctl_action, va);");
+    env.unindent();
+    env.println("va_end(va);");
+    env.println("return result;");
+    env.unindent();
+    env.println("}");
+  }
+
+}
+
+aspect C_TypeDependencies {
+  public void Decl.C_emitUserTypeDeps(C_env env, String via, boolean outputCode) {
+    if( hasDependencies() ) {
+        Iterator<Decl> it = type_dependencies().iterator();
+        while(it.hasNext()) {
+            Decl t = it.next();
+
+            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);");
+            } else {  // Just output a comment
+	        String refpath = (via == null) ? "directly" : "indirectly via "+via;
+	       env.println(" //Depends ("+refpath+") on "+t.getName() );
+            }
+        }
+    } 
+  }
+  public void Decl.C_emitUserTypeRefs(C_env env, String via, boolean outputCode) {
+    if( isReferenced() ) {
+        Iterator<Decl> it = type_references().iterator();
+        while(it.hasNext()) {
+            Decl t = it.next();
+
+            t.C_emitUserTypeRefs(env, t.getName(), outputCode);
+            if(outputCode) {
+               env.println("labcomm"+env.verStr+"_encoder_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() );
+            }
+        }
+    } 
+  }
+}
+
+aspect C_Signature {
+
+  public void ASTNode.C_emitSignature(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitSignature(C_env env)" + 
+		    " not declared");
+  }
+
+  syn String Decl.C_DeclTypeString();
+  eq SampleDecl.C_DeclTypeString() = "LABCOMM_SAMPLE";
+  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(env.versionHasMetaData()) { 
+//    if(isReferenced() || isSampleDecl()){
+//        env.println("(int (*)(void *))labcomm"+env.verStr+"_signature_" + 
+//	 	env.prefix + getName() + "_emit_signature");
+//    } else {
+//        env.println("NULL");  // HERE BE DRAGONS! Is it worth the size saving to skip emitting the emit_signature function for unused types?
+//                              //                  The code won't likely end up in a target system anyway?
+//    }
+//  }
+//  env.unindent();
+//  env.println(" };");
+//
+  }
+
+  public void ASTNode.C_emitFlatSignature(C_env env) {
+    throw new Error(this.getClass().getName() + 
+                    ".C_emitFlatSignature(C_env env)" + 
+                    " not declared");
+  }
+
+  public void Decl.C_emitFlatSignature(C_env env) {
+  }
+
+  public void SampleDecl.C_emitFlatSignature(C_env env){
+    env.println("static unsigned char signature_bytes_" + 
+  	        env.prefix + getName() + "[] = {");
+    SignatureList signature = flatSignature(env.version);
+    for (int i = 0 ; i < signature.size() ; i++) {
+      String comment = signature.getComment(i);
+      if (comment != null) {
+        env.println(signature.getIndent(i) + "// " + comment);
+      }
+      byte[] data = signature.getData(i, env.version);
+      if (data != null) {
+        env.print(signature.getIndent(i));
+        for (int j = 0 ; j < data.length ; j++) {
+          env.print(data[j] + ", ");
+        }
+        env.println("");
+      }
+    }
+    env.println("};");
+
+    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() + ",");
+    env.println("sizeof(signature_bytes_" + env.prefix + getName() + "),");
+    env.println("signature_bytes_" + env.prefix + getName() + ",");
+    env.println("0");
+    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 Signature.C_emitSignature(C_env env, boolean decl){
+      getSignatureList().C_emitSignature(env, decl);
+    }
+
+    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() +"),");
+    }
+
+    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("\"),");
+       // }
+    }
+//
+//
+//      byte[] data = getData(env.version);
+//        if (data != null) {
+//            for (int j = 0 ; j < data.length ; j++) {
+//                env.print(getIndentString());
+//                //env.print("printf(\"labcomm"+env.verStr+"_write_byte( w, (unsigned char)"+ String.format("0x%02X ", data[j]) +")\\n\"); ");
+//                env.print("labcomm"+env.verStr+"_write_byte( w, (unsigned char)"+ String.format("0x%02X ", data[j]) +"); ");
+//                env.println("if (result != 0) { return result; }");
+//            }
+//            env.println();
+//        }
+//
+//}
+  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();
+  }
+
+
+
+//  public void SampleDecl.C_emitSignature(C_env env) {
+//    env.println("static unsigned char signature_bytes_" + 
+//		       env.prefix + getName() + "[] = {");
+//    SignatureList signature = signature(env.version);
+//    for (int i = 0 ; i < signature.size() ; i++) {
+//      String comment = signature.getComment(i);
+//      if (comment != null) {
+//        env.println(signature.getIndent(i) + "// " + comment);
+//      }
+//      byte[] data = signature.getData(i);
+//      if (data != null) {
+//        env.print(signature.getIndent(i));
+//        for (int j = 0 ; j < data.length ; j++) {
+//          env.print(data[j] + ", ");
+//        }
+//        env.println("");
+//      }
+//    }
+//    env.println("};");
+//    env.println("struct labcomm"+env.verStr+"_signature labcomm"+env.verStr+"_signature_" + 
+//		env.prefix + getName() + " = {");
+//    env.indent();
+//    env.println("LABCOMM_SAMPLE, \"" + getName() + "\",");
+//    env.println("(int (*)(struct labcomm"+env.verStr+"_signature *, void *))labcomm"+env.verStr+"_sizeof_" + 
+//		env.prefix + getName() + ",");
+//    env.println("sizeof(signature_bytes_" + env.prefix + getName() + "),");
+//    env.println("signature_bytes_" + env.prefix + getName() + ",");
+//    env.println("0");
+//    env.unindent();
+//    env.println(" };");
+//  }
+
+}
+aspect C_Constructor {
+  public void ASTNode.C_emitConstructor(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitConstructor(C_env env)" + 
+		    " not declared");
+  }
+
+  public void Program.C_emitConstructor(C_env env) {
+    env.println("LABCOMM_CONSTRUCTOR void init_" +
+		env.prefix + "_signatures(void)");
+    env.println("{");
+    env.indent();
+    env.println("static int initialized = 0;");
+    env.println("if (initialized == 0) {");
+    env.indent();
+    env.println("initialized = 1;");
+    for (int i = 0; i < getNumDecl(); i++) {
+      getDecl(i).C_emitConstructor(env);
+    }
+    env.unindent();
+    env.println("}"); 
+    env.unindent();
+    env.println("}"); 
+  }
+
+  public void Decl.C_emitConstructor(C_env env) {
+  }
+//XXX
+  public void SampleDecl.C_emitConstructor(C_env env) {
+    env.println("labcomm"+env.verStr+"_set_local_index(&signature_" + 
+		env.prefix + getName() + ");");
+  }
+
+
+  public void ASTNode.C_emitConstructorDeclaration(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_emitConstructorDeclaration(C_env env)" + 
+		    " not declared");
+  }
+
+  public void Program.C_emitConstructorDeclaration(C_env env) {
+    env.println("void init_" + env.prefix + "_signatures(void);");
+  }
+
+}
+
+aspect C_Sizeof {
+ public void Decl.C_emitSizeofDeclaration(C_env env) {
+  }
+
+  public void SampleDecl.C_emitSizeofDeclaration(C_env env) {
+    env.println("extern int labcomm"+env.verStr+"_sizeof_" + env.prefix + getName() +
+        "(" + env.prefix + getName() + " *v);");
+  }
+
+  public int Decl.C_fixedSizeof() {
+    return getType().C_fixedSizeof();
+  }
+
+  public void Decl.C_emitSizeof(C_env env) {
+  }
+
+  public void SampleDecl.C_emitSizeof(C_env env) {
+    env = env.nestStruct("(*v)");
+    env.println("int labcomm"+env.verStr+"_sizeof_" + env.prefix + getName() +
+        "(" + env.prefix + getName() + " *v)");
+    env.println("{");
+    env.indent();
+    env.println("return labcomm"+env.verStr+"_internal_sizeof(" +
+                "&signature_" + env.prefix + getName() +
+                ", v);");
+    env.unindent();
+    env.println("}");
+  }
+
+  public int Type.C_fixedSizeof() {
+    throw new Error(this.getClass().getName() + 
+            ".C_fixedSizeof()" + 
+            " not declared");
+  }
+
+  public int VoidType.C_fixedSizeof() {
+    return 0;
+  }
+
+  public int PrimType.C_fixedSizeof() {
+    switch (getToken()) {
+      case LABCOMM_BOOLEAN: { return 1; } 
+      case LABCOMM_BYTE: { return 1; } 
+      case LABCOMM_SHORT: { return 2; } 
+      case LABCOMM_INT: { return 4; } 
+      case LABCOMM_LONG: { return 8; }
+      case LABCOMM_FLOAT: { return 4; }
+      case LABCOMM_DOUBLE: { return 8; }
+      case LABCOMM_SAMPLE: { return 4; }
+      default: { 
+    throw new Error(this.getClass().getName() + 
+            ".C_fixedSizeof()" + 
+            " unknown size (" + getName() + ")"); 
+      } 
+    }
+  }
+
+  public int UserType.C_fixedSizeof() {
+    return lookupType(getName()).getType().C_fixedSizeof();
+  }
+
+  public int StructType.C_fixedSizeof() {
+    int result = 0;
+    for (int i = 0 ; i < getNumField() ; i++) {
+      result += getField(i).getType().C_fixedSizeof();
+    }
+    return result;
+  }
+
+  public int ArrayType.C_fixedSizeof() {
+    int elements = 1;
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      int n = Integer.parseInt(((IntegerLiteral)getExp(i)).getValue());
+      elements = elements * n;
+    }
+    return getType().C_fixedSizeof() * elements;
+  }
+
+  public void Decl.C_emitSizeofValue(C_env env) {
+  }
+
+  public void SampleDecl.C_emitSizeofValue(C_env env) {
+    env = env.nestStruct("(*v)");
+    env.println("static int sizeof_" + env.prefix + getName() + "(void *vv)");
+    env.println("{");
+    env.indent();
+    env.println("int result = 0;");
+    if (C_isDynamic()) {
+      env.println(env.prefix + getName() + " *v = vv;");
+      getType().C_emitSizeof(env);
+    } else {
+      env.println("result += " + C_fixedSizeof() + ";");
+    }    
+    env.println("return result;");
+    env.unindent();
+    env.println("}");
+  }
+
+  public void Type.C_emitSizeof(C_env env) {
+    throw new Error(this.getClass().getName() + 
+            ".C_emitSizeof(C_env env)" + 
+            " not declared");
+  }
+
+  public void PrimType.C_emitSizeof(C_env env) {
+    switch (getToken()) {
+      case LABCOMM_STRING: { 
+        env.print("{ int l = strlen(" + env.qualid + "); ");
+    env.println("result += labcomm"+env.verStr+"_size_packed32(l) + l; }"); 
+      } break;
+      default: { 
+    throw new Error(this.getClass().getName() + 
+            ".C_emitSizeof(C_env env)" + 
+            " known size (" + getName() + ")"); 
+      } 
+    }
+  }
+
+  public void UserType.C_emitSizeof(C_env env) {
+    lookupType(getName()).getType().C_emitSizeof(env);
+  }
+
+  public void StructType.C_emitSizeof(C_env env) {
+    int fixed = 0;
+    for (int i = 0 ; i < getNumField() ; i++) {
+      if (getField(i).getType().C_isDynamic()) {
+    getField(i).getType().C_emitSizeof(
+      env.nestStruct("." + getField(i).getName()));
+      } else {
+    fixed += getField(i).getType().C_fixedSizeof();
+      }
+    }
+    if (fixed > 0) {
+      env.println("result += " + fixed + ";");
+    }
+  }
+
+  public void ArrayType.C_emitSizeof(C_env env) {
+    if (getType().C_isDynamic()) {
+      env.println("{");
+      env.indent();
+      C_emitLoopVariables(env);
+      for (int i = 0 ; i < getNumExp() ; i++) {
+    String iterator = "i_" + env.depth + "_" + i;
+    env.println("for (" + iterator + " = 0" +
+            " ; " +
+            iterator + " < " + getExp(i).C_getLimit(env, i) +
+            " ; " +
+            iterator + "++) {");
+    env.indent();
+      }
+      C_emitCalcIndex(env);
+      getType().C_emitSizeof(C_Nest(env));
+      for (int i = 0 ; i < getNumExp() ; i++) {
+    env.unindent();
+    env.println("}");
+      }
+      env.unindent();
+      env.println("}");
+    } else {
+      for (int i = 0 ; i < getNumExp() ; i++) {
+        env.println("result += labcomm"+env.verStr+"_size_packed32(" + 
+                getExp(i).C_getLimit(env, i) + ");");
+      }
+      env.print("result += " + getType().C_fixedSizeof());
+      for (int i = 0 ; i < getNumExp() ; i++) {
+    env.print(" * " + getExp(i).C_getLimit(env, i));
+      }
+      env.println(";");      
+    }
+  }
+}
+
+aspect C_forAll {
+
+  public void Program.C_emitForAll(C_env env) {
+    env.print("#define LABCOMM_FORALL_SAMPLES_" + env.lcName + 
+		"(func, sep)");
+    env.indent();
+    boolean needSeparator = false;
+    for (int i = 0; i < getNumDecl(); i++) {
+      String s = getDecl(i).C_forAll(env);
+      if (s != null) {
+	if (needSeparator) { env.print(" sep"); }
+	env.println(" \\");
+	env.print(s);
+	needSeparator = true;
+      }
+    }
+    env.println("");
+    env.unindent();
+  }
+  
+  public String Decl.C_forAll(C_env env) {
+    return null;
+  }
+
+  public String SampleDecl.C_forAll(C_env env) {
+    return "func(" + getName() + ", " + env.prefix + getName() + ")";
+  }
+
+}
+
+aspect C_Info {
+
+  public void Program.C_info(PrintStream out, String prefix, int version) {
+    C_env env = new C_env("", "", prefix, out, version);
+    for (int i = 0; i < getNumDecl(); i++) {
+      getDecl(i).C_info(env);
+    }
+  }
+
+  public void Decl.C_info(C_env env) {
+    throw new Error(this.getClass().getName() + 
+		    ".C_info((C_env env)" + 
+		    " not declared");
+  }
+
+  public void TypeDecl.C_info(C_env env) {
+    env.println(",C,typedef," + env.prefix + getName() + "," + 
+                 env.prefix + getName() + "," +
+                 C_info_type_or_void(env.prefix));
+  }
+
+  public void SampleDecl.C_info(C_env env) {
+    env.println(",C,sample," + env.prefix + getName() + "," + 
+                 env.prefix + getName() + "," +
+                 C_info_type_or_void(env.prefix));
+  }
+
+  // make void types explicitly as they require special treatment
+  // in encoder/decoder calls
+  protected String Decl.C_info_type_or_void(String prefix) {
+    if(isVoid() ) {
+      return "void";
+    } else {
+      return prefix + getName() ;
+    }
+  }
+}
diff --git a/compiler/2014/DeclNames.jrag b/compiler/2014/DeclNames.jrag
new file mode 100644
index 0000000..042739b
--- /dev/null
+++ b/compiler/2014/DeclNames.jrag
@@ -0,0 +1,14 @@
+aspect DeclNames {
+	inh String Type.declName();
+	eq Decl.getType().declName() = getName();
+
+	inh String Field.declName();
+	eq StructType.getField(int i).declName() = declName();
+    
+        //TODO: aspect should be renamed to parent-something
+
+        inh Decl Type.parentDecl();
+        inh Decl Field.parentDecl();
+        eq Decl.getType().parentDecl() = this;
+        eq StructType.getField(int i).parentDecl() = parentDecl();
+}
diff --git a/compiler/2014/ErrorCheck.jrag b/compiler/2014/ErrorCheck.jrag
new file mode 100644
index 0000000..caa8081
--- /dev/null
+++ b/compiler/2014/ErrorCheck.jrag
@@ -0,0 +1,31 @@
+import java.util.Collection;
+
+aspect ErrorCheck {
+
+	syn int ASTNode.lineNumber() = getLine(getStart());
+
+	protected String ASTNode.errors = null;
+	
+	protected void ASTNode.error(String s) {
+	    s = "Error at " + lineNumber() + ": " + s;
+	    if(errors == null) {
+	      errors = s;
+	    } else {
+	      errors = errors + "\n" + s;
+	    }
+	}
+
+	protected boolean ASTNode.hasErrors() {
+		return errors != null;
+	}
+	public void ASTNode.errorCheck(Collection collection) {
+	    nameCheck();
+            typeCheck();
+	    if(hasErrors())
+		collection.add(errors);
+	    for(int i = 0; i < getNumChild(); i++) {
+		getChild(i).errorCheck(collection);
+	    }
+	}
+
+}
diff --git a/compiler/2014/FlatSignature.jrag b/compiler/2014/FlatSignature.jrag
new file mode 100644
index 0000000..2a9ca4d
--- /dev/null
+++ b/compiler/2014/FlatSignature.jrag
@@ -0,0 +1,123 @@
+import java.util.*;
+
+aspect FlatSignature {  
+
+  public SignatureList Decl.flatSignature(int version) {
+    SignatureList result = getSignature().getFlatSignatureList();
+    return result;
+  }
+  
+  public void ASTNode.flatSignature(SignatureList list) {
+    throw new Error(this.getClass().getName() + 
+                    ".flatSignature(SignatureList list)" + 
+                    " not declared");
+  }
+
+  public void TypeDecl.flatSignature(SignatureList list) {
+    getType().flatSignature(list);
+  }
+
+  public void SampleDecl.flatSignature(SignatureList list) {
+    getType().flatSignature(list);
+  }
+
+  public void SampleRefType.flatSignature(SignatureList list) {
+    list.addInt(LABCOMM_SAMPLE_REF, "sample");
+  }
+
+  public void VoidType.flatSignature(SignatureList list) {
+    list.addInt(LABCOMM_STRUCT, "void");
+    list.addInt(0, null);
+  }
+
+  public void PrimType.flatSignature(SignatureList list) {
+    list.addInt(getToken(), null);
+  }
+
+  public void UserType.flatSignature(SignatureList list) {
+    lookupType(getName()).flatSignature(list);
+  }
+
+  public void ArrayType.flatSignature(SignatureList list) {
+    list.addInt(LABCOMM_ARRAY, signatureComment());
+    list.indent();
+    list.addInt(getNumExp(), null);
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      getExp(i).flatSignature(list);
+    }
+    getType().flatSignature(list);
+    list.unindent();
+    list.add(null, "}");
+  }
+
+  public void StructType.flatSignature(SignatureList list) {
+    list.addInt(LABCOMM_STRUCT, "struct { " + getNumField() + " fields");
+    list.indent();
+    list.addInt(getNumField(), null);
+    for (int i = 0 ; i < getNumField() ; i++) {
+      getField(i).flatSignature(list);
+    }
+    list.unindent();
+    list.add(null, "}");
+  }
+
+  public void Field.flatSignature(SignatureList list) {
+    list.addString(getName(), signatureComment());
+    getType().flatSignature(list);
+  }
+
+  public void IntegerLiteral.flatSignature(SignatureList list) {
+    list.addInt(Integer.parseInt(getValue()), null);
+  }
+
+  public void VariableSize.flatSignature(SignatureList list) {
+    list.addInt(0, null);
+  }
+
+  public String ArrayType.signatureComment() {
+    StringBuffer result = new StringBuffer("array [");
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      if (i > 0) {
+	result.append(", ");
+      }
+      result.append(getExp(i).signatureComment());
+    }
+    result.append("]");
+    return result.toString();
+  }
+
+  public String ASTNode.signatureComment() {
+    throw new Error(this.getClass().getName() + 
+                    ".signatureComment()" + 
+                    " not declared");
+  }
+
+  public String Field.signatureComment() {
+    return getType().signatureComment() + " '" + getName() +"'";
+  }
+
+  public String SampleRefType.signatureComment() {
+    return "sample";
+  }
+
+  public String PrimType.signatureComment() {
+    return getName();
+  }
+
+  public String UserType.signatureComment() {
+    return getName();
+  }
+
+  public String StructType.signatureComment() {
+    return "struct";
+  }
+
+  public String IntegerLiteral.signatureComment() {
+    return getValue();
+  }
+
+  public String VariableSize.signatureComment() {
+    return "_";
+  }
+
+}
diff --git a/compiler/2014/Java_CodeGen.jrag b/compiler/2014/Java_CodeGen.jrag
new file mode 100644
index 0000000..478a0ac
--- /dev/null
+++ b/compiler/2014/Java_CodeGen.jrag
@@ -0,0 +1,1056 @@
+import java.io.*;
+import java.util.*;
+
+aspect Java_CodeGenEnv {
+
+  // Environment wrapper for Java-code generation
+  // handles indentation, file writing,
+
+  public class Java_env {
+
+    public final int version;  //labcomm version to generate code for
+    public final String verStr;
+    private int indent;
+    private int depth;
+    private Java_printer printer;
+    private HashMap unique = new HashMap();
+
+    final private class Java_printer {
+
+      private boolean newline = true;
+      private File file;
+      private PrintStream out;
+      private IOException exception;
+
+
+      public Java_printer(File f) {
+  	file = f;
+        File parentFile = f.getParentFile();
+        if(parentFile != null) {
+            parentFile.mkdirs();
+        }
+      }
+
+     public Java_printer(PrintStream out) {
+        this.out = out;
+      }
+
+      public void close() throws IOException {
+	if (out != null) {
+  	  out.close();
+        }
+	if (exception != null) {
+	  throw exception;
+        }
+      }
+
+      public PrintStream getPrintStream() {
+	return(out);
+      }
+
+      public void checkOpen() {
+	if (out == null && exception == null) {
+          try {
+    	    out = new PrintStream(new FileOutputStream(file));
+          } catch (IOException e) {
+	    exception = e;
+          }
+        }
+      }
+
+      public void print(Java_env env, String s) {
+	checkOpen();
+        if (newline) {
+          newline = false;
+          for (int i = 0 ; i < env.indent ; i++) {
+            out.print("  ");
+          }
+        }
+        out.print(s);
+      }
+
+      public void println(Java_env env, String s) {
+	checkOpen();
+        print(env, s);
+        out.println();
+        newline = true;
+      }
+    }
+
+    private Java_env(int version, int indent) {
+      this.version = version;
+      this.verStr = LabCommVersion.versionString(version);
+      this.indent = indent;
+    }
+
+    private Java_env(int version, Java_printer printer) {
+      this(version, 0);
+      this.printer = printer;
+    }
+
+    public Java_env(int version, File f) {
+      this(version, 0);
+      this.printer = new Java_printer(f);
+    }
+
+    public Java_env(int version, PrintStream out) {
+      this(version, 0);
+      this.printer = new Java_printer(out);
+    }
+
+    public void close() throws IOException {
+      printer.close();
+    }
+
+    public PrintStream getPrintStream() {
+      return printer.getPrintStream();
+    }
+    public void indent(int amount) {
+      indent += amount;
+    }
+
+    public void indent() {
+      indent(1);
+    }
+
+    public void unindent(int amount) {
+      indent -= amount;
+    }
+
+    public void unindent() {
+      unindent(1);
+    }
+
+    public void print(String s) {
+      printer.print(this, s);
+    }
+
+    public void println(String s) {
+      printer.println(this, s);
+    }
+
+    public void println() {
+      printer.println(this, "");
+    }
+
+    public int getDepth() {
+      return depth;
+    }
+
+    public String print_for_begin(String limit) {
+      print("for (int i_" + depth + " = 0 ; ");
+      print("i_" + depth + " < " + limit + " ; ");
+      println("i_" + depth + "++) {");
+      indent();
+      depth++;
+      return "[i_" + (depth - 1) + "]";
+    }
+
+    public void print_for_end() {
+      depth--;
+      unindent();
+      println("}");
+    }
+
+    public void print_block_begin() {
+      println("{");
+      indent();
+    }
+
+    public void print_block_end() {
+      unindent();
+      println("}");
+    }
+
+    public String getUnique(Object o) {
+      String result = (String)unique.get(o);
+      if (result == null) {
+   	result = "_" + (unique.size() + 1) + "_";
+      }
+      unique.put(o, result);
+      return result;
+    }
+
+  }
+
+}
+
+aspect Java_StructName {
+
+  inh int Decl.Java_Depth();
+  inh int Type.Java_Depth();
+  eq Program.getDecl(int i).Java_Depth() = 0;
+  eq StructType.getField(int i).Java_Depth() = Java_Depth() + 1;
+
+  inh String Type.Java_structName();
+  eq Program.getDecl(int i).Java_structName() = getDecl(i).getName();
+  eq StructType.getField(int i).Java_structName() {
+    if (Java_Depth() == 0) {
+      return "struct_" + getField(i).getName();
+    } else {
+      return Java_structName() + "_" + getField(i).getName();
+    }
+  }
+}
+
+aspect Java_Void {
+
+  syn boolean Decl.isVoid() = getType().isVoid();
+  syn boolean UserType.isVoid() = decl().isVoid();
+  syn boolean Type.isVoid() = false;
+  syn boolean VoidType.isVoid() = true;
+
+}
+
+aspect Java_CodeGen {
+
+  public void Program.J_gen(PrintStream ps, String pack, int version) throws IOException {
+    Java_env env;
+    env = new Java_env(version, ps);
+    for (int i = 0; i < getNumDecl(); i++) {
+      Decl d = getDecl(i);
+      try {
+        d.Java_emitClass(env, pack);
+      } catch (Error e) {
+	System.err.println(d.getName());
+	throw e;
+      }
+    }
+    env.close();
+  }
+
+  public void Program.J_gen(String dir, String pack, int version) throws IOException {
+    Java_env env;
+    for (int i = 0; i < getNumDecl(); i++) {
+      Decl d = getDecl(i);
+      try {
+        env = new Java_env(version, new File(dir, d.getName() + ".java"));
+        d.Java_emitClass(env, pack);
+        env.close();
+      } catch (Error e) {
+	System.err.println(d.getName());
+	throw e;
+      }
+    }
+  }
+
+  /** Experimental method for generating code to a map <classname, source>
+    */
+  public void Program.J_gen(Map<String,String> src, String pack, int version) throws IOException {
+    Java_env env;
+    for (int i = 0; i < getNumDecl(); i++) {
+      Decl d = getDecl(i);
+      try {
+        ByteArrayOutputStream bs = new ByteArrayOutputStream();
+        PrintStream out = new PrintStream(bs);
+        env = new Java_env(version, out);
+        d.Java_emitClass(env, pack);
+        env.close();
+        src.put(d.getName(), bs.toString());
+      } catch (Error e) {
+	System.err.println(d.getName());
+	throw e;
+      }
+    }
+  }
+
+}
+
+aspect Java_Class {
+
+  public void Decl.Java_emitClass(Java_env env, String pack) {
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitClass(Java_env env, String pack)" +
+		    " not declared");
+  }
+
+  public void Decl.Java_emitDeclPP(Java_env env) {
+      // Hackish prettyprint preamble
+      env.println("/* ");
+      pp(env.getPrintStream());
+
+      Java_emitUserTypeDeps(env, null, false);
+      Java_emitUserTypeRefs(env, null, false);
+      env.println("*/");
+
+  }
+
+  public void Decl.Java_emitUserTypeDeps(Java_env env, String via, boolean outputCode) {
+  // XXX TODO will generate unnecessary recursion for types. fix this per commented out code
+  // XXX      but ensure that types with references actually register themselves.. (i.e., add "nested" argument)
+  //public abstract void Decl.Java_emitUserTypeDeps(Java_env env, String via, boolean outputCode);
+
+  //public void TypeDecl.Java_emitUserTypeDeps(Java_env env, String via, boolean outputCode) {
+  //  // do nothing for type decls; sampledecl iterates over all dependencies and outputs
+  //  // all type decls
+  //}
+  //public void SampleDecl.Java_emitUserTypeDeps(Java_env env, String via, boolean outputCode) {
+//  if(env.versionHasMetaData() && hasDependencies() || isReferenced() ) {
+//      if(env.versionHasMetaData() && isSampleDecl() && outputCode) {
+//         env.println("if(sendMetaData){");
+//         env.indent();
+//      }
+        Iterator<Decl> it = type_dependencies().iterator();
+        while(it.hasNext()) {
+            Decl t = it.next();
+
+            t.Java_emitUserTypeDeps(env, t.getName(), outputCode);
+            if( outputCode){// && t.getType().isUserType() ) {
+               env.println(t.getName()+".register(e);");
+            } else {  // Just output a comment
+	        String refpath = (via == null) ? "directly" : "indirectly via "+via;
+	       env.println(" //Depends ("+refpath+") on "+t.getName() );
+            }
+        }
+//      if(env.versionHasMetaData() && isSampleDecl() && outputCode) {
+//         env.unindent();
+//         env.println("}");
+//      }
+//  }
+  }
+  public void Decl.Java_emitUserTypeRefs(Java_env env, String via, boolean outputCode) {
+    if( isReferenced() ) {
+        Iterator<Decl> it = type_references().iterator();
+        while(it.hasNext()) {
+            Decl t = it.next();
+
+            t.Java_emitUserTypeRefs(env, t.getName(), outputCode);
+            if(outputCode) {
+               env.println(t.getName()+".register(e);");
+            } else {  // Just output a comment
+	        String refpath = (via == null) ? "directly" : "indirectly via "+via;
+	       env.println(" //Is referenced ("+refpath+")  by "+t.getName() );
+            }
+        }
+    }
+ }
+
+
+  public void Decl.Java_emitRegisterEncoder(Java_env env) {
+    env.println("public static void register(Encoder e) throws IOException {");
+    env.indent();
+    env.println("register(e, true);");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public static void register(Encoder e, boolean sendMetaData) throws IOException {");
+    env.indent();
+    Java_emitUserTypeDeps(env, null, true);
+    env.println("e.register(dispatcher);");
+    env.unindent();
+    env.println("}");
+    env.println("public static void registerSampleRef(Encoder e) throws IOException{");
+    env.indent();
+    env.println("e.registerSampleRef(dispatcher);");
+    env.unindent();
+    env.println("}");
+    env.println();
+  }
+
+  public void TypeDecl.Java_emitClass(Java_env env, String pack) {
+      Java_emitDeclPP(env);
+      if (pack != null && pack.length() > 0) {
+          env.println("package " + pack + ";");
+      }
+
+      env.println("import se.lth.control.labcomm"+env.verStr+".Constant;");
+      env.println("import se.lth.control.labcomm"+env.verStr+".SampleType;");
+
+      if (getType().Java_needInstance() || hasDependencies() || isReferenced()) {
+          env.println("import se.lth.control.labcomm"+env.verStr+".Encoder;");
+          env.println("import se.lth.control.labcomm"+env.verStr+".SampleDispatcher;");
+          env.println("import se.lth.control.labcomm"+env.verStr+".SampleHandler;");
+//          env.println();
+//      }
+//
+//      if (getType().Java_needInstance()) {
+          env.println("import java.io.IOException;");
+          env.println("import se.lth.control.labcomm"+env.verStr+".Decoder;");
+      }
+      // For types without type_dependencies and not needing an instance,
+      // currently just an empty class is generated
+
+      env.println("public class " + getName() + " implements SampleType {");
+      env.println();
+
+      env.indent();
+      if (getType().Java_needInstance()) {
+        getType().Java_emitInstance(env);
+        Java_emitEncoder(env);
+        Java_emitDecoder(env);
+      }
+
+      //if(hasDependencies() || isReferenced()) {
+      //if( getType().isUserType() && isReferenced()) {
+      if( isReferenced()) {
+        Java_emitRegisterEncoder(env);
+        Java_emitDispatcher(env, false);
+      }
+      Java_emitSignature(env);
+
+      env.println("}");
+      env.unindent();
+      env.println();
+  }
+
+
+  public void SampleDecl.Java_emitClass(Java_env env, String pack) {
+    Java_emitDeclPP(env);
+
+    if (pack != null && pack.length() > 0) {
+      env.println("package " + pack + ";");
+    }
+
+    env.println("import java.io.IOException;");
+    env.println("import se.lth.control.labcomm"+env.verStr+".Constant;");
+    env.println("import se.lth.control.labcomm"+env.verStr+".Decoder;");
+    env.println("import se.lth.control.labcomm"+env.verStr+".SampleDispatcher;");
+    env.println("import se.lth.control.labcomm"+env.verStr+".Encoder;");
+    env.println("import se.lth.control.labcomm"+env.verStr+".SampleHandler;");
+    env.println("import se.lth.control.labcomm"+env.verStr+".Sample;");
+    env.println();
+    env.print("public class " + getName());
+//  TODO: ?
+//  Code for making samples of user types extend their type
+//  currently commented out. Is this a good idea or not?
+//
+//    if(getType().isUserType()) {
+//        env.print(" extends "+getType().getTypeName());
+//    }
+    env.println(" implements Sample {");
+    env.println();
+    env.indent();
+    getType().Java_emitInstance(env);
+    env.println("public interface Handler extends SampleHandler {");
+    env.print("  public void handle_" + getName() + "(");
+    if (!isVoid()) {
+      getType().Java_emitType(env);
+      env.print(" value");
+    }
+    env.println(") throws Exception;");
+    env.println("}");
+    env.println();
+    env.println("public static void register(Decoder d, Handler h) throws IOException {");
+    env.indent();
+    env.println("d.register(dispatcher, h);");
+    env.unindent();
+    env.println("}");
+    env.println("public static void registerSampleRef(Decoder d) throws IOException {");
+    env.indent();
+    env.println("d.registerSampleRef(dispatcher);");
+    env.unindent();
+    env.println("}");
+    env.println();
+
+
+    Java_emitRegisterEncoder(env);
+    Java_emitDispatcher(env, true);
+    Java_emitEncoder(env);
+    Java_emitDecoder(env);
+
+    Java_emitSignature(env);
+    env.unindent();
+    env.println("}");
+    env.println();
+  }
+
+  //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
+    //for matching at the decoder side (which cannot know
+    //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());
+    //}
+  }
+
+  public void Decl.Java_emitFlatSignature(Java_env env){
+    env.println("private static byte[] signature = new byte[] {");
+      env.indent();
+      SignatureList signature = flatSignature(env.version);
+      for (int i = 0 ; i < signature.size() ; i++) {
+        String comment = signature.getComment(i);
+        if (comment != null) {
+          env.println(signature.getIndent(i) + "// " + comment);
+        }
+        byte[] data = signature.getData(i, env.version);
+        if (data != null) {
+          env.print(signature.getIndent(i));
+          for (int j = 0 ; j < data.length ; j++) {
+          env.print(data[j] + ", ");
+        }
+        env.println();
+      }
+    }
+    env.unindent();
+    env.println("};");
+    env.unindent();
+    env.println();
+  }
+
+  //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()+">":""; 
+    env.println("private static Dispatcher dispatcher = new Dispatcher();");
+    env.println();
+    env.println("public SampleDispatcher getDispatcher() {");
+    env.indent();
+    env.println("return dispatcher;");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("private static class Dispatcher implements SampleDispatcher "+genericStr+"{");
+    env.indent();
+    env.println();
+    env.println("public Class"+genericStr+" getSampleClass() {");
+    env.indent();
+    env.println("return " + getName() + ".class;");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public String getName() {");
+    env.indent();
+    env.println("return \"" + getName() + "\";");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public byte getTypeDeclTag() {");
+    env.indent();
+    if(env.version == 2006) {
+      if(isSample) {
+        env.println("return Constant.SAMPLE;");
+      } else {
+        env.println("return Constant.TYPEDEF;");
+      }
+    } else {
+      if(isSample) {
+        env.println("return Constant.SAMPLE_DEF;");
+      } else {
+        env.println("return Constant.TYPE_DEF;");
+      }
+    }
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public boolean isSample() {");
+    env.indent();
+    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();
+    env.println("/** return the flat signature. */");
+    env.println("public byte[] getSignature() {");
+    env.indent();
+    env.println("return signature;");
+    env.unindent();
+    env.println("}");
+    env.println();
+//    env.println("public void encodeSignature(Encoder e) throws IOException{");
+//    env.indent();
+//    env.println("emitSignature(e);");
+//    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 boolean canDecodeAndHandle() {");
+    env.indent();
+    env.println("return "+isSample+";");
+    env.unindent();
+    env.println("}");
+    env.println();
+    env.println("public void decodeAndHandle(Decoder d,");
+    env.println("                            SampleHandler h) throws Exception {");
+    env.indent();
+    if( isSample) {
+        if (isVoid()) {
+          env.println(getName() + ".decode(d);");
+          env.println("((Handler)h).handle_" + getName() + "();");
+        } else {
+          env.println("((Handler)h).handle_" + getName() + "(" + getName() + ".decode(d));");
+        }
+    } else {
+        env.println("throw new Exception(\"A typedef has no handler, the corresponding method on the sample class should be called.\");");
+    }
+    env.unindent();
+    env.println("}");
+    env.println("");
+    env.unindent();
+    env.println("}");
+    env.println("");
+
+ }
+
+
+  public void TypeDecl.Java_emitEncoder(Java_env env) {
+    env.print("public static void encode(Encoder e");
+    if (!isVoid()) {
+      env.print(", ");
+      getType().Java_emitType(env);
+      env.print(" value");
+    }
+    env.println(") throws IOException {");
+    env.indent();
+    getType().Java_emitEncoder(env, "value");
+    env.unindent();
+    env.println("}");
+    env.println();
+  }
+
+  public void SampleDecl.Java_emitEncoder(Java_env env) {
+    env.print("public static void encode(Encoder e");
+    if (!isVoid()) {
+      env.print(", ");
+      getType().Java_emitType(env);
+      env.print(" value");
+    }
+    env.println(") throws IOException {");
+    env.indent();
+    env.println("e.begin(" + getName() + ".class);");
+    getType().Java_emitEncoder(env, "value");
+    env.println("e.end(" + getName() + ".class);");
+    env.unindent();
+    env.println("}");
+    env.println();
+  }
+
+  public void Type.Java_emitEncoder(Java_env env, String name) {
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitEncoder(Java_env env, String name)" +
+		    " not declared");
+  }
+
+  public void VoidType.Java_emitEncoder(Java_env env, String name) {
+  }
+
+  public void PrimType.Java_emitEncoder(Java_env env, String name) {
+    switch (getToken()) {
+      case LABCOMM_BOOLEAN: { env.print("e.encodeBoolean"); } break;
+      case LABCOMM_BYTE: { env.print("e.encodeByte"); } break;
+      case LABCOMM_SHORT: { env.print("e.encodeShort"); } break;
+      case LABCOMM_INT: { env.print("e.encodeInt"); } break;
+      case LABCOMM_LONG: { env.print("e.encodeLong"); } break;
+      case LABCOMM_FLOAT: { env.print("e.encodeFloat"); } break;
+      case LABCOMM_DOUBLE: { env.print("e.encodeDouble"); } break;
+      case LABCOMM_STRING: { env.print("e.encodeString"); } break;
+      case LABCOMM_SAMPLE: { env.print("e.encodeSampleRef"); } break;
+    }
+    env.println("(" + name + ");");
+  }
+
+  public void ArrayType.Java_emitEncoder(Java_env env, String name) {
+    int baseDepth = env.getDepth();
+    String prefix = "";
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      String limit = getExp(i).Java_emitEncoder(env, name + prefix);
+      env.print_block_begin();
+      env.println("int i_" + (baseDepth + i) + "_max = " + limit + ";");
+      prefix = prefix + "[0]";
+    }
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      String limit = "i_" + (baseDepth + i) + "_max";
+      name = name + env.print_for_begin(limit);
+    }
+    getType().Java_emitEncoder(env, name);
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      env.print_for_end();
+      env.print_block_end();
+    }
+  }
+
+  public String Exp.Java_emitEncoder(Java_env env, String name) {
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitEncoder(Java_env env, String name)" +
+		    " not declared");
+  }
+
+  public String IntegerLiteral.Java_emitEncoder(Java_env env, String name) {
+    return getValue();
+  }
+
+  public String VariableSize.Java_emitEncoder(Java_env env, String name) {
+    env.println("e.encodePacked32(" + name + ".length);");
+    return name + ".length";
+  }
+
+  public void StructType.Java_emitEncoder(Java_env env, String name) {
+    for (int i = 0 ; i < getNumField() ; i++) {
+      Field f = getField(i);
+      f.getType().Java_emitEncoder(env, name + "." + f.getName());
+    }
+  }
+
+  public void UserType.Java_emitEncoder(Java_env env, String name) {
+    if (Java_needInstance()) {
+      env.println(getName() + ".encode(e, " + name + ");");
+    } else {
+      decl().getType().Java_emitEncoder(env, name);
+    }
+  }
+
+  public void Decl.Java_emitDecoder(Java_env env) {
+    env.print("public static ");
+    getType().Java_emitType(env);
+    env.println(" decode(Decoder d) throws IOException {");
+    env.indent();
+    if (!isVoid()) {
+      getType().Java_emitType(env);
+      env.println(" result;");
+      getType().Java_emitDecoder(env, "result");
+      env.println("return result;");
+    }
+    env.unindent();
+    env.println("}");
+    env.println();
+  }
+
+  public void Type.Java_emitDecoder(Java_env env, String name) {
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitDecoder(Java_env env, String name)" +
+		    " not declared");
+  }
+
+  public void VoidType.Java_emitDecoder(Java_env env, String name) {
+  }
+
+  public void PrimType.Java_emitDecoder(Java_env env, String name) {
+    env.print(name + " = ");
+    switch (getToken()) {
+      case LABCOMM_BOOLEAN: { env.println("d.decodeBoolean();"); } break;
+      case LABCOMM_BYTE: { env.println("d.decodeByte();"); } break;
+      case LABCOMM_SHORT: { env.println("d.decodeShort();"); } break;
+      case LABCOMM_INT: { env.println("d.decodeInt();"); } break;
+      case LABCOMM_LONG: { env.println("d.decodeLong();"); } break;
+      case LABCOMM_FLOAT: { env.println("d.decodeFloat();"); } break;
+      case LABCOMM_DOUBLE: { env.println("d.decodeDouble();"); } break;
+      case LABCOMM_STRING: { env.println("d.decodeString();"); } break;
+      case LABCOMM_SAMPLE: { env.println("d.decodeSampleRef();"); } break;
+    }
+  }
+
+  public void ArrayType.Java_emitDecoder(Java_env env, String name) {
+    env.println("{");
+    env.indent();
+    int baseDepth = env.getDepth();
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      env.print("int i_" + (baseDepth + i) + "_max = ");
+      getExp(i).Java_emitDecoder(env);
+      env.println(";");
+    }
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      String limit = "i_" + (baseDepth + i) + "_max";
+      env.print(name + " = ");
+      Java_emitNew(env, limit, getNumExp() - i);
+      env.println(";");
+      name = name + env.print_for_begin(limit);
+    }
+    getType().Java_emitDecoder(env, name);
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      env.print_for_end();
+    }
+    env.unindent();
+    env.println("}");
+  }
+
+  public void Exp.Java_emitDecoder(Java_env env) {
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitDecoder(Java_env env)" +
+		    " not declared");
+  }
+
+  public void IntegerLiteral.Java_emitDecoder(Java_env env) {
+    env.print(getValue());
+  }
+
+  public void VariableSize.Java_emitDecoder(Java_env env) {
+    env.print("d.decodePacked32()");
+  }
+
+  public void StructType.Java_emitDecoder(Java_env env, String name) {
+    env.print(name + " = new ");
+    Java_emitType(env);
+    env.println("();");
+    for (int i = 0 ; i < getNumField() ; i++) {
+      Field f = getField(i);
+      f.getType().Java_emitDecoder(env, name + "." + f.getName());
+    }
+  }
+
+  public void UserType.Java_emitDecoder(Java_env env, String name) {
+    if (Java_needInstance()) {
+      env.println(name + " = " + getName() + ".decode(d);");
+    } else {
+      decl().getType().Java_emitDecoder(env, name);
+    }
+  }
+
+  public void Type.Java_emitNew(Java_env env, String size) {
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitNew(Java_env env, String size)" +
+		    " not declared");
+  }
+
+  public void ArrayType.Java_emitNew(Java_env env, String size, int depth) {
+    env.print("new ");
+    getType().Java_emitTypePrefix(env);
+    env.print("[" + size + "]");
+    getType().Java_emitTypeSuffix(env);
+    for (int i = 1 ; i < depth ; i++) {
+      env.print("[]");
+    }
+  }
+
+  public void Type.Java_emitTypePrefix(Java_env env) {
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitTypePrefix(Java_env env)" +
+		    " not declared");
+  }
+
+  public void PrimType.Java_emitTypePrefix(Java_env env) {
+    switch (getToken()) {
+      case LABCOMM_STRING: { env.print("String"); } break;
+      case LABCOMM_SAMPLE: { env.print("Class"); } break;
+      default: { env.print(getName()); } break;
+    }
+  }
+
+  public void UserType.Java_emitTypePrefix(Java_env env) {
+    if (Java_needInstance()) {
+      env.print(getName());
+    } else {
+      decl().getType().Java_emitTypePrefix(env);
+    }
+  }
+
+  public void ArrayType.Java_emitTypePrefix(Java_env env){
+    getType().Java_emitTypePrefix(env);
+  }
+
+  public void StructType.Java_emitTypePrefix(Java_env env){
+    env.print(Java_structName());
+  }
+
+  public void Type.Java_emitTypeSuffix(Java_env env) {
+  }
+
+  public void UserType.Java_emitTypeSuffix(Java_env env) {
+    if (! Java_needInstance()) {
+      decl().getType().Java_emitTypeSuffix(env);
+    }
+  }
+
+  public void ArrayType.Java_emitTypeSuffix(Java_env env){
+    getType().Java_emitTypeSuffix(env);
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      env.print("[]");
+    }
+  }
+
+  public boolean Type.Java_needInstance() {
+    throw new Error(this.getClass().getName() +
+		    ".Java_needInstance()" +
+		    " not declared");
+  }
+
+  public boolean VoidType.Java_needInstance() {
+    return false;
+  }
+
+  public boolean PrimType.Java_needInstance() {
+    return false;
+  }
+
+  public boolean UserType.Java_needInstance() {
+    return decl().getType().Java_needInstance();
+  }
+
+  public boolean StructType.Java_needInstance() {
+    return true;
+  }
+
+  public boolean ArrayType.Java_needInstance() {
+    return getType().Java_needInstance();
+  }
+
+  public boolean Type.Java_isPrimitive() {
+    return false;
+  }
+
+  public boolean PrimType.Java_isPrimitive() {
+    return true;
+  }
+
+  public void Type.Java_emitInstance(Java_env env) {
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitInstance(Java_env env)" +
+		    " not declared");
+  }
+
+  public void VoidType.Java_emitInstance(Java_env env) {
+  }
+
+  public void PrimType.Java_emitInstance(Java_env env) {
+  }
+
+  public void ArrayType.Java_emitInstance(Java_env env) {
+    getType().Java_emitInstance(env);
+  }
+
+  public void StructType.Java_emitInstance(Java_env env) {
+    if (Java_Depth() > 0) {
+      env.println("public static class " + Java_structName() + " {");
+      env.indent();
+    }
+    for (int i = 0 ; i < getNumField() ; i++) {
+      getField(i).getType().Java_emitInstance(env);
+    }
+    for (int i = 0 ; i < getNumField() ; i++) {
+      getField(i).Java_emitField(env);
+    }
+    if (Java_Depth() > 0) {
+      env.unindent();
+      env.println("}");
+    }
+    env.println();
+  }
+
+  public void UserType.Java_emitInstance(Java_env env) {
+  }
+
+  public void Field.Java_emitField(Java_env env) {
+    env.print("public ");
+    getType().Java_emitType(env);
+    env.println(" " + getName() + ";");
+  }
+
+  public void Type.Java_emitType(Java_env env) {
+    throw new Error(this.getClass().getName() +
+		    ".Java_emitType(Java_env env)" +
+		    " not declared");
+  }
+
+  public void VoidType.Java_emitType(Java_env env) {
+    env.print("void");
+  }
+
+  public void PrimType.Java_emitType(Java_env env) {
+    switch (getToken()) {
+      case LABCOMM_STRING: { env.print("String"); } break;
+      case LABCOMM_SAMPLE: { env.print("Class"); } break;
+      default: { env.print(getName()); } break;
+    }
+  }
+
+  public void UserType.Java_emitType(Java_env env) {
+    decl().getType().Java_emitType(env);
+  }
+
+  public void ArrayType.Java_emitType(Java_env env){
+    getType().Java_emitType(env);
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      env.print("[]");
+    }
+  }
+
+  public void StructType.Java_emitType(Java_env env){
+    env.print(Java_structName());
+  }
+}
+
+aspect Java_Signature {
+    public void Signature.Java_emitSignature(Java_env env, boolean decl){
+      // XXX should sendOnlyFlatSignatures be kept somewhere?
+      //SignatureList sl = (parentDecl().sendOnlyFlatSignatures(env)) ? getFlatSignatureList() : getSignatureList();
+      SignatureList sl = getSignatureList();
+      sl.Java_emitSignature(env, decl);
+    }
+
+//    public void Signature.Java_emitHierarchicalSignature(Java_env env, boolean decl){
+//      SignatureList sl = getSignatureList();
+//      sl.Java_emitSignature(env, decl);
+//    }
+//
+    public abstract void SignatureLine.Java_emitSignature(Java_env env, boolean decl);
+
+    public void TypeRefSignatureLine.Java_emitSignature(Java_env env, boolean isDecl){
+      env.print(getIndentString());
+      env.println("e.encodePacked32(e.getTypeId("+decl.getName()+".class));");
+    }
+
+    public void DataSignatureLine.Java_emitSignature(Java_env env, boolean decl){
+        byte[] data = getData(env.version);
+          if (data != null) {
+              env.print(getIndentString());
+              for (int j = 0 ; j < data.length ; j++) {
+                  //env.print("e.encodeByte((byte)"+data[j]+");");
+                  env.print("e.encodeByte((byte)"+ String.format("0x%02X ", data[j]) +"); ");
+              }
+              env.println();
+          }
+  }
+    public void SignatureList.Java_emitSignature(Java_env env, boolean decl) {
+      env.println("private static void emitSignature(Encoder e) throws IOException{");
+      env.indent();
+      for (int i = 0 ; i < size() ; i++) {
+        String comment = getComment(i);
+        if (comment != null && comment.length() > 0) {
+            env.println(getIndent(i) + "// " + comment);
+        }
+        SignatureLine l = getSignatureLine(i);
+        l.Java_emitSignature(env, decl);
+      }
+      env.println("}");
+      env.unindent();
+  }
+
+}
+
+aspect Java_Info {
+
+  public void Program.Java_info(PrintStream out, int version) {
+    Java_env env = new Java_env(version, out);
+    for (int i = 0; i < getNumDecl(); i++) {
+      getDecl(i).Java_info(env);
+    }
+  }
+
+  public void Decl.Java_info(Java_env env) {
+    throw new Error(this.getClass().getName() +
+		    ".Java_info(Java_env env)" +
+		    " not declared");
+  }
+
+  public void TypeDecl.Java_info(Java_env env) {
+    env.print(",Java,typedef," + getName() + ",");
+    getType().Java_emitType(env);
+    env.print(",not_applicable_for_Java");
+    env.println();
+  }
+
+  public void SampleDecl.Java_info(Java_env env) {
+    env.print(",Java,sample," + getName() + ",");
+    getType().Java_emitType(env);
+    env.print(",not_applicable_for_Java");
+    env.println();
+  }
+
+}
diff --git a/compiler/2014/LabComm.ast b/compiler/2014/LabComm.ast
new file mode 100644
index 0000000..904cc17
--- /dev/null
+++ b/compiler/2014/LabComm.ast
@@ -0,0 +1,39 @@
+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;
+SampleDecl : 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;
+
+Dim ::= Exp*;
+
+abstract Exp;
+IntegerLiteral : Exp ::= <Value:String>;
+VariableSize : Exp;
diff --git a/compiler/2014/LabComm.java b/compiler/2014/LabComm.java
new file mode 100644
index 0000000..d041389
--- /dev/null
+++ b/compiler/2014/LabComm.java
@@ -0,0 +1,404 @@
+package se.lth.control.labcomm2014.compiler;
+
+import java.io.*;
+import java.util.*;
+
+public class LabComm {
+
+  private static void println(String s) {
+    System.out.println(s);
+  }
+
+  private static void print_help() {
+    println("\n Usage: java -jar labcom.jar [options*] FILE");
+    println("");
+    println(" --help                  Shows this help text");
+    println(" -v                      Be verbose");
+    println(" --ver=VERSION           Generate code for labcomm VERSION (=2006 or 2013)");
+    println("[ C options ]");
+    println(" -C                      Generates C/H code in FILE.[ch]");
+    println(" --cprefix=PREFIX        Prefixes C types with PREFIX");
+    println(" --cinclude=FILE         Include FILE in generated .c");
+    println(" --c=CFILE               Generates C code in CFILE");
+    println(" --h=HFILE               Generates H code in HFILE");
+    println("[ C# options]");
+    println(" --cs                    Generates C# code in FILE.cs");
+    println(" --cs=CSFILE             Generates C# code in CSFILE");
+    println(" --csnamespace=NAMESPACE Place C# classes in NAMESPACE");
+    println("[ Java options ]");
+    println(" --java=JDIR             Generates Java files in JDIR");
+    println(" --javapackage=PACKAGE   Place Java classes in PACKAGE");
+    println("[ Python options ]");
+    println(" -P                      Generates Python code in FILE.py");
+    println(" --python=PFILE          Generates Python code in PFILE");
+    println("[ RAPID options ]");
+    println(" --rapid                 Generates RAPID code in FILE.sys");
+    println("[ Misc options ]");
+    println(" --pretty=PFILE          Pretty prints to PFILE");
+    println(" --typeinfo=TIFILE       Generates typeinfo in TIFILE");
+  }
+    
+  /** To be cleaned up.
+   */
+  private static void checkVersion(int v) {
+     if(! (v == 2006 || v == 2014) ) {
+	System.err.println(" Unknown version: " + v);
+	System.err.println(" Supported versions: 2006, 2014 ");
+	System.exit(2);
+     }
+  }
+
+  private static void genH(Program p, String hName, 
+			   Vector cIncludes, String coreName, String prefix, int ver) {
+    try {
+      FileOutputStream f;
+      PrintStream out;
+      
+      f = new FileOutputStream(hName);
+      out = new PrintStream(f);
+      p.C_genH(out, cIncludes, coreName, prefix, ver);
+      out.close();
+    } catch (IOException e) {
+      System.err.println("IOException: " + hName + " " + e);
+    }
+  }
+
+  private static void genC(Program p, String cName, 
+			   Vector cIncludes, String coreName, String prefix, int ver) {
+    try {
+      FileOutputStream f;
+      PrintStream out;
+
+      f = new FileOutputStream(cName);
+      out = new PrintStream(f);
+      p.C_genC(out, cIncludes, coreName, prefix, ver);
+      out.close();
+    } catch (IOException e) {
+      System.err.println("IOException: " + cName + " " + e);
+    }
+  }
+
+  private static void genCS(Program p, String csName, String csNamespace, int ver) {
+//      throw new Error("C# generation currently disabled");
+    try {
+      p.CS_gen(csName, csNamespace, ver);
+    } catch (IOException e) {
+      System.err.println("IOException: " + csName + " " + 
+			 csNamespace + " " + e);
+    }
+  }
+
+  private static void genJava(Program p,  String dirName, String packageName, int ver) {
+    try {
+      p.J_gen(dirName, packageName, ver);
+    } catch (IOException e) {
+      System.err.println("IOException: " + dirName + " " + 
+			 packageName + " " + e);
+    }
+  }
+
+  private static void genPython(Program p, String filename, String prefix, int ver) {
+    try {
+      FileOutputStream f;
+      PrintStream out;
+
+      f = new FileOutputStream(filename);
+      out = new PrintStream(f);
+      p.Python_gen(out, prefix, ver);
+      out.close();
+    } catch (IOException e) {
+      System.err.println("IOException: " + filename + " " + e);
+    }
+  }
+
+  private static void genRAPID(Program p, String filename, String prefix, int ver) {
+    try {
+      p.RAPID_gen(filename, prefix, ver);
+    } catch (IOException e) {
+      System.err.println("IOException: " + filename + " " + e);
+    }
+  }
+
+  /** Helper class to contain command line options 
+      and their associated behaviour
+   **/
+  private static class Opts {
+    final String[] args;
+    String coreName = null;
+    String prefix = null;
+    boolean verbose = false;
+    int ver = 2013; //Version 2013 as default
+    String cFile = null;
+    String hFile = null;
+    Vector cIncludes = new Vector();
+    String cPrefix; // gets default value (prefix) in processFilename
+    String csFile = null;
+    String csNamespace = null;
+    String javaDir = null;
+    String javaPackage = "";
+    String pythonFile = null;
+    String prettyFile = null;
+    String typeinfoFile = null;
+    String rapidFile = null;
+    String fileName = null;
+
+   Opts(String[] args) {
+     this.args = args;
+   }
+
+    private static String getCoreName(String s) {
+      int i = s.lastIndexOf('.');
+      return s.substring(0, i > 0 ? i : s.length());
+    }
+  
+    private static String getFileName(String s) {
+      return s.substring(s.lastIndexOf('/') + 1, s.length());
+    }
+  
+    private static String getBaseName(String s) {
+      s = getFileName(s);
+      int i = s.lastIndexOf('.');
+      return s.substring(0, i > 0 ? i : s.length());
+    }
+  
+    private static String getPrefix(String s) {
+      return s.substring(s.lastIndexOf('/') + 1, s.length());
+    }
+  
+    boolean processFilename(){
+      // Scan for first non-option
+      for (int i = 0 ; i < args.length ; i++) {
+        if (! args[i].startsWith("-")) {
+  	fileName = args[i];
+  	break;
+        }
+      }
+      if (fileName != null) {
+        coreName = getBaseName(fileName);
+        prefix = getPrefix(coreName);
+       cPrefix = prefix;
+      }
+      return fileName != null;
+    }
+    
+    void processArgs(){
+      for (int i = 0 ; i < args.length ; i++) {
+        if (fileName == null ||
+            args[i].equals("-help") || 
+            args[i].equals("-h") || 
+            args[i].equals("--help")) {
+          print_help();
+          System.exit(0);
+        } else if (args[i].equals("-v")) {
+          verbose=true;
+        } else if (args[i].startsWith("--ver=")) {
+          ver = Integer.parseInt(args[i].substring(6));
+          checkVersion(ver);
+        } else if (args[i].equals("-C")) {
+          cFile = coreName + ".c";
+          hFile = coreName + ".h";
+        } else if (args[i].startsWith("--cinclude=")) {
+          cIncludes.add(args[i].substring(11));
+        } else if (args[i].startsWith("--cprefix=")) {
+          cPrefix = args[i].substring(10);
+        } else if (args[i].startsWith("--c=")) {
+          cFile = args[i].substring(4);
+        } else if (args[i].startsWith("--h=")) {
+          hFile = args[i].substring(4);
+        } else if (args[i].equals("--cs")) {
+          csFile = coreName + ".cs";
+        } else if (args[i].startsWith("--cs=")) {
+          csFile = args[i].substring(5);
+        } else if (args[i].startsWith("--csnamespace=")) {
+          csNamespace = args[i].substring(14);
+        } else if (args[i].startsWith("--java=")) {
+          javaDir = args[i].substring(7);
+        } else if (args[i].startsWith("--javapackage=")) {
+          javaPackage = args[i].substring(14);
+        } else if (args[i].equals("-P")) {
+          pythonFile = coreName + ".py";
+        } else if (args[i].startsWith("--python=")) {
+          pythonFile = args[i].substring(9);
+        } else if (args[i].startsWith("--pretty=")) {
+          prettyFile = args[i].substring(9);
+        } else if (args[i].startsWith("--typeinfo=")) {
+          typeinfoFile = args[i].substring(11);
+        } else if (args[i].equals("--rapid")) {
+          rapidFile = coreName + ".sys";
+        } else if (i == args.length - 1) {
+          fileName = args[i];
+        } else {
+          System.err.println(" Unknown argument " + args[i]);
+          print_help();
+          System.exit(2);
+        }
+      }
+     if(prefix==null){
+  	System.err.println("   WARNING! prefix==null");
+        prefix="";
+     }
+   }
+
+   Program parseFile(){
+     Program ast = null;
+     try {
+       // Check for errors
+       LabCommScanner scanner = new LabCommScanner(
+                                  new FileReader(fileName));
+       LabCommParser parser = new LabCommParser();
+       Program p = (Program)parser.parse(scanner);
+       Collection errors = new LinkedList();
+       p.errorCheck(errors);
+         
+       if (errors.isEmpty()) {
+         ast = p;
+       } else {
+         for (Iterator iter = errors.iterator(); iter.hasNext(); ) {
+           String s = (String)iter.next();
+           System.out.println(s);
+         }
+       }
+     } catch (FileNotFoundException e) {
+       System.err.println("Could not find file: " + fileName);
+     } catch (IOException e) {
+       System.err.println("IOException: " + fileName + " " + e);
+     } catch (beaver.Parser.Exception e) {
+       System.err.println(e.getMessage());
+     }
+     return ast;
+   }
+
+   boolean generateC(Program ast) {
+     boolean wroteFile = false; 
+     Vector hIncludes = new Vector(cIncludes);
+     if (hFile != null) {
+       cIncludes.add(hFile);
+     }
+     if (cFile != null) {
+       printStatus("C: " , cFile);
+       genC(ast, cFile, cIncludes, coreName, cPrefix, ver);
+       wroteFile = true;
+     }
+     if (hFile != null) {
+       printStatus("H: " , hFile);
+       genH(ast, hFile, hIncludes, coreName, cPrefix, ver);
+       wroteFile = true;
+     }
+     return wroteFile;
+   }
+  
+   boolean generateCS(Program ast) {
+     boolean wroteFile = false; 
+     if (csFile != null) {
+       printStatus("C#: " , csFile); 
+       genCS(ast, csFile, csNamespace, ver);
+       wroteFile = true;
+     }
+     return wroteFile;
+   }
+  
+   boolean generateJava(Program ast) {
+     boolean wroteFile = false; 
+     if (javaDir != null) {
+       printStatus("Java: " , javaDir);
+       genJava(ast, javaDir, javaPackage, ver);
+       wroteFile = true;
+     }
+     return wroteFile;
+   }
+  
+   boolean generatePython(Program ast) {
+     boolean wroteFile = false; 
+     if (pythonFile != null) {
+       printStatus("Python: " , pythonFile); 
+       genPython(ast, pythonFile, prefix, ver);
+       wroteFile = true;
+     }
+     return wroteFile;
+   }
+  
+   boolean generateRAPID(Program ast) {
+     boolean wroteFile = false; 
+     if (rapidFile != null) {
+       printStatus("RAPID: " , rapidFile);
+       genRAPID(ast, rapidFile, coreName, ver);
+       wroteFile = true;
+     }
+     return wroteFile;
+   }
+   boolean generatePrettyPrint(Program ast) {
+     boolean wroteFile = false; 
+     if (prettyFile != null) {
+       printStatus("Pretty: " , prettyFile); 
+       try {
+         FileOutputStream f = new FileOutputStream(prettyFile);
+         PrintStream out = new PrintStream(f);
+         ast.pp(out);
+         out.close();
+         wroteFile = true;
+       } catch (IOException e) {
+         System.err.println("IOException: " + prettyFile + " " + e);
+       } 
+     }
+     return wroteFile;
+   }
+  
+   boolean generateTypeinfo(Program ast) {
+     boolean wroteFile = false; 
+     if (typeinfoFile != null) {
+       printStatus("TypeInfo: " , typeinfoFile); 
+       try {
+         FileOutputStream f = new FileOutputStream(typeinfoFile);
+         PrintStream out = new PrintStream(f);
+         ast.C_info(out, cPrefix, ver);
+         ast.Java_info(out, ver);
+         ast.CS_info(out, csNamespace, ver);
+         wroteFile = true;
+       } catch (IOException e) {
+         System.err.println("IOException: " + typeinfoFile + " " + e);
+       }
+     }
+     return wroteFile;
+    }
+
+    private void printStatus(String kind, String filename){
+       if (verbose) { 
+         System.err.println("Generating "+kind+": " + filename); 
+       }
+    }
+  }
+
+
+  public static void main(String[] args) {
+    Opts opts = new Opts(args);
+    if(!opts.processFilename()) {
+      print_help();
+      System.exit(1);
+    } else {
+      opts.processArgs();
+      Program ast =  opts.parseFile();
+
+      if (ast != null) {
+	
+	boolean fileWritten = false;
+
+        fileWritten |= opts.generateC(ast);
+        fileWritten |= opts.generateCS(ast);
+        fileWritten |= opts.generateJava(ast);
+        fileWritten |= opts.generatePython(ast);
+        fileWritten |= opts.generateRAPID(ast);
+        fileWritten |= opts.generatePrettyPrint(ast);
+        fileWritten |= opts.generateTypeinfo(ast);
+
+        // if no output to files, prettyprint on stdout
+	if (!fileWritten) {
+	  ast.pp(System.out);
+	}
+      } else {
+          // Catch-all for compilation errors
+          System.err.println("Error in specification");
+          System.exit(3);
+      }
+    }
+  } 
+}
diff --git a/compiler/2014/LabCommParser.parser b/compiler/2014/LabCommParser.parser
new file mode 100644
index 0000000..e7fb759
--- /dev/null
+++ b/compiler/2014/LabCommParser.parser
@@ -0,0 +1,133 @@
+%header {:
+  package se.lth.control.labcomm2014.compiler;
+  import se.lth.control.labcomm2014.compiler.*;
+:};
+%embed {:
+  public static class SourceError extends Error {
+    public SourceError(String msg) {
+      super(msg);
+    }
+  }
+  class Events extends Parser.Events {
+    public void syntaxError(Symbol token) {
+      StringBuffer s = new StringBuffer();
+      s.append(token.getLine(token.getStart()) + ", " + token.getColumn(token.getStart()) + "\n");
+      s.append("  *** Syntactic error: unexpected token " + Terminals.NAMES[token.getId()]);
+      throw new SourceError(s.toString());
+        //super.syntaxError(token);
+        //throw new RuntimeException(token.getLine(token.getStart()) + ", " +
+	// token.getColumn(token.getStart()) + ": Syntax Error");
+    }
+    public void scannerError(Scanner.Exception e) {
+      StringBuffer s = new StringBuffer();
+      s.append(e.line + ", " + e.column + "\n");
+      s.append("  *** Lexical error: " + e.getMessage());
+      throw new SourceError(s.toString());
+        //super.scannerError(e);
+        //throw new RuntimeException("Unexpected token");
+    }
+
+  }
+
+        {
+            report = new Events(); // Use error handler in parser
+        }
+:};
+
+Program goal =
+     /* Empty program */               {: return new Program(); :}
+  |  decl_list.l                       {: return new Program(l); :}
+  ;
+
+List decl_list =
+    decl.d                          {: return new List().add(d); :}
+  | decl_list.l decl.d              {: return l.add(d); :}
+  ;
+
+Decl decl =
+    type_decl.t                     {: return t; :}
+  | sample_decl.s	            {: return s; :}
+  ;
+
+List var_decl_list =
+    var_decl.v                      {: return new List().add(v); :}
+  | var_decl_list.l var_decl.v      {: return l.add(v); :}
+  ;
+
+Field var_decl =
+    type.t IDENTIFIER SEMICOLON     {: return new Field(t, IDENTIFIER); :}
+  | type.t IDENTIFIER dim_list.d SEMICOLON
+    {: return new Field(new ParseArrayType(t, d), IDENTIFIER); :}
+  ;
+
+TypeDecl type_decl =
+    TYPEDEF type.t IDENTIFIER SEMICOLON {: return new TypeDecl(t, IDENTIFIER); :}
+  | TYPEDEF type.t IDENTIFIER dim_list.d SEMICOLON
+    {: return new TypeDecl(new ParseArrayType(t, d), IDENTIFIER); :}
+  ;
+
+SampleDecl sample_decl =
+    SAMPLE type.t IDENTIFIER SEMICOLON
+      {: return new SampleDecl(t, IDENTIFIER); :}
+  | SAMPLE type.t IDENTIFIER dim_list.d SEMICOLON
+      {: return new SampleDecl(new ParseArrayType(t, d), IDENTIFIER); :}
+  ;
+
+Type type =
+    prim_type.p                     {: return p; :}
+  | user_type.u                     {: return u; :}
+  | struct_type.s                   {: return s; :}
+  | void_type.v                     {: return v; :}
+  ;
+
+PrimType prim_type =
+    BOOLEAN
+      {: return new PrimType(BOOLEAN, ASTNode.LABCOMM_BOOLEAN); :}
+  | BYTE
+      {: return new PrimType(BYTE, ASTNode.LABCOMM_BYTE); :}
+  | SHORT
+      {: return new PrimType(SHORT, ASTNode.LABCOMM_SHORT); :}
+  | INT
+      {: return new PrimType(INT, ASTNode.LABCOMM_INT); :}
+  | LONG
+      {: return new PrimType(LONG, ASTNode.LABCOMM_LONG); :}
+  | FLOAT
+      {: return new PrimType(FLOAT, ASTNode.LABCOMM_FLOAT); :}
+  | DOUBLE
+      {: return new PrimType(DOUBLE, ASTNode.LABCOMM_DOUBLE); :}
+  | STRING
+      {: return new PrimType(STRING, ASTNode.LABCOMM_STRING); :}
+  | SAMPLE
+      {: return new PrimType(SAMPLE, ASTNode.LABCOMM_SAMPLE); :}
+  ;
+
+UserType user_type =
+    IDENTIFIER                      {: return new UserType(IDENTIFIER); :}
+  ;
+
+StructType struct_type =
+    STRUCT LBRACE var_decl_list.l RBRACE {: return new StructType(l); :}
+  ;
+
+VoidType void_type = 
+    VOID {: return new VoidType(); :} 
+;
+
+List dim_list =
+    dim.d                           {: return new List().add(d); :}
+  | dim_list.l  dim.d               {: return l.add(d); :}
+  ;
+
+Dim dim =
+    LBRACK exp_list.e RBRACK        {: return new Dim(e); :}
+  ;
+
+List exp_list =
+    exp.e                           {: return new List().add(e); :}
+  | exp_list.l COMMA exp.e          {: return l.add(e); :}
+  ;
+
+Exp exp =
+    INTEGER_LITERAL                 {: return new IntegerLiteral(INTEGER_LITERAL); :}
+  | UNDERSCORE                      {: return new VariableSize(); :}
+  ;
diff --git a/compiler/2014/LabCommScanner.flex b/compiler/2014/LabCommScanner.flex
new file mode 100644
index 0000000..b58cbb6
--- /dev/null
+++ b/compiler/2014/LabCommScanner.flex
@@ -0,0 +1,87 @@
+package se.lth.control.labcomm2014.compiler;
+
+import beaver.Symbol;
+import beaver.Scanner;
+import se.lth.control.labcomm2014.compiler.LabCommParser.Terminals;
+
+%%
+
+%public 
+%final 
+%class LabCommScanner
+%extends Scanner
+
+%type Symbol 
+%function nextToken 
+%yylexthrow Scanner.Exception
+
+%unicode
+%line %column
+
+%{
+  StringBuffer strbuf = new StringBuffer(128);
+
+  private Symbol sym(short id) {
+    return new Symbol(id, yyline + 1, yycolumn + 1, len(), str());
+  }
+
+  private Symbol sym(short id, String value) {
+    return new Symbol(id, yyline + 1, yycolumn + 1, len(), value);
+  }
+
+  private String str() { return yytext(); }
+  private int len() { return yylength(); }
+%}
+
+LineTerminator = \n|\r|\r\n
+InputCharacter = [^\r\n]
+
+WhiteSpace = [ ] | \t | \f | {LineTerminator}
+
+Comment = {TraditionalComment}
+        | {EndOfLineComment}
+
+TraditionalComment = "/*" [^*] ~"*/" | "/*" "*"+ "/" | "/*" "*"+ [^/*] ~"*/"
+EndOfLineComment = "//" {InputCharacter}* {LineTerminator}?
+
+Identifier = [:jletter:][:jletterdigit:]*
+
+DecimalNumeral = 0 | {NonZeroDigit} {Digits}? 
+Digits = {Digit}+
+Digit = 0 | {NonZeroDigit}
+NonZeroDigit = [1-9]
+
+%%
+
+<YYINITIAL> {
+  {WhiteSpace}                   { }
+  {Comment}                      { }
+
+  "sample"                       { return sym(Terminals.SAMPLE); }
+  "typedef"                      { return sym(Terminals.TYPEDEF); }
+  "struct"                       { return sym(Terminals.STRUCT); }
+  "void"                         { return sym(Terminals.VOID); }
+  "boolean"                      { return sym(Terminals.BOOLEAN); }
+  "byte"                         { return sym(Terminals.BYTE); }
+  "short"                        { return sym(Terminals.SHORT); }
+  "int"                          { return sym(Terminals.INT); }
+  "long"                         { return sym(Terminals.LONG); }
+  "float"                        { return sym(Terminals.FLOAT); }
+  "double"                       { return sym(Terminals.DOUBLE); }
+  "string"                       { return sym(Terminals.STRING); }
+
+  {DecimalNumeral}               { return sym(Terminals.INTEGER_LITERAL); }
+  "_"                            { return sym(Terminals.UNDERSCORE); }
+  "{"                            { return sym(Terminals.LBRACE); }
+  "}"                            { return sym(Terminals.RBRACE); }
+  "["                            { return sym(Terminals.LBRACK); }
+  "]"                            { return sym(Terminals.RBRACK); }
+  ";"                            { return sym(Terminals.SEMICOLON); }
+  ","                            { return sym(Terminals.COMMA); }
+  
+  {Identifier}                   { return sym(Terminals.IDENTIFIER); }
+}
+
+// fall through errors
+.|\n                             { throw new RuntimeException("Illegal character \""+str()+ "\" at line "+yyline+", column "+yycolumn); }
+<<EOF>>                          { return sym(Terminals.EOF); }
diff --git a/compiler/2014/LabCommTokens.jrag b/compiler/2014/LabCommTokens.jrag
new file mode 100644
index 0000000..557714b
--- /dev/null
+++ b/compiler/2014/LabCommTokens.jrag
@@ -0,0 +1,21 @@
+aspect LabCommTokens {
+
+  public static final int ASTNode.LABCOMM_VERSION =    0x01;  
+  public static final int ASTNode.LABCOMM_SAMPLE_DEF = 0x02;  // The flat signature
+  public static final int ASTNode.LABCOMM_SAMPLE_REF = 0x03;
+  public static final int ASTNode.LABCOMM_TYPE_DEF  =  0x04;  // and type declarations, hierarchically
+
+  public static final int ASTNode.LABCOMM_ARRAY =      0x10;
+  public static final int ASTNode.LABCOMM_STRUCT =     0x11;
+
+  public static final int ASTNode.LABCOMM_BOOLEAN =    0x20; 
+  public static final int ASTNode.LABCOMM_BYTE =       0x21;
+  public static final int ASTNode.LABCOMM_SHORT =      0x22;
+  public static final int ASTNode.LABCOMM_INT =        0x23;
+  public static final int ASTNode.LABCOMM_LONG =       0x24;
+  public static final int ASTNode.LABCOMM_FLOAT =      0x25;
+  public static final int ASTNode.LABCOMM_DOUBLE =     0x26;
+  public static final int ASTNode.LABCOMM_STRING =     0x27;
+  public static final int ASTNode.LABCOMM_SAMPLE =     0x28;
+
+}
diff --git a/compiler/2014/NameAnalysis.jrag b/compiler/2014/NameAnalysis.jrag
new file mode 100644
index 0000000..92dbb41
--- /dev/null
+++ b/compiler/2014/NameAnalysis.jrag
@@ -0,0 +1,67 @@
+
+aspect NameAnalysis {
+
+  inh String Decl.lookupName(String name);
+  eq Program.getDecl(int index).lookupName(String name) {
+    for (int i = 0; i < index; i++) {
+      String s = getDecl(i).getName();
+      if (s.equals(name)) {
+      	return s;
+      }
+    }
+    return null;
+  }
+  inh String Field.lookupName(String name);
+  eq StructType.getField(int index).lookupName(String name) {
+    for (int i = 0; i < index; i++) {
+      String s = getField(i).getName();
+      if (s.equals(name)) {
+      	return s;
+      }
+    }
+    return null;
+  }
+
+  inh TypeDecl Decl.lookupType(String name);
+  inh TypeDecl UserType.lookupType(String name);
+  eq Program.getDecl(int index).lookupType(String name) {
+    for(int i = 0; i < index; i++) {
+      Decl d = getDecl(i);  
+      if(d instanceof TypeDecl && d.getName().equals(name)) {
+	return (TypeDecl)d;
+      }
+    }
+    return null;
+  }
+
+  syn TypeDecl Type.decl(); 
+  eq Type.decl() = null;
+  eq UserType.decl() = lookupType(getName());
+  eq PrimType.decl() = null; //HERE BE DRAGONS XXX
+  
+  
+  public void ASTNode.nameCheck() {
+    for (int i = 0; i < getNumChild(); i++) {
+      getChild(i).nameCheck();
+    }
+  }
+  
+  public void Decl.nameCheck() {
+    if (lookupType(getName()) != null || lookupName(getName()) != null) {
+      error(getName() + " multiply declared");
+    }
+  }
+  
+  public void Field.nameCheck() {
+    if(lookupName(getName()) != null) {
+      error(getName() + " multiply declared");
+    }
+  }
+  
+  public void UserType.nameCheck() {
+    if (decl() == null) {
+      error("Use of undeclared type");
+    } 
+  }
+
+}
diff --git a/compiler/2014/PrettyPrint.jrag b/compiler/2014/PrettyPrint.jrag
new file mode 100644
index 0000000..a7fa877
--- /dev/null
+++ b/compiler/2014/PrettyPrint.jrag
@@ -0,0 +1,117 @@
+import java.io.PrintStream;
+
+aspect PPIndentation {
+
+  inh String Exp.pp_indent();
+  inh String Field.pp_indent();
+  inh String StructType.pp_indent();
+  eq StructType.getField(int index).pp_indent() = pp_indent() + "  ";
+  eq Program.getDecl(int index).pp_indent() = "";
+  
+}
+
+aspect PrettyPrint {
+  
+  public void ASTNode.pp(PrintStream out) {
+    throw new Error(this.getClass().getName() + 
+		    ".pp(PrintStream out)" + 
+		    " not declared");
+  }
+
+  public void Program.pp(PrintStream out) {
+    for(int i = 0; i < getNumDecl(); i++) {
+    	getDecl(i).pp(out);
+    }
+  }
+
+   // Pretty print declarations
+  public void TypeDecl.pp(PrintStream out) {
+    out.print("typedef ");
+    getType().ppIdentifier(out, getName());
+    out.println(";");
+  }
+
+  public void SampleDecl.pp(PrintStream out) {
+    out.print("sample ");
+    getType().ppIdentifier(out, getName());
+    out.println(";");
+  }
+
+  public void Field.pp(PrintStream out) {
+    out.print(pp_indent());
+    getType().ppIdentifier(out, getName());
+    out.println(";");
+  }
+
+  // Pretty print variable of a given type 
+  public void Type.ppIdentifier(PrintStream out, String id) { 
+    ppPrefix(out);
+    out.print(" ");
+    out.print(id);
+  }
+
+  public void ArrayType.ppIdentifier(PrintStream out, String id) {
+    ppPrefix(out);
+    out.print(" ");
+    out.print(id);
+    ppSuffix(out);
+  }
+
+  // PrettyPrint prefix type info
+  public void Type.ppPrefix(PrintStream out) {
+    throw new Error(this.getClass().getName() + 
+		    ".ppPrefix(PrintStream out)" + 
+		    " not declared");
+  }
+
+  public void VoidType.ppPrefix(PrintStream out) { 
+    out.print("void");
+  }
+
+  public void SampleRefType.ppPrefix(PrintStream out) { 
+    out.print("sample");
+  }
+
+  public void PrimType.ppPrefix(PrintStream out) { 
+    out.print(getName());
+  }
+
+  public void UserType.ppPrefix(PrintStream out) { 
+    out.print(getName());
+  }
+
+  public void ArrayType.ppPrefix(PrintStream out) {
+    getType().ppPrefix(out);
+  }
+
+  public void StructType.ppPrefix(PrintStream out) {
+    out.println("struct {");
+    for (int i = 0 ; i < getNumField() ; i++) {
+      getField(i).pp(out);
+    }
+    out.print(pp_indent());
+    out.print("}");
+  }
+
+  // PrettyPrint suffix type info (array dimensions)
+  public void Type.ppSuffix(PrintStream out) { }
+
+  public void ArrayType.ppSuffix(PrintStream out) { 
+    out.print("[");
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      if (i > 0) { out.print(", "); }
+      getExp(i).pp(out);
+    }
+    out.print("]");
+    getType().ppSuffix(out);
+  }
+
+  public void IntegerLiteral.pp(PrintStream out) {
+    out.print(getValue());
+  }
+
+  public void VariableSize.pp(PrintStream out) {
+    out.print("_");
+  }
+
+}
diff --git a/compiler/2014/Python_CodeGen.jrag b/compiler/2014/Python_CodeGen.jrag
new file mode 100644
index 0000000..17203b8
--- /dev/null
+++ b/compiler/2014/Python_CodeGen.jrag
@@ -0,0 +1,232 @@
+aspect Python_CodeGenEnv {
+
+  // Environment wrapper for Python code generation
+  // handles qualid nesting, indentation, file writing and
+  // prefix propagation
+
+  public class Python_env {
+
+    final private class Python_printer {
+      
+      private boolean newline = true;
+      private PrintStream out;
+
+      public Python_printer(PrintStream out) {
+        this.out = out;
+      }
+
+      public void print(Python_env env, String s) {
+        if (newline) {
+          newline = false;
+          for (int i = 0 ; i < env.indent ; i++) {
+            out.print("    ");
+          }
+        }
+        out.print(s);
+      }
+
+      public void println(Python_env env, String s) {
+        print(env, s);
+        out.println();
+        newline = true;
+      }
+
+      public void println(Python_env env) {
+        out.println();
+        newline = true;
+      }
+
+    }
+
+    private int indent;
+    private Python_printer printer;
+
+    public Python_env(PrintStream out) {
+      this.indent = 0;
+      this.printer = new Python_printer(out);
+    }
+
+    public void indent() {
+      indent++;
+    }
+
+    public void unindent() {
+      indent--;
+    }
+
+    public void print(String s) {
+      printer.print(this, s);
+    }
+
+    public void println(String s) {
+      printer.println(this, s);
+    }
+
+    public void println() {
+      printer.println(this);
+    }
+
+  }
+
+}
+
+aspect Python_CodeGen {
+
+  public void Program.Python_gen(PrintStream out, String baseName, int version) {
+    // Remove when Blomdell has verified that it is OK to ignore version
+    // when generating python code. 
+    System.err.println("*** Warning! Python_gen ignores version: "+version);
+    Python_env env = new Python_env(out);
+    env.println("#!/usr/bin/python");
+    env.println("# Auto generated " + baseName);
+    env.println();
+    env.println("import labcomm");
+    env.println("import StringIO");
+    env.println();
+    Python_genTypes(env);
+    //env.println("typedef = [");
+    //env.indent();
+    //for (int i = 0 ; i < getNumDecl() ; i++) {
+    //  getDecl(i).Python_genTypedefListEntry(env);
+    //}
+    //env.unindent();
+    //env.println("]");
+    env.println("sample = [");
+    env.indent();
+    for (int i = 0 ; i < getNumDecl() ; i++) {
+      getDecl(i).Python_genSampleListEntry(env);
+    }
+    env.unindent();
+    env.println("]");
+  }
+
+}
+
+aspect PythonTypes {
+  
+  public void Program.Python_genTypes(Python_env env) {
+    for (int i = 0 ; i < getNumDecl() ; i++) {
+      getDecl(i).Python_genSignature(env);
+    }
+  }
+
+  public void Decl.Python_genSignature(Python_env env) {
+    throw new Error(this.getClass().getName() + 
+                    ".Python_genSignature(Python_env env)" + 
+                    " not declared");
+  }
+
+  public void TypeDecl.Python_genSignature(Python_env env) {
+/*
+    env.println("class " + getName() + "(object):");
+    env.indent();
+    env.println("signature = labcomm.typedef('" + getName() + "',");
+    env.indent();
+    getType().Python_genSignature(env);
+    env.unindent();
+    env.println(")");
+    env.unindent();
+    env.println();
+*/
+  }
+
+  public void SampleDecl.Python_genSignature(Python_env env) {
+    env.println("class " + getName() + "(object):");
+    env.indent();
+    env.println("signature = labcomm.sample('" + getName() + "', ");
+    env.indent();
+    getType().Python_genSignature(env);
+    env.unindent();
+    env.println(")");
+    env.unindent();
+    env.println();
+  }
+
+  public void UserType.Python_genSignature(Python_env env) {
+    lookupType(getName()).getType().Python_genSignature(env);
+  }
+
+  public void Type.Python_genSignature(Python_env env) {
+    throw new Error(this.getClass().getName() + 
+                    ".Python_genSignature(Python_env env)" + 
+                    " not declared");
+  }
+
+  public void PrimType.Python_genSignature(Python_env env) {
+    switch (getToken()) {
+      case LABCOMM_BOOLEAN: { env.print("labcomm.BOOLEAN()"); } break;
+      case LABCOMM_BYTE: { env.print("labcomm.BYTE()"); } break;
+      case LABCOMM_SHORT: { env.print("labcomm.SHORT()"); } break;
+      case LABCOMM_INT: { env.print("labcomm.INTEGER()"); } break;
+      case LABCOMM_LONG: { env.print("labcomm.LONG()"); } break;
+      case LABCOMM_FLOAT: { env.print("labcomm.FLOAT()"); } break;
+      case LABCOMM_DOUBLE: { env.print("labcomm.DOUBLE()"); } break;
+      case LABCOMM_STRING: { env.print("labcomm.STRING()"); } break;
+      case LABCOMM_SAMPLE: { env.print("labcomm.SAMPLE()"); } break;
+    }
+  }
+
+  public void ArrayType.Python_genSignature(Python_env env) {
+    env.print("labcomm.array([");
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      if (i > 0) { env.print(", "); }
+      env.print(getExp(i).Python_getValue());
+    }
+    env.println("],");
+    env.indent();
+    getType().Python_genSignature(env);
+    env.print(")");
+    env.unindent();
+  }
+
+  public void StructType.Python_genSignature(Python_env env) {
+    env.println("labcomm.struct([");
+    env.indent();
+    for (int i = 0 ; i < getNumField() ; i++) {
+      if (i > 0) { env.println(","); }
+      getField(i).Python_genSignature(env);
+    }
+    env.print("])");
+    env.unindent();
+  }
+
+  public void VoidType.Python_genSignature(Python_env env) {
+    env.println("labcomm.struct([])");
+  }
+
+  public void Field.Python_genSignature(Python_env env) {
+    env.print("('" + getName() + "', ");
+    getType().Python_genSignature(env);
+    env.print(")");
+  }
+
+  public void Decl.Python_genTypedefListEntry(Python_env env) {
+  }
+
+  public void TypeDecl.Python_genTypedefListEntry(Python_env env) {
+    env.println("('" + getName() + "', " + getName() + ".signature),");
+  }
+
+  public void Decl.Python_genSampleListEntry(Python_env env) {
+  }
+
+  public void SampleDecl.Python_genSampleListEntry(Python_env env) {
+    env.println("('" + getName() + "', " + getName() + ".signature),");
+  }
+
+  public String Exp.Python_getValue() {
+   throw new Error(this.getClass().getName() + 
+                    ".Python_getValue()" + 
+                    " not declared");
+  }
+
+  public String IntegerLiteral.Python_getValue() {
+    return getValue();
+  }
+
+  public String VariableSize.Python_getValue() {
+    return "0";
+  }
+
+}
+
diff --git a/compiler/2014/RAPID_CodeGen.jrag b/compiler/2014/RAPID_CodeGen.jrag
new file mode 100644
index 0000000..b367ee5
--- /dev/null
+++ b/compiler/2014/RAPID_CodeGen.jrag
@@ -0,0 +1,369 @@
+
+aspect RAPID_env {
+	public class RAPID_env {
+                public final int version;
+		private String prefix;
+		private StringBuilder types;
+		private StringBuilder constants;
+		private StringBuilder procedures;
+		private PrintStream ps;
+
+		public RAPID_env(PrintStream ps, String prefix, int version)
+		{
+			this.version = version;
+			this.types = new StringBuilder();
+			this.constants = new StringBuilder();
+			this.procedures = new StringBuilder();
+			this.prefix = prefix;
+			this.ps = ps;
+		}
+
+		public String prefix() { return this.prefix; }
+
+		public String addRecord(String name, java.util.List<String> components)
+		{
+			String recordName = this.prefix + "_" + name;
+			types.append("\tRECORD " + recordName);
+			types.append("\n");
+			for (String c : components) {
+				types.append("\t\t" + c + "\n");
+			}
+			types.append("\tENDRECORD");
+			types.append("\n\n");
+			return recordName;
+		}
+
+		public void addConstant(String type, String name, String value) {
+			this.constants.append("\tLOCAL CONST " + type + " " + name +
+					" := " + value + ";\n");
+		}
+
+		public void addProc(String name, java.util.List<String> params,
+					java.util.List<String> stmts)
+		{
+			this.procedures.append("\tLOCAL PROC " + name + "(");
+			for (int i = 0; i < params.size(); i++) {
+				this.procedures.append(params.get(i));
+				if (i < params.size() - 1) {
+					this.procedures.append(", ");
+				}
+			}
+			this.procedures.append(")\n");
+			for (String stmt : stmts) {
+				this.procedures.append("\t\t" + stmt + "\n");
+			}
+			this.procedures.append("\tERROR\n\t\tRAISE ;\n\tENDPROC\n\n");
+		}
+
+		public void flush()
+		{
+			ps.println("MODULE " + prefix() + "(SYSMODULE)");
+			ps.println();
+			ps.print(types.toString());
+			ps.println();
+			ps.println("\tLOCAL CONST string prefix:=\"" + this.prefix + "\";");
+			ps.print(constants.toString());
+			ps.println();
+			ps.print(procedures.toString());
+			ps.println();
+			ps.print("ENDMODULE");
+		}
+	}
+}
+
+aspect RAPID_CodeGen {
+
+	public void ASTNode.RAPID_gen(RAPID_env env) {
+		throw new UnsupportedOperationException();
+	}
+
+	public void Program.RAPID_gen(String file, String prefix, int version)
+			throws IOException
+	{
+		PrintStream ps = new PrintStream(new FileOutputStream(new File(file)));
+		RAPID_env env = new RAPID_env(ps, prefix, version);
+		RAPID_gen(env);
+	}
+
+	public void Program.RAPID_gen(RAPID_env env)
+	{
+		for (int i = 0; i < getNumDecl(); i++) {
+			getDecl(i).RAPID_gen(env);
+		}
+		env.flush();
+	}
+
+	public void Decl.RAPID_gen(RAPID_env env) {
+		throw new UnsupportedOperationException("RAPID code generation (currently) does not support "+getClass().getSimpleName());
+	}
+
+	public void TypeDecl.RAPID_gen(RAPID_env env) {
+		System.out.println("***WARNING! TypeDecl.RapidGen(.) a NOP after sig reorganization.");
+		System.out.println("            (Tell a developer to) remove this warning when tested");
+	}
+
+	public void Decl.RAPID_emitFlatSignature(RAPID_env env, String sig_len_name, String sig_name) {
+		System.out.println("***WARNING! Code not tested after reorganization of signatures.");
+		System.out.println("            (Tell a developer to) remove this warning when tested");
+		SignatureList sig = flatSignature(env.version);
+		StringBuilder sb = new StringBuilder();
+		sb.append("[");
+		byte[] d = null;
+		int sig_len = 0;
+		for (int i = 0; i < sig.size(); i++) {
+			d = sig.getData(i, env.version);
+			for (int j = 0; d != null && j < d.length; j++) {
+				sb.append(d[j] + ",");
+				sig_len++;
+			}
+		}
+		sb.delete(sb.length() - 1, sb.length());
+		sb.append("]");
+		env.addConstant("num", sig_len_name, "" + sig_len);
+		env.addConstant("byte", sig_name + "{" + sig_len_name + "}",
+		sb.toString());
+	} 
+
+	public void SampleDecl.RAPID_gen(RAPID_env env) {
+		// Add type declarations
+		String fullName = getType().RAPID_AddType(env, getName());
+		// Add signature constants
+		String sig_len_name = "signature_len_" + getName();
+		String sig_name = "signature_" + getName();
+
+		RAPID_emitFlatSignature(env, sig_len_name, sig_name);
+
+		// Add decode procedures
+		ArrayList<String> params = new ArrayList<String>();
+		ArrayList<String> stmts = new ArrayList<String>();
+		params.add("VAR LabComm_Decoder_Sample s");
+		params.add("string handler");
+		stmts.add("s.prefix := prefix;");
+		stmts.add("s.name := \"" + getName() + "\";");
+		stmts.add("s.handler := handler;");
+		env.addProc("Dec_Reg_" + getName(), params, stmts);	
+
+		params.clear();
+		stmts.clear();
+		params.add("VAR LabComm_Decoder_Sample s");
+		params.add("VAR rawbytes sig");
+		params.add("num user_id");
+		stmts.add("VAR byte tmp_sig{" + sig_len_name + "};");
+		stmts.add("IF RawBytesLen(sig)<>" + sig_len_name + " THEN");
+		stmts.add("\tRETURN;");
+		stmts.add("ENDIF");
+		stmts.add("FOR i FROM 1 TO " + sig_len_name + " DO");
+		stmts.add("\tUnpackRawBytes sig, i, tmp_sig{i}, \\Hex1;");
+		stmts.add("ENDFOR");
+		stmts.add("IF tmp_sig<>" + sig_name + " THEN");
+		stmts.add("\tRETURN;");
+		stmts.add("ENDIF");
+		stmts.add("s.user_id := user_id;");
+		env.addProc("Reg_If_Signature_Of_" + getName(), params, stmts);
+
+		params.clear();
+		stmts.clear();
+		params.add("VAR Decoder d");
+		params.add("VAR LabComm_Stream st");
+		params.add("VAR LabComm_Decoder_Sample s");
+		stmts.add("VAR " + fullName + " tmp;");
+		getType().RAPID_AddDecodeInstr(env, stmts, "tmp", "st");
+		stmts.add("% s.handler % tmp;");
+		env.addProc("Decode_And_Handle_" + getName(), params, stmts);
+
+		params.clear();
+		stmts.clear();
+		params.add("VAR Encoder e");
+		params.add("VAR LabComm_Stream st");
+		params.add("VAR LabComm_Encoder_Sample s");
+		stmts.add("s.prefix := prefix;");
+		stmts.add("s.name := \"" + getName() + "\";");
+		stmts.add("Encoder_Register_Sample e, st, s;");
+		env.addProc("Enc_Reg_" + getName(), params, stmts);
+
+		params.clear();
+		stmts.clear();
+		params.add("VAR Encoder e");
+		params.add("VAR LabComm_Stream s");
+		stmts.add("VAR rawbytes buffer;");
+		stmts.add("FOR i FROM 1 TO " + sig_len_name + " DO");
+		stmts.add("\tPackRawBytes " + sig_name +
+					"{i}, buffer, \\Network, i, \\Hex1;");
+		stmts.add("ENDFOR");
+		stmts.add("SocketSend s.soc, \\RawData:=buffer, \\NoOfBytes:=" +
+					sig_len_name + ";");
+		env.addProc("Encode_Signature_" + getName(), params, stmts);
+
+		params.clear();
+		stmts.clear();
+		params.add("VAR Encoder e");
+		params.add("VAR LabComm_Stream st");
+		params.add("VAR LabComm_Encoder_Sample s");
+		params.add("VAR " + fullName + " val");
+		stmts.add("Encode_Packed st, s.user_id;");
+		getType().RAPID_AddEncodeInstr(env, stmts, "val", "st");
+		env.addProc("Encode_" + getName(), params, stmts);
+	}
+
+	public String Type.RAPID_AddType(RAPID_env env, String name) {
+		throw new UnsupportedOperationException("RAPID code generation does (currently) not support "+getClass().getSimpleName());
+	}
+
+	public String StructType.RAPID_AddType(RAPID_env env, String name) {
+		ArrayList<String> components = new ArrayList<String>();
+		for (int i = 0; i < getNumField(); i++) {
+			Field f = getField(i);
+			components.add(
+					f.getType().RAPID_AddType(env, name + "_" + f.getName()) +
+					" " + f.getName() + ";");
+		}
+		String typeName = env.addRecord(name, components);
+		return typeName;
+	}
+
+	public String FixedArrayType.RAPID_AddType(RAPID_env env, String name) {
+		String typeName = getType().RAPID_AddType(env, name + "_e");
+		if (getNumExp() > 1) {
+			throw new UnsupportedOperationException("RAPID generation only (currently) supports one-dimensional arrays");
+		}
+		ArrayList<String> components = new ArrayList<String>();
+		for (int i = 1; i <= getExp(0).RAPID_getValue(); i++) {
+			components.add(typeName + " e" + i + ";");
+		}
+		String completeName = env.addRecord("list_" + name, components);
+		return completeName;
+	}
+
+	public String PrimType.RAPID_AddType(RAPID_env env, String name) {
+		if (getToken() == LABCOMM_SHORT ||
+			getToken() == LABCOMM_FLOAT ||
+			getToken() == LABCOMM_INT) {
+			return "num";
+		} else if (getToken() == LABCOMM_LONG) {
+			return "dnum";
+		} else if (getToken() == LABCOMM_STRING) {
+			return "string";
+		} else if (getToken() == LABCOMM_BOOLEAN) {
+			return "bool";
+		} else if (getToken() == LABCOMM_BYTE) {
+			return "byte";
+		}
+		throw new UnsupportedOperationException("RAPID code generation does not (currently) support "+getName());
+	}
+
+	public void Type.RAPID_AddDecodeInstr(RAPID_env env,
+			java.util.List<String> instrs,
+			String var_name, String stream_name) {
+		throw new UnsupportedOperationException("RAPID code generation does not (currently) support "+getClass().getSimpleName());
+	}
+
+	public void StructType.RAPID_AddDecodeInstr(RAPID_env env,
+			java.util.List<String> instrs,
+			String var_name, String stream_name) {
+		for (int i = 0; i < getNumField(); i++) {
+			getField(i).getType().RAPID_AddDecodeInstr(env, instrs,
+					var_name + "." + getField(i).getName(), stream_name);
+		}
+	}
+
+	public void FixedArrayType.RAPID_AddDecodeInstr(RAPID_env env,
+			java.util.List<String> instrs,
+			String var_name, String stream_name) {
+		for (int i = 1; i <= getExp(0).RAPID_getValue(); i++) {
+			getType().RAPID_AddDecodeInstr(env, instrs,
+					var_name + ".e" + i, stream_name);
+		}
+	}
+
+	public void PrimType.RAPID_AddDecodeInstr(RAPID_env env,
+			java.util.List<String> instrs,
+			String var_name, String stream_name) {
+		switch(getToken()) {
+			case LABCOMM_BYTE:
+				instrs.add("Decode_Byte " + stream_name + "," + var_name + ";");
+				break;
+			case LABCOMM_BOOLEAN:
+				instrs.add("Decode_Bool " + stream_name + "," + var_name + ";");
+				break;
+			case LABCOMM_SHORT:
+				instrs.add("Decode_Short " + stream_name + "," + var_name + ";");
+				break;
+			case LABCOMM_INT:
+				instrs.add("Decode_Int " + stream_name + "," + var_name + ";");
+				break;
+			case LABCOMM_LONG:
+				instrs.add("Decode_Long " + stream_name + "," + var_name + ";");
+				break;
+			case LABCOMM_FLOAT:
+				instrs.add("Decode_Float " + stream_name + "," + var_name + ";");
+				break;
+			case LABCOMM_STRING:
+				instrs.add("Decode_String " + stream_name + "," + var_name + ";");
+				break;
+			default:
+				throw new UnsupportedOperationException("RAPID code generation does not (currently) support "+getName());
+		}
+	}
+
+	public void Type.RAPID_AddEncodeInstr(RAPID_env env,
+			java.util.List<String> instrs,
+			String var_name, String stream_name) {
+		throw new UnsupportedOperationException("RAPID code generation does not (currently) support "+getClass().getSimpleName());
+	}
+
+	public void StructType.RAPID_AddEncodeInstr(RAPID_env env,
+			java.util.List<String> instrs,
+			String var_name, String stream_name) {
+		for (int i = 0; i < getNumField(); i++) {
+			getField(i).getType().RAPID_AddEncodeInstr(env, instrs,
+					var_name + "." + getField(i).getName(), stream_name);
+		}
+	}
+
+	public void FixedArrayType.RAPID_AddEncodeInstr(RAPID_env env,
+			java.util.List<String> instrs,
+			String var_name, String stream_name) {
+		for (int i = 1; i <= getExp(0).RAPID_getValue(); i++) {
+			getType().RAPID_AddEncodeInstr(env, instrs,
+					var_name + ".e" + i, stream_name);
+		}
+	}
+
+	public void PrimType.RAPID_AddEncodeInstr(RAPID_env env,
+			java.util.List<String> instrs,
+			String var_name, String stream_name) {
+		switch(getToken()) {
+			case LABCOMM_BYTE:
+				instrs.add("Encode_Byte " + stream_name + "," + var_name + ";");
+				break;
+			case LABCOMM_BOOLEAN:
+				instrs.add("Encode_Bool " + stream_name + "," + var_name + ";");
+				break;
+			case LABCOMM_SHORT:
+				instrs.add("Encode_Short " + stream_name + "," + var_name + ";");
+				break;
+			case LABCOMM_INT:
+				instrs.add("Encode_Int " + stream_name + "," + var_name + ";");
+				break;
+			case LABCOMM_LONG:
+				instrs.add("Encode_Long " + stream_name + "," + var_name + ";");
+				break;
+			case LABCOMM_FLOAT:
+				instrs.add("Encode_Float " + stream_name + "," + var_name + ";");
+				break;
+			case LABCOMM_STRING:
+				instrs.add("Encode_String " + stream_name + "," + var_name + ";");
+				break;
+			default:
+				throw new UnsupportedOperationException("RAPID code generation does not (currently) support "+getName());
+		}
+	}
+
+	public int Exp.RAPID_getValue() {
+		throw new UnsupportedOperationException("RAPID code generation does not (currently) support "+getClass().getSimpleName());
+	}
+
+	public int IntegerLiteral.RAPID_getValue() {
+		return Integer.parseInt(getValue());
+	}
+}
diff --git a/compiler/2014/Signature.jrag b/compiler/2014/Signature.jrag
new file mode 100644
index 0000000..5395095
--- /dev/null
+++ b/compiler/2014/Signature.jrag
@@ -0,0 +1,236 @@
+import java.util.*;
+
+aspect Signature {  
+
+  syn boolean Decl.isSampleDecl();
+  eq TypeDecl.isSampleDecl() = false;
+  eq SampleDecl.isSampleDecl() = true;
+
+  syn boolean Decl.sendOnlyFlatSignatures(Java_env env) = (env.version==2006);
+
+  eq Decl.getSignature().parentDecl() = this;
+  eq Signature.getSignatureList().parentDecl() = parentDecl();
+
+  inh Decl Signature.parentDecl();
+  inh Decl SignatureList.parentDecl();
+
+
+  syn nta Signature Decl.getSignature() { 
+    SignatureList sl = new SignatureList();
+    genSigLineForDecl(sl, true);
+    SignatureList fsl = new SignatureList();
+    flatSignature(fsl);
+    Signature sig = new Signature();
+    sig.setSignatureList(sl);
+    sig.setFlatSignatureList(fsl);
+    setSignature(sig);
+    return sig;
+  }
+
+  public String SignatureLine.getIndentString() {
+    StringBuffer result = new StringBuffer();
+    int indent = getIndent();
+    for (int i = 0 ; i < indent ; i++) {
+      result.append("  ");
+    }
+    return result.toString();
+  }
+
+    syn byte[] SignatureLine.getData(int version) = null;
+    //  return new byte[0];
+
+    private Decl TypeRefSignatureLine.decl;
+    public TypeRefSignatureLine.TypeRefSignatureLine(int indent, Decl decl, String comment) {
+      super(indent, comment);
+      this.decl = decl;
+    }
+    public void SignatureList.addTypeRef(Decl type, String comment) {
+        addSignatureLine(new TypeRefSignatureLine(indent, type, comment));
+    }
+
+    public ByteArraySignatureLine.ByteArraySignatureLine(int indent, byte[] data, String comment) {
+      super(indent, comment);
+      setData(data);
+    }
+
+    public IntSignatureLine.IntSignatureLine(int indent, int data, String comment) {
+      super(indent, comment);
+      setData(data);
+    }
+
+    public void SignatureList.add(byte[] data, String comment) {
+      addSignatureLine(new ByteArraySignatureLine(indent, data, comment));
+    }
+
+    public void SignatureList.addInt(int data, String comment) {
+      addSignatureLine(new IntSignatureLine(indent, data, comment));
+    }
+
+    protected byte[] DataSignatureLine.getIntBytes(int value, int version) {
+      byte data[];
+      switch(version) {
+        case 2006:             // Use old encoding with 32 bit integers
+	    data = new byte[4];
+	    for (int i = 0 ; i < 4 ; i++) {
+	        data[3 - i] = (byte)((value >> (8 * i)) & 0xff);
+	    }
+	    //add(data, comment);
+        break;
+        case 2014:             // Use new encoding with varints
+	    byte[] tmp = new byte[5];
+ 	    long v = value & 0xffffffff;
+            int i, j;
+            for (i = 0 ; i == 0 || v != 0 ; i++, v = (v >> 7)) {
+		tmp[i] = (byte)(v & 0x7f);
+            }
+	    byte[] packed = new byte[i];
+            for (i = i - 1, j = 0 ; i >= 0 ; i--, j++) {
+		packed[j] = (byte)(tmp[i] | (i!=0?0x80:0x00));
+            }
+	    //add(packed, comment);
+            data = packed;
+        break;
+        default: 
+            throw new RuntimeException("Unsupported version = "+version+". This should never happen.");
+      }
+      return data;
+    }
+
+    eq IntSignatureLine.getData(int version) {
+      return getIntBytes(getData(), version);
+    }
+
+    public void SignatureList.addString(String data, String comment) {
+      addSignatureLine(new StringSignatureLine(indent, comment, data));
+    }
+    eq StringSignatureLine.getData(int version) {
+      byte[] lenBytes = getIntBytes(getData().length(), version);
+      byte[] data = new byte[lenBytes.length+getData().length()];
+
+      // first add the encoded length
+      for (int i = 0 ; i < lenBytes.length ; i++) {
+        data[i] = lenBytes[i];
+      }
+      // and then the actual chars
+      for (int i = 0 ; i < getData().length() ; i++) {
+        int idx = lenBytes.length + i;
+        data[idx] = (byte)(getData().charAt(i) & 0xff);
+      }
+      return data;
+    }
+
+    public int SignatureList.size() {
+      return getNumSignatureLine();
+    }
+
+    public String SignatureList.getIndent(int i) {
+      StringBuffer result = new StringBuffer();
+      int indent = getSignatureLine(i).getIndent();
+      for (i = 0 ; i < indent ; i++) {
+        result.append("  ");
+      }
+      return result.toString();
+    }
+
+    public byte[] SignatureList.getData(int i, int version) {
+      return getSignatureLine(i).getData(version);
+    }
+
+    public String SignatureList.getComment(int i) {
+      return getSignatureLine(i).getComment();
+    }
+
+    private int SignatureList.indent;
+
+    public void SignatureList.indent() {
+      indent++;
+    }
+
+    public void SignatureList.unindent() {
+      indent--;
+    }
+
+
+  public void ASTNode.genSigLineForDecl(SignatureList list, boolean decl) {
+    throw new Error(this.getClass().getName() + 
+                    ".genSigLineForDecl(SignatureList list)" + 
+                    " not declared");
+  }
+
+  public void TypeDecl.genSigLineForDecl(SignatureList list, boolean decl) {
+     //System.out.println("************ TypeDecl.genSigLine("+decl+").... for "+getName());
+    if(decl){
+      getType().genSigLineForDecl(list, decl);
+    }else{
+      list.addTypeRef(this, "//TODO (from list.addTypeRef)");
+    }
+  }
+
+  public void SampleDecl.genSigLineForDecl(SignatureList list, boolean decl) {
+     //System.out.println("************ SampleDecl.genSigLine("+decl+").... for "+getName());
+    getType().genSigLineForDecl(list, decl);
+  }
+
+  public void VoidType.genSigLineForDecl(SignatureList list, boolean decl) {
+    list.addInt(LABCOMM_STRUCT, "void");
+    list.addInt(0, null);
+  }
+
+  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);
+  }
+
+  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) {
+    list.addInt(LABCOMM_ARRAY, signatureComment());
+    list.indent();
+    list.addInt(getNumExp(), null);
+    for (int i = 0 ; i < getNumExp() ; i++) {
+      getExp(i).genSigLineForDecl(list, false);
+    }
+    getType().genSigLineForDecl(list, false);
+    list.unindent();
+    list.add(null, "}");
+  }
+
+  public void StructType.genSigLineForDecl(SignatureList list, boolean decl) {
+    list.addInt(LABCOMM_STRUCT, "struct { " + getNumField() + " fields");
+    list.indent();
+    list.addInt(getNumField(), null);
+    for (int i = 0 ; i < getNumField() ; i++) {
+      getField(i).genSigLineForDecl(list, false);
+    }
+    list.unindent();
+    list.add(null, "}");
+  }
+
+  public void Field.genSigLineForDecl(SignatureList list, boolean decl) {
+    list.addString(getName(), signatureComment());
+    getType().genSigLineForDecl(list, decl);
+  }
+
+  public void IntegerLiteral.genSigLineForDecl(SignatureList list, boolean decl) {
+    list.addInt(Integer.parseInt(getValue()), null);
+  }
+
+  public void VariableSize.genSigLineForDecl(SignatureList list, boolean decl) {
+    list.addInt(0, null);
+  }
+
+}
diff --git a/compiler/2014/TypeCheck.jrag b/compiler/2014/TypeCheck.jrag
new file mode 100644
index 0000000..a640ace
--- /dev/null
+++ b/compiler/2014/TypeCheck.jrag
@@ -0,0 +1,36 @@
+aspect TypeCheck {
+  public void ASTNode.typeCheck() {
+      // calls to the different type checks to be performed
+      nullTypeCheck();
+  }
+
+// void is not allowed as a field in a struct or an array element
+  
+  syn boolean Type.isNull();
+  eq Type.isNull() = false;
+  eq VoidType.isNull() = true;
+  eq UserType.isNull() = decl().isNull();
+
+  syn boolean TypeDecl.isNull();
+  eq TypeDecl.isNull() = getType().isNull();
+  
+  public void ASTNode.nullTypeCheck() {}
+ 
+  public void Field.nullTypeCheck() {
+    if(getType().isNull()) {
+      error("field " + getName() + " of struct "+ declName()+ " may not be of type void");
+    }
+  }
+
+  public void ParseArrayType.nullTypeCheck() {
+    if(getType().isNull()) {
+      error("elements of array "+declName()+" may not be of type void");
+    }
+  }
+
+  public void ArrayType.nullTypeCheck() {
+    if(getType().isNull()) {
+      error("elements of array "+declName()+" may not be of type void");
+    }
+  }
+} 
diff --git a/compiler/2014/TypeReferences.jrag b/compiler/2014/TypeReferences.jrag
new file mode 100644
index 0000000..0a7cd9b
--- /dev/null
+++ b/compiler/2014/TypeReferences.jrag
@@ -0,0 +1,46 @@
+aspect User_Types {
+  syn String Type.getTypeName();
+  eq Type.getTypeName() = getClass().getName();
+  eq PrimType.getTypeName() = getName();
+  eq UserType.getTypeName() = getName();
+
+  syn boolean Type.isUserType();
+  eq Type.isUserType() = false;
+  eq UserType.isUserType() = true;
+}
+
+aspect Type_References {
+ 
+  // The dependencies on other type declarations for a Decl.
+  coll Set<Decl> Decl.type_dependencies() [new HashSet<Decl>()] with add;
+
+  Field contributes ((UserType)getType()).decl()   
+  when parentDecl() != null && getType().isUserType()
+  to Decl.type_dependencies() 
+  for parentDecl();
+
+  UserType contributes decl()   
+  when parentDecl() != null 
+  to Decl.type_dependencies() 
+  for parentDecl();
+  /*
+  Field contributes getType().decl()   
+  when parentDecl() != null && getType().isLeafType()
+  to Decl.type_dependencies() 
+  for parentDecl();
+  */
+
+
+  // The references from other type declarations to a Decl.
+  coll Set<Decl> Decl.type_references() [new HashSet<Decl>()] with add;
+
+  Decl contributes this
+  to Decl.type_references()
+  for each type_dependencies();
+
+  syn boolean Decl.hasDependencies();
+  eq Decl.hasDependencies() = !type_dependencies().isEmpty();
+
+  syn boolean Decl.isReferenced();
+  eq Decl.isReferenced() = !type_references().isEmpty();
+}
diff --git a/compiler/2014/Version.jrag b/compiler/2014/Version.jrag
new file mode 100644
index 0000000..f080578
--- /dev/null
+++ b/compiler/2014/Version.jrag
@@ -0,0 +1,15 @@
+aspect Version {
+
+    /* An auxilliary class for handling naming and prefixes connected
+     * to the LabComm version
+     */
+    class LabCommVersion {
+        public static String versionString(int version) {
+            return (version == 2006) ? "2006" : "";
+        }       
+
+        public static boolean versionHasPragma(int version) {
+            return version != 2006;
+        }
+    }
+}
diff --git a/compiler/LabComm.java b/compiler/LabComm.java
index d323eeb..a6f4c6b 100644
--- a/compiler/LabComm.java
+++ b/compiler/LabComm.java
@@ -1,403 +1,36 @@
-import AST.*;
-import java.io.*;
-import java.util.*;
+import java.util.Vector;
 
 public class LabComm {
 
-  private static void println(String s) {
-    System.out.println(s);
-  }
-
-  private static void print_help() {
-    println("\n Usage: java -jar labcom.jar [options*] FILE");
-    println("");
-    println(" --help                  Shows this help text");
-    println(" -v                      Be verbose");
-    println(" --ver=VERSION           Generate code for labcomm VERSION (=2006 or 2013)");
-    println("[ C options ]");
-    println(" -C                      Generates C/H code in FILE.[ch]");
-    println(" --cprefix=PREFIX        Prefixes C types with PREFIX");
-    println(" --cinclude=FILE         Include FILE in generated .c");
-    println(" --c=CFILE               Generates C code in CFILE");
-    println(" --h=HFILE               Generates H code in HFILE");
-    println("[ C# options]");
-    println(" --cs                    Generates C# code in FILE.cs");
-    println(" --cs=CSFILE             Generates C# code in CSFILE");
-    println(" --csnamespace=NAMESPACE Place C# classes in NAMESPACE");
-    println("[ Java options ]");
-    println(" --java=JDIR             Generates Java files in JDIR");
-    println(" --javapackage=PACKAGE   Place Java classes in PACKAGE");
-    println("[ Python options ]");
-    println(" -P                      Generates Python code in FILE.py");
-    println(" --python=PFILE          Generates Python code in PFILE");
-    println("[ RAPID options ]");
-    println(" --rapid                 Generates RAPID code in FILE.sys");
-    println("[ Misc options ]");
-    println(" --pretty=PFILE          Pretty prints to PFILE");
-    println(" --typeinfo=TIFILE       Generates typeinfo in TIFILE");
-  }
+  public static void main(String[] args) throws Exception {
+    String ver = null;
+    Vector<String> outargs = new Vector<String>();
     
-  /** To be cleaned up.
-   */
-  private static void checkVersion(int v) {
-     if(! (v == 2006 || v == 2013) ) {
-	System.err.println(" Unknown version: " + v);
-	System.err.println(" Supported versions: 2006, 2013 ");
-	System.exit(2);
-     }
-  }
-
-  private static void genH(Program p, String hName, 
-			   Vector cIncludes, String coreName, String prefix, int ver) {
-    try {
-      FileOutputStream f;
-      PrintStream out;
-      
-      f = new FileOutputStream(hName);
-      out = new PrintStream(f);
-      p.C_genH(out, cIncludes, coreName, prefix, ver);
-      out.close();
-    } catch (IOException e) {
-      System.err.println("IOException: " + hName + " " + e);
-    }
-  }
-
-  private static void genC(Program p, String cName, 
-			   Vector cIncludes, String coreName, String prefix, int ver) {
-    try {
-      FileOutputStream f;
-      PrintStream out;
-
-      f = new FileOutputStream(cName);
-      out = new PrintStream(f);
-      p.C_genC(out, cIncludes, coreName, prefix, ver);
-      out.close();
-    } catch (IOException e) {
-      System.err.println("IOException: " + cName + " " + e);
-    }
-  }
-
-  private static void genCS(Program p, String csName, String csNamespace, int ver) {
-//      throw new Error("C# generation currently disabled");
-    try {
-      p.CS_gen(csName, csNamespace, ver);
-    } catch (IOException e) {
-      System.err.println("IOException: " + csName + " " + 
-			 csNamespace + " " + e);
-    }
-  }
-
-  private static void genJava(Program p,  String dirName, String packageName, int ver) {
-    try {
-      p.J_gen(dirName, packageName, ver);
-    } catch (IOException e) {
-      System.err.println("IOException: " + dirName + " " + 
-			 packageName + " " + e);
-    }
-  }
-
-  private static void genPython(Program p, String filename, String prefix, int ver) {
-    try {
-      FileOutputStream f;
-      PrintStream out;
-
-      f = new FileOutputStream(filename);
-      out = new PrintStream(f);
-      p.Python_gen(out, prefix, ver);
-      out.close();
-    } catch (IOException e) {
-      System.err.println("IOException: " + filename + " " + e);
-    }
-  }
-
-  private static void genRAPID(Program p, String filename, String prefix, int ver) {
-    try {
-      p.RAPID_gen(filename, prefix, ver);
-    } catch (IOException e) {
-      System.err.println("IOException: " + filename + " " + e);
-    }
-  }
-
-  /** Helper class to contain command line options 
-      and their associated behaviour
-   **/
-  private static class Opts {
-    final String[] args;
-    String coreName = null;
-    String prefix = null;
-    boolean verbose = false;
-    int ver = 2013; //Version 2013 as default
-    String cFile = null;
-    String hFile = null;
-    Vector cIncludes = new Vector();
-    String cPrefix; // gets default value (prefix) in processFilename
-    String csFile = null;
-    String csNamespace = null;
-    String javaDir = null;
-    String javaPackage = "";
-    String pythonFile = null;
-    String prettyFile = null;
-    String typeinfoFile = null;
-    String rapidFile = null;
-    String fileName = null;
-
-   Opts(String[] args) {
-     this.args = args;
-   }
-
-    private static String getCoreName(String s) {
-      int i = s.lastIndexOf('.');
-      return s.substring(0, i > 0 ? i : s.length());
-    }
-  
-    private static String getFileName(String s) {
-      return s.substring(s.lastIndexOf('/') + 1, s.length());
-    }
-  
-    private static String getBaseName(String s) {
-      s = getFileName(s);
-      int i = s.lastIndexOf('.');
-      return s.substring(0, i > 0 ? i : s.length());
-    }
-  
-    private static String getPrefix(String s) {
-      return s.substring(s.lastIndexOf('/') + 1, s.length());
-    }
-  
-    boolean processFilename(){
-      // Scan for first non-option
-      for (int i = 0 ; i < args.length ; i++) {
-        if (! args[i].startsWith("-")) {
-  	fileName = args[i];
-  	break;
-        }
-      }
-      if (fileName != null) {
-        coreName = getBaseName(fileName);
-        prefix = getPrefix(coreName);
-       cPrefix = prefix;
-      }
-      return fileName != null;
-    }
-    
-    void processArgs(){
-      for (int i = 0 ; i < args.length ; i++) {
-        if (fileName == null ||
-  	  args[i].equals("-help") || 
-  	  args[i].equals("-h") || 
-  	  args[i].equals("--help")) {
-  	print_help();
-  	System.exit(0);
-        } else if (args[i].equals("-v")) {
-  	verbose=true;
-        } else if (args[i].startsWith("--ver=")) {
-  	ver = Integer.parseInt(args[i].substring(6));
-          checkVersion(ver);
-        } else if (args[i].equals("-C")) {
-  	cFile = coreName + ".c";
-  	hFile = coreName + ".h";
-        } else if (args[i].startsWith("--cinclude=")) {
-  	cIncludes.add(args[i].substring(11));
-        } else if (args[i].startsWith("--cprefix=")) {
-  	cPrefix = args[i].substring(10);
-        } else if (args[i].startsWith("--c=")) {
-  	cFile = args[i].substring(4);
-        } else if (args[i].startsWith("--h=")) {
-  	hFile = args[i].substring(4);
-        } else if (args[i].equals("--cs")) {
-  	csFile = coreName + ".cs";
-        } else if (args[i].startsWith("--cs=")) {
-  	csFile = args[i].substring(5);
-        } else if (args[i].startsWith("--csnamespace=")) {
-  	csNamespace = args[i].substring(14);
-        } else if (args[i].startsWith("--java=")) {
-  	javaDir = args[i].substring(7);
-        } else if (args[i].startsWith("--javapackage=")) {
-  	javaPackage = args[i].substring(14);
-        } else if (args[i].equals("-P")) {
-  	pythonFile = coreName + ".py";
-        } else if (args[i].startsWith("--python=")) {
-  	pythonFile = args[i].substring(9);
-        } else if (args[i].startsWith("--pretty=")) {
-  	prettyFile = args[i].substring(9);
-        } else if (args[i].startsWith("--typeinfo=")) {
-  	typeinfoFile = args[i].substring(11);
-        } else if (args[i].equals("--rapid")) {
-  	rapidFile = coreName + ".sys";
-        } else if (i == args.length - 1) {
-  	fileName = args[i];
-        } else {
-  	System.err.println(" Unknown argument " + args[i]);
-  	print_help();
-  	System.exit(2);
+    for (String s: args) {
+      if (s.startsWith("--ver=")) {
+        String newver = s.substring(6);
+        if (ver != null && !ver.equals(newver)) {
+          throw new Exception("Mismatching versions '" + ver +
+                              "' != '" + newver);
+          
         }
+        ver = newver;
+      } else {
+        outargs.add(s);
       }
-     if(prefix==null){
-  	System.err.println("   WARNING! prefix==null");
-        prefix="";
-     }
-   }
-
-   Program parseFile(){
-     Program ast = null;
-     try {
-       // Check for errors
-       LabCommScanner scanner = new LabCommScanner(
-                                  new FileReader(fileName));
-       LabCommParser parser = new LabCommParser();
-       Program p = (Program)parser.parse(scanner);
-       Collection errors = new LinkedList();
-       p.errorCheck(errors);
-         
-       if (errors.isEmpty()) {
-         ast = p;
-       } else {
-         for (Iterator iter = errors.iterator(); iter.hasNext(); ) {
-           String s = (String)iter.next();
-           System.out.println(s);
-         }
-       }
-     } catch (FileNotFoundException e) {
-       System.err.println("Could not find file: " + fileName);
-     } catch (IOException e) {
-       System.err.println("IOException: " + fileName + " " + e);
-     } catch (beaver.Parser.Exception e) {
-       System.err.println(e.getMessage());
-     }
-     return ast;
-   }
-
-   boolean generateC(Program ast) {
-     boolean wroteFile = false; 
-     Vector hIncludes = new Vector(cIncludes);
-     if (hFile != null) {
-       cIncludes.add(hFile);
-     }
-     if (cFile != null) {
-       printStatus("C: " , cFile);
-       genC(ast, cFile, cIncludes, coreName, cPrefix, ver);
-       wroteFile = true;
-     }
-     if (hFile != null) {
-       printStatus("H: " , hFile);
-       genH(ast, hFile, hIncludes, coreName, cPrefix, ver);
-       wroteFile = true;
-     }
-     return wroteFile;
-   }
-  
-   boolean generateCS(Program ast) {
-     boolean wroteFile = false; 
-     if (csFile != null) {
-       printStatus("C#: " , csFile); 
-       genCS(ast, csFile, csNamespace, ver);
-       wroteFile = true;
-     }
-     return wroteFile;
-   }
-  
-   boolean generateJava(Program ast) {
-     boolean wroteFile = false; 
-     if (javaDir != null) {
-       printStatus("Java: " , javaDir);
-       genJava(ast, javaDir, javaPackage, ver);
-       wroteFile = true;
-     }
-     return wroteFile;
-   }
-  
-   boolean generatePython(Program ast) {
-     boolean wroteFile = false; 
-     if (pythonFile != null) {
-       printStatus("Python: " , pythonFile); 
-       genPython(ast, pythonFile, prefix, ver);
-       wroteFile = true;
-     }
-     return wroteFile;
-   }
-  
-   boolean generateRAPID(Program ast) {
-     boolean wroteFile = false; 
-     if (rapidFile != null) {
-       printStatus("RAPID: " , rapidFile);
-       genRAPID(ast, rapidFile, coreName, ver);
-       wroteFile = true;
-     }
-     return wroteFile;
-   }
-   boolean generatePrettyPrint(Program ast) {
-     boolean wroteFile = false; 
-     if (prettyFile != null) {
-       printStatus("Pretty: " , prettyFile); 
-       try {
-         FileOutputStream f = new FileOutputStream(prettyFile);
-         PrintStream out = new PrintStream(f);
-         ast.pp(out);
-         out.close();
-         wroteFile = true;
-       } catch (IOException e) {
-         System.err.println("IOException: " + prettyFile + " " + e);
-       } 
-     }
-     return wroteFile;
-   }
-  
-   boolean generateTypeinfo(Program ast) {
-     boolean wroteFile = false; 
-     if (typeinfoFile != null) {
-       printStatus("TypeInfo: " , typeinfoFile); 
-       try {
-         FileOutputStream f = new FileOutputStream(typeinfoFile);
-         PrintStream out = new PrintStream(f);
-         ast.C_info(out, cPrefix, ver);
-         ast.Java_info(out, ver);
-         ast.CS_info(out, csNamespace, ver);
-         wroteFile = true;
-       } catch (IOException e) {
-         System.err.println("IOException: " + typeinfoFile + " " + e);
-       }
-     }
-     return wroteFile;
     }
-
-    private void printStatus(String kind, String filename){
-       if (verbose) { 
-         System.err.println("Generating "+kind+": " + filename); 
-       }
+    for (String s: outargs) {
+      System.out.println(s);
     }
+    if (ver != null && ver.equals("2006")) {
+      outargs.add(0, "--ver=2006");
+      se.lth.control.labcomm2006.compiler.LabComm.main(outargs.toArray(
+                                                         new String[0]));
+    } else if (ver == null || ver.equals("2014")) {
+      outargs.add(0, "--ver=2014");
+      se.lth.control.labcomm2014.compiler.LabComm.main(outargs.toArray(
+                                                         new String[0]));
+    } 
   }
 
-
-  public static void main(String[] args) {
-    Opts opts = new Opts(args);
-    if(!opts.processFilename()) {
-      print_help();
-      System.exit(1);
-    } else {
-      opts.processArgs();
-      Program ast =  opts.parseFile();
-
-      if (ast != null) {
-	
-	boolean fileWritten = false;
-
-        fileWritten |= opts.generateC(ast);
-        fileWritten |= opts.generateCS(ast);
-        fileWritten |= opts.generateJava(ast);
-        fileWritten |= opts.generatePython(ast);
-        fileWritten |= opts.generateRAPID(ast);
-        fileWritten |= opts.generatePrettyPrint(ast);
-        fileWritten |= opts.generateTypeinfo(ast);
-
-        // if no output to files, prettyprint on stdout
-	if (!fileWritten) {
-	  ast.pp(System.out);
-	}
-      } else {
-          // Catch-all for compilation errors
-          System.err.println("Error in specification");
-          System.exit(3);
-      }
-    }
-  } 
 }
diff --git a/compiler/build.xml b/compiler/build.xml
index bcfe310..32c5448 100644
--- a/compiler/build.xml
+++ b/compiler/build.xml
@@ -23,48 +23,9 @@
 <taskdef name="beaver" classname="beaver.comp.run.AntTask" classpath="tools/beaver-ant.jar"/>
 <!-- "jastadd" is an ant task class in jastadd2.jar -->
 <taskdef name="jastadd" classname="jastadd.JastAddTask"
-classpath="tools/jastadd2.jar"/>
+         classpath="tools/jastadd2.jar"/>
 
-
-<!-- compile sources -->
-<target name="build" depends="gen">
-	<javac debug="true" nowarn="true" srcdir="." includes="**/*.java" excludes="test/** examples/**" classpath=".:${tools}/beaver-rt.jar:${tools}/junit.jar"
-   fork="true" memoryMaximumSize="128M">
-                 <!-- compilerarg value="-Xlint"/ -->
-        </javac>
-</target>
 	
-
-<!-- generate compiler source files -->
-<target name="gen">
-	<!-- create AST node types and weave aspect modules -->
-		<echo message = "Running JastAdd"/>
-		<jastadd package="${package}" rewrite="true" beaver="true" novisitcheck="true" lazyMaps="true" outdir="${basedir}">
-			<fileset dir=".">
-				<include name="**/*.ast"/>
-				<include name="**/*.jrag"/>
-				<include name="**/*.jadd"/>
-			</fileset>
-		</jastadd>
-	<!-- generate the scanner -->
-		<echo message = "Running jflex"/>
-		<jflex file="LabCommScanner.flex" outdir="AST" nobak="yes"/>
-	<!-- generate the parser phase 1, create a full .lalr specification from fragments-->
-		<echo message = "Running parser phase 1"/>
-		<concat destfile="AST/LabCommParser.all" binary="true">
-	    <fileset dir=".">
-	      <include name="*.parser"/>
-	    </fileset>
-	</concat>
-	<!-- generate the parser phase 2, translating .lalr to .beaver -->
-		<java fork="true" dir="${basedir}" classpath="${tools}/proj.jar:${tools}/beaver-rt.jar" classname="Main">
-			<arg line="AST/LabCommParser.all AST/LabCommParser.beaver"/>
-		</java>
-	<!-- generate the parser phase 3, translating .beaver to .java -->
-	<beaver file="AST/LabCommParser.beaver" terminalNames="yes" compress="yes" useSwitch="yes"/>
-</target>
-
-
 <!-- compile sources -->
 <target name="test" depends="jar">
   <echo message = "Running tests"/>
@@ -77,8 +38,10 @@ classpath="tools/jastadd2.jar"/>
 <!-- remove generated source files and .class files -->
 <target name="clean" depends="cleanGen">
      <!-- delete all .class files recursively -->
+    <delete dir="gen"/>
     <delete>
       <fileset dir="." includes="**/*.class"/>
+      <fileset dir="." includes="gen"/>
       <fileset dir="." includes="labcomm_compiler.jar"/>
     </delete>
 
@@ -87,21 +50,105 @@ classpath="tools/jastadd2.jar"/>
 
 <!-- remove generated source files and their .class files -->
 <target name="cleanGen">
-	 <delete dir="${package}"/>
+  <delete dir="${package}"/>
 </target>
 
 
 <target name="jar" depends="build">
   <jar destfile="labcomm_compiler.jar">
-    <fileset dir="." includes="LabComm*.class"/>
-    <fileset dir="." includes="AST/*.class"/>
+    <fileset dir="gen" includes="**/*.class"/>
     <zipfileset src="tools/beaver-rt.jar" includes="beaver/*.class"/>
     <manifest>
       <attribute name="Main-Class" value="LabComm"/>
     </manifest>
   </jar>
 </target>
-		  
+
+<!-- generate compiler source files -->
+<target name="gen_compiler_version">
+  <local name="package"/>
+  <local name="package_path"/>
+  <property name="package" value="se.lth.control.labcomm${version}.compiler"/>
+  <loadresource property="package_path">
+    <propertyresource name="package"/>
+    <filterchain>
+      <tokenfilter>
+        <filetokenizer/>
+        <replacestring from="." to="/"/>
+      </tokenfilter>
+    </filterchain>
+  </loadresource>  
+
+  <mkdir dir="${outdir}"/>
+
+  <!-- create AST node types and weave aspect modules -->
+  <echo message = "Running JastAdd"/>
+  <jastadd package="${package}" rewrite="true" beaver="true" 
+           novisitcheck="true" lazyMaps="true" outdir="${outdir}">
+    <fileset dir=".">
+      <include name="${version}/*.ast"/>
+      <include name="${version}/*.jrag"/>
+      <include name="${version}/*.jadd"/>
+    </fileset>
+  </jastadd>
+
+  <!-- generate the scanner -->
+  <echo message = "Running jflex -> ${package} ${package_path}"/>
+  <jflex file="${version}/LabCommScanner.flex" 
+         outdir="${outdir}/${package_path}" nobak="yes"/>
+
+  <!-- generate the parser phase 1, create a full .lalr specification 
+       from fragments-->
+  <echo message = "Running parser phase 1"/>
+  <concat destfile="${outdir}/${package_path}/LabCommParser.all" binary="true">
+    <fileset dir=".">
+      <include name="${version}/*.parser"/>
+    </fileset>
+  </concat>
+
+  <!-- generate the parser phase 2, translating .lalr to .beaver -->
+  <echo message = "translating .lalr to .beaver"/>
+  <java fork="true" dir="${basedir}" 
+        classpath="${tools}/proj.jar:${tools}/beaver-rt.jar" classname="Main">
+    <arg line="${outdir}/${package_path}/LabCommParser.all 
+               ${outdir}/${package_path}/LabCommParser.beaver"/>
+  </java>
+
+  <!-- generate the parser phase 3, translating .beaver to .java -->
+  <echo message = "translating .beaver to .java"/>
+  <beaver file="${outdir}/${package_path}/LabCommParser.beaver"
+          terminalNames="yes" compress="yes" useSwitch="yes"/>
+
+  <echo message = "compiling .java"/>
+<!--
+  <javac debug="true" srcdir="." destdir="${outdir}"
+         includes="${version}/*.java ${outdir}/${package_path}/*.java" 
+         classpath="gen:${tools}/beaver-rt.jar:${tools}/junit.jar"
+         includeantruntime="false"
+         fork="true" memoryMaximumSize="128M">
+    <!- -compilerarg value="-Xlint"/- ->
+  </javac>
+-->
+</target>
+
+<target name="build">
+  <antcall target="gen_compiler_version">
+    <param name="version" value="2006"/>
+    <param name="outdir" value="gen"/>
+  </antcall>
+  <antcall target="gen_compiler_version">
+    <param name="version" value="2014"/>
+    <param name="outdir" value="gen"/>
+  </antcall>
+  <echo message = "compiling main"/>
+  <javac debug="true" srcdir="." destdir="gen"
+         includes="*.java 2006/*.java 2014/*.java gen/**/*.java" 
+         classpath="gen:${tools}/beaver-rt.jar:${tools}/junit.jar"
+         includeantruntime="false"
+         fork="true" memoryMaximumSize="128M">
+    <!--compilerarg value="-Xlint"/-->
+  </javac>
+</target>
 
 </project>
 
diff --git a/compiler/cs_codegen.patch b/compiler/cs_codegen.patch
deleted file mode 100644
index 397a493..0000000
--- a/compiler/cs_codegen.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-*** CS_CodeGen.old	2010-06-03 13:46:00.000000000 +0200
---- CS_CodeGen.jrag	2010-06-03 14:05:00.000000000 +0200
-***************
-*** 419,424 ****
---- 419,426 ----
-      for (int i = 0 ; i < getNumExp() ; i++) {
-        String limit = getExp(i).CS_emitEncoder(env, 
-  					      name + ".GetLength(" + i + ")");
-+       env.println("{");
-+       env.indent();
-        env.println("int i_" + (baseDepth + i) + "_max = " + limit + ";");
-      }
-      String index = null;
-***************
-*** 434,439 ****
---- 436,443 ----
-      for (int i = 0 ; i < getNumExp() ; i++) {
-        env.print_for_end();
-      }
-+     env.unindent();
-+     env.println("}");
-    }
-    
-    public String Exp.CS_emitEncoder(CS_env env, String name) {
-***************
-*** 725,730 ****
---- 729,735 ----
-    public void PrimType.CS_emitType(CS_env env) {
-      switch (getToken()) {
-        case LABCOMM_STRING: { env.print("String"); } break;
-+       case LABCOMM_BOOLEAN: { env.print("bool"); } break;
-        default: { env.print(getName()); } break;
-      }
-    }
diff --git a/compiler/java_array_encode.patch b/compiler/java_array_encode.patch
deleted file mode 100644
index 684a55e..0000000
--- a/compiler/java_array_encode.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-*** Java_CodeGen.old	2010-05-31 10:13:44.000000000 +0200
---- Java_CodeGen.jrag	2010-05-31 10:22:55.000000000 +0200
-***************
-*** 445,450 ****
---- 445,452 ----
-      String prefix = "";
-      for (int i = 0 ; i < getNumExp() ; i++) {
-        String limit = getExp(i).Java_emitEncoder(env, name + prefix);
-+       env.println("{");
-+       env.indent();
-        env.println("int i_" + (baseDepth + i) + "_max = " + limit + ";");
-        prefix = prefix + "[0]";
-      }
-***************
-*** 456,461 ****
---- 458,465 ----
-      for (int i = 0 ; i < getNumExp() ; i++) {
-        env.print_for_end();
-      }
-+     env.unindent();
-+     env.println("}");
-    }
-    
-    public String Exp.Java_emitEncoder(Java_env env, String name) {
-- 
GitLab