Commit 38df5ec5 authored by Russ Cox's avatar Russ Cox

try to do better line number reporting

in the presence of yacc lookahead.
better but still not perfect

R=ken
OCL=33541
CL=33541
parent 8aa9161e
...@@ -146,6 +146,14 @@ testdclstack(void) ...@@ -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 * declare individual names - var, typ, const
*/ */
...@@ -153,7 +161,6 @@ void ...@@ -153,7 +161,6 @@ void
declare(Node *n, int ctxt) declare(Node *n, int ctxt)
{ {
Sym *s; Sym *s;
char *what;
int gen; int gen;
static int typegen, vargen; static int typegen, vargen;
...@@ -177,25 +184,11 @@ declare(Node *n, int ctxt) ...@@ -177,25 +184,11 @@ declare(Node *n, int ctxt)
if(ctxt == PAUTO) if(ctxt == PAUTO)
n->xoffset = BADWIDTH; n->xoffset = BADWIDTH;
if(s->block == block) { if(s->block == block)
what = "???"; redeclare(s, "in this block");
switch(n->op) {
case ONAME:
what = "variable";
break;
case OLITERAL:
what = "constant";
break;
case OTYPE:
what = "type";
break;
}
yyerror("%s %S redeclared in this block %d", what, s, block);
print("\tprevious declaration at %L\n", s->lastlineno);
}
s->block = block; s->block = block;
s->lastlineno = lineno; s->lastlineno = parserline();
s->def = n; s->def = n;
n->vargen = gen; n->vargen = gen;
n->funcdepth = funcdepth; n->funcdepth = funcdepth;
...@@ -731,10 +724,8 @@ typedcl2(Type *pt, Type *t) ...@@ -731,10 +724,8 @@ typedcl2(Type *pt, Type *t)
if(pt->etype == TFORW) if(pt->etype == TFORW)
goto ok; goto ok;
if(!cvttype(pt, t)) { if(!cvttype(pt, t))
yyerror("redeclaration of %T during imports", pt); yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t);
return;
}
return; return;
ok: ok:
...@@ -743,6 +734,7 @@ ok: ...@@ -743,6 +734,7 @@ ok:
pt->method = nil; pt->method = nil;
pt->nod = n; pt->nod = n;
pt->sym = n->sym; pt->sym = n->sym;
pt->sym->lastlineno = parserline();
declare(n, PEXTERN); declare(n, PEXTERN);
checkwidth(pt); checkwidth(pt);
......
...@@ -258,15 +258,8 @@ dumpexport(void) ...@@ -258,15 +258,8 @@ dumpexport(void)
Sym* Sym*
importsym(Sym *s, int op) importsym(Sym *s, int op)
{ {
if(s->def != N && s->def->op != op) { if(s->def != N && s->def->op != op)
// Clumsy hack for redeclare(s, "during import");
// 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);
}
// mark the symbol so it is not reexported // mark the symbol so it is not reexported
if(s->def == N) { if(s->def == N) {
...@@ -349,7 +342,7 @@ importvar(Sym *s, Type *t, int ctxt) ...@@ -349,7 +342,7 @@ importvar(Sym *s, Type *t, int ctxt)
if(s->def != N && s->def->op == ONAME) { if(s->def != N && s->def->op == ONAME) {
if(cvttype(t, s->def->type)) if(cvttype(t, s->def->type))
return; 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); s, s->def->type, t);
} }
n = newname(s); n = newname(s);
......
...@@ -593,6 +593,7 @@ EXTERN Dlist dotlist[10]; // size is max depth of embeddeds ...@@ -593,6 +593,7 @@ EXTERN Dlist dotlist[10]; // size is max depth of embeddeds
EXTERN Io curio; EXTERN Io curio;
EXTERN Io pushedio; EXTERN Io pushedio;
EXTERN int32 lexlineno;
EXTERN int32 lineno; EXTERN int32 lineno;
EXTERN int32 prevlineno; EXTERN int32 prevlineno;
EXTERN char* pathname; EXTERN char* pathname;
...@@ -704,7 +705,6 @@ void typeinit(void); ...@@ -704,7 +705,6 @@ void typeinit(void);
void lexinit(void); void lexinit(void);
char* lexname(int); char* lexname(int);
int32 getr(void); int32 getr(void);
int getnsc(void);
int escchar(int, int*, vlong*); int escchar(int, int*, vlong*);
int getc(void); int getc(void);
void ungetc(int); void ungetc(int);
...@@ -782,6 +782,7 @@ Sym* pkglookup(char*, char*); ...@@ -782,6 +782,7 @@ Sym* pkglookup(char*, char*);
Sym* restrictlookup(char*, char*); Sym* restrictlookup(char*, char*);
void importdot(Sym*); void importdot(Sym*);
void yyerror(char*, ...); void yyerror(char*, ...);
int parserline(void);
void warn(char*, ...); void warn(char*, ...);
void fatal(char*, ...); void fatal(char*, ...);
void linehist(char*, int32, int); void linehist(char*, int32, int);
...@@ -880,6 +881,8 @@ Type* tounsigned(Type*); ...@@ -880,6 +881,8 @@ Type* tounsigned(Type*);
void smagic(Magic*); void smagic(Magic*);
void umagic(Magic*); void umagic(Magic*);
void redeclare(Sym*, char*);
/* /*
* dcl.c * dcl.c
*/ */
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
%token LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH %token LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH
%token LSEMIBRACE %token LSEMIBRACE
%type <lint> lbrace %type <lint> lbrace import_here
%type <sym> sym packname %type <sym> sym packname
%type <val> oliteral %type <val> oliteral
...@@ -126,6 +126,7 @@ file: ...@@ -126,6 +126,7 @@ file:
package: package:
%prec NotPackage %prec NotPackage
{ {
prevlineno = lineno;
yyerror("package statement must be first"); yyerror("package statement must be first");
mkpackage("main"); mkpackage("main");
} }
...@@ -158,7 +159,47 @@ import: ...@@ -158,7 +159,47 @@ import:
| LIMPORT '(' ')' | LIMPORT '(' ')'
import_stmt: 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_list:
import_stmt import_stmt
...@@ -168,6 +209,7 @@ import_here: ...@@ -168,6 +209,7 @@ import_here:
LLITERAL LLITERAL
{ {
// import with original name // import with original name
$$ = parserline();
pkgimportname = S; pkgimportname = S;
pkgmyname = S; pkgmyname = S;
importfile(&$1); importfile(&$1);
...@@ -175,13 +217,17 @@ import_here: ...@@ -175,13 +217,17 @@ import_here:
| sym LLITERAL | sym LLITERAL
{ {
// import with given name // import with given name
$$ = parserline();
pkgimportname = S; pkgimportname = S;
pkgmyname = $1; pkgmyname = $1;
if(pkgmyname->def)
redeclare(pkgmyname, "as imported package name");
importfile(&$2); importfile(&$2);
} }
| '.' LLITERAL | '.' LLITERAL
{ {
// import into my name space // import into my name space
$$ = parserline();
pkgmyname = lookup("."); pkgmyname = lookup(".");
importfile(&$2); importfile(&$2);
} }
...@@ -214,48 +260,6 @@ import_there: ...@@ -214,48 +260,6 @@ import_there:
checkimports(); 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 * declarations
*/ */
......
...@@ -73,7 +73,7 @@ main(int argc, char *argv[]) ...@@ -73,7 +73,7 @@ main(int argc, char *argv[])
blockgen = 1; blockgen = 1;
dclcontext = PEXTERN; dclcontext = PEXTERN;
nerrors = 0; nerrors = 0;
lineno = 1; lexlineno = 1;
for(i=0; i<argc; i++) { for(i=0; i<argc; i++) {
if(i == 0) if(i == 0)
...@@ -369,7 +369,7 @@ unimportfile(void) ...@@ -369,7 +369,7 @@ unimportfile(void)
Bterm(curio.bin); Bterm(curio.bin);
curio.bin = nil; curio.bin = nil;
} else } else
lineno--; // re correct sys.6 line number lexlineno--; // re correct sys.6 line number
curio = pushedio; curio = pushedio;
pushedio.bin = nil; pushedio.bin = nil;
inimportsys = 0; inimportsys = 0;
...@@ -382,7 +382,7 @@ cannedimports(char *file, char *cp) ...@@ -382,7 +382,7 @@ cannedimports(char *file, char *cp)
if(!debug['A']) if(!debug['A'])
anysym->def = typenod(types[TANY]); 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 linehist(file, 0, 0); // the debugger gets confused
pushedio = curio; pushedio = curio;
...@@ -420,7 +420,6 @@ _yylex(void) ...@@ -420,7 +420,6 @@ _yylex(void)
vlong v; vlong v;
char *cp; char *cp;
Rune rune; Rune rune;
int32 lno;
Sym *s; Sym *s;
prevlineno = lineno; prevlineno = lineno;
...@@ -430,6 +429,8 @@ l0: ...@@ -430,6 +429,8 @@ l0:
if(isspace(c)) if(isspace(c))
goto l0; goto l0;
lineno = lexlineno; /* start of token */
if(c >= Runeself) { if(c >= Runeself) {
/* all multibyte runes are alpha */ /* all multibyte runes are alpha */
cp = lexbuf; cp = lexbuf;
...@@ -504,11 +505,10 @@ l0: ...@@ -504,11 +505,10 @@ l0:
clen = sizeof(int32); clen = sizeof(int32);
casebq: casebq:
lno = lineno;
for(;;) { for(;;) {
c = getc(); c = getc();
if(c == EOF) { if(c == EOF) {
yyerror("eof in string starting at line %L", lno); yyerror("eof in string");
break; break;
} }
if(c == '`') if(c == '`')
...@@ -791,7 +791,7 @@ l0: ...@@ -791,7 +791,7 @@ l0:
goto lx; goto lx;
case '{': case '{':
if(loophack == 1) { if(loophack == 1) {
DBG("%L lex: LBODY\n", lineno); DBG("%L lex: LBODY\n", lexlineno);
loophack = 0; loophack = 0;
return LBODY; return LBODY;
} }
...@@ -804,9 +804,9 @@ l0: ...@@ -804,9 +804,9 @@ l0:
lx: lx:
if(c > 0xff) if(c > 0xff)
DBG("%L lex: TOKEN %s\n", lineno, lexname(c)); DBG("%L lex: TOKEN %s\n", lexlineno, lexname(c));
else else
DBG("%L lex: TOKEN '%c'\n", lineno, c); DBG("%L lex: TOKEN '%c'\n", lexlineno, c);
if(isfrog(c)) { if(isfrog(c)) {
yyerror("illegal character 0x%ux", c); yyerror("illegal character 0x%ux", c);
goto l0; goto l0;
...@@ -1044,7 +1044,7 @@ getc(void) ...@@ -1044,7 +1044,7 @@ getc(void)
curio.peekc = curio.peekc1; curio.peekc = curio.peekc1;
curio.peekc1 = 0; curio.peekc1 = 0;
if(c == '\n') if(c == '\n')
lineno++; lexlineno++;
return c; return c;
} }
...@@ -1063,7 +1063,7 @@ getc(void) ...@@ -1063,7 +1063,7 @@ getc(void)
return EOF; return EOF;
case '\n': case '\n':
lineno++; lexlineno++;
break; break;
} }
return c; return c;
...@@ -1075,7 +1075,7 @@ ungetc(int c) ...@@ -1075,7 +1075,7 @@ ungetc(int c)
curio.peekc1 = curio.peekc; curio.peekc1 = curio.peekc;
curio.peekc = c; curio.peekc = c;
if(c == '\n') if(c == '\n')
lineno--; lexlineno--;
} }
int32 int32
...@@ -1106,24 +1106,6 @@ loop: ...@@ -1106,24 +1106,6 @@ loop:
return rune; 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 int
escchar(int e, int *escflg, vlong *val) escchar(int e, int *escflg, vlong *val)
......
...@@ -14,23 +14,35 @@ errorexit(void) ...@@ -14,23 +14,35 @@ errorexit(void)
exit(1); exit(1);
} }
extern int yychar;
int
parserline(void)
{
if(yychar != 0 && yychar != -2) // parser has one symbol lookahead
return prevlineno;
return lineno;
}
void void
yyerror(char *fmt, ...) yyerror(char *fmt, ...)
{ {
va_list arg; va_list arg;
print("%L: ", lineno);
va_start(arg, fmt);
vfprint(1, fmt, arg);
va_end(arg);
if(strcmp(fmt, "syntax error") == 0) { if(strcmp(fmt, "syntax error") == 0) {
print("%L: syntax error near %s\n", lexlineno, lexbuf);
nsyntaxerrors++; nsyntaxerrors++;
print(" near %s", lexbuf); goto out;
} }
print("%L: ", parserline());
va_start(arg, fmt);
vfprint(1, fmt, arg);
va_end(arg);
print("\n"); print("\n");
out:
if(debug['h']) if(debug['h'])
*(int*)0 = 0; *(int*)0 = 0;
nerrors++; nerrors++;
if(nerrors >= 10 && !debug['e']) if(nerrors >= 10 && !debug['e'])
fatal("too many errors"); fatal("too many errors");
...@@ -92,7 +104,7 @@ linehist(char *file, int32 off, int relative) ...@@ -92,7 +104,7 @@ linehist(char *file, int32 off, int relative)
h = mal(sizeof(Hist)); h = mal(sizeof(Hist));
h->name = file; h->name = file;
h->line = lineno; h->line = lexlineno;
h->offset = off; h->offset = off;
h->link = H; h->link = H;
if(ehist == H) { if(ehist == H) {
...@@ -245,7 +257,7 @@ importdot(Sym *opkg) ...@@ -245,7 +257,7 @@ importdot(Sym *opkg)
continue; continue;
s1 = lookup(s->name); s1 = lookup(s->name);
if(s1->def != N) { if(s1->def != N) {
yyerror("redeclaration of %S during import", s1); redeclare(s1, "during import");
continue; continue;
} }
s1->def = s->def; s1->def = s->def;
...@@ -310,7 +322,6 @@ remal(void *p, int32 on, int32 n) ...@@ -310,7 +322,6 @@ remal(void *p, int32 on, int32 n)
return p; return p;
} }
extern int yychar;
Node* Node*
nod(int op, Node *nleft, Node *nright) nod(int op, Node *nleft, Node *nright)
{ {
...@@ -320,10 +331,7 @@ nod(int op, Node *nleft, Node *nright) ...@@ -320,10 +331,7 @@ nod(int op, Node *nleft, Node *nright)
n->op = op; n->op = op;
n->left = nleft; n->left = nleft;
n->right = nright; n->right = nright;
if(yychar <= 0) // no lookahead n->lineno = parserline();
n->lineno = lineno;
else
n->lineno = prevlineno;
n->xoffset = BADWIDTH; n->xoffset = BADWIDTH;
return n; return n;
} }
......
...@@ -8,7 +8,10 @@ ...@@ -8,7 +8,10 @@
package main package main
import "bufio" // GCCGO_ERROR "previous"
import bufio "os" // ERROR "redeclared|redefinition|incompatible"
import ( import (
"bufio"; // GCCGO_ERROR "previous" "fmt"; // GCCGO_ERROR "previous"
bufio "os"; // ERROR "redeclaration|redefinition|incompatible" fmt "math"; // ERROR "redeclared|redefinition|incompatible"
) )
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment