home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / p / pccts.zip / antlr / main.c < prev    next >
C/C++ Source or Header  |  1992-12-08  |  13KB  |  500 lines

  1. /*
  2.  * main.c -- main program for PCCTS ANTLR.
  3.  *
  4.  * SOFTWARE RIGHTS
  5.  *
  6.  * We reserve no LEGAL rights to the Purdue Compiler Construction Tool
  7.  * Set (PCCTS) -- PCCTS is in the public domain.  An individual or
  8.  * company may do whatever they wish with source code distributed with
  9.  * PCCTS or the code generated by PCCTS, including the incorporation of
  10.  * PCCTS, or its output, into commerical software.
  11.  * 
  12.  * We encourage users to develop software with PCCTS.  However, we do ask
  13.  * that credit is given to us for developing PCCTS.  By "credit",
  14.  * we mean that if you incorporate our source code into one of your
  15.  * programs (commercial product, research project, or otherwise) that you
  16.  * acknowledge this fact somewhere in the documentation, research report,
  17.  * etc...  If you like PCCTS and have developed a nice tool with the
  18.  * output, please mention that you developed it using PCCTS.  In
  19.  * addition, we ask that this header remain intact in our source code.
  20.  * As long as these guidelines are kept, we expect to continue enhancing
  21.  * this system and expect to make other tools available as they are
  22.  * completed.
  23.  *
  24.  * ANTLR 1.06
  25.  * Terence Parr
  26.  * Purdue University
  27.  * 1989-1992
  28.  */
  29.  
  30. #include <stdio.h>
  31. #include "set.h"
  32. #include "syn.h"
  33. #include "hash.h"
  34. #include "generic.h"
  35. #include "antlr.h"
  36. #include "tokens.h"
  37. #include "dlgdef.h"
  38.  
  39.  
  40. #define MAX_INT_STACK 50
  41. static int istack[MAX_INT_STACK];        /* Int stack */
  42. static int isp = MAX_INT_STACK;
  43.  
  44.         /* C m d - L i n e  O p t i o n  S t r u c t  &  F u n c s */
  45.  
  46. typedef struct _Opt {
  47.             char *option;
  48.             int  arg;
  49.             void (*process)();
  50.             char *descr;
  51.         } Opt;
  52.  
  53. extern int ProcessArgs();
  54.  
  55. static void
  56. pFile(s)
  57. char *s;
  58. {
  59.     if ( *s=='-' ) { warnNoFL( eMsg1("invalid option: '%s'",s) ); return; }
  60.     require(NumFiles<MaxNumFiles,"exceeded max # of input files");
  61.     FileStr[NumFiles++] = s;
  62. }
  63.  
  64. static void
  65. pLLK(s,t)
  66. char *s,*t;
  67. {
  68.     OutputLL_k = LL_k = atoi(t);
  69.     if ( LL_k <= 0 ) {
  70.         warnNoFL("must have at least one token of look-ahead (setting to 1)");
  71.         LL_k = 1;
  72.     }
  73.     if ( ((LL_k-1)&LL_k)!=0 ) { /* output ll(k) must be power of 2 */
  74.         int n;
  75.         for(n=1; n<LL_k; n<<=1) {;}
  76.         OutputLL_k = n;
  77.     }
  78. }
  79.  
  80. static void pCGen()    { CodeGen = FALSE; LexGen = FALSE; }
  81. static void pLGen()    { LexGen = FALSE; }
  82. static void pTGen()    { TraceGen = TRUE; }
  83. static void pSGen()    { GenExprSets = FALSE; }
  84. static void pPrt()        { PrintOut = TRUE; pCGen(); pLGen(); }
  85. static void pPrtA()    { PrintOut = TRUE; PrintAnnotate = TRUE; pCGen(); pLGen(); }
  86. static void pAst()        { GenAST = TRUE; }
  87. static void pANSI()    { GenANSI = TRUE; }
  88. static void pCr()        { GenCR = TRUE; }
  89. static void pLI()        { GenLineInfo = TRUE; }
  90. static void pFe(s,t) char *s, *t; {ErrFileName = t;}
  91. static void pFl(s,t) char *s, *t; {DlgFileName = t;}
  92. static void pFt(s,t) char *s, *t; {DefFileName = t;}
  93. static void pE1()        { elevel = 1; }
  94. static void pE2()        { elevel = 2; }
  95. static void pE3()        { elevel = 3; }
  96. static void pEGen()    { GenEClasseForRules = 1; }
  97. static void pDL()        { DemandLookahead = 1; }
  98. static void pGHdr()    { GenStdPccts = 1; }
  99. static void pPre(s,t) char *s, *t; { RulePrefix = t; }
  100. static void pFHdr(s,t) char *s, *t; { stdpccts = t; pGHdr(); }
  101.  
  102. static void
  103. pPred()
  104. {
  105.     ParseWithPredicates = 1;
  106.     if ( DemandLookahead )
  107.         warnNoFL("-gk conflicts with -pr; -gk turned off");
  108.     DemandLookahead = 0;
  109. }
  110.  
  111. static void pTRes(s,t)
  112. char *s, *t;
  113. {
  114.     TreeResourceLimit = atoi(t);
  115.     if ( TreeResourceLimit <= 0 )
  116.     {
  117.         warnNoFL("analysis resource limit (# of tree nodes) must be greater than 0");
  118.         TreeResourceLimit = -1; /* set to no limit */
  119.     }
  120. }
  121.  
  122. Opt options[] = {
  123.     { "-cr", 0, pCr,    "Generate cross reference (default=FALSE)"},
  124.     { "-e1", 0, pE1,    "Ambiguities/errors shown in low detail (default)"},
  125.     { "-e2", 0, pE2,    "Ambiguities/errors shown in more detail"},
  126.     { "-e3", 0, pE3,    "Ambiguities/errors shown in excrutiating detail"},
  127.     { "-fe", 1, pFe,    "Rename err.c"},
  128.     { "-fh", 1, pFHdr,    "Rename stdpccts.h header (turns on -gh)"},
  129.     { "-fl", 1, pFl,    "Rename lexical output--parser.dlg"},
  130.     { "-ft", 1, pFt,    "Rename tokens.h"},
  131.     { "-ga", 0, pANSI,    "Generate ANSI-compatible code (default=FALSE)"},
  132.     { "-gc", 0, pCGen,    "Do not generate output parser code (default=FALSE)"},
  133.     { "-gd", 0, pTGen,    "Generate code to trace rule invocation (default=FALSE)"},
  134.     { "-ge", 0, pEGen,    "Generate an error class for each non-terminal (default=FALSE)"},
  135.     { "-gh", 0, pGHdr,    "Generate stdpccts.h for non-ANTLR-generated-files to include"},
  136.     { "-gk", 0, pDL,    "Generate parsers that delay lookahead fetches 'til needed"},
  137.     { "-gl", 0, pLI,    "Generate line info about grammar actions in C parser"},
  138.     { "-gp", 1, pPre,    "Prefix all generated rule functions with a string"},
  139.     { "-gs", 0, pSGen,    "Do not generate sets for token expression lists (default=FALSE)"},
  140.     { "-gt", 0, pAst,    "Generate code for Abstract-Syntax-Trees (default=FALSE)"},
  141.     { "-gx", 0, pLGen,    "Do not generate lexical (dlg-related) files (default=FALSE)"},
  142.     { "-k",  1, pLLK,    "Set k of LL(k) -- tokens of look-ahead (default==1)"},
  143.     { "-p",  0, pPrt,    "Print out the grammar w/o actions (default=no)"},
  144.     { "-pa", 0, pPrtA,    "Print out the grammar w/o actions & w/FIRST sets (default=no)"},
  145.     { "-pr", 0, pPred,    "Turn on use of predicates in parsing decisions (alpha version)"},
  146.     { "-rl", 1, pTRes,    "Limit max # of tree nodes used by grammar analysis"},
  147.     { "*",   0, pFile,     "" },    /* anything else is a file */
  148.     { NULL,  0, NULL }
  149. };
  150.  
  151. void readDescr();
  152. void cleanUp();
  153. static void help(), init(), buildRulePtr();
  154.  
  155.                                 /* M a i n */
  156.  
  157. main(argc,argv)
  158. int argc;
  159. char *argv[];
  160. {
  161.     static char EPSTR[] = "[Ep]";
  162.  
  163.     fprintf(stderr, "Antlr parser generator   Version %s   1989-1992\n", Version);
  164.     if ( argc == 1 ) { help(); return 1; }
  165.     ProcessArgs(argc-1, &(argv[1]), options);
  166.  
  167.     fpTrans = &(C_Trans[0]);        /* Translate to C Language */
  168.     fpJTrans = &(C_JTrans[0]);
  169.     init();
  170.     lexclass(LexStartSymbol);
  171.  
  172.     readDescr();
  173.     if ( CannotContinue ) {cleanUp(); return 1;}
  174.     if ( HdrAction == NULL ) warnNoFL("no #header action was found");
  175.  
  176.     EpToken = addTname(EPSTR);        /* add imaginary token epsilon */
  177.     set_size(NumWords(TokenNum-1));
  178.     
  179.     if ( CodeGen ) genDefFile();    /* create tokens.h */
  180.     if ( LexGen ) genLexDescr();    /* create parser.dlg */
  181.     if ( GenStdPccts )
  182.     {
  183.         FILE *f = fopen(stdpccts, "w");
  184.         if ( f==NULL ) {warnNoFL( eMsg1("can't create %s",stdpccts) );}
  185.         else
  186.         {
  187.             genStdPCCTSIncludeFile(f);
  188.             fclose(f);
  189.         }
  190.     }
  191.  
  192.     buildRulePtr();                    /* create mapping from rule # to RuleBlk junction */
  193.     ComputeErrorSets();
  194.     FoLink( (Node *)SynDiag );        /* add follow links to end of all rules */
  195.     if ( GenCR ) GenCrossRef( SynDiag );
  196.  
  197.     if ( CodeGen )
  198.     {
  199.         if ( SynDiag == NULL )
  200.         {
  201.             warnNoFL("no grammar description recognized");
  202.             cleanUp();
  203.             return 1;
  204.         }
  205.         else
  206.         {
  207.             ErrFile = fopen(ErrFileName, "w");
  208.             require(ErrFile != NULL, "main: can't open err file");
  209.             NewSetWd();
  210.             GenErrHdr();
  211.             TRANS(SynDiag);            /* Translate to the target language */
  212.             DumpSetWd();
  213.             fclose( ErrFile );
  214.         }
  215.     }
  216.  
  217.     if ( PrintOut )
  218.     {
  219.         if ( SynDiag == NULL ) {warnNoFL("no grammar description recognized");}
  220.         else PRINT(SynDiag);
  221.     }
  222.  
  223.     cleanUp();
  224.     return 0;                        /* report all is well for make etc... */
  225. }
  226.  
  227. static void
  228. init()
  229. {
  230.     Tname = newHashTable();
  231.     Rname = newHashTable();
  232.     Fcache = newHashTable();
  233.     Tcache = newHashTable();
  234.     TokenStr = (char **) calloc(TSChunk, sizeof(char *));
  235.     require(TokenStr!=NULL, "main: cannot allocate TokenStr");
  236.     FoStack = (int **) calloc(LL_k+1, sizeof(int *));
  237.     require(FoStack!=NULL, "main: cannot allocate FoStack");
  238.     FoTOS = (int **) calloc(LL_k+1, sizeof(int *));
  239.     require(FoTOS!=NULL, "main: cannot allocate FoTOS");
  240.     Cycles = (ListNode **) calloc(LL_k+1, sizeof(ListNode *));
  241.     require(Cycles!=NULL, "main: cannot allocate Cycles List");
  242. }
  243.  
  244. static
  245. void
  246. help()
  247. {
  248.     Opt *p = options;
  249.     fprintf(stderr, "antlr [options] f1 f2 ... fn\n");
  250.     while ( *(p->option) != '*' )
  251.     {
  252.         fprintf(stderr, "\t%s %s\t%s\n",
  253.                         p->option,
  254.                         (p->arg)?"___":"   ",
  255.                         p->descr);
  256.         p++;
  257.     }
  258. }
  259.  
  260. /* The RulePtr array is filled in here.  RulePtr exists primarily
  261.  * so that sets of rules can be maintained for the FOLLOW caching
  262.  * mechanism found in rJunc().  RulePtr maps a rule num from 1 to n
  263.  * to a pointer to its RuleBlk junction where n is the number of rules.
  264.  */
  265. static void
  266. buildRulePtr()
  267. {
  268.     int r=1;
  269.     Junction *p  = SynDiag;
  270.     RulePtr = (Junction **) calloc(NumRules+1, sizeof(Junction *));
  271.     require(RulePtr!=NULL, "cannot allocate RulePtr array");
  272.     
  273.     while ( p!=NULL )
  274.     {
  275.         require(r<=NumRules, "too many rules???");
  276.         RulePtr[r++] = p;
  277.         p = (Junction *)p->p2;
  278.     }
  279. }
  280.  
  281. void
  282. readDescr()
  283. {
  284.     input = NextFile();
  285.     require(input!=NULL, "No grammar description found (exiting...)");
  286.     ANTLR(grammar(), input);
  287. }
  288.  
  289. FILE *
  290. NextFile()
  291. {
  292.     FILE *f;
  293.  
  294.     for (;;)
  295.     {
  296.         CurFile++;
  297.         if ( CurFile >= NumFiles ) return(NULL);
  298.         f = fopen(FileStr[CurFile], "r");
  299.         if ( f == NULL )
  300.         {
  301.             warnNoFL( eMsg1("file %s doesn't exist; ignored", FileStr[CurFile]) );
  302.         }
  303.         else
  304.         {
  305. /*            aSourceFile = FileStr[CurFile];
  306.  * Doesn't seem to be used
  307.  */
  308.             return(f);
  309.         }
  310.     }
  311. }
  312.  
  313. /*
  314.  * Return a string corresponding to the output file name associated
  315.  * with the input file name passed in.
  316.  *
  317.  * Observe the following rules:
  318.  *
  319.  *        f.e        --> f".c"
  320.  *        f        --> f".c"
  321.  *        f.        --> f".c"
  322.  *        f.e.g    --> f.e".c"
  323.  *
  324.  * Where f,e,g are arbitrarily long sequences of characters in a file
  325.  * name.
  326.  *
  327.  * In other words, if a ".x" appears on the end of a file name, make it
  328.  * ".c".  If no ".x" appears, append ".c" to the end of the file name.
  329.  *
  330.  * Use malloc() for new string.
  331.  */
  332. char *
  333. outname(fs)
  334. char *fs;
  335. {
  336.     static char buf[MaxFileName+1];
  337.     char *p;
  338.  
  339.     p = buf;
  340.     strcpy(buf, fs);
  341.     while ( *p != '\0' )  {p++;}            /* Stop on '\0' */
  342.     while ( *p != '.' && p != buf ) {--p;}    /* Find '.' */
  343.     if ( p != buf ) *p = '\0';                /* Found '.' */
  344.     require(strlen(buf) + 2 < MaxFileName, "outname: filename too big");
  345.     strcat(buf, ".c");
  346.     return( buf );
  347. }
  348.  
  349. void
  350. fatalFL(err,f,l)
  351. char *err, *f;
  352. int l;
  353. {
  354.     fprintf(stderr, ErrHdr, f, l);
  355.     fprintf(stderr, " %s\n", err);
  356.     cleanUp();
  357.     exit(-1);
  358. }
  359.  
  360. void
  361. cleanUp()
  362. {
  363.     if ( DefFile != NULL) fclose( DefFile );
  364. }
  365.  
  366. /* sprintf up to 3 strings */
  367. char *
  368. eMsg3(s,a1,a2,a3)
  369. char *s, *a1, *a2, *a3;
  370. {
  371.     static char buf[250];            /* DANGEROUS as hell !!!!!! */
  372.     
  373.     sprintf(buf, s, a1, a2, a3);
  374.     return( buf );
  375. }
  376.  
  377. /* sprintf a decimal */
  378. char *
  379. eMsgd(s,d)
  380. char *s;
  381. int d;
  382. {
  383.     static char buf[250];            /* DANGEROUS as hell !!!!!! */
  384.     
  385.     sprintf(buf, s, d);
  386.     return( buf );
  387. }
  388.  
  389. void
  390. s_fprT(f, e)
  391. FILE *f;
  392. set e;
  393. {
  394.     register unsigned *p;
  395.     unsigned *q;
  396.  
  397.     if ( set_nil(e) ) return;
  398.     if ( (q=p=set_pdq(e)) == NULL ) fatal("Can't alloc space for set_pdq");
  399.     fprintf(f, "{");
  400.     while ( *p != nil )
  401.     {
  402.         fprintf(f, " %s", TerminalString(*p));
  403.         p++;
  404.     }
  405.     fprintf(f, " }");
  406.     free(q);
  407. }
  408.  
  409. /* Return the token name or regular expression for a token number. */
  410. char *
  411. TerminalString(token)
  412. int token;
  413. {
  414.     int j;
  415.  
  416.     /* look in all lexclasses for the token */
  417.     if ( TokenStr[token] != NULL ) return TokenStr[token];
  418.     for (j=0; j<NumLexClasses; j++)
  419.     {
  420.         lexmode(j);
  421.         if ( ExprStr[token] != NULL ) return ExprStr[token];
  422.     }
  423.     require(j<NumLexClasses, eMsgd("No label or expr for token %d",token));
  424.     return "invalid";
  425. }
  426.  
  427.                     /* S i m p l e  I n t  S t a c k */
  428.  
  429. void
  430. pushint(i)
  431. int i;
  432. {
  433.     require(isp>0, "pushint: stack overflow");
  434.     istack[--isp] = i;
  435. }
  436.  
  437. int
  438. popint()
  439. {
  440.     require(isp<MAX_INT_STACK, "popint: stack underflow");
  441.     return istack[isp++];
  442. }
  443.  
  444. int
  445. istacksize()
  446. {
  447.     return MAX_INT_STACK-isp;
  448. }
  449.  
  450. void
  451. istackreset()
  452. {
  453.     isp = MAX_INT_STACK;
  454. }
  455.  
  456. int
  457. istackempty()
  458. {
  459.     return isp==MAX_INT_STACK;
  460. }
  461.  
  462. int
  463. topint()
  464. {
  465.     require(isp<MAX_INT_STACK, "topint: stack underflow");
  466.     return istack[isp];
  467. }
  468.  
  469. ProcessArgs(argc, argv, options)
  470. int argc;
  471. char **argv;
  472. Opt *options;
  473. {
  474.     Opt *p;
  475.     require(argv!=NULL, "ProcessArgs: command line NULL");
  476.  
  477.     while ( argc-- > 0 )
  478.     {
  479.         p = options;
  480.         while ( p->option != NULL )
  481.         {
  482.             if ( strcmp(p->option, "*") == 0 ||
  483.                  strcmp(p->option, *argv) == 0 )
  484.             {
  485.                 if ( p->arg )
  486.                 {
  487.                     (*p->process)( *argv, *(argv+1) );
  488.                     argv++;
  489.                     argc--;
  490.                 }
  491.                 else
  492.                     (*p->process)( *argv );
  493.                 break;
  494.             }
  495.             p++;
  496.         }
  497.         argv++;
  498.     }
  499. }
  500.