%{ // levcomp.lpp: // Level compiler lexer for Dungeon Crawl Stone Soup. // // Based loosely on NetHack's lev_comp.l #include #include #include #include "AppHdr.h" #include "mapdef.h" #include "levcomp.tab.h" #include "stuff.h" static bool alloced = false; std::queue free_queue; static void flush_free_queue(unsigned int max_allowed) { while (free_queue.size() > max_allowed) { const char *s = free_queue.front(); free((void *) s); free_queue.pop(); } } static void add_to_queue(const char *s) { free_queue.push(s); flush_free_queue(100); } static void clean() { if (yylval.text && alloced) add_to_queue(yylval.text); yylval.text = NULL; alloced = false; } // Enter a new state, first clearing yylval of junk. #define CBEGIN(x) do { BEGIN(x); clean(); } while (0) static void post_proc_text(char *text, bool trim_right, int strip_trailing) { char *s = NULL; if (trim_right) { s = text + strlen(text) - 1; while (s >= text && isspace(*s)) *s-- = 0; } if (strip_trailing) { if (!s) s = text + strlen(text) - 1; while (s >= text && --strip_trailing >= 0) *s-- = 0; } } static char *copy_text(bool trim_right, int strip_trailing) { char *newstring = NULL; if ((yylval.text = newstring = strdup(yytext))) { alloced = true; post_proc_text(newstring, trim_right, strip_trailing); } return (newstring); } static void settext(bool trim_right = false, int strip_trailing = 0) { clean(); char *newstring = copy_text(trim_right, strip_trailing); yylval.text = newstring; } static void str_check() { if (!yylval.text) { char *buf = (char *) malloc(1); if (buf) { yylval.text = buf; *buf = 0; alloced = true; } } } static void cattext(bool trim_right = false, int strip_trailing = 0) { if (!yylval.text) settext(trim_right, strip_trailing); else { bool was_alloced = alloced; char *newbuf = (char*) malloc(strlen(yylval.text) + strlen(yytext) + 1); if (!newbuf) end(1, "Out of memory"); alloced = true; strcpy(newbuf, yylval.text); strcat(newbuf, yytext); post_proc_text(newbuf, trim_right, strip_trailing); if (was_alloced) free((void*) yylval.text); yylval.text = newbuf; } } %} %x MAPDEF %x LUA %x LUA_ONELINER %s ARGUMENT %s MNAME %s KEYWORDS %x ITEM_LIST %option yylineno %option never-interactive NSPACE [^\ \t\r\n] SPACE [\ \t\r] %% ^\s*ENDMAP[ ]* { BEGIN(INITIAL); } ^[^\r\n\t]+ { settext(true); return MAP_LINE; } ^[ ]*\r?\n return CHARACTER; # return CHARACTER; [\ ][^\ \r\n] return CHARACTER; [ ]*\r?\n ; \s*\}\}[ \t\r]*$ { BEGIN(INITIAL); } [^\r\n]+\}\}[ \t\r]*$ { settext(true, 2); BEGIN(INITIAL); return LUA_LINE; } [^\r\n]+ { settext(true); return LUA_LINE; } \r?\n ; [^\r\n]+\r?$ { settext(true); return LUA_LINE; } \r?\n { BEGIN(INITIAL); } [A-Za-z_0-9\-]+ { settext(); return STRING; } {SPACE}*\\{SPACE}*\n ; [ \t]+ ; [ \t]*\r?\n { BEGIN(INITIAL); } [^,\ \t\r\n][^,\r\n]*\\{SPACE}*\n { cattext(true, 1); } {SPACE}*\\{SPACE}*\n ; [^, \t\r\n][^,\r\n]*[^, \t\r\n] { cattext(); return ITEM_INFO; } , { clean(); return COMMA; } [ \t]+ ; [ \t]*\r?\n { BEGIN(INITIAL); } [\ \t\r]*\n { BEGIN(INITIAL); } [^,\ \t\r\n][^,\r\n]*\\{SPACE}*\n { cattext(true, 1); } {SPACE}*\\{SPACE}*\n ; [^,\ \t\r\n][^,\r\n]*[^,\ \t\r\n] { cattext(); return MONSTER_NAME; } , { clean(); return COMMA; } [ \t\r]+ ; {NSPACE}.*\\{SPACE}*\n { cattext(true, 1); } {SPACE}*\\{SPACE}*\n ; {NSPACE}.*{NSPACE} { cattext(); } {NSPACE} cattext(); {SPACE}*$ { BEGIN(INITIAL); str_check(); return STRING; } ^[ \t]*#.* ; ^\s*MAP[ \t\r]*$ { BEGIN(MAPDEF); } ^[ \t]*: { BEGIN(LUA_ONELINER); return MAIN; } ^[ \t]*prelude[ \t]*\{\{ { BEGIN(LUA); return PRELUDE; } ^[ \t]*lua[ \t]*\{\{ { BEGIN(LUA); return MAIN; } ^[ \t]*\{\{ { BEGIN(LUA); return MAIN; } ^[ \t]*validate[ \t]*\{\{ { BEGIN(LUA); return VALIDATE; } ^[ \t]*veto[ \t]*\{\{ { BEGIN(LUA); return VETO; } NAME: { CBEGIN(ARGUMENT); return NAME; } default-depth: { CBEGIN(ARGUMENT); return DEFAULT_DEPTH; } DEPTH: { CBEGIN(ARGUMENT); return DEPTH; } ORIENT: { CBEGIN(ARGUMENT); return ORIENT; } PLACE: { CBEGIN(ARGUMENT); return PLACE; } WELCOME: { CBEGIN(ARGUMENT); return WELCOME; } CHANCE: return CHANCE; WEIGHT: return WEIGHT; FLAGS: { CBEGIN(KEYWORDS); return TAGS; } TAGS: { CBEGIN(KEYWORDS); return TAGS; } LFLAGS: { CBEGIN(ARGUMENT); return LFLAGS; } BFLAGS: { CBEGIN(ARGUMENT); return BFLAGS; } SUBST: { CBEGIN(ITEM_LIST); return SUBST; } NSUBST: { CBEGIN(ITEM_LIST); return NSUBST; } COLOUR: { CBEGIN(ITEM_LIST); return COLOUR; } LFLOORCOL: { CBEGIN(ARGUMENT); return LFLOORCOL; } LROCKCOL: { CBEGIN(ARGUMENT); return LROCKCOL; } LFLOORTILE: { CBEGIN(ARGUMENT); return LFLOORTILE; } LROCKTILE: { CBEGIN(ARGUMENT); return LROCKTILE; } FTILE: { CBEGIN(ITEM_LIST); return FTILE; } RTILE: { CBEGIN(ITEM_LIST); return RTILE; } TILE: { CBEGIN(ITEM_LIST); return TILE; } MONS: { CBEGIN(MNAME); return MONS; } ITEM: { CBEGIN(ITEM_LIST); return ITEM; } MARKER: { CBEGIN(ARGUMENT); return MARKER; } SHUFFLE: { CBEGIN(ITEM_LIST); return SHUFFLE; } KFEAT: { CBEGIN(ARGUMENT); return KFEAT; } KITEM: { CBEGIN(ARGUMENT); return KITEM; } KMONS: { CBEGIN(ARGUMENT); return KMONS; } KMASK: { CBEGIN(ARGUMENT); return KMASK; } KPROP: { CBEGIN(ARGUMENT); return KPROP; } SUBVAULT: { CBEGIN(ARGUMENT); return SUBVAULT; } , return COMMA; : return COLON; % return PERC; [+-]?[0-9]+ { clean(); yylval.i = atoi(yytext); return INTEGER; } [\ \t]+ ; \r?\n ; \r ; . return CHARACTER; %% int yywrap() { clean(); flush_free_queue(0); return 1; }