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.
|
|
|
|
|
|
|
|
#define EXTERN
|
|
|
|
#include "go.h"
|
|
|
|
#include "y.tab.h"
|
2008-07-09 17:05:03 -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);
|
|
|
|
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
|
|
|
|
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
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
#define DBG if(!debug['x']);else print
|
|
|
|
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");
|
|
|
|
// -A is allow use of "any" type, for bootstrapping
|
|
|
|
print(" -I DIR search for packages in DIR\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(" -o file specify output file\n");
|
|
|
|
print(" -S print the assembly language\n");
|
|
|
|
print(" -V print the compiler version\n");
|
|
|
|
print(" -u disable package unsafe\n");
|
|
|
|
print(" -w print the parse tree after typing\n");
|
|
|
|
print(" -x print lex tokens\n");
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
NodeList *l;
|
2010-04-27 14:52:43 -06:00
|
|
|
char *p;
|
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
|
|
|
stringpkg = mkpkg(strlit("string"));
|
2010-01-24 23:36:26 -07:00
|
|
|
stringpkg->name = "string";
|
|
|
|
|
2010-01-22 18:06:20 -07:00
|
|
|
typepkg = mkpkg(strlit("type"));
|
2010-01-24 23:36:26 -07:00
|
|
|
typepkg->name = "type";
|
|
|
|
|
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;
|
|
|
|
|
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;
|
|
|
|
|
2009-03-10 21:03:31 -06:00
|
|
|
case 'I':
|
2010-06-09 12:00:55 -06:00
|
|
|
addidir(EARGF(usage()));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'u':
|
|
|
|
safemode = 1;
|
2009-03-10 21:03:31 -06:00
|
|
|
break;
|
2010-06-09 12:00:55 -06:00
|
|
|
|
2010-02-08 10:46:53 -07:00
|
|
|
case 'V':
|
|
|
|
print("%cg version %s\n", thechar, getgoversion());
|
2010-06-09 12:00:55 -06:00
|
|
|
exit(0);
|
2008-06-04 15:37:38 -06:00
|
|
|
} ARGEND
|
|
|
|
|
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 = '/';
|
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
fmtinstall('O', Oconv); // node opcodes
|
|
|
|
fmtinstall('E', Econv); // etype opcodes
|
|
|
|
fmtinstall('J', Jconv); // all the node flags
|
|
|
|
fmtinstall('S', Sconv); // sym pointer
|
|
|
|
fmtinstall('T', Tconv); // type pointer
|
|
|
|
fmtinstall('N', Nconv); // node pointer
|
|
|
|
fmtinstall('Z', Zconv); // escaped string
|
2008-06-13 19:16:23 -06:00
|
|
|
fmtinstall('L', Lconv); // line number
|
2008-08-11 14:22:04 -06:00
|
|
|
fmtinstall('B', Bconv); // big numbers
|
2008-12-01 18:22:05 -07:00
|
|
|
fmtinstall('F', Fconv); // big float numbers
|
2008-10-03 17:15:55 -06:00
|
|
|
|
2009-03-30 18:09:28 -06:00
|
|
|
betypeinit();
|
|
|
|
if(maxround == 0 || widthptr == 0)
|
|
|
|
fatal("betypeinit failed");
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
lexinit();
|
2009-06-06 13:46:38 -06:00
|
|
|
typeinit();
|
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;
|
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
|
|
|
|
|
|
|
// Process top-level declarations in three 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.
|
|
|
|
// Phase 2: Variable assignments.
|
|
|
|
// To check interface assignments, depends on phase 1.
|
|
|
|
// Phase 3: Function bodies.
|
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);
|
|
|
|
for(l=xtop; l; l=l->next)
|
|
|
|
if(l->n->op == ODCL || l->n->op == OAS)
|
|
|
|
typecheck(&l->n, Etop);
|
2009-08-12 14:18:19 -06:00
|
|
|
resumecheckwidth();
|
|
|
|
for(l=xtop; l; l=l->next)
|
|
|
|
if(l->n->op == ODCLFUNC)
|
2010-03-31 12:46:01 -06:00
|
|
|
funccompile(l->n, 0);
|
2009-08-12 14:18:19 -06:00
|
|
|
if(nerrors == 0)
|
|
|
|
fninit(xtop);
|
|
|
|
while(closures) {
|
|
|
|
l = closures;
|
|
|
|
closures = nil;
|
|
|
|
for(; l; l=l->next)
|
2010-03-31 12:46:01 -06:00
|
|
|
funccompile(l->n, 1);
|
2009-08-12 14:18:19 -06:00
|
|
|
}
|
|
|
|
dclchecks();
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
if(nerrors)
|
|
|
|
errorexit();
|
|
|
|
|
|
|
|
dumpobj();
|
|
|
|
|
2008-07-27 14:09:15 -06:00
|
|
|
if(nerrors)
|
|
|
|
errorexit();
|
|
|
|
|
2010-03-30 00:34:59 -06:00
|
|
|
flusherrors();
|
2009-03-24 13:12:57 -06:00
|
|
|
exit(0);
|
2008-06-04 15:37:38 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static int
|
2008-11-19 15:21:44 -07:00
|
|
|
arsize(Biobuf *b, char *name)
|
|
|
|
{
|
2008-07-09 17:05:03 -06:00
|
|
|
struct ar_hdr *a;
|
|
|
|
|
|
|
|
if((a = Brdline(b, '\n')) == nil)
|
2008-11-19 15:21:44 -07:00
|
|
|
return -1;
|
2008-07-09 17:05:03 -06:00
|
|
|
if(Blinelen(b) != sizeof(struct ar_hdr))
|
2008-11-19 15:21:44 -07:00
|
|
|
return -1;
|
2008-07-09 17:05:03 -06:00
|
|
|
if(strncmp(a->name, name, strlen(name)) != 0)
|
2008-11-19 15:21:44 -07:00
|
|
|
return -1;
|
2008-07-09 17:05:03 -06:00
|
|
|
return atoi(a->size);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
if(name->len >= 3 && strncmp(name->s, "../", 3) == 0)
|
|
|
|
return 1;
|
|
|
|
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;
|
2008-07-09 17:05:03 -06:00
|
|
|
|
2009-06-25 21:15:56 -06:00
|
|
|
if(islocalname(name)) {
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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;
|
2010-01-26 17:12:50 -07:00
|
|
|
char *file;
|
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;
|
2010-03-08 18:00:14 -07:00
|
|
|
char *cleanbuf;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
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");
|
|
|
|
return;
|
|
|
|
}
|
2008-06-25 21:22:10 -06:00
|
|
|
|
2010-04-11 15:52:06 -06:00
|
|
|
if(strlen(f->u.sval->s) != f->u.sval->len) {
|
|
|
|
yyerror("import path contains NUL");
|
|
|
|
errorexit();
|
|
|
|
}
|
2010-01-22 18:06:20 -07:00
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-01-22 18:06:20 -07:00
|
|
|
path = f->u.sval;
|
|
|
|
if(islocalname(path)) {
|
2010-03-08 18:00:14 -07:00
|
|
|
cleanbuf = mal(strlen(pathname) + strlen(path->s) + 2);
|
|
|
|
sprint(cleanbuf, "%s/%s", pathname, 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)) {
|
|
|
|
yyerror("can't find import: %Z", f->u.sval);
|
|
|
|
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) {
|
2010-07-16 22:38:51 -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)) {
|
|
|
|
yyerror("import not package file: %s", namebuf);
|
|
|
|
errorexit();
|
|
|
|
}
|
2009-04-08 23:45:33 -06:00
|
|
|
}
|
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;
|
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;
|
|
|
|
}
|
2008-08-08 18:13:31 -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;
|
|
|
|
}
|
2009-01-31 17:44:52 -07:00
|
|
|
if(0x80 <= c && c <= 0xa0) // 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;
|
|
|
|
c1 = 0;
|
|
|
|
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();
|
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");
|
|
|
|
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);
|
2008-06-04 15:37:38 -06:00
|
|
|
yylval.val.ctype = CTINT;
|
|
|
|
DBG("lex: codepoint literal\n");
|
|
|
|
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(;;) {
|
2009-12-11 16:59:41 -07:00
|
|
|
if(c == '\n') {
|
|
|
|
ungetc(c);
|
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
|
|
|
if(c == EOF) {
|
|
|
|
yyerror("eof in comment");
|
|
|
|
errorexit();
|
|
|
|
}
|
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;
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
return c;
|
|
|
|
|
|
|
|
asop:
|
2008-08-08 18:13:31 -06:00
|
|
|
yylval.lint = 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:
|
|
|
|
c1 = 0;
|
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");
|
|
|
|
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");
|
|
|
|
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");
|
|
|
|
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;
|
|
|
|
char *cp, *ep;
|
|
|
|
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;
|
|
|
|
for(;;) {
|
|
|
|
c = getr();
|
2010-07-16 14:34:36 -06:00
|
|
|
if(c == '\n' || c == EOF)
|
|
|
|
goto out;
|
2010-07-15 21:21:33 -06:00
|
|
|
if(c == ' ')
|
|
|
|
continue;
|
2010-07-16 14:34:36 -06:00
|
|
|
if(c == ':')
|
2010-07-15 21:21:33 -06:00
|
|
|
break;
|
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
|
|
|
|
|
|
|
n = 0;
|
|
|
|
for(;;) {
|
|
|
|
c = getr();
|
2010-07-21 00:45:33 -06:00
|
|
|
if(!yy_isdigit(c))
|
2010-07-16 14:34:36 -06:00
|
|
|
break;
|
|
|
|
n = n*10 + (c-'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
|
|
|
}
|
|
|
|
|
|
|
|
if(c != '\n' || n <= 0)
|
|
|
|
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) {
|
|
|
|
// if the nlsemi bit is set, we'd be willing to
|
|
|
|
// insert a ; if we saw a \n, but we didn't.
|
|
|
|
// that means the final \n is missing.
|
|
|
|
// complain here, because we can give a
|
|
|
|
// good message. the syntax error we'd get
|
|
|
|
// otherwise is inscrutable.
|
|
|
|
yyerror("missing newline at end of file");
|
|
|
|
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;
|
2010-07-16 14:34:36 -06: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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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:
|
|
|
|
return EOF;
|
|
|
|
|
|
|
|
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,
|
|
|
|
"byte", LNAME, TUINT8, 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,
|
|
|
|
|
|
|
|
"cap", LNAME, Txxx, OCAP,
|
|
|
|
"close", LNAME, Txxx, OCLOSE,
|
|
|
|
"closed", LNAME, Txxx, OCLOSED,
|
2010-03-05 21:16:04 -07:00
|
|
|
"cmplx", LNAME, Txxx, OCMPLX,
|
2009-11-17 21:41:44 -07:00
|
|
|
"copy", LNAME, Txxx, OCOPY,
|
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;
|
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;
|
|
|
|
}
|
|
|
|
}
|
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);
|
2009-09-21 16:45:55 -06:00
|
|
|
idealbool = typ(TBOOL);
|
|
|
|
|
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");
|
|
|
|
s->def->type = idealbool;
|
|
|
|
|
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");
|
|
|
|
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;
|
2008-06-04 15:37:38 -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.
|
|
|
|
types[TNIL] = typ(TNIL);
|
|
|
|
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->noescape = 1;
|
|
|
|
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];
|
|
|
|
|
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)
|
2010-03-03 18:23:47 -07: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) {
|
2010-03-03 18:23:47 -07: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
|
|
|
}
|
|
|
|
}
|