From 706e87a12385a678742212a436b5b386b6da5e0c Mon Sep 17 00:00:00 2001 From: Dane Johnson Date: Fri, 17 Dec 2021 13:54:05 -0600 Subject: [PATCH] Init commit --- Makefile | 9 + cyoa | Bin 0 -> 43240 bytes cyoa.c | 1017 ++++++++++++++++++++++++++++++++++++++++++++++++++ cyoa.leg | 250 +++++++++++++ demo.story | 61 +++ simple.story | 13 + spec.txt | 57 +++ 7 files changed, 1407 insertions(+) create mode 100644 Makefile create mode 100755 cyoa create mode 100644 cyoa.c create mode 100644 cyoa.leg create mode 100644 demo.story create mode 100644 simple.story create mode 100644 spec.txt diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..28df1f3 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +CC = gcc +CFLAGS = -g + +all: cyoa +cyoa: cyoa.c +cyoa.c: cyoa.leg + leg -o $@ $^ +clean: + rm -f cyoa.c cyoa diff --git a/cyoa b/cyoa new file mode 100755 index 0000000000000000000000000000000000000000..005c8725080bb6dfcee39052e3ff9056f088df88 GIT binary patch literal 43240 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 z zx`P0d?+RWTbU zbs2P@G5j6Pg4-$F0t|nL$2>vg6kQ$h1b5;lLJCdK;IX)2z&>y!ZaB8_@wiKXGu=Eh zoe#?6X$v{Wo!Ll4if`iyC+XAEPQH1BVQCvk*Ko(AA>#JS8H=f?Dt8SZy75YTZv zZV`94Q!4N)c-%=od;{l?i*?jFOKi=YzvmMvI2cu%u%~f2aMRw_=3k1}f&}ZT>jEv} z{TK9x4d!oa3)Y4jZ(yKj`U{(?+L*t!wy7n!K2!}{MP;zAsS*DU`$|9lW%(QYLG>aI z6#RZV`)zB(`7^#Im2kF#+4S$r(?2&~-PDAC;vL+QK3D(K@}v+gC>7$LkOvDaSRw?N z_?PGX(n7FqY^e(d1ao6x6Dcbt;HQ6Yz9rC#e}}%6YV{R0t+JunSqf$=m}ol@V_SmPBRp~lv_n#Mqtmwwv>1{G|S zRt2i+S^|}XMYq+!w2EM5Z9w!m3`ex7HyheyBXEZLucGpXP%{8x+R!HYN;HlK!ZuXY zhXOJhc$&>$T?gqVp;RH~A{;Wq5Dz>&sIm|h3NG@%7pSO0o`&(%qdI^&mNNA$_*Vy; zS`g8?%>j{Y1(lU}4-N~UpDAtd>K9>h3$#ju$y}M1cr#3(x}~W>EyU>&2iFL2Rhl1V-(K7&c~w z+A%BHNKEv;6-C))(kWsM)J2P%l$X|?kvSdqxEYVA!#)*La=lfCrlu*_#MajZThW1y z_V#9HQx?+@*S*ea0%)+p+9`N8h%!MAPmu`9tkuC5ig`HoWX2(Wcxc2-cp-rqsIsY% zQVcd0H8s%CYze2MB52RW;4>>U0?i5q(7z(E5#!n#I1Ed_9|@^@X?1f&CE3;(*objR zCCZxcWFpfN1CrDg)>ky%u$&b7G32Up!UKafHOr}SL$G3feZb#TUEPXFqphu^so823 zrHeKZgV$2YwpQ?bD&i2_q-U0%ZnjO1Cja_C6ZWC(V)h12BM3011&*+bwyo0 z7!Vc5uD*P6>4pnRbRJ$R!wE)ETp=BPWH^^%9$A6p-nSu8bh<>FNkN= zHCEP#FjoqGRhcCwwLX|x)UT~JPG-JwtTl-Ft~$Mz2_`@|8LAA5tP-`Vx+aN5a!CZN zLqVn#3U}e_4Eo-LF4wckJBGUM8Mj%T09mZVGq}-9}>PWpS)pd93j#TD)Y1Hn~ zt_MbcWwh(7qaPg2T;EIkbDHZXV-JmGuCI8HcwN8qp7b);qmzzJa{YPIhm#;M<>P6t zho#Tzrt`iwO8O-%U*59*SpJmB6ng~n!`=IY~ zTa3l5h{4B1VWAAbhk2B6oWeounN-;095hA{o!1C9S43jNvt9Pp$^ ze=ViIR)0z1Bfp-frznU&@*Dr73Lp7M!5-u*3DPs)i;lykA1;1H;UgbrJ)-cDPxaC-^GHwR&pU7`Ch(CzrTDADM?NavtMHM} zrbpAGEzlqNFg*SIf$)*f|BqJq$lpZJ<3_|E`7@bW3Lp7XpLq%&`RlAD3Lp7frPT@_ z`FpD`DtzQ`+^T>#@T*|`vq3xnAg;}dKk{db1I=&Sg`UA|_cEox0{WXz?gc*{8R;`$ zJu37JWs&dicwF&E&Q~uAd=kqmur!F`8$u5rhbXt>yYWzygWd{*AJSN_9`FxFzj*1P zD_nSjNnGazUR5jrzmH}~^!Atvi7Zz%5Aa@9wt~TE*NeBT>@2rp@i+$fsom%-iPvuA z3cQ_{YV?GYdRECsTnoGh`X4K|p;@KUANkYCkH{}aBGd1|(NZ@Ip#LVNC-O&@cPV`2 zkBIMA_{d**mLm@R*}o6`6wl+zez|AB`{aZkZCx0?sPsqv>i4w)_}?D@|BnIi^gCgS zXJmhk7WOBw$X`NF9l)=Jia+ug^&DkvVQ>mt-yQ3VKGbFfKS4+Nqfpo zlqlRYfS&!tPlF;~@}nxQrv-lkds;mi7f|?v1L%oCJd+T&hs!0S?nnBylL!4 zcyC{JwgUKZ{ow0J59~i!E{QrmtYUrL%to9IrdQ&A0Tq9+qK4Hq)&+s6YzejoL)FzN z;tU9PH?86fvB6)7^8{?){r;*Ze@%VU`igpg6>b|^{S~22ICE)et`7tQRd}gTzZ^J* zYOM2Dw6s*T;Y=uq@bOxG@HlUi5Rbi_{38p8EYuRux=X?8lp|aU1Nn_jwibFTQp~ z!Ievk>=fLUx8TOskMkLSu}^96Enda^moHygSg_o`a>$FDfCz=1$rqn}PNto=w+1NwxHV@v_+Np(bH!{I=vwN-f~j$zdCzKx08p@7qQ zLuEzKM)UiT3OYk6NAz@P%Mic6a#IB*SVcXKGHnXrL!hO_hGOZhZ4EfI1Pr!FSgT7o zHVU*fvve^v(U$W3wN!E%VG<+*lK?17OTpwiVBE;$9Tq)Rp(4`@MOJci-*Lsadg`VBj z^0e=!OT&Co3xAmFwL;PDf>nN#lGkuTSX7j-9kE?YQM1bHb0!VFHf}nbv0vAq`Zv6D zQQLn|wXdOWKT3&3+E3dty64mKJxX3f@$b8VPBv2Pw0sK6bk*UHM6^7;UWG0VKbBSV zGcx`+fp44-Ajhz(lA3-``EA0YzGPyQ!TIGld0hu z#i-kl^#3bLzEJVyD+Ueqdpb!TccXpcw;wo)iPleBaB(R}`E9)-`@aiBtGrjqX()&m z1rh4mw<6`$K3wm|`9zB_idtS{pNNpx_mdjNYeoel?f-$2*YRihic!G@5ecK?uejLr zC=iR5*XIBl(z%fJifsR9iX^v&x2Sy5IwISD69oJwMvMXC(dQFA>UTaD dM*#88e_4{Bk?qrT+n@Z5y^?=Jgg``<{cmWWmq-8r literal 0 HcmV?d00001 diff --git a/cyoa.c b/cyoa.c new file mode 100644 index 0000000..9ddc47c --- /dev/null +++ b/cyoa.c @@ -0,0 +1,1017 @@ +/* A recursive-descent parser generated by peg 0.1.18 */ + +#include +#include +#include +#define YYRULECOUNT 18 +#line 1 "cyoa.leg" + + +#include +#include +#include + +typedef struct page_t page_t; +typedef struct footer_t footer_t; + +typedef struct page_node_t page_node_t; +typedef struct choicelist choicelist; + +struct page_node_t { + page_t *page; + page_node_t *next; +}; + +#define FOOTER_END 1 +#define FOOTER_GOTO 2 +#define FOOTER_CHOICES 3 +struct footer_t { + int type; + union { + choicelist *choices; + char *link; + }; +}; + +struct page_t { + char *id; + char *body; + footer_t footer; +}; + +typedef struct statcheck_t statcheck_t; +typedef struct statchange_t statchange_t; +typedef struct choice_t choice_t; + +#define STATCHECK_GT 1 +#define STATCHECK_LT 2 + +struct statcheck_t { + char *stat; + int value; + int rel; +}; + +struct statchange_t { + char *stat; + int addend; +}; + + +#define CHOICE_STATCHECK 0x1 +#define CHOICE_STATCHANGE 0x2 + +struct choice_t { + int flags; + int option; + char *flavor; + statcheck_t statcheck; + char *redirect; + statchange_t statchange; +}; + +struct choicelist { + choice_t *choice; + choicelist *next; +}; + +page_node_t *pages; + +choice_t *make_choice(); + +void add_page(page_t*); +void add_choice(page_t*, choice_t*); + +page_t *emit_ending(); +page_t *emit_goto(char*); +page_t *emit_choices(); + +void append_body(page_t *page, char *str); + +union value { + page_t *page; + char *string; + choice_t *choice; +}; + +#define YYSTYPE union value + + +#ifndef YY_MALLOC +#define YY_MALLOC(C, N) malloc(N) +#endif +#ifndef YY_REALLOC +#define YY_REALLOC(C, P, N) realloc(P, N) +#endif +#ifndef YY_FREE +#define YY_FREE(C, P) free(P) +#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 YYRELEASE +#define YYRELEASE yyrelease +#endif +#ifndef YY_BEGIN +#define YY_BEGIN ( yy->__begin= yy->__pos, 1) +#endif +#ifndef YY_END +#define YY_END ( yy->__end= yy->__pos, 1) +#endif +#ifdef YY_DEBUG +# define yyprintf(args) fprintf args +#else +# define yyprintf(args) +#endif +#ifndef YYSTYPE +#define YYSTYPE int +#endif +#ifndef YY_STACK_SIZE +#define YY_STACK_SIZE 128 +#endif + +#ifndef YY_BUFFER_SIZE +#define YY_BUFFER_SIZE 1024 +#endif + +#ifndef YY_PART + +typedef struct _yycontext yycontext; +typedef void (*yyaction)(yycontext *yy, char *yytext, int yyleng); +typedef struct _yythunk { int begin, end; yyaction action; struct _yythunk *next; } yythunk; + +struct _yycontext { + char *__buf; + int __buflen; + int __pos; + int __limit; + char *__text; + int __textlen; + int __begin; + int __end; + int __textmax; + yythunk *__thunks; + int __thunkslen; + int __thunkpos; + YYSTYPE __; + YYSTYPE *__val; + YYSTYPE *__vals; + int __valslen; +#ifdef YY_CTX_MEMBERS + YY_CTX_MEMBERS +#endif +}; + +#ifdef YY_CTX_LOCAL +#define YY_CTX_PARAM_ yycontext *yyctx, +#define YY_CTX_PARAM yycontext *yyctx +#define YY_CTX_ARG_ yyctx, +#define YY_CTX_ARG yyctx +#ifndef YY_INPUT +#define YY_INPUT(yy, buf, result, max_size) \ + { \ + int yyc= getchar(); \ + result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1); \ + yyprintf((stderr, "<%c>", yyc)); \ + } +#endif +#else +#define YY_CTX_PARAM_ +#define YY_CTX_PARAM +#define YY_CTX_ARG_ +#define YY_CTX_ARG +yycontext _yyctx= { 0, 0 }; +yycontext *yyctx= &_yyctx; +#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 +#endif + +YY_LOCAL(int) yyrefill(yycontext *yy) +{ + int yyn; + while (yy->__buflen - yy->__pos < 512) + { + yy->__buflen *= 2; + yy->__buf= (char *)YY_REALLOC(yy, yy->__buf, yy->__buflen); + } +#ifdef YY_CTX_LOCAL + YY_INPUT(yy, (yy->__buf + yy->__pos), yyn, (yy->__buflen - yy->__pos)); +#else + YY_INPUT((yy->__buf + yy->__pos), yyn, (yy->__buflen - yy->__pos)); +#endif + if (!yyn) return 0; + yy->__limit += yyn; + return 1; +} + +YY_LOCAL(int) yymatchDot(yycontext *yy) +{ + if (yy->__pos >= yy->__limit && !yyrefill(yy)) return 0; + ++yy->__pos; + return 1; +} + +YY_LOCAL(int) yymatchChar(yycontext *yy, int c) +{ + if (yy->__pos >= yy->__limit && !yyrefill(yy)) return 0; + if ((unsigned char)yy->__buf[yy->__pos] == c) + { + ++yy->__pos; + yyprintf((stderr, " ok yymatchChar(yy, %c) @ %s\n", c, yy->__buf+yy->__pos)); + return 1; + } + yyprintf((stderr, " fail yymatchChar(yy, %c) @ %s\n", c, yy->__buf+yy->__pos)); + return 0; +} + +YY_LOCAL(int) yymatchString(yycontext *yy, const char *s) +{ + int yysav= yy->__pos; + while (*s) + { + if (yy->__pos >= yy->__limit && !yyrefill(yy)) return 0; + if (yy->__buf[yy->__pos] != *s) + { + yy->__pos= yysav; + return 0; + } + ++s; + ++yy->__pos; + } + return 1; +} + +YY_LOCAL(int) yymatchClass(yycontext *yy, unsigned char *bits) +{ + int c; + if (yy->__pos >= yy->__limit && !yyrefill(yy)) return 0; + c= (unsigned char)yy->__buf[yy->__pos]; + if (bits[c >> 3] & (1 << (c & 7))) + { + ++yy->__pos; + yyprintf((stderr, " ok yymatchClass @ %s\n", yy->__buf+yy->__pos)); + return 1; + } + yyprintf((stderr, " fail yymatchClass @ %s\n", yy->__buf+yy->__pos)); + return 0; +} + +YY_LOCAL(void) yyDo(yycontext *yy, yyaction action, int begin, int end) +{ + while (yy->__thunkpos >= yy->__thunkslen) + { + yy->__thunkslen *= 2; + yy->__thunks= (yythunk *)YY_REALLOC(yy, yy->__thunks, sizeof(yythunk) * yy->__thunkslen); + } + yy->__thunks[yy->__thunkpos].begin= begin; + yy->__thunks[yy->__thunkpos].end= end; + yy->__thunks[yy->__thunkpos].action= action; + ++yy->__thunkpos; +} + +YY_LOCAL(int) yyText(yycontext *yy, int begin, int end) +{ + int yyleng= end - begin; + if (yyleng <= 0) + yyleng= 0; + else + { + while (yy->__textlen < (yyleng + 1)) + { + yy->__textlen *= 2; + yy->__text= (char *)YY_REALLOC(yy, yy->__text, yy->__textlen); + } + memcpy(yy->__text, yy->__buf + begin, yyleng); + } + yy->__text[yyleng]= '\0'; + return yyleng; +} + +YY_LOCAL(void) yyDone(yycontext *yy) +{ + int pos; + for (pos= 0; pos < yy->__thunkpos; ++pos) + { + yythunk *thunk= &yy->__thunks[pos]; + int yyleng= thunk->end ? yyText(yy, thunk->begin, thunk->end) : thunk->begin; + yyprintf((stderr, "DO [%d] %p %s\n", pos, thunk->action, yy->__text)); + thunk->action(yy, yy->__text, yyleng); + } + yy->__thunkpos= 0; +} + +YY_LOCAL(void) yyCommit(yycontext *yy) +{ + if ((yy->__limit -= yy->__pos)) + { + memmove(yy->__buf, yy->__buf + yy->__pos, yy->__limit); + } + yy->__begin -= yy->__pos; + yy->__end -= yy->__pos; + yy->__pos= yy->__thunkpos= 0; +} + +YY_LOCAL(int) yyAccept(yycontext *yy, int tp0) +{ + if (tp0) + { + fprintf(stderr, "accept denied at %d\n", tp0); + return 0; + } + else + { + yyDone(yy); + yyCommit(yy); + } + return 1; +} + +YY_LOCAL(void) yyPush(yycontext *yy, char *text, int count) +{ + yy->__val += count; + while (yy->__valslen <= yy->__val - yy->__vals) + { + long offset= yy->__val - yy->__vals; + yy->__valslen *= 2; + yy->__vals= (YYSTYPE *)YY_REALLOC(yy, yy->__vals, sizeof(YYSTYPE) * yy->__valslen); + yy->__val= yy->__vals + offset; + } +} +YY_LOCAL(void) yyPop(yycontext *yy, char *text, int count) { yy->__val -= count; } +YY_LOCAL(void) yySet(yycontext *yy, char *text, int count) { yy->__val[count]= yy->__; } + +#endif /* YY_PART */ + +#define YYACCEPT yyAccept(yy, yythunkpos0) + +YY_RULE(int) yy_StatName(yycontext *yy); /* 18 */ +YY_RULE(int) yy_StatChange(yycontext *yy); /* 17 */ +YY_RULE(int) yy_StatCheck(yycontext *yy); /* 16 */ +YY_RULE(int) yy_Redirect(yycontext *yy); /* 15 */ +YY_RULE(int) yy_Spacing(yycontext *yy); /* 14 */ +YY_RULE(int) yy_Choice(yycontext *yy); /* 13 */ +YY_RULE(int) yy_Goto(yycontext *yy); /* 12 */ +YY_RULE(int) yy_Ending(yycontext *yy); /* 11 */ +YY_RULE(int) yy_TextLine(yycontext *yy); /* 10 */ +YY_RULE(int) yy_Footer(yycontext *yy); /* 9 */ +YY_RULE(int) yy_Newline(yycontext *yy); /* 8 */ +YY_RULE(int) yy_Identifier(yycontext *yy); /* 7 */ +YY_RULE(int) yy_Body(yycontext *yy); /* 6 */ +YY_RULE(int) yy_Header(yycontext *yy); /* 5 */ +YY_RULE(int) yy_EndOfFile(yycontext *yy); /* 4 */ +YY_RULE(int) yy_Page(yycontext *yy); /* 3 */ +YY_RULE(int) yy_BlankLine(yycontext *yy); /* 2 */ +YY_RULE(int) yy_Story(yycontext *yy); /* 1 */ + +YY_ACTION(void) yy_1_Choice(yycontext *yy, char *yytext, int yyleng) +{ +#define __ yy->__ +#define yypos yy->__pos +#define yythunkpos yy->__thunkpos + yyprintf((stderr, "do yy_1_Choice\n")); + { +#line 120 + __.choice = make_choice(); ; + } +#undef yythunkpos +#undef yypos +#undef yy +} +YY_ACTION(void) yy_1_Goto(yycontext *yy, char *yytext, int yyleng) +{ +#define i yy->__val[-1] +#define __ yy->__ +#define yypos yy->__pos +#define yythunkpos yy->__thunkpos + yyprintf((stderr, "do yy_1_Goto\n")); + { +#line 115 + __.string = strndup(yytext, yyleng); ; + } +#undef yythunkpos +#undef yypos +#undef yy +#undef i +} +YY_ACTION(void) yy_3_Footer(yycontext *yy, char *yytext, int yyleng) +{ +#define g yy->__val[-1] +#define __ yy->__ +#define yypos yy->__pos +#define yythunkpos yy->__thunkpos + yyprintf((stderr, "do yy_3_Footer\n")); + { +#line 111 + __.page = emit_ending(); ; + } +#undef yythunkpos +#undef yypos +#undef yy +#undef g +} +YY_ACTION(void) yy_2_Footer(yycontext *yy, char *yytext, int yyleng) +{ +#define g yy->__val[-1] +#define __ yy->__ +#define yypos yy->__pos +#define yythunkpos yy->__thunkpos + yyprintf((stderr, "do yy_2_Footer\n")); + { +#line 110 + __.page = emit_goto(g.string); ; + } +#undef yythunkpos +#undef yypos +#undef yy +#undef g +} +YY_ACTION(void) yy_1_Footer(yycontext *yy, char *yytext, int yyleng) +{ +#define g yy->__val[-1] +#define __ yy->__ +#define yypos yy->__pos +#define yythunkpos yy->__thunkpos + yyprintf((stderr, "do yy_1_Footer\n")); + { +#line 109 + __.page = emit_ending(); ; + } +#undef yythunkpos +#undef yypos +#undef yy +#undef g +} +YY_ACTION(void) yy_1_TextLine(yycontext *yy, char *yytext, int yyleng) +{ +#define __ yy->__ +#define yypos yy->__pos +#define yythunkpos yy->__thunkpos + yyprintf((stderr, "do yy_1_TextLine\n")); + { +#line 107 + __.string = strndup(yytext, yyleng); ; + } +#undef yythunkpos +#undef yypos +#undef yy +} +YY_ACTION(void) yy_1_Body(yycontext *yy, char *yytext, int yyleng) +{ +#define b yy->__val[-1] +#define t yy->__val[-2] +#define __ yy->__ +#define yypos yy->__pos +#define yythunkpos yy->__thunkpos + yyprintf((stderr, "do yy_1_Body\n")); + { +#line 105 + __ = b; append_body(b.page, t.string);; + } +#undef yythunkpos +#undef yypos +#undef yy +#undef b +#undef t +} +YY_ACTION(void) yy_1_Header(yycontext *yy, char *yytext, int yyleng) +{ +#define __ yy->__ +#define yypos yy->__pos +#define yythunkpos yy->__thunkpos + yyprintf((stderr, "do yy_1_Header\n")); + { +#line 100 + __.string = strndup(yytext, yyleng); ; + } +#undef yythunkpos +#undef yypos +#undef yy +} +YY_ACTION(void) yy_1_Page(yycontext *yy, char *yytext, int yyleng) +{ +#define b yy->__val[-1] +#define h yy->__val[-2] +#define __ yy->__ +#define yypos yy->__pos +#define yythunkpos yy->__thunkpos + yyprintf((stderr, "do yy_1_Page\n")); + { +#line 97 + __.page = b.page; __.page->id = h.string; + } +#undef yythunkpos +#undef yypos +#undef yy +#undef b +#undef h +} +YY_ACTION(void) yy_1_Story(yycontext *yy, char *yytext, int yyleng) +{ +#define p yy->__val[-1] +#define __ yy->__ +#define yypos yy->__pos +#define yythunkpos yy->__thunkpos + yyprintf((stderr, "do yy_1_Story\n")); + { +#line 95 + add_page(p.page); ; + } +#undef yythunkpos +#undef yypos +#undef yy +#undef p +} + +YY_RULE(int) yy_StatName(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; + yyprintf((stderr, "%s\n", "StatName")); if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\000\376\377\377\007\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l1; + l2:; + { int yypos3= yy->__pos, yythunkpos3= yy->__thunkpos; if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\000\376\377\377\007\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l3; goto l2; + l3:; yy->__pos= yypos3; yy->__thunkpos= yythunkpos3; + } + yyprintf((stderr, " ok %s @ %s\n", "StatName", yy->__buf+yy->__pos)); + return 1; + l1:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "StatName", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_StatChange(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; + yyprintf((stderr, "%s\n", "StatChange")); if (!yymatchChar(yy, '(')) goto l4; + { int yypos5= yy->__pos, yythunkpos5= yy->__thunkpos; if (!yymatchChar(yy, '+')) goto l6; goto l5; + l6:; yy->__pos= yypos5; yy->__thunkpos= yythunkpos5; if (!yymatchChar(yy, '-')) goto l4; + } + l5:; if (!yymatchClass(yy, (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 l4; + l7:; + { int yypos8= yy->__pos, yythunkpos8= yy->__thunkpos; if (!yymatchClass(yy, (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 l8; goto l7; + l8:; yy->__pos= yypos8; yy->__thunkpos= yythunkpos8; + } if (!yy_Spacing(yy)) goto l4; if (!yy_StatName(yy)) goto l4; if (!yymatchChar(yy, ')')) goto l4; + yyprintf((stderr, " ok %s @ %s\n", "StatChange", yy->__buf+yy->__pos)); + return 1; + l4:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "StatChange", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_StatCheck(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; + yyprintf((stderr, "%s\n", "StatCheck")); if (!yymatchChar(yy, '<')) goto l9; if (!yy_StatName(yy)) goto l9; if (!yy_Spacing(yy)) goto l9; if (!yymatchClass(yy, (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 l9; + l10:; + { int yypos11= yy->__pos, yythunkpos11= yy->__thunkpos; if (!yymatchClass(yy, (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 l11; goto l10; + l11:; yy->__pos= yypos11; yy->__thunkpos= yythunkpos11; + } + { int yypos12= yy->__pos, yythunkpos12= yy->__thunkpos; + { int yypos14= yy->__pos, yythunkpos14= yy->__thunkpos; if (!yymatchChar(yy, '+')) goto l15; goto l14; + l15:; yy->__pos= yypos14; yy->__thunkpos= yythunkpos14; if (!yymatchChar(yy, '-')) goto l12; + } + l14:; goto l13; + l12:; yy->__pos= yypos12; yy->__thunkpos= yythunkpos12; + } + l13:; if (!yymatchChar(yy, '>')) goto l9; + yyprintf((stderr, " ok %s @ %s\n", "StatCheck", yy->__buf+yy->__pos)); + return 1; + l9:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "StatCheck", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_Redirect(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; + yyprintf((stderr, "%s\n", "Redirect")); + { int yypos17= yy->__pos, yythunkpos17= yy->__thunkpos; if (!yy_StatCheck(yy)) goto l17; goto l18; + l17:; yy->__pos= yypos17; yy->__thunkpos= yythunkpos17; + } + l18:; if (!yy_Spacing(yy)) goto l16; if (!yymatchChar(yy, '[')) goto l16; if (!yy_Identifier(yy)) goto l16; if (!yymatchChar(yy, ']')) goto l16; if (!yy_Spacing(yy)) goto l16; + { int yypos19= yy->__pos, yythunkpos19= yy->__thunkpos; if (!yy_StatChange(yy)) goto l19; goto l20; + l19:; yy->__pos= yypos19; yy->__thunkpos= yythunkpos19; + } + l20:; if (!yy_Newline(yy)) goto l16; + yyprintf((stderr, " ok %s @ %s\n", "Redirect", yy->__buf+yy->__pos)); + return 1; + l16:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "Redirect", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_Spacing(yycontext *yy) +{ + yyprintf((stderr, "%s\n", "Spacing")); + l22:; + { int yypos23= yy->__pos, yythunkpos23= yy->__thunkpos; + { int yypos24= yy->__pos, yythunkpos24= yy->__thunkpos; if (!yymatchChar(yy, ' ')) goto l25; goto l24; + l25:; yy->__pos= yypos24; yy->__thunkpos= yythunkpos24; if (!yymatchChar(yy, '\t')) goto l23; + } + l24:; goto l22; + l23:; yy->__pos= yypos23; yy->__thunkpos= yythunkpos23; + } + yyprintf((stderr, " ok %s @ %s\n", "Spacing", yy->__buf+yy->__pos)); + return 1; +} +YY_RULE(int) yy_Choice(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; + yyprintf((stderr, "%s\n", "Choice")); yyDo(yy, yy_1_Choice, yy->__begin, yy->__end); if (!yymatchClass(yy, (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 l26; + l27:; + { int yypos28= yy->__pos, yythunkpos28= yy->__thunkpos; if (!yymatchClass(yy, (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 l28; goto l27; + l28:; yy->__pos= yypos28; yy->__thunkpos= yythunkpos28; + } if (!yymatchChar(yy, ')')) goto l26; if (!yy_Spacing(yy)) goto l26; yyText(yy, yy->__begin, yy->__end); { +#define yytext yy->__text +#define yyleng yy->__textlen +if (!(YY_BEGIN)) goto l26; +#undef yytext +#undef yyleng + } + { int yypos31= yy->__pos, yythunkpos31= yy->__thunkpos; if (!yy_Redirect(yy)) goto l31; goto l26; + l31:; yy->__pos= yypos31; yy->__thunkpos= yythunkpos31; + } if (!yymatchDot(yy)) goto l26; + l29:; + { int yypos30= yy->__pos, yythunkpos30= yy->__thunkpos; + { int yypos32= yy->__pos, yythunkpos32= yy->__thunkpos; if (!yy_Redirect(yy)) goto l32; goto l30; + l32:; yy->__pos= yypos32; yy->__thunkpos= yythunkpos32; + } if (!yymatchDot(yy)) goto l30; goto l29; + l30:; yy->__pos= yypos30; yy->__thunkpos= yythunkpos30; + } yyText(yy, yy->__begin, yy->__end); { +#define yytext yy->__text +#define yyleng yy->__textlen +if (!(YY_END)) goto l26; +#undef yytext +#undef yyleng + } if (!yy_Redirect(yy)) goto l26; + yyprintf((stderr, " ok %s @ %s\n", "Choice", yy->__buf+yy->__pos)); + return 1; + l26:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "Choice", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_Goto(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; yyDo(yy, yyPush, 1, 0); + yyprintf((stderr, "%s\n", "Goto")); if (!yymatchString(yy, "GOTO")) goto l33; if (!yy_Spacing(yy)) goto l33; yyText(yy, yy->__begin, yy->__end); { +#define yytext yy->__text +#define yyleng yy->__textlen +if (!(YY_BEGIN)) goto l33; +#undef yytext +#undef yyleng + } if (!yy_Identifier(yy)) goto l33; yyDo(yy, yySet, -1, 0); yyText(yy, yy->__begin, yy->__end); { +#define yytext yy->__text +#define yyleng yy->__textlen +if (!(YY_END)) goto l33; +#undef yytext +#undef yyleng + } if (!yy_Newline(yy)) goto l33; yyDo(yy, yy_1_Goto, yy->__begin, yy->__end); + yyprintf((stderr, " ok %s @ %s\n", "Goto", yy->__buf+yy->__pos)); yyDo(yy, yyPop, 1, 0); + return 1; + l33:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "Goto", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_Ending(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; + yyprintf((stderr, "%s\n", "Ending")); if (!yymatchString(yy, "THE END")) goto l34; if (!yy_Newline(yy)) goto l34; + yyprintf((stderr, " ok %s @ %s\n", "Ending", yy->__buf+yy->__pos)); + return 1; + l34:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "Ending", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_TextLine(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; + yyprintf((stderr, "%s\n", "TextLine")); yyText(yy, yy->__begin, yy->__end); { +#define yytext yy->__text +#define yyleng yy->__textlen +if (!(YY_BEGIN)) goto l35; +#undef yytext +#undef yyleng + } + l36:; + { int yypos37= yy->__pos, yythunkpos37= yy->__thunkpos; + { int yypos38= yy->__pos, yythunkpos38= yy->__thunkpos; if (!yy_Newline(yy)) goto l38; goto l37; + l38:; yy->__pos= yypos38; yy->__thunkpos= yythunkpos38; + } if (!yymatchDot(yy)) goto l37; goto l36; + l37:; yy->__pos= yypos37; yy->__thunkpos= yythunkpos37; + } if (!yy_Newline(yy)) goto l35; yyText(yy, yy->__begin, yy->__end); { +#define yytext yy->__text +#define yyleng yy->__textlen +if (!(YY_END)) goto l35; +#undef yytext +#undef yyleng + } yyDo(yy, yy_1_TextLine, yy->__begin, yy->__end); + yyprintf((stderr, " ok %s @ %s\n", "TextLine", yy->__buf+yy->__pos)); + return 1; + l35:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "TextLine", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_Footer(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; yyDo(yy, yyPush, 1, 0); + yyprintf((stderr, "%s\n", "Footer")); + { int yypos40= yy->__pos, yythunkpos40= yy->__thunkpos; if (!yy_Ending(yy)) goto l41; yyDo(yy, yy_1_Footer, yy->__begin, yy->__end); goto l40; + l41:; yy->__pos= yypos40; yy->__thunkpos= yythunkpos40; if (!yy_Goto(yy)) goto l42; yyDo(yy, yySet, -1, 0); yyDo(yy, yy_2_Footer, yy->__begin, yy->__end); goto l40; + l42:; yy->__pos= yypos40; yy->__thunkpos= yythunkpos40; if (!yy_Choice(yy)) goto l39; + l43:; + { int yypos44= yy->__pos, yythunkpos44= yy->__thunkpos; if (!yy_Choice(yy)) goto l44; goto l43; + l44:; yy->__pos= yypos44; yy->__thunkpos= yythunkpos44; + } yyDo(yy, yy_3_Footer, yy->__begin, yy->__end); + } + l40:; + yyprintf((stderr, " ok %s @ %s\n", "Footer", yy->__buf+yy->__pos)); yyDo(yy, yyPop, 1, 0); + return 1; + l39:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "Footer", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_Newline(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; + yyprintf((stderr, "%s\n", "Newline")); + { int yypos46= yy->__pos, yythunkpos46= yy->__thunkpos; if (!yymatchString(yy, "\r\n")) goto l47; goto l46; + l47:; yy->__pos= yypos46; yy->__thunkpos= yythunkpos46; if (!yymatchChar(yy, '\r')) goto l48; goto l46; + l48:; yy->__pos= yypos46; yy->__thunkpos= yythunkpos46; if (!yymatchChar(yy, '\n')) goto l45; + } + l46:; + yyprintf((stderr, " ok %s @ %s\n", "Newline", yy->__buf+yy->__pos)); + return 1; + l45:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "Newline", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_Identifier(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; + yyprintf((stderr, "%s\n", "Identifier")); if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\000\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l49; if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\376\377\377\207\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l49; + l50:; + { int yypos51= yy->__pos, yythunkpos51= yy->__thunkpos; if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\376\377\377\207\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l51; goto l50; + l51:; yy->__pos= yypos51; yy->__thunkpos= yythunkpos51; + } + yyprintf((stderr, " ok %s @ %s\n", "Identifier", yy->__buf+yy->__pos)); + return 1; + l49:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "Identifier", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_Body(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; yyDo(yy, yyPush, 2, 0); + yyprintf((stderr, "%s\n", "Body")); + { int yypos53= yy->__pos, yythunkpos53= yy->__thunkpos; if (!yy_Footer(yy)) goto l54; goto l53; + l54:; yy->__pos= yypos53; yy->__thunkpos= yythunkpos53; if (!yy_TextLine(yy)) goto l52; yyDo(yy, yySet, -2, 0); if (!yy_Body(yy)) goto l52; yyDo(yy, yySet, -1, 0); yyDo(yy, yy_1_Body, yy->__begin, yy->__end); + } + l53:; + yyprintf((stderr, " ok %s @ %s\n", "Body", yy->__buf+yy->__pos)); yyDo(yy, yyPop, 2, 0); + return 1; + l52:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "Body", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_Header(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; + yyprintf((stderr, "%s\n", "Header")); yyText(yy, yy->__begin, yy->__end); { +#define yytext yy->__text +#define yyleng yy->__textlen +if (!(YY_BEGIN)) goto l55; +#undef yytext +#undef yyleng + } if (!yy_Identifier(yy)) goto l55; yyText(yy, yy->__begin, yy->__end); { +#define yytext yy->__text +#define yyleng yy->__textlen +if (!(YY_END)) goto l55; +#undef yytext +#undef yyleng + } yyDo(yy, yy_1_Header, yy->__begin, yy->__end); if (!yy_Newline(yy)) goto l55; + l56:; + { int yypos57= yy->__pos, yythunkpos57= yy->__thunkpos; if (!yy_BlankLine(yy)) goto l57; goto l56; + l57:; yy->__pos= yypos57; yy->__thunkpos= yythunkpos57; + } + yyprintf((stderr, " ok %s @ %s\n", "Header", yy->__buf+yy->__pos)); + return 1; + l55:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "Header", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_EndOfFile(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; + yyprintf((stderr, "%s\n", "EndOfFile")); + { int yypos59= yy->__pos, yythunkpos59= yy->__thunkpos; if (!yymatchDot(yy)) goto l59; goto l58; + l59:; yy->__pos= yypos59; yy->__thunkpos= yythunkpos59; + } + yyprintf((stderr, " ok %s @ %s\n", "EndOfFile", yy->__buf+yy->__pos)); + return 1; + l58:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "EndOfFile", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_Page(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; yyDo(yy, yyPush, 2, 0); + yyprintf((stderr, "%s\n", "Page")); if (!yy_Header(yy)) goto l60; yyDo(yy, yySet, -2, 0); if (!yy_Body(yy)) goto l60; yyDo(yy, yySet, -1, 0); yyDo(yy, yy_1_Page, yy->__begin, yy->__end); + l61:; + { int yypos62= yy->__pos, yythunkpos62= yy->__thunkpos; if (!yy_BlankLine(yy)) goto l62; goto l61; + l62:; yy->__pos= yypos62; yy->__thunkpos= yythunkpos62; + } + yyprintf((stderr, " ok %s @ %s\n", "Page", yy->__buf+yy->__pos)); yyDo(yy, yyPop, 2, 0); + return 1; + l60:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "Page", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_BlankLine(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; + yyprintf((stderr, "%s\n", "BlankLine")); if (!yy_Spacing(yy)) goto l63; if (!yy_Newline(yy)) goto l63; + yyprintf((stderr, " ok %s @ %s\n", "BlankLine", yy->__buf+yy->__pos)); + return 1; + l63:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "BlankLine", yy->__buf+yy->__pos)); + return 0; +} +YY_RULE(int) yy_Story(yycontext *yy) +{ int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos; yyDo(yy, yyPush, 1, 0); + yyprintf((stderr, "%s\n", "Story")); + l65:; + { int yypos66= yy->__pos, yythunkpos66= yy->__thunkpos; if (!yy_BlankLine(yy)) goto l66; goto l65; + l66:; yy->__pos= yypos66; yy->__thunkpos= yythunkpos66; + } if (!yy_Page(yy)) goto l64; yyDo(yy, yySet, -1, 0); yyDo(yy, yy_1_Story, yy->__begin, yy->__end); + l67:; + { int yypos68= yy->__pos, yythunkpos68= yy->__thunkpos; if (!yy_Page(yy)) goto l68; yyDo(yy, yySet, -1, 0); yyDo(yy, yy_1_Story, yy->__begin, yy->__end); goto l67; + l68:; yy->__pos= yypos68; yy->__thunkpos= yythunkpos68; + } if (!yy_EndOfFile(yy)) goto l64; + yyprintf((stderr, " ok %s @ %s\n", "Story", yy->__buf+yy->__pos)); yyDo(yy, yyPop, 1, 0); + return 1; + l64:; yy->__pos= yypos0; yy->__thunkpos= yythunkpos0; + yyprintf((stderr, " fail %s @ %s\n", "Story", yy->__buf+yy->__pos)); + return 0; +} + +#ifndef YY_PART + +typedef int (*yyrule)(yycontext *yy); + +YY_PARSE(int) YYPARSEFROM(YY_CTX_PARAM_ yyrule yystart) +{ + int yyok; + if (!yyctx->__buflen) + { + yyctx->__buflen= YY_BUFFER_SIZE; + yyctx->__buf= (char *)YY_MALLOC(yyctx, yyctx->__buflen); + yyctx->__textlen= YY_BUFFER_SIZE; + yyctx->__text= (char *)YY_MALLOC(yyctx, yyctx->__textlen); + yyctx->__thunkslen= YY_STACK_SIZE; + yyctx->__thunks= (yythunk *)YY_MALLOC(yyctx, sizeof(yythunk) * yyctx->__thunkslen); + yyctx->__valslen= YY_STACK_SIZE; + yyctx->__vals= (YYSTYPE *)YY_MALLOC(yyctx, sizeof(YYSTYPE) * yyctx->__valslen); + yyctx->__begin= yyctx->__end= yyctx->__pos= yyctx->__limit= yyctx->__thunkpos= 0; + } + yyctx->__begin= yyctx->__end= yyctx->__pos; + yyctx->__thunkpos= 0; + yyctx->__val= yyctx->__vals; + yyok= yystart(yyctx); + if (yyok) yyDone(yyctx); + yyCommit(yyctx); + return yyok; +} + +YY_PARSE(int) YYPARSE(YY_CTX_PARAM) +{ + return YYPARSEFROM(YY_CTX_ARG_ yy_Story); +} + +YY_PARSE(yycontext *) YYRELEASE(yycontext *yyctx) +{ + if (yyctx->__buflen) + { + yyctx->__buflen= 0; + YY_FREE(yyctx, yyctx->__buf); + YY_FREE(yyctx, yyctx->__text); + YY_FREE(yyctx, yyctx->__thunks); + YY_FREE(yyctx, yyctx->__vals); + } + return yyctx; +} + +#endif +#line 138 "cyoa.leg" + + +void add_page(page_t *page) { + page_node_t *mynode = (page_node_t*) malloc(sizeof(page_node_t)); + mynode->page = page; + mynode->next = NULL; + + page_node_t *curr = pages; + page_node_t *prev = NULL; + + if (curr) { + for(; curr; prev = curr, curr = curr->next); + prev->next = mynode; + } else { + pages = mynode; + } +} + +void add_choice(page_t *page, choice_t* choice) { + assert(page != choice); + choicelist *mychoices = (choicelist *) malloc(sizeof(choicelist)); + mychoices->choice = choice; + mychoices->next = NULL; + + choicelist *curr = page->footer.choices; + choicelist *prev = NULL; + + if (curr) { + for(; curr; prev = curr, curr = curr->next); + prev->next = mychoices; + } else { + page->footer.choices = mychoices; + } +} + +static inline page_t *make_page() { + page_t *mypage = (page_t*) malloc(sizeof(page_t)); + mypage->id = NULL; + mypage->body = NULL; + return mypage; +} + +inline choice_t *make_choice() { + choice_t *mychoice = (choice_t*) malloc(sizeof(choice_t)); + mychoice->flags = 0x0; + printf("choice 0x%x\n", mychoice); + return mychoice; +} + +page_t *emit_goto(char *id) { + page_t *mypage = make_page(); + mypage->footer.type = FOOTER_GOTO; + mypage->footer.link = id; + return mypage; +} + +page_t *emit_ending() { + page_t *mypage = make_page(); + mypage->footer.type = FOOTER_END; + return mypage; +} + +page_t *emit_choices() { + page_t *mypage = make_page(); + mypage->footer.type = FOOTER_CHOICES; + mypage->footer.choices = NULL; + printf("page 0x%x\n", mypage); + return mypage; +} + +void append_body(page_t *page, char *str) { + if (page->body) { + int size = strlen(page->body) + strlen(str) + 1; + char *newstring = (char*) calloc(size, sizeof(char)); + strcpy(newstring, str); + strcat(newstring, page->body); + free(page->body); + page->body = newstring; + } else { + page->body = str; + } +} + +void print_page(page_t *page) { + printf("HEADER: %s\nBODY: %s\n", page->id, page->body); + switch (page->footer.type) { + case FOOTER_END: + printf("THE END\n"); + break; + case FOOTER_GOTO: + printf("GOTO %s\n", page->footer.link); + break; + case FOOTER_CHOICES: + printf("CHOICES:\n"); + break; + } +} + +int main() { + if (!yyparse()) { + printf("Parsing Error!\n"); + return 1; + } else { + for (page_node_t *curr = pages; curr; curr = curr->next) { + print_page(curr->page); + } + } + return 0; +} + +/* Local Variables: */ +/* mode: text */ +/* End: */ + diff --git a/cyoa.leg b/cyoa.leg new file mode 100644 index 0000000..e01f793 --- /dev/null +++ b/cyoa.leg @@ -0,0 +1,250 @@ +%{ + +#include +#include +#include + +typedef struct page_t page_t; +typedef struct footer_t footer_t; + +typedef struct page_node_t page_node_t; +typedef struct choicelist choicelist; + +struct page_node_t { + page_t *page; + page_node_t *next; +}; + +#define FOOTER_END 1 +#define FOOTER_GOTO 2 +#define FOOTER_CHOICES 3 +struct footer_t { + int type; + union { + choicelist *choices; + char *link; + }; +}; + +struct page_t { + char *id; + char *body; + footer_t footer; +}; + +typedef struct statcheck_t statcheck_t; +typedef struct statchange_t statchange_t; +typedef struct choice_t choice_t; + +#define STATCHECK_GT 1 +#define STATCHECK_LT 2 + +struct statcheck_t { + char *stat; + int value; + int rel; +}; + +struct statchange_t { + char *stat; + int addend; +}; + + +#define CHOICE_STATCHECK 0x1 +#define CHOICE_STATCHANGE 0x2 + +struct choice_t { + int flags; + int option; + char *flavor; + statcheck_t statcheck; + char *redirect; + statchange_t statchange; +}; + +struct choicelist { + choice_t *choice; + choicelist *next; +}; + +page_node_t *pages; + +choice_t *make_choice(); + +void add_page(page_t*); +void add_choice(page_t*, choice_t*); + +page_t *emit_ending(); +page_t *emit_goto(char*); +page_t *emit_choices(); + +void append_body(page_t *page, char *str); + +union value { + page_t *page; + char *string; + choice_t *choice; +}; + +#define YYSTYPE union value + +%} + + +Story = BlankLine* (p:Page { add_page(p.page); })+ EndOfFile; + +Page = h:Header b:Body { $$.page = b.page; $$.page->id = h.string} + BlankLine*; + +Header = < Identifier > { $$.string = strndup(yytext, yyleng); } + Newline BlankLine*; + +Identifier = [A-Z][A-Z0-9_]+; + +Body = Footer | t:TextLine b:Body { $$ = b; append_body(b.page, t.string);}; + +TextLine = < (!Newline .)* Newline > { $$.string = strndup(yytext, yyleng); }; + +Footer = Ending { $$.page = emit_ending(); } + | g:Goto { $$.page = emit_goto(g.string); } + | Choice+ { $$.page = emit_ending(); } + ; + +Goto = 'GOTO' Spacing < i:Identifier > Newline + { $$.string = strndup(yytext, yyleng); } + ; + +Ending = 'THE END' Newline; + +Choice = { $$.choice = make_choice(); } [0-9]+ ')' Spacing < (!Redirect .)+ > Redirect; + +Redirect = StatCheck? Spacing '[' Identifier ']' Spacing StatChange? Newline; + +StatCheck = '<' StatName Spacing [0-9]+ ('+' | '-')? '>'; + +StatChange = '(' ('+' | '-') [0-9]+ Spacing StatName ')'; + +StatName = [A-Za-z]+; + +EndOfFile = !.; + +BlankLine = Spacing Newline; + +Spacing = (' ' | '\t')*; + +Newline = '\r\n' | '\r' | '\n'; + +%% + +void add_page(page_t *page) { + page_node_t *mynode = (page_node_t*) malloc(sizeof(page_node_t)); + mynode->page = page; + mynode->next = NULL; + + page_node_t *curr = pages; + page_node_t *prev = NULL; + + if (curr) { + for(; curr; prev = curr, curr = curr->next); + prev->next = mynode; + } else { + pages = mynode; + } +} + +void add_choice(page_t *page, choice_t* choice) { + assert(page != choice); + choicelist *mychoices = (choicelist *) malloc(sizeof(choicelist)); + mychoices->choice = choice; + mychoices->next = NULL; + + choicelist *curr = page->footer.choices; + choicelist *prev = NULL; + + if (curr) { + for(; curr; prev = curr, curr = curr->next); + prev->next = mychoices; + } else { + page->footer.choices = mychoices; + } +} + +static inline page_t *make_page() { + page_t *mypage = (page_t*) malloc(sizeof(page_t)); + mypage->id = NULL; + mypage->body = NULL; + return mypage; +} + +inline choice_t *make_choice() { + choice_t *mychoice = (choice_t*) malloc(sizeof(choice_t)); + mychoice->flags = 0x0; + printf("choice 0x%x\n", mychoice); + return mychoice; +} + +page_t *emit_goto(char *id) { + page_t *mypage = make_page(); + mypage->footer.type = FOOTER_GOTO; + mypage->footer.link = id; + return mypage; +} + +page_t *emit_ending() { + page_t *mypage = make_page(); + mypage->footer.type = FOOTER_END; + return mypage; +} + +page_t *emit_choices() { + page_t *mypage = make_page(); + mypage->footer.type = FOOTER_CHOICES; + mypage->footer.choices = NULL; + printf("page 0x%x\n", mypage); + return mypage; +} + +void append_body(page_t *page, char *str) { + if (page->body) { + int size = strlen(page->body) + strlen(str) + 1; + char *newstring = (char*) calloc(size, sizeof(char)); + strcpy(newstring, str); + strcat(newstring, page->body); + free(page->body); + page->body = newstring; + } else { + page->body = str; + } +} + +void print_page(page_t *page) { + printf("HEADER: %s\nBODY: %s\n", page->id, page->body); + switch (page->footer.type) { + case FOOTER_END: + printf("THE END\n"); + break; + case FOOTER_GOTO: + printf("GOTO %s\n", page->footer.link); + break; + case FOOTER_CHOICES: + printf("CHOICES:\n"); + break; + } +} + +int main() { + if (!yyparse()) { + printf("Parsing Error!\n"); + return 1; + } else { + for (page_node_t *curr = pages; curr; curr = curr->next) { + print_page(curr->page); + } + } + return 0; +} + +/* Local Variables: */ +/* mode: text */ +/* End: */ diff --git a/demo.story b/demo.story new file mode 100644 index 0000000..d0ada21 --- /dev/null +++ b/demo.story @@ -0,0 +1,61 @@ +START + +You are a young boy at a carnival. The Ferris wheel is in front of you and looks tempting. You can also see the dark ride. + +1) Ride the Ferris wheel [WHEEL] +2) Ride the Dark ride [RIDE] + +RIDE + +You ride the dark ride. It's not really that interesting and by the time it's over you have to go home. + +THE END + +WHEEL + +You get to the front of the line, and you are placed in a gondola with your school crush. The two of you have +been playmates for some time, but you think that you are old enough to be more. + +1) Lean in and kiss them at the top [KISS] (+1 Romance) +2) Let the moment pass [NOKISS] (+1 Willpower) + +KISS + +You lean in and give them a quick kiss on the cheek. It's very romantic in the moonlight. + +GOTO AFTERWHEEL + +NOKISS + +You let the moment pass, and instead look out over the hills towards the moon. You feel like +anything is possible in your life. + +GOTO AFTERWHEEL + +AFTERWHEEL + +After you get off the Ferris Wheel, it is getting a bit late. You still want to go on the dark ride, maybe with +your school crush. You can also go ride the teacups. Or you could just go home. + +1) Go with your crush to the dark ride [RIDE_TOGETHER] +2) Ride the teacups [TEACUPS] +3) Go home [HOME] + +RIDE_TOGETHER + +You ride into the dark tunnel and you can feel your friend squeeze your hand. A warm feeling covers your body. + +THE END + +TEACUPS + +The swirling vortex envelopes you, but you are undeterred. You leave the park feeling like you are ready to take +on the world. + +THE END + +HOME + +You return home to your bed. A soft pillow greets you and you dream of the night's festivities. + +THE END diff --git a/simple.story b/simple.story new file mode 100644 index 0000000..f236047 --- /dev/null +++ b/simple.story @@ -0,0 +1,13 @@ +START + +One day Dane took a really big shit. +Dane: "Wow, that was a really big shit" + +1) Don't die [NEXT] + +NEXT + +Then he died. +Fuck you Dane + +THE END diff --git a/spec.txt b/spec.txt new file mode 100644 index 0000000..8ee06e4 --- /dev/null +++ b/spec.txt @@ -0,0 +1,57 @@ +################################### +# Untitled Storybook Game Project # +################################### + +This will be a project to create a system whereby "Choose Your Own Adventure" (CYOA) style stories can be easily written. + +Each page will read out story elements, and then prompt the user to select a new page based on a decision +they would like to make. + +Making certain choices will also award ad-hoc stat bonuses i.e. +1 Knowledge or something, all +stats are presumed to be 0 until points are awarded. This stat system also includes the ability +to make checks when certain choices become available, or once they are selected. + +Requirements: + 1. A language description and recognizer for creating CYOA-style stories. + 2. An interpreter and interface for interacting with these stories. + 3. Both story-writing and story-interaction tools need to be cross platform and relatively straightforwards for + a non technical user to operate. + +Story language PEG: (with apologies, this is my first PEG) + +Story <- BlankLine* Page+ EndOfFile +Page <- Header Body BlankLine* +Header <- Identifier Newline BlankLine* +Identifier <- [A-Z][A-Z0-9_]* +Body <- Footer / TextLine Body +TextLine <- (!Newline .)+ Newline +Footer <- Ending / Goto / Choice+ +Goto <- 'GOTO' Spacing Identifier Newline +Ending <- 'THE END' Newline +Choice <- [0-9]+ ')' Spacing (!Redirect .)+ Redirect +Redirect <- StatCheck? Spacing '[' Identifier ']' Spacing StatChange? Newline +StatCheck <- '<' StatName Spacing [0-9]+ ('+' / '-')? '>' +StatChange <- '(' ('+' / '-') [0-9]+ Spacing StatName ')' +StatName <- [A-Za-z]+ +EndOfFile <- !. +BlankLine <- Spacing Newline +Spacing <- (' ' / '\t')* +Newline <- '\r\n' / '\r' / '\n' + +Work log: + +12/13/21 +Right now I need to make a decision before any of the work has started on how the user would interact with the system. +I think for a MVP it would be okay to just write a console application, but I think for the long term there needs to +be a decision made on how this will work. I'm leaning towards one of three options. + +1) We put the whole thing on the JVM and make it a library or something. +Maybe in the future we can make a frontend for making and playing stories +as a web interface, but we could make the interface pluggable as far as the backend is concerned. +2) I build this non-traditional game in a traditional game engine (Godot probably). This ensures cross-platform +availibility. I'm not 100% sure about my ability to use parsers in Godot, but this looks like a good option. +3) I build this as a reactive web page. I know this sounds like a terrible idea, but there are actually a lot +of cool image and text transition libraries out there. It does mean setting up something like React tho, which +like, just kill me now + +Out of the three of these I think the Java thing would be the easiest and I think the Godot thing would be the best.