1%{ 2 3// levcomp.lpp: 4// Level compiler lexer for Dungeon Crawl Stone Soup. 5// 6// Based loosely on NetHack's lev_comp.l 7 8#include "AppHdr.h" 9#include <algorithm> 10#include <cstring> 11#include <queue> 12#include "end.h" 13#include "mapdef.h" 14#include "levcomp.tab.h" 15 16static bool alloced = false; 17 18static queue<const char *> free_queue; 19 20static void flush_free_queue(unsigned int max_allowed) 21{ 22 while (free_queue.size() > max_allowed) 23 { 24 const char *s = free_queue.front(); 25 free((void *) s); 26 free_queue.pop(); 27 } 28} 29 30static void add_to_queue(const char *s) 31{ 32 free_queue.push(s); 33 flush_free_queue(100); 34} 35 36static void clean() 37{ 38 if (yylval.text && alloced) 39 add_to_queue(yylval.text); 40 yylval.text = nullptr; 41 alloced = false; 42} 43 44// Enter a new state, first clearing yylval of junk. 45#define CBEGIN(x) do { BEGIN(x); clean(); } while (0) 46 47static void post_proc_text(char *text, bool trim_right, 48 int strip_trailing, int strip_leading) 49{ 50 char *s = nullptr; 51 if (trim_right) 52 { 53 s = text + strlen(text) - 1; 54 while (s >= text && isspace(*s)) 55 *s-- = 0; 56 } 57 if (strip_trailing) 58 { 59 if (!s) 60 s = text + strlen(text) - 1; 61 while (s >= text && --strip_trailing >= 0) 62 *s-- = 0; 63 } 64 if (strip_leading) 65 { 66 const int original_length = strlen(text); 67 if (original_length > strip_leading) 68 memmove(text, text + strip_leading, 69 original_length - strip_leading); 70 if (original_length >= strip_leading) 71 text[original_length - strip_leading] = 0; 72 } 73} 74 75static char *copy_text(bool trim_right, int strip_trailing, int strip_leading) 76{ 77 char *newstring = nullptr; 78 if ((yylval.text = newstring = strdup(yytext))) 79 { 80 alloced = true; 81 post_proc_text(newstring, trim_right, strip_trailing, strip_leading); 82 } 83 return (newstring); 84} 85 86static void settext(bool trim_right = false, 87 int strip_trailing = 0, 88 int strip_leading = 0) 89{ 90 clean(); 91 char *newstring = copy_text(trim_right, strip_trailing, strip_leading); 92 yylval.text = newstring; 93} 94 95static void str_check() 96{ 97 if (!yylval.text) 98 { 99 char *buf = (char *) malloc(1); 100 if (buf) 101 { 102 yylval.text = buf; 103 *buf = 0; 104 alloced = true; 105 } 106 } 107} 108 109static void cattext(bool trim_right = false, int strip_trailing = 0) 110{ 111 if (!yylval.text) 112 settext(trim_right, strip_trailing); 113 else 114 { 115 bool was_alloced = alloced; 116 char *newbuf = (char*) malloc(strlen(yylval.text) + strlen(yytext) + 1); 117 if (!newbuf) 118 end(1, false, "Out of memory"); 119 alloced = true; 120 strcpy(newbuf, yylval.text); 121 strcat(newbuf, yytext); 122 post_proc_text(newbuf, trim_right, strip_trailing, 0); 123 if (was_alloced) 124 free((void*) yylval.text); 125 yylval.text = newbuf; 126 } 127} 128 129%} 130 131%x MAPDEF 132%x LUA 133%x LUA_ONELINER 134%s ARGUMENT 135%s MNAME 136%s KEYWORDS 137%x ITEM_LIST 138 139%option yylineno 140%option never-interactive 141 142NSPACE [^\ \t\r\n] 143SPACE [\ \t\r] 144 145%% 146 147<MAPDEF>^\s*ENDMAP[ ]* { BEGIN(INITIAL); } 148 149<MAPDEF>^[^\r\n\t]+ { 150 settext(true); 151 return MAP_LINE; 152 } 153 154<MAPDEF>^[ ]*\r?\n return CHARACTER; 155<MAPDEF># return CHARACTER; 156<MAPDEF>[\ ][^\ \r\n] return CHARACTER; 157 158<MAPDEF>[ ]*\r?\n ; 159 160<LUA>\s*\}\}[ \t\r]*$ { BEGIN(INITIAL); } 161<LUA>[^\r\n]+\}\}[ \t\r]*$ { 162 settext(true, 2); 163 BEGIN(INITIAL); 164 return LUA_LINE; 165 } 166<LUA>[^\r\n]+ { 167 settext(true); 168 return LUA_LINE; 169 } 170<LUA>\r?\n ; 171 172<LUA_ONELINER>[^\r\n]+\r?$ { 173 settext(true); 174 return LUA_LINE; 175 } 176<LUA_ONELINER>\r?\n { BEGIN(INITIAL); } 177 178<KEYWORDS>[A-Za-z_0-9\-]+ { 179 settext(); 180 return STRING; 181 } 182 183<KEYWORDS>{SPACE}*\\{SPACE}*\n ; 184<KEYWORDS>[ \t]+ ; 185<KEYWORDS>[ \t]*\r?\n { BEGIN(INITIAL); } 186 187<ITEM_LIST>[^,\ \t\r\n][^,\r\n]*\\{SPACE}*\n { 188 cattext(true, 1); 189 } 190 191<ITEM_LIST>{SPACE}*\\{SPACE}*\n ; 192 193<ITEM_LIST>[^, \t\r\n][^,\r\n]*[^, \t\r\n] { 194 cattext(); 195 return ITEM_INFO; 196 } 197 198<ITEM_LIST>, { clean(); return COMMA; } 199<ITEM_LIST>[ \t]+ ; 200<ITEM_LIST>[ \t]*\r?\n { BEGIN(INITIAL); } 201 202<MNAME>[\ \t\r]*\n { BEGIN(INITIAL); } 203 204<MNAME>[^,\ \t\r\n][^,\r\n]*\\{SPACE}*\n { 205 cattext(true, 1); 206 } 207 208<MNAME>{SPACE}*\\{SPACE}*\n ; 209 210<MNAME>[^,\ \t\r\n][^,\r\n]*[^,\ \t\r\n] { 211 cattext(); 212 return MONSTER_NAME; 213 } 214 215<MNAME>, { clean(); return COMMA; } 216<MNAME>[ \t\r]+ ; 217 218<ARGUMENT>{NSPACE}.*\\{SPACE}*\n { 219 cattext(true, 1); 220 } 221 222<ARGUMENT>{SPACE}*\\{SPACE}*\n ; 223 224<ARGUMENT>{NSPACE}.*{NSPACE} { 225 cattext(); 226 } 227 228<ARGUMENT>{NSPACE} cattext(); 229 230<ARGUMENT>{SPACE}*$ { BEGIN(INITIAL); str_check(); return STRING; } 231 232^[ \t]*#.* ; 233 234^\s*MAP[ \t\r]*$ { BEGIN(MAPDEF); } 235 236^[ \t]*: { BEGIN(LUA_ONELINER); return MAIN; } 237 238^[ \t]*prelude[ \t]*\{\{ { BEGIN(LUA); return PRELUDE; } 239^[ \t]*lua[ \t]*\{\{ { BEGIN(LUA); return MAIN; } 240^[ \t]*\{\{ { BEGIN(LUA); return MAIN; } 241^[ \t]*validate[ \t]*\{\{ { BEGIN(LUA); return VALIDATE; } 242^[ \t]*veto[ \t]*\{\{ { BEGIN(LUA); return VETO; } 243^[ \t]*epilogue[ \t]*\{\{ { BEGIN(LUA); return EPILOGUE; } 244 245NAME: { CBEGIN(ARGUMENT); return NAME; } 246default-depth: { CBEGIN(ARGUMENT); return DEFAULT_DEPTH; } 247DESC: { CBEGIN(ARGUMENT); return DESC; } 248DEPTH: { CBEGIN(ARGUMENT); return DEPTH; } 249ORIENT: { CBEGIN(ARGUMENT); return ORIENT; } 250PLACE: { CBEGIN(ARGUMENT); return PLACE; } 251WELCOME: { CBEGIN(ARGUMENT); return WELCOME; } 252CHANCE: return CHANCE; 253WEIGHT: return WEIGHT; 254TAGS: { CBEGIN(KEYWORDS); return TAGS; } 255SUBST: { CBEGIN(ITEM_LIST); return SUBST; } 256NSUBST: { CBEGIN(ITEM_LIST); return NSUBST; } 257COLOUR: { CBEGIN(ITEM_LIST); return COLOUR; } 258LFLOORCOL: { CBEGIN(ARGUMENT); return LFLOORCOL; } 259LROCKCOL: { CBEGIN(ARGUMENT); return LROCKCOL; } 260LFLOORTILE: { CBEGIN(ARGUMENT); return LFLOORTILE; } 261LROCKTILE: { CBEGIN(ARGUMENT); return LROCKTILE; } 262FTILE: { CBEGIN(ITEM_LIST); return FTILE; } 263RTILE: { CBEGIN(ITEM_LIST); return RTILE; } 264TILE: { CBEGIN(ITEM_LIST); return TILE; } 265FHEIGHT: { CBEGIN(ITEM_LIST); return FHEIGHT; } 266MONS: { CBEGIN(MNAME); return MONS; } 267ITEM: { CBEGIN(ITEM_LIST); return ITEM; } 268MARKER: { CBEGIN(ARGUMENT); return MARKER; } 269SHUFFLE: { CBEGIN(ITEM_LIST); return SHUFFLE; } 270CLEAR: { CBEGIN(ARGUMENT); return CLEAR; } 271ORDER: { return ORDER; } 272 273KFEAT: { CBEGIN(ARGUMENT); return KFEAT; } 274KITEM: { CBEGIN(ARGUMENT); return KITEM; } 275KMONS: { CBEGIN(ARGUMENT); return KMONS; } 276KMASK: { CBEGIN(ARGUMENT); return KMASK; } 277KPROP: { CBEGIN(ARGUMENT); return KPROP; } 278SUBVAULT: { CBEGIN(ARGUMENT); return SUBVAULT; } 279 280, return COMMA; 281 282: return COLON; 283 284% return PERC; 285- return DASH; 286 287[+-]?[.][0-9]+|[+-]?[0-9]+[.]?[0-9]* { 288 clean(); 289 yylval.f = strtod(yytext, nullptr); 290 return NUMBER; 291 } 292 293\([^\r\n)]*\) { 294 settext(true, 1, 1); 295 return STRING; 296 } 297 298[\ \t]+ ; 299\r?\n ; 300\r ; 301. return CHARACTER; 302 303%% 304 305int yywrap() 306{ 307 clean(); 308 flush_free_queue(0); 309 return 1; 310} 311