*** empty log message ***
[bpt/emacs.git] / lisp / international / ccl.el
CommitLineData
3fdc9c8f 1;;; ccl.el --- CCL (Code Conversion Language) compiler
4ed46869 2
4ed46869 3;; Copyright (C) 1995 Electrotechnical Laboratory, JAPAN.
fa526c4a 4;; Licensed to the Free Software Foundation.
4ed46869
KH
5
6;; Keywords: CCL, mule, multilingual, character set, coding-system
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation; either version 2, or (at your option)
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
369314dc
KH
21;; along with GNU Emacs; see the file COPYING. If not, write to the
22;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23;; Boston, MA 02111-1307, USA.
4ed46869
KH
24
25;;; Commentary:
26
27;; CCL (Code Conversion Language) is a simple programming language to
28;; be used for various kind of code conversion. CCL program is
29;; compiled to CCL code (vector of integers) and executed by CCL
30;; interpreter of Emacs.
31;;
32;; CCL is used for code conversion at process I/O and file I/O for
33;; non-standard coding-system. In addition, it is used for
34;; calculating a code point of X's font from a character code.
35;; However, since CCL is designed as a powerful programming language,
36;; it can be used for more generic calculation. For instance,
37;; combination of three or more arithmetic operations can be
38;; calculated faster than Emacs Lisp.
39;;
40;; Here's the syntax of CCL program in BNF notation.
41;;
42;; CCL_PROGRAM :=
43;; (BUFFER_MAGNIFICATION
44;; CCL_MAIN_BLOCK
45;; [ CCL_EOF_BLOCK ])
46;;
47;; BUFFER_MAGNIFICATION := integer
48;; CCL_MAIN_BLOCK := CCL_BLOCK
49;; CCL_EOF_BLOCK := CCL_BLOCK
50;;
51;; CCL_BLOCK :=
52;; STATEMENT | (STATEMENT [STATEMENT ...])
53;; STATEMENT :=
54;; SET | IF | BRANCH | LOOP | REPEAT | BREAK | READ | WRITE | CALL
55;;
56;; SET :=
57;; (REG = EXPRESSION)
58;; | (REG ASSIGNMENT_OPERATOR EXPRESSION)
59;; | integer
60;;
61;; EXPRESSION := ARG | (EXPRESSION OPERATOR ARG)
62;;
63;; IF := (if EXPRESSION CCL_BLOCK CCL_BLOCK)
64;; BRANCH := (branch EXPRESSION CCL_BLOCK [CCL_BLOCK ...])
65;; LOOP := (loop STATEMENT [STATEMENT ...])
66;; BREAK := (break)
67;; REPEAT :=
68;; (repeat)
69;; | (write-repeat [REG | integer | string])
70;; | (write-read-repeat REG [integer | ARRAY])
71;; READ :=
72;; (read REG ...)
73;; | (read-if (REG OPERATOR ARG) CCL_BLOCK CCL_BLOCK)
74;; | (read-branch REG CCL_BLOCK [CCL_BLOCK ...])
6c7f6058 75;; | (read-multibyte-character REG {charset} REG {code-point})
4ed46869
KH
76;; WRITE :=
77;; (write REG ...)
78;; | (write EXPRESSION)
79;; | (write integer) | (write string) | (write REG ARRAY)
80;; | string
6c7f6058 81;; | (write-multibyte-character REG(charset) REG(codepoint))
6c7f6058 82;; TRANSLATE :=
50443272
KH
83;; (translate-character REG(table) REG(charset) REG(codepoint))
84;; | (translate-character SYMBOL REG(charset) REG(codepoint))
85;; MAP :=
86;; (iterate-multiple-map REG REG MAP-IDs)
87;; | (map-multiple REG REG (MAP-SET))
88;; | (map-single REG REG MAP-ID)
89;; MAP-IDs := MAP-ID ...
90;; MAP-SET := MAP-IDs | (MAP-IDs) MAP-SET
91;; MAP-ID := integer
080bb33e 92;;
4ed46869
KH
93;; CALL := (call ccl-program-name)
94;; END := (end)
95;;
96;; REG := r0 | r1 | r2 | r3 | r4 | r5 | r6 | r7
97;; ARG := REG | integer
98;; OPERATOR :=
99;; + | - | * | / | % | & | '|' | ^ | << | >> | <8 | >8 | //
100;; | < | > | == | <= | >= | != | de-sjis | en-sjis
101;; ASSIGNMENT_OPERATOR :=
102;; += | -= | *= | /= | %= | &= | '|=' | ^= | <<= | >>=
e8dd0160 103;; ARRAY := '[' integer ... ']'
4ed46869
KH
104
105;;; Code:
106
d876a0a0
SE
107(defgroup ccl nil
108 "CCL (Code Conversion Language) compiler."
109 :prefix "ccl-"
110 :group 'i18n)
111
44d086b8 112(defconst ccl-command-table
4ed46869 113 [if branch loop break repeat write-repeat write-read-repeat
6c7f6058
KH
114 read read-if read-branch write call end
115 read-multibyte-character write-multibyte-character
50443272
KH
116 translate-character
117 iterate-multiple-map map-multiple map-single]
44d086b8 118 "Vector of CCL commands (symbols).")
4ed46869
KH
119
120;; Put a property to each symbol of CCL commands for the compiler.
121(let (op (i 0) (len (length ccl-command-table)))
122 (while (< i len)
123 (setq op (aref ccl-command-table i))
124 (put op 'ccl-compile-function (intern (format "ccl-compile-%s" op)))
125 (setq i (1+ i))))
126
44d086b8 127(defconst ccl-code-table
4ed46869
KH
128 [set-register
129 set-short-const
130 set-const
131 set-array
132 jump
133 jump-cond
134 write-register-jump
135 write-register-read-jump
136 write-const-jump
137 write-const-read-jump
138 write-string-jump
139 write-array-read-jump
140 read-jump
141 branch
142 read-register
143 write-expr-const
144 read-branch
145 write-register
146 write-expr-register
147 call
148 write-const-string
149 write-array
150 end
151 set-assign-expr-const
152 set-assign-expr-register
153 set-expr-const
154 set-expr-register
155 jump-cond-expr-const
156 jump-cond-expr-register
157 read-jump-cond-expr-const
158 read-jump-cond-expr-register
6c7f6058 159 ex-cmd
4ed46869 160 ]
44d086b8 161 "Vector of CCL compiled codes (symbols).")
4ed46869 162
44d086b8 163(defconst ccl-extended-code-table
6c7f6058
KH
164 [read-multibyte-character
165 write-multibyte-character
50443272
KH
166 translate-character
167 translate-character-const-tbl
6c7f6058
KH
168 nil nil nil nil nil nil nil nil nil nil nil nil ; 0x04-0x0f
169 iterate-multiple-map
50443272
KH
170 map-multiple
171 map-single
6c7f6058 172 ]
44d086b8 173 "Vector of CCL extended compiled codes (symbols).")
6c7f6058 174
4ed46869
KH
175;; Put a property to each symbol of CCL codes for the disassembler.
176(let (code (i 0) (len (length ccl-code-table)))
177 (while (< i len)
178 (setq code (aref ccl-code-table i))
179 (put code 'ccl-code i)
180 (put code 'ccl-dump-function (intern (format "ccl-dump-%s" code)))
181 (setq i (1+ i))))
182
6c7f6058
KH
183(let (code (i 0) (len (length ccl-extended-code-table)))
184 (while (< i len)
185 (setq code (aref ccl-extended-code-table i))
186 (if code
187 (progn
188 (put code 'ccl-ex-code i)
189 (put code 'ccl-dump-function (intern (format "ccl-dump-%s" code)))))
190 (setq i (1+ i))))
191
4ed46869
KH
192(defconst ccl-jump-code-list
193 '(jump jump-cond write-register-jump write-register-read-jump
194 write-const-jump write-const-read-jump write-string-jump
195 write-array-read-jump read-jump))
196
197;; Put a property `jump-flag' to each CCL code which execute jump in
198;; some way.
199(let ((l ccl-jump-code-list))
200 (while l
201 (put (car l) 'jump-flag t)
202 (setq l (cdr l))))
203
44d086b8 204(defconst ccl-register-table
4ed46869 205 [r0 r1 r2 r3 r4 r5 r6 r7]
44d086b8 206 "Vector of CCL registers (symbols).")
4ed46869
KH
207
208;; Put a property to indicate register number to each symbol of CCL.
209;; registers.
210(let (reg (i 0) (len (length ccl-register-table)))
211 (while (< i len)
212 (setq reg (aref ccl-register-table i))
213 (put reg 'ccl-register-number i)
214 (setq i (1+ i))))
215
44d086b8 216(defconst ccl-arith-table
4ed46869
KH
217 [+ - * / % & | ^ << >> <8 >8 // nil nil nil
218 < > == <= >= != de-sjis en-sjis]
44d086b8 219 "Vector of CCL arithmetic/logical operators (symbols).")
4ed46869
KH
220
221;; Put a property to each symbol of CCL operators for the compiler.
222(let (arith (i 0) (len (length ccl-arith-table)))
223 (while (< i len)
224 (setq arith (aref ccl-arith-table i))
225 (if arith (put arith 'ccl-arith-code i))
226 (setq i (1+ i))))
227
44d086b8 228(defconst ccl-assign-arith-table
4ed46869 229 [+= -= *= /= %= &= |= ^= <<= >>= <8= >8= //=]
44d086b8 230 "Vector of CCL assignment operators (symbols).")
4ed46869
KH
231
232;; Put a property to each symbol of CCL assignment operators for the compiler.
233(let (arith (i 0) (len (length ccl-assign-arith-table)))
234 (while (< i len)
235 (setq arith (aref ccl-assign-arith-table i))
236 (put arith 'ccl-self-arith-code i)
237 (setq i (1+ i))))
238
239(defvar ccl-program-vector nil
240 "Working vector of CCL codes produced by CCL compiler.")
241(defvar ccl-current-ic 0
242 "The current index for `ccl-program-vector'.")
243
244;; Embed integer DATA in `ccl-program-vector' at `ccl-current-ic' and
245;; increment it. If IC is specified, embed DATA at IC.
246(defun ccl-embed-data (data &optional ic)
247 (if ic
248 (aset ccl-program-vector ic data)
249 (aset ccl-program-vector ccl-current-ic data)
250 (setq ccl-current-ic (1+ ccl-current-ic))))
251
982d2673
KH
252;; Embed pair of SYMBOL and PROP where (get SYMBOL PROP) should give
253;; proper index number for SYMBOL. PROP should be
254;; `translation-table-id', `code-conversion-map-id', or
255;; `ccl-program-idx'.
256(defun ccl-embed-symbol (symbol prop)
257 (ccl-embed-data (cons symbol prop)))
258
4ed46869
KH
259;; Embed string STR of length LEN in `ccl-program-vector' at
260;; `ccl-current-ic'.
261(defun ccl-embed-string (len str)
262 (let ((i 0))
263 (while (< i len)
264 (ccl-embed-data (logior (ash (aref str i) 16)
265 (if (< (1+ i) len)
266 (ash (aref str (1+ i)) 8)
267 0)
268 (if (< (+ i 2) len)
269 (aref str (+ i 2))
270 0)))
271 (setq i (+ i 3)))))
272
273;; Embed a relative jump address to `ccl-current-ic' in
274;; `ccl-program-vector' at IC without altering the other bit field.
275(defun ccl-embed-current-address (ic)
276 (let ((relative (- ccl-current-ic (1+ ic))))
277 (aset ccl-program-vector ic
278 (logior (aref ccl-program-vector ic) (ash relative 8)))))
279
280;; Embed CCL code for the operation OP and arguments REG and DATA in
281;; `ccl-program-vector' at `ccl-current-ic' in the following format.
282;; |----------------- integer (28-bit) ------------------|
283;; |------------ 20-bit ------------|- 3-bit --|- 5-bit -|
284;; |------------- DATA -------------|-- REG ---|-- OP ---|
285;; If REG2 is specified, embed a code in the following format.
286;; |------- 17-bit ------|- 3-bit --|- 3-bit --|- 5-bit -|
287;; |-------- DATA -------|-- REG2 --|-- REG ---|-- OP ---|
288
289;; If REG is a CCL register symbol (e.g. r0, r1...), the register
290;; number is embedded. If OP is one of unconditional jumps, DATA is
536477d4 291;; changed to an relative jump address.
4ed46869
KH
292
293(defun ccl-embed-code (op reg data &optional reg2)
294 (if (and (> data 0) (get op 'jump-flag))
295 ;; DATA is an absolute jump address. Make it relative to the
296 ;; next of jump code.
297 (setq data (- data (1+ ccl-current-ic))))
298 (let ((code (logior (get op 'ccl-code)
299 (ash
300 (if (symbolp reg) (get reg 'ccl-register-number) reg) 5)
301 (if reg2
302 (logior (ash (get reg2 'ccl-register-number) 8)
303 (ash data 11))
304 (ash data 8)))))
305 (aset ccl-program-vector ccl-current-ic code)
306 (setq ccl-current-ic (1+ ccl-current-ic))))
307
6c7f6058
KH
308;; extended ccl command format
309;; |- 14-bit -|- 3-bit --|- 3-bit --|- 3-bit --|- 5-bit -|
310;; |- EX-OP --|-- REG3 --|-- REG2 --|-- REG ---|-- OP ---|
311(defun ccl-embed-extended-command (ex-op reg reg2 reg3)
312 (let ((data (logior (ash (get ex-op 'ccl-ex-code) 3)
313 (if (symbolp reg3)
314 (get reg3 'ccl-register-number)
315 0))))
316 (ccl-embed-code 'ex-cmd reg data reg2)))
317
4ed46869
KH
318;; Just advance `ccl-current-ic' by INC.
319(defun ccl-increment-ic (inc)
320 (setq ccl-current-ic (+ ccl-current-ic inc)))
321
4ed46869
KH
322;; If non-nil, index of the start of the current loop.
323(defvar ccl-loop-head nil)
324;; If non-nil, list of absolute addresses of the breaking points of
325;; the current loop.
326(defvar ccl-breaks nil)
327
328;;;###autoload
329(defun ccl-compile (ccl-program)
e8dd0160 330 "Return a compiled code of CCL-PROGRAM as a vector of integer."
4ed46869
KH
331 (if (or (null (consp ccl-program))
332 (null (integerp (car ccl-program)))
333 (null (listp (car (cdr ccl-program)))))
334 (error "CCL: Invalid CCL program: %s" ccl-program))
335 (if (null (vectorp ccl-program-vector))
336 (setq ccl-program-vector (make-vector 8192 0)))
337 (setq ccl-loop-head nil ccl-breaks nil)
338 (setq ccl-current-ic 0)
339
340 ;; The first element is the buffer magnification.
341 (ccl-embed-data (car ccl-program))
342
343 ;; The second element is the address of the start CCL code for
344 ;; processing end of input buffer (we call it eof-processor). We
345 ;; set it later.
346 (ccl-increment-ic 1)
347
348 ;; Compile the main body of the CCL program.
349 (ccl-compile-1 (car (cdr ccl-program)))
350
351 ;; Embed the address of eof-processor.
352 (ccl-embed-data ccl-current-ic 1)
353
354 ;; Then compile eof-processor.
355 (if (nth 2 ccl-program)
356 (ccl-compile-1 (nth 2 ccl-program)))
357
358 ;; At last, embed termination code.
359 (ccl-embed-code 'end 0 0)
360
361 (let ((vec (make-vector ccl-current-ic 0))
362 (i 0))
363 (while (< i ccl-current-ic)
364 (aset vec i (aref ccl-program-vector i))
365 (setq i (1+ i)))
366 vec))
367
368;; Signal syntax error.
369(defun ccl-syntax-error (cmd)
370 (error "CCL: Syntax error: %s" cmd))
371
372;; Check if ARG is a valid CCL register.
373(defun ccl-check-register (arg cmd)
374 (if (get arg 'ccl-register-number)
375 arg
376 (error "CCL: Invalid register %s in %s." arg cmd)))
377
378;; Check if ARG is a valid CCL command.
379(defun ccl-check-compile-function (arg cmd)
380 (or (get arg 'ccl-compile-function)
381 (error "CCL: Invalid command: %s" cmd)))
382
383;; In the following code, most ccl-compile-XXXX functions return t if
384;; they end with unconditional jump, else return nil.
385
386;; Compile CCL-BLOCK (see the syntax above).
387(defun ccl-compile-1 (ccl-block)
388 (let (unconditional-jump
389 cmd)
390 (if (or (integerp ccl-block)
391 (stringp ccl-block)
392 (and ccl-block (symbolp (car ccl-block))))
393 ;; This block consists of single statement.
394 (setq ccl-block (list ccl-block)))
395
396 ;; Now CCL-BLOCK is a list of statements. Compile them one by
397 ;; one.
398 (while ccl-block
399 (setq cmd (car ccl-block))
400 (setq unconditional-jump
401 (cond ((integerp cmd)
402 ;; SET statement for the register 0.
403 (ccl-compile-set (list 'r0 '= cmd)))
404
405 ((stringp cmd)
406 ;; WRITE statement of string argument.
407 (ccl-compile-write-string cmd))
408
409 ((listp cmd)
410 ;; The other statements.
411 (cond ((eq (nth 1 cmd) '=)
412 ;; SET statement of the form `(REG = EXPRESSION)'.
413 (ccl-compile-set cmd))
414
415 ((and (symbolp (nth 1 cmd))
416 (get (nth 1 cmd) 'ccl-self-arith-code))
417 ;; SET statement with an assignment operation.
418 (ccl-compile-self-set cmd))
419
420 (t
421 (funcall (ccl-check-compile-function (car cmd) cmd)
422 cmd))))
423
424 (t
425 (ccl-syntax-error cmd))))
426 (setq ccl-block (cdr ccl-block)))
427 unconditional-jump))
428
429(defconst ccl-max-short-const (ash 1 19))
430(defconst ccl-min-short-const (ash -1 19))
431
432;; Compile SET statement.
433(defun ccl-compile-set (cmd)
434 (let ((rrr (ccl-check-register (car cmd) cmd))
435 (right (nth 2 cmd)))
436 (cond ((listp right)
437 ;; CMD has the form `(RRR = (XXX OP YYY))'.
438 (ccl-compile-expression rrr right))
439
440 ((integerp right)
441 ;; CMD has the form `(RRR = integer)'.
442 (if (and (<= right ccl-max-short-const)
443 (>= right ccl-min-short-const))
444 (ccl-embed-code 'set-short-const rrr right)
445 (ccl-embed-code 'set-const rrr 0)
446 (ccl-embed-data right)))
447
448 (t
449 ;; CMD has the form `(RRR = rrr [ array ])'.
450 (ccl-check-register right cmd)
451 (let ((ary (nth 3 cmd)))
452 (if (vectorp ary)
453 (let ((i 0) (len (length ary)))
454 (ccl-embed-code 'set-array rrr len right)
455 (while (< i len)
456 (ccl-embed-data (aref ary i))
457 (setq i (1+ i))))
458 (ccl-embed-code 'set-register rrr 0 right))))))
459 nil)
460
461;; Compile SET statement with ASSIGNMENT_OPERATOR.
462(defun ccl-compile-self-set (cmd)
463 (let ((rrr (ccl-check-register (car cmd) cmd))
464 (right (nth 2 cmd)))
465 (if (listp right)
466 ;; CMD has the form `(RRR ASSIGN_OP (XXX OP YYY))', compile
467 ;; the right hand part as `(r7 = (XXX OP YYY))' (note: the
468 ;; register 7 can be used for storing temporary value).
469 (progn
470 (ccl-compile-expression 'r7 right)
471 (setq right 'r7)))
472 ;; Now CMD has the form `(RRR ASSIGN_OP ARG)'. Compile it as
473 ;; `(RRR = (RRR OP ARG))'.
474 (ccl-compile-expression
475 rrr
476 (list rrr (intern (substring (symbol-name (nth 1 cmd)) 0 -1)) right)))
477 nil)
478
479;; Compile SET statement of the form `(RRR = EXPR)'.
480(defun ccl-compile-expression (rrr expr)
481 (let ((left (car expr))
482 (op (get (nth 1 expr) 'ccl-arith-code))
483 (right (nth 2 expr)))
484 (if (listp left)
485 (progn
486 ;; EXPR has the form `((EXPR2 OP2 ARG) OP RIGHT)'. Compile
487 ;; the first term as `(r7 = (EXPR2 OP2 ARG)).'
488 (ccl-compile-expression 'r7 left)
489 (setq left 'r7)))
490
491 ;; Now EXPR has the form (LEFT OP RIGHT).
ec3f8be9
KH
492 (if (and (eq rrr left)
493 (< op (length ccl-assign-arith-table)))
4ed46869
KH
494 ;; Compile this SET statement as `(RRR OP= RIGHT)'.
495 (if (integerp right)
496 (progn
497 (ccl-embed-code 'set-assign-expr-const rrr (ash op 3) 'r0)
498 (ccl-embed-data right))
499 (ccl-check-register right expr)
500 (ccl-embed-code 'set-assign-expr-register rrr (ash op 3) right))
501
502 ;; Compile this SET statement as `(RRR = (LEFT OP RIGHT))'.
503 (if (integerp right)
504 (progn
505 (ccl-embed-code 'set-expr-const rrr (ash op 3) left)
506 (ccl-embed-data right))
507 (ccl-check-register right expr)
508 (ccl-embed-code 'set-expr-register
509 rrr
510 (logior (ash op 3) (get right 'ccl-register-number))
511 left)))))
512
513;; Compile WRITE statement with string argument.
514(defun ccl-compile-write-string (str)
515 (let ((len (length str)))
516 (ccl-embed-code 'write-const-string 1 len)
517 (ccl-embed-string len str))
518 nil)
519
520;; Compile IF statement of the form `(if CONDITION TRUE-PART FALSE-PART)'.
521;; If READ-FLAG is non-nil, this statement has the form
522;; `(read-if (REG OPERATOR ARG) TRUE-PART FALSE-PART)'.
523(defun ccl-compile-if (cmd &optional read-flag)
524 (if (and (/= (length cmd) 3) (/= (length cmd) 4))
525 (error "CCL: Invalid number of arguments: %s" cmd))
526 (let ((condition (nth 1 cmd))
527 (true-cmds (nth 2 cmd))
528 (false-cmds (nth 3 cmd))
529 jump-cond-address
530 false-ic)
531 (if (and (listp condition)
532 (listp (car condition)))
533 ;; If CONDITION is a nested expression, the inner expression
534 ;; should be compiled at first as SET statement, i.e.:
535 ;; `(if ((X OP2 Y) OP Z) ...)' is compiled into two statements:
536 ;; `(r7 = (X OP2 Y)) (if (r7 OP Z) ...)'.
537 (progn
538 (ccl-compile-expression 'r7 (car condition))
539 (setq condition (cons 'r7 (cdr condition)))
540 (setq cmd (cons (car cmd)
541 (cons condition (cdr (cdr cmd)))))))
542
543 (setq jump-cond-address ccl-current-ic)
544 ;; Compile CONDITION.
545 (if (symbolp condition)
546 ;; CONDITION is a register.
547 (progn
548 (ccl-check-register condition cmd)
549 (ccl-embed-code 'jump-cond condition 0))
550 ;; CONDITION is a simple expression of the form (RRR OP ARG).
551 (let ((rrr (car condition))
552 (op (get (nth 1 condition) 'ccl-arith-code))
553 (arg (nth 2 condition)))
554 (ccl-check-register rrr cmd)
555 (if (integerp arg)
556 (progn
557 (ccl-embed-code (if read-flag 'read-jump-cond-expr-const
558 'jump-cond-expr-const)
559 rrr 0)
560 (ccl-embed-data op)
561 (ccl-embed-data arg))
562 (ccl-check-register arg cmd)
563 (ccl-embed-code (if read-flag 'read-jump-cond-expr-register
564 'jump-cond-expr-register)
565 rrr 0)
566 (ccl-embed-data op)
567 (ccl-embed-data (get arg 'ccl-register-number)))))
568
569 ;; Compile TRUE-PART.
570 (let ((unconditional-jump (ccl-compile-1 true-cmds)))
571 (if (null false-cmds)
572 ;; This is the place to jump to if condition is false.
1a30e04c
KH
573 (progn
574 (ccl-embed-current-address jump-cond-address)
575 (setq unconditional-jump nil))
4ed46869
KH
576 (let (end-true-part-address)
577 (if (not unconditional-jump)
578 (progn
579 ;; If TRUE-PART does not end with unconditional jump, we
580 ;; have to jump to the end of FALSE-PART from here.
581 (setq end-true-part-address ccl-current-ic)
582 (ccl-embed-code 'jump 0 0)))
583 ;; This is the place to jump to if CONDITION is false.
584 (ccl-embed-current-address jump-cond-address)
585 ;; Compile FALSE-PART.
586 (setq unconditional-jump
587 (and (ccl-compile-1 false-cmds) unconditional-jump))
588 (if end-true-part-address
589 ;; This is the place to jump to after the end of TRUE-PART.
590 (ccl-embed-current-address end-true-part-address))))
591 unconditional-jump)))
592
593;; Compile BRANCH statement.
594(defun ccl-compile-branch (cmd)
595 (if (< (length cmd) 3)
596 (error "CCL: Invalid number of arguments: %s" cmd))
597 (ccl-compile-branch-blocks 'branch
598 (ccl-compile-branch-expression (nth 1 cmd) cmd)
599 (cdr (cdr cmd))))
600
601;; Compile READ statement of the form `(read-branch EXPR BLOCK0 BLOCK1 ...)'.
602(defun ccl-compile-read-branch (cmd)
603 (if (< (length cmd) 3)
604 (error "CCL: Invalid number of arguments: %s" cmd))
605 (ccl-compile-branch-blocks 'read-branch
606 (ccl-compile-branch-expression (nth 1 cmd) cmd)
607 (cdr (cdr cmd))))
608
609;; Compile EXPRESSION part of BRANCH statement and return register
610;; which holds a value of the expression.
611(defun ccl-compile-branch-expression (expr cmd)
612 (if (listp expr)
613 ;; EXPR has the form `(EXPR2 OP ARG)'. Compile it as SET
614 ;; statement of the form `(r7 = (EXPR2 OP ARG))'.
615 (progn
616 (ccl-compile-expression 'r7 expr)
617 'r7)
618 (ccl-check-register expr cmd)))
619
620;; Compile BLOCKs of BRANCH statement. CODE is 'branch or 'read-branch.
621;; REG is a register which holds a value of EXPRESSION part. BLOCKs
622;; is a list of CCL-BLOCKs.
623(defun ccl-compile-branch-blocks (code rrr blocks)
624 (let ((branches (length blocks))
625 branch-idx
626 jump-table-head-address
627 empty-block-indexes
628 block-tail-addresses
629 block-unconditional-jump)
630 (ccl-embed-code code rrr branches)
631 (setq jump-table-head-address ccl-current-ic)
632 ;; The size of jump table is the number of blocks plus 1 (for the
633 ;; case RRR is out of range).
634 (ccl-increment-ic (1+ branches))
635 (setq empty-block-indexes (list branches))
636 ;; Compile each block.
637 (setq branch-idx 0)
638 (while blocks
639 (if (null (car blocks))
640 ;; This block is empty.
641 (setq empty-block-indexes (cons branch-idx empty-block-indexes)
642 block-unconditional-jump t)
643 ;; This block is not empty.
644 (ccl-embed-data (- ccl-current-ic jump-table-head-address)
645 (+ jump-table-head-address branch-idx))
646 (setq block-unconditional-jump (ccl-compile-1 (car blocks)))
647 (if (not block-unconditional-jump)
648 (progn
649 ;; Jump address of the end of branches are embedded later.
650 ;; For the moment, just remember where to embed them.
651 (setq block-tail-addresses
652 (cons ccl-current-ic block-tail-addresses))
653 (ccl-embed-code 'jump 0 0))))
654 (setq branch-idx (1+ branch-idx))
655 (setq blocks (cdr blocks)))
656 (if (not block-unconditional-jump)
657 ;; We don't need jump code at the end of the last block.
658 (setq block-tail-addresses (cdr block-tail-addresses)
659 ccl-current-ic (1- ccl-current-ic)))
660 ;; Embed jump address at the tailing jump commands of blocks.
661 (while block-tail-addresses
662 (ccl-embed-current-address (car block-tail-addresses))
663 (setq block-tail-addresses (cdr block-tail-addresses)))
664 ;; For empty blocks, make entries in the jump table point directly here.
665 (while empty-block-indexes
666 (ccl-embed-data (- ccl-current-ic jump-table-head-address)
667 (+ jump-table-head-address (car empty-block-indexes)))
668 (setq empty-block-indexes (cdr empty-block-indexes))))
669 ;; Branch command ends by unconditional jump if RRR is out of range.
670 nil)
671
672;; Compile LOOP statement.
673(defun ccl-compile-loop (cmd)
674 (if (< (length cmd) 2)
675 (error "CCL: Invalid number of arguments: %s" cmd))
676 (let* ((ccl-loop-head ccl-current-ic)
677 (ccl-breaks nil)
678 unconditional-jump)
679 (setq cmd (cdr cmd))
680 (if cmd
681 (progn
682 (setq unconditional-jump t)
683 (while cmd
684 (setq unconditional-jump
685 (and (ccl-compile-1 (car cmd)) unconditional-jump))
686 (setq cmd (cdr cmd)))
687 (if (not ccl-breaks)
688 unconditional-jump
689 ;; Embed jump address for break statements encountered in
690 ;; this loop.
691 (while ccl-breaks
692 (ccl-embed-current-address (car ccl-breaks))
693 (setq ccl-breaks (cdr ccl-breaks))))
694 nil))))
695
696;; Compile BREAK statement.
697(defun ccl-compile-break (cmd)
698 (if (/= (length cmd) 1)
699 (error "CCL: Invalid number of arguments: %s" cmd))
700 (if (null ccl-loop-head)
701 (error "CCL: No outer loop: %s" cmd))
702 (setq ccl-breaks (cons ccl-current-ic ccl-breaks))
703 (ccl-embed-code 'jump 0 0)
704 t)
705
706;; Compile REPEAT statement.
707(defun ccl-compile-repeat (cmd)
708 (if (/= (length cmd) 1)
709 (error "CCL: Invalid number of arguments: %s" cmd))
710 (if (null ccl-loop-head)
711 (error "CCL: No outer loop: %s" cmd))
712 (ccl-embed-code 'jump 0 ccl-loop-head)
713 t)
714
715;; Compile WRITE-REPEAT statement.
716(defun ccl-compile-write-repeat (cmd)
717 (if (/= (length cmd) 2)
718 (error "CCL: Invalid number of arguments: %s" cmd))
719 (if (null ccl-loop-head)
720 (error "CCL: No outer loop: %s" cmd))
721 (let ((arg (nth 1 cmd)))
722 (cond ((integerp arg)
723 (ccl-embed-code 'write-const-jump 0 ccl-loop-head)
724 (ccl-embed-data arg))
725 ((stringp arg)
726 (let ((len (length arg))
727 (i 0))
728 (ccl-embed-code 'write-string-jump 0 ccl-loop-head)
729 (ccl-embed-data len)
730 (ccl-embed-string len arg)))
731 (t
732 (ccl-check-register arg cmd)
733 (ccl-embed-code 'write-register-jump arg ccl-loop-head))))
734 t)
735
736;; Compile WRITE-READ-REPEAT statement.
737(defun ccl-compile-write-read-repeat (cmd)
738 (if (or (< (length cmd) 2) (> (length cmd) 3))
739 (error "CCL: Invalid number of arguments: %s" cmd))
740 (if (null ccl-loop-head)
741 (error "CCL: No outer loop: %s" cmd))
742 (let ((rrr (ccl-check-register (nth 1 cmd) cmd))
743 (arg (nth 2 cmd)))
744 (cond ((null arg)
745 (ccl-embed-code 'write-register-read-jump rrr ccl-loop-head))
746 ((integerp arg)
747 (ccl-embed-code 'write-const-read-jump rrr arg ccl-loop-head))
748 ((vectorp arg)
749 (let ((len (length arg))
750 (i 0))
751 (ccl-embed-code 'write-array-read-jump rrr ccl-loop-head)
752 (ccl-embed-data len)
753 (while (< i len)
754 (ccl-embed-data (aref arg i))
755 (setq i (1+ i)))))
756 (t
757 (error "CCL: Invalid argument %s: %s" arg cmd)))
758 (ccl-embed-code 'read-jump rrr ccl-loop-head))
759 t)
760
761;; Compile READ statement.
762(defun ccl-compile-read (cmd)
763 (if (< (length cmd) 2)
764 (error "CCL: Invalid number of arguments: %s" cmd))
765 (let* ((args (cdr cmd))
766 (i (1- (length args))))
767 (while args
768 (let ((rrr (ccl-check-register (car args) cmd)))
769 (ccl-embed-code 'read-register rrr i)
770 (setq args (cdr args) i (1- i)))))
771 nil)
772
773;; Compile READ-IF statement.
774(defun ccl-compile-read-if (cmd)
775 (ccl-compile-if cmd 'read))
776
777;; Compile WRITE statement.
778(defun ccl-compile-write (cmd)
779 (if (< (length cmd) 2)
780 (error "CCL: Invalid number of arguments: %s" cmd))
781 (let ((rrr (nth 1 cmd)))
782 (cond ((integerp rrr)
783 (ccl-embed-code 'write-const-string 0 rrr))
784 ((stringp rrr)
785 (ccl-compile-write-string rrr))
786 ((and (symbolp rrr) (vectorp (nth 2 cmd)))
787 (ccl-check-register rrr cmd)
788 ;; CMD has the form `(write REG ARRAY)'.
789 (let* ((arg (nth 2 cmd))
790 (len (length arg))
791 (i 0))
792 (ccl-embed-code 'write-array rrr len)
793 (while (< i len)
794 (if (not (integerp (aref arg i)))
795 (error "CCL: Invalid argument %s: %s" arg cmd))
796 (ccl-embed-data (aref arg i))
797 (setq i (1+ i)))))
798
799 ((symbolp rrr)
800 ;; CMD has the form `(write REG ...)'.
801 (let* ((args (cdr cmd))
802 (i (1- (length args))))
803 (while args
804 (setq rrr (ccl-check-register (car args) cmd))
805 (ccl-embed-code 'write-register rrr i)
806 (setq args (cdr args) i (1- i)))))
807
808 ((listp rrr)
809 ;; CMD has the form `(write (LEFT OP RIGHT))'.
810 (let ((left (car rrr))
811 (op (get (nth 1 rrr) 'ccl-arith-code))
812 (right (nth 2 rrr)))
813 (if (listp left)
814 (progn
815 ;; RRR has the form `((EXPR OP2 ARG) OP RIGHT)'.
816 ;; Compile the first term as `(r7 = (EXPR OP2 ARG))'.
817 (ccl-compile-expression 'r7 left)
818 (setq left 'r7)))
819 ;; Now RRR has the form `(ARG OP RIGHT)'.
820 (if (integerp right)
821 (progn
822 (ccl-embed-code 'write-expr-const 0 (ash op 3) left)
823 (ccl-embed-data right))
824 (ccl-check-register right rrr)
825 (ccl-embed-code 'write-expr-register 0
826 (logior (ash op 3)
827 (get right 'ccl-register-number))))))
828
829 (t
830 (error "CCL: Invalid argument: %s" cmd))))
831 nil)
832
833;; Compile CALL statement.
834(defun ccl-compile-call (cmd)
835 (if (/= (length cmd) 2)
836 (error "CCL: Invalid number of arguments: %s" cmd))
837 (if (not (symbolp (nth 1 cmd)))
838 (error "CCL: Subroutine should be a symbol: %s" cmd))
982d2673
KH
839 (ccl-embed-code 'call 1 0)
840 (ccl-embed-symbol (nth 1 cmd) 'ccl-program-idx)
4ed46869
KH
841 nil)
842
843;; Compile END statement.
844(defun ccl-compile-end (cmd)
845 (if (/= (length cmd) 1)
846 (error "CCL: Invalid number of arguments: %s" cmd))
847 (ccl-embed-code 'end 0 0)
848 t)
849
6c7f6058
KH
850;; Compile read-multibyte-character
851(defun ccl-compile-read-multibyte-character (cmd)
852 (if (/= (length cmd) 3)
853 (error "CCL: Invalid number of arguments: %s" cmd))
854 (let ((RRR (nth 1 cmd))
855 (rrr (nth 2 cmd)))
856 (ccl-check-register rrr cmd)
857 (ccl-check-register RRR cmd)
1a30e04c
KH
858 (ccl-embed-extended-command 'read-multibyte-character rrr RRR 0))
859 nil)
6c7f6058
KH
860
861;; Compile write-multibyte-character
862(defun ccl-compile-write-multibyte-character (cmd)
863 (if (/= (length cmd) 3)
864 (error "CCL: Invalid number of arguments: %s" cmd))
865 (let ((RRR (nth 1 cmd))
866 (rrr (nth 2 cmd)))
867 (ccl-check-register rrr cmd)
868 (ccl-check-register RRR cmd)
1a30e04c
KH
869 (ccl-embed-extended-command 'write-multibyte-character rrr RRR 0))
870 nil)
6c7f6058 871
50443272
KH
872;; Compile translate-character
873(defun ccl-compile-translate-character (cmd)
6c7f6058
KH
874 (if (/= (length cmd) 4)
875 (error "CCL: Invalid number of arguments: %s" cmd))
080bb33e 876 (let ((Rrr (nth 1 cmd))
6c7f6058
KH
877 (RRR (nth 2 cmd))
878 (rrr (nth 3 cmd)))
879 (ccl-check-register rrr cmd)
880 (ccl-check-register RRR cmd)
2ea00696 881 (cond ((and (symbolp Rrr) (not (get Rrr 'ccl-register-number)))
f967223b
KH
882 (if (not (get Rrr 'translation-table))
883 (error "CCL: Invalid translation table %s in %s" Rrr cmd))
50443272
KH
884 (ccl-embed-extended-command 'translate-character-const-tbl
885 rrr RRR 0)
982d2673 886 (ccl-embed-symbol Rrr 'translation-table-id))
6c7f6058
KH
887 (t
888 (ccl-check-register Rrr cmd)
1a30e04c
KH
889 (ccl-embed-extended-command 'translate-character rrr RRR Rrr))))
890 nil)
6c7f6058
KH
891
892(defun ccl-compile-iterate-multiple-map (cmd)
1a30e04c
KH
893 (ccl-compile-multiple-map-function 'iterate-multiple-map cmd)
894 nil)
6c7f6058 895
50443272 896(defun ccl-compile-map-multiple (cmd)
080bb33e 897 (if (/= (length cmd) 4)
6c7f6058 898 (error "CCL: Invalid number of arguments: %s" cmd))
080bb33e
KH
899 (let ((func '(lambda (arg mp)
900 (let ((len 0) result add)
901 (while arg
902 (if (consp (car arg))
903 (setq add (funcall func (car arg) t)
904 result (append result add)
905 add (+ (-(car add)) 1))
906 (setq result
907 (append result
908 (list (car arg)))
909 add 1))
910 (setq arg (cdr arg)
911 len (+ len add)))
912 (if mp
913 (cons (- len) result)
914 result))))
915 arg)
916 (setq arg (append (list (nth 0 cmd) (nth 1 cmd) (nth 2 cmd))
917 (funcall func (nth 3 cmd) nil)))
1a30e04c
KH
918 (ccl-compile-multiple-map-function 'map-multiple arg))
919 nil)
6c7f6058 920
50443272 921(defun ccl-compile-map-single (cmd)
6c7f6058
KH
922 (if (/= (length cmd) 4)
923 (error "CCL: Invalid number of arguments: %s" cmd))
924 (let ((RRR (nth 1 cmd))
925 (rrr (nth 2 cmd))
50443272 926 (map (nth 3 cmd))
6c7f6058
KH
927 id)
928 (ccl-check-register rrr cmd)
929 (ccl-check-register RRR cmd)
50443272
KH
930 (ccl-embed-extended-command 'map-single rrr RRR 0)
931 (cond ((symbolp map)
932 (if (get map 'code-conversion-map)
982d2673 933 (ccl-embed-symbol map 'code-conversion-map-id)
50443272 934 (error "CCL: Invalid map: %s" map)))
080bb33e 935 (t
1a30e04c
KH
936 (error "CCL: Invalid type of arguments: %s" cmd))))
937 nil)
6c7f6058
KH
938
939(defun ccl-compile-multiple-map-function (command cmd)
940 (if (< (length cmd) 4)
941 (error "CCL: Invalid number of arguments: %s" cmd))
942 (let ((RRR (nth 1 cmd))
943 (rrr (nth 2 cmd))
944 (args (nthcdr 3 cmd))
50443272 945 map)
6c7f6058
KH
946 (ccl-check-register rrr cmd)
947 (ccl-check-register RRR cmd)
948 (ccl-embed-extended-command command rrr RRR 0)
949 (ccl-embed-data (length args))
950 (while args
50443272
KH
951 (setq map (car args))
952 (cond ((symbolp map)
953 (if (get map 'code-conversion-map)
982d2673 954 (ccl-embed-symbol map 'code-conversion-map-id)
50443272
KH
955 (error "CCL: Invalid map: %s" map)))
956 ((numberp map)
957 (ccl-embed-data map))
6c7f6058
KH
958 (t
959 (error "CCL: Invalid type of arguments: %s" cmd)))
960 (setq args (cdr args)))))
961
080bb33e 962\f
4ed46869
KH
963;;; CCL dump staffs
964
965;; To avoid byte-compiler warning.
966(defvar ccl-code)
967
968;;;###autoload
969(defun ccl-dump (ccl-code)
970 "Disassemble compiled CCL-CODE."
971 (let ((len (length ccl-code))
972 (buffer-mag (aref ccl-code 0)))
973 (cond ((= buffer-mag 0)
974 (insert "Don't output anything.\n"))
975 ((= buffer-mag 1)
976 (insert "Out-buffer must be as large as in-buffer.\n"))
977 (t
978 (insert
979 (format "Out-buffer must be %d times bigger than in-buffer.\n"
980 buffer-mag))))
981 (insert "Main-body:\n")
982 (setq ccl-current-ic 2)
983 (if (> (aref ccl-code 1) 0)
984 (progn
985 (while (< ccl-current-ic (aref ccl-code 1))
986 (ccl-dump-1))
987 (insert "At EOF:\n")))
988 (while (< ccl-current-ic len)
989 (ccl-dump-1))
990 ))
991
992;; Return a CCL code in `ccl-code' at `ccl-current-ic'.
993(defun ccl-get-next-code ()
994 (prog1
995 (aref ccl-code ccl-current-ic)
996 (setq ccl-current-ic (1+ ccl-current-ic))))
997
998(defun ccl-dump-1 ()
999 (let* ((code (ccl-get-next-code))
1000 (cmd (aref ccl-code-table (logand code 31)))
1001 (rrr (ash (logand code 255) -5))
1002 (cc (ash code -8)))
1003 (insert (format "%5d:[%s] " (1- ccl-current-ic) cmd))
1004 (funcall (get cmd 'ccl-dump-function) rrr cc)))
1005
1006(defun ccl-dump-set-register (rrr cc)
1007 (insert (format "r%d = r%d\n" rrr cc)))
1008
1009(defun ccl-dump-set-short-const (rrr cc)
1010 (insert (format "r%d = %d\n" rrr cc)))
1011
1012(defun ccl-dump-set-const (rrr ignore)
1013 (insert (format "r%d = %d\n" rrr (ccl-get-next-code))))
1014
1015(defun ccl-dump-set-array (rrr cc)
1016 (let ((rrr2 (logand cc 7))
1017 (len (ash cc -3))
1018 (i 0))
1019 (insert (format "r%d = array[r%d] of length %d\n\t"
1020 rrr rrr2 len))
1021 (while (< i len)
1022 (insert (format "%d " (ccl-get-next-code)))
1023 (setq i (1+ i)))
1024 (insert "\n")))
1025
1026(defun ccl-dump-jump (ignore cc &optional address)
1027 (insert (format "jump to %d(" (+ (or address ccl-current-ic) cc)))
1028 (if (>= cc 0)
1029 (insert "+"))
1030 (insert (format "%d)\n" (1+ cc))))
1031
1032(defun ccl-dump-jump-cond (rrr cc)
1033 (insert (format "if (r%d == 0), " rrr))
1034 (ccl-dump-jump nil cc))
1035
1036(defun ccl-dump-write-register-jump (rrr cc)
1037 (insert (format "write r%d, " rrr))
1038 (ccl-dump-jump nil cc))
1039
1040(defun ccl-dump-write-register-read-jump (rrr cc)
1041 (insert (format "write r%d, read r%d, " rrr rrr))
1042 (ccl-dump-jump nil cc)
1043 (ccl-get-next-code) ; Skip dummy READ-JUMP
1044 )
1045
1046(defun ccl-extract-arith-op (cc)
1047 (aref ccl-arith-table (ash cc -6)))
1048
1049(defun ccl-dump-write-expr-const (ignore cc)
1050 (insert (format "write (r%d %s %d)\n"
1051 (logand cc 7)
1052 (ccl-extract-arith-op cc)
1053 (ccl-get-next-code))))
1054
1055(defun ccl-dump-write-expr-register (ignore cc)
1056 (insert (format "write (r%d %s r%d)\n"
1057 (logand cc 7)
1058 (ccl-extract-arith-op cc)
1059 (logand (ash cc -3) 7))))
1060
1061(defun ccl-dump-insert-char (cc)
1062 (cond ((= cc ?\t) (insert " \"^I\""))
1063 ((= cc ?\n) (insert " \"^J\""))
1064 (t (insert (format " \"%c\"" cc)))))
1065
1066(defun ccl-dump-write-const-jump (ignore cc)
1067 (let ((address ccl-current-ic))
1068 (insert "write char")
1069 (ccl-dump-insert-char (ccl-get-next-code))
1070 (insert ", ")
1071 (ccl-dump-jump nil cc address)))
1072
1073(defun ccl-dump-write-const-read-jump (rrr cc)
1074 (let ((address ccl-current-ic))
1075 (insert "write char")
1076 (ccl-dump-insert-char (ccl-get-next-code))
1077 (insert (format ", read r%d, " rrr))
1078 (ccl-dump-jump cc address)
1079 (ccl-get-next-code) ; Skip dummy READ-JUMP
1080 ))
1081
1082(defun ccl-dump-write-string-jump (ignore cc)
1083 (let ((address ccl-current-ic)
1084 (len (ccl-get-next-code))
1085 (i 0))
1086 (insert "write \"")
1087 (while (< i len)
1088 (let ((code (ccl-get-next-code)))
1089 (insert (ash code -16))
1090 (if (< (1+ i) len) (insert (logand (ash code -8) 255)))
1091 (if (< (+ i 2) len) (insert (logand code 255))))
1092 (setq i (+ i 3)))
1093 (insert "\", ")
1094 (ccl-dump-jump nil cc address)))
1095
1096(defun ccl-dump-write-array-read-jump (rrr cc)
1097 (let ((address ccl-current-ic)
1098 (len (ccl-get-next-code))
1099 (i 0))
1100 (insert (format "write array[r%d] of length %d,\n\t" rrr len))
1101 (while (< i len)
1102 (ccl-dump-insert-char (ccl-get-next-code))
1103 (setq i (1+ i)))
1104 (insert (format "\n\tthen read r%d, " rrr))
1105 (ccl-dump-jump nil cc address)
1106 (ccl-get-next-code) ; Skip dummy READ-JUMP.
1107 ))
1108
1109(defun ccl-dump-read-jump (rrr cc)
1110 (insert (format "read r%d, " rrr))
1111 (ccl-dump-jump nil cc))
1112
1113(defun ccl-dump-branch (rrr len)
1114 (let ((jump-table-head ccl-current-ic)
1115 (i 0))
1116 (insert (format "jump to array[r%d] of length %d\n\t" rrr len))
1117 (while (<= i len)
1118 (insert (format "%d " (+ jump-table-head (ccl-get-next-code))))
1119 (setq i (1+ i)))
1120 (insert "\n")))
1121
1122(defun ccl-dump-read-register (rrr cc)
1123 (insert (format "read r%d (%d remaining)\n" rrr cc)))
1124
1125(defun ccl-dump-read-branch (rrr len)
1126 (insert (format "read r%d, " rrr))
1127 (ccl-dump-branch rrr len))
1128
1129(defun ccl-dump-write-register (rrr cc)
1130 (insert (format "write r%d (%d remaining)\n" rrr cc)))
1131
1132(defun ccl-dump-call (ignore cc)
1133 (insert (format "call subroutine #%d\n" cc)))
1134
1135(defun ccl-dump-write-const-string (rrr cc)
1136 (if (= rrr 0)
1137 (progn
1138 (insert "write char")
1139 (ccl-dump-insert-char cc)
1140 (newline))
1141 (let ((len cc)
1142 (i 0))
1143 (insert "write \"")
1144 (while (< i len)
1145 (let ((code (ccl-get-next-code)))
1146 (insert (format "%c" (lsh code -16)))
1147 (if (< (1+ i) len)
1148 (insert (format "%c" (logand (lsh code -8) 255))))
1149 (if (< (+ i 2) len)
1150 (insert (format "%c" (logand code 255))))
1151 (setq i (+ i 3))))
1152 (insert "\"\n"))))
1153
1154(defun ccl-dump-write-array (rrr cc)
1155 (let ((i 0))
1156 (insert (format "write array[r%d] of length %d\n\t" rrr cc))
1157 (while (< i cc)
1158 (ccl-dump-insert-char (ccl-get-next-code))
1159 (setq i (1+ i)))
1160 (insert "\n")))
1161
1162(defun ccl-dump-end (&rest ignore)
1163 (insert "end\n"))
1164
1165(defun ccl-dump-set-assign-expr-const (rrr cc)
1166 (insert (format "r%d %s= %d\n"
1167 rrr
1168 (ccl-extract-arith-op cc)
1169 (ccl-get-next-code))))
1170
1171(defun ccl-dump-set-assign-expr-register (rrr cc)
1172 (insert (format "r%d %s= r%d\n"
1173 rrr
1174 (ccl-extract-arith-op cc)
1175 (logand cc 7))))
1176
1177(defun ccl-dump-set-expr-const (rrr cc)
1178 (insert (format "r%d = r%d %s %d\n"
1179 rrr
1180 (logand cc 7)
1181 (ccl-extract-arith-op cc)
1182 (ccl-get-next-code))))
1183
1184(defun ccl-dump-set-expr-register (rrr cc)
1185 (insert (format "r%d = r%d %s r%d\n"
1186 rrr
1187 (logand cc 7)
1188 (ccl-extract-arith-op cc)
1189 (logand (ash cc -3) 7))))
1190
1191(defun ccl-dump-jump-cond-expr-const (rrr cc)
1192 (let ((address ccl-current-ic))
1193 (insert (format "if !(r%d %s %d), "
1194 rrr
1195 (aref ccl-arith-table (ccl-get-next-code))
1196 (ccl-get-next-code)))
1197 (ccl-dump-jump nil cc address)))
1198
1199(defun ccl-dump-jump-cond-expr-register (rrr cc)
1200 (let ((address ccl-current-ic))
1201 (insert (format "if !(r%d %s r%d), "
1202 rrr
1203 (aref ccl-arith-table (ccl-get-next-code))
1204 (ccl-get-next-code)))
1205 (ccl-dump-jump nil cc address)))
1206
1207(defun ccl-dump-read-jump-cond-expr-const (rrr cc)
1208 (insert (format "read r%d, " rrr))
1209 (ccl-dump-jump-cond-expr-const rrr cc))
1210
1211(defun ccl-dump-read-jump-cond-expr-register (rrr cc)
1212 (insert (format "read r%d, " rrr))
1213 (ccl-dump-jump-cond-expr-register rrr cc))
1214
1215(defun ccl-dump-binary (ccl-code)
1216 (let ((len (length ccl-code))
1217 (i 2))
1218 (while (< i len)
1219 (let ((code (aref ccl-code i))
1220 (j 27))
1221 (while (>= j 0)
1222 (insert (if (= (logand code (ash 1 j)) 0) ?0 ?1))
1223 (setq j (1- j)))
1224 (setq code (logand code 31))
1225 (if (< code (length ccl-code-table))
1226 (insert (format ":%s" (aref ccl-code-table code))))
1227 (insert "\n"))
1228 (setq i (1+ i)))))
1229
6c7f6058
KH
1230(defun ccl-dump-ex-cmd (rrr cc)
1231 (let* ((RRR (logand cc ?\x7))
1232 (Rrr (logand (ash cc -3) ?\x7))
1233 (ex-op (aref ccl-extended-code-table (logand (ash cc -6) ?\x3fff))))
1234 (insert (format "<%s> " ex-op))
1235 (funcall (get ex-op 'ccl-dump-function) rrr RRR Rrr)))
1236
1237(defun ccl-dump-read-multibyte-character (rrr RRR Rrr)
1238 (insert (format "read-multibyte-character r%d r%d\n" RRR rrr)))
1239
1240(defun ccl-dump-write-multibyte-character (rrr RRR Rrr)
1241 (insert (format "write-multibyte-character r%d r%d\n" RRR rrr)))
1242
50443272 1243(defun ccl-dump-translate-character (rrr RRR Rrr)
f967223b 1244 (insert (format "translation table(r%d) r%d r%d\n" Rrr RRR rrr)))
6c7f6058 1245
50443272 1246(defun ccl-dump-translate-character-const-tbl (rrr RRR Rrr)
6c7f6058 1247 (let ((tbl (ccl-get-next-code)))
8137b8e3 1248 (insert (format "translation table(%S) r%d r%d\n" tbl RRR rrr))))
6c7f6058
KH
1249
1250(defun ccl-dump-iterate-multiple-map (rrr RRR Rrr)
1251 (let ((notbl (ccl-get-next-code))
1252 (i 0) id)
1253 (insert (format "iterate-multiple-map r%d r%d\n" RRR rrr))
50443272 1254 (insert (format "\tnumber of maps is %d .\n\t [" notbl))
6c7f6058
KH
1255 (while (< i notbl)
1256 (setq id (ccl-get-next-code))
080bb33e 1257 (insert (format "%S" id))
6c7f6058
KH
1258 (setq i (1+ i)))
1259 (insert "]\n")))
1260
50443272 1261(defun ccl-dump-map-multiple (rrr RRR Rrr)
6c7f6058
KH
1262 (let ((notbl (ccl-get-next-code))
1263 (i 0) id)
50443272
KH
1264 (insert (format "map-multiple r%d r%d\n" RRR rrr))
1265 (insert (format "\tnumber of maps and separators is %d\n\t [" notbl))
6c7f6058
KH
1266 (while (< i notbl)
1267 (setq id (ccl-get-next-code))
1268 (if (= id -1)
1269 (insert "]\n\t [")
080bb33e 1270 (insert (format "%S " id)))
6c7f6058
KH
1271 (setq i (1+ i)))
1272 (insert "]\n")))
1273
50443272 1274(defun ccl-dump-map-single (rrr RRR Rrr)
6c7f6058 1275 (let ((id (ccl-get-next-code)))
50443272 1276 (insert (format "map-single r%d r%d map(%S)\n" RRR rrr id))))
6c7f6058 1277
080bb33e 1278\f
4ed46869
KH
1279;; CCL emulation staffs
1280
1281;; Not yet implemented.
1282\f
080bb33e
KH
1283;; Auto-loaded functions.
1284
4ed46869 1285;;;###autoload
080bb33e 1286(defmacro declare-ccl-program (name &optional vector)
4ed46869
KH
1287 "Declare NAME as a name of CCL program.
1288
982d2673
KH
1289This macro exists for backward compatibility. In the old version of
1290Emacs, to compile a CCL program which calls another CCL program not
1291yet defined, it must be declared as a CCL program in advance. But,
1292now CCL program names are resolved not at compile time but before
1293execution.
1294
080bb33e
KH
1295Optional arg VECTOR is a compiled CCL code of the CCL program."
1296 `(put ',name 'ccl-program-idx (register-ccl-program ',name ,vector)))
4ed46869
KH
1297
1298;;;###autoload
1299(defmacro define-ccl-program (name ccl-program &optional doc)
1300 "Set NAME the compiled code of CCL-PROGRAM.
1301CCL-PROGRAM is `eval'ed before being handed to the CCL compiler `ccl-compile'.
1302The compiled code is a vector of integers."
1303 `(let ((prog ,(ccl-compile (eval ccl-program))))
1304 (defconst ,name prog ,doc)
1305 (put ',name 'ccl-program-idx (register-ccl-program ',name prog))
1306 nil))
1307
080bb33e
KH
1308;;;###autoload
1309(defmacro check-ccl-program (ccl-program &optional name)
1310 "Check validity of CCL-PROGRAM.
982d2673 1311If CCL-PROGRAM is a symbol denoting a CCL program, return
080bb33e
KH
1312CCL-PROGRAM, else return nil.
1313If CCL-PROGRAM is a vector and optional arg NAME (symbol) is supplied,
1314register CCL-PROGRAM by name NAME, and return NAME."
982d2673
KH
1315 `(if (ccl-program-p ,ccl-program)
1316 (if (vectorp ,ccl-program)
1317 (progn
1318 (register-ccl-program ,name ,ccl-program)
1319 ,name)
1320 ,ccl-program)))
080bb33e 1321
4ed46869
KH
1322;;;###autoload
1323(defun ccl-execute-with-args (ccl-prog &rest args)
1324 "Execute CCL-PROGRAM with registers initialized by the remaining args.
e8dd0160 1325The return value is a vector of resulting CCL registers."
4ed46869
KH
1326 (let ((reg (make-vector 8 0))
1327 (i 0))
1328 (while (and args (< i 8))
1329 (if (not (integerp (car args)))
1330 (error "Arguments should be integer"))
1331 (aset reg i (car args))
1332 (setq args (cdr args) i (1+ i)))
1333 (ccl-execute ccl-prog reg)
1334 reg))
1335
1336(provide 'ccl)
1337
1338;; ccl.el ends here