/* Copyright (C) 1997 Bjoern Beutel. */
/* Description. =============================================================*/
/* Options for malaga and functions to start and terminate malaga. */
/* Includes. ================================================================*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include <time.h>
#include <glib.h>
#include "basic.h"
#include "pools.h"
#include "values.h"
#include "input.h"
#include "commands.h"
#include "options.h"
#include "rule_type.h"
#include "rules.h"
#include "files.h"
#include "analysis.h"
#include "cache.h"
#include "symbols.h"
#include "lexicon.h"
#include "transmit.h"
#include "display.h"
#include "scanner.h"
#include "patterns.h"
#include "hangul.h"
#include "malaga_lib.h"
/* Global variables. ========================================================*/
bool_t auto_tree; /* TRUE if tree is shown automatically. */
bool_t auto_result; /* TRUE if result is shown automatically. */
bool_t result_as_list; /* TRUE if results will be combined into a list. */
text_t *grammar_info; /* Information about grammar. */
string_t result_format, unknown_format, error_format;
/* Format strings for output. */
/* Variables. ===============================================================*/
static string_t morphology_file, syntax_file, lexicon_file;
static string_t symbol_file, extended_symbol_file;
static bool_t info_in_project_file;
/* Indicates whether we have read grammar info from the current project file.
* Used to insert empty lines between grammar infos from different project
* files. */
/* Functions. ===============================================================*/
static void
do_mor_pruning_option( string_t arguments )
/* Set minimum number of states needed to call the morphology pruning rule. */
{
if (*arguments == EOS)
printf( "mor-pruning: %d\n", mor_pruning_min );
else
{
if (rule_system[MORPHOLOGY]->pruning_rule == -1)
complain("No morphology pruning rule.");
mor_pruning_min = parse_int( &arguments );
parse_end( &arguments );
}
}
static command_t mor_pruning_option =
{
"mor-pruning", do_mor_pruning_option,
"Usage:\n"
" set mor-pruning 0 -- Turn off morphology pruning.\n"
" set mor-pruning N -- Call pruning rule for a minimum of N states.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_syn_pruning_option( string_t arguments )
/* Set minimum number of states needed to call the syntax pruning rule. */
{
if (*arguments == EOS)
printf( "syn-pruning: %d\n", syn_pruning_min );
else
{
if (rule_system[SYNTAX] == NULL || rule_system[SYNTAX]->pruning_rule == -1)
complain("No syntax pruning rule.");
syn_pruning_min = parse_int( &arguments );
parse_end( &arguments );
}
}
static command_t syn_pruning_option =
{
"syn-pruning", do_syn_pruning_option,
"Usage:\n"
" set syn-pruning 0 -- Turn off syntax pruning.\n"
" set syn-pruning N -- Call pruning rule for a minimum of N states.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_robust_rule_option( string_t arguments )
/* Enable/disable robust-rule. */
{
if (*arguments == EOS)
{
printf( "robust-rule: %s\n",
get_analysis_option( ROBUST_RULE_OPTION ) ? "yes" : "no" );
}
else
set_analysis_option( ROBUST_RULE_OPTION, parse_yes_no( &arguments ) );
parse_end( &arguments );
}
static command_t robust_rule_option =
{
"robust-rule robust", do_robust_rule_option,
"Usage:\n"
" set robust-rule yes -- Turn robust_rule on.\n"
" set robust-rule no -- Turn robust_rule off.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_mor_out_filter_option( string_t arguments )
/* Enable/disable morphology output filter. */
{
if (*arguments == EOS)
{
printf( "mor-out-filter: %s\n",
get_analysis_option( MOR_OUT_FILTER_OPTION ) ? "yes" : "no" );
}
else
set_analysis_option( MOR_OUT_FILTER_OPTION, parse_yes_no( &arguments ) );
parse_end( &arguments );
}
static command_t mor_out_filter_option =
{
"mor-out-filter mofil", do_mor_out_filter_option,
"Usage:\n"
" set mor-out-filter yes -- Turn morphology output filter on.\n"
" set mor-out-filter no -- Turn morphology output filter off.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_syn_out_filter_option( string_t arguments )
/* Enable/disable syntax output filter. */
{
if (*arguments == EOS)
{
printf( "syn-out-filter: %s\n",
get_analysis_option( SYN_OUT_FILTER_OPTION ) ? "yes" : "no" );
}
else
set_analysis_option( SYN_OUT_FILTER_OPTION, parse_yes_no( &arguments ) );
parse_end( &arguments );
}
static command_t syn_out_filter_option =
{
"syn-out-filter sofil", do_syn_out_filter_option,
"Usage:\n"
" set syn-out-filter yes -- Turn syntax output filter on.\n"
" set syn-out-filter no -- Turn syntax output filter off.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_syn_in_filter_option( string_t arguments )
/* Enable/disable syntax input filter. */
{
if (*arguments == EOS)
{
printf( "syn-in-filter: %s\n",
get_analysis_option( SYN_IN_FILTER_OPTION ) ? "yes" : "no" );
}
else
set_analysis_option( SYN_IN_FILTER_OPTION, parse_yes_no( &arguments ) );
parse_end( &arguments );
}
static command_t syn_in_filter_option =
{
"syn-in-filter sifil", do_syn_in_filter_option,
"Usage:\n"
" set syn-in-filter yes -- Turn syntax input filter on.\n"
" set syn-in-filter no -- Turn syntax input filter off.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_mor_incomplete_option( string_t arguments )
/* Enable/disable acceptance of incompletely parsed words. */
{
if (*arguments == EOS)
{
printf( "mor-incomplete: %s\n",
get_analysis_option( MOR_INCOMPLETE_OPTION ) ? "yes" : "no" );
}
else
set_analysis_option( MOR_INCOMPLETE_OPTION, parse_yes_no( &arguments ) );
parse_end( &arguments );
}
static command_t mor_incomplete_option =
{
"mor-incomplete", do_mor_incomplete_option,
"Usage:\n"
" set mor-incomplete yes -- "
"Accept words that have been incompletely parsed.\n"
" set mor-incomplete no -- "
"Only accept words that have been completely parsed.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_syn_incomplete_option( string_t arguments )
/* Enable/disable acceptance of incompletely parsed words. */
{
if (*arguments == EOS)
{
printf( "syn-incomplete: %s\n",
get_analysis_option( SYN_INCOMPLETE_OPTION ) ? "yes" : "no" );
}
else
set_analysis_option( SYN_INCOMPLETE_OPTION, parse_yes_no( &arguments ) );
parse_end( &arguments );
}
static command_t syn_incomplete_option =
{
"syn-incomplete", do_syn_incomplete_option,
"Usage:\n"
" set syn-incomplete yes -- "
"Accept sentences that have been incompletely parsed.\n"
" set syn-incomplete no -- "
"Only accept sentences that have been completely parsed.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_result_list_option( string_t arguments )
/* Enable/disable combination of all results into a single list. */
{
if (*arguments == EOS)
printf( "result-list: %s\n", result_as_list ? "yes" : "no" );
else
result_as_list = parse_yes_no( &arguments );
parse_end( &arguments );
}
static command_t result_list_option =
{
"result-list", do_result_list_option,
"Usage:\n"
" set result-list yes -- Combine results into a single list.\n"
" set result-list no -- Leave results unchanged.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_cache_size_option( string_t arguments )
/* Change the cache size. */
{
int_t size;
if (*arguments == EOS)
{
printf( "cache-size: %d (%d used)\n",
get_cache_maximum(), get_cache_size() );
}
else
{
size = parse_int( &arguments );
set_cache_size( size );
set_analysis_option( CACHE_OPTION, (size > 0) );
}
parse_end( &arguments );
}
static command_t cache_size_option =
{
"cache-size", do_cache_size_option,
"Usage: set cache-size SIZE -- Set cache size to SIZE.\n"
"If SIZE == 0, cache is switched off.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_auto_tree_option( string_t arguments )
/* Determine if tree is shown automatically. */
{
if (*arguments == EOS)
printf( "auto-tree: %s\n", auto_tree ? "yes" : "no" );
else
auto_tree = parse_yes_no( &arguments );
parse_end( &arguments );
}
static command_t auto_tree_option =
{
"auto-tree tree", do_auto_tree_option,
"Usage:\n"
" set auto-tree yes -- Show tree after analysis.\n"
" set auto-tree no -- Don't show tree after analysis.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_auto_result_option( string_t arguments )
/* Determine if result is shown automatically. */
{
if (*arguments == EOS)
printf( "auto-result: %s\n", auto_result ? "yes" : "no" );
else
auto_result = parse_yes_no( &arguments );
parse_end( &arguments );
}
static command_t auto_result_option =
{
"auto-result result output", do_auto_result_option,
"Usage:\n"
" set auto-result yes -- Show result after analysis.\n"
" set auto-result no -- Don't show result after analysis.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_error_format_option( string_t arguments )
/* Change analysis-error print format to ARGUMENTS. */
{
string_t format;
if (*arguments == EOS)
{
format = new_string_readable( error_format, NULL );
printf( "error-format: %s\n", format );
free_mem( &format );
}
else
{
format = parse_word( &arguments );
free_mem( &error_format );
error_format = format;
}
parse_end( &arguments );
}
static command_t error_format_option =
{
"error-format", do_error_format_option,
"Set the format in which to print analysis input that produced an error.\n"
"Usage: set error-format ERROR_FORMAT_STRING\n"
"The ERROR_FORMAT_STRING may contain the following special sequences:\n"
" %e -- Error message.\n"
" %l -- Input line number.\n"
" %n -- Number of analysis states.\n"
" %s -- Surface.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_result_format_option( string_t arguments )
/* Change analysis result format to ARGUMENTS. */
{
string_t format;
if (*arguments == EOS)
{
format = new_string_readable( result_format, NULL );
printf( "result-format: %s\n", format );
free_mem( &format );
}
else
{
format = parse_word( &arguments );
free_mem( &result_format );
result_format = format;
}
parse_end( &arguments );
}
static command_t result_format_option =
{
"result-format output-format", do_result_format_option,
"Describe the format in which analysis results will be printed.\n"
"Usage: set result-format RESULT_FORMAT_STRING\n"
"The RESULT_FORMAT_STRING may contain the following special sequences:\n"
" %f -- Result feature structure.\n"
" %l -- Input line number.\n"
" %n -- Number of analysis states.\n"
" %r -- Ambiguity index.\n"
" %s -- Surface.\n"
};
/*---------------------------------------------------------------------------*/
static void
do_unknown_format_option( string_t arguments )
/* Change unknown analysis format to ARGUMENTS. */
{
string_t format;
if (*arguments == EOS)
{
format = new_string_readable( unknown_format, NULL );
printf( "unknown-format: %s\n", format );
free_mem( &format );
}
else
{
format = parse_word( &arguments );
free_mem( &unknown_format );
unknown_format = format;
}
parse_end( &arguments );
}
static command_t unknown_format_option =
{
"unknown-format", do_unknown_format_option,
"Describe the format in which unknown forms will be printed.\n"
"Usage: set unknown-format UNKNOWN_FORMAT_STRING\n"
"The UNKNOWN_FORMAT_STRING may contain the following special sequences:\n"
" %l -- Input line number.\n"
" %n -- Number of analysis states.\n"
" %s -- Surface.\n"
};
/*---------------------------------------------------------------------------*/
static void
read_project_file( string_t project_file )
/* Read the project file. */
{
FILE *project_stream;
char_t *project_line;
string_t project_line_p, argument, include_file, extension;
string_t *name_p;
volatile int_t line_count;
static bool_t err_pos_printed;
info_in_project_file = err_pos_printed = FALSE;
project_stream = open_stream( project_file, "r" );
line_count = 0;
while (TRUE)
{
TRY
project_line = read_line( project_stream );
IF_ERROR
{
print_text( error_text, " (\"%s\", line %d)",
name_in_path( project_file ), line_count + 1 );
err_pos_printed = TRUE;
}
END_TRY;
if (project_line == NULL)
break;
line_count++;
cut_comment( project_line );
project_line_p = project_line;
if (*project_line_p != EOS)
{
argument = NULL;
TRY
{
argument = parse_word( &project_line_p );
extension = NULL;
name_p = NULL;
if (strcmp_no_case( argument, "sym:" ) == 0)
{
extension = "sym";
name_p = &symbol_file;
}
else if (strcmp_no_case( argument, "esym:" ) == 0)
{
extension = "esym";
name_p = &extended_symbol_file;
}
else if (strcmp_no_case( argument, "lex:" ) == 0)
{
extension = "lex";
name_p = &lexicon_file;
}
else if (strcmp_no_case( argument, "mor:" ) == 0)
{
extension = "mor";
name_p = &morphology_file;
}
else if (strcmp_no_case( argument, "syn:" ) == 0)
{
extension = "syn";
name_p = &syntax_file;
}
else if (strcmp_no_case( argument, "include:" ) == 0)
{
include_file = parse_absolute_path( &project_line_p, project_file );
parse_end( &project_line_p );
read_project_file( include_file );
free_mem( &include_file );
}
else if (strcmp_no_case( argument, "info:" ) == 0)
{
/* Insert an empty line if we already have info that stems from a
* different project file. */
if (grammar_info->string_size > 0 && ! info_in_project_file)
add_char_to_text( grammar_info, '\n' );
add_to_text( grammar_info, project_line_p );
add_char_to_text( grammar_info, '\n' );
info_in_project_file = TRUE;
}
free_mem( &argument );
if (name_p != NULL && *name_p == NULL && *project_line_p != EOS)
{
argument = parse_absolute_path( &project_line_p, project_file );
if (! has_extension( argument, extension ))
{
complain( "\"%s\" should have extension \"%s\".",
name_in_path( argument ), extension );
}
set_binary_file_name( name_p, argument );
free_mem( &argument );
}
}
IF_ERROR
{
if (! err_pos_printed)
{
print_text( error_text, " (\"%s\", line %d)",
name_in_path( project_file ), line_count );
err_pos_printed = TRUE;
}
}
END_TRY;
}
free_mem( &project_line );
}
close_stream( &project_stream, project_file );
info_in_project_file = FALSE;
}
/*---------------------------------------------------------------------------*/
/* The commands that can be called on startup, in alphabetical order. */
static command_t *malaga_options[] =
{
&alias_option, &auto_result_option, &auto_tree_option,
&auto_variables_option, &cache_size_option, &display_cmd_option,
&error_format_option, &hidden_option, &mor_incomplete_option,
&mor_out_filter_option, &mor_pruning_option, &result_format_option,
&result_list_option, &robust_rule_option, &roman_hangul_option,
&sort_records_option, &switch_option, &syn_incomplete_option,
&syn_in_filter_option, &syn_out_filter_option, &syn_pruning_option,
&transmit_cmd_option, &unknown_format_option, &use_display_option,
NULL
};
/*---------------------------------------------------------------------------*/
void
init_malaga( string_t project_file )
/* Initialise this module. */
{
string_t malagarc_path;
init_input();
grammar_info = new_text();
/* Read project file. */
if (! has_extension( project_file, "pro" ))
{
complain( "Project file \"%s\" must have extension \".pro\".",
project_file );
}
read_project_file( project_file );
if (morphology_file == NULL)
complain( "Missing morphology rules." );
if (lexicon_file == NULL)
complain( "Missing lexicon." );
if (symbol_file == NULL)
complain( "Missing symbol file." );
/* Init modules. */
init_values();
if (extended_symbol_file != NULL)
init_symbols( extended_symbol_file );
else
init_symbols( symbol_file );
init_hangul();
init_lexicon( lexicon_file );
init_scanner();
init_transmit();
init_analysis( morphology_file, syntax_file );
/* Set options to default values. */
error_format = new_string( "%l: %s: error: %e", NULL );
result_format = new_string( "%l: %s: %f", NULL );
unknown_format = new_string( "%l: %s: unknown", NULL );
use_display = auto_tree = FALSE;
auto_result = TRUE;
/* Execute startup files. */
options = malaga_options;
execute_set_commands( project_file, "malaga:" );
malagarc_path = NULL;
#ifdef POSIX
TRY
malagarc_path = absolute_path( "~/.malagarc", NULL );
IF_ERROR
RESUME;
END_TRY;
#endif
#ifdef WIN32
TRY
malagarc_path = absolute_path( "~\\malaga.ini", NULL );
IF_ERROR
RESUME;
END_TRY;
#endif
if (malagarc_path != NULL && file_exists( malagarc_path ))
execute_set_commands( malagarc_path, "malaga:" );
free_mem( &malagarc_path );
}
/*---------------------------------------------------------------------------*/
void
terminate_malaga( void )
/* Terminate this module. */
{
free_aliases();
free_mem( &error_format );
free_mem( &result_format );
free_mem( &unknown_format );
terminate_analysis();
free_mem( &syntax_file );
free_mem( &morphology_file );
terminate_patterns();
terminate_transmit();
terminate_scanner();
terminate_lexicon();
free_mem( &lexicon_file );
terminate_hangul();
terminate_symbols();
free_mem( &extended_symbol_file );
free_mem( &symbol_file );
terminate_values();
free_text( &grammar_info );
terminate_input();
}
/* End of file. =============================================================*/