cmd/internal/gc, cmd/yacc: implement "expecting" syntax error messages
Bison includes suggestions about what tokens are expected in the
current state when there's only four or fewer of them. For example:
syntax error: unexpected literal 2.01, expecting semicolon or newline or }
This CL adds the same functionality to cmd/yacc, which fully restores
the previous error message behavior from Go 1.4.
Updates #9968.
Change-Id: I2c1a1677c6d829a829d812c05e8813aa8829d09c
Reviewed-on: https://go-review.googlesource.com/8494
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
diff --git a/src/cmd/internal/gc/subr.go b/src/cmd/internal/gc/subr.go
index 689adee..5505fe3 100644
--- a/src/cmd/internal/gc/subr.go
+++ b/src/cmd/internal/gc/subr.go
@@ -162,18 +162,13 @@
return
}
- // TODO(mdempsky): Extend cmd/yacc's verbose error
- // messages to suggest expected tokens like Bison:
- // "syntax error: unexpected literal 2.01, expecting semicolon or newline or }"
- 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)
- }
+ // 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)
msg = strings.Replace(msg, "LLITERAL", litbuf, -1)
diff --git a/src/cmd/internal/gc/y.go b/src/cmd/internal/gc/y.go
index 62dc53b..cfa4ec6 100644
--- a/src/cmd/internal/gc/y.go
+++ b/src/cmd/internal/gc/y.go
@@ -912,6 +912,63 @@
return __yyfmt__.Sprintf("state-%v", s)
}
+func yyErrorMessage(state, lookAhead int) string {
+ const TOKSTART = 4
+
+ if !yyErrorVerbose {
+ return "syntax error"
+ }
+ res := "syntax error: unexpected " + yyTokname(lookAhead)
+
+ // To match Bison, suggest at most four expected tokens.
+ expected := make([]int, 0, 4)
+
+ // Look for shiftable tokens.
+ base := yyPact[state]
+ for tok := TOKSTART; tok-1 < len(yyToknames); tok++ {
+ if n := base + tok; n >= 0 && n < yyLast && yyChk[yyAct[n]] == tok {
+ if len(expected) == cap(expected) {
+ return res
+ }
+ expected = append(expected, tok)
+ }
+ }
+
+ if yyDef[state] == -2 {
+ i := 0
+ for yyExca[i] != -1 || yyExca[i+1] != state {
+ i += 2
+ }
+
+ // Look for tokens that we accept or reduce.
+ for i += 2; yyExca[i] >= 0; i += 2 {
+ tok := yyExca[i]
+ if tok < TOKSTART || yyExca[i+1] == 0 {
+ continue
+ }
+ if len(expected) == cap(expected) {
+ return res
+ }
+ expected = append(expected, tok)
+ }
+
+ // If the default action is to accept or reduce, give up.
+ if yyExca[i+1] != 0 {
+ return res
+ }
+ }
+
+ for i, tok := range expected {
+ if i == 0 {
+ res += ", expecting "
+ } else {
+ res += " or "
+ }
+ res += yyTokname(tok)
+ }
+ return res
+}
+
func yylex1(lex yyLexer, lval *yySymType) (char, token int) {
token = 0
char = lex.Lex(lval)
@@ -1050,11 +1107,7 @@
/* error ... attempt to resume parsing */
switch Errflag {
case 0: /* brand new error */
- yyErrMsg := "syntax error"
- if yyErrorVerbose {
- yyErrMsg += ": unexpected " + yyTokname(yytoken)
- }
- yylex.Error(yyErrMsg)
+ yylex.Error(yyErrorMessage(yystate, yytoken))
Nerrs++
if yyDebug >= 1 {
__yyfmt__.Printf("%s", yyStatname(yystate))
@@ -1292,8 +1345,6 @@
Yyerror("empty top-level declaration")
yyVAL.list = nil
}
- case 24:
- yyVAL.list = yyS[yypt-0].list
case 25:
yyDollar = yyS[yypt-1 : yypt+1]
//line go.y:292
@@ -1416,8 +1467,6 @@
{
yyVAL.list = constiter(yyDollar[1].list, nil, yyDollar[3].list)
}
- case 44:
- yyVAL.list = yyS[yypt-0].list
case 45:
yyDollar = yyS[yypt-2 : yypt+1]
//line go.y:387
@@ -1717,8 +1766,6 @@
yyVAL.node = Nod(OFOR, nil, nil)
yyVAL.node.Ntest = yyDollar[1].node
}
- case 72:
- yyVAL.node = yyS[yypt-0].node
case 73:
yyDollar = yyS[yypt-2 : yypt+1]
//line go.y:654
@@ -1880,8 +1927,6 @@
yyVAL.node.List = yyDollar[4].list
typesw = typesw.Left
}
- case 93:
- yyVAL.node = yyS[yypt-0].node
case 94:
yyDollar = yyS[yypt-3 : yypt+1]
//line go.y:796
@@ -2002,8 +2047,6 @@
{
yyVAL.node = Nod(OSEND, yyDollar[1].node, yyDollar[3].node)
}
- case 114:
- yyVAL.node = yyS[yypt-0].node
case 115:
yyDollar = yyS[yypt-2 : yypt+1]
//line go.y:880
@@ -2087,8 +2130,6 @@
{
yyVAL.node = nodlit(yyDollar[1].val)
}
- case 127:
- yyVAL.node = yyS[yypt-0].node
case 128:
yyDollar = yyS[yypt-3 : yypt+1]
//line go.y:948
@@ -2138,8 +2179,6 @@
}
yyVAL.node = Nod(OSLICE3, yyDollar[1].node, Nod(OKEY, yyDollar[3].node, Nod(OKEY, yyDollar[5].node, yyDollar[7].node)))
}
- case 134:
- yyVAL.node = yyS[yypt-0].node
case 135:
yyDollar = yyS[yypt-5 : yypt+1]
//line go.y:986
@@ -2174,8 +2213,6 @@
yyVAL.node.Right = yyDollar[2].node
yyVAL.node.List = yyDollar[6].list
}
- case 139:
- yyVAL.node = yyS[yypt-0].node
case 140:
yyDollar = yyS[yypt-0 : yypt+1]
//line go.y:1014
@@ -2212,8 +2249,6 @@
yyVAL.node = yyDollar[2].node
yyVAL.node.List = yyDollar[3].list
}
- case 144:
- yyVAL.node = yyS[yypt-0].node
case 145:
yyDollar = yyS[yypt-4 : yypt+1]
//line go.y:1049
@@ -2221,8 +2256,6 @@
yyVAL.node = yyDollar[2].node
yyVAL.node.List = yyDollar[3].list
}
- case 146:
- yyVAL.node = yyS[yypt-0].node
case 147:
yyDollar = yyS[yypt-3 : yypt+1]
//line go.y:1057
@@ -2237,12 +2270,6 @@
yyVAL.node = Nod(OPAREN, yyVAL.node, nil)
}
}
- case 148:
- yyVAL.node = yyS[yypt-0].node
- case 149:
- yyVAL.node = yyS[yypt-0].node
- case 150:
- yyVAL.node = yyS[yypt-0].node
case 151:
yyDollar = yyS[yypt-1 : yypt+1]
//line go.y:1078
@@ -2277,8 +2304,6 @@
{
yyVAL.node = nil
}
- case 156:
- yyVAL.node = yyS[yypt-0].node
case 157:
yyDollar = yyS[yypt-1 : yypt+1]
//line go.y:1115
@@ -2289,8 +2314,6 @@
yyVAL.sym = Pkglookup(yyDollar[1].sym.Name, builtinpkg)
}
}
- case 158:
- yyVAL.sym = yyS[yypt-0].sym
case 159:
yyDollar = yyS[yypt-1 : yypt+1]
//line go.y:1124
@@ -2338,8 +2361,6 @@
yyVAL.node.Pack.Used = true
}
}
- case 163:
- yyVAL.node = yyS[yypt-0].node
case 164:
yyDollar = yyS[yypt-1 : yypt+1]
//line go.y:1181
@@ -2353,66 +2374,24 @@
{
yyVAL.node = Nod(ODDD, yyDollar[2].node, nil)
}
- case 166:
- yyVAL.node = yyS[yypt-0].node
- case 167:
- yyVAL.node = yyS[yypt-0].node
- case 168:
- yyVAL.node = yyS[yypt-0].node
- case 169:
- yyVAL.node = yyS[yypt-0].node
- case 170:
- yyVAL.node = yyS[yypt-0].node
case 171:
yyDollar = yyS[yypt-3 : yypt+1]
//line go.y:1197
{
yyVAL.node = yyDollar[2].node
}
- case 172:
- yyVAL.node = yyS[yypt-0].node
- case 173:
- yyVAL.node = yyS[yypt-0].node
- case 174:
- yyVAL.node = yyS[yypt-0].node
case 175:
yyDollar = yyS[yypt-2 : yypt+1]
//line go.y:1206
{
yyVAL.node = Nod(OIND, yyDollar[2].node, nil)
}
- case 176:
- yyVAL.node = yyS[yypt-0].node
- case 177:
- yyVAL.node = yyS[yypt-0].node
- case 178:
- yyVAL.node = yyS[yypt-0].node
- case 179:
- yyVAL.node = yyS[yypt-0].node
case 180:
yyDollar = yyS[yypt-3 : yypt+1]
//line go.y:1216
{
yyVAL.node = yyDollar[2].node
}
- case 181:
- yyVAL.node = yyS[yypt-0].node
- case 182:
- yyVAL.node = yyS[yypt-0].node
- case 183:
- yyVAL.node = yyS[yypt-0].node
- case 184:
- yyVAL.node = yyS[yypt-0].node
- case 185:
- yyVAL.node = yyS[yypt-0].node
- case 186:
- yyVAL.node = yyS[yypt-0].node
- case 187:
- yyVAL.node = yyS[yypt-0].node
- case 188:
- yyVAL.node = yyS[yypt-0].node
- case 189:
- yyVAL.node = yyS[yypt-0].node
case 190:
yyDollar = yyS[yypt-3 : yypt+1]
//line go.y:1237
@@ -2459,10 +2438,6 @@
{
yyVAL.node = Nod(OTMAP, yyDollar[3].node, yyDollar[5].node)
}
- case 196:
- yyVAL.node = yyS[yypt-0].node
- case 197:
- yyVAL.node = yyS[yypt-0].node
case 198:
yyDollar = yyS[yypt-2 : yypt+1]
//line go.y:1277
@@ -2721,16 +2696,12 @@
nosplit = false
nowritebarrier = false
}
- case 220:
- yyVAL.list = yyS[yypt-0].list
case 221:
yyDollar = yyS[yypt-3 : yypt+1]
//line go.y:1526
{
yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list)
}
- case 222:
- yyVAL.list = yyS[yypt-0].list
case 223:
yyDollar = yyS[yypt-3 : yypt+1]
//line go.y:1533
@@ -2749,8 +2720,6 @@
{
yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
}
- case 226:
- yyVAL.list = yyS[yypt-0].list
case 227:
yyDollar = yyS[yypt-3 : yypt+1]
//line go.y:1550
@@ -2899,8 +2868,6 @@
yyVAL.node.List = yyDollar[2].list
yyVAL.node.Rlist = yyDollar[4].list
}
- case 243:
- yyVAL.node = yyS[yypt-0].node
case 244:
yyDollar = yyS[yypt-2 : yypt+1]
//line go.y:1684
@@ -2917,8 +2884,6 @@
yyVAL.node.Sym = yyDollar[1].sym
yyVAL.node = Nod(OKEY, yyVAL.node, yyDollar[2].node)
}
- case 246:
- yyVAL.node = yyS[yypt-0].node
case 247:
yyDollar = yyS[yypt-1 : yypt+1]
//line go.y:1699
@@ -2949,32 +2914,18 @@
{
yyVAL.node = nil
}
- case 252:
- yyVAL.node = yyS[yypt-0].node
case 253:
yyDollar = yyS[yypt-1 : yypt+1]
//line go.y:1725
{
yyVAL.node = liststmt(yyDollar[1].list)
}
- case 254:
- yyVAL.node = yyS[yypt-0].node
case 255:
yyDollar = yyS[yypt-1 : yypt+1]
//line go.y:1730
{
yyVAL.node = nil
}
- case 256:
- yyVAL.node = yyS[yypt-0].node
- case 257:
- yyVAL.node = yyS[yypt-0].node
- case 258:
- yyVAL.node = yyS[yypt-0].node
- case 259:
- yyVAL.node = yyS[yypt-0].node
- case 260:
- yyVAL.node = yyS[yypt-0].node
case 261:
yyDollar = yyS[yypt-2 : yypt+1]
//line go.y:1741
@@ -3164,56 +3115,42 @@
{
yyVAL.node = nil
}
- case 291:
- yyVAL.node = yyS[yypt-0].node
case 292:
yyDollar = yyS[yypt-0 : yypt+1]
//line go.y:1906
{
yyVAL.list = nil
}
- case 293:
- yyVAL.list = yyS[yypt-0].list
case 294:
yyDollar = yyS[yypt-0 : yypt+1]
//line go.y:1912
{
yyVAL.node = nil
}
- case 295:
- yyVAL.node = yyS[yypt-0].node
case 296:
yyDollar = yyS[yypt-0 : yypt+1]
//line go.y:1918
{
yyVAL.list = nil
}
- case 297:
- yyVAL.list = yyS[yypt-0].list
case 298:
yyDollar = yyS[yypt-0 : yypt+1]
//line go.y:1924
{
yyVAL.list = nil
}
- case 299:
- yyVAL.list = yyS[yypt-0].list
case 300:
yyDollar = yyS[yypt-0 : yypt+1]
//line go.y:1930
{
yyVAL.list = nil
}
- case 301:
- yyVAL.list = yyS[yypt-0].list
case 302:
yyDollar = yyS[yypt-0 : yypt+1]
//line go.y:1936
{
yyVAL.val.Ctype = CTxxx
}
- case 303:
- yyVAL.val = yyS[yypt-0].val
case 304:
yyDollar = yyS[yypt-4 : yypt+1]
//line go.y:1946
@@ -3279,16 +3216,6 @@
yyVAL.typ = pkgtype(yyDollar[1].sym)
importsym(yyDollar[1].sym, OTYPE)
}
- case 312:
- yyVAL.typ = yyS[yypt-0].typ
- case 313:
- yyVAL.typ = yyS[yypt-0].typ
- case 314:
- yyVAL.typ = yyS[yypt-0].typ
- case 315:
- yyVAL.typ = yyS[yypt-0].typ
- case 316:
- yyVAL.typ = yyS[yypt-0].typ
case 317:
yyDollar = yyS[yypt-1 : yypt+1]
//line go.y:2014
@@ -3451,8 +3378,6 @@
{
yyVAL.list = nil
}
- case 336:
- yyVAL.list = yyS[yypt-0].list
case 337:
yyDollar = yyS[yypt-3 : yypt+1]
//line go.y:2152
@@ -3500,8 +3425,6 @@
Yyerror("bad constant %v", Sconv(yyVAL.node.Sym, 0))
}
}
- case 342:
- yyVAL.node = yyS[yypt-0].node
case 343:
yyDollar = yyS[yypt-5 : yypt+1]
//line go.y:2198