/* Copyright (C) 1995 Bjoern Beutel. */
/* Description. =============================================================*/
/* Program to dump a compiled Malaga rule file with intermediate code. */
/* Includes. ================================================================*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <setjmp.h>
#include <glib.h>
#include "basic.h"
#include "pools.h"
#include "values.h"
#include "symbols.h"
#include "files.h"
#include "rule_type.h"
#include "rules.h"
#include "patterns.h"
#include "hangul.h"
/* Functions. ===============================================================*/
static void
print_instruction( int_t pos, rule_sys_t *rule_sys )
/* Print the instruction at POS in RULE_SYS. */
{
int_t opcode, info;
string_t string;
opcode = OPCODE( rule_sys->instrs[ pos ] );
info = INSTR_INFO( rule_sys->instrs[ pos ] );
switch (opcode)
{
case INS_SYSTEM_ERROR:
switch (info)
{
case ASSERTION_ERROR:
string = "assertion_error";
break;
case NO_RETURN_ERROR:
string = "no_return_error";
break;
}
printf( "error %s", string );
break;
case INS_ERROR:
printf( "error" );
break;
case INS_TERMINATE:
printf( "terminate" );
break;
case INS_NOP:
printf( "nop" );
break;
case INS_TERMINATE_IF_NULL:
printf( "terminate_if_null" );
break;
case INS_ADD_END_STATE:
printf( "add_end_state" );
break;
case INS_ADD_STATE:
string = rule_set_readable( rule_sys, info );
printf( "add_state %s", string );
free_mem( &string );
break;
case INS_ADD_ALLO:
printf( "add_allo" );
break;
case INS_ACCEPT:
printf( "accept" );
break;
case INS_PUSH_NULL:
printf( "push_null %d", info );
break;
case INS_PUSH_VAR:
printf( "push_var %d", info );
break;
case INS_PUSH_CONST:
string = value_to_readable( rule_sys->values + info, TRUE, 30 );
printf( "push_const %s", string );
free_mem( &string );
break;
case INS_PUSH_SYMBOL:
printf( "push_symbol %s", get_symbol_name( info ) );
break;
case INS_PUSH_PATTERN_VAR:
printf( "push_pattern_var %d", info );
break;
case INS_POP:
printf( "pop %d", info );
break;
case INS_POP_TO:
printf( "pop_to %d", info );
break;
case INS_BUILD_LIST:
printf( "build_list %d", info );
break;
case INS_DECOMPOSE_LIST:
printf( "decompose_list %d", info );
break;
case INS_BUILD_RECORD:
printf( "build_record %d", info );
break;
case INS_BUILD_PATH:
printf( "build_path %d", info );
break;
case INS_DOT_OPERATION:
printf( "dot_operation" );
break;
case INS_PLUS_OPERATION:
printf( "plus_operation" );
break;
case INS_MINUS_OPERATION:
printf( "minus_operation" );
break;
case INS_ASTERISK_OPERATION:
printf( "asterisk_operation" );
break;
case INS_SLASH_OPERATION:
printf( "slash_operation" );
break;
case INS_UNARY_MINUS_OP:
printf( "unary_minus_op" );
break;
case INS_GET_ATTRIBUTE:
printf( "get_attribute %s", get_symbol_name( info ) );
break;
case INS_REMOVE_ATTRIBUTE:
printf( "remove_attribute %s", get_symbol_name( info ) );
break;
case INS_STD_FUNCTION:
switch (info)
{
case FUNC_TO_ATOMS:
string = "to_atoms";
break;
case FUNC_IS_CAPITAL:
string = "is_capital";
break;
case FUNC_GET_LENGTH:
string = "get_length";
break;
case FUNC_TO_MULTI:
string = "to_multi";
break;
case FUNC_TO_SET:
string = "to_set";
break;
case FUNC_GET_SWITCH:
string = "get_switch";
break;
case FUNC_GET_VALUE_STRING:
string = "get_value_string";
break;
case FUNC_GET_VALUE_TYPE:
string = "get_value_type";
break;
case FUNC_TRANSMIT:
string = "transmit";
break;
case FUNC_FLOOR:
string = "floor";
break;
case FUNC_SUBSTRING:
string = "substring";
break;
default:
complain( "Internal error." );
}
printf( "std_function %s", string );
break;
case INS_MATCH:
string = new_string_readable( rule_sys->strings + info, NULL );
printf( "match %s", string );
free_mem( &string );
break;
case INS_SET_VAR:
printf( "set_var %d", info );
break;
case INS_PLUS_VAR:
printf( "plus_var %d", info );
break;
case INS_MINUS_VAR:
printf( "minus_var %d", info );
break;
case INS_ASTERISK_VAR:
printf( "asterisk_var %d", info );
break;
case INS_SLASH_VAR:
printf( "slash_var %d", info );
break;
case INS_SET_VAR_PATH:
printf( "set_var_path %d", info );
break;
case INS_PLUS_VAR_PATH:
printf( "plus_var_path %d", info );
break;
case INS_MINUS_VAR_PATH:
printf( "minus_var_path %d", info );
break;
case INS_ASTERISK_VAR_PATH:
printf( "asterisk_var_path %d", info );
break;
case INS_SLASH_VAR_PATH:
printf( "slash_var_path %d", info );
break;
case INS_GET_1ST_ELEMENT:
printf( "get_1st_element" );
break;
case INS_ITERATE:
printf( "iterate %d", info );
break;
case INS_JUMP:
printf( "jump %d", info );
break;
case INS_JUMP_IF_EQUAL:
printf( "jump_if_equal %d", info );
break;
case INS_JUMP_IF_NOT_EQUAL:
printf( "jump_if_not_equal %d", info );
break;
case INS_JUMP_IF_CONGR:
printf( "jump_if_congr %d", info );
break;
case INS_JUMP_IF_NOT_CONGR:
printf( "jump_if_not_congr %d", info );
break;
case INS_JUMP_IF_IN:
printf( "jump_if_in %d", info );
break;
case INS_JUMP_IF_NOT_IN:
printf( "jump_if_not_in %d", info );
break;
case INS_JUMP_IF_LESS:
printf( "jump_if_less %d", info );
break;
case INS_JUMP_IF_NOT_LESS:
printf( "jump_if_not_less %d", info );
break;
case INS_JUMP_IF_GREATER:
printf( "jump_if_greater %d", info );
break;
case INS_JUMP_IF_NOT_GREATER:
printf( "jump_if_not_greater %d", info );
break;
case INS_JUMP_IF_NULL:
printf( "jump_if_null %d", info );
break;
case INS_JUMP_IF_NOT_NULL:
printf( "jump_if_not_null %d", info );
break;
case INS_JUMP_IF_YES:
printf( "jump_if_yes %d", info );
break;
case INS_JUMP_IF_NO:
printf( "jump_if_no %d", info );
break;
case INS_JUMP_NOW:
printf( "jump_now %d", info );
break;
case INS_JUMP_LATER:
printf( "jump_later %d", info );
break;
case INS_JUMP_SUBRULE:
printf( "jump_subrule %s",
rule_sys->strings + rule_sys->rules[ info ].name );
break;
case INS_RETURN:
printf( "return %d", info );
break;
default:
printf( "ILLEGAL INSTRUCTION %d", opcode );
break;
}
}
/*---------------------------------------------------------------------------*/
static void
print_rules( string_t source_name, rule_sys_t *rule_sys )
/* Print all rules of SOURCE_NAME. */
{
string_t next_source_name;
int_t instr, next_instr;
int_t source_line, next_source_line;
FILE *stream;
int_t c;
if (source_name != NULL)
stream = open_stream( source_name, "r" );
else
stream = NULL;
source_line = 1;
next_instr = next_source_line = 0;
for (instr = 0; instr < rule_sys->instr_count; instr++)
{
if (stream != NULL)
{
if (instr >= next_instr) /* NEXT_INSTR has a new source location. */
{
for (next_instr = instr;
next_instr < rule_sys->instr_count;
next_instr++)
{
source_of_instr( rule_sys, next_instr,
&next_source_line, &next_source_name, NULL );
if (next_source_name != NULL
&& strcmp( name_in_path( next_source_name ),
name_in_path( source_name ) ) == 0
&& next_source_line > source_line)
{
break;
}
}
}
while (source_line < next_source_line)
{
c = getc( stream );
if (c == EOF)
break;
if (c == '\n')
source_line++;
putchar( c );
}
}
printf( "|%6d: ", instr );
print_instruction( instr, rule_sys );
printf( "\n" );
}
if (stream != NULL)
{
/* Print remainder of source file. */
while ((c = getc( stream )) != EOF)
putchar( c );
close_stream( &stream, source_name );
}
}
/* Top level functions. =====================================================*/
int
main( int argc, char *argv[] )
/* The main function of "maldump". */
{
rule_sys_t *rule_sys;
string_t rule_file, symbol_file, source_file;
int_t i;
init_basic( "maldump" );
/* Parse arguments. */
if (argc == 2)
{
if (strcmp_no_case( argv[1], "--version" ) == 0
|| strcmp_no_case( argv[1], "-version" ) == 0
|| strcmp_no_case( argv[1], "-v" ) == 0)
{
program_message();
exit(0);
}
else if (strcmp_no_case( argv[1], "--help" ) == 0
|| strcmp_no_case( argv[1], "-help" ) == 0
|| strcmp_no_case( argv[1], "-h" ) == 0)
{
printf( "Dump a compiled rule file of a Malaga grammar.\n\n"
"Usage:\n"
"maldump SYM_FILE RULE_FILE "
"-- Disassemble RULE_FILE on stdout.\n"
"maldump -v[ersion] "
"-- Print version information.\n"
"maldump -h[elp] "
"-- Print this help.\n\n"
"SYM_FILE may end on \".sym\" or \".esym\".\n"
"RULE_FILE may end on \".all\", \"mor\" or \"syn\".\n"
"Option \"-s[ource] SOURCE_FILE\" gives "
"a source file for RULE_FILE.\n" );
exit(0);
}
}
rule_file = symbol_file = source_file = NULL;
for (i = 1; i < argc; i++)
{
if (has_extension( argv[i], "all" )
|| has_extension( argv[i], "mor" )
|| has_extension( argv[i], "syn" ))
{
set_binary_file_name( &rule_file, argv[i] );
}
else if (has_extension( argv[i], "sym" )
|| has_extension( argv[i], "esym" ))
{
set_binary_file_name( &symbol_file, argv[i] );
}
else if (strcmp_no_case( argv[i], "-source" ) == 0
|| strcmp_no_case( argv[i], "-s" ) == 0)
{
if (argv[ ++i ] == NULL)
complain( "Missing file name after \"-source\"." );
set_file_name( &source_file, argv[i] );
}
else
complain( "Illegal argument \"%s\".", argv[i] );
}
if (rule_file == NULL)
complain( "Missing rule file name." );
if (symbol_file == NULL)
complain( "Missing symbol file name." );
init_values();
init_symbols( symbol_file );
rule_sys = read_rule_sys( rule_file );
init_hangul();
print_rules( source_file, rule_sys );
terminate_hangul();
free_rule_sys( &rule_sys );
terminate_symbols();
free_mem( &symbol_file );
free_mem( &rule_file );
free_mem( &source_file );
terminate_values();
terminate_patterns();
terminate_basic();
return 0;
}
/* End of file. =============================================================*/