*** 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)
b07929cd 515 (setq str (string-as-unibyte str))
4ed46869
KH
516 (let ((len (length str)))
517 (ccl-embed-code 'write-const-string 1 len)
518 (ccl-embed-string len str))
519 nil)
520
521;; Compile IF statement of the form `(if CONDITION TRUE-PART FALSE-PART)'.
522;; If READ-FLAG is non-nil, this statement has the form
523;; `(read-if (REG OPERATOR ARG) TRUE-PART FALSE-PART)'.
524(defun ccl-compile-if (cmd &optional read-flag)
525 (if (and (/= (length cmd) 3) (/= (length cmd) 4))
526 (error "CCL: Invalid number of arguments: %s" cmd))
527 (let ((condition (nth 1 cmd))
528 (true-cmds (nth 2 cmd))
529 (false-cmds (nth 3 cmd))
530 jump-cond-address
531 false-ic)
532 (if (and (listp condition)
533 (listp (car condition)))
534 ;; If CONDITION is a nested expression, the inner expression
535 ;; should be compiled at first as SET statement, i.e.:
536 ;; `(if ((X OP2 Y) OP Z) ...)' is compiled into two statements:
537 ;; `(r7 = (X OP2 Y)) (if (r7 OP Z) ...)'.
538 (progn
539 (ccl-compile-expression 'r7 (car condition))
540 (setq condition (cons 'r7 (cdr condition)))
541 (setq cmd (cons (car cmd)
542 (cons condition (cdr (cdr cmd)))))))
543
544 (setq jump-cond-address ccl-current-ic)
545 ;; Compile CONDITION.
546 (if (symbolp condition)
547 ;; CONDITION is a register.
548 (progn
549 (ccl-check-register condition cmd)
550 (ccl-embed-code 'jump-cond condition 0))
551 ;; CONDITION is a simple expression of the form (RRR OP ARG).
552 (let ((rrr (car condition))
553 (op (get (nth 1 condition) 'ccl-arith-code))
554 (arg (nth 2 condition)))
555 (ccl-check-register rrr cmd)
556 (if (integerp arg)
557 (progn
558 (ccl-embed-code (if read-flag 'read-jump-cond-expr-const
559 'jump-cond-expr-const)
560 rrr 0)
561 (ccl-embed-data op)
562 (ccl-embed-data arg))
563 (ccl-check-register arg cmd)
564 (ccl-embed-code (if read-flag 'read-jump-cond-expr-register
565 'jump-cond-expr-register)
566 rrr 0)
567 (ccl-embed-data op)
568 (ccl-embed-data (get arg 'ccl-register-number)))))
569
570 ;; Compile TRUE-PART.
571 (let ((unconditional-jump (ccl-compile-1 true-cmds)))
572 (if (null false-cmds)
573 ;; This is the place to jump to if condition is false.
1a30e04c
KH
574 (progn
575 (ccl-embed-current-address jump-cond-address)
576 (setq unconditional-jump nil))
4ed46869
KH
577 (let (end-true-part-address)
578 (if (not unconditional-jump)
579 (progn
580 ;; If TRUE-PART does not end with unconditional jump, we
581 ;; have to jump to the end of FALSE-PART from here.
582 (setq end-true-part-address ccl-current-ic)
583 (ccl-embed-code 'jump 0 0)))
584 ;; This is the place to jump to if CONDITION is false.
585 (ccl-embed-current-address jump-cond-address)
586 ;; Compile FALSE-PART.
587 (setq unconditional-jump
588 (and (ccl-compile-1 false-cmds) unconditional-jump))
589 (if end-true-part-address
590 ;; This is the place to jump to after the end of TRUE-PART.
591 (ccl-embed-current-address end-true-part-address))))
592 unconditional-jump)))
593
594;; Compile BRANCH statement.
595(defun ccl-compile-branch (cmd)
596 (if (< (length cmd) 3)
597 (error "CCL: Invalid number of arguments: %s" cmd))
598 (ccl-compile-branch-blocks 'branch
599 (ccl-compile-branch-expression (nth 1 cmd) cmd)
600 (cdr (cdr cmd))))
601
602;; Compile READ statement of the form `(read-branch EXPR BLOCK0 BLOCK1 ...)'.
603(defun ccl-compile-read-branch (cmd)
604 (if (< (length cmd) 3)
605 (error "CCL: Invalid number of arguments: %s" cmd))
606 (ccl-compile-branch-blocks 'read-branch
607 (ccl-compile-branch-expression (nth 1 cmd) cmd)
608 (cdr (cdr cmd))))
609
610;; Compile EXPRESSION part of BRANCH statement and return register
611;; which holds a value of the expression.
612(defun ccl-compile-branch-expression (expr cmd)
613 (if (listp expr)
614 ;; EXPR has the form `(EXPR2 OP ARG)'. Compile it as SET
615 ;; statement of the form `(r7 = (EXPR2 OP ARG))'.
616 (progn
617 (ccl-compile-expression 'r7 expr)
618 'r7)
619 (ccl-check-register expr cmd)))
620
621;; Compile BLOCKs of BRANCH statement. CODE is 'branch or 'read-branch.
622;; REG is a register which holds a value of EXPRESSION part. BLOCKs
623;; is a list of CCL-BLOCKs.
624(defun ccl-compile-branch-blocks (code rrr blocks)
625 (let ((branches (length blocks))
626 branch-idx
627 jump-table-head-address
628 empty-block-indexes
629 block-tail-addresses
630 block-unconditional-jump)
631 (ccl-embed-code code rrr branches)
632 (setq jump-table-head-address ccl-current-ic)
633 ;; The size of jump table is the number of blocks plus 1 (for the
634 ;; case RRR is out of range).
635 (ccl-increment-ic (1+ branches))
636 (setq empty-block-indexes (list branches))
637 ;; Compile each block.
638 (setq branch-idx 0)
639 (while blocks
640 (if (null (car blocks))
641 ;; This block is empty.
642 (setq empty-block-indexes (cons branch-idx empty-block-indexes)
643 block-unconditional-jump t)
644 ;; This block is not empty.
645 (ccl-embed-data (- ccl-current-ic jump-table-head-address)
646 (+ jump-table-head-address branch-idx))
647 (setq block-unconditional-jump (ccl-compile-1 (car blocks)))
648 (if (not block-unconditional-jump)
649 (progn
650 ;; Jump address of the end of branches are embedded later.
651 ;; For the moment, just remember where to embed them.
652 (setq block-tail-addresses
653 (cons ccl-current-ic block-tail-addresses))
654 (ccl-embed-code 'jump 0 0))))
655 (setq branch-idx (1+ branch-idx))
656 (setq blocks (cdr blocks)))
657 (if (not block-unconditional-jump)
658 ;; We don't need jump code at the end of the last block.
659 (setq block-tail-addresses (cdr block-tail-addresses)
660 ccl-current-ic (1- ccl-current-ic)))
661 ;; Embed jump address at the tailing jump commands of blocks.
662 (while block-tail-addresses
663 (ccl-embed-current-address (car block-tail-addresses))
664 (setq block-tail-addresses (cdr block-tail-addresses)))
665 ;; For empty blocks, make entries in the jump table point directly here.
666 (while empty-block-indexes
667 (ccl-embed-data (- ccl-current-ic jump-table-head-address)
668 (+ jump-table-head-address (car empty-block-indexes)))
669 (setq empty-block-indexes (cdr empty-block-indexes))))
670 ;; Branch command ends by unconditional jump if RRR is out of range.
671 nil)
672
673;; Compile LOOP statement.
674(defun ccl-compile-loop (cmd)
675 (if (< (length cmd) 2)
676 (error "CCL: Invalid number of arguments: %s" cmd))
677 (let* ((ccl-loop-head ccl-current-ic)
678 (ccl-breaks nil)
679 unconditional-jump)
680 (setq cmd (cdr cmd))
681 (if cmd
682 (progn
683 (setq unconditional-jump t)
684 (while cmd
685 (setq unconditional-jump
686 (and (ccl-compile-1 (car cmd)) unconditional-jump))
687 (setq cmd (cdr cmd)))
688 (if (not ccl-breaks)
689 unconditional-jump
690 ;; Embed jump address for break statements encountered in
691 ;; this loop.
692 (while ccl-breaks
693 (ccl-embed-current-address (car ccl-breaks))
694 (setq ccl-breaks (cdr ccl-breaks))))
695 nil))))
696
697;; Compile BREAK statement.
698(defun ccl-compile-break (cmd)
699 (if (/= (length cmd) 1)
700 (error "CCL: Invalid number of arguments: %s" cmd))
701 (if (null ccl-loop-head)
702 (error "CCL: No outer loop: %s" cmd))
703 (setq ccl-breaks (cons ccl-current-ic ccl-breaks))
704 (ccl-embed-code 'jump 0 0)
705 t)
706
707;; Compile REPEAT statement.
708(defun ccl-compile-repeat (cmd)
709 (if (/= (length cmd) 1)
710 (error "CCL: Invalid number of arguments: %s" cmd))
711 (if (null ccl-loop-head)
712 (error "CCL: No outer loop: %s" cmd))
713 (ccl-embed-code 'jump 0 ccl-loop-head)
714 t)
715
716;; Compile WRITE-REPEAT statement.
717(defun ccl-compile-write-repeat (cmd)
718 (if (/= (length cmd) 2)
719 (error "CCL: Invalid number of arguments: %s" cmd))
720 (if (null ccl-loop-head)
721 (error "CCL: No outer loop: %s" cmd))
722 (let ((arg (nth 1 cmd)))
723 (cond ((integerp arg)
724 (ccl-embed-code 'write-const-jump 0 ccl-loop-head)
725 (ccl-embed-data arg))
726 ((stringp arg)
b07929cd 727 (setq arg (string-as-unibyte arg))
4ed46869
KH
728 (let ((len (length arg))
729 (i 0))
730 (ccl-embed-code 'write-string-jump 0 ccl-loop-head)
731 (ccl-embed-data len)
732 (ccl-embed-string len arg)))
733 (t
734 (ccl-check-register arg cmd)
735 (ccl-embed-code 'write-register-jump arg ccl-loop-head))))
736 t)
737
738;; Compile WRITE-READ-REPEAT statement.
739(defun ccl-compile-write-read-repeat (cmd)
740 (if (or (< (length cmd) 2) (> (length cmd) 3))
741 (error "CCL: Invalid number of arguments: %s" cmd))
742 (if (null ccl-loop-head)
743 (error "CCL: No outer loop: %s" cmd))
744 (let ((rrr (ccl-check-register (nth 1 cmd) cmd))
745 (arg (nth 2 cmd)))
746 (cond ((null arg)
747 (ccl-embed-code 'write-register-read-jump rrr ccl-loop-head))
748 ((integerp arg)
749 (ccl-embed-code 'write-const-read-jump rrr arg ccl-loop-head))
750 ((vectorp arg)
751 (let ((len (length arg))
752 (i 0))
753 (ccl-embed-code 'write-array-read-jump rrr ccl-loop-head)
754 (ccl-embed-data len)
755 (while (< i len)
756 (ccl-embed-data (aref arg i))
757 (setq i (1+ i)))))
758 (t
759 (error "CCL: Invalid argument %s: %s" arg cmd)))
760 (ccl-embed-code 'read-jump rrr ccl-loop-head))
761 t)
762
763;; Compile READ statement.
764(defun ccl-compile-read (cmd)
765 (if (< (length cmd) 2)
766 (error "CCL: Invalid number of arguments: %s" cmd))
767 (let* ((args (cdr cmd))
768 (i (1- (length args))))
769 (while args
770 (let ((rrr (ccl-check-register (car args) cmd)))
771 (ccl-embed-code 'read-register rrr i)
772 (setq args (cdr args) i (1- i)))))
773 nil)
774
775;; Compile READ-IF statement.
776(defun ccl-compile-read-if (cmd)
777 (ccl-compile-if cmd 'read))
778
779;; Compile WRITE statement.
780(defun ccl-compile-write (cmd)
781 (if (< (length cmd) 2)
782 (error "CCL: Invalid number of arguments: %s" cmd))
783 (let ((rrr (nth 1 cmd)))
784 (cond ((integerp rrr)
785 (ccl-embed-code 'write-const-string 0 rrr))
786 ((stringp rrr)
787 (ccl-compile-write-string rrr))
788 ((and (symbolp rrr) (vectorp (nth 2 cmd)))
789 (ccl-check-register rrr cmd)
790 ;; CMD has the form `(write REG ARRAY)'.
791 (let* ((arg (nth 2 cmd))
792 (len (length arg))
793 (i 0))
794 (ccl-embed-code 'write-array rrr len)
795 (while (< i len)
796 (if (not (integerp (aref arg i)))
797 (error "CCL: Invalid argument %s: %s" arg cmd))
798 (ccl-embed-data (aref arg i))
799 (setq i (1+ i)))))
800
801 ((symbolp rrr)
802 ;; CMD has the form `(write REG ...)'.
803 (let* ((args (cdr cmd))
804 (i (1- (length args))))
805 (while args
806 (setq rrr (ccl-check-register (car args) cmd))
807 (ccl-embed-code 'write-register rrr i)
808 (setq args (cdr args) i (1- i)))))
809
810 ((listp rrr)
811 ;; CMD has the form `(write (LEFT OP RIGHT))'.
812 (let ((left (car rrr))
813 (op (get (nth 1 rrr) 'ccl-arith-code))
814 (right (nth 2 rrr)))
815 (if (listp left)
816 (progn
817 ;; RRR has the form `((EXPR OP2 ARG) OP RIGHT)'.
818 ;; Compile the first term as `(r7 = (EXPR OP2 ARG))'.
819 (ccl-compile-expression 'r7 left)
820 (setq left 'r7)))
821 ;; Now RRR has the form `(ARG OP RIGHT)'.
822 (if (integerp right)
823 (progn
824 (ccl-embed-code 'write-expr-const 0 (ash op 3) left)
825 (ccl-embed-data right))
826 (ccl-check-register right rrr)
827 (ccl-embed-code 'write-expr-register 0
828 (logior (ash op 3)
829 (get right 'ccl-register-number))))))
830
831 (t
832 (error "CCL: Invalid argument: %s" cmd))))
833 nil)
834
835;; Compile CALL statement.
836(defun ccl-compile-call (cmd)
837 (if (/= (length cmd) 2)
838 (error "CCL: Invalid number of arguments: %s" cmd))
839 (if (not (symbolp (nth 1 cmd)))
840 (error "CCL: Subroutine should be a symbol: %s" cmd))
982d2673
KH
841 (ccl-embed-code 'call 1 0)
842 (ccl-embed-symbol (nth 1 cmd) 'ccl-program-idx)
4ed46869
KH
843 nil)
844
845;; Compile END statement.
846(defun ccl-compile-end (cmd)
847 (if (/= (length cmd) 1)
848 (error "CCL: Invalid number of arguments: %s" cmd))
849 (ccl-embed-code 'end 0 0)
850 t)
851
6c7f6058
KH
852;; Compile read-multibyte-character
853(defun ccl-compile-read-multibyte-character (cmd)
854 (if (/= (length cmd) 3)
855 (error "CCL: Invalid number of arguments: %s" cmd))
856 (let ((RRR (nth 1 cmd))
857 (rrr (nth 2 cmd)))
858 (ccl-check-register rrr cmd)
859 (ccl-check-register RRR cmd)
1a30e04c
KH
860 (ccl-embed-extended-command 'read-multibyte-character rrr RRR 0))
861 nil)
6c7f6058
KH
862
863;; Compile write-multibyte-character
864(defun ccl-compile-write-multibyte-character (cmd)
865 (if (/= (length cmd) 3)
866 (error "CCL: Invalid number of arguments: %s" cmd))
867 (let ((RRR (nth 1 cmd))
868 (rrr (nth 2 cmd)))
869 (ccl-check-register rrr cmd)
870 (ccl-check-register RRR cmd)
1a30e04c
KH
871 (ccl-embed-extended-command 'write-multibyte-character rrr RRR 0))
872 nil)
6c7f6058 873
50443272
KH
874;; Compile translate-character
875(defun ccl-compile-translate-character (cmd)
6c7f6058
KH
876 (if (/= (length cmd) 4)
877 (error "CCL: Invalid number of arguments: %s" cmd))
080bb33e 878 (let ((Rrr (nth 1 cmd))
6c7f6058
KH
879 (RRR (nth 2 cmd))
880 (rrr (nth 3 cmd)))
881 (ccl-check-register rrr cmd)
882 (ccl-check-register RRR cmd)
2ea00696 883 (cond ((and (symbolp Rrr) (not (get Rrr 'ccl-register-number)))
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))
bec6f62a
KH
899 (let (func arg)
900 (setq func
901 (lambda (arg mp)
902 (let ((len 0) result add)
903 (while arg
904 (if (consp (car arg))
905 (setq add (funcall func (car arg) t)
906 result (append result add)
907 add (+ (- (car add)) 1))
908 (setq result
909 (append result
910 (list (car arg)))
911 add 1))
912 (setq arg (cdr arg)
913 len (+ len add)))
914 (if mp
915 (cons (- len) result)
916 result))))
080bb33e
KH
917 (setq arg (append (list (nth 0 cmd) (nth 1 cmd) (nth 2 cmd))
918 (funcall func (nth 3 cmd) nil)))
1a30e04c
KH
919 (ccl-compile-multiple-map-function 'map-multiple arg))
920 nil)
6c7f6058 921
50443272 922(defun ccl-compile-map-single (cmd)
6c7f6058
KH
923 (if (/= (length cmd) 4)
924 (error "CCL: Invalid number of arguments: %s" cmd))
925 (let ((RRR (nth 1 cmd))
926 (rrr (nth 2 cmd))
50443272 927 (map (nth 3 cmd))
6c7f6058
KH
928 id)
929 (ccl-check-register rrr cmd)
930 (ccl-check-register RRR cmd)
50443272
KH
931 (ccl-embed-extended-command 'map-single rrr RRR 0)
932 (cond ((symbolp map)
933 (if (get map 'code-conversion-map)
982d2673 934 (ccl-embed-symbol map 'code-conversion-map-id)
50443272 935 (error "CCL: Invalid map: %s" map)))
080bb33e 936 (t
1a30e04c
KH
937 (error "CCL: Invalid type of arguments: %s" cmd))))
938 nil)
6c7f6058
KH
939
940(defun ccl-compile-multiple-map-function (command cmd)
941 (if (< (length cmd) 4)
942 (error "CCL: Invalid number of arguments: %s" cmd))
943 (let ((RRR (nth 1 cmd))
944 (rrr (nth 2 cmd))
945 (args (nthcdr 3 cmd))
50443272 946 map)
6c7f6058
KH
947 (ccl-check-register rrr cmd)
948 (ccl-check-register RRR cmd)
949 (ccl-embed-extended-command command rrr RRR 0)
950 (ccl-embed-data (length args))
951 (while args
50443272
KH
952 (setq map (car args))
953 (cond ((symbolp map)
954 (if (get map 'code-conversion-map)
982d2673 955 (ccl-embed-symbol map 'code-conversion-map-id)
50443272
KH
956 (error "CCL: Invalid map: %s" map)))
957 ((numberp map)
958 (ccl-embed-data map))
6c7f6058
KH
959 (t
960 (error "CCL: Invalid type of arguments: %s" cmd)))
961 (setq args (cdr args)))))
962
080bb33e 963\f
4ed46869
KH
964;;; CCL dump staffs
965
966;; To avoid byte-compiler warning.
967(defvar ccl-code)
968
969;;;###autoload
970(defun ccl-dump (ccl-code)
971 "Disassemble compiled CCL-CODE."
972 (let ((len (length ccl-code))
973 (buffer-mag (aref ccl-code 0)))
974 (cond ((= buffer-mag 0)
975 (insert "Don't output anything.\n"))
976 ((= buffer-mag 1)
977 (insert "Out-buffer must be as large as in-buffer.\n"))
978 (t
979 (insert
980 (format "Out-buffer must be %d times bigger than in-buffer.\n"
981 buffer-mag))))
982 (insert "Main-body:\n")
983 (setq ccl-current-ic 2)
984 (if (> (aref ccl-code 1) 0)
985 (progn
986 (while (< ccl-current-ic (aref ccl-code 1))
987 (ccl-dump-1))
988 (insert "At EOF:\n")))
989 (while (< ccl-current-ic len)
990 (ccl-dump-1))
991 ))
992
993;; Return a CCL code in `ccl-code' at `ccl-current-ic'.
994(defun ccl-get-next-code ()
995 (prog1
996 (aref ccl-code ccl-current-ic)
997 (setq ccl-current-ic (1+ ccl-current-ic))))
998
999(defun ccl-dump-1 ()
1000 (let* ((code (ccl-get-next-code))
1001 (cmd (aref ccl-code-table (logand code 31)))
1002 (rrr (ash (logand code 255) -5))
1003 (cc (ash code -8)))
1004 (insert (format "%5d:[%s] " (1- ccl-current-ic) cmd))
1005 (funcall (get cmd 'ccl-dump-function) rrr cc)))
1006
1007(defun ccl-dump-set-register (rrr cc)
1008 (insert (format "r%d = r%d\n" rrr cc)))
1009
1010(defun ccl-dump-set-short-const (rrr cc)
1011 (insert (format "r%d = %d\n" rrr cc)))
1012
1013(defun ccl-dump-set-const (rrr ignore)
1014 (insert (format "r%d = %d\n" rrr (ccl-get-next-code))))
1015
1016(defun ccl-dump-set-array (rrr cc)
1017 (let ((rrr2 (logand cc 7))
1018 (len (ash cc -3))
1019 (i 0))
1020 (insert (format "r%d = array[r%d] of length %d\n\t"
1021 rrr rrr2 len))
1022 (while (< i len)
1023 (insert (format "%d " (ccl-get-next-code)))
1024 (setq i (1+ i)))
1025 (insert "\n")))
1026
1027(defun ccl-dump-jump (ignore cc &optional address)
1028 (insert (format "jump to %d(" (+ (or address ccl-current-ic) cc)))
1029 (if (>= cc 0)
1030 (insert "+"))
1031 (insert (format "%d)\n" (1+ cc))))
1032
1033(defun ccl-dump-jump-cond (rrr cc)
1034 (insert (format "if (r%d == 0), " rrr))
1035 (ccl-dump-jump nil cc))
1036
1037(defun ccl-dump-write-register-jump (rrr cc)
1038 (insert (format "write r%d, " rrr))
1039 (ccl-dump-jump nil cc))
1040
1041(defun ccl-dump-write-register-read-jump (rrr cc)
1042 (insert (format "write r%d, read r%d, " rrr rrr))
1043 (ccl-dump-jump nil cc)
1044 (ccl-get-next-code) ; Skip dummy READ-JUMP
1045 )
1046
1047(defun ccl-extract-arith-op (cc)
1048 (aref ccl-arith-table (ash cc -6)))
1049
1050(defun ccl-dump-write-expr-const (ignore cc)
1051 (insert (format "write (r%d %s %d)\n"
1052 (logand cc 7)
1053 (ccl-extract-arith-op cc)
1054 (ccl-get-next-code))))
1055
1056(defun ccl-dump-write-expr-register (ignore cc)
1057 (insert (format "write (r%d %s r%d)\n"
1058 (logand cc 7)
1059 (ccl-extract-arith-op cc)
1060 (logand (ash cc -3) 7))))
1061
1062(defun ccl-dump-insert-char (cc)
1063 (cond ((= cc ?\t) (insert " \"^I\""))
1064 ((= cc ?\n) (insert " \"^J\""))
1065 (t (insert (format " \"%c\"" cc)))))
1066
1067(defun ccl-dump-write-const-jump (ignore cc)
1068 (let ((address ccl-current-ic))
1069 (insert "write char")
1070 (ccl-dump-insert-char (ccl-get-next-code))
1071 (insert ", ")
1072 (ccl-dump-jump nil cc address)))
1073
1074(defun ccl-dump-write-const-read-jump (rrr cc)
1075 (let ((address ccl-current-ic))
1076 (insert "write char")
1077 (ccl-dump-insert-char (ccl-get-next-code))
1078 (insert (format ", read r%d, " rrr))
1079 (ccl-dump-jump cc address)
1080 (ccl-get-next-code) ; Skip dummy READ-JUMP
1081 ))
1082
1083(defun ccl-dump-write-string-jump (ignore cc)
1084 (let ((address ccl-current-ic)
1085 (len (ccl-get-next-code))
1086 (i 0))
1087 (insert "write \"")
1088 (while (< i len)
1089 (let ((code (ccl-get-next-code)))
1090 (insert (ash code -16))
1091 (if (< (1+ i) len) (insert (logand (ash code -8) 255)))
1092 (if (< (+ i 2) len) (insert (logand code 255))))
1093 (setq i (+ i 3)))
1094 (insert "\", ")
1095 (ccl-dump-jump nil cc address)))
1096
1097(defun ccl-dump-write-array-read-jump (rrr cc)
1098 (let ((address ccl-current-ic)
1099 (len (ccl-get-next-code))
1100 (i 0))
1101 (insert (format "write array[r%d] of length %d,\n\t" rrr len))
1102 (while (< i len)
1103 (ccl-dump-insert-char (ccl-get-next-code))
1104 (setq i (1+ i)))
1105 (insert (format "\n\tthen read r%d, " rrr))
1106 (ccl-dump-jump nil cc address)
1107 (ccl-get-next-code) ; Skip dummy READ-JUMP.
1108 ))
1109
1110(defun ccl-dump-read-jump (rrr cc)
1111 (insert (format "read r%d, " rrr))
1112 (ccl-dump-jump nil cc))
1113
1114(defun ccl-dump-branch (rrr len)
1115 (let ((jump-table-head ccl-current-ic)
1116 (i 0))
1117 (insert (format "jump to array[r%d] of length %d\n\t" rrr len))
1118 (while (<= i len)
1119 (insert (format "%d " (+ jump-table-head (ccl-get-next-code))))
1120 (setq i (1+ i)))
1121 (insert "\n")))
1122
1123(defun ccl-dump-read-register (rrr cc)
1124 (insert (format "read r%d (%d remaining)\n" rrr cc)))
1125
1126(defun ccl-dump-read-branch (rrr len)
1127 (insert (format "read r%d, " rrr))
1128 (ccl-dump-branch rrr len))
1129
1130(defun ccl-dump-write-register (rrr cc)
1131 (insert (format "write r%d (%d remaining)\n" rrr cc)))
1132
1133(defun ccl-dump-call (ignore cc)
1134 (insert (format "call subroutine #%d\n" cc)))
1135
1136(defun ccl-dump-write-const-string (rrr cc)
1137 (if (= rrr 0)
1138 (progn
1139 (insert "write char")
1140 (ccl-dump-insert-char cc)
1141 (newline))
1142 (let ((len cc)
1143 (i 0))
1144 (insert "write \"")
1145 (while (< i len)
1146 (let ((code (ccl-get-next-code)))
1147 (insert (format "%c" (lsh code -16)))
1148 (if (< (1+ i) len)
1149 (insert (format "%c" (logand (lsh code -8) 255))))
1150 (if (< (+ i 2) len)
1151 (insert (format "%c" (logand code 255))))
1152 (setq i (+ i 3))))
1153 (insert "\"\n"))))
1154
1155(defun ccl-dump-write-array (rrr cc)
1156 (let ((i 0))
1157 (insert (format "write array[r%d] of length %d\n\t" rrr cc))
1158 (while (< i cc)
1159 (ccl-dump-insert-char (ccl-get-next-code))
1160 (setq i (1+ i)))
1161 (insert "\n")))
1162
1163(defun ccl-dump-end (&rest ignore)
1164 (insert "end\n"))
1165
1166(defun ccl-dump-set-assign-expr-const (rrr cc)
1167 (insert (format "r%d %s= %d\n"
1168 rrr
1169 (ccl-extract-arith-op cc)
1170 (ccl-get-next-code))))
1171
1172(defun ccl-dump-set-assign-expr-register (rrr cc)
1173 (insert (format "r%d %s= r%d\n"
1174 rrr
1175 (ccl-extract-arith-op cc)
1176 (logand cc 7))))
1177
1178(defun ccl-dump-set-expr-const (rrr cc)
1179 (insert (format "r%d = r%d %s %d\n"
1180 rrr
1181 (logand cc 7)
1182 (ccl-extract-arith-op cc)
1183 (ccl-get-next-code))))
1184
1185(defun ccl-dump-set-expr-register (rrr cc)
1186 (insert (format "r%d = r%d %s r%d\n"
1187 rrr
1188 (logand cc 7)
1189 (ccl-extract-arith-op cc)
1190 (logand (ash cc -3) 7))))
1191
1192(defun ccl-dump-jump-cond-expr-const (rrr cc)
1193 (let ((address ccl-current-ic))
1194 (insert (format "if !(r%d %s %d), "
1195 rrr
1196 (aref ccl-arith-table (ccl-get-next-code))
1197 (ccl-get-next-code)))
1198 (ccl-dump-jump nil cc address)))
1199
1200(defun ccl-dump-jump-cond-expr-register (rrr cc)
1201 (let ((address ccl-current-ic))
1202 (insert (format "if !(r%d %s r%d), "
1203 rrr
1204 (aref ccl-arith-table (ccl-get-next-code))
1205 (ccl-get-next-code)))
1206 (ccl-dump-jump nil cc address)))
1207
1208(defun ccl-dump-read-jump-cond-expr-const (rrr cc)
1209 (insert (format "read r%d, " rrr))
1210 (ccl-dump-jump-cond-expr-const rrr cc))
1211
1212(defun ccl-dump-read-jump-cond-expr-register (rrr cc)
1213 (insert (format "read r%d, " rrr))
1214 (ccl-dump-jump-cond-expr-register rrr cc))
1215
1216(defun ccl-dump-binary (ccl-code)
1217 (let ((len (length ccl-code))
1218 (i 2))
1219 (while (< i len)
1220 (let ((code (aref ccl-code i))
1221 (j 27))
1222 (while (>= j 0)
1223 (insert (if (= (logand code (ash 1 j)) 0) ?0 ?1))
1224 (setq j (1- j)))
1225 (setq code (logand code 31))
1226 (if (< code (length ccl-code-table))
1227 (insert (format ":%s" (aref ccl-code-table code))))
1228 (insert "\n"))
1229 (setq i (1+ i)))))
1230
6c7f6058
KH
1231(defun ccl-dump-ex-cmd (rrr cc)
1232 (let* ((RRR (logand cc ?\x7))
1233 (Rrr (logand (ash cc -3) ?\x7))
1234 (ex-op (aref ccl-extended-code-table (logand (ash cc -6) ?\x3fff))))
1235 (insert (format "<%s> " ex-op))
1236 (funcall (get ex-op 'ccl-dump-function) rrr RRR Rrr)))
1237
1238(defun ccl-dump-read-multibyte-character (rrr RRR Rrr)
1239 (insert (format "read-multibyte-character r%d r%d\n" RRR rrr)))
1240
1241(defun ccl-dump-write-multibyte-character (rrr RRR Rrr)
1242 (insert (format "write-multibyte-character r%d r%d\n" RRR rrr)))
1243
50443272 1244(defun ccl-dump-translate-character (rrr RRR Rrr)
f967223b 1245 (insert (format "translation table(r%d) r%d r%d\n" Rrr RRR rrr)))
6c7f6058 1246
50443272 1247(defun ccl-dump-translate-character-const-tbl (rrr RRR Rrr)
6c7f6058 1248 (let ((tbl (ccl-get-next-code)))
8137b8e3 1249 (insert (format "translation table(%S) r%d r%d\n" tbl RRR rrr))))
6c7f6058
KH
1250
1251(defun ccl-dump-iterate-multiple-map (rrr RRR Rrr)
1252 (let ((notbl (ccl-get-next-code))
1253 (i 0) id)
1254 (insert (format "iterate-multiple-map r%d r%d\n" RRR rrr))
50443272 1255 (insert (format "\tnumber of maps is %d .\n\t [" notbl))
6c7f6058
KH
1256 (while (< i notbl)
1257 (setq id (ccl-get-next-code))
080bb33e 1258 (insert (format "%S" id))
6c7f6058
KH
1259 (setq i (1+ i)))
1260 (insert "]\n")))
1261
50443272 1262(defun ccl-dump-map-multiple (rrr RRR Rrr)
6c7f6058
KH
1263 (let ((notbl (ccl-get-next-code))
1264 (i 0) id)
50443272
KH
1265 (insert (format "map-multiple r%d r%d\n" RRR rrr))
1266 (insert (format "\tnumber of maps and separators is %d\n\t [" notbl))
6c7f6058
KH
1267 (while (< i notbl)
1268 (setq id (ccl-get-next-code))
1269 (if (= id -1)
1270 (insert "]\n\t [")
080bb33e 1271 (insert (format "%S " id)))
6c7f6058
KH
1272 (setq i (1+ i)))
1273 (insert "]\n")))
1274
50443272 1275(defun ccl-dump-map-single (rrr RRR Rrr)
6c7f6058 1276 (let ((id (ccl-get-next-code)))
50443272 1277 (insert (format "map-single r%d r%d map(%S)\n" RRR rrr id))))
6c7f6058 1278
080bb33e 1279\f
4ed46869
KH
1280;; CCL emulation staffs
1281
1282;; Not yet implemented.
1283\f
080bb33e
KH
1284;; Auto-loaded functions.
1285
4ed46869 1286;;;###autoload
080bb33e 1287(defmacro declare-ccl-program (name &optional vector)
4ed46869
KH
1288 "Declare NAME as a name of CCL program.
1289
982d2673
KH
1290This macro exists for backward compatibility. In the old version of
1291Emacs, to compile a CCL program which calls another CCL program not
1292yet defined, it must be declared as a CCL program in advance. But,
1293now CCL program names are resolved not at compile time but before
1294execution.
1295
080bb33e
KH
1296Optional arg VECTOR is a compiled CCL code of the CCL program."
1297 `(put ',name 'ccl-program-idx (register-ccl-program ',name ,vector)))
4ed46869
KH
1298
1299;;;###autoload
1300(defmacro define-ccl-program (name ccl-program &optional doc)
1301 "Set NAME the compiled code of CCL-PROGRAM.
1302CCL-PROGRAM is `eval'ed before being handed to the CCL compiler `ccl-compile'.
1303The compiled code is a vector of integers."
1304 `(let ((prog ,(ccl-compile (eval ccl-program))))
1305 (defconst ,name prog ,doc)
1306 (put ',name 'ccl-program-idx (register-ccl-program ',name prog))
1307 nil))
1308
080bb33e
KH
1309;;;###autoload
1310(defmacro check-ccl-program (ccl-program &optional name)
1311 "Check validity of CCL-PROGRAM.
982d2673 1312If CCL-PROGRAM is a symbol denoting a CCL program, return
080bb33e
KH
1313CCL-PROGRAM, else return nil.
1314If CCL-PROGRAM is a vector and optional arg NAME (symbol) is supplied,
1315register CCL-PROGRAM by name NAME, and return NAME."
982d2673
KH
1316 `(if (ccl-program-p ,ccl-program)
1317 (if (vectorp ,ccl-program)
1318 (progn
1319 (register-ccl-program ,name ,ccl-program)
1320 ,name)
1321 ,ccl-program)))
080bb33e 1322
4ed46869
KH
1323;;;###autoload
1324(defun ccl-execute-with-args (ccl-prog &rest args)
1325 "Execute CCL-PROGRAM with registers initialized by the remaining args.
e8dd0160 1326The return value is a vector of resulting CCL registers."
4ed46869
KH
1327 (let ((reg (make-vector 8 0))
1328 (i 0))
1329 (while (and args (< i 8))
1330 (if (not (integerp (car args)))
1331 (error "Arguments should be integer"))
1332 (aset reg i (car args))
1333 (setq args (cdr args) i (1+ i)))
1334 (ccl-execute ccl-prog reg)
1335 reg))
1336
1337(provide 'ccl)
1338
1339;; ccl.el ends here