| // Inferno utils/cc/pickle.c |
| // http://code.google.com/p/inferno-os/source/browse/utils/cc/pickle.c |
| // |
| // 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. |
| |
| #include "cc.h" |
| |
| static char *kwd[] = |
| { |
| "$adt", "$aggr", "$append", "$complex", "$defn", |
| "$delete", "$do", "$else", "$eval", "$head", "$if", |
| "$local", "$loop", "$return", "$tail", "$then", |
| "$union", "$whatis", "$while", |
| }; |
| static char picklestr[] = "\tbp = pickle(bp, ep, un, "; |
| |
| static char* |
| pmap(char *s) |
| { |
| int i, bot, top, new; |
| |
| bot = 0; |
| top = bot + nelem(kwd) - 1; |
| while(bot <= top){ |
| new = bot + (top - bot)/2; |
| i = strcmp(kwd[new]+1, s); |
| if(i == 0) |
| return kwd[new]; |
| |
| if(i < 0) |
| bot = new + 1; |
| else |
| top = new - 1; |
| } |
| return s; |
| } |
| |
| Sym* |
| picklesue(Type *t) |
| { |
| int h; |
| Sym *s; |
| |
| if(t != T) |
| for(h=0; h<nelem(hash); h++) |
| for(s = hash[h]; s != S; s = s->link) |
| if(s->suetag && s->suetag->link == t) |
| return s; |
| return 0; |
| } |
| |
| Sym* |
| picklefun(Type *t) |
| { |
| int h; |
| Sym *s; |
| |
| for(h=0; h<nelem(hash); h++) |
| for(s = hash[h]; s != S; s = s->link) |
| if(s->type == t) |
| return s; |
| return 0; |
| } |
| |
| char picklechar[NTYPE]; |
| Init picklecinit[] = |
| { |
| TCHAR, 'C', 0, |
| TUCHAR, 'b', 0, |
| TSHORT, 'd', 0, |
| TUSHORT, 'u', 0, |
| TLONG, 'D', 0, |
| TULONG, 'U', 0, |
| TVLONG, 'V', 0, |
| TUVLONG, 'W', 0, |
| TFLOAT, 'f', 0, |
| TDOUBLE, 'F', 0, |
| TARRAY, 'a', 0, |
| TIND, 'X', 0, |
| -1, 0, 0, |
| }; |
| |
| static void |
| pickleinit(void) |
| { |
| Init *p; |
| |
| for(p=picklecinit; p->code >= 0; p++) |
| picklechar[p->code] = p->value; |
| |
| picklechar[TINT] = picklechar[TLONG]; |
| picklechar[TUINT] = picklechar[TULONG]; |
| if(types[TINT]->width != types[TLONG]->width) { |
| picklechar[TINT] = picklechar[TSHORT]; |
| picklechar[TUINT] = picklechar[TUSHORT]; |
| if(types[TINT]->width != types[TSHORT]->width) |
| warn(Z, "picklemember int not long or short"); |
| } |
| |
| } |
| |
| void |
| picklemember(Type *t, int32 off) |
| { |
| Sym *s, *s1; |
| static int picklecharinit = 0; |
| |
| if(picklecharinit == 0) { |
| pickleinit(); |
| picklecharinit = 1; |
| } |
| s = t->sym; |
| switch(t->etype) { |
| default: |
| Bprint(&outbuf, " T%d\n", t->etype); |
| break; |
| |
| case TIND: |
| if(s == S) |
| Bprint(&outbuf, |
| "%s\"p\", (char*)addr+%ld+_i*%ld);\n", |
| picklestr, t->offset+off, t->width); |
| else |
| Bprint(&outbuf, |
| "%s\"p\", &addr->%s);\n", |
| picklestr, pmap(s->name)); |
| break; |
| |
| case TINT: |
| case TUINT: |
| case TCHAR: |
| case TUCHAR: |
| case TSHORT: |
| case TUSHORT: |
| case TLONG: |
| case TULONG: |
| case TVLONG: |
| case TUVLONG: |
| case TFLOAT: |
| case TDOUBLE: |
| if(s == S) |
| Bprint(&outbuf, "%s\"%c\", (char*)addr+%ld+_i*%ld);\n", |
| picklestr, picklechar[t->etype], t->offset+off, t->width); |
| else |
| Bprint(&outbuf, "%s\"%c\", &addr->%s);\n", |
| picklestr, picklechar[t->etype], pmap(s->name)); |
| break; |
| case TARRAY: |
| Bprint(&outbuf, "\tfor(_i = 0; _i < %ld; _i++) {\n\t", |
| t->width/t->link->width); |
| picklemember(t->link, t->offset+off); |
| Bprint(&outbuf, "\t}\n\t_i = 0;\n\tUSED(_i);\n"); |
| break; |
| |
| case TSTRUCT: |
| case TUNION: |
| s1 = picklesue(t->link); |
| if(s1 == S) |
| break; |
| if(s == S) { |
| Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%ld+_i*%ld));\n", |
| pmap(s1->name), pmap(s1->name), t->offset+off, t->width); |
| } else { |
| Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, &addr->%s);\n", |
| pmap(s1->name), pmap(s->name)); |
| } |
| break; |
| } |
| } |
| |
| void |
| pickletype(Type *t) |
| { |
| Sym *s; |
| Type *l; |
| Io *i; |
| int n; |
| char *an; |
| |
| if(!debug['P']) |
| return; |
| if(debug['P'] > 1) { |
| n = 0; |
| for(i=iostack; i; i=i->link) |
| n++; |
| if(n > 1) |
| return; |
| } |
| s = picklesue(t->link); |
| if(s == S) |
| return; |
| switch(t->etype) { |
| default: |
| Bprint(&outbuf, "T%d\n", t->etype); |
| return; |
| |
| case TUNION: |
| case TSTRUCT: |
| if(debug['s']) |
| goto asmstr; |
| an = pmap(s->name); |
| |
| Bprint(&outbuf, "char *\npickle_%s(char *bp, char *ep, int un, %s *addr)\n{\n\tint _i = 0;\n\n\tUSED(_i);\n", an, an); |
| for(l = t->link; l != T; l = l->down) |
| picklemember(l, 0); |
| Bprint(&outbuf, "\treturn bp;\n}\n\n"); |
| break; |
| asmstr: |
| if(s == S) |
| break; |
| for(l = t->link; l != T; l = l->down) |
| if(l->sym != S) |
| Bprint(&outbuf, "#define\t%s.%s\t%ld\n", |
| s->name, |
| l->sym->name, |
| l->offset); |
| break; |
| } |
| } |
| |
| void |
| picklevar(Sym *s) |
| { |
| int n; |
| Io *i; |
| Type *t; |
| Sym *s1, *s2; |
| |
| if(!debug['P'] || debug['s']) |
| return; |
| if(debug['P'] > 1) { |
| n = 0; |
| for(i=iostack; i; i=i->link) |
| n++; |
| if(n > 1) |
| return; |
| } |
| t = s->type; |
| while(t && t->etype == TIND) |
| t = t->link; |
| if(t == T) |
| return; |
| if(t->etype == TENUM) { |
| Bprint(&outbuf, "%s = ", pmap(s->name)); |
| if(!typefd[t->etype]) |
| Bprint(&outbuf, "%lld;\n", s->vconst); |
| else |
| Bprint(&outbuf, "%f\n;", s->fconst); |
| return; |
| } |
| if(!typesu[t->etype]) |
| return; |
| s1 = picklesue(t->link); |
| if(s1 == S) |
| return; |
| switch(s->class) { |
| case CAUTO: |
| case CPARAM: |
| s2 = picklefun(thisfn); |
| if(s2) |
| Bprint(&outbuf, "complex %s %s:%s;\n", |
| pmap(s1->name), pmap(s2->name), pmap(s->name)); |
| break; |
| |
| case CSTATIC: |
| case CEXTERN: |
| case CGLOBL: |
| case CLOCAL: |
| Bprint(&outbuf, "complex %s %s;\n", |
| pmap(s1->name), pmap(s->name)); |
| break; |
| } |
| } |