|
Packit |
d394d9 |
/* Copyright (C) 1995 Bjoern Beutel. */
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Description. =============================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* This module contains the Malaga rule interpreter. */
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Includes. ================================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
#include <stdio.h>
|
|
Packit |
d394d9 |
#include <string.h>
|
|
Packit |
d394d9 |
#include <stdlib.h>
|
|
Packit |
d394d9 |
#include <time.h>
|
|
Packit |
d394d9 |
#include <math.h>
|
|
Packit |
d394d9 |
#include <setjmp.h>
|
|
Packit |
d394d9 |
#include <glib.h>
|
|
Packit |
d394d9 |
#include "basic.h"
|
|
Packit |
d394d9 |
#include "pools.h"
|
|
Packit |
d394d9 |
#include "values.h"
|
|
Packit |
d394d9 |
#include "symbols.h"
|
|
Packit |
d394d9 |
#include "patterns.h"
|
|
Packit |
d394d9 |
#include "files.h"
|
|
Packit |
d394d9 |
#include "malaga_files.h"
|
|
Packit |
d394d9 |
#include "rule_type.h"
|
|
Packit |
d394d9 |
#include "hangul.h"
|
|
Packit |
d394d9 |
#include "rules.h"
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Types. ===================================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
typedef struct /* Used to hold the value for a "switch". */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
list_node_t *next;
|
|
Packit |
d394d9 |
symbol_t key;
|
|
Packit |
d394d9 |
value_t value;
|
|
Packit |
d394d9 |
} switch_node_t;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
typedef struct
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
list_node_t *next;
|
|
Packit |
d394d9 |
int_t pc;
|
|
Packit |
d394d9 |
int_t nested_subrules;
|
|
Packit |
d394d9 |
int_t base;
|
|
Packit |
d394d9 |
int_t bottom;
|
|
Packit |
d394d9 |
} path_node_t;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Global variables. ========================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
void (*add_end_state)( value_t feat );
|
|
Packit |
d394d9 |
void (*add_running_state)( value_t feat, int_t rule_set );
|
|
Packit |
d394d9 |
void (*add_allo)( string_t surf, value_t feat );
|
|
Packit |
d394d9 |
void (*debug_rule)( bool_t interrupt );
|
|
Packit |
d394d9 |
void (*transmit)( void );
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
rule_sys_t *executed_rule_sys;
|
|
Packit |
d394d9 |
int_t executed_rule_number = -1;
|
|
Packit |
d394d9 |
int_t pc = -1; /* Current instruction index. */
|
|
Packit |
d394d9 |
int_t base; /* Current frame base. */
|
|
Packit |
d394d9 |
int_t nested_subrules; /* Current nesting level. */
|
|
Packit |
d394d9 |
int_t path_count; /* Current number of alternative paths. */
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
rule_sys_t *debug_rule_sys;
|
|
Packit |
d394d9 |
bool_t rule_successful;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Variables. ===============================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static int_t bottom; /* Index of first stack element used in this branch. */
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static list_t path_list; /* List of nodes for alternative paths. */
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static list_t switch_list; /* The list of switches. */
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static switch_node_t *current_switch;
|
|
Packit |
d394d9 |
/* Needed for "get_first_switch" and "get_next_switch". */
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Functions. ===============================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
void
|
|
Packit |
d394d9 |
set_switch( symbol_t key, value_t value )
|
|
Packit |
d394d9 |
/* Set the switch KEY to VALUE. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
switch_node_t *node;
|
|
Packit |
d394d9 |
switch_node_t *pre; /* predecessor node */
|
|
Packit |
d394d9 |
string_t name = get_symbol_name( key );
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
pre = NULL;
|
|
Packit |
d394d9 |
FOREACH( node, switch_list )
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
if (strcmp_no_case( name, get_symbol_name( node->key ) ) <= 0)
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
pre = node;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
if (node != NULL && key == node->key)
|
|
Packit |
d394d9 |
free_mem( &node->value );
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
node = new_mem( sizeof( switch_node_t ) );
|
|
Packit |
d394d9 |
node->key = key;
|
|
Packit |
d394d9 |
insert_node( &switch_list, (list_node_t *) node, (list_node_t *) pre );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
node->value = new_value( value );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
value_t
|
|
Packit |
d394d9 |
get_switch( symbol_t key )
|
|
Packit |
d394d9 |
/* Return the value of the switch KEY.
|
|
Packit |
d394d9 |
* Report an error if this switch doesn't exist. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
switch_node_t *switch_node;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
FOREACH( switch_node, switch_list )
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
if (switch_node->key == key)
|
|
Packit |
d394d9 |
return switch_node->value;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
complain( "Switch \"%s\" is not defined.", get_symbol_name( key ) );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
void
|
|
Packit |
d394d9 |
get_first_switch( value_t *value, symbol_t *key )
|
|
Packit |
d394d9 |
/* Return the first switch in *VALUE and its key in *KEY.
|
|
Packit |
d394d9 |
* If there is no switch, *VALUE is NULL. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
current_switch = (switch_node_t *) switch_list.first;
|
|
Packit |
d394d9 |
get_next_switch( value, key );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
void
|
|
Packit |
d394d9 |
get_next_switch( value_t *value, symbol_t *key )
|
|
Packit |
d394d9 |
/* Return the value of the next switch in *VALUE and its key in *KEY.
|
|
Packit |
d394d9 |
* If there is no more switch, *VALUE is NULL. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
if (current_switch == NULL)
|
|
Packit |
d394d9 |
*value = NULL;
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
*key = current_switch->key;
|
|
Packit |
d394d9 |
*value = current_switch->value;
|
|
Packit |
d394d9 |
current_switch = (switch_node_t *) current_switch->next;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
void
|
|
Packit |
d394d9 |
free_switches( void )
|
|
Packit |
d394d9 |
/* Free all switches. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
switch_node_t *my_switch;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
FOREACH_FREE( my_switch, switch_list )
|
|
Packit |
d394d9 |
free_mem( &my_switch->value );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Rule execution. ==========================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static void
|
|
Packit |
d394d9 |
standard_function( int_t function )
|
|
Packit |
d394d9 |
/* Stack effect: VALUE -> NEW_VALUE.
|
|
Packit |
d394d9 |
* Perform function FUNCTION on VALUE yielding NEW_VALUE. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
char_t *buffer;
|
|
Packit |
d394d9 |
string_t string;
|
|
Packit |
d394d9 |
int_t start, end, len;
|
|
Packit |
d394d9 |
gunichar code;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
switch (function)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
case FUNC_TO_ATOMS:
|
|
Packit |
d394d9 |
push_value( get_atoms( value_to_symbol( value_stack[ --top ] ) ) );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case FUNC_TO_MULTI:
|
|
Packit |
d394d9 |
push_symbol_value( find_multi_symbol( value_stack[ --top ] ) );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case FUNC_TO_SET:
|
|
Packit |
d394d9 |
convert_list_to_set();
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case FUNC_IS_CAPITAL:
|
|
Packit |
d394d9 |
code = g_utf8_get_char( value_to_string( value_stack[ --top ] ) );
|
|
Packit |
d394d9 |
if (g_unichar_tolower( code ) != code)
|
|
Packit |
d394d9 |
push_symbol_value( YES_SYMBOL );
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
push_symbol_value( NO_SYMBOL );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case FUNC_GET_SWITCH:
|
|
Packit |
d394d9 |
push_value( get_switch( value_to_symbol( value_stack[ --top ] ) ) );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case FUNC_GET_LENGTH:
|
|
Packit |
d394d9 |
if (get_value_type( value_stack[ top - 1 ] ) == STRING_SYMBOL)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
push_number_value(
|
|
Packit |
d394d9 |
g_utf8_strlen( value_to_string( value_stack[ --top ] ), -1 ) );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
push_number_value( get_list_length( value_stack[ --top ] ) );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case FUNC_GET_VALUE_TYPE:
|
|
Packit |
d394d9 |
push_symbol_value( get_value_type( value_stack[ --top ] ) );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case FUNC_GET_VALUE_STRING:
|
|
Packit |
d394d9 |
buffer = value_to_readable( value_stack[ --top ], TRUE, -1 );
|
|
Packit |
d394d9 |
encode_hangul( &buffer );
|
|
Packit |
d394d9 |
push_string_value( buffer, NULL );
|
|
Packit |
d394d9 |
free_mem( &buffer );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case FUNC_TRANSMIT:
|
|
Packit |
d394d9 |
if (transmit == NULL)
|
|
Packit |
d394d9 |
complain( "No transmit function available." );
|
|
Packit |
d394d9 |
transmit();
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case FUNC_FLOOR:
|
|
Packit |
d394d9 |
push_number_value( floor( value_to_double( value_stack[ --top ] ) ) );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case FUNC_SUBSTRING:
|
|
Packit |
d394d9 |
string = value_to_string( value_stack[ top - 3 ] );
|
|
Packit |
d394d9 |
start = value_to_int( value_stack[ top - 2 ] );
|
|
Packit |
d394d9 |
if (value_stack[ top - 1 ] == NULL)
|
|
Packit |
d394d9 |
end = start;
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
end = value_to_int( value_stack[ top - 1 ] );
|
|
Packit |
d394d9 |
len = g_utf8_strlen( string, -1 );
|
|
Packit |
d394d9 |
if (start < 0)
|
|
Packit |
d394d9 |
start += len + 1;
|
|
Packit |
d394d9 |
if (end < 0)
|
|
Packit |
d394d9 |
end += len + 1;
|
|
Packit |
d394d9 |
if (end < start)
|
|
Packit |
d394d9 |
push_string_value( "", NULL );
|
|
Packit |
d394d9 |
else if (start <= 0 || end > len)
|
|
Packit |
d394d9 |
complain( "Substring indexes out of bounds." );
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
push_string_value( g_utf8_offset_to_pointer( string, start - 1 ),
|
|
Packit |
d394d9 |
g_utf8_offset_to_pointer( string, end ) );
|
|
Packit |
d394d9 |
value_stack[ top - 4 ] = value_stack[ top - 1 ];
|
|
Packit |
d394d9 |
top -= 3;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
default:
|
|
Packit |
d394d9 |
complain( "Internal error." );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
void
|
|
Packit |
d394d9 |
execute_rule( rule_sys_t *rule_sys, int_t rule_number )
|
|
Packit |
d394d9 |
/* Execute rule RULE_NUMBER in the rule system RULE_SYS.
|
|
Packit |
d394d9 |
* Any parameters must be on the value stack. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
static symbol_t nil = NIL_SYMBOL; /* The "nil" symbol. */
|
|
Packit |
d394d9 |
bool_t terminate; /* Shall we terminate the current rule internal path? */
|
|
Packit |
d394d9 |
int_t i, info, new_pc, old_top, old_base, line;
|
|
Packit |
d394d9 |
instr_t instruction;
|
|
Packit |
d394d9 |
symbol_t symbol;
|
|
Packit |
d394d9 |
path_node_t *path;
|
|
Packit |
d394d9 |
string_t file;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Initialise the value stack. */
|
|
Packit |
d394d9 |
top = rule_sys->rules[ rule_number ].param_count;
|
|
Packit |
d394d9 |
base = bottom = 0;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Reset nesting and alternative paths. */
|
|
Packit |
d394d9 |
nested_subrules = path_count = 0;
|
|
Packit |
d394d9 |
while (path_list.first != NULL)
|
|
Packit |
d394d9 |
free_first_node( &path_list );
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Copy RULE_SYS and RULE_NUMBER for debugger and error messages. */
|
|
Packit |
d394d9 |
executed_rule_sys = rule_sys;
|
|
Packit |
d394d9 |
executed_rule_number = rule_number;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
pc = rule_sys->rules[ rule_number ].first_instr;
|
|
Packit |
d394d9 |
TRY
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
rule_successful = FALSE;
|
|
Packit |
d394d9 |
terminate = FALSE;
|
|
Packit |
d394d9 |
while (! terminate)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
if (user_break_requested)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
source_of_instr( rule_sys, pc, NULL, &file, NULL );
|
|
Packit |
d394d9 |
if (file != NULL)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
if (debug_rule_sys == rule_sys)
|
|
Packit |
d394d9 |
debug_rule( TRUE );
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
complain( "User break." );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
else if (debug_rule_sys == rule_sys)
|
|
Packit |
d394d9 |
debug_rule( FALSE );
|
|
Packit |
d394d9 |
instruction = rule_sys->instrs[ pc ];
|
|
Packit |
d394d9 |
new_pc = pc + 1;
|
|
Packit |
d394d9 |
info = INSTR_INFO( instruction );
|
|
Packit |
d394d9 |
switch (OPCODE( instruction ) )
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
case INS_SYSTEM_ERROR:
|
|
Packit |
d394d9 |
switch (info)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
case ASSERTION_ERROR:
|
|
Packit |
d394d9 |
complain( "Assertion failed." );
|
|
Packit |
d394d9 |
case NO_RETURN_ERROR:
|
|
Packit |
d394d9 |
complain( "Missing return statement." );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
case INS_ERROR:
|
|
Packit |
d394d9 |
complain( "%s", value_to_string( value_stack[ --top ] ) );
|
|
Packit |
d394d9 |
case INS_TERMINATE:
|
|
Packit |
d394d9 |
terminate = TRUE;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_NOP:
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_TERMINATE_IF_NULL:
|
|
Packit |
d394d9 |
if (value_stack[ --top ] == NULL)
|
|
Packit |
d394d9 |
terminate = TRUE;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_ADD_END_STATE:
|
|
Packit |
d394d9 |
add_end_state( value_stack[ --top ] );
|
|
Packit |
d394d9 |
rule_successful = TRUE;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_ADD_STATE:
|
|
Packit |
d394d9 |
add_running_state( value_stack[ --top ], info );
|
|
Packit |
d394d9 |
rule_successful = TRUE;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_ADD_ALLO:
|
|
Packit |
d394d9 |
add_allo( value_to_string( value_stack[ top - 2 ] ),
|
|
Packit |
d394d9 |
value_stack[ top - 1] );
|
|
Packit |
d394d9 |
top -= 2;
|
|
Packit |
d394d9 |
rule_successful = TRUE;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_ACCEPT:
|
|
Packit |
d394d9 |
path_count = 0;
|
|
Packit |
d394d9 |
while (path_list.first != NULL)
|
|
Packit |
d394d9 |
free_first_node( &path_list );
|
|
Packit |
d394d9 |
terminate = TRUE;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_PUSH_NULL:
|
|
Packit |
d394d9 |
for (i = 0; i < info; i++)
|
|
Packit |
d394d9 |
push_value( NULL );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_PUSH_VAR:
|
|
Packit |
d394d9 |
push_value( value_stack[ base + info ] );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_PUSH_CONST:
|
|
Packit |
d394d9 |
push_value( rule_sys->values + info );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_PUSH_SYMBOL:
|
|
Packit |
d394d9 |
push_symbol_value( info );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_PUSH_PATTERN_VAR:
|
|
Packit |
d394d9 |
push_string_value( pattern_var[ info ], NULL );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_POP:
|
|
Packit |
d394d9 |
top -= info;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_POP_TO:
|
|
Packit |
d394d9 |
top = base + info;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_BUILD_LIST:
|
|
Packit |
d394d9 |
build_list( info );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_BUILD_RECORD:
|
|
Packit |
d394d9 |
build_record( info );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_BUILD_PATH:
|
|
Packit |
d394d9 |
build_path( info );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_DOT_OPERATION:
|
|
Packit |
d394d9 |
dot_operation();
|
|
Packit |
d394d9 |
if (value_stack[ top - 1 ] == NULL)
|
|
Packit |
d394d9 |
value_stack[ top - 1 ] = &nil;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_PLUS_OPERATION:
|
|
Packit |
d394d9 |
plus_operation();
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_MINUS_OPERATION:
|
|
Packit |
d394d9 |
minus_operation();
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_ASTERISK_OPERATION:
|
|
Packit |
d394d9 |
asterisk_operation();
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_SLASH_OPERATION:
|
|
Packit |
d394d9 |
slash_operation();
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_UNARY_MINUS_OP:
|
|
Packit |
d394d9 |
unary_minus_operation();
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_GET_ATTRIBUTE:
|
|
Packit |
d394d9 |
value_stack[ top - 1 ] = get_attribute( value_stack[ top - 1 ],
|
|
Packit |
d394d9 |
(symbol_t) info );
|
|
Packit |
d394d9 |
if (value_stack[ top - 1 ] == NULL)
|
|
Packit |
d394d9 |
value_stack[ top - 1 ] = &nil;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_REMOVE_ATTRIBUTE:
|
|
Packit |
d394d9 |
remove_attribute( (symbol_t) info );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_STD_FUNCTION:
|
|
Packit |
d394d9 |
standard_function( info );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_MATCH:
|
|
Packit |
d394d9 |
if (match_pattern( value_to_string( value_stack[ --top ] ),
|
|
Packit |
d394d9 |
rule_sys->strings + info ))
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
push_symbol_value( YES_SYMBOL );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
push_symbol_value( NO_SYMBOL );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_SET_VAR:
|
|
Packit |
d394d9 |
value_stack[ base + info ] = value_stack[ --top ];
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_PLUS_VAR:
|
|
Packit |
d394d9 |
insert_value( 1, value_stack[ base + info ] );
|
|
Packit |
d394d9 |
plus_operation();
|
|
Packit |
d394d9 |
value_stack[ base + info ] = value_stack[ --top ];
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_MINUS_VAR:
|
|
Packit |
d394d9 |
insert_value( 1, value_stack[ base + info ]);
|
|
Packit |
d394d9 |
minus_operation();
|
|
Packit |
d394d9 |
value_stack[ base + info ] = value_stack[ --top ];
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_ASTERISK_VAR:
|
|
Packit |
d394d9 |
insert_value( 1, value_stack[ base + info ] );
|
|
Packit |
d394d9 |
asterisk_operation();
|
|
Packit |
d394d9 |
value_stack[ base + info ] = value_stack[ --top ];
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_SLASH_VAR:
|
|
Packit |
d394d9 |
insert_value( 1, value_stack[ base + info ] );
|
|
Packit |
d394d9 |
slash_operation();
|
|
Packit |
d394d9 |
value_stack[ base + info ] = value_stack[ --top ];
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_SET_VAR_PATH:
|
|
Packit |
d394d9 |
insert_value( 2, value_stack[ base + info ] );
|
|
Packit |
d394d9 |
modify_value_part( right_value );
|
|
Packit |
d394d9 |
value_stack[ base + info ] = value_stack[ --top ];
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_PLUS_VAR_PATH:
|
|
Packit |
d394d9 |
insert_value( 2, value_stack[ base + info ] );
|
|
Packit |
d394d9 |
modify_value_part( plus_operation );
|
|
Packit |
d394d9 |
value_stack[ base + info ] = value_stack[ --top ];
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_MINUS_VAR_PATH:
|
|
Packit |
d394d9 |
insert_value( 2, value_stack[ base + info ] );
|
|
Packit |
d394d9 |
modify_value_part( minus_operation );
|
|
Packit |
d394d9 |
value_stack[ base + info ] = value_stack[ --top ];
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_ASTERISK_VAR_PATH:
|
|
Packit |
d394d9 |
insert_value( 2, value_stack[ base + info ] );
|
|
Packit |
d394d9 |
modify_value_part( asterisk_operation );
|
|
Packit |
d394d9 |
value_stack[ base + info ] = value_stack[ --top ];
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_SLASH_VAR_PATH:
|
|
Packit |
d394d9 |
insert_value( 2, value_stack[ base + info ] );
|
|
Packit |
d394d9 |
modify_value_part( slash_operation );
|
|
Packit |
d394d9 |
value_stack[ base + info ] = value_stack[ --top ];
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_DECOMPOSE_LIST:
|
|
Packit |
d394d9 |
if (info != decompose_list())
|
|
Packit |
d394d9 |
complain( "List doesn't contain %d elements.", info );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_GET_1ST_ELEMENT:
|
|
Packit |
d394d9 |
get_first_element();
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_ITERATE:
|
|
Packit |
d394d9 |
get_next_element( base + info );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP:
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_EQUAL:
|
|
Packit |
d394d9 |
if (values_equal( value_stack[top - 2], value_stack[top - 1] ))
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
top -= 2;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_NOT_EQUAL:
|
|
Packit |
d394d9 |
if (! values_equal( value_stack[top - 2], value_stack[top - 1] ))
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
top -= 2;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_CONGR:
|
|
Packit |
d394d9 |
if (values_congruent( value_stack[top - 2], value_stack[top - 1] ))
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
top -= 2;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_NOT_CONGR:
|
|
Packit |
d394d9 |
if (! values_congruent( value_stack[top - 2], value_stack[top - 1] ))
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
top -= 2;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_IN:
|
|
Packit |
d394d9 |
if (value_in_value( value_stack[top - 2], value_stack[top - 1] ))
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
top -= 2;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_NOT_IN:
|
|
Packit |
d394d9 |
if (! value_in_value( value_stack[top - 2], value_stack[top - 1] ))
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
top -= 2;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_LESS:
|
|
Packit |
d394d9 |
if (value_to_double( value_stack[top - 2] )
|
|
Packit |
d394d9 |
< value_to_double( value_stack[top - 1] ))
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
top -= 2;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_NOT_LESS:
|
|
Packit |
d394d9 |
if (! (value_to_double( value_stack[top - 2] )
|
|
Packit |
d394d9 |
< value_to_double( value_stack[top - 1] )))
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
top -= 2;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_GREATER:
|
|
Packit |
d394d9 |
if (value_to_double( value_stack[top - 2] )
|
|
Packit |
d394d9 |
> value_to_double( value_stack[top - 1] ))
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
top -= 2;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_NOT_GREATER:
|
|
Packit |
d394d9 |
if (! (value_to_double( value_stack[top - 2] )
|
|
Packit |
d394d9 |
> value_to_double( value_stack[top - 1] )))
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
top -= 2;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_NULL:
|
|
Packit |
d394d9 |
if (value_stack[ --top ] == NULL)
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_NOT_NULL:
|
|
Packit |
d394d9 |
if (value_stack[ --top ] != NULL)
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_YES:
|
|
Packit |
d394d9 |
symbol = value_to_symbol( value_stack[ --top ] );
|
|
Packit |
d394d9 |
if (symbol != YES_SYMBOL && symbol != NO_SYMBOL)
|
|
Packit |
d394d9 |
complain( "Boolean value expected." );
|
|
Packit |
d394d9 |
if (symbol == YES_SYMBOL)
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_IF_NO:
|
|
Packit |
d394d9 |
symbol = value_to_symbol( value_stack[ --top ] );
|
|
Packit |
d394d9 |
if (symbol != YES_SYMBOL && symbol != NO_SYMBOL)
|
|
Packit |
d394d9 |
complain( "Boolean value expected." );
|
|
Packit |
d394d9 |
if (symbol == NO_SYMBOL)
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_NOW:
|
|
Packit |
d394d9 |
old_top = top;
|
|
Packit |
d394d9 |
path = new_node( &path_list, sizeof( path_node_t ), LIST_START );
|
|
Packit |
d394d9 |
path->pc = new_pc;
|
|
Packit |
d394d9 |
path->nested_subrules = nested_subrules;
|
|
Packit |
d394d9 |
path->base = base;
|
|
Packit |
d394d9 |
path->bottom = bottom;
|
|
Packit |
d394d9 |
while (bottom < old_top)
|
|
Packit |
d394d9 |
push_value( value_stack[ bottom++ ] );
|
|
Packit |
d394d9 |
base += (top - old_top);
|
|
Packit |
d394d9 |
path_count++;
|
|
Packit |
d394d9 |
new_pc = info;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_LATER:
|
|
Packit |
d394d9 |
old_top = top;
|
|
Packit |
d394d9 |
path = new_node( &path_list, sizeof( path_node_t ), LIST_START );
|
|
Packit |
d394d9 |
path->pc = info;
|
|
Packit |
d394d9 |
path->nested_subrules = nested_subrules;
|
|
Packit |
d394d9 |
path->base = base;
|
|
Packit |
d394d9 |
path->bottom = bottom;
|
|
Packit |
d394d9 |
while (bottom < old_top)
|
|
Packit |
d394d9 |
push_value( value_stack[ bottom++ ] );
|
|
Packit |
d394d9 |
base += (top - old_top);
|
|
Packit |
d394d9 |
path_count++;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_JUMP_SUBRULE:
|
|
Packit |
d394d9 |
push_number_value( base - bottom );
|
|
Packit |
d394d9 |
push_number_value( new_pc );
|
|
Packit |
d394d9 |
base = top;
|
|
Packit |
d394d9 |
new_pc = rule_sys->rules[ info ].first_instr;
|
|
Packit |
d394d9 |
nested_subrules++;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
case INS_RETURN:
|
|
Packit |
d394d9 |
old_base = bottom + value_to_int( value_stack[ base - 2 ] );
|
|
Packit |
d394d9 |
new_pc = value_to_int( value_stack[ base - 1 ] );
|
|
Packit |
d394d9 |
value_stack[ base - info - 2 ] = value_stack[ top - 1 ]; /* Result. */
|
|
Packit |
d394d9 |
top = base - (info + 1);
|
|
Packit |
d394d9 |
base = old_base;
|
|
Packit |
d394d9 |
nested_subrules--;
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
default:
|
|
Packit |
d394d9 |
complain( "Internal error." );
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
if (! terminate)
|
|
Packit |
d394d9 |
pc = new_pc;
|
|
Packit |
d394d9 |
else if (path_list.first != NULL)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
/* Load a previously saved rule-internal path and continue. */
|
|
Packit |
d394d9 |
path_count--;
|
|
Packit |
d394d9 |
path = (path_node_t *) path_list.first;
|
|
Packit |
d394d9 |
top = bottom;
|
|
Packit |
d394d9 |
base = path->base;
|
|
Packit |
d394d9 |
bottom = path->bottom;
|
|
Packit |
d394d9 |
pc = path->pc;
|
|
Packit |
d394d9 |
nested_subrules = path->nested_subrules;
|
|
Packit |
d394d9 |
free_first_node( &path_list );
|
|
Packit |
d394d9 |
terminate = FALSE;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
IF_ERROR
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
source_of_instr( executed_rule_sys, pc, &line, &file, NULL );
|
|
Packit |
d394d9 |
print_text( error_text, " (\"%s\", line %d)", name_in_path( file ), line );
|
|
Packit |
d394d9 |
if (in_emacs_malaga_mode)
|
|
Packit |
d394d9 |
printf( "SHOW \"%s\":%d:0\n", file, line );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
END_TRY;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
pc = -1;
|
|
Packit |
d394d9 |
executed_rule_number = -1;
|
|
Packit |
d394d9 |
executed_rule_sys = NULL;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
rule_sys_t *
|
|
Packit |
d394d9 |
read_rule_sys( string_t file_name )
|
|
Packit |
d394d9 |
/* Read rule system from file FILE_NAME.
|
|
Packit |
d394d9 |
* A symbol file must have already been loaded. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
FILE *stream;
|
|
Packit |
d394d9 |
rule_header_t header;
|
|
Packit |
d394d9 |
rule_sys_t *rule_sys;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
stream = open_stream( file_name, "rb" );
|
|
Packit |
d394d9 |
read_vector( &header, sizeof( header ), 1, stream, file_name );
|
|
Packit |
d394d9 |
check_header( &header.common_header, file_name,
|
|
Packit |
d394d9 |
RULE_FILE, MIN_RULE_CODE_VERSION, RULE_CODE_VERSION );
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
rule_sys = new_mem( sizeof( rule_sys_t ) );
|
|
Packit |
d394d9 |
rule_sys->initial_rule_set = header.initial_rule_set;
|
|
Packit |
d394d9 |
rule_sys->initial_feat = header.initial_feat;
|
|
Packit |
d394d9 |
rule_sys->robust_rule = header.robust_rule;
|
|
Packit |
d394d9 |
rule_sys->allo_rule = header.allo_rule;
|
|
Packit |
d394d9 |
rule_sys->pruning_rule = header.pruning_rule;
|
|
Packit |
d394d9 |
rule_sys->input_filter = header.input_filter;
|
|
Packit |
d394d9 |
rule_sys->output_filter = header.output_filter;
|
|
Packit |
d394d9 |
rule_sys->rule_count = header.rule_count;
|
|
Packit |
d394d9 |
rule_sys->rules = read_new_vector( sizeof( rule_t ), header.rule_count,
|
|
Packit |
d394d9 |
stream, file_name );
|
|
Packit |
d394d9 |
rule_sys->rule_sets_size = header.rule_sets_size;
|
|
Packit |
d394d9 |
rule_sys->rule_sets = read_new_vector( sizeof( int_t ),
|
|
Packit |
d394d9 |
header.rule_sets_size,
|
|
Packit |
d394d9 |
stream, file_name );
|
|
Packit |
d394d9 |
rule_sys->instr_count = header.instr_count;
|
|
Packit |
d394d9 |
rule_sys->instrs = read_new_vector( sizeof( instr_t ), header.instr_count,
|
|
Packit |
d394d9 |
stream, file_name );
|
|
Packit |
d394d9 |
rule_sys->values_size = header.values_size;
|
|
Packit |
d394d9 |
rule_sys->values = read_new_vector( sizeof( cell_t ), header.values_size,
|
|
Packit |
d394d9 |
stream, file_name );
|
|
Packit |
d394d9 |
rule_sys->src_line_count = header.src_line_count;
|
|
Packit |
d394d9 |
rule_sys->src_lines = read_new_vector( sizeof( src_line_t ),
|
|
Packit |
d394d9 |
header.src_line_count,
|
|
Packit |
d394d9 |
stream, file_name );
|
|
Packit |
d394d9 |
rule_sys->var_count = header.var_count;
|
|
Packit |
d394d9 |
rule_sys->vars = read_new_vector( sizeof( var_t ), header.var_count,
|
|
Packit |
d394d9 |
stream, file_name );
|
|
Packit |
d394d9 |
rule_sys->var_scope_count = header.var_scope_count;
|
|
Packit |
d394d9 |
rule_sys->var_scopes = read_new_vector( sizeof( var_scope_t ),
|
|
Packit |
d394d9 |
header.var_scope_count,
|
|
Packit |
d394d9 |
stream, file_name );
|
|
Packit |
d394d9 |
rule_sys->constant_count = header.constant_count;
|
|
Packit |
d394d9 |
rule_sys->constants = read_new_vector( sizeof( constant_t ),
|
|
Packit |
d394d9 |
header.constant_count,
|
|
Packit |
d394d9 |
stream, file_name );
|
|
Packit |
d394d9 |
rule_sys->strings_size = header.strings_size;
|
|
Packit |
d394d9 |
rule_sys->strings = read_new_vector( sizeof( char_t ), header.strings_size,
|
|
Packit |
d394d9 |
stream, file_name );
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
close_stream( &stream, file_name );
|
|
Packit |
d394d9 |
return rule_sys;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
void
|
|
Packit |
d394d9 |
free_rule_sys( rule_sys_t **rule_sys )
|
|
Packit |
d394d9 |
/* Free all memory used by *RULE_SYS. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
if (*rule_sys != NULL)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
free_mem( &(*rule_sys)->rules );
|
|
Packit |
d394d9 |
free_mem( &(*rule_sys)->rule_sets );
|
|
Packit |
d394d9 |
free_mem( &(*rule_sys)->instrs );
|
|
Packit |
d394d9 |
free_mem( &(*rule_sys)->values );
|
|
Packit |
d394d9 |
free_mem( &(*rule_sys)->src_lines );
|
|
Packit |
d394d9 |
free_mem( &(*rule_sys)->vars );
|
|
Packit |
d394d9 |
free_mem( &(*rule_sys)->var_scopes );
|
|
Packit |
d394d9 |
free_mem( &(*rule_sys)->constants );
|
|
Packit |
d394d9 |
free_mem( &(*rule_sys)->strings );
|
|
Packit |
d394d9 |
free_mem( rule_sys );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Debug support functions. =================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
void
|
|
Packit |
d394d9 |
source_of_instr( rule_sys_t *rule_sys, int_t instr_index,
|
|
Packit |
d394d9 |
int_t *line, string_t *file_name, string_t *rule_name )
|
|
Packit |
d394d9 |
/* Set *LINE, *FILE_NAME and *RULE_NAME to appropriate values
|
|
Packit |
d394d9 |
* for the statement that has generated the instruction at INSTR_INDEX. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
int_t lower, upper, middle;
|
|
Packit |
d394d9 |
src_line_t *src_line;
|
|
Packit |
d394d9 |
int_t rule_number, i, first_instr;
|
|
Packit |
d394d9 |
rule_t *rule;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
if (rule_sys->src_line_count == 0
|
|
Packit |
d394d9 |
|| rule_sys->src_lines[0].instr > instr_index)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
if (line != NULL)
|
|
Packit |
d394d9 |
*line = -1;
|
|
Packit |
d394d9 |
if (file_name != NULL)
|
|
Packit |
d394d9 |
*file_name = NULL;
|
|
Packit |
d394d9 |
if (rule_name != NULL)
|
|
Packit |
d394d9 |
*rule_name = NULL;
|
|
Packit |
d394d9 |
return;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
/* Find the last SRC_LINE entry with INSTR <= INSTR_INDEX. */
|
|
Packit |
d394d9 |
lower = 0;
|
|
Packit |
d394d9 |
upper = rule_sys->src_line_count - 1;
|
|
Packit |
d394d9 |
while (lower < upper)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
middle = (lower + upper + 1) / 2;
|
|
Packit |
d394d9 |
src_line = rule_sys->src_lines + middle;
|
|
Packit |
d394d9 |
if (src_line->instr <= instr_index)
|
|
Packit |
d394d9 |
lower = middle;
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
upper = middle - 1;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
src_line = rule_sys->src_lines + lower;
|
|
Packit |
d394d9 |
if (line != NULL)
|
|
Packit |
d394d9 |
*line = src_line->line;
|
|
Packit |
d394d9 |
if (file_name != NULL)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
if (src_line->file != -1)
|
|
Packit |
d394d9 |
*file_name = rule_sys->strings + src_line->file;
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
*file_name = NULL;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Find the rule of the statement */
|
|
Packit |
d394d9 |
if (rule_name != NULL)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
rule_number = 0;
|
|
Packit |
d394d9 |
first_instr = -1;
|
|
Packit |
d394d9 |
for (i = 0; i < rule_sys->rule_count; i++)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
rule = rule_sys->rules + i;
|
|
Packit |
d394d9 |
if (rule->first_instr <= instr_index && rule->first_instr > first_instr)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
rule_number = i;
|
|
Packit |
d394d9 |
first_instr = rule->first_instr;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
*rule_name = rule_sys->strings + rule_sys->rules[ rule_number ].name;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
string_t
|
|
Packit |
d394d9 |
rule_set_readable( rule_sys_t *rule_sys, int_t rule_set )
|
|
Packit |
d394d9 |
/* Return RULE_SET in RULE_SYS as a readable string.
|
|
Packit |
d394d9 |
* The string must be freed after use. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
text_t *text;
|
|
Packit |
d394d9 |
bool_t name_has_been_printed;
|
|
Packit |
d394d9 |
int_t *rule;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
text = new_text();
|
|
Packit |
d394d9 |
if (rule_set == -1)
|
|
Packit |
d394d9 |
add_to_text( text, "(end state)" );
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
add_to_text( text, "rules " );
|
|
Packit |
d394d9 |
rule = rule_sys->rule_sets + rule_set;
|
|
Packit |
d394d9 |
while (TRUE)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
name_has_been_printed = FALSE;
|
|
Packit |
d394d9 |
while (*rule >= 0)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
if (name_has_been_printed)
|
|
Packit |
d394d9 |
add_to_text( text, ", " );
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
name_has_been_printed = TRUE;
|
|
Packit |
d394d9 |
add_to_text( text,
|
|
Packit |
d394d9 |
rule_sys->strings + rule_sys->rules[ *rule++ ].name );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
if (*rule == -1)
|
|
Packit |
d394d9 |
break;
|
|
Packit |
d394d9 |
add_to_text( text, " else " );
|
|
Packit |
d394d9 |
rule++;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
return text_to_string( &text );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static int_t
|
|
Packit |
d394d9 |
first_variable_index( int_t instr_index )
|
|
Packit |
d394d9 |
/* Return the stack index of the first variable that is visible
|
|
Packit |
d394d9 |
* when PC is at INSTR_INDEX in RULE_SYS. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
rule_t *rule, *rule2;
|
|
Packit |
d394d9 |
int_t i, first_instr;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Find the rule/subrule we're in. */
|
|
Packit |
d394d9 |
rule = NULL;
|
|
Packit |
d394d9 |
first_instr = -1;
|
|
Packit |
d394d9 |
for (i = 0; i < executed_rule_sys->rule_count; i++)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
rule2 = executed_rule_sys->rules + i;
|
|
Packit |
d394d9 |
if (rule2->first_instr <= instr_index && rule2->first_instr > first_instr)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
rule = rule2;
|
|
Packit |
d394d9 |
first_instr = rule->first_instr;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
if (rule->type == SUBRULE)
|
|
Packit |
d394d9 |
return - (2 + rule->param_count);
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
return 0;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
int_t
|
|
Packit |
d394d9 |
get_frame_count( void )
|
|
Packit |
d394d9 |
/* Get the number of frames in the current path. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
int_t frame, count;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Count the number of frames. */
|
|
Packit |
d394d9 |
count = 1;
|
|
Packit |
d394d9 |
for (frame = base;
|
|
Packit |
d394d9 |
frame > bottom;
|
|
Packit |
d394d9 |
frame = bottom + value_to_int( value_stack[ frame - 2 ] ))
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
count++;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
return count;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
void
|
|
Packit |
d394d9 |
get_frame_info( int_t frame,
|
|
Packit |
d394d9 |
int_t *pc_index,
|
|
Packit |
d394d9 |
int_t *base_index,
|
|
Packit |
d394d9 |
int_t *first_var_index,
|
|
Packit |
d394d9 |
int_t *last_var_index )
|
|
Packit |
d394d9 |
/* Return *PC_INDEX, *BASE_INDEX, *FIRST_VAR_INDEX and *LAST_VAR_INDEX
|
|
Packit |
d394d9 |
* of the frame no. FRAME. Any result pointer may be NULL.
|
|
Packit |
d394d9 |
* Frame no. 0 is the current frame,
|
|
Packit |
d394d9 |
* frame no. "get_frame_count() - 1" is the outermost one. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
int_t first_var_idx, last_var_idx, base_idx, pc_idx;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
last_var_idx = top;
|
|
Packit |
d394d9 |
pc_idx = pc;
|
|
Packit |
d394d9 |
base_idx = base;
|
|
Packit |
d394d9 |
first_var_idx = base_idx + first_variable_index( pc_idx );
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Find the right frame. */
|
|
Packit |
d394d9 |
for (; frame > 0; frame--)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
last_var_idx = first_var_idx;
|
|
Packit |
d394d9 |
pc_idx = value_to_int( value_stack[ base_idx - 1 ] );
|
|
Packit |
d394d9 |
base_idx = bottom + value_to_int( value_stack[ base_idx - 2 ] );
|
|
Packit |
d394d9 |
first_var_idx = base_idx + first_variable_index( pc_idx );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
if (pc_index != NULL)
|
|
Packit |
d394d9 |
*pc_index = pc_idx;
|
|
Packit |
d394d9 |
if (base_index != NULL)
|
|
Packit |
d394d9 |
*base_index = base_idx;
|
|
Packit |
d394d9 |
if (first_var_index != NULL)
|
|
Packit |
d394d9 |
*first_var_index = first_var_idx;
|
|
Packit |
d394d9 |
if (last_var_index != NULL)
|
|
Packit |
d394d9 |
*last_var_index = last_var_idx;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static var_scope_t *
|
|
Packit |
d394d9 |
get_var_scope( rule_sys_t *rule_sys, var_t *var, int_t instr_index )
|
|
Packit |
d394d9 |
/* Return the stack index of variable VAR at INSTR_INDEX.
|
|
Packit |
d394d9 |
* Return -1 if it is not currently defined. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
int_t lower, upper, middle;
|
|
Packit |
d394d9 |
var_scope_t *var_scope;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Find last scope whose FIRST_INSTR is not higher than INSTR_INDEX. */
|
|
Packit |
d394d9 |
lower = var->first_scope;
|
|
Packit |
d394d9 |
upper = lower + var->scope_count - 1;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
while (lower < upper)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
middle = (lower + upper + 1) / 2;
|
|
Packit |
d394d9 |
var_scope = rule_sys->var_scopes + middle;
|
|
Packit |
d394d9 |
if (var_scope->first_instr <= instr_index)
|
|
Packit |
d394d9 |
lower = middle;
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
upper = middle - 1;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* LOWER is the index of the highest line
|
|
Packit |
d394d9 |
* with an instruction index not more than INSTR_INDEX. */
|
|
Packit |
d394d9 |
if (lower == upper) /* We found a scope. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
var_scope = rule_sys->var_scopes + lower;
|
|
Packit |
d394d9 |
if (instr_index >= var_scope->first_instr
|
|
Packit |
d394d9 |
&& instr_index <= var_scope->last_instr)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
return var_scope;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
return NULL;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
string_t
|
|
Packit |
d394d9 |
variable_at_index( rule_sys_t *rule_sys, int_t stack_index, int_t instr_index )
|
|
Packit |
d394d9 |
/* Return the name of the variable that is defined at STACK_INDEX
|
|
Packit |
d394d9 |
* when instruction INSTR_INDEX is executed or NULL if there is none. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
int_t i;
|
|
Packit |
d394d9 |
var_t *var;
|
|
Packit |
d394d9 |
var_scope_t *var_scope;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* There is never a variable at stack index -2 or -1. */
|
|
Packit |
d394d9 |
if (stack_index == -2 || stack_index == -1)
|
|
Packit |
d394d9 |
return NULL;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* For each variable name, test if it is the right one. */
|
|
Packit |
d394d9 |
for (i = 0; i < rule_sys->var_count; i++)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
var = rule_sys->vars + i;
|
|
Packit |
d394d9 |
var_scope = get_var_scope( rule_sys, var, instr_index );
|
|
Packit |
d394d9 |
if (var_scope != NULL && var_scope->stack_index == stack_index)
|
|
Packit |
d394d9 |
return rule_sys->strings + var->name;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
return NULL;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
var_scope_t *
|
|
Packit |
d394d9 |
get_var_scope_by_name( rule_sys_t *rule_sys,
|
|
Packit |
d394d9 |
string_t var_name,
|
|
Packit |
d394d9 |
int_t instr_index )
|
|
Packit |
d394d9 |
/* Return the scope of variable VAR_NAME at INSTR_INDEX. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
int_t lower, upper, middle, result;
|
|
Packit |
d394d9 |
var_t *var;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Search for the right variable name (binary search). */
|
|
Packit |
d394d9 |
lower = 0;
|
|
Packit |
d394d9 |
upper = rule_sys->var_count - 1;
|
|
Packit |
d394d9 |
while (lower <= upper)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
middle = (lower + upper) / 2;
|
|
Packit |
d394d9 |
var = rule_sys->vars + middle;
|
|
Packit |
d394d9 |
result = strcmp_no_case( var_name, rule_sys->strings + var->name );
|
|
Packit |
d394d9 |
if (result < 0)
|
|
Packit |
d394d9 |
upper = middle - 1;
|
|
Packit |
d394d9 |
else if (result > 0)
|
|
Packit |
d394d9 |
lower = middle + 1;
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
return get_var_scope( rule_sys, var, instr_index );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
return NULL;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
value_t
|
|
Packit |
d394d9 |
get_constant( rule_sys_t *rule_sys, string_t name )
|
|
Packit |
d394d9 |
/* Return the value of constant NAME in RULE_SYS.
|
|
Packit |
d394d9 |
* Return NULL if there is no such constant. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
int_t lower, upper, middle, result;
|
|
Packit |
d394d9 |
constant_t *constant;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Search for the right variable name (binary search). */
|
|
Packit |
d394d9 |
lower = 0;
|
|
Packit |
d394d9 |
upper = rule_sys->constant_count - 1;
|
|
Packit |
d394d9 |
while (lower <= upper)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
middle = (lower + upper) / 2;
|
|
Packit |
d394d9 |
constant = rule_sys->constants + middle;
|
|
Packit |
d394d9 |
result = strcmp_no_case( name, rule_sys->strings + constant->name );
|
|
Packit |
d394d9 |
if (result < 0)
|
|
Packit |
d394d9 |
upper = middle - 1;
|
|
Packit |
d394d9 |
else if (result > 0)
|
|
Packit |
d394d9 |
lower = middle + 1;
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
return rule_sys->values + constant->value;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
return NULL;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* End of file. =============================================================*/
|