Commit 4b7325c7 authored by griesemer's avatar griesemer Committed by Robert Griesemer

cmd/compile/internal/syntax: cleanups around parser tracing

These changes affect the parser only when the internal trace
constant is set.

- factored our printing code used for tracing
- streamlined advance function and added trace output

The parser's trace output now more clearly prints what tokens
are skipped and which is the next token in case of an error.

Example trace:

    4: . . . . . . . . . . call (
    4: . . . . . . . . . . . expr (
    4: . . . . . . . . . . . . unaryExpr (
    4: . . . . . . . . . . . . . pexpr (
    4: . . . . . . . . . . . . . . operand name (
    4: . . . . . . . . . . . . . . )
    4: . . . . . . . . . . . . . . call (
    4: . . . . . . . . . . . . . . )
    4: . . . . . . . . . . . . . )
    4: . . . . . . . . . . . . )
    4: . . . . . . . . . . . )
    4: . . . . . . . . . . . syntax error: expecting comma or )
    4: . . . . . . . . . . . skip ;
    6: . . . . . . . . . . . skip name
    6: . . . . . . . . . . . skip :=
    6: . . . . . . . . . . . skip literal
    6: . . . . . . . . . . . skip ;
    7: . . . . . . . . . . . skip }
    7: . . . . . . . . . . . skip ;
    9: . . . . . . . . . . . skip func
    9: . . . . . . . . . . . skip name
    9: . . . . . . . . . . . skip (
    9: . . . . . . . . . . . next )
    9: . . . . . . . . . . )

For #22164.

Change-Id: I4a233696b1f989ee3287472172afaf92cf424565
Reviewed-on: https://go-review.googlesource.com/70490Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
parent 5ddd3d58
......@@ -614,6 +614,7 @@ var knownFormats = map[string]string{
"[]cmd/compile/internal/ssa.Edge %v": "",
"[]cmd/compile/internal/ssa.ID %v": "",
"[]cmd/compile/internal/ssa.VarLocList %v": "",
"[]cmd/compile/internal/syntax.token %s": "",
"[]string %v": "",
"bool %v": "",
"byte %08b": "",
......@@ -683,9 +684,9 @@ var knownFormats = map[string]string{
"int32 %d": "",
"int32 %v": "",
"int32 %x": "",
"int64 %.5d": "",
"int64 %+d": "",
"int64 %-10d": "",
"int64 %.5d": "",
"int64 %X": "",
"int64 %d": "",
"int64 %v": "",
......
......@@ -97,7 +97,7 @@ func (p *parser) got(tok token) bool {
func (p *parser) want(tok token) {
if !p.got(tok) {
p.syntax_error("expecting " + tok.String())
p.syntax_error("expecting " + tokstring(tok))
p.advance()
}
}
......@@ -126,7 +126,7 @@ func (p *parser) error_at(pos src.Pos, msg string) {
// syntax_error_at reports a syntax error at the given position.
func (p *parser) syntax_error_at(pos src.Pos, msg string) {
if trace {
defer p.trace("syntax_error (" + msg + ")")()
p.print("syntax error: " + msg)
}
if p.tok == _EOF && p.first != nil {
......@@ -168,6 +168,18 @@ func (p *parser) syntax_error_at(pos src.Pos, msg string) {
p.error_at(pos, "syntax error: unexpected "+tok+msg)
}
// tokstring returns the English word for selected punctuation tokens
// for more readable error messages.
func tokstring(tok token) string {
switch tok {
case _Comma:
return "comma"
case _Semi:
return "semicolon"
}
return tok.String()
}
// Convenience methods using the current token position.
func (p *parser) pos() src.Pos { return p.pos_at(p.line, p.col) }
func (p *parser) error(msg string) { p.error_at(p.pos(), msg) }
......@@ -194,40 +206,42 @@ const stopset uint64 = 1<<_Break |
// Advance consumes tokens until it finds a token of the stopset or followlist.
// The stopset is only considered if we are inside a function (p.fnest > 0).
// The followlist is the list of valid tokens that can follow a production;
// if it is empty, exactly one token is consumed to ensure progress.
// if it is empty, exactly one (non-EOF) token is consumed to ensure progress.
func (p *parser) advance(followlist ...token) {
if len(followlist) == 0 {
p.next()
return
if trace {
p.print(fmt.Sprintf("advance %s", followlist))
}
// compute follow set
// (not speed critical, advance is only called in error situations)
var followset uint64 = 1 << _EOF // never skip over EOF
for _, tok := range followlist {
followset |= 1 << tok
var followset uint64 = 1 << _EOF // don't skip over EOF
if len(followlist) > 0 {
if p.fnest > 0 {
followset |= stopset
}
for _, tok := range followlist {
followset |= 1 << tok
}
}
for !(contains(followset, p.tok) || p.fnest > 0 && contains(stopset, p.tok)) {
for !contains(followset, p.tok) {
if trace {
p.print("skip " + p.tok.String())
}
p.next()
if len(followlist) == 0 {
break
}
}
}
func tokstring(tok token) string {
switch tok {
case _EOF:
return "EOF"
case _Comma:
return "comma"
case _Semi:
return "semicolon"
if trace {
p.print("next " + p.tok.String())
}
return tok.String()
}
// usage: defer p.trace(msg)()
func (p *parser) trace(msg string) func() {
fmt.Printf("%5d: %s%s (\n", p.line, p.indent, msg)
p.print(msg + " (")
const tab = ". "
p.indent = append(p.indent, tab...)
return func() {
......@@ -235,10 +249,14 @@ func (p *parser) trace(msg string) func() {
if x := recover(); x != nil {
panic(x) // skip print_trace
}
fmt.Printf("%5d: %s)\n", p.line, p.indent)
p.print(")")
}
}
func (p *parser) print(msg string) {
fmt.Printf("%5d: %s%s\n", p.line, p.indent, msg)
}
// ----------------------------------------------------------------------------
// Package files
//
......
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