in the presence of yacc lookahead.
better but still not perfect
R=ken
OCL=33541
CL=33541
}
}
+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(Node *n, int ctxt)
{
Sym *s;
- char *what;
int gen;
static int typegen, vargen;
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;
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:
pt->method = nil;
pt->nod = n;
pt->sym = n->sym;
+ pt->sym->lastlineno = parserline();
declare(n, PEXTERN);
checkwidth(pt);
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) {
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);
EXTERN Io curio;
EXTERN Io pushedio;
+EXTERN int32 lexlineno;
EXTERN int32 lineno;
EXTERN int32 prevlineno;
EXTERN char* pathname;
void lexinit(void);
char* lexname(int);
int32 getr(void);
-int getnsc(void);
int escchar(int, int*, vlong*);
int getc(void);
void ungetc(int);
Sym* restrictlookup(char*, char*);
void importdot(Sym*);
void yyerror(char*, ...);
+int parserline(void);
void warn(char*, ...);
void fatal(char*, ...);
void linehist(char*, int32, int);
void smagic(Magic*);
void umagic(Magic*);
+void redeclare(Sym*, char*);
+
/*
* dcl.c
*/
%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
package:
%prec NotPackage
{
+ prevlineno = lineno;
yyerror("package statement must be first");
mkpackage("main");
}
| 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
LLITERAL
{
// import with original name
+ $$ = parserline();
pkgimportname = S;
pkgmyname = S;
importfile(&$1);
| 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);
}
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
*/
blockgen = 1;
dclcontext = PEXTERN;
nerrors = 0;
- lineno = 1;
+ lexlineno = 1;
for(i=0; i<argc; i++) {
if(i == 0)
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;
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;
vlong v;
char *cp;
Rune rune;
- int32 lno;
Sym *s;
prevlineno = lineno;
if(isspace(c))
goto l0;
+ lineno = lexlineno; /* start of token */
+
if(c >= Runeself) {
/* all multibyte runes are alpha */
cp = lexbuf;
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 == '`')
goto lx;
case '{':
if(loophack == 1) {
- DBG("%L lex: LBODY\n", lineno);
+ DBG("%L lex: LBODY\n", lexlineno);
loophack = 0;
return LBODY;
}
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;
curio.peekc = curio.peekc1;
curio.peekc1 = 0;
if(c == '\n')
- lineno++;
+ lexlineno++;
return c;
}
return EOF;
case '\n':
- lineno++;
+ lexlineno++;
break;
}
return c;
curio.peekc1 = curio.peekc;
curio.peekc = c;
if(c == '\n')
- lineno--;
+ lexlineno--;
}
int32
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)
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");
h = mal(sizeof(Hist));
h->name = file;
- h->line = lineno;
+ h->line = lexlineno;
h->offset = off;
h->link = H;
if(ehist == H) {
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;
return p;
}
-extern int yychar;
Node*
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;
}
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