]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: move lexer into separate file (cleanup)
authorRobert Griesemer <gri@golang.org>
Fri, 11 Mar 2016 22:28:16 +0000 (14:28 -0800)
committerRobert Griesemer <gri@golang.org>
Fri, 11 Mar 2016 22:59:57 +0000 (22:59 +0000)
This is really moving all the non-lexer pieces out of lex.go
into main.go. It's always been confusing that the top-most
compiler entry point (Main) is in the same file with the
lexer. Both files remain of substantial size (> 1000 lines),
which justifies this even more.

No other changes.

Change-Id: I03895589d5e3cc2340580350bbc1420539893dfc
Reviewed-on: https://go-review.googlesource.com/20601
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/gc/lex.go
src/cmd/compile/internal/gc/main.go [new file with mode: 0644]

index facda14c371d93419bff747d62bec3f8b8f520b5..23eb97a5e3cf14adbdecdfa9b208f20aa29cf5ff 100644 (file)
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:generate go run mkbuiltin.go
-
 package gc
 
 import (
        "bufio"
-       "cmd/compile/internal/ssa"
        "cmd/internal/obj"
-       "flag"
        "fmt"
        "io"
-       "log"
-       "os"
-       "path"
        "strconv"
        "strings"
        "unicode"
        "unicode/utf8"
 )
 
-var imported_unsafe bool
-
-var (
-       goos    string
-       goarch  string
-       goroot  string
-       buildid string
-)
-
-var (
-       Debug_append int
-       Debug_panic  int
-       Debug_slice  int
-       Debug_wb     int
-)
-
-const BOM = 0xFEFF
-
-// Debug arguments.
-// These can be specified with the -d flag, as in "-d nil"
-// to set the debug_checknil variable. In general the list passed
-// to -d can be comma-separated.
-var debugtab = []struct {
-       name string
-       val  *int
-}{
-       {"append", &Debug_append},         // print information about append compilation
-       {"disablenil", &Disable_checknil}, // disable nil checks
-       {"gcprog", &Debug_gcprog},         // print dump of GC programs
-       {"nil", &Debug_checknil},          // print information about nil checks
-       {"panic", &Debug_panic},           // do not hide any compiler panic
-       {"slice", &Debug_slice},           // print information about slice compilation
-       {"typeassert", &Debug_typeassert}, // print information about type assertion inlining
-       {"wb", &Debug_wb},                 // print information about write barriers
-       {"export", &Debug_export},         // print export data
-}
-
 const (
        EOF = -1
+       BOM = 0xFEFF
 )
 
-func usage() {
-       fmt.Printf("usage: compile [options] file.go...\n")
-       obj.Flagprint(1)
-       Exit(2)
-}
-
-func hidePanic() {
-       if Debug_panic == 0 && nsavederrors+nerrors > 0 {
-               // If we've already complained about things
-               // in the program, don't bother complaining
-               // about a panic too; let the user clean up
-               // the code and try again.
-               if err := recover(); err != nil {
-                       errorexit()
-               }
-       }
-}
-
-func doversion() {
-       p := obj.Expstring()
-       if p == "X:none" {
-               p = ""
-       }
-       sep := ""
-       if p != "" {
-               sep = " "
-       }
-       fmt.Printf("compile version %s%s%s\n", obj.Getgoversion(), sep, p)
-       os.Exit(0)
-}
-
-func Main() {
-       defer hidePanic()
-
-       // Allow GOARCH=thearch.thestring or GOARCH=thearch.thestringsuffix,
-       // but not other values.
-       p := obj.Getgoarch()
-
-       if !strings.HasPrefix(p, Thearch.Thestring) {
-               log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.Thechar, p)
-       }
-       goarch = p
-
-       Thearch.Linkarchinit()
-       Ctxt = obj.Linknew(Thearch.Thelinkarch)
-       Ctxt.DiagFunc = Yyerror
-       Ctxt.Bso = &bstdout
-       bstdout = *obj.Binitw(os.Stdout)
-
-       localpkg = mkpkg("")
-       localpkg.Prefix = "\"\""
-
-       // pseudo-package, for scoping
-       builtinpkg = mkpkg("go.builtin")
-
-       builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
-
-       // pseudo-package, accessed by import "unsafe"
-       unsafepkg = mkpkg("unsafe")
-
-       unsafepkg.Name = "unsafe"
-
-       // real package, referred to by generated runtime calls
-       Runtimepkg = mkpkg("runtime")
-
-       Runtimepkg.Name = "runtime"
-
-       // pseudo-packages used in symbol tables
-       gostringpkg = mkpkg("go.string")
-
-       gostringpkg.Name = "go.string"
-       gostringpkg.Prefix = "go.string" // not go%2estring
-
-       itabpkg = mkpkg("go.itab")
-
-       itabpkg.Name = "go.itab"
-       itabpkg.Prefix = "go.itab" // not go%2eitab
-
-       typelinkpkg = mkpkg("go.typelink")
-       typelinkpkg.Name = "go.typelink"
-       typelinkpkg.Prefix = "go.typelink" // not go%2etypelink
-
-       trackpkg = mkpkg("go.track")
-
-       trackpkg.Name = "go.track"
-       trackpkg.Prefix = "go.track" // not go%2etrack
-
-       typepkg = mkpkg("type")
-
-       typepkg.Name = "type"
-
-       goroot = obj.Getgoroot()
-       goos = obj.Getgoos()
-
-       Nacl = goos == "nacl"
-       if Nacl {
-               flag_largemodel = 1
-       }
-
-       outfile = ""
-       obj.Flagcount("+", "compiling runtime", &compiling_runtime)
-       obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
-       obj.Flagcount("A", "for bootstrapping, allow 'any' type", &Debug['A'])
-       obj.Flagcount("B", "disable bounds checking", &Debug['B'])
-       obj.Flagstr("D", "set relative `path` for local imports", &localimport)
-       obj.Flagcount("E", "debug symbol export", &Debug['E'])
-       obj.Flagfn1("I", "add `directory` to import search path", addidir)
-       obj.Flagcount("K", "debug missing line numbers", &Debug['K'])
-       obj.Flagcount("L", "use full (long) path in error messages", &Debug['L'])
-       obj.Flagcount("M", "debug move generation", &Debug['M'])
-       obj.Flagcount("N", "disable optimizations", &Debug['N'])
-       obj.Flagcount("P", "debug peephole optimizer", &Debug['P'])
-       obj.Flagcount("R", "debug register optimizer", &Debug['R'])
-       obj.Flagcount("S", "print assembly listing", &Debug['S'])
-       obj.Flagfn0("V", "print compiler version", doversion)
-       obj.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
-       obj.Flagstr("asmhdr", "write assembly header to `file`", &asmhdr)
-       obj.Flagstr("buildid", "record `id` as the build id in the export metadata", &buildid)
-       obj.Flagcount("complete", "compiling complete package (no C or assembly)", &pure_go)
-       obj.Flagstr("d", "print debug information about items in `list`", &debugstr)
-       obj.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
-       obj.Flagcount("f", "debug stack frames", &Debug['f'])
-       obj.Flagcount("g", "debug code generation", &Debug['g'])
-       obj.Flagcount("h", "halt on error", &Debug['h'])
-       obj.Flagcount("i", "debug line number stack", &Debug['i'])
-       obj.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
-       obj.Flagstr("installsuffix", "set pkg directory `suffix`", &flag_installsuffix)
-       obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
-       obj.Flagcount("l", "disable inlining", &Debug['l'])
-       obj.Flagcount("live", "debug liveness analysis", &debuglive)
-       obj.Flagcount("m", "print optimization decisions", &Debug['m'])
-       obj.Flagcount("msan", "build code compatible with C/C++ memory sanitizer", &flag_msan)
-       obj.Flagcount("newexport", "use new export format", &newexport) // TODO(gri) remove eventually (issue 13241)
-       obj.Flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports)
-       obj.Flagstr("o", "write output to `file`", &outfile)
-       obj.Flagstr("p", "set expected package import `path`", &myimportpath)
-       obj.Flagcount("pack", "write package file instead of object file", &writearchive)
-       obj.Flagcount("r", "debug generated wrappers", &Debug['r'])
-       obj.Flagcount("race", "enable race detector", &flag_race)
-       obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
-       obj.Flagstr("trimpath", "remove `prefix` from recorded source file paths", &Ctxt.LineHist.TrimPathPrefix)
-       obj.Flagcount("u", "reject unsafe code", &safemode)
-       obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
-       obj.Flagcount("w", "debug type checking", &Debug['w'])
-       use_writebarrier = 1
-       obj.Flagcount("wb", "enable write barrier", &use_writebarrier)
-       obj.Flagcount("x", "debug lexer", &Debug['x'])
-       obj.Flagcount("y", "debug declarations in canned imports (with -d)", &Debug['y'])
-       var flag_shared int
-       var flag_dynlink bool
-       switch Thearch.Thechar {
-       case '5', '6', '7', '8', '9':
-               obj.Flagcount("shared", "generate code that can be linked into a shared library", &flag_shared)
-       }
-       if Thearch.Thechar == '6' {
-               obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel)
-       }
-       switch Thearch.Thechar {
-       case '5', '6', '7', '8', '9':
-               flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
-       }
-       obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile)
-       obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile)
-       obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate)
-       flag.BoolVar(&ssaEnabled, "ssa", true, "use SSA backend to generate code")
-       obj.Flagparse(usage)
-
-       if flag_dynlink {
-               flag_shared = 1
-       }
-       Ctxt.Flag_shared = int32(flag_shared)
-       Ctxt.Flag_dynlink = flag_dynlink
-       Ctxt.Flag_optimize = Debug['N'] == 0
-
-       Ctxt.Debugasm = int32(Debug['S'])
-       Ctxt.Debugvlog = int32(Debug['v'])
-
-       if flag.NArg() < 1 {
-               usage()
-       }
-
-       startProfile()
-
-       if flag_race != 0 {
-               racepkg = mkpkg("runtime/race")
-               racepkg.Name = "race"
-       }
-       if flag_msan != 0 {
-               msanpkg = mkpkg("runtime/msan")
-               msanpkg.Name = "msan"
-       }
-       if flag_race != 0 && flag_msan != 0 {
-               log.Fatal("cannot use both -race and -msan")
-       } else if flag_race != 0 || flag_msan != 0 {
-               instrumenting = true
-       }
-
-       // parse -d argument
-       if debugstr != "" {
-       Split:
-               for _, name := range strings.Split(debugstr, ",") {
-                       if name == "" {
-                               continue
-                       }
-                       val := 1
-                       if i := strings.Index(name, "="); i >= 0 {
-                               var err error
-                               val, err = strconv.Atoi(name[i+1:])
-                               if err != nil {
-                                       log.Fatalf("invalid debug value %v", name)
-                               }
-                               name = name[:i]
-                       }
-                       for _, t := range debugtab {
-                               if t.name == name {
-                                       if t.val != nil {
-                                               *t.val = val
-                                               continue Split
-                                       }
-                               }
-                       }
-                       // special case for ssa for now
-                       if strings.HasPrefix(name, "ssa/") {
-                               // expect form ssa/phase/flag
-                               // e.g. -d=ssa/generic_cse/time
-                               // _ in phase name also matches space
-                               phase := name[4:]
-                               flag := "debug" // default flag is debug
-                               if i := strings.Index(phase, "/"); i >= 0 {
-                                       flag = phase[i+1:]
-                                       phase = phase[:i]
-                               }
-                               err := ssa.PhaseOption(phase, flag, val)
-                               if err != "" {
-                                       log.Fatalf(err)
-                               }
-                               continue Split
-                       }
-                       log.Fatalf("unknown debug key -d %s\n", name)
-               }
-       }
-
-       // enable inlining.  for now:
-       //      default: inlining on.  (debug['l'] == 1)
-       //      -l: inlining off  (debug['l'] == 0)
-       //      -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
-       if Debug['l'] <= 1 {
-               Debug['l'] = 1 - Debug['l']
-       }
-
-       Thearch.Betypeinit()
-       if Widthptr == 0 {
-               Fatalf("betypeinit failed")
-       }
-
-       lexinit()
-       typeinit()
-       lexinit1()
-
-       blockgen = 1
-       dclcontext = PEXTERN
-       nerrors = 0
-       lexlineno = 1
-
-       loadsys()
-
-       for _, infile = range flag.Args() {
-               if trace && Debug['x'] != 0 {
-                       fmt.Printf("--- %s ---\n", infile)
-               }
-
-               linehistpush(infile)
-
-               f, err := os.Open(infile)
-               if err != nil {
-                       fmt.Printf("open %s: %v\n", infile, err)
-                       errorexit()
-               }
-               bin := bufio.NewReader(f)
-
-               // Skip initial BOM if present.
-               if r, _, _ := bin.ReadRune(); r != BOM {
-                       bin.UnreadRune()
-               }
-
-               block = 1
-               iota_ = -1000000
-
-               imported_unsafe = false
-
-               parse_file(bin)
-               if nsyntaxerrors != 0 {
-                       errorexit()
-               }
-
-               // Instead of converting EOF into '\n' in getc and count it as an extra line
-               // for the line history to work, and which then has to be corrected elsewhere,
-               // just add a line here.
-               lexlineno++
-
-               linehistpop()
-               f.Close()
-       }
-
-       testdclstack()
-       mkpackage(localpkg.Name) // final import not used checks
-       lexfini()
-
-       typecheckok = true
-       if Debug['f'] != 0 {
-               frame(1)
-       }
-
-       // Process top-level declarations in phases.
-
-       // Phase 1: const, type, and names and types of funcs.
-       //   This will gather all the information about types
-       //   and methods but doesn't depend on any of it.
-       defercheckwidth()
-
-       // Don't use range--typecheck can add closures to xtop.
-       for i := 0; i < len(xtop); i++ {
-               if xtop[i].Op != ODCL && xtop[i].Op != OAS && xtop[i].Op != OAS2 {
-                       typecheck(&xtop[i], Etop)
-               }
-       }
-
-       // Phase 2: Variable assignments.
-       //   To check interface assignments, depends on phase 1.
-
-       // Don't use range--typecheck can add closures to xtop.
-       for i := 0; i < len(xtop); i++ {
-               if xtop[i].Op == ODCL || xtop[i].Op == OAS || xtop[i].Op == OAS2 {
-                       typecheck(&xtop[i], Etop)
-               }
-       }
-       resumecheckwidth()
-
-       // Phase 3: Type check function bodies.
-       // Don't use range--typecheck can add closures to xtop.
-       for i := 0; i < len(xtop); i++ {
-               if xtop[i].Op == ODCLFUNC || xtop[i].Op == OCLOSURE {
-                       Curfn = xtop[i]
-                       decldepth = 1
-                       saveerrors()
-                       typechecklist(Curfn.Nbody.Slice(), Etop)
-                       checkreturn(Curfn)
-                       if nerrors != 0 {
-                               Curfn.Nbody.Set(nil) // type errors; do not compile
-                       }
-               }
-       }
-
-       // Phase 4: Decide how to capture closed variables.
-       // This needs to run before escape analysis,
-       // because variables captured by value do not escape.
-       for _, n := range xtop {
-               if n.Op == ODCLFUNC && n.Func.Closure != nil {
-                       Curfn = n
-                       capturevars(n)
-               }
-       }
-
-       Curfn = nil
-
-       if nsavederrors+nerrors != 0 {
-               errorexit()
-       }
-
-       // Phase 5: Inlining
-       if Debug['l'] > 1 {
-               // Typecheck imported function bodies if debug['l'] > 1,
-               // otherwise lazily when used or re-exported.
-               for _, n := range importlist {
-                       if len(n.Func.Inl.Slice()) != 0 {
-                               saveerrors()
-                               typecheckinl(n)
-                       }
-               }
-
-               if nsavederrors+nerrors != 0 {
-                       errorexit()
-               }
-       }
-
-       if Debug['l'] != 0 {
-               // Find functions that can be inlined and clone them before walk expands them.
-               visitBottomUp(xtop, func(list []*Node, recursive bool) {
-                       // TODO: use a range statement here if the order does not matter
-                       for i := len(list) - 1; i >= 0; i-- {
-                               n := list[i]
-                               if n.Op == ODCLFUNC {
-                                       caninl(n)
-                                       inlcalls(n)
-                               }
-                       }
-               })
-       }
-
-       // Phase 6: Escape analysis.
-       // Required for moving heap allocations onto stack,
-       // which in turn is required by the closure implementation,
-       // which stores the addresses of stack variables into the closure.
-       // If the closure does not escape, it needs to be on the stack
-       // or else the stack copier will not update it.
-       // Large values are also moved off stack in escape analysis;
-       // because large values may contain pointers, it must happen early.
-       escapes(xtop)
-
-       // Phase 7: Transform closure bodies to properly reference captured variables.
-       // This needs to happen before walk, because closures must be transformed
-       // before walk reaches a call of a closure.
-       for _, n := range xtop {
-               if n.Op == ODCLFUNC && n.Func.Closure != nil {
-                       Curfn = n
-                       transformclosure(n)
-               }
-       }
-
-       Curfn = nil
-
-       // Phase 8: Compile top level functions.
-       // Don't use range--walk can add functions to xtop.
-       for i := 0; i < len(xtop); i++ {
-               if xtop[i].Op == ODCLFUNC {
-                       funccompile(xtop[i])
-               }
-       }
-
-       if nsavederrors+nerrors == 0 {
-               fninit(xtop)
-       }
-
-       if compiling_runtime != 0 {
-               checknowritebarrierrec()
-       }
-
-       // Phase 9: Check external declarations.
-       for i, n := range externdcl {
-               if n.Op == ONAME {
-                       typecheck(&externdcl[i], Erv)
-               }
-       }
-
-       if nerrors+nsavederrors != 0 {
-               errorexit()
-       }
-
-       dumpobj()
-
-       if asmhdr != "" {
-               dumpasmhdr()
-       }
-
-       if nerrors+nsavederrors != 0 {
-               errorexit()
-       }
-
-       Flusherrors()
-}
-
-var importMap = map[string]string{}
-
-func addImportMap(s string) {
-       if strings.Count(s, "=") != 1 {
-               log.Fatal("-importmap argument must be of the form source=actual")
-       }
-       i := strings.Index(s, "=")
-       source, actual := s[:i], s[i+1:]
-       if source == "" || actual == "" {
-               log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
-       }
-       importMap[source] = actual
-}
-
-func saveerrors() {
-       nsavederrors += nerrors
-       nerrors = 0
-}
-
-func arsize(b *bufio.Reader, name string) int {
-       var buf [ArhdrSize]byte
-       if _, err := io.ReadFull(b, buf[:]); err != nil {
-               return -1
-       }
-       aname := strings.Trim(string(buf[0:16]), " ")
-       if !strings.HasPrefix(aname, name) {
-               return -1
-       }
-       asize := strings.Trim(string(buf[48:58]), " ")
-       i, _ := strconv.Atoi(asize)
-       return i
-}
-
-func skiptopkgdef(b *bufio.Reader) bool {
-       // archive header
-       p, err := b.ReadString('\n')
-       if err != nil {
-               log.Fatalf("reading input: %v", err)
-       }
-       if p != "!<arch>\n" {
-               return false
-       }
-
-       // package export block should be first
-       sz := arsize(b, "__.PKGDEF")
-       return sz > 0
-}
-
-var idirs []string
-
-func addidir(dir string) {
-       if dir != "" {
-               idirs = append(idirs, dir)
-       }
-}
-
-func isDriveLetter(b byte) bool {
-       return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
-}
-
-// is this path a local name?  begins with ./ or ../ or /
-func islocalname(name string) bool {
-       return strings.HasPrefix(name, "/") ||
-               Ctxt.Windows != 0 && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
-               strings.HasPrefix(name, "./") || name == "." ||
-               strings.HasPrefix(name, "../") || name == ".."
-}
-
-func findpkg(name string) (file string, ok bool) {
-       if islocalname(name) {
-               if safemode != 0 || nolocalimports != 0 {
-                       return "", false
-               }
-
-               // try .a before .6.  important for building libraries:
-               // if there is an array.6 in the array.a library,
-               // want to find all of array.a, not just array.6.
-               file = fmt.Sprintf("%s.a", name)
-               if _, err := os.Stat(file); err == nil {
-                       return file, true
-               }
-               file = fmt.Sprintf("%s.o", name)
-               if _, err := os.Stat(file); err == nil {
-                       return file, true
-               }
-               return "", false
-       }
-
-       // local imports should be canonicalized already.
-       // don't want to see "encoding/../encoding/base64"
-       // as different from "encoding/base64".
-       if q := path.Clean(name); q != name {
-               Yyerror("non-canonical import path %q (should be %q)", name, q)
-               return "", false
-       }
-
-       for _, dir := range idirs {
-               file = fmt.Sprintf("%s/%s.a", dir, name)
-               if _, err := os.Stat(file); err == nil {
-                       return file, true
-               }
-               file = fmt.Sprintf("%s/%s.o", dir, name)
-               if _, err := os.Stat(file); err == nil {
-                       return file, true
-               }
-       }
-
-       if goroot != "" {
-               suffix := ""
-               suffixsep := ""
-               if flag_installsuffix != "" {
-                       suffixsep = "_"
-                       suffix = flag_installsuffix
-               } else if flag_race != 0 {
-                       suffixsep = "_"
-                       suffix = "race"
-               } else if flag_msan != 0 {
-                       suffixsep = "_"
-                       suffix = "msan"
-               }
-
-               file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", goroot, goos, goarch, suffixsep, suffix, name)
-               if _, err := os.Stat(file); err == nil {
-                       return file, true
-               }
-               file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", goroot, goos, goarch, suffixsep, suffix, name)
-               if _, err := os.Stat(file); err == nil {
-                       return file, true
-               }
-       }
-
-       return "", false
-}
-
-// loadsys loads the definitions for the low-level runtime and unsafe functions,
-// so that the compiler can generate calls to them,
-// but does not make the names "runtime" or "unsafe" visible as packages.
-func loadsys() {
-       if Debug['A'] != 0 {
-               return
-       }
-
-       block = 1
-       iota_ = -1000000
-       incannedimport = 1
-
-       importpkg = Runtimepkg
-       parse_import(bufio.NewReader(strings.NewReader(runtimeimport)), nil)
-
-       importpkg = unsafepkg
-       parse_import(bufio.NewReader(strings.NewReader(unsafeimport)), nil)
-
-       importpkg = nil
-       incannedimport = 0
-}
-
-func importfile(f *Val, indent []byte) {
-       if importpkg != nil {
-               Fatalf("importpkg not nil")
-       }
-
-       path_, ok := f.U.(string)
-       if !ok {
-               Yyerror("import statement not a string")
-               return
-       }
-
-       if len(path_) == 0 {
-               Yyerror("import path is empty")
-               return
-       }
-
-       if isbadimport(path_) {
-               return
-       }
-
-       // The package name main is no longer reserved,
-       // but we reserve the import path "main" to identify
-       // the main package, just as we reserve the import
-       // path "math" to identify the standard math package.
-       if path_ == "main" {
-               Yyerror("cannot import \"main\"")
-               errorexit()
-       }
-
-       if myimportpath != "" && path_ == myimportpath {
-               Yyerror("import %q while compiling that package (import cycle)", path_)
-               errorexit()
-       }
-
-       if mapped, ok := importMap[path_]; ok {
-               path_ = mapped
-       }
-
-       if path_ == "unsafe" {
-               if safemode != 0 {
-                       Yyerror("cannot import package unsafe")
-                       errorexit()
-               }
-
-               importpkg = unsafepkg
-               imported_unsafe = true
-               return
-       }
-
-       if islocalname(path_) {
-               if path_[0] == '/' {
-                       Yyerror("import path cannot be absolute path")
-                       return
-               }
-
-               prefix := Ctxt.Pathname
-               if localimport != "" {
-                       prefix = localimport
-               }
-               path_ = path.Join(prefix, path_)
-
-               if isbadimport(path_) {
-                       return
-               }
-       }
-
-       file, found := findpkg(path_)
-       if !found {
-               Yyerror("can't find import: %q", path_)
-               errorexit()
-       }
-
-       importpkg = mkpkg(path_)
-
-       if importpkg.Imported {
-               return
-       }
-
-       importpkg.Imported = true
-
-       impf, err := os.Open(file)
-       if err != nil {
-               Yyerror("can't open import: %q: %v", path_, err)
-               errorexit()
-       }
-       defer impf.Close()
-       imp := bufio.NewReader(impf)
-
-       if strings.HasSuffix(file, ".a") {
-               if !skiptopkgdef(imp) {
-                       Yyerror("import %s: not a package file", file)
-                       errorexit()
-               }
-       }
-
-       // check object header
-       p, err := imp.ReadString('\n')
-       if err != nil {
-               log.Fatalf("reading input: %v", err)
-       }
-       if len(p) > 0 {
-               p = p[:len(p)-1]
-       }
-
-       if p != "empty archive" {
-               if !strings.HasPrefix(p, "go object ") {
-                       Yyerror("import %s: not a go object file", file)
-                       errorexit()
-               }
-
-               q := fmt.Sprintf("%s %s %s %s", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
-               if p[10:] != q {
-                       Yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
-                       errorexit()
-               }
-       }
-
-       // assume files move (get installed)
-       // so don't record the full path.
-       linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
-
-       // In the importfile, if we find:
-       // $$\n  (old format): position the input right after $$\n and return
-       // $$B\n (new format): import directly, then feed the lexer a dummy statement
-
-       // look for $$
-       var c byte
-       for {
-               c, err = imp.ReadByte()
-               if err != nil {
-                       break
-               }
-               if c == '$' {
-                       c, err = imp.ReadByte()
-                       if c == '$' || err != nil {
-                               break
-                       }
-               }
-       }
-
-       // get character after $$
-       if err == nil {
-               c, _ = imp.ReadByte()
-       }
-
-       switch c {
-       case '\n':
-               // old export format
-               parse_import(imp, indent)
-
-       case 'B':
-               // new export format
-               imp.ReadByte() // skip \n after $$B
-               Import(imp)
-
-       default:
-               Yyerror("no import in %q", path_)
-               errorexit()
-       }
-
-       if safemode != 0 && !importpkg.Safe {
-               Yyerror("cannot import unsafe package %q", importpkg.Path)
-       }
-}
-
 func isSpace(c rune) bool {
        return c == ' ' || c == '\t' || c == '\n' || c == '\r'
 }
@@ -2037,349 +1212,3 @@ func (l *lexer) hexchar(n int) uint32 {
 
        return x
 }
-
-var basicTypes = [...]struct {
-       name  string
-       etype EType
-}{
-       {"int8", TINT8},
-       {"int16", TINT16},
-       {"int32", TINT32},
-       {"int64", TINT64},
-       {"uint8", TUINT8},
-       {"uint16", TUINT16},
-       {"uint32", TUINT32},
-       {"uint64", TUINT64},
-       {"float32", TFLOAT32},
-       {"float64", TFLOAT64},
-       {"complex64", TCOMPLEX64},
-       {"complex128", TCOMPLEX128},
-       {"bool", TBOOL},
-       {"string", TSTRING},
-       {"any", TANY},
-}
-
-var typedefs = [...]struct {
-       name     string
-       etype    EType
-       width    *int
-       sameas32 EType
-       sameas64 EType
-}{
-       {"int", TINT, &Widthint, TINT32, TINT64},
-       {"uint", TUINT, &Widthint, TUINT32, TUINT64},
-       {"uintptr", TUINTPTR, &Widthptr, TUINT32, TUINT64},
-}
-
-var builtinFuncs = [...]struct {
-       name string
-       op   Op
-}{
-       {"append", OAPPEND},
-       {"cap", OCAP},
-       {"close", OCLOSE},
-       {"complex", OCOMPLEX},
-       {"copy", OCOPY},
-       {"delete", ODELETE},
-       {"imag", OIMAG},
-       {"len", OLEN},
-       {"make", OMAKE},
-       {"new", ONEW},
-       {"panic", OPANIC},
-       {"print", OPRINT},
-       {"println", OPRINTN},
-       {"real", OREAL},
-       {"recover", ORECOVER},
-}
-
-// lexinit initializes known symbols and the basic types.
-func lexinit() {
-       for _, s := range basicTypes {
-               etype := s.etype
-               if int(etype) >= len(Types) {
-                       Fatalf("lexinit: %s bad etype", s.name)
-               }
-               s2 := Pkglookup(s.name, builtinpkg)
-               t := Types[etype]
-               if t == nil {
-                       t = typ(etype)
-                       t.Sym = s2
-                       if etype != TANY && etype != TSTRING {
-                               dowidth(t)
-                       }
-                       Types[etype] = t
-               }
-               s2.Def = typenod(t)
-               s2.Def.Name = new(Name)
-       }
-
-       for _, s := range builtinFuncs {
-               // TODO(marvin): Fix Node.EType type union.
-               s2 := Pkglookup(s.name, builtinpkg)
-               s2.Def = Nod(ONAME, nil, nil)
-               s2.Def.Sym = s2
-               s2.Def.Etype = EType(s.op)
-       }
-
-       idealstring = typ(TSTRING)
-       idealbool = typ(TBOOL)
-
-       s := Pkglookup("true", builtinpkg)
-       s.Def = Nodbool(true)
-       s.Def.Sym = Lookup("true")
-       s.Def.Name = new(Name)
-       s.Def.Type = idealbool
-
-       s = Pkglookup("false", builtinpkg)
-       s.Def = Nodbool(false)
-       s.Def.Sym = Lookup("false")
-       s.Def.Name = new(Name)
-       s.Def.Type = idealbool
-
-       s = Lookup("_")
-       s.Block = -100
-       s.Def = Nod(ONAME, nil, nil)
-       s.Def.Sym = s
-       Types[TBLANK] = typ(TBLANK)
-       s.Def.Type = Types[TBLANK]
-       nblank = s.Def
-
-       s = Pkglookup("_", builtinpkg)
-       s.Block = -100
-       s.Def = Nod(ONAME, nil, nil)
-       s.Def.Sym = s
-       Types[TBLANK] = typ(TBLANK)
-       s.Def.Type = Types[TBLANK]
-
-       Types[TNIL] = typ(TNIL)
-       s = Pkglookup("nil", builtinpkg)
-       var v Val
-       v.U = new(NilVal)
-       s.Def = nodlit(v)
-       s.Def.Sym = s
-       s.Def.Name = new(Name)
-
-       s = Pkglookup("iota", builtinpkg)
-       s.Def = Nod(OIOTA, nil, nil)
-       s.Def.Sym = s
-       s.Def.Name = new(Name)
-}
-
-func lexinit1() {
-       // t = interface { Error() string }
-       rcvr := typ(TSTRUCT)
-
-       rcvr.Type = typ(TFIELD)
-       rcvr.Type.Type = Ptrto(typ(TSTRUCT))
-       rcvr.Funarg = true
-       in := typ(TSTRUCT)
-       in.Funarg = true
-       out := typ(TSTRUCT)
-       out.Type = typ(TFIELD)
-       out.Type.Type = Types[TSTRING]
-       out.Funarg = true
-       f := typ(TFUNC)
-       *f.RecvsP() = rcvr
-       *f.ResultsP() = out
-       *f.ParamsP() = in
-       f.Thistuple = 1
-       f.Intuple = 0
-       f.Outnamed = false
-       f.Outtuple = 1
-       t := typ(TINTER)
-       t.Type = typ(TFIELD)
-       t.Type.Sym = Lookup("Error")
-       t.Type.Type = f
-
-       // error type
-       s := Pkglookup("error", builtinpkg)
-       errortype = t
-       errortype.Sym = s
-       s.Def = typenod(errortype)
-
-       // byte alias
-       s = Pkglookup("byte", builtinpkg)
-       bytetype = typ(TUINT8)
-       bytetype.Sym = s
-       s.Def = typenod(bytetype)
-       s.Def.Name = new(Name)
-
-       // rune alias
-       s = Pkglookup("rune", builtinpkg)
-       runetype = typ(TINT32)
-       runetype.Sym = s
-       s.Def = typenod(runetype)
-       s.Def.Name = new(Name)
-
-       // backend-dependent builtin types (e.g. int).
-       for _, s := range typedefs {
-               s1 := Pkglookup(s.name, builtinpkg)
-
-               sameas := s.sameas32
-               if *s.width == 8 {
-                       sameas = s.sameas64
-               }
-
-               Simtype[s.etype] = sameas
-               minfltval[s.etype] = minfltval[sameas]
-               maxfltval[s.etype] = maxfltval[sameas]
-               Minintval[s.etype] = Minintval[sameas]
-               Maxintval[s.etype] = Maxintval[sameas]
-
-               t := typ(s.etype)
-               t.Sym = s1
-               Types[s.etype] = t
-               s1.Def = typenod(t)
-               s1.Def.Name = new(Name)
-               s1.Origpkg = builtinpkg
-
-               dowidth(t)
-       }
-}
-
-func lexfini() {
-       for _, s := range builtinpkg.Syms {
-               if s.Def == nil || (s.Name == "any" && Debug['A'] == 0) {
-                       continue
-               }
-               s1 := Lookup(s.Name)
-               if s1.Def != nil {
-                       continue
-               }
-
-               s1.Def = s.Def
-               s1.Block = s.Block
-       }
-
-       nodfp = Nod(ONAME, nil, nil)
-       nodfp.Type = Types[TINT32]
-       nodfp.Xoffset = 0
-       nodfp.Class = PPARAM
-       nodfp.Sym = Lookup(".fp")
-}
-
-var lexn = map[rune]string{
-       LNAME:    "NAME",
-       LLITERAL: "LITERAL",
-
-       LOPER:  "OPER",
-       LASOP:  "ASOP",
-       LINCOP: "INCOP",
-
-       LCOLAS: "COLAS",
-       LCOMM:  "COMM",
-       LDDD:   "DDD",
-
-       LBREAK:     "BREAK",
-       LCASE:      "CASE",
-       LCHAN:      "CHAN",
-       LCONST:     "CONST",
-       LCONTINUE:  "CONTINUE",
-       LDEFAULT:   "DEFAULT",
-       LDEFER:     "DEFER",
-       LELSE:      "ELSE",
-       LFALL:      "FALL",
-       LFOR:       "FOR",
-       LFUNC:      "FUNC",
-       LGO:        "GO",
-       LGOTO:      "GOTO",
-       LIF:        "IF",
-       LIMPORT:    "IMPORT",
-       LINTERFACE: "INTERFACE",
-       LMAP:       "MAP",
-       LPACKAGE:   "PACKAGE",
-       LRANGE:     "RANGE",
-       LRETURN:    "RETURN",
-       LSELECT:    "SELECT",
-       LSTRUCT:    "STRUCT",
-       LSWITCH:    "SWITCH",
-       LTYPE:      "TYPE",
-       LVAR:       "VAR",
-}
-
-func lexname(lex rune) string {
-       if s, ok := lexn[lex]; ok {
-               return s
-       }
-       return fmt.Sprintf("LEX-%d", lex)
-}
-
-func pkgnotused(lineno int32, path string, name string) {
-       // If the package was imported with a name other than the final
-       // import path element, show it explicitly in the error message.
-       // Note that this handles both renamed imports and imports of
-       // packages containing unconventional package declarations.
-       // Note that this uses / always, even on Windows, because Go import
-       // paths always use forward slashes.
-       elem := path
-       if i := strings.LastIndex(elem, "/"); i >= 0 {
-               elem = elem[i+1:]
-       }
-       if name == "" || elem == name {
-               yyerrorl(lineno, "imported and not used: %q", path)
-       } else {
-               yyerrorl(lineno, "imported and not used: %q as %s", path, name)
-       }
-}
-
-func mkpackage(pkgname string) {
-       if localpkg.Name == "" {
-               if pkgname == "_" {
-                       Yyerror("invalid package name _")
-               }
-               localpkg.Name = pkgname
-       } else {
-               if pkgname != localpkg.Name {
-                       Yyerror("package %s; expected %s", pkgname, localpkg.Name)
-               }
-               for _, s := range localpkg.Syms {
-                       if s.Def == nil {
-                               continue
-                       }
-                       if s.Def.Op == OPACK {
-                               // throw away top-level package name leftover
-                               // from previous file.
-                               // leave s->block set to cause redeclaration
-                               // errors if a conflicting top-level name is
-                               // introduced by a different file.
-                               if !s.Def.Used && nsyntaxerrors == 0 {
-                                       pkgnotused(s.Def.Lineno, s.Def.Name.Pkg.Path, s.Name)
-                               }
-                               s.Def = nil
-                               continue
-                       }
-
-                       if s.Def.Sym != s {
-                               // throw away top-level name left over
-                               // from previous import . "x"
-                               if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
-                                       pkgnotused(s.Def.Name.Pack.Lineno, s.Def.Name.Pack.Name.Pkg.Path, "")
-                                       s.Def.Name.Pack.Used = true
-                               }
-
-                               s.Def = nil
-                               continue
-                       }
-               }
-       }
-
-       if outfile == "" {
-               p := infile
-               if i := strings.LastIndex(p, "/"); i >= 0 {
-                       p = p[i+1:]
-               }
-               if Ctxt.Windows != 0 {
-                       if i := strings.LastIndex(p, `\`); i >= 0 {
-                               p = p[i+1:]
-                       }
-               }
-               if i := strings.LastIndex(p, "."); i >= 0 {
-                       p = p[:i]
-               }
-               suffix := ".o"
-               if writearchive > 0 {
-                       suffix = ".a"
-               }
-               outfile = p + suffix
-       }
-}
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
new file mode 100644 (file)
index 0000000..fb6a940
--- /dev/null
@@ -0,0 +1,1184 @@
+// Copyright 2009 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.
+
+//go:generate go run mkbuiltin.go
+
+package gc
+
+import (
+       "bufio"
+       "cmd/compile/internal/ssa"
+       "cmd/internal/obj"
+       "flag"
+       "fmt"
+       "io"
+       "log"
+       "os"
+       "path"
+       "strconv"
+       "strings"
+)
+
+var imported_unsafe bool
+
+var (
+       goos    string
+       goarch  string
+       goroot  string
+       buildid string
+)
+
+var (
+       Debug_append int
+       Debug_panic  int
+       Debug_slice  int
+       Debug_wb     int
+)
+
+// Debug arguments.
+// These can be specified with the -d flag, as in "-d nil"
+// to set the debug_checknil variable. In general the list passed
+// to -d can be comma-separated.
+var debugtab = []struct {
+       name string
+       val  *int
+}{
+       {"append", &Debug_append},         // print information about append compilation
+       {"disablenil", &Disable_checknil}, // disable nil checks
+       {"gcprog", &Debug_gcprog},         // print dump of GC programs
+       {"nil", &Debug_checknil},          // print information about nil checks
+       {"panic", &Debug_panic},           // do not hide any compiler panic
+       {"slice", &Debug_slice},           // print information about slice compilation
+       {"typeassert", &Debug_typeassert}, // print information about type assertion inlining
+       {"wb", &Debug_wb},                 // print information about write barriers
+       {"export", &Debug_export},         // print export data
+}
+
+func usage() {
+       fmt.Printf("usage: compile [options] file.go...\n")
+       obj.Flagprint(1)
+       Exit(2)
+}
+
+func hidePanic() {
+       if Debug_panic == 0 && nsavederrors+nerrors > 0 {
+               // If we've already complained about things
+               // in the program, don't bother complaining
+               // about a panic too; let the user clean up
+               // the code and try again.
+               if err := recover(); err != nil {
+                       errorexit()
+               }
+       }
+}
+
+func doversion() {
+       p := obj.Expstring()
+       if p == "X:none" {
+               p = ""
+       }
+       sep := ""
+       if p != "" {
+               sep = " "
+       }
+       fmt.Printf("compile version %s%s%s\n", obj.Getgoversion(), sep, p)
+       os.Exit(0)
+}
+
+func Main() {
+       defer hidePanic()
+
+       // Allow GOARCH=thearch.thestring or GOARCH=thearch.thestringsuffix,
+       // but not other values.
+       p := obj.Getgoarch()
+
+       if !strings.HasPrefix(p, Thearch.Thestring) {
+               log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.Thechar, p)
+       }
+       goarch = p
+
+       Thearch.Linkarchinit()
+       Ctxt = obj.Linknew(Thearch.Thelinkarch)
+       Ctxt.DiagFunc = Yyerror
+       Ctxt.Bso = &bstdout
+       bstdout = *obj.Binitw(os.Stdout)
+
+       localpkg = mkpkg("")
+       localpkg.Prefix = "\"\""
+
+       // pseudo-package, for scoping
+       builtinpkg = mkpkg("go.builtin")
+
+       builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
+
+       // pseudo-package, accessed by import "unsafe"
+       unsafepkg = mkpkg("unsafe")
+
+       unsafepkg.Name = "unsafe"
+
+       // real package, referred to by generated runtime calls
+       Runtimepkg = mkpkg("runtime")
+
+       Runtimepkg.Name = "runtime"
+
+       // pseudo-packages used in symbol tables
+       gostringpkg = mkpkg("go.string")
+
+       gostringpkg.Name = "go.string"
+       gostringpkg.Prefix = "go.string" // not go%2estring
+
+       itabpkg = mkpkg("go.itab")
+
+       itabpkg.Name = "go.itab"
+       itabpkg.Prefix = "go.itab" // not go%2eitab
+
+       typelinkpkg = mkpkg("go.typelink")
+       typelinkpkg.Name = "go.typelink"
+       typelinkpkg.Prefix = "go.typelink" // not go%2etypelink
+
+       trackpkg = mkpkg("go.track")
+
+       trackpkg.Name = "go.track"
+       trackpkg.Prefix = "go.track" // not go%2etrack
+
+       typepkg = mkpkg("type")
+
+       typepkg.Name = "type"
+
+       goroot = obj.Getgoroot()
+       goos = obj.Getgoos()
+
+       Nacl = goos == "nacl"
+       if Nacl {
+               flag_largemodel = 1
+       }
+
+       outfile = ""
+       obj.Flagcount("+", "compiling runtime", &compiling_runtime)
+       obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
+       obj.Flagcount("A", "for bootstrapping, allow 'any' type", &Debug['A'])
+       obj.Flagcount("B", "disable bounds checking", &Debug['B'])
+       obj.Flagstr("D", "set relative `path` for local imports", &localimport)
+       obj.Flagcount("E", "debug symbol export", &Debug['E'])
+       obj.Flagfn1("I", "add `directory` to import search path", addidir)
+       obj.Flagcount("K", "debug missing line numbers", &Debug['K'])
+       obj.Flagcount("L", "use full (long) path in error messages", &Debug['L'])
+       obj.Flagcount("M", "debug move generation", &Debug['M'])
+       obj.Flagcount("N", "disable optimizations", &Debug['N'])
+       obj.Flagcount("P", "debug peephole optimizer", &Debug['P'])
+       obj.Flagcount("R", "debug register optimizer", &Debug['R'])
+       obj.Flagcount("S", "print assembly listing", &Debug['S'])
+       obj.Flagfn0("V", "print compiler version", doversion)
+       obj.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
+       obj.Flagstr("asmhdr", "write assembly header to `file`", &asmhdr)
+       obj.Flagstr("buildid", "record `id` as the build id in the export metadata", &buildid)
+       obj.Flagcount("complete", "compiling complete package (no C or assembly)", &pure_go)
+       obj.Flagstr("d", "print debug information about items in `list`", &debugstr)
+       obj.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
+       obj.Flagcount("f", "debug stack frames", &Debug['f'])
+       obj.Flagcount("g", "debug code generation", &Debug['g'])
+       obj.Flagcount("h", "halt on error", &Debug['h'])
+       obj.Flagcount("i", "debug line number stack", &Debug['i'])
+       obj.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
+       obj.Flagstr("installsuffix", "set pkg directory `suffix`", &flag_installsuffix)
+       obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
+       obj.Flagcount("l", "disable inlining", &Debug['l'])
+       obj.Flagcount("live", "debug liveness analysis", &debuglive)
+       obj.Flagcount("m", "print optimization decisions", &Debug['m'])
+       obj.Flagcount("msan", "build code compatible with C/C++ memory sanitizer", &flag_msan)
+       obj.Flagcount("newexport", "use new export format", &newexport) // TODO(gri) remove eventually (issue 13241)
+       obj.Flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports)
+       obj.Flagstr("o", "write output to `file`", &outfile)
+       obj.Flagstr("p", "set expected package import `path`", &myimportpath)
+       obj.Flagcount("pack", "write package file instead of object file", &writearchive)
+       obj.Flagcount("r", "debug generated wrappers", &Debug['r'])
+       obj.Flagcount("race", "enable race detector", &flag_race)
+       obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
+       obj.Flagstr("trimpath", "remove `prefix` from recorded source file paths", &Ctxt.LineHist.TrimPathPrefix)
+       obj.Flagcount("u", "reject unsafe code", &safemode)
+       obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
+       obj.Flagcount("w", "debug type checking", &Debug['w'])
+       use_writebarrier = 1
+       obj.Flagcount("wb", "enable write barrier", &use_writebarrier)
+       obj.Flagcount("x", "debug lexer", &Debug['x'])
+       obj.Flagcount("y", "debug declarations in canned imports (with -d)", &Debug['y'])
+       var flag_shared int
+       var flag_dynlink bool
+       switch Thearch.Thechar {
+       case '5', '6', '7', '8', '9':
+               obj.Flagcount("shared", "generate code that can be linked into a shared library", &flag_shared)
+       }
+       if Thearch.Thechar == '6' {
+               obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel)
+       }
+       switch Thearch.Thechar {
+       case '5', '6', '7', '8', '9':
+               flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
+       }
+       obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile)
+       obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile)
+       obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate)
+       flag.BoolVar(&ssaEnabled, "ssa", true, "use SSA backend to generate code")
+       obj.Flagparse(usage)
+
+       if flag_dynlink {
+               flag_shared = 1
+       }
+       Ctxt.Flag_shared = int32(flag_shared)
+       Ctxt.Flag_dynlink = flag_dynlink
+       Ctxt.Flag_optimize = Debug['N'] == 0
+
+       Ctxt.Debugasm = int32(Debug['S'])
+       Ctxt.Debugvlog = int32(Debug['v'])
+
+       if flag.NArg() < 1 {
+               usage()
+       }
+
+       startProfile()
+
+       if flag_race != 0 {
+               racepkg = mkpkg("runtime/race")
+               racepkg.Name = "race"
+       }
+       if flag_msan != 0 {
+               msanpkg = mkpkg("runtime/msan")
+               msanpkg.Name = "msan"
+       }
+       if flag_race != 0 && flag_msan != 0 {
+               log.Fatal("cannot use both -race and -msan")
+       } else if flag_race != 0 || flag_msan != 0 {
+               instrumenting = true
+       }
+
+       // parse -d argument
+       if debugstr != "" {
+       Split:
+               for _, name := range strings.Split(debugstr, ",") {
+                       if name == "" {
+                               continue
+                       }
+                       val := 1
+                       if i := strings.Index(name, "="); i >= 0 {
+                               var err error
+                               val, err = strconv.Atoi(name[i+1:])
+                               if err != nil {
+                                       log.Fatalf("invalid debug value %v", name)
+                               }
+                               name = name[:i]
+                       }
+                       for _, t := range debugtab {
+                               if t.name == name {
+                                       if t.val != nil {
+                                               *t.val = val
+                                               continue Split
+                                       }
+                               }
+                       }
+                       // special case for ssa for now
+                       if strings.HasPrefix(name, "ssa/") {
+                               // expect form ssa/phase/flag
+                               // e.g. -d=ssa/generic_cse/time
+                               // _ in phase name also matches space
+                               phase := name[4:]
+                               flag := "debug" // default flag is debug
+                               if i := strings.Index(phase, "/"); i >= 0 {
+                                       flag = phase[i+1:]
+                                       phase = phase[:i]
+                               }
+                               err := ssa.PhaseOption(phase, flag, val)
+                               if err != "" {
+                                       log.Fatalf(err)
+                               }
+                               continue Split
+                       }
+                       log.Fatalf("unknown debug key -d %s\n", name)
+               }
+       }
+
+       // enable inlining.  for now:
+       //      default: inlining on.  (debug['l'] == 1)
+       //      -l: inlining off  (debug['l'] == 0)
+       //      -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
+       if Debug['l'] <= 1 {
+               Debug['l'] = 1 - Debug['l']
+       }
+
+       Thearch.Betypeinit()
+       if Widthptr == 0 {
+               Fatalf("betypeinit failed")
+       }
+
+       lexinit()
+       typeinit()
+       lexinit1()
+
+       blockgen = 1
+       dclcontext = PEXTERN
+       nerrors = 0
+       lexlineno = 1
+
+       loadsys()
+
+       for _, infile = range flag.Args() {
+               if trace && Debug['x'] != 0 {
+                       fmt.Printf("--- %s ---\n", infile)
+               }
+
+               linehistpush(infile)
+
+               f, err := os.Open(infile)
+               if err != nil {
+                       fmt.Printf("open %s: %v\n", infile, err)
+                       errorexit()
+               }
+               bin := bufio.NewReader(f)
+
+               // Skip initial BOM if present.
+               if r, _, _ := bin.ReadRune(); r != BOM {
+                       bin.UnreadRune()
+               }
+
+               block = 1
+               iota_ = -1000000
+
+               imported_unsafe = false
+
+               parse_file(bin)
+               if nsyntaxerrors != 0 {
+                       errorexit()
+               }
+
+               // Instead of converting EOF into '\n' in getc and count it as an extra line
+               // for the line history to work, and which then has to be corrected elsewhere,
+               // just add a line here.
+               lexlineno++
+
+               linehistpop()
+               f.Close()
+       }
+
+       testdclstack()
+       mkpackage(localpkg.Name) // final import not used checks
+       lexfini()
+
+       typecheckok = true
+       if Debug['f'] != 0 {
+               frame(1)
+       }
+
+       // Process top-level declarations in phases.
+
+       // Phase 1: const, type, and names and types of funcs.
+       //   This will gather all the information about types
+       //   and methods but doesn't depend on any of it.
+       defercheckwidth()
+
+       // Don't use range--typecheck can add closures to xtop.
+       for i := 0; i < len(xtop); i++ {
+               if xtop[i].Op != ODCL && xtop[i].Op != OAS && xtop[i].Op != OAS2 {
+                       typecheck(&xtop[i], Etop)
+               }
+       }
+
+       // Phase 2: Variable assignments.
+       //   To check interface assignments, depends on phase 1.
+
+       // Don't use range--typecheck can add closures to xtop.
+       for i := 0; i < len(xtop); i++ {
+               if xtop[i].Op == ODCL || xtop[i].Op == OAS || xtop[i].Op == OAS2 {
+                       typecheck(&xtop[i], Etop)
+               }
+       }
+       resumecheckwidth()
+
+       // Phase 3: Type check function bodies.
+       // Don't use range--typecheck can add closures to xtop.
+       for i := 0; i < len(xtop); i++ {
+               if xtop[i].Op == ODCLFUNC || xtop[i].Op == OCLOSURE {
+                       Curfn = xtop[i]
+                       decldepth = 1
+                       saveerrors()
+                       typechecklist(Curfn.Nbody.Slice(), Etop)
+                       checkreturn(Curfn)
+                       if nerrors != 0 {
+                               Curfn.Nbody.Set(nil) // type errors; do not compile
+                       }
+               }
+       }
+
+       // Phase 4: Decide how to capture closed variables.
+       // This needs to run before escape analysis,
+       // because variables captured by value do not escape.
+       for _, n := range xtop {
+               if n.Op == ODCLFUNC && n.Func.Closure != nil {
+                       Curfn = n
+                       capturevars(n)
+               }
+       }
+
+       Curfn = nil
+
+       if nsavederrors+nerrors != 0 {
+               errorexit()
+       }
+
+       // Phase 5: Inlining
+       if Debug['l'] > 1 {
+               // Typecheck imported function bodies if debug['l'] > 1,
+               // otherwise lazily when used or re-exported.
+               for _, n := range importlist {
+                       if len(n.Func.Inl.Slice()) != 0 {
+                               saveerrors()
+                               typecheckinl(n)
+                       }
+               }
+
+               if nsavederrors+nerrors != 0 {
+                       errorexit()
+               }
+       }
+
+       if Debug['l'] != 0 {
+               // Find functions that can be inlined and clone them before walk expands them.
+               visitBottomUp(xtop, func(list []*Node, recursive bool) {
+                       // TODO: use a range statement here if the order does not matter
+                       for i := len(list) - 1; i >= 0; i-- {
+                               n := list[i]
+                               if n.Op == ODCLFUNC {
+                                       caninl(n)
+                                       inlcalls(n)
+                               }
+                       }
+               })
+       }
+
+       // Phase 6: Escape analysis.
+       // Required for moving heap allocations onto stack,
+       // which in turn is required by the closure implementation,
+       // which stores the addresses of stack variables into the closure.
+       // If the closure does not escape, it needs to be on the stack
+       // or else the stack copier will not update it.
+       // Large values are also moved off stack in escape analysis;
+       // because large values may contain pointers, it must happen early.
+       escapes(xtop)
+
+       // Phase 7: Transform closure bodies to properly reference captured variables.
+       // This needs to happen before walk, because closures must be transformed
+       // before walk reaches a call of a closure.
+       for _, n := range xtop {
+               if n.Op == ODCLFUNC && n.Func.Closure != nil {
+                       Curfn = n
+                       transformclosure(n)
+               }
+       }
+
+       Curfn = nil
+
+       // Phase 8: Compile top level functions.
+       // Don't use range--walk can add functions to xtop.
+       for i := 0; i < len(xtop); i++ {
+               if xtop[i].Op == ODCLFUNC {
+                       funccompile(xtop[i])
+               }
+       }
+
+       if nsavederrors+nerrors == 0 {
+               fninit(xtop)
+       }
+
+       if compiling_runtime != 0 {
+               checknowritebarrierrec()
+       }
+
+       // Phase 9: Check external declarations.
+       for i, n := range externdcl {
+               if n.Op == ONAME {
+                       typecheck(&externdcl[i], Erv)
+               }
+       }
+
+       if nerrors+nsavederrors != 0 {
+               errorexit()
+       }
+
+       dumpobj()
+
+       if asmhdr != "" {
+               dumpasmhdr()
+       }
+
+       if nerrors+nsavederrors != 0 {
+               errorexit()
+       }
+
+       Flusherrors()
+}
+
+var importMap = map[string]string{}
+
+func addImportMap(s string) {
+       if strings.Count(s, "=") != 1 {
+               log.Fatal("-importmap argument must be of the form source=actual")
+       }
+       i := strings.Index(s, "=")
+       source, actual := s[:i], s[i+1:]
+       if source == "" || actual == "" {
+               log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
+       }
+       importMap[source] = actual
+}
+
+func saveerrors() {
+       nsavederrors += nerrors
+       nerrors = 0
+}
+
+func arsize(b *bufio.Reader, name string) int {
+       var buf [ArhdrSize]byte
+       if _, err := io.ReadFull(b, buf[:]); err != nil {
+               return -1
+       }
+       aname := strings.Trim(string(buf[0:16]), " ")
+       if !strings.HasPrefix(aname, name) {
+               return -1
+       }
+       asize := strings.Trim(string(buf[48:58]), " ")
+       i, _ := strconv.Atoi(asize)
+       return i
+}
+
+func skiptopkgdef(b *bufio.Reader) bool {
+       // archive header
+       p, err := b.ReadString('\n')
+       if err != nil {
+               log.Fatalf("reading input: %v", err)
+       }
+       if p != "!<arch>\n" {
+               return false
+       }
+
+       // package export block should be first
+       sz := arsize(b, "__.PKGDEF")
+       return sz > 0
+}
+
+var idirs []string
+
+func addidir(dir string) {
+       if dir != "" {
+               idirs = append(idirs, dir)
+       }
+}
+
+func isDriveLetter(b byte) bool {
+       return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
+}
+
+// is this path a local name?  begins with ./ or ../ or /
+func islocalname(name string) bool {
+       return strings.HasPrefix(name, "/") ||
+               Ctxt.Windows != 0 && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
+               strings.HasPrefix(name, "./") || name == "." ||
+               strings.HasPrefix(name, "../") || name == ".."
+}
+
+func findpkg(name string) (file string, ok bool) {
+       if islocalname(name) {
+               if safemode != 0 || nolocalimports != 0 {
+                       return "", false
+               }
+
+               // try .a before .6.  important for building libraries:
+               // if there is an array.6 in the array.a library,
+               // want to find all of array.a, not just array.6.
+               file = fmt.Sprintf("%s.a", name)
+               if _, err := os.Stat(file); err == nil {
+                       return file, true
+               }
+               file = fmt.Sprintf("%s.o", name)
+               if _, err := os.Stat(file); err == nil {
+                       return file, true
+               }
+               return "", false
+       }
+
+       // local imports should be canonicalized already.
+       // don't want to see "encoding/../encoding/base64"
+       // as different from "encoding/base64".
+       if q := path.Clean(name); q != name {
+               Yyerror("non-canonical import path %q (should be %q)", name, q)
+               return "", false
+       }
+
+       for _, dir := range idirs {
+               file = fmt.Sprintf("%s/%s.a", dir, name)
+               if _, err := os.Stat(file); err == nil {
+                       return file, true
+               }
+               file = fmt.Sprintf("%s/%s.o", dir, name)
+               if _, err := os.Stat(file); err == nil {
+                       return file, true
+               }
+       }
+
+       if goroot != "" {
+               suffix := ""
+               suffixsep := ""
+               if flag_installsuffix != "" {
+                       suffixsep = "_"
+                       suffix = flag_installsuffix
+               } else if flag_race != 0 {
+                       suffixsep = "_"
+                       suffix = "race"
+               } else if flag_msan != 0 {
+                       suffixsep = "_"
+                       suffix = "msan"
+               }
+
+               file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", goroot, goos, goarch, suffixsep, suffix, name)
+               if _, err := os.Stat(file); err == nil {
+                       return file, true
+               }
+               file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", goroot, goos, goarch, suffixsep, suffix, name)
+               if _, err := os.Stat(file); err == nil {
+                       return file, true
+               }
+       }
+
+       return "", false
+}
+
+// loadsys loads the definitions for the low-level runtime and unsafe functions,
+// so that the compiler can generate calls to them,
+// but does not make the names "runtime" or "unsafe" visible as packages.
+func loadsys() {
+       if Debug['A'] != 0 {
+               return
+       }
+
+       block = 1
+       iota_ = -1000000
+       incannedimport = 1
+
+       importpkg = Runtimepkg
+       parse_import(bufio.NewReader(strings.NewReader(runtimeimport)), nil)
+
+       importpkg = unsafepkg
+       parse_import(bufio.NewReader(strings.NewReader(unsafeimport)), nil)
+
+       importpkg = nil
+       incannedimport = 0
+}
+
+func importfile(f *Val, indent []byte) {
+       if importpkg != nil {
+               Fatalf("importpkg not nil")
+       }
+
+       path_, ok := f.U.(string)
+       if !ok {
+               Yyerror("import statement not a string")
+               return
+       }
+
+       if len(path_) == 0 {
+               Yyerror("import path is empty")
+               return
+       }
+
+       if isbadimport(path_) {
+               return
+       }
+
+       // The package name main is no longer reserved,
+       // but we reserve the import path "main" to identify
+       // the main package, just as we reserve the import
+       // path "math" to identify the standard math package.
+       if path_ == "main" {
+               Yyerror("cannot import \"main\"")
+               errorexit()
+       }
+
+       if myimportpath != "" && path_ == myimportpath {
+               Yyerror("import %q while compiling that package (import cycle)", path_)
+               errorexit()
+       }
+
+       if mapped, ok := importMap[path_]; ok {
+               path_ = mapped
+       }
+
+       if path_ == "unsafe" {
+               if safemode != 0 {
+                       Yyerror("cannot import package unsafe")
+                       errorexit()
+               }
+
+               importpkg = unsafepkg
+               imported_unsafe = true
+               return
+       }
+
+       if islocalname(path_) {
+               if path_[0] == '/' {
+                       Yyerror("import path cannot be absolute path")
+                       return
+               }
+
+               prefix := Ctxt.Pathname
+               if localimport != "" {
+                       prefix = localimport
+               }
+               path_ = path.Join(prefix, path_)
+
+               if isbadimport(path_) {
+                       return
+               }
+       }
+
+       file, found := findpkg(path_)
+       if !found {
+               Yyerror("can't find import: %q", path_)
+               errorexit()
+       }
+
+       importpkg = mkpkg(path_)
+
+       if importpkg.Imported {
+               return
+       }
+
+       importpkg.Imported = true
+
+       impf, err := os.Open(file)
+       if err != nil {
+               Yyerror("can't open import: %q: %v", path_, err)
+               errorexit()
+       }
+       defer impf.Close()
+       imp := bufio.NewReader(impf)
+
+       if strings.HasSuffix(file, ".a") {
+               if !skiptopkgdef(imp) {
+                       Yyerror("import %s: not a package file", file)
+                       errorexit()
+               }
+       }
+
+       // check object header
+       p, err := imp.ReadString('\n')
+       if err != nil {
+               log.Fatalf("reading input: %v", err)
+       }
+       if len(p) > 0 {
+               p = p[:len(p)-1]
+       }
+
+       if p != "empty archive" {
+               if !strings.HasPrefix(p, "go object ") {
+                       Yyerror("import %s: not a go object file", file)
+                       errorexit()
+               }
+
+               q := fmt.Sprintf("%s %s %s %s", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
+               if p[10:] != q {
+                       Yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
+                       errorexit()
+               }
+       }
+
+       // assume files move (get installed)
+       // so don't record the full path.
+       linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
+
+       // In the importfile, if we find:
+       // $$\n  (old format): position the input right after $$\n and return
+       // $$B\n (new format): import directly, then feed the lexer a dummy statement
+
+       // look for $$
+       var c byte
+       for {
+               c, err = imp.ReadByte()
+               if err != nil {
+                       break
+               }
+               if c == '$' {
+                       c, err = imp.ReadByte()
+                       if c == '$' || err != nil {
+                               break
+                       }
+               }
+       }
+
+       // get character after $$
+       if err == nil {
+               c, _ = imp.ReadByte()
+       }
+
+       switch c {
+       case '\n':
+               // old export format
+               parse_import(imp, indent)
+
+       case 'B':
+               // new export format
+               imp.ReadByte() // skip \n after $$B
+               Import(imp)
+
+       default:
+               Yyerror("no import in %q", path_)
+               errorexit()
+       }
+
+       if safemode != 0 && !importpkg.Safe {
+               Yyerror("cannot import unsafe package %q", importpkg.Path)
+       }
+}
+
+var basicTypes = [...]struct {
+       name  string
+       etype EType
+}{
+       {"int8", TINT8},
+       {"int16", TINT16},
+       {"int32", TINT32},
+       {"int64", TINT64},
+       {"uint8", TUINT8},
+       {"uint16", TUINT16},
+       {"uint32", TUINT32},
+       {"uint64", TUINT64},
+       {"float32", TFLOAT32},
+       {"float64", TFLOAT64},
+       {"complex64", TCOMPLEX64},
+       {"complex128", TCOMPLEX128},
+       {"bool", TBOOL},
+       {"string", TSTRING},
+       {"any", TANY},
+}
+
+var typedefs = [...]struct {
+       name     string
+       etype    EType
+       width    *int
+       sameas32 EType
+       sameas64 EType
+}{
+       {"int", TINT, &Widthint, TINT32, TINT64},
+       {"uint", TUINT, &Widthint, TUINT32, TUINT64},
+       {"uintptr", TUINTPTR, &Widthptr, TUINT32, TUINT64},
+}
+
+var builtinFuncs = [...]struct {
+       name string
+       op   Op
+}{
+       {"append", OAPPEND},
+       {"cap", OCAP},
+       {"close", OCLOSE},
+       {"complex", OCOMPLEX},
+       {"copy", OCOPY},
+       {"delete", ODELETE},
+       {"imag", OIMAG},
+       {"len", OLEN},
+       {"make", OMAKE},
+       {"new", ONEW},
+       {"panic", OPANIC},
+       {"print", OPRINT},
+       {"println", OPRINTN},
+       {"real", OREAL},
+       {"recover", ORECOVER},
+}
+
+// lexinit initializes known symbols and the basic types.
+func lexinit() {
+       for _, s := range basicTypes {
+               etype := s.etype
+               if int(etype) >= len(Types) {
+                       Fatalf("lexinit: %s bad etype", s.name)
+               }
+               s2 := Pkglookup(s.name, builtinpkg)
+               t := Types[etype]
+               if t == nil {
+                       t = typ(etype)
+                       t.Sym = s2
+                       if etype != TANY && etype != TSTRING {
+                               dowidth(t)
+                       }
+                       Types[etype] = t
+               }
+               s2.Def = typenod(t)
+               s2.Def.Name = new(Name)
+       }
+
+       for _, s := range builtinFuncs {
+               // TODO(marvin): Fix Node.EType type union.
+               s2 := Pkglookup(s.name, builtinpkg)
+               s2.Def = Nod(ONAME, nil, nil)
+               s2.Def.Sym = s2
+               s2.Def.Etype = EType(s.op)
+       }
+
+       idealstring = typ(TSTRING)
+       idealbool = typ(TBOOL)
+
+       s := Pkglookup("true", builtinpkg)
+       s.Def = Nodbool(true)
+       s.Def.Sym = Lookup("true")
+       s.Def.Name = new(Name)
+       s.Def.Type = idealbool
+
+       s = Pkglookup("false", builtinpkg)
+       s.Def = Nodbool(false)
+       s.Def.Sym = Lookup("false")
+       s.Def.Name = new(Name)
+       s.Def.Type = idealbool
+
+       s = Lookup("_")
+       s.Block = -100
+       s.Def = Nod(ONAME, nil, nil)
+       s.Def.Sym = s
+       Types[TBLANK] = typ(TBLANK)
+       s.Def.Type = Types[TBLANK]
+       nblank = s.Def
+
+       s = Pkglookup("_", builtinpkg)
+       s.Block = -100
+       s.Def = Nod(ONAME, nil, nil)
+       s.Def.Sym = s
+       Types[TBLANK] = typ(TBLANK)
+       s.Def.Type = Types[TBLANK]
+
+       Types[TNIL] = typ(TNIL)
+       s = Pkglookup("nil", builtinpkg)
+       var v Val
+       v.U = new(NilVal)
+       s.Def = nodlit(v)
+       s.Def.Sym = s
+       s.Def.Name = new(Name)
+
+       s = Pkglookup("iota", builtinpkg)
+       s.Def = Nod(OIOTA, nil, nil)
+       s.Def.Sym = s
+       s.Def.Name = new(Name)
+}
+
+func lexinit1() {
+       // t = interface { Error() string }
+       rcvr := typ(TSTRUCT)
+
+       rcvr.Type = typ(TFIELD)
+       rcvr.Type.Type = Ptrto(typ(TSTRUCT))
+       rcvr.Funarg = true
+       in := typ(TSTRUCT)
+       in.Funarg = true
+       out := typ(TSTRUCT)
+       out.Type = typ(TFIELD)
+       out.Type.Type = Types[TSTRING]
+       out.Funarg = true
+       f := typ(TFUNC)
+       *f.RecvsP() = rcvr
+       *f.ResultsP() = out
+       *f.ParamsP() = in
+       f.Thistuple = 1
+       f.Intuple = 0
+       f.Outnamed = false
+       f.Outtuple = 1
+       t := typ(TINTER)
+       t.Type = typ(TFIELD)
+       t.Type.Sym = Lookup("Error")
+       t.Type.Type = f
+
+       // error type
+       s := Pkglookup("error", builtinpkg)
+       errortype = t
+       errortype.Sym = s
+       s.Def = typenod(errortype)
+
+       // byte alias
+       s = Pkglookup("byte", builtinpkg)
+       bytetype = typ(TUINT8)
+       bytetype.Sym = s
+       s.Def = typenod(bytetype)
+       s.Def.Name = new(Name)
+
+       // rune alias
+       s = Pkglookup("rune", builtinpkg)
+       runetype = typ(TINT32)
+       runetype.Sym = s
+       s.Def = typenod(runetype)
+       s.Def.Name = new(Name)
+
+       // backend-dependent builtin types (e.g. int).
+       for _, s := range typedefs {
+               s1 := Pkglookup(s.name, builtinpkg)
+
+               sameas := s.sameas32
+               if *s.width == 8 {
+                       sameas = s.sameas64
+               }
+
+               Simtype[s.etype] = sameas
+               minfltval[s.etype] = minfltval[sameas]
+               maxfltval[s.etype] = maxfltval[sameas]
+               Minintval[s.etype] = Minintval[sameas]
+               Maxintval[s.etype] = Maxintval[sameas]
+
+               t := typ(s.etype)
+               t.Sym = s1
+               Types[s.etype] = t
+               s1.Def = typenod(t)
+               s1.Def.Name = new(Name)
+               s1.Origpkg = builtinpkg
+
+               dowidth(t)
+       }
+}
+
+func lexfini() {
+       for _, s := range builtinpkg.Syms {
+               if s.Def == nil || (s.Name == "any" && Debug['A'] == 0) {
+                       continue
+               }
+               s1 := Lookup(s.Name)
+               if s1.Def != nil {
+                       continue
+               }
+
+               s1.Def = s.Def
+               s1.Block = s.Block
+       }
+
+       nodfp = Nod(ONAME, nil, nil)
+       nodfp.Type = Types[TINT32]
+       nodfp.Xoffset = 0
+       nodfp.Class = PPARAM
+       nodfp.Sym = Lookup(".fp")
+}
+
+var lexn = map[rune]string{
+       LNAME:    "NAME",
+       LLITERAL: "LITERAL",
+
+       LOPER:  "OPER",
+       LASOP:  "ASOP",
+       LINCOP: "INCOP",
+
+       LCOLAS: "COLAS",
+       LCOMM:  "COMM",
+       LDDD:   "DDD",
+
+       LBREAK:     "BREAK",
+       LCASE:      "CASE",
+       LCHAN:      "CHAN",
+       LCONST:     "CONST",
+       LCONTINUE:  "CONTINUE",
+       LDEFAULT:   "DEFAULT",
+       LDEFER:     "DEFER",
+       LELSE:      "ELSE",
+       LFALL:      "FALL",
+       LFOR:       "FOR",
+       LFUNC:      "FUNC",
+       LGO:        "GO",
+       LGOTO:      "GOTO",
+       LIF:        "IF",
+       LIMPORT:    "IMPORT",
+       LINTERFACE: "INTERFACE",
+       LMAP:       "MAP",
+       LPACKAGE:   "PACKAGE",
+       LRANGE:     "RANGE",
+       LRETURN:    "RETURN",
+       LSELECT:    "SELECT",
+       LSTRUCT:    "STRUCT",
+       LSWITCH:    "SWITCH",
+       LTYPE:      "TYPE",
+       LVAR:       "VAR",
+}
+
+func lexname(lex rune) string {
+       if s, ok := lexn[lex]; ok {
+               return s
+       }
+       return fmt.Sprintf("LEX-%d", lex)
+}
+
+func pkgnotused(lineno int32, path string, name string) {
+       // If the package was imported with a name other than the final
+       // import path element, show it explicitly in the error message.
+       // Note that this handles both renamed imports and imports of
+       // packages containing unconventional package declarations.
+       // Note that this uses / always, even on Windows, because Go import
+       // paths always use forward slashes.
+       elem := path
+       if i := strings.LastIndex(elem, "/"); i >= 0 {
+               elem = elem[i+1:]
+       }
+       if name == "" || elem == name {
+               yyerrorl(lineno, "imported and not used: %q", path)
+       } else {
+               yyerrorl(lineno, "imported and not used: %q as %s", path, name)
+       }
+}
+
+func mkpackage(pkgname string) {
+       if localpkg.Name == "" {
+               if pkgname == "_" {
+                       Yyerror("invalid package name _")
+               }
+               localpkg.Name = pkgname
+       } else {
+               if pkgname != localpkg.Name {
+                       Yyerror("package %s; expected %s", pkgname, localpkg.Name)
+               }
+               for _, s := range localpkg.Syms {
+                       if s.Def == nil {
+                               continue
+                       }
+                       if s.Def.Op == OPACK {
+                               // throw away top-level package name leftover
+                               // from previous file.
+                               // leave s->block set to cause redeclaration
+                               // errors if a conflicting top-level name is
+                               // introduced by a different file.
+                               if !s.Def.Used && nsyntaxerrors == 0 {
+                                       pkgnotused(s.Def.Lineno, s.Def.Name.Pkg.Path, s.Name)
+                               }
+                               s.Def = nil
+                               continue
+                       }
+
+                       if s.Def.Sym != s {
+                               // throw away top-level name left over
+                               // from previous import . "x"
+                               if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
+                                       pkgnotused(s.Def.Name.Pack.Lineno, s.Def.Name.Pack.Name.Pkg.Path, "")
+                                       s.Def.Name.Pack.Used = true
+                               }
+
+                               s.Def = nil
+                               continue
+                       }
+               }
+       }
+
+       if outfile == "" {
+               p := infile
+               if i := strings.LastIndex(p, "/"); i >= 0 {
+                       p = p[i+1:]
+               }
+               if Ctxt.Windows != 0 {
+                       if i := strings.LastIndex(p, `\`); i >= 0 {
+                               p = p[i+1:]
+                       }
+               }
+               if i := strings.LastIndex(p, "."); i >= 0 {
+                       p = p[:i]
+               }
+               suffix := ".o"
+               if writearchive > 0 {
+                       suffix = ".a"
+               }
+               outfile = p + suffix
+       }
+}