OSDN Git Service

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