--- /dev/null
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Example-based syntax error messages.
+// See yaccerrors.go.
+
+package gc
+
+var yymsg = []struct {
+ yystate int
+ yychar int
+ msg string
+}{
+ // Each line of the form % token list
+ // is converted by yaccerrors.go into the yystate and yychar caused
+ // by that token list.
+
+ % loadsys package LIMPORT '(' LLITERAL import_package import_there ','
+ "unexpected comma during import block"},
+
+ % loadsys package LIMPORT LNAME ';'
+ "missing import path; require quoted string"},
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';'
+ "missing { after if clause"},
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';'
+ "missing { after switch clause"},
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';'
+ "missing { after for clause"},
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY
+ "missing { after for clause"},
+
+ % loadsys package imports LFUNC LNAME '(' ')' ';' '{'
+ "unexpected semicolon or newline before {"},
+
+ % loadsys package imports LTYPE LNAME ';'
+ "unexpected semicolon or newline in type declaration"},
+
+ % loadsys package imports LCHAN '}'
+ "unexpected } in channel type"},
+
+ % loadsys package imports LCHAN ')'
+ "unexpected ) in channel type"},
+
+ % loadsys package imports LCHAN ','
+ "unexpected comma in channel type"},
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE
+ "unexpected semicolon or newline before else"},
+
+ % loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME
+ "name list not allowed in interface type"},
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME
+ "var declaration not allowed in for initializer"},
+
+ % loadsys package imports LVAR LNAME '[' ']' LNAME '{'
+ "unexpected { at end of statement"},
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{'
+ "unexpected { at end of statement"},
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';'
+ "argument to go/defer must be function call"},
+
+ % loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';'
+ "need trailing comma before newline in composite literal"},
+
+ % loadsys package imports LVAR LNAME '=' comptype '{' LNAME ';'
+ "need trailing comma before newline in composite literal"},
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME
+ "nested func not allowed"},
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';'
+ "else must be followed by if or statement block"},
+}
// license that can be found in the LICENSE file.
//go:generate go tool yacc go.y
+//go:generate go run yaccerrors.go
//go:generate go run mkbuiltin.go runtime unsafe
package gc
type yy struct{}
-var yymsg []struct {
- yystate, yychar int
- msg string
-}
-
func (yy) Lex(v *yySymType) int {
return int(yylex(v))
}
}
}
-var yystate int
-
-var yychar_subr int
-
var yyerror_lastsyntax int
func Yyerror(fmt_ string, args ...interface{}) {
if strings.HasPrefix(fmt_, "syntax error") {
nsyntaxerrors++
+ yystate := theparser.(*yyParserImpl).state()
+ yychar := theparser.Lookahead()
+
if Debug['x'] != 0 {
- fmt.Printf("yyerror: yystate=%d yychar=%d\n", yystate, yychar_subr)
+ fmt.Printf("yyerror: yystate=%d yychar=%d\n", yystate, yychar)
}
// An unexpected EOF caused a syntax error. Use the previous
}
// look for parse state-specific errors in list (see go.errors).
- for i := 0; i < len(yymsg); i++ {
- if yymsg[i].yystate == yystate && yymsg[i].yychar == yychar_subr {
+ for i := range yymsg {
+ if yymsg[i].yystate == yystate && yymsg[i].yychar == yychar {
yyerrorl(int(lexlineno), "syntax error: %s", yymsg[i].msg)
return
}
type yyParserImpl struct {
lookahead func() int
+ state func() int
}
func (p *yyParserImpl) Lookahead() int {
func yyNewParser() yyParser {
p := &yyParserImpl{
lookahead: func() int { return -1 },
+ state: func() int { return -1 },
}
return p
}
yystate := 0
yychar := -1
yytoken := -1 // yychar translated into internal numbering
+ yyrcvr.state = func() int { return yystate }
yyrcvr.lookahead = func() int { return yychar }
defer func() {
// Make sure we report no lookahead when not parsing.
+ yystate = -1
yychar = -1
yytoken = -1
}()
--- /dev/null
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// This program implements the core idea from
+//
+// Clinton L. Jeffery, Generating LR syntax error messages from examples,
+// ACM TOPLAS 25(5) (September 2003). http://doi.acm.org/10.1145/937563.937566
+//
+// It reads Bison's summary of a grammar followed by a file
+// like go.errors, replacing lines beginning with % by the
+// yystate and yychar that will be active when an error happens
+// while parsing that line.
+//
+// Unlike the system described in the paper, the lines in go.errors
+// give grammar symbol name lists, not actual program fragments.
+// This is a little less programmer-friendly but doesn't require being
+// able to run the text through lex.c.
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "strconv"
+ "strings"
+)
+
+func xatoi(s string) int {
+ n, err := strconv.Atoi(s)
+ if err != nil {
+ log.Fatal(err)
+ }
+ return n
+}
+
+func trimParen(s string) string {
+ s = strings.TrimPrefix(s, "(")
+ s = strings.TrimSuffix(s, ")")
+ return s
+}
+
+type action struct {
+ token string
+ n int
+}
+
+var shift = map[int][]action{}
+var reduce = map[int][]action{}
+
+type rule struct {
+ lhs string
+ size int
+}
+
+var rules = map[int]rule{}
+
+func readYaccOutput() {
+ r, err := os.Open("y.output")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer r.Close()
+
+ var state int
+
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ f := strings.Fields(scanner.Text())
+ nf := len(f)
+
+ if nf >= 4 && f[1] == "terminals," && f[3] == "nonterminals" {
+ // We're done.
+ break
+ }
+
+ if nf >= 2 && f[0] == "state" {
+ state = xatoi(f[1])
+ continue
+ }
+ if nf >= 3 && (f[1] == "shift" || f[1] == "goto") {
+ shift[state] = append(shift[state], action{f[0], xatoi(f[2])})
+ continue
+ }
+ if nf >= 3 && f[1] == "reduce" {
+ reduce[state] = append(reduce[state], action{f[0], xatoi(f[2])})
+ continue
+ }
+ if nf >= 3 && strings.HasSuffix(f[0], ":") && strings.HasPrefix(f[nf-1], "(") && strings.HasSuffix(f[nf-1], ")") {
+ n := xatoi(trimParen(f[nf-1]))
+
+ size := nf - 2
+ if size == 1 && f[1] == "." {
+ size = 0
+ }
+
+ rules[n] = rule{strings.TrimSuffix(f[0], ":"), size}
+ continue
+ }
+ }
+}
+
+func runMachine(w io.Writer, s string) {
+ f := strings.Fields(s)
+
+ // Run it through the LR machine and print the induced "yystate, yychar,"
+ // at the point where the error happens.
+
+ var stack []int
+ state := 0
+ i := 1
+ tok := ""
+
+Loop:
+ if tok == "" && i < len(f) {
+ tok = f[i]
+ i++
+ }
+
+ for _, a := range shift[state] {
+ if a.token == tok {
+ if false {
+ fmt.Println("SHIFT ", tok, " ", state, " -> ", a)
+ }
+ stack = append(stack, state)
+ state = a.n
+ tok = ""
+ goto Loop
+ }
+ }
+
+ for _, a := range reduce[state] {
+ if a.token == tok || a.token == "." {
+ stack = append(stack, state)
+ rule, ok := rules[a.n]
+ if !ok {
+ log.Fatal("missing rule")
+ }
+ stack = stack[:len(stack)-rule.size]
+ state = stack[len(stack)-1]
+ stack = stack[:len(stack)-1]
+ if tok != "" {
+ i--
+ }
+ tok = rule.lhs
+ if false {
+ fmt.Println("REDUCE ", stack, " ", state, " ", tok, " rule ", rule)
+ }
+ goto Loop
+ }
+ }
+
+ // No shift or reduce applied - found the error.
+ fmt.Fprintf(w, "\t{%d, %s,\n", state, tok)
+}
+
+func processGoErrors() {
+ r, err := os.Open("go.errors")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer r.Close()
+
+ w, err := os.Create("yymsg.go")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer w.Close()
+
+ fmt.Fprintf(w, "// DO NOT EDIT - generated with go generate\n\n")
+
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ s := scanner.Text()
+
+ // Treat % as first field on line as introducing a pattern (token sequence).
+ if strings.HasPrefix(strings.TrimSpace(s), "%") {
+ runMachine(w, s)
+ continue
+ }
+
+ fmt.Fprintln(w, s)
+ }
+}
+
+func main() {
+ readYaccOutput()
+ processGoErrors()
+}
--- /dev/null
+// DO NOT EDIT - generated with go generate
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Example-based syntax error messages.
+// See yaccerrors.go.
+
+package gc
+
+var yymsg = []struct {
+ yystate int
+ yychar int
+ msg string
+}{
+ // Each line of the form % token list
+ // is converted by bisonerrors into the yystate and yychar caused
+ // by that token list.
+
+ {332, ',',
+ "unexpected comma during import block"},
+
+ {89, ';',
+ "missing import path; require quoted string"},
+
+ {390, ';',
+ "missing { after if clause"},
+
+ {387, ';',
+ "missing { after switch clause"},
+
+ {279, ';',
+ "missing { after for clause"},
+
+ {498, LBODY,
+ "missing { after for clause"},
+
+ {17, '{',
+ "unexpected semicolon or newline before {"},
+
+ {111, ';',
+ "unexpected semicolon or newline in type declaration"},
+
+ {78, '}',
+ "unexpected } in channel type"},
+
+ {78, ')',
+ "unexpected ) in channel type"},
+
+ {78, ',',
+ "unexpected comma in channel type"},
+
+ {416, LELSE,
+ "unexpected semicolon or newline before else"},
+
+ {329, ',',
+ "name list not allowed in interface type"},
+
+ {279, LVAR,
+ "var declaration not allowed in for initializer"},
+
+ {25, '{',
+ "unexpected { at end of statement"},
+
+ {371, '{',
+ "unexpected { at end of statement"},
+
+ {122, ';',
+ "argument to go/defer must be function call"},
+
+ {398, ';',
+ "need trailing comma before newline in composite literal"},
+
+ {414, ';',
+ "need trailing comma before newline in composite literal"},
+
+ {124, LNAME,
+ "nested func not allowed"},
+
+ {650, ';',
+ "else must be followed by if or statement block"},
+}
type $$ParserImpl struct {
lookahead func() int
+ state func() int
}
func (p *$$ParserImpl) Lookahead() int {
func $$NewParser() $$Parser {
p := &$$ParserImpl{
lookahead: func() int { return -1 },
+ state: func() int { return -1 },
}
return p
}
$$state := 0
$$char := -1
$$token := -1 // $$char translated into internal numbering
+ $$rcvr.state = func() int { return $$state }
$$rcvr.lookahead = func() int { return $$char }
defer func() {
// Make sure we report no lookahead when not parsing.
+ $$state = -1
$$char = -1
$$token = -1
}()
-// skip
-// TODO(rsc): Reenable. See issue 9968.
-
// errorcheck
// Copyright 2009 The Go Authors. All rights reserved.
type J interface {
h T; // ERROR "syntax|signature"
}
-
-// skip
-// TODO(rsc): Reenable. See issue 9968.
-
// errorcheck
// Copyright 2012 The Go Authors. All rights reserved.