diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7ae22a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +leg +peg diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bc45e64 --- /dev/null +++ b/Makefile @@ -0,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 : diff --git a/README.md b/README.md new file mode 100644 index 0000000..02fef7a --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# peg/leg — 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 license 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)) — 2007-05-15 +First public release. diff --git a/compile.c b/compile.c new file mode 100644 index 0000000..b6ce7ad --- /dev/null +++ b/compile.c @@ -0,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 +#include +#include +#include + +#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 \n\ +#include \n\ +#include \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); +} diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 0000000..57ac5f5 --- /dev/null +++ b/examples/Makefile @@ -0,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 : diff --git a/examples/accept.c b/examples/accept.c new file mode 100644 index 0000000..781e3b1 --- /dev/null +++ b/examples/accept.c @@ -0,0 +1,11 @@ +#include +#include + +#include "accept.peg.c" + +int main() +{ + while (yyparse()); + + return 0; +} diff --git a/examples/accept.peg b/examples/accept.peg new file mode 100644 index 0000000..9b28e40 --- /dev/null +++ b/examples/accept.peg @@ -0,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); } diff --git a/examples/accept.ref b/examples/accept.ref new file mode 100644 index 0000000..789f528 --- /dev/null +++ b/examples/accept.ref @@ -0,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 diff --git a/examples/basic.leg b/examples/basic.leg new file mode 100644 index 0000000..20227af --- /dev/null +++ b/examples/basic.leg @@ -0,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 + + 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 +#include + +char *help= + "print | [, | ...] [,]\n" + "if <|<=|<>|=|>=|> then \n" + "input [, ...] let = \n" + "goto gosub \n" + "end return\n" + "list clear\n" + "run [\"filename\"] rem \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 +# include +#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; +} diff --git a/examples/basic.ref b/examples/basic.ref new file mode 100644 index 0000000..90d916c --- /dev/null +++ b/examples/basic.ref @@ -0,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 diff --git a/examples/bench.bas b/examples/bench.bas new file mode 100644 index 0000000..ffdbd44 --- /dev/null +++ b/examples/bench.bas @@ -0,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 +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; +} diff --git a/examples/calc.ref b/examples/calc.ref new file mode 100644 index 0000000..dbd7d59 --- /dev/null +++ b/examples/calc.ref @@ -0,0 +1,3 @@ +6 +7 +42 diff --git a/examples/dc.c b/examples/dc.c new file mode 100644 index 0000000..32bf1a5 --- /dev/null +++ b/examples/dc.c @@ -0,0 +1,17 @@ +#include +#include + +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; +} diff --git a/examples/dc.peg b/examples/dc.peg new file mode 100644 index 0000000..75dcb67 --- /dev/null +++ b/examples/dc.peg @@ -0,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' diff --git a/examples/dc.ref b/examples/dc.ref new file mode 100644 index 0000000..d81cc07 --- /dev/null +++ b/examples/dc.ref @@ -0,0 +1 @@ +42 diff --git a/examples/dcv.c b/examples/dcv.c new file mode 100644 index 0000000..0c5c46d --- /dev/null +++ b/examples/dcv.c @@ -0,0 +1,20 @@ +#include +#include + +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; +} diff --git a/examples/dcv.peg b/examples/dcv.peg new file mode 100644 index 0000000..2ae3a8c --- /dev/null +++ b/examples/dcv.peg @@ -0,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' / ';' diff --git a/examples/dcv.ref b/examples/dcv.ref new file mode 100644 index 0000000..dbd7d59 --- /dev/null +++ b/examples/dcv.ref @@ -0,0 +1,3 @@ +6 +7 +42 diff --git a/examples/fibonacci.bas b/examples/fibonacci.bas new file mode 100644 index 0000000..1872bd3 --- /dev/null +++ b/examples/fibonacci.bas @@ -0,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 diff --git a/examples/left.c b/examples/left.c new file mode 100644 index 0000000..ac8cd0b --- /dev/null +++ b/examples/left.c @@ -0,0 +1,17 @@ +#include + +#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; +} diff --git a/examples/left.peg b/examples/left.peg new file mode 100644 index 0000000..f282227 --- /dev/null +++ b/examples/left.peg @@ -0,0 +1,3 @@ +# Grammar + +S <- (S 'a' / 'a') !'a' diff --git a/examples/rule.c b/examples/rule.c new file mode 100644 index 0000000..15eb0c6 --- /dev/null +++ b/examples/rule.c @@ -0,0 +1,11 @@ +#include +#include + +#include "rule.peg.c" + +int main() +{ + while (yyparse()); + + return 0; +} diff --git a/examples/rule.peg b/examples/rule.peg new file mode 100644 index 0000000..60a32fa --- /dev/null +++ b/examples/rule.peg @@ -0,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); } diff --git a/examples/rule.ref b/examples/rule.ref new file mode 100644 index 0000000..4249ebe --- /dev/null +++ b/examples/rule.ref @@ -0,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 diff --git a/examples/test.bas b/examples/test.bas new file mode 100644 index 0000000..8a96e10 --- /dev/null +++ b/examples/test.bas @@ -0,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 diff --git a/examples/test.c b/examples/test.c new file mode 100644 index 0000000..0403422 --- /dev/null +++ b/examples/test.c @@ -0,0 +1,8 @@ +#include +#include "test.peg.c" + +int main() +{ + while (yyparse()); + return 0; +} diff --git a/examples/test.peg b/examples/test.peg new file mode 100644 index 0000000..716d523 --- /dev/null +++ b/examples/test.peg @@ -0,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 ") } ) diff --git a/examples/test.ref b/examples/test.ref new file mode 100644 index 0000000..2d18109 --- /dev/null +++ b/examples/test.ref @@ -0,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 . diff --git a/examples/username.leg b/examples/username.leg new file mode 100644 index 0000000..2170052 --- /dev/null +++ b/examples/username.leg @@ -0,0 +1,14 @@ +%{ +#include +%} + +start = "username" { printf("%s", getlogin()); } +| < . > { putchar(yytext[0]); } + +%% + +int main() +{ + while (yyparse()); + return 0; +} diff --git a/examples/wc.leg b/examples/wc.leg new file mode 100644 index 0000000..59199c8 --- /dev/null +++ b/examples/wc.leg @@ -0,0 +1,22 @@ +%{ +#include +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; +} diff --git a/examples/wc.ref b/examples/wc.ref new file mode 100644 index 0000000..083a46e --- /dev/null +++ b/examples/wc.ref @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +22 lines +425 chars +52 words diff --git a/leg.c b/leg.c new file mode 100644 index 0000000..36372ba --- /dev/null +++ b/leg.c @@ -0,0 +1,1058 @@ +/* A recursive-descent parser generated by peg 0.1.0 */ + +#include +#include +#include +#define YYRULECOUNT 35 + +# include "tree.h" +# include "version.h" + +# include +# include +# include +# include +# include +# include + + 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 [