#
#
# Create tables so that we can lookup ANSI C objects and functions in
# an object file (by reading nm output from stdin).
#
# This tool makes assumptions compatible with ANSI C. Unfortunately
# this implies that we need to rely on ANSI C features.

function sort(V, N, 	                        tmp, i, j) {
  V[-1] = ""; # Used as a sentinel before V[0].
  for (i = 1; i < N; i++) 
    for (j = i; V[j - 1] > V[j]; j--) { 
      tmp = V[j];
      V[j] = V[j - 1];
      V[j - 1] = tmp;
    }
  return;
}

BEGIN {
 ndata = ntext = 0;
 builtin["sym_function"] = "sym_func_t sym_function(const char *)";
 builtin["sym_object"] = "void *sym_object(const char *)";
#
 builtin["printf"] =	"int printf(const char *, ...)";
 builtin["sprintf"] =	"int sprintf(char *, const char *, ...)";
 builtin["malloc"] =	"void *malloc()";
 builtin["memcpy"] =	"void *memcpy()";
 builtin["memset"] =	"void *memset()";
 builtin["memmove"] =	"void *memmove()";
 builtin["strcpy"] =	"char *strcpy()";
#
 builtin["sin"] =	"double sin()";
 builtin["cos"] =	"double cos()";
 builtin["sinf"] =	"float sinf(float)";
 builtin["cosf"] =	"float cosf(float)";
 builtin[""] = 	"";
}

# DATA or TEXT (ignored)
/^[0123456789abcdef]+ [AVWw] / { 
  print "/* " $1 " " $2 " " $3 " */";
}

# DATA
/^[0123456789abcdef]+ [BCDGRS] / { 
  if ($3 != "sym_obj" && $3 != "sym_obj_nelts" &&
      $3 != "sym_func" && $3 != "sym_func_nelts") {
    data[ndata++] = $3;
  }
}

# TEXT
/^[0123456789abcdef]+ [T] / { 
  if ($3 != "sym_obj" && $3 != "sym_obj_nelts" &&
      $3 != "sym_func" && $3 != "sym_func_nelts") {
    text[ntext++] = $3;
  }
}

END {
  sort(data, ndata);
  sort(text, ntext);

  print "#ifdef __AVR__"
  print "#define PROGMEM __attribute__((__progmem__))"
  print "#else"
  print "#define PROGMEM"
  print "#endif"
  print "#include \"loader/sym.h\"";

  print "";
  for (x = 0; x < ndata; x++) {
    print "static const PROGMEM char __D"x"[] = \""data[x]"\";";
  }

  # Extern decls. Must deal with compiler builtins etc.
  print "";
  for (x = 0; x < ndata; x++) {
    if (builtin[data[x]] != "")
      print builtin[data[x]] ";";
    else
      print "extern int " data[x]";";
  }

  print "";
  print "const int sym_obj_nelts = " ndata ";";
  print "PROGMEM const struct sym_bol sym_obj[" ndata "] = {";
  for (x = 0; x < ndata; x++)
    print "  { (const char *)__D"x", { .obj = (void *)&" data[x] " } },";
  print "};";

  print "";
  for (x = 0; x < ntext; x++) {
    print "static const PROGMEM char __T"x"[] = \""text[x]"\";";
  }

  # Extern decls. Must deal with compiler builtins etc.
  print "";
  for (x = 0; x < ntext; x++) {
    if (builtin[text[x]] != "")
      print builtin[text[x]] ";";
    else
      print "extern int " text[x]"();";
  }

  print "";
  print "const int sym_func_nelts = " ntext ";";
  print "PROGMEM const struct sym_bol sym_func[" ntext "] = {";
  for (x = 0; x < ntext; x++)
    print "  { (const char *)__T"x", { .func = (sym_func_t)&" text[x] " } },";
  print "};";
}