2 /* NetHack 3.6 lev_comp.y $NHDT-Date: 1448074095 2015/11/21 02:48:15 $ $NHDT-Branch: master $:$NHDT-Revision: 1.18 $ */
3 /* Copyright (c) 1989 by Jean-Christophe Collet */
4 /* NetHack may be freely redistributed. See license for details. */
7 * This file contains the Level Compiler code
8 * It may handle special mazes & special room-levels
11 /* In case we're using bison in AIX. This definition must be
12 * placed before any other C-language construct in the file
13 * excluding comments and preprocessor directives (thanks IBM
14 * for this wonderful feature...).
16 * Note: some cpps barf on this 'undefined control' (#pragma).
17 * Addition of the leading space seems to prevent barfage for now,
18 * and AIX will still see the directive.
21 #pragma alloca /* keep leading space! */
24 #define SPEC_LEV /* for USE_OLDARGS (sp_lev.h) */
29 /* many types of things are put in chars for transference to NetHack.
30 * since some systems will use signed chars, limit everybody to the
31 * same number for portability.
33 #define MAX_OF_TYPE 128
35 #define MAX_NESTED_IFS 20
36 #define MAX_SWITCH_CASES 20
39 (type *) memset((genericptr_t)alloc(sizeof(type)), 0, sizeof(type))
40 #define NewTab(type, size) (type **) alloc(sizeof(type *) * size)
41 #define Free(ptr) free((genericptr_t)ptr)
43 extern void VDECL(lc_error, (const char *, ...));
44 extern void VDECL(lc_warning, (const char *, ...));
45 extern void FDECL(yyerror, (const char *));
46 extern void FDECL(yywarning, (const char *));
47 extern int NDECL(yylex);
50 extern int FDECL(get_floor_type, (CHAR_P));
51 extern int FDECL(get_room_type, (char *));
52 extern int FDECL(get_trap_type, (char *));
53 extern int FDECL(get_monster_id, (char *,CHAR_P));
54 extern int FDECL(get_object_id, (char *,CHAR_P));
55 extern boolean FDECL(check_monster_char, (CHAR_P));
56 extern boolean FDECL(check_object_char, (CHAR_P));
57 extern char FDECL(what_map_char, (CHAR_P));
58 extern void FDECL(scan_map, (char *, sp_lev *));
59 extern void FDECL(add_opcode, (sp_lev *, int, genericptr_t));
60 extern genericptr_t FDECL(get_last_opcode_data1, (sp_lev *, int));
61 extern genericptr_t FDECL(get_last_opcode_data2, (sp_lev *, int,int));
62 extern boolean FDECL(check_subrooms, (sp_lev *));
63 extern boolean FDECL(write_level_file, (char *,sp_lev *));
64 extern struct opvar *FDECL(set_opvar_int, (struct opvar *, long));
65 extern void VDECL(add_opvars, (sp_lev *, const char *, ...));
66 extern void FDECL(start_level_def, (sp_lev * *, char *));
68 extern struct lc_funcdefs *FDECL(funcdef_new,(long,char *));
69 extern void FDECL(funcdef_free_all,(struct lc_funcdefs *));
70 extern struct lc_funcdefs *FDECL(funcdef_defined,(struct lc_funcdefs *,char *, int));
71 extern char *FDECL(funcdef_paramtypes, (struct lc_funcdefs *));
72 extern char *FDECL(decode_parm_str, (char *));
74 extern struct lc_vardefs *FDECL(vardef_new,(long,char *));
75 extern void FDECL(vardef_free_all,(struct lc_vardefs *));
76 extern struct lc_vardefs *FDECL(vardef_defined,(struct lc_vardefs *,char *, int));
78 extern void NDECL(break_stmt_start);
79 extern void FDECL(break_stmt_end, (sp_lev *));
80 extern void FDECL(break_stmt_new, (sp_lev *, long));
82 extern void FDECL(splev_add_from, (sp_lev *, sp_lev *));
84 extern void FDECL(check_vardef_type, (struct lc_vardefs *, char *, long));
85 extern void FDECL(vardef_used, (struct lc_vardefs *, char *));
86 extern struct lc_vardefs *FDECL(add_vardef_type, (struct lc_vardefs *, char *, long));
88 extern int FDECL(reverse_jmp_opcode, (int));
99 static struct forloopdef forloop_list[MAX_NESTED_IFS];
100 static short n_forloops = 0;
103 sp_lev *splev = NULL;
105 static struct opvar *if_list[MAX_NESTED_IFS];
107 static short n_if_list = 0;
109 unsigned int max_x_map, max_y_map;
110 int obj_containment = 0;
112 int in_container_obj = 0;
114 /* integer value is possibly an inconstant value (eg. dice notation or a variable) */
115 int is_inconstant_number = 0;
117 int in_switch_statement = 0;
118 static struct opvar *switch_check_jump = NULL;
119 static struct opvar *switch_default_case = NULL;
120 static struct opvar *switch_case_list[MAX_SWITCH_CASES];
121 static long switch_case_value[MAX_SWITCH_CASES];
122 int n_switch_case_list = 0;
124 int allow_break_statements = 0;
125 struct lc_breakdef *break_list = NULL;
127 extern struct lc_vardefs *variable_definitions;
130 struct lc_vardefs *function_tmp_var_defs = NULL;
131 extern struct lc_funcdefs *function_definitions;
132 struct lc_funcdefs *curr_function = NULL;
133 struct lc_funcdefs_parm * curr_function_param = NULL;
134 int in_function_definition = 0;
135 sp_lev *function_splev_backup = NULL;
137 extern int fatal_error;
138 extern int got_errors;
139 extern int line_number;
140 extern const char *fname;
142 extern char curr_token[512];
185 %token <i> CHAR INTEGER BOOLEAN PERCENT SPERCENT
186 %token <i> MINUS_INTEGER PLUS_INTEGER
187 %token <i> MAZE_GRID_ID SOLID_FILL_ID MINES_ID ROGUELEV_ID
188 %token <i> MESSAGE_ID MAZE_ID LEVEL_ID LEV_INIT_ID GEOMETRY_ID NOMAP_ID
189 %token <i> OBJECT_ID COBJECT_ID MONSTER_ID TRAP_ID DOOR_ID DRAWBRIDGE_ID
190 %token <i> object_ID monster_ID terrain_ID
191 %token <i> MAZEWALK_ID WALLIFY_ID REGION_ID FILLING IRREGULAR JOINED
192 %token <i> ALTAR_ID LADDER_ID STAIR_ID NON_DIGGABLE_ID NON_PASSWALL_ID ROOM_ID
193 %token <i> PORTAL_ID TELEPRT_ID BRANCH_ID LEV MINERALIZE_ID
194 %token <i> CORRIDOR_ID GOLD_ID ENGRAVING_ID FOUNTAIN_ID POOL_ID SINK_ID NONE
195 %token <i> RAND_CORRIDOR_ID DOOR_STATE LIGHT_STATE CURSE_TYPE ENGRAVING_TYPE
196 %token <i> DIRECTION RANDOM_TYPE RANDOM_TYPE_BRACKET A_REGISTER
197 %token <i> ALIGNMENT LEFT_OR_RIGHT CENTER TOP_OR_BOT ALTAR_TYPE UP_OR_DOWN
198 %token <i> SUBROOM_ID NAME_ID FLAGS_ID FLAG_TYPE MON_ATTITUDE MON_ALERTNESS
199 %token <i> MON_APPEARANCE ROOMDOOR_ID IF_ID ELSE_ID
200 %token <i> TERRAIN_ID HORIZ_OR_VERT REPLACE_TERRAIN_ID
201 %token <i> EXIT_ID SHUFFLE_ID
202 %token <i> QUANTITY_ID BURIED_ID LOOP_ID
203 %token <i> FOR_ID TO_ID
204 %token <i> SWITCH_ID CASE_ID BREAK_ID DEFAULT_ID
205 %token <i> ERODED_ID TRAPPED_STATE RECHARGED_ID INVIS_ID GREASED_ID
206 %token <i> FEMALE_ID CANCELLED_ID REVIVED_ID AVENGE_ID FLEEING_ID BLINDED_ID
207 %token <i> PARALYZED_ID STUNNED_ID CONFUSED_ID SEENTRAPS_ID ALL_ID
208 %token <i> MONTYPE_ID
209 %token <i> GRAVE_ID ERODEPROOF_ID
210 %token <i> FUNCTION_ID
211 %token <i> MSG_OUTPUT_TYPE
212 %token <i> COMPARE_TYPE
213 %token <i> UNKNOWN_TYPE
214 %token <i> rect_ID fillrect_ID line_ID randline_ID grow_ID selection_ID flood_ID
215 %token <i> rndcoord_ID circle_ID ellipse_ID filter_ID complement_ID
216 %token <i> gradient_ID GRADIENT_TYPE LIMITED HUMIDITY_TYPE
217 %token <i> ',' ':' '(' ')' '[' ']' '{' '}'
218 %token <map> STRING MAP_ID
219 %token <map> NQSTRING VARSTRING
220 %token <map> CFUNC CFUNC_INT CFUNC_STR CFUNC_COORD CFUNC_REGION
221 %token <map> VARSTRING_INT VARSTRING_INT_ARRAY
222 %token <map> VARSTRING_STRING VARSTRING_STRING_ARRAY
223 %token <map> VARSTRING_VAR VARSTRING_VAR_ARRAY
224 %token <map> VARSTRING_COORD VARSTRING_COORD_ARRAY
225 %token <map> VARSTRING_REGION VARSTRING_REGION_ARRAY
226 %token <map> VARSTRING_MAPCHAR VARSTRING_MAPCHAR_ARRAY
227 %token <map> VARSTRING_MONST VARSTRING_MONST_ARRAY
228 %token <map> VARSTRING_OBJ VARSTRING_OBJ_ARRAY
229 %token <map> VARSTRING_SEL VARSTRING_SEL_ARRAY
230 %token <meth> METHOD_INT METHOD_INT_ARRAY
231 %token <meth> METHOD_STRING METHOD_STRING_ARRAY
232 %token <meth> METHOD_VAR METHOD_VAR_ARRAY
233 %token <meth> METHOD_COORD METHOD_COORD_ARRAY
234 %token <meth> METHOD_REGION METHOD_REGION_ARRAY
235 %token <meth> METHOD_MAPCHAR METHOD_MAPCHAR_ARRAY
236 %token <meth> METHOD_MONST METHOD_MONST_ARRAY
237 %token <meth> METHOD_OBJ METHOD_OBJ_ARRAY
238 %token <meth> METHOD_SEL METHOD_SEL_ARRAY
240 %type <i> h_justif v_justif trap_name room_type door_state light_state
241 %type <i> alignment altar_type a_register roomfill door_pos
242 %type <i> alignment_prfx
243 %type <i> door_wall walled secret
244 %type <i> dir_list teleprt_detail
245 %type <i> object_infos object_info monster_infos monster_info
246 %type <i> levstatements stmt_block region_detail_end
247 %type <i> engraving_type flag_list roomregionflag roomregionflags optroomregionflags
248 %type <i> humidity_flags
249 %type <i> comparestmt encodecoord encoderegion mapchar
250 %type <i> seen_trap_mask
251 %type <i> encodemonster encodeobj encodeobj_list
252 %type <i> integer_list string_list encodecoord_list encoderegion_list mapchar_list encodemonster_list
253 %type <i> opt_percent opt_fillchar
254 %type <i> all_integers
255 %type <i> ter_selection ter_selection_x
256 %type <i> func_param_type
257 %type <i> objectid monsterid terrainid
258 %type <i> opt_coord_or_var opt_limited
260 %type <map> level_def
261 %type <map> any_var any_var_array any_var_or_arr any_var_or_unk
262 %type <map> func_call_params_list func_call_param_list
263 %type <i> func_call_param_part
264 %type <corpos> corr_spec
265 %type <lregn> region lev_region
266 %type <crd> room_pos subroom_pos room_align
267 %type <sze> room_size
268 %type <terr> terrain_type
282 level : level_def flags levstatements
284 if (fatal_error > 0) {
285 (void) fprintf(stderr,
286 "%s: %d errors detected for level \"%s\". No output created!\n",
287 fname, fatal_error, $1);
290 } else if (!got_errors) {
291 if (!write_level_file($1, splev)) {
292 lc_error("Can't write output file for '%s'!", $1);
299 vardef_free_all(variable_definitions);
300 variable_definitions = NULL;
304 level_def : LEVEL_ID ':' STRING
306 start_level_def(&splev, $3);
309 | MAZE_ID ':' STRING ',' mazefiller
311 start_level_def(&splev, $3);
313 add_opvars(splev, "iiiiiiiio",
314 VA_PASS9(LVLINIT_MAZEGRID,HWALL,0,0,
315 0,0,0,0, SPO_INITLEVEL));
317 long bg = what_map_char((char) $5);
318 add_opvars(splev, "iiiiiiiio",
319 VA_PASS9(LVLINIT_SOLIDFILL, bg, 0,0,
320 0,0,0,0, SPO_INITLEVEL));
322 add_opvars(splev, "io",
323 VA_PASS2(MAZELEVEL, SPO_LEVEL_FLAGS));
330 mazefiller : RANDOM_TYPE
336 $$ = what_map_char((char) $1);
340 lev_init : LEV_INIT_ID ':' SOLID_FILL_ID ',' terrain_type
342 long filling = $5.ter;
343 if (filling == INVALID_TYPE || filling >= MAX_TYPE)
344 lc_error("INIT_MAP: Invalid fill char type.");
345 add_opvars(splev, "iiiiiiiio",
346 LVLINIT_SOLIDFILL,filling,0,(long)$5.lit, 0,0,0,0, SPO_INITLEVEL);
350 | LEV_INIT_ID ':' MAZE_GRID_ID ',' CHAR
352 long filling = what_map_char((char) $5);
353 if (filling == INVALID_TYPE || filling >= MAX_TYPE)
354 lc_error("INIT_MAP: Invalid fill char type.");
355 add_opvars(splev, "iiiiiiiio",
356 VA_PASS9(LVLINIT_MAZEGRID,filling,0,0,
357 0,0,0,0, SPO_INITLEVEL));
361 | LEV_INIT_ID ':' ROGUELEV_ID
363 add_opvars(splev, "iiiiiiiio",
364 VA_PASS9(LVLINIT_ROGUE,0,0,0,
365 0,0,0,0, SPO_INITLEVEL));
367 | LEV_INIT_ID ':' MINES_ID ',' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled opt_fillchar
369 long fg = what_map_char((char) $5);
370 long bg = what_map_char((char) $7);
376 if (fg == INVALID_TYPE || fg >= MAX_TYPE)
377 lc_error("INIT_MAP: Invalid foreground type.");
378 if (bg == INVALID_TYPE || bg >= MAX_TYPE)
379 lc_error("INIT_MAP: Invalid background type.");
380 if (joined && fg != CORR && fg != ROOM)
381 lc_error("INIT_MAP: Invalid foreground type for joined map.");
383 if (filling == INVALID_TYPE)
384 lc_error("INIT_MAP: Invalid fill char type.");
386 add_opvars(splev, "iiiiiiiio",
387 VA_PASS9(LVLINIT_MINES,filling,walled,lit,
388 joined,smoothed,bg,fg,
395 opt_limited : /* nothing */
405 opt_coord_or_var : /* nothing */
407 add_opvars(splev, "o", VA_PASS1(SPO_COPY));
416 opt_fillchar : /* nothing */
422 $$ = what_map_char((char) $2);
431 flags : /* nothing */
433 add_opvars(splev, "io", VA_PASS2(0, SPO_LEVEL_FLAGS));
435 | FLAGS_ID ':' flag_list
437 add_opvars(splev, "io", VA_PASS2($3, SPO_LEVEL_FLAGS));
441 flag_list : FLAG_TYPE ',' flag_list
451 levstatements : /* nothing */
455 | levstatement levstatements
461 stmt_block : '{' levstatements '}'
467 levstatement : message
505 | replace_terrain_detail
513 any_var_array : VARSTRING_INT_ARRAY
514 | VARSTRING_STRING_ARRAY
515 | VARSTRING_VAR_ARRAY
516 | VARSTRING_COORD_ARRAY
517 | VARSTRING_REGION_ARRAY
518 | VARSTRING_MAPCHAR_ARRAY
519 | VARSTRING_MONST_ARRAY
520 | VARSTRING_OBJ_ARRAY
521 | VARSTRING_SEL_ARRAY
524 any_var : VARSTRING_INT
535 any_var_or_arr : any_var_array
540 any_var_or_unk : VARSTRING
544 shuffle_detail : SHUFFLE_ID ':' any_var_array
546 struct lc_vardefs *vd;
547 if ((vd = vardef_defined(variable_definitions, $3, 1))) {
548 if (!(vd->var_type & SPOVAR_ARRAY))
549 lc_error("Trying to shuffle non-array variable '%s'", $3);
550 } else lc_error("Trying to shuffle undefined variable '%s'", $3);
551 add_opvars(splev, "so", VA_PASS2($3, SPO_SHUFFLE_ARRAY));
556 variable_define : any_var_or_arr '=' math_expr_var
558 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_INT);
559 add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
562 | any_var_or_arr '=' selection_ID ':' ter_selection
564 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_SEL);
565 add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
568 | any_var_or_arr '=' string_expr
570 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_STRING);
571 add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
574 | any_var_or_arr '=' terrainid ':' mapchar_or_var
576 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_MAPCHAR);
577 add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
580 | any_var_or_arr '=' monsterid ':' monster_or_var
582 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_MONST);
583 add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
586 | any_var_or_arr '=' objectid ':' object_or_var
588 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_OBJ);
589 add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
592 | any_var_or_arr '=' coord_or_var
594 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_COORD);
595 add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
598 | any_var_or_arr '=' region_or_var
600 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_REGION);
601 add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
604 | any_var_or_arr '=' '{' integer_list '}'
607 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_INT|SPOVAR_ARRAY);
608 add_opvars(splev, "iso",
609 VA_PASS3(n_items, $1, SPO_VAR_INIT));
612 | any_var_or_arr '=' '{' encodecoord_list '}'
615 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_COORD|SPOVAR_ARRAY);
616 add_opvars(splev, "iso",
617 VA_PASS3(n_items, $1, SPO_VAR_INIT));
620 | any_var_or_arr '=' '{' encoderegion_list '}'
623 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_REGION|SPOVAR_ARRAY);
624 add_opvars(splev, "iso",
625 VA_PASS3(n_items, $1, SPO_VAR_INIT));
628 | any_var_or_arr '=' terrainid ':' '{' mapchar_list '}'
631 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_MAPCHAR|SPOVAR_ARRAY);
632 add_opvars(splev, "iso",
633 VA_PASS3(n_items, $1, SPO_VAR_INIT));
636 | any_var_or_arr '=' monsterid ':' '{' encodemonster_list '}'
639 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_MONST|SPOVAR_ARRAY);
640 add_opvars(splev, "iso",
641 VA_PASS3(n_items, $1, SPO_VAR_INIT));
644 | any_var_or_arr '=' objectid ':' '{' encodeobj_list '}'
647 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_OBJ|SPOVAR_ARRAY);
648 add_opvars(splev, "iso",
649 VA_PASS3(n_items, $1, SPO_VAR_INIT));
652 | any_var_or_arr '=' '{' string_list '}'
655 variable_definitions = add_vardef_type(variable_definitions, $1, SPOVAR_STRING|SPOVAR_ARRAY);
656 add_opvars(splev, "iso",
657 VA_PASS3(n_items, $1, SPO_VAR_INIT));
662 encodeobj_list : encodeobj
664 add_opvars(splev, "O", VA_PASS1($1));
667 | encodeobj_list ',' encodeobj
669 add_opvars(splev, "O", VA_PASS1($3));
674 encodemonster_list : encodemonster
676 add_opvars(splev, "M", VA_PASS1($1));
679 | encodemonster_list ',' encodemonster
681 add_opvars(splev, "M", VA_PASS1($3));
686 mapchar_list : mapchar
688 add_opvars(splev, "m", VA_PASS1($1));
691 | mapchar_list ',' mapchar
693 add_opvars(splev, "m", VA_PASS1($3));
698 encoderegion_list : encoderegion
702 | encoderegion_list ',' encoderegion
708 encodecoord_list : encodecoord
710 add_opvars(splev, "c", VA_PASS1($1));
713 | encodecoord_list ',' encodecoord
715 add_opvars(splev, "c", VA_PASS1($3));
720 integer_list : math_expr_var
724 | integer_list ',' math_expr_var
730 string_list : string_expr
734 | string_list ',' string_expr
740 function_define : FUNCTION_ID NQSTRING '('
742 struct lc_funcdefs *funcdef;
744 if (in_function_definition)
745 lc_error("Recursively defined functions not allowed (function %s).", $2);
747 in_function_definition++;
749 if (funcdef_defined(function_definitions, $2, 1))
750 lc_error("Function '%s' already defined once.", $2);
752 funcdef = funcdef_new(-1, $2);
753 funcdef->next = function_definitions;
754 function_definitions = funcdef;
755 function_splev_backup = splev;
756 splev = &(funcdef->code);
758 curr_function = funcdef;
759 function_tmp_var_defs = variable_definitions;
760 variable_definitions = NULL;
768 add_opvars(splev, "io", VA_PASS2(0, SPO_RETURN));
769 splev = function_splev_backup;
770 in_function_definition--;
771 curr_function = NULL;
772 vardef_free_all(variable_definitions);
773 variable_definitions = function_tmp_var_defs;
777 function_call : NQSTRING '(' func_call_params_list ')'
779 struct lc_funcdefs *tmpfunc;
780 tmpfunc = funcdef_defined(function_definitions, $1, 1);
783 long nparams = strlen( $3 );
784 char *fparamstr = funcdef_paramtypes(tmpfunc);
785 if (strcmp($3, fparamstr)) {
786 char *tmps = strdup(decode_parm_str(fparamstr));
787 lc_error("Function '%s' requires params '%s', got '%s' instead.", $1, tmps, decode_parm_str($3));
792 if (!(tmpfunc->n_called)) {
793 /* we haven't called the function yet, so insert it in the code */
794 struct opvar *jmp = New(struct opvar);
795 set_opvar_int(jmp, splev->n_opcodes+1);
796 add_opcode(splev, SPO_PUSH, jmp);
797 add_opcode(splev, SPO_JMP, NULL); /* we must jump past it first, then CALL it, due to RETURN. */
799 tmpfunc->addr = splev->n_opcodes;
801 { /* init function parameter variables */
802 struct lc_funcdefs_parm *tfp = tmpfunc->params;
804 add_opvars(splev, "iso",
805 VA_PASS3(0, tfp->name,
811 splev_add_from(splev, &(tmpfunc->code));
812 set_opvar_int(jmp, splev->n_opcodes - jmp->vardata.l);
814 l = tmpfunc->addr - splev->n_opcodes - 2;
815 add_opvars(splev, "iio",
816 VA_PASS3(nparams, l, SPO_CALL));
819 lc_error("Function '%s' not defined.", $1);
825 exitstatement : EXIT_ID
827 add_opcode(splev, SPO_EXIT, NULL);
831 opt_percent : /* nothing */
841 comparestmt : PERCENT
844 add_opvars(splev, "iio",
845 VA_PASS3((long)$1, 100, SPO_RN2));
848 | '[' math_expr_var COMPARE_TYPE math_expr_var ']'
852 | '[' math_expr_var ']'
854 /* boolean, explicit foo != 0 */
855 add_opvars(splev, "i", VA_PASS1(0));
860 switchstatement : SWITCH_ID
862 is_inconstant_number = 0;
864 '[' integer_or_var ']'
866 struct opvar *chkjmp;
867 if (in_switch_statement > 0)
868 lc_error("Cannot nest switch-statements.");
870 in_switch_statement++;
872 n_switch_case_list = 0;
873 switch_default_case = NULL;
875 if (!is_inconstant_number)
876 add_opvars(splev, "o", VA_PASS1(SPO_RN2));
877 is_inconstant_number = 0;
879 chkjmp = New(struct opvar);
880 set_opvar_int(chkjmp, splev->n_opcodes+1);
881 switch_check_jump = chkjmp;
882 add_opcode(splev, SPO_PUSH, chkjmp);
883 add_opcode(splev, SPO_JMP, NULL);
888 struct opvar *endjump = New(struct opvar);
891 set_opvar_int(endjump, splev->n_opcodes+1);
893 add_opcode(splev, SPO_PUSH, endjump);
894 add_opcode(splev, SPO_JMP, NULL);
896 set_opvar_int(switch_check_jump,
897 splev->n_opcodes - switch_check_jump->vardata.l);
899 for (i = 0; i < n_switch_case_list; i++) {
900 add_opvars(splev, "oio",
902 switch_case_value[i], SPO_CMP));
903 set_opvar_int(switch_case_list[i],
904 switch_case_list[i]->vardata.l - splev->n_opcodes-1);
905 add_opcode(splev, SPO_PUSH, switch_case_list[i]);
906 add_opcode(splev, SPO_JE, NULL);
909 if (switch_default_case) {
910 set_opvar_int(switch_default_case,
911 switch_default_case->vardata.l - splev->n_opcodes-1);
912 add_opcode(splev, SPO_PUSH, switch_default_case);
913 add_opcode(splev, SPO_JMP, NULL);
916 set_opvar_int(endjump, splev->n_opcodes - endjump->vardata.l);
918 break_stmt_end(splev);
920 add_opcode(splev, SPO_POP, NULL); /* get rid of the value in stack */
921 in_switch_statement--;
927 switchcases : /* nothing */
928 | switchcase switchcases
931 switchcase : CASE_ID all_integers ':'
933 if (n_switch_case_list < MAX_SWITCH_CASES) {
934 struct opvar *tmppush = New(struct opvar);
935 set_opvar_int(tmppush, splev->n_opcodes);
936 switch_case_value[n_switch_case_list] = $2;
937 switch_case_list[n_switch_case_list++] = tmppush;
938 } else lc_error("Too many cases in a switch.");
945 struct opvar *tmppush = New(struct opvar);
947 if (switch_default_case)
948 lc_error("Switch default case already used.");
950 set_opvar_int(tmppush, splev->n_opcodes);
951 switch_default_case = tmppush;
958 breakstatement : BREAK_ID
960 if (!allow_break_statements)
961 lc_error("Cannot use BREAK outside a statement block.");
963 break_stmt_new(splev, splev->n_opcodes);
968 for_to_span : '.' '.'
972 forstmt_start : FOR_ID any_var_or_unk '=' math_expr_var for_to_span math_expr_var
974 char buf[256], buf2[256];
976 if (n_forloops >= MAX_NESTED_IFS) {
977 lc_error("FOR: Too deeply nested loops.");
978 n_forloops = MAX_NESTED_IFS - 1;
981 /* first, define a variable for the for-loop end value */
982 snprintf(buf, 255, "%s end", $2);
983 /* the value of which is already in stack (the 2nd math_expr) */
984 add_opvars(splev, "iso", VA_PASS3(0, buf, SPO_VAR_INIT));
986 variable_definitions = add_vardef_type(variable_definitions,
988 /* define the for-loop variable. value is in stack (1st math_expr) */
989 add_opvars(splev, "iso", VA_PASS3(0, $2, SPO_VAR_INIT));
991 /* calculate value for the loop "step" variable */
992 snprintf(buf2, 255, "%s step", $2);
994 add_opvars(splev, "vvo",
995 VA_PASS3(buf, $2, SPO_MATH_SUB));
997 add_opvars(splev, "o", VA_PASS1(SPO_MATH_SIGN));
998 /* save the sign into the step var */
999 add_opvars(splev, "iso",
1000 VA_PASS3(0, buf2, SPO_VAR_INIT));
1002 forloop_list[n_forloops].varname = strdup($2);
1003 forloop_list[n_forloops].jmp_point = splev->n_opcodes;
1010 forstatement : forstmt_start
1017 char buf[256], buf2[256];
1019 snprintf(buf, 255, "%s step", forloop_list[n_forloops].varname);
1020 snprintf(buf2, 255, "%s end", forloop_list[n_forloops].varname);
1021 /* compare for-loop var to end value */
1022 add_opvars(splev, "vvo",
1023 VA_PASS3(forloop_list[n_forloops].varname,
1026 add_opvars(splev, "vvo",
1027 VA_PASS3(buf, forloop_list[n_forloops].varname,
1029 /* for-loop var = (for-loop var + step) */
1030 add_opvars(splev, "iso",
1031 VA_PASS3(0, forloop_list[n_forloops].varname,
1033 /* jump back if compared values were not equal */
1034 add_opvars(splev, "io",
1036 forloop_list[n_forloops].jmp_point - splev->n_opcodes - 1,
1038 Free(forloop_list[n_forloops].varname);
1039 break_stmt_end(splev);
1043 loopstatement : LOOP_ID '[' integer_or_var ']'
1045 struct opvar *tmppush = New(struct opvar);
1047 if (n_if_list >= MAX_NESTED_IFS) {
1048 lc_error("LOOP: Too deeply nested conditionals.");
1049 n_if_list = MAX_NESTED_IFS - 1;
1051 set_opvar_int(tmppush, splev->n_opcodes);
1052 if_list[n_if_list++] = tmppush;
1054 add_opvars(splev, "o", VA_PASS1(SPO_DEC));
1059 struct opvar *tmppush;
1061 add_opvars(splev, "oio", VA_PASS3(SPO_COPY, 0, SPO_CMP));
1063 tmppush = (struct opvar *) if_list[--n_if_list];
1064 set_opvar_int(tmppush, tmppush->vardata.l - splev->n_opcodes-1);
1065 add_opcode(splev, SPO_PUSH, tmppush);
1066 add_opcode(splev, SPO_JG, NULL);
1067 add_opcode(splev, SPO_POP, NULL); /* get rid of the count value in stack */
1068 break_stmt_end(splev);
1072 chancestatement : comparestmt ':'
1074 struct opvar *tmppush2 = New(struct opvar);
1076 if (n_if_list >= MAX_NESTED_IFS) {
1077 lc_error("IF: Too deeply nested conditionals.");
1078 n_if_list = MAX_NESTED_IFS - 1;
1081 add_opcode(splev, SPO_CMP, NULL);
1083 set_opvar_int(tmppush2, splev->n_opcodes+1);
1085 if_list[n_if_list++] = tmppush2;
1087 add_opcode(splev, SPO_PUSH, tmppush2);
1089 add_opcode(splev, reverse_jmp_opcode( $1 ), NULL);
1094 if (n_if_list > 0) {
1095 struct opvar *tmppush;
1096 tmppush = (struct opvar *) if_list[--n_if_list];
1097 set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l);
1098 } else lc_error("IF: Huh?! No start address?");
1102 ifstatement : IF_ID comparestmt
1104 struct opvar *tmppush2 = New(struct opvar);
1106 if (n_if_list >= MAX_NESTED_IFS) {
1107 lc_error("IF: Too deeply nested conditionals.");
1108 n_if_list = MAX_NESTED_IFS - 1;
1111 add_opcode(splev, SPO_CMP, NULL);
1113 set_opvar_int(tmppush2, splev->n_opcodes+1);
1115 if_list[n_if_list++] = tmppush2;
1117 add_opcode(splev, SPO_PUSH, tmppush2);
1119 add_opcode(splev, reverse_jmp_opcode( $2 ), NULL);
1128 if_ending : stmt_block
1130 if (n_if_list > 0) {
1131 struct opvar *tmppush;
1132 tmppush = (struct opvar *) if_list[--n_if_list];
1133 set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l);
1134 } else lc_error("IF: Huh?! No start address?");
1138 if (n_if_list > 0) {
1139 struct opvar *tmppush = New(struct opvar);
1140 struct opvar *tmppush2;
1142 set_opvar_int(tmppush, splev->n_opcodes+1);
1143 add_opcode(splev, SPO_PUSH, tmppush);
1145 add_opcode(splev, SPO_JMP, NULL);
1147 tmppush2 = (struct opvar *) if_list[--n_if_list];
1149 set_opvar_int(tmppush2, splev->n_opcodes - tmppush2->vardata.l);
1150 if_list[n_if_list++] = tmppush;
1151 } else lc_error("IF: Huh?! No else-part address?");
1155 if (n_if_list > 0) {
1156 struct opvar *tmppush;
1157 tmppush = (struct opvar *) if_list[--n_if_list];
1158 set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l);
1159 } else lc_error("IF: Huh?! No end address?");
1163 message : MESSAGE_ID ':' string_expr
1165 add_opvars(splev, "o", VA_PASS1(SPO_MESSAGE));
1169 random_corridors: RAND_CORRIDOR_ID
1171 add_opvars(splev, "iiiiiio",
1172 VA_PASS7(-1, 0, -1, -1, -1, -1, SPO_CORRIDOR));
1174 | RAND_CORRIDOR_ID ':' all_integers
1176 add_opvars(splev, "iiiiiio",
1177 VA_PASS7(-1, $3, -1, -1, -1, -1, SPO_CORRIDOR));
1179 | RAND_CORRIDOR_ID ':' RANDOM_TYPE
1181 add_opvars(splev, "iiiiiio",
1182 VA_PASS7(-1, -1, -1, -1, -1, -1, SPO_CORRIDOR));
1186 corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec
1188 add_opvars(splev, "iiiiiio",
1189 VA_PASS7($3.room, $3.door, $3.wall,
1190 $5.room, $5.door, $5.wall,
1193 | CORRIDOR_ID ':' corr_spec ',' all_integers
1195 add_opvars(splev, "iiiiiio",
1196 VA_PASS7($3.room, $3.door, $3.wall,
1202 corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')'
1210 room_begin : room_type opt_percent ',' light_state
1212 if (($2 < 100) && ($1 == OROOM))
1213 lc_error("Only typed rooms can have a chance.");
1215 add_opvars(splev, "iii",
1216 VA_PASS3((long)$1, (long)$2, (long)$4));
1221 subroom_def : SUBROOM_ID ':' room_begin ',' subroom_pos ',' room_size optroomregionflags
1225 if (rflags == -1) rflags = (1 << 0);
1226 add_opvars(splev, "iiiiiiio",
1227 VA_PASS8(rflags, ERR, ERR,
1228 $5.x, $5.y, $7.width, $7.height,
1234 break_stmt_end(splev);
1235 add_opcode(splev, SPO_ENDROOM, NULL);
1239 room_def : ROOM_ID ':' room_begin ',' room_pos ',' room_align ',' room_size optroomregionflags
1243 if (rflags == -1) rflags = (1 << 0);
1244 add_opvars(splev, "iiiiiiio",
1246 $7.x, $7.y, $5.x, $5.y,
1247 $9.width, $9.height, SPO_ROOM));
1252 break_stmt_end(splev);
1253 add_opcode(splev, SPO_ENDROOM, NULL);
1257 roomfill : /* nothing */
1267 room_pos : '(' INTEGER ',' INTEGER ')'
1269 if ( $2 < 1 || $2 > 5 ||
1270 $4 < 1 || $4 > 5 ) {
1271 lc_error("Room positions should be between 1-5: (%li,%li)!", $2, $4);
1283 subroom_pos : '(' INTEGER ',' INTEGER ')'
1285 if ( $2 < 0 || $4 < 0) {
1286 lc_error("Invalid subroom position (%li,%li)!", $2, $4);
1298 room_align : '(' h_justif ',' v_justif ')'
1309 room_size : '(' INTEGER ',' INTEGER ')'
1316 $$.height = $$.width = ERR;
1320 door_detail : ROOMDOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos
1322 /* ERR means random here */
1323 if ($7 == ERR && $9 != ERR) {
1324 lc_error("If the door wall is random, so must be its pos!");
1326 add_opvars(splev, "iiiio",
1327 VA_PASS5((long)$9, (long)$5, (long)$3,
1328 (long)$7, SPO_ROOM_DOOR));
1331 | DOOR_ID ':' door_state ',' ter_selection
1333 add_opvars(splev, "io", VA_PASS2((long)$3, SPO_DOOR));
1341 door_wall : dir_list
1345 dir_list : DIRECTION
1349 | DIRECTION '|' dir_list
1359 map_definition : NOMAP_ID
1361 add_opvars(splev, "ciisiio",
1362 VA_PASS7(0, 0, 1, (char *)0, 0, 0, SPO_MAP));
1363 max_x_map = COLNO-1;
1366 | GEOMETRY_ID ':' h_justif ',' v_justif roomfill MAP_ID
1368 add_opvars(splev, "cii",
1369 VA_PASS3(SP_COORD_PACK(($3),($5)),
1371 scan_map($7, splev);
1374 | GEOMETRY_ID ':' coord_or_var roomfill MAP_ID
1376 add_opvars(splev, "ii", VA_PASS2(2, (long)$4));
1377 scan_map($5, splev);
1382 h_justif : LEFT_OR_RIGHT
1386 v_justif : TOP_OR_BOT
1390 monster_detail : MONSTER_ID ':' monster_desc
1392 add_opvars(splev, "io", VA_PASS2(0, SPO_MONSTER));
1394 | MONSTER_ID ':' monster_desc
1396 add_opvars(splev, "io", VA_PASS2(1, SPO_MONSTER));
1402 break_stmt_end(splev);
1404 add_opvars(splev, "o", VA_PASS1(SPO_END_MONINVENT));
1408 monster_desc : monster_or_var ',' coord_or_var monster_infos
1414 monster_infos : /* nothing */
1416 struct opvar *stopit = New(struct opvar);
1417 set_opvar_int(stopit, SP_M_V_END);
1418 add_opcode(splev, SPO_PUSH, stopit);
1421 | monster_infos ',' monster_info
1424 lc_error("MONSTER extra info defined twice.");
1429 monster_info : string_expr
1431 add_opvars(splev, "i", VA_PASS1(SP_M_V_NAME));
1436 add_opvars(splev, "ii",
1437 VA_PASS2((long)$<i>1, SP_M_V_PEACEFUL));
1442 add_opvars(splev, "ii",
1443 VA_PASS2((long)$<i>1, SP_M_V_ASLEEP));
1448 add_opvars(splev, "ii",
1449 VA_PASS2((long)$1, SP_M_V_ALIGN));
1452 | MON_APPEARANCE string_expr
1454 add_opvars(splev, "ii",
1455 VA_PASS2((long)$<i>1, SP_M_V_APPEAR));
1460 add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_FEMALE));
1465 add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_INVIS));
1470 add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_CANCELLED));
1475 add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_REVIVED));
1480 add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_AVENGE));
1483 | FLEEING_ID ':' integer_or_var
1485 add_opvars(splev, "i", VA_PASS1(SP_M_V_FLEEING));
1488 | BLINDED_ID ':' integer_or_var
1490 add_opvars(splev, "i", VA_PASS1(SP_M_V_BLINDED));
1493 | PARALYZED_ID ':' integer_or_var
1495 add_opvars(splev, "i", VA_PASS1(SP_M_V_PARALYZED));
1500 add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_STUNNED));
1505 add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_CONFUSED));
1508 | SEENTRAPS_ID ':' seen_trap_mask
1510 add_opvars(splev, "ii",
1511 VA_PASS2((long)$3, SP_M_V_SEENTRAPS));
1516 seen_trap_mask : STRING
1518 int token = get_trap_type($1);
1519 if (token == ERR || token == 0)
1520 lc_error("Unknown trap type '%s'!", $1);
1522 $$ = (1L << (token - 1));
1528 | STRING '|' seen_trap_mask
1530 int token = get_trap_type($1);
1531 if (token == ERR || token == 0)
1532 lc_error("Unknown trap type '%s'!", $1);
1534 if ((1L << (token - 1)) & $3)
1535 lc_error("Monster seen_traps, trap '%s' listed twice.", $1);
1537 $$ = ((1L << (token - 1)) | $3);
1541 object_detail : OBJECT_ID ':' object_desc
1544 if (in_container_obj) cnt |= SP_OBJ_CONTENT;
1545 add_opvars(splev, "io", VA_PASS2(cnt, SPO_OBJECT));
1547 | COBJECT_ID ':' object_desc
1549 long cnt = SP_OBJ_CONTAINER;
1550 if (in_container_obj) cnt |= SP_OBJ_CONTENT;
1551 add_opvars(splev, "io", VA_PASS2(cnt, SPO_OBJECT));
1557 break_stmt_end(splev);
1559 add_opcode(splev, SPO_POP_CONTAINER, NULL);
1563 object_desc : object_or_var object_infos
1565 if (( $2 & 0x4000) && in_container_obj)
1566 lc_error("Object cannot have a coord when contained.");
1567 else if (!( $2 & 0x4000) && !in_container_obj)
1568 lc_error("Object needs a coord when not contained.");
1572 object_infos : /* nothing */
1574 struct opvar *stopit = New(struct opvar);
1575 set_opvar_int(stopit, SP_O_V_END);
1576 add_opcode(splev, SPO_PUSH, stopit);
1579 | object_infos ',' object_info
1582 lc_error("OBJECT extra info '%s' defined twice.", curr_token);
1587 object_info : CURSE_TYPE
1589 add_opvars(splev, "ii",
1590 VA_PASS2((long)$1, SP_O_V_CURSE));
1593 | MONTYPE_ID ':' monster_or_var
1595 add_opvars(splev, "i", VA_PASS1(SP_O_V_CORPSENM));
1600 add_opvars(splev, "i", VA_PASS1(SP_O_V_SPE));
1603 | NAME_ID ':' string_expr
1605 add_opvars(splev, "i", VA_PASS1(SP_O_V_NAME));
1608 | QUANTITY_ID ':' integer_or_var
1610 add_opvars(splev, "i", VA_PASS1(SP_O_V_QUAN));
1615 add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_BURIED));
1620 add_opvars(splev, "ii", VA_PASS2((long)$1, SP_O_V_LIT));
1623 | ERODED_ID ':' integer_or_var
1625 add_opvars(splev, "i", VA_PASS1(SP_O_V_ERODED));
1630 add_opvars(splev, "ii", VA_PASS2(-1, SP_O_V_ERODED));
1635 if ($1 == D_LOCKED) {
1636 add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_LOCKED));
1638 } else if ($1 == D_BROKEN) {
1639 add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_BROKEN));
1642 lc_error("DOOR state can only be locked or broken.");
1646 add_opvars(splev, "ii", VA_PASS2($1, SP_O_V_TRAPPED));
1649 | RECHARGED_ID ':' integer_or_var
1651 add_opvars(splev, "i", VA_PASS1(SP_O_V_RECHARGED));
1656 add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_INVIS));
1661 add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_GREASED));
1666 add_opvars(splev, "i", VA_PASS1(SP_O_V_COORD));
1671 trap_detail : TRAP_ID ':' trap_name ',' coord_or_var
1673 add_opvars(splev, "io", VA_PASS2((long)$3, SPO_TRAP));
1677 drawbridge_detail: DRAWBRIDGE_ID ':' coord_or_var ',' DIRECTION ',' door_state
1679 long dir, state = 0;
1681 /* convert dir from a DIRECTION to a DB_DIR */
1684 case W_NORTH: dir = DB_NORTH; break;
1685 case W_SOUTH: dir = DB_SOUTH; break;
1686 case W_EAST: dir = DB_EAST; break;
1687 case W_WEST: dir = DB_WEST; break;
1689 lc_error("Invalid drawbridge direction.");
1693 if ( $7 == D_ISOPEN )
1695 else if ( $7 == D_CLOSED )
1697 else if ( $7 == -1 )
1700 lc_error("A drawbridge can only be open, closed or random!");
1701 add_opvars(splev, "iio",
1702 VA_PASS3(state, dir, SPO_DRAWBRIDGE));
1706 mazewalk_detail : MAZEWALK_ID ':' coord_or_var ',' DIRECTION
1708 add_opvars(splev, "iiio",
1709 VA_PASS4((long)$5, 1, 0, SPO_MAZEWALK));
1711 | MAZEWALK_ID ':' coord_or_var ',' DIRECTION ',' BOOLEAN opt_fillchar
1713 add_opvars(splev, "iiio",
1714 VA_PASS4((long)$5, (long)$<i>7,
1715 (long)$8, SPO_MAZEWALK));
1719 wallify_detail : WALLIFY_ID
1721 add_opvars(splev, "rio",
1722 VA_PASS3(SP_REGION_PACK(-1,-1,-1,-1),
1725 | WALLIFY_ID ':' ter_selection
1727 add_opvars(splev, "io", VA_PASS2(1, SPO_WALLIFY));
1731 ladder_detail : LADDER_ID ':' coord_or_var ',' UP_OR_DOWN
1733 add_opvars(splev, "io",
1734 VA_PASS2((long)$<i>5, SPO_LADDER));
1738 stair_detail : STAIR_ID ':' coord_or_var ',' UP_OR_DOWN
1740 add_opvars(splev, "io",
1741 VA_PASS2((long)$<i>5, SPO_STAIR));
1745 stair_region : STAIR_ID ':' lev_region ',' lev_region ',' UP_OR_DOWN
1747 add_opvars(splev, "iiiii iiiii iiso",
1748 VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area,
1749 $5.x1, $5.y1, $5.x2, $5.y2, $5.area,
1750 (long)(($7) ? LR_UPSTAIR : LR_DOWNSTAIR),
1751 0, (char *)0, SPO_LEVREGION));
1755 portal_region : PORTAL_ID ':' lev_region ',' lev_region ',' STRING
1757 add_opvars(splev, "iiiii iiiii iiso",
1758 VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area,
1759 $5.x1, $5.y1, $5.x2, $5.y2, $5.area,
1760 LR_PORTAL, 0, $7, SPO_LEVREGION));
1765 teleprt_region : TELEPRT_ID ':' lev_region ',' lev_region teleprt_detail
1769 case -1: rtyp = LR_TELE; break;
1770 case 0: rtyp = LR_DOWNTELE; break;
1771 case 1: rtyp = LR_UPTELE; break;
1773 add_opvars(splev, "iiiii iiiii iiso",
1774 VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area,
1775 $5.x1, $5.y1, $5.x2, $5.y2, $5.area,
1776 rtyp, 0, (char *)0, SPO_LEVREGION));
1780 branch_region : BRANCH_ID ':' lev_region ',' lev_region
1782 add_opvars(splev, "iiiii iiiii iiso",
1783 VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area,
1784 $5.x1, $5.y1, $5.x2, $5.y2, $5.area,
1786 (char *)0, SPO_LEVREGION));
1790 teleprt_detail : /* empty */
1800 fountain_detail : FOUNTAIN_ID ':' ter_selection
1802 add_opvars(splev, "o", VA_PASS1(SPO_FOUNTAIN));
1806 sink_detail : SINK_ID ':' ter_selection
1808 add_opvars(splev, "o", VA_PASS1(SPO_SINK));
1812 pool_detail : POOL_ID ':' ter_selection
1814 add_opvars(splev, "o", VA_PASS1(SPO_POOL));
1821 $$.ter = what_map_char((char) $<i>1);
1823 | '(' CHAR ',' light_state ')'
1826 $$.ter = what_map_char((char) $<i>2);
1830 replace_terrain_detail : REPLACE_TERRAIN_ID ':' region_or_var ',' mapchar_or_var ',' mapchar_or_var ',' SPERCENT
1832 add_opvars(splev, "io",
1833 VA_PASS2($9, SPO_REPLACETERRAIN));
1837 terrain_detail : TERRAIN_ID ':' ter_selection ',' mapchar_or_var
1839 add_opvars(splev, "o", VA_PASS1(SPO_TERRAIN));
1843 diggable_detail : NON_DIGGABLE_ID ':' region_or_var
1845 add_opvars(splev, "o", VA_PASS1(SPO_NON_DIGGABLE));
1849 passwall_detail : NON_PASSWALL_ID ':' region_or_var
1851 add_opvars(splev, "o", VA_PASS1(SPO_NON_PASSWALL));
1855 region_detail : REGION_ID ':' region_or_var ',' light_state ',' room_type optroomregionflags
1861 if (rflags == -1) rflags = (1 << 0);
1862 if (!(rflags & 1)) rt += MAXRTYPE+1;
1863 irr = ((rflags & 2) != 0);
1864 add_opvars(splev, "iiio",
1865 VA_PASS4((long)$5, rt, rflags, SPO_REGION));
1866 $<i>$ = (irr || (rflags & 1) || rt != OROOM);
1871 break_stmt_end(splev);
1873 add_opcode(splev, SPO_ENDROOM, NULL);
1874 } else if ( $<i>10 )
1875 lc_error("Cannot use lev statements in non-permanent REGION");
1879 region_detail_end : /* nothing */
1889 altar_detail : ALTAR_ID ':' coord_or_var ',' alignment ',' altar_type
1891 add_opvars(splev, "iio",
1892 VA_PASS3((long)$7, (long)$5, SPO_ALTAR));
1896 grave_detail : GRAVE_ID ':' coord_or_var ',' string_expr
1898 add_opvars(splev, "io", VA_PASS2(2, SPO_GRAVE));
1900 | GRAVE_ID ':' coord_or_var ',' RANDOM_TYPE
1902 add_opvars(splev, "sio",
1903 VA_PASS3((char *)0, 1, SPO_GRAVE));
1905 | GRAVE_ID ':' coord_or_var
1907 add_opvars(splev, "sio",
1908 VA_PASS3((char *)0, 0, SPO_GRAVE));
1912 gold_detail : GOLD_ID ':' math_expr_var ',' coord_or_var
1914 add_opvars(splev, "o", VA_PASS1(SPO_GOLD));
1918 engraving_detail: ENGRAVING_ID ':' coord_or_var ',' engraving_type ',' string_expr
1920 add_opvars(splev, "io",
1921 VA_PASS2((long)$5, SPO_ENGRAVING));
1925 mineralize : MINERALIZE_ID ':' integer_or_var ',' integer_or_var ',' integer_or_var ',' integer_or_var
1927 add_opvars(splev, "o", VA_PASS1(SPO_MINERALIZE));
1931 add_opvars(splev, "iiiio",
1932 VA_PASS5(-1L, -1L, -1L, -1L, SPO_MINERALIZE));
1938 int token = get_trap_type($1);
1940 lc_error("Unknown trap type '%s'!", $1);
1949 int token = get_room_type($1);
1951 lc_warning("Unknown room type \"%s\"! Making ordinary room...", $1);
1960 optroomregionflags : /* empty */
1964 | ',' roomregionflags
1970 roomregionflags : roomregionflag
1974 | roomregionflag ',' roomregionflags
1980 /* 0 is the "default" here */
1981 roomregionflag : FILLING
1995 door_state : DOOR_STATE
1999 light_state : LIGHT_STATE
2003 alignment : ALIGNMENT
2007 $$ = - MAX_REGISTERS - 1;
2011 alignment_prfx : ALIGNMENT
2013 | A_REGISTER ':' RANDOM_TYPE
2015 $$ = - MAX_REGISTERS - 1;
2019 altar_type : ALTAR_TYPE
2023 a_register : A_REGISTER '[' INTEGER ']'
2026 lc_error("Register Index overflow!");
2032 string_or_var : STRING
2034 add_opvars(splev, "s", VA_PASS1($1));
2039 check_vardef_type(variable_definitions, $1, SPOVAR_STRING);
2040 vardef_used(variable_definitions, $1);
2041 add_opvars(splev, "v", VA_PASS1($1));
2044 | VARSTRING_STRING_ARRAY '[' math_expr_var ']'
2046 check_vardef_type(variable_definitions, $1, SPOVAR_STRING|SPOVAR_ARRAY);
2047 vardef_used(variable_definitions, $1);
2048 add_opvars(splev, "v", VA_PASS1($1));
2054 integer_or_var : math_expr_var
2060 coord_or_var : encodecoord
2062 add_opvars(splev, "c", VA_PASS1($1));
2064 | rndcoord_ID '(' ter_selection ')'
2066 add_opvars(splev, "o", VA_PASS1(SPO_SEL_RNDCOORD));
2070 check_vardef_type(variable_definitions, $1, SPOVAR_COORD);
2071 vardef_used(variable_definitions, $1);
2072 add_opvars(splev, "v", VA_PASS1($1));
2075 | VARSTRING_COORD_ARRAY '[' math_expr_var ']'
2077 check_vardef_type(variable_definitions, $1, SPOVAR_COORD|SPOVAR_ARRAY);
2078 vardef_used(variable_definitions, $1);
2079 add_opvars(splev, "v", VA_PASS1($1));
2084 encodecoord : '(' INTEGER ',' INTEGER ')'
2086 if ($2 < 0 || $4 < 0 || $2 >= COLNO || $4 >= ROWNO)
2087 lc_error("Coordinates (%li,%li) out of map range!", $2, $4);
2088 $$ = SP_COORD_PACK($2, $4);
2092 $$ = SP_COORD_PACK_RANDOM(0);
2094 | RANDOM_TYPE_BRACKET humidity_flags ']'
2096 $$ = SP_COORD_PACK_RANDOM( $2 );
2100 humidity_flags : HUMIDITY_TYPE
2104 | HUMIDITY_TYPE ',' humidity_flags
2107 lc_warning("Humidity flag used twice.");
2112 region_or_var : encoderegion
2118 check_vardef_type(variable_definitions, $1, SPOVAR_REGION);
2119 vardef_used(variable_definitions, $1);
2120 add_opvars(splev, "v", VA_PASS1($1));
2123 | VARSTRING_REGION_ARRAY '[' math_expr_var ']'
2125 check_vardef_type(variable_definitions, $1, SPOVAR_REGION|SPOVAR_ARRAY);
2126 vardef_used(variable_definitions, $1);
2127 add_opvars(splev, "v", VA_PASS1($1));
2132 encoderegion : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
2134 long r = SP_REGION_PACK($2, $4, $6, $8);
2135 if ( $2 > $6 || $4 > $8 )
2136 lc_error("Region start > end: (%li,%li,%li,%li)!", $2, $4, $6, $8);
2138 add_opvars(splev, "r", VA_PASS1(r));
2143 mapchar_or_var : mapchar
2145 add_opvars(splev, "m", VA_PASS1($1));
2149 check_vardef_type(variable_definitions, $1, SPOVAR_MAPCHAR);
2150 vardef_used(variable_definitions, $1);
2151 add_opvars(splev, "v", VA_PASS1($1));
2154 | VARSTRING_MAPCHAR_ARRAY '[' math_expr_var ']'
2156 check_vardef_type(variable_definitions, $1, SPOVAR_MAPCHAR|SPOVAR_ARRAY);
2157 vardef_used(variable_definitions, $1);
2158 add_opvars(splev, "v", VA_PASS1($1));
2165 if (what_map_char((char) $1) != INVALID_TYPE)
2166 $$ = SP_MAPCHAR_PACK(what_map_char((char) $1), -2);
2168 lc_error("Unknown map char type '%c'!", $1);
2169 $$ = SP_MAPCHAR_PACK(STONE, -2);
2172 | '(' CHAR ',' light_state ')'
2174 if (what_map_char((char) $2) != INVALID_TYPE)
2175 $$ = SP_MAPCHAR_PACK(what_map_char((char) $2), $4);
2177 lc_error("Unknown map char type '%c'!", $2);
2178 $$ = SP_MAPCHAR_PACK(STONE, $4);
2183 monster_or_var : encodemonster
2185 add_opvars(splev, "M", VA_PASS1($1));
2189 check_vardef_type(variable_definitions, $1, SPOVAR_MONST);
2190 vardef_used(variable_definitions, $1);
2191 add_opvars(splev, "v", VA_PASS1($1));
2194 | VARSTRING_MONST_ARRAY '[' math_expr_var ']'
2196 check_vardef_type(variable_definitions, $1, SPOVAR_MONST|SPOVAR_ARRAY);
2197 vardef_used(variable_definitions, $1);
2198 add_opvars(splev, "v", VA_PASS1($1));
2203 encodemonster : STRING
2205 long m = get_monster_id($1, (char)0);
2207 lc_error("Unknown monster \"%s\"!", $1);
2210 $$ = SP_MONST_PACK(m, def_monsyms[(int)mons[m].mlet].sym);
2215 if (check_monster_char((char) $1))
2216 $$ = SP_MONST_PACK(-1, $1);
2218 lc_error("Unknown monster class '%c'!", $1);
2222 | '(' CHAR ',' STRING ')'
2224 long m = get_monster_id($4, (char) $2);
2226 lc_error("Unknown monster ('%c', \"%s\")!", $2, $4);
2229 $$ = SP_MONST_PACK(m, $2);
2238 object_or_var : encodeobj
2240 add_opvars(splev, "O", VA_PASS1($1));
2244 check_vardef_type(variable_definitions, $1, SPOVAR_OBJ);
2245 vardef_used(variable_definitions, $1);
2246 add_opvars(splev, "v", VA_PASS1($1));
2249 | VARSTRING_OBJ_ARRAY '[' math_expr_var ']'
2251 check_vardef_type(variable_definitions, $1, SPOVAR_OBJ|SPOVAR_ARRAY);
2252 vardef_used(variable_definitions, $1);
2253 add_opvars(splev, "v", VA_PASS1($1));
2260 long m = get_object_id($1, (char)0);
2262 lc_error("Unknown object \"%s\"!", $1);
2265 $$ = SP_OBJ_PACK(m, 1); /* obj class != 0 to force generation of a specific item */
2270 if (check_object_char((char) $1))
2271 $$ = SP_OBJ_PACK(-1, $1);
2273 lc_error("Unknown object class '%c'!", $1);
2277 | '(' CHAR ',' STRING ')'
2279 long m = get_object_id($4, (char) $2);
2281 lc_error("Unknown object ('%c', \"%s\")!", $2, $4);
2284 $$ = SP_OBJ_PACK(m, $2);
2294 string_expr : string_or_var { }
2295 | string_expr '.' string_or_var
2297 add_opvars(splev, "o", VA_PASS1(SPO_MATH_ADD));
2301 math_expr_var : INTEGER
2303 add_opvars(splev, "i", VA_PASS1($1));
2307 is_inconstant_number = 1;
2309 | '(' MINUS_INTEGER ')'
2311 add_opvars(splev, "i", VA_PASS1($2));
2315 check_vardef_type(variable_definitions, $1, SPOVAR_INT);
2316 vardef_used(variable_definitions, $1);
2317 add_opvars(splev, "v", VA_PASS1($1));
2319 is_inconstant_number = 1;
2321 | VARSTRING_INT_ARRAY '[' math_expr_var ']'
2323 check_vardef_type(variable_definitions,
2324 $1, SPOVAR_INT|SPOVAR_ARRAY);
2325 vardef_used(variable_definitions, $1);
2326 add_opvars(splev, "v", VA_PASS1($1));
2328 is_inconstant_number = 1;
2330 | math_expr_var '+' math_expr_var
2332 add_opvars(splev, "o", VA_PASS1(SPO_MATH_ADD));
2334 | math_expr_var '-' math_expr_var
2336 add_opvars(splev, "o", VA_PASS1(SPO_MATH_SUB));
2338 | math_expr_var '*' math_expr_var
2340 add_opvars(splev, "o", VA_PASS1(SPO_MATH_MUL));
2342 | math_expr_var '/' math_expr_var
2344 add_opvars(splev, "o", VA_PASS1(SPO_MATH_DIV));
2346 | math_expr_var '%' math_expr_var
2348 add_opvars(splev, "o", VA_PASS1(SPO_MATH_MOD));
2350 | '(' math_expr_var ')' { }
2353 func_param_type : CFUNC_INT
2355 if (!strcmp("int", $1) || !strcmp("integer", $1)) {
2358 lc_error("Unknown function parameter type '%s'", $1);
2362 if (!strcmp("str", $1) || !strcmp("string", $1)) {
2365 lc_error("Unknown function parameter type '%s'", $1);
2369 func_param_part : any_var_or_arr ':' func_param_type
2371 struct lc_funcdefs_parm *tmp = New(struct lc_funcdefs_parm);
2373 if (!curr_function) {
2374 lc_error("Function parameters outside function definition.");
2376 lc_error("Could not alloc function params.");
2379 tmp->name = strdup($1);
2380 tmp->parmtype = (char) $3;
2381 tmp->next = curr_function->params;
2382 curr_function->params = tmp;
2383 curr_function->n_params++;
2384 switch (tmp->parmtype) {
2385 case 'i': vt = SPOVAR_INT; break;
2386 case 's': vt = SPOVAR_STRING; break;
2387 default: lc_error("Unknown func param conversion."); break;
2389 variable_definitions = add_vardef_type(
2390 variable_definitions,
2397 func_param_list : func_param_part
2398 | func_param_list ',' func_param_part
2401 func_params_list : /* nothing */
2405 func_call_param_part : math_expr_var
2416 func_call_param_list : func_call_param_part
2419 tmpbuf[0] = (char) $1;
2421 $$ = strdup(tmpbuf);
2423 | func_call_param_list ',' func_call_param_part
2425 long len = strlen( $1 );
2426 char *tmp = (char *)alloc(len + 2);
2427 sprintf(tmp, "%c%s", (char) $3, $1 );
2433 func_call_params_list : /* nothing */
2437 | func_call_param_list
2439 char *tmp = strdup( $1 );
2445 ter_selection_x : coord_or_var
2447 add_opvars(splev, "o", VA_PASS1(SPO_SEL_POINT));
2449 | rect_ID region_or_var
2451 add_opvars(splev, "o", VA_PASS1(SPO_SEL_RECT));
2453 | fillrect_ID region_or_var
2455 add_opvars(splev, "o", VA_PASS1(SPO_SEL_FILLRECT));
2457 | line_ID coord_or_var ',' coord_or_var
2459 add_opvars(splev, "o", VA_PASS1(SPO_SEL_LINE));
2461 | randline_ID coord_or_var ',' coord_or_var ',' math_expr_var
2463 /* randline (x1,y1),(x2,y2), roughness */
2464 add_opvars(splev, "o", VA_PASS1(SPO_SEL_RNDLINE));
2466 | grow_ID '(' ter_selection ')'
2468 add_opvars(splev, "io", VA_PASS2(W_ANY, SPO_SEL_GROW));
2470 | grow_ID '(' dir_list ',' ter_selection ')'
2472 add_opvars(splev, "io", VA_PASS2($3, SPO_SEL_GROW));
2474 | filter_ID '(' SPERCENT ',' ter_selection ')'
2476 add_opvars(splev, "iio",
2477 VA_PASS3($3, SPOFILTER_PERCENT, SPO_SEL_FILTER));
2479 | filter_ID '(' ter_selection ',' ter_selection ')'
2481 add_opvars(splev, "io",
2482 VA_PASS2(SPOFILTER_SELECTION, SPO_SEL_FILTER));
2484 | filter_ID '(' mapchar_or_var ',' ter_selection ')'
2486 add_opvars(splev, "io",
2487 VA_PASS2(SPOFILTER_MAPCHAR, SPO_SEL_FILTER));
2489 | flood_ID coord_or_var
2491 add_opvars(splev, "o", VA_PASS1(SPO_SEL_FLOOD));
2493 | circle_ID '(' coord_or_var ',' math_expr_var ')'
2495 add_opvars(splev, "oio",
2496 VA_PASS3(SPO_COPY, 1, SPO_SEL_ELLIPSE));
2498 | circle_ID '(' coord_or_var ',' math_expr_var ',' FILLING ')'
2500 add_opvars(splev, "oio",
2501 VA_PASS3(SPO_COPY, $7, SPO_SEL_ELLIPSE));
2503 | ellipse_ID '(' coord_or_var ',' math_expr_var ',' math_expr_var ')'
2505 add_opvars(splev, "io", VA_PASS2(1, SPO_SEL_ELLIPSE));
2507 | ellipse_ID '(' coord_or_var ',' math_expr_var ',' math_expr_var ',' FILLING ')'
2509 add_opvars(splev, "io", VA_PASS2($9, SPO_SEL_ELLIPSE));
2511 | gradient_ID '(' GRADIENT_TYPE ',' '(' math_expr_var '-' math_expr_var opt_limited ')' ',' coord_or_var opt_coord_or_var ')'
2513 add_opvars(splev, "iio",
2514 VA_PASS3($9, $3, SPO_SEL_GRADIENT));
2516 | complement_ID ter_selection_x
2518 add_opvars(splev, "o", VA_PASS1(SPO_SEL_COMPLEMENT));
2522 check_vardef_type(variable_definitions, $1, SPOVAR_SEL);
2523 vardef_used(variable_definitions, $1);
2524 add_opvars(splev, "v", VA_PASS1($1));
2527 | '(' ter_selection ')'
2533 ter_selection : ter_selection_x
2537 | ter_selection_x '&' ter_selection
2539 add_opvars(splev, "o", VA_PASS1(SPO_SEL_ADD));
2545 add_opvars(splev, "iio",
2546 VA_PASS3($1.num, $1.die, SPO_DICE));
2550 all_integers : MINUS_INTEGER
2555 all_ints_push : MINUS_INTEGER
2557 add_opvars(splev, "i", VA_PASS1($1));
2561 add_opvars(splev, "i", VA_PASS1($1));
2565 add_opvars(splev, "i", VA_PASS1($1));
2573 objectid : object_ID
2577 monsterid : monster_ID
2581 terrainid : terrain_ID
2585 engraving_type : ENGRAVING_TYPE
2593 | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
2595 if ($3 <= 0 || $3 >= COLNO)
2596 lc_error("Region (%li,%li,%li,%li) out of level range (x1)!", $3, $5, $7, $9);
2597 else if ($5 < 0 || $5 >= ROWNO)
2598 lc_error("Region (%li,%li,%li,%li) out of level range (y1)!", $3, $5, $7, $9);
2599 else if ($7 <= 0 || $7 >= COLNO)
2600 lc_error("Region (%li,%li,%li,%li) out of level range (x2)!", $3, $5, $7, $9);
2601 else if ($9 < 0 || $9 >= ROWNO)
2602 lc_error("Region (%li,%li,%li,%li) out of level range (y2)!", $3, $5, $7, $9);
2611 region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
2613 /* This series of if statements is a hack for MSC 5.1. It seems that its
2614 tiny little brain cannot compile if these are all one big if statement. */
2615 if ($2 < 0 || $2 > (int)max_x_map)
2616 lc_error("Region (%li,%li,%li,%li) out of map range (x1)!", $2, $4, $6, $8);
2617 else if ($4 < 0 || $4 > (int)max_y_map)
2618 lc_error("Region (%li,%li,%li,%li) out of map range (y1)!", $2, $4, $6, $8);
2619 else if ($6 < 0 || $6 > (int)max_x_map)
2620 lc_error("Region (%li,%li,%li,%li) out of map range (x2)!", $2, $4, $6, $8);
2621 else if ($8 < 0 || $8 > (int)max_y_map)
2622 lc_error("Region (%li,%li,%li,%li) out of map range (y2)!", $2, $4, $6, $8);