OSDN Git Service

add missing "#ifdef X11LARGETILE"
[jnethack/source.git] / util / lev_comp.y
1 %{
2 /* NetHack 3.6  lev_comp.y      $NHDT-Date: 1543371691 2018/11/28 02:21:31 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.22 $ */
3 /*      Copyright (c) 1989 by Jean-Christophe Collet */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 /*
7  * This file contains the Level Compiler code
8  * It may handle special mazes & special room-levels
9  */
10
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...).
15  *
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.
19  */
20 #ifdef _AIX
21  #pragma alloca         /* keep leading space! */
22 #endif
23
24 #define SPEC_LEV    /* for USE_OLDARGS (sp_lev.h) */
25 #include "hack.h"
26 #include "sp_lev.h"
27
28 #define ERR             (-1)
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.
32  */
33 #define MAX_OF_TYPE     128
34
35 #define MAX_NESTED_IFS   20
36 #define MAX_SWITCH_CASES 20
37
38 #define New(type) \
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)
42
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);
48 int NDECL(yyparse);
49
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 *));
67
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 *,
71                                                    char *, int));
72 extern char *FDECL(funcdef_paramtypes, (struct lc_funcdefs *));
73 extern char *FDECL(decode_parm_str, (char *));
74
75 extern struct lc_vardefs *FDECL(vardef_new, (long,char *));
76 extern void FDECL(vardef_free_all, (struct lc_vardefs *));
77 extern struct lc_vardefs *FDECL(vardef_defined, (struct lc_vardefs *,
78                                                  char *, int));
79
80 extern void NDECL(break_stmt_start);
81 extern void FDECL(break_stmt_end, (sp_lev *));
82 extern void FDECL(break_stmt_new, (sp_lev *, long));
83
84 extern void FDECL(splev_add_from, (sp_lev *, sp_lev *));
85
86 extern void FDECL(check_vardef_type, (struct lc_vardefs *, char *, long));
87 extern void FDECL(vardef_used, (struct lc_vardefs *, char *));
88 extern struct lc_vardefs *FDECL(add_vardef_type, (struct lc_vardefs *,
89                                                   char *, long));
90
91 extern int FDECL(reverse_jmp_opcode, (int));
92
93 struct coord {
94     long x;
95     long y;
96 };
97
98 struct forloopdef {
99     char *varname;
100     long jmp_point;
101 };
102 static struct forloopdef forloop_list[MAX_NESTED_IFS];
103 static short n_forloops = 0;
104
105
106 sp_lev *splev = NULL;
107
108 static struct opvar *if_list[MAX_NESTED_IFS];
109
110 static short n_if_list = 0;
111
112 unsigned int max_x_map, max_y_map;
113 int obj_containment = 0;
114
115 int in_container_obj = 0;
116
117 /* integer value is possibly an inconstant value (eg. dice notation
118    or a variable) */
119 int is_inconstant_number = 0;
120
121 int in_switch_statement = 0;
122 static struct opvar *switch_check_jump = NULL;
123 static struct opvar *switch_default_case = NULL;
124 static struct opvar *switch_case_list[MAX_SWITCH_CASES];
125 static long switch_case_value[MAX_SWITCH_CASES];
126 int n_switch_case_list = 0;
127
128 int allow_break_statements = 0;
129 struct lc_breakdef *break_list = NULL;
130
131 extern struct lc_vardefs *vardefs; /* variable definitions */
132
133
134 struct lc_vardefs *function_tmp_var_defs = NULL;
135 extern struct lc_funcdefs *function_definitions;
136 struct lc_funcdefs *curr_function = NULL;
137 struct lc_funcdefs_parm * curr_function_param = NULL;
138 int in_function_definition = 0;
139 sp_lev *function_splev_backup = NULL;
140
141 extern int fatal_error;
142 extern int got_errors;
143 extern int line_number;
144 extern const char *fname;
145
146 extern char curr_token[512];
147
148 %}
149
150 %union
151 {
152     long    i;
153     char    *map;
154     struct {
155         long room;
156         long wall;
157         long door;
158     } corpos;
159     struct {
160         long area;
161         long x1;
162         long y1;
163         long x2;
164         long y2;
165     } lregn;
166     struct {
167         long x;
168         long y;
169     } crd;
170     struct {
171         long ter;
172         long lit;
173     } terr;
174     struct {
175         long height;
176         long width;
177     } sze;
178     struct {
179         long die;
180         long num;
181     } dice;
182     struct {
183         long cfunc;
184         char *varstr;
185     } meth;
186 }
187
188
189 %token  <i> CHAR INTEGER BOOLEAN PERCENT SPERCENT
190 %token  <i> MINUS_INTEGER PLUS_INTEGER
191 %token  <i> MAZE_GRID_ID SOLID_FILL_ID MINES_ID ROGUELEV_ID
192 %token  <i> MESSAGE_ID MAZE_ID LEVEL_ID LEV_INIT_ID GEOMETRY_ID NOMAP_ID
193 %token  <i> OBJECT_ID COBJECT_ID MONSTER_ID TRAP_ID DOOR_ID DRAWBRIDGE_ID
194 %token  <i> object_ID monster_ID terrain_ID
195 %token  <i> MAZEWALK_ID WALLIFY_ID REGION_ID FILLING IRREGULAR JOINED
196 %token  <i> ALTAR_ID LADDER_ID STAIR_ID NON_DIGGABLE_ID NON_PASSWALL_ID ROOM_ID
197 %token  <i> PORTAL_ID TELEPRT_ID BRANCH_ID LEV MINERALIZE_ID
198 %token  <i> CORRIDOR_ID GOLD_ID ENGRAVING_ID FOUNTAIN_ID POOL_ID SINK_ID NONE
199 %token  <i> RAND_CORRIDOR_ID DOOR_STATE LIGHT_STATE CURSE_TYPE ENGRAVING_TYPE
200 %token  <i> DIRECTION RANDOM_TYPE RANDOM_TYPE_BRACKET A_REGISTER
201 %token  <i> ALIGNMENT LEFT_OR_RIGHT CENTER TOP_OR_BOT ALTAR_TYPE UP_OR_DOWN
202 %token  <i> SUBROOM_ID NAME_ID FLAGS_ID FLAG_TYPE MON_ATTITUDE MON_ALERTNESS
203 %token  <i> MON_APPEARANCE ROOMDOOR_ID IF_ID ELSE_ID
204 %token  <i> TERRAIN_ID HORIZ_OR_VERT REPLACE_TERRAIN_ID
205 %token  <i> EXIT_ID SHUFFLE_ID
206 %token  <i> QUANTITY_ID BURIED_ID LOOP_ID
207 %token  <i> FOR_ID TO_ID
208 %token  <i> SWITCH_ID CASE_ID BREAK_ID DEFAULT_ID
209 %token  <i> ERODED_ID TRAPPED_STATE RECHARGED_ID INVIS_ID GREASED_ID
210 %token  <i> FEMALE_ID CANCELLED_ID REVIVED_ID AVENGE_ID FLEEING_ID BLINDED_ID
211 %token  <i> PARALYZED_ID STUNNED_ID CONFUSED_ID SEENTRAPS_ID ALL_ID
212 %token  <i> MONTYPE_ID
213 %token  <i> GRAVE_ID ERODEPROOF_ID
214 %token  <i> FUNCTION_ID
215 %token  <i> MSG_OUTPUT_TYPE
216 %token  <i> COMPARE_TYPE
217 %token  <i> UNKNOWN_TYPE
218 %token  <i> rect_ID fillrect_ID line_ID randline_ID grow_ID
219 %token  <i> selection_ID flood_ID
220 %token  <i> rndcoord_ID circle_ID ellipse_ID filter_ID complement_ID
221 %token  <i> gradient_ID GRADIENT_TYPE LIMITED HUMIDITY_TYPE
222 %token  <i> ',' ':' '(' ')' '[' ']' '{' '}'
223 %token  <map> STRING MAP_ID
224 %token  <map> NQSTRING VARSTRING
225 %token  <map> CFUNC CFUNC_INT CFUNC_STR CFUNC_COORD CFUNC_REGION
226 %token  <map> VARSTRING_INT VARSTRING_INT_ARRAY
227 %token  <map> VARSTRING_STRING VARSTRING_STRING_ARRAY
228 %token  <map> VARSTRING_VAR VARSTRING_VAR_ARRAY
229 %token  <map> VARSTRING_COORD VARSTRING_COORD_ARRAY
230 %token  <map> VARSTRING_REGION VARSTRING_REGION_ARRAY
231 %token  <map> VARSTRING_MAPCHAR VARSTRING_MAPCHAR_ARRAY
232 %token  <map> VARSTRING_MONST VARSTRING_MONST_ARRAY
233 %token  <map> VARSTRING_OBJ VARSTRING_OBJ_ARRAY
234 %token  <map> VARSTRING_SEL VARSTRING_SEL_ARRAY
235 %token  <meth> METHOD_INT METHOD_INT_ARRAY
236 %token  <meth> METHOD_STRING METHOD_STRING_ARRAY
237 %token  <meth> METHOD_VAR METHOD_VAR_ARRAY
238 %token  <meth> METHOD_COORD METHOD_COORD_ARRAY
239 %token  <meth> METHOD_REGION METHOD_REGION_ARRAY
240 %token  <meth> METHOD_MAPCHAR METHOD_MAPCHAR_ARRAY
241 %token  <meth> METHOD_MONST METHOD_MONST_ARRAY
242 %token  <meth> METHOD_OBJ METHOD_OBJ_ARRAY
243 %token  <meth> METHOD_SEL METHOD_SEL_ARRAY
244 %token  <dice> DICE
245 %type   <i> h_justif v_justif trap_name room_type door_state light_state
246 %type   <i> alignment altar_type a_register roomfill door_pos
247 %type   <i> alignment_prfx
248 %type   <i> door_wall walled secret
249 %type   <i> dir_list teleprt_detail
250 %type   <i> object_infos object_info monster_infos monster_info
251 %type   <i> levstatements stmt_block region_detail_end
252 %type   <i> engraving_type flag_list roomregionflag roomregionflags
253 %type   <i> optroomregionflags
254 %type   <i> humidity_flags
255 %type   <i> comparestmt encodecoord encoderegion mapchar
256 %type   <i> seen_trap_mask
257 %type   <i> encodemonster encodeobj encodeobj_list
258 %type   <i> integer_list string_list encodecoord_list encoderegion_list
259 %type   <i> mapchar_list encodemonster_list
260 %type   <i> opt_percent opt_fillchar
261 %type   <i> all_integers
262 %type   <i> ter_selection ter_selection_x
263 %type   <i> func_param_type
264 %type   <i> objectid monsterid terrainid
265 %type   <i> opt_coord_or_var opt_limited
266 %type   <i> mazefiller
267 %type   <map> level_def
268 %type   <map> any_var any_var_array any_var_or_arr any_var_or_unk
269 %type   <map> func_call_params_list func_call_param_list
270 %type   <i> func_call_param_part
271 %type   <corpos> corr_spec
272 %type   <lregn> region lev_region
273 %type   <crd> room_pos subroom_pos room_align
274 %type   <sze> room_size
275 %type   <terr> terrain_type
276 %left  '+' '-'
277 %left  '*' '/' '%'
278 %start  file
279
280 %%
281 file            : /* nothing */
282                 | levels
283                 ;
284
285 levels          : level
286                 | level levels
287                 ;
288
289 level           : level_def flags levstatements
290                   {
291                         if (fatal_error > 0) {
292                                 (void) fprintf(stderr,
293               "%s: %d errors detected for level \"%s\". No output created!\n",
294                                                fname, fatal_error, $1);
295                                 fatal_error = 0;
296                                 got_errors++;
297                         } else if (!got_errors) {
298                                 if (!write_level_file($1, splev)) {
299                                     lc_error("Can't write output file for '%s'!",
300                                              $1);
301                                     exit(EXIT_FAILURE);
302                                 }
303                         }
304                         Free($1);
305                         Free(splev);
306                         splev = NULL;
307                         vardef_free_all(vardefs);
308                         vardefs = NULL;
309                   }
310                 ;
311
312 level_def       : LEVEL_ID ':' STRING
313                   {
314                       start_level_def(&splev, $3);
315                       $$ = $3;
316                   }
317                 | MAZE_ID ':' STRING ',' mazefiller
318                   {
319                       start_level_def(&splev, $3);
320                       if ($5 == -1) {
321                           add_opvars(splev, "iiiiiiiio",
322                                      VA_PASS9(LVLINIT_MAZEGRID, HWALL, 0,0,
323                                               0,0,0,0, SPO_INITLEVEL));
324                       } else {
325                           int bg = (int) what_map_char((char) $5);
326
327                           add_opvars(splev, "iiiiiiiio",
328                                      VA_PASS9(LVLINIT_SOLIDFILL, bg, 0,0,
329                                               0,0,0,0, SPO_INITLEVEL));
330                       }
331                       add_opvars(splev, "io",
332                                  VA_PASS2(MAZELEVEL, SPO_LEVEL_FLAGS));
333                       max_x_map = COLNO-1;
334                       max_y_map = ROWNO;
335                       $$ = $3;
336                   }
337                 ;
338
339 mazefiller      : RANDOM_TYPE
340                   {
341                       $$ = -1;
342                   }
343                 | CHAR
344                   {
345                       $$ = what_map_char((char) $1);
346                   }
347                 ;
348
349 lev_init        : LEV_INIT_ID ':' SOLID_FILL_ID ',' terrain_type
350                   {
351                       int filling = (int) $5.ter;
352
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_SOLIDFILL, filling,
357                                           0, (int) $5.lit,
358                                           0,0,0,0, SPO_INITLEVEL));
359                       max_x_map = COLNO-1;
360                       max_y_map = ROWNO;
361                   }
362                 | LEV_INIT_ID ':' MAZE_GRID_ID ',' CHAR
363                   {
364                       int filling = (int) what_map_char((char) $5);
365
366                       if (filling == INVALID_TYPE || filling >= MAX_TYPE)
367                           lc_error("INIT_MAP: Invalid fill char type.");
368                       add_opvars(splev, "iiiiiiiio",
369                                  VA_PASS9(LVLINIT_MAZEGRID, filling, 0,0,
370                                           0,0,0,0, SPO_INITLEVEL));
371                       max_x_map = COLNO-1;
372                       max_y_map = ROWNO;
373                   }
374                 | LEV_INIT_ID ':' ROGUELEV_ID
375                   {
376                       add_opvars(splev, "iiiiiiiio",
377                                  VA_PASS9(LVLINIT_ROGUE,0,0,0,
378                                           0,0,0,0, SPO_INITLEVEL));
379                   }
380                 | LEV_INIT_ID ':' MINES_ID ',' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled opt_fillchar
381                   {
382                       int fg = (int) what_map_char((char) $5),
383                           bg = (int) what_map_char((char) $7);
384                       int smoothed = (int) $9,
385                           joined = (int) $11,
386                           lit = (int) $13,
387                           walled = (int) $15,
388                           filling = (int) $16;
389
390                       if (fg == INVALID_TYPE || fg >= MAX_TYPE)
391                           lc_error("INIT_MAP: Invalid foreground type.");
392                       if (bg == INVALID_TYPE || bg >= MAX_TYPE)
393                           lc_error("INIT_MAP: Invalid background type.");
394                       if (joined && fg != CORR && fg != ROOM)
395                           lc_error("INIT_MAP: Invalid foreground type for joined map.");
396
397                       if (filling == INVALID_TYPE)
398                           lc_error("INIT_MAP: Invalid fill char type.");
399
400                       add_opvars(splev, "iiiiiiiio",
401                                  VA_PASS9(LVLINIT_MINES, filling, walled, lit,
402                                           joined, smoothed, bg, fg,
403                                           SPO_INITLEVEL));
404                         max_x_map = COLNO-1;
405                         max_y_map = ROWNO;
406                   }
407                 ;
408
409 opt_limited     : /* nothing */
410                   {
411                       $$ = 0;
412                   }
413                 | ',' LIMITED
414                   {
415                       $$ = $2;
416                   }
417                 ;
418
419 opt_coord_or_var        : /* nothing */
420                   {
421                       add_opvars(splev, "o", VA_PASS1(SPO_COPY));
422                       $$ = 0;
423                   }
424                 | ',' coord_or_var
425                   {
426                       $$ = 1;
427                   }
428                 ;
429
430 opt_fillchar    : /* nothing */
431                   {
432                       $$ = -1;
433                   }
434                 | ',' CHAR
435                   {
436                       $$ = what_map_char((char) $2);
437                   }
438                 ;
439
440
441 walled          : BOOLEAN
442                 | RANDOM_TYPE
443                 ;
444
445 flags           : /* nothing */
446                   {
447                       add_opvars(splev, "io", VA_PASS2(0, SPO_LEVEL_FLAGS));
448                   }
449                 | FLAGS_ID ':' flag_list
450                   {
451                       add_opvars(splev, "io",
452                                  VA_PASS2((int) $3, SPO_LEVEL_FLAGS));
453                   }
454                 ;
455
456 flag_list       : FLAG_TYPE ',' flag_list
457                   {
458                       $$ = ($1 | $3);
459                   }
460                 | FLAG_TYPE
461                   {
462                       $$ = $1;
463                   }
464                 ;
465
466 levstatements   : /* nothing */
467                   {
468                       $$ = 0;
469                   }
470                 | levstatement levstatements
471                   {
472                       $$ = 1 + $2;
473                   }
474                 ;
475
476 stmt_block      : '{' levstatements '}'
477                   {
478                       $$ = $2;
479                   }
480                 ;
481
482 levstatement    : message
483                 | lev_init
484                 | altar_detail
485                 | grave_detail
486                 | branch_region
487                 | corridor
488                 | variable_define
489                 | shuffle_detail
490                 | diggable_detail
491                 | door_detail
492                 | drawbridge_detail
493                 | engraving_detail
494                 | mineralize
495                 | fountain_detail
496                 | gold_detail
497                 | switchstatement
498                 | forstatement
499                 | loopstatement
500                 | ifstatement
501                 | chancestatement
502                 | exitstatement
503                 | breakstatement
504                 | function_define
505                 | function_call
506                 | ladder_detail
507                 | map_definition
508                 | mazewalk_detail
509                 | monster_detail
510                 | object_detail
511                 | passwall_detail
512                 | pool_detail
513                 | portal_region
514                 | random_corridors
515                 | region_detail
516                 | room_def
517                 | subroom_def
518                 | sink_detail
519                 | terrain_detail
520                 | replace_terrain_detail
521                 | stair_detail
522                 | stair_region
523                 | teleprt_region
524                 | trap_detail
525                 | wallify_detail
526                 ;
527
528 any_var_array   : VARSTRING_INT_ARRAY
529                 | VARSTRING_STRING_ARRAY
530                 | VARSTRING_VAR_ARRAY
531                 | VARSTRING_COORD_ARRAY
532                 | VARSTRING_REGION_ARRAY
533                 | VARSTRING_MAPCHAR_ARRAY
534                 | VARSTRING_MONST_ARRAY
535                 | VARSTRING_OBJ_ARRAY
536                 | VARSTRING_SEL_ARRAY
537                 ;
538
539 any_var         : VARSTRING_INT
540                 | VARSTRING_STRING
541                 | VARSTRING_VAR
542                 | VARSTRING_COORD
543                 | VARSTRING_REGION
544                 | VARSTRING_MAPCHAR
545                 | VARSTRING_MONST
546                 | VARSTRING_OBJ
547                 | VARSTRING_SEL
548                 ;
549
550 any_var_or_arr  : any_var_array
551                 | any_var
552                 | VARSTRING
553                 ;
554
555 any_var_or_unk  : VARSTRING
556                 | any_var
557                 ;
558
559 shuffle_detail  : SHUFFLE_ID ':' any_var_array
560                   {
561                       struct lc_vardefs *vd;
562
563                       if ((vd = vardef_defined(vardefs, $3, 1))) {
564                           if (!(vd->var_type & SPOVAR_ARRAY))
565                               lc_error("Trying to shuffle non-array variable '%s'",
566                                        $3);
567                       } else
568                           lc_error("Trying to shuffle undefined variable '%s'",
569                                    $3);
570                       add_opvars(splev, "so", VA_PASS2($3, SPO_SHUFFLE_ARRAY));
571                       Free($3);
572                   }
573                 ;
574
575 variable_define : any_var_or_arr '=' math_expr_var
576                   {
577                       vardefs = add_vardef_type(vardefs, $1, SPOVAR_INT);
578                       add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
579                       Free($1);
580                   }
581                 | any_var_or_arr '=' selection_ID ':' ter_selection
582                   {
583                       vardefs = add_vardef_type(vardefs, $1, SPOVAR_SEL);
584                       add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
585                       Free($1);
586                   }
587                 | any_var_or_arr '=' string_expr
588                   {
589                       vardefs = add_vardef_type(vardefs, $1, SPOVAR_STRING);
590                       add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
591                       Free($1);
592                   }
593                 | any_var_or_arr '=' terrainid ':' mapchar_or_var
594                   {
595                       vardefs = add_vardef_type(vardefs, $1, SPOVAR_MAPCHAR);
596                       add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
597                       Free($1);
598                   }
599                 | any_var_or_arr '=' monsterid ':' monster_or_var
600                   {
601                       vardefs = add_vardef_type(vardefs, $1, SPOVAR_MONST);
602                       add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
603                       Free($1);
604                   }
605                 | any_var_or_arr '=' objectid ':' object_or_var
606                   {
607                       vardefs = add_vardef_type(vardefs, $1, SPOVAR_OBJ);
608                       add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
609                       Free($1);
610                   }
611                 | any_var_or_arr '=' coord_or_var
612                   {
613                       vardefs = add_vardef_type(vardefs, $1, SPOVAR_COORD);
614                       add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
615                       Free($1);
616                   }
617                 | any_var_or_arr '=' region_or_var
618                   {
619                       vardefs = add_vardef_type(vardefs, $1, SPOVAR_REGION);
620                       add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT));
621                       Free($1);
622                   }
623                 | any_var_or_arr '=' '{' integer_list '}'
624                   {
625                       int n_items = (int) $4;
626
627                       vardefs = add_vardef_type(vardefs, $1,
628                                                 SPOVAR_INT | SPOVAR_ARRAY);
629                       add_opvars(splev, "iso",
630                                  VA_PASS3(n_items, $1, SPO_VAR_INIT));
631                       Free($1);
632                   }
633                 | any_var_or_arr '=' '{' encodecoord_list '}'
634                   {
635                       int n_items = (int) $4;
636
637                       vardefs = add_vardef_type(vardefs, $1,
638                                                 SPOVAR_COORD | SPOVAR_ARRAY);
639                       add_opvars(splev, "iso",
640                                  VA_PASS3(n_items, $1, SPO_VAR_INIT));
641                       Free($1);
642                   }
643                 | any_var_or_arr '=' '{' encoderegion_list '}'
644                   {
645                       int n_items = (int) $4;
646
647                       vardefs = add_vardef_type(vardefs, $1,
648                                                 SPOVAR_REGION | SPOVAR_ARRAY);
649                       add_opvars(splev, "iso",
650                                  VA_PASS3(n_items, $1, SPO_VAR_INIT));
651                       Free($1);
652                   }
653                 | any_var_or_arr '=' terrainid ':' '{' mapchar_list '}'
654                   {
655                       int n_items = (int) $6;
656
657                       vardefs = add_vardef_type(vardefs, $1,
658                                                 SPOVAR_MAPCHAR | SPOVAR_ARRAY);
659                       add_opvars(splev, "iso",
660                                  VA_PASS3(n_items, $1, SPO_VAR_INIT));
661                       Free($1);
662                   }
663                 | any_var_or_arr '=' monsterid ':' '{' encodemonster_list '}'
664                   {
665                       int n_items = (int) $6;
666
667                       vardefs = add_vardef_type(vardefs, $1,
668                                                 SPOVAR_MONST | SPOVAR_ARRAY);
669                       add_opvars(splev, "iso",
670                                  VA_PASS3(n_items, $1, SPO_VAR_INIT));
671                       Free($1);
672                   }
673                 | any_var_or_arr '=' objectid ':' '{' encodeobj_list '}'
674                   {
675                       int n_items = (int) $6;
676
677                       vardefs = add_vardef_type(vardefs, $1,
678                                                 SPOVAR_OBJ | SPOVAR_ARRAY);
679                       add_opvars(splev, "iso",
680                                  VA_PASS3(n_items, $1, SPO_VAR_INIT));
681                       Free($1);
682                   }
683                 | any_var_or_arr '=' '{' string_list '}'
684                   {
685                       int n_items = (int) $4;
686
687                       vardefs = add_vardef_type(vardefs, $1,
688                                                 SPOVAR_STRING | SPOVAR_ARRAY);
689                       add_opvars(splev, "iso",
690                                  VA_PASS3(n_items, $1, SPO_VAR_INIT));
691                       Free($1);
692                   }
693                 ;
694
695 encodeobj_list  : encodeobj
696                   {
697                       add_opvars(splev, "O", VA_PASS1($1));
698                       $$ = 1;
699                   }
700                 | encodeobj_list ',' encodeobj
701                   {
702                       add_opvars(splev, "O", VA_PASS1($3));
703                       $$ = 1 + $1;
704                   }
705                 ;
706
707 encodemonster_list      : encodemonster
708                   {
709                       add_opvars(splev, "M", VA_PASS1($1));
710                       $$ = 1;
711                   }
712                 | encodemonster_list ',' encodemonster
713                   {
714                       add_opvars(splev, "M", VA_PASS1($3));
715                       $$ = 1 + $1;
716                   }
717                 ;
718
719 mapchar_list    : mapchar
720                   {
721                       add_opvars(splev, "m", VA_PASS1($1));
722                       $$ = 1;
723                   }
724                 | mapchar_list ',' mapchar
725                   {
726                       add_opvars(splev, "m", VA_PASS1($3));
727                       $$ = 1 + $1;
728                   }
729                 ;
730
731 encoderegion_list       : encoderegion
732                   {
733                       $$ = 1;
734                   }
735                 | encoderegion_list ',' encoderegion
736                   {
737                       $$ = 1 + $1;
738                   }
739                 ;
740
741 encodecoord_list        : encodecoord
742                   {
743                       add_opvars(splev, "c", VA_PASS1($1));
744                       $$ = 1;
745                   }
746                 | encodecoord_list ',' encodecoord
747                   {
748                       add_opvars(splev, "c", VA_PASS1($3));
749                       $$ = 1 + $1;
750                   }
751                 ;
752
753 integer_list    : math_expr_var
754                   {
755                       $$ = 1;
756                   }
757                 | integer_list ',' math_expr_var
758                   {
759                       $$ = 1 + $1;
760                   }
761                 ;
762
763 string_list     : string_expr
764                   {
765                       $$ = 1;
766                   }
767                 | string_list ',' string_expr
768                   {
769                       $$ = 1 + $1;
770                   }
771                 ;
772
773 function_define : FUNCTION_ID NQSTRING '('
774                   {
775                       struct lc_funcdefs *funcdef;
776
777                       if (in_function_definition)
778                           lc_error("Recursively defined functions not allowed (function %s).", $2);
779
780                       in_function_definition++;
781
782                       if (funcdef_defined(function_definitions, $2, 1))
783                           lc_error("Function '%s' already defined once.", $2);
784
785                       funcdef = funcdef_new(-1, $2);
786                       funcdef->next = function_definitions;
787                       function_definitions = funcdef;
788                       function_splev_backup = splev;
789                       splev = &(funcdef->code);
790                       Free($2);
791                       curr_function = funcdef;
792                       function_tmp_var_defs = vardefs;
793                       vardefs = NULL;
794                   }
795                 func_params_list ')'
796                   {
797                       /* nothing */
798                   }
799                 stmt_block
800                   {
801                       add_opvars(splev, "io", VA_PASS2(0, SPO_RETURN));
802                       splev = function_splev_backup;
803                       in_function_definition--;
804                       curr_function = NULL;
805                       vardef_free_all(vardefs);
806                       vardefs = function_tmp_var_defs;
807                   }
808                 ;
809
810 function_call   : NQSTRING '(' func_call_params_list ')'
811                   {
812                       struct lc_funcdefs *tmpfunc;
813
814                       tmpfunc = funcdef_defined(function_definitions, $1, 1);
815                       if (tmpfunc) {
816                           int l;
817                           int nparams = (int) strlen($3);
818                           char *fparamstr = funcdef_paramtypes(tmpfunc);
819
820                           if (strcmp($3, fparamstr)) {
821                               char *tmps = strdup(decode_parm_str(fparamstr));
822
823                               lc_error("Function '%s' requires params '%s', got '%s' instead.",
824                                        $1, tmps, decode_parm_str($3));
825                               Free(tmps);
826                           }
827                           Free(fparamstr);
828                           Free($3);
829                           if (!(tmpfunc->n_called)) {
830                               /* we haven't called the function yet, so insert it in the code */
831                               struct opvar *jmp = New(struct opvar);
832
833                               set_opvar_int(jmp, splev->n_opcodes+1);
834                               add_opcode(splev, SPO_PUSH, jmp);
835                               /* we must jump past it first, then CALL it, due to RETURN. */
836                               add_opcode(splev, SPO_JMP, NULL);
837
838                               tmpfunc->addr = splev->n_opcodes;
839
840                               { /* init function parameter variables */
841                                   struct lc_funcdefs_parm *tfp = tmpfunc->params;
842                                   while (tfp) {
843                                       add_opvars(splev, "iso",
844                                                  VA_PASS3(0, tfp->name,
845                                                           SPO_VAR_INIT));
846                                       tfp = tfp->next;
847                                   }
848                               }
849
850                               splev_add_from(splev, &(tmpfunc->code));
851                               set_opvar_int(jmp,
852                                             splev->n_opcodes - jmp->vardata.l);
853                           }
854                           l = (int) (tmpfunc->addr - splev->n_opcodes - 2);
855                           add_opvars(splev, "iio",
856                                      VA_PASS3(nparams, l, SPO_CALL));
857                           tmpfunc->n_called++;
858                       } else {
859                           lc_error("Function '%s' not defined.", $1);
860                       }
861                       Free($1);
862                   }
863                 ;
864
865 exitstatement   : EXIT_ID
866                   {
867                       add_opcode(splev, SPO_EXIT, NULL);
868                   }
869                 ;
870
871 opt_percent     : /* nothing */
872                   {
873                       $$ = 100;
874                   }
875                 | PERCENT
876                   {
877                       $$ = $1;
878                   }
879                 ;
880
881 comparestmt     : PERCENT
882                   {
883                       /* val > rn2(100) */
884                       add_opvars(splev, "iio",
885                                  VA_PASS3((int) $1, 100, SPO_RN2));
886                       $$ = SPO_JG;
887                   }
888                 | '[' math_expr_var COMPARE_TYPE math_expr_var ']'
889                   {
890                       $$ = $3;
891                   }
892                 | '[' math_expr_var ']'
893                   {
894                       /* boolean, explicit foo != 0 */
895                       add_opvars(splev, "i", VA_PASS1(0));
896                       $$ = SPO_JNE;
897                   }
898                 ;
899
900 switchstatement : SWITCH_ID
901                   {
902                       is_inconstant_number = 0;
903                   }
904                   '[' integer_or_var ']'
905                   {
906                       struct opvar *chkjmp;
907
908                       if (in_switch_statement > 0)
909                           lc_error("Cannot nest switch-statements.");
910
911                       in_switch_statement++;
912
913                       n_switch_case_list = 0;
914                       switch_default_case = NULL;
915
916                       if (!is_inconstant_number)
917                           add_opvars(splev, "o", VA_PASS1(SPO_RN2));
918                       is_inconstant_number = 0;
919
920                       chkjmp = New(struct opvar);
921                       set_opvar_int(chkjmp, splev->n_opcodes+1);
922                       switch_check_jump = chkjmp;
923                       add_opcode(splev, SPO_PUSH, chkjmp);
924                       add_opcode(splev, SPO_JMP, NULL);
925                       break_stmt_start();
926                   }
927                 '{' switchcases '}'
928                   {
929                       struct opvar *endjump = New(struct opvar);
930                       int i;
931
932                       set_opvar_int(endjump, splev->n_opcodes+1);
933
934                       add_opcode(splev, SPO_PUSH, endjump);
935                       add_opcode(splev, SPO_JMP, NULL);
936
937                       set_opvar_int(switch_check_jump,
938                              splev->n_opcodes - switch_check_jump->vardata.l);
939
940                       for (i = 0; i < n_switch_case_list; i++) {
941                           add_opvars(splev, "oio",
942                                      VA_PASS3(SPO_COPY,
943                                               switch_case_value[i], SPO_CMP));
944                           set_opvar_int(switch_case_list[i],
945                          switch_case_list[i]->vardata.l - splev->n_opcodes-1);
946                           add_opcode(splev, SPO_PUSH, switch_case_list[i]);
947                           add_opcode(splev, SPO_JE, NULL);
948                       }
949
950                       if (switch_default_case) {
951                           set_opvar_int(switch_default_case,
952                          switch_default_case->vardata.l - splev->n_opcodes-1);
953                           add_opcode(splev, SPO_PUSH, switch_default_case);
954                           add_opcode(splev, SPO_JMP, NULL);
955                       }
956
957                       set_opvar_int(endjump, splev->n_opcodes - endjump->vardata.l);
958
959                       break_stmt_end(splev);
960
961                       add_opcode(splev, SPO_POP, NULL); /* get rid of the value in stack */
962                       in_switch_statement--;
963
964
965                   }
966                 ;
967
968 switchcases     : /* nothing */
969                 | switchcase switchcases
970                 ;
971
972 switchcase      : CASE_ID all_integers ':'
973                   {
974                       if (n_switch_case_list < MAX_SWITCH_CASES) {
975                           struct opvar *tmppush = New(struct opvar);
976
977                           set_opvar_int(tmppush, splev->n_opcodes);
978                           switch_case_value[n_switch_case_list] = $2;
979                           switch_case_list[n_switch_case_list++] = tmppush;
980                       } else lc_error("Too many cases in a switch.");
981                   }
982                 levstatements
983                   {
984                   }
985                 | DEFAULT_ID ':'
986                   {
987                       struct opvar *tmppush = New(struct opvar);
988
989                       if (switch_default_case)
990                           lc_error("Switch default case already used.");
991
992                       set_opvar_int(tmppush, splev->n_opcodes);
993                       switch_default_case = tmppush;
994                   }
995                 levstatements
996                   {
997                   }
998                 ;
999
1000 breakstatement  : BREAK_ID
1001                   {
1002                       if (!allow_break_statements)
1003                           lc_error("Cannot use BREAK outside a statement block.");
1004                       else {
1005                           break_stmt_new(splev, splev->n_opcodes);
1006                       }
1007                   }
1008                 ;
1009
1010 for_to_span     : '.' '.'
1011                 | TO_ID
1012                 ;
1013
1014 forstmt_start   : FOR_ID any_var_or_unk '=' math_expr_var for_to_span math_expr_var
1015                   {
1016                       char buf[256], buf2[256];
1017
1018                       if (n_forloops >= MAX_NESTED_IFS) {
1019                           lc_error("FOR: Too deeply nested loops.");
1020                           n_forloops = MAX_NESTED_IFS - 1;
1021                       }
1022
1023                       /* first, define a variable for the for-loop end value */
1024                       Sprintf(buf, "%s end", $2);
1025                       /* the value of which is already in stack (the 2nd math_expr) */
1026                       add_opvars(splev, "iso", VA_PASS3(0, buf, SPO_VAR_INIT));
1027
1028                       vardefs = add_vardef_type(vardefs, $2, SPOVAR_INT);
1029                       /* define the for-loop variable. value is in stack (1st math_expr) */
1030                       add_opvars(splev, "iso", VA_PASS3(0, $2, SPO_VAR_INIT));
1031
1032                       /* calculate value for the loop "step" variable */
1033                       Sprintf(buf2, "%s step", $2);
1034                       /* end - start */
1035                       add_opvars(splev, "vvo",
1036                                  VA_PASS3(buf, $2, SPO_MATH_SUB));
1037                       /* sign of that */
1038                       add_opvars(splev, "o", VA_PASS1(SPO_MATH_SIGN));
1039                       /* save the sign into the step var */
1040                       add_opvars(splev, "iso",
1041                                  VA_PASS3(0, buf2, SPO_VAR_INIT));
1042
1043                       forloop_list[n_forloops].varname = strdup($2);
1044                       forloop_list[n_forloops].jmp_point = splev->n_opcodes;
1045
1046                       n_forloops++;
1047                       Free($2);
1048                   }
1049                 ;
1050
1051 forstatement    : forstmt_start
1052                   {
1053                       /* nothing */
1054                       break_stmt_start();
1055                   }
1056                  stmt_block
1057                   {
1058                       int l;
1059                       char buf[256], buf2[256];
1060
1061                       n_forloops--;
1062                       Sprintf(buf, "%s step", forloop_list[n_forloops].varname);
1063                       Sprintf(buf2, "%s end", forloop_list[n_forloops].varname);
1064                       /* compare for-loop var to end value */
1065                       add_opvars(splev, "vvo",
1066                                  VA_PASS3(forloop_list[n_forloops].varname,
1067                                           buf2, SPO_CMP));
1068                       /* var + step */
1069                       add_opvars(splev, "vvo",
1070                                 VA_PASS3(buf, forloop_list[n_forloops].varname,
1071                                          SPO_MATH_ADD));
1072                       /* for-loop var = (for-loop var + step) */
1073                       add_opvars(splev, "iso",
1074                                  VA_PASS3(0, forloop_list[n_forloops].varname,
1075                                           SPO_VAR_INIT));
1076                       /* jump back if compared values were not equal */
1077                       l = (int) (forloop_list[n_forloops].jmp_point
1078                                  - splev->n_opcodes - 1);
1079                       add_opvars(splev, "io", VA_PASS2(l, SPO_JNE));
1080                       Free(forloop_list[n_forloops].varname);
1081                       break_stmt_end(splev);
1082                   }
1083                 ;
1084
1085 loopstatement   : LOOP_ID '[' integer_or_var ']'
1086                   {
1087                       struct opvar *tmppush = New(struct opvar);
1088
1089                       if (n_if_list >= MAX_NESTED_IFS) {
1090                           lc_error("LOOP: Too deeply nested conditionals.");
1091                           n_if_list = MAX_NESTED_IFS - 1;
1092                       }
1093                       set_opvar_int(tmppush, splev->n_opcodes);
1094                       if_list[n_if_list++] = tmppush;
1095
1096                       add_opvars(splev, "o", VA_PASS1(SPO_DEC));
1097                       break_stmt_start();
1098                   }
1099                  stmt_block
1100                   {
1101                       struct opvar *tmppush;
1102
1103                       add_opvars(splev, "oio", VA_PASS3(SPO_COPY, 0, SPO_CMP));
1104
1105                       tmppush = (struct opvar *) if_list[--n_if_list];
1106                       set_opvar_int(tmppush,
1107                                     tmppush->vardata.l - splev->n_opcodes-1);
1108                       add_opcode(splev, SPO_PUSH, tmppush);
1109                       add_opcode(splev, SPO_JG, NULL);
1110                       add_opcode(splev, SPO_POP, NULL); /* discard count */
1111                       break_stmt_end(splev);
1112                   }
1113                 ;
1114
1115 chancestatement : comparestmt ':'
1116                   {
1117                       struct opvar *tmppush2 = New(struct opvar);
1118
1119                       if (n_if_list >= MAX_NESTED_IFS) {
1120                           lc_error("IF: Too deeply nested conditionals.");
1121                           n_if_list = MAX_NESTED_IFS - 1;
1122                       }
1123
1124                       add_opcode(splev, SPO_CMP, NULL);
1125
1126                       set_opvar_int(tmppush2, splev->n_opcodes+1);
1127
1128                       if_list[n_if_list++] = tmppush2;
1129
1130                       add_opcode(splev, SPO_PUSH, tmppush2);
1131
1132                       add_opcode(splev, reverse_jmp_opcode( $1 ), NULL);
1133
1134                   }
1135                 levstatement
1136                   {
1137                       if (n_if_list > 0) {
1138                           struct opvar *tmppush;
1139
1140                           tmppush = (struct opvar *) if_list[--n_if_list];
1141                           set_opvar_int(tmppush,
1142                                         splev->n_opcodes - tmppush->vardata.l);
1143                       } else lc_error("IF: Huh?!  No start address?");
1144                   }
1145                 ;
1146
1147 ifstatement     : IF_ID comparestmt
1148                   {
1149                       struct opvar *tmppush2 = New(struct opvar);
1150
1151                       if (n_if_list >= MAX_NESTED_IFS) {
1152                           lc_error("IF: Too deeply nested conditionals.");
1153                           n_if_list = MAX_NESTED_IFS - 1;
1154                       }
1155
1156                       add_opcode(splev, SPO_CMP, NULL);
1157
1158                       set_opvar_int(tmppush2, splev->n_opcodes+1);
1159
1160                       if_list[n_if_list++] = tmppush2;
1161
1162                       add_opcode(splev, SPO_PUSH, tmppush2);
1163
1164                       add_opcode(splev, reverse_jmp_opcode( $2 ), NULL);
1165
1166                   }
1167                  if_ending
1168                   {
1169                      /* do nothing */
1170                   }
1171                 ;
1172
1173 if_ending       : stmt_block
1174                   {
1175                       if (n_if_list > 0) {
1176                           struct opvar *tmppush;
1177
1178                           tmppush = (struct opvar *) if_list[--n_if_list];
1179                           set_opvar_int(tmppush,
1180                                         splev->n_opcodes - tmppush->vardata.l);
1181                       } else lc_error("IF: Huh?!  No start address?");
1182                   }
1183                 | stmt_block
1184                   {
1185                       if (n_if_list > 0) {
1186                           struct opvar *tmppush = New(struct opvar);
1187                           struct opvar *tmppush2;
1188
1189                           set_opvar_int(tmppush, splev->n_opcodes+1);
1190                           add_opcode(splev, SPO_PUSH, tmppush);
1191
1192                           add_opcode(splev, SPO_JMP, NULL);
1193
1194                           tmppush2 = (struct opvar *) if_list[--n_if_list];
1195
1196                           set_opvar_int(tmppush2,
1197                                       splev->n_opcodes - tmppush2->vardata.l);
1198                           if_list[n_if_list++] = tmppush;
1199                       } else lc_error("IF: Huh?!  No else-part address?");
1200                   }
1201                  ELSE_ID stmt_block
1202                   {
1203                       if (n_if_list > 0) {
1204                           struct opvar *tmppush;
1205                           tmppush = (struct opvar *) if_list[--n_if_list];
1206                           set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l);
1207                       } else lc_error("IF: Huh?! No end address?");
1208                   }
1209                 ;
1210
1211 message         : MESSAGE_ID ':' string_expr
1212                   {
1213                       add_opvars(splev, "o", VA_PASS1(SPO_MESSAGE));
1214                   }
1215                 ;
1216
1217 random_corridors: RAND_CORRIDOR_ID
1218                   {
1219                       add_opvars(splev, "iiiiiio",
1220                               VA_PASS7(-1,  0, -1, -1, -1, -1, SPO_CORRIDOR));
1221                   }
1222                 | RAND_CORRIDOR_ID ':' all_integers
1223                   {
1224                       add_opvars(splev, "iiiiiio",
1225                               VA_PASS7(-1, $3, -1, -1, -1, -1, SPO_CORRIDOR));
1226                   }
1227                 | RAND_CORRIDOR_ID ':' RANDOM_TYPE
1228                   {
1229                       add_opvars(splev, "iiiiiio",
1230                               VA_PASS7(-1, -1, -1, -1, -1, -1, SPO_CORRIDOR));
1231                   }
1232                 ;
1233
1234 corridor        : CORRIDOR_ID ':' corr_spec ',' corr_spec
1235                   {
1236                       add_opvars(splev, "iiiiiio",
1237                                  VA_PASS7($3.room, $3.door, $3.wall,
1238                                           $5.room, $5.door, $5.wall,
1239                                           SPO_CORRIDOR));
1240                   }
1241                 | CORRIDOR_ID ':' corr_spec ',' all_integers
1242                   {
1243                       add_opvars(splev, "iiiiiio",
1244                                  VA_PASS7($3.room, $3.door, $3.wall,
1245                                           -1, -1, (long)$5,
1246                                           SPO_CORRIDOR));
1247                   }
1248                 ;
1249
1250 corr_spec       : '(' INTEGER ',' DIRECTION ',' door_pos ')'
1251                   {
1252                         $$.room = $2;
1253                         $$.wall = $4;
1254                         $$.door = $6;
1255                   }
1256                 ;
1257
1258 room_begin      : room_type opt_percent ',' light_state
1259                   {
1260                       if (($2 < 100) && ($1 == OROOM))
1261                           lc_error("Only typed rooms can have a chance.");
1262                       else {
1263                           add_opvars(splev, "iii",
1264                                      VA_PASS3((long)$1, (long)$2, (long)$4));
1265                       }
1266                   }
1267                 ;
1268
1269 subroom_def     : SUBROOM_ID ':' room_begin ',' subroom_pos ',' room_size optroomregionflags
1270                   {
1271                       long rflags = $8;
1272
1273                       if (rflags == -1) rflags = (1 << 0);
1274                       add_opvars(splev, "iiiiiiio",
1275                                  VA_PASS8(rflags, ERR, ERR,
1276                                           $5.x, $5.y, $7.width, $7.height,
1277                                           SPO_SUBROOM));
1278                       break_stmt_start();
1279                   }
1280                   stmt_block
1281                   {
1282                       break_stmt_end(splev);
1283                       add_opcode(splev, SPO_ENDROOM, NULL);
1284                   }
1285                 ;
1286
1287 room_def        : ROOM_ID ':' room_begin ',' room_pos ',' room_align ',' room_size optroomregionflags
1288                   {
1289                       long rflags = $8;
1290
1291                       if (rflags == -1) rflags = (1 << 0);
1292                       add_opvars(splev, "iiiiiiio",
1293                                  VA_PASS8(rflags,
1294                                           $7.x, $7.y, $5.x, $5.y,
1295                                           $9.width, $9.height, SPO_ROOM));
1296                       break_stmt_start();
1297                   }
1298                   stmt_block
1299                   {
1300                       break_stmt_end(splev);
1301                       add_opcode(splev, SPO_ENDROOM, NULL);
1302                   }
1303                 ;
1304
1305 roomfill        : /* nothing */
1306                   {
1307                         $$ = 1;
1308                   }
1309                 | ',' BOOLEAN
1310                   {
1311                         $$ = $2;
1312                   }
1313                 ;
1314
1315 room_pos        : '(' INTEGER ',' INTEGER ')'
1316                   {
1317                         if ( $2 < 1 || $2 > 5 ||
1318                             $4 < 1 || $4 > 5 ) {
1319                             lc_error("Room positions should be between 1-5: (%li,%li)!", $2, $4);
1320                         } else {
1321                             $$.x = $2;
1322                             $$.y = $4;
1323                         }
1324                   }
1325                 | RANDOM_TYPE
1326                   {
1327                         $$.x = $$.y = ERR;
1328                   }
1329                 ;
1330
1331 subroom_pos     : '(' INTEGER ',' INTEGER ')'
1332                   {
1333                         if ( $2 < 0 || $4 < 0) {
1334                             lc_error("Invalid subroom position (%li,%li)!", $2, $4);
1335                         } else {
1336                             $$.x = $2;
1337                             $$.y = $4;
1338                         }
1339                   }
1340                 | RANDOM_TYPE
1341                   {
1342                         $$.x = $$.y = ERR;
1343                   }
1344                 ;
1345
1346 room_align      : '(' h_justif ',' v_justif ')'
1347                   {
1348                       $$.x = $2;
1349                       $$.y = $4;
1350                   }
1351                 | RANDOM_TYPE
1352                   {
1353                       $$.x = $$.y = ERR;
1354                   }
1355                 ;
1356
1357 room_size       : '(' INTEGER ',' INTEGER ')'
1358                   {
1359                         $$.width = $2;
1360                         $$.height = $4;
1361                   }
1362                 | RANDOM_TYPE
1363                   {
1364                         $$.height = $$.width = ERR;
1365                   }
1366                 ;
1367
1368 door_detail     : ROOMDOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos
1369                   {
1370                         /* ERR means random here */
1371                         if ($7 == ERR && $9 != ERR) {
1372                             lc_error("If the door wall is random, so must be its pos!");
1373                         } else {
1374                             add_opvars(splev, "iiiio",
1375                                        VA_PASS5((long)$9, (long)$5, (long)$3,
1376                                                 (long)$7, SPO_ROOM_DOOR));
1377                         }
1378                   }
1379                 | DOOR_ID ':' door_state ',' ter_selection
1380                   {
1381                       add_opvars(splev, "io", VA_PASS2((long)$3, SPO_DOOR));
1382                   }
1383                 ;
1384
1385 secret          : BOOLEAN
1386                 | RANDOM_TYPE
1387                 ;
1388
1389 door_wall       : dir_list
1390                 | RANDOM_TYPE
1391                 ;
1392
1393 dir_list        : DIRECTION
1394                   {
1395                       $$ = $1;
1396                   }
1397                 | DIRECTION '|' dir_list
1398                   {
1399                       $$ = ($1 | $3);
1400                   }
1401                 ;
1402
1403 door_pos        : INTEGER
1404                 | RANDOM_TYPE
1405                 ;
1406
1407 map_definition  : NOMAP_ID
1408                   {
1409                       add_opvars(splev, "ciisiio",
1410                                  VA_PASS7(0, 0, 1, (char *) 0, 0, 0, SPO_MAP));
1411                       max_x_map = COLNO-1;
1412                       max_y_map = ROWNO;
1413                   }
1414                 | GEOMETRY_ID ':' h_justif ',' v_justif roomfill MAP_ID
1415                   {
1416                       add_opvars(splev, "cii",
1417                                  VA_PASS3(SP_COORD_PACK(($3), ($5)),
1418                                           1, (int) $6));
1419                       scan_map($7, splev);
1420                       Free($7);
1421                   }
1422                 | GEOMETRY_ID ':' coord_or_var roomfill MAP_ID
1423                   {
1424                       add_opvars(splev, "ii", VA_PASS2(2, (int) $4));
1425                       scan_map($5, splev);
1426                       Free($5);
1427                   }
1428                 ;
1429
1430 h_justif        : LEFT_OR_RIGHT
1431                 | CENTER
1432                 ;
1433
1434 v_justif        : TOP_OR_BOT
1435                 | CENTER
1436                 ;
1437
1438 monster_detail  : MONSTER_ID ':' monster_desc
1439                   {
1440                       add_opvars(splev, "io", VA_PASS2(0, SPO_MONSTER));
1441                   }
1442                 | MONSTER_ID ':' monster_desc
1443                   {
1444                       add_opvars(splev, "io", VA_PASS2(1, SPO_MONSTER));
1445                       in_container_obj++;
1446                       break_stmt_start();
1447                   }
1448                 stmt_block
1449                  {
1450                      break_stmt_end(splev);
1451                      in_container_obj--;
1452                      add_opvars(splev, "o", VA_PASS1(SPO_END_MONINVENT));
1453                  }
1454                 ;
1455
1456 monster_desc    : monster_or_var ',' coord_or_var monster_infos
1457                   {
1458                       /* nothing */
1459                   }
1460                 ;
1461
1462 monster_infos   : /* nothing */
1463                   {
1464                       struct opvar *stopit = New(struct opvar);
1465
1466                       set_opvar_int(stopit, SP_M_V_END);
1467                       add_opcode(splev, SPO_PUSH, stopit);
1468                       $$ = 0x0000;
1469                   }
1470                 | monster_infos ',' monster_info
1471                   {
1472                       if (( $1 & $3 ))
1473                           lc_error("MONSTER extra info defined twice.");
1474                       $$ = ( $1 | $3 );
1475                   }
1476                 ;
1477
1478 monster_info    : string_expr
1479                   {
1480                       add_opvars(splev, "i", VA_PASS1(SP_M_V_NAME));
1481                       $$ = 0x0001;
1482                   }
1483                 | MON_ATTITUDE
1484                   {
1485                       add_opvars(splev, "ii",
1486                                  VA_PASS2((int) $<i>1, SP_M_V_PEACEFUL));
1487                       $$ = 0x0002;
1488                   }
1489                 | MON_ALERTNESS
1490                   {
1491                       add_opvars(splev, "ii",
1492                                  VA_PASS2((int) $<i>1, SP_M_V_ASLEEP));
1493                       $$ = 0x0004;
1494                   }
1495                 | alignment_prfx
1496                   {
1497                       add_opvars(splev, "ii",
1498                                  VA_PASS2((int) $1, SP_M_V_ALIGN));
1499                       $$ = 0x0008;
1500                   }
1501                 | MON_APPEARANCE string_expr
1502                   {
1503                       add_opvars(splev, "ii",
1504                                  VA_PASS2((int) $<i>1, SP_M_V_APPEAR));
1505                       $$ = 0x0010;
1506                   }
1507                 | FEMALE_ID
1508                   {
1509                       add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_FEMALE));
1510                       $$ = 0x0020;
1511                   }
1512                 | INVIS_ID
1513                   {
1514                       add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_INVIS));
1515                       $$ = 0x0040;
1516                   }
1517                 | CANCELLED_ID
1518                   {
1519                       add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_CANCELLED));
1520                       $$ = 0x0080;
1521                   }
1522                 | REVIVED_ID
1523                   {
1524                       add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_REVIVED));
1525                       $$ = 0x0100;
1526                   }
1527                 | AVENGE_ID
1528                   {
1529                       add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_AVENGE));
1530                       $$ = 0x0200;
1531                   }
1532                 | FLEEING_ID ':' integer_or_var
1533                   {
1534                       add_opvars(splev, "i", VA_PASS1(SP_M_V_FLEEING));
1535                       $$ = 0x0400;
1536                   }
1537                 | BLINDED_ID ':' integer_or_var
1538                   {
1539                       add_opvars(splev, "i", VA_PASS1(SP_M_V_BLINDED));
1540                       $$ = 0x0800;
1541                   }
1542                 | PARALYZED_ID ':' integer_or_var
1543                   {
1544                       add_opvars(splev, "i", VA_PASS1(SP_M_V_PARALYZED));
1545                       $$ = 0x1000;
1546                   }
1547                 | STUNNED_ID
1548                   {
1549                       add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_STUNNED));
1550                       $$ = 0x2000;
1551                   }
1552                 | CONFUSED_ID
1553                   {
1554                       add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_CONFUSED));
1555                       $$ = 0x4000;
1556                   }
1557                 | SEENTRAPS_ID ':' seen_trap_mask
1558                   {
1559                       add_opvars(splev, "ii",
1560                                  VA_PASS2((int) $3, SP_M_V_SEENTRAPS));
1561                       $$ = 0x8000;
1562                   }
1563                 ;
1564
1565 seen_trap_mask  : STRING
1566                   {
1567                       int token = get_trap_type($1);
1568
1569                       if (token == ERR || token == 0)
1570                           lc_error("Unknown trap type '%s'!", $1);
1571                       Free($1);
1572                       $$ = (1L << (token - 1));
1573                   }
1574                 | ALL_ID
1575                   {
1576                       $$ = (long) ~0;
1577                   }
1578                 | STRING '|' seen_trap_mask
1579                   {
1580                       int token = get_trap_type($1);
1581                       if (token == ERR || token == 0)
1582                           lc_error("Unknown trap type '%s'!", $1);
1583
1584                       if ((1L << (token - 1)) & $3)
1585                           lc_error("Monster seen_traps, trap '%s' listed twice.", $1);
1586                       Free($1);
1587                       $$ = ((1L << (token - 1)) | $3);
1588                   }
1589                 ;
1590
1591 object_detail   : OBJECT_ID ':' object_desc
1592                   {
1593                       int cnt = 0;
1594
1595                       if (in_container_obj)
1596                           cnt |= SP_OBJ_CONTENT;
1597                       add_opvars(splev, "io", VA_PASS2(cnt, SPO_OBJECT));
1598                   }
1599                 | COBJECT_ID ':' object_desc
1600                   {
1601                       int cnt = SP_OBJ_CONTAINER;
1602
1603                       if (in_container_obj)
1604                           cnt |= SP_OBJ_CONTENT;
1605                       add_opvars(splev, "io", VA_PASS2(cnt, SPO_OBJECT));
1606                       in_container_obj++;
1607                       break_stmt_start();
1608                   }
1609                 stmt_block
1610                  {
1611                      break_stmt_end(splev);
1612                      in_container_obj--;
1613                      add_opcode(splev, SPO_POP_CONTAINER, NULL);
1614                  }
1615                 ;
1616
1617 object_desc     : object_or_var object_infos
1618                   {
1619                       if (( $2 & 0x4000) && in_container_obj)
1620                           lc_error("Object cannot have a coord when contained.");
1621                       else if (!( $2 & 0x4000) && !in_container_obj)
1622                           lc_error("Object needs a coord when not contained.");
1623                   }
1624                 ;
1625
1626 object_infos    : /* nothing */
1627                   {
1628                       struct opvar *stopit = New(struct opvar);
1629                       set_opvar_int(stopit, SP_O_V_END);
1630                       add_opcode(splev, SPO_PUSH, stopit);
1631                       $$ = 0x00;
1632                   }
1633                 | object_infos ',' object_info
1634                   {
1635                       if (( $1 & $3 ))
1636                           lc_error("OBJECT extra info '%s' defined twice.", curr_token);
1637                       $$ = ( $1 | $3 );
1638                   }
1639                 ;
1640
1641 object_info     : CURSE_TYPE
1642                   {
1643                       add_opvars(splev, "ii",
1644                                  VA_PASS2((int) $1, SP_O_V_CURSE));
1645                       $$ = 0x0001;
1646                   }
1647                 | MONTYPE_ID ':' monster_or_var
1648                   {
1649                       add_opvars(splev, "i", VA_PASS1(SP_O_V_CORPSENM));
1650                       $$ = 0x0002;
1651                   }
1652                 | all_ints_push
1653                   {
1654                       add_opvars(splev, "i", VA_PASS1(SP_O_V_SPE));
1655                       $$ = 0x0004;
1656                   }
1657                 | NAME_ID ':' string_expr
1658                   {
1659                       add_opvars(splev, "i", VA_PASS1(SP_O_V_NAME));
1660                       $$ = 0x0008;
1661                   }
1662                 | QUANTITY_ID ':' integer_or_var
1663                   {
1664                       add_opvars(splev, "i", VA_PASS1(SP_O_V_QUAN));
1665                       $$ = 0x0010;
1666                   }
1667                 | BURIED_ID
1668                   {
1669                       add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_BURIED));
1670                       $$ = 0x0020;
1671                   }
1672                 | LIGHT_STATE
1673                   {
1674                       add_opvars(splev, "ii", VA_PASS2((int) $1, SP_O_V_LIT));
1675                       $$ = 0x0040;
1676                   }
1677                 | ERODED_ID ':' integer_or_var
1678                   {
1679                       add_opvars(splev, "i", VA_PASS1(SP_O_V_ERODED));
1680                       $$ = 0x0080;
1681                   }
1682                 | ERODEPROOF_ID
1683                   {
1684                       add_opvars(splev, "ii", VA_PASS2(-1, SP_O_V_ERODED));
1685                       $$ = 0x0080;
1686                   }
1687                 | DOOR_STATE
1688                   {
1689                       if ($1 == D_LOCKED) {
1690                           add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_LOCKED));
1691                           $$ = 0x0100;
1692                       } else if ($1 == D_BROKEN) {
1693                           add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_BROKEN));
1694                           $$ = 0x0200;
1695                       } else
1696                           lc_error("DOOR state can only be locked or broken.");
1697                   }
1698                 | TRAPPED_STATE
1699                   {
1700                       add_opvars(splev, "ii",
1701                                  VA_PASS2((int) $1, SP_O_V_TRAPPED));
1702                       $$ = 0x0400;
1703                   }
1704                 | RECHARGED_ID ':' integer_or_var
1705                   {
1706                       add_opvars(splev, "i", VA_PASS1(SP_O_V_RECHARGED));
1707                       $$ = 0x0800;
1708                   }
1709                 | INVIS_ID
1710                   {
1711                       add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_INVIS));
1712                       $$ = 0x1000;
1713                   }
1714                 | GREASED_ID
1715                   {
1716                       add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_GREASED));
1717                       $$ = 0x2000;
1718                   }
1719                 | coord_or_var
1720                   {
1721                       add_opvars(splev, "i", VA_PASS1(SP_O_V_COORD));
1722                       $$ = 0x4000;
1723                   }
1724                 ;
1725
1726 trap_detail     : TRAP_ID ':' trap_name ',' coord_or_var
1727                   {
1728                       add_opvars(splev, "io", VA_PASS2((int) $3, SPO_TRAP));
1729                   }
1730                 ;
1731
1732 drawbridge_detail: DRAWBRIDGE_ID ':' coord_or_var ',' DIRECTION ',' door_state
1733                    {
1734                        long dir, state = 0;
1735
1736                        /* convert dir from a DIRECTION to a DB_DIR */
1737                        dir = $5;
1738                        switch (dir) {
1739                        case W_NORTH: dir = DB_NORTH; break;
1740                        case W_SOUTH: dir = DB_SOUTH; break;
1741                        case W_EAST:  dir = DB_EAST;  break;
1742                        case W_WEST:  dir = DB_WEST;  break;
1743                        default:
1744                            lc_error("Invalid drawbridge direction.");
1745                            break;
1746                        }
1747
1748                        if ( $7 == D_ISOPEN )
1749                            state = 1;
1750                        else if ( $7 == D_CLOSED )
1751                            state = 0;
1752                        else if ( $7 == -1 )
1753                            state = -1;
1754                        else
1755                            lc_error("A drawbridge can only be open, closed or random!");
1756                        add_opvars(splev, "iio",
1757                                   VA_PASS3(state, dir, SPO_DRAWBRIDGE));
1758                    }
1759                 ;
1760
1761 mazewalk_detail : MAZEWALK_ID ':' coord_or_var ',' DIRECTION
1762                   {
1763                       add_opvars(splev, "iiio",
1764                                  VA_PASS4((int) $5, 1, 0, SPO_MAZEWALK));
1765                   }
1766                 | MAZEWALK_ID ':' coord_or_var ',' DIRECTION ',' BOOLEAN opt_fillchar
1767                   {
1768                       add_opvars(splev, "iiio",
1769                                  VA_PASS4((int) $5, (int) $<i>7,
1770                                           (int) $8, SPO_MAZEWALK));
1771                   }
1772                 ;
1773
1774 wallify_detail  : WALLIFY_ID
1775                   {
1776                       add_opvars(splev, "rio",
1777                                  VA_PASS3(SP_REGION_PACK(-1,-1,-1,-1),
1778                                           0, SPO_WALLIFY));
1779                   }
1780                 | WALLIFY_ID ':' ter_selection
1781                   {
1782                       add_opvars(splev, "io", VA_PASS2(1, SPO_WALLIFY));
1783                   }
1784                 ;
1785
1786 ladder_detail   : LADDER_ID ':' coord_or_var ',' UP_OR_DOWN
1787                   {
1788                       add_opvars(splev, "io",
1789                                  VA_PASS2((int) $<i>5, SPO_LADDER));
1790                   }
1791                 ;
1792
1793 stair_detail    : STAIR_ID ':' coord_or_var ',' UP_OR_DOWN
1794                   {
1795                       add_opvars(splev, "io",
1796                                  VA_PASS2((int) $<i>5, SPO_STAIR));
1797                   }
1798                 ;
1799
1800 stair_region    : STAIR_ID ':' lev_region ',' lev_region ',' UP_OR_DOWN
1801                   {
1802                       add_opvars(splev, "iiiii iiiii iiso",
1803                                  VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area,
1804                                            $5.x1, $5.y1, $5.x2, $5.y2, $5.area,
1805                                      (long) (($7) ? LR_UPSTAIR : LR_DOWNSTAIR),
1806                                            0, (char *) 0, SPO_LEVREGION));
1807                   }
1808                 ;
1809
1810 portal_region   : PORTAL_ID ':' lev_region ',' lev_region ',' STRING
1811                   {
1812                       add_opvars(splev, "iiiii iiiii iiso",
1813                                  VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area,
1814                                            $5.x1, $5.y1, $5.x2, $5.y2, $5.area,
1815                                            LR_PORTAL, 0, $7, SPO_LEVREGION));
1816                       Free($7);
1817                   }
1818                 ;
1819
1820 teleprt_region  : TELEPRT_ID ':' lev_region ',' lev_region teleprt_detail
1821                   {
1822                       long rtyp = 0;
1823                       switch($6) {
1824                       case -1: rtyp = LR_TELE; break;
1825                       case  0: rtyp = LR_DOWNTELE; break;
1826                       case  1: rtyp = LR_UPTELE; break;
1827                       }
1828                       add_opvars(splev, "iiiii iiiii iiso",
1829                                  VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area,
1830                                            $5.x1, $5.y1, $5.x2, $5.y2, $5.area,
1831                                            rtyp, 0, (char *)0, SPO_LEVREGION));
1832                   }
1833                 ;
1834
1835 branch_region   : BRANCH_ID ':' lev_region ',' lev_region
1836                   {
1837                       add_opvars(splev, "iiiii iiiii iiso",
1838                                  VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area,
1839                                            $5.x1, $5.y1, $5.x2, $5.y2, $5.area,
1840                                            (long) LR_BRANCH, 0,
1841                                            (char *) 0, SPO_LEVREGION));
1842                   }
1843                 ;
1844
1845 teleprt_detail  : /* empty */
1846                   {
1847                         $$ = -1;
1848                   }
1849                 | ',' UP_OR_DOWN
1850                   {
1851                         $$ = $2;
1852                   }
1853                 ;
1854
1855 fountain_detail : FOUNTAIN_ID ':' ter_selection
1856                   {
1857                       add_opvars(splev, "o", VA_PASS1(SPO_FOUNTAIN));
1858                   }
1859                 ;
1860
1861 sink_detail : SINK_ID ':' ter_selection
1862                   {
1863                       add_opvars(splev, "o", VA_PASS1(SPO_SINK));
1864                   }
1865                 ;
1866
1867 pool_detail : POOL_ID ':' ter_selection
1868                   {
1869                       add_opvars(splev, "o", VA_PASS1(SPO_POOL));
1870                   }
1871                 ;
1872
1873 terrain_type    : CHAR
1874                   {
1875                       $$.lit = -2;
1876                       $$.ter = what_map_char((char) $<i>1);
1877                   }
1878                 | '(' CHAR ',' light_state ')'
1879                   {
1880                       $$.lit = $4;
1881                       $$.ter = what_map_char((char) $<i>2);
1882                   }
1883                 ;
1884
1885 replace_terrain_detail : REPLACE_TERRAIN_ID ':' region_or_var ',' mapchar_or_var ',' mapchar_or_var ',' SPERCENT
1886                   {
1887                       add_opvars(splev, "io",
1888                                  VA_PASS2($9, SPO_REPLACETERRAIN));
1889                   }
1890                 ;
1891
1892 terrain_detail : TERRAIN_ID ':' ter_selection ',' mapchar_or_var
1893                  {
1894                      add_opvars(splev, "o", VA_PASS1(SPO_TERRAIN));
1895                  }
1896                ;
1897
1898 diggable_detail : NON_DIGGABLE_ID ':' region_or_var
1899                   {
1900                       add_opvars(splev, "o", VA_PASS1(SPO_NON_DIGGABLE));
1901                   }
1902                 ;
1903
1904 passwall_detail : NON_PASSWALL_ID ':' region_or_var
1905                   {
1906                       add_opvars(splev, "o", VA_PASS1(SPO_NON_PASSWALL));
1907                   }
1908                 ;
1909
1910 region_detail   : REGION_ID ':' region_or_var ',' light_state ',' room_type optroomregionflags
1911                   {
1912                       long irr;
1913                       long rt = $7;
1914                       long rflags = $8;
1915
1916                       if (rflags == -1) rflags = (1 << 0);
1917                       if (!(rflags & 1)) rt += MAXRTYPE+1;
1918                       irr = ((rflags & 2) != 0);
1919                       add_opvars(splev, "iiio",
1920                                  VA_PASS4((long)$5, rt, rflags, SPO_REGION));
1921                       $<i>$ = (irr || (rflags & 1) || rt != OROOM);
1922                       break_stmt_start();
1923                   }
1924                   region_detail_end
1925                   {
1926                       break_stmt_end(splev);
1927                       if ( $<i>9 ) {
1928                           add_opcode(splev, SPO_ENDROOM, NULL);
1929                       } else if ( $<i>10 )
1930                           lc_error("Cannot use lev statements in non-permanent REGION");
1931                   }
1932                 ;
1933
1934 region_detail_end : /* nothing */
1935                   {
1936                       $$ = 0;
1937                   }
1938                 | stmt_block
1939                   {
1940                       $$ = $1;
1941                   }
1942                 ;
1943
1944 altar_detail    : ALTAR_ID ':' coord_or_var ',' alignment ',' altar_type
1945                   {
1946                       add_opvars(splev, "iio",
1947                                  VA_PASS3((long)$7, (long)$5, SPO_ALTAR));
1948                   }
1949                 ;
1950
1951 grave_detail    : GRAVE_ID ':' coord_or_var ',' string_expr
1952                   {
1953                       add_opvars(splev, "io", VA_PASS2(2, SPO_GRAVE));
1954                   }
1955                 | GRAVE_ID ':' coord_or_var ',' RANDOM_TYPE
1956                   {
1957                       add_opvars(splev, "sio",
1958                                  VA_PASS3((char *)0, 1, SPO_GRAVE));
1959                   }
1960                 | GRAVE_ID ':' coord_or_var
1961                   {
1962                       add_opvars(splev, "sio",
1963                                  VA_PASS3((char *)0, 0, SPO_GRAVE));
1964                   }
1965                 ;
1966
1967 gold_detail     : GOLD_ID ':' math_expr_var ',' coord_or_var
1968                   {
1969                       add_opvars(splev, "o", VA_PASS1(SPO_GOLD));
1970                   }
1971                 ;
1972
1973 engraving_detail: ENGRAVING_ID ':' coord_or_var ',' engraving_type ',' string_expr
1974                   {
1975                       add_opvars(splev, "io",
1976                                  VA_PASS2((long)$5, SPO_ENGRAVING));
1977                   }
1978                 ;
1979
1980 mineralize      : MINERALIZE_ID ':' integer_or_var ',' integer_or_var ',' integer_or_var ',' integer_or_var
1981                   {
1982                       add_opvars(splev, "o", VA_PASS1(SPO_MINERALIZE));
1983                   }
1984                 | MINERALIZE_ID
1985                   {
1986                       add_opvars(splev, "iiiio",
1987                                  VA_PASS5(-1L, -1L, -1L, -1L, SPO_MINERALIZE));
1988                   }
1989                 ;
1990
1991 trap_name       : STRING
1992                   {
1993                         int token = get_trap_type($1);
1994                         if (token == ERR)
1995                             lc_error("Unknown trap type '%s'!", $1);
1996                         $$ = token;
1997                         Free($1);
1998                   }
1999                 | RANDOM_TYPE
2000                 ;
2001
2002 room_type       : STRING
2003                   {
2004                         int token = get_room_type($1);
2005                         if (token == ERR) {
2006                             lc_warning("Unknown room type \"%s\"!  Making ordinary room...", $1);
2007                                 $$ = OROOM;
2008                         } else
2009                                 $$ = token;
2010                         Free($1);
2011                   }
2012                 | RANDOM_TYPE
2013                 ;
2014
2015 optroomregionflags : /* empty */
2016                   {
2017                         $$ = -1;
2018                   }
2019                 | ',' roomregionflags
2020                   {
2021                         $$ = $2;
2022                   }
2023                 ;
2024
2025 roomregionflags : roomregionflag
2026                   {
2027                         $$ = $1;
2028                   }
2029                 | roomregionflag ',' roomregionflags
2030                   {
2031                         $$ = $1 | $3;
2032                   }
2033                 ;
2034
2035 /* 0 is the "default" here */
2036 roomregionflag : FILLING
2037                   {
2038                       $$ = ($1 << 0);
2039                   }
2040                 | IRREGULAR
2041                   {
2042                       $$ = ($1 << 1);
2043                   }
2044                 | JOINED
2045                   {
2046                       $$ = ($1 << 2);
2047                   }
2048                 ;
2049
2050 door_state      : DOOR_STATE
2051                 | RANDOM_TYPE
2052                 ;
2053
2054 light_state     : LIGHT_STATE
2055                 | RANDOM_TYPE
2056                 ;
2057
2058 alignment       : ALIGNMENT
2059                 | a_register
2060                 | RANDOM_TYPE
2061                   {
2062                         $$ = - MAX_REGISTERS - 1;
2063                   }
2064                 ;
2065
2066 alignment_prfx  : ALIGNMENT
2067                 | a_register
2068                 | A_REGISTER ':' RANDOM_TYPE
2069                   {
2070                         $$ = - MAX_REGISTERS - 1;
2071                   }
2072                 ;
2073
2074 altar_type      : ALTAR_TYPE
2075                 | RANDOM_TYPE
2076                 ;
2077
2078 a_register      : A_REGISTER '[' INTEGER ']'
2079                   {
2080                         if ( $3 >= 3 )
2081                                 lc_error("Register Index overflow!");
2082                         else
2083                                 $$ = - $3 - 1;
2084                   }
2085                 ;
2086
2087 string_or_var   : STRING
2088                   {
2089                       add_opvars(splev, "s", VA_PASS1($1));
2090                       Free($1);
2091                   }
2092                 | VARSTRING_STRING
2093                   {
2094                       check_vardef_type(vardefs, $1, SPOVAR_STRING);
2095                       vardef_used(vardefs, $1);
2096                       add_opvars(splev, "v", VA_PASS1($1));
2097                       Free($1);
2098                   }
2099                 | VARSTRING_STRING_ARRAY '[' math_expr_var ']'
2100                   {
2101                       check_vardef_type(vardefs, $1,
2102                                         SPOVAR_STRING | SPOVAR_ARRAY);
2103                       vardef_used(vardefs, $1);
2104                       add_opvars(splev, "v", VA_PASS1($1));
2105                       Free($1);
2106                   }
2107                 ;
2108
2109
2110 integer_or_var  : math_expr_var
2111                   {
2112                       /* nothing */
2113                   }
2114                 ;
2115
2116 coord_or_var    : encodecoord
2117                   {
2118                       add_opvars(splev, "c", VA_PASS1($1));
2119                   }
2120                 | rndcoord_ID '(' ter_selection ')'
2121                   {
2122                       add_opvars(splev, "o", VA_PASS1(SPO_SEL_RNDCOORD));
2123                   }
2124                 | VARSTRING_COORD
2125                   {
2126                       check_vardef_type(vardefs, $1, SPOVAR_COORD);
2127                       vardef_used(vardefs, $1);
2128                       add_opvars(splev, "v", VA_PASS1($1));
2129                       Free($1);
2130                   }
2131                 | VARSTRING_COORD_ARRAY '[' math_expr_var ']'
2132                   {
2133                       check_vardef_type(vardefs, $1,
2134                                         SPOVAR_COORD | SPOVAR_ARRAY);
2135                       vardef_used(vardefs, $1);
2136                       add_opvars(splev, "v", VA_PASS1($1));
2137                       Free($1);
2138                   }
2139                 ;
2140
2141 encodecoord     : '(' INTEGER ',' INTEGER ')'
2142                   {
2143                       if ($2 < 0 || $4 < 0 || $2 >= COLNO || $4 >= ROWNO)
2144                           lc_error("Coordinates (%li,%li) out of map range!",
2145                                    $2, $4);
2146                       $$ = SP_COORD_PACK($2, $4);
2147                   }
2148                 | RANDOM_TYPE
2149                   {
2150                       $$ = SP_COORD_PACK_RANDOM(0);
2151                   }
2152                 | RANDOM_TYPE_BRACKET humidity_flags ']'
2153                   {
2154                       $$ = SP_COORD_PACK_RANDOM($2);
2155                   }
2156                 ;
2157
2158 humidity_flags  : HUMIDITY_TYPE
2159                   {
2160                       $$ = $1;
2161                   }
2162                 | HUMIDITY_TYPE ',' humidity_flags
2163                   {
2164                       if (($1 & $3))
2165                           lc_warning("Humidity flag used twice.");
2166                       $$ = ($1 | $3);
2167                   }
2168                 ;
2169
2170 region_or_var   : encoderegion
2171                   {
2172                       /* nothing */
2173                   }
2174                 | VARSTRING_REGION
2175                   {
2176                       check_vardef_type(vardefs, $1, SPOVAR_REGION);
2177                       vardef_used(vardefs, $1);
2178                       add_opvars(splev, "v", VA_PASS1($1));
2179                       Free($1);
2180                   }
2181                 | VARSTRING_REGION_ARRAY '[' math_expr_var ']'
2182                   {
2183                       check_vardef_type(vardefs, $1,
2184                                         SPOVAR_REGION | SPOVAR_ARRAY);
2185                       vardef_used(vardefs, $1);
2186                       add_opvars(splev, "v", VA_PASS1($1));
2187                       Free($1);
2188                   }
2189                 ;
2190
2191 encoderegion    : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
2192                   {
2193                       long r = SP_REGION_PACK($2, $4, $6, $8);
2194
2195                       if ($2 > $6 || $4 > $8)
2196                           lc_error("Region start > end: (%ld,%ld,%ld,%ld)!",
2197                                    $2, $4, $6, $8);
2198
2199                       add_opvars(splev, "r", VA_PASS1(r));
2200                       $$ = r;
2201                   }
2202                 ;
2203
2204 mapchar_or_var  : mapchar
2205                   {
2206                       add_opvars(splev, "m", VA_PASS1($1));
2207                   }
2208                 | VARSTRING_MAPCHAR
2209                   {
2210                       check_vardef_type(vardefs, $1, SPOVAR_MAPCHAR);
2211                       vardef_used(vardefs, $1);
2212                       add_opvars(splev, "v", VA_PASS1($1));
2213                       Free($1);
2214                   }
2215                 | VARSTRING_MAPCHAR_ARRAY '[' math_expr_var ']'
2216                   {
2217                       check_vardef_type(vardefs, $1,
2218                                         SPOVAR_MAPCHAR | SPOVAR_ARRAY);
2219                       vardef_used(vardefs, $1);
2220                       add_opvars(splev, "v", VA_PASS1($1));
2221                       Free($1);
2222                   }
2223                 ;
2224
2225 mapchar         : CHAR
2226                   {
2227                       if (what_map_char((char) $1) != INVALID_TYPE)
2228                           $$ = SP_MAPCHAR_PACK(what_map_char((char) $1), -2);
2229                       else {
2230                           lc_error("Unknown map char type '%c'!", $1);
2231                           $$ = SP_MAPCHAR_PACK(STONE, -2);
2232                       }
2233                   }
2234                 | '(' CHAR ',' light_state ')'
2235                   {
2236                       if (what_map_char((char) $2) != INVALID_TYPE)
2237                           $$ = SP_MAPCHAR_PACK(what_map_char((char) $2), $4);
2238                       else {
2239                           lc_error("Unknown map char type '%c'!", $2);
2240                           $$ = SP_MAPCHAR_PACK(STONE, $4);
2241                       }
2242                   }
2243                 ;
2244
2245 monster_or_var  : encodemonster
2246                   {
2247                       add_opvars(splev, "M", VA_PASS1($1));
2248                   }
2249                 | VARSTRING_MONST
2250                   {
2251                       check_vardef_type(vardefs, $1, SPOVAR_MONST);
2252                       vardef_used(vardefs, $1);
2253                       add_opvars(splev, "v", VA_PASS1($1));
2254                       Free($1);
2255                   }
2256                 | VARSTRING_MONST_ARRAY '[' math_expr_var ']'
2257                   {
2258                       check_vardef_type(vardefs, $1,
2259                                         SPOVAR_MONST | SPOVAR_ARRAY);
2260                       vardef_used(vardefs, $1);
2261                       add_opvars(splev, "v", VA_PASS1($1));
2262                       Free($1);
2263                   }
2264                 ;
2265
2266 encodemonster   : STRING
2267                   {
2268                       long m = get_monster_id($1, (char)0);
2269                       if (m == ERR) {
2270                           lc_error("Unknown monster \"%s\"!", $1);
2271                           $$ = -1;
2272                       } else
2273                           $$ = SP_MONST_PACK(m,
2274                                          def_monsyms[(int) mons[m].mlet].sym);
2275                       Free($1);
2276                   }
2277                 | CHAR
2278                   {
2279                         if (check_monster_char((char) $1))
2280                             $$ = SP_MONST_PACK(-1, $1);
2281                         else {
2282                             lc_error("Unknown monster class '%c'!", $1);
2283                             $$ = -1;
2284                         }
2285                   }
2286                 | '(' CHAR ',' STRING ')'
2287                   {
2288                       long m = get_monster_id($4, (char) $2);
2289                       if (m == ERR) {
2290                           lc_error("Unknown monster ('%c', \"%s\")!", $2, $4);
2291                           $$ = -1;
2292                       } else
2293                           $$ = SP_MONST_PACK(m, $2);
2294                       Free($4);
2295                   }
2296                 | RANDOM_TYPE
2297                   {
2298                       $$ = -1;
2299                   }
2300                 ;
2301
2302 object_or_var   : encodeobj
2303                   {
2304                       add_opvars(splev, "O", VA_PASS1($1));
2305                   }
2306                 | VARSTRING_OBJ
2307                   {
2308                       check_vardef_type(vardefs, $1, SPOVAR_OBJ);
2309                       vardef_used(vardefs, $1);
2310                       add_opvars(splev, "v", VA_PASS1($1));
2311                       Free($1);
2312                   }
2313                 | VARSTRING_OBJ_ARRAY '[' math_expr_var ']'
2314                   {
2315                       check_vardef_type(vardefs, $1,
2316                                         SPOVAR_OBJ | SPOVAR_ARRAY);
2317                       vardef_used(vardefs, $1);
2318                       add_opvars(splev, "v", VA_PASS1($1));
2319                       Free($1);
2320                   }
2321                 ;
2322
2323 encodeobj       : STRING
2324                   {
2325                       long m = get_object_id($1, (char)0);
2326                       if (m == ERR) {
2327                           lc_error("Unknown object \"%s\"!", $1);
2328                           $$ = -1;
2329                       } else
2330                           /* obj class != 0 to force generation of a specific item */
2331                           $$ = SP_OBJ_PACK(m, 1);
2332                       Free($1);
2333                   }
2334                 | CHAR
2335                   {
2336                         if (check_object_char((char) $1))
2337                             $$ = SP_OBJ_PACK(-1, $1);
2338                         else {
2339                             lc_error("Unknown object class '%c'!", $1);
2340                             $$ = -1;
2341                         }
2342                   }
2343                 | '(' CHAR ',' STRING ')'
2344                   {
2345                       long m = get_object_id($4, (char) $2);
2346                       if (m == ERR) {
2347                           lc_error("Unknown object ('%c', \"%s\")!", $2, $4);
2348                           $$ = -1;
2349                       } else
2350                           $$ = SP_OBJ_PACK(m, $2);
2351                       Free($4);
2352                   }
2353                 | RANDOM_TYPE
2354                   {
2355                       $$ = -1;
2356                   }
2357                 ;
2358
2359
2360 string_expr     : string_or_var                 { }
2361                 | string_expr '.' string_or_var
2362                   {
2363                       add_opvars(splev, "o", VA_PASS1(SPO_MATH_ADD));
2364                   }
2365                 ;
2366
2367 math_expr_var   : INTEGER
2368                   {
2369                       add_opvars(splev, "i", VA_PASS1($1));
2370                   }
2371                 | dice
2372                   {
2373                       is_inconstant_number = 1;
2374                   }
2375                 | '(' MINUS_INTEGER ')'
2376                   {
2377                       add_opvars(splev, "i", VA_PASS1($2));
2378                   }
2379                 | VARSTRING_INT
2380                   {
2381                       check_vardef_type(vardefs, $1, SPOVAR_INT);
2382                       vardef_used(vardefs, $1);
2383                       add_opvars(splev, "v", VA_PASS1($1));
2384                       Free($1);
2385                       is_inconstant_number = 1;
2386                   }
2387                 | VARSTRING_INT_ARRAY '[' math_expr_var ']'
2388                   {
2389                       check_vardef_type(vardefs, $1,
2390                                         SPOVAR_INT | SPOVAR_ARRAY);
2391                       vardef_used(vardefs, $1);
2392                       add_opvars(splev, "v", VA_PASS1($1));
2393                       Free($1);
2394                       is_inconstant_number = 1;
2395                   }
2396                 | math_expr_var '+' math_expr_var
2397                   {
2398                       add_opvars(splev, "o", VA_PASS1(SPO_MATH_ADD));
2399                   }
2400                 | math_expr_var '-' math_expr_var
2401                   {
2402                       add_opvars(splev, "o", VA_PASS1(SPO_MATH_SUB));
2403                   }
2404                 | math_expr_var '*' math_expr_var
2405                   {
2406                       add_opvars(splev, "o", VA_PASS1(SPO_MATH_MUL));
2407                   }
2408                 | math_expr_var '/' math_expr_var
2409                   {
2410                       add_opvars(splev, "o", VA_PASS1(SPO_MATH_DIV));
2411                   }
2412                 | math_expr_var '%' math_expr_var
2413                   {
2414                       add_opvars(splev, "o", VA_PASS1(SPO_MATH_MOD));
2415                   }
2416                 | '(' math_expr_var ')'             { }
2417                 ;
2418
2419 func_param_type : CFUNC_INT
2420                   {
2421                       if (!strcmp("int", $1) || !strcmp("integer", $1)) {
2422                           $$ = (int)'i';
2423                       } else
2424                           lc_error("Unknown function parameter type '%s'", $1);
2425                   }
2426                 | CFUNC_STR
2427                   {
2428                       if (!strcmp("str", $1) || !strcmp("string", $1)) {
2429                           $$ = (int)'s';
2430                       } else
2431                           lc_error("Unknown function parameter type '%s'", $1);
2432                   }
2433                 ;
2434
2435 func_param_part : any_var_or_arr ':' func_param_type
2436                   {
2437                       struct lc_funcdefs_parm *tmp = New(struct lc_funcdefs_parm);
2438
2439                       if (!curr_function) {
2440                           lc_error("Function parameters outside function definition.");
2441                       } else if (!tmp) {
2442                           lc_error("Could not alloc function params.");
2443                       } else {
2444                           long vt = SPOVAR_NULL;
2445
2446                           tmp->name = strdup($1);
2447                           tmp->parmtype = (char) $3;
2448                           tmp->next = curr_function->params;
2449                           curr_function->params = tmp;
2450                           curr_function->n_params++;
2451                           switch (tmp->parmtype) {
2452                           case 'i':
2453                               vt = SPOVAR_INT;
2454                               break;
2455                           case 's':
2456                               vt = SPOVAR_STRING;
2457                               break;
2458                           default:
2459                               lc_error("Unknown func param conversion.");
2460                               break;
2461                           }
2462                           vardefs = add_vardef_type( vardefs, $1, vt);
2463                       }
2464                       Free($1);
2465                   }
2466                 ;
2467
2468 func_param_list         : func_param_part
2469                         | func_param_list ',' func_param_part
2470                         ;
2471
2472 func_params_list        : /* nothing */
2473                         | func_param_list
2474                         ;
2475
2476 func_call_param_part    : math_expr_var
2477                           {
2478                               $$ = (int)'i';
2479                           }
2480                         | string_expr
2481                           {
2482                               $$ = (int)'s';
2483                           }
2484                         ;
2485
2486
2487 func_call_param_list    : func_call_param_part
2488                           {
2489                               char tmpbuf[2];
2490                               tmpbuf[0] = (char) $1;
2491                               tmpbuf[1] = '\0';
2492                               $$ = strdup(tmpbuf);
2493                           }
2494                         | func_call_param_list ',' func_call_param_part
2495                           {
2496                               long len = strlen( $1 );
2497                               char *tmp = (char *) alloc(len + 2);
2498                               sprintf(tmp, "%c%s", (char) $3, $1 );
2499                               Free( $1 );
2500                               $$ = tmp;
2501                           }
2502                         ;
2503
2504 func_call_params_list   : /* nothing */
2505                           {
2506                               $$ = strdup("");
2507                           }
2508                         | func_call_param_list
2509                           {
2510                               char *tmp = strdup( $1 );
2511                               Free( $1 );
2512                               $$ = tmp;
2513                           }
2514                         ;
2515
2516 ter_selection_x : coord_or_var
2517                   {
2518                       add_opvars(splev, "o", VA_PASS1(SPO_SEL_POINT));
2519                   }
2520                 | rect_ID region_or_var
2521                   {
2522                       add_opvars(splev, "o", VA_PASS1(SPO_SEL_RECT));
2523                   }
2524                 | fillrect_ID region_or_var
2525                   {
2526                       add_opvars(splev, "o", VA_PASS1(SPO_SEL_FILLRECT));
2527                   }
2528                 | line_ID coord_or_var ',' coord_or_var
2529                   {
2530                       add_opvars(splev, "o", VA_PASS1(SPO_SEL_LINE));
2531                   }
2532                 | randline_ID coord_or_var ',' coord_or_var ',' math_expr_var
2533                   {
2534                       /* randline (x1,y1),(x2,y2), roughness */
2535                       add_opvars(splev, "o", VA_PASS1(SPO_SEL_RNDLINE));
2536                   }
2537                 | grow_ID '(' ter_selection ')'
2538                   {
2539                       add_opvars(splev, "io", VA_PASS2(W_ANY, SPO_SEL_GROW));
2540                   }
2541                 | grow_ID '(' dir_list ',' ter_selection ')'
2542                   {
2543                       add_opvars(splev, "io", VA_PASS2($3, SPO_SEL_GROW));
2544                   }
2545                 | filter_ID '(' SPERCENT ',' ter_selection ')'
2546                   {
2547                       add_opvars(splev, "iio",
2548                              VA_PASS3($3, SPOFILTER_PERCENT, SPO_SEL_FILTER));
2549                   }
2550                 | filter_ID '(' ter_selection ',' ter_selection ')'
2551                   {
2552                       add_opvars(splev, "io",
2553                                VA_PASS2(SPOFILTER_SELECTION, SPO_SEL_FILTER));
2554                   }
2555                 | filter_ID '(' mapchar_or_var ',' ter_selection ')'
2556                   {
2557                       add_opvars(splev, "io",
2558                                  VA_PASS2(SPOFILTER_MAPCHAR, SPO_SEL_FILTER));
2559                   }
2560                 | flood_ID coord_or_var
2561                   {
2562                       add_opvars(splev, "o", VA_PASS1(SPO_SEL_FLOOD));
2563                   }
2564                 | circle_ID '(' coord_or_var ',' math_expr_var ')'
2565                   {
2566                       add_opvars(splev, "oio",
2567                                  VA_PASS3(SPO_COPY, 1, SPO_SEL_ELLIPSE));
2568                   }
2569                 | circle_ID '(' coord_or_var ',' math_expr_var ',' FILLING ')'
2570                   {
2571                       add_opvars(splev, "oio",
2572                                  VA_PASS3(SPO_COPY, $7, SPO_SEL_ELLIPSE));
2573                   }
2574                 | ellipse_ID '(' coord_or_var ',' math_expr_var ',' math_expr_var ')'
2575                   {
2576                       add_opvars(splev, "io", VA_PASS2(1, SPO_SEL_ELLIPSE));
2577                   }
2578                 | ellipse_ID '(' coord_or_var ',' math_expr_var ',' math_expr_var ',' FILLING ')'
2579                   {
2580                       add_opvars(splev, "io", VA_PASS2($9, SPO_SEL_ELLIPSE));
2581                   }
2582                 | gradient_ID '(' GRADIENT_TYPE ',' '(' math_expr_var '-' math_expr_var opt_limited ')' ',' coord_or_var opt_coord_or_var ')'
2583                   {
2584                       add_opvars(splev, "iio",
2585                                  VA_PASS3($9, $3, SPO_SEL_GRADIENT));
2586                   }
2587                 | complement_ID ter_selection_x
2588                   {
2589                       add_opvars(splev, "o", VA_PASS1(SPO_SEL_COMPLEMENT));
2590                   }
2591                 | VARSTRING_SEL
2592                   {
2593                       check_vardef_type(vardefs, $1, SPOVAR_SEL);
2594                       vardef_used(vardefs, $1);
2595                       add_opvars(splev, "v", VA_PASS1($1));
2596                       Free($1);
2597                   }
2598                 | '(' ter_selection ')'
2599                   {
2600                       /* nothing */
2601                   }
2602                 ;
2603
2604 ter_selection   : ter_selection_x
2605                   {
2606                       /* nothing */
2607                   }
2608                 | ter_selection_x '&' ter_selection
2609                   {
2610                       add_opvars(splev, "o", VA_PASS1(SPO_SEL_ADD));
2611                   }
2612                 ;
2613
2614 dice            : DICE
2615                   {
2616                       add_opvars(splev, "iio",
2617                                  VA_PASS3($1.num, $1.die, SPO_DICE));
2618                   }
2619                 ;
2620
2621 all_integers    : MINUS_INTEGER
2622                 | PLUS_INTEGER
2623                 | INTEGER
2624                 ;
2625
2626 all_ints_push   : MINUS_INTEGER
2627                   {
2628                       add_opvars(splev, "i", VA_PASS1($1));
2629                   }
2630                 | PLUS_INTEGER
2631                   {
2632                       add_opvars(splev, "i", VA_PASS1($1));
2633                   }
2634                 | INTEGER
2635                   {
2636                       add_opvars(splev, "i", VA_PASS1($1));
2637                   }
2638                 | dice
2639                   {
2640                       /* nothing */
2641                   }
2642                 ;
2643
2644 objectid        : object_ID
2645                 | OBJECT_ID
2646                 ;
2647
2648 monsterid       : monster_ID
2649                 | MONSTER_ID
2650                 ;
2651
2652 terrainid       : terrain_ID
2653                 | TERRAIN_ID
2654                 ;
2655
2656 engraving_type  : ENGRAVING_TYPE
2657                 | RANDOM_TYPE
2658                 ;
2659
2660 lev_region      : region
2661                   {
2662                         $$ = $1;
2663                   }
2664                 | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
2665                   {
2666                         if ($3 <= 0 || $3 >= COLNO)
2667                             lc_error(
2668                           "Region (%ld,%ld,%ld,%ld) out of level range (x1)!",
2669                                      $3, $5, $7, $9);
2670                         else if ($5 < 0 || $5 >= ROWNO)
2671                             lc_error(
2672                           "Region (%ld,%ld,%ld,%ld) out of level range (y1)!",
2673                                      $3, $5, $7, $9);
2674                         else if ($7 <= 0 || $7 >= COLNO)
2675                             lc_error(
2676                           "Region (%ld,%ld,%ld,%ld) out of level range (x2)!",
2677                                      $3, $5, $7, $9);
2678                         else if ($9 < 0 || $9 >= ROWNO)
2679                             lc_error(
2680                           "Region (%ld,%ld,%ld,%ld) out of level range (y2)!",
2681                                      $3, $5, $7, $9);
2682                         $$.x1 = $3;
2683                         $$.y1 = $5;
2684                         $$.x2 = $7;
2685                         $$.y2 = $9;
2686                         $$.area = 1;
2687                   }
2688                 ;
2689
2690 region          : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'
2691                   {
2692 /* This series of if statements is a hack for MSC 5.1.  It seems that its
2693    tiny little brain cannot compile if these are all one big if statement. */
2694                         if ($2 < 0 || $2 > (int) max_x_map)
2695                             lc_error(
2696                             "Region (%ld,%ld,%ld,%ld) out of map range (x1)!",
2697                                      $2, $4, $6, $8);
2698                         else if ($4 < 0 || $4 > (int) max_y_map)
2699                             lc_error(
2700                             "Region (%ld,%ld,%ld,%ld) out of map range (y1)!",
2701                                      $2, $4, $6, $8);
2702                         else if ($6 < 0 || $6 > (int) max_x_map)
2703                             lc_error(
2704                             "Region (%ld,%ld,%ld,%ld) out of map range (x2)!",
2705                                      $2, $4, $6, $8);
2706                         else if ($8 < 0 || $8 > (int) max_y_map)
2707                             lc_error(
2708                             "Region (%ld,%ld,%ld,%ld) out of map range (y2)!",
2709                                      $2, $4, $6, $8);
2710                         $$.area = 0;
2711                         $$.x1 = $2;
2712                         $$.y1 = $4;
2713                         $$.x2 = $6;
2714                         $$.y2 = $8;
2715                   }
2716                 ;
2717
2718
2719 %%
2720
2721 /*lev_comp.y*/