1
/* This file is part of Malaga, a system for Natural Language Analysis.
2
* Copyright (C) 1995-1999 Bjoern Beutel
5
* Universitaet Erlangen-Nuernberg
6
* Abteilung fuer Computerlinguistik
9
* e-mail: malaga@linguistik.uni-erlangen.de
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.
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.
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 */
25
/* description ==============================================================*/
27
/* This module contains the Malaga rule interpreter. */
29
/* includes =================================================================*/
41
#include "malaga_files.h"
42
#include "rule_type.h"
48
/* constants ================================================================*/
50
#define BACKUP_STACK_SIZE 50 /* maximum number of backtracking points */
52
/* types ====================================================================*/
54
typedef struct SWITCH_T /* used to hold the value for a "switch". */
56
struct SWITCH_T *next;
61
/* variables ================================================================*/
63
/* the internal state of rule execution */
64
GLOBAL bool_t executing_rule = FALSE;
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;
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 */
77
int_t nested_subrules;
80
} backup_stack[BACKUP_STACK_SIZE];
82
GLOBAL int_t backup_top = 0; /* index of first free item in <backup_stack> */
84
switch_t *switches; /* the list of switches. */
85
switch_t *current_switch; /* used for "start_switches" and "get_next_switch" */
87
/* functions ================================================================*/
89
GLOBAL void set_switch (symbol_t key, value_t value)
90
/* Set the switch <key> to <value>. */
94
my_switch = &switches;
95
while (*my_switch != NULL && (*my_switch)->key != key)
96
my_switch = &(*my_switch)->next;
98
if (*my_switch != NULL)
100
free_mem (&(*my_switch)->value);
101
(*my_switch)->value = new_value (value);
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;
112
/*---------------------------------------------------------------------------*/
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. */
120
for (my_switch = switches; my_switch != NULL; my_switch = my_switch->next)
122
if (my_switch->key == key)
123
return my_switch->value;
125
error ("switch \"%s\" is not defined", get_symbol_name (key));
128
/*---------------------------------------------------------------------------*/
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 */
134
current_switch = switches;
135
return (current_switch != NULL);
138
/*---------------------------------------------------------------------------*/
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. */
146
if (current_switch == NULL)
149
*key = current_switch->key;
150
value = current_switch->value;
152
current_switch = current_switch->next;
156
/*---------------------------------------------------------------------------*/
158
GLOBAL void free_switches (void)
159
/* Free all settings. */
161
switch_t *my_switch, *next_switch;
163
for (my_switch = switches; my_switch != NULL; my_switch = next_switch)
165
next_switch = my_switch->next;
166
free_mem (&my_switch->value);
167
free_mem (&my_switch);
172
/* rule execution ===========================================================*/
174
LOCAL void standard_function (int_t function)
175
/* STACK EFFECT: <value> -> <new_value>.
176
* Perform function <function> on <value> yielding <new_value>. */
181
push_value (get_atoms (value_to_symbol (value_stack[--top])));
184
push_symbol_value (find_multi_symbol (value_stack[--top]));
187
convert_list_to_set ();
189
case FUNC_IS_CAPITAL:
191
string_t string = value_to_string (value_stack[--top]);
193
if (TO_LOWER (*string) != *string)
194
push_symbol_value (YES_SYMBOL);
196
push_symbol_value (NO_SYMBOL);
199
case FUNC_GET_SWITCH:
200
push_value (get_switch (value_to_symbol (value_stack[--top])));
202
case FUNC_GET_LENGTH:
203
push_number_value (get_list_length (value_stack[--top]));
205
case FUNC_GET_VALUE_TYPE:
206
push_symbol_value (get_value_type (value_stack[--top]));
208
case FUNC_GET_VALUE_STRING:
210
string_t value_string = value_to_readable (value_stack[--top], TRUE);
212
push_string_value (value_string, NULL);
213
free_mem (&value_string);
217
if (transmit == NULL)
218
error ("no transmit function available");
221
push_number_value (floor (value_to_double (value_stack[--top])));
224
error ("internal (unknown standard function)");
228
/*---------------------------------------------------------------------------*/
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. */
234
static symbol_t nil = NIL_SYMBOL; /* the "nil" symbol */
235
bool_t terminate; /* shall we terminate the current rule internal path? */
238
/* Initialise the value stack. */
239
top = rule_sys->rules[rule_number].num_params;
244
/* See if the rule exists at all. */
245
DB_ASSERT (rule_number < rule_sys->rules_size);
247
/* Copy for debug purposes and error messages. */
248
executed_rule_sys = rule_sys;
249
executed_rule_number = rule_number;
251
pc = rule_sys->rules[rule_number].first_instr;
252
executing_rule = TRUE;
254
rule_successful = FALSE;
261
if (debug_rule_sys == rule_sys)
264
instruction = rule_sys->instrs[pc];
266
info = INSTR_INFO (instruction);
267
switch (OPCODE (instruction))
272
case ASSERTION_ERROR:
273
error ("assertion failed");
274
case NO_RETURN_ERROR:
275
error ("missing return statement");
277
error ("%s", rule_sys->strings + info);
287
case INS_TERMINATE_IF_NULL:
288
DB_ASSERT (top >= base + 1);
289
if (value_stack[--top] == NULL)
293
case INS_ADD_END_STATE:
294
DB_ASSERT (top >= base + 1);
295
add_end_state (value_stack[top-1]);
297
rule_successful = TRUE;
301
DB_ASSERT (top >= base + 1);
302
add_running_state (value_stack[top-1], info);
304
rule_successful = TRUE;
308
DB_ASSERT (top >= base + 2);
309
add_allo (value_stack[top-2], value_stack[top-1]);
311
rule_successful = TRUE;
315
DB_ASSERT (top >= base + 1);
321
for (i = 0; i < info; i++)
326
DB_ASSERT (base + info < top);
327
push_value (value_stack[base + info]);
331
DB_ASSERT (info < rule_sys->values_size);
332
push_value (rule_sys->values + info);
335
case INS_PUSH_SYMBOL:
336
push_symbol_value (info);
339
case INS_PUSH_PATTERN_VAR:
340
DB_ASSERT (info < PATTERN_VAR_MAX);
341
push_string_value (pattern_var[info], NULL);
345
DB_ASSERT (top >= base + info);
350
DB_ASSERT (top >= base + info);
354
case INS_BUILD_RECORD:
355
DB_ASSERT (top >= base + 2*info);
360
DB_ASSERT (top >= base + info);
364
case INS_DOT_OPERATION:
365
DB_ASSERT (top >= base + 2);
367
if (value_stack[top-1] == NULL)
368
value_stack[top-1] = &nil;
371
case INS_PLUS_OPERATION:
372
DB_ASSERT (top >= base + 2);
376
case INS_MINUS_OPERATION:
377
DB_ASSERT (top >= base + 2);
381
case INS_ASTERISK_OPERATION:
382
DB_ASSERT (top >= base + 2);
383
asterisk_operation ();
386
case INS_SLASH_OPERATION:
387
DB_ASSERT (top >= base + 2);
391
case INS_UNARY_MINUS_OP:
392
DB_ASSERT (top >= base + 1);
393
unary_minus_operation ();
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;
403
case INS_REMOVE_ATTRIBUTE:
404
DB_ASSERT (top >= base + 1);
405
remove_attribute ((symbol_t) info);
408
case INS_STD_FUNCTION:
409
DB_ASSERT (top >= base + 1);
410
standard_function (info);
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);
420
push_symbol_value (NO_SYMBOL);
424
DB_ASSERT (top >= base + 1);
425
DB_ASSERT (base + info < top);
426
value_stack[base + info] = value_stack[--top];
430
DB_ASSERT (top >= base + 1);
431
DB_ASSERT (base + info < top);
432
insert_value (1, value_stack[base + info]);
434
value_stack[base + info] = value_stack[--top];
438
DB_ASSERT (top >= base + 1);
439
DB_ASSERT (base + info < top);
440
insert_value (1, value_stack[base + info]);
442
value_stack[base + info] = value_stack[--top];
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];
454
DB_ASSERT (top >= base + 1);
455
DB_ASSERT (base + info < top);
456
insert_value (1, value_stack[base + info]);
458
value_stack[base + info] = value_stack[--top];
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];
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];
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];
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];
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];
501
case INS_GET_1ST_ELEMENT:
502
DB_ASSERT (top >= base + 1);
503
get_first_element ();
507
DB_ASSERT (info >= 1 && base + info < top);
508
get_next_element (base + info);
512
DB_ASSERT (info < rule_sys->instrs_size);
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]))
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]))
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]))
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]))
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]))
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]))
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]))
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])))
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]))
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])))
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)
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)
614
case INS_JUMP_IF_YES:
618
DB_ASSERT (top >= base + 1);
619
DB_ASSERT (info < rule_sys->instrs_size);
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)
633
DB_ASSERT (top >= base + 1);
634
DB_ASSERT (info < rule_sys->instrs_size);
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)
648
DB_ASSERT (info < rule_sys->instrs_size);
649
if (backup_top >= BACKUP_STACK_SIZE)
650
error ("too many branches in a rule");
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);
668
DB_ASSERT (info < rule_sys->instrs_size);
669
if (backup_top >= BACKUP_STACK_SIZE)
670
error ("too many branches in a rule");
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);
683
case INS_JUMP_SUBRULE:
684
push_number_value (base - bottom);
685
push_number_value (pc);
687
pc = rule_sys->rules[info].first_instr;
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);
706
error ("internal (unknown instruction %d)", OPCODE (instruction));
710
if (terminate && backup_top > 0)
711
{ /* Load a previously saved rule-internal state and continue. */
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;
722
executing_rule = FALSE;
724
executed_rule_number = -1;
725
executed_rule_sys = NULL;
728
/*---------------------------------------------------------------------------*/
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. */
735
rule_header_t header;
736
rule_sys_t *rule_sys = new_mem (sizeof (rule_sys_t));
738
stream = open_stream (file_name, "rb");
740
read_vector (&header, sizeof (header), 1, stream, file_name);
742
check_header (&header.common_header, file_name,
743
RULE_FILE, RULE_CODE_VERSION);
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,
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,
758
rule_sys->instrs_size = header.instrs_size;
759
rule_sys->instrs = read_new_vector (sizeof (instr_t), header.instrs_size,
761
rule_sys->values_size = header.values_size;
762
rule_sys->values = read_new_vector (sizeof (cell_t), header.values_size,
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,
768
rule_sys->vars_size = header.vars_size;
769
rule_sys->vars = read_new_vector (sizeof (var_t), header.vars_size,
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,
775
rule_sys->strings_size = header.strings_size;
776
rule_sys->strings = read_new_vector (sizeof (char), header.strings_size,
779
close_stream (&stream, file_name);
784
/*---------------------------------------------------------------------------*/
786
GLOBAL void free_rule_sys (rule_sys_t **rule_sys)
787
/* Free all memory used by <*rule_sys>. */
789
if (*rule_sys != NULL)
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);
803
/* debug support functions ==================================================*/
805
GLOBAL value_t inspect_stack (int_t index)
806
/* Return S[index] or NULL if it is not defined. */
808
if (base + index >= top)
811
return value_stack[base + index];
814
/*---------------------------------------------------------------------------*/
816
GLOBAL void get_base_and_pc_indexes (int_t 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. */
825
*base_index = base - bottom;
829
*pc_index = value_to_int (value_stack[bottom + index - 1]);
830
*base_index = value_to_int (value_stack[bottom + index - 2]);
834
/*---------------------------------------------------------------------------*/
836
GLOBAL int_t inspect_stack_pointer (void)
837
/* Return value of rule stack pointer. */
842
/*---------------------------------------------------------------------------*/
844
GLOBAL int_t first_variable_index (rule_sys_t *rule_sys,
846
/* Return the stack index of the first variable that is visible
847
* when pc is at <instr_index> in <rule_sys>. */
850
int_t i, first_instr;
852
/* Find the rule/subrule we're in. */
855
for (i = 0; i < rule_sys->rules_size; i++)
857
rule_t *rule2 = rule_sys->rules + i;
859
if (rule2->first_instr <= instr_index
860
&& rule2->first_instr > first_instr)
863
first_instr = rule->first_instr;
867
DB_ASSERT (rule != NULL);
869
if (rule->type == SUBRULE)
870
return - (2 + rule->num_params);
875
/*---------------------------------------------------------------------------*/
877
GLOBAL void source_of_instr (rule_sys_t *rule_sys,
883
/* Set *<first_line>, *<last_line> and *<file_name> to appropriate values
884
* for the statement that has generated the instruction at <instr_index>. */
886
int_t lower, upper, middle;
887
src_line_t *src_line;
889
if (rule_sys->src_lines_size == 0
890
|| rule_sys->src_lines[0].instr > instr_index)
892
if (first_line != NULL)
894
if (last_line != NULL)
896
if (file_name != NULL)
898
if (rule_name != NULL)
903
/* Find the last src_line entry with <instr> <= <instr_index>. */
905
upper = rule_sys->src_lines_size - 1;
906
while (lower < upper)
908
middle = (lower + upper + 1) / 2;
909
src_line = rule_sys->src_lines + middle;
911
if (src_line->instr <= instr_index)
917
src_line = rule_sys->src_lines + lower;
919
if (first_line != NULL)
920
*first_line = src_line->line;
922
if (file_name != NULL)
924
if (src_line->file != -1)
925
*file_name = rule_sys->strings + src_line->file;
930
/* Find the last line of the statement. */
931
if (last_line != NULL)
936
} while (src_line < rule_sys->src_lines + rule_sys->src_lines_size
937
&& src_line->line == -1);
939
if (src_line < rule_sys->src_lines + rule_sys->src_lines_size)
940
*last_line = src_line->line - 1;
945
/* Find the rule of the statement */
946
if (rule_name != NULL)
954
for (i = 0; i < rule_sys->rules_size; i++)
956
rule_t *rule = rule_sys->rules + i;
958
if (rule->first_instr <= instr_index && rule->first_instr > first_instr)
961
first_instr = rule->first_instr;
964
*rule_name = rule_sys->strings + rule_sys->rules[rule_number].name;
968
/*---------------------------------------------------------------------------*/
970
LOCAL int_t local_variable_index (rule_sys_t *rule_sys,
973
/* Return the stack index of variable <var> at <instr_index>.
974
* Return -1 if it is not currently defined. */
976
int_t lower, upper, middle;
977
var_scope_t *var_scope;
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;
983
while (lower < upper)
985
middle = (lower + upper + 1) / 2;
986
var_scope = rule_sys->var_scopes + middle;
988
if (var_scope->first_instr <= instr_index)
994
/* <lower> is the index of the highest line
995
* with an instruction index not more than <instr_index>. */
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;
1009
/*---------------------------------------------------------------------------*/
1011
GLOBAL string_t variable_at_index (rule_sys_t *rule_sys,
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. */
1019
/* There is never a variable at stack index -2 or -1. */
1020
if (stack_index == -2 || stack_index == -1)
1023
/* For each variable name, test if it is the right one. */
1024
for (i = 0; i < rule_sys->vars_size; i++)
1026
var_t *var = rule_sys->vars + i;
1028
if (stack_index == local_variable_index (rule_sys, var, instr_index))
1029
return rule_sys->strings + var->name;
1035
/*---------------------------------------------------------------------------*/
1037
GLOBAL int_t variable_index (rule_sys_t *rule_sys,
1040
/* Return the stack index of variable <var_name> at <instr_index>. */
1042
/* Search for the right variable name (binary search). */
1044
int_t upper = rule_sys->vars_size - 1;
1046
while (lower <= upper)
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);
1054
else if (result > 0)
1057
return local_variable_index (rule_sys, var, instr_index);
1062
/*---------------------------------------------------------------------------*/
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. */
1068
text_t text = new_text ();
1071
add_to_text (text, "(end state)");
1074
bool_t name_has_been_printed;
1077
add_to_text (text, "rules ");
1079
rule = rule_sys->rule_sets + rule_set;
1082
name_has_been_printed = FALSE;
1085
if (name_has_been_printed)
1086
add_to_text (text, ", ");
1088
name_has_been_printed = TRUE;
1090
add_to_text (text, rule_sys->strings + rule_sys->rules[*rule++].name);
1096
add_to_text (text, " else ");
1101
return text_to_string (&text);
1104
/* end of file ==============================================================*/