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

« back to all changes in this revision

Viewing changes to malaga.c

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 1995 Bjoern Beutel. */
 
2
 
 
3
/* Description. =============================================================*/
 
4
 
 
5
/* This is the interactive program for morphological and syntactic analysis. */
 
6
 
 
7
/* Includes. ================================================================*/
 
8
 
 
9
#include <stdio.h>
 
10
#include <stdarg.h>
 
11
#include <string.h>
 
12
#include <errno.h>
 
13
#include <stdlib.h>
 
14
#include <setjmp.h>
 
15
#include <time.h>
 
16
#include "basic.h"
 
17
#include "pools.h"
 
18
#include "values.h"
 
19
#include "symbols.h"
 
20
#include "files.h"
 
21
#include "rule_type.h"
 
22
#include "rules.h"
 
23
#include "analysis.h"
 
24
#include "input.h"
 
25
#include "commands.h"
 
26
#include "options.h"
 
27
#include "display.h"
 
28
#include "malaga_lib.h"
 
29
#include "generation.h"
 
30
#include "debugger.h"
 
31
#include "breakpoints.h"
 
32
#include "cache.h"
 
33
#include "transmit.h"
 
34
#include "hangul.h"
 
35
 
 
36
/* Macros. ==================================================================*/
 
37
 
 
38
#define SAFE_STRING(s) ((s) != NULL ? (s) : (string_t) "")
 
39
/* Return an empty string if S == NULL. */
 
40
 
 
41
/* Variables. ===============================================================*/
 
42
 
 
43
static string_t analysis_input; /* Input line for interactive analysis. */
 
44
 
 
45
static int_t debug_analysis_node_index; /* Index of state to debug or -1. */
 
46
 
 
47
static debug_mode_t state_debug_mode; 
 
48
/* Debug mode to use for states to debug. */
 
49
 
 
50
/* Analysis result output. ==================================================*/
 
51
 
 
52
static void 
 
53
display_result( void )
 
54
/* Generate result file and start program to display result. */
 
55
 
56
  string_t input;
 
57
  string_t value_string;
 
58
  string_t count_string;
 
59
  value_t fs;
 
60
  int_t result_count;
 
61
 
 
62
  if (! analysis_has_nodes()) 
 
63
    complain( "No analysis started." );
 
64
 
 
65
  /* Print analysis result header. */
 
66
  input = new_string_readable( analysis_input, NULL );
 
67
  decode_hangul( &input );
 
68
  if (use_display) 
 
69
  { 
 
70
    start_display_process();
 
71
    fprintf( display_stream, "result\n" );
 
72
    fprintf( display_stream, "%s\n", input );
 
73
  } 
 
74
  else 
 
75
  { 
 
76
    if (! analysis_has_results()) 
 
77
      printf( "No analyses of %s.\n", input );
 
78
    else 
 
79
      printf( "Analyses of %s:\n", input );
 
80
  }
 
81
  free_mem( &input );
 
82
 
 
83
  /* Print analysis results. */
 
84
  result_count = 0;
 
85
  for (fs = first_analysis_result(); fs != NULL; fs = next_analysis_result())
 
86
  { 
 
87
    result_count++;
 
88
    if (use_display) 
 
89
    { 
 
90
      value_string = value_to_readable( fs, FALSE, -1 );
 
91
      fprintf( display_stream, "%d {%s}\n", result_count, value_string );
 
92
      free_mem( &value_string );
 
93
    } 
 
94
    else
 
95
    { 
 
96
      count_string = int_to_string( result_count );
 
97
      value_string = value_to_readable( fs, FALSE, 
 
98
                                        strlen( count_string ) + 2 );
 
99
      printf( "%s: %s\n", count_string, value_string );
 
100
      free_mem( &value_string );
 
101
      free_mem( &count_string );
 
102
    }
 
103
  }
 
104
 
 
105
  /* Print analysis results footer. */
 
106
  if (use_display) 
 
107
  { 
 
108
    fprintf( display_stream, "end\n" );
 
109
    fflush( display_stream );
 
110
  }
 
111
}
 
112
 
 
113
/*---------------------------------------------------------------------------*/
 
114
 
 
115
static void 
 
116
display_tree( void )
 
117
/* Display analysis tree. */
 
118
 
119
  analysis_node_t *node;
 
120
  string_t input, node_type = 0, value_string, surf_string;
 
121
 
 
122
  if (! analysis_has_nodes()) 
 
123
    complain( "No analysis started." );
 
124
  start_display_process();
 
125
  fprintf( display_stream, "tree\n" );
 
126
 
 
127
  /* Print sentence that has been analysed. */
 
128
  input = new_string_readable( analysis_input, NULL );
 
129
  decode_hangul( &input );
 
130
  fprintf( display_stream, "%s\n", input );
 
131
  free_mem( &input );
 
132
 
 
133
  /* Print nodes. */
 
134
  for (node = get_first_analysis_node(); 
 
135
       node != NULL; 
 
136
       node = get_next_analysis_node()) 
 
137
  { 
 
138
    /* Print node index and type, parent index and rule name. */
 
139
    switch (node->type) 
 
140
    {
 
141
    case INTER_NODE: node_type = "inter"; break;
 
142
    case BREAK_NODE: node_type = "break"; break;
 
143
    case FINAL_NODE: node_type = "final"; break;
 
144
    case UNFINAL_NODE: node_type = "unfinal"; break;
 
145
    case PRUNED_NODE: node_type = "pruned"; break;
 
146
    }
 
147
    fprintf( display_stream, "%d %s %d \"%s\" ", 
 
148
             node->index, node_type, node->parent_index, 
 
149
             SAFE_STRING( node->rule_name ) );
 
150
 
 
151
    /* Print link's surface and feature structure. */
 
152
    if (node->link_surf != NULL) 
 
153
    { 
 
154
      surf_string = new_string_readable( node->link_surf, NULL );
 
155
      decode_hangul( &surf_string );
 
156
    } 
 
157
    else 
 
158
      surf_string = new_string( "", NULL );
 
159
    value_string = value_to_readable( node->link_fs, FALSE, -1 );
 
160
    fprintf( display_stream, "{%s} {%s} ", surf_string, value_string );
 
161
    free_mem( &value_string );
 
162
    free_mem( &surf_string );
 
163
 
 
164
    /* Print result surface and feature structure. */
 
165
    if (node->result_surf != NULL) 
 
166
    { 
 
167
      surf_string = new_string_readable( node->result_surf, NULL );
 
168
      decode_hangul( &surf_string );
 
169
    } 
 
170
    else 
 
171
      surf_string = new_string( "", NULL );
 
172
    value_string = value_to_readable( node->result_fs, FALSE, -1 );
 
173
    fprintf( display_stream, "{%s} {%s} ", surf_string, value_string );
 
174
    free_mem( &value_string );
 
175
    free_mem( &surf_string );
 
176
 
 
177
    /* Print rule set. */
 
178
    fprintf( display_stream, "\"%s\"\n", SAFE_STRING( node->rule_set ) );
 
179
    free_analysis_node( &node );
 
180
  }
 
181
  fprintf( display_stream, "end\n" );
 
182
  fflush( display_stream );
 
183
}
 
184
 
 
185
/*---------------------------------------------------------------------------*/
 
186
 
 
187
static void 
 
188
display_after_analysis( void )
 
189
/* Display result in the modes that have been switched on after analysis. */
 
190
 
191
  if (auto_result) 
 
192
    display_result();
 
193
  if (auto_tree) 
 
194
    display_tree();
 
195
}
 
196
 
 
197
/*---------------------------------------------------------------------------*/
 
198
 
 
199
static void 
 
200
do_result( string_t arguments )
 
201
/* Show result of last analysis. */
 
202
 
203
  parse_end( &arguments );
 
204
  if (! analysis_has_nodes()) 
 
205
    complain( "No previous analysis." );
 
206
  display_result();
 
207
}
 
208
 
 
209
static command_t result_command = 
 
210
 
211
  "result res", do_result,
 
212
  "Show result of last analysis.\n"
 
213
  "Usage: result\n"
 
214
};
 
215
 
 
216
/*---------------------------------------------------------------------------*/
 
217
 
 
218
static void 
 
219
do_tree( string_t arguments )
 
220
/* Generate analysis tree file and start program to display tree. */
 
221
 
222
  parse_end( &arguments );
 
223
  if (! analysis_has_nodes()) 
 
224
    complain( "No analysis started." );
 
225
  display_tree();
 
226
}
 
227
 
 
228
static command_t tree_command = 
 
229
{
 
230
  "tree t", do_tree,
 
231
  "Display the analysis tree.\n"
 
232
  "Usage: tree\n"
 
233
  "In debug mode or after a rule execution error, the tree may be "
 
234
  "incomplete.\n"
 
235
};
 
236
 
 
237
/* Analysis functions. ======================================================*/
 
238
 
 
239
static void 
 
240
analyse_argument( grammar_t grammar, string_t arguments )
 
241
/* Analyse ARGUMENTS (or last analysis, if *ARGUMENTS == EOS).
 
242
 * Use GRAMMAR (SYNTAX or MORPHOLOGY). */
 
243
 
244
  if (*arguments == EOS) 
 
245
  { 
 
246
    if (analysis_input == NULL) 
 
247
      complain( "No previous analysis." );
 
248
  } 
 
249
  else 
 
250
  { 
 
251
    free_mem( &analysis_input );
 
252
    analysis_input = new_string( arguments, NULL );
 
253
    preprocess_input( analysis_input, FALSE );
 
254
    encode_hangul( &analysis_input );
 
255
  }
 
256
  debug_state = NULL;
 
257
  analyse( grammar, analysis_input, BUILD_TREE, ANALYSE_ALL );
 
258
}
 
259
 
 
260
/*---------------------------------------------------------------------------*/
 
261
 
 
262
static void 
 
263
analyse_line( grammar_t grammar, string_t arguments )
 
264
/* Analyse a word or a sentence in file FILE, line LINE_NO.
 
265
 * ARGUMENTS must be of format "FILE LINE_NO".
 
266
 * Use GRAMMAR. */
 
267
{
 
268
  int_t line_number, current_line_number;
 
269
  FILE *input_stream;
 
270
  string_t file_name, input_line;
 
271
  
 
272
  input_stream = NULL;
 
273
  TRY 
 
274
  { 
 
275
    /* Read arguments. */
 
276
    file_name = parse_absolute_path( &arguments, NULL );
 
277
    line_number = parse_int( &arguments );
 
278
    parse_end( &arguments );
 
279
 
 
280
    /* Read the line from input. */
 
281
    input_stream = open_stream( file_name, "r" );
 
282
    free_mem( &file_name );
 
283
    current_line_number = 0;
 
284
    input_line = NULL;
 
285
    do 
 
286
    { 
 
287
      check_user_break();
 
288
      free_mem( &input_line );
 
289
      input_line = read_line( input_stream );
 
290
      if (input_line == NULL) 
 
291
        complain( "No line %d.", line_number );
 
292
      current_line_number++;
 
293
    } while (current_line_number < line_number);
 
294
    preprocess_input( input_line, FALSE );
 
295
    if (*input_line == EOS) 
 
296
      complain( "Line %d is empty.", line_number );
 
297
    free_mem( &analysis_input );
 
298
    analysis_input = input_line;
 
299
    encode_hangul( &analysis_input );
 
300
  } 
 
301
  FINALLY 
 
302
    close_stream( &input_stream, NULL );
 
303
  END_TRY;
 
304
 
 
305
  debug_state = NULL;
 
306
  analyse( grammar, analysis_input, BUILD_TREE, ANALYSE_ALL );
 
307
}
 
308
 
 
309
/*---------------------------------------------------------------------------*/
 
310
 
 
311
static void 
 
312
do_ma( string_t arguments )
 
313
/* Analyse ARGUMENTS morphologically. */
 
314
{
 
315
  assert_not_in_debug_mode();
 
316
  set_debug_mode( RUN_MODE, NULL );
 
317
  analyse_argument( MORPHOLOGY, arguments );
 
318
  display_after_analysis();
 
319
}
 
320
 
 
321
static command_t ma_command = 
 
322
 
323
  "ma", do_ma,
 
324
  "Analyse the argument morphologically.\n"
 
325
  "Usage:\n"
 
326
  "  ma INPUT -- Analyse INPUT.\n"
 
327
  "  ma -- Re-analyse last input.\n"
 
328
  "\"ma\" can't be used in debug mode.\n"
 
329
};
 
330
 
 
331
/*---------------------------------------------------------------------------*/
 
332
 
 
333
static void 
 
334
do_sa( string_t arguments )
 
335
/* Analyse ARGUMENTS syntactically. */
 
336
{
 
337
  assert_not_in_debug_mode();
 
338
  set_debug_mode( RUN_MODE, NULL );
 
339
  analyse_argument( SYNTAX, arguments );
 
340
  display_after_analysis();
 
341
}
 
342
 
 
343
static command_t sa_command = 
 
344
{
 
345
  "sa", do_sa,
 
346
  "Analyse the argument syntactically.\n"
 
347
  "Usage:\n"
 
348
  "  sa INPUT -- Analyse INPUT.\n"
 
349
  "  sa -- Re-analyse last input.\n"
 
350
  "\"sa\" can't be used in debug mode.\n"
 
351
};
 
352
 
 
353
/*---------------------------------------------------------------------------*/
 
354
 
 
355
static void 
 
356
do_ma_line( string_t arguments )
 
357
/* Analyse ARGUMENTS morphologically. */
 
358
 
359
  assert_not_in_debug_mode();
 
360
  set_debug_mode( RUN_MODE, NULL );
 
361
  analyse_line( MORPHOLOGY, arguments );
 
362
  display_after_analysis();
 
363
}
 
364
 
 
365
static command_t ma_line_command = 
 
366
{
 
367
  "ma-line mal", do_ma_line,
 
368
  "Analyse a line in a file morphologically.\n"
 
369
  "Usage:\n"
 
370
  "  ma-line FILE LINE -- Analyse LINE in FILE.\n"
 
371
  "\"ma-line\" can't be used in debug mode.\n"
 
372
};
 
373
 
 
374
/*---------------------------------------------------------------------------*/
 
375
 
 
376
static void 
 
377
do_sa_line( string_t arguments )
 
378
/* Analyse ARGUMENTS syntactically. */
 
379
 
380
  assert_not_in_debug_mode();
 
381
  set_debug_mode( RUN_MODE, NULL );
 
382
  analyse_line( SYNTAX, arguments );
 
383
  display_after_analysis();
 
384
}
 
385
 
 
386
static command_t sa_line_command = 
 
387
{
 
388
  "sa-line sal", do_sa_line,
 
389
  "Analyse a line in a file syntactically.\n"
 
390
  "Usage:\n"
 
391
  "  sa-line FILE LINE -- Analyse LINE in FILE.\n"
 
392
  "\"sa-line\" can't be used in debug mode.\n"
 
393
};
 
394
 
 
395
/*---------------------------------------------------------------------------*/
 
396
 
 
397
static void analyse_input( grammar_t grammar, string_t input )
 
398
{
 
399
  value_t value;
 
400
  int_t i;
 
401
  string_t string, count, input_readable;
 
402
 
 
403
  analysis_input = new_string( input, NULL );
 
404
  input_readable = new_string_readable( input, NULL );
 
405
  preprocess_input( analysis_input, FALSE );
 
406
  encode_hangul( &analysis_input );
 
407
  analyse( grammar, analysis_input, BUILD_TREE, ANALYSE_ALL );
 
408
 
 
409
  if (analysis_has_results()) 
 
410
  {
 
411
    printf( "Results for %s:\n", input_readable );
 
412
    i = 0;
 
413
    for (value = first_analysis_result(); 
 
414
         value != NULL;  
 
415
         value = next_analysis_result()) 
 
416
    {
 
417
      i++;
 
418
      count = int_to_string( i );
 
419
      string = value_to_readable( value, FALSE, strlen( count ) + 2) ;
 
420
      printf( "\n%s: %s\n", count, string );
 
421
      free_mem( &string );
 
422
      free_mem( &count );
 
423
    }
 
424
  }
 
425
  else 
 
426
    printf( "No results for %s.\n", input_readable );
 
427
  free( input_readable );
 
428
}
 
429
 
 
430
/* Debug support. ===========================================================*/
 
431
 
 
432
static void 
 
433
display_where( void )
 
434
/* Print rule name, left and right surface. */
 
435
 
436
  string_t surf, file, rule;
 
437
  int_t line;
 
438
 
 
439
  source_of_instr( executed_rule_sys, pc, &line, &file, &rule );
 
440
  printf( "At \"%s\", line %d, rule \"%s\", ", 
 
441
          name_in_path( file ), line, rule );
 
442
 
 
443
  /* Print state's surface. */
 
444
  surf = get_surface( STATE_SURFACE );
 
445
  decode_hangul( &surf );
 
446
  printf( "surf: %s", surf );
 
447
  free_mem( &surf );
 
448
 
 
449
  /* Print link's surface. */
 
450
  surf = get_surface( LINK_SURFACE );
 
451
  decode_hangul( &surf );
 
452
  if (*surf != EOS) 
 
453
    printf( ", link: %s", surf );
 
454
  free_mem( &surf );
 
455
 
 
456
  /* Print state number. */
 
457
  if (current_state != -1) 
 
458
    printf( ", state: %d", current_state );
 
459
  printf( ".\n" );
 
460
  if (in_emacs_malaga_mode) 
 
461
    printf( "SHOW \"%s\":%d:0\n", file, line );
 
462
}
 
463
 
 
464
/*---------------------------------------------------------------------------*/
 
465
 
 
466
static bool_t 
 
467
analysis_node_exists( int_t node_index )
 
468
/* Return TRUE iff an analysis node with index NODE_INDEX has been
 
469
 * generated in the last analysis. */
 
470
 
471
  analysis_node_t *node;
 
472
  int_t index;
 
473
 
 
474
  for (node = get_first_analysis_node(); 
 
475
       node != NULL; 
 
476
       node = get_next_analysis_node()) 
 
477
  { 
 
478
    index = node->index;
 
479
    free_analysis_node( &node );
 
480
    if (index == node_index) 
 
481
      return TRUE;
 
482
  }
 
483
  return FALSE;
 
484
}
 
485
 
 
486
/*---------------------------------------------------------------------------*/
 
487
 
 
488
static void 
 
489
malaga_debug_state( int_t state, bool_t enter )
 
490
/* Callback function for "analyse". 
 
491
 * This is called with ENTER == TRUE when successor rules for
 
492
 * state with analysis node INDEX will be executed.
 
493
 * It is called with ENTER == FALSE when successor rules for state with 
 
494
 * analysis node INDEX have been executed. */
 
495
 
496
  if (state != debug_analysis_node_index) 
 
497
    return;
 
498
  if (enter)
 
499
    set_debug_mode( state_debug_mode, rule_system[ top_grammar ] );
 
500
  else
 
501
  {
 
502
    state_debug_mode = get_debug_mode();
 
503
    set_debug_mode( RUN_MODE, NULL );
 
504
  }
 
505
}
 
506
 
 
507
/*---------------------------------------------------------------------------*/
 
508
 
 
509
static void 
 
510
check_interactive_analysis( void )
 
511
{
 
512
  if (analysis_input == NULL || analysis_input != last_analysis_input) 
 
513
    complain( "No interactive analysis." );
 
514
}
 
515
 
 
516
/*---------------------------------------------------------------------------*/
 
517
 
 
518
static void 
 
519
do_debug_state( string_t arguments )
 
520
/* Analyse the last argument again and stop before executing the rules for a
 
521
 * state whose tree node index is specified in ARGUMENTS. */
 
522
 
523
  assert_not_in_debug_mode();
 
524
  check_interactive_analysis();
 
525
 
 
526
  debug_analysis_node_index = parse_int( &arguments );
 
527
  parse_end( &arguments );
 
528
 
 
529
  if (! analysis_node_exists( debug_analysis_node_index )) 
 
530
    complain( "State not found." );
 
531
  
 
532
  state_debug_mode = WALK_MODE;
 
533
  debug_state = malaga_debug_state;
 
534
  /* Debug mode is set by "malaga_debug_state" before and after 
 
535
   * rule application. */
 
536
 
 
537
  analyse( top_grammar, analysis_input, BUILD_TREE, ANALYSE_ALL );
 
538
}
 
539
 
 
540
static command_t debug_state_command = 
 
541
 
542
  "debug-state debug-node dn", do_debug_state,
 
543
  "Re-analyse the last analysis input.\n"
 
544
  "Execute successor rule for given state in debug mode.\n"
 
545
  "Usage: debug-state STATE_INDEX\n"
 
546
  "Analysis is restarted for last input and switches to debug mode\n"
 
547
  "when executing successor rules for state STATE_INDEX.\n"
 
548
  "\"debug-state\" can't be used in debug mode.\n"
 
549
};
 
550
 
 
551
/*---------------------------------------------------------------------------*/
 
552
 
 
553
static void 
 
554
do_debug_ma( string_t arguments )
 
555
/* Analyse ARGUMENTS morphologically.
 
556
 * Execute morphology combination rules in debug mode. */
 
557
 
558
  assert_not_in_debug_mode();
 
559
  set_debug_mode( WALK_MODE, rule_system[ MORPHOLOGY ] );
 
560
  analyse_argument( MORPHOLOGY, arguments );
 
561
}
 
562
 
 
563
static command_t debug_ma_command = 
 
564
 
565
  "debug-ma dma debug-mor ma-debug mad", do_debug_ma,
 
566
  "Analyse morphologically. "
 
567
  "Execute morphology combination rules in debug mode.\n"
 
568
  "Usage:\n"
 
569
  "  debug-ma INPUT -- Analyse INPUT.\n"
 
570
  "  debug-ma -- Re-analyse the last analysis argument.\n"
 
571
  "Rule execution stops at the first statement.\n"
 
572
  "\"debug-ma\" can't be used in debug mode.\n"
 
573
};
 
574
 
 
575
/*---------------------------------------------------------------------------*/
 
576
 
 
577
static void 
 
578
do_debug_sa( string_t arguments )
 
579
/* Analyse ARGUMENTS syntactically.
 
580
 * Execute syntax combination rules in debug mode. */
 
581
 
582
  assert_not_in_debug_mode();
 
583
  set_debug_mode( WALK_MODE, rule_system[ SYNTAX ] );
 
584
  analyse_argument( SYNTAX, arguments );
 
585
}
 
586
 
 
587
static command_t debug_sa_command = 
 
588
 
589
  "debug-sa dsa debug-syn sa-debug sad", do_debug_sa,
 
590
  "Analyse syntactically. Execute syntax combination rules in debug mode.\n"
 
591
  "Usage:\n"
 
592
  "  debug-sa INPUT -- Analyse INPUT.\n"
 
593
  "  debug-sa -- Re-analyse the last analysis argument.\n"
 
594
  "Rule execution stops at the first statement.\n"
 
595
  "\"debug-sa\" can't be used in debug mode.\n"
 
596
};
 
597
 
 
598
/*---------------------------------------------------------------------------*/
 
599
 
 
600
static void 
 
601
do_debug_ma_line( string_t arguments )
 
602
/* Analyse a word in file FILE, line LINE_NO.
 
603
 * ARGUMENTS must be of format "FILE LINE_NO".
 
604
 * Execute morphology combination rules in debug mode. */
 
605
 
606
  assert_not_in_debug_mode();
 
607
  set_debug_mode( WALK_MODE, rule_system[ MORPHOLOGY ] );
 
608
  analyse_line( MORPHOLOGY, arguments );
 
609
}
 
610
 
 
611
static command_t debug_ma_line_command = 
 
612
 
613
  "debug-ma-line dmal", do_debug_ma_line,
 
614
  "Analyse a line in a file morphologically.\n"
 
615
  "Execute morphology combination rules in debug mode.\n"
 
616
  "Usage:\n"
 
617
  "  debug-ma-line FILE LINE -- Analyse LINE in FILE.\n"
 
618
  "Rule execution stops at the first statement.\n"
 
619
  "\"debug-ma-line\" can't be used in debug mode.\n"
 
620
};
 
621
 
 
622
/*---------------------------------------------------------------------------*/
 
623
 
 
624
static void 
 
625
do_debug_sa_line( string_t arguments )
 
626
/* Analyse a sentence in file FILE, line LINE_NO.
 
627
 * ARGUMENTS must be of format "FILE LINE_NO".
 
628
 * Execute syntax combination rules in debug mode. */
 
629
 
630
  assert_not_in_debug_mode();
 
631
  set_debug_mode( WALK_MODE, rule_system[ SYNTAX ] );
 
632
  analyse_line( SYNTAX, arguments );
 
633
}
 
634
 
 
635
static command_t debug_sa_line_command = 
 
636
 
637
  "debug-sa-line dsal", do_debug_sa_line,
 
638
  "Analyse a line in a file syntactically.\n"
 
639
  "Execute syntax combination rules in debug mode.\n"
 
640
  "Usage:\n"
 
641
  "  debug-sa-line FILE LINE_NO -- Analyse LINE_NO in FILE.\n"
 
642
  "Rule execution stops at the first statement.\n"
 
643
  "\"debug-sa-line\" can't be used in debug mode.\n"
 
644
};
 
645
 
 
646
/* File analysis. ===========================================================*/
 
647
 
 
648
static void 
 
649
write_output( string_t input, int_t line_number, string_t error_message,
 
650
              FILE *output )
 
651
/* Write the result of the last analysis on OUTPUT. */
 
652
 
653
  string_t input_string, line_number_string, state_count_string, buffer;
 
654
  string_t value_string, result_number_string;
 
655
  int_t result_count;
 
656
  value_t fs;
 
657
 
 
658
  input_string = new_string_readable( input, NULL );
 
659
  decode_hangul( &input_string );
 
660
  line_number_string = int_to_string( line_number );
 
661
  state_count_string = int_to_string( state_count );
 
662
  if (error_message != NULL) 
 
663
  { 
 
664
    /* Print error result. */
 
665
    if (*error_format != EOS) 
 
666
    { 
 
667
      buffer = replace_arguments( error_format, "slne",
 
668
                                  input_string, line_number_string, 
 
669
                                  state_count_string, error_message );
 
670
      fprintf( output, "%s\n", buffer );
 
671
      free_mem( &buffer );
 
672
    }
 
673
  } 
 
674
  else if (! analysis_has_results()) 
 
675
  { 
 
676
    /* Print unknown result. */
 
677
    if (*unknown_format != EOS) 
 
678
    { 
 
679
      buffer = replace_arguments( unknown_format, "sln", 
 
680
                                  input_string, line_number_string,
 
681
                                  state_count_string );
 
682
      fprintf( output, "%s\n", buffer );
 
683
      free_mem( &buffer );
 
684
    }
 
685
  } 
 
686
  else 
 
687
  { 
 
688
    if (result_as_list)
 
689
    {
 
690
      result_count = 0;
 
691
      for (fs = first_analysis_result();
 
692
           fs != NULL;
 
693
           fs = next_analysis_result())
 
694
      {
 
695
        result_count++;
 
696
        push_value( fs );
 
697
      }
 
698
      build_list( result_count );
 
699
      value_string = value_to_readable( value_stack[ --top], FALSE, -1 );
 
700
      buffer = replace_arguments( result_format, "slrfn",
 
701
                                  input_string, line_number_string,
 
702
                                  "0", value_string, state_count_string );
 
703
      fprintf( output, "%s\n", buffer );
 
704
      free_mem( &buffer );
 
705
      free_mem( &value_string );
 
706
    }
 
707
    else
 
708
    {
 
709
      /* Print real results. */
 
710
      result_count = 0;
 
711
      for (fs = first_analysis_result(); 
 
712
           fs != NULL; 
 
713
           fs = next_analysis_result())
 
714
      { 
 
715
        result_count++;
 
716
        if (*result_format != EOS) 
 
717
        { 
 
718
          result_number_string = int_to_string( result_count );
 
719
          value_string = value_to_readable( fs, FALSE, -1 );
 
720
          buffer = replace_arguments( result_format, "slrfn", 
 
721
                                      input_string, line_number_string, 
 
722
                                      result_number_string, value_string,
 
723
                                      state_count_string );
 
724
          fprintf( output, "%s\n", buffer );
 
725
          free_mem( &buffer );
 
726
          free_mem( &value_string );
 
727
          free_mem( &result_number_string );
 
728
        }
 
729
      }
 
730
    }
 
731
  }
 
732
  free_mem( &input_string );
 
733
  free_mem( &line_number_string );
 
734
  free_mem( &state_count_string );
 
735
  if (ferror( output )) 
 
736
    complain( "Can't write result: %s.", strerror( errno ) );
 
737
}
 
738
 
 
739
/*---------------------------------------------------------------------------*/
 
740
 
 
741
static void 
 
742
analyse_stream( grammar_t grammar, 
 
743
                FILE *input, 
 
744
                FILE *output, 
 
745
                FILE *statistics,
 
746
                bool_t expect_quotes )
 
747
/* Analyse words or sentences in INPUT, write result to OUTPUT.
 
748
 * Use GRAMMAR for analysis, LIST_FILE_NAME is name of INPUT stream.
 
749
 * If EXPECT_QUOTES == TRUE, expect quoted input lines and remove the quotes.
 
750
 * Write statistic information to STATISTICS. */
 
751
 
752
  volatile int_t analyses, recognised, results; /* Statistic information. */
 
753
  volatile int_t combi_recognised, robust_recognised, errors, line_number;
 
754
  volatile string_t item, error_message;
 
755
  time_t start_time, stop_time;
 
756
  string_t input_line;
 
757
  bool_t old_in_emacs_malaga_mode;
 
758
  value_t fs;
 
759
  double time_diff;
 
760
 
 
761
  item = (grammar == MORPHOLOGY ? "wordform" : "sentence");
 
762
  set_debug_mode( RUN_MODE, NULL );
 
763
  debug_state = NULL;
 
764
  robust_recognised = recognised = results = analyses = errors = 0;
 
765
  combi_recognised = line_number = 0;
 
766
  cache_hits = cache_accesses = 0;
 
767
  time( &start_time );
 
768
  input_line = NULL;
 
769
  TRY 
 
770
  { 
 
771
    while (TRUE) 
 
772
    { 
 
773
      check_user_break();
 
774
      free_mem( &input_line );
 
775
      input_line = read_line( input );
 
776
      if (input_line == NULL) 
 
777
        break;
 
778
      line_number++;
 
779
      preprocess_input( input_line, expect_quotes );
 
780
      if (*input_line != EOS) 
 
781
      { 
 
782
        /* Analyse a non-empty line. */
 
783
        old_in_emacs_malaga_mode = in_emacs_malaga_mode;
 
784
        in_emacs_malaga_mode = FALSE;
 
785
        error_message = NULL;
 
786
        TRY 
 
787
        { 
 
788
          analyses++;
 
789
          encode_hangul( &input_line );
 
790
          analyse( grammar, input_line, NO_TREE, ANALYSE_ALL );
 
791
          if (recognised_by_combi_rules) 
 
792
            combi_recognised++;
 
793
          if (recognised_by_robust_rule) 
 
794
            robust_recognised++;
 
795
          if (analysis_has_results()) 
 
796
            recognised++;
 
797
          for (fs = first_analysis_result(); 
 
798
               fs != NULL; 
 
799
               fs = next_analysis_result()) 
 
800
          { 
 
801
            results++; 
 
802
          }
 
803
        }
 
804
        IF_ERROR 
 
805
        { 
 
806
          error_message = error_text->buffer;
 
807
          errors++;
 
808
          RESUME;
 
809
        } 
 
810
        FINALLY 
 
811
          in_emacs_malaga_mode = old_in_emacs_malaga_mode;
 
812
        END_TRY;
 
813
        write_output( input_line, line_number, error_message, output );
 
814
        fflush( output );
 
815
      }
 
816
    }
 
817
  } 
 
818
  IF_ERROR 
 
819
  { 
 
820
    printf( "%s (line %d)\n", error_text->buffer, line_number );
 
821
    RESUME;
 
822
  } 
 
823
  FINALLY 
 
824
    free_mem( &input_line );
 
825
  END_TRY;
 
826
  time( &stop_time );
 
827
  if (analyses == 0) 
 
828
    fprintf( statistics, "No %ss analysed.\n", item );
 
829
  else 
 
830
  { 
 
831
    time_diff = difftime( stop_time, start_time );
 
832
    fprintf( statistics, "Analysed %ss:        %d\n", item, analyses );
 
833
    fprintf( statistics, "Recognised:                %d (%.2f%%)\n", 
 
834
             recognised, (100.0 * recognised) / analyses );
 
835
    if (combi_recognised > 0) 
 
836
    { 
 
837
      fprintf( statistics, "Recognised by combi rules: %d (%.2f%%)\n", 
 
838
               combi_recognised, (100.0 * combi_recognised) / analyses );
 
839
    }
 
840
    if (robust_recognised > 0) 
 
841
    { 
 
842
      fprintf( statistics, "Recognised by robust rule: %d (%.2f%%)\n",
 
843
               robust_recognised, (100.0 * robust_recognised) / analyses );
 
844
    }
 
845
    if (errors > 0) 
 
846
    { 
 
847
      fprintf( statistics, "Error-creating %ss:  %d (%.2f%%)\n", 
 
848
               item, errors, (100.0 * errors) / analyses );
 
849
    }
 
850
    if (results > 0) 
 
851
    { 
 
852
      fprintf( statistics, "Results per %s:      %.4G\n",
 
853
               item, ((double) results / (double) recognised) );
 
854
    }
 
855
    if (time_diff > 0) 
 
856
    { 
 
857
      fprintf( statistics, "Analysis run time:         %d sec\n", 
 
858
               (int_t) time_diff );
 
859
      fprintf( statistics, "Avg. %ss per second: %d\n", 
 
860
               item, (int_t) (analyses / time_diff) );
 
861
    }
 
862
    if (cache_accesses > 0) 
 
863
    { 
 
864
      fprintf( statistics, "Cache accesses:            %d\n", 
 
865
               cache_accesses );
 
866
      fprintf( statistics, "Cache hits:                %d (%.2f%%)\n",
 
867
               cache_hits, (100.0 * cache_hits) / cache_accesses );
 
868
    }
 
869
  }
 
870
}
 
871
 
 
872
/*---------------------------------------------------------------------------*/
 
873
 
 
874
static void 
 
875
analyse_file( string_t arguments, grammar_t grammar )
 
876
/* Open the file with name in ARGUMENTS, which must contain a word list
 
877
 * or sentence list, analyse all its lines according to GRAMMAR,
 
878
 * and write the results to a file with extension ".out". */
 
879
 
880
  string_t list_file_name, result_file_name;
 
881
  FILE *input_stream, *output_stream;
 
882
 
 
883
  input_stream = output_stream = NULL;
 
884
  list_file_name = result_file_name = NULL;
 
885
  TRY 
 
886
  { 
 
887
    list_file_name = parse_absolute_path( &arguments, NULL );
 
888
    if (*arguments != EOS) 
 
889
      result_file_name = parse_absolute_path( &arguments, NULL );
 
890
    else 
 
891
      result_file_name = concat_strings( list_file_name, ".out", NULL );
 
892
    parse_end( &arguments );
 
893
    input_stream = open_stream( list_file_name, "r" );
 
894
    output_stream = open_stream( result_file_name, "w" );
 
895
    analyse_stream( grammar, input_stream, output_stream, stdout, FALSE );
 
896
  } 
 
897
  FINALLY 
 
898
  { 
 
899
    close_stream( &input_stream, list_file_name );
 
900
    close_stream( &output_stream, result_file_name );
 
901
    free_mem( &list_file_name );
 
902
    free_mem( &result_file_name );
 
903
  } 
 
904
  END_TRY;
 
905
}
 
906
 
 
907
/*---------------------------------------------------------------------------*/
 
908
 
 
909
static void 
 
910
do_ma_file( string_t arguments )
 
911
/* Analyse file in ARGUMENTS morphologically. */
 
912
{
 
913
  assert_not_in_debug_mode();
 
914
  analyse_file( arguments, MORPHOLOGY );
 
915
}
 
916
 
 
917
static command_t ma_file_command = 
 
918
 
919
  "ma-file maf", do_ma_file,
 
920
  "Analyse a word list file.\n"
 
921
  "Usage: ma-file INPUT_FILE [OUTPUT_FILE]\n"
 
922
  "INPUT_FILE must contain one word form on each line.\n"
 
923
  "The results are written to \"OUTPUT_FILE\".\n"
 
924
  "If OUTPUT_FILE is missing, they are written to \"INPUT_FILE.out\".\n"
 
925
  "\"ma-file\" can't be used in debug mode.\n"
 
926
};
 
927
 
 
928
/*---------------------------------------------------------------------------*/
 
929
 
 
930
static void 
 
931
do_sa_file( string_t arguments )
 
932
/* Analyse file in ARGUMENTS syntactically. */
 
933
 
934
  assert_not_in_debug_mode();
 
935
  if (rule_system[ SYNTAX ] == NULL) 
 
936
    complain( "Syntax rule file not loaded." );
 
937
  analyse_file( arguments, SYNTAX );
 
938
}
 
939
 
 
940
static command_t sa_file_command = 
 
941
 
942
  "sa-file saf", do_sa_file,
 
943
  "Analyse a sentence list file.\n"
 
944
  "Usage: sa-file INPUT_FILE [OUTPUT_FILE]\n"
 
945
  "INPUT_FILE must contain one sentence on each line.\n"
 
946
  "The results are written to \"OUTPUT_FILE\".\n"
 
947
  "If OUTPUT_FILE is missing, they are written to \"INPUT_FILE.out\".\n"
 
948
  "\"sa-file\" can't be used in debug mode.\n"
 
949
};
 
950
 
 
951
/*===========================================================================*/
 
952
 
 
953
static void 
 
954
do_clear_cache( string_t arguments )
 
955
/* Clear the wordform analysis cache. */
 
956
 
957
  parse_end( &arguments );
 
958
  clear_cache();
 
959
}
 
960
 
 
961
static command_t clear_cache_command = 
 
962
 
963
  "clear-cache", do_clear_cache,
 
964
  "Clear the wordform analysis cache.\n"
 
965
  "Usage: clear-cache\n"
 
966
};
 
967
 
 
968
/*---------------------------------------------------------------------------*/
 
969
 
 
970
static void 
 
971
do_info( string_t arguments )
 
972
/* Show information about morphology and syntax. */
 
973
 
974
  parse_end( &arguments );
 
975
  printf( "%s", grammar_info->buffer );
 
976
}
 
977
 
 
978
static command_t info_command = 
 
979
 
980
  "info", do_info,
 
981
  "Show information about current grammar.\n"
 
982
  "Usage: info\n"
 
983
};
 
984
 
 
985
/*---------------------------------------------------------------------------*/
 
986
 
 
987
/* The commands that can be called interactively, in alphabetical order. */
 
988
static command_t *malaga_commands[] = 
 
989
 
990
  &backtrace_command, &break_command, &clear_cache_command, &continue_command,
 
991
  &debug_ma_command, &debug_ma_line_command, &debug_sa_command,
 
992
  &debug_sa_line_command, &debug_state_command, &delete_command, &down_command,
 
993
  &finish_command, &frame_command, &get_command, &help_command, &info_command, 
 
994
  &list_command, &ma_command, &ma_file_command, &ma_line_command, &mg_command, 
 
995
  &next_command, &print_command, &quit_command, &result_command, &run_command, 
 
996
  &sa_command, &sa_file_command, &sa_line_command, &set_command, &sg_command, 
 
997
  &step_command, &transmit_command, &tree_command, &up_command, 
 
998
  &variables_command, &walk_command, &where_command, 
 
999
  NULL
 
1000
};
 
1001
 
 
1002
/*---------------------------------------------------------------------------*/
 
1003
 
 
1004
int 
 
1005
main( int argc, char *argv[] )
 
1006
/* The main function of "malaga". */
 
1007
 
1008
  enum {INTERACTIVE_MODE, MORPHOLOGY_MODE, SYNTAX_MODE} malaga_mode;
 
1009
  int_t i;
 
1010
  string_t project_file, input;
 
1011
  rule_sys_name_t rule_systems[2]; /* Rule systems for debugger. */
 
1012
  grammar_t grammar; /* Grammar for batch mode. */
 
1013
  bool_t expect_quotes;
 
1014
 
 
1015
  expect_quotes = FALSE;
 
1016
  malaga_mode = INTERACTIVE_MODE;
 
1017
  input = NULL;
 
1018
  init_basic( "malaga" );
 
1019
 
 
1020
  /* Parse arguments. */
 
1021
  if (argc == 2) 
 
1022
  { 
 
1023
    if (strcmp_no_case( argv[1], "--version" ) == 0
 
1024
        || strcmp_no_case( argv[1], "-version" ) == 0
 
1025
        || strcmp_no_case( argv[1], "-v" ) == 0) 
 
1026
    { 
 
1027
      program_message();
 
1028
      exit(0);
 
1029
    } 
 
1030
    else if (strcmp_no_case( argv[1], "--help" ) == 0
 
1031
             || strcmp_no_case( argv[1], "-help" ) == 0
 
1032
             || strcmp_no_case( argv[1], "-h" ) == 0) 
 
1033
    { 
 
1034
      printf( "Analyse words and/or sentences according to a Malaga grammar.\n"
 
1035
              "\n"
 
1036
              "Usage:\n"
 
1037
              "malaga PROJECT-FILE               "
 
1038
              "-- Start interactive malaga.\n"
 
1039
              "malaga PROJECT-FILE -m[orphology] "
 
1040
              "-- Run as a morphology filter.\n"
 
1041
              "malaga PROJECT-FILE -s[yntax]     "
 
1042
              "-- Run as a syntax filter.\n"
 
1043
              "malaga -v[ersion]                 "
 
1044
              "-- Print version information.\n"
 
1045
              "malaga -h[elp]                    "
 
1046
              "-- Print this help.\n\n"
 
1047
              "Option \"-i[nput] STRING\" makes malaga analyse STRING.\n"
 
1048
              "Option \"-q[uoted]\" expects quoted lines in filter mode.\n"
 
1049
              "PROJECT_FILE must end on \".pro\".\n" );
 
1050
      exit(0);
 
1051
    }
 
1052
  }
 
1053
  project_file = NULL;
 
1054
  for (i = 1; i < argc; i++) 
 
1055
  { 
 
1056
    if (has_extension( argv[i], "pro" )) 
 
1057
      set_file_name( &project_file, argv[i] );
 
1058
    else if (strcmp_no_case( argv[i], "-morphology" ) == 0
 
1059
             || strcmp_no_case( argv[i], "-m" ) == 0) 
 
1060
    { 
 
1061
      malaga_mode = MORPHOLOGY_MODE; 
 
1062
    } 
 
1063
    else if (strcmp_no_case( argv[i], "-syntax" ) == 0
 
1064
             || strcmp_no_case( argv[i], "-s" ) == 0) 
 
1065
    { 
 
1066
      malaga_mode = SYNTAX_MODE; 
 
1067
    } 
 
1068
    else if (strcmp_no_case( argv[i], "-input" ) == 0
 
1069
             || strcmp_no_case( argv[i], "-i" ) == 0)
 
1070
    {
 
1071
      if (argv[ ++i ] == NULL) 
 
1072
        complain( "Missing string after \"-input\"." );
 
1073
      if (input != NULL) 
 
1074
        complain( "Redundant \"-input\"." );
 
1075
      input = argv[i];
 
1076
    }
 
1077
    else if (strcmp_no_case( argv[i], "-quoted" ) == 0
 
1078
             || strcmp_no_case( argv[i], "-q" ) == 0)
 
1079
    {
 
1080
      expect_quotes = TRUE;
 
1081
    }
 
1082
    else 
 
1083
      complain( "Illegal argument \"%s\".", argv[i] );
 
1084
  }
 
1085
  if (project_file == NULL) 
 
1086
    complain( "Missing project file name." );
 
1087
  init_malaga( project_file );
 
1088
  if (malaga_mode == INTERACTIVE_MODE) 
 
1089
  { 
 
1090
    if (input != NULL) 
 
1091
      complain( "Need \"-morphology\" or \"-syntax\"." );
 
1092
    init_debugger( display_where, malaga_commands );
 
1093
    rule_systems[0].rule_sys = rule_system[ MORPHOLOGY ];
 
1094
    rule_systems[0].name = "mor";
 
1095
    rule_systems[1].rule_sys = rule_system[ SYNTAX ];
 
1096
    rule_systems[1].name = "syn";
 
1097
    init_breakpoints( 2, rule_systems );
 
1098
    init_generation();
 
1099
    program_message();
 
1100
    command_loop( program_name, malaga_commands );
 
1101
    terminate_generation();
 
1102
    terminate_breakpoints();
 
1103
    terminate_debugger();
 
1104
  } 
 
1105
  else
 
1106
  { 
 
1107
    grammar = (malaga_mode == MORPHOLOGY_MODE) ? MORPHOLOGY : SYNTAX;
 
1108
    if (rule_system[ grammar ] == NULL) 
 
1109
      complain( "Rule file not loaded." );
 
1110
    if (input != NULL) 
 
1111
      analyse_input( grammar, input );
 
1112
    else 
 
1113
      analyse_stream( grammar, stdin, stdout, stderr, expect_quotes );
 
1114
  }
 
1115
  stop_display_process();
 
1116
  terminate_malaga();
 
1117
  free_mem( &analysis_input );
 
1118
  free_mem( &project_file );
 
1119
  terminate_basic();
 
1120
  return 0;
 
1121
}
 
1122
 
 
1123
/* End of file. =============================================================*/