/*ident "@(#)G2++:compsrc/comp.c 3.1" */ /****************************************************************************** * * C++ Standard Components, Release 3.0. * * Copyright (c) 1991, 1992 AT&T and Unix System Laboratories, Inc. * Copyright (c) 1988, 1989, 1990 AT&T. All Rights Reserved. * * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T and Unix System * Laboratories, Inc. The copyright notice above does not evidence * any actual or intended publication of such source code. * ******************************************************************************/ // g2++comp - Compile g2++ record definitions // // g2++comp compiles the g2++ record definitions in one or // more files. The files must have a ".g" suffix in their // name to be considered. Each ".g" file is compiled into // corresponding ".h" and ".c" files. // // g2++comp is an extension of g2comp, written by // Jim Weythman. ////-------------------------------------------- //#include "compfns.h" #ifdef __GNUG__ #pragma implementation "Map.h" #endif #include #include #include #include #include #include #include #define IOSTREAMH #ifdef IOSTREAMH #include #else #include #endif #include #include #include #include #include // Global data extern String progname; extern String filename; extern int err; extern G2NODE* stack[G2MAXDEPTH_ATTLC]; // should use a block extern /*long*/time_t seed; // for ranstr() extern G2BUF* gbuf; // global so transorm can grow gbuf->buf extern G2NODE* head; extern G2NODE* tail; extern G2NODE nulldef; extern G2NODE chardef; extern G2NODE shortdef; extern G2NODE longdef; extern G2NODE stringdef; extern G2BUF char_def; extern G2BUF short_def; extern G2BUF long_def; extern G2BUF string_def; struct mtbl{ G2BUF* buf; mtbl* next; }; extern mtbl* mtblhead; extern mtbl* mtbltail; #ifdef _MSC_VER Mapdeclare(String,int) extern Map(String,udt_info_ATTLC) udt_map_ATTLC; extern Map(String,int) SoS; #else #ifdef __GNUG__ template class Map; template class Map; #endif extern Map udt_map_ATTLC; extern Map SoS; #endif // Local functions mtbl* addtbl(G2BUF*); void bdef(G2NODE* t, FILE* hf, FILE* cf); void blockdef(G2NODE* t, FILE* hf, FILE* cf); void bolt(const String& stem, FILE* hf, FILE* cf); int dotg(const char*, const char *); void errf(int level, const char* msg); void errf(int level, const char* msg, const char* arg); void errf(int level, const char* msg, const char* arg1, const char* arg2); void errf(int level, const char* msg, const char* arg1, const char* arg2, const char* arg3); void error(const char* msg); void error(const char* msg, const char* a); void error(const char* msg, const char* a, const char* b); void error(const char* msg, const char* a, long b); void extract_udt_info(G2NODE* gp); void generate(G2NODE* t, FILE* hf, FILE* cf); void gen_io(G2NODE* t, FILE* hf, FILE* cf); void include_udt(FILE* f); String lower(const String&); void nullify(FILE*); FILE* openfile(const String& filename); void parse(const String& path, String& dir, String& stem); String pathname(int level); #ifdef IOSTREAMH int perfile(ifstream&, const String& stem, const String& hfilename, const String& cfilename); #else int perfile(istream&, const String& stem, const String& hfilename, const String& cfilename); #endif void prologue(FILE* hf, FILE* cf, const String& stem, const String& hfilename); void prtbls(const String& stem, FILE* hf, FILE* cf); String ranstr(int); void remtbl(); void resettbl(); void show_udt_info(udt_info_ATTLC x); void show_udt_map(); void sizealign(FILE* cf); void transform(G2NODE* p); int valid(int level, G2NODE* gp); void valid1(int, G2NODE*); void wrap(FILE*); unsigned do_checksum(const char *); ////-------------------------------------------- #ifdef _MSC_VER Map(String,udt_info_ATTLC) udt_map_ATTLC; Map(String,int) SoS; #else Map udt_map_ATTLC; Map SoS; #endif mtbl* mtblhead=0; mtbl* mtbltail=0; String progname; String filename; int err; G2NODE* stack[G2MAXDEPTH_ATTLC]; // should use a block /*long*/time_t seed; // for ranstr() G2BUF* gbuf; // global so transorm can grow gbuf->buf G2NODE* head; G2NODE* tail; G2NODE nulldef; G2NODE chardef; G2NODE shortdef; G2NODE longdef; G2NODE stringdef; G2BUF char_def; G2BUF short_def; G2BUF long_def; G2BUF string_def; int no_cap_flag = 0; int vblock_flag = 0; main(int argc, char* argv[]){ String stem; String dir; int i; // int tflag = 0; // int Tflag = 0; #ifdef IOSTREAMH // ifstream ins; // input fstream #else FILE* f_file; #endif char *cur_suffix = ".g"; progname = argv[0]; seed = time(0); // srand((unsigned)seed); // Initialize table of G2NODE resettbl(); // Loop over .g arguments in command line for(i = 1; i < argc; i++){ if(strcmp(argv[i],"-n") == 0) { // the -n option causes g2++comp to refrain from // converting typenames to all uppercase in the // generated code no_cap_flag = 1; continue; } if(strcmp(argv[i],"-s") == 0) { // the -s option affects the code that is generated // for simple types (G2++ types that are not structures) // Arrays will be derived from Vblock, character // strings will be derived from String, and the integer-based // types (long, short, char) will have special class code // generated vblock_flag = 1; continue; } if(strcmp(argv[i],"-g") == 0) { cur_suffix = ""; continue; } if(strncmp(argv[i],"-g",2) == 0) { cur_suffix = &argv[i][2]; continue; } if(!dotg(argv[i], cur_suffix)){ continue; } #ifdef IOSTREAMH ifstream ins(argv[i],ios::in); if(!ins){ error("cannot open '%s': ", argv[i]); perror(""); err++; continue; } #else if ((f_file = fopen(argv[i],"r")) == NULL) { error("cannot open '%s': ", argv[i]); perror(""); err++; continue; } istream ins(f_file); #endif srand(do_checksum(argv[i])); filename = String(argv[i]); // might be "a/b/c/d.g" DEBUG(cerr << "in main, filename=" << filename << "\n" ;) // Display the filename on stderr fprintf(stderr, "%s:\n", (const char*)filename); // Extract directory part of the filename into 'dir' // and file part (less .g) into 'stem' parse( filename, // might be a/b/c/d.g dir, // would be a/b/c stem // would be d ); DEBUG(cerr << "on return from parse:\n" << " dir=" << dir << "\n" << " stem=" << stem << "\n" ;) // We will put the .h and .c files in the current directory String hfilename = /* dir + "/" + */ stem + ".h"; #if defined(_MSC_VER) || defined(__TCPLUSPLUS__) String cfilename = /* dir + "/" + */ stem + ".cpp"; #else String cfilename = /* dir + "/" + */ stem + ".c"; #endif DEBUG(cerr << " hfilename=" << hfilename << "\n" ;) DEBUG(cerr << " cfilename=" << cfilename << "\n" ;) // Do it if(perfile(ins,stem,hfilename,cfilename)){ // Success! Display the rest of the message to user #if defined(_MSC_VER) || defined(__TCPLUSPLUS__) fprintf(stderr, " => %s.h, %s.cpp\n", (const char*)stem, (const char*)stem); #else fprintf(stderr, " => %s.[hc]\n", (const char*)stem); #endif } // Prepare to process the next .g file ins.close(); resettbl(); } return err; } int valid(int level, G2NODE* gp){ DEBUG(cerr << "enter valid with level=" << level << "\n" ;) int saverr = err; valid1(level, gp); return err - saverr; } void valid1(int level, G2NODE* gp){ stack[level] = gp; DEBUG(cerr << "enter valid1 with level = " << level << ", gp = " << "\n" ;) DEBUG( showtree_ATTLC(gp,0); ) String temp=g2name_ATTLC(gp); // elim "sorry not implemented" DEBUG( cerr << "temp = " << temp << endl; ) DEBUG( cerr << "stack contains:" << endl; for(int k = 0;k<=level;k++){ cerr << " " << g2name_ATTLC(stack[k]) << endl; } ) if(level<=0 && !isname_ATTLC(temp) ){ errf(level, " root is not a name\n"); err++; return; } if(isname_ATTLC(temp)){ G2NODE* next=g2next_ATTLC(gp); if(next){ temp=g2name_ATTLC(next); if(!temp.is_empty() && isint_ATTLC(temp)){ stack[level] = next; errf(level, " mixed names and indexes\n"); err++; } }else{ // Check for variable size String declared at level zero // and issue initial allocation warning message temp = g2val_ATTLC(gp); const char* pn = (const char*)temp; int n = atoi(pn); DEBUG( cerr << "max size = " << n << endl; ) if(n == 0 && temp.length() >= 4 && temp.char_at(1) == '('){ n = atoi(pn+2); } DEBUG( cerr << "initial capacity = " << n << endl; ) if(n > 0 && level==0){ if (vblock_flag == 0) { String nn = int_to_str(n); String type = upper( g2name_ATTLC(stack[0]) ); errf( level, " warning: %s will not be\nused as the initial string size;for proper preallocation,\nuse a constructor argument, e.g. %s x(Stringsize(%s));\n --> or use the -s option\n", (const char*)nn, (const char*)type, (const char*)nn ); } } } }else if(isdigit_ATTLC(temp.char_at(0))){ // Array // // Remember: all arrays should be at level 0, // so we should now be at level 1 looking at the // size info. DEBUG(cerr << "array" << endl; ) G2NODE* next=g2next_ATTLC(gp); if(next){ stack[level] = next; if(isint_ATTLC(g2name_ATTLC(next))){ errf(level, " only one dimension allowed per level\n"); }else{ errf(level, " mixed names and indexes\n"); } err++; }else{ // Decode size and initial allocation information const char* pn = (const char*)temp; int n = atoi(pn); DEBUG( cerr << "max size = " << n << endl; ) if(n == 0 && temp.length() >= 4 && temp.char_at(1) == '('){ n = atoi(pn+2); } DEBUG( cerr << "initial capacity = " << n << endl; ) if(n > 0){ String pval = g2val_ATTLC(stack[level-1]); DEBUG( cerr << "level, pval = " << level << ", " << pval << endl; ) if(level==1 && pval != "HOISTED"){ DEBUG(cerr << "level==1 && pval!=HOISTED" << endl;) // Corrective action: use a constructor argument if (vblock_flag == 0) { String nn = int_to_str(n); String type = upper(g2name_ATTLC(stack[0])); errf( level, " warning: %s will not be\nused as the initial array capacity; for proper preallocation,\nuse a constructor argument, e.g. %s x(%s);\n --> or use the -s option\n", (const char*)nn, (const char*)type, (const char*)nn ); } }else{ // level>1 || (level==1 && pval == HOISTED) // Corrective action: modify record structure DEBUG( cerr << "level>1 || (level==1 && pval == HOISTED)" << endl; ) #if 0 String nn = int_to_str(n); errf( level, " warning: %s will not be used as the initial array capacity; consider making this array the member of a structure\n", (const char*)nn ); #endif } } // Issue warning for array elements declared as n or 0(n) pn = (const char*)gp->val; n = atoi(pn); DEBUG( cerr << "max size = " << n << endl; ) if(n == 0 && gp->val.length() >= 4 && gp->val.char_at(1) == '('){ n = atoi(pn+2); } DEBUG( cerr << "initial capacity = " << n << endl; ) #if 0 if(n > 0){ DEBUG(cerr << "n>0: issue array element warning" << endl;) char buf[10]; sprintf(buf,"%d",n); errf(level, " warning: %s will not be used as the initial string capacity; consider redefining the element type as a structure\n",buf); } #endif } }else{ errf(level, " name is neither a name nor an index\n"); err++; } temp=g2val_ATTLC(gp); if(temp.is_empty() && !g2child_ATTLC(gp)){ errf(level, " missing value\n"); err++; } if(!g2child_ATTLC(gp)){ temp=g2val_ATTLC(gp); DEBUG(cerr << "gp has no children; set temp=" << temp << "\n" ;) if(!isdigit_ATTLC(temp.char_at(0))){ // Cludge -- prevent user from saying "STRING" if(temp=="STRING"){ errf(level, " type '%s' not defined\n", (const char*)temp); err++; }else{ if(!lookup(temp) ){ if(!udt_map_ATTLC.element(temp)){ errf(level, " type '%s' not defined\n", (const char*)temp); err++; } } } } } DEBUG( cerr << "ready to call valid1 recursively for children" << endl; ) for(G2NODE* cp=g2child_ATTLC(gp); cp; cp=g2next_ATTLC(cp)){ valid1(level+1,cp); } } void errf(int level, const char* msg){ fprintf(stderr, "%s: ", (const char*)progname); if(filename.length()>0){ fprintf(stderr, "file '%s': ", (const char*)filename); } fprintf(stderr, "path '%s'", (const char*)pathname(level)); fprintf(stderr, msg); } void errf(int level, const char* msg, const char* arg){ fprintf(stderr, "%s: ", (const char*)progname); if(filename.length()>0){ fprintf(stderr, "file '%s': ", (const char*)filename); } fprintf(stderr, "path '%s'", (const char*)pathname(level)); fprintf(stderr, msg, arg); } void errf(int level, const char* msg, const char* arg1, const char* arg2){ fprintf(stderr, "%s: ", (const char*)progname); if(filename.length()>0){ fprintf(stderr, "file '%s': ", (const char*)filename); } fprintf(stderr, "path '%s'", (const char*)pathname(level)); fprintf(stderr, msg, arg1, arg2); } void errf(int level, const char* msg, const char* arg1, const char* arg2, const char* arg3){ fprintf(stderr, "%s: ", (const char*)progname); if(filename.length()>0){ fprintf(stderr, "file '%s': ", (const char*)filename); } fprintf(stderr, "path '%s'", (const char*)pathname(level)); fprintf(stderr, msg, arg1, arg2, arg3); } String pathname(int level){ String result=""; for(int i = 0; i <= level; i++){ String name; if(g2val_ATTLC(stack[i]) == "HOISTED"){ name = "?"; }else{ name=g2name_ATTLC(stack[i]); } result+=name; if(inext){ /* DEBUG(cerr << "consider buffer at address " << long(mp) << "\n" ;) */ for(G2NODE* t=g2root_ATTLC(mp->buf); t; t=g2next_ATTLC(t)){ /* DEBUG(cerr << "consider G2NODE t:\n";) DEBUG(shownode_ATTLC(t);) DEBUG(cerr << "g2name_ATTLC(t)=" << g2name_ATTLC(t) << "\n" ;) */ if(name == g2name_ATTLC(t)){ DEBUG(cerr << "hit!\n";) return t; } } DEBUG(cerr << "exit from inner forloop\n";) } DEBUG(cerr << "lookup failed!\n";) return NULL; } void error(const char* msg){ fprintf(stderr, "%s: ", (const char*)progname); #ifdef _MSC_VER if( filename != "" ){ #else if( filename ){ #endif fprintf(stderr, "file '%s': ", (const char*)filename); } fprintf(stderr, msg); } void error(const char* msg, const char* a){ fprintf(stderr, "%s: ", (const char*)progname); #ifdef _MSC_VER if( filename != "" ){ #else if( filename ){ #endif fprintf(stderr, "file '%s': ", (const char*)filename); } fprintf(stderr, msg, a); } void error(const char* msg, const char* a, const char* b){ fprintf(stderr, "%s: ", (const char*)progname); #ifdef _MSC_VER if( filename != "" ){ #else if( filename ){ #endif fprintf(stderr, "file '%s': ", (const char*)filename); } fprintf(stderr, msg, a, b); } void error(const char* msg, const char* a, long b){ fprintf(stderr, "%s: ", (const char*)progname); #ifdef _MSC_VER if( filename != "" ){ #else if( filename ){ #endif fprintf(stderr, "file '%s': ", (const char*)filename); } fprintf(stderr, msg, a, b); } FILE* openfile(const String& filename){ DEBUG(cerr << "enter openfile with filename=" << filename << "\n" ;) FILE* result=fopen(filename, "w"); if(result == NULL){ error("cannot open '%s': ", (const char*)filename); perror(""); err++; } return result; } int dotg(const char *name, const char *suffix){ // screen out files w/o '.g' suffix if(suffix == 0 || strcmp(suffix, "") == 0) return 1; int suflen = strlen(suffix); if(strlen(name) <= suflen || strcmp(name+strlen(name)-suflen,suffix)){ error("skipping '%s'; doesn't have a '%s' suffix\n", name, suffix); err++; return 0; } return 1; } void parse( // Parse directory part of path into 'dir' // and file part (less '.g') into 'stem' const String& path, // could be a/b/c/d.g String& dir, // would be a/b/c String& stem // would be d ){ DEBUG(cerr << "enter parse with path=" << path << "\n" ;) int index = path.length()-1; while(index>=0){ #if defined(_MSC_VER) || defined(__TCPLUSPLUS__) if(path[index]=='/' || path[index]=='\\'){ #else if(path[(unsigned) index]=='/'){ #endif break; } index--; } DEBUG(cerr << "break from loop with index=" << index << "\n" ;) if(index<0){ dir=""; }else{ dir=path.chunk(0,index); } DEBUG(cerr << "dir=" << dir << "\n" ;) stem = path.chunk( index+1, // starting character path.length()-index-3 // number of characters ); DEBUG(cerr << "stem=" << stem << "\n" ;) } #ifdef _MSC_VER Mapimplement(String,udt_info_ATTLC) Mapimplement(String,int) #endif ////-------------------------------------------- //#include "compfns.h" void prologue(FILE* hf, FILE* cf, const String& stem, const String& hfilename){ DEBUG(cerr << "enter prologue with stem=" << stem << "\n" << "hfilename=" << hfilename << "\n" ;) fprintf(hf, "#include \n"); fprintf(hf, "#include \"Vblock.h\"\n"); #if defined(_MSC_VER) || defined(__TCPLUSPLUS__) fprintf(hf, "#include \"g2.h\"\n\n"); #else fprintf(hf, "#include \"g2++.h\"\n\n"); #endif fprintf(hf, "class istream;\nclass ostream;\n\n"); fprintf(hf, "typedef int %sTYPE;\n", (const char*)upper(stem)); fprintf(hf, "typedef long LONG;\n"); fprintf(hf, "typedef char CHAR;\n"); fprintf(hf, "typedef short SHORT;\n"); fprintf(hf, "typedef String STRING;\n"); fprintf(hf, "\n"); fflush(hf); // Debug // Write necessary #include's to cf #ifdef __GNUG__ fprintf(cf, "#ifdef __GNUG__\n"); fprintf(cf, "#pragma implementation \"Vblock.h\"\n"); fprintf(cf, "#pragma implementation \"Block.h\"\n"); fprintf(cf, "#endif\n"); #endif fprintf(cf, "#include \"%s\"\n", (const char*)hfilename); fprintf(cf, "#include \"g2desc.h\"\n"); fprintf(cf, "#include \"g2inline.h\"\n"); fprintf(cf, "#include \"g2io.h\"\n"); fprintf(cf, "#include \"g2mach.h\"\n"); #if defined(_MSC_VER) || defined(__TCPLUSPLUS__) fprintf(cf, "#include \n"); #else fprintf(cf, "#include \n"); #endif fprintf(cf, "\n"); fflush(cf); // Debug // Generate declaration for array used to hold intermediate // alignment expressions in constructors fprintf(cf,"static int align_val[%d];\n",G2MAXDEPTH_ATTLC); } int #ifdef IOSTREAMH perfile(ifstream& ins, const String& stem, const String& hfilename, const String& cfilename){ #else perfile(istream& ins, const String& stem, const String& hfilename, const String& cfilename){ #endif FILE* hf; FILE* cf; // Use untyped I/O to extract information from // g2 record definitions in ifstream 'ins' // G2NODE* root; G2NODE* t; mtbl* mp; mtbl* first = 0; int OK = 1; for(;;){ // Get a new buffer if(!(gbuf=new G2BUF)){ error("out of memory\n"); exit(1); } if(!getbuf_ATTLC(gbuf,ins)){ DEBUG(cerr << "getbuf_ATTLC returns EOF -- break\n";) break; } DEBUG(cerr << "in perfile, getbuf_ATTLC returns *gbuf=\n";) DEBUG(showbuf_ATTLC(gbuf);) if( gbuf->root->val == "USER" ){ DEBUG(cerr << "USER type!\n";) // This is a USER type: store info in udt_map_ATTLC. // // Note: I tried to do this in a more uniform // fashion (treating user-defined type as an // ordinary type definition (linking it into // mtbl, etc.), and ran into lots of problems. // Now, all information is stored in a separate // table, udt_map_ATTLC. extract_udt_info(gbuf->root); }else{ DEBUG(cerr << "ordinary record type\n";) // Transform the type tree rooted at gbuf->root: // // o Hoist array types to level 0 // o Change string and block definitions // o Generate structure tags for anonymous structures // Begin debug: DEBUG(cerr << "before calling transform, ";) DEBUG(cerr << "list of type trees=\n";) DEBUG( for(t=gbuf->root; t; t=t->next){ showtree_ATTLC(t,0); } ) // End debug head=tail=0; transform(gbuf->root); // Debug: display the list of hoisted types G2NODE* ptr=tail; DEBUG(cerr << "tail:\n";) while( ptr ){ DEBUG(showtree_ATTLC(ptr,1);) ptr=ptr->next; DEBUG(cerr << "tail->next:\n";) } // If any array types were hoisted, append the original // type definition to the end of the chain if( tail ){ DEBUG(cerr << "append the original typedef to the end\n";) tail->next = gbuf->root; /*root =*/ gbuf->root = head; } // Begin debug DEBUG(cerr << "after calling transform, ";) DEBUG(cerr << "list of type trees=\n";) DEBUG(for(t=gbuf->root; t; t=t->next){ DEBUG(showtree_ATTLC(t,0);) }) // End debug // Link this G2BUF into the mtblhead list // Note: this was done previously AFTER checking the // types. Now we must remove the buffer from the mtbl // list before deleting it whenever errors are found. DEBUG(cerr << "ready to call addtbl\n";) if(first==0){ DEBUG(cerr << "first call to addtbl\n";) first = addtbl(gbuf); DEBUG(cerr << "addtbl returns:\n";) DEBUG(showbuf_ATTLC(first->buf);) }else{ DEBUG(cerr << "subsequent call to addtbl\n";) addtbl(gbuf); } DEBUG(cerr << "on return from addtbl, mtblhead-> =\n";) // Begin debug DEBUG(for(mp=mtblhead; mp; mp=mp->next){ DEBUG(cerr << "->\n";) DEBUG(showbuf_ATTLC(mp->buf);) }) // End debug // Check the types... DEBUG(cerr << "Check the types\n";) int ok=1; for(t=gbuf->root; t; t=t->next){ // t->name=lower(t->name); // ...for typename clashes... DEBUG(cerr << "...for typename clashes...\n";) DEBUG(cerr << "ready to call lookup with t->name = " << t->name << "\n" ;) if(lookup(t->name)!=t){ error("duplicate record: '%s'\n", (const char*)t->name); err++; ok=0; } // ...and for well-formedness of the definition DEBUG(cerr << "and for well-formedness of the definition\n";) DEBUG(cerr << "ready to call valid\n";) int temp=valid(0,t); DEBUG(cerr << "valid returns " << temp << "\n" ;) ok &= (temp==0); } DEBUG(cerr << "exit from check-ok loop with ok=" << ok << "\n" ;) if(!ok){ DEBUG(cerr << "ready to call remtbl\n";) remtbl(); // Begin debug DEBUG(cerr << "after remtbl(), mtblhead-> =\n";) DEBUG(for(mp=mtblhead; mp; mp=mp->next){ DEBUG(cerr << "->\n";) DEBUG(showbuf_ATTLC(mp->buf);) }) // End debug delete gbuf; } OK &= ok; } } DEBUG(cerr << "exit from getbuf_ATTLC-loop with OK = " << OK << "\n";) if(!OK){ // Do not generate code if errors were found return 0; }else{ // *********************************************** // * * // * BEGIN CODE GENERATION * // * * // *********************************************** // Debug: display the list of G2BUF's DEBUG(cerr << "mtbl list=\n";) DEBUG(for(mp = mtblhead; mp; mp = mp->next){ cerr << "->\n"; showbuf_ATTLC(mp->buf); }) // Open hfilename for output, setting file pointer hf if((hf=openfile(hfilename))==NULL){ return 0; } // Open cfilename for output, setting file pointer cf if((cf=openfile(cfilename))==NULL){ return 0; } // Write header file guard to protect against multiple // inclusion fprintf(hf, "#ifndef %sH\n#define %sH\n\n", (const char*)upper(stem), (const char*)upper(stem)); // Generate the prologue at beginning of .h and .c files prologue(hf,cf,stem,hfilename); // For each user-defined type in udt_map_ATTLC, generate // the appropriate #include directives. // // Note: include_udt(), sizealign(), wrap(), and // nullify() should be bundled into one routine. DEBUG(cerr << "ready to call include_udt\n";) include_udt(hf); // For each user-defined type T in udt_map_ATTLC, generate // size and alignment constants (these are used in // size and offset computations -- see desc2) DEBUG(cerr << "ready to call sizealign\n";) sizealign(cf); // For each user-defined type T in udt_map_ATTLC, generate // x_put_T and x_get_T wrappers for the client-provided // I/O routines. DEBUG(cerr << "ready to call wrap\n";) wrap(cf); // For each user-defined type T in udt_map_ATTLC, generate // nullify() and isnull() routines that can be called // through a pointer by g2clear(). DEBUG(cerr << "ready to call nullify\n";) nullify(cf); // Generate everything else on a type-by-type basis. DEBUG(cerr << "Generate everything else on a type-by-type basis\n";) for(mp = first; mp; mp = mp->next){ gbuf = mp->buf; for(t=gbuf->root; t; t=t->next){ DEBUG(cerr << "consider tree:\n";) DEBUG(showtree_ATTLC(t,0);) DEBUG(cerr << "ready to call generate\n";) generate(t,hf,cf); if(t->next){ DEBUG(cerr << "this is a hoisted type\n";) // This is a hoisted type; generate a // Vblockdeclare/Vblockimplement pair. #ifdef __GNUG__ blockdef(t,hf,cf); #endif } } } // Bolt the .c file and the .h file together bolt(stem,hf,cf); // Closing endif for file guard fprintf(hf, "\n#endif\n"); // Close the files fclose(hf); fclose(cf); // Return success return 1; } } void extract_udt_info(G2NODE* t){ DEBUG(cerr << "enter extract_udt_info with *t=\n";) DEBUG(showtree_ATTLC(t,0);) udt_info_ATTLC x; // Assume most user-defined types will name five // or fewer header files x.headers.size(5); #ifdef _MSC_VER if(((void *) udt_map_ATTLC.element(g2name_ATTLC(t))) != 0){ #else if(udt_map_ATTLC.element(g2name_ATTLC(t))){ #endif // This type has been defined earlier! error("duplicate user-defined type %s ignored\n", (const char*)g2name_ATTLC(t)); }else{ // Set defaults (may be overridden by attributes) x.headers[0] = g2name_ATTLC(t) + ".h"; x.null = g2name_ATTLC(t) + "()"; x.isnull=""; x.put="operator<<"; x.get="operator>>"; // Get attributes int header_count=0; int put_count=0; int get_count=0; int null_count=0; int isnull_count=0; for(G2NODE* c=g2achild_ATTLC(t); c; c=g2anext_ATTLC(c)){ DEBUG(cerr << "consider attribute child:\n";) DEBUG(shownode_ATTLC(c);) if(g2name_ATTLC(c) == ".header"){ DEBUG(cerr << "header\n";) if(header_count==x.headers.size()){ x.headers.size(2*x.headers.size()); } if (g2val_ATTLC(c) == "") { error("missing file name (or missing tab character) in .header statement for %s\n", g2name_ATTLC(t)); } x.headers[header_count++]=g2val_ATTLC(c); }else if(g2name_ATTLC(c) == ".get"){ DEBUG(cerr << "get\n";) if(++get_count>1){ fprintf(stderr, "file %s: user-defined type %s: duplicate get attribute\n", (const char*)filename, (const char*)t->name); }else{ x.get=g2val_ATTLC(c); } }else if(g2name_ATTLC(c) == ".put"){ DEBUG(cerr << "put\n";) if(++put_count>1){ fprintf(stderr, "file %s: user-defined type %s: duplicate put attribute\n", (const char*)filename, (const char*)t->name); }else{ x.put=g2val_ATTLC(c); } }else if(g2name_ATTLC(c) == ".null"){ DEBUG(cerr << "null\n";) if(++null_count>1){ fprintf(stderr, "file %s: user-defined type %s: duplicate null attribute\n", (const char*)filename, (const char*)t->name); }else{ x.null=g2val_ATTLC(c); } }else if(g2name_ATTLC(c) == ".isnull"){ DEBUG(cerr << "isnull\n";) if(++isnull_count>1){ fprintf(stderr, "file %s: user-defined type %s: duplicate isnull attribute\n", (const char*)filename, (const char*)t->name); }else{ x.isnull=g2val_ATTLC(c); } } } if(header_count==0){ header_count=1; // the default; } x.header_count=header_count; DEBUG(cerr << "after for loop, x=\n";) DEBUG(show_udt_info(x);) // Store x in udt_map_ATTLC DEBUG(cerr << "ready to store x in udt_map_ATTLC\n";) udt_map_ATTLC[g2name_ATTLC(t)]=x; DEBUG(cerr << "ready to return\n";) } } ////-------------------------------------------- //#include "compfns.h" void show_udt_info(udt_info_ATTLC x){ int nheaders=x.header_count; DEBUG(cerr << "nheaders=" << nheaders << "\n" ;) for(int k=0; k < nheaders; k++){ DEBUG(cerr << x.headers[k] << "\n";) } DEBUG(cerr << ".put=" << x.put << "\n" << ".get=" << x.get << "\n" << ".null=" << x.null << "\n" << ".isnull=" << x.isnull << "\n" ;) } void show_udt_map(){ #ifdef _MSC_VER Mapiter(String,udt_info_ATTLC) i(udt_map_ATTLC); #else Mapiter i(udt_map_ATTLC); #endif DEBUG(cerr << "udt_map_ATTLC:\n";) while(++i){ DEBUG(cerr << " " << i.key() << "\t" << "(" ;) DEBUG(udt_info_ATTLC x = i.value();) DEBUG(cerr << ",";) DEBUG(show_udt_info(x);) DEBUG(cerr << ")";) } } void sizealign(FILE* cf){ // Generate size and alignment constants for // each user-defined type in udt_map_ATTLC #ifdef _MSC_VER Mapiter(String,udt_info_ATTLC) i(udt_map_ATTLC); #else Mapiter i(udt_map_ATTLC); #endif while(++i){ fprintf(cf, "static struct x%s{\n char base[1];\n %s x;\n}x%s;\n\n", (const char*)i.key(), (const char*)i.key(), (const char*)i.key()); fprintf(cf, "static const int %s_SIZE=sizeof(%s);\n", (const char*)i.key(), (const char*)i.key()); fprintf(cf, "static const char* %s_ALIGN_SIMPLIFY_EXPRESSION=(char*)(&x%s.x);\n", (const char*)i.key(), (const char*)i.key()); // fprintf(cf, // "static const int %s_ALIGN=%s_ALIGN_SIMPLIFY_EXPRESSION-x%s.base;\n\n", // (const char*)i.key(), (const char*)i.key(), (const char*)i.key()); fprintf(cf, "static int get_%s_ALIGN() {\n return(%s_ALIGN_SIMPLIFY_EXPRESSION-x%s.base); }\n\n", (const char*)i.key(), (const char*)i.key(), (const char*)i.key()); } } void include_udt(FILE* hf){ #ifdef _MSC_VER Mapiter(String,udt_info_ATTLC) i(udt_map_ATTLC); #else Mapiter i(udt_map_ATTLC); #endif DEBUG(cerr << "enter include_udt\n";) while(++i){ udt_info_ATTLC x=i.value(); DEBUG(cerr << "in while loop, x=\n";) DEBUG(show_udt_info(x);) for(int j=0;j i(udt_map_ATTLC); #endif DEBUG(cerr << "enter wrap\n";) while(++i){ String name=i.key(); DEBUG(cerr << "in while loop, i.key()=" << name << "\n" ;) udt_info_ATTLC x=i.value(); DEBUG(cerr << "...and i.value()=\n";) DEBUG(show_udt_info(x);) if(x.put == "operator<<"){ fprintf(cf, "static ostream& x_put_%s(ostream& os,const void* vp){\n", (const char*)name); fprintf(cf, " return os << *(%s*)vp;\n}\n", (const char*)name); }else{ fprintf(cf, "static ostream& x_put_%s(ostream& os,const void* vp){\n", (const char*)name); fprintf(cf, " return %s(os,*(%s*)vp);\n}\n", (const char*)x.put, (const char*)name); } if(x.get == "operator>>"){ fprintf(cf, "static istream& x_get_%s(istream& is,void* vp){\n", (const char*)name); fprintf(cf, " return is >> *(%s*)vp;\n}\n", (const char*)name); }else{ fprintf(cf, "static istream& x_get_%s(istream& is,void* vp){\n", (const char*)name); fprintf(cf, " return %s(is,*(%s*)vp);\n}\n", (const char*)x.get, (const char*)name); } } } void nullify(FILE* cf){ #ifdef _MSC_VER Mapiter(String,udt_info_ATTLC) i(udt_map_ATTLC); #else Mapiter i(udt_map_ATTLC); #endif DEBUG(cerr << "enter nullify\n";) while(++i){ String name=i.key(); udt_info_ATTLC x=i.value(); // fprintf(cf, "static %s null_%s=%s;\n", // (const char*)name, // (const char*)name, // (const char*)x.null); if (x.null != "") { fprintf(cf, "static %s& null_%s(){\n static %s nval = %s; return nval;}\n", (const char*)name, (const char*)name, (const char*)name, (const char*)x.null); } else { fprintf(cf, "static %s& null_%s(){\n static %s nval; return nval;}\n", (const char*)name, (const char*)name, (const char*)name); } fprintf(cf, // "static void %s_nullify(void* vp){\n *(%s*)vp=null_%s;\n}\n", "static void %s_nullify(void* vp){\n *(%s*)vp=null_%s();\n}\n", (const char*)name, (const char*)name, (const char*)name); String result; if( x.isnull.is_empty() ){ // result = "*(" + name + "*)vp==null_" + name; result = "*(" + name + "*)vp==null_" + name + "()"; }else{ result = x.isnull + "(*(" + name + "*)vp)"; } fprintf(cf, "static int %s_is_null(void* vp){\n return %s;\n}\n", (const char*)name, (const char*)result); } } void bdef(G2NODE* t, FILE* hf, FILE* cf){ DEBUG(cerr << "enter bdef with t=\n";) DEBUG(showtree_ATTLC(t,1);) // Visit t's children for(G2NODE* cp=t->child; cp; cp=cp->next){ DEBUG(cerr << "ready to visit t's next child\n";) bdef(cp,hf,cf); } // Then visit t DEBUG(cerr << "exit from children loop; now visit t itself\n";) DEBUG(showtree_ATTLC(t,1);) if(isdigit_ATTLC(t->name.char_at(0))){ // t is an array (note: all arrays have // been transformed into terminal arrays) DEBUG( cerr << "t->name is a digit: t is an array\n"; ) String a_typename; if(isdigit_ATTLC(t->val.char_at(0))){ a_typename = "STRING"; }else{ a_typename = upper(t->val); } DEBUG(cerr << "t's typename is " << a_typename << "\n" ;) #ifdef _MSC_VER // Invoke vblockdeclare macro DEBUG(cerr << "put to .h file:\n ***Vblockdeclare(" << a_typename << ");\n" ;) fprintf(hf, "Vblockdeclare(%s);\n", (const char*)a_typename); fflush(hf); // Debug // Invoke blockimplement macro DEBUG(cerr << "put to .c file:\n ***Vblockimplement(" << a_typename << ");\n" ;) fprintf(cf, "Vblockimplement(%s);\n", (const char*)a_typename); fflush(cf); // Debug #endif } } void #ifdef __GNUG__ blockdef(G2NODE* t, FILE* hf, FILE* cf){ DEBUG(cerr << "put to .c file:\n ***#ifdef __GNUG__\n";) DEBUG(cerr << "put to .c file:\n ***template class Vblock<" << upper(t->name) << ">;\n" ;) DEBUG(cerr << "put to .c file:\n ***#endif\n";) fprintf(cf, "#ifdef __GNUG__\n"); fprintf(cf, "template class Vblock<%s>;\n", (const char*)upper(t->name)); fprintf(cf, "#endif\n"); fflush(hf); // Debug #else #ifndef _MSC_VER blockdef(G2NODE*, FILE*, FILE*){ #else blockdef(G2NODE* t, FILE* hf, FILE* cf){ DEBUG(cerr << "put to .h file:\n ***Vblockdeclare(" << upper(t->name) << ");\n" ;) fprintf(hf, "Vblockdeclare(%s);\n", (const char*)upper(t->name)); fflush(hf); // Debug DEBUG(cerr << "put to .c file:\n ***Vblockimplement(" << upper(t->name) << ");\n" ;) fprintf(cf, "Vblockimplement(%s);\n", (const char*)upper(t->name)); fflush(cf); // Debug #endif #endif } void generate(G2NODE* t, FILE* hf, FILE* cf){ // Generate typedefs in .h file // (.c file is needed for constructor definitions, which // used to be inline in the .h file, but which gave "outline // inline" warning messages from CC +w DEBUG(cerr << "ready to call tdef\n";) bdef(t,hf,cf); tdef(t,hf,cf); // Generate descriptor tables in .c file DEBUG(cerr << "ready to call desc\n";) desc(t,t->name,cf); // Generate stream insertion and extraction operators DEBUG(cerr << "ready to call gen_io\n";) gen_io(t,hf,cf); } void gen_io(G2NODE* t, FILE* hf, FILE* cf){ // Generate stream insertion and extraction // function declarations in .h file fprintf(hf, "\nostream& operator<<(ostream& os, const %s& buf);\n", (const char*)(upper(t->name))); fprintf(hf, "istream& operator>>(istream& is, %s& buf);\n\n", (const char*)(upper(t->name))); fflush(hf); // Debug // Generate function definitions in .c file fprintf(cf, "\nostream& operator<<(ostream& os, const %s& buf){\n", (const char*)(upper(t->name))); fprintf(cf, // " if(!os)return os;\n putrec_ATTLC((void*)&buf,%s,os);\n", " if(!os)return os;\n putrec_ATTLC((void*)&buf,%s_,os);\n", (const char*)t->name); fprintf(cf, " return os;\n}\n"); fprintf(cf, "\nistream& operator>>(istream& is, %s& buf){\n", (const char*)(upper(t->name))); // fprintf(cf, " if(!is)return is;\n getrec_ATTLC(&buf,%s,is);\n", fprintf(cf, " if(!is)return is;\n getrec_ATTLC(&buf,%s_,is);\n", (const char*)t->name); fprintf(cf, " return is;\n}\n"); fflush(cf); // Debug } void transform(G2NODE* p){ // static int count=0; DEBUG(cerr << "enter transform with *p=\n";) DEBUG(showtree_ATTLC(p,0);) G2NODE* c=p->child; if(c){ // Generate a type tag // // Note: we just ignore the case where p->val is nonempty // // assert(p->val==""); String rand=ranstr(G2TAGLEN_ATTLC); SoS[rand] = 1; // record randomly generated class names p->val=rand; DEBUG(cerr << "after generating tag, *p=\n";) DEBUG(showtree_ATTLC(p,0);) char temp = c->name.char_at(0); int isarray=( temp=='*' || // flexible isdigit_ATTLC(temp) // fixed ); if(isarray){ DEBUG(cerr << "p is an array\n";) }else{ DEBUG(cerr << "p is a structure\n";) } // Visit p's children DEBUG(cerr << "ready to visit p's children\n";) for(G2NODE* cp=c; cp; cp=cp->next){ DEBUG(cerr << "visit next child\n";) transform(cp); } DEBUG(cerr << "after transforming, p=\n";) DEBUG(showtree_ATTLC(p,0);) if(isarray){ // Change arrays dimensioned using "*" to "0" // // Note: only modify the first character, preserving // any initial-reserve specification that may follow the // asterisk, e.g.: // // usr // *(100) LONG # initially reserve 100 if(c->name.char_at(0) == '*'){ c->name[(unsigned)0]='0'; } // Hoist a type definition for non-terminal arrays if(c->child!=0){ DEBUG(cerr << "non-terminal array\n";) DEBUG(cerr << "after hoisting,\n";) // Set up a new G2NODE for the hoisted type if(gbuf->ptr >= gbuf->end){ error("out of memory\n"); exit(1); } G2NODE* n = gbuf->ptr++; n->name = c->val; n->val = "HOISTED"; // jfi n->next = 0; n->child = c->child; // Detach the subtree rooted at p's child c->child = 0; DEBUG(cerr << "p=\n";) DEBUG(showtree_ATTLC(p,0);) DEBUG(cerr << "n=\n";) DEBUG(showtree_ATTLC(n,0);) // Link the subtree into the list of generated type trees if(tail){ tail->next = n; tail = n; }else{ head = tail = n; } } } // Fix up Strings declared with "*" }else if(p->val.char_at(0)=='*'){ DEBUG(cerr << "p->val.char_at(0)=='*' means p is a flexible string\n";) // Again, we only modify the first character, preserving // any initial-reserve specification that may follow the // asterisk, e.g.: // // usr *(100) # initially reserve 100 p->val[(unsigned)0] = '0'; DEBUG(showtree_ATTLC(p,0);) // Fix up arrays declared with "*" }else if(p->name.char_at(0)=='*'){ DEBUG(cerr << "p is a flexible array\n";) // Again, we only modify the first character, preserving // any initial-reserve specification that may follow the // asterisk, e.g.: // // usr // *(100) LONG # initially reserve 100 p->name[(unsigned)0] = '0'; DEBUG(showtree_ATTLC(p,0);) } } void bolt(const String& stem, FILE* hf, FILE* cf){ // Bolt .h and .c files together with strange symbol String fastener = "g2" + stem + ranstr(4) + "_ATTLC"; fprintf(hf, "extern int %s;\n", (const char*)fastener); fflush(hf); // Debug fprintf(hf, "static int *_%s = &%s;\n\n", (const char*)fastener, (const char*)fastener); fflush(hf); // Debug fprintf(cf, "int %s;\n", (const char*)fastener); fflush(hf); // Debug // The following trick eliminates the warning about the // unused static int* given by cfront (the inline should // never be "laid down" fprintf(hf, "inline void __%s(){ (*_%s)++; }\n", (const char*)fastener, (const char*)fastener); fflush(hf); // Debug } void resettbl(){ DEBUG(cerr << "enter resettbl\n";) nulldef.name=""; nulldef.val=""; nulldef.next = nulldef.child = 0; // set up definition for char type // // char_def: // // tattoo G2MOTHER_ATTLC // root o--------------> chardef // base o--------------> chardef // ptr o--------------> nulldef // end o-----------| // buf chardef | // nulldef | // xxxxxxx <---------- // xxxxxxx // // chardef: // // name "CHAR" // val "-100" // next o-----> // child o-----> // DEBUG(cerr << "ready to initialize chardef\n";) chardef.name="CHAR"; chardef.val=CHAR_ASC_ATTLC; chardef.next = chardef.child = 0; DEBUG(shownode_ATTLC(&chardef);) DEBUG(cerr << "ready to initialize char_def\n";) char_def.tattoo=G2MOTHER_ATTLC; char_def.buf.size(2); char_def.buf[0]=chardef; char_def.buf[1]=nulldef; char_def.base=char_def.root=char_def.buf; #if defined(_MSC_VER) || defined(__TCPLUSPLUS__) || defined(__SUNPRO_CC) || defined(__GNUG__) char_def.ptr=((G2NODE*)char_def.buf)+1; char_def.end=((G2NODE*)char_def.buf)+2; #else char_def.ptr=char_def.buf+1; char_def.end=char_def.buf+2; #endif DEBUG(showbuf_ATTLC(&char_def);) // do same for short... DEBUG(cerr << "ready to initialize shortdef\n";) shortdef.name="SHORT"; shortdef.val=SHORT_ASC_ATTLC; shortdef.next = shortdef.child = 0; DEBUG(shownode_ATTLC(&shortdef);) DEBUG(cerr << "ready to initialize short_def\n";) short_def.buf.size(2); short_def.buf[0]=shortdef; short_def.buf[1]=nulldef; short_def.base=short_def.root=short_def.buf; #if defined(_MSC_VER) || defined(__TCPLUSPLUS__) || defined(__SUNPRO_CC) || defined(__GNUG__) short_def.ptr=((G2NODE*)short_def.buf)+1; short_def.end=((G2NODE*)short_def.buf)+2; #else short_def.ptr=short_def.buf+1; short_def.end=short_def.buf+2; #endif DEBUG(showbuf_ATTLC(&short_def);) // ...and long DEBUG(cerr << "ready to initialize longdef\n";) longdef.name="LONG"; longdef.val=LONG_ASC_ATTLC; longdef.next = longdef.child = 0; DEBUG(shownode_ATTLC(&longdef);) DEBUG(cerr << "ready to initialize long_def\n";) long_def.buf.size(2); long_def.buf[0]=longdef; long_def.buf[1]=nulldef; long_def.base=long_def.root=long_def.buf; #if defined(_MSC_VER) || defined(__TCPLUSPLUS__) || defined(__SUNPRO_CC) || defined(__GNUG__) long_def.ptr=((G2NODE*)long_def.buf)+1; long_def.end=((G2NODE*)long_def.buf)+2; #else long_def.ptr=long_def.buf+1; long_def.end=long_def.buf+2; #endif DEBUG(showbuf_ATTLC(&long_def);) // ...and string DEBUG(cerr << "ready to initialize stringdef\n";) stringdef.name="STRING"; stringdef.val=STRING_ASC_ATTLC; stringdef.next = stringdef.child = 0; DEBUG(shownode_ATTLC(&stringdef);) DEBUG(cerr << "ready to initialize string_def\n";) string_def.buf.size(2); string_def.buf[0]=stringdef; string_def.buf[1]=nulldef; string_def.base=string_def.root=string_def.buf; #if defined(_MSC_VER) || defined(__TCPLUSPLUS__) || defined(__SUNPRO_CC) || defined(__GNUG__) string_def.ptr=((G2NODE*)string_def.buf)+1; string_def.end=((G2NODE*)string_def.buf)+2; #else string_def.ptr=string_def.buf+1; string_def.end=string_def.buf+2; #endif DEBUG(showbuf_ATTLC(&string_def);) // reinitialize mtblhead-> list to empty DEBUG(cerr << "ready to initialize mtblhead-> list to empty\n";) mtbl* mp = mtblhead; DEBUG(cerr << "in resettbl, mp = " << long(mp) << "\n";) while( mp ){ mtbl* t = mp; mp = mp->next; delete t; } mtblhead = NULL; // Pre-populate list with definitions for string, long, short, // and char types // // mtbltail // | // V // mtblhead------>o o-------->o o------------>o o // | | | // | | | // V V V // long_def short_def char_def // addtbl(&string_def); addtbl(&long_def); addtbl(&short_def); addtbl(&char_def); } ////-------------------------------------------- //#include "compfns.h" mtbl* addtbl(G2BUF* buf){ // mtbl* mp = (mtbl*)calloc(1,sizeof(mtbl)); mtbl* mp = new mtbl; mp->buf = 0; mp->next=0; if( !mp ){ error("out of memory\n"); exit(1); } mp->buf = buf; if( !mtblhead ){ // first time mtblhead = mtbltail = mp; }else{ mtbltail->next = mp; mtbltail = mp; } return mp; } void remtbl(){ mtbl* mp=mtblhead; mtbl* temp; mtbltail=0; // Find the end of the list while(mp && ((temp=mp->next) != 0)){ mtbltail=mp; mp=temp; } // Remove the last element and fix up pointers if( mtbltail ){ mtbltail->next=0; }else{ mtblhead=0; } } #if 0 void prtbls(const String& stem, FILE* hf, FILE* cf){ int i; String ustem=upper(stem); mtbl* mp; fprintf(hf, "extern G2DESC *%s[];\n", (const char*)stem); fflush(hf); // Debug fprintf(hf, "typedef union %s {\n", (const char*)ustem); fflush(hf); // Debug for( mp = mtblhead; mp; mp = mp->next ){ String name = mp->buf->root->name; String uname=upper(name); if( !isupper(name.char_at(0)) ){ fprintf(hf, " %s %s;\n", (const char*)uname, (const char*)name); fflush(hf); // Debug } } fprintf(hf, "} %s;\n\n", (const char*)ustem); fflush(hf); // Debug i = 0; for( mp = mtblhead; mp; mp = mp->next ){ String name = mp->buf->root->name; if( !isupper(name.char_at(0)) ){ String uname=upper(name); fprintf(hf, "#define %s_%s %d\n", (const char*)ustem, (const char*)uname, i++); fflush(hf); // Debug } } fprintf(cf, "G2DESC *%s[] = {\n", (const char*)stem); fflush(cf); // Debug for( mp = mtblhead; mp; mp = mp->next ){ String name = mp->buf->root->name; if( !isupper(name.char_at(0)) ){ fprintf(cf, " %s,\n", (const char*)name); fflush(cf); // Debug } } fprintf(cf, " 0\n"); fflush(cf); // Debug fprintf(cf, "};\n"); fflush(cf); // Debug fprintf(cf, "int %s_nrec_ = %d;\n\n", (const char*)stem, i); fflush(cf); // Debug } #endif String lower(const String& s){ String result(Stringsize(s.length())); for( int i=0;i= 0 ){ int i=rand(); int k = i % j; result+=range.char_at(k); } DEBUG(cerr << "ranstr returns result = " << result << "\n";) return result; } ostream& operator<<(ostream& os, const udt_info_ATTLC &) { return os; } unsigned do_checksum(const char *fname) { unsigned retval = 0; FILE *f = fopen(fname, "r"); int c; while ((c = getc(f)) != EOF) { retval = retval * 271 + c; } fclose(f); return (retval); }