blob: 96273370777693de547f918a688331850dbe930b [file] [log] [blame]
// 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.
package gc
import (
"bytes"
"cmd/internal/obj"
"flag"
"fmt"
"io"
"log"
"os"
"path"
"strconv"
"strings"
"unicode"
"unicode/utf8"
)
var yychar_lex int
var yyprev int
var yylast int
var imported_unsafe int
var goos string
var goarch string
var goroot string
// 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
}{struct {
name string
val *int
}{"nil", &Debug_checknil}}
// Our own isdigit, isspace, isalpha, isalnum that take care
// of EOF and other out of range arguments.
func yy_isdigit(c int) bool {
return c >= 0 && c <= 0xFF && isdigit(c)
}
func yy_isspace(c int) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
}
func yy_isalpha(c int) bool {
return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
}
func yy_isalnum(c int) bool {
return c >= 0 && c <= 0xFF && isalnum(c)
}
// Disallow use of isdigit etc.
const (
EOF = -1
)
func usage() {
fmt.Printf("usage: %cg [options] file.go...\n", Thearch.Thechar)
obj.Flagprint(1)
Exit(2)
}
func hidePanic() {
if 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("%cg version %s%s%s\n", Thearch.Thechar, 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.Diag = Yyerror
Ctxt.Bso = &bstdout
bstdout = *obj.Binitw(os.Stdout)
localpkg = mkpkg(newstrlit(""))
localpkg.Prefix = "\"\""
// pseudo-package, for scoping
builtinpkg = mkpkg(newstrlit("go.builtin"))
builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
// pseudo-package, accessed by import "unsafe"
unsafepkg = mkpkg(newstrlit("unsafe"))
unsafepkg.Name = "unsafe"
// real package, referred to by generated runtime calls
Runtimepkg = mkpkg(newstrlit("runtime"))
Runtimepkg.Name = "runtime"
// pseudo-packages used in symbol tables
gostringpkg = mkpkg(newstrlit("go.string"))
gostringpkg.Name = "go.string"
gostringpkg.Prefix = "go.string" // not go%2estring
itabpkg = mkpkg(newstrlit("go.itab"))
itabpkg.Name = "go.itab"
itabpkg.Prefix = "go.itab" // not go%2eitab
weaktypepkg = mkpkg(newstrlit("go.weak.type"))
weaktypepkg.Name = "go.weak.type"
weaktypepkg.Prefix = "go.weak.type" // not go%2eweak%2etype
typelinkpkg = mkpkg(newstrlit("go.typelink"))
typelinkpkg.Name = "go.typelink"
typelinkpkg.Prefix = "go.typelink" // not go%2etypelink
trackpkg = mkpkg(newstrlit("go.track"))
trackpkg.Name = "go.track"
trackpkg.Prefix = "go.track" // not go%2etrack
typepkg = mkpkg(newstrlit("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", "path: set relative path for local imports", &localimport)
obj.Flagcount("E", "debug symbol export", &Debug['E'])
obj.Flagfn1("I", "dir: add dir 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", "file: write assembly header to named file", &asmhdr)
obj.Flagcount("complete", "compiling complete package (no C or assembly)", &pure_go)
obj.Flagstr("d", "list: 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.Flagstr("installsuffix", "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("nolocalimports", "reject local (relative) imports", &nolocalimports)
obj.Flagstr("o", "obj: set output file", &outfile)
obj.Flagstr("p", "path: 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", "prefix: remove prefix from recorded source file paths", &Ctxt.Trimpath)
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'])
if Thearch.Thechar == '6' {
obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel)
}
obj.Flagstr("cpuprofile", "file: write cpu profile to file", &cpuprofile)
obj.Flagstr("memprofile", "file: write memory profile to file", &memprofile)
obj.Flagparse(usage)
Ctxt.Debugasm = int32(Debug['S'])
Ctxt.Debugvlog = int32(Debug['v'])
if flag.NArg() < 1 {
usage()
}
startProfile()
if flag_race != 0 {
racepkg = mkpkg(newstrlit("runtime/race"))
racepkg.Name = "race"
}
// parse -d argument
if debugstr != "" {
var j int
f := strings.Split(debugstr, ",")
for i := range f {
if f[i] == "" {
continue
}
for j = 0; j < len(debugtab); j++ {
if debugtab[j].name == f[i] {
if debugtab[j].val != nil {
*debugtab[j].val = 1
}
break
}
}
if j >= len(debugtab) {
log.Fatalf("unknown debug information -d '%s'\n", f[i])
}
}
}
// 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']
}
if Thearch.Thechar == '8' {
p := obj.Getgo386()
if p == "387" {
Use_sse = 0
} else if p == "sse2" {
Use_sse = 1
} else {
log.Fatalf("unsupported setting GO386=%s", p)
}
}
Thearch.Betypeinit()
if Widthptr == 0 {
Fatal("betypeinit failed")
}
lexinit()
typeinit()
lexinit1()
// TODO(rsc): Restore yytinit?
blockgen = 1
dclcontext = PEXTERN
nerrors = 0
lexlineno = 1
for _, infile = range flag.Args() {
linehist(infile, 0, 0)
curio.infile = infile
var err error
curio.bin, err = obj.Bopenr(infile)
if err != nil {
fmt.Printf("open %s: %v\n", infile, err)
errorexit()
}
curio.peekc = 0
curio.peekc1 = 0
curio.nlsemi = 0
curio.eofnl = 0
curio.last = 0
// Skip initial BOM if present.
if obj.Bgetrune(curio.bin) != obj.BOM {
obj.Bungetrune(curio.bin)
}
block = 1
iota_ = -1000000
imported_unsafe = 0
yyparse()
if nsyntaxerrors != 0 {
errorexit()
}
linehist("<pop>", 0, 0)
if curio.bin != nil {
obj.Bterm(curio.bin)
}
}
testdclstack()
mkpackage(localpkg.Name) // final import not used checks
lexfini()
typecheckok = 1
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()
for l := xtop; l != nil; l = l.Next {
if l.N.Op != ODCL && l.N.Op != OAS {
typecheck(&l.N, Etop)
}
}
// Phase 2: Variable assignments.
// To check interface assignments, depends on phase 1.
for l := xtop; l != nil; l = l.Next {
if l.N.Op == ODCL || l.N.Op == OAS {
typecheck(&l.N, Etop)
}
}
resumecheckwidth()
// Phase 3: Type check function bodies.
for l := xtop; l != nil; l = l.Next {
if l.N.Op == ODCLFUNC || l.N.Op == OCLOSURE {
Curfn = l.N
decldepth = 1
saveerrors()
typechecklist(l.N.Nbody, Etop)
checkreturn(l.N)
if nerrors != 0 {
l.N.Nbody = 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 l := xtop; l != nil; l = l.Next {
if l.N.Op == ODCLFUNC && l.N.Closure != nil {
Curfn = l.N
capturevars(l.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 l := importlist; l != nil; l = l.Next {
if l.N.Inl != nil {
saveerrors()
typecheckinl(l.N)
}
}
if nsavederrors+nerrors != 0 {
errorexit()
}
}
if Debug['l'] != 0 {
// Find functions that can be inlined and clone them before walk expands them.
for l := xtop; l != nil; l = l.Next {
if l.N.Op == ODCLFUNC {
caninl(l.N)
}
}
// Expand inlineable calls in all functions
for l := xtop; l != nil; l = l.Next {
if l.N.Op == ODCLFUNC {
inlcalls(l.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.
escapes(xtop)
// Escape analysis moved escaped values off stack.
// Move large values off stack too.
movelarge(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 l := xtop; l != nil; l = l.Next {
if l.N.Op == ODCLFUNC && l.N.Closure != nil {
Curfn = l.N
transformclosure(l.N)
}
}
Curfn = nil
// Phase 8: Compile top level functions.
for l := xtop; l != nil; l = l.Next {
if l.N.Op == ODCLFUNC {
funccompile(l.N)
}
}
if nsavederrors+nerrors == 0 {
fninit(xtop)
}
// Phase 9: Check external declarations.
for l := externdcl; l != nil; l = l.Next {
if l.N.Op == ONAME {
typecheck(&l.N, Erv)
}
}
if nerrors+nsavederrors != 0 {
errorexit()
}
dumpobj()
if asmhdr != "" {
dumpasmhdr()
}
if nerrors+nsavederrors != 0 {
errorexit()
}
Flusherrors()
}
func saveerrors() {
nsavederrors += nerrors
nerrors = 0
}
func arsize(b *obj.Biobuf, 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 *obj.Biobuf) bool {
/* archive header */
p := obj.Brdline(b, '\n')
if p == "" {
return false
}
if obj.Blinelen(b) != 8 {
return false
}
if p != "!<arch>\n" {
return false
}
/* symbol table may be first; skip it */
sz := arsize(b, "__.GOSYMDEF")
if sz >= 0 {
obj.Bseek(b, int64(sz), 1)
} else {
obj.Bseek(b, 8, 0)
}
/* package export block is next */
sz = arsize(b, "__.PKGDEF")
if sz <= 0 {
return false
}
return true
}
func addidir(dir string) {
if dir == "" {
return
}
var pp **Idir
for pp = &idirs; *pp != nil; pp = &(*pp).link {
}
*pp = new(Idir)
(*pp).link = nil
(*pp).dir = dir
}
// is this path a local name? begins with ./ or ../ or /
func islocalname(name *Strlit) bool {
return strings.HasPrefix(name.S, "/") ||
Ctxt.Windows != 0 && len(name.S) >= 3 && yy_isalpha(int(name.S[0])) && name.S[1] == ':' && name.S[2] == '/' ||
strings.HasPrefix(name.S, "./") || name.S == "." ||
strings.HasPrefix(name.S, "../") || name.S == ".."
}
func findpkg(name *Strlit) 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.
namebuf = fmt.Sprintf("%v.a", Zconv(name, 0))
if obj.Access(namebuf, 0) >= 0 {
return true
}
namebuf = fmt.Sprintf("%v.%c", Zconv(name, 0), Thearch.Thechar)
if obj.Access(namebuf, 0) >= 0 {
return true
}
return false
}
// local imports should be canonicalized already.
// don't want to see "encoding/../encoding/base64"
// as different from "encoding/base64".
var q string
_ = q
if path.Clean(name.S) != name.S {
Yyerror("non-canonical import path %v (should be %s)", Zconv(name, 0), q)
return false
}
for p := idirs; p != nil; p = p.link {
namebuf = fmt.Sprintf("%s/%v.a", p.dir, Zconv(name, 0))
if obj.Access(namebuf, 0) >= 0 {
return true
}
namebuf = fmt.Sprintf("%s/%v.%c", p.dir, Zconv(name, 0), Thearch.Thechar)
if obj.Access(namebuf, 0) >= 0 {
return true
}
}
if goroot != "" {
suffix := ""
suffixsep := ""
if flag_installsuffix != "" {
suffixsep = "_"
suffix = flag_installsuffix
} else if flag_race != 0 {
suffixsep = "_"
suffix = "race"
}
namebuf = fmt.Sprintf("%s/pkg/%s_%s%s%s/%v.a", goroot, goos, goarch, suffixsep, suffix, Zconv(name, 0))
if obj.Access(namebuf, 0) >= 0 {
return true
}
namebuf = fmt.Sprintf("%s/pkg/%s_%s%s%s/%v.%c", goroot, goos, goarch, suffixsep, suffix, Zconv(name, 0), Thearch.Thechar)
if obj.Access(namebuf, 0) >= 0 {
return true
}
}
return false
}
func fakeimport() {
importpkg = mkpkg(newstrlit("fake"))
cannedimports("fake.6", "$$\n")
}
func importfile(f *Val, line int) {
if f.Ctype != CTSTR {
Yyerror("import statement not a string")
fakeimport()
return
}
if len(f.U.Sval.S) == 0 {
Yyerror("import path is empty")
fakeimport()
return
}
if isbadimport(f.U.Sval) {
fakeimport()
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 f.U.Sval.S == "main" {
Yyerror("cannot import \"main\"")
errorexit()
}
if myimportpath != "" && f.U.Sval.S == myimportpath {
Yyerror("import \"%v\" while compiling that package (import cycle)", Zconv(f.U.Sval, 0))
errorexit()
}
if f.U.Sval.S == "unsafe" {
if safemode != 0 {
Yyerror("cannot import package unsafe")
errorexit()
}
importpkg = mkpkg(f.U.Sval)
cannedimports("unsafe.6", unsafeimport)
imported_unsafe = 1
return
}
path_ := f.U.Sval
if islocalname(path_) {
if path_.S[0] == '/' {
Yyerror("import path cannot be absolute path")
fakeimport()
return
}
prefix := Ctxt.Pathname
if localimport != "" {
prefix = localimport
}
cleanbuf := prefix
cleanbuf += "/"
cleanbuf += path_.S
cleanbuf = path.Clean(cleanbuf)
path_ = newstrlit(cleanbuf)
if isbadimport(path_) {
fakeimport()
return
}
}
if !findpkg(path_) {
Yyerror("can't find import: \"%v\"", Zconv(f.U.Sval, 0))
errorexit()
}
importpkg = mkpkg(path_)
// If we already saw that package, feed a dummy statement
// to the lexer to avoid parsing export data twice.
if importpkg.Imported != 0 {
file := namebuf
tag := ""
if importpkg.Safe {
tag = "safe"
}
p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag)
cannedimports(file, p)
return
}
importpkg.Imported = 1
var err error
var imp *obj.Biobuf
imp, err = obj.Bopenr(namebuf)
if err != nil {
Yyerror("can't open import: \"%v\": %v", Zconv(f.U.Sval, 0), err)
errorexit()
}
file := namebuf
n := len(namebuf)
if n > 2 && namebuf[n-2] == '.' && namebuf[n-1] == 'a' {
if !skiptopkgdef(imp) {
Yyerror("import %s: not a package file", file)
errorexit()
}
}
// check object header
p := obj.Brdstr(imp, '\n', 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.
linehist(file[n-len(path_.S)-2:], -1, 1) // acts as #pragma lib
/*
* position the input right
* after $$ and return
*/
pushedio = curio
curio.bin = imp
curio.peekc = 0
curio.peekc1 = 0
curio.infile = file
curio.nlsemi = 0
typecheckok = 1
var c int32
for {
c = int32(getc())
if c == EOF {
break
}
if c != '$' {
continue
}
c = int32(getc())
if c == EOF {
break
}
if c != '$' {
continue
}
return
}
Yyerror("no import in \"%v\"", Zconv(f.U.Sval, 0))
unimportfile()
}
func unimportfile() {
if curio.bin != nil {
obj.Bterm(curio.bin)
curio.bin = nil
} else {
lexlineno-- // re correct sys.6 line number
}
curio = pushedio
pushedio.bin = nil
incannedimport = 0
typecheckok = 0
}
func cannedimports(file string, cp string) {
lexlineno++ // if sys.6 is included on line 1,
pushedio = curio
curio.bin = nil
curio.peekc = 0
curio.peekc1 = 0
curio.infile = file
curio.cp = cp
curio.nlsemi = 0
curio.importsafe = false
typecheckok = 1
incannedimport = 1
}
func isfrog(c int) bool {
// complain about possibly invisible control characters
if c < ' ' {
return !yy_isspace(c) // exclude good white space
}
if 0x7f <= c && c <= 0xa0 { // DEL, unicode block including unbreakable space.
return true
}
return false
}
type Loophack struct {
v int
next *Loophack
}
var _yylex_lstk *Loophack
func _yylex(yylval *yySymType) int32 {
var c int
var c1 int
var escflag int
var v int64
var cp *bytes.Buffer
var rune_ uint
var s *Sym
var h *Loophack
prevlineno = lineno
l0:
c = getc()
if yy_isspace(c) {
if c == '\n' && curio.nlsemi != 0 {
ungetc(c)
DBG("lex: implicit semi\n")
return ';'
}
goto l0
}
lineno = lexlineno /* start of token */
if c >= utf8.RuneSelf {
/* all multibyte runes are alpha */
cp = &lexbuf
cp.Reset()
goto talph
}
if yy_isalpha(c) {
cp = &lexbuf
cp.Reset()
goto talph
}
if yy_isdigit(c) {
goto tnum
}
switch c {
case EOF:
lineno = prevlineno
ungetc(EOF)
return -1
case '_':
cp = &lexbuf
cp.Reset()
goto talph
case '.':
c1 = getc()
if yy_isdigit(c1) {
cp = &lexbuf
cp.Reset()
cp.WriteByte(byte(c))
c = c1
goto casedot
}
if c1 == '.' {
c1 = getc()
if c1 == '.' {
c = LDDD
goto lx
}
ungetc(c1)
c1 = '.'
}
/* "..." */
case '"':
lexbuf.Reset()
lexbuf.WriteString(`"<string>"`)
cp = &strbuf
cp.Reset()
for {
if escchar('"', &escflag, &v) {
break
}
if v < utf8.RuneSelf || escflag != 0 {
cp.WriteByte(byte(v))
} else {
rune_ = uint(v)
cp.WriteRune(rune(rune_))
}
}
goto strlit
/* `...` */
case '`':
lexbuf.Reset()
lexbuf.WriteString("`<string>`")
cp = &strbuf
cp.Reset()
for {
c = int(getr())
if c == '\r' {
continue
}
if c == EOF {
Yyerror("eof in string")
break
}
if c == '`' {
break
}
cp.WriteRune(rune(c))
}
goto strlit
/* '.' */
case '\'':
if escchar('\'', &escflag, &v) {
Yyerror("empty character literal or unescaped ' in character literal")
v = '\''
}
if !escchar('\'', &escflag, &v) {
Yyerror("missing '")
ungetc(int(v))
}
yylval.val.U.Xval = new(Mpint)
Mpmovecfix(yylval.val.U.Xval, v)
yylval.val.Ctype = CTRUNE
DBG("lex: codepoint literal\n")
litbuf = "string literal"
return LLITERAL
case '/':
c1 = getc()
if c1 == '*' {
nl := 0
for {
c = int(getr())
if c == '\n' {
nl = 1
}
for c == '*' {
c = int(getr())
if c == '/' {
if nl != 0 {
ungetc('\n')
}
goto l0
}
if c == '\n' {
nl = 1
}
}
if c == EOF {
Yyerror("eof in comment")
errorexit()
}
}
}
if c1 == '/' {
c = getlinepragma()
for {
if c == '\n' || c == EOF {
ungetc(c)
goto l0
}
c = int(getr())
}
}
if c1 == '=' {
c = ODIV
goto asop
}
case ':':
c1 = getc()
if c1 == '=' {
c = LCOLAS
yylval.i = int(lexlineno)
goto lx
}
case '*':
c1 = getc()
if c1 == '=' {
c = OMUL
goto asop
}
case '%':
c1 = getc()
if c1 == '=' {
c = OMOD
goto asop
}
case '+':
c1 = getc()
if c1 == '+' {
c = LINC
goto lx
}
if c1 == '=' {
c = OADD
goto asop
}
case '-':
c1 = getc()
if c1 == '-' {
c = LDEC
goto lx
}
if c1 == '=' {
c = OSUB
goto asop
}
case '>':
c1 = getc()
if c1 == '>' {
c = LRSH
c1 = getc()
if c1 == '=' {
c = ORSH
goto asop
}
break
}
if c1 == '=' {
c = LGE
goto lx
}
c = LGT
case '<':
c1 = getc()
if c1 == '<' {
c = LLSH
c1 = getc()
if c1 == '=' {
c = OLSH
goto asop
}
break
}
if c1 == '=' {
c = LLE
goto lx
}
if c1 == '-' {
c = LCOMM
goto lx
}
c = LLT
case '=':
c1 = getc()
if c1 == '=' {
c = LEQ
goto lx
}
case '!':
c1 = getc()
if c1 == '=' {
c = LNE
goto lx
}
case '&':
c1 = getc()
if c1 == '&' {
c = LANDAND
goto lx
}
if c1 == '^' {
c = LANDNOT
c1 = getc()
if c1 == '=' {
c = OANDNOT
goto asop
}
break
}
if c1 == '=' {
c = OAND
goto asop
}
case '|':
c1 = getc()
if c1 == '|' {
c = LOROR
goto lx
}
if c1 == '=' {
c = OOR
goto asop
}
case '^':
c1 = getc()
if c1 == '=' {
c = OXOR
goto asop
}
/*
* clumsy dance:
* to implement rule that disallows
* if T{1}[0] { ... }
* but allows
* if (T{1}[0]) { ... }
* the block bodies for if/for/switch/select
* begin with an LBODY token, not '{'.
*
* when we see the keyword, the next
* non-parenthesized '{' becomes an LBODY.
* loophack is normally 0.
* a keyword makes it go up to 1.
* parens push loophack onto a stack and go back to 0.
* a '{' with loophack == 1 becomes LBODY and disables loophack.
*
* i said it was clumsy.
*/
case '(',
'[':
if loophack != 0 || _yylex_lstk != nil {
h = new(Loophack)
if h == nil {
Flusherrors()
Yyerror("out of memory")
errorexit()
}
h.v = loophack
h.next = _yylex_lstk
_yylex_lstk = h
loophack = 0
}
goto lx
case ')',
']':
if _yylex_lstk != nil {
h = _yylex_lstk
loophack = h.v
_yylex_lstk = h.next
}
goto lx
case '{':
if loophack == 1 {
DBG("%L lex: LBODY\n", lexlineno)
loophack = 0
return LBODY
}
goto lx
default:
goto lx
}
ungetc(c1)
lx:
if c > 0xff {
DBG("%L lex: TOKEN %s\n", lexlineno, lexname(c))
} else {
DBG("%L lex: TOKEN '%c'\n", lexlineno, c)
}
if isfrog(c) {
Yyerror("illegal character 0x%x", uint(c))
goto l0
}
if importpkg == nil && (c == '#' || c == '$' || c == '?' || c == '@' || c == '\\') {
Yyerror("%s: unexpected %c", "syntax error", c)
goto l0
}
return int32(c)
asop:
yylval.i = c // rathole to hold which asop
DBG("lex: TOKEN ASOP %c\n", c)
return LASOP
/*
* cp is set to lexbuf and some
* prefix has been stored
*/
talph:
for {
if c >= utf8.RuneSelf {
ungetc(c)
rune_ = uint(getr())
// 0xb7 · is used for internal names
if !unicode.IsLetter(rune(rune_)) && !unicode.IsDigit(rune(rune_)) && (importpkg == nil || rune_ != 0xb7) {
Yyerror("invalid identifier character U+%04x", rune_)
}
cp.WriteRune(rune(rune_))
} else if !yy_isalnum(c) && c != '_' {
break
} else {
cp.WriteByte(byte(c))
}
c = getc()
}
cp = nil
ungetc(c)
s = Lookup(lexbuf.String())
switch s.Lexical {
case LIGNORE:
goto l0
case LFOR,
LIF,
LSWITCH,
LSELECT:
loophack = 1 // see comment about loophack above
}
DBG("lex: %S %s\n", s, lexname(int(s.Lexical)))
yylval.sym = s
return int32(s.Lexical)
tnum:
cp = &lexbuf
cp.Reset()
if c != '0' {
for {
cp.WriteByte(byte(c))
c = getc()
if yy_isdigit(c) {
continue
}
goto dc
}
}
cp.WriteByte(byte(c))
c = getc()
if c == 'x' || c == 'X' {
for {
cp.WriteByte(byte(c))
c = getc()
if yy_isdigit(c) {
continue
}
if c >= 'a' && c <= 'f' {
continue
}
if c >= 'A' && c <= 'F' {
continue
}
if lexbuf.Len() == 2 {
Yyerror("malformed hex constant")
}
if c == 'p' {
goto caseep
}
goto ncu
}
}
if c == 'p' { // 0p begins floating point zero
goto caseep
}
c1 = 0
for {
if !yy_isdigit(c) {
break
}
if c < '0' || c > '7' {
c1 = 1 // not octal
}
cp.WriteByte(byte(c))
c = getc()
}
if c == '.' {
goto casedot
}
if c == 'e' || c == 'E' {
goto caseep
}
if c == 'i' {
goto casei
}
if c1 != 0 {
Yyerror("malformed octal constant")
}
goto ncu
dc:
if c == '.' {
goto casedot
}
if c == 'e' || c == 'E' || c == 'p' || c == 'P' {
goto caseep
}
if c == 'i' {
goto casei
}
ncu:
cp = nil
ungetc(c)
yylval.val.U.Xval = new(Mpint)
mpatofix(yylval.val.U.Xval, lexbuf.String())
if yylval.val.U.Xval.Ovf != 0 {
Yyerror("overflow in constant")
Mpmovecfix(yylval.val.U.Xval, 0)
}
yylval.val.Ctype = CTINT
DBG("lex: integer literal\n")
litbuf = "literal "
litbuf += lexbuf.String()
return LLITERAL
casedot:
for {
cp.WriteByte(byte(c))
c = getc()
if !yy_isdigit(c) {
break
}
}
if c == 'i' {
goto casei
}
if c != 'e' && c != 'E' {
goto caseout
}
caseep:
cp.WriteByte(byte(c))
c = getc()
if c == '+' || c == '-' {
cp.WriteByte(byte(c))
c = getc()
}
if !yy_isdigit(c) {
Yyerror("malformed fp constant exponent")
}
for yy_isdigit(c) {
cp.WriteByte(byte(c))
c = getc()
}
if c == 'i' {
goto casei
}
goto caseout
// imaginary constant
casei:
cp = nil
yylval.val.U.Cval = new(Mpcplx)
Mpmovecflt(&yylval.val.U.Cval.Real, 0.0)
mpatoflt(&yylval.val.U.Cval.Imag, lexbuf.String())
if yylval.val.U.Cval.Imag.Val.Ovf != 0 {
Yyerror("overflow in imaginary constant")
Mpmovecflt(&yylval.val.U.Cval.Real, 0.0)
}
yylval.val.Ctype = CTCPLX
DBG("lex: imaginary literal\n")
litbuf = "literal "
litbuf += lexbuf.String()
return LLITERAL
caseout:
cp = nil
ungetc(c)
yylval.val.U.Fval = new(Mpflt)
mpatoflt(yylval.val.U.Fval, lexbuf.String())
if yylval.val.U.Fval.Val.Ovf != 0 {
Yyerror("overflow in float constant")
Mpmovecflt(yylval.val.U.Fval, 0.0)
}
yylval.val.Ctype = CTFLT
DBG("lex: floating literal\n")
litbuf = "literal "
litbuf += lexbuf.String()
return LLITERAL
strlit:
yylval.val.U.Sval = &Strlit{S: cp.String()}
yylval.val.Ctype = CTSTR
DBG("lex: string literal\n")
litbuf = "string literal"
return LLITERAL
}
func more(pp *string) bool {
p := *pp
for p != "" && yy_isspace(int(p[0])) {
p = p[1:]
}
*pp = p
return p != ""
}
/*
* read and interpret syntax that looks like
* //line parse.y:15
* as a discontinuity in sequential line numbers.
* the next line of input comes from parse.y:15
*/
func getlinepragma() int {
var cmd, verb, name string
var n int
var cp *bytes.Buffer
var linep int
c := int(getr())
if c == 'g' {
goto go_
}
if c != 'l' {
goto out
}
for i := 1; i < 5; i++ {
c = int(getr())
if c != int("line "[i]) {
goto out
}
}
cp = &lexbuf
cp.Reset()
linep = 0
for {
c = int(getr())
if c == EOF {
goto out
}
if c == '\n' {
break
}
if c == ' ' {
continue
}
if c == ':' {
linep = cp.Len() + 1
}
cp.WriteByte(byte(c))
}
cp = nil
if linep == 0 {
goto out
}
n = 0
for _, c := range lexbuf.String()[linep:] {
if c < '0' || c > '9' {
goto out
}
n = n*10 + int(c) - '0'
if n > 1e8 {
Yyerror("line number out of range")
errorexit()
}
}
if n <= 0 {
goto out
}
// try to avoid allocating file name over and over
name = lexbuf.String()[:linep-1]
for h := Ctxt.Hist; h != nil; h = h.Link {
if h.Name != "" && h.Name == name {
linehist(h.Name, int32(n), 0)
goto out
}
}
linehist(name, int32(n), 0)
goto out
go_:
cp = &lexbuf
cp.Reset()
cp.WriteByte('g') // already read
for {
c = int(getr())
if c == EOF || c >= utf8.RuneSelf {
goto out
}
if c == '\n' {
break
}
cp.WriteByte(byte(c))
}
cp = nil
if strings.HasPrefix(lexbuf.String(), "go:cgo_") {
pragcgo(lexbuf.String())
}
cmd = lexbuf.String()
verb = cmd
if i := strings.Index(verb, " "); i >= 0 {
verb = verb[:i]
}
if verb == "go:linkname" {
if imported_unsafe == 0 {
Yyerror("//go:linkname only allowed in Go files that import \"unsafe\"")
}
f := strings.Fields(cmd)
if len(f) != 3 {
Yyerror("usage: //go:linkname localname linkname")
goto out
}
Lookup(f[1]).Linkname = f[2]
goto out
}
if verb == "go:nointerface" && obj.Fieldtrack_enabled != 0 {
nointerface = true
goto out
}
if verb == "go:noescape" {
noescape = true
goto out
}
if verb == "go:nosplit" {
nosplit = true
goto out
}
if verb == "go:nowritebarrier" {
if compiling_runtime == 0 {
Yyerror("//go:nowritebarrier only allowed in runtime")
}
nowritebarrier = true
goto out
}
out:
return c
}
func getimpsym(pp *string) string {
more(pp) // skip spaces
p := *pp
if p == "" || p[0] == '"' {
return ""
}
i := 0
for i < len(p) && !yy_isspace(int(p[i])) && p[i] != '"' {
i++
}
sym := p[:i]
*pp = p[i:]
return sym
}
func getquoted(pp *string) (string, bool) {
more(pp) // skip spaces
p := *pp
if p == "" || p[0] != '"' {
return "", false
}
p = p[1:]
i := strings.Index(p, `"`)
if i < 0 {
return "", false
}
*pp = p[i+1:]
return p[:i], true
}
// Copied nearly verbatim from the C compiler's #pragma parser.
// TODO: Rewrite more cleanly once the compiler is written in Go.
func pragcgo(text string) {
var q string
if i := strings.Index(text, " "); i >= 0 {
text, q = text[:i], text[i:]
}
verb := text[3:] // skip "go:"
if verb == "cgo_dynamic_linker" || verb == "dynlinker" {
var ok bool
var p string
p, ok = getquoted(&q)
if !ok {
goto err1
}
pragcgobuf += fmt.Sprintf("cgo_dynamic_linker %v\n", plan9quote(p))
goto out
err1:
Yyerror("usage: //go:cgo_dynamic_linker \"path\"")
goto out
}
if verb == "dynexport" {
verb = "cgo_export_dynamic"
}
if verb == "cgo_export_static" || verb == "cgo_export_dynamic" {
local := getimpsym(&q)
var remote string
if local == "" {
goto err2
}
if !more(&q) {
pragcgobuf += fmt.Sprintf("%s %v\n", verb, plan9quote(local))
goto out
}
remote = getimpsym(&q)
if remote == "" {
goto err2
}
pragcgobuf += fmt.Sprintf("%s %v %v\n", verb, plan9quote(local), plan9quote(remote))
goto out
err2:
Yyerror("usage: //go:%s local [remote]", verb)
goto out
}
if verb == "cgo_import_dynamic" || verb == "dynimport" {
var ok bool
local := getimpsym(&q)
var p string
var remote string
if local == "" {
goto err3
}
if !more(&q) {
pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v\n", plan9quote(local))
goto out
}
remote = getimpsym(&q)
if remote == "" {
goto err3
}
if !more(&q) {
pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v\n", plan9quote(local), plan9quote(remote))
goto out
}
p, ok = getquoted(&q)
if !ok {
goto err3
}
pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v %v\n", plan9quote(local), plan9quote(remote), plan9quote(p))
goto out
err3:
Yyerror("usage: //go:cgo_import_dynamic local [remote [\"library\"]]")
goto out
}
if verb == "cgo_import_static" {
local := getimpsym(&q)
if local == "" || more(&q) {
goto err4
}
pragcgobuf += fmt.Sprintf("cgo_import_static %v\n", plan9quote(local))
goto out
err4:
Yyerror("usage: //go:cgo_import_static local")
goto out
}
if verb == "cgo_ldflag" {
var ok bool
var p string
p, ok = getquoted(&q)
if !ok {
goto err5
}
pragcgobuf += fmt.Sprintf("cgo_ldflag %v\n", plan9quote(p))
goto out
err5:
Yyerror("usage: //go:cgo_ldflag \"arg\"")
goto out
}
out:
}
type yy struct{}
var yymsg []struct {
yystate, yychar int
msg string
}
func (yy) Lex(v *yySymType) int {
return int(yylex(v))
}
func (yy) Error(msg string) {
Yyerror("%s", msg)
}
var theparser yyParser
var parsing bool
func yyparse() {
theparser = yyNewParser()
parsing = true
theparser.Parse(yy{})
parsing = false
}
func yylex(yylval *yySymType) int32 {
lx := int(_yylex(yylval))
if curio.nlsemi != 0 && lx == EOF {
// Treat EOF as "end of line" for the purposes
// of inserting a semicolon.
lx = ';'
}
switch lx {
case LNAME,
LLITERAL,
LBREAK,
LCONTINUE,
LFALL,
LRETURN,
LINC,
LDEC,
')',
'}',
']':
curio.nlsemi = 1
default:
curio.nlsemi = 0
}
// Track last two tokens returned by yylex.
yyprev = yylast
yylast = lx
return int32(lx)
}
func getc() int {
c := curio.peekc
if c != 0 {
curio.peekc = curio.peekc1
curio.peekc1 = 0
goto check
}
if curio.bin == nil {
if len(curio.cp) == 0 {
c = 0
} else {
c = int(curio.cp[0])
curio.cp = curio.cp[1:]
}
} else {
var c1 int
var c2 int
loop:
c = obj.Bgetc(curio.bin)
if c == 0xef {
c1 = obj.Bgetc(curio.bin)
c2 = obj.Bgetc(curio.bin)
if c1 == 0xbb && c2 == 0xbf {
yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file")
goto loop
}
obj.Bungetc(curio.bin)
obj.Bungetc(curio.bin)
}
}
check:
switch c {
case 0:
if curio.bin != nil {
Yyerror("illegal NUL byte")
break
}
fallthrough
// insert \n at EOF
case EOF:
if curio.eofnl != 0 || curio.last == '\n' {
return EOF
}
curio.eofnl = 1
c = '\n'
fallthrough
case '\n':
if pushedio.bin == nil {
lexlineno++
}
}
curio.last = c
return c
}
func ungetc(c int) {
curio.peekc1 = curio.peekc
curio.peekc = c
if c == '\n' && pushedio.bin == nil {
lexlineno--
}
}
func getr() int32 {
var buf [utf8.UTFMax]byte
for i := 0; ; i++ {
c := getc()
if i == 0 && c < utf8.RuneSelf {
return int32(c)
}
buf[i] = byte(c)
if i+1 == len(buf) || utf8.FullRune(buf[:i+1]) {
r, w := utf8.DecodeRune(buf[:i+1])
if r == utf8.RuneError && w == 1 {
lineno = lexlineno
Yyerror("illegal UTF-8 sequence % x", buf[:i+1])
}
return int32(r)
}
}
}
func escchar(e int, escflg *int, val *int64) bool {
*escflg = 0
c := int(getr())
switch c {
case EOF:
Yyerror("eof in string")
return true
case '\n':
Yyerror("newline in string")
return true
case '\\':
break
default:
if c == e {
return true
}
*val = int64(c)
return false
}
u := 0
c = int(getr())
var l int64
var i int
switch c {
case 'x':
*escflg = 1 // it's a byte
i = 2
goto hex
case 'u':
i = 4
u = 1
goto hex
case 'U':
i = 8
u = 1
goto hex
case '0',
'1',
'2',
'3',
'4',
'5',
'6',
'7':
*escflg = 1 // it's a byte
goto oct
case 'a':
c = '\a'
case 'b':
c = '\b'
case 'f':
c = '\f'
case 'n':
c = '\n'
case 'r':
c = '\r'
case 't':
c = '\t'
case 'v':
c = '\v'
case '\\':
c = '\\'
default:
if c != e {
Yyerror("unknown escape sequence: %c", c)
}
}
*val = int64(c)
return false
hex:
l = 0
for ; i > 0; i-- {
c = getc()
if c >= '0' && c <= '9' {
l = l*16 + int64(c) - '0'
continue
}
if c >= 'a' && c <= 'f' {
l = l*16 + int64(c) - 'a' + 10
continue
}
if c >= 'A' && c <= 'F' {
l = l*16 + int64(c) - 'A' + 10
continue
}
Yyerror("non-hex character in escape sequence: %c", c)
ungetc(c)
break
}
if u != 0 && (l > utf8.MaxRune || (0xd800 <= l && l < 0xe000)) {
Yyerror("invalid Unicode code point in escape sequence: %#x", l)
l = utf8.RuneError
}
*val = l
return false
oct:
l = int64(c) - '0'
for i := 2; i > 0; i-- {
c = getc()
if c >= '0' && c <= '7' {
l = l*8 + int64(c) - '0'
continue
}
Yyerror("non-octal character in escape sequence: %c", c)
ungetc(c)
}
if l > 255 {
Yyerror("octal escape value > 255: %d", l)
}
*val = l
return false
}
var syms = []struct {
name string
lexical int
etype int
op int
}{
/* name lexical etype op
*/
/* basic types */
struct {
name string
lexical int
etype int
op int
}{"int8", LNAME, TINT8, OXXX},
struct {
name string
lexical int
etype int
op int
}{"int16", LNAME, TINT16, OXXX},
struct {
name string
lexical int
etype int
op int
}{"int32", LNAME, TINT32, OXXX},
struct {
name string
lexical int
etype int
op int
}{"int64", LNAME, TINT64, OXXX},
struct {
name string
lexical int
etype int
op int
}{"uint8", LNAME, TUINT8, OXXX},
struct {
name string
lexical int
etype int
op int
}{"uint16", LNAME, TUINT16, OXXX},
struct {
name string
lexical int
etype int
op int
}{"uint32", LNAME, TUINT32, OXXX},
struct {
name string
lexical int
etype int
op int
}{"uint64", LNAME, TUINT64, OXXX},
struct {
name string
lexical int
etype int
op int
}{"float32", LNAME, TFLOAT32, OXXX},
struct {
name string
lexical int
etype int
op int
}{"float64", LNAME, TFLOAT64, OXXX},
struct {
name string
lexical int
etype int
op int
}{"complex64", LNAME, TCOMPLEX64, OXXX},
struct {
name string
lexical int
etype int
op int
}{"complex128", LNAME, TCOMPLEX128, OXXX},
struct {
name string
lexical int
etype int
op int
}{"bool", LNAME, TBOOL, OXXX},
struct {
name string
lexical int
etype int
op int
}{"string", LNAME, TSTRING, OXXX},
struct {
name string
lexical int
etype int
op int
}{"any", LNAME, TANY, OXXX},
struct {
name string
lexical int
etype int
op int
}{"break", LBREAK, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"case", LCASE, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"chan", LCHAN, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"const", LCONST, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"continue", LCONTINUE, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"default", LDEFAULT, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"else", LELSE, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"defer", LDEFER, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"fallthrough", LFALL, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"for", LFOR, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"func", LFUNC, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"go", LGO, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"goto", LGOTO, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"if", LIF, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"import", LIMPORT, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"interface", LINTERFACE, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"map", LMAP, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"package", LPACKAGE, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"range", LRANGE, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"return", LRETURN, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"select", LSELECT, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"struct", LSTRUCT, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"switch", LSWITCH, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"type", LTYPE, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"var", LVAR, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"append", LNAME, Txxx, OAPPEND},
struct {
name string
lexical int
etype int
op int
}{"cap", LNAME, Txxx, OCAP},
struct {
name string
lexical int
etype int
op int
}{"close", LNAME, Txxx, OCLOSE},
struct {
name string
lexical int
etype int
op int
}{"complex", LNAME, Txxx, OCOMPLEX},
struct {
name string
lexical int
etype int
op int
}{"copy", LNAME, Txxx, OCOPY},
struct {
name string
lexical int
etype int
op int
}{"delete", LNAME, Txxx, ODELETE},
struct {
name string
lexical int
etype int
op int
}{"imag", LNAME, Txxx, OIMAG},
struct {
name string
lexical int
etype int
op int
}{"len", LNAME, Txxx, OLEN},
struct {
name string
lexical int
etype int
op int
}{"make", LNAME, Txxx, OMAKE},
struct {
name string
lexical int
etype int
op int
}{"new", LNAME, Txxx, ONEW},
struct {
name string
lexical int
etype int
op int
}{"panic", LNAME, Txxx, OPANIC},
struct {
name string
lexical int
etype int
op int
}{"print", LNAME, Txxx, OPRINT},
struct {
name string
lexical int
etype int
op int
}{"println", LNAME, Txxx, OPRINTN},
struct {
name string
lexical int
etype int
op int
}{"real", LNAME, Txxx, OREAL},
struct {
name string
lexical int
etype int
op int
}{"recover", LNAME, Txxx, ORECOVER},
struct {
name string
lexical int
etype int
op int
}{"notwithstanding", LIGNORE, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"thetruthofthematter", LIGNORE, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"despiteallobjections", LIGNORE, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"whereas", LIGNORE, Txxx, OXXX},
struct {
name string
lexical int
etype int
op int
}{"insofaras", LIGNORE, Txxx, OXXX},
}
func lexinit() {
var lex int
var s *Sym
var s1 *Sym
var t *Type
var etype int
/*
* initialize basic types array
* initialize known symbols
*/
for i := 0; i < len(syms); i++ {
lex = syms[i].lexical
s = Lookup(syms[i].name)
s.Lexical = uint16(lex)
etype = syms[i].etype
if etype != Txxx {
if etype < 0 || etype >= len(Types) {
Fatal("lexinit: %s bad etype", s.Name)
}
s1 = Pkglookup(syms[i].name, builtinpkg)
t = Types[etype]
if t == nil {
t = typ(etype)
t.Sym = s1
if etype != TANY && etype != TSTRING {
dowidth(t)
}
Types[etype] = t
}
s1.Lexical = LNAME
s1.Def = typenod(t)
continue
}
etype = syms[i].op
if etype != OXXX {
s1 = Pkglookup(syms[i].name, builtinpkg)
s1.Lexical = LNAME
s1.Def = Nod(ONAME, nil, nil)
s1.Def.Sym = s1
s1.Def.Etype = uint8(etype)
s1.Def.Builtin = 1
}
}
// logically, the type of a string literal.
// types[TSTRING] is the named type string
// (the type of x in var x string or var x = "hello").
// this is the ideal form
// (the type of x in const x = "hello").
idealstring = typ(TSTRING)
idealbool = typ(TBOOL)
s = Pkglookup("true", builtinpkg)
s.Def = Nodbool(true)
s.Def.Sym = Lookup("true")
s.Def.Type = idealbool
s = Pkglookup("false", builtinpkg)
s.Def = Nodbool(false)
s.Def.Sym = Lookup("false")
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.Ctype = CTNIL
s.Def = nodlit(v)
s.Def.Sym = s
}
func lexinit1() {
// t = interface { Error() string }
rcvr := typ(TSTRUCT)
rcvr.Type = typ(TFIELD)
rcvr.Type.Type = Ptrto(typ(TSTRUCT))
rcvr.Funarg = 1
in := typ(TSTRUCT)
in.Funarg = 1
out := typ(TSTRUCT)
out.Type = typ(TFIELD)
out.Type.Type = Types[TSTRING]
out.Funarg = 1
f := typ(TFUNC)
*getthis(f) = rcvr
*Getoutarg(f) = out
*getinarg(f) = in
f.Thistuple = 1
f.Intuple = 0
f.Outnamed = 0
f.Outtuple = 1
t := typ(TINTER)
t.Type = typ(TFIELD)
t.Type.Sym = Lookup("Error")
t.Type.Type = f
// error type
s := Lookup("error")
s.Lexical = LNAME
s1 := Pkglookup("error", builtinpkg)
errortype = t
errortype.Sym = s1
s1.Lexical = LNAME
s1.Def = typenod(errortype)
// byte alias
s = Lookup("byte")
s.Lexical = LNAME
s1 = Pkglookup("byte", builtinpkg)
bytetype = typ(TUINT8)
bytetype.Sym = s1
s1.Lexical = LNAME
s1.Def = typenod(bytetype)
// rune alias
s = Lookup("rune")
s.Lexical = LNAME
s1 = Pkglookup("rune", builtinpkg)
runetype = typ(TINT32)
runetype.Sym = s1
s1.Lexical = LNAME
s1.Def = typenod(runetype)
}
func lexfini() {
var s *Sym
var lex int
var etype int
var i int
for i = 0; i < len(syms); i++ {
lex = syms[i].lexical
if lex != LNAME {
continue
}
s = Lookup(syms[i].name)
s.Lexical = uint16(lex)
etype = syms[i].etype
if etype != Txxx && (etype != TANY || Debug['A'] != 0) && s.Def == nil {
s.Def = typenod(Types[etype])
s.Origpkg = builtinpkg
}
etype = syms[i].op
if etype != OXXX && s.Def == nil {
s.Def = Nod(ONAME, nil, nil)
s.Def.Sym = s
s.Def.Etype = uint8(etype)
s.Def.Builtin = 1
s.Origpkg = builtinpkg
}
}
// backend-specific builtin types (e.g. int).
for i = range Thearch.Typedefs {
s = Lookup(Thearch.Typedefs[i].Name)
if s.Def == nil {
s.Def = typenod(Types[Thearch.Typedefs[i].Etype])
s.Origpkg = builtinpkg
}
}
// there's only so much table-driven we can handle.
// these are special cases.
s = Lookup("byte")
if s.Def == nil {
s.Def = typenod(bytetype)
s.Origpkg = builtinpkg
}
s = Lookup("error")
if s.Def == nil {
s.Def = typenod(errortype)
s.Origpkg = builtinpkg
}
s = Lookup("rune")
if s.Def == nil {
s.Def = typenod(runetype)
s.Origpkg = builtinpkg
}
s = Lookup("nil")
if s.Def == nil {
var v Val
v.Ctype = CTNIL
s.Def = nodlit(v)
s.Def.Sym = s
s.Origpkg = builtinpkg
}
s = Lookup("iota")
if s.Def == nil {
s.Def = Nod(OIOTA, nil, nil)
s.Def.Sym = s
s.Origpkg = builtinpkg
}
s = Lookup("true")
if s.Def == nil {
s.Def = Nodbool(true)
s.Def.Sym = s
s.Origpkg = builtinpkg
}
s = Lookup("false")
if s.Def == nil {
s.Def = Nodbool(false)
s.Def.Sym = s
s.Origpkg = builtinpkg
}
nodfp = Nod(ONAME, nil, nil)
nodfp.Type = Types[TINT32]
nodfp.Xoffset = 0
nodfp.Class = PPARAM
nodfp.Sym = Lookup(".fp")
}
var lexn = []struct {
lex int
name string
}{
struct {
lex int
name string
}{LANDAND, "ANDAND"},
struct {
lex int
name string
}{LANDNOT, "ANDNOT"},
struct {
lex int
name string
}{LASOP, "ASOP"},
struct {
lex int
name string
}{LBREAK, "BREAK"},
struct {
lex int
name string
}{LCASE, "CASE"},
struct {
lex int
name string
}{LCHAN, "CHAN"},
struct {
lex int
name string
}{LCOLAS, "COLAS"},
struct {
lex int
name string
}{LCOMM, "<-"},
struct {
lex int
name string
}{LCONST, "CONST"},
struct {
lex int
name string
}{LCONTINUE, "CONTINUE"},
struct {
lex int
name string
}{LDDD, "..."},
struct {
lex int
name string
}{LDEC, "DEC"},
struct {
lex int
name string
}{LDEFAULT, "DEFAULT"},
struct {
lex int
name string
}{LDEFER, "DEFER"},
struct {
lex int
name string
}{LELSE, "ELSE"},
struct {
lex int
name string
}{LEQ, "EQ"},
struct {
lex int
name string
}{LFALL, "FALL"},
struct {
lex int
name string
}{LFOR, "FOR"},
struct {
lex int
name string
}{LFUNC, "FUNC"},
struct {
lex int
name string
}{LGE, "GE"},
struct {
lex int
name string
}{LGO, "GO"},
struct {
lex int
name string
}{LGOTO, "GOTO"},
struct {
lex int
name string
}{LGT, "GT"},
struct {
lex int
name string
}{LIF, "IF"},
struct {
lex int
name string
}{LIMPORT, "IMPORT"},
struct {
lex int
name string
}{LINC, "INC"},
struct {
lex int
name string
}{LINTERFACE, "INTERFACE"},
struct {
lex int
name string
}{LLE, "LE"},
struct {
lex int
name string
}{LLITERAL, "LITERAL"},
struct {
lex int
name string
}{LLSH, "LSH"},
struct {
lex int
name string
}{LLT, "LT"},
struct {
lex int
name string
}{LMAP, "MAP"},
struct {
lex int
name string
}{LNAME, "NAME"},
struct {
lex int
name string
}{LNE, "NE"},
struct {
lex int
name string
}{LOROR, "OROR"},
struct {
lex int
name string
}{LPACKAGE, "PACKAGE"},
struct {
lex int
name string
}{LRANGE, "RANGE"},
struct {
lex int
name string
}{LRETURN, "RETURN"},
struct {
lex int
name string
}{LRSH, "RSH"},
struct {
lex int
name string
}{LSELECT, "SELECT"},
struct {
lex int
name string
}{LSTRUCT, "STRUCT"},
struct {
lex int
name string
}{LSWITCH, "SWITCH"},
struct {
lex int
name string
}{LTYPE, "TYPE"},
struct {
lex int
name string
}{LVAR, "VAR"},
}
var lexname_buf string
func lexname(lex int) string {
for i := 0; i < len(lexn); i++ {
if lexn[i].lex == lex {
return lexn[i].name
}
}
lexname_buf = fmt.Sprintf("LEX-%d", lex)
return lexname_buf
}
var yytfix = []struct {
have string
want string
}{
struct {
have string
want string
}{"$end", "EOF"},
struct {
have string
want string
}{"LLITERAL", "literal"},
struct {
have string
want string
}{"LASOP", "op="},
struct {
have string
want string
}{"LBREAK", "break"},
struct {
have string
want string
}{"LCASE", "case"},
struct {
have string
want string
}{"LCHAN", "chan"},
struct {
have string
want string
}{"LCOLAS", ":="},
struct {
have string
want string
}{"LCONST", "const"},
struct {
have string
want string
}{"LCONTINUE", "continue"},
struct {
have string
want string
}{"LDDD", "..."},
struct {
have string
want string
}{"LDEFAULT", "default"},
struct {
have string
want string
}{"LDEFER", "defer"},
struct {
have string
want string
}{"LELSE", "else"},
struct {
have string
want string
}{"LFALL", "fallthrough"},
struct {
have string
want string
}{"LFOR", "for"},
struct {
have string
want string
}{"LFUNC", "func"},
struct {
have string
want string
}{"LGO", "go"},
struct {
have string
want string
}{"LGOTO", "goto"},
struct {
have string
want string
}{"LIF", "if"},
struct {
have string
want string
}{"LIMPORT", "import"},
struct {
have string
want string
}{"LINTERFACE", "interface"},
struct {
have string
want string
}{"LMAP", "map"},
struct {
have string
want string
}{"LNAME", "name"},
struct {
have string
want string
}{"LPACKAGE", "package"},
struct {
have string
want string
}{"LRANGE", "range"},
struct {
have string
want string
}{"LRETURN", "return"},
struct {
have string
want string
}{"LSELECT", "select"},
struct {
have string
want string
}{"LSTRUCT", "struct"},
struct {
have string
want string
}{"LSWITCH", "switch"},
struct {
have string
want string
}{"LTYPE", "type"},
struct {
have string
want string
}{"LVAR", "var"},
struct {
have string
want string
}{"LANDAND", "&&"},
struct {
have string
want string
}{"LANDNOT", "&^"},
struct {
have string
want string
}{"LBODY", "{"},
struct {
have string
want string
}{"LCOMM", "<-"},
struct {
have string
want string
}{"LDEC", "--"},
struct {
have string
want string
}{"LINC", "++"},
struct {
have string
want string
}{"LEQ", "=="},
struct {
have string
want string
}{"LGE", ">="},
struct {
have string
want string
}{"LGT", ">"},
struct {
have string
want string
}{"LLE", "<="},
struct {
have string
want string
}{"LLT", "<"},
struct {
have string
want string
}{"LLSH", "<<"},
struct {
have string
want string
}{"LRSH", ">>"},
struct {
have string
want string
}{"LOROR", "||"},
struct {
have string
want string
}{"LNE", "!="},
// spell out to avoid confusion with punctuation in error messages
struct {
have string
want string
}{"';'", "semicolon or newline"},
struct {
have string
want string
}{"','", "comma"},
}
func pkgnotused(lineno int, path_ *Strlit, 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_.S
if i := strings.LastIndex(elem, "/"); i >= 0 {
elem = elem[i+1:]
}
if name == "" || elem == name {
yyerrorl(int(lineno), "imported and not used: \"%v\"", Zconv(path_, 0))
} else {
yyerrorl(int(lineno), "imported and not used: \"%v\" as %s", Zconv(path_, 0), 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)
}
var s *Sym
for h := int32(0); h < NHASH; h++ {
for s = hash[h]; s != nil; s = s.Link {
if s.Def == nil || s.Pkg != localpkg {
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 == 0 && nsyntaxerrors == 0 {
pkgnotused(int(s.Def.Lineno), s.Def.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.Pack != nil && s.Def.Pack.Used == 0 && nsyntaxerrors == 0 {
pkgnotused(int(s.Def.Pack.Lineno), s.Def.Pack.Pkg.Path, "")
s.Def.Pack.Used = 1
}
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:]
}
}
namebuf = p
if i := strings.LastIndex(namebuf, "."); i >= 0 {
namebuf = namebuf[:i]
}
outfile = fmt.Sprintf("%s.%c", namebuf, Thearch.Thechar)
}
}