mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal/gc: recursive-descent parser
This is a translation of the yacc-based parser with adjustements to make the grammar work for a recursive-descent parser followed by cleanups and simplifications. The yacc actions were mostly literally copied for correctness with better temporary names. A few of the syntax tests were adjusted for slightly different error messages (it is very difficult to match the yacc-based error messages in all cases, and sometimes the new parser could produce better errors). The new parser is enabled by default. To switch back to the yacc-based parser, set -oldparser. To hardwire the switch back, uncomment "oldparser = 1" in lex.go. - passes all.bash - ~18% reduced parse time per file on average for make.bash - ~3% reduced compile time for building cmd/compile Change-Id: Icb5651bb9d8b9f66261762d2c94a03793050d4ce Reviewed-on: https://go-review.googlesource.com/16665 Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
b5c1b5d7a0
commit
b569b87ca1
11 changed files with 3494 additions and 22 deletions
|
|
@ -628,7 +628,7 @@ var Widthint int
|
||||||
|
|
||||||
var Widthreg int
|
var Widthreg int
|
||||||
|
|
||||||
var typesw *Node
|
var typesw *Node // TODO(gri) remove when yacc-based parser is gone
|
||||||
|
|
||||||
var nblank *Node
|
var nblank *Node
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,8 @@ func Main() {
|
||||||
obj.Flagcount("live", "debug liveness analysis", &debuglive)
|
obj.Flagcount("live", "debug liveness analysis", &debuglive)
|
||||||
obj.Flagcount("m", "print optimization decisions", &Debug['m'])
|
obj.Flagcount("m", "print optimization decisions", &Debug['m'])
|
||||||
obj.Flagcount("msan", "build code compatible with C/C++ memory sanitizer", &flag_msan)
|
obj.Flagcount("msan", "build code compatible with C/C++ memory sanitizer", &flag_msan)
|
||||||
obj.Flagcount("newexport", "use new export format", &newexport) // TODO remove eventually
|
obj.Flagcount("newexport", "use new export format", &newexport) // TODO(gri) remove eventually
|
||||||
|
obj.Flagcount("oldparser", "use old parser", &oldparser) // TODO(gri) remove eventually
|
||||||
obj.Flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports)
|
obj.Flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports)
|
||||||
obj.Flagstr("o", "write output to `file`", &outfile)
|
obj.Flagstr("o", "write output to `file`", &outfile)
|
||||||
obj.Flagstr("p", "set expected package import `path`", &myimportpath)
|
obj.Flagstr("p", "set expected package import `path`", &myimportpath)
|
||||||
|
|
@ -317,7 +318,19 @@ func Main() {
|
||||||
lexlineno = 1
|
lexlineno = 1
|
||||||
const BOM = 0xFEFF
|
const BOM = 0xFEFF
|
||||||
|
|
||||||
|
// Uncomment the line below to temporarily switch the compiler back
|
||||||
|
// to the yacc-based parser. Short-term work-around for issues with
|
||||||
|
// the new recursive-descent parser for which setting -oldparser is
|
||||||
|
// not sufficient.
|
||||||
|
// TODO(gri) remove this eventually
|
||||||
|
//
|
||||||
|
// oldparser = 1
|
||||||
|
|
||||||
for _, infile = range flag.Args() {
|
for _, infile = range flag.Args() {
|
||||||
|
if trace && Debug['x'] != 0 && oldparser == 0 {
|
||||||
|
fmt.Printf("--- %s ---\n", infile)
|
||||||
|
}
|
||||||
|
|
||||||
linehistpush(infile)
|
linehistpush(infile)
|
||||||
|
|
||||||
curio.infile = infile
|
curio.infile = infile
|
||||||
|
|
@ -831,6 +844,10 @@ func importfile(f *Val, line int) {
|
||||||
curio.nlsemi = false
|
curio.nlsemi = false
|
||||||
typecheckok = true
|
typecheckok = true
|
||||||
|
|
||||||
|
if oldparser == 0 {
|
||||||
|
push_parser()
|
||||||
|
}
|
||||||
|
|
||||||
case 'B':
|
case 'B':
|
||||||
// new export format
|
// new export format
|
||||||
obj.Bgetc(imp) // skip \n after $$B
|
obj.Bgetc(imp) // skip \n after $$B
|
||||||
|
|
@ -850,6 +867,10 @@ func importfile(f *Val, line int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func unimportfile() {
|
func unimportfile() {
|
||||||
|
if oldparser == 0 {
|
||||||
|
pop_parser()
|
||||||
|
}
|
||||||
|
|
||||||
if curio.bin != nil {
|
if curio.bin != nil {
|
||||||
obj.Bterm(curio.bin)
|
obj.Bterm(curio.bin)
|
||||||
curio.bin = nil
|
curio.bin = nil
|
||||||
|
|
@ -879,6 +900,10 @@ func cannedimports(file string, cp string) {
|
||||||
|
|
||||||
typecheckok = true
|
typecheckok = true
|
||||||
incannedimport = 1
|
incannedimport = 1
|
||||||
|
|
||||||
|
if oldparser == 0 {
|
||||||
|
push_parser()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isSpace(c int) bool {
|
func isSpace(c int) bool {
|
||||||
|
|
@ -1358,8 +1383,10 @@ l0:
|
||||||
// a '{' with loophack == true becomes LBODY and disables loophack.
|
// a '{' with loophack == true becomes LBODY and disables loophack.
|
||||||
//
|
//
|
||||||
// I said it was clumsy.
|
// I said it was clumsy.
|
||||||
|
//
|
||||||
|
// We only need the loophack when running with -oldparser.
|
||||||
case '(', '[':
|
case '(', '[':
|
||||||
if loophack || _yylex_lstk != nil {
|
if oldparser != 0 && (loophack || _yylex_lstk != nil) {
|
||||||
h = new(Loophack)
|
h = new(Loophack)
|
||||||
if h == nil {
|
if h == nil {
|
||||||
Flusherrors()
|
Flusherrors()
|
||||||
|
|
@ -1376,7 +1403,7 @@ l0:
|
||||||
goto lx
|
goto lx
|
||||||
|
|
||||||
case ')', ']':
|
case ')', ']':
|
||||||
if _yylex_lstk != nil {
|
if oldparser != 0 && _yylex_lstk != nil {
|
||||||
h = _yylex_lstk
|
h = _yylex_lstk
|
||||||
loophack = h.v
|
loophack = h.v
|
||||||
_yylex_lstk = h.next
|
_yylex_lstk = h.next
|
||||||
|
|
@ -1385,7 +1412,7 @@ l0:
|
||||||
goto lx
|
goto lx
|
||||||
|
|
||||||
case '{':
|
case '{':
|
||||||
if loophack {
|
if oldparser != 0 && loophack {
|
||||||
if Debug['x'] != 0 {
|
if Debug['x'] != 0 {
|
||||||
fmt.Printf("%v lex: LBODY\n", Ctxt.Line(int(lexlineno)))
|
fmt.Printf("%v lex: LBODY\n", Ctxt.Line(int(lexlineno)))
|
||||||
}
|
}
|
||||||
|
|
@ -1460,7 +1487,9 @@ talph:
|
||||||
goto l0
|
goto l0
|
||||||
|
|
||||||
case LFOR, LIF, LSWITCH, LSELECT:
|
case LFOR, LIF, LSWITCH, LSELECT:
|
||||||
loophack = true // see comment about loophack above
|
if oldparser != 0 {
|
||||||
|
loophack = true // see comment about loophack above
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if Debug['x'] != 0 {
|
if Debug['x'] != 0 {
|
||||||
|
|
@ -1902,13 +1931,18 @@ func (yy) Error(msg string) {
|
||||||
Yyerror("%s", msg)
|
Yyerror("%s", msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var oldparser int // if set, theparser is used (otherwise we use the recursive-descent parser)
|
||||||
var theparser yyParser
|
var theparser yyParser
|
||||||
var parsing bool
|
var parsing bool
|
||||||
|
|
||||||
func yyparse() {
|
func yyparse() {
|
||||||
theparser = yyNewParser()
|
|
||||||
parsing = true
|
parsing = true
|
||||||
theparser.Parse(yy{})
|
if oldparser != 0 {
|
||||||
|
theparser = yyNewParser()
|
||||||
|
theparser.Parse(yy{})
|
||||||
|
} else {
|
||||||
|
parse_file()
|
||||||
|
}
|
||||||
parsing = false
|
parsing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
3438
src/cmd/compile/internal/gc/parser.go
Normal file
3438
src/cmd/compile/internal/gc/parser.go
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -34,7 +34,7 @@ func errorexit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parserline() int {
|
func parserline() int {
|
||||||
if parsing && theparser.Lookahead() > 0 {
|
if oldparser != 0 && parsing && theparser.Lookahead() > 0 {
|
||||||
// parser has one symbol lookahead
|
// parser has one symbol lookahead
|
||||||
return int(prevlineno)
|
return int(prevlineno)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil" // GCCGO_ERROR "imported and not used"
|
// avoid imported and not used errors
|
||||||
|
// "io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os" // GCCGO_ERROR "imported and not used"
|
// "os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
|
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) // ERROR "syntax error|invalid use of type"
|
return func(w http.ResponseWriter, r *http.Request) // ERROR "syntax error|not an expression|invalid use of type"
|
||||||
}
|
}
|
||||||
|
|
||||||
type Page struct {
|
type Page struct {
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ package main
|
||||||
|
|
||||||
type xyz struct {
|
type xyz struct {
|
||||||
ch chan
|
ch chan
|
||||||
} // ERROR "unexpected .*}.* in channel type"
|
} // ERROR "unexpected .*}.* in channel type|missing channel element type"
|
||||||
|
|
||||||
func Foo(y chan) { // ERROR "unexpected .*\).* in channel type"
|
func Foo(y chan) { // ERROR "unexpected .*\).* in channel type|missing channel element type"
|
||||||
}
|
}
|
||||||
|
|
||||||
func Bar(x chan, y int) { // ERROR "unexpected comma in channel type"
|
func Bar(x chan, y int) { // ERROR "unexpected comma in channel type|missing channel element type"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,5 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
var x int // avoid undefined: x error below with recursive-descent parser
|
||||||
for var x = 0; x < 10; x++ { // ERROR "var declaration not allowed in for initializer"
|
for var x = 0; x < 10; x++ { // ERROR "var declaration not allowed in for initializer"
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ package main
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
for x // GCCGO_ERROR "undefined"
|
for x // GCCGO_ERROR "undefined"
|
||||||
{ // ERROR "missing .*{.* after for clause"
|
{ // ERROR "missing .*{.* after for clause|missing operand"
|
||||||
z // GCCGO_ERROR "undefined"
|
z // GCCGO_ERROR "undefined"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,5 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
type T // ERROR "unexpected semicolon or newline in type declaration"
|
type T // ERROR "unexpected semicolon or newline in type declaration"
|
||||||
{
|
// line below uncommented to avoid follow-up error
|
||||||
|
// {
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@ package main
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if x { } // GCCGO_ERROR "undefined"
|
if x { } // GCCGO_ERROR "undefined"
|
||||||
else { } // ERROR "unexpected semicolon or newline before .?else.?"
|
else { } // ERROR "unexpected semicolon or newline before .?else.?|unexpected else"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,5 @@
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
var x map[string]string{"a":"b"} // ERROR "unexpected { at end of statement|expected ';' or newline after top level declaration"
|
var x map[string]string{"a":"b"} // ERROR "unexpected { at end of statement|unexpected { after top level declaration|expected ';' or newline after top level declaration"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue