/* * Hooks to make the browser's life eaiser. */ #include "std-macros.h" #include "parse-tree.h" #include "sym.h" #include "tokens.h" #include "browser-hooks.h" #include "token-mapping.h" /* * Init a symtab that will contain every browsable symbol in all spec modules, * excluding module names themselves. Viz., all object names, operation names, * and other top-level names. This tab will be used by the browser to locate * any symbol it's interested in. A separte symtab is also built to hold * module names. */ void InitBrowserSymtab() { BrowserSymtab = AllocSymtab(5000); BrowserSymtab->ParentTab = Level0Symtab; BrowserModuleSymtab = AllocSymtab(500); BrowserModuleSymtab->ParentTab = Level0Symtab; } int BrowserEnter(SymtabEntry** sym) { /* ^^ NOTE CALL BY VAR. This is because the caller wants the new sym that SimpleSymCopy builds. */ SymtabEntry* origsym = *sym; /* * Enter a copy of the given symtab entry into the flat browser symtab. */ EnterIn(*sym = SimpleSymCopy(*sym), BrowserSymtab); /* * Use the parent field to point to the parent module's symtab entry. This * is done so that the browser can fetch the name of the parent module in * cases where namespace disambiguation is required. I.e., if two or more * entities have the same name, and hence need to be disambiguated in the * browser list. */ switch ((*sym)->Class) { case C_Obj: (*sym)->Info.Obj.parent = CurSymtab->ParentEntry; break; case C_Op: (*sym)->Info.Op.parent = CurSymtab->ParentEntry; break; } /* * Use the Chain of the original sym (pre-copy) to point to the copy that * was stored in the flat browser symtab. The reason for this is a bit * convoluted. Viz., during the remainder of processing on the translator * side, specifically the EnterXXXInfo functions, we may have to look * symbols up. We want to do these lookups in the normal translator * symtabs, not in the flat browser symtab, since looking up in the latter * could lead to ambig sym problems (since, of course, the flat browser * symtab is not scoped). However, if we lookup in the translator symtabs, * we wont get the copy of the sym we may need -- the copy that's in the * browser symtab that will subsequently be scanned by the browser. This * is particularly the case in EnterObjInstances, q.v. So, the conclusion * is that we point the sym that's in the translator tabs to the sym that's * in the browser tab so that we can get to the latter from a lookup of the * former. All of this would of course be unnecessary if we didn't have to * make copies of symtab entries in the first place, but alas, we do, so * here we are. */ origsym->Chain = *sym; if ((CurSymtab == MainSymtab) and (not mainFilenameEntered)) EnterMainFilename(origsym->Loc.file); } int BrowserModuleEnter(SymtabEntry* sym) { /* * Enter the given symtab entry into the flat browser module symtab. * Leave out module "Main" since it's not explicitly defined, and selecting * it from the browser Modules menu is awkward at best. * * Not. Awkward as it is, we need to do it or we cant get to the loose * entity defs in the browser. if (not streq(sym->Symbol, "Main")) */ EnterIn(sym = SimpleSymCopy(sym), BrowserModuleSymtab); } void BrowserEnterUndefined(char* name) { /* * For now, this is dormant. The deal is that we'll not yet enter undef'd * symbols, but just let them be unlinked in the dd.html file. We'll see * how it goes. */ } SymtabEntry* BrowserLookup(char* name) { return LookupStringIn(name, BrowserSymtab); } SymtabEntry* BrowserModuleLookup(char* name) { return LookupStringIn(name, BrowserModuleSymtab); } void MoveToBrowserSymtab() { CurSymtab = BrowserSymtab; } void MoveToBrowserModuleSymtab() { CurSymtab = BrowserModuleSymtab; } /* * Wooooooooe! Dont try to enter the same symtab entry in two different * symtabs. If overflow happens in both tabs, the Next fields get el * mangolinoed. */ SymtabEntry* SimpleSymCopy(SymtabEntry* sym) { SymtabEntry* newsym; newsym = AllocSymtabEntry(sym->Symbol, sym->Class, sym->Type, sym->Level); newsym->Flags = sym->Flags; newsym->comment = sym->comment; newsym->Loc = sym->Loc; newsym->Info = sym->Info; return newsym; } /* * NOT -- do some first-pass processing here, by calling * EnterBrowserXXXInfo. trans-interface.c will then do second-pass processing, * like sorting, etc. * All this puppy does is stick the given parse tree into the theTree field of * the symtab entry, which field will subsequently be used by the browser to * construct all the lists of info it needs. The parse-tree-related processing * would logically better be done here in the translator. However, it's done * in the browser for the very practical reason that the list sort routine is * already done for C++ lists, but not for plain C lists. If the translator * ever gets converted to C++, we may adjust things a little here, but it's * really no biggie. */ void EnterBrowserInfo(nodep t, SymtabEntry* sym) { /* * NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE * * Browser hooks disalbed for now. FIX LATER. if (1) return; */ /* -- BrowserEnter now called in sym-aux.c:EnterObject, EnterOperation, q.q.v. * This avoids the prob of not having BrowserEnter'd befor use. * BrowserEnter(&sym); */ /* ^---- NOTE call-by-var. This is because BrowserEnter makes a * copy of sym before entering, and we want this copy back to * pass on to EnterXXXInfo. */ /* * Get the browser symtab copy of the sym. See comments about this * elsewhere in this file. Note that there be none for functions, so we * just split. LATER, functions should be browsable. */ sym = sym->Chain; if (not sym) return; switch (sym->Class) { case C_Obj: sym->Info.Obj.theTree = t;; EnterObjInfo(t, sym); break; case C_Op: sym->Info.Op.theTree = t;; EnterOpInfo(t, sym); break; } } void EnterObjInfo(nodep t, SymtabEntry* sym) { EnterObjComponents(t, sym); /* Calls EnterObjPartof */ EnterObjInheritsFrom(t, sym); /* Calls EnterObjInstances */ EnterObjOps(t, sym); EnterObjLinks(t, sym); } void EnterObjComponents(nodep t, SymtabEntry* sym) { EnterComponents(t, sym, sym->Info.Obj.namelist, &(sym->Info.Obj.brComponents), true); } /* * Cruise the flat namelist to find each component name. As we do so, make an * entry in the brComponents list of this symbol, as well as a complementary * entry in the brPartof list of each component symbol. * * IMPORTANT NOTE: The namelist will have been checked for homegeneity, but not * pruned of non-homogeneous entries. I.e., the namelist for an obj may * contain non-object sym's. A subtle and nasty bug occurs if we try to add, * say, an obj to an op's parts list. The problem is due to the fact that the * pointers in the Info portions of obj's and op's are not aligned, as we well * know. */ void EnterComponents(nodep t, SymtabEntry* sym, nodep namelist, CppList* brComponentsPtr, bool isObj) { char* cname; /* Child name */ SymtabEntry* csym; /* Child symtab entry */ nodep n; /* Temp */ *brComponentsPtr = NewCppList(); /* * Cruise the namelist list, making a new one in brComponents, and making * appro brPartof entries. */ for (n = namelist; n; n = n->components.atom.next) { /* * 25oct07 gfisher: Since we've re-enabled constant values in comp * exprs, we need to check that the what we have here is an ident, and * if not, ignore it (for now). The "for now" bit means that for data * dic purposes, we should do somthing to generate a printable version * of the constant value, but for now, we'll just ignore it to prevent * the seg fault that happens if we don't . */ if (n->header.name != Yident) { continue; } cname = n->components.atom.val.text; if ((csym = Lookup(cname)) == null) { csym = LookupString(cname); } if (csym and csym->Chain) { csym = csym->Chain; /* See lengthy comment in BrowserEnter * re. use of Chain field. */ } /* 16jun07 gfisher: csym->Chain will be null if we're dealing with a built-in symbol, such as "integer". For use in the Java code generator, we now want these entered in the brComponents. */ /* * The homogenity check is necessary as described above. */ if (sym and csym and HomoComponent(sym, csym)) { PutCppList(*brComponentsPtr, (CppListElem) NewAuxCppListElem( cname, csym)); } /* * The following check for csym is necessary if we allow the browser to * be run on an incomplete spec, which we may elect to do. */ if (csym and HomoComponent(sym, csym)) { EnterPartof(csym, sym, isObj ? &(csym->Info.Obj.brPartof) : &(csym->Info.Op.brPartof)); } } } /* * Check that a component is the same class as its parent. */ bool HomoComponent(SymtabEntry* sym, SymtabEntry* csym) { return (sym->Class == csym->Class); } void EnterPartof(SymtabEntry* sym, SymtabEntry* parentsym, CppList* brPartofPtr) { CppList po = *brPartofPtr; if (not po) po = *brPartofPtr = NewCppList(); PutCppList(po, (CppListElem) NewAuxCppListElem(parentsym->Symbol, parentsym)); } void EnterObjInheritsFrom(nodep t, SymtabEntry* sym) { EnterInheritsFrom(t, sym, &(sym->Info.Obj.brInheritsFrom), true); } /* * Cruise parse tree instanceof field to find the name of each parent class (of * which this symbol is an instance).. As we do so, make an entry in the * brInheritsFrom list of this symbol, as well as a complementary entry in the * brInstances list of each class parent symbol. * * Note the obvious similarity here with EnterObjComponents. The practical * diff is that here we deal with parents whereas in the aformentioned, we deal * with children. Also, there's likely not to be much multiple inheritance, so * the lists here won't typically be as long as brComponents and brPartof * lists. */ void EnterInheritsFrom(nodep t, SymtabEntry* sym, CppList* brInheritsFromPtr, bool isObj) { char* pname; /* Parent class name */ SymtabEntry* psym; /* Parent class symtab entry */ nodep n; /* Temp */ *brInheritsFromPtr = NewCppList(); /* * Cruise the parse tree instanceof list, making a new one in brInstance, * and making appro brInstances entries. */ for (n = t->components.decl.kind.obj.inheritsfrom; n; n = n->components.atom.next) { pname = n->components.atom.val.text; psym = Lookup(pname); if (psym) psym = psym->Chain; /* See lengthy comment in BrowserEnter * re. use of Chain field. */ PutCppList(*brInheritsFromPtr, (CppListElem) NewAuxCppListElem( pname, psym)); /* * Check that objs inherit from objs and ops from ops, not mixed or * from other types of symbol. The error messaging for this is handled * in typechk.c. The extra check is necessary here because, it would * seem, we'd need to nuke the offending parent symbol from the list * that's being used here for it not to be considered. Anyway, things * will blow up without this check. */ if (sym and psym and (sym->Class != psym->Class)) { break; } /* * The following check for psym is necessary if we allow the browser to * be run on an incomplete spec, which we may elect to do. */ if (psym) EnterInstances(psym, sym, isObj ? &(psym->Info.Obj.brInstances) : &(psym->Info.Op.brInstances)); } } void EnterInstances(SymtabEntry* sym, SymtabEntry* instancesym, CppList* brInstancesPtr) { CppList po = *brInstancesPtr; if (not po) po = *brInstancesPtr = NewCppList(); PutCppList(po, (CppListElem) NewAuxCppListElem(instancesym->Symbol, instancesym)); } /* * Cruise the parse tree ops field to pick out the name of each op. There's a * bit more picking necessary here than in components or instances, since we * have to get the names from the op signatures, if present. */ void EnterObjOps(nodep t, SymtabEntry* sym) { char* oname; /* Op name */ SymtabEntry* osym; /* Op symtab entry */ nodep n; /* Temp */ sym->Info.Obj.brOps = NewCppList(); for (n = t->components.decl.kind.obj.ops; n; n = n->components.decl.next) { oname = n->components.decl.kind.opsig.name-> components.atom.val.text; osym = Lookup(oname); PutCppList(sym->Info.Obj.brOps, (CppListElem) NewAuxCppListElem( oname, osym)); } } void EnterObjLinks(nodep t, SymtabEntry* sym) { EnterLinks(t, sym, &(sym->Info.Obj.brLinks), &(sym->Info.Obj.attrs)); } /* * Build an aux list of aux lists. Each top-level list elem is an attribute * cum link name, with an aux pointer to its sublist. Each sublist elem is the * entity related by the link name on its respective top-level. See note in * trans-interface.c:TransInterface::GetLinks about making sure that this * list-of-list structure get's used properly. */ void EnterLinks(nodep t, SymtabEntry* sym, CppList* brLinksPtr, nodep* attrsPtr) { CppList names; nodep n, v; *brLinksPtr = NewCppList(); /* * Cruise the attributes list, grabbing each attribute. The attrs field is * a decl list of decl nodes with name ':'. */ for (n = *attrsPtr; n; n = n->components.decl.next) { /* * Ensure that attr is not one of the buit-ins, such as equations, * which have their own, specialized syntax. */ if (n->header.name != ':') continue; /* * Ensure that attr val is an ident list rather than a comment. * Comment is legal, but doesnt generate a list that the browser can * use. Also chk that attr val is non-null, which is legal as a * convenience, since it's typical with unfilled templates. */ if ((v = n->components.decl.kind.attr.value) and v->header.name != Ytext) { if (names = BuildLinkNames(v, streq("pictures", n->components.decl.kind.attr.name-> components.atom.val.text))) { PutCppList(*brLinksPtr, NewAuxCppListElem( n->components.decl.kind.attr.name-> components.atom.val.text, (SymtabEntry *) names)); } } } } /* * Make an aux list of the entity names given as the value field of an * attribute. */ CppList BuildLinkNames(nodep identlist, bool isPicture) { char* iname; /* Ident name */ SymtabEntry* isym; /* Ident symtab entry */ nodep i; CppList l = NewCppList(); for (i = identlist; i; i = i->components.atom.next) { iname = i->components.atom.val.text; isym = Lookup(iname); if (isym) isym = isym->Chain; /* See lengthy comment in BrowserEnter * re. use of Chain field. */ if (isPicture) /* * Note that for a picture link we dont have any symtab entry in * the aux list elem, since we're dealing with names of pictures * that are defined in the graphics browser, the locations of which * we determine at runtime by the browser. */ PutCppList(l, (CppListElem) NewAuxCppListElem(iname, null)); else PutCppList(l, (CppListElem) NewAuxCppListElem(iname, isym)); } return l; } void EnterOpInfo(nodep t, SymtabEntry* sym) { EnterOpComponents(t, sym); /* Calls EnterOpPartof */ EnterOpInheritsFrom(t, sym); /* Calls EnterOpInstances */ EnterOpIns(t, sym); EnterOpOuts(t, sym); EnterOpLinks(t, sym); } void EnterOpComponents(nodep t, SymtabEntry* sym) { EnterComponents(t, sym, sym->Info.Op.namelist, &(sym->Info.Op.brComponents), false); } void EnterOpInheritsFrom(nodep t, SymtabEntry* sym) { EnterInheritsFrom(t, sym, &(sym->Info.Op.brInheritsFrom), false); } /* * Cruise the parse tree ins field to pick out the name of each input. */ void EnterOpIns(nodep t, SymtabEntry* sym) { char* iname; /* Input name */ SymtabEntry* isym; /* Input symtab entry */ nodep n; /* Temp */ sym->Info.Op.brIns = NewCppList(); /* * Cruise the ins namelist list, making a new one in brCompnents, and * making appro brPartof entries. */ for (n = sym->Info.Op.ins; n; n = n->components.atom.next) { iname = n->components.atom.val.text; isym = Lookup(iname); PutCppList(sym->Info.Op.brIns, (CppListElem) NewAuxCppListElem( iname, isym)); } } /* * Cruise the parse tree outs field to pick out the name of each output. */ void EnterOpOuts(nodep t, SymtabEntry* sym) { char* oname; /* Output name */ SymtabEntry* osym; /* Output symtab entry */ nodep n; /* Temp */ sym->Info.Op.brOuts = NewCppList(); /* * Cruise the outs namelist list, making a new one in brCompnents, and * making appro brPartof entries. */ for (n = sym->Info.Op.outs; n; n = n->components.atom.next) { oname = n->components.atom.val.text; osym = Lookup(oname); PutCppList(sym->Info.Op.brOuts, (CppListElem) NewAuxCppListElem( oname, osym)); } } void EnterOpLinks(nodep t, SymtabEntry* sym) { EnterLinks(t, sym, &(sym->Info.Op.brLinks), &(sym->Info.Op.attrs)); } void EnterMainFilename(char* fn) { SymtabEntry* sym; CurSymtab->ParentEntry->Loc.file = fn; mainFilenameEntered++; }