Commit 4f2a7301 authored by Matthew Dempsky's avatar Matthew Dempsky

cmd/internal/gc, cmd/yacc: restore remaining custom error messages

This CL extends cmd/yacc to expose a yyErrorVerbose variable that
changes the error messages from just "syntax error" to "syntax error:
unexpected ${tokname}".

It also moves the yyToknames table generation to after rules have been
processed so that entries can be generated for tokens that aren't
mentioned in the preamble (e.g., '.' in the case of go.y).

Lastly, it restores gc's old code for applying yytfix to yyToknames,
except that substituting "LLITERAL" with litbuf happens in Yyerror.

Fixes #9968.

Change-Id: Icec188d11fdabc1dae31b8a471c35b5c7f6deec7
Reviewed-on: https://go-review.googlesource.com/8432Reviewed-by: 's avatarRuss Cox <rsc@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 0c9f3e49
...@@ -2436,7 +2436,6 @@ var yytfix = []struct { ...@@ -2436,7 +2436,6 @@ var yytfix = []struct {
want string want string
}{ }{
{"$end", "EOF"}, {"$end", "EOF"},
{"LLITERAL", "literal"},
{"LASOP", "op="}, {"LASOP", "op="},
{"LBREAK", "break"}, {"LBREAK", "break"},
{"LCASE", "case"}, {"LCASE", "case"},
...@@ -2486,6 +2485,27 @@ var yytfix = []struct { ...@@ -2486,6 +2485,27 @@ var yytfix = []struct {
{"','", "comma"}, {"','", "comma"},
} }
func init() {
yyErrorVerbose = true
Outer:
for i, s := range yyToknames {
// Apply yytfix if possible.
for _, fix := range yytfix {
if s == fix.have {
yyToknames[i] = fix.want
continue Outer
}
}
// Turn 'x' into x.
if len(s) == 3 && s[0] == '\'' && s[2] == '\'' {
yyToknames[i] = s[1:2]
continue
}
}
}
func pkgnotused(lineno int, path string, name string) { func pkgnotused(lineno int, path string, name string) {
// If the package was imported with a name other than the final // If the package was imported with a name other than the final
// import path element, show it explicitly in the error message. // import path element, show it explicitly in the error message.
......
...@@ -55,7 +55,7 @@ func adderrorname(n *Node) { ...@@ -55,7 +55,7 @@ func adderrorname(n *Node) {
} }
} }
func adderr(line int, format string, args []interface{}) { func adderr(line int, format string, args ...interface{}) {
errors = append(errors, Error{ errors = append(errors, Error{
seq: len(errors), seq: len(errors),
lineno: line, lineno: line,
...@@ -110,8 +110,8 @@ func hcrash() { ...@@ -110,8 +110,8 @@ func hcrash() {
} }
} }
func yyerrorl(line int, fmt_ string, args ...interface{}) { func yyerrorl(line int, format string, args ...interface{}) {
adderr(line, fmt_, args) adderr(line, format, args...)
hcrash() hcrash()
nerrors++ nerrors++
...@@ -124,15 +124,9 @@ func yyerrorl(line int, fmt_ string, args ...interface{}) { ...@@ -124,15 +124,9 @@ func yyerrorl(line int, fmt_ string, args ...interface{}) {
var yyerror_lastsyntax int var yyerror_lastsyntax int
func Yyerror(fmt_ string, args ...interface{}) { func Yyerror(format string, args ...interface{}) {
// bison used to invoke yyerror("syntax error"). msg := fmt.Sprintf(format, args...)
// With Go yacc we get yyerror("%s", "syntax error"). if strings.HasPrefix(msg, "syntax error") {
// Convert to keep the old code working.
if fmt_ == "%s" && len(args) == 1 && args[0] == "syntax error" {
fmt_ = "syntax error"
args = nil
}
if strings.HasPrefix(fmt_, "syntax error") {
nsyntaxerrors++ nsyntaxerrors++
yystate := theparser.(*yyParserImpl).state() yystate := theparser.(*yyParserImpl).state()
...@@ -154,16 +148,6 @@ func Yyerror(fmt_ string, args ...interface{}) { ...@@ -154,16 +148,6 @@ func Yyerror(fmt_ string, args ...interface{}) {
} }
yyerror_lastsyntax = int(lexlineno) yyerror_lastsyntax = int(lexlineno)
if strings.Contains(fmt_, "{ or {") || strings.Contains(fmt_, " or ?") || strings.Contains(fmt_, " or @") {
// The grammar has { and LBRACE but both show up as {.
// Rewrite syntax error referring to "{ or {" to say just "{".
// The grammar has ? and @ but only for reading imports.
// Silence them in ordinary errors.
fmt_ = strings.Replace(fmt_, "{ or {", "{", -1)
fmt_ = strings.Replace(fmt_, " or ?", "", -1)
fmt_ = strings.Replace(fmt_, " or @", "", -1)
}
// look for parse state-specific errors in list (see go.errors). // look for parse state-specific errors in list (see go.errors).
for i := range yymsg { for i := range yymsg {
if yymsg[i].yystate == yystate && yymsg[i].yychar == yychar { if yymsg[i].yystate == yystate && yymsg[i].yychar == yychar {
...@@ -173,22 +157,31 @@ func Yyerror(fmt_ string, args ...interface{}) { ...@@ -173,22 +157,31 @@ func Yyerror(fmt_ string, args ...interface{}) {
} }
// plain "syntax error" gets "near foo" added // plain "syntax error" gets "near foo" added
if fmt_ == "syntax error" { if msg == "syntax error" {
yyerrorl(int(lexlineno), "syntax error near %s", lexbuf.String()) yyerrorl(int(lexlineno), "syntax error near %s", lexbuf.String())
return return
} }
// if bison says "syntax error, more info"; print "syntax error: more info". // TODO(mdempsky): Extend cmd/yacc's verbose error
if fmt_[12] == ',' { // messages to suggest expected tokens like Bison:
yyerrorl(int(lexlineno), "syntax error:%s", fmt_[13:]) // "syntax error: unexpected literal 2.01, expecting semicolon or newline or }"
return if false {
// The grammar has { and LBRACE but both show up as {.
// Rewrite syntax error referring to "{ or {" to say just "{".
// The grammar has ? and @ but only for reading imports.
// Silence them in ordinary errors.
msg = strings.Replace(msg, "{ or {", "{", -1)
msg = strings.Replace(msg, " or ?", "", -1)
msg = strings.Replace(msg, " or @", "", -1)
} }
yyerrorl(int(lexlineno), "%s", fmt_) msg = strings.Replace(msg, "LLITERAL", litbuf, -1)
yyerrorl(int(lexlineno), "%s", msg)
return return
} }
adderr(parserline(), fmt_, args) adderr(parserline(), "%s", msg)
hcrash() hcrash()
nerrors++ nerrors++
...@@ -200,13 +193,13 @@ func Yyerror(fmt_ string, args ...interface{}) { ...@@ -200,13 +193,13 @@ func Yyerror(fmt_ string, args ...interface{}) {
} }
func Warn(fmt_ string, args ...interface{}) { func Warn(fmt_ string, args ...interface{}) {
adderr(parserline(), fmt_, args) adderr(parserline(), fmt_, args...)
hcrash() hcrash()
} }
func Warnl(line int, fmt_ string, args ...interface{}) { func Warnl(line int, fmt_ string, args ...interface{}) {
adderr(line, fmt_, args) adderr(line, fmt_, args...)
if Debug['m'] != 0 { if Debug['m'] != 0 {
Flusherrors() Flusherrors()
} }
......
...@@ -70,6 +70,9 @@ const NotParen = 57393 ...@@ -70,6 +70,9 @@ const NotParen = 57393
const PreferToRightParen = 57394 const PreferToRightParen = 57394
var yyToknames = [...]string{ var yyToknames = [...]string{
"$end",
"error",
"$unk",
"LLITERAL", "LLITERAL",
"LASOP", "LASOP",
"LCOLAS", "LCOLAS",
...@@ -129,6 +132,20 @@ var yyToknames = [...]string{ ...@@ -129,6 +132,20 @@ var yyToknames = [...]string{
"'('", "'('",
"')'", "')'",
"PreferToRightParen", "PreferToRightParen",
"';'",
"'.'",
"'$'",
"'='",
"':'",
"'{'",
"'}'",
"'!'",
"'~'",
"'['",
"']'",
"'?'",
"'@'",
"','",
} }
var yyStatenames = [...]string{} var yyStatenames = [...]string{}
...@@ -843,7 +860,10 @@ var yyTok3 = [...]int{ ...@@ -843,7 +860,10 @@ var yyTok3 = [...]int{
/* parser for yacc output */ /* parser for yacc output */
var yyDebug = 0 var (
yyDebug = 0
yyErrorVerbose = false
)
type yyLexer interface { type yyLexer interface {
Lex(lval *yySymType) int Lex(lval *yySymType) int
...@@ -875,10 +895,9 @@ func yyNewParser() yyParser { ...@@ -875,10 +895,9 @@ func yyNewParser() yyParser {
const yyFlag = -1000 const yyFlag = -1000
func yyTokname(c int) string { func yyTokname(c int) string {
// 4 is TOKSTART above if c >= 1 && c-1 < len(yyToknames) {
if c >= 4 && c-4 < len(yyToknames) { if yyToknames[c-1] != "" {
if yyToknames[c-4] != "" { return yyToknames[c-1]
return yyToknames[c-4]
} }
} }
return __yyfmt__.Sprintf("tok-%v", c) return __yyfmt__.Sprintf("tok-%v", c)
...@@ -1031,7 +1050,11 @@ yydefault: ...@@ -1031,7 +1050,11 @@ yydefault:
/* error ... attempt to resume parsing */ /* error ... attempt to resume parsing */
switch Errflag { switch Errflag {
case 0: /* brand new error */ case 0: /* brand new error */
yylex.Error("syntax error") yyErrMsg := "syntax error"
if yyErrorVerbose {
yyErrMsg += ": unexpected " + yyTokname(yytoken)
}
yylex.Error(yyErrMsg)
Nerrs++ Nerrs++
if yyDebug >= 1 { if yyDebug >= 1 {
__yyfmt__.Printf("%s", yyStatname(yystate)) __yyfmt__.Printf("%s", yyStatname(yystate))
......
...@@ -15,7 +15,7 @@ var yymsg = []struct { ...@@ -15,7 +15,7 @@ var yymsg = []struct {
msg string msg string
}{ }{
// Each line of the form % token list // Each line of the form % token list
// is converted by bisonerrors into the yystate and yychar caused // is converted by yaccerrors.go into the yystate and yychar caused
// by that token list. // by that token list.
{332, ',', {332, ',',
......
...@@ -507,29 +507,6 @@ outer: ...@@ -507,29 +507,6 @@ outer:
errorf("unexpected EOF before %%") errorf("unexpected EOF before %%")
} }
// put out non-literal terminals
for i := TOKSTART; i <= ntokens; i++ {
// non-literals
if !tokset[i].noconst {
fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
}
}
// put out names of token names
ftable.WriteRune('\n')
fmt.Fprintf(ftable, "var %sToknames = [...]string{\n", prefix)
for i := TOKSTART; i <= ntokens; i++ {
fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name)
}
fmt.Fprintf(ftable, "}\n")
// put out names of state names
fmt.Fprintf(ftable, "var %sStatenames = [...]string{", prefix)
// for i:=TOKSTART; i<=ntokens; i++ {
// fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name);
// }
fmt.Fprintf(ftable, "}\n")
fmt.Fprintf(fcode, "switch %snt {\n", prefix) fmt.Fprintf(fcode, "switch %snt {\n", prefix)
moreprod() moreprod()
...@@ -679,6 +656,29 @@ outer: ...@@ -679,6 +656,29 @@ outer:
fmt.Fprintf(fcode, "\n\t}") fmt.Fprintf(fcode, "\n\t}")
// put out non-literal terminals
for i := TOKSTART; i <= ntokens; i++ {
// non-literals
if !tokset[i].noconst {
fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
}
}
// put out names of token names
ftable.WriteRune('\n')
fmt.Fprintf(ftable, "var %sToknames = [...]string{\n", prefix)
for i := 1; i <= ntokens; i++ {
fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name)
}
fmt.Fprintf(ftable, "}\n")
// put out names of state names
fmt.Fprintf(ftable, "var %sStatenames = [...]string{", prefix)
// for i:=TOKSTART; i<=ntokens; i++ {
// fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name);
// }
fmt.Fprintf(ftable, "}\n")
ftable.WriteRune('\n') ftable.WriteRune('\n')
fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix) fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix)
fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix) fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix)
...@@ -3198,7 +3198,10 @@ var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g ...@@ -3198,7 +3198,10 @@ var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g
var yaccpartext = ` var yaccpartext = `
/* parser for yacc output */ /* parser for yacc output */
var $$Debug = 0 var (
$$Debug = 0
$$ErrorVerbose = false
)
type $$Lexer interface { type $$Lexer interface {
Lex(lval *$$SymType) int Lex(lval *$$SymType) int
...@@ -3230,10 +3233,9 @@ func $$NewParser() $$Parser { ...@@ -3230,10 +3233,9 @@ func $$NewParser() $$Parser {
const $$Flag = -1000 const $$Flag = -1000
func $$Tokname(c int) string { func $$Tokname(c int) string {
// 4 is TOKSTART above if c >= 1 && c-1 < len($$Toknames) {
if c >= 4 && c-4 < len($$Toknames) { if $$Toknames[c-1] != "" {
if $$Toknames[c-4] != "" { return $$Toknames[c-1]
return $$Toknames[c-4]
} }
} }
return __yyfmt__.Sprintf("tok-%v", c) return __yyfmt__.Sprintf("tok-%v", c)
...@@ -3386,7 +3388,11 @@ $$default: ...@@ -3386,7 +3388,11 @@ $$default:
/* error ... attempt to resume parsing */ /* error ... attempt to resume parsing */
switch Errflag { switch Errflag {
case 0: /* brand new error */ case 0: /* brand new error */
$$lex.Error("syntax error") $$ErrMsg := "syntax error"
if $$ErrorVerbose {
$$ErrMsg += ": unexpected " + $$Tokname($$token)
}
$$lex.Error($$ErrMsg)
Nerrs++ Nerrs++
if $$Debug >= 1 { if $$Debug >= 1 {
__yyfmt__.Printf("%s", $$Statname($$state)) __yyfmt__.Printf("%s", $$Statname($$state))
......
// skip
// TODO(rsc): Reenable. See issue 9968.
// errorcheck // errorcheck
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
......
// skip
// TODO(rsc): Reenable. See issue 9968.
// errorcheck // errorcheck
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
......
// skip
// TODO(rsc): Reenable. See issue 9968.
// errorcheck // errorcheck
// Copyright 2012 The Go Authors. All rights reserved. // Copyright 2012 The Go Authors. All rights reserved.
......
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