Patchwork [gccgo] Support //line comments

login
register
mail settings
Submitter Ian Taylor
Date Sept. 12, 2010, 6:32 a.m.
Message ID <mcrocc35v51.fsf@google.com>
Download mbox | patch
Permalink /patch/64544/
State New
Headers show

Comments

Ian Taylor - Sept. 12, 2010, 6:32 a.m.
By convention, a Go comment of the form //line FILE:LINENO is the
equivalent of a C #line comment.  This patch implements that for gccgo.
Committed to gccgo branch.

Ian
Basile Starynkevitch - Sept. 12, 2010, 7:02 a.m.
On Sat, 11 Sep 2010 23:32:58 -0700
Ian Lance Taylor <iant@google.com> wrote:

> By convention, a Go comment of the form //line FILE:LINENO is the
> equivalent of a C #line comment.  This patch implements that for gccgo.
> Committed to gccgo branch.

I don't use Go yet (even if I liked reading its specification &
documentation) but, as someone who did wrote significant source code
generators (notably the GCC MELT branch and plugin see
http://gcc.gnu.org/wiki/MELT for more) I would suggest an advice.  

There are lots of code generators which generate several lines of
generated code per line of their input code. So it would help these to
be able to say that a given chunk of lines of code is orginated from
the same position.

So an hypothetical code generator would not have to generate
  //line "ab.cd":3
  x23 = 2 + z;
  //line "ab.cd":3
  x34 = 3 * y;
  //line "ab.cd":3
  y = x23 + x34;
  //line "ab.cd":3
  if (y < 0) y=0;
  //line "ab.cd":3
  if (z > x34) z=x34;
I assume above is correct Go syntax. 

If it is generated C it would be
  #line "ab.cd" 3
  x23 = 2 + z;
  #line "ab.cd" 3
  x32 = 3 * y;
  #line "ab.cd" 3
  y = x23 + x34;
  #line "ab.cd" 3
  if (y < 0) y = 0;
  #line "ab.cd" 3
  if (z > x34) z=x34;

I am suggesting to accept in Go two new magical
comments //startsamelines & //endsamelines and generate  
   //startsamelines "ab.cd":3
   x23 = 2 + z;
   x34 = 3 * y;
   y = x23 + x33;
   if (y < 0) y = 0;
   if (z > x34) z=x34;
   //endsamelines
this in addition of your //line proposal.

Within GCC, the suggestions could be to have pragmas
   #pragma GCC startsamelines "ab.cd":3
   x23 = 2 + z;
   x34 = 3 * y;
   y = x23 + x33;
   if (y < 0) y = 0;
   if (z > x34) z=x34;
   #pragma GCC endsamelines
   
And these chunks of code will have the same effect as the previous with
only //line for Go & #line for C. The proposed trick avoid the
generator to have to emit the same //line comment in Go or #line
directive in C for every line generated for the same source position.

Regards.
Ian Taylor - Sept. 13, 2010, 4:38 a.m.
Basile Starynkevitch <basile@starynkevitch.net> writes:

> I am suggesting to accept in Go two new magical
> comments //startsamelines & //endsamelines and generate  
>    //startsamelines "ab.cd":3
>    x23 = 2 + z;
>    x34 = 3 * y;
>    y = x23 + x33;
>    if (y < 0) y = 0;
>    if (z > x34) z=x34;
>    //endsamelines
> this in addition of your //line proposal.

Thanks for the suggestion, but I don't think the benefit is worth adding
the feature.  It should be easy enough for the code generator to simply
put all the generated lines on the same line of the generated source
file--it should be as simple as generating a semicolon instead of a
newline.  After all, generated code is rarely read, and the compiler
doesn't care.  In that cases where that is impossible for some reason, I
don't think it is much of a hardship for the code generator to generate
multiple //line comments.

Ian

Patch

diff -r 54b04d338c19 go/lex.cc
--- a/go/lex.cc	Fri Sep 10 16:18:13 2010 -0700
+++ b/go/lex.cc	Sat Sep 11 23:29:35 2010 -0700
@@ -448,7 +448,6 @@ 
 Lex::~Lex()
 {
   delete[] this->linebuf_;
-  linemap_add(line_table, LC_LEAVE, 0, NULL, 0);
 }
 
 // Read a new line from the file.
@@ -1579,6 +1578,44 @@ 
 {
   const char* p = this->linebuf_ + this->lineoff_;
   const char* pend = this->linebuf_ + this->linesize_;
+
+  // By convention, a C++ comment at the start of the line of the form
+  //   //line FILE:LINENO
+  // is interpreted as setting the file name and line number of the
+  // next source line.
+
+  if (this->lineoff_ == 2
+      && pend - p > 5
+      && memcmp(p, "line ", 5) == 0)
+    {
+      p += 5;
+      while (p < pend && *p == ' ')
+	++p;
+      const char* pcolon = static_cast<const char*>(memchr(p, ':', pend - p));
+      if (pcolon != NULL
+	  && pcolon[1] >= '0'
+	  && pcolon[1] <= '9')
+	{
+	  char* plend;
+	  long lineno = strtol(pcolon + 1, &plend, 10);
+	  if (plend > pcolon + 1
+	      && (plend == pend
+		  || *plend < '0'
+		  || *plend > '9'))
+	    {
+	      unsigned int filelen = pcolon - p;
+	      char* file = new char[filelen + 1];
+	      memcpy(file, p, filelen);
+	      file[filelen] = '\0';
+
+	      linemap_add(line_table, LC_ENTER, 0, file, lineno);
+	      this->lineno_ = lineno - 1;
+
+	      p = plend;
+	    }
+	}
+    }
+
   while (p < pend)
     {
       this->lineoff_ = p - this->linebuf_;