comparison src/mule-ccl.c @ 70:131b0175ea99 r20-0b30

Import from CVS: tag r20-0b30
author cvs
date Mon, 13 Aug 2007 09:02:59 +0200
parents
children 538048ae2ab8
comparison
equal deleted inserted replaced
69:804d1389bcd6 70:131b0175ea99
1 /* CCL -- Code Conversion Language Interpreter
2 Copyright (C) 1992, 1995 Free Software Foundation, Inc.
3 Copyright (C) 1995 Sun Microsystems, Inc.
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 /* Synched up with: Mule 2.3. Not in FSF. */
23
24 #include <config.h>
25 #include "lisp.h"
26
27 #include "buffer.h"
28 #include "mule-coding.h"
29
30 /* CCL operators */
31 #define CCL_SetCS 0x00
32 #define CCL_SetCL 0x01
33 #define CCL_SetR 0x02
34 #define CCL_SetA 0x03
35 #define CCL_Jump 0x04
36 #define CCL_JumpCond 0x05
37 #define CCL_WriteJump 0x06
38 #define CCL_WriteReadJump 0x07
39 #define CCL_WriteCJump 0x08
40 #define CCL_WriteCReadJump 0x09
41 #define CCL_WriteSJump 0x0A
42 #define CCL_WriteSReadJump 0x0B
43 #define CCL_WriteAReadJump 0x0C
44 #define CCL_Branch 0x0D
45 #define CCL_Read1 0x0E
46 #define CCL_Read2 0x0F
47 #define CCL_ReadBranch 0x10
48 #define CCL_Write1 0x11
49 #define CCL_Write2 0x12
50 #define CCL_WriteC 0x13
51 #define CCL_WriteS 0x14
52 #define CCL_WriteA 0x15
53 #define CCL_End 0x16
54 #define CCL_SetSelfCS 0x17
55 #define CCL_SetSelfCL 0x18
56 #define CCL_SetSelfR 0x19
57 #define CCL_SetExprCL 0x1A
58 #define CCL_SetExprR 0x1B
59 #define CCL_JumpCondC 0x1C
60 #define CCL_JumpCondR 0x1D
61 #define CCL_ReadJumpCondC 0x1E
62 #define CCL_ReadJumpCondR 0x1F
63
64 #define CCL_PLUS 0x00
65 #define CCL_MINUS 0x01
66 #define CCL_MUL 0x02
67 #define CCL_DIV 0x03
68 #define CCL_MOD 0x04
69 #define CCL_AND 0x05
70 #define CCL_OR 0x06
71 #define CCL_XOR 0x07
72 #define CCL_LSH 0x08
73 #define CCL_RSH 0x09
74 #define CCL_LSH8 0x0A
75 #define CCL_RSH8 0x0B
76 #define CCL_DIVMOD 0x0C
77 #define CCL_LS 0x10
78 #define CCL_GT 0x11
79 #define CCL_EQ 0x12
80 #define CCL_LE 0x13
81 #define CCL_GE 0x14
82 #define CCL_NE 0x15
83
84 /* Header of CCL compiled code */
85 #define CCL_HEADER_EOF 0
86 #define CCL_HEADER_MAIN 1
87
88 #define CCL_STAT_SUCCESS 0
89 #define CCL_STAT_SUSPEND 1
90 #define CCL_STAT_INVALID_CMD 2
91
92 #define CCL_SUCCESS \
93 ccl->status = CCL_STAT_SUCCESS; \
94 goto ccl_finish
95 #define CCL_SUSPEND \
96 ccl->ic = --ic; \
97 ccl->status = CCL_STAT_SUSPEND; \
98 goto ccl_finish
99 #define CCL_INVALID_CMD \
100 ccl->status = CCL_STAT_INVALID_CMD; \
101 goto ccl_error_handler
102
103 #define CCL_WRITE_CHAR(ch) do \
104 { \
105 if (!src) \
106 { \
107 CCL_INVALID_CMD; \
108 } \
109 else \
110 { \
111 /* !!#### is this correct for both directions????? */ \
112 Bufbyte __buf__[MAX_EMCHAR_LEN]; \
113 int __len__; \
114 __len__ = set_charptr_emchar (__buf__, ch); \
115 Dynarr_add_many (dst, __buf__, __len__); \
116 } \
117 } while (0)
118
119 #define CCL_WRITE_STRING(len) do \
120 { \
121 if (!src) \
122 { \
123 CCL_INVALID_CMD; \
124 } \
125 else \
126 { \
127 for (j = 0; j < len; j++) \
128 Dynarr_add (dst, XINT (prog[ic + 1 + j])); \
129 } \
130 } while (0)
131
132 #define CCL_READ_CHAR(r) do \
133 { \
134 if (!src) \
135 { \
136 CCL_INVALID_CMD; \
137 } \
138 else if (s < s_end) \
139 r = *s++; \
140 else if (end_flag) \
141 { \
142 ic = XINT (prog[CCL_HEADER_EOF]); \
143 continue; \
144 } \
145 else \
146 { \
147 CCL_SUSPEND; \
148 } \
149 } while (0)
150
151
152 /* Run a CCL program. The initial state and program are contained in
153 CCL. SRC, if non-zero, specifies a source string (of size N)
154 to read bytes from, and DST, of non-zero, specifies a destination
155 Dynarr to write bytes to. If END_FLAG is set, it means that
156 the end section of the CCL program should be run rather than
157 the normal section.
158
159 For CCL programs that do not involve code conversion (e.g.
160 converting a single character into a font index), all parameters
161 but the first will usually be 0. */
162
163 int
164 ccl_driver (struct ccl_program *ccl, CONST unsigned char *src,
165 unsigned_char_dynarr *dst, int n, int end_flag)
166 {
167 int code, op, rrr, cc, i, j;
168 CONST unsigned char *s, *s_end;
169 int ic = ccl->ic;
170 int *reg = ccl->reg;
171 Lisp_Object *prog = ccl->prog;
172
173 if (!ic)
174 ic = CCL_HEADER_MAIN;
175
176 if (src)
177 {
178 s = src;
179 s_end = s + n;
180 }
181
182 while (1)
183 {
184 code = XINT (prog[ic++]);
185 op = code & 0x1F;
186 rrr = (code >> 5) & 0x7;
187 cc = code >> 8;
188
189 switch (op)
190 {
191 case CCL_SetCS:
192 reg[rrr] = cc; continue;
193 case CCL_SetCL:
194 reg[rrr] = XINT (prog[ic++]); continue;
195 case CCL_SetR:
196 reg[rrr] = reg[cc]; continue;
197 case CCL_SetA:
198 cc = reg[cc];
199 i = XINT (prog[ic++]);
200 if (cc >= 0 && cc < i)
201 reg[rrr] = XINT (prog[ic + cc]);
202 ic += i;
203 continue;
204 case CCL_Jump:
205 ic = cc; continue;
206 case CCL_JumpCond:
207 if (!reg[rrr])
208 ic = cc;
209 continue;
210 case CCL_WriteJump:
211 CCL_WRITE_CHAR (reg[rrr]);
212 ic = cc;
213 continue;
214 case CCL_WriteReadJump:
215 if (ccl->status != CCL_STAT_SUSPEND)
216 {
217 CCL_WRITE_CHAR (reg[rrr]);
218 }
219 else
220 ccl->status = CCL_STAT_SUCCESS;
221 CCL_READ_CHAR (reg[rrr]);
222 ic = cc;
223 continue;
224 case CCL_WriteCJump:
225 CCL_WRITE_CHAR (XINT (prog[ic]));
226 ic = cc;
227 continue;
228 case CCL_WriteCReadJump:
229 if (ccl->status != CCL_STAT_SUSPEND)
230 {
231 CCL_WRITE_CHAR (XINT (prog[ic]));
232 }
233 else
234 ccl->status = CCL_STAT_SUCCESS;
235 CCL_READ_CHAR (reg[rrr]);
236 ic = cc;
237 continue;
238 case CCL_WriteSJump:
239 i = XINT (prog[ic]);
240 CCL_WRITE_STRING (i);
241 ic = cc;
242 continue;
243 case CCL_WriteSReadJump:
244 if (ccl->status != CCL_STAT_SUSPEND)
245 {
246 i = XINT (prog[ic]);
247 CCL_WRITE_STRING (i);
248 }
249 else
250 ccl->status = CCL_STAT_SUCCESS;
251 CCL_READ_CHAR (reg[rrr]);
252 ic = cc;
253 continue;
254 case CCL_WriteAReadJump:
255 if (ccl->status != CCL_STAT_SUSPEND)
256 {
257 i = XINT (prog[ic]);
258 if (reg[rrr] >= 0 && reg[rrr] < i)
259 CCL_WRITE_CHAR (XINT (prog[ic + 1 + reg[rrr]]));
260 }
261 else
262 ccl->status = CCL_STAT_SUCCESS;
263 CCL_READ_CHAR (reg[rrr]);
264 ic = cc;
265 continue;
266 case CCL_ReadBranch:
267 CCL_READ_CHAR (reg[rrr]);
268 case CCL_Branch:
269 ic = XINT (prog[ic + (((unsigned int) reg[rrr] < cc)
270 ? reg[rrr] : cc)]);
271 continue;
272 case CCL_Read1:
273 CCL_READ_CHAR (reg[rrr]);
274 continue;
275 case CCL_Read2:
276 CCL_READ_CHAR (reg[rrr]);
277 CCL_READ_CHAR (reg[cc]);
278 continue;
279 case CCL_Write1:
280 CCL_WRITE_CHAR (reg[rrr]);
281 continue;
282 case CCL_Write2:
283 CCL_WRITE_CHAR (reg[rrr]);
284 CCL_WRITE_CHAR (reg[cc]);
285 continue;
286 case CCL_WriteC:
287 i = XINT (prog[ic++]);
288 CCL_WRITE_CHAR (i);
289 continue;
290 case CCL_WriteS:
291 cc = XINT (prog[ic]);
292 CCL_WRITE_STRING (cc);
293 ic += cc + 1;
294 continue;
295 case CCL_WriteA:
296 i = XINT (prog[ic++]);
297 cc = reg[rrr];
298 if (cc >= 0 && cc < i)
299 CCL_WRITE_CHAR (XINT (prog[ic + cc]));
300 ic += i;
301 continue;
302 case CCL_End:
303 CCL_SUCCESS;
304 case CCL_SetSelfCS:
305 i = cc;
306 op = XINT (prog[ic++]);
307 goto ccl_set_self;
308 case CCL_SetSelfCL:
309 i = XINT (prog[ic++]);
310 op = XINT (prog[ic++]);
311 goto ccl_set_self;
312 case CCL_SetSelfR:
313 i = reg[cc];
314 op = XINT (prog[ic++]);
315 ccl_set_self:
316 switch (op)
317 {
318 case CCL_PLUS: reg[rrr] += i; break;
319 case CCL_MINUS: reg[rrr] -= i; break;
320 case CCL_MUL: reg[rrr] *= i; break;
321 case CCL_DIV: reg[rrr] /= i; break;
322 case CCL_MOD: reg[rrr] %= i; break;
323 case CCL_AND: reg[rrr] &= i; break;
324 case CCL_OR: reg[rrr] |= i; break;
325 case CCL_XOR: reg[rrr] ^= i; break;
326 case CCL_LSH: reg[rrr] <<= i; break;
327 case CCL_RSH: reg[rrr] >>= i; break;
328 case CCL_LSH8: reg[rrr] <<= 8; reg[rrr] |= i; break;
329 case CCL_RSH8: reg[7] = reg[rrr] & 0xFF; reg[rrr] >>= 8; break;
330 case CCL_DIVMOD: reg[7] = reg[rrr] % i; reg[rrr] /= i; break;
331 case CCL_LS: reg[rrr] = reg[rrr] < i; break;
332 case CCL_GT: reg[rrr] = reg[rrr] > i; break;
333 case CCL_EQ: reg[rrr] = reg[rrr] == i; break;
334 case CCL_LE: reg[rrr] = reg[rrr] <= i; break;
335 case CCL_GE: reg[rrr] = reg[rrr] >= i; break;
336 case CCL_NE: reg[rrr] = reg[rrr] != i; break;
337 default: CCL_INVALID_CMD;
338 }
339 continue;
340 case CCL_SetExprCL:
341 i = reg[cc];
342 j = XINT (prog[ic++]);
343 op = XINT (prog[ic++]);
344 cc = 0;
345 goto ccl_set_expr;
346 case CCL_SetExprR:
347 i = reg[cc];
348 j = reg[XINT (prog[ic++])];
349 op = XINT (prog[ic++]);
350 cc = 0;
351 goto ccl_set_expr;
352 case CCL_ReadJumpCondC:
353 CCL_READ_CHAR (reg[rrr]);
354 case CCL_JumpCondC:
355 i = reg[rrr];
356 j = XINT (prog[ic++]);
357 rrr = 7;
358 op = XINT (prog[ic++]);
359 goto ccl_set_expr;
360 case CCL_ReadJumpCondR:
361 CCL_READ_CHAR (reg[rrr]);
362 case CCL_JumpCondR:
363 i = reg[rrr];
364 j = reg[XINT (prog[ic++])];
365 rrr = 7;
366 op = XINT (prog[ic++]);
367 ccl_set_expr:
368 switch (op)
369 {
370 case CCL_PLUS: reg[rrr] = i + j; break;
371 case CCL_MINUS: reg[rrr] = i - j; break;
372 case CCL_MUL: reg[rrr] = i * j; break;
373 case CCL_DIV: reg[rrr] = i / j; break;
374 case CCL_MOD: reg[rrr] = i % j; break;
375 case CCL_AND: reg[rrr] = i & j; break;
376 case CCL_OR: reg[rrr] = i | j; break;
377 case CCL_XOR: reg[rrr] = i ^ j;; break;
378 case CCL_LSH: reg[rrr] = i << j; break;
379 case CCL_RSH: reg[rrr] = i >> j; break;
380 case CCL_LSH8: reg[rrr] = (i << 8) | j; break;
381 case CCL_RSH8: reg[rrr] = i >> 8; reg[7] = i & 0xFF; break;
382 case CCL_DIVMOD: reg[rrr] = i / j; reg[7] = i % j; break;
383 case CCL_LS: reg[rrr] = i < j; break;
384 case CCL_GT: reg[rrr] = i > j; break;
385 case CCL_EQ: reg[rrr] = i == j; break;
386 case CCL_LE: reg[rrr] = i <= j; break;
387 case CCL_GE: reg[rrr] = i >= j; break;
388 case CCL_NE: reg[rrr] = i != j; break;
389 default: CCL_INVALID_CMD;
390 }
391 if (cc && !reg[rrr])
392 ic = cc;
393 continue;
394 default:
395 CCL_INVALID_CMD;
396 }
397 }
398
399 ccl_error_handler:
400 if (dst)
401 {
402 char buf[200];
403 switch (ccl->status)
404 {
405 case CCL_STAT_INVALID_CMD:
406 sprintf (buf, "CCL: Invalid command (%x).\n", op);
407 break;
408 default:
409 sprintf (buf, "CCL: Unknown error type (%d).\n", ccl->status);
410 }
411 Dynarr_add_many (dst, (unsigned char *) buf, strlen (buf));
412 }
413
414 ccl_finish:
415 ccl->ic = ic;
416 if (dst)
417 return Dynarr_length (dst);
418 else
419 return 0;
420 }
421
422 /* Set up CCL to execute CCL program VAL, with initial register values
423 coming from REGS (NUMREGS of them are specified) and initial
424 instruction counter coming from INITIAL_IC (a value of 0 means
425 start at the beginning of the program, wherever that is).
426 */
427
428 void
429 set_ccl_program (struct ccl_program *ccl, Lisp_Object val, int *regs,
430 int numregs, int initial_ic)
431 {
432 int i;
433
434 ccl->saved_vector = val;
435 ccl->prog = XVECTOR (val)->contents;
436 ccl->size = XVECTOR (val)->size;
437 if (initial_ic == 0)
438 ccl->ic = CCL_HEADER_MAIN;
439 else
440 ccl->ic = initial_ic;
441 for (i = 0; i < numregs; i++)
442 ccl->reg[i] = regs[i];
443 for (; i < 8; i++)
444 ccl->reg[i] = 0;
445 ccl->end_flag = 0;
446 ccl->status = 0;
447 }
448
449 #ifdef emacs
450
451 static void
452 set_ccl_program_from_lisp_values (struct ccl_program *ccl,
453 Lisp_Object prog,
454 Lisp_Object status)
455 {
456 int i;
457 int intregs[8];
458 int ic;
459
460 CHECK_VECTOR (prog);
461 CHECK_VECTOR (status);
462
463 if (vector_length (XVECTOR (status)) != 9)
464 signal_simple_error ("Must specify values for the eight registers and IC",
465 status);
466 for (i = 0; i < 8; i++)
467 {
468 Lisp_Object regval = XVECTOR (status)->contents[i];
469 if (NILP (regval))
470 intregs[i] = 0;
471 else
472 {
473 CHECK_INT (regval);
474 intregs[i] = XINT (regval);
475 }
476 }
477
478 {
479 Lisp_Object lic = XVECTOR (status)->contents[8];
480 if (NILP (lic))
481 ic = 0;
482 else
483 {
484 CHECK_NATNUM (lic);
485 ic = XINT (lic);
486 }
487 }
488
489 set_ccl_program (ccl, prog, intregs, 8, ic);
490 }
491
492 static void
493 set_lisp_status_from_ccl_program (Lisp_Object status,
494 struct ccl_program *ccl)
495 {
496 int i;
497
498 for (i = 0; i < 8; i++)
499 XVECTOR (status)->contents[i] = make_int (ccl->reg[i]);
500 XVECTOR (status)->contents[8] = make_int (ccl->ic);
501 }
502
503
504 DEFUN ("execute-ccl-program", Fexecute_ccl_program, 2, 2, 0, /*
505 Execute CCL-PROGRAM with registers initialized by STATUS.
506 CCL-PROGRAM is a vector of compiled CCL code created by `ccl-compile'.
507 STATUS must be a vector of nine values, specifying the initial value
508 for the R0, R1 .. R7 registers and for the instruction counter IC.
509 A nil value for a register initializer causes the register to be set
510 to 0. A nil value for the IC initializer causes execution to start
511 at the beginning of the program.
512 When the program is done, STATUS is modified (by side-effect) to contain
513 the ending values for the corresponding registers and IC.
514 */
515 (ccl_program, status))
516 {
517 struct ccl_program ccl;
518
519 set_ccl_program_from_lisp_values (&ccl, ccl_program, status);
520 ccl_driver (&ccl, 0, 0, 0, 0);
521 set_lisp_status_from_ccl_program (status, &ccl);
522 return Qnil;
523 }
524
525 DEFUN ("execute-ccl-program-string", Fexecute_ccl_program_string, 3, 3, 0, /*
526 Execute CCL-PROGRAM with initial STATUS on STRING.
527 CCL-PROGRAM is a vector of compiled CCL code created by `ccl-compile'.
528 STATUS must be a vector of nine values, specifying the initial value
529 for the R0, R1 .. R7 registers and for the instruction counter IC.
530 A nil value for a register initializer causes the register to be set
531 to 0. A nil value for the IC initializer causes execution to start
532 at the beginning of the program.
533 When the program is done, STATUS is modified (by side-effect) to contain
534 the ending values for the corresponding registers and IC.
535 Returns the resulting string.
536 */
537 (ccl_program, status, str))
538 {
539 struct ccl_program ccl;
540 Lisp_Object val;
541 int len;
542 unsigned_char_dynarr *outbuf;
543
544 set_ccl_program_from_lisp_values (&ccl, ccl_program, status);
545 CHECK_STRING (str);
546
547 outbuf = Dynarr_new (unsigned char);
548 len = ccl_driver (&ccl, XSTRING_DATA (str), outbuf, XSTRING_LENGTH (str), 0);
549 ccl_driver (&ccl, (unsigned char *) "", outbuf, 0, 1);
550 set_lisp_status_from_ccl_program (status, &ccl);
551
552 val = make_string (Dynarr_atp (outbuf, 0), len);
553 Dynarr_free (outbuf);
554 return val;
555 }
556
557 DEFUN ("ccl-reset-elapsed-time", Fccl_reset_elapsed_time, 0, 0, 0, /*
558 Reset the internal value which holds the time elapsed by CCL interpreter.
559 */
560 ())
561 {
562 error ("Not yet implemented; use `current-process-time'");
563 return Qnil;
564 }
565
566 DEFUN ("ccl-elapsed-time", Fccl_elapsed_time, 0, 0, 0, /*
567 Return the time elapsed by CCL interpreter as cons of user and system time.
568 This measures processor time, not real time. Both values are floating point
569 numbers measured in seconds. If only one overall value can be determined,
570 the return value will be a cons of that value and 0.
571 */
572 ())
573 {
574 error ("Not yet implemented; use `current-process-time'");
575 return Qnil;
576 }
577
578 void
579 syms_of_mule_ccl (void)
580 {
581 DEFSUBR (Fexecute_ccl_program);
582 DEFSUBR (Fexecute_ccl_program_string);
583 DEFSUBR (Fccl_reset_elapsed_time);
584 DEFSUBR (Fccl_elapsed_time);
585 }
586
587 #else /* not emacs */
588 #ifdef standalone
589
590 #include <alloca.h>
591
592 #define INBUF_SIZE 1024
593 #define MAX_CCL_CODE_SIZE 4096
594
595 void
596 main (int argc, char **argv)
597 {
598 FILE *progf;
599 char inbuf[INBUF_SIZE];
600 unsigned_char_dynarr *outbuf;
601 struct ccl_program ccl;
602 int i;
603 Lisp_Object ccl_prog = make_vector (MAX_CCL_CODE_SIZE);
604
605 if (argc < 2)
606 {
607 fprintf (stderr,
608 "Usage: %s ccl_program_file_name <infile >outfile\n",
609 argv[0]);
610 exit (1);
611 }
612
613 if ((progf = fopen (argv[1], "r")) == NULL)
614 {
615 fprintf (stderr, "%s: Can't read file %s", argv[0], argv[1]);
616 exit (1);
617 }
618
619 XVECTOR (ccl_prog)->size = 0;
620 while (fscanf (progf, "%x", &i) == 1)
621 XVECTOR (ccl_prog)->contents[XVECTOR (ccl_prog)->size++] = make_int (i);
622 set_ccl_program (&ccl, ccl_prog, 0, 0, 0);
623
624 outbuf = Dynarr_new (unsigned char);
625
626 while ((i = fread (inbuf, 1, INBUF_SIZE, stdin)) == INBUF_SIZE)
627 {
628 i = ccl_driver (&ccl, inbuf, outbuf, INBUF_SIZE, 0);
629 fwrite (Dynarr_atp (outbuf, 0), 1, i, stdout);
630 }
631 if (i)
632 {
633 i = ccl_driver (&ccl, inbuf, outbuf, i, 1);
634 fwrite (Dynarr_atp (outbuf, 0), 1, i, stdout);
635 }
636
637 fclose (progf);
638 exit (0);
639 }
640 #endif /* standalone */
641 #endif /* not emacs */