%{
/* NetHack 3.6  lev_comp.l	$NHDT-Date: 1449385191 2015/12/06 06:59:51 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.22 $ */
/*	Copyright (c) 1989 by Jean-Christophe Collet */
/* NetHack may be freely redistributed.  See license for details. */

#define LEV_LEX_C

#include "hack.h"
#include "lev_comp.h"
#include "sp_lev.h"

/* Most of these don't exist in flex, yywrap is macro and
 * yyunput is properly declared in flex.skel.
 */
#if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER)
int FDECL(yyback, (int *,int));
int NDECL(yylook);
int NDECL(yyinput);
int NDECL(yywrap);
int NDECL(yylex);
	/* Traditional lexes let yyunput() and yyoutput() default to int;
	 * newer ones may declare them as void since they don't return
	 * values.  For even more fun, the lex supplied as part of the
	 * newer unbundled compiler for SunOS 4.x adds the void declarations
	 * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain
	 * int) while the bundled lex and the one with the older unbundled
	 * compiler do not.  To detect this, we need help from outside --
	 * sys/unix/Makefile.utl.
	 *
	 * Digital UNIX is difficult and still has int in spite of all
	 * other signs.
	 */
# if defined(NeXT) || defined(SVR4) || defined(_AIX32)
#  define VOIDYYPUT
# endif
# if !defined(VOIDYYPUT) && defined(POSIX_TYPES)
#  if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS)
#   define VOIDYYPUT
#  endif
# endif
# if !defined(VOIDYYPUT) && defined(WEIRD_LEX)
#  if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1)
#   define VOIDYYPUT
#  endif
# endif
# if defined(VOIDYYPUT) && defined(__osf__)
#  undef VOIDYYPUT
# endif
# ifdef VOIDYYPUT
void FDECL(yyunput, (int));
void FDECL(yyoutput, (int));
# else
int FDECL(yyunput, (int));
int FDECL(yyoutput, (int));
# endif

#else	/* !FLEX_SCANNER && !FLEXHACK_SCANNER */
/* most recent flex allows suppressing yyunput() altogether when not needed */
#define YY_NO_UNPUT
#endif

#if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER)
/* older flex wants this */
#define YY_MALLOC_DECL  genericptr_t FDECL(malloc, (size_t)); \
                        genericptr_t FDECL(realloc, (genericptr_t, size_t));
/* newer flex assumes <stdlib.h> so needs this in case it's been suppressed */
YY_MALLOC_DECL
#endif

void FDECL(init_yyin, (FILE *));
void FDECL(init_yyout, (FILE *));

long NDECL(handle_varstring_check);
long FDECL(corefunc_str_check, (char *, long));

extern void VDECL(lc_error, (const char *, ...));
extern struct lc_vardefs *FDECL(vardef_defined,(struct lc_vardefs *,char *, int));

extern struct lc_vardefs *variable_definitions;

extern long FDECL(method_defined, (char *, long, long *));

void FDECL(savetoken, (char *));
void NDECL(newline);
void FDECL(advancepos, (char *));

/*
 * This doesn't always get put in lev_comp.h
 * (esp. when using older versions of bison).
 */
extern YYSTYPE yylval;

int nh_line_number = 1;
int token_start_pos = 0;
char curr_token[512];
static char map[4096];
static int map_cnt = 0;

FILE *orig_yyin = NULL;

#define ST_RET(x) do { savetoken(yytext); return x; } while (0);
#define ST_RETF(y, x) do { savetoken(yytext); y; return x; } while (0);

%}
%e 2000
%p 5000
%n 700
%s MAPC
%%
<MAPC>ENDMAP	{
		  savetoken(yytext);
		  BEGIN(INITIAL);
		  yylval.map = (char *) alloc(map_cnt + 1);
		  (void) strncpy(yylval.map, map, map_cnt);
		  yylval.map[map_cnt] = 0;
		  map_cnt = 0;
		  return MAP_ID;
		}
<MAPC>[-|}{+xABCISHKPLWTF\\#. 0123456789]*\r?\n	{
		  int len = yyleng;
		  savetoken(yytext);
		  /* convert \r\n to \n */
		  if (len >= 2 && yytext[len - 2] == '\r')
		      len -= 1;
		  (void) strncpy(map + map_cnt, yytext, len);
		  map_cnt += len;
		  map[map_cnt - 1] = '\n';
		  map[map_cnt] = '\0';
		  newline();
		}
^[ \t]*#.*\n	{ savetoken(yytext); newline(); }
MESSAGE		ST_RET(MESSAGE_ID);
NOMAP		ST_RET(NOMAP_ID);
MAZE		ST_RET(MAZE_ID);
LEVEL		ST_RET(LEVEL_ID);
INIT_MAP	ST_RET(LEV_INIT_ID);
mazegrid	ST_RET(MAZE_GRID_ID);
solidfill	ST_RET(SOLID_FILL_ID);
mines		ST_RET(MINES_ID);
rogue		ST_RET(ROGUELEV_ID);
FLAGS		ST_RET(FLAGS_ID);
GEOMETRY	ST_RET(GEOMETRY_ID);
^MAP\r?\n	{ savetoken(yytext); BEGIN(MAPC); newline(); }
obj(ect)?	ST_RET(object_ID);
OBJECT		ST_RET(OBJECT_ID);
CONTAINER	ST_RET(COBJECT_ID);
MONSTER		ST_RET(MONSTER_ID);
monster		ST_RET(monster_ID);
TRAP		ST_RET(TRAP_ID);
DOOR		ST_RET(DOOR_ID);
ROOMDOOR	ST_RET(ROOMDOOR_ID);
DRAWBRIDGE	ST_RET(DRAWBRIDGE_ID);
MAZEWALK	ST_RET(MAZEWALK_ID);
WALLIFY		ST_RET(WALLIFY_ID);
REGION		ST_RET(REGION_ID);
ALTAR		ST_RET(ALTAR_ID);
LADDER		ST_RET(LADDER_ID);
STAIR		ST_RET(STAIR_ID);
PORTAL		ST_RET(PORTAL_ID);
TELEPORT_REGION	ST_RET(TELEPRT_ID);
BRANCH		ST_RET(BRANCH_ID);
FOUNTAIN	ST_RET(FOUNTAIN_ID);
SINK		ST_RET(SINK_ID);
POOL		ST_RET(POOL_ID);
NON_DIGGABLE	ST_RET(NON_DIGGABLE_ID);
NON_PASSWALL	ST_RET(NON_PASSWALL_ID);
IF		ST_RET(IF_ID);
ELSE		ST_RET(ELSE_ID);
EXIT		ST_RET(EXIT_ID);
ROOM		ST_RET(ROOM_ID);
SUBROOM		ST_RET(SUBROOM_ID);
RANDOM_CORRIDORS	ST_RET(RAND_CORRIDOR_ID);
CORRIDOR	ST_RET(CORRIDOR_ID);
TERRAIN		ST_RET(TERRAIN_ID);
terrain		ST_RET(terrain_ID);
REPLACE_TERRAIN	ST_RET(REPLACE_TERRAIN_ID);
GOLD		ST_RET(GOLD_ID);
GRAVE		ST_RET(GRAVE_ID);
ENGRAVING	ST_RET(ENGRAVING_ID);
MINERALIZE	ST_RET(MINERALIZE_ID);
(NAME|name)	ST_RET(NAME_ID);
FOR		ST_RET(FOR_ID);
TO		ST_RET(TO_ID);
LOOP		ST_RET(LOOP_ID);
SWITCH		ST_RET(SWITCH_ID);
CASE		ST_RET(CASE_ID);
BREAK		ST_RET(BREAK_ID);
DEFAULT		ST_RET(DEFAULT_ID);
FUNCTION	ST_RET(FUNCTION_ID);
SHUFFLE		ST_RET(SHUFFLE_ID);
montype		ST_RET(MONTYPE_ID);
selection	ST_RET(selection_ID);
rect		ST_RET(rect_ID);
fillrect	ST_RET(fillrect_ID);
line		ST_RET(line_ID);
randline	ST_RET(randline_ID);
grow		ST_RET(grow_ID);
floodfill	ST_RET(flood_ID);
rndcoord	ST_RET(rndcoord_ID);
circle		ST_RET(circle_ID);
ellipse		ST_RET(ellipse_ID);
filter		ST_RET(filter_ID);
gradient	ST_RET(gradient_ID);
complement	ST_RET(complement_ID);
radial		{ savetoken(yytext); yylval.i=SEL_GRADIENT_RADIAL;  return GRADIENT_TYPE; }
square		{ savetoken(yytext); yylval.i=SEL_GRADIENT_SQUARE;  return GRADIENT_TYPE; }
dry		{ savetoken(yytext); yylval.i=DRY;  return HUMIDITY_TYPE; }
wet		{ savetoken(yytext); yylval.i=WET;  return HUMIDITY_TYPE; }
hot		{ savetoken(yytext); yylval.i=HOT;  return HUMIDITY_TYPE; }
solid		{ savetoken(yytext); yylval.i=SOLID;  return HUMIDITY_TYPE; }
any		{ savetoken(yytext); yylval.i=ANY_LOC;  return HUMIDITY_TYPE; }
levregion	ST_RET(LEV);
quantity	ST_RET(QUANTITY_ID);
buried		ST_RET(BURIED_ID);
eroded		ST_RET(ERODED_ID);
erodeproof	ST_RET(ERODEPROOF_ID);
trapped     { savetoken(yytext); yylval.i=1; return TRAPPED_STATE; }
not_trapped { savetoken(yytext); yylval.i=0; return TRAPPED_STATE; }
recharged	ST_RET(RECHARGED_ID);
invisible	ST_RET(INVIS_ID);
greased		ST_RET(GREASED_ID);
female		ST_RET(FEMALE_ID);
cancelled	ST_RET(CANCELLED_ID);
revived		ST_RET(REVIVED_ID);
avenge		ST_RET(AVENGE_ID);
fleeing		ST_RET(FLEEING_ID);
blinded		ST_RET(BLINDED_ID);
paralyzed	ST_RET(PARALYZED_ID);
stunned		ST_RET(STUNNED_ID);
confused	ST_RET(CONFUSED_ID);
seen_traps	ST_RET(SEENTRAPS_ID);
all		ST_RET(ALL_ID);
horizontal	ST_RETF((yylval.i=1), HORIZ_OR_VERT);
vertical	{ savetoken(yytext); yylval.i=2; return HORIZ_OR_VERT; }
open		{ savetoken(yytext); yylval.i=D_ISOPEN; return DOOR_STATE; }
closed		{ savetoken(yytext); yylval.i=D_CLOSED; return DOOR_STATE; }
locked		{ savetoken(yytext); yylval.i=D_LOCKED; return DOOR_STATE; }
nodoor		{ savetoken(yytext); yylval.i=D_NODOOR; return DOOR_STATE; }
broken		{ savetoken(yytext); yylval.i=D_BROKEN; return DOOR_STATE; }
secret		{ savetoken(yytext); yylval.i=D_SECRET; return DOOR_STATE; }
north		{ savetoken(yytext); yylval.i=W_NORTH; return DIRECTION; }
east		{ savetoken(yytext); yylval.i=W_EAST; return DIRECTION; }
south		{ savetoken(yytext); yylval.i=W_SOUTH; return DIRECTION; }
west		{ savetoken(yytext); yylval.i=W_WEST; return DIRECTION; }
random		{ savetoken(yytext); yylval.i = -1; return RANDOM_TYPE; }
random\[	{ savetoken(yytext); yylval.i = -1; return RANDOM_TYPE_BRACKET; }
none		{ savetoken(yytext); yylval.i = -2; return NONE; }
align		ST_RET(A_REGISTER);
left		{ savetoken(yytext); yylval.i=1; return LEFT_OR_RIGHT; }
half-left	{ savetoken(yytext); yylval.i=2; return LEFT_OR_RIGHT; }
center		{ savetoken(yytext); yylval.i=3; return CENTER; }
half-right	{ savetoken(yytext); yylval.i=4; return LEFT_OR_RIGHT; }
right		{ savetoken(yytext); yylval.i=5; return LEFT_OR_RIGHT; }
top		{ savetoken(yytext); yylval.i=1; return TOP_OR_BOT; }
bottom		{ savetoken(yytext); yylval.i=5; return TOP_OR_BOT; }
lit		{ savetoken(yytext); yylval.i=1; return LIGHT_STATE; }
unlit		{ savetoken(yytext); yylval.i=0; return LIGHT_STATE; }
filled		{ savetoken(yytext); yylval.i=1; return FILLING; }
unfilled	{ savetoken(yytext); yylval.i=0; return FILLING; }
regular		{ savetoken(yytext); yylval.i=0; return IRREGULAR; }
irregular	{ savetoken(yytext); yylval.i=1; return IRREGULAR; }
unjoined	{ savetoken(yytext); yylval.i=1; return JOINED; }
joined		{ savetoken(yytext); yylval.i=0; return JOINED; }
limited		{ savetoken(yytext); yylval.i=1; return LIMITED; }
unlimited	{ savetoken(yytext); yylval.i=0; return LIMITED; }
noalign		{ savetoken(yytext); yylval.i= AM_NONE; return ALIGNMENT; }
law		{ savetoken(yytext); yylval.i= AM_LAWFUL; return ALIGNMENT; }
neutral		{ savetoken(yytext); yylval.i= AM_NEUTRAL; return ALIGNMENT; }
chaos		{ savetoken(yytext); yylval.i= AM_CHAOTIC; return ALIGNMENT; }
coaligned	{ savetoken(yytext); yylval.i= AM_SPLEV_CO; return ALIGNMENT; }
noncoaligned	{ savetoken(yytext); yylval.i= AM_SPLEV_NONCO; return ALIGNMENT; }
peaceful	{ savetoken(yytext); yylval.i=1; return MON_ATTITUDE; }
hostile		{ savetoken(yytext); yylval.i=0; return MON_ATTITUDE; }
asleep		{ savetoken(yytext); yylval.i=1; return MON_ALERTNESS; }
awake		{ savetoken(yytext); yylval.i=0; return MON_ALERTNESS; }
m_feature	{ savetoken(yytext); yylval.i= M_AP_FURNITURE; return MON_APPEARANCE; }
m_monster	{ savetoken(yytext); yylval.i= M_AP_MONSTER;   return MON_APPEARANCE; }
m_object	{ savetoken(yytext); yylval.i= M_AP_OBJECT;    return MON_APPEARANCE; }
sanctum		{ savetoken(yytext); yylval.i=2; return ALTAR_TYPE; }
shrine		{ savetoken(yytext); yylval.i=1; return ALTAR_TYPE; }
altar		{ savetoken(yytext); yylval.i=0; return ALTAR_TYPE; }
up		{ savetoken(yytext); yylval.i=1; return UP_OR_DOWN; }
down		{ savetoken(yytext); yylval.i=0; return UP_OR_DOWN; }
false		{ savetoken(yytext); yylval.i=0; return BOOLEAN; }
true		{ savetoken(yytext); yylval.i=1; return BOOLEAN; }
dust		{ savetoken(yytext); yylval.i=DUST; return ENGRAVING_TYPE; }
engrave		{ savetoken(yytext); yylval.i=ENGRAVE; return ENGRAVING_TYPE; }
burn		{ savetoken(yytext); yylval.i=BURN; return ENGRAVING_TYPE; }
mark		{ savetoken(yytext); yylval.i=MARK; return ENGRAVING_TYPE; }
blood		{ savetoken(yytext); yylval.i=ENGR_BLOOD; return ENGRAVING_TYPE; }
blessed		{ savetoken(yytext); yylval.i=1; return CURSE_TYPE; }
uncursed	{ savetoken(yytext); yylval.i=2; return CURSE_TYPE; }
cursed		{ savetoken(yytext); yylval.i=3; return CURSE_TYPE; }
noteleport	{ savetoken(yytext); yylval.i=NOTELEPORT; return FLAG_TYPE; }
hardfloor	{ savetoken(yytext); yylval.i=HARDFLOOR; return FLAG_TYPE; }
nommap		{ savetoken(yytext); yylval.i=NOMMAP; return FLAG_TYPE; }
arboreal	{ savetoken(yytext); yylval.i=ARBOREAL; return FLAG_TYPE; } /* KMH */
shortsighted	{ savetoken(yytext); yylval.i=SHORTSIGHTED; return FLAG_TYPE; }
mazelevel	{ savetoken(yytext); yylval.i=MAZELEVEL; return FLAG_TYPE; }
premapped	{ savetoken(yytext); yylval.i=PREMAPPED; return FLAG_TYPE; }
shroud		{ savetoken(yytext); yylval.i=SHROUD; return FLAG_TYPE; }
graveyard	{ savetoken(yytext); yylval.i=GRAVEYARD; return FLAG_TYPE; }
icedpools	{ savetoken(yytext); yylval.i=ICEDPOOLS; return FLAG_TYPE; }
solidify	{ savetoken(yytext); yylval.i=SOLIDIFY; return FLAG_TYPE; }
corrmaze        { savetoken(yytext); yylval.i=CORRMAZE; return FLAG_TYPE; }
inaccessibles   { savetoken(yytext); yylval.i=CHECK_INACCESSIBLES; return FLAG_TYPE; }
[0-9]+d[0-9]+	{ char *p = index(yytext, 'd');
		  savetoken(yytext);
		  if (p) {
			*p++ = '\0';
			yylval.dice.num = atoi(yytext);
			yylval.dice.die = atoi(p);
		  } else {
			yylval.dice.num = yylval.dice.die = 1;
		  }
		  return DICE;
		}
\[\ *[0-9]+\%\ *\] { savetoken(yytext); yylval.i = atoi(yytext + 1);
		     if (yylval.i < 0 || yylval.i > 100)
			lc_error("Unexpected percentile '%li%%'", yylval.i);
		     return PERCENT; }
-[0-9]+		{ savetoken(yytext); yylval.i=atoi(yytext); return MINUS_INTEGER; }
\+[0-9]+	{ savetoken(yytext); yylval.i=atoi(yytext); return PLUS_INTEGER; }
[0-9]+\%	{ savetoken(yytext); yylval.i = atoi(yytext);
		  if (yylval.i < 0 || yylval.i > 100)
		     lc_error("Unexpected percentile '%li%%'", yylval.i);
		  return SPERCENT; }
[0-9]+		{ savetoken(yytext); yylval.i=atoi(yytext); return INTEGER; }
\"[^"]*\"	{ savetoken(yytext);
		  yytext[yyleng - 1] = '\0'; /* discard the trailing \" */
		  yylval.map = dupstr(yytext + 1); /* skip the first \" */
		  return STRING; }
\$[a-zA-Z_]+	{ savetoken(yytext); return handle_varstring_check(); }
"=="		{ savetoken(yytext); yylval.i = SPO_JE; return COMPARE_TYPE; }
"!="		{ savetoken(yytext); yylval.i = SPO_JNE; return COMPARE_TYPE; }
"<>"		{ savetoken(yytext); yylval.i = SPO_JNE; return COMPARE_TYPE; }
"<="		{ savetoken(yytext); yylval.i = SPO_JLE; return COMPARE_TYPE; }
">="		{ savetoken(yytext); yylval.i = SPO_JGE; return COMPARE_TYPE; }
"<"		{ savetoken(yytext); yylval.i = SPO_JL; return COMPARE_TYPE; }
">"		{ savetoken(yytext); yylval.i = SPO_JG; return COMPARE_TYPE; }
\r?\n		{ newline(); }
[ \t]+		{ advancepos(yytext); }
'\\.'		{ savetoken(yytext); yylval.i = yytext[2]; return CHAR; }
'.'		{ savetoken(yytext); yylval.i = yytext[1]; return CHAR; }
[-_a-zA-Z0-9]+	ST_RET(UNKNOWN_TYPE);
.		{ savetoken(yytext); return yytext[0]; }
%%
#ifdef	AMIGA
long *
alloc(n)
    unsigned n;
{
    return (long *) malloc(n);
}
#endif

/* routine to switch to another input file; needed for flex */
void
init_yyin( input_f )
FILE *input_f;
{
#if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER)
    if (yyin)
        yyrestart(input_f);
    else
#endif
        yyin = input_f;

    if (!orig_yyin)
        orig_yyin = yyin;
}
/* analogous routine (for completeness) */
void
init_yyout( output_f )
FILE *output_f;
{
    yyout = output_f;
}

long
handle_varstring_check()
{
    struct lc_vardefs *vd;

    yylval.map = dupstr(yytext);
    if ((vd = vardef_defined(variable_definitions, yytext, 1)) != 0) {
        long l = vd->var_type;
        int a = ((l & SPOVAR_ARRAY) == SPOVAR_ARRAY);

        l &= ~SPOVAR_ARRAY;
        if (l == SPOVAR_INT)
	    return (a ? VARSTRING_INT_ARRAY : VARSTRING_INT);
        if (l == SPOVAR_STRING)
	    return (a ? VARSTRING_STRING_ARRAY : VARSTRING_STRING);
        if (l == SPOVAR_VARIABLE)
	    return (a ? VARSTRING_VAR_ARRAY : VARSTRING_VAR);
        if (l == SPOVAR_COORD)
	    return (a ? VARSTRING_COORD_ARRAY : VARSTRING_COORD);
        if (l == SPOVAR_REGION)
	    return (a ? VARSTRING_REGION_ARRAY : VARSTRING_REGION);
        if (l == SPOVAR_MAPCHAR)
	    return (a ? VARSTRING_MAPCHAR_ARRAY : VARSTRING_MAPCHAR);
        if (l == SPOVAR_MONST)
	    return (a ? VARSTRING_MONST_ARRAY : VARSTRING_MONST);
        if (l == SPOVAR_OBJ)
	    return (a ? VARSTRING_OBJ_ARRAY : VARSTRING_OBJ);
        if (l == SPOVAR_SEL)
	    return (a ? VARSTRING_SEL_ARRAY : VARSTRING_SEL);
    }
    return VARSTRING;
}

void
newline()
{
    nh_line_number++;
    token_start_pos = 0;
    (void) memset((genericptr_t) curr_token, 0, 512);
}

void
savetoken(s)
char *s;
{
    Sprintf(curr_token, "%s", s);
    advancepos(s);
}

void
advancepos(s)
char *s;
{
    token_start_pos += strlen(s);
}

/*lev_comp.l*/
