Files
nethack/util/lev_comp.y
PatR ba7fbb6e8b lev_comp lint redux
The rest of this accidentally got pushed with the Reaper Man passages.
2016-02-17 14:08:19 -08:00

2663 lines
66 KiB
Plaintext

%{
/* NetHack 3.6 lev_comp.y $NHDT-Date: 1455746893 2016/02/17 22:08:13 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.21 $ */
/* Copyright (c) 1989 by Jean-Christophe Collet */
/* NetHack may be freely redistributed. See license for details. */
/*
* This file contains the Level Compiler code
* It may handle special mazes & special room-levels
*/
/* In case we're using bison in AIX. This definition must be
* placed before any other C-language construct in the file
* excluding comments and preprocessor directives (thanks IBM
* for this wonderful feature...).
*
* Note: some cpps barf on this 'undefined control' (#pragma).
* Addition of the leading space seems to prevent barfage for now,
* and AIX will still see the directive.
*/
#ifdef _AIX
#pragma alloca /* keep leading space! */
#endif
#define SPEC_LEV /* for USE_OLDARGS (sp_lev.h) */
#include "hack.h"
#include "sp_lev.h"
#define ERR (-1)
/* many types of things are put in chars for transference to NetHack.
* since some systems will use signed chars, limit everybody to the
* same number for portability.
*/
#define MAX_OF_TYPE 128
#define MAX_NESTED_IFS 20
#define MAX_SWITCH_CASES 20
#define New(type) \
(type *) memset((genericptr_t) alloc(sizeof (type)), 0, sizeof (type))
#define NewTab(type, size) (type **) alloc(sizeof (type *) * size)
#define Free(ptr) free((genericptr_t) ptr)
extern void VDECL(lc_error, (const char *, ...));
extern void VDECL(lc_warning, (const char *, ...));
extern void FDECL(yyerror, (const char *));
extern void FDECL(yywarning, (const char *));
extern int NDECL(yylex);
int NDECL(yyparse);
extern int FDECL(get_floor_type, (CHAR_P));
extern int FDECL(get_room_type, (char *));
extern int FDECL(get_trap_type, (char *));
extern int FDECL(get_monster_id, (char *,CHAR_P));
extern int FDECL(get_object_id, (char *,CHAR_P));
extern boolean FDECL(check_monster_char, (CHAR_P));
extern boolean FDECL(check_object_char, (CHAR_P));
extern char FDECL(what_map_char, (CHAR_P));
extern void FDECL(scan_map, (char *, sp_lev *));
extern void FDECL(add_opcode, (sp_lev *, int, genericptr_t));
extern genericptr_t FDECL(get_last_opcode_data1, (sp_lev *, int));
extern genericptr_t FDECL(get_last_opcode_data2, (sp_lev *, int, int));
extern boolean FDECL(check_subrooms, (sp_lev *));
extern boolean FDECL(write_level_file, (char *,sp_lev *));
extern struct opvar *FDECL(set_opvar_int, (struct opvar *, long));
extern void VDECL(add_opvars, (sp_lev *, const char *, ...));
extern void FDECL(start_level_def, (sp_lev * *, char *));
extern struct lc_funcdefs *FDECL(funcdef_new, (long,char *));
extern void FDECL(funcdef_free_all, (struct lc_funcdefs *));
extern struct lc_funcdefs *FDECL(funcdef_defined, (struct lc_funcdefs *,
char *, int));
extern char *FDECL(funcdef_paramtypes, (struct lc_funcdefs *));
extern char *FDECL(decode_parm_str, (char *));
extern struct lc_vardefs *FDECL(vardef_new, (long,char *));
extern void FDECL(vardef_free_all, (struct lc_vardefs *));
extern struct lc_vardefs *FDECL(vardef_defined, (struct lc_vardefs *,
char *, int));
extern void NDECL(break_stmt_start);
extern void FDECL(break_stmt_end, (sp_lev *));
extern void FDECL(break_stmt_new, (sp_lev *, long));
extern void FDECL(splev_add_from, (sp_lev *, sp_lev *));
extern void FDECL(check_vardef_type, (struct lc_vardefs *, char *, long));
extern void FDECL(vardef_used, (struct lc_vardefs *, char *));
extern struct lc_vardefs *FDECL(add_vardef_type, (struct lc_vardefs *,
char *, long));
extern int FDECL(reverse_jmp_opcode, (int));
struct coord {
long x;
long y;
};
struct forloopdef {
char *varname;
long jmp_point;
};
static struct forloopdef forloop_list[MAX_NESTED_IFS];
static short n_forloops = 0;
sp_lev *splev = NULL;
static struct opvar *if_list[MAX_NESTED_IFS];
static short n_if_list = 0;
unsigned int max_x_map, max_y_map;
int obj_containment = 0;
int in_container_obj = 0;
/* integer value is possibly an inconstant value (eg. dice notation or a variable) */
int is_inconstant_number = 0;
int in_switch_statement = 0;
static struct opvar *switch_check_jump = NULL;
static struct opvar *switch_default_case = NULL;
static struct opvar *switch_case_list[MAX_SWITCH_CASES];
static long switch_case_value[MAX_SWITCH_CASES];
int n_switch_case_list = 0;
int allow_break_statements = 0;
struct lc_breakdef *break_list = NULL;
extern struct lc_vardefs *variable_definitions;
struct lc_vardefs *function_tmp_var_defs = NULL;
extern struct lc_funcdefs *function_definitions;
struct lc_funcdefs *curr_function = NULL;
struct lc_funcdefs_parm * curr_function_param = NULL;
int in_function_definition = 0;
sp_lev *function_splev_backup = NULL;
extern int fatal_error;
extern int got_errors;
extern int line_number;
extern const char *fname;
extern char curr_token[512];
%}
%union
{
long i;
char* map;
struct {
long room;
long wall;
long door;
} corpos;
struct {
long area;
long x1;
long y1;
long x2;
long y2;
} lregn;
struct {
long x;
long y;
} crd;
struct {
long ter;
long lit;
} terr;
struct {
long height;
long width;
} sze;
struct {
long die;
long num;
} dice;
struct {
long cfunc;
char *varstr;
} meth;
}
%token <i> CHAR INTEGER BOOLEAN PERCENT SPERCENT
%token <i> MINUS_INTEGER PLUS_INTEGER
%token <i> MAZE_GRID_ID SOLID_FILL_ID MINES_ID ROGUELEV_ID
%token <i> MESSAGE_ID MAZE_ID LEVEL_ID LEV_INIT_ID GEOMETRY_ID NOMAP_ID
%token <i> OBJECT_ID COBJECT_ID MONSTER_ID TRAP_ID DOOR_ID DRAWBRIDGE_ID
%token <i> object_ID monster_ID terrain_ID
%token <i> MAZEWALK_ID WALLIFY_ID REGION_ID FILLING IRREGULAR JOINED
%token <i> ALTAR_ID LADDER_ID STAIR_ID NON_DIGGABLE_ID NON_PASSWALL_ID ROOM_ID
%token <i> PORTAL_ID TELEPRT_ID BRANCH_ID LEV MINERALIZE_ID
%token <i> CORRIDOR_ID GOLD_ID ENGRAVING_ID FOUNTAIN_ID POOL_ID SINK_ID NONE
%token <i> RAND_CORRIDOR_ID DOOR_STATE LIGHT_STATE CURSE_TYPE ENGRAVING_TYPE
%token <i> DIRECTION RANDOM_TYPE RANDOM_TYPE_BRACKET A_REGISTER
%token <i> ALIGNMENT LEFT_OR_RIGHT CENTER TOP_OR_BOT ALTAR_TYPE UP_OR_DOWN
%token <i> SUBROOM_ID NAME_ID FLAGS_ID FLAG_TYPE MON_ATTITUDE MON_ALERTNESS
%token <i> MON_APPEARANCE ROOMDOOR_ID IF_ID ELSE_ID
%token <i> TERRAIN_ID HORIZ_OR_VERT REPLACE_TERRAIN_ID
%token <i> EXIT_ID SHUFFLE_ID
%token <i> QUANTITY_ID BURIED_ID LOOP_ID
%token <i> FOR_ID TO_ID
%token <i> SWITCH_ID CASE_ID BREAK_ID DEFAULT_ID
%token <i> ERODED_ID TRAPPED_STATE RECHARGED_ID INVIS_ID GREASED_ID
%token <i> FEMALE_ID CANCELLED_ID REVIVED_ID AVENGE_ID FLEEING_ID BLINDED_ID
%token <i> PARALYZED_ID STUNNED_ID CONFUSED_ID SEENTRAPS_ID ALL_ID
%token <i> MONTYPE_ID
%token <i> GRAVE_ID ERODEPROOF_ID
%token <i> FUNCTION_ID
%token <i> MSG_OUTPUT_TYPE
%token <i> COMPARE_TYPE
%token <i> UNKNOWN_TYPE
%token <i> rect_ID fillrect_ID line_ID randline_ID grow_ID selection_ID flood_ID
%token <i> rndcoord_ID circle_ID ellipse_ID filter_ID complement_ID
%token <i> gradient_ID GRADIENT_TYPE LIMITED HUMIDITY_TYPE
%token <i> ',' ':' '(' ')' '[' ']' '{' '}'
%token <map> STRING MAP_ID
%token <map> NQSTRING VARSTRING
%token <map> CFUNC CFUNC_INT CFUNC_STR CFUNC_COORD CFUNC_REGION
%token <map> VARSTRING_INT VARSTRING_INT_ARRAY
%token <map> VARSTRING_STRING VARSTRING_STRING_ARRAY
%token <map> VARSTRING_VAR VARSTRING_VAR_ARRAY
%token <map> VARSTRING_COORD VARSTRING_COORD_ARRAY
%token <map> VARSTRING_REGION VARSTRING_REGION_ARRAY
%token <map> VARSTRING_MAPCHAR VARSTRING_MAPCHAR_ARRAY
%token <map> VARSTRING_MONST VARSTRING_MONST_ARRAY
%token <map> VARSTRING_OBJ VARSTRING_OBJ_ARRAY
%token <map> VARSTRING_SEL VARSTRING_SEL_ARRAY
%token <meth> METHOD_INT METHOD_INT_ARRAY
%token <meth> METHOD_STRING METHOD_STRING_ARRAY
%token <meth> METHOD_VAR METHOD_VAR_ARRAY
%token <meth> METHOD_COORD METHOD_COORD_ARRAY
%token <meth> METHOD_REGION METHOD_REGION_ARRAY
%token <meth> METHOD_MAPCHAR METHOD_MAPCHAR_ARRAY
%token <meth> METHOD_MONST METHOD_MONST_ARRAY
%token <meth> METHOD_OBJ METHOD_OBJ_ARRAY
%token <meth> METHOD_SEL METHOD_SEL_ARRAY
%token <dice> DICE
%type <i> h_justif v_justif trap_name room_type door_state light_state
%type <i> alignment altar_type a_register roomfill door_pos
%type <i> alignment_prfx
%type <i> door_wall walled secret
%type <i> dir_list teleprt_detail
%type <i> object_infos object_info monster_infos monster_info
%type <i> levstatements stmt_block region_detail_end
%type <i> engraving_type flag_list roomregionflag roomregionflags optroomregionflags
%type <i> humidity_flags
%type <i> comparestmt encodecoord encoderegion mapchar
%type <i> seen_trap_mask
%type <i> encodemonster encodeobj encodeobj_list
%type <i> integer_list string_list encodecoord_list encoderegion_list mapchar_list encodemonster_list
%type <i> opt_percent opt_fillchar
%type <i> all_integers
%type <i> ter_selection ter_selection_x
%type <i> func_param_type
%type <i> objectid monsterid terrainid
%type <i> opt_coord_or_var opt_limited
%type <i> mazefiller
%type <map> level_def
%type <map> any_var any_var_array any_var_or_arr any_var_or_unk
%type <map> func_call_params_list func_call_param_list
%type <i> func_call_param_part
%type <corpos> corr_spec
%type <lregn> region lev_region
%type <crd> room_pos subroom_pos room_align
%type <sze> room_size
%type <terr> terrain_type
%left '+' '-'
%left '*' '/' '%'
%start file
%%
file : /* nothing */
| levels
;
levels : level
| level levels
;
level : level_def flags levstatements
{
if (fatal_error > 0) {
(void) fprintf(stderr,
"%s: %d errors detected for level \"%s\". No output created!\n",
fname, fatal_error, $1);
fatal_error = 0;
got_errors++;
} else if (!got_errors) {
if (!write_level_file($1, splev)) {
lc_error("Can't write output file for '%s'!", $1);
exit(EXIT_FAILURE);
}
}
Free($1);
Free(splev);
splev = NULL;
vardef_free_all(variable_definitions);
variable_definitions = NULL;
}
;
level_def : LEVEL_ID ':' STRING
{
start_level_def(&splev, $3);
$$ = $3;
}
| MAZE_ID ':' STRING ',' mazefiller
{
start_level_def(&splev, $3);
if ($5 == -1) {
add_opvars(splev, "iiiiiiiio",
VA_PASS9(LVLINIT_MAZEGRID,HWALL,0,0,
0,0,0,0, SPO_INITLEVEL));
} else {
long bg = what_map_char((char) $5);
add_opvars(splev, "iiiiiiiio",
VA_PASS9(LVLINIT_SOLIDFILL, bg, 0,0,
0,0,0,0, SPO_INITLEVEL));
}
add_opvars(splev, "io",
VA_PASS2(MAZELEVEL, SPO_LEVEL_FLAGS));
max_x_map = COLNO-1;
max_y_map = ROWNO;
$$ = $3;
}
;
mazefiller : RANDOM_TYPE
{
$$ = -1;
}
| CHAR
{
$$ = what_map_char((char) $1);
}
;
lev_init : LEV_INIT_ID ':' SOLID_FILL_ID ',' terrain_type
{
long filling = $5.ter;
if (filling == INVALID_TYPE || filling >= MAX_TYPE)
lc_error("INIT_MAP: Invalid fill char type.");
add_opvars(splev, "iiiiiiiio",
LVLINIT_SOLIDFILL,filling,0,(long)$5.lit, 0,0,0,0, SPO_INITLEVEL);
max_x_map = COLNO-1;
max_y_map = ROWNO;
}
| LEV_INIT_ID ':' MAZE_GRID_ID ',' CHAR
{
long filling = what_map_char((char) $5);
if (filling == INVALID_TYPE || filling >= MAX_TYPE)
lc_error("INIT_MAP: Invalid fill char type.");
add_opvars(splev, "iiiiiiiio",
VA_PASS9(LVLINIT_MAZEGRID,filling,0,0,
0,0,0,0, SPO_INITLEVEL));
max_x_map = COLNO-1;
max_y_map = ROWNO;
}
| LEV_INIT_ID ':' ROGUELEV_ID
{
add_opvars(splev, "iiiiiiiio",
VA_PASS9(LVLINIT_ROGUE,0,0,0,
0,0,0,0, SPO_INITLEVEL));
}
| LEV_INIT_ID ':' MINES_ID ',' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled opt_fillchar
{
long fg = what_map_char((char) $5);
long bg = what_map_char((char) $7);
long smoothed = $9;
long joined = $11;
long lit = $13;
long walled = $15;
long filling = $16;
if (fg == INVALID_TYPE || fg >= MAX_TYPE)
lc_error("INIT_MAP: Invalid foreground type.");
if (bg == INVALID_TYPE || bg >= MAX_TYPE)
lc_error("INIT_MAP: Invalid background type.");
if (joined && fg != CORR && fg != ROOM)
lc_error("INIT_MAP: Invalid foreground type for joined map.");
if (filling == INVALID_TYPE)
lc_error("INIT_MAP: Invalid fill char type.");
add_opvars(splev, "iiiiiiiio",
VA_PASS9(LVLINIT_MINES,filling,walled,lit,
joined,smoothed,bg,fg,
SPO_INITLEVEL));
max_x_map = COLNO-1;
max_y_map = ROWNO;
}
;
opt_limited : /* nothing */
{
$$ = 0;
}
| ',' LIMITED
{
$$ = $2;
}
;
opt_coord_or_var : /* nothing */
{
add_opvars(splev, "o", VA_PASS1(SPO_COPY));
$$ = 0;
}
| ',' coord_or_var
{
$$ = 1;
}
;
opt_fillchar : /* nothing */
{
$$ = -1;
}
| ',' CHAR
{
$$ = what_map_char((char) $2);
}
;
walled : BOOLEAN
| RANDOM_TYPE
;
flags : /* nothing */
{
add_opvars(splev, "io", VA_PASS2(0, SPO_LEVEL_FLAGS));
}
| FLAGS_ID ':' flag_list
{
add_opvars(splev, "io", VA_PASS2($3, SPO_LEVEL_FLAGS));
}
;
flag_list : FLAG_TYPE ',' flag_list
{
$$ = ($1 | $3);
}
| FLAG_TYPE
{
$$ = $1;
}
;
levstatements : /* nothing */
{
$$ = 0;
}
| levstatement levstatements
{
$$ = 1 + $2;
}
;
stmt_block : '{' levstatements '}'
{
$$ = $2;
}
;
levstatement : message
| lev_init
| altar_detail
| grave_detail
| branch_region
| corridor
| variable_define
| shuffle_detail
| diggable_detail
| door_detail
| drawbridge_detail
| engraving_detail
| mineralize
| fountain_detail
| gold_detail
| switchstatement
| forstatement
| loopstatement
| ifstatement
| chancestatement
| exitstatement
| breakstatement
| function_define
| function_call
| ladder_detail
| map_definition
| mazewalk_detail
| monster_detail
| object_detail
| passwall_detail
| pool_detail
| portal_region
| random_corridors
| region_detail
| room_def
| subroom_def
| sink_detail
| terrain_detail
| replace_terrain_detail
| stair_detail
| stair_region
| teleprt_region
| trap_detail
| wallify_detail
;
any_var_array : VARSTRING_INT_ARRAY
| VARSTRING_STRING_ARRAY
| VARSTRING_VAR_ARRAY
| VARSTRING_COORD_ARRAY
| VARSTRING_REGION_ARRAY
| VARSTRING_MAPCHAR_ARRAY
| VARSTRING_MONST_ARRAY
| VARSTRING_OBJ_ARRAY
| VARSTRING_SEL_ARRAY
;
any_var : VARSTRING_INT
| VARSTRING_STRING
| VARSTRING_VAR
| VARSTRING_COORD
| VARSTRING_REGION
| VARSTRING_MAPCHAR
| VARSTRING_MONST
| VARSTRING_OBJ
| VARSTRING_SEL
;
any_var_or_arr : any_var_array
| any_var
| VARSTRING
;
any_var_or_unk : VARSTRING
| any_var
;
shuffle_detail : SHUFFLE_ID ':' any_var_array
{
struct lc_vardefs *vd;
if ((vd = vardef_defined(variable_definitions, $3, 1))) {
if (!(vd->var_type & SPOVAR_ARRAY))
lc_error("Trying to shuffle non-array variable '%s'", $3);
} else lc_error("Trying to shuffle undefined variable '%s'", $3);
add_opvars(splev, "so", VA_PASS2($3, SPO_SHUFFLE_ARRAY));
Free($3);
}
;
variable_define : any_var_or_arr '=' math_expr_var
{
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_INT);
add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' selection_ID ':' ter_selection
{
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_SEL);
add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' string_expr
{
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_STRING);
add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' terrainid ':' mapchar_or_var
{
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_MAPCHAR);
add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' monsterid ':' monster_or_var
{
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_MONST);
add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' objectid ':' object_or_var
{
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_OBJ);
add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' coord_or_var
{
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_COORD);
add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' region_or_var
{
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_REGION);
add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' '{' integer_list '}'
{
long n_items = $4;
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_INT|SPOVAR_ARRAY);
add_opvars(splev, "iso",
VA_PASS3(n_items, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' '{' encodecoord_list '}'
{
long n_items = $4;
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_COORD|SPOVAR_ARRAY);
add_opvars(splev, "iso",
VA_PASS3(n_items, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' '{' encoderegion_list '}'
{
long n_items = $4;
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_REGION|SPOVAR_ARRAY);
add_opvars(splev, "iso",
VA_PASS3(n_items, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' terrainid ':' '{' mapchar_list '}'
{
long n_items = $6;
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_MAPCHAR|SPOVAR_ARRAY);
add_opvars(splev, "iso",
VA_PASS3(n_items, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' monsterid ':' '{' encodemonster_list '}'
{
long n_items = $6;
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_MONST|SPOVAR_ARRAY);
add_opvars(splev, "iso",
VA_PASS3(n_items, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' objectid ':' '{' encodeobj_list '}'
{
long n_items = $6;
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_OBJ|SPOVAR_ARRAY);
add_opvars(splev, "iso",
VA_PASS3(n_items, $1, SPO_VAR_INIT));
Free($1);
}
| any_var_or_arr '=' '{' string_list '}'
{
long n_items = $4;
variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_STRING|SPOVAR_ARRAY);
add_opvars(splev, "iso",
VA_PASS3(n_items, $1, SPO_VAR_INIT));
Free($1);
}
;
encodeobj_list : encodeobj
{
add_opvars(splev, "O", VA_PASS1($1));
$$ = 1;
}
| encodeobj_list ',' encodeobj
{
add_opvars(splev, "O", VA_PASS1($3));
$$ = 1 + $1;
}
;
encodemonster_list : encodemonster
{
add_opvars(splev, "M", VA_PASS1($1));
$$ = 1;
}
| encodemonster_list ',' encodemonster
{
add_opvars(splev, "M", VA_PASS1($3));
$$ = 1 + $1;
}
;
mapchar_list : mapchar
{
add_opvars(splev, "m", VA_PASS1($1));
$$ = 1;
}
| mapchar_list ',' mapchar
{
add_opvars(splev, "m", VA_PASS1($3));
$$ = 1 + $1;
}
;
encoderegion_list : encoderegion
{
$$ = 1;
}
| encoderegion_list ',' encoderegion
{
$$ = 1 + $1;
}
;
encodecoord_list : encodecoord
{
add_opvars(splev, "c", VA_PASS1($1));
$$ = 1;
}
| encodecoord_list ',' encodecoord
{
add_opvars(splev, "c", VA_PASS1($3));
$$ = 1 + $1;
}
;
integer_list : math_expr_var
{
$$ = 1;
}
| integer_list ',' math_expr_var
{
$$ = 1 + $1;
}
;
string_list : string_expr
{
$$ = 1;
}
| string_list ',' string_expr
{
$$ = 1 + $1;
}
;
function_define : FUNCTION_ID NQSTRING '('
{
struct lc_funcdefs *funcdef;
if (in_function_definition)
lc_error("Recursively defined functions not allowed (function %s).", $2);
in_function_definition++;
if (funcdef_defined(function_definitions, $2, 1))
lc_error("Function '%s' already defined once.", $2);
funcdef = funcdef_new(-1, $2);
funcdef->next = function_definitions;
function_definitions = funcdef;
function_splev_backup = splev;
splev = &(funcdef->code);
Free($2);
curr_function = funcdef;
function_tmp_var_defs = variable_definitions;
variable_definitions = NULL;
}
func_params_list ')'
{
/* nothing */
}
stmt_block
{
add_opvars(splev, "io", VA_PASS2(0, SPO_RETURN));
splev = function_splev_backup;
in_function_definition--;
curr_function = NULL;
vardef_free_all(variable_definitions);
variable_definitions = function_tmp_var_defs;
}
;
function_call : NQSTRING '(' func_call_params_list ')'
{
struct lc_funcdefs *tmpfunc;
tmpfunc = funcdef_defined(function_definitions, $1, 1);
if (tmpfunc) {
long l;
long nparams = strlen( $3 );
char *fparamstr = funcdef_paramtypes(tmpfunc);
if (strcmp($3, fparamstr)) {
char *tmps = strdup(decode_parm_str(fparamstr));
lc_error("Function '%s' requires params '%s', got '%s' instead.", $1, tmps, decode_parm_str($3));
Free(tmps);
}
Free(fparamstr);
Free($3);
if (!(tmpfunc->n_called)) {
/* we haven't called the function yet, so insert it in the code */
struct opvar *jmp = New(struct opvar);
set_opvar_int(jmp, splev->n_opcodes+1);
add_opcode(splev, SPO_PUSH, jmp);
add_opcode(splev, SPO_JMP, NULL); /* we must jump past it first, then CALL it, due to RETURN. */
tmpfunc->addr = splev->n_opcodes;
{ /* init function parameter variables */
struct lc_funcdefs_parm *tfp = tmpfunc->params;
while (tfp) {
add_opvars(splev, "iso",
VA_PASS3(0, tfp->name,
SPO_VAR_INIT));
tfp = tfp->next;
}
}
splev_add_from(splev, &(tmpfunc->code));
set_opvar_int(jmp, splev->n_opcodes - jmp->vardata.l);
}
l = tmpfunc->addr - splev->n_opcodes - 2;
add_opvars(splev, "iio",
VA_PASS3(nparams, l, SPO_CALL));
tmpfunc->n_called++;
} else {
lc_error("Function '%s' not defined.", $1);
}
Free($1);
}
;
exitstatement : EXIT_ID
{
add_opcode(splev, SPO_EXIT, NULL);
}
;
opt_percent : /* nothing */
{
$$ = 100;
}
| PERCENT
{
$$ = $1;
}
;
comparestmt : PERCENT
{
/* val > rn2(100) */
add_opvars(splev, "iio",
VA_PASS3((long)$1, 100, SPO_RN2));
$$ = SPO_JG;
}
| '[' math_expr_var COMPARE_TYPE math_expr_var ']'
{
$$ = $3;
}
| '[' math_expr_var ']'
{
/* boolean, explicit foo != 0 */
add_opvars(splev, "i", VA_PASS1(0));
$$ = SPO_JNE;
}
;
switchstatement : SWITCH_ID
{
is_inconstant_number = 0;
}
'[' integer_or_var ']'
{
struct opvar *chkjmp;
if (in_switch_statement > 0)
lc_error("Cannot nest switch-statements.");
in_switch_statement++;
n_switch_case_list = 0;
switch_default_case = NULL;
if (!is_inconstant_number)
add_opvars(splev, "o", VA_PASS1(SPO_RN2));
is_inconstant_number = 0;
chkjmp = New(struct opvar);
set_opvar_int(chkjmp, splev->n_opcodes+1);
switch_check_jump = chkjmp;
add_opcode(splev, SPO_PUSH, chkjmp);
add_opcode(splev, SPO_JMP, NULL);
break_stmt_start();
}
'{' switchcases '}'
{
struct opvar *endjump = New(struct opvar);
int i;
set_opvar_int(endjump, splev->n_opcodes+1);
add_opcode(splev, SPO_PUSH, endjump);
add_opcode(splev, SPO_JMP, NULL);
set_opvar_int(switch_check_jump,
splev->n_opcodes - switch_check_jump->vardata.l);
for (i = 0; i < n_switch_case_list; i++) {
add_opvars(splev, "oio",
VA_PASS3(SPO_COPY,
switch_case_value[i], SPO_CMP));
set_opvar_int(switch_case_list[i],
switch_case_list[i]->vardata.l - splev->n_opcodes-1);
add_opcode(splev, SPO_PUSH, switch_case_list[i]);
add_opcode(splev, SPO_JE, NULL);
}
if (switch_default_case) {
set_opvar_int(switch_default_case,
switch_default_case->vardata.l - splev->n_opcodes-1);
add_opcode(splev, SPO_PUSH, switch_default_case);
add_opcode(splev, SPO_JMP, NULL);
}
set_opvar_int(endjump, splev->n_opcodes - endjump->vardata.l);
break_stmt_end(splev);
add_opcode(splev, SPO_POP, NULL); /* get rid of the value in stack */
in_switch_statement--;
}
;
switchcases : /* nothing */
| switchcase switchcases
;
switchcase : CASE_ID all_integers ':'
{
if (n_switch_case_list < MAX_SWITCH_CASES) {
struct opvar *tmppush = New(struct opvar);
set_opvar_int(tmppush, splev->n_opcodes);
switch_case_value[n_switch_case_list] = $2;
switch_case_list[n_switch_case_list++] = tmppush;
} else lc_error("Too many cases in a switch.");
}
levstatements
{
}
| DEFAULT_ID ':'
{
struct opvar *tmppush = New(struct opvar);
if (switch_default_case)
lc_error("Switch default case already used.");
set_opvar_int(tmppush, splev->n_opcodes);
switch_default_case = tmppush;
}
levstatements
{
}
;
breakstatement : BREAK_ID
{
if (!allow_break_statements)
lc_error("Cannot use BREAK outside a statement block.");
else {
break_stmt_new(splev, splev->n_opcodes);
}
}
;
for_to_span : '.' '.'
| TO_ID
;
forstmt_start : FOR_ID any_var_or_unk '=' math_expr_var for_to_span math_expr_var
{
char buf[256], buf2[256];
if (n_forloops >= MAX_NESTED_IFS) {
lc_error("FOR: Too deeply nested loops.");
n_forloops = MAX_NESTED_IFS - 1;
}
/* first, define a variable for the for-loop end value */
Sprintf(buf, "%s end", $2);
/* the value of which is already in stack (the 2nd math_expr) */
add_opvars(splev, "iso", VA_PASS3(0, buf, SPO_VAR_INIT));
variable_definitions = add_vardef_type(variable_definitions,
$2, SPOVAR_INT);
/* define the for-loop variable. value is in stack (1st math_expr) */
add_opvars(splev, "iso", VA_PASS3(0, $2, SPO_VAR_INIT));
/* calculate value for the loop "step" variable */
Sprintf(buf2, "%s step", $2);
/* end - start */
add_opvars(splev, "vvo",
VA_PASS3(buf, $2, SPO_MATH_SUB));
/* sign of that */
add_opvars(splev, "o", VA_PASS1(SPO_MATH_SIGN));
/* save the sign into the step var */
add_opvars(splev, "iso",
VA_PASS3(0, buf2, SPO_VAR_INIT));
forloop_list[n_forloops].varname = strdup($2);
forloop_list[n_forloops].jmp_point = splev->n_opcodes;
n_forloops++;
Free($2);
}
;
forstatement : forstmt_start
{
/* nothing */
break_stmt_start();
}
stmt_block
{
char buf[256], buf2[256];
n_forloops--;
Sprintf(buf, "%s step", forloop_list[n_forloops].varname);
Sprintf(buf2, "%s end", forloop_list[n_forloops].varname);
/* compare for-loop var to end value */
add_opvars(splev, "vvo",
VA_PASS3(forloop_list[n_forloops].varname,
buf2, SPO_CMP));
/* var + step */
add_opvars(splev, "vvo",
VA_PASS3(buf, forloop_list[n_forloops].varname,
SPO_MATH_ADD));
/* for-loop var = (for-loop var + step) */
add_opvars(splev, "iso",
VA_PASS3(0, forloop_list[n_forloops].varname,
SPO_VAR_INIT));
/* jump back if compared values were not equal */
add_opvars(splev, "io",
VA_PASS2(
forloop_list[n_forloops].jmp_point - splev->n_opcodes - 1,
SPO_JNE));
Free(forloop_list[n_forloops].varname);
break_stmt_end(splev);
}
;
loopstatement : LOOP_ID '[' integer_or_var ']'
{
struct opvar *tmppush = New(struct opvar);
if (n_if_list >= MAX_NESTED_IFS) {
lc_error("LOOP: Too deeply nested conditionals.");
n_if_list = MAX_NESTED_IFS - 1;
}
set_opvar_int(tmppush, splev->n_opcodes);
if_list[n_if_list++] = tmppush;
add_opvars(splev, "o", VA_PASS1(SPO_DEC));
break_stmt_start();
}
stmt_block
{
struct opvar *tmppush;
add_opvars(splev, "oio", VA_PASS3(SPO_COPY, 0, SPO_CMP));
tmppush = (struct opvar *) if_list[--n_if_list];
set_opvar_int(tmppush, tmppush->vardata.l - splev->n_opcodes-1);
add_opcode(splev, SPO_PUSH, tmppush);
add_opcode(splev, SPO_JG, NULL);
add_opcode(splev, SPO_POP, NULL); /* get rid of the count value in stack */
break_stmt_end(splev);
}
;
chancestatement : comparestmt ':'
{
struct opvar *tmppush2 = New(struct opvar);
if (n_if_list >= MAX_NESTED_IFS) {
lc_error("IF: Too deeply nested conditionals.");
n_if_list = MAX_NESTED_IFS - 1;
}
add_opcode(splev, SPO_CMP, NULL);
set_opvar_int(tmppush2, splev->n_opcodes+1);
if_list[n_if_list++] = tmppush2;
add_opcode(splev, SPO_PUSH, tmppush2);
add_opcode(splev, reverse_jmp_opcode( $1 ), NULL);
}
levstatement
{
if (n_if_list > 0) {
struct opvar *tmppush;
tmppush = (struct opvar *) if_list[--n_if_list];
set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l);
} else lc_error("IF: Huh?! No start address?");
}
;
ifstatement : IF_ID comparestmt
{
struct opvar *tmppush2 = New(struct opvar);
if (n_if_list >= MAX_NESTED_IFS) {
lc_error("IF: Too deeply nested conditionals.");
n_if_list = MAX_NESTED_IFS - 1;
}
add_opcode(splev, SPO_CMP, NULL);
set_opvar_int(tmppush2, splev->n_opcodes+1);
if_list[n_if_list++] = tmppush2;
add_opcode(splev, SPO_PUSH, tmppush2);
add_opcode(splev, reverse_jmp_opcode( $2 ), NULL);
}
if_ending
{
/* do nothing */
}
;
if_ending : stmt_block
{
if (n_if_list > 0) {
struct opvar *tmppush;
tmppush = (struct opvar *) if_list[--n_if_list];
set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l);
} else lc_error("IF: Huh?! No start address?");
}
| stmt_block
{
if (n_if_list > 0) {
struct opvar *tmppush = New(struct opvar);
struct opvar *tmppush2;
set_opvar_int(tmppush, splev->n_opcodes+1);
add_opcode(splev, SPO_PUSH, tmppush);
add_opcode(splev, SPO_JMP, NULL);
tmppush2 = (struct opvar *) if_list[--n_if_list];
set_opvar_int(tmppush2, splev->n_opcodes - tmppush2->vardata.l);
if_list[n_if_list++] = tmppush;
} else lc_error("IF: Huh?! No else-part address?");
}
ELSE_ID stmt_block
{
if (n_if_list > 0) {
struct opvar *tmppush;
tmppush = (struct opvar *) if_list[--n_if_list];
set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l);
} else lc_error("IF: Huh?! No end address?");
}
;
message : MESSAGE_ID ':' string_expr
{
add_opvars(splev, "o", VA_PASS1(SPO_MESSAGE));
}
;
random_corridors: RAND_CORRIDOR_ID
{
add_opvars(splev, "iiiiiio",
VA_PASS7(-1, 0, -1, -1, -1, -1, SPO_CORRIDOR));
}
| RAND_CORRIDOR_ID ':' all_integers
{
add_opvars(splev, "iiiiiio",
VA_PASS7(-1, $3, -1, -1, -1, -1, SPO_CORRIDOR));
}
| RAND_CORRIDOR_ID ':' RANDOM_TYPE
{
add_opvars(splev, "iiiiiio",
VA_PASS7(-1, -1, -1, -1, -1, -1, SPO_CORRIDOR));
}
;
corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec
{
add_opvars(splev, "iiiiiio",
VA_PASS7($3.room, $3.door, $3.wall,
$5.room, $5.door, $5.wall,
SPO_CORRIDOR));
}
| CORRIDOR_ID ':' corr_spec ',' all_integers
{
add_opvars(splev, "iiiiiio",
VA_PASS7($3.room, $3.door, $3.wall,
-1, -1, (long)$5,
SPO_CORRIDOR));
}
;
corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')'
{
$$.room = $2;
$$.wall = $4;
$$.door = $6;
}
;
room_begin : room_type opt_percent ',' light_state
{
if (($2 < 100) && ($1 == OROOM))
lc_error("Only typed rooms can have a chance.");
else {
add_opvars(splev, "iii",
VA_PASS3((long)$1, (long)$2, (long)$4));
}
}
;
subroom_def : SUBROOM_ID ':' room_begin ',' subroom_pos ',' room_size optroomregionflags
{
long rflags = $8;
if (rflags == -1) rflags = (1 << 0);
add_opvars(splev, "iiiiiiio",
VA_PASS8(rflags, ERR, ERR,
$5.x, $5.y, $7.width, $7.height,
SPO_SUBROOM));
break_stmt_start();
}
stmt_block
{
break_stmt_end(splev);
add_opcode(splev, SPO_ENDROOM, NULL);
}
;
room_def : ROOM_ID ':' room_begin ',' room_pos ',' room_align ',' room_size optroomregionflags
{
long rflags = $8;
if (rflags == -1) rflags = (1 << 0);
add_opvars(splev, "iiiiiiio",
VA_PASS8(rflags,
$7.x, $7.y, $5.x, $5.y,
$9.width, $9.height, SPO_ROOM));
break_stmt_start();
}
stmt_block
{
break_stmt_end(splev);
add_opcode(splev, SPO_ENDROOM, NULL);
}
;
roomfill : /* nothing */
{
$$ = 1;
}
| ',' BOOLEAN
{
$$ = $2;
}
;
room_pos : '(' INTEGER ',' INTEGER ')'
{
if ( $2 < 1 || $2 > 5 ||
$4 < 1 || $4 > 5 ) {
lc_error("Room positions should be between 1-5: (%li,%li)!", $2, $4);
} else {
$$.x = $2;
$$.y = $4;
}
}
| RANDOM_TYPE
{
$$.x = $$.y = ERR;
}
;
subroom_pos : '(' INTEGER ',' INTEGER ')'
{
if ( $2 < 0 || $4 < 0) {
lc_error("Invalid subroom position (%li,%li)!", $2, $4);
} else {
$$.x = $2;
$$.y = $4;
}
}
| RANDOM_TYPE
{
$$.x = $$.y = ERR;
}
;
room_align : '(' h_justif ',' v_justif ')'
{
$$.x = $2;
$$.y = $4;
}
| RANDOM_TYPE
{
$$.x = $$.y = ERR;
}
;
room_size : '(' INTEGER ',' INTEGER ')'
{
$$.width = $2;
$$.height = $4;
}
| RANDOM_TYPE
{
$$.height = $$.width = ERR;
}
;
door_detail : ROOMDOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos
{
/* ERR means random here */
if ($7 == ERR && $9 != ERR) {
lc_error("If the door wall is random, so must be its pos!");
} else {
add_opvars(splev, "iiiio",
VA_PASS5((long)$9, (long)$5, (long)$3,
(long)$7, SPO_ROOM_DOOR));
}
}
| DOOR_ID ':' door_state ',' ter_selection
{
add_opvars(splev, "io", VA_PASS2((long)$3, SPO_DOOR));
}
;
secret : BOOLEAN
| RANDOM_TYPE
;
door_wall : dir_list
| RANDOM_TYPE
;
dir_list : DIRECTION
{
$$ = $1;
}
| DIRECTION '|' dir_list
{
$$ = ($1 | $3);
}
;
door_pos : INTEGER
| RANDOM_TYPE
;
map_definition : NOMAP_ID
{
add_opvars(splev, "ciisiio",
VA_PASS7(0, 0, 1, (char *)0, 0, 0, SPO_MAP));
max_x_map = COLNO-1;
max_y_map = ROWNO;
}
| GEOMETRY_ID ':' h_justif ',' v_justif roomfill MAP_ID
{
add_opvars(splev, "cii",
VA_PASS3(SP_COORD_PACK(($3),($5)),
1, (long)$6));
scan_map($7, splev);
Free($7);
}
| GEOMETRY_ID ':' coord_or_var roomfill MAP_ID
{
add_opvars(splev, "ii", VA_PASS2(2, (long)$4));
scan_map($5, splev);
Free($5);
}
;
h_justif : LEFT_OR_RIGHT
| CENTER
;
v_justif : TOP_OR_BOT
| CENTER
;
monster_detail : MONSTER_ID ':' monster_desc
{
add_opvars(splev, "io", VA_PASS2(0, SPO_MONSTER));
}
| MONSTER_ID ':' monster_desc
{
add_opvars(splev, "io", VA_PASS2(1, SPO_MONSTER));
in_container_obj++;
break_stmt_start();
}
stmt_block
{
break_stmt_end(splev);
in_container_obj--;
add_opvars(splev, "o", VA_PASS1(SPO_END_MONINVENT));
}
;
monster_desc : monster_or_var ',' coord_or_var monster_infos
{
/* nothing */
}
;
monster_infos : /* nothing */
{
struct opvar *stopit = New(struct opvar);
set_opvar_int(stopit, SP_M_V_END);
add_opcode(splev, SPO_PUSH, stopit);
$$ = 0x0000;
}
| monster_infos ',' monster_info
{
if (( $1 & $3 ))
lc_error("MONSTER extra info defined twice.");
$$ = ( $1 | $3 );
}
;
monster_info : string_expr
{
add_opvars(splev, "i", VA_PASS1(SP_M_V_NAME));
$$ = 0x0001;
}
| MON_ATTITUDE
{
add_opvars(splev, "ii",
VA_PASS2((long)$<i>1, SP_M_V_PEACEFUL));
$$ = 0x0002;
}
| MON_ALERTNESS
{
add_opvars(splev, "ii",
VA_PASS2((long)$<i>1, SP_M_V_ASLEEP));
$$ = 0x0004;
}
| alignment_prfx
{
add_opvars(splev, "ii",
VA_PASS2((long)$1, SP_M_V_ALIGN));
$$ = 0x0008;
}
| MON_APPEARANCE string_expr
{
add_opvars(splev, "ii",
VA_PASS2((long)$<i>1, SP_M_V_APPEAR));
$$ = 0x0010;
}
| FEMALE_ID
{
add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_FEMALE));
$$ = 0x0020;
}
| INVIS_ID
{
add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_INVIS));
$$ = 0x0040;
}
| CANCELLED_ID
{
add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_CANCELLED));
$$ = 0x0080;
}
| REVIVED_ID
{
add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_REVIVED));
$$ = 0x0100;
}
| AVENGE_ID
{
add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_AVENGE));
$$ = 0x0200;
}
| FLEEING_ID ':' integer_or_var
{
add_opvars(splev, "i", VA_PASS1(SP_M_V_FLEEING));
$$ = 0x0400;
}
| BLINDED_ID ':' integer_or_var
{
add_opvars(splev, "i", VA_PASS1(SP_M_V_BLINDED));
$$ = 0x0800;
}
| PARALYZED_ID ':' integer_or_var
{
add_opvars(splev, "i", VA_PASS1(SP_M_V_PARALYZED));
$$ = 0x1000;
}
| STUNNED_ID
{
add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_STUNNED));
$$ = 0x2000;
}
| CONFUSED_ID
{
add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_CONFUSED));
$$ = 0x4000;
}
| SEENTRAPS_ID ':' seen_trap_mask
{
add_opvars(splev, "ii",
VA_PASS2((long)$3, SP_M_V_SEENTRAPS));
$$ = 0x8000;
}
;
seen_trap_mask : STRING
{
int token = get_trap_type($1);
if (token == ERR || token == 0)
lc_error("Unknown trap type '%s'!", $1);
Free($1);
$$ = (1L << (token - 1));
}
| ALL_ID
{
$$ = (long) ~0;
}
| STRING '|' seen_trap_mask
{
int token = get_trap_type($1);
if (token == ERR || token == 0)
lc_error("Unknown trap type '%s'!", $1);
if ((1L << (token - 1)) & $3)
lc_error("Monster seen_traps, trap '%s' listed twice.", $1);
Free($1);
$$ = ((1L << (token - 1)) | $3);
}
;
object_detail : OBJECT_ID ':' object_desc
{
long cnt = 0;
if (in_container_obj) cnt |= SP_OBJ_CONTENT;
add_opvars(splev, "io", VA_PASS2(cnt, SPO_OBJECT));
}
| COBJECT_ID ':' object_desc
{
long cnt = SP_OBJ_CONTAINER;
if (in_container_obj) cnt |= SP_OBJ_CONTENT;
add_opvars(splev, "io", VA_PASS2(cnt, SPO_OBJECT));
in_container_obj++;
break_stmt_start();
}
stmt_block
{
break_stmt_end(splev);
in_container_obj--;
add_opcode(splev, SPO_POP_CONTAINER, NULL);
}
;
object_desc : object_or_var object_infos
{
if (( $2 & 0x4000) && in_container_obj)
lc_error("Object cannot have a coord when contained.");
else if (!( $2 & 0x4000) && !in_container_obj)
lc_error("Object needs a coord when not contained.");
}
;
object_infos : /* nothing */
{
struct opvar *stopit = New(struct opvar);
set_opvar_int(stopit, SP_O_V_END);
add_opcode(splev, SPO_PUSH, stopit);
$$ = 0x00;
}
| object_infos ',' object_info
{
if (( $1 & $3 ))
lc_error("OBJECT extra info '%s' defined twice.", curr_token);
$$ = ( $1 | $3 );
}
;
object_info : CURSE_TYPE
{
add_opvars(splev, "ii",
VA_PASS2((long)$1, SP_O_V_CURSE));
$$ = 0x0001;
}
| MONTYPE_ID ':' monster_or_var
{
add_opvars(splev, "i", VA_PASS1(SP_O_V_CORPSENM));
$$ = 0x0002;
}
| all_ints_push
{
add_opvars(splev, "i", VA_PASS1(SP_O_V_SPE));
$$ = 0x0004;
}
| NAME_ID ':' string_expr
{
add_opvars(splev, "i", VA_PASS1(SP_O_V_NAME));
$$ = 0x0008;
}
| QUANTITY_ID ':' integer_or_var
{
add_opvars(splev, "i", VA_PASS1(SP_O_V_QUAN));
$$ = 0x0010;
}
| BURIED_ID
{
add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_BURIED));
$$ = 0x0020;
}
| LIGHT_STATE
{
add_opvars(splev, "ii", VA_PASS2((long)$1, SP_O_V_LIT));
$$ = 0x0040;
}
| ERODED_ID ':' integer_or_var
{
add_opvars(splev, "i", VA_PASS1(SP_O_V_ERODED));
$$ = 0x0080;
}
| ERODEPROOF_ID
{
add_opvars(splev, "ii", VA_PASS2(-1, SP_O_V_ERODED));
$$ = 0x0080;
}
| DOOR_STATE
{
if ($1 == D_LOCKED) {
add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_LOCKED));
$$ = 0x0100;
} else if ($1 == D_BROKEN) {
add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_BROKEN));
$$ = 0x0200;
} else
lc_error("DOOR state can only be locked or broken.");
}
| TRAPPED_STATE
{
add_opvars(splev, "ii", VA_PASS2($1, SP_O_V_TRAPPED));
$$ = 0x0400;
}
| RECHARGED_ID ':' integer_or_var
{
add_opvars(splev, "i", VA_PASS1(SP_O_V_RECHARGED));
$$ = 0x0800;
}
| INVIS_ID
{
add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_INVIS));
$$ = 0x1000;
}
| GREASED_ID
{
add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_GREASED));
$$ = 0x2000;
}
| coord_or_var
{
add_opvars(splev, "i", VA_PASS1(SP_O_V_COORD));
$$ = 0x4000;
}
;
trap_detail : TRAP_ID ':' trap_name ',' coord_or_var
{
add_opvars(splev, "io", VA_PASS2((long)$3, SPO_TRAP));
}
;
drawbridge_detail: DRAWBRIDGE_ID ':' coord_or_var ',' DIRECTION ',' door_state
{
long dir, state = 0;
/* convert dir from a DIRECTION to a DB_DIR */
dir = $5;
switch (dir) {
case W_NORTH: dir = DB_NORTH; break;
case W_SOUTH: dir = DB_SOUTH; break;
case W_EAST: dir = DB_EAST; break;
case W_WEST: dir = DB_WEST; break;
default:
lc_error("Invalid drawbridge direction.");
break;
}
if ( $7 == D_ISOPEN )
state = 1;
else if ( $7 == D_CLOSED )
state = 0;
else if ( $7 == -1 )
state = -1;
else
lc_error("A drawbridge can only be open, closed or random!");
add_opvars(splev, "iio",
VA_PASS3(state, dir, SPO_DRAWBRIDGE));
}
;
mazewalk_detail : MAZEWALK_ID ':' coord_or_var ',' DIRECTION
{
add_opvars(splev, "iiio",
VA_PASS4((long)$5, 1, 0, SPO_MAZEWALK));
}
| MAZEWALK_ID ':' coord_or_var ',' DIRECTION ',' BOOLEAN opt_fillchar
{
add_opvars(splev, "iiio",
VA_PASS4((long)$5, (long)$<i>7,
(long)$8, SPO_MAZEWALK));
}
;
wallify_detail : WALLIFY_ID
{
add_opvars(splev, "rio",
VA_PASS3(SP_REGION_PACK(-1,-1,-1,-1),
0, SPO_WALLIFY));
}
| WALLIFY_ID ':' ter_selection
{
add_opvars(splev, "io", VA_PASS2(1, SPO_WALLIFY));
}
;
ladder_detail : LADDER_ID ':' coord_or_var ',' UP_OR_DOWN
{
add_opvars(splev, "io",
VA_PASS2((long)$<i>5, SPO_LADDER));
}
;
stair_detail : STAIR_ID ':' coord_or_var ',' UP_OR_DOWN
{
add_opvars(splev, "io",
VA_PASS2((long)$<i>5, SPO_STAIR));
}
;
stair_region : STAIR_ID ':' lev_region ',' lev_region ',' UP_OR_DOWN
{
add_opvars(splev, "iiiii iiiii iiso",
VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area,
$5.x1, $5.y1, $5.x2, $5.y2, $5.area,
(long) (($7) ? LR_UPSTAIR : LR_DOWNSTAIR),
0, (char *) 0, SPO_LEVREGION));
}
;
portal_region : PORTAL_ID ':' lev_region ',' lev_region ',' STRING
{
add_opvars(splev, "iiiii iiiii iiso",
VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area,
$5.x1, $5.y1, $5.x2, $5.y2, $5.area,
LR_PORTAL, 0, $7, SPO_LEVREGION));
Free($7);
}
;
teleprt_region : TELEPRT_ID ':' lev_region ',' lev_region teleprt_detail
{
long rtyp = 0;
switch($6) {
case -1: rtyp = LR_TELE; break;
case 0: rtyp = LR_DOWNTELE; break;
case 1: rtyp = LR_UPTELE; break;
}
add_opvars(splev, "iiiii iiiii iiso",
VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area,
$5.x1, $5.y1, $5.x2, $5.y2, $5.area,
rtyp, 0, (char *)0, SPO_LEVREGION));
}
;
branch_region : BRANCH_ID ':' lev_region ',' lev_region
{
add_opvars(splev, "iiiii iiiii iiso",
VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area,
$5.x1, $5.y1, $5.x2, $5.y2, $5.area,
(long) LR_BRANCH, 0,
(char *) 0, SPO_LEVREGION));
}
;
teleprt_detail : /* empty */
{
$$ = -1;
}
| ',' UP_OR_DOWN
{
$$ = $2;
}
;
fountain_detail : FOUNTAIN_ID ':' ter_selection
{
add_opvars(splev, "o", VA_PASS1(SPO_FOUNTAIN));
}
;
sink_detail : SINK_ID ':' ter_selection
{
add_opvars(splev, "o", VA_PASS1(SPO_SINK));
}
;
pool_detail : POOL_ID ':' ter_selection
{
add_opvars(splev, "o", VA_PASS1(SPO_POOL));
}
;
terrain_type : CHAR
{
$$.lit = -2;
$$.ter = what_map_char((char) $<i>1);
}
| '(' CHAR ',' light_state ')'
{
$$.lit = $4;
$$.ter = what_map_char((char) $<i>2);
}
;
replace_terrain_detail : REPLACE_TERRAIN_ID ':' region_or_var ',' mapchar_or_var ',' mapchar_or_var ',' SPERCENT
{
add_opvars(splev, "io",
VA_PASS2($9, SPO_REPLACETERRAIN));
}
;
terrain_detail : TERRAIN_ID ':' ter_selection ',' mapchar_or_var
{
add_opvars(splev, "o", VA_PASS1(SPO_TERRAIN));
}
;
diggable_detail : NON_DIGGABLE_ID ':' region_or_var
{
add_opvars(splev, "o", VA_PASS1(SPO_NON_DIGGABLE));
}
;
passwall_detail : NON_PASSWALL_ID ':' region_or_var
{
add_opvars(splev, "o", VA_PASS1(SPO_NON_PASSWALL));
}
;
region_detail : REGION_ID ':' region_or_var ',' light_state ',' room_type optroomregionflags
{
long irr;
long rt = $7;
long rflags = $8;
if (rflags == -1) rflags = (1 << 0);
if (!(rflags & 1)) rt += MAXRTYPE+1;
irr = ((rflags & 2) != 0);
add_opvars(splev, "iiio",
VA_PASS4((long)$5, rt, rflags, SPO_REGION));
$<i>$ = (irr || (rflags & 1) || rt != OROOM);
break_stmt_start();
}
region_detail_end
{
break_stmt_end(splev);
if ( $<i>9 ) {
add_opcode(splev, SPO_ENDROOM, NULL);
} else if ( $<i>10 )
lc_error("Cannot use lev statements in non-permanent REGION");
}
;
region_detail_end : /* nothing */
{
$$ = 0;
}
| stmt_block
{
$$ = $1;
}
;
altar_detail : ALTAR_ID ':' coord_or_var ',' alignment ',' altar_type
{
add_opvars(splev, "iio",
VA_PASS3((long)$7, (long)$5, SPO_ALTAR));
}
;
grave_detail : GRAVE_ID ':' coord_or_var ',' string_expr
{
add_opvars(splev, "io", VA_PASS2(2, SPO_GRAVE));
}
| GRAVE_ID ':' coord_or_var ',' RANDOM_TYPE
{
add_opvars(splev, "sio",
VA_PASS3((char *)0, 1, SPO_GRAVE));
}
| GRAVE_ID ':' coord_or_var
{
add_opvars(splev, "sio",
VA_PASS3((char *)0, 0, SPO_GRAVE));
}
;
gold_detail : GOLD_ID ':' math_expr_var ',' coord_or_var
{
add_opvars(splev, "o", VA_PASS1(SPO_GOLD));
}
;
engraving_detail: ENGRAVING_ID ':' coord_or_var ',' engraving_type ',' string_expr
{
add_opvars(splev, "io",
VA_PASS2((long)$5, SPO_ENGRAVING));
}
;
mineralize : MINERALIZE_ID ':' integer_or_var ',' integer_or_var ',' integer_or_var ',' integer_or_var
{
add_opvars(splev, "o", VA_PASS1(SPO_MINERALIZE));
}
| MINERALIZE_ID
{
add_opvars(splev, "iiiio",
VA_PASS5(-1L, -1L, -1L, -1L, SPO_MINERALIZE));
}
;
trap_name : STRING
{
int token = get_trap_type($1);
if (token == ERR)
lc_error("Unknown trap type '%s'!", $1);
$$ = token;
Free($1);
}
| RANDOM_TYPE
;
room_type : STRING
{
int token = get_room_type($1);
if (token == ERR) {
lc_warning("Unknown room type \"%s\"! Making ordinary room...", $1);
$$ = OROOM;
} else
$$ = token;
Free($1);
}
| RANDOM_TYPE
;
optroomregionflags : /* empty */
{
$$ = -1;
}
| ',' roomregionflags
{
$$ = $2;
}
;
roomregionflags : roomregionflag
{
$$ = $1;
}
| roomregionflag ',' roomregionflags
{
$$ = $1 | $3;
}
;
/* 0 is the "default" here */
roomregionflag : FILLING
{
$$ = ($1 << 0);
}
| IRREGULAR
{
$$ = ($1 << 1);
}
| JOINED
{
$$ = ($1 << 2);
}
;
door_state : DOOR_STATE
| RANDOM_TYPE
;
light_state : LIGHT_STATE
| RANDOM_TYPE
;
alignment : ALIGNMENT
| a_register
| RANDOM_TYPE
{
$$ = - MAX_REGISTERS - 1;
}
;
alignment_prfx : ALIGNMENT
| a_register
| A_REGISTER ':' RANDOM_TYPE
{
$$ = - MAX_REGISTERS - 1;
}
;
altar_type : ALTAR_TYPE
| RANDOM_TYPE
;
a_register : A_REGISTER '[' INTEGER ']'
{
if ( $3 >= 3 )
lc_error("Register Index overflow!");
else
$$ = - $3 - 1;
}
;
string_or_var : STRING
{
add_opvars(splev, "s", VA_PASS1($1));
Free($1);
}
| VARSTRING_STRING
{
check_vardef_type(variable_definitions, $1, SPOVAR_STRING);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
}
| VARSTRING_STRING_ARRAY '[' math_expr_var ']'
{
check_vardef_type(variable_definitions, $1, SPOVAR_STRING|SPOVAR_ARRAY);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
}
;
integer_or_var : math_expr_var
{
/* nothing */
}
;
coord_or_var : encodecoord
{
add_opvars(splev, "c", VA_PASS1($1));
}
| rndcoord_ID '(' ter_selection ')'
{
add_opvars(splev, "o", VA_PASS1(SPO_SEL_RNDCOORD));
}
| VARSTRING_COORD
{
check_vardef_type(variable_definitions, $1, SPOVAR_COORD);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
}
| VARSTRING_COORD_ARRAY '[' math_expr_var ']'
{
check_vardef_type(variable_definitions, $1, SPOVAR_COORD|SPOVAR_ARRAY);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
}
;
encodecoord : '(' INTEGER ',' INTEGER ')'
{
if ($2 < 0 || $4 < 0 || $2 >= COLNO || $4 >= ROWNO)
lc_error("Coordinates (%li,%li) out of map range!", $2, $4);
$$ = SP_COORD_PACK($2, $4);
}
| RANDOM_TYPE
{
$$ = SP_COORD_PACK_RANDOM(0);
}
| RANDOM_TYPE_BRACKET humidity_flags ']'
{
$$ = SP_COORD_PACK_RANDOM( $2 );
}
;
humidity_flags : HUMIDITY_TYPE
{
$$ = $1;
}
| HUMIDITY_TYPE ',' humidity_flags
{
if (($1 & $3))
lc_warning("Humidity flag used twice.");
$$ = ($1 | $3);
}
;
region_or_var : encoderegion
{
/* nothing */
}
| VARSTRING_REGION
{
check_vardef_type(variable_definitions, $1, SPOVAR_REGION);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
}
| VARSTRING_REGION_ARRAY '[' math_expr_var ']'
{
check_vardef_type(variable_definitions, $1, SPOVAR_REGION|SPOVAR_ARRAY);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
}
;
encoderegion : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
{
long r = SP_REGION_PACK($2, $4, $6, $8);
if ( $2 > $6 || $4 > $8 )
lc_error("Region start > end: (%li,%li,%li,%li)!", $2, $4, $6, $8);
add_opvars(splev, "r", VA_PASS1(r));
$$ = r;
}
;
mapchar_or_var : mapchar
{
add_opvars(splev, "m", VA_PASS1($1));
}
| VARSTRING_MAPCHAR
{
check_vardef_type(variable_definitions, $1, SPOVAR_MAPCHAR);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
}
| VARSTRING_MAPCHAR_ARRAY '[' math_expr_var ']'
{
check_vardef_type(variable_definitions, $1, SPOVAR_MAPCHAR|SPOVAR_ARRAY);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
}
;
mapchar : CHAR
{
if (what_map_char((char) $1) != INVALID_TYPE)
$$ = SP_MAPCHAR_PACK(what_map_char((char) $1), -2);
else {
lc_error("Unknown map char type '%c'!", $1);
$$ = SP_MAPCHAR_PACK(STONE, -2);
}
}
| '(' CHAR ',' light_state ')'
{
if (what_map_char((char) $2) != INVALID_TYPE)
$$ = SP_MAPCHAR_PACK(what_map_char((char) $2), $4);
else {
lc_error("Unknown map char type '%c'!", $2);
$$ = SP_MAPCHAR_PACK(STONE, $4);
}
}
;
monster_or_var : encodemonster
{
add_opvars(splev, "M", VA_PASS1($1));
}
| VARSTRING_MONST
{
check_vardef_type(variable_definitions, $1, SPOVAR_MONST);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
}
| VARSTRING_MONST_ARRAY '[' math_expr_var ']'
{
check_vardef_type(variable_definitions, $1, SPOVAR_MONST|SPOVAR_ARRAY);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
}
;
encodemonster : STRING
{
long m = get_monster_id($1, (char)0);
if (m == ERR) {
lc_error("Unknown monster \"%s\"!", $1);
$$ = -1;
} else
$$ = SP_MONST_PACK(m,
def_monsyms[(int) mons[m].mlet].sym);
Free($1);
}
| CHAR
{
if (check_monster_char((char) $1))
$$ = SP_MONST_PACK(-1, $1);
else {
lc_error("Unknown monster class '%c'!", $1);
$$ = -1;
}
}
| '(' CHAR ',' STRING ')'
{
long m = get_monster_id($4, (char) $2);
if (m == ERR) {
lc_error("Unknown monster ('%c', \"%s\")!", $2, $4);
$$ = -1;
} else
$$ = SP_MONST_PACK(m, $2);
Free($4);
}
| RANDOM_TYPE
{
$$ = -1;
}
;
object_or_var : encodeobj
{
add_opvars(splev, "O", VA_PASS1($1));
}
| VARSTRING_OBJ
{
check_vardef_type(variable_definitions, $1, SPOVAR_OBJ);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
}
| VARSTRING_OBJ_ARRAY '[' math_expr_var ']'
{
check_vardef_type(variable_definitions, $1, SPOVAR_OBJ|SPOVAR_ARRAY);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
}
;
encodeobj : STRING
{
long m = get_object_id($1, (char)0);
if (m == ERR) {
lc_error("Unknown object \"%s\"!", $1);
$$ = -1;
} else
$$ = SP_OBJ_PACK(m, 1); /* obj class != 0 to force generation of a specific item */
Free($1);
}
| CHAR
{
if (check_object_char((char) $1))
$$ = SP_OBJ_PACK(-1, $1);
else {
lc_error("Unknown object class '%c'!", $1);
$$ = -1;
}
}
| '(' CHAR ',' STRING ')'
{
long m = get_object_id($4, (char) $2);
if (m == ERR) {
lc_error("Unknown object ('%c', \"%s\")!", $2, $4);
$$ = -1;
} else
$$ = SP_OBJ_PACK(m, $2);
Free($4);
}
| RANDOM_TYPE
{
$$ = -1;
}
;
string_expr : string_or_var { }
| string_expr '.' string_or_var
{
add_opvars(splev, "o", VA_PASS1(SPO_MATH_ADD));
}
;
math_expr_var : INTEGER
{
add_opvars(splev, "i", VA_PASS1($1));
}
| dice
{
is_inconstant_number = 1;
}
| '(' MINUS_INTEGER ')'
{
add_opvars(splev, "i", VA_PASS1($2));
}
| VARSTRING_INT
{
check_vardef_type(variable_definitions, $1, SPOVAR_INT);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
is_inconstant_number = 1;
}
| VARSTRING_INT_ARRAY '[' math_expr_var ']'
{
check_vardef_type(variable_definitions,
$1, SPOVAR_INT|SPOVAR_ARRAY);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
is_inconstant_number = 1;
}
| math_expr_var '+' math_expr_var
{
add_opvars(splev, "o", VA_PASS1(SPO_MATH_ADD));
}
| math_expr_var '-' math_expr_var
{
add_opvars(splev, "o", VA_PASS1(SPO_MATH_SUB));
}
| math_expr_var '*' math_expr_var
{
add_opvars(splev, "o", VA_PASS1(SPO_MATH_MUL));
}
| math_expr_var '/' math_expr_var
{
add_opvars(splev, "o", VA_PASS1(SPO_MATH_DIV));
}
| math_expr_var '%' math_expr_var
{
add_opvars(splev, "o", VA_PASS1(SPO_MATH_MOD));
}
| '(' math_expr_var ')' { }
;
func_param_type : CFUNC_INT
{
if (!strcmp("int", $1) || !strcmp("integer", $1)) {
$$ = (int)'i';
} else
lc_error("Unknown function parameter type '%s'", $1);
}
| CFUNC_STR
{
if (!strcmp("str", $1) || !strcmp("string", $1)) {
$$ = (int)'s';
} else
lc_error("Unknown function parameter type '%s'", $1);
}
;
func_param_part : any_var_or_arr ':' func_param_type
{
struct lc_funcdefs_parm *tmp = New(struct lc_funcdefs_parm);
if (!curr_function) {
lc_error("Function parameters outside function definition.");
} else if (!tmp) {
lc_error("Could not alloc function params.");
} else {
long vt = SPOVAR_NULL;
tmp->name = strdup($1);
tmp->parmtype = (char) $3;
tmp->next = curr_function->params;
curr_function->params = tmp;
curr_function->n_params++;
switch (tmp->parmtype) {
case 'i':
vt = SPOVAR_INT;
break;
case 's':
vt = SPOVAR_STRING;
break;
default:
lc_error("Unknown func param conversion.");
break;
}
variable_definitions = add_vardef_type(
variable_definitions,
$1, vt);
}
Free($1);
}
;
func_param_list : func_param_part
| func_param_list ',' func_param_part
;
func_params_list : /* nothing */
| func_param_list
;
func_call_param_part : math_expr_var
{
$$ = (int)'i';
}
| string_expr
{
$$ = (int)'s';
}
;
func_call_param_list : func_call_param_part
{
char tmpbuf[2];
tmpbuf[0] = (char) $1;
tmpbuf[1] = '\0';
$$ = strdup(tmpbuf);
}
| func_call_param_list ',' func_call_param_part
{
long len = strlen( $1 );
char *tmp = (char *) alloc(len + 2);
sprintf(tmp, "%c%s", (char) $3, $1 );
Free( $1 );
$$ = tmp;
}
;
func_call_params_list : /* nothing */
{
$$ = strdup("");
}
| func_call_param_list
{
char *tmp = strdup( $1 );
Free( $1 );
$$ = tmp;
}
;
ter_selection_x : coord_or_var
{
add_opvars(splev, "o", VA_PASS1(SPO_SEL_POINT));
}
| rect_ID region_or_var
{
add_opvars(splev, "o", VA_PASS1(SPO_SEL_RECT));
}
| fillrect_ID region_or_var
{
add_opvars(splev, "o", VA_PASS1(SPO_SEL_FILLRECT));
}
| line_ID coord_or_var ',' coord_or_var
{
add_opvars(splev, "o", VA_PASS1(SPO_SEL_LINE));
}
| randline_ID coord_or_var ',' coord_or_var ',' math_expr_var
{
/* randline (x1,y1),(x2,y2), roughness */
add_opvars(splev, "o", VA_PASS1(SPO_SEL_RNDLINE));
}
| grow_ID '(' ter_selection ')'
{
add_opvars(splev, "io", VA_PASS2(W_ANY, SPO_SEL_GROW));
}
| grow_ID '(' dir_list ',' ter_selection ')'
{
add_opvars(splev, "io", VA_PASS2($3, SPO_SEL_GROW));
}
| filter_ID '(' SPERCENT ',' ter_selection ')'
{
add_opvars(splev, "iio",
VA_PASS3($3, SPOFILTER_PERCENT, SPO_SEL_FILTER));
}
| filter_ID '(' ter_selection ',' ter_selection ')'
{
add_opvars(splev, "io",
VA_PASS2(SPOFILTER_SELECTION, SPO_SEL_FILTER));
}
| filter_ID '(' mapchar_or_var ',' ter_selection ')'
{
add_opvars(splev, "io",
VA_PASS2(SPOFILTER_MAPCHAR, SPO_SEL_FILTER));
}
| flood_ID coord_or_var
{
add_opvars(splev, "o", VA_PASS1(SPO_SEL_FLOOD));
}
| circle_ID '(' coord_or_var ',' math_expr_var ')'
{
add_opvars(splev, "oio",
VA_PASS3(SPO_COPY, 1, SPO_SEL_ELLIPSE));
}
| circle_ID '(' coord_or_var ',' math_expr_var ',' FILLING ')'
{
add_opvars(splev, "oio",
VA_PASS3(SPO_COPY, $7, SPO_SEL_ELLIPSE));
}
| ellipse_ID '(' coord_or_var ',' math_expr_var ',' math_expr_var ')'
{
add_opvars(splev, "io", VA_PASS2(1, SPO_SEL_ELLIPSE));
}
| ellipse_ID '(' coord_or_var ',' math_expr_var ',' math_expr_var ',' FILLING ')'
{
add_opvars(splev, "io", VA_PASS2($9, SPO_SEL_ELLIPSE));
}
| gradient_ID '(' GRADIENT_TYPE ',' '(' math_expr_var '-' math_expr_var opt_limited ')' ',' coord_or_var opt_coord_or_var ')'
{
add_opvars(splev, "iio",
VA_PASS3($9, $3, SPO_SEL_GRADIENT));
}
| complement_ID ter_selection_x
{
add_opvars(splev, "o", VA_PASS1(SPO_SEL_COMPLEMENT));
}
| VARSTRING_SEL
{
check_vardef_type(variable_definitions, $1, SPOVAR_SEL);
vardef_used(variable_definitions, $1);
add_opvars(splev, "v", VA_PASS1($1));
Free($1);
}
| '(' ter_selection ')'
{
/* nothing */
}
;
ter_selection : ter_selection_x
{
/* nothing */
}
| ter_selection_x '&' ter_selection
{
add_opvars(splev, "o", VA_PASS1(SPO_SEL_ADD));
}
;
dice : DICE
{
add_opvars(splev, "iio",
VA_PASS3($1.num, $1.die, SPO_DICE));
}
;
all_integers : MINUS_INTEGER
| PLUS_INTEGER
| INTEGER
;
all_ints_push : MINUS_INTEGER
{
add_opvars(splev, "i", VA_PASS1($1));
}
| PLUS_INTEGER
{
add_opvars(splev, "i", VA_PASS1($1));
}
| INTEGER
{
add_opvars(splev, "i", VA_PASS1($1));
}
| dice
{
/* nothing */
}
;
objectid : object_ID
| OBJECT_ID
;
monsterid : monster_ID
| MONSTER_ID
;
terrainid : terrain_ID
| TERRAIN_ID
;
engraving_type : ENGRAVING_TYPE
| RANDOM_TYPE
;
lev_region : region
{
$$ = $1;
}
| LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
{
if ($3 <= 0 || $3 >= COLNO)
lc_error(
"Region (%ld,%ld,%ld,%ld) out of level range (x1)!",
$3, $5, $7, $9);
else if ($5 < 0 || $5 >= ROWNO)
lc_error(
"Region (%ld,%ld,%ld,%ld) out of level range (y1)!",
$3, $5, $7, $9);
else if ($7 <= 0 || $7 >= COLNO)
lc_error(
"Region (%ld,%ld,%ld,%ld) out of level range (x2)!",
$3, $5, $7, $9);
else if ($9 < 0 || $9 >= ROWNO)
lc_error(
"Region (%ld,%ld,%ld,%ld) out of level range (y2)!",
$3, $5, $7, $9);
$$.x1 = $3;
$$.y1 = $5;
$$.x2 = $7;
$$.y2 = $9;
$$.area = 1;
}
;
region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
{
/* This series of if statements is a hack for MSC 5.1. It seems that its
tiny little brain cannot compile if these are all one big if statement. */
if ($2 < 0 || $2 > (int) max_x_map)
lc_error(
"Region (%ld,%ld,%ld,%ld) out of map range (x1)!",
$2, $4, $6, $8);
else if ($4 < 0 || $4 > (int) max_y_map)
lc_error(
"Region (%ld,%ld,%ld,%ld) out of map range (y1)!",
$2, $4, $6, $8);
else if ($6 < 0 || $6 > (int) max_x_map)
lc_error(
"Region (%ld,%ld,%ld,%ld) out of map range (x2)!",
$2, $4, $6, $8);
else if ($8 < 0 || $8 > (int) max_y_map)
lc_error(
"Region (%ld,%ld,%ld,%ld) out of map range (y2)!",
$2, $4, $6, $8);
$$.area = 0;
$$.x1 = $2;
$$.y1 = $4;
$$.x2 = $6;
$$.y2 = $8;
}
;
%%
/*lev_comp.y*/