2008-06-04 15:37:38 -06:00
|
|
|
// 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.
|
|
|
|
|
2011-08-25 14:25:10 -06:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
2008-06-04 15:37:38 -06:00
|
|
|
#include "go.h"
|
|
|
|
#include "y.tab.h"
|
2011-06-07 10:57:26 -06:00
|
|
|
#include <ar.h>
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
#undef getc
|
|
|
|
#undef ungetc
|
|
|
|
#define getc ccgetc
|
|
|
|
#define ungetc ccungetc
|
|
|
|
|
2009-06-06 20:27:48 -06:00
|
|
|
extern int yychar;
|
2010-04-27 18:19:15 -06:00
|
|
|
int windows;
|
2010-07-15 16:05:56 -06:00
|
|
|
int yyprev;
|
|
|
|
int yylast;
|
2010-04-27 18:19:15 -06:00
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static void lexinit(void);
|
2011-10-18 12:55:50 -06:00
|
|
|
static void lexinit1(void);
|
2010-06-14 12:24:51 -06:00
|
|
|
static void lexfini(void);
|
|
|
|
static void yytinit(void);
|
|
|
|
static int getc(void);
|
|
|
|
static void ungetc(int);
|
|
|
|
static int32 getr(void);
|
|
|
|
static int escchar(int, int*, vlong*);
|
|
|
|
static void addidir(char*);
|
2010-07-15 21:21:33 -06:00
|
|
|
static int getlinepragma(void);
|
2010-01-22 18:06:20 -07:00
|
|
|
static char *goos, *goarch, *goroot;
|
2009-06-06 20:27:48 -06:00
|
|
|
|
2011-10-25 23:19:39 -06:00
|
|
|
// Compiler experiments.
|
2011-11-01 23:25:24 -06:00
|
|
|
// These are controlled by the GOEXPERIMENT environment
|
2011-10-25 23:19:39 -06:00
|
|
|
// variable recorded when the compiler is built.
|
|
|
|
static struct {
|
|
|
|
char *name;
|
|
|
|
int *val;
|
|
|
|
} exper[] = {
|
2011-12-08 22:12:07 -07:00
|
|
|
// {"rune32", &rune32},
|
2011-12-12 14:25:31 -07:00
|
|
|
{nil, nil},
|
2011-10-25 23:19:39 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
addexp(char *s)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2011-12-12 14:25:31 -07:00
|
|
|
for(i=0; exper[i].name != nil; i++) {
|
2011-10-25 23:19:39 -06:00
|
|
|
if(strcmp(exper[i].name, s) == 0) {
|
|
|
|
*exper[i].val = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
print("unknown experiment %s\n", s);
|
|
|
|
exits("unknown experiment");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
setexp(void)
|
|
|
|
{
|
|
|
|
char *f[20];
|
|
|
|
int i, nf;
|
|
|
|
|
|
|
|
// The makefile #defines GOEXPERIMENT for us.
|
|
|
|
nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ",");
|
|
|
|
for(i=0; i<nf; i++)
|
|
|
|
addexp(f[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
char*
|
|
|
|
expstring(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
static char buf[512];
|
|
|
|
|
|
|
|
strcpy(buf, "X");
|
2011-12-12 14:25:31 -07:00
|
|
|
for(i=0; exper[i].name != nil; i++)
|
2011-10-25 23:19:39 -06:00
|
|
|
if(*exper[i].val)
|
|
|
|
seprint(buf+strlen(buf), buf+sizeof buf, ",%s", exper[i].name);
|
|
|
|
if(strlen(buf) == 1)
|
|
|
|
strcpy(buf, "X,none");
|
|
|
|
buf[1] = ':';
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2010-07-21 00:45:33 -06:00
|
|
|
// Our own isdigit, isspace, isalpha, isalnum that take care
|
|
|
|
// of EOF and other out of range arguments.
|
|
|
|
static int
|
|
|
|
yy_isdigit(int c)
|
|
|
|
{
|
|
|
|
return c >= 0 && c <= 0xFF && isdigit(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
yy_isspace(int c)
|
|
|
|
{
|
|
|
|
return c >= 0 && c <= 0xFF && isspace(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
yy_isalpha(int c)
|
|
|
|
{
|
|
|
|
return c >= 0 && c <= 0xFF && isalpha(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
yy_isalnum(int c)
|
|
|
|
{
|
|
|
|
return c >= 0 && c <= 0xFF && isalnum(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disallow use of isdigit etc.
|
|
|
|
#undef isdigit
|
|
|
|
#undef isspace
|
|
|
|
#undef isalpha
|
|
|
|
#undef isalnum
|
|
|
|
#define isdigit use_yy_isdigit_instead_of_isdigit
|
|
|
|
#define isspace use_yy_isspace_instead_of_isspace
|
|
|
|
#define isalpha use_yy_isalpha_instead_of_isalpha
|
|
|
|
#define isalnum use_yy_isalnum_instead_of_isalnum
|
|
|
|
|
2011-08-29 07:35:04 -06:00
|
|
|
#define DBG if(!debug['x']){}else print
|
2008-06-04 15:37:38 -06:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
EOF = -1,
|
|
|
|
};
|
|
|
|
|
2010-06-09 12:00:55 -06:00
|
|
|
void
|
|
|
|
usage(void)
|
|
|
|
{
|
2010-07-12 17:31:51 -06:00
|
|
|
print("gc: usage: %cg [flags] file.go...\n", thechar);
|
2010-06-09 12:00:55 -06:00
|
|
|
print("flags:\n");
|
2012-02-02 15:02:54 -07:00
|
|
|
// -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
|
cmd/go: fix relative imports again
I tried before to make relative imports work by simply
invoking the compiler in the right directory, so that
an import of ./foo could be resolved by ./foo.a.
This required creating a separate tree of package binaries
that included the full path to the source directory, so that
/home/gopher/bar.go would be compiled in
tmpdir/work/local/home/gopher and perhaps find
a ./foo.a in that directory.
This model breaks on Windows because : appears in path
names but cannot be used in subdirectory names, and I
missed one or two places where it needed to be removed.
The model breaks more fundamentally when compiling
a test of a package that lives outside the Go path, because
we effectively use a ./ import in the generated testmain,
but there we want to be able to resolve the ./ import
of the test package to one directory and all the other ./
imports to a different directory. Piggybacking on the compiler's
current working directory is then no longer possible.
Instead, introduce a new compiler option -D prefix that
makes the compiler turn a ./ import into prefix+that,
so that import "./foo" with -D a/b/c turns into import
"a/b/c/foo". Then we can invent a package hierarchy
"_/" with subdirectories named for file system paths:
import "./foo" in the directory /home/gopher becomes
import "_/home/gopher/foo", and since that final path
is just an ordinary import now, all the ordinary processing
works, without special cases.
We will have to change the name of the hierarchy if we
ever decide to introduce a standard package with import
path "_", but that seems unlikely, and the detail is known
only in temporary packages that get thrown away at the
end of a build.
Fixes #3169.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5732045
2012-03-02 20:16:02 -07:00
|
|
|
print(" -D PATH interpret local imports relative to this import path\n");
|
2010-06-09 12:00:55 -06:00
|
|
|
print(" -I DIR search for packages in DIR\n");
|
2011-08-28 10:05:00 -06:00
|
|
|
print(" -L show full path in file:line prints\n");
|
2012-02-02 15:02:54 -07:00
|
|
|
print(" -N disable optimizations\n");
|
2011-08-28 10:05:00 -06:00
|
|
|
print(" -S print the assembly language\n");
|
|
|
|
print(" -V print the compiler version\n");
|
2011-12-07 09:45:30 -07:00
|
|
|
print(" -W print the parse tree after typing\n");
|
2010-06-09 12:00:55 -06:00
|
|
|
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");
|
2012-02-02 15:02:54 -07:00
|
|
|
print(" -l disable inlining\n");
|
|
|
|
print(" -m print optimization decisions\n");
|
2010-06-09 12:00:55 -06:00
|
|
|
print(" -o file specify output file\n");
|
2011-09-07 13:50:21 -06:00
|
|
|
print(" -p assumed import path for this code\n");
|
2010-06-09 12:00:55 -06:00
|
|
|
print(" -u disable package unsafe\n");
|
2011-12-07 09:45:30 -07:00
|
|
|
print(" -w print type checking details\n");
|
2010-06-09 12:00:55 -06:00
|
|
|
print(" -x print lex tokens\n");
|
2011-10-25 23:19:39 -06:00
|
|
|
exits("usage");
|
2010-06-09 12:00:55 -06:00
|
|
|
}
|
|
|
|
|
2010-07-26 17:52:51 -06:00
|
|
|
void
|
|
|
|
fault(int s)
|
|
|
|
{
|
2011-08-25 14:08:13 -06:00
|
|
|
USED(s);
|
|
|
|
|
2010-07-26 17:52:51 -06:00
|
|
|
// If we've already complained about things
|
|
|
|
// in the program, don't bother complaining
|
|
|
|
// about the seg fault too; let the user clean up
|
|
|
|
// the code and try again.
|
2011-06-17 13:25:05 -06:00
|
|
|
if(nsavederrors + nerrors > 0)
|
2010-07-26 17:52:51 -06:00
|
|
|
errorexit();
|
|
|
|
fatal("fault");
|
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
int
|
2009-03-30 18:09:28 -06:00
|
|
|
main(int argc, char *argv[])
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-12 14:18:19 -06:00
|
|
|
int i, c;
|
2012-02-23 21:09:53 -07:00
|
|
|
NodeList *l, *batch;
|
2010-04-27 14:52:43 -06:00
|
|
|
char *p;
|
2011-08-29 07:35:04 -06:00
|
|
|
|
|
|
|
#ifdef SIGBUS
|
2010-07-26 17:52:51 -06:00
|
|
|
signal(SIGBUS, fault);
|
|
|
|
signal(SIGSEGV, fault);
|
2011-08-29 07:35:04 -06:00
|
|
|
#endif
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2010-01-22 18:06:20 -07:00
|
|
|
localpkg = mkpkg(strlit(""));
|
|
|
|
localpkg->prefix = "\"\"";
|
|
|
|
|
|
|
|
builtinpkg = mkpkg(strlit("go.builtin"));
|
2010-01-24 23:36:26 -07:00
|
|
|
|
2010-01-22 18:06:20 -07:00
|
|
|
gostringpkg = mkpkg(strlit("go.string"));
|
2010-01-24 23:36:26 -07:00
|
|
|
gostringpkg->name = "go.string";
|
|
|
|
gostringpkg->prefix = "go.string"; // not go%2estring
|
|
|
|
|
2010-01-22 18:06:20 -07:00
|
|
|
runtimepkg = mkpkg(strlit("runtime"));
|
2010-01-24 23:36:26 -07:00
|
|
|
runtimepkg->name = "runtime";
|
|
|
|
|
2010-01-22 18:06:20 -07:00
|
|
|
typepkg = mkpkg(strlit("type"));
|
2010-01-24 23:36:26 -07:00
|
|
|
typepkg->name = "type";
|
|
|
|
|
2012-02-12 21:26:20 -07:00
|
|
|
weaktypepkg = mkpkg(strlit("weak.type"));
|
|
|
|
weaktypepkg->name = "weak.type";
|
|
|
|
weaktypepkg->prefix = "weak.type"; // not weak%2etype
|
|
|
|
|
2010-01-22 18:06:20 -07:00
|
|
|
unsafepkg = mkpkg(strlit("unsafe"));
|
2010-01-24 23:36:26 -07:00
|
|
|
unsafepkg->name = "unsafe";
|
2010-01-22 18:06:20 -07:00
|
|
|
|
|
|
|
goroot = getgoroot();
|
|
|
|
goos = getgoos();
|
|
|
|
goarch = thestring;
|
2011-10-25 23:19:39 -06:00
|
|
|
|
|
|
|
setexp();
|
2010-01-22 18:06:20 -07:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
outfile = nil;
|
|
|
|
ARGBEGIN {
|
|
|
|
default:
|
|
|
|
c = ARGC();
|
|
|
|
if(c >= 0 && c < sizeof(debug))
|
|
|
|
debug[c]++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'o':
|
2010-06-09 12:00:55 -06:00
|
|
|
outfile = EARGF(usage());
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2011-09-07 13:50:21 -06:00
|
|
|
|
|
|
|
case 'p':
|
|
|
|
myimportpath = EARGF(usage());
|
|
|
|
break;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2010-06-09 12:00:55 -06:00
|
|
|
case 'u':
|
|
|
|
safemode = 1;
|
2009-03-10 21:03:31 -06:00
|
|
|
break;
|
2010-06-09 12:00:55 -06:00
|
|
|
|
cmd/go: fix relative imports again
I tried before to make relative imports work by simply
invoking the compiler in the right directory, so that
an import of ./foo could be resolved by ./foo.a.
This required creating a separate tree of package binaries
that included the full path to the source directory, so that
/home/gopher/bar.go would be compiled in
tmpdir/work/local/home/gopher and perhaps find
a ./foo.a in that directory.
This model breaks on Windows because : appears in path
names but cannot be used in subdirectory names, and I
missed one or two places where it needed to be removed.
The model breaks more fundamentally when compiling
a test of a package that lives outside the Go path, because
we effectively use a ./ import in the generated testmain,
but there we want to be able to resolve the ./ import
of the test package to one directory and all the other ./
imports to a different directory. Piggybacking on the compiler's
current working directory is then no longer possible.
Instead, introduce a new compiler option -D prefix that
makes the compiler turn a ./ import into prefix+that,
so that import "./foo" with -D a/b/c turns into import
"a/b/c/foo". Then we can invent a package hierarchy
"_/" with subdirectories named for file system paths:
import "./foo" in the directory /home/gopher becomes
import "_/home/gopher/foo", and since that final path
is just an ordinary import now, all the ordinary processing
works, without special cases.
We will have to change the name of the hierarchy if we
ever decide to introduce a standard package with import
path "_", but that seems unlikely, and the detail is known
only in temporary packages that get thrown away at the
end of a build.
Fixes #3169.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5732045
2012-03-02 20:16:02 -07:00
|
|
|
case 'D':
|
|
|
|
localimport = EARGF(usage());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'I':
|
|
|
|
addidir(EARGF(usage()));
|
|
|
|
break;
|
|
|
|
|
2010-02-08 10:46:53 -07:00
|
|
|
case 'V':
|
2011-10-25 23:19:39 -06:00
|
|
|
p = expstring();
|
|
|
|
if(strcmp(p, "X:none") == 0)
|
|
|
|
p = "";
|
2011-10-26 01:16:46 -06:00
|
|
|
print("%cg version %s%s%s\n", thechar, getgoversion(), *p ? " " : "", p);
|
2011-08-29 07:35:04 -06:00
|
|
|
exits(0);
|
2008-06-04 15:37:38 -06:00
|
|
|
} ARGEND
|
2012-01-10 21:08:53 -07:00
|
|
|
|
|
|
|
// 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'];
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-12 14:18:19 -06:00
|
|
|
if(argc < 1)
|
2010-06-09 12:00:55 -06:00
|
|
|
usage();
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2010-01-25 00:33:59 -07:00
|
|
|
// special flag to detect compilation of package runtime
|
|
|
|
compiling_runtime = debug['+'];
|
|
|
|
|
2009-11-11 13:00:41 -07:00
|
|
|
pathname = mal(1000);
|
|
|
|
if(getwd(pathname, 999) == 0)
|
2008-06-13 19:16:23 -06:00
|
|
|
strcpy(pathname, "/???");
|
|
|
|
|
2010-07-21 00:45:33 -06:00
|
|
|
if(yy_isalpha(pathname[0]) && pathname[1] == ':') {
|
2010-04-27 18:19:15 -06:00
|
|
|
// On Windows.
|
|
|
|
windows = 1;
|
|
|
|
|
2010-04-27 14:52:43 -06:00
|
|
|
// Canonicalize path by converting \ to / (Windows accepts both).
|
|
|
|
for(p=pathname; *p; p++)
|
|
|
|
if(*p == '\\')
|
|
|
|
*p = '/';
|
|
|
|
}
|
|
|
|
|
2011-10-31 11:09:40 -06:00
|
|
|
fmtinstallgo();
|
2009-03-30 18:09:28 -06:00
|
|
|
betypeinit();
|
2010-12-13 09:57:41 -07:00
|
|
|
if(widthptr == 0)
|
2009-03-30 18:09:28 -06:00
|
|
|
fatal("betypeinit failed");
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
lexinit();
|
2009-06-06 13:46:38 -06:00
|
|
|
typeinit();
|
2011-10-18 12:55:50 -06:00
|
|
|
lexinit1();
|
2010-01-27 00:13:22 -07:00
|
|
|
yytinit();
|
2009-03-30 18:09:28 -06:00
|
|
|
|
2008-06-21 16:11:29 -06:00
|
|
|
blockgen = 1;
|
2009-08-12 14:18:19 -06:00
|
|
|
dclcontext = PEXTERN;
|
|
|
|
nerrors = 0;
|
2009-08-19 16:18:08 -06:00
|
|
|
lexlineno = 1;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-12 14:18:19 -06:00
|
|
|
for(i=0; i<argc; i++) {
|
|
|
|
infile = argv[i];
|
|
|
|
linehist(infile, 0, 0);
|
|
|
|
|
|
|
|
curio.infile = infile;
|
|
|
|
curio.bin = Bopen(infile, OREAD);
|
2010-04-11 15:52:06 -06:00
|
|
|
if(curio.bin == nil) {
|
|
|
|
print("open %s: %r\n", infile);
|
|
|
|
errorexit();
|
|
|
|
}
|
2009-08-12 14:18:19 -06:00
|
|
|
curio.peekc = 0;
|
|
|
|
curio.peekc1 = 0;
|
2009-12-11 16:59:41 -07:00
|
|
|
curio.nlsemi = 0;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-12 14:18:19 -06:00
|
|
|
block = 1;
|
2011-07-27 12:45:27 -06:00
|
|
|
iota = -1000000;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-12 14:18:19 -06:00
|
|
|
yyparse();
|
|
|
|
if(nsyntaxerrors != 0)
|
|
|
|
errorexit();
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-12 14:18:19 -06:00
|
|
|
linehist(nil, 0, 0);
|
|
|
|
if(curio.bin != nil)
|
|
|
|
Bterm(curio.bin);
|
|
|
|
}
|
|
|
|
testdclstack();
|
2010-01-22 18:06:20 -07:00
|
|
|
mkpackage(localpkg->name); // final import not used checks
|
2009-09-09 02:01:39 -06:00
|
|
|
lexfini();
|
2009-08-12 14:18:19 -06:00
|
|
|
|
|
|
|
typecheckok = 1;
|
|
|
|
if(debug['f'])
|
|
|
|
frame(1);
|
2010-06-08 19:50:02 -06:00
|
|
|
|
2011-08-24 11:07:08 -06:00
|
|
|
// Process top-level declarations in phases.
|
2010-06-08 19:50:02 -06:00
|
|
|
// 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.
|
2009-08-12 14:18:19 -06:00
|
|
|
defercheckwidth();
|
2010-06-08 19:50:02 -06:00
|
|
|
for(l=xtop; l; l=l->next)
|
|
|
|
if(l->n->op != ODCL && l->n->op != OAS)
|
|
|
|
typecheck(&l->n, Etop);
|
2011-08-24 11:07:08 -06:00
|
|
|
|
|
|
|
// Phase 2: Variable assignments.
|
|
|
|
// To check interface assignments, depends on phase 1.
|
2010-06-08 19:50:02 -06:00
|
|
|
for(l=xtop; l; l=l->next)
|
|
|
|
if(l->n->op == ODCL || l->n->op == OAS)
|
|
|
|
typecheck(&l->n, Etop);
|
2011-04-27 22:13:49 -06:00
|
|
|
resumetypecopy();
|
2009-08-12 14:18:19 -06:00
|
|
|
resumecheckwidth();
|
2011-06-02 10:48:17 -06:00
|
|
|
|
2011-08-24 11:07:08 -06:00
|
|
|
// Phase 3: Type check function bodies.
|
2011-07-28 10:31:16 -06:00
|
|
|
for(l=xtop; l; l=l->next) {
|
2011-07-27 17:31:11 -06:00
|
|
|
if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE) {
|
2011-06-02 10:48:17 -06:00
|
|
|
curfn = l->n;
|
2011-06-17 13:25:05 -06:00
|
|
|
saveerrors();
|
2011-06-02 10:48:17 -06:00
|
|
|
typechecklist(l->n->nbody, Etop);
|
2011-06-17 13:25:05 -06:00
|
|
|
if(nerrors != 0)
|
|
|
|
l->n->nbody = nil; // type errors; do not compile
|
2011-06-02 10:48:17 -06:00
|
|
|
}
|
2011-07-28 10:31:16 -06:00
|
|
|
}
|
|
|
|
|
2011-06-02 10:48:17 -06:00
|
|
|
curfn = nil;
|
2011-07-28 10:31:16 -06:00
|
|
|
|
|
|
|
if(nsavederrors+nerrors)
|
|
|
|
errorexit();
|
2011-06-02 10:48:17 -06:00
|
|
|
|
2011-12-14 07:05:33 -07:00
|
|
|
// Phase 4: Inlining
|
2012-01-10 13:24:31 -07:00
|
|
|
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)
|
|
|
|
if (l->n->inl) {
|
|
|
|
saveerrors();
|
|
|
|
typecheckinl(l->n);
|
|
|
|
}
|
2011-12-14 07:05:33 -07:00
|
|
|
|
|
|
|
if(nsavederrors+nerrors)
|
|
|
|
errorexit();
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
caninl(l->n);
|
|
|
|
|
|
|
|
// Expand inlineable calls in all functions
|
|
|
|
for(l=xtop; l; l=l->next)
|
|
|
|
if(l->n->op == ODCLFUNC)
|
|
|
|
inlcalls(l->n);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Phase 5: escape analysis.
|
2011-12-02 12:13:12 -07:00
|
|
|
if(!debug['N'])
|
2012-02-23 21:09:53 -07:00
|
|
|
escapes(xtop);
|
2011-08-24 11:07:08 -06:00
|
|
|
|
2011-12-14 07:05:33 -07:00
|
|
|
// Phase 6: Compile top level functions.
|
2009-08-12 14:18:19 -06:00
|
|
|
for(l=xtop; l; l=l->next)
|
|
|
|
if(l->n->op == ODCLFUNC)
|
2010-03-31 12:46:01 -06:00
|
|
|
funccompile(l->n, 0);
|
2011-06-02 10:48:17 -06:00
|
|
|
|
2011-06-17 13:25:05 -06:00
|
|
|
if(nsavederrors+nerrors == 0)
|
2009-08-12 14:18:19 -06:00
|
|
|
fninit(xtop);
|
2011-06-02 10:48:17 -06:00
|
|
|
|
2011-12-14 07:05:33 -07:00
|
|
|
// Phase 6b: Compile all closures.
|
2012-02-23 21:09:53 -07:00
|
|
|
// Can generate more closures, so run in batches.
|
2009-08-12 14:18:19 -06:00
|
|
|
while(closures) {
|
2012-02-23 21:09:53 -07:00
|
|
|
batch = closures;
|
2009-08-12 14:18:19 -06:00
|
|
|
closures = nil;
|
2012-02-23 21:09:53 -07:00
|
|
|
if(debug['l'])
|
|
|
|
for(l=batch; l; l=l->next)
|
2012-01-10 13:24:31 -07:00
|
|
|
inlcalls(l->n);
|
2012-02-23 21:09:53 -07:00
|
|
|
if(!debug['N'])
|
|
|
|
escapes(batch);
|
|
|
|
for(l=batch; l; l=l->next)
|
2010-03-31 12:46:01 -06:00
|
|
|
funccompile(l->n, 1);
|
2009-08-12 14:18:19 -06:00
|
|
|
}
|
2011-06-02 10:48:17 -06:00
|
|
|
|
2011-12-14 07:05:33 -07:00
|
|
|
// Phase 7: check external declarations.
|
2011-06-03 09:44:02 -06:00
|
|
|
for(l=externdcl; l; l=l->next)
|
|
|
|
if(l->n->op == ONAME)
|
|
|
|
typecheck(&l->n, Erv);
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2011-06-17 13:25:05 -06:00
|
|
|
if(nerrors+nsavederrors)
|
2008-06-04 15:37:38 -06:00
|
|
|
errorexit();
|
|
|
|
|
|
|
|
dumpobj();
|
|
|
|
|
2011-06-17 13:25:05 -06:00
|
|
|
if(nerrors+nsavederrors)
|
2008-07-27 14:09:15 -06:00
|
|
|
errorexit();
|
|
|
|
|
2010-03-30 00:34:59 -06:00
|
|
|
flusherrors();
|
2011-08-29 07:35:04 -06:00
|
|
|
exits(0);
|
2008-06-04 15:37:38 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-06-17 13:25:05 -06:00
|
|
|
void
|
|
|
|
saveerrors(void)
|
|
|
|
{
|
|
|
|
nsavederrors += nerrors;
|
|
|
|
nerrors = 0;
|
|
|
|
}
|
|
|
|
|
2011-11-07 09:42:13 -07:00
|
|
|
/*
|
|
|
|
* macro to portably read/write archive header.
|
|
|
|
* 'cmd' is read/write/Bread/Bwrite, etc.
|
|
|
|
*/
|
|
|
|
#define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\
|
|
|
|
|| cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\
|
|
|
|
|| cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\
|
|
|
|
|| cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\
|
|
|
|
|| cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\
|
|
|
|
|| cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\
|
|
|
|
|| cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag)
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static int
|
2008-11-19 15:21:44 -07:00
|
|
|
arsize(Biobuf *b, char *name)
|
|
|
|
{
|
2011-11-07 09:42:13 -07:00
|
|
|
struct ar_hdr a;
|
2008-07-09 17:05:03 -06:00
|
|
|
|
2011-11-07 09:42:13 -07:00
|
|
|
if (HEADER_IO(Bread, b, a))
|
2008-11-19 15:21:44 -07:00
|
|
|
return -1;
|
2011-11-07 09:42:13 -07:00
|
|
|
|
|
|
|
if(strncmp(a.name, name, strlen(name)) != 0)
|
2008-11-19 15:21:44 -07:00
|
|
|
return -1;
|
2011-11-07 09:42:13 -07:00
|
|
|
|
|
|
|
return atoi(a.size);
|
2008-07-09 17:05:03 -06:00
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static int
|
2008-07-09 17:05:03 -06:00
|
|
|
skiptopkgdef(Biobuf *b)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
int sz;
|
|
|
|
|
|
|
|
/* archive header */
|
|
|
|
if((p = Brdline(b, '\n')) == nil)
|
|
|
|
return 0;
|
|
|
|
if(Blinelen(b) != 8)
|
|
|
|
return 0;
|
|
|
|
if(memcmp(p, "!<arch>\n", 8) != 0)
|
|
|
|
return 0;
|
|
|
|
/* symbol table is first; skip it */
|
|
|
|
sz = arsize(b, "__.SYMDEF");
|
2008-11-19 15:21:44 -07:00
|
|
|
if(sz < 0)
|
2008-07-09 17:05:03 -06:00
|
|
|
return 0;
|
|
|
|
Bseek(b, sz, 1);
|
|
|
|
/* package export block is second */
|
|
|
|
sz = arsize(b, "__.PKGDEF");
|
|
|
|
if(sz <= 0)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static void
|
2009-03-10 21:03:31 -06:00
|
|
|
addidir(char* dir)
|
|
|
|
{
|
|
|
|
Idir** pp;
|
|
|
|
|
|
|
|
if(dir == nil)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for(pp = &idirs; *pp != nil; pp = &(*pp)->link)
|
|
|
|
;
|
|
|
|
*pp = mal(sizeof(Idir));
|
|
|
|
(*pp)->link = nil;
|
|
|
|
(*pp)->dir = dir;
|
|
|
|
}
|
|
|
|
|
2009-06-25 21:15:56 -06:00
|
|
|
// is this path a local name? begins with ./ or ../ or /
|
2010-06-14 12:24:51 -06:00
|
|
|
static int
|
2009-06-25 21:15:56 -06:00
|
|
|
islocalname(Strlit *name)
|
|
|
|
{
|
2010-04-27 18:19:15 -06:00
|
|
|
if(!windows && name->len >= 1 && name->s[0] == '/')
|
2009-06-25 21:15:56 -06:00
|
|
|
return 1;
|
2010-04-27 18:19:15 -06:00
|
|
|
if(windows && name->len >= 3 &&
|
2010-07-21 00:45:33 -06:00
|
|
|
yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
|
2010-04-27 14:52:43 -06:00
|
|
|
return 1;
|
2009-06-25 21:15:56 -06:00
|
|
|
if(name->len >= 2 && strncmp(name->s, "./", 2) == 0)
|
|
|
|
return 1;
|
cmd/go: fix relative imports again
I tried before to make relative imports work by simply
invoking the compiler in the right directory, so that
an import of ./foo could be resolved by ./foo.a.
This required creating a separate tree of package binaries
that included the full path to the source directory, so that
/home/gopher/bar.go would be compiled in
tmpdir/work/local/home/gopher and perhaps find
a ./foo.a in that directory.
This model breaks on Windows because : appears in path
names but cannot be used in subdirectory names, and I
missed one or two places where it needed to be removed.
The model breaks more fundamentally when compiling
a test of a package that lives outside the Go path, because
we effectively use a ./ import in the generated testmain,
but there we want to be able to resolve the ./ import
of the test package to one directory and all the other ./
imports to a different directory. Piggybacking on the compiler's
current working directory is then no longer possible.
Instead, introduce a new compiler option -D prefix that
makes the compiler turn a ./ import into prefix+that,
so that import "./foo" with -D a/b/c turns into import
"a/b/c/foo". Then we can invent a package hierarchy
"_/" with subdirectories named for file system paths:
import "./foo" in the directory /home/gopher becomes
import "_/home/gopher/foo", and since that final path
is just an ordinary import now, all the ordinary processing
works, without special cases.
We will have to change the name of the hierarchy if we
ever decide to introduce a standard package with import
path "_", but that seems unlikely, and the detail is known
only in temporary packages that get thrown away at the
end of a build.
Fixes #3169.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5732045
2012-03-02 20:16:02 -07:00
|
|
|
if(name->len == 1 && strncmp(name->s, ".", 1) == 0)
|
|
|
|
return 1;
|
2009-06-25 21:15:56 -06:00
|
|
|
if(name->len >= 3 && strncmp(name->s, "../", 3) == 0)
|
|
|
|
return 1;
|
cmd/go: fix relative imports again
I tried before to make relative imports work by simply
invoking the compiler in the right directory, so that
an import of ./foo could be resolved by ./foo.a.
This required creating a separate tree of package binaries
that included the full path to the source directory, so that
/home/gopher/bar.go would be compiled in
tmpdir/work/local/home/gopher and perhaps find
a ./foo.a in that directory.
This model breaks on Windows because : appears in path
names but cannot be used in subdirectory names, and I
missed one or two places where it needed to be removed.
The model breaks more fundamentally when compiling
a test of a package that lives outside the Go path, because
we effectively use a ./ import in the generated testmain,
but there we want to be able to resolve the ./ import
of the test package to one directory and all the other ./
imports to a different directory. Piggybacking on the compiler's
current working directory is then no longer possible.
Instead, introduce a new compiler option -D prefix that
makes the compiler turn a ./ import into prefix+that,
so that import "./foo" with -D a/b/c turns into import
"a/b/c/foo". Then we can invent a package hierarchy
"_/" with subdirectories named for file system paths:
import "./foo" in the directory /home/gopher becomes
import "_/home/gopher/foo", and since that final path
is just an ordinary import now, all the ordinary processing
works, without special cases.
We will have to change the name of the hierarchy if we
ever decide to introduce a standard package with import
path "_", but that seems unlikely, and the detail is known
only in temporary packages that get thrown away at the
end of a build.
Fixes #3169.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5732045
2012-03-02 20:16:02 -07:00
|
|
|
if(name->len == 2 && strncmp(name->s, "..", 2) == 0)
|
|
|
|
return 1;
|
2009-06-25 21:15:56 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static int
|
2009-04-09 19:16:21 -06:00
|
|
|
findpkg(Strlit *name)
|
2008-07-09 17:05:03 -06:00
|
|
|
{
|
2009-06-05 23:18:32 -06:00
|
|
|
Idir *p;
|
2010-09-16 13:37:57 -06:00
|
|
|
char *q;
|
2008-07-09 17:05:03 -06:00
|
|
|
|
2009-06-25 21:15:56 -06:00
|
|
|
if(islocalname(name)) {
|
2010-09-16 13:50:46 -06:00
|
|
|
if(safemode)
|
2010-09-16 13:37:57 -06:00
|
|
|
return 0;
|
2009-06-25 21:15:56 -06:00
|
|
|
// 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.
|
|
|
|
snprint(namebuf, sizeof(namebuf), "%Z.a", name);
|
|
|
|
if(access(namebuf, 0) >= 0)
|
|
|
|
return 1;
|
|
|
|
snprint(namebuf, sizeof(namebuf), "%Z.%c", name, thechar);
|
|
|
|
if(access(namebuf, 0) >= 0)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-09-16 13:37:57 -06:00
|
|
|
// local imports should be canonicalized already.
|
2011-08-21 22:07:27 -06:00
|
|
|
// don't want to see "encoding/../encoding/base64"
|
|
|
|
// as different from "encoding/base64".
|
2010-09-16 13:37:57 -06:00
|
|
|
q = mal(name->len+1);
|
|
|
|
memmove(q, name->s, name->len);
|
|
|
|
q[name->len] = '\0';
|
|
|
|
cleanname(q);
|
|
|
|
if(strlen(q) != name->len || memcmp(q, name->s, name->len) != 0) {
|
2010-09-27 10:59:26 -06:00
|
|
|
yyerror("non-canonical import path %Z (should be %s)", name, q);
|
2010-09-16 13:37:57 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-10 21:03:31 -06:00
|
|
|
for(p = idirs; p != nil; p = p->link) {
|
|
|
|
snprint(namebuf, sizeof(namebuf), "%s/%Z.a", p->dir, name);
|
|
|
|
if(access(namebuf, 0) >= 0)
|
|
|
|
return 1;
|
2009-03-30 22:31:29 -06:00
|
|
|
snprint(namebuf, sizeof(namebuf), "%s/%Z.%c", p->dir, name, thechar);
|
2009-03-10 21:03:31 -06:00
|
|
|
if(access(namebuf, 0) >= 0)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if(goroot != nil) {
|
2009-06-05 23:18:32 -06:00
|
|
|
snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s/%Z.a", goroot, goos, goarch, name);
|
2009-03-10 21:03:31 -06:00
|
|
|
if(access(namebuf, 0) >= 0)
|
|
|
|
return 1;
|
2009-06-05 23:18:32 -06:00
|
|
|
snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s/%Z.%c", goroot, goos, goarch, name, thechar);
|
2009-03-10 21:03:31 -06:00
|
|
|
if(access(namebuf, 0) >= 0)
|
|
|
|
return 1;
|
|
|
|
}
|
2008-07-09 17:05:03 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-02-24 12:48:36 -07:00
|
|
|
static void
|
|
|
|
fakeimport(void)
|
|
|
|
{
|
|
|
|
importpkg = mkpkg(strlit("fake"));
|
|
|
|
cannedimports("fake.6", "$$\n");
|
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
2009-09-17 17:42:10 -06:00
|
|
|
importfile(Val *f, int line)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
|
|
|
Biobuf *imp;
|
2011-02-03 11:51:43 -07:00
|
|
|
char *file, *p, *q;
|
2008-08-03 18:25:15 -06:00
|
|
|
int32 c;
|
2008-07-09 17:05:03 -06:00
|
|
|
int len;
|
2010-01-22 18:06:20 -07:00
|
|
|
Strlit *path;
|
cmd/go: fix relative imports again
I tried before to make relative imports work by simply
invoking the compiler in the right directory, so that
an import of ./foo could be resolved by ./foo.a.
This required creating a separate tree of package binaries
that included the full path to the source directory, so that
/home/gopher/bar.go would be compiled in
tmpdir/work/local/home/gopher and perhaps find
a ./foo.a in that directory.
This model breaks on Windows because : appears in path
names but cannot be used in subdirectory names, and I
missed one or two places where it needed to be removed.
The model breaks more fundamentally when compiling
a test of a package that lives outside the Go path, because
we effectively use a ./ import in the generated testmain,
but there we want to be able to resolve the ./ import
of the test package to one directory and all the other ./
imports to a different directory. Piggybacking on the compiler's
current working directory is then no longer possible.
Instead, introduce a new compiler option -D prefix that
makes the compiler turn a ./ import into prefix+that,
so that import "./foo" with -D a/b/c turns into import
"a/b/c/foo". Then we can invent a package hierarchy
"_/" with subdirectories named for file system paths:
import "./foo" in the directory /home/gopher becomes
import "_/home/gopher/foo", and since that final path
is just an ordinary import now, all the ordinary processing
works, without special cases.
We will have to change the name of the hierarchy if we
ever decide to introduce a standard package with import
path "_", but that seems unlikely, and the detail is known
only in temporary packages that get thrown away at the
end of a build.
Fixes #3169.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5732045
2012-03-02 20:16:02 -07:00
|
|
|
char *cleanbuf, *prefix;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2011-08-25 14:08:13 -06:00
|
|
|
USED(line);
|
|
|
|
|
2010-01-25 19:31:35 -07:00
|
|
|
// TODO(rsc): don't bother reloading imports more than once?
|
2010-01-22 18:06:20 -07:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
if(f->ctype != CTSTR) {
|
|
|
|
yyerror("import statement not a string");
|
2012-02-24 12:48:36 -07:00
|
|
|
fakeimport();
|
2008-06-04 15:37:38 -06:00
|
|
|
return;
|
|
|
|
}
|
2008-06-25 21:22:10 -06:00
|
|
|
|
2012-02-24 12:48:36 -07:00
|
|
|
if(f->u.sval->len == 0) {
|
|
|
|
yyerror("import path is empty");
|
|
|
|
fakeimport();
|
|
|
|
return;
|
2010-04-11 15:52:06 -06:00
|
|
|
}
|
2012-02-24 12:48:36 -07:00
|
|
|
|
|
|
|
if(isbadimport(f->u.sval)) {
|
|
|
|
fakeimport();
|
|
|
|
return;
|
2012-01-31 15:29:59 -07:00
|
|
|
}
|
2010-01-22 18:06:20 -07:00
|
|
|
|
2011-02-03 12:17:20 -07:00
|
|
|
// 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(strcmp(f->u.sval->s, "main") == 0) {
|
|
|
|
yyerror("cannot import \"main\"");
|
|
|
|
errorexit();
|
|
|
|
}
|
|
|
|
|
2011-09-07 13:50:21 -06:00
|
|
|
if(myimportpath != nil && strcmp(f->u.sval->s, myimportpath) == 0) {
|
|
|
|
yyerror("import \"%Z\" while compiling that package (import cycle)", f->u.sval);
|
|
|
|
errorexit();
|
|
|
|
}
|
|
|
|
|
2008-12-08 20:46:39 -07:00
|
|
|
if(strcmp(f->u.sval->s, "unsafe") == 0) {
|
2010-06-09 12:00:55 -06:00
|
|
|
if(safemode) {
|
|
|
|
yyerror("cannot import package unsafe");
|
|
|
|
errorexit();
|
|
|
|
}
|
2010-01-22 18:06:20 -07:00
|
|
|
importpkg = mkpkg(f->u.sval);
|
2008-12-08 20:46:39 -07:00
|
|
|
cannedimports("unsafe.6", unsafeimport);
|
|
|
|
return;
|
|
|
|
}
|
2011-02-03 11:51:43 -07:00
|
|
|
|
2010-01-22 18:06:20 -07:00
|
|
|
path = f->u.sval;
|
|
|
|
if(islocalname(path)) {
|
2012-02-29 13:28:36 -07:00
|
|
|
if(path->s[0] == '/') {
|
|
|
|
yyerror("import path cannot be absolute path");
|
|
|
|
fakeimport();
|
|
|
|
return;
|
|
|
|
}
|
cmd/go: fix relative imports again
I tried before to make relative imports work by simply
invoking the compiler in the right directory, so that
an import of ./foo could be resolved by ./foo.a.
This required creating a separate tree of package binaries
that included the full path to the source directory, so that
/home/gopher/bar.go would be compiled in
tmpdir/work/local/home/gopher and perhaps find
a ./foo.a in that directory.
This model breaks on Windows because : appears in path
names but cannot be used in subdirectory names, and I
missed one or two places where it needed to be removed.
The model breaks more fundamentally when compiling
a test of a package that lives outside the Go path, because
we effectively use a ./ import in the generated testmain,
but there we want to be able to resolve the ./ import
of the test package to one directory and all the other ./
imports to a different directory. Piggybacking on the compiler's
current working directory is then no longer possible.
Instead, introduce a new compiler option -D prefix that
makes the compiler turn a ./ import into prefix+that,
so that import "./foo" with -D a/b/c turns into import
"a/b/c/foo". Then we can invent a package hierarchy
"_/" with subdirectories named for file system paths:
import "./foo" in the directory /home/gopher becomes
import "_/home/gopher/foo", and since that final path
is just an ordinary import now, all the ordinary processing
works, without special cases.
We will have to change the name of the hierarchy if we
ever decide to introduce a standard package with import
path "_", but that seems unlikely, and the detail is known
only in temporary packages that get thrown away at the
end of a build.
Fixes #3169.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5732045
2012-03-02 20:16:02 -07:00
|
|
|
prefix = pathname;
|
|
|
|
if(localimport != nil)
|
|
|
|
prefix = localimport;
|
|
|
|
cleanbuf = mal(strlen(prefix) + strlen(path->s) + 2);
|
|
|
|
strcpy(cleanbuf, prefix);
|
2010-09-30 13:02:43 -06:00
|
|
|
strcat(cleanbuf, "/");
|
|
|
|
strcat(cleanbuf, path->s);
|
2010-01-22 18:06:20 -07:00
|
|
|
cleanname(cleanbuf);
|
|
|
|
path = strlit(cleanbuf);
|
|
|
|
}
|
|
|
|
|
2010-04-11 15:52:06 -06:00
|
|
|
if(!findpkg(path)) {
|
2011-09-07 13:50:21 -06:00
|
|
|
yyerror("can't find import: \"%Z\"", f->u.sval);
|
2010-04-11 15:52:06 -06:00
|
|
|
errorexit();
|
|
|
|
}
|
2010-01-22 18:06:20 -07:00
|
|
|
importpkg = mkpkg(path);
|
|
|
|
|
2008-07-09 17:05:03 -06:00
|
|
|
imp = Bopen(namebuf, OREAD);
|
2010-04-11 15:52:06 -06:00
|
|
|
if(imp == nil) {
|
2011-09-07 13:50:21 -06:00
|
|
|
yyerror("can't open import: \"%Z\": %r", f->u.sval);
|
2010-04-11 15:52:06 -06:00
|
|
|
errorexit();
|
|
|
|
}
|
2008-06-13 19:16:23 -06:00
|
|
|
file = strdup(namebuf);
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-07-09 17:05:03 -06:00
|
|
|
len = strlen(namebuf);
|
2009-04-08 23:45:33 -06:00
|
|
|
if(len > 2 && namebuf[len-2] == '.' && namebuf[len-1] == 'a') {
|
2010-04-11 15:52:06 -06:00
|
|
|
if(!skiptopkgdef(imp)) {
|
2011-02-03 11:51:43 -07:00
|
|
|
yyerror("import %s: not a package file", file);
|
2010-04-11 15:52:06 -06:00
|
|
|
errorexit();
|
|
|
|
}
|
2009-04-08 23:45:33 -06:00
|
|
|
}
|
2011-02-03 11:51:43 -07:00
|
|
|
|
|
|
|
// check object header
|
|
|
|
p = Brdstr(imp, '\n', 1);
|
|
|
|
if(strcmp(p, "empty archive") != 0) {
|
|
|
|
if(strncmp(p, "go object ", 10) != 0) {
|
|
|
|
yyerror("import %s: not a go object file", file);
|
|
|
|
errorexit();
|
|
|
|
}
|
2011-10-25 23:19:39 -06:00
|
|
|
q = smprint("%s %s %s %s", getgoos(), thestring, getgoversion(), expstring());
|
2011-02-03 11:51:43 -07:00
|
|
|
if(strcmp(p+10, q) != 0) {
|
|
|
|
yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
|
|
|
|
errorexit();
|
|
|
|
}
|
|
|
|
free(q);
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2010-01-26 17:12:50 -07:00
|
|
|
// assume files move (get installed)
|
|
|
|
// so don't record the full path.
|
|
|
|
linehist(file + len - path->len - 2, -1, 1); // acts as #pragma lib
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
/*
|
|
|
|
* position the input right
|
2008-10-03 17:15:55 -06:00
|
|
|
* after $$ and return
|
2008-06-04 15:37:38 -06:00
|
|
|
*/
|
|
|
|
pushedio = curio;
|
|
|
|
curio.bin = imp;
|
|
|
|
curio.peekc = 0;
|
2008-10-29 13:46:44 -06:00
|
|
|
curio.peekc1 = 0;
|
2008-06-13 19:16:23 -06:00
|
|
|
curio.infile = file;
|
2009-12-11 16:59:41 -07:00
|
|
|
curio.nlsemi = 0;
|
2009-08-07 13:50:26 -06:00
|
|
|
typecheckok = 1;
|
2011-02-03 11:51:43 -07:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
for(;;) {
|
|
|
|
c = getc();
|
|
|
|
if(c == EOF)
|
|
|
|
break;
|
2008-10-03 17:15:55 -06:00
|
|
|
if(c != '$')
|
2008-06-04 15:37:38 -06:00
|
|
|
continue;
|
|
|
|
c = getc();
|
|
|
|
if(c == EOF)
|
|
|
|
break;
|
2008-10-03 17:15:55 -06:00
|
|
|
if(c != '$')
|
2008-06-04 15:37:38 -06:00
|
|
|
continue;
|
|
|
|
return;
|
|
|
|
}
|
2011-09-07 13:50:21 -06:00
|
|
|
yyerror("no import in \"%Z\"", f->u.sval);
|
2008-06-04 15:37:38 -06:00
|
|
|
unimportfile();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
unimportfile(void)
|
|
|
|
{
|
|
|
|
if(curio.bin != nil) {
|
|
|
|
Bterm(curio.bin);
|
|
|
|
curio.bin = nil;
|
2008-06-28 18:27:39 -06:00
|
|
|
} else
|
2009-08-19 16:18:08 -06:00
|
|
|
lexlineno--; // re correct sys.6 line number
|
2009-09-17 17:42:10 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
curio = pushedio;
|
|
|
|
pushedio.bin = nil;
|
2009-10-16 00:10:49 -06:00
|
|
|
incannedimport = 0;
|
2009-08-07 13:50:26 -06:00
|
|
|
typecheckok = 0;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-12-08 20:46:39 -07:00
|
|
|
cannedimports(char *file, char *cp)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2009-08-19 16:18:08 -06:00
|
|
|
lexlineno++; // if sys.6 is included on line 1,
|
2009-06-25 17:57:56 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
pushedio = curio;
|
|
|
|
curio.bin = nil;
|
|
|
|
curio.peekc = 0;
|
2008-10-29 13:46:44 -06:00
|
|
|
curio.peekc1 = 0;
|
2008-06-13 19:16:23 -06:00
|
|
|
curio.infile = file;
|
2008-12-08 20:46:39 -07:00
|
|
|
curio.cp = cp;
|
2009-12-11 16:59:41 -07:00
|
|
|
curio.nlsemi = 0;
|
2010-06-11 16:28:43 -06:00
|
|
|
curio.importsafe = 0;
|
2008-06-13 19:16:23 -06:00
|
|
|
|
2009-08-07 13:50:26 -06:00
|
|
|
typecheckok = 1;
|
2009-10-16 00:10:49 -06:00
|
|
|
incannedimport = 1;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static int
|
2009-03-30 20:15:07 -06:00
|
|
|
isfrog(int c)
|
|
|
|
{
|
2009-01-31 17:42:10 -07:00
|
|
|
// complain about possibly invisible control characters
|
|
|
|
if(c < 0)
|
|
|
|
return 1;
|
|
|
|
if(c < ' ') {
|
2009-01-31 17:44:52 -07:00
|
|
|
if(c == '\n' || c== '\r' || c == '\t') // good white space
|
2009-01-31 17:42:10 -07:00
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
2010-09-24 15:09:31 -06:00
|
|
|
if(0x7f <= c && c <= 0xa0) // DEL, unicode block including unbreakable space.
|
2009-01-31 17:42:10 -07:00
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-01-08 00:24:48 -07:00
|
|
|
typedef struct Loophack Loophack;
|
|
|
|
struct Loophack {
|
|
|
|
int v;
|
|
|
|
Loophack *next;
|
|
|
|
};
|
|
|
|
|
2009-06-06 20:27:48 -06:00
|
|
|
static int32
|
|
|
|
_yylex(void)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2010-02-16 11:16:24 -07:00
|
|
|
int c, c1, clen, escflag, ncp;
|
2008-06-06 20:16:18 -06:00
|
|
|
vlong v;
|
2010-06-09 12:00:55 -06:00
|
|
|
char *cp, *ep;
|
2008-06-04 15:37:38 -06:00
|
|
|
Rune rune;
|
|
|
|
Sym *s;
|
2010-01-08 00:24:48 -07:00
|
|
|
static Loophack *lstk;
|
|
|
|
Loophack *h;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-11-18 10:32:05 -07:00
|
|
|
prevlineno = lineno;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
l0:
|
|
|
|
c = getc();
|
2010-07-21 00:45:33 -06:00
|
|
|
if(yy_isspace(c)) {
|
2009-12-11 16:59:41 -07:00
|
|
|
if(c == '\n' && curio.nlsemi) {
|
|
|
|
ungetc(c);
|
|
|
|
DBG("lex: implicit semi\n");
|
|
|
|
return ';';
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
goto l0;
|
2009-12-11 16:59:41 -07:00
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2009-08-19 16:18:08 -06:00
|
|
|
lineno = lexlineno; /* start of token */
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
if(c >= Runeself) {
|
|
|
|
/* all multibyte runes are alpha */
|
2009-04-02 18:59:09 -06:00
|
|
|
cp = lexbuf;
|
2010-06-09 12:00:55 -06:00
|
|
|
ep = lexbuf+sizeof lexbuf;
|
2008-06-04 15:37:38 -06:00
|
|
|
goto talph;
|
|
|
|
}
|
|
|
|
|
2010-07-21 00:45:33 -06:00
|
|
|
if(yy_isalpha(c)) {
|
2009-04-02 18:59:09 -06:00
|
|
|
cp = lexbuf;
|
2010-06-09 12:00:55 -06:00
|
|
|
ep = lexbuf+sizeof lexbuf;
|
2008-06-04 15:37:38 -06:00
|
|
|
goto talph;
|
|
|
|
}
|
|
|
|
|
2010-07-21 00:45:33 -06:00
|
|
|
if(yy_isdigit(c))
|
2008-06-04 15:37:38 -06:00
|
|
|
goto tnum;
|
|
|
|
|
|
|
|
switch(c) {
|
|
|
|
case EOF:
|
2009-08-19 18:27:08 -06:00
|
|
|
lineno = prevlineno;
|
2008-06-04 15:37:38 -06:00
|
|
|
ungetc(EOF);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
case '_':
|
2009-04-02 18:59:09 -06:00
|
|
|
cp = lexbuf;
|
2010-06-09 12:00:55 -06:00
|
|
|
ep = lexbuf+sizeof lexbuf;
|
2008-06-04 15:37:38 -06:00
|
|
|
goto talph;
|
|
|
|
|
|
|
|
case '.':
|
|
|
|
c1 = getc();
|
2010-07-21 00:45:33 -06:00
|
|
|
if(yy_isdigit(c1)) {
|
2009-04-02 18:59:09 -06:00
|
|
|
cp = lexbuf;
|
2010-06-09 12:00:55 -06:00
|
|
|
ep = lexbuf+sizeof lexbuf;
|
2008-06-04 15:37:38 -06:00
|
|
|
*cp++ = c;
|
|
|
|
c = c1;
|
|
|
|
goto casedot;
|
|
|
|
}
|
2008-10-29 13:46:44 -06:00
|
|
|
if(c1 == '.') {
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '.') {
|
|
|
|
c = LDDD;
|
|
|
|
goto lx;
|
|
|
|
}
|
|
|
|
ungetc(c1);
|
|
|
|
c1 = '.';
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
case '"':
|
|
|
|
/* "..." */
|
2009-04-02 18:59:09 -06:00
|
|
|
strcpy(lexbuf, "\"<string>\"");
|
2010-02-16 11:16:24 -07:00
|
|
|
cp = mal(8);
|
2008-10-29 13:46:44 -06:00
|
|
|
clen = sizeof(int32);
|
2010-02-16 11:16:24 -07:00
|
|
|
ncp = 8;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
for(;;) {
|
2010-02-16 11:16:24 -07:00
|
|
|
if(clen+UTFmax > ncp) {
|
|
|
|
cp = remal(cp, ncp, ncp);
|
|
|
|
ncp += ncp;
|
|
|
|
}
|
2008-06-08 20:02:27 -06:00
|
|
|
if(escchar('"', &escflag, &v))
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2008-06-09 14:16:50 -06:00
|
|
|
if(v < Runeself || escflag) {
|
2008-10-29 13:46:44 -06:00
|
|
|
cp[clen++] = v;
|
2008-06-08 20:02:27 -06:00
|
|
|
} else {
|
2008-06-06 20:16:18 -06:00
|
|
|
rune = v;
|
2008-06-04 15:37:38 -06:00
|
|
|
c = runelen(rune);
|
2008-10-29 13:46:44 -06:00
|
|
|
runetochar(cp+clen, &rune);
|
|
|
|
clen += c;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
}
|
2009-12-11 16:59:41 -07:00
|
|
|
goto strlit;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
case '`':
|
|
|
|
/* `...` */
|
2009-04-02 18:59:09 -06:00
|
|
|
strcpy(lexbuf, "`<string>`");
|
2010-02-16 11:16:24 -07:00
|
|
|
cp = mal(8);
|
2008-10-29 13:46:44 -06:00
|
|
|
clen = sizeof(int32);
|
2010-02-16 11:16:24 -07:00
|
|
|
ncp = 8;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
for(;;) {
|
2010-02-16 17:47:39 -07:00
|
|
|
if(clen+UTFmax > ncp) {
|
|
|
|
cp = remal(cp, ncp, ncp);
|
2010-02-16 11:16:24 -07:00
|
|
|
ncp += ncp;
|
|
|
|
}
|
2010-02-16 17:47:39 -07:00
|
|
|
c = getr();
|
2011-12-15 08:47:09 -07:00
|
|
|
if(c == '\r')
|
|
|
|
continue;
|
2009-06-18 16:49:41 -06:00
|
|
|
if(c == EOF) {
|
2009-08-19 16:18:08 -06:00
|
|
|
yyerror("eof in string");
|
2009-06-18 16:49:41 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(c == '`')
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2010-02-16 17:47:39 -07:00
|
|
|
rune = c;
|
|
|
|
clen += runetochar(cp+clen, &rune);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2008-10-29 13:46:44 -06:00
|
|
|
|
2009-12-11 16:59:41 -07:00
|
|
|
strlit:
|
2008-10-29 13:46:44 -06:00
|
|
|
*(int32*)cp = clen-sizeof(int32); // length
|
2008-06-04 15:37:38 -06:00
|
|
|
do {
|
2008-10-29 13:46:44 -06:00
|
|
|
cp[clen++] = 0;
|
|
|
|
} while(clen & MAXALIGN);
|
2009-04-09 19:16:21 -06:00
|
|
|
yylval.val.u.sval = (Strlit*)cp;
|
2008-06-04 15:37:38 -06:00
|
|
|
yylval.val.ctype = CTSTR;
|
|
|
|
DBG("lex: string literal\n");
|
2011-07-27 12:36:21 -06:00
|
|
|
strcpy(litbuf, "string literal");
|
2008-06-04 15:37:38 -06:00
|
|
|
return LLITERAL;
|
|
|
|
|
|
|
|
case '\'':
|
|
|
|
/* '.' */
|
2009-10-19 20:55:17 -06:00
|
|
|
if(escchar('\'', &escflag, &v)) {
|
|
|
|
yyerror("empty character literal or unescaped ' in character literal");
|
|
|
|
v = '\'';
|
|
|
|
}
|
2008-06-08 20:02:27 -06:00
|
|
|
if(!escchar('\'', &escflag, &v)) {
|
2008-06-04 15:37:38 -06:00
|
|
|
yyerror("missing '");
|
2008-06-06 20:16:18 -06:00
|
|
|
ungetc(v);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2008-08-08 18:13:31 -06:00
|
|
|
yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
|
|
|
|
mpmovecfix(yylval.val.u.xval, v);
|
2011-12-08 20:07:43 -07:00
|
|
|
yylval.val.ctype = CTRUNE;
|
2008-06-04 15:37:38 -06:00
|
|
|
DBG("lex: codepoint literal\n");
|
2011-07-27 12:36:21 -06:00
|
|
|
strcpy(litbuf, "string literal");
|
2008-06-04 15:37:38 -06:00
|
|
|
return LLITERAL;
|
|
|
|
|
|
|
|
case '/':
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '*') {
|
2009-12-11 16:59:41 -07:00
|
|
|
int nl;
|
|
|
|
|
|
|
|
nl = 0;
|
2008-06-04 15:37:38 -06:00
|
|
|
for(;;) {
|
|
|
|
c = getr();
|
2009-12-11 16:59:41 -07:00
|
|
|
if(c == '\n')
|
|
|
|
nl = 1;
|
2008-06-04 15:37:38 -06:00
|
|
|
while(c == '*') {
|
|
|
|
c = getr();
|
2009-12-11 16:59:41 -07:00
|
|
|
if(c == '/') {
|
|
|
|
if(nl)
|
|
|
|
ungetc('\n');
|
2008-06-04 15:37:38 -06:00
|
|
|
goto l0;
|
2009-12-11 16:59:41 -07:00
|
|
|
}
|
|
|
|
if(c == '\n')
|
|
|
|
nl = 1;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
if(c == EOF) {
|
|
|
|
yyerror("eof in comment");
|
|
|
|
errorexit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(c1 == '/') {
|
2010-07-15 21:21:33 -06:00
|
|
|
c = getlinepragma();
|
2008-06-04 15:37:38 -06:00
|
|
|
for(;;) {
|
2010-11-04 14:04:04 -06:00
|
|
|
if(c == '\n' || c == EOF) {
|
2009-12-11 16:59:41 -07:00
|
|
|
ungetc(c);
|
2008-06-04 15:37:38 -06:00
|
|
|
goto l0;
|
2009-12-11 16:59:41 -07:00
|
|
|
}
|
2010-07-15 21:21:33 -06:00
|
|
|
c = getr();
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = ODIV;
|
|
|
|
goto asop;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ':':
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = LCOLAS;
|
|
|
|
goto lx;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '*':
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = OMUL;
|
|
|
|
goto asop;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '%':
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = OMOD;
|
|
|
|
goto asop;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '+':
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '+') {
|
|
|
|
c = LINC;
|
|
|
|
goto lx;
|
|
|
|
}
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = OADD;
|
|
|
|
goto asop;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '-':
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '-') {
|
|
|
|
c = LDEC;
|
|
|
|
goto lx;
|
|
|
|
}
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = OSUB;
|
|
|
|
goto asop;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '>':
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '>') {
|
|
|
|
c = LRSH;
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = ORSH;
|
|
|
|
goto asop;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = LGE;
|
|
|
|
goto lx;
|
|
|
|
}
|
|
|
|
c = LGT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '<':
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '<') {
|
|
|
|
c = LLSH;
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = OLSH;
|
|
|
|
goto asop;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = LLE;
|
|
|
|
goto lx;
|
|
|
|
}
|
2008-07-15 22:07:59 -06:00
|
|
|
if(c1 == '-') {
|
2008-09-16 20:14:33 -06:00
|
|
|
c = LCOMM;
|
2008-07-15 22:07:59 -06:00
|
|
|
goto lx;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
c = LLT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '=':
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = LEQ;
|
|
|
|
goto lx;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '!':
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = LNE;
|
|
|
|
goto lx;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '&':
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '&') {
|
|
|
|
c = LANDAND;
|
|
|
|
goto lx;
|
|
|
|
}
|
2009-03-11 20:59:35 -06:00
|
|
|
if(c1 == '^') {
|
|
|
|
c = LANDNOT;
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = OANDNOT;
|
|
|
|
goto asop;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
if(c1 == '=') {
|
|
|
|
c = OAND;
|
|
|
|
goto asop;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '|':
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '|') {
|
|
|
|
c = LOROR;
|
|
|
|
goto lx;
|
|
|
|
}
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = OOR;
|
|
|
|
goto asop;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '^':
|
|
|
|
c1 = getc();
|
|
|
|
if(c1 == '=') {
|
|
|
|
c = OXOR;
|
|
|
|
goto asop;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2009-06-06 13:46:38 -06:00
|
|
|
/*
|
|
|
|
* 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.
|
2010-01-08 00:24:48 -07:00
|
|
|
* parens push loophack onto a stack and go back to 0.
|
2009-06-06 13:46:38 -06:00
|
|
|
* a '{' with loophack == 1 becomes LBODY and disables loophack.
|
|
|
|
*
|
|
|
|
* i said it was clumsy.
|
|
|
|
*/
|
|
|
|
case '(':
|
2010-05-03 16:29:59 -06:00
|
|
|
case '[':
|
2010-01-08 00:24:48 -07:00
|
|
|
if(loophack || lstk != nil) {
|
|
|
|
h = malloc(sizeof *h);
|
|
|
|
h->v = loophack;
|
|
|
|
h->next = lstk;
|
|
|
|
lstk = h;
|
|
|
|
loophack = 0;
|
|
|
|
}
|
2009-06-06 13:46:38 -06:00
|
|
|
goto lx;
|
|
|
|
case ')':
|
2010-05-03 16:29:59 -06:00
|
|
|
case ']':
|
2010-01-08 00:24:48 -07:00
|
|
|
if(lstk != nil) {
|
|
|
|
h = lstk;
|
|
|
|
loophack = h->v;
|
|
|
|
lstk = h->next;
|
|
|
|
free(h);
|
|
|
|
}
|
2009-06-06 13:46:38 -06:00
|
|
|
goto lx;
|
|
|
|
case '{':
|
|
|
|
if(loophack == 1) {
|
2009-08-19 16:18:08 -06:00
|
|
|
DBG("%L lex: LBODY\n", lexlineno);
|
2009-06-06 13:46:38 -06:00
|
|
|
loophack = 0;
|
|
|
|
return LBODY;
|
|
|
|
}
|
|
|
|
goto lx;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
default:
|
|
|
|
goto lx;
|
|
|
|
}
|
|
|
|
ungetc(c1);
|
|
|
|
|
|
|
|
lx:
|
|
|
|
if(c > 0xff)
|
2009-08-19 16:18:08 -06:00
|
|
|
DBG("%L lex: TOKEN %s\n", lexlineno, lexname(c));
|
2008-06-04 15:37:38 -06:00
|
|
|
else
|
2009-08-19 16:18:08 -06:00
|
|
|
DBG("%L lex: TOKEN '%c'\n", lexlineno, c);
|
2009-01-31 17:42:10 -07:00
|
|
|
if(isfrog(c)) {
|
|
|
|
yyerror("illegal character 0x%ux", c);
|
|
|
|
goto l0;
|
|
|
|
}
|
2010-09-24 15:09:31 -06:00
|
|
|
if(importpkg == nil && (c == '#' || c == '$' || c == '?' || c == '@' || c == '\\')) {
|
|
|
|
yyerror("%s: unexpected %c", "syntax error", c);
|
|
|
|
goto l0;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
return c;
|
|
|
|
|
|
|
|
asop:
|
2011-12-07 21:38:32 -07:00
|
|
|
yylval.i = c; // rathole to hold which asop
|
2008-06-04 15:37:38 -06:00
|
|
|
DBG("lex: TOKEN ASOP %c\n", c);
|
|
|
|
return LASOP;
|
|
|
|
|
|
|
|
talph:
|
|
|
|
/*
|
2009-04-02 18:59:09 -06:00
|
|
|
* cp is set to lexbuf and some
|
2008-06-04 15:37:38 -06:00
|
|
|
* prefix has been stored
|
|
|
|
*/
|
|
|
|
for(;;) {
|
2010-06-09 12:00:55 -06:00
|
|
|
if(cp+10 >= ep) {
|
|
|
|
yyerror("identifier too long");
|
|
|
|
errorexit();
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
if(c >= Runeself) {
|
2010-02-16 17:47:39 -07:00
|
|
|
ungetc(c);
|
|
|
|
rune = getr();
|
|
|
|
// 0xb7 · is used for internal names
|
2010-05-20 18:34:22 -06:00
|
|
|
if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7))
|
2010-02-16 17:47:39 -07:00
|
|
|
yyerror("invalid identifier character 0x%ux", rune);
|
|
|
|
cp += runetochar(cp, &rune);
|
2010-07-21 00:45:33 -06:00
|
|
|
} else if(!yy_isalnum(c) && c != '_')
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
2010-02-16 17:47:39 -07:00
|
|
|
else
|
|
|
|
*cp++ = c;
|
2008-06-04 15:37:38 -06:00
|
|
|
c = getc();
|
|
|
|
}
|
|
|
|
*cp = 0;
|
|
|
|
ungetc(c);
|
|
|
|
|
2009-04-02 18:59:09 -06:00
|
|
|
s = lookup(lexbuf);
|
2009-06-06 13:46:38 -06:00
|
|
|
switch(s->lexical) {
|
|
|
|
case LIGNORE:
|
2008-06-04 15:37:38 -06:00
|
|
|
goto l0;
|
|
|
|
|
2009-06-06 13:46:38 -06:00
|
|
|
case LFOR:
|
|
|
|
case LIF:
|
|
|
|
case LSWITCH:
|
|
|
|
case LSELECT:
|
|
|
|
loophack = 1; // see comment about loophack above
|
|
|
|
break;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
DBG("lex: %S %s\n", s, lexname(s->lexical));
|
|
|
|
yylval.sym = s;
|
|
|
|
return s->lexical;
|
|
|
|
|
|
|
|
tnum:
|
2009-04-02 18:59:09 -06:00
|
|
|
cp = lexbuf;
|
2010-06-09 12:00:55 -06:00
|
|
|
ep = lexbuf+sizeof lexbuf;
|
2008-06-04 15:37:38 -06:00
|
|
|
if(c != '0') {
|
|
|
|
for(;;) {
|
2010-06-09 12:00:55 -06:00
|
|
|
if(cp+10 >= ep) {
|
|
|
|
yyerror("identifier too long");
|
|
|
|
errorexit();
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
*cp++ = c;
|
|
|
|
c = getc();
|
2010-07-21 00:45:33 -06:00
|
|
|
if(yy_isdigit(c))
|
2008-06-04 15:37:38 -06:00
|
|
|
continue;
|
|
|
|
goto dc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*cp++ = c;
|
|
|
|
c = getc();
|
2008-07-05 13:49:25 -06:00
|
|
|
if(c == 'x' || c == 'X') {
|
2008-06-04 15:37:38 -06:00
|
|
|
for(;;) {
|
2010-06-09 12:00:55 -06:00
|
|
|
if(cp+10 >= ep) {
|
|
|
|
yyerror("identifier too long");
|
|
|
|
errorexit();
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
*cp++ = c;
|
|
|
|
c = getc();
|
2010-07-21 00:45:33 -06:00
|
|
|
if(yy_isdigit(c))
|
2008-06-04 15:37:38 -06:00
|
|
|
continue;
|
|
|
|
if(c >= 'a' && c <= 'f')
|
|
|
|
continue;
|
|
|
|
if(c >= 'A' && c <= 'F')
|
|
|
|
continue;
|
2009-04-02 18:59:09 -06:00
|
|
|
if(cp == lexbuf+2)
|
2008-06-04 15:37:38 -06:00
|
|
|
yyerror("malformed hex constant");
|
|
|
|
goto ncu;
|
|
|
|
}
|
2008-07-05 13:49:25 -06:00
|
|
|
}
|
|
|
|
|
2009-06-04 12:06:37 -06:00
|
|
|
if(c == 'p') // 0p begins floating point zero
|
|
|
|
goto casep;
|
|
|
|
|
2008-07-05 13:49:25 -06:00
|
|
|
c1 = 0;
|
2008-06-04 15:37:38 -06:00
|
|
|
for(;;) {
|
2010-06-09 12:00:55 -06:00
|
|
|
if(cp+10 >= ep) {
|
|
|
|
yyerror("identifier too long");
|
|
|
|
errorexit();
|
|
|
|
}
|
2010-07-21 00:45:33 -06:00
|
|
|
if(!yy_isdigit(c))
|
2008-07-05 13:49:25 -06:00
|
|
|
break;
|
|
|
|
if(c < '0' || c > '7')
|
|
|
|
c1 = 1; // not octal
|
|
|
|
*cp++ = c;
|
|
|
|
c = getc();
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2008-07-05 13:49:25 -06:00
|
|
|
if(c == '.')
|
|
|
|
goto casedot;
|
|
|
|
if(c == 'e' || c == 'E')
|
|
|
|
goto casee;
|
2010-02-17 23:08:30 -07:00
|
|
|
if(c == 'i')
|
|
|
|
goto casei;
|
2008-07-05 13:49:25 -06:00
|
|
|
if(c1)
|
|
|
|
yyerror("malformed octal constant");
|
|
|
|
goto ncu;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
dc:
|
|
|
|
if(c == '.')
|
|
|
|
goto casedot;
|
|
|
|
if(c == 'e' || c == 'E')
|
|
|
|
goto casee;
|
2008-12-03 14:17:26 -07:00
|
|
|
if(c == 'p' || c == 'P')
|
|
|
|
goto casep;
|
2010-02-17 23:08:30 -07:00
|
|
|
if(c == 'i')
|
|
|
|
goto casei;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
ncu:
|
|
|
|
*cp = 0;
|
|
|
|
ungetc(c);
|
2008-08-08 18:13:31 -06:00
|
|
|
|
|
|
|
yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
|
2009-04-02 18:59:09 -06:00
|
|
|
mpatofix(yylval.val.u.xval, lexbuf);
|
2008-08-08 18:13:31 -06:00
|
|
|
if(yylval.val.u.xval->ovf) {
|
2008-06-04 15:37:38 -06:00
|
|
|
yyerror("overflow in constant");
|
2008-08-08 18:13:31 -06:00
|
|
|
mpmovecfix(yylval.val.u.xval, 0);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
yylval.val.ctype = CTINT;
|
|
|
|
DBG("lex: integer literal\n");
|
2011-07-27 12:36:21 -06:00
|
|
|
strcpy(litbuf, "literal ");
|
|
|
|
strcat(litbuf, lexbuf);
|
2008-06-04 15:37:38 -06:00
|
|
|
return LLITERAL;
|
|
|
|
|
|
|
|
casedot:
|
|
|
|
for(;;) {
|
2010-06-09 12:00:55 -06:00
|
|
|
if(cp+10 >= ep) {
|
|
|
|
yyerror("identifier too long");
|
|
|
|
errorexit();
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
*cp++ = c;
|
|
|
|
c = getc();
|
2010-07-21 00:45:33 -06:00
|
|
|
if(!yy_isdigit(c))
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
|
|
|
}
|
2010-02-17 23:08:30 -07:00
|
|
|
if(c == 'i')
|
|
|
|
goto casei;
|
2008-06-04 15:37:38 -06:00
|
|
|
if(c != 'e' && c != 'E')
|
|
|
|
goto caseout;
|
|
|
|
|
|
|
|
casee:
|
|
|
|
*cp++ = 'e';
|
|
|
|
c = getc();
|
|
|
|
if(c == '+' || c == '-') {
|
|
|
|
*cp++ = c;
|
|
|
|
c = getc();
|
|
|
|
}
|
2010-07-21 00:45:33 -06:00
|
|
|
if(!yy_isdigit(c))
|
2008-06-04 15:37:38 -06:00
|
|
|
yyerror("malformed fp constant exponent");
|
2010-07-21 00:45:33 -06:00
|
|
|
while(yy_isdigit(c)) {
|
2010-06-09 12:00:55 -06:00
|
|
|
if(cp+10 >= ep) {
|
|
|
|
yyerror("identifier too long");
|
|
|
|
errorexit();
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
*cp++ = c;
|
|
|
|
c = getc();
|
|
|
|
}
|
2010-02-17 23:08:30 -07:00
|
|
|
if(c == 'i')
|
|
|
|
goto casei;
|
2008-12-03 14:17:26 -07:00
|
|
|
goto caseout;
|
|
|
|
|
|
|
|
casep:
|
|
|
|
*cp++ = 'p';
|
|
|
|
c = getc();
|
|
|
|
if(c == '+' || c == '-') {
|
|
|
|
*cp++ = c;
|
|
|
|
c = getc();
|
|
|
|
}
|
2010-07-21 00:45:33 -06:00
|
|
|
if(!yy_isdigit(c))
|
2008-12-03 14:17:26 -07:00
|
|
|
yyerror("malformed fp constant exponent");
|
2010-07-21 00:45:33 -06:00
|
|
|
while(yy_isdigit(c)) {
|
2010-06-09 12:00:55 -06:00
|
|
|
if(cp+10 >= ep) {
|
|
|
|
yyerror("identifier too long");
|
|
|
|
errorexit();
|
|
|
|
}
|
2008-12-03 14:17:26 -07:00
|
|
|
*cp++ = c;
|
|
|
|
c = getc();
|
|
|
|
}
|
2010-02-17 23:08:30 -07:00
|
|
|
if(c == 'i')
|
|
|
|
goto casei;
|
2008-12-03 14:17:26 -07:00
|
|
|
goto caseout;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2010-02-17 23:08:30 -07:00
|
|
|
casei:
|
|
|
|
// imaginary constant
|
|
|
|
*cp = 0;
|
|
|
|
yylval.val.u.cval = mal(sizeof(*yylval.val.u.cval));
|
|
|
|
mpmovecflt(&yylval.val.u.cval->real, 0.0);
|
|
|
|
mpatoflt(&yylval.val.u.cval->imag, lexbuf);
|
|
|
|
if(yylval.val.u.cval->imag.val.ovf) {
|
|
|
|
yyerror("overflow in imaginary constant");
|
|
|
|
mpmovecflt(&yylval.val.u.cval->real, 0.0);
|
|
|
|
}
|
|
|
|
yylval.val.ctype = CTCPLX;
|
|
|
|
DBG("lex: imaginary literal\n");
|
2011-07-27 12:36:21 -06:00
|
|
|
strcpy(litbuf, "literal ");
|
|
|
|
strcat(litbuf, lexbuf);
|
2010-02-17 23:08:30 -07:00
|
|
|
return LLITERAL;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
caseout:
|
|
|
|
*cp = 0;
|
|
|
|
ungetc(c);
|
2008-08-08 18:13:31 -06:00
|
|
|
|
|
|
|
yylval.val.u.fval = mal(sizeof(*yylval.val.u.fval));
|
2009-04-02 18:59:09 -06:00
|
|
|
mpatoflt(yylval.val.u.fval, lexbuf);
|
2008-12-01 18:22:05 -07:00
|
|
|
if(yylval.val.u.fval->val.ovf) {
|
2008-06-04 15:37:38 -06:00
|
|
|
yyerror("overflow in float constant");
|
2008-08-08 18:13:31 -06:00
|
|
|
mpmovecflt(yylval.val.u.fval, 0.0);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
yylval.val.ctype = CTFLT;
|
|
|
|
DBG("lex: floating literal\n");
|
2011-07-27 12:36:21 -06:00
|
|
|
strcpy(litbuf, "literal ");
|
|
|
|
strcat(litbuf, lexbuf);
|
2008-06-04 15:37:38 -06:00
|
|
|
return LLITERAL;
|
|
|
|
}
|
|
|
|
|
2010-07-15 21:21:33 -06:00
|
|
|
/*
|
|
|
|
* read and interpret syntax that looks like
|
2010-07-16 14:34:36 -06:00
|
|
|
* //line parse.y:15
|
2010-07-16 16:08:31 -06:00
|
|
|
* as a discontinuity in sequential line numbers.
|
2010-07-15 21:21:33 -06:00
|
|
|
* the next line of input comes from parse.y:15
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
getlinepragma(void)
|
|
|
|
{
|
|
|
|
int i, c, n;
|
2011-12-12 13:41:54 -07:00
|
|
|
char *cp, *ep, *linep;
|
2010-07-15 21:21:33 -06:00
|
|
|
Hist *h;
|
|
|
|
|
|
|
|
for(i=0; i<5; i++) {
|
|
|
|
c = getr();
|
|
|
|
if(c != "line "[i])
|
2010-07-16 14:34:36 -06:00
|
|
|
goto out;
|
2010-07-15 21:21:33 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
cp = lexbuf;
|
|
|
|
ep = lexbuf+sizeof(lexbuf)-5;
|
2011-12-12 13:41:54 -07:00
|
|
|
linep = nil;
|
2010-07-15 21:21:33 -06:00
|
|
|
for(;;) {
|
|
|
|
c = getr();
|
2011-12-12 13:41:54 -07:00
|
|
|
if(c == EOF)
|
2010-07-16 14:34:36 -06:00
|
|
|
goto out;
|
2011-12-12 13:41:54 -07:00
|
|
|
if(c == '\n')
|
|
|
|
break;
|
2010-07-15 21:21:33 -06:00
|
|
|
if(c == ' ')
|
|
|
|
continue;
|
2010-07-16 14:34:36 -06:00
|
|
|
if(c == ':')
|
2011-12-12 13:41:54 -07:00
|
|
|
linep = cp;
|
2010-07-16 14:34:36 -06:00
|
|
|
if(cp < ep)
|
|
|
|
*cp++ = c;
|
2010-07-15 21:21:33 -06:00
|
|
|
}
|
|
|
|
*cp = 0;
|
2010-07-16 14:34:36 -06:00
|
|
|
|
2011-12-12 13:41:54 -07:00
|
|
|
if(linep == nil || linep >= ep)
|
|
|
|
goto out;
|
|
|
|
*linep++ = '\0';
|
2010-07-16 14:34:36 -06:00
|
|
|
n = 0;
|
2011-12-12 13:41:54 -07:00
|
|
|
for(cp=linep; *cp; cp++) {
|
|
|
|
if(*cp < '0' || *cp > '9')
|
|
|
|
goto out;
|
|
|
|
n = n*10 + *cp - '0';
|
2010-07-21 00:45:33 -06:00
|
|
|
if(n > 1e8) {
|
|
|
|
yyerror("line number out of range");
|
|
|
|
errorexit();
|
|
|
|
}
|
2010-07-16 14:34:36 -06:00
|
|
|
}
|
2011-12-12 13:41:54 -07:00
|
|
|
if(n <= 0)
|
2010-07-16 14:34:36 -06:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
// try to avoid allocating file name over and over
|
|
|
|
for(h=hist; h!=H; h=h->link) {
|
|
|
|
if(h->name != nil && strcmp(h->name, lexbuf) == 0) {
|
|
|
|
linehist(h->name, n, 0);
|
|
|
|
goto out;
|
2010-07-15 21:21:33 -06:00
|
|
|
}
|
|
|
|
}
|
2010-07-16 14:34:36 -06:00
|
|
|
linehist(strdup(lexbuf), n, 0);
|
|
|
|
|
|
|
|
out:
|
2010-07-15 21:21:33 -06:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2009-06-06 20:27:48 -06:00
|
|
|
int32
|
|
|
|
yylex(void)
|
|
|
|
{
|
2009-12-11 16:59:41 -07:00
|
|
|
int lx;
|
|
|
|
|
|
|
|
lx = _yylex();
|
|
|
|
|
|
|
|
if(curio.nlsemi && lx == EOF) {
|
2010-09-28 08:35:02 -06:00
|
|
|
// Treat EOF as "end of line" for the purposes
|
|
|
|
// of inserting a semicolon.
|
2009-12-11 16:59:41 -07:00
|
|
|
lx = ';';
|
2009-06-06 20:27:48 -06:00
|
|
|
}
|
|
|
|
|
2009-12-11 16:59:41 -07:00
|
|
|
switch(lx) {
|
|
|
|
case LNAME:
|
|
|
|
case LLITERAL:
|
|
|
|
case LBREAK:
|
|
|
|
case LCONTINUE:
|
|
|
|
case LFALL:
|
|
|
|
case LRETURN:
|
|
|
|
case LINC:
|
|
|
|
case LDEC:
|
|
|
|
case ')':
|
|
|
|
case '}':
|
|
|
|
case ']':
|
|
|
|
curio.nlsemi = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
curio.nlsemi = 0;
|
|
|
|
break;
|
2009-06-06 20:27:48 -06:00
|
|
|
}
|
2010-07-15 16:05:56 -06:00
|
|
|
|
|
|
|
// Track last two tokens returned by yylex.
|
|
|
|
yyprev = yylast;
|
|
|
|
yylast = lx;
|
2011-12-05 12:40:19 -07:00
|
|
|
return lx;
|
2009-06-06 20:27:48 -06:00
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static int
|
2008-06-04 15:37:38 -06:00
|
|
|
getc(void)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
|
|
|
c = curio.peekc;
|
|
|
|
if(c != 0) {
|
2008-10-29 13:46:44 -06:00
|
|
|
curio.peekc = curio.peekc1;
|
|
|
|
curio.peekc1 = 0;
|
2009-10-07 15:55:12 -06:00
|
|
|
if(c == '\n' && pushedio.bin == nil)
|
2009-08-19 16:18:08 -06:00
|
|
|
lexlineno++;
|
2008-06-04 15:37:38 -06:00
|
|
|
return c;
|
|
|
|
}
|
2011-04-23 08:54:05 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
if(curio.bin == nil) {
|
|
|
|
c = *curio.cp & 0xff;
|
|
|
|
if(c != 0)
|
|
|
|
curio.cp++;
|
|
|
|
} else
|
|
|
|
c = Bgetc(curio.bin);
|
|
|
|
|
|
|
|
switch(c) {
|
|
|
|
case 0:
|
2010-02-16 17:47:39 -07:00
|
|
|
if(curio.bin != nil) {
|
|
|
|
yyerror("illegal NUL byte");
|
2008-07-09 17:05:03 -06:00
|
|
|
break;
|
2010-02-16 17:47:39 -07:00
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
case EOF:
|
2011-04-23 08:54:05 -06:00
|
|
|
// insert \n at EOF
|
|
|
|
if(curio.eofnl)
|
|
|
|
return EOF;
|
|
|
|
curio.eofnl = 1;
|
|
|
|
c = '\n';
|
2008-06-04 15:37:38 -06:00
|
|
|
case '\n':
|
2009-10-07 15:55:12 -06:00
|
|
|
if(pushedio.bin == nil)
|
|
|
|
lexlineno++;
|
2008-06-04 15:37:38 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static void
|
2008-06-04 15:37:38 -06:00
|
|
|
ungetc(int c)
|
|
|
|
{
|
2008-10-29 13:46:44 -06:00
|
|
|
curio.peekc1 = curio.peekc;
|
2008-06-04 15:37:38 -06:00
|
|
|
curio.peekc = c;
|
2009-10-07 15:55:12 -06:00
|
|
|
if(c == '\n' && pushedio.bin == nil)
|
2009-08-19 16:18:08 -06:00
|
|
|
lexlineno--;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static int32
|
2008-06-04 15:37:38 -06:00
|
|
|
getr(void)
|
|
|
|
{
|
|
|
|
int c, i;
|
|
|
|
char str[UTFmax+1];
|
|
|
|
Rune rune;
|
|
|
|
|
|
|
|
c = getc();
|
|
|
|
if(c < Runeself)
|
|
|
|
return c;
|
|
|
|
i = 0;
|
|
|
|
str[i++] = c;
|
|
|
|
|
|
|
|
loop:
|
|
|
|
c = getc();
|
|
|
|
str[i++] = c;
|
|
|
|
if(!fullrune(str, i))
|
|
|
|
goto loop;
|
|
|
|
c = chartorune(&rune, str);
|
|
|
|
if(rune == Runeerror && c == 1) {
|
2009-12-03 00:23:11 -07:00
|
|
|
lineno = lexlineno;
|
2010-02-16 17:47:39 -07:00
|
|
|
yyerror("illegal UTF-8 sequence");
|
2009-12-03 00:23:11 -07:00
|
|
|
flusherrors();
|
2010-02-16 17:47:39 -07:00
|
|
|
print("\t");
|
2008-06-04 15:37:38 -06:00
|
|
|
for(c=0; c<i; c++)
|
2010-02-16 17:47:39 -07:00
|
|
|
print("%s%.2x", c > 0 ? " " : "", *(uchar*)(str+c));
|
2008-06-04 15:37:38 -06:00
|
|
|
print("\n");
|
|
|
|
}
|
|
|
|
return rune;
|
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static int
|
2008-06-08 20:02:27 -06:00
|
|
|
escchar(int e, int *escflg, vlong *val)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2010-06-08 19:50:02 -06:00
|
|
|
int i, u, c;
|
2008-06-06 20:16:18 -06:00
|
|
|
vlong l;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-06-08 20:02:27 -06:00
|
|
|
*escflg = 0;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
c = getr();
|
2009-06-18 16:49:41 -06:00
|
|
|
switch(c) {
|
|
|
|
case EOF:
|
|
|
|
yyerror("eof in string");
|
|
|
|
return 1;
|
|
|
|
case '\n':
|
2008-06-04 15:37:38 -06:00
|
|
|
yyerror("newline in string");
|
2008-06-06 20:16:18 -06:00
|
|
|
return 1;
|
2009-06-18 16:49:41 -06:00
|
|
|
case '\\':
|
|
|
|
break;
|
|
|
|
default:
|
2008-06-04 15:37:38 -06:00
|
|
|
if(c == e)
|
2008-06-06 20:16:18 -06:00
|
|
|
return 1;
|
|
|
|
*val = c;
|
|
|
|
return 0;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2008-06-06 20:16:18 -06:00
|
|
|
|
2010-06-08 19:50:02 -06:00
|
|
|
u = 0;
|
2008-06-04 15:37:38 -06:00
|
|
|
c = getr();
|
|
|
|
switch(c) {
|
|
|
|
case 'x':
|
2008-06-08 20:02:27 -06:00
|
|
|
*escflg = 1; // it's a byte
|
2008-06-04 15:37:38 -06:00
|
|
|
i = 2;
|
|
|
|
goto hex;
|
|
|
|
|
|
|
|
case 'u':
|
|
|
|
i = 4;
|
2010-06-08 19:50:02 -06:00
|
|
|
u = 1;
|
2008-06-04 15:37:38 -06:00
|
|
|
goto hex;
|
|
|
|
|
|
|
|
case 'U':
|
|
|
|
i = 8;
|
2010-06-08 19:50:02 -06:00
|
|
|
u = 1;
|
2008-06-04 15:37:38 -06:00
|
|
|
goto hex;
|
|
|
|
|
|
|
|
case '0':
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
2008-06-08 20:02:27 -06:00
|
|
|
*escflg = 1; // it's a byte
|
2008-06-04 15:37:38 -06:00
|
|
|
goto oct;
|
|
|
|
|
2008-06-06 20:16:18 -06:00
|
|
|
case 'a': c = '\a'; break;
|
|
|
|
case 'b': c = '\b'; break;
|
|
|
|
case 'f': c = '\f'; break;
|
|
|
|
case 'n': c = '\n'; break;
|
|
|
|
case 'r': c = '\r'; break;
|
|
|
|
case 't': c = '\t'; break;
|
|
|
|
case 'v': c = '\v'; break;
|
|
|
|
case '\\': c = '\\'; break;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
default:
|
|
|
|
if(c != e)
|
2008-06-21 16:11:29 -06:00
|
|
|
yyerror("unknown escape sequence: %c", c);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2008-06-06 20:16:18 -06:00
|
|
|
*val = c;
|
|
|
|
return 0;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
hex:
|
|
|
|
l = 0;
|
|
|
|
for(; i>0; i--) {
|
|
|
|
c = getc();
|
|
|
|
if(c >= '0' && c <= '9') {
|
|
|
|
l = l*16 + c-'0';
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(c >= 'a' && c <= 'f') {
|
|
|
|
l = l*16 + c-'a' + 10;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(c >= 'A' && c <= 'F') {
|
|
|
|
l = l*16 + c-'A' + 10;
|
|
|
|
continue;
|
|
|
|
}
|
2008-06-21 16:11:29 -06:00
|
|
|
yyerror("non-hex character in escape sequence: %c", c);
|
2008-06-04 15:37:38 -06:00
|
|
|
ungetc(c);
|
|
|
|
break;
|
|
|
|
}
|
2010-06-09 12:00:55 -06:00
|
|
|
if(u && (l > Runemax || (0xd800 <= l && l < 0xe000))) {
|
2010-06-08 19:50:02 -06:00
|
|
|
yyerror("invalid Unicode code point in escape sequence: %#llx", l);
|
|
|
|
l = Runeerror;
|
|
|
|
}
|
2008-06-06 20:16:18 -06:00
|
|
|
*val = l;
|
|
|
|
return 0;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
oct:
|
|
|
|
l = c - '0';
|
|
|
|
for(i=2; i>0; i--) {
|
|
|
|
c = getc();
|
|
|
|
if(c >= '0' && c <= '7') {
|
|
|
|
l = l*8 + c-'0';
|
|
|
|
continue;
|
|
|
|
}
|
2010-02-16 17:47:39 -07:00
|
|
|
yyerror("non-octal character in escape sequence: %c", c);
|
2008-06-04 15:37:38 -06:00
|
|
|
ungetc(c);
|
|
|
|
}
|
|
|
|
if(l > 255)
|
2010-02-16 17:47:39 -07:00
|
|
|
yyerror("octal escape value > 255: %d", l);
|
2008-06-08 20:02:27 -06:00
|
|
|
|
2008-06-06 20:16:18 -06:00
|
|
|
*val = l;
|
|
|
|
return 0;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct
|
|
|
|
{
|
|
|
|
char* name;
|
|
|
|
int lexical;
|
|
|
|
int etype;
|
2009-06-06 13:46:38 -06:00
|
|
|
int op;
|
2008-06-04 15:37:38 -06:00
|
|
|
} syms[] =
|
|
|
|
{
|
2009-06-06 13:46:38 -06:00
|
|
|
/* name lexical etype op
|
2008-06-04 15:37:38 -06:00
|
|
|
*/
|
|
|
|
/* basic types */
|
2009-06-06 13:46:38 -06:00
|
|
|
"int8", LNAME, TINT8, OXXX,
|
|
|
|
"int16", LNAME, TINT16, OXXX,
|
|
|
|
"int32", LNAME, TINT32, OXXX,
|
|
|
|
"int64", LNAME, TINT64, OXXX,
|
|
|
|
|
|
|
|
"uint8", LNAME, TUINT8, OXXX,
|
|
|
|
"uint16", LNAME, TUINT16, OXXX,
|
|
|
|
"uint32", LNAME, TUINT32, OXXX,
|
|
|
|
"uint64", LNAME, TUINT64, OXXX,
|
|
|
|
|
|
|
|
"float32", LNAME, TFLOAT32, OXXX,
|
|
|
|
"float64", LNAME, TFLOAT64, OXXX,
|
|
|
|
|
2010-02-17 23:08:30 -07:00
|
|
|
"complex64", LNAME, TCOMPLEX64, OXXX,
|
|
|
|
"complex128", LNAME, TCOMPLEX128, OXXX,
|
|
|
|
|
2009-06-06 13:46:38 -06:00
|
|
|
"bool", LNAME, TBOOL, OXXX,
|
|
|
|
"string", LNAME, TSTRING, OXXX,
|
|
|
|
|
|
|
|
"any", LNAME, TANY, OXXX,
|
|
|
|
|
|
|
|
"break", LBREAK, Txxx, OXXX,
|
|
|
|
"case", LCASE, Txxx, OXXX,
|
|
|
|
"chan", LCHAN, Txxx, OXXX,
|
|
|
|
"const", LCONST, Txxx, OXXX,
|
|
|
|
"continue", LCONTINUE, Txxx, OXXX,
|
|
|
|
"default", LDEFAULT, Txxx, OXXX,
|
|
|
|
"else", LELSE, Txxx, OXXX,
|
|
|
|
"defer", LDEFER, Txxx, OXXX,
|
|
|
|
"fallthrough", LFALL, Txxx, OXXX,
|
|
|
|
"for", LFOR, Txxx, OXXX,
|
|
|
|
"func", LFUNC, Txxx, OXXX,
|
|
|
|
"go", LGO, Txxx, OXXX,
|
|
|
|
"goto", LGOTO, Txxx, OXXX,
|
|
|
|
"if", LIF, Txxx, OXXX,
|
|
|
|
"import", LIMPORT, Txxx, OXXX,
|
|
|
|
"interface", LINTERFACE, Txxx, OXXX,
|
|
|
|
"map", LMAP, Txxx, OXXX,
|
|
|
|
"package", LPACKAGE, Txxx, OXXX,
|
|
|
|
"range", LRANGE, Txxx, OXXX,
|
|
|
|
"return", LRETURN, Txxx, OXXX,
|
|
|
|
"select", LSELECT, Txxx, OXXX,
|
|
|
|
"struct", LSTRUCT, Txxx, OXXX,
|
|
|
|
"switch", LSWITCH, Txxx, OXXX,
|
|
|
|
"type", LTYPE, Txxx, OXXX,
|
|
|
|
"var", LVAR, Txxx, OXXX,
|
|
|
|
|
2011-12-05 12:40:19 -07:00
|
|
|
"append", LNAME, Txxx, OAPPEND,
|
2009-06-06 13:46:38 -06:00
|
|
|
"cap", LNAME, Txxx, OCAP,
|
|
|
|
"close", LNAME, Txxx, OCLOSE,
|
2011-01-19 21:08:11 -07:00
|
|
|
"complex", LNAME, Txxx, OCOMPLEX,
|
2009-11-17 21:41:44 -07:00
|
|
|
"copy", LNAME, Txxx, OCOPY,
|
2011-12-05 12:40:19 -07:00
|
|
|
"delete", LNAME, Txxx, ODELETE,
|
2010-03-05 21:16:04 -07:00
|
|
|
"imag", LNAME, Txxx, OIMAG,
|
2009-06-06 13:46:38 -06:00
|
|
|
"len", LNAME, Txxx, OLEN,
|
|
|
|
"make", LNAME, Txxx, OMAKE,
|
|
|
|
"new", LNAME, Txxx, ONEW,
|
|
|
|
"panic", LNAME, Txxx, OPANIC,
|
|
|
|
"print", LNAME, Txxx, OPRINT,
|
|
|
|
"println", LNAME, Txxx, OPRINTN,
|
2010-03-05 21:16:04 -07:00
|
|
|
"real", LNAME, Txxx, OREAL,
|
2010-03-30 11:53:16 -06:00
|
|
|
"recover", LNAME, Txxx, ORECOVER,
|
2009-06-06 13:46:38 -06:00
|
|
|
|
|
|
|
"notwithstanding", LIGNORE, Txxx, OXXX,
|
|
|
|
"thetruthofthematter", LIGNORE, Txxx, OXXX,
|
|
|
|
"despiteallobjections", LIGNORE, Txxx, OXXX,
|
|
|
|
"whereas", LIGNORE, Txxx, OXXX,
|
|
|
|
"insofaras", LIGNORE, Txxx, OXXX,
|
2008-06-04 15:37:38 -06:00
|
|
|
};
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static void
|
2008-06-04 15:37:38 -06:00
|
|
|
lexinit(void)
|
|
|
|
{
|
2009-03-30 18:09:28 -06:00
|
|
|
int i, lex;
|
2009-09-09 02:01:39 -06:00
|
|
|
Sym *s, *s1;
|
2009-03-30 18:09:28 -06:00
|
|
|
Type *t;
|
|
|
|
int etype;
|
2011-12-05 12:40:19 -07:00
|
|
|
Val v;
|
2008-08-08 18:13:31 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
/*
|
|
|
|
* initialize basic types array
|
|
|
|
* initialize known symbols
|
|
|
|
*/
|
|
|
|
for(i=0; i<nelem(syms); i++) {
|
|
|
|
lex = syms[i].lexical;
|
|
|
|
s = lookup(syms[i].name);
|
|
|
|
s->lexical = lex;
|
|
|
|
|
2009-05-22 23:46:06 -06:00
|
|
|
etype = syms[i].etype;
|
2009-06-06 13:46:38 -06:00
|
|
|
if(etype != Txxx) {
|
|
|
|
if(etype < 0 || etype >= nelem(types))
|
|
|
|
fatal("lexinit: %s bad etype", s->name);
|
|
|
|
t = types[etype];
|
|
|
|
if(t == T) {
|
|
|
|
t = typ(etype);
|
|
|
|
t->sym = s;
|
|
|
|
|
2009-08-07 13:50:26 -06:00
|
|
|
if(etype != TANY && etype != TSTRING)
|
|
|
|
dowidth(t);
|
2009-06-06 13:46:38 -06:00
|
|
|
types[etype] = t;
|
|
|
|
}
|
2010-01-22 18:06:20 -07:00
|
|
|
s1 = pkglookup(syms[i].name, builtinpkg);
|
2009-09-09 02:01:39 -06:00
|
|
|
s1->lexical = LNAME;
|
|
|
|
s1->def = typenod(t);
|
2008-06-04 15:37:38 -06:00
|
|
|
continue;
|
|
|
|
}
|
2011-12-05 12:40:19 -07:00
|
|
|
|
|
|
|
etype = syms[i].op;
|
|
|
|
if(etype != OXXX) {
|
|
|
|
s1 = pkglookup(syms[i].name, builtinpkg);
|
|
|
|
s1->lexical = LNAME;
|
|
|
|
s1->def = nod(ONAME, N, N);
|
2011-12-09 06:28:17 -07:00
|
|
|
s1->def->sym = s1;
|
2011-12-05 12:40:19 -07:00
|
|
|
s1->def->etype = etype;
|
|
|
|
s1->def->builtin = 1;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2009-05-08 16:40:31 -06:00
|
|
|
|
|
|
|
// 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);
|
2012-02-21 20:54:07 -07:00
|
|
|
idealbool = typ(TBOOL);
|
2009-09-21 16:45:55 -06:00
|
|
|
|
2010-01-22 18:06:20 -07:00
|
|
|
s = pkglookup("true", builtinpkg);
|
2009-09-21 16:45:55 -06:00
|
|
|
s->def = nodbool(1);
|
|
|
|
s->def->sym = lookup("true");
|
2012-02-21 20:54:07 -07:00
|
|
|
s->def->type = idealbool;
|
2009-09-21 16:45:55 -06:00
|
|
|
|
2010-01-22 18:06:20 -07:00
|
|
|
s = pkglookup("false", builtinpkg);
|
2009-09-21 16:45:55 -06:00
|
|
|
s->def = nodbool(0);
|
|
|
|
s->def->sym = lookup("false");
|
2012-02-21 20:54:07 -07:00
|
|
|
s->def->type = idealbool;
|
2009-09-09 00:16:19 -06:00
|
|
|
|
|
|
|
s = lookup("_");
|
|
|
|
s->block = -100;
|
|
|
|
s->def = nod(ONAME, N, N);
|
|
|
|
s->def->sym = s;
|
|
|
|
types[TBLANK] = typ(TBLANK);
|
|
|
|
s->def->type = types[TBLANK];
|
2009-09-09 01:18:16 -06:00
|
|
|
nblank = s->def;
|
2011-12-05 12:40:19 -07:00
|
|
|
|
|
|
|
s = pkglookup("_", builtinpkg);
|
|
|
|
s->block = -100;
|
|
|
|
s->def = nod(ONAME, N, N);
|
|
|
|
s->def->sym = s;
|
|
|
|
types[TBLANK] = typ(TBLANK);
|
|
|
|
s->def->type = types[TBLANK];
|
|
|
|
|
|
|
|
types[TNIL] = typ(TNIL);
|
|
|
|
s = pkglookup("nil", builtinpkg);
|
|
|
|
v.ctype = CTNIL;
|
|
|
|
s->def = nodlit(v);
|
|
|
|
s->def->sym = s;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2011-10-18 12:55:50 -06:00
|
|
|
static void
|
|
|
|
lexinit1(void)
|
|
|
|
{
|
|
|
|
Sym *s, *s1;
|
2011-11-01 19:46:41 -06:00
|
|
|
Type *t, *f, *rcvr, *in, *out;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
errortype = t;
|
|
|
|
errortype->sym = s;
|
|
|
|
s1 = pkglookup("error", builtinpkg);
|
|
|
|
s1->lexical = LNAME;
|
|
|
|
s1->def = typenod(errortype);
|
2011-10-18 12:55:50 -06:00
|
|
|
|
|
|
|
// byte alias
|
|
|
|
s = lookup("byte");
|
|
|
|
s->lexical = LNAME;
|
|
|
|
bytetype = typ(TUINT8);
|
|
|
|
bytetype->sym = s;
|
|
|
|
s1 = pkglookup("byte", builtinpkg);
|
|
|
|
s1->lexical = LNAME;
|
|
|
|
s1->def = typenod(bytetype);
|
2011-10-25 23:19:39 -06:00
|
|
|
|
|
|
|
// rune alias
|
|
|
|
s = lookup("rune");
|
|
|
|
s->lexical = LNAME;
|
2011-12-08 22:12:07 -07:00
|
|
|
runetype = typ(TINT32);
|
2011-10-25 23:19:39 -06:00
|
|
|
runetype->sym = s;
|
|
|
|
s1 = pkglookup("rune", builtinpkg);
|
|
|
|
s1->lexical = LNAME;
|
|
|
|
s1->def = typenod(runetype);
|
2011-10-18 12:55:50 -06:00
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static void
|
2009-09-09 02:01:39 -06:00
|
|
|
lexfini(void)
|
|
|
|
{
|
|
|
|
Sym *s;
|
|
|
|
int lex, etype, i;
|
|
|
|
Val v;
|
|
|
|
|
|
|
|
for(i=0; i<nelem(syms); i++) {
|
|
|
|
lex = syms[i].lexical;
|
|
|
|
if(lex != LNAME)
|
|
|
|
continue;
|
|
|
|
s = lookup(syms[i].name);
|
|
|
|
s->lexical = lex;
|
|
|
|
|
|
|
|
etype = syms[i].etype;
|
2010-06-12 12:17:24 -06:00
|
|
|
if(etype != Txxx && (etype != TANY || debug['A']) && s->def == N)
|
|
|
|
s->def = typenod(types[etype]);
|
2009-09-09 02:01:39 -06:00
|
|
|
|
|
|
|
etype = syms[i].op;
|
2010-06-12 12:17:24 -06:00
|
|
|
if(etype != OXXX && s->def == N) {
|
|
|
|
s->def = nod(ONAME, N, N);
|
2009-09-09 02:01:39 -06:00
|
|
|
s->def->sym = s;
|
|
|
|
s->def->etype = etype;
|
|
|
|
s->def->builtin = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i=0; typedefs[i].name; i++) {
|
|
|
|
s = lookup(typedefs[i].name);
|
2010-06-12 12:17:24 -06:00
|
|
|
if(s->def == N)
|
|
|
|
s->def = typenod(types[typedefs[i].etype]);
|
2009-09-09 02:01:39 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// there's only so much table-driven we can handle.
|
|
|
|
// these are special cases.
|
2011-10-18 12:55:50 -06:00
|
|
|
s = lookup("byte");
|
|
|
|
if(s->def == N)
|
|
|
|
s->def = typenod(bytetype);
|
2011-11-01 19:46:41 -06:00
|
|
|
|
|
|
|
s = lookup("error");
|
|
|
|
if(s->def == N)
|
|
|
|
s->def = typenod(errortype);
|
2011-10-18 12:55:50 -06:00
|
|
|
|
2011-10-25 23:19:39 -06:00
|
|
|
s = lookup("rune");
|
|
|
|
if(s->def == N)
|
|
|
|
s->def = typenod(runetype);
|
|
|
|
|
2009-09-09 02:01:39 -06:00
|
|
|
s = lookup("nil");
|
2010-06-12 12:17:24 -06:00
|
|
|
if(s->def == N) {
|
2009-09-09 02:01:39 -06:00
|
|
|
v.ctype = CTNIL;
|
2010-06-12 12:17:24 -06:00
|
|
|
s->def = nodlit(v);
|
|
|
|
s->def->sym = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = lookup("iota");
|
|
|
|
if(s->def == N) {
|
|
|
|
s->def = nod(OIOTA, N, N);
|
2009-09-09 02:01:39 -06:00
|
|
|
s->def->sym = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = lookup("true");
|
2010-06-12 12:17:24 -06:00
|
|
|
if(s->def == N) {
|
|
|
|
s->def = nodbool(1);
|
2009-09-09 02:01:39 -06:00
|
|
|
s->def->sym = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = lookup("false");
|
2010-06-12 12:17:24 -06:00
|
|
|
if(s->def == N) {
|
|
|
|
s->def = nodbool(0);
|
2009-09-09 02:01:39 -06:00
|
|
|
s->def->sym = s;
|
|
|
|
}
|
2010-03-31 12:46:01 -06:00
|
|
|
|
|
|
|
nodfp = nod(ONAME, N, N);
|
|
|
|
nodfp->type = types[TINT32];
|
|
|
|
nodfp->xoffset = 0;
|
|
|
|
nodfp->class = PPARAM;
|
|
|
|
nodfp->sym = lookup(".fp");
|
2009-09-09 02:01:39 -06:00
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
int lex;
|
|
|
|
char* name;
|
|
|
|
} lexn[] =
|
|
|
|
{
|
|
|
|
LANDAND, "ANDAND",
|
|
|
|
LASOP, "ASOP",
|
|
|
|
LBREAK, "BREAK",
|
|
|
|
LCASE, "CASE",
|
|
|
|
LCHAN, "CHAN",
|
|
|
|
LCOLAS, "COLAS",
|
|
|
|
LCONST, "CONST",
|
|
|
|
LCONTINUE, "CONTINUE",
|
|
|
|
LDEC, "DEC",
|
2009-06-06 13:46:38 -06:00
|
|
|
LDEFER, "DEFER",
|
2008-06-04 15:37:38 -06:00
|
|
|
LELSE, "ELSE",
|
|
|
|
LEQ, "EQ",
|
2009-06-06 13:46:38 -06:00
|
|
|
LFALL, "FALL",
|
|
|
|
LFOR, "FOR",
|
2008-06-04 15:37:38 -06:00
|
|
|
LFUNC, "FUNC",
|
|
|
|
LGE, "GE",
|
|
|
|
LGO, "GO",
|
|
|
|
LGOTO, "GOTO",
|
|
|
|
LGT, "GT",
|
|
|
|
LIF, "IF",
|
2009-06-06 13:46:38 -06:00
|
|
|
LIMPORT, "IMPORT",
|
2008-06-04 15:37:38 -06:00
|
|
|
LINC, "INC",
|
|
|
|
LINTERFACE, "INTERFACE",
|
|
|
|
LLE, "LE",
|
|
|
|
LLITERAL, "LITERAL",
|
|
|
|
LLSH, "LSH",
|
|
|
|
LLT, "LT",
|
|
|
|
LMAP, "MAP",
|
|
|
|
LNAME, "NAME",
|
|
|
|
LNE, "NE",
|
|
|
|
LOROR, "OROR",
|
2009-06-06 13:46:38 -06:00
|
|
|
LPACKAGE, "PACKAGE",
|
2008-06-04 15:37:38 -06:00
|
|
|
LRANGE, "RANGE",
|
|
|
|
LRETURN, "RETURN",
|
|
|
|
LRSH, "RSH",
|
|
|
|
LSTRUCT, "STRUCT",
|
|
|
|
LSWITCH, "SWITCH",
|
|
|
|
LTYPE, "TYPE",
|
|
|
|
LVAR, "VAR",
|
|
|
|
};
|
|
|
|
|
|
|
|
char*
|
|
|
|
lexname(int lex)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
static char buf[100];
|
|
|
|
|
|
|
|
for(i=0; i<nelem(lexn); i++)
|
|
|
|
if(lexn[i].lex == lex)
|
|
|
|
return lexn[i].name;
|
|
|
|
snprint(buf, sizeof(buf), "LEX-%d", lex);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2010-01-27 00:13:22 -07:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
char *have;
|
|
|
|
char *want;
|
|
|
|
} yytfix[] =
|
|
|
|
{
|
|
|
|
"$end", "EOF",
|
|
|
|
"LLITERAL", "literal",
|
|
|
|
"LASOP", "op=",
|
|
|
|
"LBREAK", "break",
|
|
|
|
"LCASE", "case",
|
|
|
|
"LCOLAS", ":=",
|
|
|
|
"LCONST", "const",
|
|
|
|
"LCONTINUE", "continue",
|
|
|
|
"LDDD", "...",
|
|
|
|
"LDEFAULT", "default",
|
|
|
|
"LDEFER", "defer",
|
|
|
|
"LELSE", "else",
|
|
|
|
"LFALL", "fallthrough",
|
|
|
|
"LFOR", "for",
|
|
|
|
"LFUNC", "func",
|
|
|
|
"LGO", "go",
|
|
|
|
"LGOTO", "goto",
|
|
|
|
"LIF", "if",
|
|
|
|
"LIMPORT", "import",
|
|
|
|
"LINTERFACE", "interface",
|
|
|
|
"LMAP", "map",
|
|
|
|
"LNAME", "name",
|
|
|
|
"LPACKAGE", "package",
|
|
|
|
"LRANGE", "range",
|
|
|
|
"LRETURN", "return",
|
|
|
|
"LSELECT", "select",
|
|
|
|
"LSTRUCT", "struct",
|
|
|
|
"LSWITCH", "switch",
|
|
|
|
"LTYPE", "type",
|
|
|
|
"LVAR", "var",
|
|
|
|
"LANDAND", "&&",
|
|
|
|
"LANDNOT", "&^",
|
|
|
|
"LBODY", "{",
|
|
|
|
"LCOMM", "<-",
|
|
|
|
"LDEC", "--",
|
|
|
|
"LINC", "++",
|
|
|
|
"LEQ", "==",
|
|
|
|
"LGE", ">=",
|
|
|
|
"LGT", ">",
|
|
|
|
"LLE", "<=",
|
|
|
|
"LLT", "<",
|
|
|
|
"LLSH", "<<",
|
|
|
|
"LRSH", ">>",
|
|
|
|
"LOROR", "||",
|
|
|
|
"LNE", "!=",
|
2010-01-28 16:57:44 -07:00
|
|
|
|
|
|
|
// spell out to avoid confusion with punctuation in error messages
|
|
|
|
"';'", "semicolon or newline",
|
|
|
|
"','", "comma",
|
2010-01-27 00:13:22 -07:00
|
|
|
};
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static void
|
2010-01-27 00:13:22 -07:00
|
|
|
yytinit(void)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
extern char *yytname[];
|
|
|
|
char *s, *t;
|
|
|
|
|
|
|
|
for(i=0; yytname[i] != nil; i++) {
|
|
|
|
s = yytname[i];
|
|
|
|
|
2011-07-27 12:36:21 -06:00
|
|
|
if(strcmp(s, "LLITERAL") == 0) {
|
|
|
|
strcpy(litbuf, "literal");
|
|
|
|
yytname[i] = litbuf;
|
|
|
|
goto loop;
|
|
|
|
}
|
|
|
|
|
2010-01-28 16:57:44 -07:00
|
|
|
// apply yytfix if possible
|
|
|
|
for(j=0; j<nelem(yytfix); j++) {
|
|
|
|
if(strcmp(s, yytfix[j].have) == 0) {
|
|
|
|
yytname[i] = yytfix[j].want;
|
|
|
|
goto loop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-27 00:13:22 -07:00
|
|
|
// turn 'x' into x.
|
|
|
|
if(s[0] == '\'') {
|
|
|
|
t = strdup(s+1);
|
|
|
|
t[strlen(t)-1] = '\0';
|
|
|
|
yytname[i] = t;
|
|
|
|
}
|
2010-01-28 16:57:44 -07:00
|
|
|
loop:;
|
2010-01-27 00:13:22 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
2010-01-22 18:06:20 -07:00
|
|
|
mkpackage(char* pkgname)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
|
|
|
Sym *s;
|
2008-08-03 18:25:15 -06:00
|
|
|
int32 h;
|
2008-06-05 20:38:39 -06:00
|
|
|
char *p;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2010-01-22 18:06:20 -07:00
|
|
|
if(localpkg->name == nil) {
|
|
|
|
if(strcmp(pkgname, "_") == 0)
|
2009-09-17 17:42:10 -06:00
|
|
|
yyerror("invalid package name _");
|
2010-01-22 18:06:20 -07:00
|
|
|
localpkg->name = pkgname;
|
2009-08-12 14:18:19 -06:00
|
|
|
} else {
|
2010-01-22 18:06:20 -07:00
|
|
|
if(strcmp(pkgname, localpkg->name) != 0)
|
|
|
|
yyerror("package %s; expected %s", pkgname, localpkg->name);
|
2009-08-12 14:18:19 -06:00
|
|
|
for(h=0; h<NHASH; h++) {
|
|
|
|
for(s = hash[h]; s != S; s = s->link) {
|
2010-01-22 18:06:20 -07:00
|
|
|
if(s->def == N || s->pkg != localpkg)
|
2009-08-12 14:18:19 -06:00
|
|
|
continue;
|
|
|
|
if(s->def->op == OPACK) {
|
|
|
|
// throw away top-level package name leftover
|
|
|
|
// from previous file.
|
2010-01-18 17:26:40 -07:00
|
|
|
// leave s->block set to cause redeclaration
|
|
|
|
// errors if a conflicting top-level name is
|
|
|
|
// introduced by a different file.
|
2009-10-12 12:03:48 -06:00
|
|
|
if(!s->def->used && !nsyntaxerrors)
|
2011-09-07 13:50:21 -06:00
|
|
|
yyerrorl(s->def->lineno, "imported and not used: \"%Z\"", s->def->pkg->path);
|
2009-08-12 14:18:19 -06:00
|
|
|
s->def = N;
|
|
|
|
continue;
|
|
|
|
}
|
2009-09-09 02:01:39 -06:00
|
|
|
if(s->def->sym != s) {
|
2009-08-12 14:18:19 -06:00
|
|
|
// throw away top-level name left over
|
|
|
|
// from previous import . "x"
|
2009-10-12 12:03:48 -06:00
|
|
|
if(s->def->pack != N && !s->def->pack->used && !nsyntaxerrors) {
|
2011-09-07 13:50:21 -06:00
|
|
|
yyerrorl(s->def->pack->lineno, "imported and not used: \"%Z\"", s->def->pack->pkg->path);
|
2009-09-17 17:42:10 -06:00
|
|
|
s->def->pack->used = 1;
|
|
|
|
}
|
2009-08-12 14:18:19 -06:00
|
|
|
s->def = N;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if(outfile == nil) {
|
2008-06-05 20:38:39 -06:00
|
|
|
p = strrchr(infile, '/');
|
|
|
|
if(p == nil)
|
|
|
|
p = infile;
|
|
|
|
else
|
|
|
|
p = p+1;
|
|
|
|
snprint(namebuf, sizeof(namebuf), "%s", p);
|
|
|
|
p = strrchr(namebuf, '.');
|
|
|
|
if(p != nil)
|
|
|
|
*p = 0;
|
2009-03-30 22:31:29 -06:00
|
|
|
outfile = smprint("%s.%c", namebuf, thechar);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
}
|