Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 91b467100535c7959a85c4160cccde166e16586c 0 parents
@tj authored
4 .gitignore
@@ -0,0 +1,4 @@
+.DS_Store
+node_modules
+*.sock
+bin
4 .npmignore
@@ -0,0 +1,4 @@
+support
+test
+examples
+*.sock
5 History.md
@@ -0,0 +1,5 @@
+
+0.0.1 / 2010-01-03
+==================
+
+ * Initial release
8 Makefile
@@ -0,0 +1,8 @@
+
+SRC = src/cdescent.c \
+ src/compile.c \
+ src/tree.c
+
+bin/cdescent:
+ @mkdir -p bin
+ $(CC) -03 $(SRC) -o $@
31 Readme.md
@@ -0,0 +1,31 @@
+
+# cdescent
+
+ C Recursive descent parser generator based on _why's "greg", which is Ian Piumarta's [peg(1)](http://piumarta.com/software/peg/) extended to become reentrant.
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
+Copyright (c) 2008 why the lucky stiff
+Copyright (c) 2007 by Ian Piumarta
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1,127 src/cdescent.c
@@ -0,0 +1,1127 @@
+/* A recursive-descent parser generated by greg 0.3.0 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+struct _CDESCENT;
+#define YYRULECOUNT 36
+
+# include "cdescent.h"
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <unistd.h>
+# include <string.h>
+# include <libgen.h>
+# include <assert.h>
+
+ typedef struct Header Header;
+
+ struct Header {
+ char *text;
+ Header *next;
+ };
+
+ FILE *input= 0;
+
+ int verboseFlag= 0;
+
+ static int lineNumber= 0;
+ static char *fileName= 0;
+ static char *trailer= 0;
+ static Header *headers= 0;
+
+ void makeHeader(char *text);
+ void makeTrailer(char *text);
+
+ void yyerror(struct _CDESCENT *, char *message);
+
+# define YY_INPUT(buf, result, max) \
+ { \
+ int c= getc(input); \
+ if ('\n' == c || '\r' == c) ++lineNumber; \
+ result= (EOF == c) ? 0 : (*(buf)= c, 1); \
+ }
+
+# define YY_LOCAL(T) static T
+# define YY_RULE(T) static T
+
+#ifndef YY_ALLOC
+#define YY_ALLOC(N, D) malloc(N)
+#endif
+#ifndef YY_CALLOC
+#define YY_CALLOC(N, S, D) calloc(N, S)
+#endif
+#ifndef YY_REALLOC
+#define YY_REALLOC(B, N, D) realloc(B, N)
+#endif
+#ifndef YY_FREE
+#define YY_FREE free
+#endif
+#ifndef YY_LOCAL
+#define YY_LOCAL(T) static T
+#endif
+#ifndef YY_ACTION
+#define YY_ACTION(T) static T
+#endif
+#ifndef YY_RULE
+#define YY_RULE(T) static T
+#endif
+#ifndef YY_PARSE
+#define YY_PARSE(T) T
+#endif
+#ifndef YY_NAME
+#define YY_NAME(N) yy##N
+#endif
+#ifndef YY_INPUT
+#define YY_INPUT(buf, result, max_size) \
+ { \
+ int yyc= getchar(); \
+ result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1); \
+ yyprintf((stderr, "<%c>", yyc)); \
+ }
+#endif
+#ifndef YY_BEGIN
+#define YY_BEGIN ( G->begin= G->pos, 1)
+#endif
+#ifndef YY_END
+#define YY_END ( G->end= G->pos, 1)
+#endif
+#ifdef YY_DEBUG
+# define yyprintf(args) fprintf args
+#else
+# define yyprintf(args)
+#endif
+#ifndef YYSTYPE
+#define YYSTYPE int
+#endif
+#ifndef YY_XTYPE
+#define YY_XTYPE void *
+#endif
+#ifndef YY_XVAR
+#define YY_XVAR yydata
+#endif
+
+#ifndef YY_PART
+#define yy G->ss
+
+typedef void (*yyaction)(struct _CDESCENT *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR);
+typedef struct _yythunk { int begin, end; yyaction action; struct _yythunk *next; } yythunk;
+
+typedef struct _CDESCENT {
+ char *buf;
+ int buflen;
+ int pos;
+ int limit;
+ char *text;
+ int textlen;
+ int begin;
+ int end;
+ yythunk *thunks;
+ int thunkslen;
+ int thunkpos;
+ YYSTYPE ss;
+ YYSTYPE *val;
+ YYSTYPE *vals;
+ int valslen;
+ YY_XTYPE data;
+} GREG;
+
+YY_LOCAL(int) yyrefill(GREG *G)
+{
+ int yyn;
+ while (G->buflen - G->pos < 512)
+ {
+ G->buflen *= 2;
+ G->buf= YY_REALLOC(G->buf, G->buflen, G->data);
+ }
+ YY_INPUT((G->buf + G->pos), yyn, (G->buflen - G->pos));
+ if (!yyn) return 0;
+ G->limit += yyn;
+ return 1;
+}
+
+YY_LOCAL(int) yymatchDot(GREG *G)
+{
+ if (G->pos >= G->limit && !yyrefill(G)) return 0;
+ ++G->pos;
+ return 1;
+}
+
+YY_LOCAL(int) yymatchChar(GREG *G, int c)
+{
+ if (G->pos >= G->limit && !yyrefill(G)) return 0;
+ if ((unsigned char)G->buf[G->pos] == c)
+ {
+ ++G->pos;
+ yyprintf((stderr, " ok yymatchChar(%c) @ %s\n", c, G->buf+G->pos));
+ return 1;
+ }
+ yyprintf((stderr, " fail yymatchChar(%c) @ %s\n", c, G->buf+G->pos));
+ return 0;
+}
+
+YY_LOCAL(int) yymatchString(GREG *G, char *s)
+{
+ int yysav= G->pos;
+ while (*s)
+ {
+ if (G->pos >= G->limit && !yyrefill(G)) return 0;
+ if (G->buf[G->pos] != *s)
+ {
+ G->pos= yysav;
+ return 0;
+ }
+ ++s;
+ ++G->pos;
+ }
+ return 1;
+}
+
+YY_LOCAL(int) yymatchClass(GREG *G, unsigned char *bits)
+{
+ int c;
+ if (G->pos >= G->limit && !yyrefill(G)) return 0;
+ c= (unsigned char)G->buf[G->pos];
+ if (bits[c >> 3] & (1 << (c & 7)))
+ {
+ ++G->pos;
+ yyprintf((stderr, " ok yymatchClass @ %s\n", G->buf+G->pos));
+ return 1;
+ }
+ yyprintf((stderr, " fail yymatchClass @ %s\n", G->buf+G->pos));
+ return 0;
+}
+
+YY_LOCAL(void) yyDo(GREG *G, yyaction action, int begin, int end)
+{
+ while (G->thunkpos >= G->thunkslen)
+ {
+ G->thunkslen *= 2;
+ G->thunks= YY_REALLOC(G->thunks, sizeof(yythunk) * G->thunkslen, G->data);
+ }
+ G->thunks[G->thunkpos].begin= begin;
+ G->thunks[G->thunkpos].end= end;
+ G->thunks[G->thunkpos].action= action;
+ ++G->thunkpos;
+}
+
+YY_LOCAL(int) yyText(GREG *G, int begin, int end)
+{
+ int yyleng= end - begin;
+ if (yyleng <= 0)
+ yyleng= 0;
+ else
+ {
+ while (G->textlen < (yyleng - 1))
+ {
+ G->textlen *= 2;
+ G->text= YY_REALLOC(G->text, G->textlen, G->data);
+ }
+ memcpy(G->text, G->buf + begin, yyleng);
+ }
+ G->text[yyleng]= '\0';
+ return yyleng;
+}
+
+YY_LOCAL(void) yyDone(GREG *G)
+{
+ int pos;
+ for (pos= 0; pos < G->thunkpos; ++pos)
+ {
+ yythunk *thunk= &G->thunks[pos];
+ int yyleng= thunk->end ? yyText(G, thunk->begin, thunk->end) : thunk->begin;
+ yyprintf((stderr, "DO [%d] %p %s\n", pos, thunk->action, G->text));
+ thunk->action(G, G->text, yyleng, G->data);
+ }
+ G->thunkpos= 0;
+}
+
+YY_LOCAL(void) yyCommit(GREG *G)
+{
+ if ((G->limit -= G->pos))
+ {
+ memmove(G->buf, G->buf + G->pos, G->limit);
+ }
+ G->begin -= G->pos;
+ G->end -= G->pos;
+ G->pos= G->thunkpos= 0;
+}
+
+YY_LOCAL(int) yyAccept(GREG *G, int tp0)
+{
+ if (tp0)
+ {
+ fprintf(stderr, "accept denied at %d\n", tp0);
+ return 0;
+ }
+ else
+ {
+ yyDone(G);
+ yyCommit(G);
+ }
+ return 1;
+}
+
+YY_LOCAL(void) yyPush(GREG *G, char *text, int count, YY_XTYPE YY_XVAR) { G->val += count; }
+YY_LOCAL(void) yyPop(GREG *G, char *text, int count, YY_XTYPE YY_XVAR) { G->val -= count; }
+YY_LOCAL(void) yySet(GREG *G, char *text, int count, YY_XTYPE YY_XVAR) { G->val[count]= G->ss; }
+
+#endif /* YY_PART */
+
+#define YYACCEPT yyAccept(G, yythunkpos0)
+
+YY_RULE(int) yy_end_of_line(GREG *G); /* 36 */
+YY_RULE(int) yy_comment(GREG *G); /* 35 */
+YY_RULE(int) yy_space(GREG *G); /* 34 */
+YY_RULE(int) yy_braces(GREG *G); /* 33 */
+YY_RULE(int) yy_range(GREG *G); /* 32 */
+YY_RULE(int) yy_char(GREG *G); /* 31 */
+YY_RULE(int) yy_END(GREG *G); /* 30 */
+YY_RULE(int) yy_BEGIN(GREG *G); /* 29 */
+YY_RULE(int) yy_DOT(GREG *G); /* 28 */
+YY_RULE(int) yy_class(GREG *G); /* 27 */
+YY_RULE(int) yy_literal(GREG *G); /* 26 */
+YY_RULE(int) yy_CLOSE(GREG *G); /* 25 */
+YY_RULE(int) yy_OPEN(GREG *G); /* 24 */
+YY_RULE(int) yy_COLON(GREG *G); /* 23 */
+YY_RULE(int) yy_PLUS(GREG *G); /* 22 */
+YY_RULE(int) yy_STAR(GREG *G); /* 21 */
+YY_RULE(int) yy_QUESTION(GREG *G); /* 20 */
+YY_RULE(int) yy_primary(GREG *G); /* 19 */
+YY_RULE(int) yy_NOT(GREG *G); /* 18 */
+YY_RULE(int) yy_suffix(GREG *G); /* 17 */
+YY_RULE(int) yy_action(GREG *G); /* 16 */
+YY_RULE(int) yy_AND(GREG *G); /* 15 */
+YY_RULE(int) yy_prefix(GREG *G); /* 14 */
+YY_RULE(int) yy_BAR(GREG *G); /* 13 */
+YY_RULE(int) yy_sequence(GREG *G); /* 12 */
+YY_RULE(int) yy_SEMICOLON(GREG *G); /* 11 */
+YY_RULE(int) yy_expression(GREG *G); /* 10 */
+YY_RULE(int) yy_EQUAL(GREG *G); /* 9 */
+YY_RULE(int) yy_identifier(GREG *G); /* 8 */
+YY_RULE(int) yy_RPERCENT(GREG *G); /* 7 */
+YY_RULE(int) yy_end_of_file(GREG *G); /* 6 */
+YY_RULE(int) yy_trailer(GREG *G); /* 5 */
+YY_RULE(int) yy_definition(GREG *G); /* 4 */
+YY_RULE(int) yy_declaration(GREG *G); /* 3 */
+YY_RULE(int) yy__(GREG *G); /* 2 */
+YY_RULE(int) yy_grammar(GREG *G); /* 1 */
+
+YY_ACTION(void) yy_9_primary(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_9_primary\n"));
+ push(makePredicate("YY_END")); ;
+}
+YY_ACTION(void) yy_8_primary(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_8_primary\n"));
+ push(makePredicate("YY_BEGIN")); ;
+}
+YY_ACTION(void) yy_7_primary(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_7_primary\n"));
+ push(makeAction(yytext)); ;
+}
+YY_ACTION(void) yy_6_primary(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_6_primary\n"));
+ push(makeDot()); ;
+}
+YY_ACTION(void) yy_5_primary(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_5_primary\n"));
+ push(makeClass(yytext)); ;
+}
+YY_ACTION(void) yy_4_primary(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_4_primary\n"));
+ push(makeString(yytext)); ;
+}
+YY_ACTION(void) yy_3_primary(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_3_primary\n"));
+ push(makeName(findRule(yytext, 0))); ;
+}
+YY_ACTION(void) yy_2_primary(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_2_primary\n"));
+ Node *name= makeName(findRule(yytext, 0)); name->name.variable= pop(); push(name); ;
+}
+YY_ACTION(void) yy_1_primary(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_1_primary\n"));
+ push(makeVariable(yytext)); ;
+}
+YY_ACTION(void) yy_3_suffix(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_3_suffix\n"));
+ push(makePlus (pop())); ;
+}
+YY_ACTION(void) yy_2_suffix(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_2_suffix\n"));
+ push(makeStar (pop())); ;
+}
+YY_ACTION(void) yy_1_suffix(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_1_suffix\n"));
+ push(makeQuery(pop())); ;
+}
+YY_ACTION(void) yy_3_prefix(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_3_prefix\n"));
+ push(makePeekNot(pop())); ;
+}
+YY_ACTION(void) yy_2_prefix(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_2_prefix\n"));
+ push(makePeekFor(pop())); ;
+}
+YY_ACTION(void) yy_1_prefix(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_1_prefix\n"));
+ push(makePredicate(yytext)); ;
+}
+YY_ACTION(void) yy_1_sequence(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_1_sequence\n"));
+ Node *f= pop(); push(Sequence_append(pop(), f)); ;
+}
+YY_ACTION(void) yy_1_expression(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_1_expression\n"));
+ Node *f= pop(); push(Alternate_append(pop(), f)); ;
+}
+YY_ACTION(void) yy_3_definition(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+#define s G->val[-1]
+ yyprintf((stderr, "do yy_3_definition\n"));
+ Node *e= pop(); Rule_setExpression(pop(), e); ;
+#undef s
+}
+YY_ACTION(void) yy_2_definition(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+#define s G->val[-1]
+ yyprintf((stderr, "do yy_2_definition\n"));
+ if (push(beginRule(findRule(yytext, s)))->rule.expression)
+ fprintf(stderr, "rule '%s' redefined\n", yytext); ;
+#undef s
+}
+YY_ACTION(void) yy_1_definition(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+#define s G->val[-1]
+ yyprintf((stderr, "do yy_1_definition\n"));
+ s = 1; ;
+#undef s
+}
+YY_ACTION(void) yy_1_trailer(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_1_trailer\n"));
+ makeTrailer(yytext); ;
+}
+YY_ACTION(void) yy_1_declaration(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)
+{
+ yyprintf((stderr, "do yy_1_declaration\n"));
+ makeHeader(yytext); ;
+}
+
+YY_RULE(int) yy_end_of_line(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "end_of_line"));
+ { int yypos2= G->pos, yythunkpos2= G->thunkpos; if (!yymatchString(G, "\r\n")) goto l3; goto l2;
+ l3:; G->pos= yypos2; G->thunkpos= yythunkpos2; if (!yymatchChar(G, '\n')) goto l4; goto l2;
+ l4:; G->pos= yypos2; G->thunkpos= yythunkpos2; if (!yymatchChar(G, '\r')) goto l1;
+ }
+ l2:;
+ yyprintf((stderr, " ok %s @ %s\n", "end_of_line", G->buf+G->pos));
+ return 1;
+ l1:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "end_of_line", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_comment(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "comment")); if (!yymatchChar(G, '#')) goto l5;
+ l6:;
+ { int yypos7= G->pos, yythunkpos7= G->thunkpos;
+ { int yypos8= G->pos, yythunkpos8= G->thunkpos; if (!yy_end_of_line(G)) goto l8; goto l7;
+ l8:; G->pos= yypos8; G->thunkpos= yythunkpos8;
+ } if (!yymatchDot(G)) goto l7; goto l6;
+ l7:; G->pos= yypos7; G->thunkpos= yythunkpos7;
+ } if (!yy_end_of_line(G)) goto l5;
+ yyprintf((stderr, " ok %s @ %s\n", "comment", G->buf+G->pos));
+ return 1;
+ l5:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "comment", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_space(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "space"));
+ { int yypos10= G->pos, yythunkpos10= G->thunkpos; if (!yymatchChar(G, ' ')) goto l11; goto l10;
+ l11:; G->pos= yypos10; G->thunkpos= yythunkpos10; if (!yymatchChar(G, '\t')) goto l12; goto l10;
+ l12:; G->pos= yypos10; G->thunkpos= yythunkpos10; if (!yy_end_of_line(G)) goto l9;
+ }
+ l10:;
+ yyprintf((stderr, " ok %s @ %s\n", "space", G->buf+G->pos));
+ return 1;
+ l9:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "space", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_braces(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "braces"));
+ { int yypos14= G->pos, yythunkpos14= G->thunkpos; if (!yymatchChar(G, '{')) goto l15;
+ l16:;
+ { int yypos17= G->pos, yythunkpos17= G->thunkpos;
+ { int yypos18= G->pos, yythunkpos18= G->thunkpos; if (!yymatchChar(G, '}')) goto l18; goto l17;
+ l18:; G->pos= yypos18; G->thunkpos= yythunkpos18;
+ } if (!yymatchDot(G)) goto l17; goto l16;
+ l17:; G->pos= yypos17; G->thunkpos= yythunkpos17;
+ } if (!yymatchChar(G, '}')) goto l15; goto l14;
+ l15:; G->pos= yypos14; G->thunkpos= yythunkpos14;
+ { int yypos19= G->pos, yythunkpos19= G->thunkpos; if (!yymatchChar(G, '}')) goto l19; goto l13;
+ l19:; G->pos= yypos19; G->thunkpos= yythunkpos19;
+ } if (!yymatchDot(G)) goto l13;
+ }
+ l14:;
+ yyprintf((stderr, " ok %s @ %s\n", "braces", G->buf+G->pos));
+ return 1;
+ l13:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "braces", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_range(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "range"));
+ { int yypos21= G->pos, yythunkpos21= G->thunkpos; if (!yy_char(G)) goto l22; if (!yymatchChar(G, '-')) goto l22; if (!yy_char(G)) goto l22; goto l21;
+ l22:; G->pos= yypos21; G->thunkpos= yythunkpos21; if (!yy_char(G)) goto l20;
+ }
+ l21:;
+ yyprintf((stderr, " ok %s @ %s\n", "range", G->buf+G->pos));
+ return 1;
+ l20:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "range", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_char(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "char"));
+ { int yypos24= G->pos, yythunkpos24= G->thunkpos; if (!yymatchChar(G, '\\')) goto l25; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\204\000\000\000\000\000\000\070\146\100\124\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l25; goto l24;
+ l25:; G->pos= yypos24; G->thunkpos= yythunkpos24; if (!yymatchChar(G, '\\')) goto l26; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\000\000\017\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l26; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l26; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l26; goto l24;
+ l26:; G->pos= yypos24; G->thunkpos= yythunkpos24; if (!yymatchChar(G, '\\')) goto l27; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l27;
+ { int yypos28= G->pos, yythunkpos28= G->thunkpos; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l28; goto l29;
+ l28:; G->pos= yypos28; G->thunkpos= yythunkpos28;
+ }
+ l29:; goto l24;
+ l27:; G->pos= yypos24; G->thunkpos= yythunkpos24;
+ { int yypos30= G->pos, yythunkpos30= G->thunkpos; if (!yymatchChar(G, '\\')) goto l30; goto l23;
+ l30:; G->pos= yypos30; G->thunkpos= yythunkpos30;
+ } if (!yymatchDot(G)) goto l23;
+ }
+ l24:;
+ yyprintf((stderr, " ok %s @ %s\n", "char", G->buf+G->pos));
+ return 1;
+ l23:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "char", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_END(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "END")); if (!yymatchChar(G, '>')) goto l31; if (!yy__(G)) goto l31;
+ yyprintf((stderr, " ok %s @ %s\n", "END", G->buf+G->pos));
+ return 1;
+ l31:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "END", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_BEGIN(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "BEGIN")); if (!yymatchChar(G, '<')) goto l32; if (!yy__(G)) goto l32;
+ yyprintf((stderr, " ok %s @ %s\n", "BEGIN", G->buf+G->pos));
+ return 1;
+ l32:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "BEGIN", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_DOT(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "DOT")); if (!yymatchChar(G, '.')) goto l33; if (!yy__(G)) goto l33;
+ yyprintf((stderr, " ok %s @ %s\n", "DOT", G->buf+G->pos));
+ return 1;
+ l33:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "DOT", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_class(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "class")); if (!yymatchChar(G, '[')) goto l34; yyText(G, G->begin, G->end); if (!(YY_BEGIN)) goto l34;
+ l35:;
+ { int yypos36= G->pos, yythunkpos36= G->thunkpos;
+ { int yypos37= G->pos, yythunkpos37= G->thunkpos; if (!yymatchChar(G, ']')) goto l37; goto l36;
+ l37:; G->pos= yypos37; G->thunkpos= yythunkpos37;
+ } if (!yy_range(G)) goto l36; goto l35;
+ l36:; G->pos= yypos36; G->thunkpos= yythunkpos36;
+ } yyText(G, G->begin, G->end); if (!(YY_END)) goto l34; if (!yymatchChar(G, ']')) goto l34; if (!yy__(G)) goto l34;
+ yyprintf((stderr, " ok %s @ %s\n", "class", G->buf+G->pos));
+ return 1;
+ l34:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "class", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_literal(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "literal"));
+ { int yypos39= G->pos, yythunkpos39= G->thunkpos; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l40; yyText(G, G->begin, G->end); if (!(YY_BEGIN)) goto l40;
+ l41:;
+ { int yypos42= G->pos, yythunkpos42= G->thunkpos;
+ { int yypos43= G->pos, yythunkpos43= G->thunkpos; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l43; goto l42;
+ l43:; G->pos= yypos43; G->thunkpos= yythunkpos43;
+ } if (!yy_char(G)) goto l42; goto l41;
+ l42:; G->pos= yypos42; G->thunkpos= yythunkpos42;
+ } yyText(G, G->begin, G->end); if (!(YY_END)) goto l40; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l40; if (!yy__(G)) goto l40; goto l39;
+ l40:; G->pos= yypos39; G->thunkpos= yythunkpos39; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l38; yyText(G, G->begin, G->end); if (!(YY_BEGIN)) goto l38;
+ l44:;
+ { int yypos45= G->pos, yythunkpos45= G->thunkpos;
+ { int yypos46= G->pos, yythunkpos46= G->thunkpos; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l46; goto l45;
+ l46:; G->pos= yypos46; G->thunkpos= yythunkpos46;
+ } if (!yy_char(G)) goto l45; goto l44;
+ l45:; G->pos= yypos45; G->thunkpos= yythunkpos45;
+ } yyText(G, G->begin, G->end); if (!(YY_END)) goto l38; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l38; if (!yy__(G)) goto l38;
+ }
+ l39:;
+ yyprintf((stderr, " ok %s @ %s\n", "literal", G->buf+G->pos));
+ return 1;
+ l38:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "literal", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_CLOSE(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "CLOSE")); if (!yymatchChar(G, ')')) goto l47; if (!yy__(G)) goto l47;
+ yyprintf((stderr, " ok %s @ %s\n", "CLOSE", G->buf+G->pos));
+ return 1;
+ l47:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "CLOSE", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_OPEN(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "OPEN")); if (!yymatchChar(G, '(')) goto l48; if (!yy__(G)) goto l48;
+ yyprintf((stderr, " ok %s @ %s\n", "OPEN", G->buf+G->pos));
+ return 1;
+ l48:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "OPEN", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_COLON(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "COLON")); if (!yymatchChar(G, ':')) goto l49; if (!yy__(G)) goto l49;
+ yyprintf((stderr, " ok %s @ %s\n", "COLON", G->buf+G->pos));
+ return 1;
+ l49:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "COLON", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_PLUS(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "PLUS")); if (!yymatchChar(G, '+')) goto l50; if (!yy__(G)) goto l50;
+ yyprintf((stderr, " ok %s @ %s\n", "PLUS", G->buf+G->pos));
+ return 1;
+ l50:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "PLUS", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_STAR(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "STAR")); if (!yymatchChar(G, '*')) goto l51; if (!yy__(G)) goto l51;
+ yyprintf((stderr, " ok %s @ %s\n", "STAR", G->buf+G->pos));
+ return 1;
+ l51:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "STAR", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_QUESTION(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "QUESTION")); if (!yymatchChar(G, '?')) goto l52; if (!yy__(G)) goto l52;
+ yyprintf((stderr, " ok %s @ %s\n", "QUESTION", G->buf+G->pos));
+ return 1;
+ l52:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "QUESTION", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_primary(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "primary"));
+ { int yypos54= G->pos, yythunkpos54= G->thunkpos; if (!yy_identifier(G)) goto l55; yyDo(G, yy_1_primary, G->begin, G->end); if (!yy_COLON(G)) goto l55; if (!yy_identifier(G)) goto l55;
+ { int yypos56= G->pos, yythunkpos56= G->thunkpos; if (!yy_EQUAL(G)) goto l56; goto l55;
+ l56:; G->pos= yypos56; G->thunkpos= yythunkpos56;
+ } yyDo(G, yy_2_primary, G->begin, G->end); goto l54;
+ l55:; G->pos= yypos54; G->thunkpos= yythunkpos54; if (!yy_identifier(G)) goto l57;
+ { int yypos58= G->pos, yythunkpos58= G->thunkpos; if (!yy_EQUAL(G)) goto l58; goto l57;
+ l58:; G->pos= yypos58; G->thunkpos= yythunkpos58;
+ } yyDo(G, yy_3_primary, G->begin, G->end); goto l54;
+ l57:; G->pos= yypos54; G->thunkpos= yythunkpos54; if (!yy_OPEN(G)) goto l59; if (!yy_expression(G)) goto l59; if (!yy_CLOSE(G)) goto l59; goto l54;
+ l59:; G->pos= yypos54; G->thunkpos= yythunkpos54; if (!yy_literal(G)) goto l60; yyDo(G, yy_4_primary, G->begin, G->end); goto l54;
+ l60:; G->pos= yypos54; G->thunkpos= yythunkpos54; if (!yy_class(G)) goto l61; yyDo(G, yy_5_primary, G->begin, G->end); goto l54;
+ l61:; G->pos= yypos54; G->thunkpos= yythunkpos54; if (!yy_DOT(G)) goto l62; yyDo(G, yy_6_primary, G->begin, G->end); goto l54;
+ l62:; G->pos= yypos54; G->thunkpos= yythunkpos54; if (!yy_action(G)) goto l63; yyDo(G, yy_7_primary, G->begin, G->end); goto l54;
+ l63:; G->pos= yypos54; G->thunkpos= yythunkpos54; if (!yy_BEGIN(G)) goto l64; yyDo(G, yy_8_primary, G->begin, G->end); goto l54;
+ l64:; G->pos= yypos54; G->thunkpos= yythunkpos54; if (!yy_END(G)) goto l53; yyDo(G, yy_9_primary, G->begin, G->end);
+ }
+ l54:;
+ yyprintf((stderr, " ok %s @ %s\n", "primary", G->buf+G->pos));
+ return 1;
+ l53:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "primary", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_NOT(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "NOT")); if (!yymatchChar(G, '!')) goto l65; if (!yy__(G)) goto l65;
+ yyprintf((stderr, " ok %s @ %s\n", "NOT", G->buf+G->pos));
+ return 1;
+ l65:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "NOT", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_suffix(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "suffix")); if (!yy_primary(G)) goto l66;
+ { int yypos67= G->pos, yythunkpos67= G->thunkpos;
+ { int yypos69= G->pos, yythunkpos69= G->thunkpos; if (!yy_QUESTION(G)) goto l70; yyDo(G, yy_1_suffix, G->begin, G->end); goto l69;
+ l70:; G->pos= yypos69; G->thunkpos= yythunkpos69; if (!yy_STAR(G)) goto l71; yyDo(G, yy_2_suffix, G->begin, G->end); goto l69;
+ l71:; G->pos= yypos69; G->thunkpos= yythunkpos69; if (!yy_PLUS(G)) goto l67; yyDo(G, yy_3_suffix, G->begin, G->end);
+ }
+ l69:; goto l68;
+ l67:; G->pos= yypos67; G->thunkpos= yythunkpos67;
+ }
+ l68:;
+ yyprintf((stderr, " ok %s @ %s\n", "suffix", G->buf+G->pos));
+ return 1;
+ l66:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "suffix", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_action(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "action")); if (!yymatchChar(G, '{')) goto l72; yyText(G, G->begin, G->end); if (!(YY_BEGIN)) goto l72;
+ l73:;
+ { int yypos74= G->pos, yythunkpos74= G->thunkpos; if (!yy_braces(G)) goto l74; goto l73;
+ l74:; G->pos= yypos74; G->thunkpos= yythunkpos74;
+ } yyText(G, G->begin, G->end); if (!(YY_END)) goto l72; if (!yymatchChar(G, '}')) goto l72; if (!yy__(G)) goto l72;
+ yyprintf((stderr, " ok %s @ %s\n", "action", G->buf+G->pos));
+ return 1;
+ l72:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "action", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_AND(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "AND")); if (!yymatchChar(G, '&')) goto l75; if (!yy__(G)) goto l75;
+ yyprintf((stderr, " ok %s @ %s\n", "AND", G->buf+G->pos));
+ return 1;
+ l75:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "AND", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_prefix(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "prefix"));
+ { int yypos77= G->pos, yythunkpos77= G->thunkpos; if (!yy_AND(G)) goto l78; if (!yy_action(G)) goto l78; yyDo(G, yy_1_prefix, G->begin, G->end); goto l77;
+ l78:; G->pos= yypos77; G->thunkpos= yythunkpos77; if (!yy_AND(G)) goto l79; if (!yy_suffix(G)) goto l79; yyDo(G, yy_2_prefix, G->begin, G->end); goto l77;
+ l79:; G->pos= yypos77; G->thunkpos= yythunkpos77; if (!yy_NOT(G)) goto l80; if (!yy_suffix(G)) goto l80; yyDo(G, yy_3_prefix, G->begin, G->end); goto l77;
+ l80:; G->pos= yypos77; G->thunkpos= yythunkpos77; if (!yy_suffix(G)) goto l76;
+ }
+ l77:;
+ yyprintf((stderr, " ok %s @ %s\n", "prefix", G->buf+G->pos));
+ return 1;
+ l76:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "prefix", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_BAR(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "BAR")); if (!yymatchChar(G, '|')) goto l81; if (!yy__(G)) goto l81;
+ yyprintf((stderr, " ok %s @ %s\n", "BAR", G->buf+G->pos));
+ return 1;
+ l81:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "BAR", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_sequence(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "sequence")); if (!yy_prefix(G)) goto l82;
+ l83:;
+ { int yypos84= G->pos, yythunkpos84= G->thunkpos; if (!yy_prefix(G)) goto l84; yyDo(G, yy_1_sequence, G->begin, G->end); goto l83;
+ l84:; G->pos= yypos84; G->thunkpos= yythunkpos84;
+ }
+ yyprintf((stderr, " ok %s @ %s\n", "sequence", G->buf+G->pos));
+ return 1;
+ l82:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "sequence", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_SEMICOLON(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "SEMICOLON")); if (!yymatchChar(G, ';')) goto l85; if (!yy__(G)) goto l85;
+ yyprintf((stderr, " ok %s @ %s\n", "SEMICOLON", G->buf+G->pos));
+ return 1;
+ l85:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "SEMICOLON", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_expression(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "expression")); if (!yy_sequence(G)) goto l86;
+ l87:;
+ { int yypos88= G->pos, yythunkpos88= G->thunkpos; if (!yy_BAR(G)) goto l88; if (!yy_sequence(G)) goto l88; yyDo(G, yy_1_expression, G->begin, G->end); goto l87;
+ l88:; G->pos= yypos88; G->thunkpos= yythunkpos88;
+ }
+ yyprintf((stderr, " ok %s @ %s\n", "expression", G->buf+G->pos));
+ return 1;
+ l86:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "expression", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_EQUAL(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "EQUAL")); if (!yymatchChar(G, '=')) goto l89; if (!yy__(G)) goto l89;
+ yyprintf((stderr, " ok %s @ %s\n", "EQUAL", G->buf+G->pos));
+ return 1;
+ l89:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "EQUAL", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_identifier(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "identifier")); yyText(G, G->begin, G->end); if (!(YY_BEGIN)) goto l90; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\000\040\000\000\376\377\377\207\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l90;
+ l91:;
+ { int yypos92= G->pos, yythunkpos92= G->thunkpos; if (!yymatchClass(G, (unsigned char *)"\000\000\000\000\000\040\377\003\376\377\377\207\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l92; goto l91;
+ l92:; G->pos= yypos92; G->thunkpos= yythunkpos92;
+ } yyText(G, G->begin, G->end); if (!(YY_END)) goto l90; if (!yy__(G)) goto l90;
+ yyprintf((stderr, " ok %s @ %s\n", "identifier", G->buf+G->pos));
+ return 1;
+ l90:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "identifier", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_RPERCENT(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "RPERCENT")); if (!yymatchString(G, "%}")) goto l93; if (!yy__(G)) goto l93;
+ yyprintf((stderr, " ok %s @ %s\n", "RPERCENT", G->buf+G->pos));
+ return 1;
+ l93:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "RPERCENT", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_end_of_file(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "end_of_file"));
+ { int yypos95= G->pos, yythunkpos95= G->thunkpos; if (!yymatchDot(G)) goto l95; goto l94;
+ l95:; G->pos= yypos95; G->thunkpos= yythunkpos95;
+ }
+ yyprintf((stderr, " ok %s @ %s\n", "end_of_file", G->buf+G->pos));
+ return 1;
+ l94:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "end_of_file", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_trailer(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "trailer")); if (!yymatchString(G, "%%")) goto l96; yyText(G, G->begin, G->end); if (!(YY_BEGIN)) goto l96;
+ l97:;
+ { int yypos98= G->pos, yythunkpos98= G->thunkpos; if (!yymatchDot(G)) goto l98; goto l97;
+ l98:; G->pos= yypos98; G->thunkpos= yythunkpos98;
+ } yyText(G, G->begin, G->end); if (!(YY_END)) goto l96; yyDo(G, yy_1_trailer, G->begin, G->end);
+ yyprintf((stderr, " ok %s @ %s\n", "trailer", G->buf+G->pos));
+ return 1;
+ l96:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "trailer", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_definition(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos; yyDo(G, yyPush, 1, 0);
+ yyprintf((stderr, "%s\n", "definition"));
+ { int yypos100= G->pos, yythunkpos100= G->thunkpos; if (!yymatchChar(G, '$')) goto l100; if (!yy__(G)) goto l100; yyDo(G, yySet, -1, 0); yyDo(G, yy_1_definition, G->begin, G->end); goto l101;
+ l100:; G->pos= yypos100; G->thunkpos= yythunkpos100;
+ }
+ l101:; if (!yy_identifier(G)) goto l99; yyDo(G, yy_2_definition, G->begin, G->end); if (!yy_EQUAL(G)) goto l99; if (!yy_expression(G)) goto l99; yyDo(G, yy_3_definition, G->begin, G->end);
+ { int yypos102= G->pos, yythunkpos102= G->thunkpos; if (!yy_SEMICOLON(G)) goto l102; goto l103;
+ l102:; G->pos= yypos102; G->thunkpos= yythunkpos102;
+ }
+ l103:;
+ yyprintf((stderr, " ok %s @ %s\n", "definition", G->buf+G->pos)); yyDo(G, yyPop, 1, 0);
+ return 1;
+ l99:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "definition", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy_declaration(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "declaration")); if (!yymatchString(G, "%{")) goto l104; yyText(G, G->begin, G->end); if (!(YY_BEGIN)) goto l104;
+ l105:;
+ { int yypos106= G->pos, yythunkpos106= G->thunkpos;
+ { int yypos107= G->pos, yythunkpos107= G->thunkpos; if (!yymatchString(G, "%}")) goto l107; goto l106;
+ l107:; G->pos= yypos107; G->thunkpos= yythunkpos107;
+ } if (!yymatchDot(G)) goto l106; goto l105;
+ l106:; G->pos= yypos106; G->thunkpos= yythunkpos106;
+ } yyText(G, G->begin, G->end); if (!(YY_END)) goto l104; if (!yy_RPERCENT(G)) goto l104; yyDo(G, yy_1_declaration, G->begin, G->end);
+ yyprintf((stderr, " ok %s @ %s\n", "declaration", G->buf+G->pos));
+ return 1;
+ l104:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "declaration", G->buf+G->pos));
+ return 0;
+}
+YY_RULE(int) yy__(GREG *G)
+{
+ yyprintf((stderr, "%s\n", "_"));
+ l109:;
+ { int yypos110= G->pos, yythunkpos110= G->thunkpos;
+ { int yypos111= G->pos, yythunkpos111= G->thunkpos; if (!yy_space(G)) goto l112; goto l111;
+ l112:; G->pos= yypos111; G->thunkpos= yythunkpos111; if (!yy_comment(G)) goto l110;
+ }
+ l111:; goto l109;
+ l110:; G->pos= yypos110; G->thunkpos= yythunkpos110;
+ }
+ yyprintf((stderr, " ok %s @ %s\n", "_", G->buf+G->pos));
+ return 1;
+}
+YY_RULE(int) yy_grammar(GREG *G)
+{ int yypos0= G->pos, yythunkpos0= G->thunkpos;
+ yyprintf((stderr, "%s\n", "grammar")); if (!yy__(G)) goto l113;
+ { int yypos116= G->pos, yythunkpos116= G->thunkpos; if (!yy_declaration(G)) goto l117; goto l116;
+ l117:; G->pos= yypos116; G->thunkpos= yythunkpos116; if (!yy_definition(G)) goto l113;
+ }
+ l116:;
+ l114:;
+ { int yypos115= G->pos, yythunkpos115= G->thunkpos;
+ { int yypos118= G->pos, yythunkpos118= G->thunkpos; if (!yy_declaration(G)) goto l119; goto l118;
+ l119:; G->pos= yypos118; G->thunkpos= yythunkpos118; if (!yy_definition(G)) goto l115;
+ }
+ l118:; goto l114;
+ l115:; G->pos= yypos115; G->thunkpos= yythunkpos115;
+ }
+ { int yypos120= G->pos, yythunkpos120= G->thunkpos; if (!yy_trailer(G)) goto l120; goto l121;
+ l120:; G->pos= yypos120; G->thunkpos= yythunkpos120;
+ }
+ l121:; if (!yy_end_of_file(G)) goto l113;
+ yyprintf((stderr, " ok %s @ %s\n", "grammar", G->buf+G->pos));
+ return 1;
+ l113:; G->pos= yypos0; G->thunkpos= yythunkpos0;
+ yyprintf((stderr, " fail %s @ %s\n", "grammar", G->buf+G->pos));
+ return 0;
+}
+
+#ifndef YY_PART
+
+typedef int (*yyrule)(GREG *G);
+
+YY_PARSE(int) YY_NAME(parse_from)(GREG *G, yyrule yystart)
+{
+ int yyok;
+ if (!G->buflen)
+ {
+ G->buflen= 1024;
+ G->buf= YY_ALLOC(G->buflen, G->data);
+ G->textlen= 1024;
+ G->text= YY_ALLOC(G->textlen, G->data);
+ G->thunkslen= 32;
+ G->thunks= YY_ALLOC(sizeof(yythunk) * G->thunkslen, G->data);
+ G->valslen= 32;
+ G->vals= YY_ALLOC(sizeof(YYSTYPE) * G->valslen, G->data);
+ G->begin= G->end= G->pos= G->limit= G->thunkpos= 0;
+ }
+ G->begin= G->end= G->pos;
+ G->thunkpos= 0;
+ G->val= G->vals;
+ yyok= yystart(G);
+ if (yyok) yyDone(G);
+ yyCommit(G);
+ return yyok;
+ (void)yyrefill;
+ (void)yymatchDot;
+ (void)yymatchChar;
+ (void)yymatchString;
+ (void)yymatchClass;
+ (void)yyDo;
+ (void)yyText;
+ (void)yyDone;
+ (void)yyCommit;
+ (void)yyAccept;
+ (void)yyPush;
+ (void)yyPop;
+ (void)yySet;
+}
+
+YY_PARSE(int) YY_NAME(parse)(GREG *G)
+{
+ return YY_NAME(parse_from)(G, yy_grammar);
+}
+
+YY_PARSE(GREG *) YY_NAME(parse_new)(YY_XTYPE data)
+{
+ GREG *G = (GREG *)YY_CALLOC(1, sizeof(GREG), G->data);
+ G->data = data;
+ return G;
+}
+
+YY_PARSE(void) YY_NAME(parse_free)(GREG *G)
+{
+ YY_FREE(G);
+}
+
+#endif
+
+
+void yyerror(struct _CDESCENT *G, char *message)
+{
+ fprintf(stderr, "%s:%d: %s", fileName, lineNumber, message);
+ if (G->text[0]) fprintf(stderr, " near token '%s'", G->text);
+ if (G->pos < G->limit || !feof(input))
+ {
+ G->buf[G->limit]= '\0';
+ fprintf(stderr, " before text \"");
+ while (G->pos < G->limit)
+ {
+ if ('\n' == G->buf[G->pos] || '\r' == G->buf[G->pos]) break;
+ fputc(G->buf[G->pos++], stderr);
+ }
+ if (G->pos == G->limit)
+ {
+ int c;
+ while (EOF != (c= fgetc(input)) && '\n' != c && '\r' != c)
+ fputc(c, stderr);
+ }
+ fputc('\"', stderr);
+ }
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+void makeHeader(char *text)
+{
+ Header *header= (Header *)malloc(sizeof(Header));
+ header->text= strdup(text);
+ header->next= headers;
+ headers= header;
+}
+
+void makeTrailer(char *text)
+{
+ trailer= strdup(text);
+}
+
+static void version(char *name)
+{
+ printf("%s version %s\n", name, CDESCENT_VERSION);
+}
+
+static void usage(char *name)
+{
+ version(name);
+ fprintf(stderr, "usage: %s [<option>...] [<file>...]\n", name);
+ fprintf(stderr, "where <option> can be\n");
+ fprintf(stderr, " -h print this help information\n");
+ fprintf(stderr, " -o <ofile> write output to <ofile>\n");
+ fprintf(stderr, " -v be verbose\n");
+ fprintf(stderr, " -V print version number and exit\n");
+ fprintf(stderr, "if no <file> is given, input is read from stdin\n");
+ fprintf(stderr, "if no <ofile> is given, output is written to stdout\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ GREG *G;
+ Node *n;
+ int c;
+
+ output= stdout;
+ input= stdin;
+ lineNumber= 1;
+ fileName= "<stdin>";
+
+ while (-1 != (c= getopt(argc, argv, "Vho:v")))
+ {
+ switch (c)
+ {
+ case 'V':
+ version(basename(argv[0]));
+ exit(0);
+
+ case 'h':
+ usage(basename(argv[0]));
+ break;
+
+ case 'o':
+ if (!(output= fopen(optarg, "w")))
+ {
+ perror(optarg);
+ exit(1);
+ }
+ break;
+
+ case 'v':
+ verboseFlag= 1;
+ break;
+
+ default:
+ fprintf(stderr, "for usage try: %s -h\n", argv[0]);
+ exit(1);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ G = yyparse_new(NULL);
+ if (argc)
+ {
+ for (; argc; --argc, ++argv)
+ {
+ if (!strcmp(*argv, "-"))
+ {
+ input= stdin;
+ fileName= "<stdin>";
+ }
+ else
+ {
+ if (!(input= fopen(*argv, "r")))
+ {
+ perror(*argv);
+ exit(1);
+ }
+ fileName= *argv;
+ }
+ lineNumber= 1;
+ if (!yyparse(G))
+ yyerror(G, "syntax error");
+ if (input != stdin)
+ fclose(input);
+ }
+ }
+ else
+ if (!yyparse(G))
+ yyerror(G, "syntax error");
+ yyparse_free(G);
+
+ if (verboseFlag)
+ for (n= rules; n; n= n->any.next)
+ Rule_print(n);
+
+ Rule_compile_c_header();
+
+ for (; headers; headers= headers->next)
+ fprintf(output, "%s\n", headers->text);
+
+ if (rules)
+ Rule_compile_c(rules);
+
+ if (trailer)
+ fprintf(output, "%s\n", trailer);
+
+ return 0;
+}
+
110 src/cdescent.h
@@ -0,0 +1,110 @@
+/* Copyright (c) 2007 by Ian Piumarta
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the 'Software'),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, provided that the above copyright notice(s) and this
+ * permission notice appear in all copies of the Software. Acknowledgement
+ * of the use of this Software in supporting documentation would be
+ * appreciated but is not required.
+ *
+ * THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
+ *
+ * Last edited: 2007-05-15 10:32:05 by piumarta on emilia
+ */
+
+#include <stdio.h>
+
+#define CDESCENT_VERSION "0.0.1"
+
+enum { Unknown= 0, Rule, Variable, Name, Dot, Character, String, Class, Action, Predicate, Alternate, Sequence, PeekFor, PeekNot, Query, Star, Plus };
+
+enum {
+ RuleUsed = 1<<0,
+ RuleReached = 1<<1,
+};
+
+typedef union Node Node;
+
+struct Rule { int type; Node *next; char *name; Node *variables; Node *expression; int id; int flags; };
+struct Variable { int type; Node *next; char *name; Node *value; int offset; };
+struct Name { int type; Node *next; Node *rule; Node *variable; };
+struct Dot { int type; Node *next; };
+struct Character { int type; Node *next; char *value; };
+struct String { int type; Node *next; char *value; };
+struct Class { int type; Node *next; unsigned char *value; };
+struct Action { int type; Node *next; char *text; Node *list; char *name; Node *rule; };
+struct Predicate { int type; Node *next; char *text; };
+struct Alternate { int type; Node *next; Node *first; Node *last; };
+struct Sequence { int type; Node *next; Node *first; Node *last; };
+struct PeekFor { int type; Node *next; Node *element; };
+struct PeekNot { int type; Node *next; Node *element; };
+struct Query { int type; Node *next; Node *element; };
+struct Star { int type; Node *next; Node *element; };
+struct Plus { int type; Node *next; Node *element; };
+struct Any { int type; Node *next; };
+
+union Node
+{
+ int type;
+ struct Rule rule;
+ struct Variable variable;
+ struct Name name;
+ struct Dot dot;
+ struct Character character;
+ struct String string;
+ struct Class cclass;
+ struct Action action;
+ struct Predicate predicate;
+ struct Alternate alternate;
+ struct Sequence sequence;
+ struct PeekFor peekFor;
+ struct PeekNot peekNot;
+ struct Query query;
+ struct Star star;
+ struct Plus plus;
+ struct Any any;
+};
+
+extern Node *actions;
+extern Node *rules;
+extern Node *start;
+
+extern int ruleCount;
+
+extern FILE *output;
+
+extern Node *makeRule(char *name, int starts);
+extern Node *findRule(char *name, int starts);
+extern Node *beginRule(Node *rule);
+extern void Rule_setExpression(Node *rule, Node *expression);
+extern Node *Rule_beToken(Node *rule);
+extern Node *makeVariable(char *name);
+extern Node *makeName(Node *rule);
+extern Node *makeDot(void);
+extern Node *makeCharacter(char *text);
+extern Node *makeString(char *text);
+extern Node *makeClass(char *text);
+extern Node *makeAction(char *text);
+extern Node *makePredicate(char *text);
+extern Node *makeAlternate(Node *e);
+extern Node *Alternate_append(Node *e, Node *f);
+extern Node *makeSequence(Node *e);
+extern Node *Sequence_append(Node *e, Node *f);
+extern Node *makePeekFor(Node *e);
+extern Node *makePeekNot(Node *e);
+extern Node *makeQuery(Node *e);
+extern Node *makeStar(Node *e);
+extern Node *makePlus(Node *e);
+extern Node *push(Node *node);
+extern Node *top(void);
+extern Node *pop(void);
+
+extern void Rule_compile_c_header(void);
+extern void Rule_compile_c(Node *node);
+
+extern void Node_print(Node *node);
+extern void Rule_print(Node *node);
739 src/compile.c
@@ -0,0 +1,739 @@
+/* Copyright (c) 2007 by Ian Piumarta
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the 'Software'),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, provided that the above copyright notice(s) and this
+ * permission notice appear in all copies of the Software. Acknowledgement
+ * of the use of this Software in supporting documentation would be
+ * appreciated but is not required.
+ *
+ * THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
+ *
+ * Last edited: 2007-08-31 13:55:23 by piumarta on emilia.local
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "cdescent.h"
+
+static int yyl(void)
+{
+ static int prev= 0;
+ return ++prev;
+}
+
+static void charClassSet (unsigned char bits[], int c) { bits[c >> 3] |= (1 << (c & 7)); }
+static void charClassClear(unsigned char bits[], int c) { bits[c >> 3] &= ~(1 << (c & 7)); }
+
+typedef void (*setter)(unsigned char bits[], int c);
+
+static int readChar(unsigned char **cp)
+{
+ unsigned char *cclass = *cp;
+ int c= *cclass++, i = 0;
+ if ('\\' == c && *cclass)
+ {
+ c= *cclass++;
+ if (c >= '0' && c <= '9')
+ {
+ unsigned char oct= 0;
+ for (i= 2; i >= 0; i--) {
+ if (!(c >= '0' && c <= '9'))
+ break;
+ oct= (oct * 8) + (c - '0');
+ c= *cclass++;
+ }
+ cclass--;
+ c= oct;
+ goto done;
+ }
+
+ switch (c)
+ {
+ case 'a': c= '\a'; break; /* bel */
+ case 'b': c= '\b'; break; /* bs */
+ case 'e': c= '\e'; break; /* esc */
+ case 'f': c= '\f'; break; /* ff */
+ case 'n': c= '\n'; break; /* nl */
+ case 'r': c= '\r'; break; /* cr */
+ case 't': c= '\t'; break; /* ht */
+ case 'v': c= '\v'; break; /* vt */
+ default: break;
+ }
+ }
+
+done:
+ *cp = cclass;
+ return c;
+}
+
+static char *makeCharClass(unsigned char *cclass)
+{
+ unsigned char bits[32];
+ setter set;
+ int c, prev= -1;
+ static char string[256];
+ char *ptr;
+
+ if ('^' == *cclass)
+ {
+ memset(bits, 255, 32);
+ set= charClassClear;
+ ++cclass;
+ }
+ else
+ {
+ memset(bits, 0, 32);
+ set= charClassSet;
+ }
+ while (0 != (c= readChar(&cclass)))
+ {
+ if ('-' == c && *cclass && prev >= 0)
+ {
+ for (c= readChar(&cclass); prev <= c; ++prev)
+ set(bits, prev);
+ prev= -1;
+ }
+ else
+ {
+ set(bits, prev= c);
+ }
+ }
+
+ ptr= string;
+ for (c= 0; c < 32; ++c)
+ ptr += sprintf(ptr, "\\%03o", bits[c]);
+
+ return string;
+}
+
+static void begin(void) { fprintf(output, "\n {"); }
+static void end(void) { fprintf(output, "\n }"); }
+static void label(int n) { fprintf(output, "\n l%d:;\t", n); }
+static void jump(int n) { fprintf(output, " goto l%d;", n); }
+static void save(int n) { fprintf(output, " int yypos%d= G->pos, yythunkpos%d= G->thunkpos;", n, n); }
+static void restore(int n) { fprintf(output, " G->pos= yypos%d; G->thunkpos= yythunkpos%d;", n, n); }
+
+static void Node_compile_c_ko(Node *node, int ko)
+{
+ assert(node);
+ switch (node->type)
+ {
+ case Rule:
+ fprintf(stderr, "\ninternal error #1 (%s)\n", node->rule.name);
+ exit(1);
+ break;
+
+ case Dot:
+ fprintf(output, " if (!yymatchDot(G)) goto l%d;", ko);
+ break;
+
+ case Name:
+ fprintf(output, " if (!yy_%s(G)) goto l%d;", node->name.rule->rule.name, ko);
+ if (node->name.variable)
+ fprintf(output, " yyDo(G, yySet, %d, 0);", node->name.variable->variable.offset);
+ break;
+
+ case Character:
+ case String:
+ {
+ int len= strlen(node->string.value);
+ if (1 == len || (2 == len && '\\' == node->string.value[0]))
+ fprintf(output, " if (!yymatchChar(G, '%s')) goto l%d;", node->string.value, ko);
+ else
+ fprintf(output, " if (!yymatchString(G, \"%s\")) goto l%d;", node->string.value, ko);
+ }
+ break;
+
+ case Class:
+ fprintf(output, " if (!yymatchClass(G, (unsigned char *)\"%s\")) goto l%d;", makeCharClass(node->cclass.value), ko);
+ break;
+
+ case Action:
+ fprintf(output, " yyDo(G, yy%s, G->begin, G->end);", node->action.name);
+ break;
+
+ case Predicate:
+ fprintf(output, " yyText(G, G->begin, G->end); if (!(%s)) goto l%d;", node->action.text, ko);
+ break;
+
+ case Alternate:
+ {
+ int ok= yyl();
+ begin();
+ save(ok);
+ for (node= node->alternate.first; node; node= node->alternate.next)
+ if (node->alternate.next)
+ {
+ int next= yyl();
+ Node_compile_c_ko(node, next);
+ jump(ok);
+ label(next);
+ restore(ok);
+ }
+ else
+ Node_compile_c_ko(node, ko);
+ end();
+ label(ok);
+ }
+ break;
+
+ case Sequence:
+ for (node= node->sequence.first; node; node= node->sequence.next)
+ Node_compile_c_ko(node, ko);
+ break;
+
+ case PeekFor:
+ {
+ int ok= yyl();
+ begin();
+ save(ok);
+ Node_compile_c_ko(node->peekFor.element, ko);
+ restore(ok);
+ end();
+ }
+ break;
+
+ case PeekNot:
+ {
+ int ok= yyl();
+ begin();
+ save(ok);
+ Node_compile_c_ko(node->peekFor.element, ok);
+ jump(ko);
+ label(ok);
+ restore(ok);
+ end();
+ }
+ break;
+
+ case Query:
+ {
+ int qko= yyl(), qok= yyl();
+ begin();
+ save(qko);
+ Node_compile_c_ko(node->query.element, qko);
+ jump(qok);
+ label(qko);
+ restore(qko);
+ end();
+ label(qok);
+ }
+ break;
+
+ case Star:
+ {
+ int again= yyl(), out= yyl();
+ label(again);
+ begin();
+ save(out);
+ Node_compile_c_ko(node->star.element, out);
+ jump(again);
+ label(out);
+ restore(out);
+ end();
+ }
+ break;
+
+ case Plus:
+ {
+ int again= yyl(), out= yyl();
+ Node_compile_c_ko(node->plus.element, ko);
+ label(again);
+ begin();
+ save(out);
+ Node_compile_c_ko(node->plus.element, out);
+ jump(again);
+ label(out);
+ restore(out);
+ end();
+ }
+ break;
+
+ default:
+ fprintf(stderr, "\nNode_compile_c_ko: illegal node type %d\n", node->type);
+ exit(1);
+ }
+}
+
+
+static int countVariables(Node *node)
+{
+ int count= 0;
+ while (node)
+ {
+ ++count;
+ node= node->variable.next;
+ }
+ return count;
+}
+
+static void defineVariables(Node *node)
+{
+ int count= 0;
+ while (node)
+ {
+ fprintf(output, "#define %s G->val[%d]\n", node->variable.name, --count);
+ node->variable.offset= count;
+ node= node->variable.next;
+ }
+}
+
+static void undefineVariables(Node *node)
+{
+ while (node)
+ {
+ fprintf(output, "#undef %s\n", node->variable.name);
+ node= node->variable.next;
+ }
+}
+
+
+static void Rule_compile_c2(Node *node)
+{
+ assert(node);
+ assert(Rule == node->type);
+
+ if (!node->rule.expression)
+ fprintf(stderr, "rule '%s' used but not defined\n", node->rule.name);
+ else
+ {
+ int ko= yyl(), safe;
+
+ if ((!(RuleUsed & node->rule.flags)) && (node != start))
+ fprintf(stderr, "rule '%s' defined but not used\n", node->rule.name);
+
+ safe= ((Query == node->rule.expression->type) || (Star == node->rule.expression->type));
+
+ fprintf(output, "\nYY_RULE(int) yy_%s(GREG *G)\n{", node->rule.name);
+ if (!safe) save(0);
+ if (node->rule.variables)
+ fprintf(output, " yyDo(G, yyPush, %d, 0);", countVariables(node->rule.variables));
+ fprintf(output, "\n yyprintf((stderr, \"%%s\\n\", \"%s\"));", node->rule.name);
+ Node_compile_c_ko(node->rule.expression, ko);
+ fprintf(output, "\n yyprintf((stderr, \" ok %%s @ %%s\\n\", \"%s\", G->buf+G->pos));", node->rule.name);
+ if (node->rule.variables)
+ fprintf(output, " yyDo(G, yyPop, %d, 0);", countVariables(node->rule.variables));
+ fprintf(output, "\n return 1;");
+ if (!safe)
+ {
+ label(ko);
+ restore(0);
+ fprintf(output, "\n yyprintf((stderr, \" fail %%s @ %%s\\n\", \"%s\", G->buf+G->pos));", node->rule.name);
+ fprintf(output, "\n return 0;");
+ }
+ fprintf(output, "\n}");
+ }
+
+ if (node->rule.next)
+ Rule_compile_c2(node->rule.next);
+}
+
+static char *header= "\
+#include <stdio.h>\n\
+#include <stdlib.h>\n\
+#include <string.h>\n\
+struct _GREG;\n\
+";
+
+static char *preamble= "\
+#ifndef YY_ALLOC\n\
+#define YY_ALLOC(N, D) malloc(N)\n\
+#endif\n\
+#ifndef YY_CALLOC\n\
+#define YY_CALLOC(N, S, D) calloc(N, S)\n\
+#endif\n\
+#ifndef YY_REALLOC\n\
+#define YY_REALLOC(B, N, D) realloc(B, N)\n\
+#endif\n\
+#ifndef YY_FREE\n\
+#define YY_FREE free\n\
+#endif\n\
+#ifndef YY_LOCAL\n\
+#define YY_LOCAL(T) static T\n\
+#endif\n\
+#ifndef YY_ACTION\n\
+#define YY_ACTION(T) static T\n\
+#endif\n\
+#ifndef YY_RULE\n\
+#define YY_RULE(T) static T\n\
+#endif\n\
+#ifndef YY_PARSE\n\
+#define YY_PARSE(T) T\n\
+#endif\n\
+#ifndef YY_NAME\n\
+#define YY_NAME(N) yy##N\n\
+#endif\n\
+#ifndef YY_INPUT\n\
+#define YY_INPUT(buf, result, max_size) \\\n\
+ { \\\n\
+ int yyc= getchar(); \\\n\
+ result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1); \\\n\
+ yyprintf((stderr, \"<%c>\", yyc)); \\\n\
+ }\n\
+#endif\n\
+#ifndef YY_BEGIN\n\
+#define YY_BEGIN ( G->begin= G->pos, 1)\n\
+#endif\n\
+#ifndef YY_END\n\
+#define YY_END ( G->end= G->pos, 1)\n\
+#endif\n\
+#ifdef YY_DEBUG\n\
+# define yyprintf(args) fprintf args\n\
+#else\n\
+# define yyprintf(args)\n\
+#endif\n\
+#ifndef YYSTYPE\n\
+#define YYSTYPE int\n\
+#endif\n\
+#ifndef YY_XTYPE\n\
+#define YY_XTYPE void *\n\
+#endif\n\
+#ifndef YY_XVAR\n\
+#define YY_XVAR yydata\n\
+#endif\n\
+\n\
+#ifndef YY_PART\n\
+#define yy G->ss\n\
+\n\
+typedef void (*yyaction)(struct _GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR);\n\
+typedef struct _yythunk { int begin, end; yyaction action; struct _yythunk *next; } yythunk;\n\
+\n\
+typedef struct _GREG {\n\
+ char *buf;\n\
+ int buflen;\n\
+ int pos;\n\
+ int limit;\n\
+ char *text;\n\
+ int textlen;\n\
+ int begin;\n\
+ int end;\n\
+ yythunk *thunks;\n\
+ int thunkslen;\n\
+ int thunkpos;\n\
+ YYSTYPE ss;\n\
+ YYSTYPE *val;\n\
+ YYSTYPE *vals;\n\
+ int valslen;\n\
+ YY_XTYPE data;\n\
+} GREG;\n\
+\n\
+YY_LOCAL(int) yyrefill(GREG *G)\n\
+{\n\
+ int yyn;\n\
+ YY_XTYPE YY_XVAR = (YY_XTYPE)G->data;\n\
+ while (G->buflen - G->pos < 512)\n\
+ {\n\
+ G->buflen *= 2;\n\
+ G->buf= YY_REALLOC(G->buf, G->buflen, G->data);\n\
+ }\n\
+ YY_INPUT((G->buf + G->pos), yyn, (G->buflen - G->pos));\n\
+ if (!yyn) return 0;\n\
+ G->limit += yyn;\n\
+ return 1;\n\
+}\n\
+\n\
+YY_LOCAL(int) yymatchDot(GREG *G)\n\
+{\n\
+ if (G->pos >= G->limit && !yyrefill(G)) return 0;\n\
+ ++G->pos;\n\
+ return 1;\n\
+}\n\
+\n\
+YY_LOCAL(int) yymatchChar(GREG *G, int c)\n\
+{\n\
+ if (G->pos >= G->limit && !yyrefill(G)) return 0;\n\
+ if ((unsigned char)G->buf[G->pos] == c)\n\
+ {\n\
+ ++G->pos;\n\
+ yyprintf((stderr, \" ok yymatchChar(%c) @ %s\\n\", c, G->buf+G->pos));\n\
+ return 1;\n\
+ }\n\
+ yyprintf((stderr, \" fail yymatchChar(%c) @ %s\\n\", c, G->buf+G->pos));\n\
+ return 0;\n\
+}\n\
+\n\
+YY_LOCAL(int) yymatchString(GREG *G, char *s)\n\
+{\n\
+ int yysav= G->pos;\n\
+ while (*s)\n\
+ {\n\
+ if (G->pos >= G->limit && !yyrefill(G)) return 0;\n\
+ if (G->buf[G->pos] != *s)\n\
+ {\n\
+ G->pos= yysav;\n\
+ return 0;\n\
+ }\n\
+ ++s;\n\
+ ++G->pos;\n\
+ }\n\
+ return 1;\n\
+}\n\
+\n\
+YY_LOCAL(int) yymatchClass(GREG *G, unsigned char *bits)\n\
+{\n\
+ int c;\n\
+ if (G->pos >= G->limit && !yyrefill(G)) return 0;\n\
+ c= (unsigned char)G->buf[G->pos];\n\
+ if (bits[c >> 3] & (1 << (c & 7)))\n\
+ {\n\
+ ++G->pos;\n\
+ yyprintf((stderr, \" ok yymatchClass @ %s\\n\", G->buf+G->pos));\n\
+ return 1;\n\
+ }\n\
+ yyprintf((stderr, \" fail yymatchClass @ %s\\n\", G->buf+G->pos));\n\
+ return 0;\n\
+}\n\
+\n\
+YY_LOCAL(void) yyDo(GREG *G, yyaction action, int begin, int end)\n\
+{\n\
+ while (G->thunkpos >= G->thunkslen)\n\
+ {\n\
+ G->thunkslen *= 2;\n\
+ G->thunks= YY_REALLOC(G->thunks, sizeof(yythunk) * G->thunkslen, G->data);\n\
+ }\n\
+ G->thunks[G->thunkpos].begin= begin;\n\
+ G->thunks[G->thunkpos].end= end;\n\
+ G->thunks[G->thunkpos].action= action;\n\
+ ++G->thunkpos;\n\
+}\n\
+\n\
+YY_LOCAL(int) yyText(GREG *G, int begin, int end)\n\
+{\n\
+ int yyleng= end - begin;\n\
+ if (yyleng <= 0)\n\
+ yyleng= 0;\n\
+ else\n\
+ {\n\
+ while (G->textlen < (yyleng - 1))\n\
+ {\n\
+ G->textlen *= 2;\n\
+ G->text= YY_REALLOC(G->text, G->textlen, G->data);\n\
+ }\n\
+ memcpy(G->text, G->buf + begin, yyleng);\n\
+ }\n\
+ G->text[yyleng]= '\\0';\n\
+ return yyleng;\n\
+}\n\
+\n\
+YY_LOCAL(void) yyDone(GREG *G)\n\
+{\n\
+ int pos;\n\
+ for (pos= 0; pos < G->thunkpos; ++pos)\n\
+ {\n\
+ yythunk *thunk= &G->thunks[pos];\n\
+ int yyleng= thunk->end ? yyText(G, thunk->begin, thunk->end) : thunk->begin;\n\
+ yyprintf((stderr, \"DO [%d] %p %s\\n\", pos, thunk->action, G->text));\n\
+ thunk->action(G, G->text, yyleng, G->data);\n\
+ }\n\
+ G->thunkpos= 0;\n\
+}\n\
+\n\
+YY_LOCAL(void) yyCommit(GREG *G)\n\
+{\n\
+ if ((G->limit -= G->pos))\n\
+ {\n\
+ memmove(G->buf, G->buf + G->pos, G->limit);\n\
+ }\n\
+ G->begin -= G->pos;\n\
+ G->end -= G->pos;\n\
+ G->pos= G->thunkpos= 0;\n\
+}\n\
+\n\
+YY_LOCAL(int) yyAccept(GREG *G, int tp0)\n\
+{\n\
+ if (tp0)\n\
+ {\n\
+ fprintf(stderr, \"accept denied at %d\\n\", tp0);\n\
+ return 0;\n\
+ }\n\
+ else\n\
+ {\n\
+ yyDone(G);\n\
+ yyCommit(G);\n\
+ }\n\
+ return 1;\n\
+}\n\
+\n\
+YY_LOCAL(void) yyPush(GREG *G, char *text, int count, YY_XTYPE YY_XVAR) {\n\
+ size_t off = (G->val - G->vals) + count;\n\
+ if (off > G->valslen) {\n\
+ while (G->valslen < off + 1)\n\
+ G->valslen *= 2;\n\
+ G->vals= YY_REALLOC((void *)G->vals, sizeof(YYSTYPE) * G->valslen, G->data);\n\
+ G->val= G->vals + off;\n\
+ } else {\n\
+ G->val += count;\n\
+ }\n\
+}\n\
+YY_LOCAL(void) yyPop(GREG *G, char *text, int count, YY_XTYPE YY_XVAR) { G->val -= count; }\n\
+YY_LOCAL(void) yySet(GREG *G, char *text, int count, YY_XTYPE YY_XVAR) { G->val[count]= G->ss; }\n\
+\n\
+#endif /* YY_PART */\n\
+\n\
+#define YYACCEPT yyAccept(G, yythunkpos0)\n\
+\n\
+";
+
+static char *footer= "\n\
+\n\
+#ifndef YY_PART\n\
+\n\
+typedef int (*yyrule)(GREG *G);\n\
+\n\
+YY_PARSE(int) YY_NAME(parse_from)(GREG *G, yyrule yystart)\n\
+{\n\
+ int yyok;\n\
+ if (!G->buflen)\n\
+ {\n\
+ G->buflen= 1024;\n\
+ G->buf= YY_ALLOC(G->buflen, G->data);\n\
+ G->textlen= 1024;\n\
+ G->text= YY_ALLOC(G->textlen, G->data);\n\
+ G->thunkslen= 32;\n\
+ G->thunks= YY_ALLOC(sizeof(yythunk) * G->thunkslen, G->data);\n\
+ G->valslen= 32;\n\
+ G->vals= YY_ALLOC(sizeof(YYSTYPE) * G->valslen, G->data);\n\
+ G->begin= G->end= G->pos= G->limit= G->thunkpos= 0;\n\
+ }\n\
+ G->begin= G->end= G->pos;\n\
+ G->thunkpos= 0;\n\
+ G->val= G->vals;\n\
+ yyok= yystart(G);\n\
+ if (yyok) yyDone(G);\n\
+ yyCommit(G);\n\
+ return yyok;\n\
+ (void)yyrefill;\n\
+ (void)yymatchDot;\n\
+ (void)yymatchChar;\n\
+ (void)yymatchString;\n\
+ (void)yymatchClass;\n\
+ (void)yyDo;\n\
+ (void)yyText;\n\
+ (void)yyDone;\n\
+ (void)yyCommit;\n\
+ (void)yyAccept;\n\
+ (void)yyPush;\n\
+ (void)yyPop;\n\
+ (void)yySet;\n\
+}\n\
+\n\
+YY_PARSE(int) YY_NAME(parse)(GREG *G)\n\
+{\n\
+ return YY_NAME(parse_from)(G, yy_%s);\n\
+}\n\
+\n\
+YY_PARSE(GREG *) YY_NAME(parse_new)(YY_XTYPE data)\n\
+{\n\
+ GREG *G = (GREG *)YY_CALLOC(1, sizeof(GREG), G->data);\n\
+ G->data = data;\n\
+ return G;\n\
+}\n\
+\n\
+YY_PARSE(void) YY_NAME(parse_free)(GREG *G)\n\
+{\n\
+ YY_FREE(G);\n\
+}\n\
+\n\
+#endif\n\
+";
+
+void Rule_compile_c_header(void)
+{
+ fprintf(output, "/* A recursive-descent parser generated by cdescent %s */\n", CDESCENT_VERSION);
+ fprintf(output, "\n");
+ fprintf(output, "%s", header);
+ fprintf(output, "#define YYRULECOUNT %d\n", ruleCount);
+}
+
+int consumesInput(Node *node)
+{
+ if (!node) return 0;
+
+ switch (node->type)
+ {
+ case Rule:
+ {
+ int result= 0;
+ if (RuleReached & node->rule.flags)
+ fprintf(stderr, "possible infinite left recursion in rule '%s'\n", node->rule.name);
+ else
+ {
+ node->rule.flags |= RuleReached;
+ result= consumesInput(node->rule.expression);
+ node->rule.flags &= ~RuleReached;
+ }
+ return result;
+ }
+ break;
+
+ case Dot: return 1;
+ case Name: return consumesInput(node->name.rule);
+ case Character:
+ case String: return strlen(node->string.value) > 0;
+ case Class: return 1;
+ case Action: return 0;
+ case Predicate: return 0;
+
+ case Alternate:
+ {
+ Node *n;
+ for (n= node->alternate.first; n; n= n->alternate.next)
+ if (!consumesInput(n))
+ return 0;
+ }
+ return 1;
+
+ case Sequence:
+ {
+ Node *n;
+ for (n= node->alternate.first; n; n= n->alternate.next)
+ if (consumesInput(n))
+ return 1;
+ }
+ return 0;
+
+ case PeekFor: return 0;
+ case PeekNot: return 0;
+ case Query: return 0;
+ case Star: return 0;
+ case Plus: return consumesInput(node->plus.element);
+
+ default:
+ fprintf(stderr, "\nconsumesInput: illegal node type %d\n", node->type);
+ exit(1);
+ }
+ return 0;
+}
+
+
+void Rule_compile_c(Node *node)
+{
+ Node *n;
+
+ for (n= rules; n; n= n->rule.next)
+ consumesInput(n);
+
+ fprintf(output, "%s", preamble);
+ for (n= node; n; n= n->rule.next)
+ fprintf(output, "YY_RULE(int) yy_%s(GREG *G); /* %d */\n", n->rule.name, n->rule.id);
+ fprintf(output, "\n");
+ for (n= actions; n; n= n->action.list)
+ {
+ fprintf(output, "YY_ACTION(void) yy%s(GREG *G, char *yytext, int yyleng, YY_XTYPE YY_XVAR)\n{\n", n->action.name);
+ defineVariables(n->action.rule->rule.variables);
+ fprintf(output, " yyprintf((stderr, \"do yy%s\\n\"));\n", n->action.name);
+ fprintf(output, " %s;\n", n->action.text);
+ undefineVariables(n->action.rule->rule.variables);
+ fprintf(output, "}\n");
+ }
+ Rule_compile_c2(node);
+ fprintf(output, footer, start->rule.name);
+}
352 src/tree.c
@@ -0,0 +1,352 @@
+/* Copyright (c) 2007 by Ian Piumarta
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the 'Software'),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, provided that the above copyright notice(s) and this
+ * permission notice appear in all copies of the Software. Acknowledgement
+ * of the use of this Software in supporting documentation would be
+ * appreciated but is not required.
+ *
+ * THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
+ *
+ * Last edited: 2007-05-15 10:32:09 by piumarta on emilia
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "cdescent.h"
+
+Node *actions= 0;
+Node *rules= 0;
+Node *thisRule= 0;
+Node *start= 0;
+
+FILE *output= 0;
+
+int actionCount= 0;
+int ruleCount= 0;
+int lastToken= -1;
+
+static inline Node *_newNode(int type, int size)
+{
+ Node *node= calloc(1, size);
+ node->type= type;
+ return node;
+}
+
+#define newNode(T) _newNode(T, sizeof(struct T))
+
+Node *makeRule(char *name, int starts)
+{
+ Node *node= newNode(Rule);
+ node->rule.name= strdup(name);
+ node->rule.id= ++ruleCount;
+ node->rule.flags= starts ? RuleUsed : 0;
+ node->rule.next= rules;
+ rules= node;
+ return node;
+}
+
+Node *findRule(char *name, int starts)
+{
+ Node *n;
+ char *ptr;
+ for (ptr= name; *ptr; ptr++) if ('-' == *ptr) *ptr= '_';
+ for (n= rules; n; n= n->any.next)
+ {
+ assert(Rule == n->type);
+ if (!strcmp(name, n->rule.name))
+ return n;
+ }
+ return makeRule(name, starts);
+}
+
+Node *beginRule(Node *rule)
+{
+ actionCount= 0;
+ return thisRule= rule;
+}
+
+void Rule_setExpression(Node *node, Node *expression)
+{
+ assert(node);
+#ifdef DEBUG
+ Node_print(node); fprintf(stderr, " [%d]<- ", node->type); Node_print(expression); fprintf(stderr, "\n");
+#endif
+ assert(Rule == node->type);
+ node->rule.expression= expression;
+ if (!start || !strcmp(node->rule.name, "start"))
+ start= node;
+}
+
+Node *makeVariable(char *name)
+{
+ Node *node;
+ assert(thisRule);
+ for (node= thisRule->rule.variables; node; node= node->variable.next)
+ if (!strcmp(name, node->variable.name))
+ return node;
+ node= newNode(Variable);
+ node->variable.name= strdup(name);
+ node->variable.next= thisRule->rule.variables;
+ thisRule->rule.variables= node;
+ return node;
+}
+
+Node *makeName(Node *rule)
+{
+ Node *node= newNode(Name);
+ node->name.rule= rule;
+ node->name.variable= 0;
+ rule->rule.flags |= RuleUsed;
+ return node;
+}
+
+Node *makeDot(void)
+{
+ return newNode(Dot);
+}
+
+Node *makeCharacter(char *text)
+{
+ Node *node= newNode(Character);
+ node->character.value= strdup(text);
+ return node;
+}
+
+Node *makeString(char *text)
+{
+ Node *node= newNode(String);
+ node->string.value= strdup(text);
+ return node;
+}
+
+Node *makeClass(char *text)
+{
+ Node *node= newNode(Class);
+ node->cclass.value= (unsigned char *)strdup(text);
+ return node;
+}
+
+Node *makeAction(char *text)
+{
+ Node *node= newNode(Action);
+ char name[1024];
+ assert(thisRule);
+ sprintf(name, "_%d_%s", ++actionCount, thisRule->rule.name);
+ node->action.name= strdup(name);
+ node->action.text= strdup(text);
+ node->action.list= actions;
+ node->action.rule= thisRule;
+ actions= node;
+ {
+ char *ptr;
+ for (ptr= node->action.text; *ptr; ++ptr)
+ if ('$' == ptr[0] && '$' == ptr[1])
+ ptr[1]= ptr[0]= 'y';
+ }
+ return node;
+}
+
+Node *makePredicate(char *text)
+{
+ Node *node= newNode(Predicate);
+ node->predicate.text= strdup(text);
+ return node;
+}
+
+Node *makeAlternate(Node *e)
+{
+ if (Alternate != e->type)
+ {
+ Node *node= newNode(Alternate);
+ assert(e);
+ assert(!e->any.next);
+ node->alternate.first=
+ node->alternate.last= e;
+ return node;
+ }
+ return e;
+}
+
+Node *Alternate_append(Node *a, Node *e)
+{
+ assert(a);
+ a= makeAlternate(a);
+ assert(a->alternate.last);
+ assert(e);
+ a->alternate.last->any.next= e;
+ a->alternate.last= e;
+ return a;
+}
+
+Node *makeSequence(Node *e)
+{
+ if (Sequence != e->type)
+ {
+ Node *node= newNode(Sequence);
+ assert(e);
+ assert(!e->any.next);
+ node->sequence.first=
+ node->sequence.last= e;
+ return node;
+ }
+ return e;
+}
+
+Node *Sequence_append(Node *a, Node *e)
+{
+ assert(a);
+ a= makeSequence(a);
+ assert(a->sequence.last);
+ assert(e);
+ a->sequence.last->any.next= e;
+ a->sequence.last= e;
+ return a;
+}
+
+Node *makePeekFor(Node *e)
+{
+ Node *node= newNode(PeekFor);
+ node->peekFor.element= e;
+ return node;
+}
+
+Node *makePeekNot(Node *e)
+{
+ Node *node= newNode(PeekNot);
+ node->peekNot.element= e;
+ return node;
+}
+
+Node *makeQuery(Node *e)
+{
+ Node *node= newNode(Query);
+ node->query.element= e;
+ return node;
+}
+
+Node *makeStar(Node *e)
+{
+ Node *node= newNode(Star);
+ node->star.element= e;
+ return node;
+}
+
+Node *makePlus(Node *e)
+{
+ Node *node= newNode(Plus);
+ node->plus.element= e;
+ return node;
+}
+
+
+static Node *stack[1024];
+static Node **stackPointer= stack;
+
+
+#ifdef DEBUG
+static void dumpStack(void)
+{
+ Node **p;
+ for (p= stack + 1; p <= stackPointer; ++p)
+ {
+ fprintf(stderr, "### %ld\t", p - stack);
+ Node_print(*p);
+ fprintf(stderr, "\n");
+ }
+}
+#endif
+
+Node *push(Node *node)
+{
+ assert(node);
+ assert(stackPointer < stack + 1023);
+#ifdef DEBUG
+ dumpStack(); fprintf(stderr, " PUSH "); Node_print(node); fprintf(stderr, "\n");
+#endif
+ return *++stackPointer= node;
+}
+
+Node *top(void)
+{
+ assert(stackPointer > stack);
+ return *stackPointer;
+}
+
+Node *pop(void)
+{
+ assert(stackPointer > stack);
+#ifdef DEBUG
+ dumpStack(); fprintf(stderr, " POP\n");
+#endif
+ return *stackPointer--;
+}
+
+
+static void Node_fprint(FILE *stream, Node *node)
+{
+ assert(node);
+ switch (node->type)
+ {
+ case Rule: fprintf(stream, " %s", node->rule.name); break;
+ case Name: fprintf(stream, " %s", node->name.rule->rule.name); break;
+ case Dot: fprintf(stream, " ."); break;
+ case Character: fprintf(stream, " '%s'", node->character.value); break;
+ case String: fprintf(stream, " \"%s\"", node->string.value); break;
+ case Class: fprintf(stream, " [%s]", node->cclass.value); break;
+ case Action: fprintf(stream, " { %s }", node->action.text); break;
+ case Predicate: fprintf(stream, " ?{ %s }", node->action.text); break;
+
+ case Alternate: node= node->alternate.first;
+ fprintf(stream, " (");
+ Node_fprint(stream, node);
+ while ((node= node->any.next))
+ {
+ fprintf(stream, " |");
+ Node_fprint(stream, node);
+ }
+ fprintf(stream, " )");
+ break;
+
+ case Sequence: node= node->sequence.first;
+ fprintf(stream, " (");
+ Node_fprint(stream, node);
+ while ((node= node->any.next))
+ Node_fprint(stream, node);
+ fprintf(stream, " )");
+ break;
+
+ case PeekFor: fprintf(stream, "&"); Node_fprint(stream, node->query.element); break;
+ case PeekNot: fprintf(stream, "!"); Node_fprint(stream, node->query.element); break;
+ case Query: Node_fprint(stream, node->query.element); fprintf(stream, "?"); break;
+ case Star: Node_fprint(stream, node->query.element); fprintf(stream, "*"); break;
+ case Plus: Node_fprint(stream, node->query.element); fprintf(stream, "+"); break;
+ default:
+ fprintf(stream, "\nunknown node type %d\n", node->type);
+ exit(1);
+ }
+}
+
+void Node_print(Node *node) { Node_fprint(stderr, node); }
+
+static void Rule_fprint(FILE *stream, Node *node)
+{
+ assert(node);
+ assert(Rule == node->type);
+ fprintf(stream, "%s.%d =", node->rule.name, node->rule.id);
+ if (node->rule.expression)
+ Node_fprint(stream, node->rule.expression);