Skip to content
Snippets Groups Projects
C_CodeGen.jrag 37.4 KiB
Newer Older
Anders Nilsson's avatar
Anders Nilsson committed
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 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 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;
Anders Nilsson's avatar
Anders Nilsson committed

    private C_env(String qualid, String lcName, String rawPrefix, 
		  int indent, int depth, C_printer printer, int nestedLevel) {
Anders Nilsson's avatar
Anders Nilsson committed
      this.qualid = qualid;
      this.lcName = lcName;
      this.rawPrefix = rawPrefix;
      if (rawPrefix.equals("")) {
        this.prefix = rawPrefix;
      } else {
        this.prefix = rawPrefix + "_";
      }
Anders Nilsson's avatar
Anders Nilsson committed
      this.indent = indent;
      this.depth = depth;
      this.printer = printer;
Anders Nilsson's avatar
Anders Nilsson committed
    }

    public C_env(String qualid, String lcName, String rawPrefix, 
		 PrintStream out) {
      this.qualid = qualid;
      this.lcName = lcName;
      this.rawPrefix = rawPrefix;
      if (rawPrefix.equals("")) {
        this.prefix = rawPrefix;
      } else {
        this.prefix = rawPrefix + "_";
      }
Anders Nilsson's avatar
Anders Nilsson committed
      this.depth = 0;
      this.indent = 0;
      this.printer = new C_printer(out);
      this.nestedLevel = 0;
    }

    public C_env(String qualid, String lcName, String rawPrefix,
		 int indent, int depth, C_printer printer) {
      this(qualid, lcName, rawPrefix, indent, depth, printer, 0);
Anders Nilsson's avatar
Anders Nilsson committed
    }

    public C_env nestArray(String suffix) {
      return new C_env(qualid + suffix, lcName, rawPrefix, 
		       indent, depth + 1, printer, nestedLevel + 1);
Anders Nilsson's avatar
Anders Nilsson committed
    }

    public C_env nestStruct(String suffix) {
      return new C_env(qualid + suffix, lcName, rawPrefix, 
		       indent, depth, printer, nestedLevel + 1);
Anders Nilsson's avatar
Anders Nilsson committed
    }

    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(String s) {
      printer.println(this, s);
    }

    public C_env setPointer() {
      rootIsPointer = true;
      rootLevel = nestedLevel;
      return this;
    }

    public String memeberAccessor() {
      return (rootIsPointer && (nestedLevel == rootLevel)) ? "->" : ".";
    }
Anders Nilsson's avatar
Anders Nilsson committed
  }

  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.memeberAccessor() + "a";
Anders Nilsson's avatar
Anders Nilsson committed
    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.memeberAccessor() + "a[i_" + env.depth + "]");
Anders Nilsson's avatar
Anders Nilsson committed
  }


}

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) {
    C_env env = new C_env("", lcName, prefix, out);

    // 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
Tommy Olofsson's avatar
Tommy Olofsson committed
    // env.println("#include <stdint.h>");
Anders Nilsson's avatar
Anders Nilsson committed
    env.println("#include \"labcomm.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) {
    C_env env = new C_env("", lcName, prefix, out);

    // Include
    env.println("#include \"labcomm.h\"");
    env.println("#include \"labcomm_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);
Anders Nilsson's avatar
Anders Nilsson committed
      getDecl(i).C_emitEncoderDeclaration(env);
      getDecl(i).C_emitSizeofDeclaration(env);
      env.println("");
    }
Anders Blomdell's avatar
Anders Blomdell committed
    C_emitConstructorDeclaration(env);
Anders Nilsson's avatar
Anders Nilsson committed
    C_emitForAll(env);
  }

  public void Program.C_emitC(C_env env) {
    for (int i = 0; i < getNumDecl(); i++) {
Anders Nilsson's avatar
Anders Nilsson committed
      getDecl(i).C_emitDecoder(env);
      getDecl(i).C_emitDecoderRegisterHandler(env);
      getDecl(i).C_emitDecoderIoctl(env);
Anders Nilsson's avatar
Anders Nilsson committed
      getDecl(i).C_emitEncoder(env);
      getDecl(i).C_emitEncoderRegisterHandler(env);
      getDecl(i).C_emitEncoderIoctl(env);
Anders Nilsson's avatar
Anders Nilsson committed
      getDecl(i).C_emitSizeof(env);
Anders Nilsson's avatar
Anders Nilsson committed
    }
Anders Nilsson's avatar
Anders Nilsson committed
  }
 
}

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");
  }

  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;
Anders Nilsson's avatar
Anders Nilsson committed
      case LABCOMM_STRING: { env.print("char*"); } 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) {
Anders Nilsson's avatar
Anders Nilsson committed
  }

  public void SampleDecl.C_emitDecoderDeclaration(C_env env) {
    env.println("int labcomm_decoder_register_" + 
Anders Nilsson's avatar
Anders Nilsson committed
		env.prefix + getName() + "(");
    env.indent();
    env.println("struct labcomm_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_decoder_ioctl_" + env.prefix + getName() + "(");
    env.indent();
    env.println("struct labcomm_decoder *d,");
    env.println("int ioctl_action,");
    env.println("...");
    env.unindent();
    env.println(");");
Anders Nilsson's avatar
Anders Nilsson committed
  }
  
  public void Decl.C_emitEncoderDeclaration(C_env env) {
  }

  public void SampleDecl.C_emitEncoderDeclaration(C_env env) {
    env.println("int labcomm_encoder_register_" + 
Anders Nilsson's avatar
Anders Nilsson committed
		env.prefix + getName() + "(");
    env.indent();
    env.println("struct labcomm_encoder *e);");
    env.unindent();

    env.println("int labcomm_encode_" + env.prefix + getName() + "(");
Anders Nilsson's avatar
Anders Nilsson committed
    env.indent();
    env.println("struct labcomm_encoder *e,");
    env.println(env.prefix + getName() + " *v");
    env.unindent();
    env.println(");");

    env.println("int labcomm_encoder_ioctl_" + env.prefix + getName() + "(");
    env.indent();
    env.println("struct labcomm_encoder *e,");
    env.println("int ioctl_action,");
    env.println("...");
    env.unindent();
    env.println(");");
Anders Nilsson's avatar
Anders Nilsson committed
  }

}

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.memeberAccessor() + "n_" + i;
Anders Nilsson's avatar
Anders Nilsson committed
  }
  
}

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() + "(");
Anders Nilsson's avatar
Anders Nilsson committed
    env.indent();
    env.println("struct labcomm_reader *r,");
Anders Nilsson's avatar
Anders Nilsson committed
    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.println(env.qualid + " = labcomm_read_" + getName() + "(r);");
Anders Nilsson's avatar
Anders Nilsson committed
  }

  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_read_packed32(r);");
Anders Nilsson's avatar
Anders Nilsson committed
  }

  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_memory_alloc(r->memory, 1, sizeof(" + 
	      env.qualid + ".a[0])");
Anders Nilsson's avatar
Anders Nilsson committed
    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_memory_free(r->memory, 1, " + 
                  env.qualid + ");");
Anders Nilsson's avatar
Anders Nilsson committed
    }
  }

  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_memory_free(r->memory, 1, " + 
                env.qualid + ".a);");
Anders Nilsson's avatar
Anders Nilsson committed
  }

  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_decoder_register_" + 
Anders Nilsson's avatar
Anders Nilsson committed
		env.prefix + getName() + "(");
    env.indent();
    env.println("struct labcomm_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_internal_decoder_register(");
Anders Nilsson's avatar
Anders Nilsson committed
    env.indent();
    env.println("d,");
    env.println("&labcomm_signature_" + env.prefix + getName() + ",");
    env.println("(labcomm_decoder_function)decode_" + env.prefix + getName() + ",");
    env.println("(labcomm_handler_function)handler,");
Anders Nilsson's avatar
Anders Nilsson committed
    env.println("context");
    env.unindent();
    env.println(");");
    env.unindent();
    env.println("}");
  }

}

aspect C_copy {

  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();
    env_src.println("static void copy_" + env_src.prefix + getName() + "(");
    env_src.indent();
    env_src.println("struct labcomm_memory *mem ,");
    env_src.println(env_src.prefix + getName() + " *" + dst + ",");
    env_src.println(env_src.prefix + getName() + " *" + src);
    env_src.unindent();
    env_src.println(")");
    env_src.println("{");
    env_src.indent();
    getType().C_emitCopy(env_src, env_dst);
    // if (C_isDynamic()) {
    //   env_src.println("{");
    //   env_src.indent();
    //   getType().C_emitCopyDeallocation(env_src);
    //   env_src.unindent();
    //   env_src.println("}");
    // }
    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) {
    env_src.println(env_dst.qualid + " = " + 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);
    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.memeberAccessor() + getName();
    getType().C_emitCopy(env_src.nestStruct(fnam), env_dst.nestStruct(fnam));
  }

  public void Exp.C_emitCopyDecodeLimit(C_env env, int i) {
  }

  public void VariableSize.C_emitCopyDecodeLimit(C_env env_src, int i,
						 C_env env_dst)
  {
    String index = ".n_" + i;
    env_src.println(env_dst.qualid + index + " = " + env_src.qualid + index + ";");
  }

  public void ArrayType.C_emitCopyDecodeLimit(C_env env) {
    for (int i = 0 ; i < getNumExp() ; i++) {
      getExp(i).C_emitCopyDecodeLimit(env, 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)
  {
    String access = (env_dst.nestedLevel == 1) ? "->" : ".";
    env_src.print(env_dst.qualid + env_dst.memeberAccessor() +
	      "a = labcomm_memory_alloc(mem, 1, sizeof(" +
		  env_src.qualid + env_src.memeberAccessor() + "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 

  public void Type.C_emitCopyDeallocation(C_env env) {
    throw new Error(this.getClass().getName() + 
  		    ".C_emitCopyDeallocation(C_env env)" + 
  		    " not declared");
  }

  public void PrimType.C_emitCopyDeallocation(C_env env) {
    if (C_isDynamic()) {
      env.println("labcomm_memory_free(mem, 1, " + 
                  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_memory_free(r->memory, 1, " + 
                env.qualid + ".a);");
  }

  public void Field.C_emitCopyDeallocation(C_env env) {
    getType().C_emitCopyDeallocation(env.nestStruct("." + 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_decoder_ioctl_" + env.prefix + getName() + "(");
    env.indent();
    env.println("struct labcomm_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_internal_decoder_ioctl(");
    env.indent();
    env.println("d, &labcomm_signature_" + env.prefix + getName() + ", ");
    env.println("ioctl_action, va);");
    env.unindent();
    env.println("va_end(va);");
    env.println("return result;");
    env.unindent();
    env.println("}");
  }
}

Anders Nilsson's avatar
Anders Nilsson committed

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) {
  }

  public void SampleDecl.C_emitEncoder(C_env env) {
    env = env.nestStruct("(*v)");
    env.println("static int encode_" + env.prefix + getName() + "(");
Anders Nilsson's avatar
Anders Nilsson committed
    env.indent();
    env.println("struct labcomm_writer *w,");
Anders Nilsson's avatar
Anders Nilsson committed
    env.println(env.prefix + getName() + " *v");
    env.unindent();
    env.println(")");
    env.println("{");
    env.indent();
    env.println("int result = 0;");
Anders Nilsson's avatar
Anders Nilsson committed
    getType().C_emitEncoder(env);
    env.println("return result;");
Anders Nilsson's avatar
Anders Nilsson committed
    env.unindent();
    env.println("}");

    // Typesafe encode wrapper
    env.println("int labcomm_encode_" + env.prefix + getName() + "(");
    env.println("struct labcomm_encoder *e,");
Anders Nilsson's avatar
Anders Nilsson committed
    env.println(env.prefix + getName() + " *v");
    env.unindent();
    env.println(")");
    env.println("{");
    env.indent();
    env.println("return labcomm_internal_encode(e, &labcomm_signature_" + 
		env.prefix + getName() + 
		", (labcomm_encoder_function)encode_" + env.prefix + getName() +
Anders Nilsson's avatar
Anders Nilsson committed
    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;");
Anders Nilsson's avatar
Anders Nilsson committed
  }

  public void PrimType.C_emitEncoder(C_env env) {
    env.println("result = labcomm_write_" + getName() + 
                "(w, " + env.qualid + ");");
    env.println("if (result != 0) { return result; }");
Anders Nilsson's avatar
Anders Nilsson committed
  }

  public void UserType.C_emitEncoder(C_env env) {
    lookupType(getName()).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) {
  }