diff --git a/bin/precompile.pike b/bin/precompile.pike
index 3684e070f35881a62d9ad18d947c578c9ff8a5d4..761794a2ca6f999668ba3210d27be5a6b77c91c2 100644
--- a/bin/precompile.pike
+++ b/bin/precompile.pike
@@ -6,17 +6,22 @@
  *
  * The input can look something like this:
  *
- * PIKEFUNC int function_name (int x)
- *  attribute;
- *  attribute value;
+ * PIKECLASS fnord 
+ *  attributes;
  * {
- *   C code using 'x'.
  *
- *   RETURN x;
+ *   PIKEFUNC int function_name (int x)
+ *    attribute;
+ *    attribute value;
+ *   {
+ *     C code using 'x'.
+ *
+ *     RETURN x;
+ *   }
  * }
  *
- * All the ADD_EFUN/ADD_FUNCTION calls will be inserted instead of the
- * word INIT in your code.
+ * All the begin_class/ADD_EFUN/ADD_FUNCTION calls will be inserted
+ * instead of the word INIT in your code.
  *
  * Currently, the following attributes are understood:
  *   efun;     makes this function a global constant (no value)
@@ -29,7 +34,7 @@
  * BUGS/LIMITATIONS
  *  o Parenthesis must match, even within #if 0
  *  o Not all Pike types are supported yet
- *  o Line numbers are wrong after INIT
+ *  o No support for class variables yet
  */
 
 #define PC Parser.C
@@ -151,6 +156,7 @@ mapping(string:string) parse_arg(array x)
   if(sizeof(ret->type/({"|"}))>1)
     ret->basetype="mixed";
   ret->ctype=cname(ret->basetype);
+  ret->typename=merge(recursive(strip_type_assignments,ret->type));
   return ret;
 }
 
@@ -201,6 +207,7 @@ string convert_type(array s)
   }
 }
 
+
 string make_pop(mixed howmany)
 {
   switch(howmany)
@@ -241,7 +248,7 @@ array strip_type_assignments(array data)
   int pos;
 
   while( (pos=search(data,PC.Token("=",0))) != -1)
-    data=data[pos-2]+data[pos+1];
+    data=data[..pos-2]+data[pos+1..];
   return data;
 }
 
@@ -352,7 +359,6 @@ array convert(array x)
 //    werror("  args=%O\n",args);
 
     ret+=({
-      sprintf("\n#line %d %O\n",rettype[0]->line,file),
       sprintf("void f_%s(INT32 args) {\n",name),
     });
 
@@ -360,13 +366,11 @@ array convert(array x)
 
     foreach(args, mapping arg)
       ret+=({
-//	sprintf("\n#line %d %O\n",rettype[0]->line,file),
 	sprintf("%s %s;\n",arg->ctype, arg->name)
       });
 
 
     addfuncs+=({
-      sprintf("\n#line %d %O\n",rettype[0]->line,file),
       sprintf("  %s(%O,f_%s,tFunc(%s,%s),%s);\n",
 	      attributes->efun ? "ADD_EFUN" : "ADD_FUNCTION",
 	      name,
@@ -383,7 +387,6 @@ array convert(array x)
 
     argnum=0;
     ret+=({
-//      sprintf("\n#line %d %O\n",rettype[0]->line,file),
       sprintf("if(args != %d) wrong_number_of_args_error(%O,args,%d);\n",
 	      sizeof(args),
 	      name,
@@ -393,7 +396,6 @@ array convert(array x)
     int sp=-sizeof(args);
     foreach(args, mapping arg)
       {
-//	ret+=({ sprintf("\n#line %d %O\n",rettype[0]->line,file), });
 	if(arg->basetype != "mixed")
 	{
 	  ret+=({
@@ -402,7 +404,7 @@ array convert(array x)
 	    sprintf("  SIMPLE_BAD_ARG_ERROR(%O,%d,%O);\n",
 		    name,
 		    argnum+1,
-		    merge(arg->type)),
+		    arg->typename),
 	  });
 	}
 
@@ -448,7 +450,6 @@ array convert(array x)
     if(sizeof(body))
     {
       ret+=({
-	sprintf("#line %d %O\n",body[0]->line,file),
 	body,
       });
     }
@@ -458,10 +459,7 @@ array convert(array x)
 
     if(sizeof(rest))
     {
-      ret+=({
-	sprintf("#line %d %O\n",rest[0]->line,file),
-      })+
-	recursive(replace,rest,PC.Token("INIT",0),addfuncs);
+      ret+=recursive(replace,rest,PC.Token("INIT",0),addfuncs);
     }
       
   }
@@ -476,10 +474,10 @@ int main(int argc, array(string) argv)
   file=argv[1];
   x=Stdio.read_file(file);
   x=PC.split(x);
-  x=PC.tokenize(x);
+  x=PC.tokenize(x,file);
   x=PC.group(x);
 
   x=convert(x);
 
-  write(merge(x[0]));
+  write(PC.reconstitute_with_line_numbers(x[0]));
 }
diff --git a/lib/modules/Parser.pmod/C.pmod b/lib/modules/Parser.pmod/C.pmod
index 90e6c54c8ad9cbaacb21a05026e0979d7bebc9fc..b31026e29c1fa044d3c757a80ec540b7ce3402de 100644
--- a/lib/modules/Parser.pmod/C.pmod
+++ b/lib/modules/Parser.pmod/C.pmod
@@ -189,12 +189,13 @@ class Token
 {
   int line;
   string text;
-  /* string file; */
+  string file;
 
-  void create(string t, int l)
+  void create(string t, int l, void|string f)
     {
       text=t;
       line=l;
+      file=f;
     }
 
   string _sprintf(int how)
@@ -204,7 +205,7 @@ class Token
 	case 's':
 	  return text;
 	case 'O':
-	  return sprintf("Token(%O,%d)",text,line);
+	  return sprintf("Token(%O,%O,%d)",text,file,line);
       }
     }
 
@@ -222,15 +223,20 @@ class Token
     {
       return predef::`+(@s,text);
     }
+
+  mixed _cast(string to)
+    {
+      if(to=="string") return text;
+    }
 }
 
-array(Token) tokenize(array(string) s)
+array(Token) tokenize(array(string) s, void|string file)
 {
   array(Token) ret=allocate(sizeof(s));
   int line=1;
   for(int e=0;e<sizeof(s);e++)
   {
-    ret[e]=Token(s[e],line);
+    ret[e]=Token(s[e],line,file);
     line+=sizeof(s[e]/"\n")-1;
   }
   return ret;
@@ -276,3 +282,29 @@ string simple_reconstitute(array(Token) tokens)
 {
   return FLATTEN(tokens->text) * "";
 }
+
+string reconstitute_with_line_numbers(array(string|object(Token)|array) tokens)
+{
+  int line=1;
+  string file;
+  string ret="";
+  foreach(FLATTEN(tokens), mixed tok)
+    {
+      if(objectp(tok))
+      {
+	if((tok->line && tok->line != line) ||
+	   (tok->file && tok->file != file))
+	{
+	  if(strlen(ret) && ret[-1]!='\n') ret+="\n";
+	  ret+=sprintf("#line %d %O\n",tok->line,tok->file);
+	  line=tok->line;
+	  file=tok->file;
+	}
+	tok=tok->text;
+      }
+      ret+=tok;
+      line+=sizeof(tok/"\n")-1;
+    }
+
+  return ret;
+}
diff --git a/src/builtin.cmod b/src/builtin.cmod
index c1d8d80aa89180e909325ac97d96a676a4a385fc..cede3d048a24f42e2b2ca49a20f017da9d904a2e 100644
--- a/src/builtin.cmod
+++ b/src/builtin.cmod
@@ -101,5 +101,5 @@ PIKEFUN mapping(1:2) mkmapping(array(1=mixed) a, array(2=mixed) b)
 
 void init_builtin(void)
 {
-  INIT;
+INIT
 }