// 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" #include #define DBG if(!debug['x']);else print enum { EOF = -1, }; int mainlex(int argc, char *argv[]) { int c; outfile = nil; package = "____"; ARGBEGIN { default: c = ARGC(); if(c >= 0 && c < sizeof(debug)) debug[c]++; break; case 'o': outfile = ARGF(); break; case 'k': package = ARGF(); break; } ARGEND if(argc != 1) goto usage; pathname = mal(100); if(mygetwd(pathname, 99) == 0) strcpy(pathname, "/???"); 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 fmtinstall('L', Lconv); // line number fmtinstall('B', Bconv); // big numbers lexinit(); lineno = 1; block = 1; blockgen = 1; setfilename(argv[0]); infile = argv[0]; linehist(infile, 0); curio.infile = infile; curio.bin = Bopen(infile, OREAD); if(curio.bin == nil) fatal("cant open: %s", infile); curio.peekc = 0; externdcl = mal(sizeof(*externdcl)); externdcl->back = externdcl; dclcontext = PEXTERN; exportlist = mal(sizeof(*exportlist)); exportlist->back = exportlist; // function field skeleton fskel = nod(OLIST, N, nod(OLIST, N, N)); fskel->left = nod(ODCLFIELD, N, N); fskel->right->left = nod(ODCLFIELD, N, N); fskel->right->right = nod(ODCLFIELD, N, N); nerrors = 0; yyparse(); linehist(nil, 0); if(curio.bin != nil) Bterm(curio.bin); if(nerrors) errorexit(); dumpobj(); if(nerrors) errorexit(); myexit(0); return 0; usage: print("flags:\n"); print(" -d print declarations\n"); print(" -f print stack frame structure\n"); print(" -k name specify package name\n"); print(" -o file specify output file\n"); print(" -p print the assembly language\n"); print(" -w print the parse tree after typing\n"); print(" -x print lex tokens\n"); print(" -h panic on an error\n"); myexit(0); return 0; } void setfilename(char *file) { char *p; p = strrchr(file, '/'); if(p != nil) file = p+1; strncpy(namebuf, file, sizeof(namebuf)); p = strchr(namebuf, '.'); if(p != nil) *p = 0; filename = strdup(namebuf); } int arsize(Biobuf *b, char *name){ struct ar_hdr *a; if((a = Brdline(b, '\n')) == nil) return 0; if(Blinelen(b) != sizeof(struct ar_hdr)) return 0; if(strncmp(a->name, name, strlen(name)) != 0) return 0; return atoi(a->size); } int 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, "!\n", 8) != 0) return 0; /* symbol table is first; skip it */ sz = arsize(b, "__.SYMDEF"); if(sz <= 0) return 0; Bseek(b, sz, 1); /* package export block is second */ sz = arsize(b, "__.PKGDEF"); if(sz <= 0) return 0; return 1; } int findpkg(String *name) { static char* goroot; if(goroot == nil) { goroot = getenv("GOROOT"); if(goroot == nil) return 0; } // BOTCH need to get .6 from backend snprint(namebuf, sizeof(namebuf), "%Z.6", name); if(access(namebuf, 0) >= 0) return 1; snprint(namebuf, sizeof(namebuf), "%Z.a", name); if(access(namebuf, 0) >= 0) return 1; snprint(namebuf, sizeof(namebuf), "%s/pkg/%Z.6", goroot, name); if(access(namebuf, 0) >= 0) return 1; snprint(namebuf, sizeof(namebuf), "%s/pkg/%Z.a", goroot, name); if(access(namebuf, 0) >= 0) return 1; return 0; } void importfile(Val *f) { Biobuf *imp; char *file; int32 c; char *p; int len; if(f->ctype != CTSTR) { yyerror("import statement not a string"); return; } if(!findpkg(f->u.sval)) fatal("can't find import: %Z", f->u.sval); imp = Bopen(namebuf, OREAD); if(imp == nil) fatal("can't open import: %Z", f->u.sval); file = strdup(namebuf); len = strlen(namebuf); if(len > 2) if(namebuf[len-2] == '.') if(namebuf[len-1] == 'a') if(!skiptopkgdef(imp)) fatal("import not package file: %s", namebuf); linehist(file, 0); linehist(file, -1); // acts as #pragma lib /* * position the input right * after (( and return */ pushedio = curio; curio.bin = imp; curio.peekc = 0; curio.infile = file; for(;;) { c = getc(); if(c == EOF) break; if(c != '(') continue; c = getc(); if(c == EOF) break; if(c != '(') continue; return; } yyerror("no import in: %Z", f->u.sval); unimportfile(); } void unimportfile(void) { linehist(nil, 0); if(curio.bin != nil) { Bterm(curio.bin); curio.bin = nil; } else lineno--; // re correct sys.6 line number curio = pushedio; pushedio.bin = nil; inimportsys = 0; } void cannedimports(void) { char *file; file = "sys.6"; lineno++; // if sys.6 is included on line 1, linehist(file, 0); // the debugger gets confused pushedio = curio; curio.bin = nil; curio.peekc = 0; curio.infile = file; curio.cp = sysimport; pkgmyname = S; inimportsys = 1; } int32 yylex(void) { int c, c1; vlong v; char *cp; Rune rune; int escflag; Sym *s; l0: c = getc(); if(isspace(c)) goto l0; if(c >= Runeself) { /* all multibyte runes are alpha */ cp = namebuf; goto talph; } if(isalpha(c)) { cp = namebuf; goto talph; } if(isdigit(c)) goto tnum; switch(c) { case EOF: ungetc(EOF); return -1; case '_': cp = namebuf; goto talph; case '.': c1 = getc(); if(isdigit(c1)) { cp = namebuf; *cp++ = c; c = c1; c1 = 0; goto casedot; } break; case '"': /* "..." */ strcpy(namebuf, "\"\""); cp = mal(sizeof(int32)); c1 = sizeof(int32); caseq: for(;;) { if(escchar('"', &escflag, &v)) break; if(v < Runeself || escflag) { cp = remal(cp, c1, 1); cp[c1++] = v; } else { // botch - this limits size of runes rune = v; c = runelen(rune); cp = remal(cp, c1, c); runetochar(cp+c1, &rune); c1 += c; } } goto catem; case '`': /* `...` */ strcpy(namebuf, "``"); cp = mal(sizeof(int32)); c1 = sizeof(int32); casebq: for(;;) { c = getc(); if(c == EOF || c == '`') break; cp = remal(cp, c1, 1); cp[c1++] = c; } catem: for(;;) { /* it takes 2 peekc's to skip comments */ c = getc(); if(isspace(c)) continue; if(c == '"') goto caseq; if(c == '`') goto casebq; ungetc(c); break; } *(int32*)cp = c1-sizeof(int32); // length do { cp = remal(cp, c1, 1); cp[c1++] = 0; } while(c1 & MAXALIGN); yylval.val.u.sval = (String*)cp; yylval.val.ctype = CTSTR; DBG("lex: string literal\n"); return LLITERAL; case '\'': /* '.' */ if(escchar('\'', &escflag, &v)) v = '\''; // allow ''' if(!escchar('\'', &escflag, &v)) { yyerror("missing '"); ungetc(v); } yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval)); mpmovecfix(yylval.val.u.xval, v); yylval.val.ctype = CTINT; DBG("lex: codepoint literal\n"); return LLITERAL; case '/': c1 = getc(); if(c1 == '*') { for(;;) { c = getr(); while(c == '*') { c = getr(); if(c == '/') goto l0; } if(c == EOF) { yyerror("eof in comment"); errorexit(); } } } if(c1 == '/') { for(;;) { c = getr(); if(c == '\n') goto l0; if(c == EOF) { yyerror("eof in comment"); errorexit(); } } } 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 = LSEND; 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; } if(c1 == '-') { c = LRECV; goto lx; } 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; } 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; default: goto lx; } ungetc(c1); lx: if(c > 0xff) DBG("lex: TOKEN %s\n", lexname(c)); else DBG("lex: TOKEN '%c'\n", c); return c; asop: yylval.lint = c; // rathole to hold which asop DBG("lex: TOKEN ASOP %c\n", c); return LASOP; talph: /* * cp is set to namebuf and some * prefix has been stored */ for(;;) { if(c >= Runeself) { for(c1=0;;) { cp[c1++] = c; if(fullrune(cp, c1)) break; c = getc(); } cp += c1; c = getc(); continue; } if(!isalnum(c) && c != '_') break; *cp++ = c; c = getc(); } *cp = 0; ungetc(c); s = lookup(namebuf); if(s->lexical == LIGNORE) goto l0; if(context != nil) { s = pkglookup(s->name, context); if(s->lexical == LIGNORE) goto l0; } DBG("lex: %S %s\n", s, lexname(s->lexical)); yylval.sym = s; if(s->lexical == LBASETYPE) return LATYPE; return s->lexical; tnum: c1 = 0; cp = namebuf; if(c != '0') { for(;;) { *cp++ = c; c = getc(); if(isdigit(c)) continue; goto dc; } } *cp++ = c; c = getc(); if(c == 'x' || c == 'X') { for(;;) { *cp++ = c; c = getc(); if(isdigit(c)) continue; if(c >= 'a' && c <= 'f') continue; if(c >= 'A' && c <= 'F') continue; if(cp == namebuf+2) yyerror("malformed hex constant"); goto ncu; } } c1 = 0; for(;;) { if(!isdigit(c)) break; if(c < '0' || c > '7') c1 = 1; // not octal *cp++ = c; c = getc(); } if(c == '.') goto casedot; if(c == 'e' || c == 'E') goto casee; if(c1) yyerror("malformed octal constant"); goto ncu; dc: if(c == '.') goto casedot; if(c == 'e' || c == 'E') goto casee; ncu: *cp = 0; ungetc(c); yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval)); mpatofix(yylval.val.u.xval, namebuf); if(yylval.val.u.xval->ovf) { yyerror("overflow in constant"); mpmovecfix(yylval.val.u.xval, 0); } yylval.val.ctype = CTINT; DBG("lex: integer literal\n"); return LLITERAL; casedot: for(;;) { *cp++ = c; c = getc(); if(!isdigit(c)) break; } if(c != 'e' && c != 'E') goto caseout; casee: *cp++ = 'e'; c = getc(); if(c == '+' || c == '-') { *cp++ = c; c = getc(); } if(!isdigit(c)) yyerror("malformed fp constant exponent"); while(isdigit(c)) { *cp++ = c; c = getc(); } caseout: *cp = 0; ungetc(c); yylval.val.u.fval = mal(sizeof(*yylval.val.u.fval)); mpatoflt(yylval.val.u.fval, namebuf); if(yylval.val.u.fval->ovf) { yyerror("overflow in float constant"); mpmovecflt(yylval.val.u.fval, 0.0); } yylval.val.ctype = CTFLT; DBG("lex: floating literal\n"); return LLITERAL; } int getc(void) { int c; c = curio.peekc; if(c != 0) { curio.peekc = 0; if(c == '\n') lineno++; return c; } if(curio.bin == nil) { c = *curio.cp & 0xff; if(c != 0) curio.cp++; } else c = Bgetc(curio.bin); switch(c) { case 0: if(curio.bin != nil) break; case EOF: return EOF; case '\n': lineno++; break; } return c; } void ungetc(int c) { curio.peekc = c; if(c == '\n') lineno--; } int32 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) { yyerror("illegal rune in string"); for(c=0; c0; 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; } yyerror("non-hex character in escape sequence: %c", c); ungetc(c); break; } *val = l; return 0; oct: l = c - '0'; for(i=2; i>0; i--) { c = getc(); if(c >= '0' && c <= '7') { l = l*8 + c-'0'; continue; } yyerror("non-oct character in escape sequence: %c", c); ungetc(c); } if(l > 255) yyerror("oct escape value > 255: %d", l); *val = l; return 0; } static struct { char* name; int lexical; int etype; } syms[] = { /* name lexical etype */ /* basic types */ "int8", LBASETYPE, TINT8, "int16", LBASETYPE, TINT16, "int32", LBASETYPE, TINT32, "int64", LBASETYPE, TINT64, "uint8", LBASETYPE, TUINT8, "uint16", LBASETYPE, TUINT16, "uint32", LBASETYPE, TUINT32, "uint64", LBASETYPE, TUINT64, "float32", LBASETYPE, TFLOAT32, "float64", LBASETYPE, TFLOAT64, "float80", LBASETYPE, TFLOAT80, "bool", LBASETYPE, TBOOL, "byte", LBASETYPE, TUINT8, "char", LBASETYPE, TUINT8, // temp?? "string", LBASETYPE, TSTRING, "any", LBASETYPE, TANY, "sys", LPACK, Txxx, /* keywords */ "break", LBREAK, Txxx, "case", LCASE, Txxx, "chan", LCHAN, Txxx, "const", LCONST, Txxx, "continue", LCONTINUE, Txxx, "convert", LCONVERT, Txxx, // should be a var "default", LDEFAULT, Txxx, "else", LELSE, Txxx, "export", LEXPORT, Txxx, "fallthrough", LFALL, Txxx, "false", LFALSE, Txxx, // should be a var "for", LFOR, Txxx, "func", LFUNC, Txxx, "go", LGO, Txxx, "goto", LGOTO, Txxx, "if", LIF, Txxx, "import", LIMPORT, Txxx, "interface", LINTERFACE, Txxx, "iota", LIOTA, Txxx, "map", LMAP, Txxx, "new", LNEW, Txxx, // should be a var "len", LLEN, Txxx, // should be a var "nil", LNIL, Txxx, // should be a var "package", LPACKAGE, Txxx, "panic", LPANIC, Txxx, // temp "print", LPRINT, Txxx, // temp "range", LRANGE, Txxx, "return", LRETURN, Txxx, "select", LSELECT, Txxx, "struct", LSTRUCT, Txxx, "switch", LSWITCH, Txxx, "true", LTRUE, Txxx, // should be a var "type", LTYPE, Txxx, "var", LVAR, Txxx, "notwithstanding", LIGNORE, Txxx, "thetruthofthematter", LIGNORE, Txxx, "despiteallobjections", LIGNORE, Txxx, "whereas", LIGNORE, Txxx, "insofaras", LIGNORE, Txxx, }; void lexinit(void) { int i, etype, lex; Sym *s; Type *t; besetptr(); for(i=TINT8; i<=TUINT64; i++) isint[i] = 1; for(i=TFLOAT32; i<=TFLOAT80; i++) isfloat[i] = 1; isptr[TPTR32] = 1; isptr[TPTR64] = 1; issigned[TINT8] = 1; issigned[TINT16] = 1; issigned[TINT32] = 1; issigned[TINT64] = 1; /* * initialize okfor */ for(i=0; ilexical = lex; if(lex != LBASETYPE) continue; etype = syms[i].etype; if(etype < 0 || etype >= nelem(types)) fatal("lexinit: %s bad etype", s->name); t = types[etype]; if(t != T) { s->otype = t; continue; } t = typ(etype); switch(etype) { case TSTRING: case TCHAN: case TMAP: t = ptrto(t); } t->sym = s; t->recur = 1; // supresses printing beyond name dowidth(t); types[etype] = t; s->otype = t; } /* pick up the backend typedefs */ belexinit(LBASETYPE); booltrue = nod(OLITERAL, N, N); booltrue->val.u.bval = 1; booltrue->val.ctype = CTBOOL; booltrue->type = types[TBOOL]; booltrue->addable = 1; boolfalse = nod(OLITERAL, N, N); boolfalse->val.u.bval = 0; boolfalse->val.ctype = CTBOOL; boolfalse->type = types[TBOOL]; boolfalse->addable = 1; } struct { int lex; char* name; } lexn[] = { LANDAND, "ANDAND", LASOP, "ASOP", LACONST, "ACONST", LATYPE, "ATYPE", LBASETYPE, "BASETYPE", LBREAK, "BREAK", LCASE, "CASE", LCHAN, "CHAN", LCOLAS, "COLAS", LCONST, "CONST", LCONTINUE, "CONTINUE", LDEC, "DEC", LELSE, "ELSE", LEQ, "EQ", LFUNC, "FUNC", LGE, "GE", LGO, "GO", LGOTO, "GOTO", LGT, "GT", LIF, "IF", LINC, "INC", LINTERFACE, "INTERFACE", LLE, "LE", LLITERAL, "LITERAL", LLSH, "LSH", LLT, "LT", LMAP, "MAP", LNAME, "NAME", LNE, "NE", LOROR, "OROR", LPACK, "PACK", LRANGE, "RANGE", LRETURN, "RETURN", LRSH, "RSH", LSTRUCT, "STRUCT", LSWITCH, "SWITCH", LTYPE, "TYPE", LVAR, "VAR", LFOR, "FOR", LNEW, "NEW", LLEN, "LEN", LFALL, "FALL", LCONVERT, "CONVERT", LIOTA, "IOTA", LPRINT, "PRINT", LPACKAGE, "PACKAGE", LIMPORT, "IMPORT", LEXPORT, "EXPORT", LPANIC, "PANIC", }; char* lexname(int lex) { int i; static char buf[100]; for(i=0; ilink) { s->package = package; s->opackage = package; } if(outfile == nil) { // BOTCH need to get .6 from backend 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; strncat(namebuf, ".6", sizeof(namebuf)); outfile = strdup(namebuf); } }