/* * main.c -- main program for PCCTS ANTLR. * * $Id: main.c,v 1.7 95/10/05 11:57:08 parrt Exp $ * $Revision: 1.7 $ * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-1995 */ #include #ifdef __cplusplus #ifndef __STDC__ #define __STDC__ #endif #endif #include "stdpccts.h" #define MAX_INT_STACK 50 static int istack[MAX_INT_STACK]; /* Int stack */ static int isp = MAX_INT_STACK; static int DontAcceptFiles = 0; /* if stdin, don't read files */ static int DontAcceptStdin = 0; /* if files seen first, don't accept stdin */ /* C m d - L i n e O p t i o n S t r u c t & F u n c s */ typedef struct _Opt { char *option; int arg; #ifdef __cplusplus void (*process)(...); #else void (*process)(); #endif char *descr; } Opt; #ifdef __STDC__ extern void ProcessArgs(int, char **, Opt *); #else extern void ProcessArgs(); #endif static void #ifdef __STDC__ pStdin( void ) #else pStdin( ) #endif { if ( DontAcceptStdin ) { warnNoFL("'-' (stdin) ignored as files were specified first"); return; } require(NumFiles0 ) { warnNoFL("must have compressed lookahead >= full LL(k) lookahead (setting -ck to -k)"); CLL_k = LL_k; } if ( CLL_k == -1 ) CLL_k = LL_k; OutputLL_k = CLL_k; if ( ((CLL_k-1)&CLL_k)!=0 ) { /* output ll(k) must be power of 2 */ int n; for(n=1; n1 && HdrAction == NULL ) warnNoFL("no #header action was found"); EpToken = addTname(EPSTR); /* add imaginary token epsilon */ set_orel(EpToken, &imag_tokens); /* this won't work for hand-built scanners since EofToken is not * known. Forces EOF to be token type 1. */ set_orel(EofToken, &imag_tokens); set_size(NumWords(TokenNum-1)); /* compute the set of all known token types * It represents the set of tokens from 1 to last_token_num + the * reserved positions above that (if any). Don't include the set of * imaginary tokens such as the token/error classes or EOF. */ { set a; a = set_dup(reserved_positions); for (i=1; inext; p!=NULL; p=p->next) { UserAction *ua = (UserAction *)p->elem; dumpAction( ua->action, Parser_h, 0, ua->file, ua->line, 1); } } GenParser_c_Hdr(); NewSetWd(); TRANS(SynDiag); /* Translate to the target language */ DumpSetWd(); GenRuleMemberDeclarationsForCC(Parser_h, SynDiag); if ( class_after_actions != NULL ) { ListNode *p; for (p = class_after_actions->next; p!=NULL; p=p->next) { UserAction *ua = (UserAction *)p->elem; dumpAction( ua->action, Parser_h, 0, ua->file, ua->line, 1); } } DumpRemainingTokSets(); fprintf(Parser_h, "};\n"); fprintf(Parser_h, "\n#endif /* %s_h */\n", CurrentClassName); fclose( Parser_h ); fclose( Parser_c ); } } if ( PrintOut ) { if ( SynDiag == NULL ) {warnNoFL("no grammar description recognized");} else PRINT(SynDiag); } GenRemapFile(); /* create remap.h */ cleanUp(); exit(PCCTS_EXIT_SUCCESS); } static void #ifdef __STDC__ init( void ) #else init( ) #endif { SignalEntry *q; Tname = newHashTable(); Rname = newHashTable(); Fcache = newHashTable(); Tcache = newHashTable(); Sname = newHashTable(); /* Add default signal names */ q = (SignalEntry *)hash_add(Sname, "NoViableAlt", (Entry *)newSignalEntry("NoViableAlt")); require(q!=NULL, "cannot alloc signal entry"); q->signum = sigNoViableAlt; q = (SignalEntry *)hash_add(Sname, "MismatchedToken", (Entry *)newSignalEntry("MismatchedToken")); require(q!=NULL, "cannot alloc signal entry"); q->signum = sigMismatchedToken; q = (SignalEntry *)hash_add(Sname, "NoSemViableAlt", (Entry *)newSignalEntry("NoSemViableAlt")); require(q!=NULL, "cannot alloc signal entry"); q->signum = sigNoSemViableAlt; reserved_positions = empty; all_tokens = empty; imag_tokens = empty; tokclasses = empty; TokenStr = (char **) calloc(TSChunk, sizeof(char *)); require(TokenStr!=NULL, "main: cannot allocate TokenStr"); FoStack = (int **) calloc(CLL_k+1, sizeof(int *)); require(FoStack!=NULL, "main: cannot allocate FoStack"); FoTOS = (int **) calloc(CLL_k+1, sizeof(int *)); require(FoTOS!=NULL, "main: cannot allocate FoTOS"); Cycles = (ListNode **) calloc(CLL_k+1, sizeof(ListNode *)); require(Cycles!=NULL, "main: cannot allocate Cycles List"); } static void #ifdef __STDC__ help( void ) #else help( ) #endif { Opt *p = options; fprintf(stderr, "antlr [options] f1 f2 ... fn\n"); while ( *(p->option) != '*' ) { fprintf(stderr, "\t%-4s %s %s\n", p->option, (p->arg)?"___":" ", p->descr); p++; } } /* The RulePtr array is filled in here. RulePtr exists primarily * so that sets of rules can be maintained for the FOLLOW caching * mechanism found in rJunc(). RulePtr maps a rule num from 1 to n * to a pointer to its RuleBlk junction where n is the number of rules. */ static void #ifdef __STDC__ buildRulePtr( void ) #else buildRulePtr( ) #endif { int r=1; Junction *p = SynDiag; RulePtr = (Junction **) calloc(NumRules+1, sizeof(Junction *)); require(RulePtr!=NULL, "cannot allocate RulePtr array"); while ( p!=NULL ) { require(r<=NumRules, "too many rules???"); RulePtr[r++] = p; p = (Junction *)p->p2; } } void #ifdef __STDC__ dlgerror(const char *s) #else dlgerror(s) char *s; #endif { fprintf(stderr, ErrHdr, FileStr[CurFile], zzline); fprintf(stderr, " lexical error: %s (text was '%s')\n", ((s == NULL) ? "Lexical error" : s), zzlextext); } void #ifdef __STDC__ readDescr( void ) #else readDescr( ) #endif { zzerr = dlgerror; input = NextFile(); if ( input==NULL ) fatal("No grammar description found (exiting...)"); ANTLR(grammar(), input); } FILE * #ifdef __STDC__ NextFile( void ) #else NextFile( ) #endif { FILE *f; for (;;) { CurFile++; if ( CurFile >= NumFiles ) return(NULL); if ( strcmp(FileStr[CurFile],"stdin") == 0 ) return stdin; f = fopen(FileStr[CurFile], "r"); if ( f == NULL ) { warnNoFL( eMsg1("file %s doesn't exist; ignored", FileStr[CurFile]) ); } else { return(f); } } } /* * Return a string corresponding to the output file name associated * with the input file name passed in. * * Observe the following rules: * * f.e --> f".c" * f --> f".c" * f. --> f".c" * f.e.g --> f.e".c" * * Where f,e,g are arbitrarily long sequences of characters in a file * name. * * In other words, if a ".x" appears on the end of a file name, make it * ".c". If no ".x" appears, append ".c" to the end of the file name. * * C++ mode using .cpp not .c. * * Use malloc() for new string. */ char * #ifdef __STDC__ outname( char *fs ) #else outname( fs ) char *fs; #endif { static char buf[MaxFileName+1]; char *p; require(fs!=NULL&&*fs!='\0', "outname: NULL filename"); p = buf; strcpy(buf, fs); while ( *p != '\0' ) {p++;} /* Stop on '\0' */ while ( *p != '.' && p != buf ) {--p;} /* Find '.' */ if ( p != buf ) *p = '\0'; /* Found '.' */ require(strlen(buf) + 2 < (size_t)MaxFileName, "outname: filename too big"); if ( GenCC ) strcat(buf, CPP_FILE_SUFFIX); else strcat(buf, ".c"); return( buf ); } void #ifdef __STDC__ fatalFL( char *err_, char *f, int l ) #else fatalFL( err_, f, l ) char *err_; char *f; int l; #endif { fprintf(stderr, ErrHdr, f, l); fprintf(stderr, " %s\n", err_); cleanUp(); exit(PCCTS_EXIT_FAILURE); } void #ifdef __STDC__ fatal_intern( char *err_, char *f, int l ) #else fatal_intern( err_, f, l ) char *err_; char *f; int l; #endif { fprintf(stderr, ErrHdr, f, l); fprintf(stderr, " #$%%*&@# internal error: %s\n", err_); fprintf(stderr, ErrHdr, f, l); fprintf(stderr, " [complain to nearest government official\n"); fprintf(stderr, ErrHdr, f, l); fprintf(stderr, " or send hate-mail to parrt@parr-research.com;\n"); fprintf(stderr, ErrHdr, f, l); fprintf(stderr, " please pray to the ``bug'' gods that there is a trival fix.]\n"); cleanUp(); exit(PCCTS_EXIT_FAILURE); } void #ifdef __STDC__ cleanUp( void ) #else cleanUp( ) #endif { if ( DefFile != NULL) fclose( DefFile ); } /* sprintf up to 3 strings */ char * #ifdef __STDC__ eMsg3( char *s, char *a1, char *a2, char *a3 ) #else eMsg3( s, a1, a2, a3 ) char *s; char *a1; char *a2; char *a3; #endif { static char buf[250]; /* DANGEROUS as hell !!!!!! */ sprintf(buf, s, a1, a2, a3); return( buf ); } /* sprintf a decimal */ char * #ifdef __STDC__ eMsgd( char *s, int d ) #else eMsgd( s, d ) char *s; int d; #endif { static char buf[250]; /* DANGEROUS as hell !!!!!! */ sprintf(buf, s, d); return( buf ); } void #ifdef __STDC__ s_fprT( FILE *f, set e ) #else s_fprT( f, e ) FILE *f; set e; #endif { register unsigned *p; unsigned *q; if ( set_nil(e) ) return; if ( (q=p=set_pdq(e)) == NULL ) fatal_internal("Can't alloc space for set_pdq"); fprintf(f, "{"); while ( *p != nil ) { fprintf(f, " %s", TerminalString(*p)); p++; } fprintf(f, " }"); free((char *)q); } /* Return the token name or regular expression for a token number. */ char * #ifdef __STDC__ TerminalString( int token ) #else TerminalString( token ) int token; #endif { int j; /* look in all lexclasses for the token */ if ( TokenString(token) != NULL ) return TokenString(token); for (j=0; j0, "pushint: stack overflow"); istack[--isp] = i; } int #ifdef __STDC__ popint( void ) #else popint( ) #endif { require(isp 0 ) { p = options; while ( p->option != NULL ) { if ( strcmp(p->option, "*") == 0 || strcmp(p->option, *argv) == 0 ) { if ( p->arg ) { (*p->process)( *argv, *(argv+1) ); argv++; argc--; } else (*p->process)( *argv ); break; } p++; } argv++; } } /* Go back into the syntax diagram and compute all meta tokens; i.e. * turn all '.', ranges, token class refs etc... into actual token sets */ static void CompleteTokenSetRefs() { ListNode *p; if ( MetaTokenNodes==NULL ) return; for (p = MetaTokenNodes->next; p!=NULL; p=p->next) { set a,b; TokNode *q = (TokNode *)p->elem; if ( q->wild_card ) { q->tset = all_tokens; } else if ( q->tclass!=NULL ) { if ( q->complement ) q->tset = set_dif(all_tokens, q->tclass->tset); else q->tset = q->tclass->tset; } else if ( q->upper_range!=0 ) { /* we have a range on our hands: make a set from q->token .. q->upper_range */ int i; a = empty; for (i=q->token; i<=(int)q->upper_range; i++) { set_orel(i, &a); } q->tset = a; } /* at this point, it can only be a complemented single token */ else if ( q->complement ) { a = set_of(q->token); b = set_dif(all_tokens, a); set_free(a); q->tset=b; } else fatal("invalid meta token"); } } char * #ifdef __STDC__ OutMetaName(char *n) #else OutMetaName(n) char *n; #endif { static char buf[MaxFileName+1]; if ( strcmp(OutputDirectory,TopDirectory)==0 ) return n; strcpy(buf, OutputDirectory); if ( strcmp(&buf[strlen(buf) - 1], DirectorySymbol ) ) strcat(buf, DirectorySymbol); strcat(buf, n); return buf; } static void #ifdef __STDC__ ensure_no_C_file_collisions(char *class_c_file) #else ensure_no_C_file_collisions(class_c_file) char *class_c_file; #endif { int i; for (i=0; i= NumFiles && CurFile >= 1 ) CurFile--; fprintf(stderr, ErrHdr, FileStr[CurFile], zzline); fprintf(stderr, " warning: %s\n", err); } void #ifdef __STDC__ warnNoCR( char *err ) #else warnNoCR( err ) char *err; #endif { /* back up the file number if we hit an error at the end of the last file */ if ( CurFile >= NumFiles && CurFile >= 1 ) CurFile--; fprintf(stderr, ErrHdr, FileStr[CurFile], zzline); fprintf(stderr, " warning: %s", err); } void #ifdef __STDC__ errNoFL(char *err) #else errNoFL(err) char *err; #endif { fprintf(stderr, "error: %s\n", err); } void #ifdef __STDC__ errFL(char *err,char *f,int l) #else errFL(err,f,l) char *err; char *f; int l; #endif { fprintf(stderr, ErrHdr, f, l); fprintf(stderr, " error: %s\n", err); } void #ifdef __STDC__ err(char *err) #else err(err) char *err; #endif { /* back up the file number if we hit an error at the end of the last file */ if ( CurFile >= NumFiles && CurFile >= 1 ) CurFile--; fprintf(stderr, ErrHdr, FileStr[CurFile], zzline); fprintf(stderr, " error: %s\n", err); } void #ifdef __STDC__ errNoCR( char *err ) #else errNoCR( err ) char *err; #endif { /* back up the file number if we hit an error at the end of the last file */ if ( CurFile >= NumFiles && CurFile >= 1 ) CurFile--; fprintf(stderr, ErrHdr, FileStr[CurFile], zzline); fprintf(stderr, " error: %s", err); } UserAction * #ifdef __STDC__ newUserAction(char *s) #else newUserAction(s) char *s; #endif { UserAction *ua = (UserAction *) calloc(1, sizeof(UserAction)); require(ua!=NULL, "cannot allocate UserAction"); ua->action = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); strcpy(ua->action, s); return ua; } /* Added by TJP September 1994 */ /* Take in file.h and return file_h; names w/o '.'s are left alone */ char * #ifdef __USE_PROTOS gate_symbol(char *name) #else gate_symbol(name) char *name; #endif { static char buf[100]; char *p; sprintf(buf, "%s", name); for (p=buf; *p!='\0'; p++) { if ( *p=='.' ) *p = '_'; } return buf; } char * #ifdef __USE_PROTOS makeAltID(int blockid, int altnum) #else makeAltID(blockid, altnum) int blockid; int altnum; #endif { static char buf[100]; char *p; sprintf(buf, "_blk%d_alt%d", blockid, altnum); p = (char *)malloc(strlen(buf)+1); strcpy(p, buf); return p; }