storybook/cyoa.leg

215 lines
4.4 KiB
Plaintext
Raw Normal View History

2021-12-17 13:54:05 -06:00
%{
2021-12-17 15:47:46 -06:00
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cassert>
2021-12-17 13:54:05 -06:00
typedef struct page_t page_t;
typedef struct footer_t footer_t;
2021-12-17 16:02:24 -06:00
typedef struct statcheck_t statcheck_t;
typedef struct statchange_t statchange_t;
typedef struct choice_t choice_t;
2021-12-17 13:54:05 -06:00
#define FOOTER_END 1
#define FOOTER_GOTO 2
#define FOOTER_CHOICES 3
struct footer_t {
int type;
union {
2021-12-17 16:02:24 -06:00
std::vector<choice_t*> choices;
2021-12-17 13:54:05 -06:00
char *link;
};
};
struct page_t {
char *id;
char *body;
footer_t footer;
};
#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;
};
2021-12-17 16:02:24 -06:00
std::vector<page_t*> pages;
2021-12-17 13:54:05 -06:00
choice_t *make_choice();
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;
2021-12-17 16:02:24 -06:00
std::vector<choice_t*> *choices;
2021-12-17 15:42:47 -06:00
int num;
2021-12-17 13:54:05 -06:00
};
#define YYSTYPE union value
%}
2021-12-17 16:02:24 -06:00
Story = BlankLine* (p:Page { pages.push_back(p.page); })+ EndOfFile;
2021-12-17 13:54:05 -06:00
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); }
2021-12-17 15:47:46 -06:00
| c:ChoiceList { $$.page = emit_choices(); }
2021-12-17 13:54:05 -06:00
;
Goto = 'GOTO' Spacing < i:Identifier > Newline
{ $$.string = strndup(yytext, yyleng); }
;
Ending = 'THE END' Newline;
2021-12-17 16:02:24 -06:00
ChoiceList = c:Choice l:ChoiceList { $$ = l; $$.choices->push_back(c.choice); }
| c:Choice { $$.choices = new std::vector<choice_t*>(); $$.choices->push_back(c.choice); }
2021-12-17 15:42:47 -06:00
Choice = b:Bullet f:Freetext r:Redirect
{
$$ = r;
$$.choice->option = b.num;
$$.choice->flavor = f.string;
};
Bullet = < [0-9]+ > ')' Spacing { $$.num = atoi(yytext); };
Freetext = < (!Redirect .)+ > { $$.string = strndup(yytext, yyleng); };
2021-12-17 13:54:05 -06:00
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';
%%
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;
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 {
2021-12-17 16:02:24 -06:00
for (page_t* page: pages) {
print_page(page);
2021-12-17 13:54:05 -06:00
}
}
return 0;
}
/* Local Variables: */
/* mode: text */
/* End: */