/**** * * Implementation of RSLToDict. * */ #include #include "std-macros++.h" #include "rsl-to-dict.h" #include "sym++.h" #include "sym-aux.h" #include "tokens.h" #include "token-mapping.h" #include "type-preds.h" void DumpAllSymsInDeclOrder(); // Quickie testing function /* * For some reason, this fails as a member function from time to time. When it * does, use this version instead. What utter crap C++ is. */ bool Open(ofstream& dd_file, ofstream& dd_links_file) { dd_file.open("dd.html"); if (! dd_file) { cout << "Output file \"dd.html\" could not be opened." << endl; return false; } dd_links_file.open("dd-links.dat"); if (! dd_links_file) { cout << "Output file \"dd-links.dat\" could not be opened." << endl; return false; } return true; } RSLToDict::RSLToDict(TransInterface* ti) { /* * Set the TransInterface link. */ this->ti = ti; /* * Build an image file helper dude. */ im = new Images(); /* * Init the toplist. */ toplist = new EntityStructList(); } void RSLToDict::Generate(BrowserSymLists* syms) { /* * Open the output files. Split if any open fails. */ if (not OpenFiles()) exit(0); // Open(dd_file, dd_links_file); /* * Write top-level index.html file, including frame specs. */ WriteHtmlIndex(); /* * Generate the module, obj, and op indices for the left-side frames. */ GenerateModObjOpIndices(syms); /* * Write data dict header for the top of the right frame. */ WriteDDHeader(); /* * Temp output of total number of modules. */ // printf("Total Number of Modules = %d\n", syms->num_mods); /* * Generate the object (data) dictionary. */ GenerateDD(syms->objs); /* * Write operation dict header, including end of data dict. */ WriteODHeader(); /* * Generate the operation dictionary. */ GenerateOD(syms->ops); /* * Write dict footer. */ WriteDictFooter(); /* * Write header, guts, and footer for the tree view. This needs to be * moved out of the RSLToDict class altogether in the finished design. */ WriteTreeViewHeader(); GenerateTreeView(); WriteTreeViewFooter(); /* * DEBUGGING: * DumpAllSymsInDeclOrder(); * */ } bool RSLToDict::OpenFiles() { int i,argc; char** argv; bool ok = true; ok = ok and OpenFile(index, "index.html"); ok = ok and OpenFile(module_index, "module-index.html"); ok = ok and OpenFile(all_objs_index, "all-objs-index.html"); ok = ok and OpenFile(all_ops_index, "all-ops-index.html"); ok = ok and OpenFile(all_dict, "dd.html"); ok = ok and OpenFile(all_tree, "dd-tree.html"); /* * If Emacs-based implmentation changes, we can re-enable the following * code, which opens f.rsl.html for each f.rsl command line arg. * ti->GetArgs(argc, argv); for (i = 0; i < argc; i++) { if (not OpenRslHtmlFile(argv[i])) { return false; } } * */ /* * Open dd-links.dat. */ ok = ok and OpenFile(dd_links_file, "dd-links.dat"); /* * Write the little image files. */ im->Write(); return ok; } bool RSLToDict::OpenFile(ofstream& filestream, char* filename) { /* * Open dd.html. */ filestream.open(filename); if (! filestream) { cout << "Output file " << filename << " could not be opened." << endl; return false; } return true; } /** * For some, at this point unknown, reason, the use of "\n" in strings does not * work, whereas the use of ``<< endl'' does. So, as ugly as it is, I've * replaced all "\n"s with ``<< endl''s. S---! */ void RSLToDict::WriteHtmlIndex() { index << "" << endl << "" << endl << "RSL Data Dictionary" << endl << "" << endl << "" << endl << "" << endl << "" << endl << "" << endl << "" << endl << "" << endl << "" << endl << "" << endl << "" << endl << "" << endl << "" << endl; } void RSLToDict::GenerateModObjOpIndices(BrowserSymLists* syms) { GenerateModIndex(syms->mods); GenerateObjOpIndex(syms->objs, all_objs_index, "Objects"); GenerateObjOpIndex(syms->ops, all_ops_index, "Operations"); } void RSLToDict::GenerateModIndex(EntityStructList* mods) { EntityStruct* e; SymtabEntry* sym; char* name; WriteHtmlIndexHeader(module_index, "Modules"); /* * Cruise the mod list, extracting the necessary info and spewing it to * the output file. */ while (e = mods->Enum()) { name = e->GetName(); sym = e->GetSym(); if (sym and sym->Loc.file) { module_index << "Loc.file << "\"" << " target=\"new\"> " << name << " " << endl << "
" << endl; } } WriteHtmlIndexFooter(module_index); } void RSLToDict::GenerateObjOpIndex(EntityStructList* ents, ofstream& file, char* title) { EntityStruct* e; SymtabEntry* sym; char* name; WriteHtmlIndexHeader(file, title); /* * Cruise the objs list, extracting the necessary info and spewing it to * the output file. */ while (e = ents->Enum()) { name = e->GetName(); sym = e->GetSym(); if (BrowserLookup(name)) { file << "" << name << "" << endl; } else if (sym and ChkSymFlag(sym, isAmbig)) { file << "" << ti->GetBrowserSymtab()-> BuildDisambiguatedHtmlStr(sym, 0) << "" << endl; } else { file << name; } file << "
" << endl; } WriteHtmlIndexFooter(file); } void RSLToDict::WriteHtmlIndexHeader(ofstream& file, char* title) { file << "" << endl << "" << endl << "" << title << " Index" << endl << "" << endl << "

" << "" << "" << title << "" << endl << "" << endl << "

" << endl; } void RSLToDict::WriteHtmlIndexFooter(ofstream& file) { file << "" << endl << "" << endl; } void RSLToDict::WriteDDHeader() { all_dict << "" << endl << "" << endl << "Data Dictionary" << endl << "" << endl << "" << endl << "

" << "" << "Data Dictionary" << endl << "" << endl << "

" << endl << "" << endl << "" << endl << "
" << endl << "" << endl << "

" << "Object Name

" << endl << "
" << endl << "
" << endl << "" << endl << "

" << "Components

" << endl << "
" << endl << "
" << endl << "" << endl << "

" << "Description

" << endl << "
" << endl; } void RSLToDict::WriteODHeader() { all_dict << "
" << endl << "


" << endl << "

" << "" << "Operation Dictionary" << endl << "" << endl << "

" << endl << "" << endl << "" << endl << "
" << endl << "" << endl << "

" << "Operation Name

" << endl << "
" << endl << "
" << endl << "" << endl << "

" << "Inputs

" << endl << "
" << endl << "
" << endl << "" << endl << "

" << "Outputs

" << endl << "
" << endl << "
" << endl << "" << endl << "

" << "Description

" << endl << "
" << endl; } void RSLToDict::WriteDictFooter() { all_dict << "
" << endl << "" << endl << "" << endl; } void RSLToDict::GenerateDD(EntityStructList* objs) { EntityStruct* e; SymtabEntry* sym; char* name; /* * Cruise the object list, extracting the necessary info and spewing it to * the output file. */ while (e = objs->Enum()) { name = e->GetName(); sym = e->GetSym(); /* * Call the printing functions to print an entry in each table column * for this object. */ PrintName(name); PrintComponents(sym); PrintDescription(sym->Info.Obj.attrs); /* * Make the html file as readable as possible. */ all_dict << endl; /* * Record the source location info for each object in ddlinks.dat. */ WriteLinkInfo(name, sym->Loc); /* * While we're going through the objs, make a list of the top-level * objs, sorted by size. */ if (IsTopLevelObject(sym)) { PutInTopLevelList(e); } } } bool RSLToDict::IsTopLevelObject(SymtabEntry* sym) { EntityStructList* parents = ti->GetParents(sym); EntityStructList* class_parents = ti->GetClassParents(sym); return (parents->Len() == 0) and (class_parents->Len() == 0) and (not ChkSymFlag(sym, isWhereRHS)); } void RSLToDict::PutInTopLevelList(EntityStruct* e) /*SymtabEntry* sym)*/ { toplist->Put(e); /* new EntityStruct(sym->Symbol, (void*) sym)); */ /* * TESTING: * * int size = BrowserTypeSize(sym->Type); EntityStructList* kids; EntityStruct* kid; printf("%s is a top-level object of size %d\n", sym->Symbol, size); cout << "Its instances are: "; for (kids = ti->GetInstances(sym); kid = kids->Enum(); ) { cout << kid->GetName(); } cout << endl; cout << "Its components are: "; for (kids = ti->GetUnsortedComponents(sym); kid = kids->Enum(); ) { cout << kid->GetName() << " "; } cout << endl << endl; * * */ } void RSLToDict::WriteLinkInfo(char* name, SrcLoc loc) { dd_links_file << name << " " << loc.file << " " << loc.line << " " << loc.col << endl; } void RSLToDict::PrintName(char* name) { all_dict << "" << endl << "" << endl << "" << name << "" << endl << "" << endl << endl; } void RSLToDict::PrintComponents(SymtabEntry* sym) { nodep parent; char* name; all_dict << "" << endl; if (parent = sym->Info.Obj.inheritsfrom ) { if (name = parent->components.atom.val.text) { all_dict << "Inherits from: "; if (BrowserLookup(name)) { all_dict << "" << name << "" << endl; } else { all_dict << name; } all_dict << "

" << endl; } } if (sym->Type) { PrettyPrintType(sym->Type); } else { all_dict << " " << endl; } all_dict << "" << endl; } extern "C" nodep FindUserAttr(nodep attrs, char* name); void RSLToDict::PrintDescription(nodep attrs) { nodep attr_val; all_dict << "" << endl; if (attr_val = FindUserAttr(attrs, "description")) { all_dict << attr_val->components.atom.val.string; } /* * Print an nbsp unconditionally, in case the description is non-empty but * only whitespace. */ all_dict << " " << endl; all_dict << "" << endl << "" << endl; } void RSLToDict::PrettyPrintType(nodep t) { switch(t->header.name) { case ';': all_dict << " " << endl; break; case Yident: PrettyPrintIdentType(t); break; case YRECORD: PrettyPrintTupleType(t); break; case YOR: PrettyPrintUnionType(t); break; case YARRAY: PrettyPrintListType(t); break; case YOP: PrettyPrintOpType(t); break; } } void RSLToDict::PrettyPrintIdentType(nodep t) { nodep t1; SymtabEntry* sym; char* name, *dname; if (t1 = t->components.type.kind.ident.type) { if (sym = BrowserLookup(name = dname = t1->components.atom.val.text)) { if (ChkSymFlag(sym, isAmbig)) { dname = ti->GetBrowserSymtab()->BuildDisambiguatedStr(sym, 0); } all_dict << "" << name << ""; } else { all_dict << name; } } else { all_dict << " "; } } void RSLToDict::PrettyPrintTupleType(nodep t) { nodep field, type; bool nested = false; int i; for (field = t->components.type.kind.record.fields, i=0; field and (i < t->components.type.kind.record.numfields); i++) { if ((type = field->components.decl.kind.field.type) and (not field->components.decl.kind.field.isinherited)) { if (nested = (type->header.name == YOR)) { all_dict << "("; } PrettyPrintType(type); if (nested) { all_dict << ")"; } if (field = field->components.decl.next) { all_dict << " and "; } } else { field = field->components.decl.next; } } } void RSLToDict::PrettyPrintUnionType(nodep t) { nodep field, type, next; for (field = t->components.type.kind.record.fields; field; ) { if (type = field->components.decl.kind.field.type) { next = field->components.decl.next; PrettyPrintType(type); if (field = next) { all_dict << " or "; } } } } void RSLToDict::PrettyPrintListType(nodep t) { nodep base = t->components.type.kind.arraytype.basetype; if (not isIdentType(base)) { all_dict << "("; } PrettyPrintType(base); if (not isIdentType(base)) { all_dict << ")"; } all_dict << "*"; } void RSLToDict::PrettyPrintOpType(nodep t) { all_dict << "op ("; PrintOpTypeParms(t->components.type.kind.op.ins); all_dict << ")->("; PrintOpTypeParms(t->components.type.kind.op.outs); all_dict << ")"; } void RSLToDict::PrintOpTypeParms(nodep parms) { if (parms) all_dict << "..."; } void RSLToDict::GenerateOD(EntityStructList* ops){ EntityStruct* e; char* name; /* * Cruise the operation list, extracting the necessary info and spewing it * to the output file. */ while (e = ops->Enum()) { name = e->GetName(); /* * Call the printing functions to print an entry in each table column * for this operation. */ PrintName(name/*e->GetSym()->Symbol*/); PrintParms(ti->GetInputs(e->GetSym())); PrintParms(ti->GetOutputs(e->GetSym())); PrintDescription(e->GetSym()->Info.Op.attrs); /* * Make the html file as readable as possible. */ all_dict << endl; /* * Record the source location info for each object in ddlinks.dat. */ WriteLinkInfo(e->GetName(), e->GetSym()->Loc); } } void RSLToDict::PrintParms(EntityStructList* ins) { EntityStruct* e; SymtabEntry* sym; char* name; all_dict << "" << endl; if (not (e = (EntityStruct*) ins->Enum())) { all_dict << " " << endl; } while (e) { if (sym = BrowserLookup(name = e->GetName())) { all_dict << "" << name << ""; } else { all_dict << name; } if (e = (EntityStruct*) ins->Enum()) { all_dict << ", "; } } all_dict << "" << endl; } bool RSLToDict::IsBuiltInAtomicType(char* tname) { return ( streq(tname, "integer") or streq(tname, "real") or streq(tname, "string") or streq(tname, "boolean") or streq(tname, "nil") ); } void RSLToDict::WriteTreeViewHeader() { all_tree << "" << endl << "" << endl << "Object Hierarchy" << endl << "" << endl << "" << endl << "

" << "" << "Object Hierarchy" << endl << "" << endl << "

" << endl; } const char* spacing = " "; void RSLToDict::GenerateTreeView() { EntityStruct* e; StrList* vstk = new StrList(); EntitySymtab* vsymt = new EntitySymtab(); char* name, *dname; SymtabEntry* sym; while (e = (EntityStruct*) toplist->Enum()) { all_tree << spacing << spacing << spacing; name = dname = e->GetName(); sym = e->GetSym(); if (ChkSymFlag(sym, isAmbig)) { dname = sym->Symbol /*ti->GetBrowserSymtab()->BuildDisambiguatedHtmlStr(sym, 0)*/; } all_tree << "" << dname << "
" << endl; GenerateDescendents(e, 5, vstk, vsymt); } all_tree << endl; } void RSLToDict::GenerateDescendents(EntityStruct* e, int indent, StrList* vstk, EntitySymtab* vsymt) { EntityStructList* kids; EntityStruct* kid; EntityStruct* vsym = new EntityStruct(e->GetName(), (void*) e->GetSym()); int i; SymtabEntry* sym = e->GetSym(); SymtabEntry* ksym; char* name, *dname; bool newgen; // True if first-time generation for sym // cout << sym->Symbol << ": "; // vstk->Print(); if (! sym) { return; } vstk->Push(new StrListElem(sym->Symbol, null)); vsymt->EnterSym(vsym); if ((kids = ti->GetUnsortedComponents(sym)) != 0) { while (kid = kids->Enum()) { newgen = GenerateDescendent(kid, indent, "component", vsymt); if (newgen and (not vstk->Find(kid->GetName()))) { GenerateDescendents(kid, indent+5, vstk, vsymt); } } } if ((kids = ti->GetInstances(sym)) != 0) { while (kid = kids->Enum()) { newgen = GenerateDescendent(kid, indent, "inheritance", vsymt); if (newgen and (not vstk->Find(kid->GetName()))) { GenerateDescendents(kid, indent+5, vstk, vsymt); } } } vstk->Pull(); } bool RSLToDict::GenerateDescendent(EntityStruct* kid, int indent, char* icon, EntitySymtab* vsymt) { int i; char* name, *dname; SymtabEntry* ksym; bool rtn, no_link; if (kid == null) return false; for (i = 0; i < indent; i++) { all_tree << spacing; } /* * The no_link bit is a kludge to get multiply-defined symbols to come out * decent until we can find a better way. I've logged the problem. */ if (kid->GetSym() == null) { name = dname = kid->GetName(); no_link = true; } else { name = dname = kid->GetSym()->Symbol; no_link = false; } if (ksym = BrowserLookup(name)) { if (ChkSymFlag(ksym, isAmbig) and (not no_link)) { dname = ti->GetBrowserSymtab()->BuildDisambiguatedHtmlStr(ksym, 0); } /* * If sym hasn't been output yet, do it with a surrounding href and * return true. Otherwise, do it without the surrounding href, add the * href arrow to prev output, and return false. */ if (not vsymt->LookupSym(kid->GetName())) { all_tree << "" << " " << "" << "" << dname << "" // End " // End " << " " << dname << "" << "  " << "" << "" << "" << endl; rtn = false; } } else { all_tree << "<> " << dname; rtn = false; } all_tree << "
" << endl; return rtn; } void RSLToDict::WriteTreeViewFooter() { all_tree << "" << endl << "" << endl; } void DumpAllSymsInDeclOrder() { Symtab* msymt; PlainCAuxListElem elem; CppList l; while (msymt = (Symtab*) EnumCppList(ModuleList)) { cout << "module " << msymt->ParentEntry->Symbol << endl; l = msymt->DeclOrderList; while (elem = (PlainCAuxListElem) EnumCppList(l)) { cout << " obj " << elem->AuxData->Symbol << endl; } } }