Personal tools
You are here: Home Projects C++ Cfront releases Release 3.0.3 source libSC G2++ compsrc comp.c
Document Actions

comp.c

by Michael L Powell last modified 2007-01-26 03:23

Click here to get the file

Size 48.1 kB - File type text/plain

File contents

/*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 <Map.h>
#include <g2comp.h>
#include <g2ctype.h>
#include <g2debug.h>
#include <g2io.h>
#include <g2mach.h>

#include <ctype.h>
#define IOSTREAMH
#ifdef IOSTREAMH
#include <fstream.h>
#else
#include <iostream.h>
#endif
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>
#include <iostream.h>
#include <String.h>

//  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<String,udt_info_ATTLC>;
template class Map<String,int>;
#endif
extern Map<String,udt_info_ATTLC> udt_map_ATTLC;
extern Map<String,int> 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<String,udt_info_ATTLC> udt_map_ATTLC;
Map<String,int> 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<XXX>, 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(i<level){
	    result += ".";
	}
    }
    return result;
}

String 
upper(const String& s){
    String result(Stringsize(s.length()));;

    if (no_cap_flag) {
	result = s;
    }
    else {
    for( int i=0;i<s.length();i++ ){

	if( islower(s.char_at(i)) ){
	    result += toupper(s.char_at(i));
	}else{
	    result += s.char_at(i);
	}
    }
    }
    return result;
}

G2NODE* 
lookup(const String& name){
    if(isdigit_ATTLC(name.char_at(0))){  // optimization
	return NULL;
    }
    DEBUG(cerr << "enter lookup with name=" << name << "\n" ;)
    for(mtbl* mp = mtblhead; mp; mp = mp->next){
/*	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 <String.h>\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 <iostream.h>\n");
#else
    fprintf(cf, "#include <stream.h>\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<String,udt_info_ATTLC> 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<String,udt_info_ATTLC> 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<String,udt_info_ATTLC> 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<x.header_count;j++){
	    DEBUG(cerr << "in j loop, consider header " << x.headers[j]
		<< "\n" ;)
	    fprintf(hf, "#include \"%s\"\n", (const char*)x.headers[j]);
	}
    }
    DEBUG(cerr << "ready to return from include_udt\n";)
}

void
wrap(FILE* cf){
#ifdef _MSC_VER
    Mapiter(String,udt_info_ATTLC) i(udt_map_ATTLC);
#else
    Mapiter<String,udt_info_ATTLC> 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<String,udt_info_ATTLC> 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<s.length();i++ ){
	
	if( isupper(s.char_at(i)) ){
	    result += tolower(s.char_at(i));
	}else{
	    result += s.char_at(i);
	}
    }
    return result;
}

String 
ranstr(int len){
//#if defined(_MSC_VER) || defined(__TCPLUSPLUS__)
    Stringsize sz_tmp(len);
    String result(sz_tmp);
//#else
//    String result(Stringsize(len));
//#endif
    String range = "abcdefghijklmnopqrstuvwxyz"; // used to include caps and digits

    int j = range.length();
    while( --len >= 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);
}
« April 2024 »
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: