]> Cypherpunks repositories - gostls13.git/commitdiff
try to do better line number reporting
authorRuss Cox <rsc@golang.org>
Wed, 19 Aug 2009 22:18:08 +0000 (15:18 -0700)
committerRuss Cox <rsc@golang.org>
Wed, 19 Aug 2009 22:18:08 +0000 (15:18 -0700)
in the presence of yacc lookahead.
better but still not perfect

R=ken
OCL=33541
CL=33541

src/cmd/gc/dcl.c
src/cmd/gc/export.c
src/cmd/gc/go.h
src/cmd/gc/go.y
src/cmd/gc/lex.c
src/cmd/gc/subr.c
test/import1.go

index 199f5369a1cf529ad59914981f08bb76d5f3cafd..684697fbb9701ffda0b0c8a9938500460d26b403 100644 (file)
@@ -146,6 +146,14 @@ testdclstack(void)
        }
 }
 
+void
+redeclare(Sym *s, char *where)
+{
+       yyerror("%S redeclared %s\n"
+               "\tprevious declaration at %L",
+               s, where, s->lastlineno);
+}
+
 /*
  * declare individual names - var, typ, const
  */
@@ -153,7 +161,6 @@ void
 declare(Node *n, int ctxt)
 {
        Sym *s;
-       char *what;
        int gen;
        static int typegen, vargen;
 
@@ -177,25 +184,11 @@ declare(Node *n, int ctxt)
        if(ctxt == PAUTO)
                n->xoffset = BADWIDTH;
 
-       if(s->block == block) {
-               what = "???";
-               switch(n->op) {
-               case ONAME:
-                       what = "variable";
-                       break;
-               case OLITERAL:
-                       what = "constant";
-                       break;
-               case OTYPE:
-                       what = "type";
-                       break;
-               }
+       if(s->block == block)
+               redeclare(s, "in this block");
 
-               yyerror("%s %S redeclared in this block %d", what, s, block);
-               print("\tprevious declaration at %L\n", s->lastlineno);
-       }
        s->block = block;
-       s->lastlineno = lineno;
+       s->lastlineno = parserline();
        s->def = n;
        n->vargen = gen;
        n->funcdepth = funcdepth;
@@ -731,10 +724,8 @@ typedcl2(Type *pt, Type *t)
 
        if(pt->etype == TFORW)
                goto ok;
-       if(!cvttype(pt, t)) {
-               yyerror("redeclaration of %T during imports", pt);
-               return;
-       }
+       if(!cvttype(pt, t))
+               yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t);
        return;
 
 ok:
@@ -743,6 +734,7 @@ ok:
        pt->method = nil;
        pt->nod = n;
        pt->sym = n->sym;
+       pt->sym->lastlineno = parserline();
        declare(n, PEXTERN);
 
        checkwidth(pt);
index 1d5253ff5f23412173fc31828a7b0f4e4165e781..65f537c83ccf47db75ff8eb136181a9f442ab55f 100644 (file)
@@ -258,15 +258,8 @@ dumpexport(void)
 Sym*
 importsym(Sym *s, int op)
 {
-       if(s->def != N && s->def->op != op) {
-               // Clumsy hack for
-               //      package parser
-               //      import "go/parser"      // defines type parser
-               if(s == lookup(package))
-                       s->def = N;
-               else
-                       yyerror("redeclaration of %lS during import", s, s->def->op, op);
-       }
+       if(s->def != N && s->def->op != op)
+               redeclare(s, "during import");
 
        // mark the symbol so it is not reexported
        if(s->def == N) {
@@ -349,7 +342,7 @@ importvar(Sym *s, Type *t, int ctxt)
        if(s->def != N && s->def->op == ONAME) {
                if(cvttype(t, s->def->type))
                        return;
-               warn("redeclare import var %S from %T to %T",
+               yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T",
                        s, s->def->type, t);
        }
        n = newname(s);
index e13d7bdd0d540f35c784e9b9da413ccd9df29a71..b4fcd4befc1775c8e3cfb9a0616cd63e488b0d6b 100644 (file)
@@ -593,6 +593,7 @@ EXTERN      Dlist   dotlist[10];    // size is max depth of embeddeds
 
 EXTERN Io      curio;
 EXTERN Io      pushedio;
+EXTERN int32   lexlineno;
 EXTERN int32   lineno;
 EXTERN int32   prevlineno;
 EXTERN char*   pathname;
@@ -704,7 +705,6 @@ void        typeinit(void);
 void   lexinit(void);
 char*  lexname(int);
 int32  getr(void);
-int    getnsc(void);
 int    escchar(int, int*, vlong*);
 int    getc(void);
 void   ungetc(int);
@@ -782,6 +782,7 @@ Sym*        pkglookup(char*, char*);
 Sym*   restrictlookup(char*, char*);
 void   importdot(Sym*);
 void   yyerror(char*, ...);
+int    parserline(void);
 void   warn(char*, ...);
 void   fatal(char*, ...);
 void   linehist(char*, int32, int);
@@ -880,6 +881,8 @@ Type*       tounsigned(Type*);
 void   smagic(Magic*);
 void   umagic(Magic*);
 
+void   redeclare(Sym*, char*);
+
 /*
  *     dcl.c
  */
index 722ca82db0cf60a38427224cb69d6120d0e02fc8..129e77d6d77ff76d714f3d626d3be75d8a337dfc 100644 (file)
@@ -43,7 +43,7 @@
 %token         LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH
 %token         LSEMIBRACE
 
-%type  <lint>  lbrace
+%type  <lint>  lbrace import_here
 %type  <sym>   sym packname
 %type  <val>   oliteral
 
@@ -126,6 +126,7 @@ file:
 package:
        %prec NotPackage
        {
+               prevlineno = lineno;
                yyerror("package statement must be first");
                mkpackage("main");
        }
@@ -158,7 +159,47 @@ import:
 |      LIMPORT '(' ')'
 
 import_stmt:
-       import_here import_package import_there import_done
+       import_here import_package import_there
+       {
+               Sym *import, *my;
+
+               import = pkgimportname;
+               my = pkgmyname;
+               pkgmyname = S;
+               pkgimportname = S;
+
+               if(import == S)
+                       break;
+               if(my == S)
+                       my = import;
+               if(my->name[0] == '.') {
+                       importdot(import);
+                       break;
+               }
+
+               // In order to allow multifile packages to use type names
+               // that are the same as the package name (i.e. go/parser
+               // is package parser and has a type called parser), we have
+               // to not bother trying to declare the package if it is our package.
+               // TODO(rsc): Is there a better way to tell if the package is ours?
+               if(my == import && strcmp(import->name, package) == 0)
+                       break;
+
+               // TODO(rsc): this line is needed for a package
+               // which does bytes := in a function, which creates
+               // an ONONAME for bytes, but then a different file
+               // imports "bytes".  more generally we need to figure out
+               // what it means if one file imports "bytes" and another
+               // declares a top-level name.
+               if(my->def && my->def->op == ONONAME)
+                       my->def = N;
+
+               my->def = nod(OPACK, N, N);
+               my->def->sym = import;
+               my->lastlineno = $1;
+               import->block = -1;     // above top level
+       }
+       
 
 import_stmt_list:
        import_stmt
@@ -168,6 +209,7 @@ import_here:
        LLITERAL
        {
                // import with original name
+               $$ = parserline();
                pkgimportname = S;
                pkgmyname = S;
                importfile(&$1);
@@ -175,13 +217,17 @@ import_here:
 |      sym LLITERAL
        {
                // import with given name
+               $$ = parserline();
                pkgimportname = S;
                pkgmyname = $1;
+               if(pkgmyname->def)
+                       redeclare(pkgmyname, "as imported package name");
                importfile(&$2);
        }
 |      '.' LLITERAL
        {
                // import into my name space
+               $$ = parserline();
                pkgmyname = lookup(".");
                importfile(&$2);
        }
@@ -214,48 +260,6 @@ import_there:
                checkimports();
        }
 
-import_done:
-       {
-               Sym *import, *my;
-
-               import = pkgimportname;
-               my = pkgmyname;
-               pkgmyname = S;
-               pkgimportname = S;
-
-               if(import == S)
-                       break;
-               if(my == S)
-                       my = import;
-               if(my->name[0] == '.') {
-                       importdot(import);
-                       break;
-               }
-
-               // In order to allow multifile packages to use type names
-               // that are the same as the package name (i.e. go/parser
-               // is package parser and has a type called parser), we have
-               // to not bother trying to declare the package if it is our package.
-               // TODO(rsc): Is there a better way to tell if the package is ours?
-               if(my == import && strcmp(import->name, package) == 0)
-                       break;
-
-               // TODO(rsc): this line is needed for a package
-               // which does bytes := in a function, which creates
-               // an ONONAME for bytes, but then a different file
-               // imports "bytes".  more generally we need to figure out
-               // what it means if one file imports "bytes" and another
-               // declares a top-level name.
-               if(my->def && my->def->op == ONONAME)
-                       my->def = N;
-
-               if(my->def)
-                       yyerror("redeclaration of %S by import\n\t%N", my, my->def);
-               my->def = nod(OPACK, N, N);
-               my->def->sym = import;
-               import->block = -1;     // above top level
-       }
-
 /*
  * declarations
  */
index 7440ef8b25276867773e9ddd7248bcf57a506ff3..7e9e8d5b35b39313cea80c8c2fdf68a84fba24d6 100644 (file)
@@ -73,7 +73,7 @@ main(int argc, char *argv[])
        blockgen = 1;
        dclcontext = PEXTERN;
        nerrors = 0;
-       lineno = 1;
+       lexlineno = 1;
 
        for(i=0; i<argc; i++) {
                if(i == 0)
@@ -369,7 +369,7 @@ unimportfile(void)
                Bterm(curio.bin);
                curio.bin = nil;
        } else
-               lineno--;       // re correct sys.6 line number
+               lexlineno--;    // re correct sys.6 line number
        curio = pushedio;
        pushedio.bin = nil;
        inimportsys = 0;
@@ -382,7 +382,7 @@ cannedimports(char *file, char *cp)
        if(!debug['A'])
                anysym->def = typenod(types[TANY]);
 
-       lineno++;               // if sys.6 is included on line 1,
+       lexlineno++;            // if sys.6 is included on line 1,
        linehist(file, 0, 0);   // the debugger gets confused
 
        pushedio = curio;
@@ -420,7 +420,6 @@ _yylex(void)
        vlong v;
        char *cp;
        Rune rune;
-       int32 lno;
        Sym *s;
 
        prevlineno = lineno;
@@ -430,6 +429,8 @@ l0:
        if(isspace(c))
                goto l0;
 
+       lineno = lexlineno;     /* start of token */
+
        if(c >= Runeself) {
                /* all multibyte runes are alpha */
                cp = lexbuf;
@@ -504,11 +505,10 @@ l0:
                clen = sizeof(int32);
 
        casebq:
-               lno = lineno;
                for(;;) {
                        c = getc();
                        if(c == EOF) {
-                               yyerror("eof in string starting at line %L", lno);
+                               yyerror("eof in string");
                                break;
                        }
                        if(c == '`')
@@ -791,7 +791,7 @@ l0:
                goto lx;
        case '{':
                if(loophack == 1) {
-                       DBG("%L lex: LBODY\n", lineno);
+                       DBG("%L lex: LBODY\n", lexlineno);
                        loophack = 0;
                        return LBODY;
                }
@@ -804,9 +804,9 @@ l0:
 
 lx:
        if(c > 0xff)
-               DBG("%L lex: TOKEN %s\n", lineno, lexname(c));
+               DBG("%L lex: TOKEN %s\n", lexlineno, lexname(c));
        else
-               DBG("%L lex: TOKEN '%c'\n", lineno, c);
+               DBG("%L lex: TOKEN '%c'\n", lexlineno, c);
        if(isfrog(c)) {
                yyerror("illegal character 0x%ux", c);
                goto l0;
@@ -1044,7 +1044,7 @@ getc(void)
                curio.peekc = curio.peekc1;
                curio.peekc1 = 0;
                if(c == '\n')
-                       lineno++;
+                       lexlineno++;
                return c;
        }
 
@@ -1063,7 +1063,7 @@ getc(void)
                return EOF;
 
        case '\n':
-               lineno++;
+               lexlineno++;
                break;
        }
        return c;
@@ -1075,7 +1075,7 @@ ungetc(int c)
        curio.peekc1 = curio.peekc;
        curio.peekc = c;
        if(c == '\n')
-               lineno--;
+               lexlineno--;
 }
 
 int32
@@ -1106,24 +1106,6 @@ loop:
        return rune;
 }
 
-int
-getnsc(void)
-{
-       int c;
-
-       c = getc();
-       for(;;) {
-               if(!isspace(c))
-                       return c;
-               if(c == '\n') {
-                       lineno++;
-                       return c;
-               }
-               c = getc();
-       }
-       return 0;
-}
-
 
 int
 escchar(int e, int *escflg, vlong *val)
index c566b7f070952e50bfccd310e23afe02f63483e4..7a7259ca3eb787ce9af073995db5c6fff1af1efb 100644 (file)
@@ -14,23 +14,35 @@ errorexit(void)
        exit(1);
 }
 
+extern int yychar;
+int
+parserline(void)
+{
+       if(yychar != 0 && yychar != -2) // parser has one symbol lookahead
+               return prevlineno;
+       return lineno;
+}
+
 void
 yyerror(char *fmt, ...)
 {
        va_list arg;
 
-       print("%L: ", lineno);
-       va_start(arg, fmt);
-       vfprint(1, fmt, arg);
-       va_end(arg);
        if(strcmp(fmt, "syntax error") == 0) {
+               print("%L: syntax error near %s\n", lexlineno, lexbuf);
                nsyntaxerrors++;
-               print(" near %s", lexbuf);
+               goto out;
        }
+
+       print("%L: ", parserline());
+       va_start(arg, fmt);
+       vfprint(1, fmt, arg);
+       va_end(arg);
        print("\n");
+
+out:
        if(debug['h'])
                *(int*)0 = 0;
-
        nerrors++;
        if(nerrors >= 10 && !debug['e'])
                fatal("too many errors");
@@ -92,7 +104,7 @@ linehist(char *file, int32 off, int relative)
 
        h = mal(sizeof(Hist));
        h->name = file;
-       h->line = lineno;
+       h->line = lexlineno;
        h->offset = off;
        h->link = H;
        if(ehist == H) {
@@ -245,7 +257,7 @@ importdot(Sym *opkg)
                                continue;
                        s1 = lookup(s->name);
                        if(s1->def != N) {
-                               yyerror("redeclaration of %S during import", s1);
+                               redeclare(s1, "during import");
                                continue;
                        }
                        s1->def = s->def;
@@ -310,7 +322,6 @@ remal(void *p, int32 on, int32 n)
        return p;
 }
 
-extern int yychar;
 Node*
 nod(int op, Node *nleft, Node *nright)
 {
@@ -320,10 +331,7 @@ nod(int op, Node *nleft, Node *nright)
        n->op = op;
        n->left = nleft;
        n->right = nright;
-       if(yychar <= 0) // no lookahead
-               n->lineno = lineno;
-       else
-               n->lineno = prevlineno;
+       n->lineno = parserline();
        n->xoffset = BADWIDTH;
        return n;
 }
index 35b618937f402cd1df2b0e63025f2fb753c162ca..e809990b766a81f6cc9664d989dbef698204c63f 100644 (file)
@@ -8,7 +8,10 @@
 
 package main
 
+import "bufio" // GCCGO_ERROR "previous"
+import bufio "os"      // ERROR "redeclared|redefinition|incompatible"
+
 import (
-       "bufio";        // GCCGO_ERROR "previous"
-       bufio "os";     // ERROR "redeclaration|redefinition|incompatible"
-)
+       "fmt";  // GCCGO_ERROR "previous"
+       fmt "math";     // ERROR "redeclared|redefinition|incompatible"
+)
\ No newline at end of file