1
/* This file is part of Malaga, a system for Natural Language Analysis.
2
* Copyright (C) 1995-1999 Bjoern Beutel
5
* Universitaet Erlangen-Nuernberg
6
* Abteilung fuer Computerlinguistik
9
* e-mail: malaga@linguistik.uni-erlangen.de
11
* This program is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License as published by
13
* the Free Software Foundation; either version 2 of the License, or
14
* (at your option) any later version.
16
* This program is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
* GNU General Public License for more details.
21
* You should have received a copy of the GNU General Public License
22
* along with this program; if not, write to the Free Software
23
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
25
/* description ==============================================================*/
27
/* This module manages the emission of instructions and keeps track of the
28
* stack index. It also holds buffers for the compiled code. */
30
/* includes =================================================================*/
39
#include "rule_type.h"
41
#include "malaga_files.h"
46
#include "rule_code.h"
48
/* variables ================================================================*/
50
LOCAL instr_t *instr_stack;
51
/* The instruction stack. The associated constant values are stored in
53
LOCAL int_t instr_stack_size; /* the size of <instr_stack>. */
55
/* functions ================================================================*/
57
GLOBAL void init_rule_code (int_t file_type)
58
/* Initialise this module.
59
* <code> will contain compilation data for a file of <file_type>.
60
* <file_type> may be ALLO_RULE_FILE, MORPHO_RULE_FILE, or SYNTAX_RULE_FILE. */
62
code.file_type = file_type;
64
code.next_instr_index = 0;
65
code.rule_pool = new_pool (sizeof (rule_t));
66
code.rule_set_pool = new_pool (sizeof (int_t));
67
code.instr_pool = new_pool (sizeof (instr_t));
68
code.value_pool = new_pool (sizeof (cell_t));
69
code.string_pool = new_pool (sizeof (char));
70
code.src_line_pool = new_pool (sizeof (src_line_t));
71
code.var_pool = new_pool (sizeof (var_t));
72
code.var_scope_pool = new_pool (sizeof (var_scope_t));
74
instr_stack_size = 50;
75
instr_stack = new_vector (sizeof (instr_t), instr_stack_size);
79
/*---------------------------------------------------------------------------*/
81
GLOBAL void term_rule_code (void)
82
/* Terminate this module. */
84
free_pool (&code.rule_pool);
85
free_pool (&code.rule_set_pool);
86
free_pool (&code.instr_pool);
87
free_pool (&code.value_pool);
88
free_pool (&code.string_pool);
89
free_pool (&code.src_line_pool);
90
free_pool (&code.var_pool);
91
free_pool (&code.var_scope_pool);
92
free_mem (&instr_stack);
95
/*---------------------------------------------------------------------------*/
97
GLOBAL void write_code (string_t file_name)
98
/* Write <code> to <file_name>. */
101
rule_header_t rule_header;
103
stream = open_stream (file_name, "wb");
105
/* Set rule file header data. */
106
set_header (&rule_header.common_header, RULE_FILE, RULE_CODE_VERSION);
107
rule_header.initial_rule_set = code.initial_rule_set;
108
rule_header.initial_cat = code.initial_cat;
109
rule_header.robust_rule = code.robust_rule;
110
rule_header.pruning_rule = code.pruning_rule;
111
rule_header.allo_rule = code.allo_rule;
112
rule_header.input_filter = code.input_filter;
113
rule_header.output_filter = code.output_filter;
114
rule_header.rules_size = pool_items (code.rule_pool);
115
rule_header.rule_sets_size = pool_items (code.rule_set_pool);
116
rule_header.instrs_size = pool_items (code.instr_pool);
117
rule_header.values_size = pool_items (code.value_pool);
118
rule_header.src_lines_size = pool_items (code.src_line_pool);
119
rule_header.vars_size = pool_items (code.var_pool);
120
rule_header.var_scopes_size = pool_items (code.var_scope_pool);
121
rule_header.strings_size = pool_items (code.string_pool);
123
/* Write the header. */
124
write_vector (&rule_header, sizeof (rule_header), 1, stream, file_name);
126
/* Write the tables. */
127
write_pool (code.rule_pool, stream, file_name);
128
write_pool (code.rule_set_pool, stream, file_name);
129
write_pool (code.instr_pool, stream, file_name);
130
write_pool (code.value_pool, stream, file_name);
131
write_pool (code.src_line_pool, stream, file_name);
132
write_pool (code.var_pool, stream, file_name);
133
write_pool (code.var_scope_pool, stream, file_name);
134
write_pool (code.string_pool, stream, file_name);
136
close_stream (&stream, file_name);
139
/*---------------------------------------------------------------------------*/
141
LOCAL void set_stack_index (int_t opcode, int_t info)
142
/* Set the stack index according to the given instruction. */
144
/* We can not check for stack overflow here (sorry), because in
145
* "choose" and "foreach", a PUSH_NULL instruction is patched, so
146
* stack index is (transiently) not quite the real thing. */
153
case INS_UNARY_MINUS_OP:
154
case INS_GET_ATTRIBUTE:
155
case INS_REMOVE_ATTRIBUTE:
156
case INS_STD_FUNCTION:
158
case INS_GET_1ST_ELEMENT:
163
/* These instructions leave the stack size unchanged. */
167
case INS_PUSH_SYMBOL:
168
case INS_PUSH_PATTERN_VAR:
169
case INS_JUMP_SUBRULE: /* subtract number of parameters from stack_index */
173
code.stack_index += info;
175
case INS_ADD_END_STATE:
177
case INS_TERMINATE_IF_NULL:
178
case INS_DOT_OPERATION:
179
case INS_PLUS_OPERATION:
180
case INS_MINUS_OPERATION:
181
case INS_ASTERISK_OPERATION:
182
case INS_SLASH_OPERATION:
186
case INS_ASTERISK_VAR:
188
case INS_JUMP_IF_NULL:
189
case INS_JUMP_IF_NOT_NULL:
190
case INS_JUMP_IF_YES:
192
case INS_ACCEPT: /* no instruction after this instruction is executed. */
193
case INS_RETURN: /* no instruction after this instruction is executed. */
197
case INS_SET_VAR_PATH:
198
case INS_PLUS_VAR_PATH:
199
case INS_MINUS_VAR_PATH:
200
case INS_ASTERISK_VAR_PATH:
201
case INS_SLASH_VAR_PATH:
202
case INS_JUMP_IF_EQUAL:
203
case INS_JUMP_IF_NOT_EQUAL:
204
case INS_JUMP_IF_CONGR:
205
case INS_JUMP_IF_NOT_CONGR:
207
case INS_JUMP_IF_NOT_IN:
208
case INS_JUMP_IF_LESS:
209
case INS_JUMP_IF_NOT_LESS:
210
case INS_JUMP_IF_GREATER:
211
case INS_JUMP_IF_NOT_GREATER:
212
code.stack_index -= 2;
215
code.stack_index -= info;
219
code.stack_index -= (info - 1);
221
case INS_BUILD_RECORD:
222
code.stack_index -= (2*info - 1);
225
error ("internal (instruction %d unknown in rule_code)", opcode);
229
/*---------------------------------------------------------------------------*/
231
LOCAL instr_t *local_emit_instr (int_t opcode, int_t info)
232
/* Emit an instruction to the instruction pool. DO NOT FLUSH BUFFER!
233
* Return the address of the instruction in the pool. */
238
if (info < INSTR_INFO_MIN || info > INSTR_INFO_MAX)
239
error ("internal (instruction info out of range)");
241
/* Fill the next instruction */
242
instr = INSTR (opcode, info);
244
/* Generate instruction. */
245
instr_ptr = (instr_t *) copy_to_pool (code.instr_pool, &instr, 1, NULL);
246
set_stack_index (opcode, info);
247
code.next_instr_index = pool_items (code.instr_pool);
252
/* functions that support constant folding of values ========================*/
254
LOCAL void put_instr (int_t opcode, int_t info)
255
/* Put the instruction (<opcode>,<info>) at <instr_stack[top-1]>. */
257
if (top > instr_stack_size)
258
instr_stack_size = renew_vector (&instr_stack, sizeof (u_int_t), 2 * top);
259
instr_stack[top-1] = INSTR (opcode, info);
262
/*---------------------------------------------------------------------------*/
264
GLOBAL void buffer_instr (int_t opcode, int_t info)
265
/* Buffer the instructions BUILD_LIST, BUILD_RECORD, PUSH_SYMBOL,
266
* and PUSH_CONST for constant folding. */
269
DB_ASSERT (info >= INSTR_INFO_MIN && info <= INSTR_INFO_MAX);
273
case INS_PUSH_SYMBOL:
274
push_symbol_value (info);
275
put_instr (INS_PUSH_SYMBOL, info);
279
push_value ((value_t) pool_item (code.value_pool, info));
280
put_instr (INS_PUSH_CONST, info);
284
if (top >= info) /* Execute the operation in the buffer. */
287
put_instr (INS_PUSH_CONST, -1);
290
emit_instr (opcode, info);
293
case INS_BUILD_RECORD:
294
if (top >= 2*info) /* Execute the operation in the buffer. */
297
put_instr (INS_PUSH_CONST, -1);
300
emit_instr (opcode, info);
304
if (top >= info) /* Execute the operation in the buffer. */
307
put_instr (INS_PUSH_CONST, -1);
310
emit_instr (opcode, info);
313
case INS_DOT_OPERATION:
314
case INS_PLUS_OPERATION:
315
case INS_MINUS_OPERATION:
316
case INS_ASTERISK_OPERATION:
317
case INS_SLASH_OPERATION:
318
if (top >= 2) /* Execute the operation in the buffer. */
322
case INS_DOT_OPERATION:
325
case INS_PLUS_OPERATION:
328
case INS_MINUS_OPERATION:
331
case INS_ASTERISK_OPERATION:
332
asterisk_operation ();
334
case INS_SLASH_OPERATION:
338
error ("internal (unknown instruction in constant folding)");
340
put_instr (INS_PUSH_CONST, -1);
343
emit_instr (opcode, info);
346
case INS_UNARY_MINUS_OP:
347
case INS_GET_ATTRIBUTE:
348
case INS_REMOVE_ATTRIBUTE:
349
if (top >= 1) /* Execute the operation in the buffer. */
353
case INS_UNARY_MINUS_OP:
354
unary_minus_operation ();
356
case INS_GET_ATTRIBUTE:
357
push_value (get_attribute (value_stack[--top], info));
359
case INS_REMOVE_ATTRIBUTE:
360
remove_attribute (info);
363
error ("internal (unknown instruction in constant folding)");
365
put_instr (INS_PUSH_CONST, -1);
368
emit_instr (opcode, info);
372
emit_instr (opcode, info);
377
/*---------------------------------------------------------------------------*/
379
GLOBAL void buffer_push_number_instr (double number)
380
/* Buffer the instruction PUSH_CONST with <number> converted to a value. */
382
push_number_value (number);
383
put_instr (INS_PUSH_CONST, -1);
386
/*---------------------------------------------------------------------------*/
388
GLOBAL void buffer_push_string_instr (string_t string, string_t string_end)
389
/* Buffer the instruction PUSH_CONST with the given value. */
391
push_string_value (string, string_end);
392
put_instr (INS_PUSH_CONST, -1);
395
/*---------------------------------------------------------------------------*/
397
GLOBAL void flush_buffer (void)
398
/* Emit the instructions that are still in the buffer. */
402
for (i = 0; i < top; i++)
404
switch (OPCODE (instr_stack[i]))
410
if (INSTR_INFO (instr_stack[i]) == -1)
411
copy_value_to_pool (code.value_pool, value_stack[i], &value_index);
413
value_index = INSTR_INFO (instr_stack[i]);
415
local_emit_instr (INS_PUSH_CONST, value_index);
419
case INS_PUSH_SYMBOL:
420
local_emit_instr (INS_PUSH_SYMBOL, INSTR_INFO (instr_stack[i]));
428
/*---------------------------------------------------------------------------*/
430
GLOBAL value_t get_buffer_top_value (void)
431
/* Test if the buffer contains a value and return the top value. */
434
error ("internal (buffer is empty)");
436
return value_stack[top-1];
439
/*---------------------------------------------------------------------------*/
441
GLOBAL value_t pop_buffer_top_value (void)
442
/* Pop the top value in the buffer. */
445
error ("internal (buffer is empty)");
447
return value_stack[--top];
450
/*---------------------------------------------------------------------------*/
452
GLOBAL instr_t *emit_instr (int_t opcode, int_t info)
453
/* Emit an instruction to the instruction pool (flushes buffer before)
454
* and return the address of the instruction in the pool. */
457
return local_emit_instr (opcode, info);
460
/* end of file ==============================================================*/