summaryrefslogtreecommitdiff
path: root/src/cmd/gc/lex.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/lex.c')
-rw-r--r--src/cmd/gc/lex.c390
1 files changed, 230 insertions, 160 deletions
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 624dfb0b4..68ae6864d 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -30,6 +30,8 @@ static void addidir(char*);
static int getlinepragma(void);
static char *goos, *goarch, *goroot;
+#define BOM 0xFEFF
+
// Compiler experiments.
// These are controlled by the GOEXPERIMENT environment
// variable recorded when the compiler is built.
@@ -38,6 +40,7 @@ static struct {
int *val;
} exper[] = {
// {"rune32", &rune32},
+ {"fieldtrack", &fieldtrack_enabled},
{nil, nil},
};
@@ -96,7 +99,7 @@ yy_isdigit(int c)
static int
yy_isspace(int c)
{
- return c >= 0 && c <= 0xFF && isspace(c);
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
}
static int
@@ -130,42 +133,8 @@ enum
void
usage(void)
{
- print("gc: usage: %cg [flags] file.go...\n", thechar);
- print("flags:\n");
- // -A allow use of "any" type, for bootstrapping
- // -B disable bounds checking
- // -E print imported declarations
- // -K warn when lineno is zero
- // -M print arguments to gmove
- // -P print peephole diagnostics
- // -R print optimizer diagnostics
- // -g print code generation diagnostics
- // -i print line history
- // -j print variables to be initialized at runtime
- // -r print generated helper functions
- // -s print redundant types in composite literals
- // -v print more information with -P or -R
- // -y print declarations in cannedimports (used with -d)
- // -% print non-static initializers
- // -+ indicate that the runtime is being compiled
- print(" -D PATH interpret local imports relative to this import path\n");
- print(" -I DIR search for packages in DIR\n");
- print(" -L show full path in file:line prints\n");
- print(" -N disable optimizations\n");
- print(" -S print the assembly language\n");
- print(" -V print the compiler version\n");
- print(" -W print the parse tree after typing\n");
- print(" -d print declarations\n");
- print(" -e no limit on number of errors printed\n");
- print(" -f print stack frame structure\n");
- print(" -h panic on an error\n");
- print(" -l disable inlining\n");
- print(" -m print optimization decisions\n");
- print(" -o file specify output file\n");
- print(" -p assumed import path for this code\n");
- print(" -u disable package unsafe\n");
- print(" -w print type checking details\n");
- print(" -x print lex tokens\n");
+ print("usage: %cg [options] file.go...\n", thechar);
+ flagprint(1);
exits("usage");
}
@@ -183,11 +152,23 @@ fault(int s)
fatal("fault");
}
+void
+doversion(void)
+{
+ char *p;
+
+ p = expstring();
+ if(strcmp(p, "X:none") == 0)
+ p = "";
+ print("%cg version %s%s%s\n", thechar, getgoversion(), *p ? " " : "", p);
+ exits(0);
+}
+
int
main(int argc, char *argv[])
{
- int i, c;
- NodeList *l, *batch;
+ int i;
+ NodeList *l;
char *p;
#ifdef SIGBUS
@@ -197,25 +178,41 @@ main(int argc, char *argv[])
localpkg = mkpkg(strlit(""));
localpkg->prefix = "\"\"";
-
+
+ // pseudo-package, for scoping
builtinpkg = mkpkg(strlit("go.builtin"));
+ // pseudo-package, accessed by import "unsafe"
+ unsafepkg = mkpkg(strlit("unsafe"));
+ unsafepkg->name = "unsafe";
+
+ // real package, referred to by generated runtime calls
+ runtimepkg = mkpkg(strlit("runtime"));
+ runtimepkg->name = "runtime";
+
+ // pseudo-packages used in symbol tables
gostringpkg = mkpkg(strlit("go.string"));
gostringpkg->name = "go.string";
gostringpkg->prefix = "go.string"; // not go%2estring
- runtimepkg = mkpkg(strlit("runtime"));
- runtimepkg->name = "runtime";
+ itabpkg = mkpkg(strlit("go.itab"));
+ itabpkg->name = "go.itab";
+ itabpkg->prefix = "go.itab"; // not go%2eitab
- typepkg = mkpkg(strlit("type"));
- typepkg->name = "type";
+ weaktypepkg = mkpkg(strlit("go.weak.type"));
+ weaktypepkg->name = "go.weak.type";
+ weaktypepkg->prefix = "go.weak.type"; // not go%2eweak%2etype
+
+ typelinkpkg = mkpkg(strlit("go.typelink"));
+ typelinkpkg->name = "go.typelink";
+ typelinkpkg->prefix = "go.typelink"; // not go%2etypelink
- weaktypepkg = mkpkg(strlit("weak.type"));
- weaktypepkg->name = "weak.type";
- weaktypepkg->prefix = "weak.type"; // not weak%2etype
+ trackpkg = mkpkg(strlit("go.track"));
+ trackpkg->name = "go.track";
+ trackpkg->prefix = "go.track"; // not go%2etrack
- unsafepkg = mkpkg(strlit("unsafe"));
- unsafepkg->name = "unsafe";
+ typepkg = mkpkg(strlit("type"));
+ typepkg->name = "type";
goroot = getgoroot();
goos = getgoos();
@@ -224,41 +221,55 @@ main(int argc, char *argv[])
setexp();
outfile = nil;
- ARGBEGIN {
- default:
- c = ARGC();
- if(c >= 0 && c < sizeof(debug))
- debug[c]++;
- break;
-
- case 'o':
- outfile = EARGF(usage());
- break;
-
- case 'p':
- myimportpath = EARGF(usage());
- break;
+ flagcount("+", "compiling runtime", &compiling_runtime);
+ flagcount("%", "debug non-static initializers", &debug['%']);
+ flagcount("A", "for bootstrapping, allow 'any' type", &debug['A']);
+ flagcount("B", "disable bounds checking", &debug['B']);
+ flagstr("D", "path: set relative path for local imports", &localimport);
+ flagcount("E", "debug symbol export", &debug['E']);
+ flagfn1("I", "dir: add dir to import search path", addidir);
+ flagcount("K", "debug missing line numbers", &debug['K']);
+ flagcount("L", "use full (long) path in error messages", &debug['L']);
+ flagcount("M", "debug move generation", &debug['M']);
+ flagcount("N", "disable optimizations", &debug['N']);
+ flagcount("P", "debug peephole optimizer", &debug['P']);
+ flagcount("R", "debug register optimizer", &debug['R']);
+ flagcount("S", "print assembly listing", &debug['S']);
+ flagfn0("V", "print compiler version", doversion);
+ flagcount("W", "debug parse tree after type checking", &debug['W']);
+ flagcount("complete", "compiling complete package (no C or assembly)", &pure_go);
+ flagcount("d", "debug declarations", &debug['d']);
+ flagcount("e", "no limit on number of errors reported", &debug['e']);
+ flagcount("f", "debug stack frames", &debug['f']);
+ flagcount("g", "debug code generation", &debug['g']);
+ flagcount("h", "halt on error", &debug['h']);
+ flagcount("i", "debug line number stack", &debug['i']);
+ flagcount("j", "debug runtime-initialized variables", &debug['j']);
+ flagcount("l", "disable inlining", &debug['l']);
+ flagcount("m", "print optimization decisions", &debug['m']);
+ flagstr("o", "obj: set output file", &outfile);
+ flagstr("p", "path: set expected package import path", &myimportpath);
+ flagcount("r", "debug generated wrappers", &debug['r']);
+ flagcount("race", "enable race detector", &flag_race);
+ flagcount("s", "warn about composite literals that can be simplified", &debug['s']);
+ flagcount("u", "reject unsafe code", &safemode);
+ flagcount("v", "increase debug verbosity", &debug['v']);
+ flagcount("w", "debug type checking", &debug['w']);
+ flagcount("x", "debug lexer", &debug['x']);
+ flagcount("y", "debug declarations in canned imports (with -d)", &debug['y']);
+ if(thechar == '6')
+ flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel);
+
+ flagparse(&argc, &argv, usage);
- case 'u':
- safemode = 1;
- break;
+ if(argc < 1)
+ usage();
- case 'D':
- localimport = EARGF(usage());
- break;
+ if(flag_race) {
+ racepkg = mkpkg(strlit("runtime/race"));
+ racepkg->name = "race";
+ }
- case 'I':
- addidir(EARGF(usage()));
- break;
-
- case 'V':
- p = expstring();
- if(strcmp(p, "X:none") == 0)
- p = "";
- print("%cg version %s%s%s\n", thechar, getgoversion(), *p ? " " : "", p);
- exits(0);
- } ARGEND
-
// enable inlining. for now:
// default: inlining on. (debug['l'] == 1)
// -l: inlining off (debug['l'] == 0)
@@ -266,11 +277,15 @@ main(int argc, char *argv[])
if(debug['l'] <= 1)
debug['l'] = 1 - debug['l'];
- if(argc < 1)
- usage();
-
- // special flag to detect compilation of package runtime
- compiling_runtime = debug['+'];
+ if(thechar == '8') {
+ p = getgo386();
+ if(strcmp(p, "387") == 0)
+ use_sse = 0;
+ else if(strcmp(p, "sse2") == 0)
+ use_sse = 1;
+ else
+ sysfatal("unsupported setting GO386=%s", p);
+ }
pathname = mal(1000);
if(getwd(pathname, 999) == 0)
@@ -315,6 +330,10 @@ main(int argc, char *argv[])
curio.peekc1 = 0;
curio.nlsemi = 0;
+ // Skip initial BOM if present.
+ if(Bgetrune(curio.bin) != BOM)
+ Bungetrune(curio.bin);
+
block = 1;
iota = -1000000;
@@ -335,6 +354,7 @@ main(int argc, char *argv[])
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.
@@ -367,7 +387,7 @@ main(int argc, char *argv[])
errorexit();
// Phase 4: Inlining
- if (debug['l'] > 1) {
+ if(debug['l'] > 1) {
// Typecheck imported function bodies if debug['l'] > 1,
// otherwise lazily when used or re-exported.
for(l=importlist; l; l=l->next)
@@ -380,7 +400,7 @@ main(int argc, char *argv[])
errorexit();
}
- if (debug['l']) {
+ if(debug['l']) {
// Find functions that can be inlined and clone them before walk expands them.
for(l=xtop; l; l=l->next)
if(l->n->op == ODCLFUNC)
@@ -392,7 +412,7 @@ main(int argc, char *argv[])
inlcalls(l->n);
}
- // Phase 5: escape analysis.
+ // Phase 5: Escape analysis.
if(!debug['N'])
escapes(xtop);
@@ -404,21 +424,7 @@ main(int argc, char *argv[])
if(nsavederrors+nerrors == 0)
fninit(xtop);
- // Phase 6b: Compile all closures.
- // Can generate more closures, so run in batches.
- while(closures) {
- batch = closures;
- closures = nil;
- if(debug['l'])
- for(l=batch; l; l=l->next)
- inlcalls(l->n);
- if(!debug['N'])
- escapes(batch);
- for(l=batch; l; l=l->next)
- funccompile(l->n, 1);
- }
-
- // Phase 7: check external declarations.
+ // Phase 7: Check external declarations.
for(l=externdcl; l; l=l->next)
if(l->n->op == ONAME)
typecheck(&l->n, Erv);
@@ -483,7 +489,7 @@ skiptopkgdef(Biobuf *b)
if(memcmp(p, "!<arch>\n", 8) != 0)
return 0;
/* symbol table is first; skip it */
- sz = arsize(b, "__.SYMDEF");
+ sz = arsize(b, "__.GOSYMDEF");
if(sz < 0)
return 0;
Bseek(b, sz, 1);
@@ -533,7 +539,7 @@ static int
findpkg(Strlit *name)
{
Idir *p;
- char *q;
+ char *q, *race;
if(islocalname(name)) {
if(safemode)
@@ -571,10 +577,13 @@ findpkg(Strlit *name)
return 1;
}
if(goroot != nil) {
- snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s/%Z.a", goroot, goos, goarch, name);
+ race = "";
+ if(flag_race)
+ race = "_race";
+ snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s/%Z.a", goroot, goos, goarch, race, name);
if(access(namebuf, 0) >= 0)
return 1;
- snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s/%Z.%c", goroot, goos, goarch, name, thechar);
+ snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s/%Z.%c", goroot, goos, goarch, race, name, thechar);
if(access(namebuf, 0) >= 0)
return 1;
}
@@ -659,6 +668,11 @@ importfile(Val *f, int line)
strcat(cleanbuf, path->s);
cleanname(cleanbuf);
path = strlit(cleanbuf);
+
+ if(isbadimport(path)) {
+ fakeimport();
+ return;
+ }
}
if(!findpkg(path)) {
@@ -667,6 +681,16 @@ importfile(Val *f, int line)
}
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) {
+ file = strdup(namebuf);
+ p = smprint("package %s\n$$\n", importpkg->name);
+ cannedimports(file, p);
+ return;
+ }
+ importpkg->imported = 1;
+
imp = Bopen(namebuf, OREAD);
if(imp == nil) {
yyerror("can't open import: \"%Z\": %r", f->u.sval);
@@ -767,12 +791,8 @@ static int
isfrog(int c)
{
// complain about possibly invisible control characters
- if(c < 0)
- return 1;
if(c < ' ') {
- if(c == '\n' || c== '\r' || c == '\t') // good white space
- return 0;
- return 1;
+ return !yy_isspace(c); // exclude good white space
}
if(0x7f <= c && c <= 0xa0) // DEL, unicode block including unbreakable space.
return 1;
@@ -982,6 +1002,7 @@ l0:
c1 = getc();
if(c1 == '=') {
c = LCOLAS;
+ yylval.i = lexlineno;
goto lx;
}
break;
@@ -1145,6 +1166,11 @@ l0:
case '[':
if(loophack || lstk != nil) {
h = malloc(sizeof *h);
+ if(h == nil) {
+ flusherrors();
+ yyerror("out of memory");
+ errorexit();
+ }
h->v = loophack;
h->next = lstk;
lstk = h;
@@ -1208,7 +1234,7 @@ talph:
rune = getr();
// 0xb7 ยท is used for internal names
if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7))
- yyerror("invalid identifier character 0x%ux", rune);
+ yyerror("invalid identifier character U+%04x", rune);
cp += runetochar(cp, &rune);
} else if(!yy_isalnum(c) && c != '_')
break;
@@ -1270,12 +1296,14 @@ tnum:
continue;
if(cp == lexbuf+2)
yyerror("malformed hex constant");
+ if(c == 'p')
+ goto caseep;
goto ncu;
}
}
if(c == 'p') // 0p begins floating point zero
- goto casep;
+ goto caseep;
c1 = 0;
for(;;) {
@@ -1293,7 +1321,7 @@ tnum:
if(c == '.')
goto casedot;
if(c == 'e' || c == 'E')
- goto casee;
+ goto caseep;
if(c == 'i')
goto casei;
if(c1)
@@ -1303,10 +1331,8 @@ tnum:
dc:
if(c == '.')
goto casedot;
- if(c == 'e' || c == 'E')
- goto casee;
- if(c == 'p' || c == 'P')
- goto casep;
+ if(c == 'e' || c == 'E' || c == 'p' || c == 'P')
+ goto caseep;
if(c == 'i')
goto casei;
@@ -1342,29 +1368,8 @@ casedot:
if(c != 'e' && c != 'E')
goto caseout;
-casee:
- *cp++ = 'e';
- c = getc();
- if(c == '+' || c == '-') {
- *cp++ = c;
- c = getc();
- }
- if(!yy_isdigit(c))
- yyerror("malformed fp constant exponent");
- while(yy_isdigit(c)) {
- if(cp+10 >= ep) {
- yyerror("identifier too long");
- errorexit();
- }
- *cp++ = c;
- c = getc();
- }
- if(c == 'i')
- goto casei;
- goto caseout;
-
-casep:
- *cp++ = 'p';
+caseep:
+ *cp++ = c;
c = getc();
if(c == '+' || c == '-') {
*cp++ = c;
@@ -1430,7 +1435,12 @@ getlinepragma(void)
char *cp, *ep, *linep;
Hist *h;
- for(i=0; i<5; i++) {
+ c = getr();
+ if(c == 'g')
+ goto go;
+ if(c != 'l')
+ goto out;
+ for(i=1; i<5; i++) {
c = getr();
if(c != "line "[i])
goto out;
@@ -1478,7 +1488,35 @@ getlinepragma(void)
}
}
linehist(strdup(lexbuf), n, 0);
+ goto out;
+
+go:
+ cp = lexbuf;
+ ep = lexbuf+sizeof(lexbuf)-5;
+ *cp++ = 'g'; // already read
+ for(;;) {
+ c = getr();
+ if(c == EOF || c >= Runeself)
+ goto out;
+ if(c == '\n')
+ break;
+ if(cp < ep)
+ *cp++ = c;
+ }
+ *cp = 0;
+ ep = strchr(lexbuf, ' ');
+ if(ep != nil)
+ *ep = 0;
+ if(strcmp(lexbuf, "go:nointerface") == 0 && fieldtrack_enabled) {
+ nointerface = 1;
+ goto out;
+ }
+ if(strcmp(lexbuf, "go:noescape") == 0) {
+ noescape = 1;
+ goto out;
+ }
+
out:
return c;
}
@@ -1524,24 +1562,35 @@ yylex(void)
static int
getc(void)
{
- int c;
+ int c, c1, c2;
c = curio.peekc;
if(c != 0) {
curio.peekc = curio.peekc1;
curio.peekc1 = 0;
- if(c == '\n' && pushedio.bin == nil)
- lexlineno++;
- return c;
+ goto check;
}
if(curio.bin == nil) {
c = *curio.cp & 0xff;
if(c != 0)
curio.cp++;
- } else
+ } else {
+ loop:
c = Bgetc(curio.bin);
+ if(c == 0xef) {
+ c1 = Bgetc(curio.bin);
+ c2 = Bgetc(curio.bin);
+ if(c1 == 0xbb && c2 == 0xbf) {
+ yyerrorl(lexlineno, "Unicode (UTF-8) BOM in middle of file");
+ goto loop;
+ }
+ Bungetc(curio.bin);
+ Bungetc(curio.bin);
+ }
+ }
+check:
switch(c) {
case 0:
if(curio.bin != nil) {
@@ -1820,16 +1869,16 @@ lexinit(void)
if(etype != Txxx) {
if(etype < 0 || etype >= nelem(types))
fatal("lexinit: %s bad etype", s->name);
+ s1 = pkglookup(syms[i].name, builtinpkg);
t = types[etype];
if(t == T) {
t = typ(etype);
- t->sym = s;
+ t->sym = s1;
if(etype != TANY && etype != TSTRING)
dowidth(t);
types[etype] = t;
}
- s1 = pkglookup(syms[i].name, builtinpkg);
s1->lexical = LNAME;
s1->def = typenod(t);
continue;
@@ -1959,8 +2008,10 @@ lexfini(void)
s->lexical = lex;
etype = syms[i].etype;
- if(etype != Txxx && (etype != TANY || debug['A']) && s->def == N)
+ if(etype != Txxx && (etype != TANY || debug['A']) && s->def == N) {
s->def = typenod(types[etype]);
+ s->origpkg = builtinpkg;
+ }
etype = syms[i].op;
if(etype != OXXX && s->def == N) {
@@ -1968,54 +2019,68 @@ lexfini(void)
s->def->sym = s;
s->def->etype = etype;
s->def->builtin = 1;
+ s->origpkg = builtinpkg;
}
}
+ // backend-specific builtin types (e.g. int).
for(i=0; typedefs[i].name; i++) {
s = lookup(typedefs[i].name);
- if(s->def == N)
+ if(s->def == N) {
s->def = typenod(types[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 == N)
+ if(s->def == N) {
s->def = typenod(bytetype);
-
+ s->origpkg = builtinpkg;
+ }
+
s = lookup("error");
- if(s->def == N)
+ if(s->def == N) {
s->def = typenod(errortype);
+ s->origpkg = builtinpkg;
+ }
s = lookup("rune");
- if(s->def == N)
+ if(s->def == N) {
s->def = typenod(runetype);
+ s->origpkg = builtinpkg;
+ }
s = lookup("nil");
if(s->def == N) {
v.ctype = CTNIL;
s->def = nodlit(v);
s->def->sym = s;
+ s->origpkg = builtinpkg;
}
-
+
s = lookup("iota");
if(s->def == N) {
s->def = nod(OIOTA, N, N);
s->def->sym = s;
+ s->origpkg = builtinpkg;
}
s = lookup("true");
if(s->def == N) {
s->def = nodbool(1);
s->def->sym = s;
+ s->origpkg = builtinpkg;
}
s = lookup("false");
if(s->def == N) {
s->def = nodbool(0);
s->def->sym = s;
+ s->origpkg = builtinpkg;
}
-
+
nodfp = nod(ONAME, N, N);
nodfp->type = types[TINT32];
nodfp->xoffset = 0;
@@ -2179,7 +2244,7 @@ mkpackage(char* pkgname)
{
Sym *s;
int32 h;
- char *p;
+ char *p, *q;
if(localpkg->name == nil) {
if(strcmp(pkgname, "_") == 0)
@@ -2219,6 +2284,11 @@ mkpackage(char* pkgname)
if(outfile == nil) {
p = strrchr(infile, '/');
+ if(windows) {
+ q = strrchr(infile, '\\');
+ if(q > p)
+ p = q;
+ }
if(p == nil)
p = infile;
else