"Compiling" version

This commit is contained in:
Guido van Rossum 1990-12-20 15:06:42 +00:00
parent 226d79eb4a
commit 3f5da24ea3
72 changed files with 3363 additions and 2061 deletions

View file

@ -1,11 +1,52 @@
/* Parser accelerator module */
#include <stdio.h>
/* The parser as originally conceived had disappointing performance.
This module does some precomputation that speeds up the selection
of a DFA based upon a token, turning a search through an array
into a simple indexing operation. The parser now cannot work
without the accelerators installed. Note that the accelerators
are installed dynamically when the parser is initialized, they
are not part of the static data structure written on graminit.[ch]
by the parser generator. */
#include "PROTO.h"
#include "pgenheaders.h"
#include "grammar.h"
#include "token.h"
#include "malloc.h"
#include "parser.h"
/* Forward references */
static void fixdfa PROTO((grammar *, dfa *));
static void fixstate PROTO((grammar *, dfa *, state *));
void
addaccelerators(g)
grammar *g;
{
dfa *d;
int i;
#ifdef DEBUG
printf("Adding parser accellerators ...\n");
#endif
d = g->g_dfa;
for (i = g->g_ndfas; --i >= 0; d++)
fixdfa(g, d);
g->g_accel = 1;
#ifdef DEBUG
printf("Done.\n");
#endif
}
static void
fixdfa(g, d)
grammar *g;
dfa *d;
{
state *s;
int j;
s = d->d_state;
for (j = 0; j < d->d_nstates; j++, s++)
fixstate(g, d, s);
}
static void
fixstate(g, d, s)
@ -69,33 +110,3 @@ fixstate(g, d, s)
}
DEL(accel);
}
static void
fixdfa(g, d)
grammar *g;
dfa *d;
{
state *s;
int j;
s = d->d_state;
for (j = 0; j < d->d_nstates; j++, s++)
fixstate(g, d, s);
}
void
addaccelerators(g)
grammar *g;
{
dfa *d;
int i;
#ifdef DEBUG
printf("Adding parser accellerators ...\n");
#endif
d = g->g_dfa;
for (i = g->g_ndfas; --i >= 0; d++)
fixdfa(g, d);
g->g_accel = 1;
#ifdef DEBUG
printf("Done.\n");
#endif
}

View file

@ -1,7 +1,6 @@
/* Bitset primitives */
/* Bitset primitives used by the parser generator */
#include "PROTO.h"
#include "malloc.h"
#include "pgenheaders.h"
#include "bitset.h"
bitset

View file

@ -1,14 +1,29 @@
/* Computation of FIRST stets */
#include <stdio.h>
#include "PROTO.h"
#include "malloc.h"
#include "pgenheaders.h"
#include "grammar.h"
#include "token.h"
extern int debugging;
/* Forward */
static void calcfirstset PROTO((grammar *, dfa *));
void
addfirstsets(g)
grammar *g;
{
int i;
dfa *d;
printf("Adding FIRST sets ...\n");
for (i = 0; i < g->g_ndfas; i++) {
d = &g->g_dfa[i];
if (d->d_first == NULL)
calcfirstset(g, d);
}
}
static void
calcfirstset(g, d)
grammar *g;
@ -92,18 +107,3 @@ calcfirstset(g, d)
printf(" }\n");
}
}
void
addfirstsets(g)
grammar *g;
{
int i;
dfa *d;
printf("Adding FIRST sets ...\n");
for (i = 0; i < g->g_ndfas; i++) {
d = &g->g_dfa[i];
if (d->d_first == NULL)
calcfirstset(g, d);
}
}

View file

@ -1,10 +1,9 @@
/* Grammar implementation */
#include <stdio.h>
#include "pgenheaders.h"
#include <ctype.h>
#include "PROTO.h"
#include "malloc.h"
#include "assert.h"
#include "token.h"
#include "grammar.h"
@ -127,6 +126,21 @@ findlabel(ll, type, str)
abort();
}
/* Forward */
static void translabel PROTO((grammar *, label *));
void
translatelabels(g)
grammar *g;
{
int i;
printf("Translating labels ...\n");
/* Don't translate EMPTY */
for (i = EMPTY+1; i < g->g_ll.ll_nlabels; i++)
translabel(g, &g->g_ll.ll_label[i]);
}
static void
translabel(g, lb)
grammar *g;
@ -193,15 +207,3 @@ translabel(g, lb)
else
printf("Can't translate label '%s'\n", labelrepr(lb));
}
void
translatelabels(g)
grammar *g;
{
int i;
printf("Translating labels ...\n");
/* Don't translate EMPTY */
for (i = EMPTY+1; i < g->g_ll.ll_nlabels; i++)
translabel(g, &g->g_ll.ll_label[i]);
}

View file

@ -1,7 +1,6 @@
/* Grammar subroutines needed by parser */
#include "PROTO.h"
#define NULL 0
#include "pgenheaders.h"
#include "assert.h"
#include "grammar.h"
#include "token.h"

View file

@ -2,7 +2,7 @@
#ifdef MSDOS
/* This might work for MS-DOS: */
/* This might work for MS-DOS (untested though): */
void
initintr()
@ -37,7 +37,7 @@ initintr()
int
intrcheck()
{
/* Static to make it faster(?) only */
/* Static to make it faster only */
static EventRecord e;
/* XXX This fails if the user first types ahead and then
@ -59,7 +59,7 @@ intrcheck()
#ifndef OK
/* Default version -- should work for Unix and Standard C */
/* Default version -- for real operating systems and for Standard C */
#include <stdio.h>
#include <signal.h>

View file

@ -1,13 +1,31 @@
/* List a node on a file */
#include <stdio.h>
#include "PROTO.h"
#include "pgenheaders.h"
#include "token.h"
#include "node.h"
/* Forward */
static void list1node PROTO((FILE *, node *));
void
listtree(n)
node *n;
{
listnode(stdout, n);
}
static int level, atbol;
void
listnode(fp, n)
FILE *fp;
node *n;
{
level = 0;
atbol = 1;
list1node(fp, n);
}
static void
list1node(fp, n)
FILE *fp;
@ -49,20 +67,3 @@ list1node(fp, n)
else
fprintf(fp, "? ");
}
void
listnode(fp, n)
FILE *fp;
node *n;
{
level = 0;
atbol = 1;
list1node(fp, n);
}
void
listtree(n)
node *n;
{
listnode(stdout, n);
}

View file

@ -1,6 +1,7 @@
#include "PROTO.h"
#include "pgenheaders.h"
#include "metagrammar.h"
#include "grammar.h"
#include "pgen.h"
static arc arcs_0_0[3] = {
{2, 0},
{3, 0},

View file

@ -1,11 +1,10 @@
/* Parse tree node implementation */
#include "PROTO.h"
#include "malloc.h"
#include "pgenheaders.h"
#include "node.h"
node *
newnode(type)
newtree(type)
int type;
{
node *n = NEW(node, 1);
@ -13,6 +12,7 @@ newnode(type)
return NULL;
n->n_type = type;
n->n_str = NULL;
n->n_lineno = 0;
n->n_nchildren = 0;
n->n_child = NULL;
return n;
@ -22,10 +22,11 @@ newnode(type)
#define XXXROUNDUP(n) ((n) == 1 ? 1 : ((n) + XXX - 1) / XXX * XXX)
node *
addchild(n1, type, str)
addchild(n1, type, str, lineno)
register node *n1;
int type;
char *str;
int lineno;
{
register int nch = n1->n_nchildren;
register int nch1 = nch+1;
@ -41,11 +42,26 @@ addchild(n1, type, str)
n = &n1->n_child[n1->n_nchildren++];
n->n_type = type;
n->n_str = str;
n->n_lineno = lineno;
n->n_nchildren = 0;
n->n_child = NULL;
return n;
}
/* Forward */
static void freechildren PROTO((node *));
void
freetree(n)
node *n;
{
if (n != NULL) {
freechildren(n);
DEL(n);
}
}
static void
freechildren(n)
node *n;
@ -58,13 +74,3 @@ freechildren(n)
if (STR(n) != NULL)
DEL(STR(n));
}
void
freenode(n)
node *n;
{
if (n != NULL) {
freechildren(n);
DEL(n);
}
}

View file

@ -4,20 +4,17 @@
/* XXX To do: error recovery */
#include <stdio.h>
#include "pgenheaders.h"
#include "assert.h"
#include "PROTO.h"
#include "malloc.h"
#include "token.h"
#include "grammar.h"
#include "node.h"
#include "parser.h"
#include "errcode.h"
extern int debugging;
#ifdef DEBUG
extern int debugging;
#define D(x) if (!debugging); else x
#else
#define D(x)
@ -94,7 +91,7 @@ newparser(g, start)
if (ps == NULL)
return NULL;
ps->p_grammar = g;
ps->p_tree = newnode(start);
ps->p_tree = newtree(start);
if (ps->p_tree == NULL) {
DEL(ps);
return NULL;
@ -110,24 +107,25 @@ delparser(ps)
{
/* NB If you want to save the parse tree,
you must set p_tree to NULL before calling delparser! */
freenode(ps->p_tree);
freetree(ps->p_tree);
DEL(ps);
}
/* PARSER STACK OPERATIONS */
static int shift PROTO((stack *, int, char *, int));
static int shift PROTO((stack *, int, char *, int, int));
static int
shift(s, type, str, newstate)
shift(s, type, str, newstate, lineno)
register stack *s;
int type;
char *str;
int newstate;
int lineno;
{
assert(!s_empty(s));
if (addchild(s->s_top->s_parent, type, str) == NULL) {
if (addchild(s->s_top->s_parent, type, str, lineno) == NULL) {
fprintf(stderr, "shift: no mem in addchild\n");
return -1;
}
@ -135,19 +133,20 @@ shift(s, type, str, newstate)
return 0;
}
static int push PROTO((stack *, int, dfa *, int));
static int push PROTO((stack *, int, dfa *, int, int));
static int
push(s, type, d, newstate)
push(s, type, d, newstate, lineno)
register stack *s;
int type;
dfa *d;
int newstate;
int lineno;
{
register node *n;
n = s->s_top->s_parent;
assert(!s_empty(s));
if (addchild(n, type, (char *)NULL) == NULL) {
if (addchild(n, type, (char *)NULL, lineno) == NULL) {
fprintf(stderr, "push: no mem in addchild\n");
return -1;
}
@ -198,10 +197,11 @@ classify(g, type, str)
}
int
addtoken(ps, type, str)
addtoken(ps, type, str, lineno)
register parser_state *ps;
register int type;
char *str;
int lineno;
{
register int ilabel;
@ -230,7 +230,8 @@ addtoken(ps, type, str)
int nt = (x >> 8) + NT_OFFSET;
int arrow = x & ((1<<7)-1);
dfa *d1 = finddfa(ps->p_grammar, nt);
if (push(&ps->p_stack, nt, d1, arrow) < 0) {
if (push(&ps->p_stack, nt, d1,
arrow, lineno) < 0) {
D(printf(" MemError: push.\n"));
return E_NOMEM;
}
@ -239,7 +240,8 @@ addtoken(ps, type, str)
}
/* Shift the token */
if (shift(&ps->p_stack, type, str, x) < 0) {
if (shift(&ps->p_stack, type, str,
x, lineno) < 0) {
D(printf(" MemError: shift.\n"));
return E_NOMEM;
}

View file

@ -5,7 +5,7 @@
typedef struct _stackentry {
int s_state; /* State in current DFA */
dfa *s_dfa; /* Current DFA */
node *s_parent; /* Where to add next node */
struct _node *s_parent; /* Where to add next node */
} stackentry;
typedef struct _stack {
@ -22,4 +22,5 @@ typedef struct {
parser_state *newparser PROTO((struct _grammar *g, int start));
void delparser PROTO((parser_state *ps));
int addtoken PROTO((parser_state *ps, int type, char *str));
int addtoken PROTO((parser_state *ps, int type, char *str, int lineno));
void addaccelerators PROTO((grammar *g));

View file

@ -1,16 +1,82 @@
/* Parser-tokenizer link implementation */
#include <stdio.h>
#include "PROTO.h"
#include "malloc.h"
#include "pgenheaders.h"
#include "tokenizer.h"
#include "node.h"
#include "grammar.h"
#include "parser.h"
#include "parsetok.h"
#include "errcode.h"
extern int debugging;
/* Forward */
static int parsetok PROTO((struct tok_state *, grammar *, int, node **));
/* Parse input coming from a string. Return error code, print some errors. */
int
parsestring(s, g, start, n_ret)
char *s;
grammar *g;
int start;
node **n_ret;
{
struct tok_state *tok = tok_setups(s);
int ret;
if (tok == NULL) {
fprintf(stderr, "no mem for tok_setups\n");
return E_NOMEM;
}
ret = parsetok(tok, g, start, n_ret);
if (ret == E_TOKEN || ret == E_SYNTAX) {
fprintf(stderr, "String parsing error at line %d\n",
tok->lineno);
}
tok_free(tok);
return ret;
}
/* Parse input coming from a file. Return error code, print some errors. */
int
parsefile(fp, filename, g, start, ps1, ps2, n_ret)
FILE *fp;
char *filename;
grammar *g;
int start;
char *ps1, *ps2;
node **n_ret;
{
struct tok_state *tok = tok_setupf(fp, ps1, ps2);
int ret;
if (tok == NULL) {
fprintf(stderr, "no mem for tok_setupf\n");
return E_NOMEM;
}
ret = parsetok(tok, g, start, n_ret);
if (ret == E_TOKEN || ret == E_SYNTAX) {
char *p;
fprintf(stderr, "Parsing error: file %s, line %d:\n",
filename, tok->lineno);
*tok->inp = '\0';
if (tok->inp > tok->buf && tok->inp[-1] == '\n')
tok->inp[-1] = '\0';
fprintf(stderr, "%s\n", tok->buf);
for (p = tok->buf; p < tok->cur; p++) {
if (*p == '\t')
putc('\t', stderr);
else
putc(' ', stderr);
}
fprintf(stderr, "^\n");
}
tok_free(tok);
return ret;
}
/* Parse input coming from the given tokenizer structure.
@ -51,7 +117,7 @@ parsetok(tok, g, start, n_ret)
}
strncpy(str, a, len);
str[len] = '\0';
ret = addtoken(ps, (int)type, str);
ret = addtoken(ps, (int)type, str, tok->lineno);
if (ret != E_OK) {
if (ret == E_DONE) {
*n_ret = ps->p_tree;
@ -66,67 +132,3 @@ parsetok(tok, g, start, n_ret)
delparser(ps);
return ret;
}
/* Parse input coming from a string. Return error code. */
int
parsestring(s, g, start, n_ret)
char *s;
grammar *g;
int start;
node **n_ret;
{
struct tok_state *tok = tok_setups(s);
int ret;
if (tok == NULL) {
fprintf(stderr, "no mem for tok_setups\n");
return E_NOMEM;
}
ret = parsetok(tok, g, start, n_ret);
if (ret == E_TOKEN || ret == E_SYNTAX) {
fprintf(stderr, "String parsing error at line %d\n",
tok->lineno);
}
tok_free(tok);
return ret;
}
/* Parse input coming from a file. Return error code. */
int
parsefile(fp, g, start, ps1, ps2, n_ret)
FILE *fp;
grammar *g;
int start;
char *ps1, *ps2;
node **n_ret;
{
struct tok_state *tok = tok_setupf(fp, ps1, ps2);
int ret;
if (tok == NULL) {
fprintf(stderr, "no mem for tok_setupf\n");
return E_NOMEM;
}
ret = parsetok(tok, g, start, n_ret);
if (ret == E_TOKEN || ret == E_SYNTAX) {
char *p;
fprintf(stderr, "Parsing error at line %d:\n", tok->lineno);
*tok->inp = '\0';
if (tok->inp > tok->buf && tok->inp[-1] == '\n')
tok->inp[-1] = '\0';
fprintf(stderr, "%s\n", tok->buf);
for (p = tok->buf; p < tok->cur; p++) {
if (*p == '\t')
putc('\t', stderr);
else
putc(' ', stderr);
}
fprintf(stderr, "^\n");
}
tok_free(tok);
return ret;
}

View file

@ -1,12 +1,10 @@
/* Parser generator */
/* XXX This file is not yet fully PROTOized */
/* For a description, see the comments at end of this file */
#include <stdio.h>
#include "pgenheaders.h"
#include "assert.h"
#include "PROTO.h"
#include "malloc.h"
#include "token.h"
#include "node.h"
#include "grammar.h"

View file

@ -3,4 +3,4 @@
extern grammar gram;
extern grammar *meta_grammar PROTO((void));
extern grammar *pgen PROTO((node *));
extern grammar *pgen PROTO((struct _node *));

View file

@ -1,8 +1,14 @@
/* Parser generator main program */
#include <stdio.h>
/* This expects a filename containing the grammar as argv[1] (UNIX)
or asks the console for such a file name (THINK C).
It writes its output on two files in the current directory:
- "graminit.c" gets the grammar as a bunch of initialized data
- "graminit.h" gets the grammar's non-terminals as #defines.
Error messages and status info during the generation process are
written to stdout, or sometimes to stderr. */
#include "PROTO.h"
#include "pgenheaders.h"
#include "grammar.h"
#include "node.h"
#include "parsetok.h"
@ -10,54 +16,14 @@
int debugging;
/* Forward */
grammar *getgrammar PROTO((char *filename));
#ifdef THINK_C
char *
askfile()
{
char buf[256];
static char name[256];
printf("Input file name: ");
if (fgets(buf, sizeof buf, stdin) == NULL) {
printf("EOF\n");
exit(1);
}
if (sscanf(buf, " %s ", name) != 1) {
printf("No file\n");
exit(1);
}
return name;
}
int main PROTO((int, char **));
char *askfile PROTO((void));
#endif
grammar *
getgrammar(filename)
char *filename;
{
FILE *fp;
node *n;
grammar *g0, *g;
fp = fopen(filename, "r");
if (fp == NULL) {
perror(filename);
exit(1);
}
g0 = meta_grammar();
n = NULL;
parsefile(fp, g0, g0->g_start, (char *)NULL, (char *)NULL, &n);
fclose(fp);
if (n == NULL) {
fprintf(stderr, "Parsing error.\n");
exit(1);
}
g = pgen(n);
if (g == NULL) {
printf("Bad grammar.\n");
exit(1);
}
return g;
}
int
main(argc, argv)
int argc;
char **argv;
@ -96,6 +62,55 @@ main(argc, argv)
exit(0);
}
grammar *
getgrammar(filename)
char *filename;
{
FILE *fp;
node *n;
grammar *g0, *g;
fp = fopen(filename, "r");
if (fp == NULL) {
perror(filename);
exit(1);
}
g0 = meta_grammar();
n = NULL;
parsefile(fp, filename, g0, g0->g_start, (char *)NULL, (char *)NULL, &n);
fclose(fp);
if (n == NULL) {
fprintf(stderr, "Parsing error.\n");
exit(1);
}
g = pgen(n);
if (g == NULL) {
printf("Bad grammar.\n");
exit(1);
}
return g;
}
#ifdef THINK_C
char *
askfile()
{
char buf[256];
static char name[256];
printf("Input file name: ");
if (fgets(buf, sizeof buf, stdin) == NULL) {
printf("EOF\n");
exit(1);
}
/* XXX The (unsigned char *) case is needed by THINK C */
if (sscanf((unsigned char *)buf, " %s ", name) != 1) {
printf("No file\n");
exit(1);
}
return name;
}
#endif
void
fatal(msg)
char *msg;
@ -104,8 +119,6 @@ fatal(msg)
exit(1);
}
/* TO DO:
- improve user interface
- check for duplicate definitions of names (instead of fatal err)
/* XXX TO DO:
- check for duplicate definitions of names (instead of fatal err)
*/

View file

@ -1,10 +1,44 @@
/* Print a bunch of C initializers that represent a grammar */
#include <stdio.h>
#include "PROTO.h"
#include "pgenheaders.h"
#include "grammar.h"
/* Forward */
static void printarcs PROTO((int, dfa *, FILE *));
static void printstates PROTO((grammar *, FILE *));
static void printdfas PROTO((grammar *, FILE *));
static void printlabels PROTO((grammar *, FILE *));
void
printgrammar(g, fp)
grammar *g;
FILE *fp;
{
fprintf(fp, "#include \"pgenheaders.h\"\n");
fprintf(fp, "#include \"grammar.h\"\n");
printdfas(g, fp);
printlabels(g, fp);
fprintf(fp, "grammar gram = {\n");
fprintf(fp, "\t%d,\n", g->g_ndfas);
fprintf(fp, "\tdfas,\n");
fprintf(fp, "\t{%d, labels},\n", g->g_ll.ll_nlabels);
fprintf(fp, "\t%d\n", g->g_start);
fprintf(fp, "};\n");
}
void
printnonterminals(g, fp)
grammar *g;
FILE *fp;
{
dfa *d;
int i;
d = g->g_dfa;
for (i = g->g_ndfas; --i >= 0; d++)
fprintf(fp, "#define %s %d\n", d->d_name, d->d_type);
}
static void
printarcs(i, d, fp)
int i;
@ -89,33 +123,3 @@ printlabels(g, fp)
}
fprintf(fp, "};\n");
}
void
printgrammar(g, fp)
grammar *g;
FILE *fp;
{
fprintf(fp, "#include \"PROTO.h\"\n");
fprintf(fp, "#include \"grammar.h\"\n");
printdfas(g, fp);
printlabels(g, fp);
fprintf(fp, "grammar gram = {\n");
fprintf(fp, "\t%d,\n", g->g_ndfas);
fprintf(fp, "\tdfas,\n");
fprintf(fp, "\t{%d, labels},\n", g->g_ll.ll_nlabels);
fprintf(fp, "\t%d\n", g->g_start);
fprintf(fp, "};\n");
}
void
printnonterminals(g, fp)
grammar *g;
FILE *fp;
{
dfa *d;
int i;
d = g->g_dfa;
for (i = g->g_ndfas; --i >= 0; d++)
fprintf(fp, "#define %s %d\n", d->d_name, d->d_type);
}

View file

@ -2,13 +2,14 @@
/* XXX This is rather old, should be restructured perhaps */
/* XXX Need a better interface to report errors than writing to stderr */
/* XXX Should use editor resource to fetch true tab size on Macintosh */
#include "pgenheaders.h"
#include <stdio.h>
#include <ctype.h>
#include "string.h"
#include "PROTO.h"
#include "malloc.h"
#include "fgetsintr.h"
#include "tokenizer.h"
#include "errcode.h"
@ -20,6 +21,11 @@
#define TABSIZE 8
#endif
/* Forward */
static struct tok_state *tok_new PROTO((void));
static int tok_nextc PROTO((struct tok_state *tok));
static void tok_backup PROTO((struct tok_state *tok, int c));
/* Token names */
char *tok_name[] = {
@ -352,7 +358,9 @@ tok_get(tok, p_start, p_end)
This is also recognized by vi, when it occurs near the
beginning or end of the file. (Will vi never die...?) */
int x;
if (sscanf(tok->cur, " vi:set tabsize=%d:", &x) == 1 &&
/* XXX The case to (unsigned char *) is needed by THINK C */
if (sscanf((unsigned char *)tok->cur,
" vi:set tabsize=%d:", &x) == 1 &&
x >= 1 && x <= 40) {
fprintf(stderr, "# vi:set tabsize=%d:\n", x);
tok->tabsize = x;