home: hub: minipeg

Download patch

ref: df19b6dc50e821ae5f7ff96961d866bcff61839e
author: Gregory Pakosz <gregory.pakosz@gmail.com>
date: Mon May 14 19:00:00 CDT 2007

imported peg-0.1.1

--- /dev/null
+++ b/.gitignore
@@ -1,0 +1,2 @@
+leg
+peg
--- /dev/null
+++ b/Makefile
@@ -1,0 +1,58 @@
+CFLAGS = -g -Wall $(OFLAGS) $(XFLAGS)
+OFLAGS = -O3 -DNDEBUG
+#OFLAGS = -pg
+
+OBJS = tree.o compile.o
+
+all : peg leg
+
+peg : peg.o $(OBJS)
+	$(CC) $(CFLAGS) -o $@-new peg.o $(OBJS)
+	mv $@-new $@
+
+leg : leg.o $(OBJS)
+	$(CC) $(CFLAGS) -o $@-new leg.o $(OBJS)
+	mv $@-new $@
+
+ROOT	=
+PREFIX	= /usr/local
+BINDIR	= $(ROOT)$(PREFIX)/bin
+
+install : $(BINDIR)/peg $(BINDIR)/leg
+
+$(BINDIR)/% : %
+	cp -p $< $@
+	strip $@
+
+uninstall : .FORCE
+	rm -f $(BINDIR)/peg
+	rm -f $(BINDIR)/leg
+
+peg.o : peg.c peg.peg-c
+
+%.peg-c : %.peg
+#	./peg -o $@ $<
+
+leg.o : leg.c
+
+leg.c : leg.leg
+#	./leg -o $@ $<
+
+check : peg .FORCE
+	./peg < peg.peg > peg.out
+	diff peg.peg-c peg.out
+	rm peg.out
+
+test examples : .FORCE
+	$(SHELL) -ec '(cd examples;  $(MAKE))'
+
+clean : .FORCE
+	rm -f *~ *.o *.peg.[cd] *.leg.[cd]
+	$(SHELL) -ec '(cd examples;  $(MAKE) $@)'
+
+spotless : clean .FORCE
+	rm -f peg
+	rm -f leg
+	$(SHELL) -ec '(cd examples;  $(MAKE) $@)'
+
+.FORCE :
--- /dev/null
+++ b/README.md
@@ -1,0 +1,30 @@
+# peg/leg &mdash; recursive-descent parser generators for C
+
+`peg` and `leg` are tools for generating recursive-descent parsers: programs that perform pattern matching on
+text.  They processes a Parsing Expression Grammar (PEG)[Ford 2004] to produce a program that recognises legal sentences of that grammar.
+
+`peg` processes PEGs written using the original syntax described by Ford.
+
+`leg` processes PEGs written using slightly different syntax and conventions that are intended to make it an attractive replacement for parsers built with `lex` and `yacc`.
+
+Unlike `lex` and `yacc`, `peg` and `leg` support unlimited backtracking, provide ordered choice as a means for disambiguation, and can combine scanning (lexical analysis) and parsing (syntactic analysis) into a single activity.
+
+`peg` is distributed under the MIT license.  It will not infect your project with a contagious <strike>license</strike> disease if you
+decide to modify it for your own use.  The parser generators that `peg` creates are unencumbered and you are free to use and/or
+distribute them any way you like.
+
+`peg`/`leg` is copyright (c) 2007 by Ian Piumarta.
+
+## References
+
+* `peg`/`leg` manual page: [peg.1.html][1]
+
+* [Ford 2004] Bryan Ford, [*Parsing Expression Grammars: A Recognition-Based Syntactic Foundation*][2]. ACM SIGPLAN Symposium on Principles of Programming Languages (POPL), 2004.
+
+[1]: http://piumarta.com/software/peg/peg.1.html "peg/leg manual"
+[2]: http://bford.info/pub/lang/peg "Parsing Expression Grammars: A Recognition-Based Syntactic Foundation"
+
+## Version history
+
+* **0.1.1** ([zip](peg/zipball/0.1.1), [tar.gz](peg/tarball/0.1.1)) &mdash; 2007-05-15  
+First public release.
--- /dev/null
+++ b/compile.c
@@ -1,0 +1,676 @@
+/* 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:31:16 by piumarta on emilia
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "version.h"
+#include "tree.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 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 ((c= *cclass++))
+    {
+      if ('-' == c && *cclass && prev >= 0)
+	{
+	  for (c= *cclass++;  prev <= c;  ++prev)
+	    set(bits, prev);
+	  prev= -1;
+	}
+      else if ('\\' == c && *cclass)
+	{
+	  switch (c= *cclass++)
+	    {
+	    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;
+	    }
+	  set(bits, prev= c);
+	}
+      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= yypos, yythunkpos%d= yythunkpos;", n, n); }
+static void restore(int n)	{ fprintf(output,     "  yypos= yypos%d; yythunkpos= 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()) goto l%d;", ko);
+      break;
+
+    case Name:
+      fprintf(output, "  if (!yy_%s()) goto l%d;", node->name.rule->rule.name, ko);
+      if (node->name.variable)
+	fprintf(output, "  yyDo(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('%s')) goto l%d;", node->string.value, ko);
+	else
+	  fprintf(output, "  if (!yymatchString(\"%s\")) goto l%d;", node->string.value, ko);
+      }
+      break;
+
+    case Class:
+      fprintf(output, "  if (!yymatchClass((unsigned char *)\"%s\")) goto l%d;", makeCharClass(node->cclass.value), ko);
+      break;
+
+    case Action:
+      fprintf(output, "  yyDo(yy%s, yybegin, yyend);", node->action.name);
+      break;
+
+    case Predicate:
+      fprintf(output, "  yyText(yybegin, yyend);  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 yyval[%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()\n{", node->rule.name);
+      if (!safe) save(0);
+      if (node->rule.variables)
+	fprintf(output, "  yyDo(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\", yybuf+yypos));", node->rule.name);
+      if (node->rule.variables)
+	fprintf(output, "  yyDo(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\", yybuf+yypos));", 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\
+";
+
+static char *preamble= "\
+#ifndef YY_VARIABLE\n\
+#define YY_VARIABLE(T)	static T\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 YYPARSE\n\
+#define YYPARSE		yyparse\n\
+#endif\n\
+#ifndef YYPARSEFROM\n\
+#define YYPARSEFROM	yyparsefrom\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	( yybegin= yypos, 1)\n\
+#endif\n\
+#ifndef YY_END\n\
+#define YY_END		( yyend= yypos, 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\
+\n\
+#ifndef YY_PART\n\
+\n\
+typedef void (*yyaction)(char *yytext, int yyleng);\n\
+typedef struct _yythunk { int begin, end;  yyaction  action;  struct _yythunk *next; } yythunk;\n\
+\n\
+YY_VARIABLE(char *   ) yybuf= 0;\n\
+YY_VARIABLE(int	     ) yybuflen= 0;\n\
+YY_VARIABLE(int	     ) yypos= 0;\n\
+YY_VARIABLE(int	     ) yylimit= 0;\n\
+YY_VARIABLE(char *   ) yytext= 0;\n\
+YY_VARIABLE(int	     ) yytextlen= 0;\n\
+YY_VARIABLE(int	     ) yybegin= 0;\n\
+YY_VARIABLE(int	     ) yyend= 0;\n\
+YY_VARIABLE(int	     ) yytextmax= 0;\n\
+YY_VARIABLE(yythunk *) yythunks= 0;\n\
+YY_VARIABLE(int	     ) yythunkslen= 0;\n\
+YY_VARIABLE(int      ) yythunkpos= 0;\n\
+YY_VARIABLE(YYSTYPE  ) yy;\n\
+YY_VARIABLE(YYSTYPE *) yyval= 0;\n\
+YY_VARIABLE(YYSTYPE *) yyvals= 0;\n\
+YY_VARIABLE(int      ) yyvalslen= 0;\n\
+\n\
+YY_LOCAL(int) yyrefill(void)\n\
+{\n\
+  int yyn;\n\
+  if (yybuflen - yypos < 512)\n\
+    {\n\
+      yybuflen *= 2;\n\
+      yybuf= realloc(yybuf, yybuflen);\n\
+    }\n\
+  YY_INPUT((yybuf + yypos), yyn, (yybuflen - yypos));\n\
+  if (!yyn) return 0;\n\
+  yylimit += yyn;\n\
+  return 1;\n\
+}\n\
+\n\
+YY_LOCAL(int) yymatchDot(void)\n\
+{\n\
+  if (yypos >= yylimit && !yyrefill()) return 0;\n\
+  ++yypos;\n\
+  return 1;\n\
+}\n\
+\n\
+YY_LOCAL(int) yymatchChar(int c)\n\
+{\n\
+  if (yypos >= yylimit && !yyrefill()) return 0;\n\
+  if (yybuf[yypos] == c)\n\
+    {\n\
+      ++yypos;\n\
+      yyprintf((stderr, \"  ok   yymatchChar(%c) @ %s\\n\", c, yybuf+yypos));\n\
+      return 1;\n\
+    }\n\
+  yyprintf((stderr, \"  fail yymatchChar(%c) @ %s\\n\", c, yybuf+yypos));\n\
+  return 0;\n\
+}\n\
+\n\
+YY_LOCAL(int) yymatchString(char *s)\n\
+{\n\
+  int yysav= yypos;\n\
+  while (*s)\n\
+    {\n\
+      if (yypos >= yylimit && !yyrefill()) return 0;\n\
+      if (yybuf[yypos] != *s)\n\
+        {\n\
+          yypos= yysav;\n\
+          return 0;\n\
+        }\n\
+      ++s;\n\
+      ++yypos;\n\
+    }\n\
+  return 1;\n\
+}\n\
+\n\
+YY_LOCAL(int) yymatchClass(unsigned char *bits)\n\
+{\n\
+  int c;\n\
+  if (yypos >= yylimit && !yyrefill()) return 0;\n\
+  c= yybuf[yypos];\n\
+  if (bits[c >> 3] & (1 << (c & 7)))\n\
+    {\n\
+      ++yypos;\n\
+      yyprintf((stderr, \"  ok   yymatchClass @ %s\\n\", yybuf+yypos));\n\
+      return 1;\n\
+    }\n\
+  yyprintf((stderr, \"  fail yymatchClass @ %s\\n\", yybuf+yypos));\n\
+  return 0;\n\
+}\n\
+\n\
+YY_LOCAL(void) yyDo(yyaction action, int begin, int end)\n\
+{\n\
+  if (yythunkpos >= yythunkslen)\n\
+    {\n\
+      yythunkslen *= 2;\n\
+      yythunks= realloc(yythunks, sizeof(yythunk) * yythunkslen);\n\
+    }\n\
+  yythunks[yythunkpos].begin=  begin;\n\
+  yythunks[yythunkpos].end=    end;\n\
+  yythunks[yythunkpos].action= action;\n\
+  ++yythunkpos;\n\
+}\n\
+\n\
+YY_LOCAL(int) yyText(int begin, int end)\n\
+{\n\
+  int yyleng= end - begin;\n\
+  if (yyleng <= 0)\n\
+    yyleng= 0;\n\
+  else\n\
+    {\n\
+      if (yytextlen < (yyleng - 1))\n\
+	{\n\
+	  yytextlen *= 2;\n\
+	  yytext= realloc(yytext, yytextlen);\n\
+	}\n\
+      memcpy(yytext, yybuf + begin, yyleng);\n\
+    }\n\
+  yytext[yyleng]= '\\0';\n\
+  return yyleng;\n\
+}\n\
+\n\
+YY_LOCAL(void) yyDone(void)\n\
+{\n\
+  int pos;\n\
+  for (pos= 0;  pos < yythunkpos;  ++pos)\n\
+    {\n\
+      yythunk *thunk= &yythunks[pos];\n\
+      int yyleng= thunk->end ? yyText(thunk->begin, thunk->end) : thunk->begin;\n\
+      yyprintf((stderr, \"DO [%d] %p %s\\n\", pos, thunk->action, yytext));\n\
+      thunk->action(yytext, yyleng);\n\
+    }\n\
+  yythunkpos= 0;\n\
+}\n\
+\n\
+YY_LOCAL(void) yyCommit()\n\
+{\n\
+  if ((yylimit -= yypos))\n\
+    {\n\
+      memmove(yybuf, yybuf + yypos, yylimit);\n\
+    }\n\
+  yybegin -= yypos;\n\
+  yyend -= yypos;\n\
+  yypos= yythunkpos= 0;\n\
+}\n\
+\n\
+YY_LOCAL(int) yyAccept(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();\n\
+      yyCommit();\n\
+    }\n\
+  return 1;\n\
+}\n\
+\n\
+YY_LOCAL(void) yyPush(char *text, int count)	{ yyval += count; }\n\
+YY_LOCAL(void) yyPop(char *text, int count)	{ yyval -= count; }\n\
+YY_LOCAL(void) yySet(char *text, int count)	{ yyval[count]= yy; }\n\
+\n\
+#endif /* YY_PART */\n\
+\n\
+#define	YYACCEPT	yyAccept(yythunkpos0)\n\
+\n\
+";
+
+static char *footer= "\n\
+\n\
+#ifndef YY_PART\n\
+\n\
+typedef int (*yyrule)();\n\
+\n\
+YY_PARSE(int) YYPARSEFROM(yyrule yystart)\n\
+{\n\
+  int yyok;\n\
+  if (!yybuflen)\n\
+    {\n\
+      yybuflen= 1024;\n\
+      yybuf= malloc(yybuflen);\n\
+      yytextlen= 1024;\n\
+      yytext= malloc(yytextlen);\n\
+      yythunkslen= 32;\n\
+      yythunks= malloc(sizeof(yythunk) * yythunkslen);\n\
+      yyvalslen= 32;\n\
+      yyvals= malloc(sizeof(YYSTYPE) * yyvalslen);\n\
+      yybegin= yyend= yypos= yylimit= yythunkpos= 0;\n\
+    }\n\
+  yybegin= yyend= yypos;\n\
+  yythunkpos= 0;\n\
+  yyval= yyvals;\n\
+  yyok= yystart();\n\
+  if (yyok) yyDone();\n\
+  yyCommit();\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\
+  (void)yytextmax;\n\
+}\n\
+\n\
+YY_PARSE(int) YYPARSE(void)\n\
+{\n\
+  return YYPARSEFROM(yy_%s);\n\
+}\n\
+\n\
+#endif\n\
+";
+
+void Rule_compile_c_header(void)
+{
+  fprintf(output, "/* A recursive-descent parser generated by peg %d.%d.%d */\n", PEG_MAJOR, PEG_MINOR, PEG_LEVEL);
+  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(); /* %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(char *yytext, int yyleng)\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);
+}
--- /dev/null
+++ b/examples/Makefile
@@ -1,0 +1,79 @@
+EXAMPLES = test rule accept wc dc dcv calc basic
+
+CFLAGS = -g -O3
+
+DIFF = diff
+TEE = cat >
+
+all : $(EXAMPLES)
+
+test : .FORCE
+	../peg -o test.peg.c test.peg
+	$(CC) $(CFLAGS) -o test test.c
+	echo 'ab.ac.ad.ae.afg.afh.afg.afh.afi.afj.' | ./$@ | $(TEE) $@.out
+	$(DIFF) $@.ref $@.out
+	rm -f $@.out
+	@echo
+
+rule : .FORCE
+	../peg -o rule.peg.c rule.peg
+	$(CC) $(CFLAGS) -o rule rule.c
+	echo 'abcbcdabcbcdabcbcdabcbcd' | ./$@ | $(TEE) $@.out
+	$(DIFF) $@.ref $@.out
+	rm -f $@.out
+	@echo
+
+accept : .FORCE
+	../peg -o accept.peg.c accept.peg
+	$(CC) $(CFLAGS) -o accept accept.c
+	echo 'abcbcdabcbcdabcbcdabcbcd' | ./$@ | $(TEE) $@.out
+	$(DIFF) $@.ref $@.out
+	rm -f $@.out
+	@echo
+
+wc : .FORCE
+	../leg -o wc.leg.c wc.leg
+	$(CC) $(CFLAGS) -o wc wc.leg.c
+	cat wc.leg | ./$@ | $(TEE) $@.out
+	$(DIFF) $@.ref $@.out
+	rm -f $@.out
+	@echo
+
+dc : .FORCE
+	../peg -o dc.peg.c dc.peg
+	$(CC) $(CFLAGS) -o dc dc.c
+	echo '  2  *3 *(3+ 4) ' | ./dc | $(TEE) $@.out
+	$(DIFF) $@.ref $@.out
+	rm -f $@.out
+	@echo
+
+dcv : .FORCE
+	../peg -o dcv.peg.c dcv.peg
+	$(CC) $(CFLAGS) -o dcv dcv.c
+	echo 'a = 6;  b = 7;  a * b' | ./dcv | $(TEE) $@.out
+	$(DIFF) $@.ref $@.out
+	rm -f $@.out
+	@echo
+
+calc : .FORCE
+	../leg -o calc.leg.c calc.leg
+	$(CC) $(CFLAGS) -o calc calc.leg.c
+	echo 'a = 6;  b = 7;  a * b' | ./calc | $(TEE) $@.out
+	$(DIFF) $@.ref $@.out
+	rm -f $@.out
+	@echo
+
+basic : .FORCE
+	../leg -o basic.leg.c basic.leg
+	$(CC) $(CFLAGS) -o basic basic.leg.c
+	( echo 'load "test"'; echo "run" ) | ./basic | $(TEE) $@.out
+	$(DIFF) $@.ref $@.out
+	rm -f $@.out
+	@echo
+
+clean : .FORCE
+	rm -f *~ *.o *.[pl]eg.[cd] $(EXAMPLES)
+
+spotless : clean
+
+.FORCE :
--- /dev/null
+++ b/examples/accept.c
@@ -1,0 +1,11 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "accept.peg.c"
+
+int main()
+{
+  while (yyparse());
+
+  return 0;
+}
--- /dev/null
+++ b/examples/accept.peg
@@ -1,0 +1,8 @@
+start	<- abcd+
+
+abcd	<- 'a' { printf("A %d\n", yypos); } bc { printf("ABC %d\n", yypos); } &{YYACCEPT}
+	 / 'b' { printf("B %d\n", yypos); } cd { printf("BCD %d\n", yypos); } &{YYACCEPT}
+
+bc	<- 'b' { printf("B %d\n", yypos); } 'c' { printf("C %d\n", yypos); }
+
+cd	<- 'c' { printf("C %d\n", yypos); } 'd' { printf("D %d\n", yypos); }
--- /dev/null
+++ b/examples/accept.ref
@@ -1,0 +1,32 @@
+A 3
+B 3
+C 3
+ABC 3
+B 3
+C 3
+D 3
+BCD 3
+A 3
+B 3
+C 3
+ABC 3
+B 3
+C 3
+D 3
+BCD 3
+A 3
+B 3
+C 3
+ABC 3
+B 3
+C 3
+D 3
+BCD 3
+A 3
+B 3
+C 3
+ABC 3
+B 3
+C 3
+D 3
+BCD 3
--- /dev/null
+++ b/examples/basic.leg
@@ -1,0 +1,360 @@
+# A 'syntax-directed interpreter' (all execution is a side-effect of parsing).
+# Inspired by Dennis Allison's original Tiny BASIC grammar, circa 1975.
+# 
+# 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-14 11:32:49 by piumarta on emilia
+
+%{
+# include <stdio.h>
+
+  typedef struct line line;
+
+  struct line
+  {
+    int	  number;
+    int	  length;
+    char *text;
+  };
+
+  line *lines= 0;
+  int   numLines= 0;
+  int   pc= -1, epc= -1;
+  int   batch= 0;
+
+  int getline(char *buf, int max);
+
+# define min(x, y) ((x) < (y) ? (x) : (y))
+
+# define YY_INPUT(buf, result, max_size)	\
+  {						\
+    if ((pc >= 0) && (pc < numLines))		\
+      {						\
+        line *linep= lines+pc++;		\
+        result= min(max_size, linep->length);	\
+        memcpy(buf, linep->text, result);	\
+      }						\
+    else					\
+      result= getline(buf, max_size);		\
+  }
+
+  union value {
+    int		  number;
+    char	 *string;
+    int		(*binop)(int lhs, int rhs);
+  };
+
+# define YYSTYPE union value
+
+  int variables[26];
+
+  void accept(int number, char *line);
+
+  void save(char *name);
+  void load(char *name);
+  void type(char *name);
+
+  int lessThan(int lhs, int rhs)	{ return lhs <  rhs; }
+  int lessEqual(int lhs, int rhs)	{ return lhs <= rhs; }
+  int notEqual(int lhs, int rhs)	{ return lhs != rhs; }
+  int equalTo(int lhs, int rhs)		{ return lhs == rhs; }
+  int greaterEqual(int lhs, int rhs)	{ return lhs >= rhs; }
+  int greaterThan(int lhs, int rhs)	{ return lhs >  rhs; }
+
+  int input(void);
+
+  int stack[1024], sp= 0;
+
+  char *help;
+
+  void error(char *fmt, ...);
+%}
+
+line = - s:statement CR
+|      - n:number < ( !CR . )* CR >			{ accept(n.number, yytext); }
+|      - CR
+|      - < ( !CR . )* CR >				{ epc= pc;  error("syntax error"); }
+|      - !.						{ exit(0); }
+
+statement = 'print'- expr-list
+|           'if'- e1:expression r:relop e2:expression	{ if (!r.binop(e1.number, e2.number)) yythunkpos= 0; }
+		'then'- statement
+|           'goto'- e:expression			{ epc= pc;  if ((pc= findLine(e.number, 0)) < 0) error("no such line"); }
+|           'input'- var-list
+|           'let'- v:var EQUAL e:expression		{ variables[v.number]= e.number; }
+|           'gosub'- e:expression			{ epc= pc;  if (sp < 1024) stack[sp++]= pc, pc= findLine(e.number); else error("too many gosubs");
+							  if (pc < 0) error("no such line"); }
+|           'return'-					{ epc= pc;  if ((pc= sp ? stack[--sp] : -1) < 0) error("no gosub"); }
+|           'clear'-					{ while (numLines) accept(lines->number, "\n"); }
+|           'list'-					{ int i;  for (i= 0;  i < numLines;  ++i) printf("%5d %s", lines[i].number, lines[i].text); }
+|           'run'- s:string				{ load(s.string);  pc= 0; }
+|           'run'-					{ pc= 0; }
+|           'end'-					{ pc= -1;  if (batch) exit(0); }
+|           'rem'- ( !CR . )*
+|           ('bye'|'quit'|'exit')-			{ exit(0); }
+|           'save'- s:string				{ save(s.string); }
+|           'load'- s:string				{ load(s.string); }
+|           'type'- s:string				{ type(s.string); }
+|           'dir'-					{ system("ls *.bas"); }
+|           'help'-					{ fprintf(stderr, "%s", help); }
+
+expr-list = ( e:string					{ printf("%s", e.string); }
+            | e:expression				{ printf("%d", e.number); }
+            )? ( COMMA ( e:string			{ printf("%s", e.string); }
+                       | e:expression			{ printf("%d", e.number); }
+                       )
+               )* ( COMMA
+	          | !COMMA				{ printf("\n"); }
+		  )
+
+var-list = v:var					{ variables[v.number]= input(); }
+           ( COMMA v:var				{ variables[v.number]= input(); }
+           )*
+
+expression = ( PLUS? l:term
+             | MINUS l:term				{ l.number = -l.number }
+             ) ( PLUS  r:term				{ l.number += r.number }
+               | MINUS r:term				{ l.number -= r.number }
+               )*					{ $$.number = l.number }
+
+term = l:factor ( STAR  r:factor			{ l.number *= r.number }
+                | SLASH r:factor			{ l.number /= r.number }
+                )*					{ $$.number = l.number }
+
+factor = v:var						{ $$.number = variables[v.number] }
+|        n:number
+|        OPEN expression CLOSE
+
+var = < [a-z] > -					{ $$.number = yytext[0] - 'a' }
+
+number = < digit+ > -					{ $$.number = atoi(yytext); }
+
+digit = [0-9]
+
+string = '"' < [^\"]* > '"' -				{ $$.string = yytext; }
+
+relop = '<=' -						{ $$.binop= lessEqual; }
+|       '<>' -						{ $$.binop= notEqual; }
+|       '<'  -						{ $$.binop= lessThan; }
+|       '>=' -						{ $$.binop= greaterEqual; }
+|       '>'  -						{ $$.binop= greaterThan; }
+|       '='  -						{ $$.binop= equalTo; }
+
+EQUAL  = '=' -  CLOSE  = ')' -  OPEN   = '(' -
+SLASH  = '/' -  STAR   = '*' -  MINUS  = '-' -
+PLUS   = '+' -  COMMA  = ',' -
+
+- = [ \t]*
+
+CR = '\n' | '\r' | '\r\n'
+
+%%
+
+#include <unistd.h>
+#include <stdarg.h>
+
+char *help=
+  "print <num>|<string> [, <num>|<string> ...] [,]\n"
+  "if <expr> <|<=|<>|=|>=|> <expr> then <stmt>\n"
+  "input <var> [, <var> ...]     let <var> = <expr>\n"
+  "goto <expr>                   gosub <expr>\n"
+  "end                           return\n"
+  "list                          clear\n"
+  "run [\"filename\"]              rem <comment...>\n"
+  "dir                           type \"filename\"\n"
+  "save \"filename\"               load \"filename\"\n"
+  "bye|quit|exit                 help\n"
+  ;
+
+void error(char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  if (epc > 0)
+    fprintf(stderr, "\nline %d: %s", lines[epc-1].number, lines[epc-1].text);
+  else
+    fprintf(stderr, "\n");
+  vfprintf(stderr, fmt, ap);
+  fprintf(stderr, "\n");
+  va_end(ap);
+  epc= pc= -1;
+}
+
+#ifdef USE_READLINE
+# include <readline/readline.h>
+# include <readline/history.h>
+#endif
+
+int getline(char *buf, int max)
+{
+  pc= -1;
+  if (batch) exit(0);
+  if (isatty(fileno(stdin)))
+    {
+#    ifdef USE_READLINE
+      char *line= readline(">");
+      if (line)
+	{
+	  int len= strlen(line);
+	  if (len >= max) len= max - 1;
+	  strncpy(buf, line, len);
+	  (buf)[len]= '\n';
+	  add_history(line);
+	  free(line);
+	  return len + 1;
+	}
+      else
+	{
+	  printf("\n");
+	  return 0;
+	}
+#    endif
+      putchar('>');
+      fflush(stdout);
+    }
+  return fgets(buf, max, stdin) ? strlen(buf) : 0;
+}
+
+int maxLines= 0;
+
+int findLine(int n, int create)
+{
+  int lo= 0, hi= numLines - 1;
+  while (lo <= hi)
+    {
+      int mid= (lo + hi) / 2, lno= lines[mid].number;
+      if (lno > n)
+	hi= mid - 1;
+      else if (lno < n)
+	lo= mid + 1;
+      else
+	return mid;
+    }
+  if (create)
+    {
+      if (numLines == maxLines)
+	{
+	  maxLines *= 2;
+	  lines= realloc(lines, sizeof(line) * maxLines);
+	}
+      if (lo < numLines)
+	memmove(lines + lo + 1, lines + lo, sizeof(line) * (numLines - lo));
+      ++numLines;
+      lines[lo].number= n;
+      lines[lo].text= 0;
+      return lo;
+    }
+  return -1;
+}
+
+void accept(int n, char *s)
+{
+  if (s[0] < 32)	/* delete */
+    {
+      int lno= findLine(n, 0);
+      if (lno >= 0)
+	{
+	  if (lno < numLines - 1)
+	    memmove(lines + lno, lines + lno + 1, sizeof(line) * (numLines - lno - 1));
+	  --numLines;
+	}
+    }
+  else			/* insert */
+    {
+      int lno= findLine(n, 1);
+      if (lines[lno].text) free(lines[lno].text);
+      lines[lno].length= strlen(s);
+      lines[lno].text= strdup(s);
+    }
+}
+
+char *extend(char *name)
+{
+  static char path[1024];
+  int len= strlen(name);
+  sprintf(path, "%s%s", name, (((len > 4) && !strcasecmp(".bas", name + len - 4)) ? "" : ".bas"));
+  return path;
+}
+
+void save(char *name)
+{
+  FILE *f= fopen(name= extend(name), "w");
+  if (!f)
+    perror(name);
+  else
+    {
+      int i;
+      for (i= 0;  i < numLines;  ++i)
+	fprintf(f, "%d %s", lines[i].number, lines[i].text);
+      fclose(f);
+    }
+}
+
+void load(char *name)
+{
+  FILE *f= fopen(name= extend(name), "r");
+  if (!f)
+    perror(name);
+  else
+    {
+      int  lineNumber;
+      char lineText[1024];
+      while ((1 == fscanf(f, " %d ", &lineNumber)) && fgets(lineText, sizeof(lineText), f))
+	accept(lineNumber, lineText);
+      fclose(f);
+    }
+}
+
+void type(char *name)
+{
+  FILE *f= fopen(name= extend(name), "r");
+  if (!f)
+    perror(name);
+  else
+    {
+      int  c, d;
+      while ((c= getc(f)) >= 0)
+	putchar(d= c);
+      fclose(f);
+      if ('\n' != d && '\r' != d) putchar('\n');
+    }
+}
+
+int input(void)
+{
+  char line[32];
+  fgets(line, sizeof(line), stdin);
+  return atoi(line);
+}
+
+int main(int argc, char **argv)
+{
+  lines= malloc(sizeof(line) * (maxLines= 32));
+  numLines= 0;
+
+  if (argc > 1)
+    {
+      batch= 1;
+      while (argc-- > 1)
+	load(*++argv);
+      pc= 0;
+    }
+
+  while (!feof(stdin))
+    yyparse();
+
+  return 0;
+}
--- /dev/null
+++ b/examples/basic.ref
@@ -1,0 +1,10 @@
+ 1
+ 2 4
+ 3 6 9
+ 4 8 12 16
+ 5 10 15 20 25
+ 6 12 18 24 30 36
+ 7 14 21 28 35 42 49
+ 8 16 24 32 40 48 56 64
+ 9 18 27 36 45 54 63 72 81
+ 10 20 30 40 50 60 70 80 90 100
--- /dev/null
+++ b/examples/bench.bas
@@ -1,0 +1,8 @@
+100 let n=100000
+120 let m=0
+110 let s=0
+130 let m=m+1
+140 let s=s+m
+150 if m<n then goto 130
+160 print "interpreted ", n*3, " lines of code; answer is ", s
+170 end
--- /dev/null
+++ b/examples/calc.leg
@@ -1,0 +1,46 @@
+%{
+#include <stdio.h>
+int vars[26];
+%}
+
+Stmt	= - e:Expr EOL			{ printf("%d\n", e); }
+	| ( !EOL . )* EOL		{ printf("error\n"); }
+
+Expr	= i:ID ASSIGN s:Sum		{ $$= vars[i]= s; }
+	| s:Sum				{ $$= s; }
+
+Sum	= l:Product
+		( PLUS  r:Product	{ l += r; }
+		| MINUS r:Product	{ l -= r; }
+		)*			{ $$= l; }
+
+Product	= l:Value
+		( TIMES  r:Value	{ l *= r; }
+		| DIVIDE r:Value	{ l /= r; }
+		)*			{ $$= l; }
+
+Value	= i:NUMBER			{ $$= atoi(yytext); }
+	| i:ID !ASSIGN			{ $$= vars[i]; }
+	| OPEN i:Expr CLOSE		{ $$= i; }
+
+NUMBER	= < [0-9]+ >	-		{ $$= atoi(yytext); }
+ID	= < [a-z]  >	-		{ $$= yytext[0] - 'a'; }
+ASSIGN	= '='		-
+PLUS	= '+'		-
+MINUS	= '-'		-
+TIMES	= '*'		-
+DIVIDE	= '/'		-
+OPEN	= '('		-
+CLOSE	= ')'		-
+
+-	= [ \t]*
+EOL	= '\n' | '\r\n' | '\r' | ';'
+
+%%
+
+int main()
+{
+  while (yyparse());
+
+  return 0;
+}
--- /dev/null
+++ b/examples/calc.ref
@@ -1,0 +1,3 @@
+6
+7
+42
--- /dev/null
+++ b/examples/dc.c
@@ -1,0 +1,17 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int stack[1024];
+int stackp= -1;
+
+int push(int n)	{ return stack[++stackp]= n; }
+int pop(void)	{ return stack[stackp--]; }
+
+#include "dc.peg.c"
+
+int main()
+{
+  while (yyparse());
+
+  return 0;
+}
--- /dev/null
+++ b/examples/dc.peg
@@ -1,0 +1,27 @@
+# Grammar
+
+Expr	<- SPACE Sum EOL		{ printf("%d\n", pop()); }
+	 / (!EOL .)* EOL		{ printf("error\n"); }
+
+Sum	<- Product ( PLUS  Product	{ int r= pop(), l= pop();  push(l + r); }
+		   / MINUS Product	{ int r= pop(), l= pop();  push(l - r); }
+		   )*
+
+Product	<- Value ( TIMES  Value		{ int r= pop(), l= pop();  push(l * r); }
+                 / DIVIDE Value		{ int r= pop(), l= pop();  push(l / r); }
+		 )*
+
+Value	<- NUMBER			{ push(atoi(yytext)); }
+	 / OPEN Sum CLOSE
+
+# Lexemes
+
+NUMBER	<- < [0-9]+ > SPACE
+PLUS	<- '+' SPACE
+MINUS	<- '-' SPACE
+TIMES	<- '*' SPACE
+DIVIDE	<- '/' SPACE
+OPEN	<- '(' SPACE
+CLOSE	<- ')' SPACE
+SPACE	<- [ \t]*
+EOL	<- '\n' / '\r\n' / '\r'
--- /dev/null
+++ b/examples/dc.ref
@@ -1,0 +1,1 @@
+42
--- /dev/null
+++ b/examples/dcv.c
@@ -1,0 +1,20 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int stack[1024];
+int stackp= -1;
+int var= 0;
+int vars[26];
+
+int push(int n)	{ return stack[++stackp]= n; }
+int pop(void)	{ return stack[stackp--]; }
+int top(void)	{ return stack[stackp]; }
+
+#include "dcv.peg.c"
+
+int main()
+{
+  while (yyparse());
+
+  return 0;
+}
--- /dev/null
+++ b/examples/dcv.peg
@@ -1,0 +1,34 @@
+# Grammar
+
+Stmt	<- SPACE Expr EOL			{ printf("%d\n", pop()); }
+	 / (!EOL .)* EOL			{ printf("error\n"); }
+
+Expr	<- ID { var= yytext[0] } ASSIGN Sum	{ vars[var - 'a']= top(); }
+	 / Sum
+
+Sum	<- Product ( PLUS  Product		{ int r= pop(), l= pop();  push(l + r); }
+		   / MINUS Product		{ int r= pop(), l= pop();  push(l - r); }
+		   )*
+
+Product	<- Value ( TIMES  Value			{ int r= pop(), l= pop();  push(l * r); }
+                 / DIVIDE Value			{ int r= pop(), l= pop();  push(l / r); }
+		 )*
+
+Value	<- NUMBER				{ push(atoi(yytext)); }
+	 / < ID > !ASSIGN			{ push(vars[yytext[0] - 'a']); }
+	 / OPEN Expr CLOSE
+
+# Lexemes
+
+NUMBER	<- < [0-9]+ >	SPACE
+ID	<- < [a-z]  >	SPACE
+ASSIGN	<- '='		SPACE
+PLUS	<- '+'		SPACE
+MINUS	<- '-'		SPACE
+TIMES	<- '*'		SPACE
+DIVIDE	<- '/'		SPACE
+OPEN	<- '('		SPACE
+CLOSE	<- ')'		SPACE
+
+SPACE	<- [ \t]*
+EOL	<- '\n' / '\r\n' / '\r' / ';'
--- /dev/null
+++ b/examples/dcv.ref
@@ -1,0 +1,3 @@
+6
+7
+42
--- /dev/null
+++ b/examples/fibonacci.bas
@@ -1,0 +1,17 @@
+100 let n=32
+110 gosub 200
+120 print "fibonacci(",n,") = ", m
+130 end
+
+200 let c=n
+210 let b=1
+220 if c<2 then goto 400
+230 let c=c-1
+240 let a=1
+300 let c=c-1
+310 let d=a+b
+320 let a=b
+330 let b=d+1
+340 if c<>0 then goto 300
+400 let m=b
+410 return
--- /dev/null
+++ b/examples/left.c
@@ -1,0 +1,17 @@
+#include <stdio.h>
+
+#define YY_INPUT(buf, result, max)			\
+{							\
+  int c= getchar();					\
+  result= (EOF == c) ? 0 : (*(buf)= c, 1);		\
+  if (EOF != c) printf("<%c>\n", c);			\
+}
+
+#include "left.peg.c"
+
+int main()
+{
+  printf(yyparse() ? "success\n" : "failure\n");
+
+  return 0;
+}
--- /dev/null
+++ b/examples/left.peg
@@ -1,0 +1,3 @@
+# Grammar
+
+S	<- (S 'a' / 'a') !'a'
--- /dev/null
+++ b/examples/rule.c
@@ -1,0 +1,11 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "rule.peg.c"
+
+int main()
+{
+  while (yyparse());
+
+  return 0;
+}
--- /dev/null
+++ b/examples/rule.peg
@@ -1,0 +1,8 @@
+start	<- abcd+
+
+abcd	<- 'a' { printf("A %d\n", yypos); } bc { printf("ABC %d\n", yypos); }
+	 / 'b' { printf("B %d\n", yypos); } cd { printf("BCD %d\n", yypos); }
+
+bc	<- 'b' { printf("B %d\n", yypos); } 'c' { printf("C %d\n", yypos); }
+
+cd	<- 'c' { printf("C %d\n", yypos); } 'd' { printf("D %d\n", yypos); }
--- /dev/null
+++ b/examples/rule.ref
@@ -1,0 +1,32 @@
+A 24
+B 24
+C 24
+ABC 24
+B 24
+C 24
+D 24
+BCD 24
+A 24
+B 24
+C 24
+ABC 24
+B 24
+C 24
+D 24
+BCD 24
+A 24
+B 24
+C 24
+ABC 24
+B 24
+C 24
+D 24
+BCD 24
+A 24
+B 24
+C 24
+ABC 24
+B 24
+C 24
+D 24
+BCD 24
--- /dev/null
+++ b/examples/test.bas
@@ -1,0 +1,12 @@
+10 let i=1
+20 gosub 100
+30 let i=i+1
+40 if i<=10 then goto 20
+50 end
+
+100 let j=1
+110 print " ", i*j,
+120 let j=j+1
+130 if j<=i then goto 110
+140 print
+150 return
--- /dev/null
+++ b/examples/test.c
@@ -1,0 +1,8 @@
+#include <stdio.h>
+#include "test.peg.c"
+
+int main()
+{
+  while (yyparse());
+  return 0;
+}
--- /dev/null
+++ b/examples/test.peg
@@ -1,0 +1,13 @@
+start	<- body '.' { printf(".\n"); }
+
+body	<- 'a' { printf("a1 "); }   'b'  { printf("ab1 "); }
+
+	 / 'a' { printf("a2 "); }   'c'  { printf("ac2 "); }
+
+	 / 'a' { printf("a3 "); } ( 'd'  { printf("ad3 "); } / 'e'  { printf("ae3 "); } )
+
+	 / 'a' { printf("a4 "); } ( 'f'  { printf("af4 "); }   'g'  { printf("afg4 "); }
+				  / 'f'  { printf("af5 "); }   'h'  { printf("afh5 "); } )
+
+	 / 'a' { printf("a6 "); } ( 'f' &{ printf("af6 ")  }   'i' &{ printf("afi6 ") }
+				  / 'f' &{ printf("af7 ")  }   'j' &{ printf("afj7 ") } )
--- /dev/null
+++ b/examples/test.ref
@@ -1,0 +1,10 @@
+a1 ab1 .
+a2 ac2 .
+a3 ad3 .
+a3 ae3 .
+a4 af4 afg4 .
+a4 af5 afh5 .
+a4 af4 afg4 .
+a4 af5 afh5 .
+af6 afi6 a6 .
+af6 af7 afj7 a6 .
--- /dev/null
+++ b/examples/username.leg
@@ -1,0 +1,14 @@
+%{
+#include <unistd.h>
+%}
+
+start =	"username"	{ printf("%s", getlogin()); }
+|	< . >		{ putchar(yytext[0]); }
+
+%%
+
+int main()
+{
+  while (yyparse());
+  return 0;
+}
--- /dev/null
+++ b/examples/wc.leg
@@ -1,0 +1,22 @@
+%{
+#include <stdio.h>
+int lines= 0, words= 0, chars= 0;
+%}
+
+start	= (line | word | char)
+
+line	= < (( '\n' '\r'* ) | ( '\r' '\n'* )) >	{ lines++;  chars += yyleng; }
+word	= < [a-zA-Z]+ >				{ words++;  chars += yyleng;  printf("<%s>\n", yytext); }
+char	= .					{ chars++; }
+
+%%
+
+int main()
+{
+  while (yyparse())
+    ;
+  printf("%d lines\n", lines);
+  printf("%d chars\n", chars);
+  printf("%d words\n", words);
+  return 0;
+}
--- /dev/null
+++ b/examples/wc.ref
@@ -1,0 +1,55 @@
+<include>
+<stdio>
+<h>
+<int>
+<lines>
+<words>
+<chars>
+<start>
+<line>
+<word>
+<char>
+<line>
+<n>
+<r>
+<r>
+<n>
+<lines>
+<chars>
+<yyleng>
+<word>
+<a>
+<zA>
+<Z>
+<words>
+<chars>
+<yyleng>
+<printf>
+<s>
+<n>
+<yytext>
+<char>
+<chars>
+<int>
+<main>
+<while>
+<yyparse>
+<printf>
+<d>
+<lines>
+<n>
+<lines>
+<printf>
+<d>
+<chars>
+<n>
+<chars>
+<printf>
+<d>
+<words>
+<n>
+<words>
+<return>
+22 lines
+425 chars
+52 words
--- /dev/null
+++ b/leg.c
@@ -1,0 +1,1058 @@
+/* A recursive-descent parser generated by peg 0.1.0 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define YYRULECOUNT 35
+
+# include "tree.h"
+# include "version.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(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_VARIABLE
+#define YY_VARIABLE(T)	static T
+#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 YYPARSE
+#define YYPARSE		yyparse
+#endif
+#ifndef YYPARSEFROM
+#define YYPARSEFROM	yyparsefrom
+#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	( yybegin= yypos, 1)
+#endif
+#ifndef YY_END
+#define YY_END		( yyend= yypos, 1)
+#endif
+#ifdef YY_DEBUG
+# define yyprintf(args)	fprintf args
+#else
+# define yyprintf(args)
+#endif
+#ifndef YYSTYPE
+#define YYSTYPE	int
+#endif
+
+#ifndef YY_PART
+
+typedef void (*yyaction)(char *yytext, int yyleng);
+typedef struct _yythunk { int begin, end;  yyaction  action;  struct _yythunk *next; } yythunk;
+
+YY_VARIABLE(char *   ) yybuf= 0;
+YY_VARIABLE(int	     ) yybuflen= 0;
+YY_VARIABLE(int	     ) yypos= 0;
+YY_VARIABLE(int	     ) yylimit= 0;
+YY_VARIABLE(char *   ) yytext= 0;
+YY_VARIABLE(int	     ) yytextlen= 0;
+YY_VARIABLE(int	     ) yybegin= 0;
+YY_VARIABLE(int	     ) yyend= 0;
+YY_VARIABLE(int	     ) yytextmax= 0;
+YY_VARIABLE(yythunk *) yythunks= 0;
+YY_VARIABLE(int	     ) yythunkslen= 0;
+YY_VARIABLE(int      ) yythunkpos= 0;
+YY_VARIABLE(YYSTYPE  ) yy;
+YY_VARIABLE(YYSTYPE *) yyval= 0;
+YY_VARIABLE(YYSTYPE *) yyvals= 0;
+YY_VARIABLE(int      ) yyvalslen= 0;
+
+YY_LOCAL(int) yyrefill(void)
+{
+  int yyn;
+  if (yybuflen - yypos < 512)
+    {
+      yybuflen *= 2;
+      yybuf= realloc(yybuf, yybuflen);
+    }
+  YY_INPUT((yybuf + yypos), yyn, (yybuflen - yypos));
+  if (!yyn) return 0;
+  yylimit += yyn;
+  return 1;
+}
+
+YY_LOCAL(int) yymatchDot(void)
+{
+  if (yypos >= yylimit && !yyrefill()) return 0;
+  ++yypos;
+  return 1;
+}
+
+YY_LOCAL(int) yymatchChar(int c)
+{
+  if (yypos >= yylimit && !yyrefill()) return 0;
+  if (yybuf[yypos] == c)
+    {
+      ++yypos;
+      yyprintf((stderr, "  ok   yymatchChar(%c) @ %s\n", c, yybuf+yypos));
+      return 1;
+    }
+  yyprintf((stderr, "  fail yymatchChar(%c) @ %s\n", c, yybuf+yypos));
+  return 0;
+}
+
+YY_LOCAL(int) yymatchString(char *s)
+{
+  int yysav= yypos;
+  while (*s)
+    {
+      if (yypos >= yylimit && !yyrefill()) return 0;
+      if (yybuf[yypos] != *s)
+        {
+          yypos= yysav;
+          return 0;
+        }
+      ++s;
+      ++yypos;
+    }
+  return 1;
+}
+
+YY_LOCAL(int) yymatchClass(unsigned char *bits)
+{
+  int c;
+  if (yypos >= yylimit && !yyrefill()) return 0;
+  c= yybuf[yypos];
+  if (bits[c >> 3] & (1 << (c & 7)))
+    {
+      ++yypos;
+      yyprintf((stderr, "  ok   yymatchClass @ %s\n", yybuf+yypos));
+      return 1;
+    }
+  yyprintf((stderr, "  fail yymatchClass @ %s\n", yybuf+yypos));
+  return 0;
+}
+
+YY_LOCAL(void) yyDo(yyaction action, int begin, int end)
+{
+  if (yythunkpos >= yythunkslen)
+    {
+      yythunkslen *= 2;
+      yythunks= realloc(yythunks, sizeof(yythunk) * yythunkslen);
+    }
+  yythunks[yythunkpos].begin=  begin;
+  yythunks[yythunkpos].end=    end;
+  yythunks[yythunkpos].action= action;
+  ++yythunkpos;
+}
+
+YY_LOCAL(int) yyText(int begin, int end)
+{
+  int yyleng= end - begin;
+  if (yyleng <= 0)
+    yyleng= 0;
+  else
+    {
+      if (yytextlen < (yyleng - 1))
+	{
+	  yytextlen *= 2;
+	  yytext= realloc(yytext, yytextlen);
+	}
+      memcpy(yytext, yybuf + begin, yyleng);
+    }
+  yytext[yyleng]= '\0';
+  return yyleng;
+}
+
+YY_LOCAL(void) yyDone(void)
+{
+  int pos;
+  for (pos= 0;  pos < yythunkpos;  ++pos)
+    {
+      yythunk *thunk= &yythunks[pos];
+      int yyleng= thunk->end ? yyText(thunk->begin, thunk->end) : thunk->begin;
+      yyprintf((stderr, "DO [%d] %p %s\n", pos, thunk->action, yytext));
+      thunk->action(yytext, yyleng);
+    }
+  yythunkpos= 0;
+}
+
+YY_LOCAL(void) yyCommit()
+{
+  if ((yylimit -= yypos))
+    {
+      memmove(yybuf, yybuf + yypos, yylimit);
+    }
+  yybegin -= yypos;
+  yyend -= yypos;
+  yypos= yythunkpos= 0;
+}
+
+YY_LOCAL(int) yyAccept(int tp0)
+{
+  if (tp0)
+    {
+      fprintf(stderr, "accept denied at %d\n", tp0);
+      return 0;
+    }
+  else
+    {
+      yyDone();
+      yyCommit();
+    }
+  return 1;
+}
+
+YY_LOCAL(void) yyPush(char *text, int count)	{ yyval += count; }
+YY_LOCAL(void) yyPop(char *text, int count)	{ yyval -= count; }
+YY_LOCAL(void) yySet(char *text, int count)	{ yyval[count]= yy; }
+
+#endif /* YY_PART */
+
+#define	YYACCEPT	yyAccept(yythunkpos0)
+
+YY_RULE(int) yy_end_of_line(); /* 35 */
+YY_RULE(int) yy_comment(); /* 34 */
+YY_RULE(int) yy_space(); /* 33 */
+YY_RULE(int) yy_range(); /* 32 */
+YY_RULE(int) yy_char(); /* 31 */
+YY_RULE(int) yy_END(); /* 30 */
+YY_RULE(int) yy_BEGIN(); /* 29 */
+YY_RULE(int) yy_DOT(); /* 28 */
+YY_RULE(int) yy_class(); /* 27 */
+YY_RULE(int) yy_literal(); /* 26 */
+YY_RULE(int) yy_CLOSE(); /* 25 */
+YY_RULE(int) yy_OPEN(); /* 24 */
+YY_RULE(int) yy_COLON(); /* 23 */
+YY_RULE(int) yy_PLUS(); /* 22 */
+YY_RULE(int) yy_STAR(); /* 21 */
+YY_RULE(int) yy_QUESTION(); /* 20 */
+YY_RULE(int) yy_primary(); /* 19 */
+YY_RULE(int) yy_NOT(); /* 18 */
+YY_RULE(int) yy_suffix(); /* 17 */
+YY_RULE(int) yy_action(); /* 16 */
+YY_RULE(int) yy_AND(); /* 15 */
+YY_RULE(int) yy_prefix(); /* 14 */
+YY_RULE(int) yy_BAR(); /* 13 */
+YY_RULE(int) yy_sequence(); /* 12 */
+YY_RULE(int) yy_SEMICOLON(); /* 11 */
+YY_RULE(int) yy_expression(); /* 10 */
+YY_RULE(int) yy_EQUAL(); /* 9 */
+YY_RULE(int) yy_identifier(); /* 8 */
+YY_RULE(int) yy_RPERCENT(); /* 7 */
+YY_RULE(int) yy_end_of_file(); /* 6 */
+YY_RULE(int) yy_trailer(); /* 5 */
+YY_RULE(int) yy_definition(); /* 4 */
+YY_RULE(int) yy_declaration(); /* 3 */
+YY_RULE(int) yy__(); /* 2 */
+YY_RULE(int) yy_grammar(); /* 1 */
+
+YY_ACTION(void) yy_9_primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_9_primary\n"));
+   push(makePredicate("YY_END")); ;
+}
+YY_ACTION(void) yy_8_primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_8_primary\n"));
+   push(makePredicate("YY_BEGIN")); ;
+}
+YY_ACTION(void) yy_7_primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_7_primary\n"));
+   push(makeAction(yytext)); ;
+}
+YY_ACTION(void) yy_6_primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_6_primary\n"));
+   push(makeDot()); ;
+}
+YY_ACTION(void) yy_5_primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_5_primary\n"));
+   push(makeClass(yytext)); ;
+}
+YY_ACTION(void) yy_4_primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_4_primary\n"));
+   push(makeString(yytext)); ;
+}
+YY_ACTION(void) yy_3_primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_3_primary\n"));
+   push(makeName(findRule(yytext))); ;
+}
+YY_ACTION(void) yy_2_primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_2_primary\n"));
+   Node *name= makeName(findRule(yytext));  name->name.variable= pop();  push(name); ;
+}
+YY_ACTION(void) yy_1_primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_primary\n"));
+   push(makeVariable(yytext)); ;
+}
+YY_ACTION(void) yy_3_suffix(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_3_suffix\n"));
+   push(makePlus (pop())); ;
+}
+YY_ACTION(void) yy_2_suffix(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_2_suffix\n"));
+   push(makeStar (pop())); ;
+}
+YY_ACTION(void) yy_1_suffix(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_suffix\n"));
+   push(makeQuery(pop())); ;
+}
+YY_ACTION(void) yy_3_prefix(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_3_prefix\n"));
+   push(makePeekNot(pop())); ;
+}
+YY_ACTION(void) yy_2_prefix(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_2_prefix\n"));
+   push(makePeekFor(pop())); ;
+}
+YY_ACTION(void) yy_1_prefix(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_prefix\n"));
+   push(makePredicate(yytext)); ;
+}
+YY_ACTION(void) yy_1_sequence(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_sequence\n"));
+   Node *f= pop();  push(Sequence_append(pop(), f)); ;
+}
+YY_ACTION(void) yy_1_expression(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_expression\n"));
+   Node *f= pop();  push(Alternate_append(pop(), f)); ;
+}
+YY_ACTION(void) yy_2_definition(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_2_definition\n"));
+   Node *e= pop();  Rule_setExpression(pop(), e); ;
+}
+YY_ACTION(void) yy_1_definition(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_definition\n"));
+   if (push(beginRule(findRule(yytext)))->rule.expression)
+							    fprintf(stderr, "rule '%s' redefined\n", yytext); ;
+}
+YY_ACTION(void) yy_1_trailer(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_trailer\n"));
+   makeTrailer(yytext); ;
+}
+YY_ACTION(void) yy_1_declaration(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_declaration\n"));
+   makeHeader(yytext); ;
+}
+
+YY_RULE(int) yy_end_of_line()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "end_of_line"));
+  {  int yypos2= yypos, yythunkpos2= yythunkpos;  if (!yymatchString("\r\n")) goto l3;  goto l2;
+  l3:;	  yypos= yypos2; yythunkpos= yythunkpos2;  if (!yymatchChar('\n')) goto l4;  goto l2;
+  l4:;	  yypos= yypos2; yythunkpos= yythunkpos2;  if (!yymatchChar('\r')) goto l1;
+  }
+  l2:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "end_of_line", yybuf+yypos));
+  return 1;
+  l1:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "end_of_line", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_comment()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "comment"));  if (!yymatchChar('#')) goto l5;
+  l6:;	
+  {  int yypos7= yypos, yythunkpos7= yythunkpos;
+  {  int yypos8= yypos, yythunkpos8= yythunkpos;  if (!yy_end_of_line()) goto l8;  goto l7;
+  l8:;	  yypos= yypos8; yythunkpos= yythunkpos8;
+  }  if (!yymatchDot()) goto l7;  goto l6;
+  l7:;	  yypos= yypos7; yythunkpos= yythunkpos7;
+  }  if (!yy_end_of_line()) goto l5;
+  yyprintf((stderr, "  ok   %s @ %s\n", "comment", yybuf+yypos));
+  return 1;
+  l5:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "comment", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_space()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "space"));
+  {  int yypos10= yypos, yythunkpos10= yythunkpos;  if (!yymatchChar(' ')) goto l11;  goto l10;
+  l11:;	  yypos= yypos10; yythunkpos= yythunkpos10;  if (!yymatchChar('\t')) goto l12;  goto l10;
+  l12:;	  yypos= yypos10; yythunkpos= yythunkpos10;  if (!yy_end_of_line()) goto l9;
+  }
+  l10:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "space", yybuf+yypos));
+  return 1;
+  l9:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "space", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_range()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "range"));
+  {  int yypos14= yypos, yythunkpos14= yythunkpos;  if (!yy_char()) goto l15;  if (!yymatchChar('-')) goto l15;  if (!yy_char()) goto l15;  goto l14;
+  l15:;	  yypos= yypos14; yythunkpos= yythunkpos14;  if (!yy_char()) goto l13;
+  }
+  l14:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "range", yybuf+yypos));
+  return 1;
+  l13:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "range", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_char()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "char"));
+  {  int yypos17= yypos, yythunkpos17= yythunkpos;  if (!yymatchChar('\\')) goto l18;  if (!yymatchClass((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 l18;  goto l17;
+  l18:;	  yypos= yypos17; yythunkpos= yythunkpos17;  if (!yymatchChar('\\')) goto l19;  if (!yymatchClass((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 l19;  if (!yymatchClass((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 l19;  if (!yymatchClass((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 l19;  goto l17;
+  l19:;	  yypos= yypos17; yythunkpos= yythunkpos17;  if (!yymatchChar('\\')) goto l20;  if (!yymatchClass((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 l20;
+  {  int yypos21= yypos, yythunkpos21= yythunkpos;  if (!yymatchClass((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 l21;  goto l22;
+  l21:;	  yypos= yypos21; yythunkpos= yythunkpos21;
+  }
+  l22:;	  goto l17;
+  l20:;	  yypos= yypos17; yythunkpos= yythunkpos17;
+  {  int yypos23= yypos, yythunkpos23= yythunkpos;  if (!yymatchChar('\\')) goto l23;  goto l16;
+  l23:;	  yypos= yypos23; yythunkpos= yythunkpos23;
+  }  if (!yymatchDot()) goto l16;
+  }
+  l17:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "char", yybuf+yypos));
+  return 1;
+  l16:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "char", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_END()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "END"));  if (!yymatchChar('>')) goto l24;  if (!yy__()) goto l24;
+  yyprintf((stderr, "  ok   %s @ %s\n", "END", yybuf+yypos));
+  return 1;
+  l24:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "END", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_BEGIN()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "BEGIN"));  if (!yymatchChar('<')) goto l25;  if (!yy__()) goto l25;
+  yyprintf((stderr, "  ok   %s @ %s\n", "BEGIN", yybuf+yypos));
+  return 1;
+  l25:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "BEGIN", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_DOT()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "DOT"));  if (!yymatchChar('.')) goto l26;  if (!yy__()) goto l26;
+  yyprintf((stderr, "  ok   %s @ %s\n", "DOT", yybuf+yypos));
+  return 1;
+  l26:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "DOT", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_class()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "class"));  if (!yymatchChar('[')) goto l27;  yyText(yybegin, yyend);  if (!(YY_BEGIN)) goto l27;
+  l28:;	
+  {  int yypos29= yypos, yythunkpos29= yythunkpos;
+  {  int yypos30= yypos, yythunkpos30= yythunkpos;  if (!yymatchChar(']')) goto l30;  goto l29;
+  l30:;	  yypos= yypos30; yythunkpos= yythunkpos30;
+  }  if (!yy_range()) goto l29;  goto l28;
+  l29:;	  yypos= yypos29; yythunkpos= yythunkpos29;
+  }  yyText(yybegin, yyend);  if (!(YY_END)) goto l27;  if (!yymatchChar(']')) goto l27;  if (!yy__()) goto l27;
+  yyprintf((stderr, "  ok   %s @ %s\n", "class", yybuf+yypos));
+  return 1;
+  l27:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "class", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_literal()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "literal"));
+  {  int yypos32= yypos, yythunkpos32= yythunkpos;  if (!yymatchClass((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 l33;  yyText(yybegin, yyend);  if (!(YY_BEGIN)) goto l33;
+  l34:;	
+  {  int yypos35= yypos, yythunkpos35= yythunkpos;
+  {  int yypos36= yypos, yythunkpos36= yythunkpos;  if (!yymatchClass((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 l36;  goto l35;
+  l36:;	  yypos= yypos36; yythunkpos= yythunkpos36;
+  }  if (!yy_char()) goto l35;  goto l34;
+  l35:;	  yypos= yypos35; yythunkpos= yythunkpos35;
+  }  yyText(yybegin, yyend);  if (!(YY_END)) goto l33;  if (!yymatchClass((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 l33;  if (!yy__()) goto l33;  goto l32;
+  l33:;	  yypos= yypos32; yythunkpos= yythunkpos32;  if (!yymatchClass((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 l31;  yyText(yybegin, yyend);  if (!(YY_BEGIN)) goto l31;
+  l37:;	
+  {  int yypos38= yypos, yythunkpos38= yythunkpos;
+  {  int yypos39= yypos, yythunkpos39= yythunkpos;  if (!yymatchClass((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 l39;  goto l38;
+  l39:;	  yypos= yypos39; yythunkpos= yythunkpos39;
+  }  if (!yy_char()) goto l38;  goto l37;
+  l38:;	  yypos= yypos38; yythunkpos= yythunkpos38;
+  }  yyText(yybegin, yyend);  if (!(YY_END)) goto l31;  if (!yymatchClass((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 l31;  if (!yy__()) goto l31;
+  }
+  l32:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "literal", yybuf+yypos));
+  return 1;
+  l31:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "literal", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_CLOSE()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "CLOSE"));  if (!yymatchChar(')')) goto l40;  if (!yy__()) goto l40;
+  yyprintf((stderr, "  ok   %s @ %s\n", "CLOSE", yybuf+yypos));
+  return 1;
+  l40:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "CLOSE", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_OPEN()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "OPEN"));  if (!yymatchChar('(')) goto l41;  if (!yy__()) goto l41;
+  yyprintf((stderr, "  ok   %s @ %s\n", "OPEN", yybuf+yypos));
+  return 1;
+  l41:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "OPEN", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_COLON()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "COLON"));  if (!yymatchChar(':')) goto l42;  if (!yy__()) goto l42;
+  yyprintf((stderr, "  ok   %s @ %s\n", "COLON", yybuf+yypos));
+  return 1;
+  l42:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "COLON", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_PLUS()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "PLUS"));  if (!yymatchChar('+')) goto l43;  if (!yy__()) goto l43;
+  yyprintf((stderr, "  ok   %s @ %s\n", "PLUS", yybuf+yypos));
+  return 1;
+  l43:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "PLUS", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_STAR()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "STAR"));  if (!yymatchChar('*')) goto l44;  if (!yy__()) goto l44;
+  yyprintf((stderr, "  ok   %s @ %s\n", "STAR", yybuf+yypos));
+  return 1;
+  l44:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "STAR", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_QUESTION()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "QUESTION"));  if (!yymatchChar('?')) goto l45;  if (!yy__()) goto l45;
+  yyprintf((stderr, "  ok   %s @ %s\n", "QUESTION", yybuf+yypos));
+  return 1;
+  l45:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "QUESTION", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_primary()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "primary"));
+  {  int yypos47= yypos, yythunkpos47= yythunkpos;  if (!yy_identifier()) goto l48;  yyDo(yy_1_primary, yybegin, yyend);  if (!yy_COLON()) goto l48;  if (!yy_identifier()) goto l48;
+  {  int yypos49= yypos, yythunkpos49= yythunkpos;  if (!yy_EQUAL()) goto l49;  goto l48;
+  l49:;	  yypos= yypos49; yythunkpos= yythunkpos49;
+  }  yyDo(yy_2_primary, yybegin, yyend);  goto l47;
+  l48:;	  yypos= yypos47; yythunkpos= yythunkpos47;  if (!yy_identifier()) goto l50;
+  {  int yypos51= yypos, yythunkpos51= yythunkpos;  if (!yy_EQUAL()) goto l51;  goto l50;
+  l51:;	  yypos= yypos51; yythunkpos= yythunkpos51;
+  }  yyDo(yy_3_primary, yybegin, yyend);  goto l47;
+  l50:;	  yypos= yypos47; yythunkpos= yythunkpos47;  if (!yy_OPEN()) goto l52;  if (!yy_expression()) goto l52;  if (!yy_CLOSE()) goto l52;  goto l47;
+  l52:;	  yypos= yypos47; yythunkpos= yythunkpos47;  if (!yy_literal()) goto l53;  yyDo(yy_4_primary, yybegin, yyend);  goto l47;
+  l53:;	  yypos= yypos47; yythunkpos= yythunkpos47;  if (!yy_class()) goto l54;  yyDo(yy_5_primary, yybegin, yyend);  goto l47;
+  l54:;	  yypos= yypos47; yythunkpos= yythunkpos47;  if (!yy_DOT()) goto l55;  yyDo(yy_6_primary, yybegin, yyend);  goto l47;
+  l55:;	  yypos= yypos47; yythunkpos= yythunkpos47;  if (!yy_action()) goto l56;  yyDo(yy_7_primary, yybegin, yyend);  goto l47;
+  l56:;	  yypos= yypos47; yythunkpos= yythunkpos47;  if (!yy_BEGIN()) goto l57;  yyDo(yy_8_primary, yybegin, yyend);  goto l47;
+  l57:;	  yypos= yypos47; yythunkpos= yythunkpos47;  if (!yy_END()) goto l46;  yyDo(yy_9_primary, yybegin, yyend);
+  }
+  l47:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "primary", yybuf+yypos));
+  return 1;
+  l46:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "primary", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_NOT()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "NOT"));  if (!yymatchChar('!')) goto l58;  if (!yy__()) goto l58;
+  yyprintf((stderr, "  ok   %s @ %s\n", "NOT", yybuf+yypos));
+  return 1;
+  l58:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "NOT", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_suffix()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "suffix"));  if (!yy_primary()) goto l59;
+  {  int yypos60= yypos, yythunkpos60= yythunkpos;
+  {  int yypos62= yypos, yythunkpos62= yythunkpos;  if (!yy_QUESTION()) goto l63;  yyDo(yy_1_suffix, yybegin, yyend);  goto l62;
+  l63:;	  yypos= yypos62; yythunkpos= yythunkpos62;  if (!yy_STAR()) goto l64;  yyDo(yy_2_suffix, yybegin, yyend);  goto l62;
+  l64:;	  yypos= yypos62; yythunkpos= yythunkpos62;  if (!yy_PLUS()) goto l60;  yyDo(yy_3_suffix, yybegin, yyend);
+  }
+  l62:;	  goto l61;
+  l60:;	  yypos= yypos60; yythunkpos= yythunkpos60;
+  }
+  l61:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "suffix", yybuf+yypos));
+  return 1;
+  l59:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "suffix", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_action()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "action"));  if (!yymatchChar('{')) goto l65;  yyText(yybegin, yyend);  if (!(YY_BEGIN)) goto l65;
+  l66:;	
+  {  int yypos67= yypos, yythunkpos67= yythunkpos;  if (!yymatchClass((unsigned char *)"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\337\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377")) goto l67;  goto l66;
+  l67:;	  yypos= yypos67; yythunkpos= yythunkpos67;
+  }  yyText(yybegin, yyend);  if (!(YY_END)) goto l65;  if (!yymatchChar('}')) goto l65;  if (!yy__()) goto l65;
+  yyprintf((stderr, "  ok   %s @ %s\n", "action", yybuf+yypos));
+  return 1;
+  l65:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "action", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_AND()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "AND"));  if (!yymatchChar('&')) goto l68;  if (!yy__()) goto l68;
+  yyprintf((stderr, "  ok   %s @ %s\n", "AND", yybuf+yypos));
+  return 1;
+  l68:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "AND", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_prefix()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "prefix"));
+  {  int yypos70= yypos, yythunkpos70= yythunkpos;  if (!yy_AND()) goto l71;  if (!yy_action()) goto l71;  yyDo(yy_1_prefix, yybegin, yyend);  goto l70;
+  l71:;	  yypos= yypos70; yythunkpos= yythunkpos70;  if (!yy_AND()) goto l72;  if (!yy_suffix()) goto l72;  yyDo(yy_2_prefix, yybegin, yyend);  goto l70;
+  l72:;	  yypos= yypos70; yythunkpos= yythunkpos70;  if (!yy_NOT()) goto l73;  if (!yy_suffix()) goto l73;  yyDo(yy_3_prefix, yybegin, yyend);  goto l70;
+  l73:;	  yypos= yypos70; yythunkpos= yythunkpos70;  if (!yy_suffix()) goto l69;
+  }
+  l70:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "prefix", yybuf+yypos));
+  return 1;
+  l69:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "prefix", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_BAR()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "BAR"));  if (!yymatchChar('|')) goto l74;  if (!yy__()) goto l74;
+  yyprintf((stderr, "  ok   %s @ %s\n", "BAR", yybuf+yypos));
+  return 1;
+  l74:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "BAR", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_sequence()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "sequence"));  if (!yy_prefix()) goto l75;
+  l76:;	
+  {  int yypos77= yypos, yythunkpos77= yythunkpos;  if (!yy_prefix()) goto l77;  yyDo(yy_1_sequence, yybegin, yyend);  goto l76;
+  l77:;	  yypos= yypos77; yythunkpos= yythunkpos77;
+  }
+  yyprintf((stderr, "  ok   %s @ %s\n", "sequence", yybuf+yypos));
+  return 1;
+  l75:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "sequence", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_SEMICOLON()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "SEMICOLON"));  if (!yymatchChar(';')) goto l78;  if (!yy__()) goto l78;
+  yyprintf((stderr, "  ok   %s @ %s\n", "SEMICOLON", yybuf+yypos));
+  return 1;
+  l78:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "SEMICOLON", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_expression()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "expression"));  if (!yy_sequence()) goto l79;
+  l80:;	
+  {  int yypos81= yypos, yythunkpos81= yythunkpos;  if (!yy_BAR()) goto l81;  if (!yy_sequence()) goto l81;  yyDo(yy_1_expression, yybegin, yyend);  goto l80;
+  l81:;	  yypos= yypos81; yythunkpos= yythunkpos81;
+  }
+  yyprintf((stderr, "  ok   %s @ %s\n", "expression", yybuf+yypos));
+  return 1;
+  l79:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "expression", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_EQUAL()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "EQUAL"));  if (!yymatchChar('=')) goto l82;  if (!yy__()) goto l82;
+  yyprintf((stderr, "  ok   %s @ %s\n", "EQUAL", yybuf+yypos));
+  return 1;
+  l82:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "EQUAL", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_identifier()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "identifier"));  yyText(yybegin, yyend);  if (!(YY_BEGIN)) goto l83;  if (!yymatchClass((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 l83;
+  l84:;	
+  {  int yypos85= yypos, yythunkpos85= yythunkpos;  if (!yymatchClass((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 l85;  goto l84;
+  l85:;	  yypos= yypos85; yythunkpos= yythunkpos85;
+  }  yyText(yybegin, yyend);  if (!(YY_END)) goto l83;  if (!yy__()) goto l83;
+  yyprintf((stderr, "  ok   %s @ %s\n", "identifier", yybuf+yypos));
+  return 1;
+  l83:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "identifier", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_RPERCENT()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "RPERCENT"));  if (!yymatchString("%}")) goto l86;  if (!yy__()) goto l86;
+  yyprintf((stderr, "  ok   %s @ %s\n", "RPERCENT", yybuf+yypos));
+  return 1;
+  l86:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "RPERCENT", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_end_of_file()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "end_of_file"));
+  {  int yypos88= yypos, yythunkpos88= yythunkpos;  if (!yymatchDot()) goto l88;  goto l87;
+  l88:;	  yypos= yypos88; yythunkpos= yythunkpos88;
+  }
+  yyprintf((stderr, "  ok   %s @ %s\n", "end_of_file", yybuf+yypos));
+  return 1;
+  l87:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "end_of_file", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_trailer()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "trailer"));  if (!yymatchString("%%")) goto l89;  yyText(yybegin, yyend);  if (!(YY_BEGIN)) goto l89;
+  l90:;	
+  {  int yypos91= yypos, yythunkpos91= yythunkpos;  if (!yymatchDot()) goto l91;  goto l90;
+  l91:;	  yypos= yypos91; yythunkpos= yythunkpos91;
+  }  yyText(yybegin, yyend);  if (!(YY_END)) goto l89;  yyDo(yy_1_trailer, yybegin, yyend);
+  yyprintf((stderr, "  ok   %s @ %s\n", "trailer", yybuf+yypos));
+  return 1;
+  l89:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "trailer", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_definition()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "definition"));  if (!yy_identifier()) goto l92;  yyDo(yy_1_definition, yybegin, yyend);  if (!yy_EQUAL()) goto l92;  if (!yy_expression()) goto l92;  yyDo(yy_2_definition, yybegin, yyend);
+  {  int yypos93= yypos, yythunkpos93= yythunkpos;  if (!yy_SEMICOLON()) goto l93;  goto l94;
+  l93:;	  yypos= yypos93; yythunkpos= yythunkpos93;
+  }
+  l94:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "definition", yybuf+yypos));
+  return 1;
+  l92:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "definition", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_declaration()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "declaration"));  if (!yymatchString("%{")) goto l95;  yyText(yybegin, yyend);  if (!(YY_BEGIN)) goto l95;
+  l96:;	
+  {  int yypos97= yypos, yythunkpos97= yythunkpos;
+  {  int yypos98= yypos, yythunkpos98= yythunkpos;  if (!yymatchString("%}")) goto l98;  goto l97;
+  l98:;	  yypos= yypos98; yythunkpos= yythunkpos98;
+  }  if (!yymatchDot()) goto l97;  goto l96;
+  l97:;	  yypos= yypos97; yythunkpos= yythunkpos97;
+  }  yyText(yybegin, yyend);  if (!(YY_END)) goto l95;  if (!yy_RPERCENT()) goto l95;  yyDo(yy_1_declaration, yybegin, yyend);
+  yyprintf((stderr, "  ok   %s @ %s\n", "declaration", yybuf+yypos));
+  return 1;
+  l95:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "declaration", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy__()
+{
+  yyprintf((stderr, "%s\n", "_"));
+  l100:;	
+  {  int yypos101= yypos, yythunkpos101= yythunkpos;
+  {  int yypos102= yypos, yythunkpos102= yythunkpos;  if (!yy_space()) goto l103;  goto l102;
+  l103:;	  yypos= yypos102; yythunkpos= yythunkpos102;  if (!yy_comment()) goto l101;
+  }
+  l102:;	  goto l100;
+  l101:;	  yypos= yypos101; yythunkpos= yythunkpos101;
+  }
+  yyprintf((stderr, "  ok   %s @ %s\n", "_", yybuf+yypos));
+  return 1;
+}
+YY_RULE(int) yy_grammar()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "grammar"));  if (!yy__()) goto l104;
+  {  int yypos107= yypos, yythunkpos107= yythunkpos;  if (!yy_declaration()) goto l108;  goto l107;
+  l108:;	  yypos= yypos107; yythunkpos= yythunkpos107;  if (!yy_definition()) goto l104;
+  }
+  l107:;	
+  l105:;	
+  {  int yypos106= yypos, yythunkpos106= yythunkpos;
+  {  int yypos109= yypos, yythunkpos109= yythunkpos;  if (!yy_declaration()) goto l110;  goto l109;
+  l110:;	  yypos= yypos109; yythunkpos= yythunkpos109;  if (!yy_definition()) goto l106;
+  }
+  l109:;	  goto l105;
+  l106:;	  yypos= yypos106; yythunkpos= yythunkpos106;
+  }
+  {  int yypos111= yypos, yythunkpos111= yythunkpos;  if (!yy_trailer()) goto l111;  goto l112;
+  l111:;	  yypos= yypos111; yythunkpos= yythunkpos111;
+  }
+  l112:;	  if (!yy_end_of_file()) goto l104;
+  yyprintf((stderr, "  ok   %s @ %s\n", "grammar", yybuf+yypos));
+  return 1;
+  l104:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "grammar", yybuf+yypos));
+  return 0;
+}
+
+#ifndef YY_PART
+
+typedef int (*yyrule)();
+
+YY_PARSE(int) YYPARSEFROM(yyrule yystart)
+{
+  int yyok;
+  if (!yybuflen)
+    {
+      yybuflen= 1024;
+      yybuf= malloc(yybuflen);
+      yytextlen= 1024;
+      yytext= malloc(yytextlen);
+      yythunkslen= 32;
+      yythunks= malloc(sizeof(yythunk) * yythunkslen);
+      yyvalslen= 32;
+      yyvals= malloc(sizeof(YYSTYPE) * yyvalslen);
+      yybegin= yyend= yypos= yylimit= yythunkpos= 0;
+    }
+  yybegin= yyend= yypos;
+  yythunkpos= 0;
+  yyval= yyvals;
+  yyok= yystart();
+  if (yyok) yyDone();
+  yyCommit();
+  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;
+  (void)yytextmax;
+}
+
+YY_PARSE(int) YYPARSE(void)
+{
+  return YYPARSEFROM(yy_grammar);
+}
+
+#endif
+
+
+void yyerror(char *message)
+{
+  fprintf(stderr, "%s:%d: %s", fileName, lineNumber, message);
+  if (yytext[0]) fprintf(stderr, " near token '%s'", yytext);
+  if (yypos < yylimit || !feof(input))
+    {
+      yybuf[yylimit]= '\0';
+      fprintf(stderr, " before text \"");
+      while (yypos < yylimit)
+	{
+	  if ('\n' == yybuf[yypos] || '\r' == yybuf[yypos]) break;
+	  fputc(yybuf[yypos++], stderr);
+	}
+      if (yypos == yylimit)
+	{
+	  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 %d.%d.%d\n", name, PEG_MAJOR, PEG_MINOR, PEG_LEVEL);
+}
+
+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)
+{
+  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;
+
+  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())
+	    yyerror("syntax error");
+	  if (input != stdin)
+	    fclose(input);
+	}
+    }
+  else
+    if (!yyparse())
+      yyerror("syntax error");
+
+  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);
+
+  Rule_compile_c(rules);
+
+  if (trailer)
+    fprintf(output, "%s\n", trailer);
+
+  return 0;
+}
+
--- /dev/null
+++ b/leg.leg
@@ -1,0 +1,288 @@
+# LE Grammar for LE Grammars
+# 
+# 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:34:05 by piumarta on emilia
+
+%{
+# include "tree.h"
+# include "version.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(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
+%}
+
+# Hierarchical syntax
+
+grammar=	- ( declaration | definition )+ trailer? end-of-file
+
+declaration=	'%{' < ( !'%}' . )* > RPERCENT		{ makeHeader(yytext); }						#{YYACCEPT}
+
+trailer=	'%%' < .* >				{ makeTrailer(yytext); }					#{YYACCEPT}
+
+definition=	identifier 				{ if (push(beginRule(findRule(yytext)))->rule.expression)
+							    fprintf(stderr, "rule '%s' redefined\n", yytext); }
+			EQUAL expression		{ Node *e= pop();  Rule_setExpression(pop(), e); }
+			SEMICOLON?											#{YYACCEPT}
+
+expression=	sequence (BAR sequence			{ Node *f= pop();  push(Alternate_append(pop(), f)); }
+			    )*
+
+sequence=	prefix (prefix				{ Node *f= pop();  push(Sequence_append(pop(), f)); }
+			  )*
+
+prefix=		AND action				{ push(makePredicate(yytext)); }
+|		AND suffix				{ push(makePeekFor(pop())); }
+|		NOT suffix				{ push(makePeekNot(pop())); }
+|		    suffix
+
+suffix=		primary (QUESTION			{ push(makeQuery(pop())); }
+			     | STAR			{ push(makeStar (pop())); }
+			     | PLUS			{ push(makePlus (pop())); }
+			   )?
+
+primary=	identifier				{ push(makeVariable(yytext)); }
+			COLON identifier !EQUAL		{ Node *name= makeName(findRule(yytext));  name->name.variable= pop();  push(name); }
+|		identifier !EQUAL			{ push(makeName(findRule(yytext))); }
+|		OPEN expression CLOSE
+|		literal					{ push(makeString(yytext)); }
+|		class					{ push(makeClass(yytext)); }
+|		DOT					{ push(makeDot()); }
+|		action					{ push(makeAction(yytext)); }
+|		BEGIN					{ push(makePredicate("YY_BEGIN")); }
+|		END					{ push(makePredicate("YY_END")); }
+
+# Lexical syntax
+
+identifier=	< [-a-zA-Z_][-a-zA-Z_0-9]* > -
+
+literal=	['] < ( !['] char )* > ['] -
+|		["] < ( !["] char )* > ["] -
+
+class=		'[' < ( !']' range )* > ']' -
+
+range=		char '-' char | char
+
+char=		'\\' [abefnrtv'"\[\]\\]
+|		'\\' [0-3][0-7][0-7]
+|		'\\' [0-7][0-7]?
+|		!'\\' .
+
+action=		'{' < [^}]* > '}' -
+
+EQUAL=		'=' -
+COLON=		':' -
+SEMICOLON=	';' -
+BAR=		'|' -
+AND=		'&' -
+NOT=		'!' -
+QUESTION=	'?' -
+STAR=		'*' -
+PLUS=		'+' -
+OPEN=		'(' -
+CLOSE=		')' -
+DOT=		'.' -
+BEGIN=		'<' -
+END=		'>' -
+RPERCENT=	'%}' -
+
+-=		(space | comment)*
+space=		' ' | '\t' | end-of-line
+comment=	'#' (!end-of-line .)* end-of-line
+end-of-line=	'\r\n' | '\n' | '\r'
+end-of-file=	!.
+
+%%
+
+void yyerror(char *message)
+{
+  fprintf(stderr, "%s:%d: %s", fileName, lineNumber, message);
+  if (yytext[0]) fprintf(stderr, " near token '%s'", yytext);
+  if (yypos < yylimit || !feof(input))
+    {
+      yybuf[yylimit]= '\0';
+      fprintf(stderr, " before text \"");
+      while (yypos < yylimit)
+	{
+	  if ('\n' == yybuf[yypos] || '\r' == yybuf[yypos]) break;
+	  fputc(yybuf[yypos++], stderr);
+	}
+      if (yypos == yylimit)
+	{
+	  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 %d.%d.%d\n", name, PEG_MAJOR, PEG_MINOR, PEG_LEVEL);
+}
+
+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)
+{
+  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;
+
+  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())
+	    yyerror("syntax error");
+	  if (input != stdin)
+	    fclose(input);
+	}
+    }
+  else
+    if (!yyparse())
+      yyerror("syntax error");
+
+  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);
+
+  Rule_compile_c(rules);
+
+  if (trailer)
+    fprintf(output, "%s\n", trailer);
+
+  return 0;
+}
--- /dev/null
+++ b/peg.1
@@ -1,0 +1,891 @@
+.\" 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-12 17:12:40 by piumarta on emilia
+.\"
+.TH PEG 1 "May 2007" "Version 0.1"
+.SH NAME
+peg, leg \- parser generators
+.SH SYNOPSIS
+.B peg
+.B [\-hvV \-ooutput]
+.I [filename ...]
+.sp 0
+.B leg
+.B [\-hvV \-ooutput]
+.I [filename ...]
+.SH DESCRIPTION
+.I peg
+and
+.I leg
+are tools for generating recursive-descent parsers: programs that
+perform pattern matching on text.  They process a Parsing Expression
+Grammar (PEG) [Ford 2004] to produce a program that recognises legal
+sentences of that grammar.
+.I peg
+processes PEGs written using the original syntax described by Ford;
+.I leg
+processes PEGs written using slightly different syntax and conventions
+that are intended to make it an attractive replacement for parsers
+built with
+.IR lex (1)
+and
+.IR yacc (1).
+Unlike
+.I lex
+and
+.IR yacc ,
+.I peg
+and
+.I leg
+support unlimited backtracking, provide ordered choice as a means for
+disambiguation, and can combine scanning (lexical analysis) and
+parsing (syntactic analysis) into a single activity.
+.PP
+.I peg
+reads the specified
+.IR filename s,
+or standard input if no
+.IR filename s
+are given, for a grammar describing the parser to generate.
+.I peg
+then generates a C source file that defines a function
+.IR yyparse().
+This C source file can be included in, or compiled and then linked
+with, a client program.  Each time the client program calls
+.IR yyparse ()
+the parser consumes input text according to the parsing rules,
+starting from the first rule in the grammar.
+.IR yyparse ()
+returns non-zero if the input could be parsed according to the
+grammar; it returns zero if the input could not be parsed.
+.PP
+The prefix 'yy' or 'YY' is prepended to all externally-visible symbols
+in the generated parser.  This is intended to reduce the risk of
+namespace pollution in client programs.  (The choice of 'yy' is
+historical; see
+.IR lex (1)
+and
+.IR yacc (1),
+for example.)
+.SH OPTIONS
+.I peg
+and 
+.I leg
+provide the following options:
+.TP
+.B \-h
+prints a summary of available options and then exits.
+.TP
+.B \-ooutput
+writes the generated parser to the file
+.B output
+instead of the standard output.
+.TP
+.B \-v
+writes verbose information to standard error while working.
+.TP
+.B \-V
+writes version information to standard error then exits.
+.SH A SIMPLE EXAMPLE
+The following
+.I peg
+input specifies a grammar with a single rule (called 'start') that is
+satisfied when the input contains the string "username".
+.nf
+
+    start <- "username"
+
+.fi
+(The quotation marks are
+.I not
+part of the matched text; they serve to indicate a literal string to
+be matched.)  In other words,
+.IR  yyparse ()
+in the generated C source will return non-zero only if the next eight
+characters read from the input spell the word "username".  If the
+input contains anything else,
+.IR yyparse ()
+returns zero and no input will have been consumed.  (Subsequent calls
+to
+.IR yyparse ()
+will also return zero, since the parser is effectively blocked looking
+for the string "username".)  To ensure progress we can add an
+alternative clause to the 'start' rule that will match any single
+character if "username" is not found.
+.nf
+
+    start <- "username"
+           / .
+
+.fi
+.IR yyparse ()
+now always returns non-zero (except at the very end of the input).  To
+do something useful we can add actions to the rules.  These actions
+are performed after a complete match is found (starting from the first
+rule) and are chosen according to the 'path' taken through the grammar
+to match the input.  (Linguists would call this path a 'phrase
+marker'.)
+.nf
+
+    start <- "username"    { printf("%s\\n", getlogin()); }
+           / < . >         { putchar(yytext[0]); }
+
+.fi
+The first line instructs the parser to print the user's login name
+whenever it sees "username" in the input.  If that match fails, the
+second line tells the parser to echo the next character on the input
+the standard output.  Our parser is now performing useful work: it
+will copy the input to the output, replacing all occurrences of
+"username" with the user's account name.
+.PP
+Note the angle brackets ('<' and '>') that were added to the second
+alternative.  These have no effect on the meaning of the rule, but
+serve to delimit the text made available to the following action in
+the variable
+.IR yytext .
+.PP
+If the above grammar is placed in the file
+.BR username.peg ,
+running the command
+.nf
+
+    peg -o username.c username.peg
+
+.fi
+will save the corresponding parser in the file
+.BR username.c .
+To create a complete program this parser could be included by a C
+program as follows.
+.nf
+
+    #include <stdio.h>      /* printf(), putchar() */
+    #include <unistd.h>     /* getlogin() */
+
+    #include "username.c"   /* yyparse() */
+
+    int main()
+    {
+      while (yyparse())     /* repeat until EOF */
+        ;
+      return 0;
+    }
+.fi
+.SH PEG GRAMMARS
+A grammar consists of a set of named rules.
+.nf
+
+    name <- pattern
+
+.fi
+The
+.B pattern
+contains one or more of the following elements.
+.TP
+.B name
+The element stands for the entire pattern in the rule with the given
+.BR name .
+.TP
+.BR \(dq characters \(dq
+A character or string enclosed in double quotes is matched literally.
+The ANSI C esacpe sequences are recognised within the
+.IR characters .
+.TP
+.BR ' characters '
+A character or string enclosed in single quotes is matched literally, as above.
+.TP
+.BR [ characters ]
+A set of characters enclosed in square brackets matches any single
+character from the set, with escape characters recognised as above.
+If the set begins with an uparrow (^) then the set is negated (the
+element matches any character
+.I not
+in the set).  Any pair of characters separated with a dash (-)
+represents the range of characters from the first to the second,
+inclusive.  A single alphabetic character or underscore is matched by
+the following set.
+.nf
+
+    [a-zA-Z_]
+
+.fi
+Similarly, the following matches  any single non-digit character.
+.nf
+
+    [^0-9]
+
+.fi
+.TP
+.B .
+A dot matches any character.  Note that the only time this fails is at
+the end of file, where there is no character to match.
+.TP
+.BR ( \ pattern\  )
+Parentheses are used for grouping (modifying the precendence of the
+operators described below).
+.TP
+.BR { \ action\  }
+Curly braces surround actions.  The action is arbitray C source code
+to be executed at the end of matching.  (Currently the C source cannot
+contain any braces.  This restriction is likely to be removed in the
+future.)  Any input text that was matched before the action and
+delimited by angle brackets (see below) is made available within the
+action as the contents of the character array
+.IR yytext .
+The length of (number of characters in)
+.I yytext
+is available in the variable
+.IR yyleng .
+(These variable names are historical; see
+.IR lex (1).)
+.TP
+.B <
+An opening angle bracket always matches (consuming no input) and
+causes the parser to begin accumulating matched text.  This text will
+be made available to actions in the variable
+.IR yytext .
+.TP
+.B >
+A closing angle bracket always matches (consuming no input) and causes
+the parser to stop accumulating text for
+.IR yytext .
+.PP
+The above
+.IR element s
+can be made optional and/or repeatable with the following suffixes:
+.TP
+.RB element\  ?
+The element is optional.  If present on the input, it is consumed and
+the match succeeds.  If not present on the input, no text is consumed
+and the match succeeds anyway.
+.TP
+.RB element\  +
+The element is repeatable.  If present on the input, one or more
+occurrences of
+.I element
+are consumed and the match succeeds.  If no occurrences of
+.I element
+are present on the input, the match fails.
+.TP
+.RB element\  *
+The element is optional and repeatable.  If present on the input, one or more
+occurrences of
+.I element
+are consumed and the match succeeds.  If no occurrences of
+.I element
+are present on the input, the match succeeds anyway.
+.PP
+The above elements and suffixes can be converted into predicates (that
+match arbitray input text and subsequently succeed or fail
+.I without
+consuming that input) with the following prefixes:
+.TP
+.BR & \ element
+The predicate succeeds only if
+.I element
+can be matched.  Input text scanned while matching
+.I element
+is not consumed from the input and remains available for subsequent
+matching.
+.TP
+.BR ! \ element
+The predicate succeeds only if
+.I element
+cannot be matched.  Input text scanned while matching
+.I element
+is not consumed from the input and remains available for subsequent
+matching.  A popular idiom is
+.nf
+
+    !.
+
+.fi
+which matches the end of file, after the last character of the input
+has already been consumed.
+.PP
+A special form of the '&' predicate is provided:
+.TP
+.BR & {\ expression\ }
+In this predicate the simple C
+.I expression
+.RB ( not
+statement) is evaluated immediately when the parser reaches the
+predicate.  If the
+.I expression
+yields non-zero (true) the 'match' succeeds and the parser continues
+with the next element in the pattern.  If the
+.I expression
+yields zero (false) the 'match' fails and the parser backs up to look
+for an alternative parse of the input.
+.PP
+Several elements (with or without prefixes and suffixes) can be
+combined into a
+.I sequence
+by writing them one after the other.  The entire sequence matches only
+if each individual element within it matches, from left to right.
+.PP
+Sequences can be separated into disjoint alternatives by the
+alternation operator '/'.
+.TP
+.RB sequence-1\  / \ sequence-2\  / \ ...\  / \ sequence-N
+Each sequence is tried in turn until one of them matches, at which
+time matching for the overall pattern succeeds.  If none of the
+sequences matches then the match of the overall pattern fails.
+.PP
+Finally, the pound sign (#) introduces a comment (discarded) that
+continues until the end of the line.
+.PP
+To summarise the above, the parser tries to match the input text
+against a pattern containing literals, names (representing other
+rules), and various operators (written as prefixes, suffixes,
+juxtaposition for sequencing and and infix alternation operator) that
+modify how the elements within the pattern are matched.  Matches are
+made from left to right, 'descending' into named sub-rules as they are
+encountered.  If the matching process fails, the parser 'back tracks'
+('rewinding' the input appropriately in the process) to find the
+nearest alternative 'path' through the grammar.  In other words the
+parser performs a depth-first, left-to-right search for the first
+successfully-matching path through the rules.  If found, the actions
+along the successful path are executed (in the order they were
+encountered).
+.PP
+Note that predicates are evaluated
+.I immediately
+during the search for a successful match, since they contribute to the
+success or failure of the search.  Actions, however, are evaluated
+only after a successful match has been found.
+.SH PEG GRAMMAR FOR PEG GRAMMARS
+The grammar for
+.I peg
+grammars is shown below.  This will both illustrate and formalise
+the above description.
+.nf
+
+    Grammar         <- Spacing Definition+ EndOfFile
+    
+    Definition      <- Identifier LEFTARROW Expression
+    Expression      <- Sequence ( SLASH Sequence )*
+    Sequence        <- Prefix*
+    Prefix          <- AND Action
+                     / ( AND | NOT )? Suffix
+    Suffix          <- Primary ( QUERY / STAR / PLUS )?
+    Primary         <- Identifier !LEFTARROW
+                     / OPEN Expression CLOSE
+                     / Literal
+                     / Class
+                     / DOT
+                     / Action
+                     / BEGIN
+                     / END
+    
+    Identifier      <- < IdentStart IdentCont* > Spacing
+    IdentStart      <- [a-zA-Z_]
+    IdentCont       <- IdentStart / [0-9]
+    Literal         <- ['] < ( !['] Char  )* > ['] Spacing
+                     / ["] < ( !["] Char  )* > ["] Spacing
+    Class           <- '[' < ( !']' Range )* > ']' Spacing
+    Range           <- Char '-' Char / Char
+    Char            <- '\\\\' [abefnrtv'"\\[\\]\\\\]
+                     / '\\\\' [0-3][0-7][0-7]
+                     / '\\\\' [0-7][0-7]?
+                     / '\\\\' '-'
+                     / !'\\\\' .
+    LEFTARROW       <- '<-' Spacing
+    SLASH           <- '/' Spacing
+    AND             <- '&' Spacing
+    NOT             <- '!' Spacing
+    QUERY           <- '?' Spacing
+    STAR            <- '*' Spacing
+    PLUS            <- '+' Spacing
+    OPEN            <- '(' Spacing
+    CLOSE           <- ')' Spacing
+    DOT             <- '.' Spacing
+    Spacing         <- ( Space / Comment )*
+    Comment         <- '#' ( !EndOfLine . )* EndOfLine
+    Space           <- ' ' / '\\t' / EndOfLine
+    EndOfLine       <- '\\r\\n' / '\\n' / '\\r'
+    EndOfFile       <- !.
+    Action          <- '{' < [^}]* > '}' Spacing
+    BEGIN           <- '<' Spacing
+    END             <- '>' Spacing
+
+.fi
+.SH LEG GRAMMARS
+.I leg
+is a variant of
+.I peg
+that adds some features of
+.IR lex (1)
+and
+.IR yacc (1).
+It differs from
+.I peg
+in the following ways.
+.TP
+.BI %{\  text... \ %}
+A declaration section can appear anywhere that a rule definition is
+expected.  The
+.I text
+between the delimiters '%{' and '%}' is copied verbatim to the
+generated C parser code
+.I before
+the code that implements the parser itself.
+.TP
+.IB name\  = \ pattern
+The 'assignment' operator replaces the left arrow operator '<-'.
+.TP
+.B rule-name
+Hyphens can appear as letters in the names of rules.  Each hyphen is
+converted into an underscore in the generated C source code.  A single
+single hyphen '-' is a legal rule name.
+.nf
+
+    -       = [ \\t\\n\\r]*
+    number  = [0-9]+                 -
+    name    = [a-zA-Z_][a-zA_Z_0-9]* -
+    l-paren = '('                    -
+    r-paren = ')'                    -
+    
+.fi
+This example shows how ignored whitespace can be obvious when reading
+the grammar and yet unobtrusive when placed liberally at the end of
+every rule associated with a lexical element.
+.TP
+.IB seq-1\  | \ seq-2
+The alternation operator is vertical bar '|' rather than forward
+slash '/'.  The
+.I peg
+rule
+.nf
+
+    name <- sequence-1
+          / sequence-2
+          / sequence-3
+
+.fi
+is therefore written
+.nf
+
+    name = sequence-1
+         | sequence-2
+         | sequence-3
+         ;
+
+.fi
+in
+.I leg
+(with the final semicolon being optional, as described next).
+.TP
+.IB pattern\  ;
+A semicolon punctuator can optionally terminate a
+.IR pattern .
+.TP
+.BI %% \ text...
+A double percent '%%' terminates the rules (and declarations) section of
+the grammar.  All
+.I text
+following '%%' is copied verbatim to the generated C parser code
+.I after
+the parser implementation code.
+.TP
+.BI $$\ = \ value
+A sub-rule can return a semantic
+.I value
+from an action by assigning it to the pseudo-variable '$$'.  All
+semantic values must have the same type (which defaults to 'int').
+This type can be changed by defining YYSTYPE in a declaration section.
+.TP
+.IB identifier : name
+The semantic value returned (by assigning to '$$') from the sub-rule
+.I name
+is associated with the
+.I identifier
+and can be referred to in subsequent actions.
+.PP
+The desk calclator example below illustrates the use of '$$' and ':'.
+.SH LEG EXAMPLE: A DESK CALCULATOR
+The extensions in
+.I leg
+described above allow useful parsers and evaluators (including
+declarations, grammar rules, and supporting C functions such
+as 'main') to be kept within a single source file.  To illustrate this
+we show a simple desk calculator supporting the four common arithmetic
+operators and named variables.  The intermediate results of arithmetic
+evaluation will be accumulated on an implicit stack by returning them
+as semantic values from sub-rules.
+.nf
+
+    %{
+    #include <stdio.h>     /* printf() */
+    #include <stdlib.h>    /* atoi() */
+    int vars[26];
+    %}
+    
+    Stmt    = - e:Expr EOL                  { printf("%d\\n", e); }
+            | ( !EOL . )* EOL               { printf("error\\n"); }
+    
+    Expr    = i:ID ASSIGN s:Sum             { $$ = vars[i] = s; }
+            | s:Sum                         { $$ = s; }
+    
+    Sum     = l:Product
+                    ( PLUS  r:Product       { l += r; }
+                    | MINUS r:Product       { l -= r; }
+                    )*                      { $$ = l; }
+    
+    Product = l:Value
+                    ( TIMES  r:Value        { l *= r; }
+                    | DIVIDE r:Value        { l /= r; }
+                    )*                      { $$ = l; }
+    
+    Value   = i:NUMBER                      { $$ = atoi(yytext); }
+            | i:ID !ASSIGN                  { $$ = vars[i]; }
+            | OPEN i:Expr CLOSE             { $$ = i; }
+    
+    NUMBER  = < [0-9]+ >    -               { $$ = atoi(yytext); }
+    ID      = < [a-z]  >    -               { $$ = yytext[0] - 'a'; }
+    ASSIGN  = '='           -
+    PLUS    = '+'           -
+    MINUS   = '-'           -
+    TIMES   = '*'           -
+    DIVIDE  = '/'           -
+    OPEN    = '('           -
+    CLOSE   = ')'           -
+    
+    -       = [ \\t]*
+    EOL     = '\\n' | '\\r\\n' | '\\r' | ';'
+    
+    %%
+    
+    int main()
+    {
+      while (yyparse())
+        ;
+      return 0;
+    }
+
+.fi
+.SH LEG GRAMMAR FOR LEG GRAMMARS
+The grammar for
+.I leg
+grammars is shown below.  This will both illustrate and formalise the
+above description.
+.nf
+
+    grammar =       -
+                    ( declaration | definition )+
+                    trailer? end-of-file
+    
+    declaration =   '%{' < ( !'%}' . )* > RPERCENT
+    
+    trailer =       '%%' < .* >
+    
+    definition =    identifier EQUAL expression SEMICOLON?
+    
+    expression =    sequence ( BAR sequence )*
+    
+    sequence =      prefix+
+    
+    prefix =        AND action
+    |               ( AND | NOT )? suffix
+    
+    suffix =        primary ( QUERY | STAR | PLUS )?
+    
+    primary =       identifier COLON identifier !EQUAL
+    |               identifier !EQUAL
+    |               OPEN expression CLOSE
+    |               literal
+    |               class
+    |               DOT
+    |               action
+    |               BEGIN
+    |               END
+    
+    identifier =    < [-a-zA-Z_][-a-zA-Z_0-9]* > -
+    
+    literal =       ['] < ( !['] char )* > ['] -
+    |               ["] < ( !["] char )* > ["] -
+    
+    class =         '[' < ( !']' range )* > ']' -
+    
+    range =         char '-' char | char
+    
+    char =          '\\\\' [abefnrtv'"\\[\\]\\\\]
+    |               '\\\\' [0-3][0-7][0-7]
+    |               '\\\\' [0-7][0-7]?
+    |               !'\\\\' .
+    
+    action =        '{' < [^}]* > '}' -
+    
+    EQUAL =         '=' -
+    COLON =         ':' -
+    SEMICOLON =     ';' -
+    BAR =           '|' -
+    AND =           '&' -
+    NOT =           '!' -
+    QUERY =         '?' -
+    STAR =          '*' -
+    PLUS =          '+' -
+    OPEN =          '(' -
+    CLOSE =         ')' -
+    DOT =           '.' -
+    BEGIN =         '<' -
+    END =           '>' -
+    RPERCENT =      '%}' -
+    
+    - =             ( space | comment )*
+    space =         ' ' | '\\t' | end-of-line
+    comment =       '#' ( !end-of-line . )* end-of-line
+    end-of-line =   '\\r\\n' | '\\n' | '\\r'
+    end-of-file =   !.
+
+.fi
+.SH CUSTOMISING THE PARSER
+The following symbols can be redefined in declaration sections to
+modify the generated parser code.
+.TP
+.B YYSTYPE
+The semantic value type.  The pseudo-variable '$$' and the
+identifiers 'bound' to rule results with the colon operator ':' should
+all be considered as being declared to have this type.  The default
+value is 'int'.
+.TP
+.B YYPARSE
+The name of the main entry point to the parser.  The default value
+is 'yyparse'.
+.TP
+.B YYPARSEFROM
+The name of an alternative entry point to the parser.  This function
+expects one argument: the function corresponding to the rule from
+which the search for a match should begin.  The default
+is 'yyparsefrom'.  Note that yyparse() is defined as
+.nf
+
+    int yyparse() { return yyparsefrom(yy_foo); }
+
+.fi
+where 'foo' is the name of the first rule in the grammar.
+.TP
+.BI YY_INPUT( buf , \ result , \ max_size )
+This macro is invoked by the parser to obtain more input text.
+.I buf
+points to an area of memory that can hold at most
+.I max_size
+characters.  The macro should copy input text to
+.I buf
+and then assign the integer variable
+.I result
+to indicate the number of characters copied.  If no more input is available,
+the macro should assign 0 to
+.IR result .
+By default, the YY_INPUT macro is defined as follows.
+.nf
+
+    #define YY_INPUT(buf, result, max_size)        \\
+    {                                              \\
+      int yyc= getchar();                          \\
+      result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1); \\
+    }
+
+.fi
+.TP
+.B YY_DEBUG
+If this symbols is defined then additional code will be included in
+the parser that prints vast quantities of arcane information to the
+standard error while the parser is running.
+.TP
+.B YY_BEGIN
+This macro is invoked to mark the start of input text that will be
+made available in actions as 'yytext'.  This corresponds to
+occurrences of '<' in the grammar.  These are converted into
+predicates that are expected to succeed.  The default definition
+.nf
+
+    #define YY_BEGIN (yybegin= yypos, 1)
+
+.fi
+therefore saves the current input position and returns 1 ('true') as
+the result of the predicate.
+.TP
+.B YY_END
+This macros corresponds to '>' in the grammar.  Again, it is a
+predicate so the default definition saves the input position
+before 'succeeding'.
+.nf
+
+    #define YY_END (yyend= yypos, 1)
+
+.fi
+.TP
+.BI YY_PARSE( T )
+This macro declares the parser entry points (yyparse and yyparsefrom)
+to be of type
+.IR T .
+The default definition
+.nf
+
+    #define YY_PARSE(T) T
+
+.fi
+leaves yyparse() and yyparsefrom() with global visibility.  If they
+should not be externally visible in other source files, this macro can
+be redefined to declare them 'static'.
+.nf
+
+    #define YY_PARSE(T) static T
+
+.fi
+.PP
+The following variables can be reffered to within actions.
+.TP
+.B char *yybuf
+This variable points to the parser's input buffer used to store input
+text that has not yet been matched.
+.TP
+.B int yypos
+This is the offset (in yybuf) of the next character to be matched and
+consumed.
+.TP
+.B char *yytext
+The most recent matched text delimited by '<' and '>' is stored in this variable.
+.TP
+.B int yyleng
+This variable indicates the number of characters in 'yytext'.
+.SH DIAGNOSTICS
+.I peg
+and
+.I leg
+warn about the following conditions while converting a grammar into a parser.
+.TP
+.B syntax error
+The input grammar was malformed in some way.  The error message will
+include the text about to be matched (often backed up a huge amount
+from the actual location of the error) and the line number of the most
+recently considered character (which is often the real location of the
+problem).
+.TP
+.B rule 'foo' used but not defined
+The grammar referred to a rule named 'foo' but no definition for it
+was given.  Attempting to use the generated parser will likely result
+in errors from the linker due to undefined symbols associated with the
+missing rule.
+.TP
+.B rule 'foo' defined but not used
+The grammar defined a rule named 'foo' and then ignored it.  The code
+associated with the rule is included in the generated parser which
+will in all other respects be healthy.
+.TP
+.B possible infinite left recursion in rule 'foo'
+There exists at least one path through the grammar that leads from the
+rule 'foo' back to (a recursive invocation of) the same rule without
+consuming any input.
+.PP
+Left recursion, especially that found in standards documents, is
+often 'direct' and implies trivial repetition.
+.nf
+
+    # (6.7.6)
+    direct-abstract-declarator =
+        LPAREN abstract-declarator RPAREN
+    |   direct-abstract-declarator? LBRACKET assign-expr? RBRACKET
+    |   direct-abstract-declarator? LBRACKET STAR RBRACKET
+    |   direct-abstract-declarator? LPAREN param-type-list? RPAREN
+
+.fi
+The recursion can easily be eliminated by converting the parts of the
+pattern following the recursion into a repeatable suffix.
+.nf
+    
+    # (6.7.6)
+    direct-abstract-declarator =
+        direct-abstract-declarator-head?
+        direct-abstract-declarator-tail*
+    
+    direct-abstract-declarator-head =
+        LPAREN abstract-declarator RPAREN
+    
+    direct-abstract-declarator-tail =
+        LBRACKET assign-expr? RBRACKET
+    |   LBRACKET STAR RBRACKET
+    |   LPAREN param-type-list? RPAREN
+
+.fi
+.SH BUGS
+The 'yy' and 'YY' prefixes cannot be changed.
+.PP
+Braces are not counted while scanning an action.  (A closing brace '}'
+therefore cannot appear in an action.)
+.PP
+Left recursion is detected in the input grammar but is not handled
+correctly in the generated parser.
+.PP
+Diagnostics for errors in the input grammar are obscure and not
+particularly helpful.
+.PP
+Several commonly-used
+.IR lex (1)
+features (yywrap(), yyin, etc.) are completely absent.
+.PP
+The generated parser foes not contain '#line' directives to direct C
+compiler errors back to the grammar description when appropriate.
+.IR lex (1)
+features (yywrap(), yyin, etc.) are completely absent.
+.SH SEE ALSO
+D. Val Schorre,
+.I META II, a syntax-oriented compiler writing language,
+19th ACM National Conference, 1964, pp.\ 41.301--41.311.  Describes a
+self-implementing parser generator for analytic grammars with no
+backtracking.
+.PP
+Alexander Birman,
+.I The TMG Recognition Schema,
+Ph.D. dissertation, Princeton, 1970.  A mathematical treatment of the
+power and complexity of recursive-descent parsing with backtracking.
+.PP
+Bryan Ford,
+.I Parsing Expression Grammars: A Recognition-Based Syntactic Foundation,
+ACM SIGPLAN Symposium on Principles of Programming Languages, 2004.
+Defines PEGs and analyses them in relation to context-free and regular
+grammars.  Introduces the syntax adopted in
+.IR peg .
+.PP
+The standard Unix utilies
+.IR lex (1)
+and
+.IR yacc (1)
+which influenced the syntax and features of
+.IR leg .
+.PP
+The source code for
+.I peg
+and
+.I leg
+whose grammar parsers are written using themselves.
+.PP
+The latest version of this software and documentation:
+.nf
+
+    http://piumarta.com/software/peg
+
+.fi
+.SH AUTHOR
+.IR peg ,
+.I leg
+and this manual page were written by Ian Piumarta (first-name at
+last-name dot com) while investigating the viablility of regular- and
+parsing-expression grammars for efficiently extracting type and
+signature information from C header files.
+.PP
+Please send bug reports and suggestions for improvements to the author
+at the above address.
--- /dev/null
+++ b/peg.c
@@ -1,0 +1,173 @@
+/* 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:34:42 by piumarta on emilia
+ */
+
+#include "tree.h"
+#include "version.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <libgen.h>
+#include <assert.h>
+
+FILE *input= 0;
+
+int   verboseFlag= 0;
+
+static int   lineNumber= 0;
+static char *fileName= 0;
+
+void yyerror(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
+
+#include "peg.peg-c"
+
+void yyerror(char *message)
+{
+  fprintf(stderr, "%s:%d: %s", fileName, lineNumber, message);
+  if (yytext[0]) fprintf(stderr, " near token '%s'", yytext);
+  if (yypos < yylimit || !feof(input))
+    {
+      yybuf[yylimit]= '\0';
+      fprintf(stderr, " before text \"");
+      while (yypos < yylimit)
+	{
+	  if ('\n' == yybuf[yypos] || '\r' == yybuf[yypos]) break;
+	  fputc(yybuf[yypos++], stderr);
+	}
+      if (yypos == yylimit)
+	{
+	  int c;
+	  while (EOF != (c= fgetc(input)) && '\n' != c && '\r' != c)
+	    fputc(c, stderr);
+	}
+      fputc('\"', stderr);
+    }
+  fprintf(stderr, "\n");
+  exit(1);
+}
+
+static void version(char *name)
+{
+  printf("%s version %d.%d.%d\n", name, PEG_MAJOR, PEG_MINOR, PEG_LEVEL);
+}
+
+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)
+{
+  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;
+
+  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())
+	    yyerror("syntax error");
+	  if (input != stdin)
+	    fclose(input);
+	}
+    }
+  else
+    if (!yyparse())
+      yyerror("syntax error");
+
+  if (verboseFlag)
+    for (n= rules;  n;  n= n->any.next)
+      Rule_print(n);
+
+  Rule_compile_c_header();
+  Rule_compile_c(rules);
+
+  return 0;
+}
--- /dev/null
+++ b/peg.peg
@@ -1,0 +1,77 @@
+# PE Grammar for PE Grammars
+# 
+# Adapted from [1] by Ian Piumarta <first-name at last-name point com>.
+# 
+# Local modifications (marked '#ikp') to support:
+#     C text in '{ ... }' copied verbatim to output as 'semantic action'
+#     input consumed between '<' and '>' is 'char yytext[]' in semantic actions
+# 
+# Best viewed using 140 columns monospaced with tabs every 8.
+# 
+# [1] Bryan Ford.  "Parsing Expression Grammars: A Recognition-Based Syntactic
+#     Foundation."  Symposium on Principles of Programming Languages,
+#     January 14--16, 2004, Venice, Italy.
+# 
+# Last edited: 2007-05-15 10:32:44 by piumarta on emilia
+
+# Hierarchical syntax
+
+Grammar		<- Spacing Definition+ EndOfFile
+
+Definition	<- Identifier 			{ if (push(beginRule(findRule(yytext)))->rule.expression) fprintf(stderr, "rule '%s' redefined\n", yytext); }
+		     LEFTARROW Expression	{ Node *e= pop();  Rule_setExpression(pop(), e); } &{ YYACCEPT }
+Expression	<- Sequence (SLASH Sequence	{ Node *f= pop();  push(Alternate_append(pop(), f)); }
+			    )*
+Sequence	<- Prefix (Prefix		{ Node *f= pop();  push(Sequence_append(pop(), f)); }	#ikp expanded from 'Seq <- Prefix*'
+			  )*
+		 / 				{ push(makePredicate("1")); }				#ikp added
+Prefix		<- AND Action			{ push(makePredicate(yytext)); }	#ikp added
+		 / AND Suffix			{ push(makePeekFor(pop())); }		#ikp expanded from 'Prefix <- (AND/NOT)? Suffix'
+		 / NOT Suffix			{ push(makePeekNot(pop())); }
+		 /     Suffix
+Suffix		<- Primary (QUESTION		{ push(makeQuery(pop())); }
+			     / STAR		{ push(makeStar (pop())); }
+			     / PLUS		{ push(makePlus (pop())); }
+			   )?
+Primary		<- Identifier !LEFTARROW	{ push(makeName(findRule(yytext))); }
+		 / OPEN Expression CLOSE
+		 / Literal			{ push(makeString(yytext)); }
+		 / Class			{ push(makeClass(yytext)); }
+		 / DOT				{ push(makeDot()); }
+		 / Action			{ push(makeAction(yytext)); }		#ikp added
+		 / BEGIN			{ push(makePredicate("YY_BEGIN")); }	#ikp added
+		 / END				{ push(makePredicate("YY_END")); }	#ikp added
+
+# Lexical syntax
+
+Identifier	<- < IdentStart IdentCont* > Spacing		#ikp inserted < ... >
+IdentStart	<- [a-zA-Z_]
+IdentCont	<- IdentStart / [0-9]
+Literal		<- ['] < (!['] Char )* > ['] Spacing		#ikp inserted < ... >
+		 / ["] < (!["] Char )* > ["] Spacing		#ikp inserted < ... >
+Class		<- '[' < (!']' Range)* > ']' Spacing		#ikp inserted < ... >
+Range		<- Char '-' Char / Char
+Char		<- '\\' [abefnrtv'"\[\]\\]			#ikp added missing ANSI escapes: abefv
+		 / '\\' [0-3][0-7][0-7]
+		 / '\\' [0-7][0-7]?
+		 / '\\' '-'					#ikp added
+		 / !'\\' .
+LEFTARROW	<- '<-' Spacing
+SLASH		<- '/' Spacing
+AND		<- '&' Spacing
+NOT		<- '!' Spacing
+QUESTION	<- '?' Spacing
+STAR		<- '*' Spacing
+PLUS		<- '+' Spacing
+OPEN		<- '(' Spacing
+CLOSE		<- ')' Spacing
+DOT		<- '.' Spacing
+Spacing		<- (Space / Comment)*
+Comment		<- '#' (!EndOfLine .)* EndOfLine
+Space		<- ' ' / '\t' / EndOfLine
+EndOfLine	<- '\r\n' / '\n' / '\r'
+EndOfFile	<- !.
+
+Action		<- '{' < [^}]* > '}' Spacing		#ikp added
+BEGIN		<- '<' Spacing				#ikp added
+END		<- '>' Spacing				#ikp added
--- /dev/null
+++ b/peg.peg-c
@@ -1,0 +1,800 @@
+/* A recursive-descent parser generated by peg 0.1.0 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define YYRULECOUNT 32
+#ifndef YY_VARIABLE
+#define YY_VARIABLE(T)	static T
+#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 YYPARSE
+#define YYPARSE		yyparse
+#endif
+#ifndef YYPARSEFROM
+#define YYPARSEFROM	yyparsefrom
+#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	( yybegin= yypos, 1)
+#endif
+#ifndef YY_END
+#define YY_END		( yyend= yypos, 1)
+#endif
+#ifdef YY_DEBUG
+# define yyprintf(args)	fprintf args
+#else
+# define yyprintf(args)
+#endif
+#ifndef YYSTYPE
+#define YYSTYPE	int
+#endif
+
+#ifndef YY_PART
+
+typedef void (*yyaction)(char *yytext, int yyleng);
+typedef struct _yythunk { int begin, end;  yyaction  action;  struct _yythunk *next; } yythunk;
+
+YY_VARIABLE(char *   ) yybuf= 0;
+YY_VARIABLE(int	     ) yybuflen= 0;
+YY_VARIABLE(int	     ) yypos= 0;
+YY_VARIABLE(int	     ) yylimit= 0;
+YY_VARIABLE(char *   ) yytext= 0;
+YY_VARIABLE(int	     ) yytextlen= 0;
+YY_VARIABLE(int	     ) yybegin= 0;
+YY_VARIABLE(int	     ) yyend= 0;
+YY_VARIABLE(int	     ) yytextmax= 0;
+YY_VARIABLE(yythunk *) yythunks= 0;
+YY_VARIABLE(int	     ) yythunkslen= 0;
+YY_VARIABLE(int      ) yythunkpos= 0;
+YY_VARIABLE(YYSTYPE  ) yy;
+YY_VARIABLE(YYSTYPE *) yyval= 0;
+YY_VARIABLE(YYSTYPE *) yyvals= 0;
+YY_VARIABLE(int      ) yyvalslen= 0;
+
+YY_LOCAL(int) yyrefill(void)
+{
+  int yyn;
+  if (yybuflen - yypos < 512)
+    {
+      yybuflen *= 2;
+      yybuf= realloc(yybuf, yybuflen);
+    }
+  YY_INPUT((yybuf + yypos), yyn, (yybuflen - yypos));
+  if (!yyn) return 0;
+  yylimit += yyn;
+  return 1;
+}
+
+YY_LOCAL(int) yymatchDot(void)
+{
+  if (yypos >= yylimit && !yyrefill()) return 0;
+  ++yypos;
+  return 1;
+}
+
+YY_LOCAL(int) yymatchChar(int c)
+{
+  if (yypos >= yylimit && !yyrefill()) return 0;
+  if (yybuf[yypos] == c)
+    {
+      ++yypos;
+      yyprintf((stderr, "  ok   yymatchChar(%c) @ %s\n", c, yybuf+yypos));
+      return 1;
+    }
+  yyprintf((stderr, "  fail yymatchChar(%c) @ %s\n", c, yybuf+yypos));
+  return 0;
+}
+
+YY_LOCAL(int) yymatchString(char *s)
+{
+  int yysav= yypos;
+  while (*s)
+    {
+      if (yypos >= yylimit && !yyrefill()) return 0;
+      if (yybuf[yypos] != *s)
+        {
+          yypos= yysav;
+          return 0;
+        }
+      ++s;
+      ++yypos;
+    }
+  return 1;
+}
+
+YY_LOCAL(int) yymatchClass(unsigned char *bits)
+{
+  int c;
+  if (yypos >= yylimit && !yyrefill()) return 0;
+  c= yybuf[yypos];
+  if (bits[c >> 3] & (1 << (c & 7)))
+    {
+      ++yypos;
+      yyprintf((stderr, "  ok   yymatchClass @ %s\n", yybuf+yypos));
+      return 1;
+    }
+  yyprintf((stderr, "  fail yymatchClass @ %s\n", yybuf+yypos));
+  return 0;
+}
+
+YY_LOCAL(void) yyDo(yyaction action, int begin, int end)
+{
+  if (yythunkpos >= yythunkslen)
+    {
+      yythunkslen *= 2;
+      yythunks= realloc(yythunks, sizeof(yythunk) * yythunkslen);
+    }
+  yythunks[yythunkpos].begin=  begin;
+  yythunks[yythunkpos].end=    end;
+  yythunks[yythunkpos].action= action;
+  ++yythunkpos;
+}
+
+YY_LOCAL(int) yyText(int begin, int end)
+{
+  int yyleng= end - begin;
+  if (yyleng <= 0)
+    yyleng= 0;
+  else
+    {
+      if (yytextlen < (yyleng - 1))
+	{
+	  yytextlen *= 2;
+	  yytext= realloc(yytext, yytextlen);
+	}
+      memcpy(yytext, yybuf + begin, yyleng);
+    }
+  yytext[yyleng]= '\0';
+  return yyleng;
+}
+
+YY_LOCAL(void) yyDone(void)
+{
+  int pos;
+  for (pos= 0;  pos < yythunkpos;  ++pos)
+    {
+      yythunk *thunk= &yythunks[pos];
+      int yyleng= thunk->end ? yyText(thunk->begin, thunk->end) : thunk->begin;
+      yyprintf((stderr, "DO [%d] %p %s\n", pos, thunk->action, yytext));
+      thunk->action(yytext, yyleng);
+    }
+  yythunkpos= 0;
+}
+
+YY_LOCAL(void) yyCommit()
+{
+  if ((yylimit -= yypos))
+    {
+      memmove(yybuf, yybuf + yypos, yylimit);
+    }
+  yybegin -= yypos;
+  yyend -= yypos;
+  yypos= yythunkpos= 0;
+}
+
+YY_LOCAL(int) yyAccept(int tp0)
+{
+  if (tp0)
+    {
+      fprintf(stderr, "accept denied at %d\n", tp0);
+      return 0;
+    }
+  else
+    {
+      yyDone();
+      yyCommit();
+    }
+  return 1;
+}
+
+YY_LOCAL(void) yyPush(char *text, int count)	{ yyval += count; }
+YY_LOCAL(void) yyPop(char *text, int count)	{ yyval -= count; }
+YY_LOCAL(void) yySet(char *text, int count)	{ yyval[count]= yy; }
+
+#endif /* YY_PART */
+
+#define	YYACCEPT	yyAccept(yythunkpos0)
+
+YY_RULE(int) yy_EndOfLine(); /* 32 */
+YY_RULE(int) yy_Comment(); /* 31 */
+YY_RULE(int) yy_Space(); /* 30 */
+YY_RULE(int) yy_Range(); /* 29 */
+YY_RULE(int) yy_Char(); /* 28 */
+YY_RULE(int) yy_IdentCont(); /* 27 */
+YY_RULE(int) yy_IdentStart(); /* 26 */
+YY_RULE(int) yy_END(); /* 25 */
+YY_RULE(int) yy_BEGIN(); /* 24 */
+YY_RULE(int) yy_DOT(); /* 23 */
+YY_RULE(int) yy_Class(); /* 22 */
+YY_RULE(int) yy_Literal(); /* 21 */
+YY_RULE(int) yy_CLOSE(); /* 20 */
+YY_RULE(int) yy_OPEN(); /* 19 */
+YY_RULE(int) yy_PLUS(); /* 18 */
+YY_RULE(int) yy_STAR(); /* 17 */
+YY_RULE(int) yy_QUESTION(); /* 16 */
+YY_RULE(int) yy_Primary(); /* 15 */
+YY_RULE(int) yy_NOT(); /* 14 */
+YY_RULE(int) yy_Suffix(); /* 13 */
+YY_RULE(int) yy_Action(); /* 12 */
+YY_RULE(int) yy_AND(); /* 11 */
+YY_RULE(int) yy_Prefix(); /* 10 */
+YY_RULE(int) yy_SLASH(); /* 9 */
+YY_RULE(int) yy_Sequence(); /* 8 */
+YY_RULE(int) yy_Expression(); /* 7 */
+YY_RULE(int) yy_LEFTARROW(); /* 6 */
+YY_RULE(int) yy_Identifier(); /* 5 */
+YY_RULE(int) yy_EndOfFile(); /* 4 */
+YY_RULE(int) yy_Definition(); /* 3 */
+YY_RULE(int) yy_Spacing(); /* 2 */
+YY_RULE(int) yy_Grammar(); /* 1 */
+
+YY_ACTION(void) yy_7_Primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_7_Primary\n"));
+   push(makePredicate("YY_END")); ;
+}
+YY_ACTION(void) yy_6_Primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_6_Primary\n"));
+   push(makePredicate("YY_BEGIN")); ;
+}
+YY_ACTION(void) yy_5_Primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_5_Primary\n"));
+   push(makeAction(yytext)); ;
+}
+YY_ACTION(void) yy_4_Primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_4_Primary\n"));
+   push(makeDot()); ;
+}
+YY_ACTION(void) yy_3_Primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_3_Primary\n"));
+   push(makeClass(yytext)); ;
+}
+YY_ACTION(void) yy_2_Primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_2_Primary\n"));
+   push(makeString(yytext)); ;
+}
+YY_ACTION(void) yy_1_Primary(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_Primary\n"));
+   push(makeName(findRule(yytext))); ;
+}
+YY_ACTION(void) yy_3_Suffix(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_3_Suffix\n"));
+   push(makePlus (pop())); ;
+}
+YY_ACTION(void) yy_2_Suffix(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_2_Suffix\n"));
+   push(makeStar (pop())); ;
+}
+YY_ACTION(void) yy_1_Suffix(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_Suffix\n"));
+   push(makeQuery(pop())); ;
+}
+YY_ACTION(void) yy_3_Prefix(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_3_Prefix\n"));
+   push(makePeekNot(pop())); ;
+}
+YY_ACTION(void) yy_2_Prefix(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_2_Prefix\n"));
+   push(makePeekFor(pop())); ;
+}
+YY_ACTION(void) yy_1_Prefix(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_Prefix\n"));
+   push(makePredicate(yytext)); ;
+}
+YY_ACTION(void) yy_2_Sequence(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_2_Sequence\n"));
+   push(makePredicate("1")); ;
+}
+YY_ACTION(void) yy_1_Sequence(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_Sequence\n"));
+   Node *f= pop();  push(Sequence_append(pop(), f)); ;
+}
+YY_ACTION(void) yy_1_Expression(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_Expression\n"));
+   Node *f= pop();  push(Alternate_append(pop(), f)); ;
+}
+YY_ACTION(void) yy_2_Definition(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_2_Definition\n"));
+   Node *e= pop();  Rule_setExpression(pop(), e); ;
+}
+YY_ACTION(void) yy_1_Definition(char *yytext, int yyleng)
+{
+  yyprintf((stderr, "do yy_1_Definition\n"));
+   if (push(beginRule(findRule(yytext)))->rule.expression) fprintf(stderr, "rule '%s' redefined\n", yytext); ;
+}
+
+YY_RULE(int) yy_EndOfLine()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "EndOfLine"));
+  {  int yypos2= yypos, yythunkpos2= yythunkpos;  if (!yymatchString("\r\n")) goto l3;  goto l2;
+  l3:;	  yypos= yypos2; yythunkpos= yythunkpos2;  if (!yymatchChar('\n')) goto l4;  goto l2;
+  l4:;	  yypos= yypos2; yythunkpos= yythunkpos2;  if (!yymatchChar('\r')) goto l1;
+  }
+  l2:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "EndOfLine", yybuf+yypos));
+  return 1;
+  l1:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "EndOfLine", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Comment()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Comment"));  if (!yymatchChar('#')) goto l5;
+  l6:;	
+  {  int yypos7= yypos, yythunkpos7= yythunkpos;
+  {  int yypos8= yypos, yythunkpos8= yythunkpos;  if (!yy_EndOfLine()) goto l8;  goto l7;
+  l8:;	  yypos= yypos8; yythunkpos= yythunkpos8;
+  }  if (!yymatchDot()) goto l7;  goto l6;
+  l7:;	  yypos= yypos7; yythunkpos= yythunkpos7;
+  }  if (!yy_EndOfLine()) goto l5;
+  yyprintf((stderr, "  ok   %s @ %s\n", "Comment", yybuf+yypos));
+  return 1;
+  l5:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Comment", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Space()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Space"));
+  {  int yypos10= yypos, yythunkpos10= yythunkpos;  if (!yymatchChar(' ')) goto l11;  goto l10;
+  l11:;	  yypos= yypos10; yythunkpos= yythunkpos10;  if (!yymatchChar('\t')) goto l12;  goto l10;
+  l12:;	  yypos= yypos10; yythunkpos= yythunkpos10;  if (!yy_EndOfLine()) goto l9;
+  }
+  l10:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "Space", yybuf+yypos));
+  return 1;
+  l9:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Space", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Range()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Range"));
+  {  int yypos14= yypos, yythunkpos14= yythunkpos;  if (!yy_Char()) goto l15;  if (!yymatchChar('-')) goto l15;  if (!yy_Char()) goto l15;  goto l14;
+  l15:;	  yypos= yypos14; yythunkpos= yythunkpos14;  if (!yy_Char()) goto l13;
+  }
+  l14:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "Range", yybuf+yypos));
+  return 1;
+  l13:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Range", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Char()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Char"));
+  {  int yypos17= yypos, yythunkpos17= yythunkpos;  if (!yymatchChar('\\')) goto l18;  if (!yymatchClass((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 l18;  goto l17;
+  l18:;	  yypos= yypos17; yythunkpos= yythunkpos17;  if (!yymatchChar('\\')) goto l19;  if (!yymatchClass((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 l19;  if (!yymatchClass((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 l19;  if (!yymatchClass((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 l19;  goto l17;
+  l19:;	  yypos= yypos17; yythunkpos= yythunkpos17;  if (!yymatchChar('\\')) goto l20;  if (!yymatchClass((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 l20;
+  {  int yypos21= yypos, yythunkpos21= yythunkpos;  if (!yymatchClass((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 l21;  goto l22;
+  l21:;	  yypos= yypos21; yythunkpos= yythunkpos21;
+  }
+  l22:;	  goto l17;
+  l20:;	  yypos= yypos17; yythunkpos= yythunkpos17;  if (!yymatchChar('\\')) goto l23;  if (!yymatchChar('-')) goto l23;  goto l17;
+  l23:;	  yypos= yypos17; yythunkpos= yythunkpos17;
+  {  int yypos24= yypos, yythunkpos24= yythunkpos;  if (!yymatchChar('\\')) goto l24;  goto l16;
+  l24:;	  yypos= yypos24; yythunkpos= yythunkpos24;
+  }  if (!yymatchDot()) goto l16;
+  }
+  l17:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "Char", yybuf+yypos));
+  return 1;
+  l16:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Char", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_IdentCont()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "IdentCont"));
+  {  int yypos26= yypos, yythunkpos26= yythunkpos;  if (!yy_IdentStart()) goto l27;  goto l26;
+  l27:;	  yypos= yypos26; yythunkpos= yythunkpos26;  if (!yymatchClass((unsigned char *)"\000\000\000\000\000\000\377\003\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 l25;
+  }
+  l26:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "IdentCont", yybuf+yypos));
+  return 1;
+  l25:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "IdentCont", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_IdentStart()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "IdentStart"));  if (!yymatchClass((unsigned char *)"\000\000\000\000\000\000\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 l28;
+  yyprintf((stderr, "  ok   %s @ %s\n", "IdentStart", yybuf+yypos));
+  return 1;
+  l28:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "IdentStart", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_END()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "END"));  if (!yymatchChar('>')) goto l29;  if (!yy_Spacing()) goto l29;
+  yyprintf((stderr, "  ok   %s @ %s\n", "END", yybuf+yypos));
+  return 1;
+  l29:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "END", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_BEGIN()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "BEGIN"));  if (!yymatchChar('<')) goto l30;  if (!yy_Spacing()) goto l30;
+  yyprintf((stderr, "  ok   %s @ %s\n", "BEGIN", yybuf+yypos));
+  return 1;
+  l30:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "BEGIN", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_DOT()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "DOT"));  if (!yymatchChar('.')) goto l31;  if (!yy_Spacing()) goto l31;
+  yyprintf((stderr, "  ok   %s @ %s\n", "DOT", yybuf+yypos));
+  return 1;
+  l31:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "DOT", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Class()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Class"));  if (!yymatchChar('[')) goto l32;  yyText(yybegin, yyend);  if (!(YY_BEGIN)) goto l32;
+  l33:;	
+  {  int yypos34= yypos, yythunkpos34= yythunkpos;
+  {  int yypos35= yypos, yythunkpos35= yythunkpos;  if (!yymatchChar(']')) goto l35;  goto l34;
+  l35:;	  yypos= yypos35; yythunkpos= yythunkpos35;
+  }  if (!yy_Range()) goto l34;  goto l33;
+  l34:;	  yypos= yypos34; yythunkpos= yythunkpos34;
+  }  yyText(yybegin, yyend);  if (!(YY_END)) goto l32;  if (!yymatchChar(']')) goto l32;  if (!yy_Spacing()) goto l32;
+  yyprintf((stderr, "  ok   %s @ %s\n", "Class", yybuf+yypos));
+  return 1;
+  l32:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Class", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Literal()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Literal"));
+  {  int yypos37= yypos, yythunkpos37= yythunkpos;  if (!yymatchClass((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 l38;  yyText(yybegin, yyend);  if (!(YY_BEGIN)) goto l38;
+  l39:;	
+  {  int yypos40= yypos, yythunkpos40= yythunkpos;
+  {  int yypos41= yypos, yythunkpos41= yythunkpos;  if (!yymatchClass((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 l41;  goto l40;
+  l41:;	  yypos= yypos41; yythunkpos= yythunkpos41;
+  }  if (!yy_Char()) goto l40;  goto l39;
+  l40:;	  yypos= yypos40; yythunkpos= yythunkpos40;
+  }  yyText(yybegin, yyend);  if (!(YY_END)) goto l38;  if (!yymatchClass((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 l38;  if (!yy_Spacing()) goto l38;  goto l37;
+  l38:;	  yypos= yypos37; yythunkpos= yythunkpos37;  if (!yymatchClass((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 l36;  yyText(yybegin, yyend);  if (!(YY_BEGIN)) goto l36;
+  l42:;	
+  {  int yypos43= yypos, yythunkpos43= yythunkpos;
+  {  int yypos44= yypos, yythunkpos44= yythunkpos;  if (!yymatchClass((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 l44;  goto l43;
+  l44:;	  yypos= yypos44; yythunkpos= yythunkpos44;
+  }  if (!yy_Char()) goto l43;  goto l42;
+  l43:;	  yypos= yypos43; yythunkpos= yythunkpos43;
+  }  yyText(yybegin, yyend);  if (!(YY_END)) goto l36;  if (!yymatchClass((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 l36;  if (!yy_Spacing()) goto l36;
+  }
+  l37:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "Literal", yybuf+yypos));
+  return 1;
+  l36:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Literal", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_CLOSE()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "CLOSE"));  if (!yymatchChar(')')) goto l45;  if (!yy_Spacing()) goto l45;
+  yyprintf((stderr, "  ok   %s @ %s\n", "CLOSE", yybuf+yypos));
+  return 1;
+  l45:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "CLOSE", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_OPEN()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "OPEN"));  if (!yymatchChar('(')) goto l46;  if (!yy_Spacing()) goto l46;
+  yyprintf((stderr, "  ok   %s @ %s\n", "OPEN", yybuf+yypos));
+  return 1;
+  l46:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "OPEN", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_PLUS()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "PLUS"));  if (!yymatchChar('+')) goto l47;  if (!yy_Spacing()) goto l47;
+  yyprintf((stderr, "  ok   %s @ %s\n", "PLUS", yybuf+yypos));
+  return 1;
+  l47:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "PLUS", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_STAR()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "STAR"));  if (!yymatchChar('*')) goto l48;  if (!yy_Spacing()) goto l48;
+  yyprintf((stderr, "  ok   %s @ %s\n", "STAR", yybuf+yypos));
+  return 1;
+  l48:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "STAR", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_QUESTION()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "QUESTION"));  if (!yymatchChar('?')) goto l49;  if (!yy_Spacing()) goto l49;
+  yyprintf((stderr, "  ok   %s @ %s\n", "QUESTION", yybuf+yypos));
+  return 1;
+  l49:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "QUESTION", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Primary()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Primary"));
+  {  int yypos51= yypos, yythunkpos51= yythunkpos;  if (!yy_Identifier()) goto l52;
+  {  int yypos53= yypos, yythunkpos53= yythunkpos;  if (!yy_LEFTARROW()) goto l53;  goto l52;
+  l53:;	  yypos= yypos53; yythunkpos= yythunkpos53;
+  }  yyDo(yy_1_Primary, yybegin, yyend);  goto l51;
+  l52:;	  yypos= yypos51; yythunkpos= yythunkpos51;  if (!yy_OPEN()) goto l54;  if (!yy_Expression()) goto l54;  if (!yy_CLOSE()) goto l54;  goto l51;
+  l54:;	  yypos= yypos51; yythunkpos= yythunkpos51;  if (!yy_Literal()) goto l55;  yyDo(yy_2_Primary, yybegin, yyend);  goto l51;
+  l55:;	  yypos= yypos51; yythunkpos= yythunkpos51;  if (!yy_Class()) goto l56;  yyDo(yy_3_Primary, yybegin, yyend);  goto l51;
+  l56:;	  yypos= yypos51; yythunkpos= yythunkpos51;  if (!yy_DOT()) goto l57;  yyDo(yy_4_Primary, yybegin, yyend);  goto l51;
+  l57:;	  yypos= yypos51; yythunkpos= yythunkpos51;  if (!yy_Action()) goto l58;  yyDo(yy_5_Primary, yybegin, yyend);  goto l51;
+  l58:;	  yypos= yypos51; yythunkpos= yythunkpos51;  if (!yy_BEGIN()) goto l59;  yyDo(yy_6_Primary, yybegin, yyend);  goto l51;
+  l59:;	  yypos= yypos51; yythunkpos= yythunkpos51;  if (!yy_END()) goto l50;  yyDo(yy_7_Primary, yybegin, yyend);
+  }
+  l51:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "Primary", yybuf+yypos));
+  return 1;
+  l50:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Primary", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_NOT()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "NOT"));  if (!yymatchChar('!')) goto l60;  if (!yy_Spacing()) goto l60;
+  yyprintf((stderr, "  ok   %s @ %s\n", "NOT", yybuf+yypos));
+  return 1;
+  l60:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "NOT", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Suffix()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Suffix"));  if (!yy_Primary()) goto l61;
+  {  int yypos62= yypos, yythunkpos62= yythunkpos;
+  {  int yypos64= yypos, yythunkpos64= yythunkpos;  if (!yy_QUESTION()) goto l65;  yyDo(yy_1_Suffix, yybegin, yyend);  goto l64;
+  l65:;	  yypos= yypos64; yythunkpos= yythunkpos64;  if (!yy_STAR()) goto l66;  yyDo(yy_2_Suffix, yybegin, yyend);  goto l64;
+  l66:;	  yypos= yypos64; yythunkpos= yythunkpos64;  if (!yy_PLUS()) goto l62;  yyDo(yy_3_Suffix, yybegin, yyend);
+  }
+  l64:;	  goto l63;
+  l62:;	  yypos= yypos62; yythunkpos= yythunkpos62;
+  }
+  l63:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "Suffix", yybuf+yypos));
+  return 1;
+  l61:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Suffix", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Action()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Action"));  if (!yymatchChar('{')) goto l67;  yyText(yybegin, yyend);  if (!(YY_BEGIN)) goto l67;
+  l68:;	
+  {  int yypos69= yypos, yythunkpos69= yythunkpos;  if (!yymatchClass((unsigned char *)"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\337\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377")) goto l69;  goto l68;
+  l69:;	  yypos= yypos69; yythunkpos= yythunkpos69;
+  }  yyText(yybegin, yyend);  if (!(YY_END)) goto l67;  if (!yymatchChar('}')) goto l67;  if (!yy_Spacing()) goto l67;
+  yyprintf((stderr, "  ok   %s @ %s\n", "Action", yybuf+yypos));
+  return 1;
+  l67:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Action", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_AND()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "AND"));  if (!yymatchChar('&')) goto l70;  if (!yy_Spacing()) goto l70;
+  yyprintf((stderr, "  ok   %s @ %s\n", "AND", yybuf+yypos));
+  return 1;
+  l70:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "AND", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Prefix()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Prefix"));
+  {  int yypos72= yypos, yythunkpos72= yythunkpos;  if (!yy_AND()) goto l73;  if (!yy_Action()) goto l73;  yyDo(yy_1_Prefix, yybegin, yyend);  goto l72;
+  l73:;	  yypos= yypos72; yythunkpos= yythunkpos72;  if (!yy_AND()) goto l74;  if (!yy_Suffix()) goto l74;  yyDo(yy_2_Prefix, yybegin, yyend);  goto l72;
+  l74:;	  yypos= yypos72; yythunkpos= yythunkpos72;  if (!yy_NOT()) goto l75;  if (!yy_Suffix()) goto l75;  yyDo(yy_3_Prefix, yybegin, yyend);  goto l72;
+  l75:;	  yypos= yypos72; yythunkpos= yythunkpos72;  if (!yy_Suffix()) goto l71;
+  }
+  l72:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "Prefix", yybuf+yypos));
+  return 1;
+  l71:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Prefix", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_SLASH()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "SLASH"));  if (!yymatchChar('/')) goto l76;  if (!yy_Spacing()) goto l76;
+  yyprintf((stderr, "  ok   %s @ %s\n", "SLASH", yybuf+yypos));
+  return 1;
+  l76:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "SLASH", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Sequence()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Sequence"));
+  {  int yypos78= yypos, yythunkpos78= yythunkpos;  if (!yy_Prefix()) goto l79;
+  l80:;	
+  {  int yypos81= yypos, yythunkpos81= yythunkpos;  if (!yy_Prefix()) goto l81;  yyDo(yy_1_Sequence, yybegin, yyend);  goto l80;
+  l81:;	  yypos= yypos81; yythunkpos= yythunkpos81;
+  }  goto l78;
+  l79:;	  yypos= yypos78; yythunkpos= yythunkpos78;  yyDo(yy_2_Sequence, yybegin, yyend);
+  }
+  l78:;	
+  yyprintf((stderr, "  ok   %s @ %s\n", "Sequence", yybuf+yypos));
+  return 1;
+  l77:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Sequence", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Expression()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Expression"));  if (!yy_Sequence()) goto l82;
+  l83:;	
+  {  int yypos84= yypos, yythunkpos84= yythunkpos;  if (!yy_SLASH()) goto l84;  if (!yy_Sequence()) goto l84;  yyDo(yy_1_Expression, yybegin, yyend);  goto l83;
+  l84:;	  yypos= yypos84; yythunkpos= yythunkpos84;
+  }
+  yyprintf((stderr, "  ok   %s @ %s\n", "Expression", yybuf+yypos));
+  return 1;
+  l82:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Expression", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_LEFTARROW()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "LEFTARROW"));  if (!yymatchString("<-")) goto l85;  if (!yy_Spacing()) goto l85;
+  yyprintf((stderr, "  ok   %s @ %s\n", "LEFTARROW", yybuf+yypos));
+  return 1;
+  l85:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "LEFTARROW", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Identifier()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Identifier"));  yyText(yybegin, yyend);  if (!(YY_BEGIN)) goto l86;  if (!yy_IdentStart()) goto l86;
+  l87:;	
+  {  int yypos88= yypos, yythunkpos88= yythunkpos;  if (!yy_IdentCont()) goto l88;  goto l87;
+  l88:;	  yypos= yypos88; yythunkpos= yythunkpos88;
+  }  yyText(yybegin, yyend);  if (!(YY_END)) goto l86;  if (!yy_Spacing()) goto l86;
+  yyprintf((stderr, "  ok   %s @ %s\n", "Identifier", yybuf+yypos));
+  return 1;
+  l86:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Identifier", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_EndOfFile()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "EndOfFile"));
+  {  int yypos90= yypos, yythunkpos90= yythunkpos;  if (!yymatchDot()) goto l90;  goto l89;
+  l90:;	  yypos= yypos90; yythunkpos= yythunkpos90;
+  }
+  yyprintf((stderr, "  ok   %s @ %s\n", "EndOfFile", yybuf+yypos));
+  return 1;
+  l89:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "EndOfFile", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Definition()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Definition"));  if (!yy_Identifier()) goto l91;  yyDo(yy_1_Definition, yybegin, yyend);  if (!yy_LEFTARROW()) goto l91;  if (!yy_Expression()) goto l91;  yyDo(yy_2_Definition, yybegin, yyend);  yyText(yybegin, yyend);  if (!( YYACCEPT )) goto l91;
+  yyprintf((stderr, "  ok   %s @ %s\n", "Definition", yybuf+yypos));
+  return 1;
+  l91:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Definition", yybuf+yypos));
+  return 0;
+}
+YY_RULE(int) yy_Spacing()
+{
+  yyprintf((stderr, "%s\n", "Spacing"));
+  l93:;	
+  {  int yypos94= yypos, yythunkpos94= yythunkpos;
+  {  int yypos95= yypos, yythunkpos95= yythunkpos;  if (!yy_Space()) goto l96;  goto l95;
+  l96:;	  yypos= yypos95; yythunkpos= yythunkpos95;  if (!yy_Comment()) goto l94;
+  }
+  l95:;	  goto l93;
+  l94:;	  yypos= yypos94; yythunkpos= yythunkpos94;
+  }
+  yyprintf((stderr, "  ok   %s @ %s\n", "Spacing", yybuf+yypos));
+  return 1;
+}
+YY_RULE(int) yy_Grammar()
+{  int yypos0= yypos, yythunkpos0= yythunkpos;
+  yyprintf((stderr, "%s\n", "Grammar"));  if (!yy_Spacing()) goto l97;  if (!yy_Definition()) goto l97;
+  l98:;	
+  {  int yypos99= yypos, yythunkpos99= yythunkpos;  if (!yy_Definition()) goto l99;  goto l98;
+  l99:;	  yypos= yypos99; yythunkpos= yythunkpos99;
+  }  if (!yy_EndOfFile()) goto l97;
+  yyprintf((stderr, "  ok   %s @ %s\n", "Grammar", yybuf+yypos));
+  return 1;
+  l97:;	  yypos= yypos0; yythunkpos= yythunkpos0;
+  yyprintf((stderr, "  fail %s @ %s\n", "Grammar", yybuf+yypos));
+  return 0;
+}
+
+#ifndef YY_PART
+
+typedef int (*yyrule)();
+
+YY_PARSE(int) YYPARSEFROM(yyrule yystart)
+{
+  int yyok;
+  if (!yybuflen)
+    {
+      yybuflen= 1024;
+      yybuf= malloc(yybuflen);
+      yytextlen= 1024;
+      yytext= malloc(yytextlen);
+      yythunkslen= 32;
+      yythunks= malloc(sizeof(yythunk) * yythunkslen);
+      yyvalslen= 32;
+      yyvals= malloc(sizeof(YYSTYPE) * yyvalslen);
+      yybegin= yyend= yypos= yylimit= yythunkpos= 0;
+    }
+  yybegin= yyend= yypos;
+  yythunkpos= 0;
+  yyval= yyvals;
+  yyok= yystart();
+  if (yyok) yyDone();
+  yyCommit();
+  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) YYPARSE(void)
+{
+  return YYPARSEFROM(yy_Grammar);
+}
+
+#endif
--- /dev/null
+++ b/tree.c
@@ -1,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 "tree.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)
+{
+  Node *node= newNode(Rule);
+  node->rule.name= strdup(name);
+  node->rule.id= ++ruleCount;
+  node->rule.flags= 0;
+  node->rule.next= rules;
+  rules= node;
+  return node;
+}
+
+Node *findRule(char *name)
+{
+  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);
+}
+
+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, "### %d\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);
+  else
+    fprintf(stream, " UNDEFINED");
+  fprintf(stream, " ;\n");
+}
+
+void Rule_print(Node *node)	{ Rule_fprint(stderr, node); }
--- /dev/null
+++ b/tree.h
@@ -1,0 +1,108 @@
+/* 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>
+
+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);
+extern Node *findRule(char *name);
+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);
--- /dev/null
+++ b/version.h
@@ -1,0 +1,3 @@
+#define PEG_MAJOR	0
+#define PEG_MINOR	1
+#define PEG_LEVEL	1