summaryrefslogtreecommitdiff
path: root/src/cmd/cc/macbody
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
committerOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
commit5ff4c17907d5b19510a62e08fd8d3b11e62b431d (patch)
treec0650497e988f47be9c6f2324fa692a52dea82e1 /src/cmd/cc/macbody
parent80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff)
downloadgolang-upstream/60.tar.gz
Imported Upstream version 60upstream/60
Diffstat (limited to 'src/cmd/cc/macbody')
-rw-r--r--src/cmd/cc/macbody852
1 files changed, 852 insertions, 0 deletions
diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody
new file mode 100644
index 000000000..ed66361f1
--- /dev/null
+++ b/src/cmd/cc/macbody
@@ -0,0 +1,852 @@
+// Inferno utils/cc/macbody
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#define VARMAC 0x80
+
+int32
+getnsn(void)
+{
+ int32 n;
+ int c;
+
+ c = getnsc();
+ if(c < '0' || c > '9')
+ return -1;
+ n = 0;
+ while(c >= '0' && c <= '9') {
+ n = n*10 + c-'0';
+ c = getc();
+ }
+ unget(c);
+ return n;
+}
+
+Sym*
+getsym(void)
+{
+ int c;
+ char *cp;
+
+ c = getnsc();
+ if(!isalpha(c) && c != '_' && c < 0x80) {
+ unget(c);
+ return S;
+ }
+ for(cp = symb;;) {
+ if(cp <= symb+NSYMB-4)
+ *cp++ = c;
+ c = getc();
+ if(isalnum(c) || c == '_' || c >= 0x80)
+ continue;
+ unget(c);
+ break;
+ }
+ *cp = 0;
+ if(cp > symb+NSYMB-4)
+ yyerror("symbol too large: %s", symb);
+ return lookup();
+}
+
+Sym*
+getsymdots(int *dots)
+{
+ int c;
+ Sym *s;
+
+ s = getsym();
+ if(s != S)
+ return s;
+
+ c = getnsc();
+ if(c != '.'){
+ unget(c);
+ return S;
+ }
+ if(getc() != '.' || getc() != '.')
+ yyerror("bad dots in macro");
+ *dots = 1;
+ return slookup("__VA_ARGS__");
+}
+
+int
+getcom(void)
+{
+ int c;
+
+ for(;;) {
+ c = getnsc();
+ if(c != '/')
+ break;
+ c = getc();
+ if(c == '/') {
+ while(c != '\n')
+ c = getc();
+ break;
+ }
+ if(c != '*')
+ break;
+ c = getc();
+ for(;;) {
+ if(c == '*') {
+ c = getc();
+ if(c != '/')
+ continue;
+ c = getc();
+ break;
+ }
+ if(c == '\n') {
+ yyerror("comment across newline");
+ break;
+ }
+ c = getc();
+ }
+ if(c == '\n')
+ break;
+ }
+ return c;
+}
+
+void
+dodefine(char *cp)
+{
+ Sym *s;
+ char *p;
+ int32 l;
+
+ ensuresymb(strlen(cp));
+ strcpy(symb, cp);
+ p = strchr(symb, '=');
+ if(p) {
+ *p++ = 0;
+ s = lookup();
+ l = strlen(p) + 2; /* +1 null, +1 nargs */
+ s->macro = alloc(l);
+ strcpy(s->macro+1, p);
+ } else {
+ s = lookup();
+ s->macro = "\0001"; /* \000 is nargs */
+ }
+ if(debug['m'])
+ print("#define (-D) %s %s\n", s->name, s->macro+1);
+}
+
+struct
+{
+ char *macname;
+ void (*macf)(void);
+} mactab[] =
+{
+ "ifdef", 0, /* macif(0) */
+ "ifndef", 0, /* macif(1) */
+ "else", 0, /* macif(2) */
+
+ "line", maclin,
+ "define", macdef,
+ "include", macinc,
+ "undef", macund,
+
+ "pragma", macprag,
+ "endif", macend,
+ 0
+};
+
+void
+domacro(void)
+{
+ int i;
+ Sym *s;
+
+ s = getsym();
+ if(s == S)
+ s = slookup("endif");
+ for(i=0; mactab[i].macname; i++)
+ if(strcmp(s->name, mactab[i].macname) == 0) {
+ if(mactab[i].macf)
+ (*mactab[i].macf)();
+ else
+ macif(i);
+ return;
+ }
+ yyerror("unknown #: %s", s->name);
+ macend();
+}
+
+void
+macund(void)
+{
+ Sym *s;
+
+ s = getsym();
+ macend();
+ if(s == S) {
+ yyerror("syntax in #undef");
+ return;
+ }
+ s->macro = 0;
+}
+
+#define NARG 25
+void
+macdef(void)
+{
+ Sym *s, *a;
+ char *args[NARG], *np, *base;
+ int n, i, c, len, dots;
+ int ischr;
+
+ s = getsym();
+ if(s == S)
+ goto bad;
+ if(s->macro)
+ yyerror("macro redefined: %s", s->name);
+ c = getc();
+ n = -1;
+ dots = 0;
+ if(c == '(') {
+ n++;
+ c = getnsc();
+ if(c != ')') {
+ unget(c);
+ for(;;) {
+ a = getsymdots(&dots);
+ if(a == S)
+ goto bad;
+ if(n >= NARG) {
+ yyerror("too many arguments in #define: %s", s->name);
+ goto bad;
+ }
+ args[n++] = a->name;
+ c = getnsc();
+ if(c == ')')
+ break;
+ if(c != ',' || dots)
+ goto bad;
+ }
+ }
+ c = getc();
+ }
+ if(isspace(c))
+ if(c != '\n')
+ c = getnsc();
+ base = hunk;
+ len = 1;
+ ischr = 0;
+ for(;;) {
+ if(isalpha(c) || c == '_') {
+ np = symb;
+ *np++ = c;
+ c = getc();
+ while(isalnum(c) || c == '_') {
+ *np++ = c;
+ c = getc();
+ }
+ *np = 0;
+ for(i=0; i<n; i++)
+ if(strcmp(symb, args[i]) == 0)
+ break;
+ if(i >= n) {
+ i = strlen(symb);
+ base = allocn(base, len, i);
+ memcpy(base+len, symb, i);
+ len += i;
+ continue;
+ }
+ base = allocn(base, len, 2);
+ base[len++] = '#';
+ base[len++] = 'a' + i;
+ continue;
+ }
+ if(ischr){
+ if(c == '\\'){
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ c = getc();
+ }else if(c == ischr)
+ ischr = 0;
+ }else{
+ if(c == '"' || c == '\''){
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ ischr = c;
+ c = getc();
+ continue;
+ }
+ if(c == '/') {
+ c = getc();
+ if(c == '/'){
+ c = getc();
+ for(;;) {
+ if(c == '\n')
+ break;
+ c = getc();
+ }
+ continue;
+ }
+ if(c == '*'){
+ c = getc();
+ for(;;) {
+ if(c == '*') {
+ c = getc();
+ if(c != '/')
+ continue;
+ c = getc();
+ break;
+ }
+ if(c == '\n') {
+ yyerror("comment and newline in define: %s", s->name);
+ break;
+ }
+ c = getc();
+ }
+ continue;
+ }
+ base = allocn(base, len, 1);
+ base[len++] = '/';
+ continue;
+ }
+ }
+ if(c == '\\') {
+ c = getc();
+ if(c == '\n') {
+ c = getc();
+ continue;
+ }
+ else if(c == '\r') {
+ c = getc();
+ if(c == '\n') {
+ c = getc();
+ continue;
+ }
+ }
+ base = allocn(base, len, 1);
+ base[len++] = '\\';
+ continue;
+ }
+ if(c == '\n')
+ break;
+ if(c == '#')
+ if(n > 0) {
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ }
+ base = allocn(base, len, 1);
+ base[len++] = c;
+ c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
+ if(c == '\n')
+ lineno++;
+ if(c == -1) {
+ yyerror("eof in a macro: %s", s->name);
+ break;
+ }
+ }
+ do {
+ base = allocn(base, len, 1);
+ base[len++] = 0;
+ } while(len & 3);
+
+ *base = n+1;
+ if(dots)
+ *base |= VARMAC;
+ s->macro = base;
+ if(debug['m'])
+ print("#define %s %s\n", s->name, s->macro+1);
+ return;
+
+bad:
+ if(s == S)
+ yyerror("syntax in #define");
+ else
+ yyerror("syntax in #define: %s", s->name);
+ macend();
+}
+
+void
+macexpand(Sym *s, char *b)
+{
+ char buf[2000];
+ int n, l, c, nargs;
+ char *arg[NARG], *cp, *ob, *ecp, dots;
+
+ ob = b;
+ if(*s->macro == 0) {
+ strcpy(b, s->macro+1);
+ if(debug['m'])
+ print("#expand %s %s\n", s->name, ob);
+ return;
+ }
+
+ nargs = (char)(*s->macro & ~VARMAC) - 1;
+ dots = *s->macro & VARMAC;
+
+ c = getnsc();
+ if(c != '(')
+ goto bad;
+ n = 0;
+ c = getc();
+ if(c != ')') {
+ unget(c);
+ l = 0;
+ cp = buf;
+ ecp = cp + sizeof(buf)-4;
+ arg[n++] = cp;
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ c = getc();
+ if(c == '"')
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ *cp++ = c;
+ c = getc();
+ if(c == '\\') {
+ *cp++ = c;
+ c = getc();
+ continue;
+ }
+ if(c == '\n')
+ goto bad;
+ if(c == '"')
+ break;
+ }
+ if(c == '\'')
+ for(;;) {
+ if(cp >= ecp)
+ goto toobig;
+ *cp++ = c;
+ c = getc();
+ if(c == '\\') {
+ *cp++ = c;
+ c = getc();
+ continue;
+ }
+ if(c == '\n')
+ goto bad;
+ if(c == '\'')
+ break;
+ }
+ if(c == '/') {
+ c = getc();
+ switch(c) {
+ case '*':
+ for(;;) {
+ c = getc();
+ if(c == '*') {
+ c = getc();
+ if(c == '/')
+ break;
+ }
+ }
+ *cp++ = ' ';
+ continue;
+ case '/':
+ while((c = getc()) != '\n')
+ ;
+ break;
+ default:
+ unget(c);
+ c = '/';
+ }
+ }
+ if(l == 0) {
+ if(c == ',') {
+ if(n == nargs && dots) {
+ *cp++ = ',';
+ continue;
+ }
+ *cp++ = 0;
+ arg[n++] = cp;
+ if(n > nargs)
+ break;
+ continue;
+ }
+ if(c == ')')
+ break;
+ }
+ if(c == '\n')
+ c = ' ';
+ *cp++ = c;
+ if(c == '(')
+ l++;
+ if(c == ')')
+ l--;
+ }
+ *cp = 0;
+ }
+ if(n != nargs) {
+ yyerror("argument mismatch expanding: %s", s->name);
+ *b = 0;
+ return;
+ }
+ cp = s->macro+1;
+ for(;;) {
+ c = *cp++;
+ if(c == '\n')
+ c = ' ';
+ if(c != '#') {
+ *b++ = c;
+ if(c == 0)
+ break;
+ continue;
+ }
+ c = *cp++;
+ if(c == 0)
+ goto bad;
+ if(c == '#') {
+ *b++ = c;
+ continue;
+ }
+ c -= 'a';
+ if(c < 0 || c >= n)
+ continue;
+ strcpy(b, arg[c]);
+ b += strlen(arg[c]);
+ }
+ *b = 0;
+ if(debug['m'])
+ print("#expand %s %s\n", s->name, ob);
+ return;
+
+bad:
+ yyerror("syntax in macro expansion: %s", s->name);
+ *b = 0;
+ return;
+
+toobig:
+ yyerror("too much text in macro expansion: %s", s->name);
+ *b = 0;
+}
+
+void
+macinc(void)
+{
+ int c0, c, i, f;
+ char str[STRINGSZ], *hp;
+
+ c0 = getnsc();
+ if(c0 != '"') {
+ c = c0;
+ if(c0 != '<')
+ goto bad;
+ c0 = '>';
+ }
+ for(hp = str;;) {
+ c = getc();
+ if(c == c0)
+ break;
+ if(c == '\n')
+ goto bad;
+ *hp++ = c;
+ }
+ *hp = 0;
+
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+ f = -1;
+ for(i=0; i<ninclude; i++) {
+ if(i == 0 && c0 == '>')
+ continue;
+ ensuresymb(strlen(include[i])+strlen(str)+2);
+ strcpy(symb, include[i]);
+ strcat(symb, "/");
+ if(strcmp(symb, "./") == 0)
+ symb[0] = 0;
+ strcat(symb, str);
+ f = open(symb, OREAD);
+ if(f >= 0)
+ break;
+ }
+ if(f < 0)
+ strcpy(symb, str);
+ c = strlen(symb) + 1;
+ hp = alloc(c);
+ memcpy(hp, symb, c);
+ newio();
+ pushio();
+ newfile(hp, f);
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #include");
+ macend();
+}
+
+void
+maclin(void)
+{
+ char *cp;
+ int c;
+ int32 n;
+
+ n = getnsn();
+ c = getc();
+ if(n < 0)
+ goto bad;
+
+ for(;;) {
+ if(c == ' ' || c == '\t') {
+ c = getc();
+ continue;
+ }
+ if(c == '"')
+ break;
+ if(c == '\n') {
+ strcpy(symb, "<noname>");
+ goto nn;
+ }
+ goto bad;
+ }
+ cp = symb;
+ for(;;) {
+ c = getc();
+ if(c == '"')
+ break;
+ *cp++ = c;
+ }
+ *cp = 0;
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+nn:
+ c = strlen(symb) + 1;
+ cp = alloc(c);
+ memcpy(cp, symb, c);
+ linehist(cp, n);
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #line");
+ macend();
+}
+
+void
+macif(int f)
+{
+ int c, l, bol;
+ Sym *s;
+
+ if(f == 2)
+ goto skip;
+ s = getsym();
+ if(s == S)
+ goto bad;
+ if(getcom() != '\n')
+ goto bad;
+ if((s->macro != 0) ^ f)
+ return;
+
+skip:
+ bol = 1;
+ l = 0;
+ for(;;) {
+ c = getc();
+ if(c != '#') {
+ if(!isspace(c))
+ bol = 0;
+ if(c == '\n')
+ bol = 1;
+ continue;
+ }
+ if(!bol)
+ continue;
+ s = getsym();
+ if(s == S)
+ continue;
+ if(strcmp(s->name, "endif") == 0) {
+ if(l) {
+ l--;
+ continue;
+ }
+ macend();
+ return;
+ }
+ if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
+ l++;
+ continue;
+ }
+ if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
+ macend();
+ return;
+ }
+ }
+
+bad:
+ yyerror("syntax in #if(n)def");
+ macend();
+}
+
+void
+macprag(void)
+{
+ Sym *s;
+ int c0, c;
+ char *hp;
+ Hist *h;
+
+ s = getsym();
+
+ if(s && strcmp(s->name, "lib") == 0)
+ goto praglib;
+ if(s && strcmp(s->name, "pack") == 0) {
+ pragpack();
+ return;
+ }
+ if(s && strcmp(s->name, "fpround") == 0) {
+ pragfpround();
+ return;
+ }
+ if(s && strcmp(s->name, "textflag") == 0) {
+ pragtextflag();
+ return;
+ }
+ if(s && strcmp(s->name, "varargck") == 0) {
+ pragvararg();
+ return;
+ }
+ if(s && strcmp(s->name, "incomplete") == 0) {
+ pragincomplete();
+ return;
+ }
+ if(s && strcmp(s->name, "dynimport") == 0) {
+ pragdynimport();
+ return;
+ }
+ if(s && strcmp(s->name, "dynexport") == 0) {
+ pragdynexport();
+ return;
+ }
+ while(getnsc() != '\n')
+ ;
+ return;
+
+praglib:
+ c0 = getnsc();
+ if(c0 != '"') {
+ c = c0;
+ if(c0 != '<')
+ goto bad;
+ c0 = '>';
+ }
+ for(hp = symb;;) {
+ c = getc();
+ if(c == c0)
+ break;
+ if(c == '\n')
+ goto bad;
+ *hp++ = c;
+ }
+ *hp = 0;
+ c = getcom();
+ if(c != '\n')
+ goto bad;
+
+ /*
+ * put pragma-line in as a funny history
+ */
+ c = strlen(symb) + 1;
+ hp = alloc(c);
+ memcpy(hp, symb, c);
+
+ h = alloc(sizeof(Hist));
+ h->name = hp;
+ h->line = lineno;
+ h->offset = -1;
+ h->link = H;
+ if(ehist == H) {
+ hist = h;
+ ehist = h;
+ return;
+ }
+ ehist->link = h;
+ ehist = h;
+ return;
+
+bad:
+ unget(c);
+ yyerror("syntax in #pragma lib");
+ macend();
+}
+
+void
+macend(void)
+{
+ int c;
+
+ for(;;) {
+ c = getnsc();
+ if(c < 0 || c == '\n')
+ return;
+ }
+}
+
+void
+linehist(char *f, int offset)
+{
+ Hist *h;
+
+ /*
+ * overwrite the last #line directive if
+ * no alloc has happened since the last one
+ */
+ if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0)
+ if(f && ehist->name && strcmp(f, ehist->name) == 0) {
+ ehist->line = lineno;
+ ehist->offset = offset;
+ return;
+ }
+
+ if(debug['f'])
+ if(f) {
+ if(offset)
+ print("%4d: %s (#line %d)\n", lineno, f, offset);
+ else
+ print("%4d: %s\n", lineno, f);
+ } else
+ print("%4d: <pop>\n", lineno);
+ newflag = 0;
+
+ h = alloc(sizeof(Hist));
+ h->name = f;
+ h->line = lineno;
+ h->offset = offset;
+ h->link = H;
+ if(ehist == H) {
+ hist = h;
+ ehist = h;
+ return;
+ }
+ ehist->link = h;
+ ehist = h;
+}