Organization, ignore binaries
This commit is contained in:
10
src/Makefile
Normal file
10
src/Makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
CC = g++
|
||||
CFLAGS = -g
|
||||
|
||||
all: storybook
|
||||
storybook: main.c cyoa.c
|
||||
$(CC) $(CFLAGS) main.c -o storybook
|
||||
cyoa.c: cyoa.leg
|
||||
leg -o $@ $^
|
||||
clean:
|
||||
rm -f cyoa.c cyoa storybook
|
||||
234
src/cyoa.leg
Normal file
234
src/cyoa.leg
Normal file
@@ -0,0 +1,234 @@
|
||||
%{
|
||||
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
FILE* yyin = stdin;
|
||||
|
||||
#define YY_INPUT(buf, result, max_size) { \
|
||||
int yyc = getc(yyin); \
|
||||
result = (EOF == yyc) ? 0 : (*(buf) = yyc, 1); \
|
||||
}
|
||||
|
||||
#define STATCHECK_GT 1
|
||||
#define STATCHECK_LT 2
|
||||
|
||||
struct statcheck_t {
|
||||
char *stat;
|
||||
int value;
|
||||
int rel;
|
||||
};
|
||||
|
||||
struct statchange_t {
|
||||
char *stat;
|
||||
int addend;
|
||||
};
|
||||
|
||||
struct Choice {
|
||||
int option;
|
||||
char *flavor;
|
||||
statcheck_t *statcheck;
|
||||
char *id;
|
||||
statchange_t *statchange;
|
||||
|
||||
Choice(char*, statcheck_t *statcheck, statchange_t *statchange);
|
||||
};
|
||||
|
||||
enum class FooterType {
|
||||
End,
|
||||
Goto,
|
||||
Choices
|
||||
};
|
||||
|
||||
struct Footer {
|
||||
FooterType type;
|
||||
union {
|
||||
std::vector<Choice*> *choices;
|
||||
char *link;
|
||||
};
|
||||
|
||||
Footer();
|
||||
~Footer();
|
||||
};
|
||||
|
||||
struct Page {
|
||||
char *id;
|
||||
char *body;
|
||||
Footer footer;
|
||||
|
||||
Page();
|
||||
~Page();
|
||||
};
|
||||
|
||||
std::vector<Page*> pages;
|
||||
|
||||
Page *emit_ending();
|
||||
Page *emit_goto(char*);
|
||||
Page *emit_choices(std::vector<Choice*>*);
|
||||
|
||||
void append_body(Page *page, char *str);
|
||||
|
||||
union value {
|
||||
Page *page;
|
||||
char *string;
|
||||
Choice *choice;
|
||||
std::vector<Choice*> *choices;
|
||||
int num;
|
||||
statcheck_t *statcheck;
|
||||
statchange_t *statchange;
|
||||
};
|
||||
|
||||
#define YYSTYPE union value
|
||||
|
||||
%}
|
||||
|
||||
|
||||
Story = BlankLine* (p:Page { pages.push_back(p.page); })+ EndOfFile
|
||||
|
||||
Page = h:Header b:Body { $$.page = b.page; $$.page->id = h.string}
|
||||
BlankLine*
|
||||
|
||||
Header = < i:Identifier > Newline BlankLine* { $$ = i; }
|
||||
|
||||
Identifier = < [A-Z][A-Z0-9_]+ > - { $$.string = strndup(yytext, yyleng); }
|
||||
|
||||
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); }
|
||||
| c:ChoiceList { $$.page = emit_choices(c.choices); }
|
||||
|
||||
Goto = 'GOTO' - < i:Identifier > Newline
|
||||
{ $$.string = strndup(yytext, yyleng); }
|
||||
|
||||
Ending = 'THE END' Newline
|
||||
|
||||
ChoiceList = c:Choice l:ChoiceList { $$ = l; $$.choices->push_back(c.choice); }
|
||||
| c:Choice { $$.choices = new std::vector<Choice*>(); $$.choices->push_back(c.choice); }
|
||||
|
||||
Choice = b:Bullet f:Freetext r:Redirect
|
||||
{
|
||||
$$ = r;
|
||||
$$.choice->option = b.num;
|
||||
$$.choice->flavor = f.string;
|
||||
}
|
||||
|
||||
Bullet = < [0-9]+ > ')' - { $$.num = atoi(yytext); }
|
||||
|
||||
Freetext = < ([^[<])+ > { $$.string = strndup(yytext, yyleng); }
|
||||
|
||||
Redirect = ck:StatCheck? '[' i:Identifier ']' - cg:StatChange? Newline
|
||||
{ $$.choice = new Choice(i.string, ck.statcheck, cg.statchange); }
|
||||
|
||||
StatCheck = '<' n:StatName v:StatVal r:StatRel '>' -
|
||||
{ $$.statcheck = new statcheck_t{n.string, v.num, r.num}; }
|
||||
|
||||
StatChange = '(' ('+' | '-') v:StatVal n:StatName ')'
|
||||
{ $$.statchange = new statchange_t{n.string, v.num}; }
|
||||
|
||||
StatName = < [A-Za-z]+ > - { $$.string = strdup(yytext); }
|
||||
|
||||
StatVal = < [0-9]+ > - { $$.num = atoi(yytext); }
|
||||
|
||||
StatRel = < ('+'|'-')? > { $$.num = 0x0 } -
|
||||
|
||||
EndOfFile = !.
|
||||
|
||||
BlankLine = - Newline
|
||||
|
||||
- = (' ' | '\t')*
|
||||
|
||||
Newline = '\r\n' | '\r' | '\n'
|
||||
|
||||
%%
|
||||
|
||||
Choice::Choice(char *id, statcheck_t *statcheck, statchange_t *statchange) {
|
||||
this->id = id;
|
||||
this->statcheck = statcheck;
|
||||
this->statchange = statchange;
|
||||
}
|
||||
|
||||
Footer::Footer() {
|
||||
}
|
||||
|
||||
Footer::~Footer() {
|
||||
}
|
||||
|
||||
Page::Page() {
|
||||
id = NULL;
|
||||
body = NULL;
|
||||
}
|
||||
|
||||
Page::~Page() {
|
||||
if (id) {
|
||||
free(id);
|
||||
}
|
||||
if (body) {
|
||||
free(body);
|
||||
}
|
||||
}
|
||||
|
||||
Page *emit_goto(char *id) {
|
||||
Page *mypage = new Page;
|
||||
mypage->footer.type = FooterType::Goto;
|
||||
mypage->footer.link = id;
|
||||
return mypage;
|
||||
}
|
||||
|
||||
Page *emit_ending() {
|
||||
Page *mypage = new Page;
|
||||
mypage->footer.type = FooterType::End;
|
||||
return mypage;
|
||||
}
|
||||
|
||||
Page *emit_choices(std::vector<Choice*> *choices) {
|
||||
Page *mypage = new Page;
|
||||
mypage->footer.type = FooterType::Choices;
|
||||
mypage->footer.choices = choices;
|
||||
return mypage;
|
||||
}
|
||||
|
||||
void append_body(Page *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 *page) {
|
||||
printf("HEADER: %s\nBODY: %s\n", page->id, page->body);
|
||||
switch (page->footer.type) {
|
||||
case FooterType::End:
|
||||
printf("THE END\n");
|
||||
break;
|
||||
case FooterType::Goto:
|
||||
printf("GOTO %s\n", page->footer.link);
|
||||
break;
|
||||
case FooterType::Choices:
|
||||
printf("CHOICES:\n");
|
||||
for (Choice *c : *page->footer.choices) {
|
||||
printf("%d) %s\n", c->option, c->flavor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Page*> CyoaParse(FILE *file) {
|
||||
yyin = file;
|
||||
yyparse();
|
||||
yyin = stdin;
|
||||
return pages;
|
||||
}
|
||||
|
||||
/* Local Variables: */
|
||||
/* mode: text */
|
||||
/* End: */
|
||||
13
src/main.c
Normal file
13
src/main.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "cyoa.c"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
return 1;
|
||||
}
|
||||
FILE* fin = fopen(argv[1], "r");
|
||||
auto mypages = CyoaParse(fin);
|
||||
for (Page* page : pages) {
|
||||
print_page(page);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user