OSDN Git Service

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