~ubuntu-branches/ubuntu/dapper/malaga/dapper

« back to all changes in this revision

Viewing changes to source/rules.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Bushnell, BSG
  • Date: 2005-01-10 11:52:04 UTC
  • mfrom: (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050110115204-hpgncw5pb0m1t8i6
Tags: 6.13-5
debian/control (malaga-doc Recommends): Suggest gv as a
postscript-viewer instead of ghostview.  (Closes: #289701).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* This file is part of Malaga, a system for Natural Language Analysis.
2
 
 * Copyright (C) 1995-1999 Bjoern Beutel
3
 
 *
4
 
 * Bjoern Beutel
5
 
 * Universitaet Erlangen-Nuernberg
6
 
 * Abteilung fuer Computerlinguistik
7
 
 * Bismarckstrasse 12
8
 
 * D-91054 Erlangen
9
 
 * e-mail: malaga@linguistik.uni-erlangen.de 
10
 
 *
11
 
 * This program is free software; you can redistribute it and/or modify
12
 
 * it under the terms of the GNU General Public License as published by
13
 
 * the Free Software Foundation; either version 2 of the License, or
14
 
 * (at your option) any later version.
15
 
 *
16
 
 * This program is distributed in the hope that it will be useful,
17
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 
 * GNU General Public License for more details.
20
 
 *
21
 
 * You should have received a copy of the GNU General Public License
22
 
 * along with this program; if not, write to the Free Software
23
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
24
 
 
25
 
/* description ==============================================================*/
26
 
 
27
 
/* This module contains the Malaga rule interpreter. */
28
 
 
29
 
/* includes =================================================================*/
30
 
 
31
 
#include <stdio.h>
32
 
#include <stdlib.h>
33
 
#include <time.h>
34
 
#include <math.h>
35
 
#include "basic.h"
36
 
#include "pools.h"
37
 
#include "values.h"
38
 
#include "symbols.h"
39
 
#include "patterns.h"
40
 
#include "files.h"
41
 
#include "malaga_files.h"
42
 
#include "rule_type.h"
43
 
 
44
 
#undef GLOBAL
45
 
#define GLOBAL
46
 
#include "rules.h"
47
 
 
48
 
/* constants ================================================================*/
49
 
 
50
 
#define BACKUP_STACK_SIZE 50 /* maximum number of backtracking points */
51
 
 
52
 
/* types ====================================================================*/
53
 
 
54
 
typedef struct SWITCH_T /* used to hold the value for a "switch". */
55
 
56
 
  struct SWITCH_T *next; 
57
 
  symbol_t key; 
58
 
  value_t value; 
59
 
} switch_t;
60
 
 
61
 
/* variables ================================================================*/
62
 
 
63
 
/* the internal state of rule execution */
64
 
GLOBAL bool_t executing_rule = FALSE;
65
 
GLOBAL int_t pc = -1;
66
 
GLOBAL int_t nested_subrules = 0;
67
 
GLOBAL int_t executed_rule_number = -1;
68
 
GLOBAL rule_sys_t *executed_rule_sys = NULL;
69
 
GLOBAL rule_sys_t *debug_rule_sys = NULL;
70
 
 
71
 
LOCAL int_t base; /* index of first stack element used in this rule */
72
 
LOCAL int_t bottom; /* index of first stack element used in this branch */
73
 
 
74
 
LOCAL struct 
75
 
76
 
  int_t pc;
77
 
  int_t nested_subrules;
78
 
  int_t base; 
79
 
  int_t bottom;
80
 
} backup_stack[BACKUP_STACK_SIZE];
81
 
 
82
 
GLOBAL int_t backup_top = 0; /* index of first free item in <backup_stack> */
83
 
 
84
 
switch_t *switches; /* the list of switches. */
85
 
switch_t *current_switch; /* used for "start_switches" and "get_next_switch" */
86
 
 
87
 
/* functions ================================================================*/
88
 
 
89
 
GLOBAL void set_switch (symbol_t key, value_t value)
90
 
/* Set the switch <key> to <value>. */
91
 
{
92
 
  switch_t **my_switch;
93
 
 
94
 
  my_switch = &switches;
95
 
  while (*my_switch != NULL && (*my_switch)->key != key)
96
 
    my_switch = &(*my_switch)->next;
97
 
 
98
 
  if (*my_switch != NULL)
99
 
  {
100
 
    free_mem (&(*my_switch)->value);
101
 
    (*my_switch)->value = new_value (value);
102
 
  }
103
 
  else
104
 
  {
105
 
    (*my_switch) = new_mem (sizeof (switch_t));
106
 
    (*my_switch)->key = key;
107
 
    (*my_switch)->value = new_value (value);
108
 
    (*my_switch)->next = NULL;
109
 
  }
110
 
}
111
 
 
112
 
/*---------------------------------------------------------------------------*/
113
 
 
114
 
LOCAL value_t get_switch (symbol_t key)
115
 
/* Return the value of the switch <key>. 
116
 
 * Report an error if this switch doesn't exist. */
117
 
{
118
 
  switch_t *my_switch;
119
 
 
120
 
  for (my_switch = switches; my_switch != NULL; my_switch = my_switch->next)
121
 
  {
122
 
    if (my_switch->key == key)
123
 
      return my_switch->value;
124
 
  }
125
 
  error ("switch \"%s\" is not defined", get_symbol_name (key));
126
 
}
127
 
 
128
 
/*---------------------------------------------------------------------------*/
129
 
 
130
 
GLOBAL bool_t start_switches (void)
131
 
/* Must be called before "get_next_switch" is called.
132
 
 * Returns TRUE iff there are any switches */
133
 
{
134
 
  current_switch = switches;
135
 
  return (current_switch != NULL);
136
 
}
137
 
 
138
 
/*---------------------------------------------------------------------------*/
139
 
 
140
 
GLOBAL value_t get_next_switch (symbol_t *key)
141
 
/* Return the value of the next switch. Return its key in <*key>.
142
 
 * If there is no more switch, return NULL. */
143
 
{
144
 
  value_t value;
145
 
 
146
 
  if (current_switch == NULL)
147
 
    return NULL;
148
 
 
149
 
  *key = current_switch->key;
150
 
  value = current_switch->value;
151
 
 
152
 
  current_switch = current_switch->next;
153
 
  return value;
154
 
}
155
 
 
156
 
/*---------------------------------------------------------------------------*/
157
 
 
158
 
GLOBAL void free_switches (void)
159
 
/* Free all settings. */
160
 
{
161
 
  switch_t *my_switch, *next_switch;
162
 
 
163
 
  for (my_switch = switches; my_switch != NULL; my_switch = next_switch)
164
 
  {
165
 
    next_switch = my_switch->next;
166
 
    free_mem (&my_switch->value);
167
 
    free_mem (&my_switch);
168
 
  }
169
 
  switches = NULL;
170
 
}
171
 
 
172
 
/* rule execution ===========================================================*/
173
 
 
174
 
LOCAL void standard_function (int_t function)
175
 
/* STACK EFFECT: <value> -> <new_value>.
176
 
 * Perform function <function> on <value> yielding <new_value>. */
177
 
{
178
 
  switch (function)
179
 
  {
180
 
  case FUNC_TO_ATOMS:
181
 
    push_value (get_atoms (value_to_symbol (value_stack[--top])));
182
 
    break;
183
 
  case FUNC_TO_MULTI:
184
 
    push_symbol_value (find_multi_symbol (value_stack[--top]));
185
 
    break;
186
 
  case FUNC_TO_SET:
187
 
    convert_list_to_set ();
188
 
    break;
189
 
  case FUNC_IS_CAPITAL:
190
 
  {
191
 
    string_t string = value_to_string (value_stack[--top]);
192
 
 
193
 
    if (TO_LOWER (*string) != *string)
194
 
      push_symbol_value (YES_SYMBOL);
195
 
    else
196
 
      push_symbol_value (NO_SYMBOL);
197
 
    break;
198
 
  }
199
 
  case FUNC_GET_SWITCH:
200
 
    push_value (get_switch (value_to_symbol (value_stack[--top])));
201
 
    break;
202
 
  case FUNC_GET_LENGTH:
203
 
    push_number_value (get_list_length (value_stack[--top]));
204
 
    break;
205
 
  case FUNC_GET_VALUE_TYPE:
206
 
    push_symbol_value (get_value_type (value_stack[--top]));
207
 
    break;
208
 
  case FUNC_GET_VALUE_STRING:
209
 
  {
210
 
    string_t value_string = value_to_readable (value_stack[--top], TRUE);
211
 
 
212
 
    push_string_value (value_string, NULL);
213
 
    free_mem (&value_string);
214
 
    break;
215
 
  }
216
 
  case FUNC_TRANSMIT:
217
 
    if (transmit == NULL)
218
 
      error ("no transmit function available");
219
 
    transmit ();
220
 
  case FUNC_FLOOR:
221
 
    push_number_value (floor (value_to_double (value_stack[--top])));
222
 
    break;
223
 
  default:
224
 
    error ("internal (unknown standard function)");
225
 
  }
226
 
}
227
 
 
228
 
/*---------------------------------------------------------------------------*/
229
 
 
230
 
GLOBAL void execute_rule (rule_sys_t *rule_sys, int_t rule_number)
231
 
/* Execute rule <rule_number> in the rule system <rule_sys>.
232
 
 * Any parameters must be on the value stack. */
233
 
{
234
 
  static symbol_t nil = NIL_SYMBOL; /* the "nil" symbol */
235
 
  bool_t terminate; /* shall we terminate the current rule internal path? */
236
 
  int_t i;
237
 
 
238
 
  /* Initialise the value stack. */
239
 
  top = rule_sys->rules[rule_number].num_params;
240
 
  base = bottom = 0;
241
 
  backup_top = 0;
242
 
  nested_subrules = 0;
243
 
 
244
 
  /* See if the rule exists at all. */
245
 
  DB_ASSERT (rule_number < rule_sys->rules_size);
246
 
 
247
 
  /* Copy for debug purposes and error messages. */
248
 
  executed_rule_sys = rule_sys;
249
 
  executed_rule_number = rule_number;
250
 
 
251
 
  pc = rule_sys->rules[rule_number].first_instr;
252
 
  executing_rule = TRUE;
253
 
 
254
 
  rule_successful = FALSE;
255
 
  terminate = FALSE;
256
 
  while (! terminate) 
257
 
  {
258
 
    instr_t instruction;
259
 
    int_t info;
260
 
 
261
 
    if (debug_rule_sys == rule_sys)
262
 
      debug_rule ();
263
 
      
264
 
    instruction = rule_sys->instrs[pc];
265
 
    pc++;
266
 
    info = INSTR_INFO (instruction);
267
 
    switch (OPCODE (instruction)) 
268
 
    {
269
 
    case INS_ERROR:
270
 
      switch (info)
271
 
      {
272
 
      case ASSERTION_ERROR:
273
 
        error ("assertion failed");
274
 
      case NO_RETURN_ERROR:
275
 
        error ("missing return statement");
276
 
      default:
277
 
        error ("%s", rule_sys->strings + info);
278
 
      }
279
 
 
280
 
    case INS_TERMINATE:
281
 
      terminate = TRUE;
282
 
      break;
283
 
 
284
 
    case INS_NOP:
285
 
      break;
286
 
 
287
 
    case INS_TERMINATE_IF_NULL:
288
 
      DB_ASSERT (top >= base + 1);
289
 
      if (value_stack[--top] == NULL)
290
 
        terminate = TRUE;
291
 
      break;
292
 
 
293
 
    case INS_ADD_END_STATE:
294
 
      DB_ASSERT (top >= base + 1);
295
 
      add_end_state (value_stack[top-1]);
296
 
      top--;
297
 
      rule_successful = TRUE;
298
 
      break;
299
 
 
300
 
    case INS_ADD_STATE:
301
 
      DB_ASSERT (top >= base + 1);
302
 
      add_running_state (value_stack[top-1], info);
303
 
      top--;
304
 
      rule_successful = TRUE;
305
 
      break;
306
 
 
307
 
    case INS_ADD_ALLO:
308
 
      DB_ASSERT (top >= base + 2);
309
 
      add_allo (value_stack[top-2], value_stack[top-1]);
310
 
      top -= 2;
311
 
      rule_successful = TRUE;
312
 
      break;
313
 
 
314
 
    case INS_ACCEPT:
315
 
      DB_ASSERT (top >= base + 1);
316
 
      backup_top = 0;
317
 
      terminate = TRUE;
318
 
      break;
319
 
 
320
 
    case INS_PUSH_NULL:
321
 
      for (i = 0; i < info; i++)
322
 
        push_value (NULL);
323
 
      break;
324
 
 
325
 
    case INS_PUSH_VAR:
326
 
      DB_ASSERT (base + info < top);
327
 
      push_value (value_stack[base + info]);
328
 
      break;
329
 
 
330
 
    case INS_PUSH_CONST:
331
 
      DB_ASSERT (info < rule_sys->values_size);
332
 
      push_value (rule_sys->values + info);
333
 
      break;
334
 
 
335
 
    case INS_PUSH_SYMBOL:
336
 
      push_symbol_value (info);
337
 
      break;
338
 
 
339
 
    case INS_PUSH_PATTERN_VAR:
340
 
      DB_ASSERT (info < PATTERN_VAR_MAX);
341
 
      push_string_value (pattern_var[info], NULL);
342
 
      break;
343
 
 
344
 
    case INS_POP:
345
 
      DB_ASSERT (top >= base + info);
346
 
      top -= info;
347
 
      break;
348
 
 
349
 
    case INS_BUILD_LIST:
350
 
      DB_ASSERT (top >= base + info);
351
 
      build_list (info);
352
 
      break;
353
 
 
354
 
    case INS_BUILD_RECORD:
355
 
      DB_ASSERT (top >= base + 2*info);
356
 
      build_record (info);
357
 
      break;
358
 
 
359
 
    case INS_BUILD_PATH:
360
 
      DB_ASSERT (top >= base + info);
361
 
      build_path (info);
362
 
      break;
363
 
 
364
 
    case INS_DOT_OPERATION:
365
 
      DB_ASSERT (top >= base + 2);
366
 
      dot_operation ();
367
 
      if (value_stack[top-1] == NULL)
368
 
        value_stack[top-1] = &nil;
369
 
      break;
370
 
      
371
 
    case INS_PLUS_OPERATION:
372
 
      DB_ASSERT (top >= base + 2);
373
 
      plus_operation ();
374
 
      break;
375
 
      
376
 
    case INS_MINUS_OPERATION:
377
 
      DB_ASSERT (top >= base + 2);
378
 
      minus_operation ();
379
 
      break;
380
 
 
381
 
    case INS_ASTERISK_OPERATION:
382
 
      DB_ASSERT (top >= base + 2);
383
 
      asterisk_operation ();
384
 
      break;
385
 
 
386
 
    case INS_SLASH_OPERATION:
387
 
      DB_ASSERT (top >= base + 2);
388
 
      slash_operation ();
389
 
      break;
390
 
 
391
 
    case INS_UNARY_MINUS_OP:
392
 
      DB_ASSERT (top >= base + 1);
393
 
      unary_minus_operation ();
394
 
      break;
395
 
 
396
 
    case INS_GET_ATTRIBUTE:
397
 
      DB_ASSERT (top >= base + 1);
398
 
      value_stack[top-1] = get_attribute (value_stack[top-1], (symbol_t) info);
399
 
      if (value_stack[top-1] == NULL)
400
 
        value_stack[top-1] = &nil;
401
 
      break;
402
 
 
403
 
    case INS_REMOVE_ATTRIBUTE:
404
 
      DB_ASSERT (top >= base + 1);
405
 
      remove_attribute ((symbol_t) info);
406
 
      break;
407
 
 
408
 
    case INS_STD_FUNCTION:
409
 
      DB_ASSERT (top >= base + 1);
410
 
      standard_function (info);
411
 
      break;
412
 
 
413
 
    case INS_MATCH:
414
 
      DB_ASSERT (top >= base + 1);
415
 
      DB_ASSERT (info < rule_sys->strings_size);
416
 
      if (match_pattern (value_to_string (value_stack[--top]), 
417
 
                         rule_sys->strings + info))
418
 
        push_symbol_value (YES_SYMBOL);
419
 
      else
420
 
        push_symbol_value (NO_SYMBOL);
421
 
      break;
422
 
 
423
 
    case INS_SET_VAR:
424
 
      DB_ASSERT (top >= base + 1);
425
 
      DB_ASSERT (base + info < top);
426
 
      value_stack[base + info] = value_stack[--top];
427
 
      break;
428
 
 
429
 
    case INS_PLUS_VAR:
430
 
      DB_ASSERT (top >= base + 1);
431
 
      DB_ASSERT (base + info < top);
432
 
      insert_value (1, value_stack[base + info]);
433
 
      plus_operation ();
434
 
      value_stack[base + info] = value_stack[--top];
435
 
      break;
436
 
 
437
 
    case INS_MINUS_VAR:
438
 
      DB_ASSERT (top >= base + 1);
439
 
      DB_ASSERT (base + info < top);
440
 
      insert_value (1, value_stack[base + info]);
441
 
      minus_operation ();
442
 
      value_stack[base + info] = value_stack[--top];
443
 
      break;
444
 
 
445
 
    case INS_ASTERISK_VAR:
446
 
      DB_ASSERT (top >= base + 1);
447
 
      DB_ASSERT (base + info < top);
448
 
      insert_value (1, value_stack[base + info]);
449
 
      asterisk_operation ();
450
 
      value_stack[base + info] = value_stack[--top];
451
 
      break;
452
 
 
453
 
    case INS_SLASH_VAR:
454
 
      DB_ASSERT (top >= base + 1);
455
 
      DB_ASSERT (base + info < top);
456
 
      insert_value (1, value_stack[base + info]);
457
 
      slash_operation ();
458
 
      value_stack[base + info] = value_stack[--top];
459
 
      break;
460
 
 
461
 
    case INS_SET_VAR_PATH:
462
 
      DB_ASSERT (top >= base + 2);
463
 
      DB_ASSERT (base + info < top);
464
 
      insert_value (2, value_stack[base + info]);
465
 
      modify_value_part (right_value);
466
 
      value_stack[base + info] = value_stack[--top];
467
 
      break;
468
 
 
469
 
    case INS_PLUS_VAR_PATH:
470
 
      DB_ASSERT (top >= base + 2);
471
 
      DB_ASSERT (base + info < top);
472
 
      insert_value (2, value_stack[base + info]);
473
 
      modify_value_part (plus_operation);
474
 
      value_stack[base + info] = value_stack[--top];
475
 
      break;
476
 
 
477
 
    case INS_MINUS_VAR_PATH:
478
 
      DB_ASSERT (top >= base + 2);
479
 
      DB_ASSERT (base + info < top);
480
 
      insert_value (2, value_stack[base + info]);
481
 
      modify_value_part (minus_operation);
482
 
      value_stack[base + info] = value_stack[--top];
483
 
      break;
484
 
 
485
 
    case INS_ASTERISK_VAR_PATH:
486
 
      DB_ASSERT (top >= base + 2);
487
 
      DB_ASSERT (base + info < top);
488
 
      insert_value (2, value_stack[base + info]);
489
 
      modify_value_part (asterisk_operation);
490
 
      value_stack[base + info] = value_stack[--top];
491
 
      break;
492
 
 
493
 
    case INS_SLASH_VAR_PATH:
494
 
      DB_ASSERT (top >= base + 2);
495
 
      DB_ASSERT (base + info < top);
496
 
      insert_value (2, value_stack[base + info]);
497
 
      modify_value_part (slash_operation);
498
 
      value_stack[base + info] = value_stack[--top];
499
 
      break;
500
 
 
501
 
    case INS_GET_1ST_ELEMENT:
502
 
      DB_ASSERT (top >= base + 1);
503
 
      get_first_element ();
504
 
      break;
505
 
 
506
 
    case INS_ITERATE:
507
 
      DB_ASSERT (info >= 1 && base + info < top);
508
 
      get_next_element (base + info);
509
 
      break;
510
 
 
511
 
    case INS_JUMP:
512
 
      DB_ASSERT (info < rule_sys->instrs_size);
513
 
      pc = info;
514
 
      break;
515
 
 
516
 
    case INS_JUMP_IF_EQUAL:
517
 
      DB_ASSERT (top >= base + 2);
518
 
      DB_ASSERT (info < rule_sys->instrs_size);
519
 
      if (values_equal (value_stack[top-2], value_stack[top-1]))
520
 
        pc = info;
521
 
      top -= 2;
522
 
      break;
523
 
 
524
 
    case INS_JUMP_IF_NOT_EQUAL:
525
 
      DB_ASSERT (top >= base + 2);
526
 
      DB_ASSERT (info < rule_sys->instrs_size);
527
 
      if (! values_equal (value_stack[top-2], value_stack[top-1]))
528
 
        pc = info;
529
 
      top -= 2;
530
 
      break;
531
 
 
532
 
    case INS_JUMP_IF_CONGR:
533
 
      DB_ASSERT (top >= base + 2);
534
 
      DB_ASSERT (info < rule_sys->instrs_size);
535
 
      if (values_congruent (value_stack[top-2], value_stack[top-1]))
536
 
        pc = info;
537
 
      top -= 2;
538
 
      break;
539
 
          
540
 
    case INS_JUMP_IF_NOT_CONGR:
541
 
      DB_ASSERT (top >= base + 2);
542
 
      DB_ASSERT (info < rule_sys->instrs_size);
543
 
      if (! values_congruent (value_stack[top-2], value_stack[top-1]))
544
 
        pc = info;
545
 
      top -= 2;
546
 
      break;
547
 
 
548
 
    case INS_JUMP_IF_IN:
549
 
      DB_ASSERT (top >= base + 2);
550
 
      DB_ASSERT (info < rule_sys->instrs_size);
551
 
      if (value_in_value (value_stack[top-2], value_stack[top-1]))
552
 
        pc = info;
553
 
      top -= 2;
554
 
      break;
555
 
 
556
 
    case INS_JUMP_IF_NOT_IN:
557
 
      DB_ASSERT (top >= base + 2);
558
 
      DB_ASSERT (info < rule_sys->instrs_size);
559
 
      if (! value_in_value (value_stack[top-2], value_stack[top-1]))
560
 
        pc = info;
561
 
      top -= 2;
562
 
      break;
563
 
 
564
 
    case INS_JUMP_IF_LESS:
565
 
      DB_ASSERT (top >= base + 2);
566
 
      DB_ASSERT (info < rule_sys->instrs_size);
567
 
      if (value_to_double (value_stack[top-2])
568
 
          < value_to_double (value_stack[top-1]))
569
 
        pc = info;
570
 
      top -= 2;
571
 
      break;
572
 
          
573
 
    case INS_JUMP_IF_NOT_LESS:
574
 
      DB_ASSERT (top >= base + 2);
575
 
      DB_ASSERT (info < rule_sys->instrs_size);
576
 
      if (! (value_to_double (value_stack[top-2])
577
 
             < value_to_double (value_stack[top-1])))
578
 
        pc = info;
579
 
      top -= 2;
580
 
      break;
581
 
 
582
 
    case INS_JUMP_IF_GREATER:
583
 
      DB_ASSERT (top >= base + 2);
584
 
      DB_ASSERT (info < rule_sys->instrs_size);
585
 
      if (value_to_double (value_stack[top-2])
586
 
          > value_to_double (value_stack[top-1]))
587
 
        pc = info;
588
 
      top -= 2;
589
 
      break;
590
 
          
591
 
    case INS_JUMP_IF_NOT_GREATER:
592
 
      DB_ASSERT (top >= base + 2);
593
 
      DB_ASSERT (info < rule_sys->instrs_size);
594
 
      if (! (value_to_double (value_stack[top-2])
595
 
             > value_to_double (value_stack[top-1])))
596
 
        pc = info;
597
 
      top -= 2;
598
 
      break;
599
 
 
600
 
    case INS_JUMP_IF_NULL:
601
 
      DB_ASSERT (top >= base + 1);
602
 
      DB_ASSERT (info < rule_sys->instrs_size);
603
 
      if (value_stack[--top] == NULL)
604
 
        pc = info;
605
 
      break;
606
 
 
607
 
    case INS_JUMP_IF_NOT_NULL:
608
 
      DB_ASSERT (top >= base + 1);
609
 
      DB_ASSERT (info < rule_sys->instrs_size);
610
 
      if (value_stack[--top] != NULL)
611
 
        pc = info;
612
 
      break;
613
 
 
614
 
    case INS_JUMP_IF_YES:
615
 
    {
616
 
      symbol_t symbol;
617
 
 
618
 
      DB_ASSERT (top >= base + 1);
619
 
      DB_ASSERT (info < rule_sys->instrs_size);
620
 
          
621
 
      symbol = value_to_symbol (value_stack[--top]);
622
 
      if (symbol != YES_SYMBOL && symbol != NO_SYMBOL)
623
 
        error ("boolean value expected");
624
 
      if (symbol == YES_SYMBOL)
625
 
        pc = info;
626
 
      break;
627
 
    }
628
 
 
629
 
    case INS_JUMP_IF_NO:
630
 
    {
631
 
      symbol_t symbol;
632
 
 
633
 
      DB_ASSERT (top >= base + 1);
634
 
      DB_ASSERT (info < rule_sys->instrs_size);
635
 
          
636
 
      symbol = value_to_symbol (value_stack[--top]);
637
 
      if (symbol != YES_SYMBOL && symbol != NO_SYMBOL)
638
 
        error ("boolean value expected");
639
 
      if (symbol == NO_SYMBOL)
640
 
        pc = info;
641
 
      break;
642
 
    }
643
 
          
644
 
    case INS_JUMP_NOW:
645
 
    {
646
 
      int_t old_top = top;
647
 
 
648
 
      DB_ASSERT (info < rule_sys->instrs_size);
649
 
      if (backup_top >= BACKUP_STACK_SIZE)
650
 
        error ("too many branches in a rule");
651
 
 
652
 
      backup_stack[backup_top].pc = pc;
653
 
      backup_stack[backup_top].nested_subrules = nested_subrules;
654
 
      backup_stack[backup_top].base = base;
655
 
      backup_stack[backup_top].bottom = bottom;
656
 
      while (bottom < old_top)
657
 
        push_value (value_stack[bottom++]);
658
 
      base += (top - old_top);
659
 
      backup_top++;
660
 
      pc = info;
661
 
      break;
662
 
    }
663
 
 
664
 
    case INS_JUMP_LATER:
665
 
    {
666
 
      int_t old_top = top;
667
 
 
668
 
      DB_ASSERT (info < rule_sys->instrs_size);
669
 
      if (backup_top >= BACKUP_STACK_SIZE)
670
 
        error ("too many branches in a rule");
671
 
 
672
 
      backup_stack[backup_top].pc = info;
673
 
      backup_stack[backup_top].nested_subrules = nested_subrules;
674
 
      backup_stack[backup_top].base = base;
675
 
      backup_stack[backup_top].bottom = bottom;
676
 
      while (bottom < old_top)
677
 
        push_value (value_stack[bottom++]);
678
 
      base += (top - old_top);
679
 
      backup_top++;
680
 
      break;
681
 
    }
682
 
 
683
 
    case INS_JUMP_SUBRULE:
684
 
      push_number_value (base - bottom);
685
 
      push_number_value (pc);
686
 
      base = top;
687
 
      pc = rule_sys->rules[info].first_instr;
688
 
      nested_subrules++;
689
 
      break;
690
 
 
691
 
    case INS_RETURN:
692
 
    {
693
 
      int_t old_base;
694
 
 
695
 
      DB_ASSERT (base - bottom >= 2 + info);
696
 
      old_base = bottom + value_to_int (value_stack[base - 2]);
697
 
      pc = value_to_int (value_stack[base - 1]);
698
 
      value_stack[base - info - 2] = value_stack[top-1]; /* Copy result. */
699
 
      top = base - (info + 1);
700
 
      base = old_base;
701
 
      nested_subrules--;
702
 
      break;
703
 
    }
704
 
 
705
 
    default:
706
 
      error ("internal (unknown instruction %d)", OPCODE (instruction));
707
 
      break;
708
 
    }
709
 
 
710
 
    if (terminate && backup_top > 0) 
711
 
    { /* Load a previously saved rule-internal state and continue. */
712
 
      backup_top--;
713
 
      top = bottom;
714
 
      base = backup_stack[backup_top].base;
715
 
      bottom = backup_stack[backup_top].bottom;
716
 
      pc = backup_stack[backup_top].pc;
717
 
      nested_subrules = backup_stack[backup_top].nested_subrules;
718
 
      terminate = FALSE;
719
 
    }
720
 
  }
721
 
 
722
 
  executing_rule = FALSE;
723
 
  pc = -1;
724
 
  executed_rule_number = -1;
725
 
  executed_rule_sys = NULL;
726
 
}
727
 
 
728
 
/*---------------------------------------------------------------------------*/
729
 
 
730
 
GLOBAL rule_sys_t *read_rule_sys (string_t file_name)
731
 
/* Read rule system from file <file_name>.
732
 
 * A symbol file must have already been loaded. */
733
 
{
734
 
  FILE *stream;
735
 
  rule_header_t header;
736
 
  rule_sys_t *rule_sys = new_mem (sizeof (rule_sys_t));
737
 
 
738
 
  stream = open_stream (file_name, "rb");
739
 
 
740
 
  read_vector (&header, sizeof (header), 1, stream, file_name);
741
 
 
742
 
  check_header (&header.common_header, file_name, 
743
 
                RULE_FILE, RULE_CODE_VERSION);
744
 
 
745
 
  rule_sys->initial_rule_set = header.initial_rule_set;
746
 
  rule_sys->initial_cat = header.initial_cat;
747
 
  rule_sys->robust_rule = header.robust_rule;
748
 
  rule_sys->allo_rule = header.allo_rule;
749
 
  rule_sys->pruning_rule = header.pruning_rule;
750
 
  rule_sys->input_filter = header.input_filter;
751
 
  rule_sys->output_filter = header.output_filter;
752
 
  rule_sys->rules_size = header.rules_size;
753
 
  rule_sys->rules = read_new_vector (sizeof (rule_t), header.rules_size, 
754
 
                                     stream, file_name);
755
 
  rule_sys->rule_sets_size = header.rule_sets_size;
756
 
  rule_sys->rule_sets = read_new_vector (sizeof (int_t), header.rule_sets_size,
757
 
                                         stream, file_name);
758
 
  rule_sys->instrs_size = header.instrs_size;
759
 
  rule_sys->instrs = read_new_vector (sizeof (instr_t), header.instrs_size, 
760
 
                                      stream, file_name);
761
 
  rule_sys->values_size = header.values_size;
762
 
  rule_sys->values = read_new_vector (sizeof (cell_t), header.values_size, 
763
 
                                      stream, file_name);
764
 
  rule_sys->src_lines_size = header.src_lines_size;
765
 
  rule_sys->src_lines = read_new_vector (sizeof (src_line_t), 
766
 
                                         header.src_lines_size, 
767
 
                                         stream, file_name);
768
 
  rule_sys->vars_size = header.vars_size;
769
 
  rule_sys->vars = read_new_vector (sizeof (var_t), header.vars_size,
770
 
                                    stream, file_name);
771
 
  rule_sys->var_scopes_size = header.var_scopes_size;
772
 
  rule_sys->var_scopes = read_new_vector (sizeof (var_scope_t), 
773
 
                                          header.var_scopes_size,
774
 
                                          stream, file_name);
775
 
  rule_sys->strings_size = header.strings_size;
776
 
  rule_sys->strings = read_new_vector (sizeof (char), header.strings_size, 
777
 
                                       stream, file_name);
778
 
 
779
 
  close_stream (&stream, file_name);
780
 
  
781
 
  return rule_sys;
782
 
}
783
 
 
784
 
/*---------------------------------------------------------------------------*/
785
 
 
786
 
GLOBAL void free_rule_sys (rule_sys_t **rule_sys)
787
 
/* Free all memory used by <*rule_sys>. */
788
 
789
 
  if (*rule_sys != NULL)
790
 
  {
791
 
    free_mem (&(*rule_sys)->rules);
792
 
    free_mem (&(*rule_sys)->rule_sets);
793
 
    free_mem (&(*rule_sys)->instrs);
794
 
    free_mem (&(*rule_sys)->values);
795
 
    free_mem (&(*rule_sys)->src_lines);
796
 
    free_mem (&(*rule_sys)->vars);
797
 
    free_mem (&(*rule_sys)->var_scopes);
798
 
    free_mem (&(*rule_sys)->strings);
799
 
    free_mem (rule_sys);
800
 
  }
801
 
}
802
 
 
803
 
/* debug support functions ==================================================*/
804
 
 
805
 
GLOBAL value_t inspect_stack (int_t index)
806
 
/* Return S[index] or NULL if it is not defined. */
807
 
{
808
 
  if (base + index >= top)
809
 
    return NULL;
810
 
  else
811
 
    return value_stack[base + index];
812
 
}
813
 
 
814
 
/*---------------------------------------------------------------------------*/
815
 
 
816
 
GLOBAL void get_base_and_pc_indexes (int_t index, 
817
 
                                     int_t *base_index, 
818
 
                                     int_t *pc_index)
819
 
/* If <index> == 0, return the current <pc_index> and the <base_index> of the
820
 
 * stack when this rule was called as a subrule. */
821
 
{
822
 
  if (index == 0)
823
 
  {
824
 
    *pc_index = pc;
825
 
    *base_index = base - bottom;
826
 
  }
827
 
  else
828
 
  {
829
 
    *pc_index = value_to_int (value_stack[bottom + index - 1]);
830
 
    *base_index = value_to_int (value_stack[bottom + index - 2]);
831
 
  }
832
 
}
833
 
 
834
 
/*---------------------------------------------------------------------------*/
835
 
 
836
 
GLOBAL int_t inspect_stack_pointer (void)
837
 
/* Return value of rule stack pointer. */
838
 
{
839
 
  return top - base;
840
 
}
841
 
 
842
 
/*---------------------------------------------------------------------------*/
843
 
 
844
 
GLOBAL int_t first_variable_index (rule_sys_t *rule_sys,
845
 
                                   int_t instr_index)
846
 
/* Return the stack index of the first variable that is visible
847
 
 * when pc is at <instr_index> in <rule_sys>. */
848
 
{
849
 
  rule_t *rule;
850
 
  int_t i, first_instr;
851
 
 
852
 
  /* Find the rule/subrule we're in. */
853
 
  rule = NULL;
854
 
  first_instr = -1;
855
 
  for (i = 0; i < rule_sys->rules_size; i++)
856
 
  {
857
 
    rule_t *rule2 = rule_sys->rules + i;
858
 
 
859
 
    if (rule2->first_instr <= instr_index 
860
 
        && rule2->first_instr > first_instr)
861
 
    {
862
 
      rule = rule2;
863
 
      first_instr = rule->first_instr;
864
 
    }
865
 
  }
866
 
 
867
 
  DB_ASSERT (rule != NULL);
868
 
 
869
 
  if (rule->type == SUBRULE)
870
 
    return - (2 + rule->num_params);
871
 
  else
872
 
    return 0;
873
 
}
874
 
 
875
 
/*---------------------------------------------------------------------------*/
876
 
 
877
 
GLOBAL void source_of_instr (rule_sys_t *rule_sys,
878
 
                             int_t instr_index, 
879
 
                             int_t *first_line, 
880
 
                             int_t *last_line, 
881
 
                             string_t *file_name,
882
 
                             string_t *rule_name)
883
 
/* Set *<first_line>, *<last_line> and *<file_name> to appropriate values
884
 
 * for the statement that has generated the instruction at <instr_index>. */
885
 
{
886
 
  int_t lower, upper, middle;
887
 
  src_line_t *src_line;
888
 
 
889
 
  if (rule_sys->src_lines_size == 0 
890
 
      || rule_sys->src_lines[0].instr > instr_index)
891
 
  {
892
 
    if (first_line != NULL)
893
 
      *first_line = -1;
894
 
    if (last_line != NULL)
895
 
      *last_line = -1;
896
 
    if (file_name != NULL)
897
 
      *file_name = NULL;
898
 
    if (rule_name != NULL)
899
 
      *rule_name = NULL;
900
 
    return;
901
 
  }
902
 
 
903
 
  /* Find the last src_line entry with <instr> <= <instr_index>. */
904
 
  lower = 0;
905
 
  upper = rule_sys->src_lines_size - 1;
906
 
  while (lower < upper) 
907
 
  {
908
 
    middle = (lower + upper + 1) / 2;
909
 
    src_line = rule_sys->src_lines + middle;
910
 
 
911
 
    if (src_line->instr <= instr_index)
912
 
      lower = middle;
913
 
    else
914
 
      upper = middle - 1;
915
 
  }
916
 
  
917
 
  src_line = rule_sys->src_lines + lower;
918
 
 
919
 
  if (first_line != NULL)
920
 
    *first_line = src_line->line;
921
 
 
922
 
  if (file_name != NULL)
923
 
  {
924
 
    if (src_line->file != -1)
925
 
      *file_name = rule_sys->strings + src_line->file;
926
 
    else
927
 
      *file_name = NULL;
928
 
  }
929
 
 
930
 
  /* Find the last line of the statement. */
931
 
  if (last_line != NULL) 
932
 
  {
933
 
    do
934
 
    {
935
 
      src_line++;
936
 
    } while (src_line < rule_sys->src_lines + rule_sys->src_lines_size
937
 
             && src_line->line == -1);
938
 
 
939
 
    if (src_line < rule_sys->src_lines + rule_sys->src_lines_size)
940
 
      *last_line = src_line->line - 1;
941
 
    else
942
 
    *last_line = -1;
943
 
  }
944
 
 
945
 
  /* Find the rule of the statement */
946
 
  if (rule_name != NULL)
947
 
  {
948
 
    int_t rule_number;
949
 
    int_t i;
950
 
    int_t first_instr;
951
 
    
952
 
    rule_number = 0;
953
 
    first_instr = -1;
954
 
    for (i = 0; i < rule_sys->rules_size; i++)
955
 
    {
956
 
      rule_t *rule = rule_sys->rules + i;
957
 
 
958
 
      if (rule->first_instr <= instr_index && rule->first_instr > first_instr)
959
 
      {
960
 
        rule_number = i;
961
 
        first_instr = rule->first_instr;
962
 
      }
963
 
    }
964
 
    *rule_name = rule_sys->strings + rule_sys->rules[rule_number].name;
965
 
  }
966
 
}
967
 
 
968
 
/*---------------------------------------------------------------------------*/
969
 
 
970
 
LOCAL int_t local_variable_index (rule_sys_t *rule_sys, 
971
 
                                  var_t *var, 
972
 
                                  int_t instr_index)
973
 
/* Return the stack index of variable <var> at <instr_index>.
974
 
 * Return -1 if it is not currently defined. */
975
 
{
976
 
  int_t lower, upper, middle;
977
 
  var_scope_t *var_scope;
978
 
 
979
 
  /* Find last scope whose <first_instr> is not higher than <instr_index>. */ 
980
 
  lower = var->first_scope;
981
 
  upper = lower + var->number_of_scopes - 1;
982
 
 
983
 
  while (lower < upper) 
984
 
  {
985
 
    middle = (lower + upper + 1) / 2;
986
 
    var_scope = rule_sys->var_scopes + middle;
987
 
 
988
 
    if (var_scope->first_instr <= instr_index)
989
 
      lower = middle;
990
 
    else
991
 
      upper = middle - 1;
992
 
  }
993
 
 
994
 
  /* <lower> is the index of the highest line
995
 
   * with an instruction index not more than <instr_index>. */
996
 
  if (lower == upper) 
997
 
  {
998
 
    /* We found a scope. */
999
 
    var_scope = rule_sys->var_scopes + lower;
1000
 
    if (instr_index >= var_scope->first_instr 
1001
 
        && instr_index <= var_scope->last_instr)
1002
 
      /* Variable is defined. */
1003
 
      return var_scope->stack_index;
1004
 
  }
1005
 
  
1006
 
  return -1;
1007
 
}
1008
 
 
1009
 
/*---------------------------------------------------------------------------*/
1010
 
 
1011
 
GLOBAL string_t variable_at_index (rule_sys_t *rule_sys,
1012
 
                                   int_t stack_index, 
1013
 
                                   int_t instr_index)
1014
 
/* Return the name of the variable that is defined at <stack_index>
1015
 
 * when instruction <instr_index> is executed or NULL if there is none. */
1016
 
{
1017
 
  int_t i;
1018
 
 
1019
 
  /* There is never a variable at stack index -2 or -1. */
1020
 
  if (stack_index == -2 || stack_index == -1)
1021
 
    return NULL;
1022
 
 
1023
 
  /* For each variable name, test if it is the right one. */
1024
 
  for (i = 0; i < rule_sys->vars_size; i++) 
1025
 
  {
1026
 
    var_t *var = rule_sys->vars + i;
1027
 
 
1028
 
    if (stack_index == local_variable_index (rule_sys, var, instr_index))
1029
 
      return rule_sys->strings + var->name;
1030
 
  }
1031
 
 
1032
 
  return NULL;
1033
 
}
1034
 
 
1035
 
/*---------------------------------------------------------------------------*/
1036
 
 
1037
 
GLOBAL int_t variable_index (rule_sys_t *rule_sys,
1038
 
                             string_t var_name, 
1039
 
                             int_t instr_index)
1040
 
/* Return the stack index of variable <var_name> at <instr_index>. */
1041
 
{
1042
 
  /* Search for the right variable name (binary search). */
1043
 
  int_t lower = 0;
1044
 
  int_t upper = rule_sys->vars_size - 1;
1045
 
 
1046
 
  while (lower <= upper) 
1047
 
  {
1048
 
    int_t middle = (lower + upper) / 2;
1049
 
    var_t *var = rule_sys->vars + middle;
1050
 
    int_t result = strcmp_no_case (var_name, rule_sys->strings + var->name);
1051
 
 
1052
 
    if (result < 0)
1053
 
      upper = middle - 1;
1054
 
    else if (result > 0)
1055
 
      lower = middle + 1;
1056
 
    else
1057
 
      return local_variable_index (rule_sys, var, instr_index);
1058
 
  }
1059
 
  return -1;
1060
 
}
1061
 
 
1062
 
/*---------------------------------------------------------------------------*/
1063
 
 
1064
 
GLOBAL string_t rule_set_readable (rule_sys_t *rule_sys, int_t rule_set)
1065
 
/* Return <rule_set> in <rule_sys> as a readable string.
1066
 
 * The string must be freed with "free" after use. */
1067
 
{
1068
 
  text_t text = new_text ();
1069
 
 
1070
 
  if (rule_set == -1)
1071
 
    add_to_text (text, "(end state)");
1072
 
  else
1073
 
  { 
1074
 
    bool_t name_has_been_printed;
1075
 
    int_t *rule;
1076
 
      
1077
 
    add_to_text (text, "rules ");
1078
 
 
1079
 
    rule = rule_sys->rule_sets + rule_set;
1080
 
    while (TRUE)
1081
 
    {
1082
 
      name_has_been_printed = FALSE;
1083
 
      while (*rule >= 0)
1084
 
      {
1085
 
        if (name_has_been_printed)
1086
 
          add_to_text (text, ", ");
1087
 
        else
1088
 
          name_has_been_printed = TRUE;
1089
 
        
1090
 
        add_to_text (text, rule_sys->strings + rule_sys->rules[*rule++].name);
1091
 
      }
1092
 
      
1093
 
      if (*rule == -1)
1094
 
        break;
1095
 
 
1096
 
      add_to_text (text, " else ");
1097
 
      rule++;
1098
 
    }
1099
 
  }
1100
 
 
1101
 
  return text_to_string (&text);
1102
 
}
1103
 
 
1104
 
/* end of file ==============================================================*/