Home | History | Annotate | Download | only in Parser
      1 
      2 /* Parser generator main program */
      3 
      4 /* This expects a filename containing the grammar as argv[1] (UNIX)
      5    or asks the console for such a file name (THINK C).
      6    It writes its output on two files in the current directory:
      7    - "graminit.c" gets the grammar as a bunch of initialized data
      8    - "graminit.h" gets the grammar's non-terminals as #defines.
      9    Error messages and status info during the generation process are
     10    written to stdout, or sometimes to stderr. */
     11 
     12 /* XXX TO DO:
     13    - check for duplicate definitions of names (instead of fatal err)
     14 */
     15 
     16 #include "Python.h"
     17 #include "pgenheaders.h"
     18 #include "grammar.h"
     19 #include "node.h"
     20 #include "parsetok.h"
     21 #include "pgen.h"
     22 
     23 int Py_DebugFlag;
     24 int Py_VerboseFlag;
     25 int Py_IgnoreEnvironmentFlag;
     26 
     27 /* Forward */
     28 grammar *getgrammar(char *filename);
     29 
     30 void
     31 Py_Exit(int sts)
     32 {
     33     exit(sts);
     34 }
     35 
     36 int
     37 main(int argc, char **argv)
     38 {
     39     grammar *g;
     40     FILE *fp;
     41     char *filename, *graminit_h, *graminit_c;
     42 
     43     if (argc != 4) {
     44         fprintf(stderr,
     45             "usage: %s grammar graminit.h graminit.c\n", argv[0]);
     46         Py_Exit(2);
     47     }
     48     filename = argv[1];
     49     graminit_h = argv[2];
     50     graminit_c = argv[3];
     51     g = getgrammar(filename);
     52     fp = fopen(graminit_c, "w");
     53     if (fp == NULL) {
     54         perror(graminit_c);
     55         Py_Exit(1);
     56     }
     57     if (Py_DebugFlag)
     58         printf("Writing %s ...\n", graminit_c);
     59     printgrammar(g, fp);
     60     fclose(fp);
     61     fp = fopen(graminit_h, "w");
     62     if (fp == NULL) {
     63         perror(graminit_h);
     64         Py_Exit(1);
     65     }
     66     if (Py_DebugFlag)
     67         printf("Writing %s ...\n", graminit_h);
     68     printnonterminals(g, fp);
     69     fclose(fp);
     70     Py_Exit(0);
     71     return 0; /* Make gcc -Wall happy */
     72 }
     73 
     74 grammar *
     75 getgrammar(char *filename)
     76 {
     77     FILE *fp;
     78     node *n;
     79     grammar *g0, *g;
     80     perrdetail err;
     81 
     82     fp = fopen(filename, "r");
     83     if (fp == NULL) {
     84         perror(filename);
     85         Py_Exit(1);
     86     }
     87     g0 = meta_grammar();
     88     n = PyParser_ParseFile(fp, filename, g0, g0->g_start,
     89                   (char *)NULL, (char *)NULL, &err);
     90     fclose(fp);
     91     if (n == NULL) {
     92         fprintf(stderr, "Parsing error %d, line %d.\n",
     93             err.error, err.lineno);
     94         if (err.text != NULL) {
     95             size_t i;
     96             fprintf(stderr, "%s", err.text);
     97             i = strlen(err.text);
     98             if (i == 0 || err.text[i-1] != '\n')
     99                 fprintf(stderr, "\n");
    100             for (i = 0; i < err.offset; i++) {
    101                 if (err.text[i] == '\t')
    102                     putc('\t', stderr);
    103                 else
    104                     putc(' ', stderr);
    105             }
    106             fprintf(stderr, "^\n");
    107             PyObject_FREE(err.text);
    108         }
    109         Py_Exit(1);
    110     }
    111     g = pgen(n);
    112     if (g == NULL) {
    113         printf("Bad grammar.\n");
    114         Py_Exit(1);
    115     }
    116     return g;
    117 }
    118 
    119 /* Can't happen in pgen */
    120 PyObject*
    121 PyErr_Occurred()
    122 {
    123     return 0;
    124 }
    125 
    126 void
    127 Py_FatalError(const char *msg)
    128 {
    129     fprintf(stderr, "pgen: FATAL ERROR: %s\n", msg);
    130     Py_Exit(1);
    131 }
    132 
    133 /* No-nonsense my_readline() for tokenizer.c */
    134 
    135 char *
    136 PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
    137 {
    138     size_t n = 1000;
    139     char *p = (char *)PyMem_MALLOC(n);
    140     char *q;
    141     if (p == NULL)
    142         return NULL;
    143     fprintf(stderr, "%s", prompt);
    144     q = fgets(p, n, sys_stdin);
    145     if (q == NULL) {
    146         *p = '\0';
    147         return p;
    148     }
    149     n = strlen(p);
    150     if (n > 0 && p[n-1] != '\n')
    151         p[n-1] = '\n';
    152     return (char *)PyMem_REALLOC(p, n+1);
    153 }
    154 
    155 /* No-nonsense fgets */
    156 char *
    157 Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj)
    158 {
    159     return fgets(buf, n, stream);
    160 }
    161 
    162 
    163 #include <stdarg.h>
    164 
    165 void
    166 PySys_WriteStderr(const char *format, ...)
    167 {
    168     va_list va;
    169 
    170     va_start(va, format);
    171     vfprintf(stderr, format, va);
    172     va_end(va);
    173 }
    174