;;; -*- Emacs-Lisp -*- ;;; $Id: irex-auto.el,v 3.1 1998/11/24 12:45:51 tsuchiya Exp $ ;; This file is part of IREX tools. ;; Please refer "Copyright file" at the root directory. ;; (C) IREX committee IREX実行委員会. All rights reserved. ;;; 依存関係の宣言 (provide 'irex-auto) (require 'irex-input) (require 'irex-judge) (require 'irex-tougou) ;;; 変数の宣言 (defvar irex-auto-judge-sexp nil "自動判定用 S 式を格納している変数") (defvar irex-auto-judge-history nil "自動判定用 S 式の一番最近の入力文字列") (defvar irex-auto-judge-alist nil "自動判定用 S 式中に現れる判定者のシンボルの連想配列") ;;;---------------------------------------------------------------------- ;;; S 式を入力するための関数 ;;;---------------------------------------------------------------------- (defun irex-auto-judge-input () "\ 自動判定用 S 式を入力するためのコマンド" (interactive) (let ((i 0) slist jstr) (irex-input-string (concat "\ # 自動判定用S式を入力してください。 # # 入力されたS式に含まれている # (\"J1\" . \"A\") # という形式の1つの cons cell は、「判定者 J1 の判定したスコアが A である」 # という条件をみたす場合に t となるようなS式に置換されます。したがって、 # (and (\"J1\" . \"A\") (\"J2\" . \"A\") \"A\") # というS式は、「判定者 J1 の判定したスコアが A であり、かつ、判定者 J2 の # 判定したスコアが A である時、その記事のスコアを A とする」という意味にな # ります。cond , if , and , or などの全ての特殊表現と関数及び整数が利用で # きます。また、以下の変数が利用できます。 # docno : 判定の対象となっている記事の記事番号 # line : 判定の対象となっている記事の表示順位 # (記事リストバッファの左端に表示されている整数) # x,y,z : 一時変数 (自由に利用して下さい) # 従って、表示順位によってS式の返り値を変更することが可能です。 # (cond # ((and (< line 50) (\"J1\" . \"A\") (\"J2\" . \"A\")) \"A\") # ((and (> line 200) (\"J1\" . \"C\") (\"J2\" . \"C\")) \"C\")) # なお、S式の返り値がスコアとして有効な値ではなかった場合(nil,t など)は、 # 単に無視されます。 # # 現在の判定者の指定は次のようになっています。 # (記事リストバッファの左からの表示順序に対応しています。) " (mapconcat '(lambda (pid) (setq i (1+ i)) (setq irex-auto-judge-alist (cons (cons (format "J%d" i) pid) irex-auto-judge-alist)) (format "# J%-2d : %s" i (cond ((string-match "^1" pid) (setq slist (cons (format "J%d" i) slist)) "Student judge") ((string-match "^2" pid) "Executive judge") ((string-match "^9" pid) "God's judge") (t "Undefined")) )) (delete irex-judge-current-pid (irex-tougou-get-all-judge-list)) "\n") " # # リストの入力が終ったら、C-c C-c と入力して下さい。(Ctrl キーを押しながら c を2回押す) # リストの入力を中断する場合は、C-c C-g と入力して下さい。 ") (or irex-auto-judge-history (concat "(cond\n" (mapconcat '(lambda (r) (format " ((and %s) \"%s\")" (mapconcat '(lambda (j) (format "(\"%s\" . \"%s\")" j r)) (reverse slist) " ") r)) '("A" "B" "C") "\n") ")")) 'irex-auto-judge-input-exit 'irex-auto-judge-input-quit t))) (defun irex-auto-judge-input-quit () "\ 自動判定用 S 式の入力を中断するコマンド " (interactive) (irex-judge-split-window) (select-window (get-buffer-window (get-buffer irex-list-buffer-name) t))) (defun irex-auto-judge-input-exit () "\ 自動判定用 S 式の入力を終了するコマンド ユーザーの入力が正常に論理式に変換できた場合は、その式を利用して各記事の 自動判定を行ない、その後 irex-judge を実行できるようにウインドウ配置を変 更する。正常に変換できなかった場合は何もしない。 " (interactive) (goto-char (point-min)) (if (search-forward irex-input-prompt nil t) (if (irex-auto-read-from-buffer) ;; ユーザーの入力が正常に論理式に変換できた場合 (let (r (c 0)) (mapcar '(lambda (docno) (and (setq r (let ((line (irex-list-get-line docno)) x y z) (eval irex-auto-judge-sexp))) (stringp r) (string-match "^[A-C]\\??$" r) (irex-list-change-score docno r) (setq c (1+ c)))) (irex-tougou-get-all-docno-list)) (irex-judge-split-window) (select-window (get-buffer-window (get-buffer irex-list-buffer-name) t)) (setq irex-auto-judge-alist nil irex-auto-judge-sexp nil) (message "%d 個の記事を自動判定しました。" c))) (message "指示された場所に入力して下さい。") (irex-auto-judge-input))) (defun irex-auto-exit () "自動判定用論理式の履歴をクリアする関数" (setq irex-auto-judge-history nil)) ;;;---------------------------------------------------------------------- ;;; 入力された S 式から論理式を生成する関数 ;;;---------------------------------------------------------------------- (defun irex-auto-read-from-buffer () "\ バッファからリストを読みとり論理式を生成する関数 (buffer-substring (point) (point-max)) からリストを読みとり、判定用論理式を 生成する。その過程でなんらかのエラーが生じた場合 nil を返す。正常に論理式が 生成された場合は irex-auto-judge-sexp にその論理式を設定して、t を返す。また、 論理式を生成するために用いた部分文字列を irex-auto-judge-history に保存する。 " (condition-case err (progn (skip-chars-forward " \t\n\f\r") ; Lisp 式までの空白を無視する (or (and (eobp) ; 何も入力されていない場合は何もしない (progn (setq irex-auto-judge-sexp nil) t)) ;; ユーザーの入力した文字列をリストにする (let* ((s (buffer-substring (point) (save-excursion (goto-char (point-max)) (skip-chars-backward " \t\n\f\r") (point)))) (r (read-from-string s))) (or (= (length s) (cdr r)) ; ユーザーが余分な構文要素を入力していないか検査 (error "S 式を1つだけ入力して下さい。")) ;; ユーザーの入力したリストを論理式に変換する (setq irex-auto-judge-sexp (irex-auto-logic-generate (car r))) ;; ユーザーの入力を履歴に保存する (setq irex-auto-judge-history s) t))) ; 正常に S 式が入力された場合は t を返す (error (princ (format "%s" (if (equal err '(end-of-file)) '(error "S 式を解析中にバッファの終端に達しました。") err))) nil))) ; error が発生した場合は nil を返す (defun irex-auto-logic-generate (logic) "\ ユーザーの入力したリストから論理式を生成するための関数 JUDGE-SYMBOL が nil 以外の場合は、リスト中に含まれている J1,J2... などの 判定者の PID を表す文字列を置換する。 " (cond ;; ある判定者の判定したスコアについての条件文は ("123" . "A") のように ;; cons-cell の形で表現し、適切な Lisp 式を生成して返す。 ((and (consp logic) (stringp (car logic)) (stringp (cdr logic))) (let ((j (upcase (car logic)))) (if (assoc j irex-auto-judge-alist) (setq j (cdr (assoc j irex-auto-judge-alist)))) (if (and (string-match "[0-9]+" j) (string-match "[A-C]\\??" (upcase (cdr logic)))) (list 'equal (list 'irex-tougou-get-judge_info-score 'docno j) (upcase (cdr logic))) (error "判定者またはスコアの指定が間違っています : %s" (prin1-to-string logic)) ))) ;; A,B... などの文字列は自動判定結果を返すための自己評価形式とみなす ((and (stringp logic) (string-match "[A-C]\\??" (upcase logic))) (upcase logic)) ;; 関数や t, nil, docno, line, x, y, z を指定された場合はそのまま返す ((and (symbolp logic) (or (fboundp logic) ; 関数 (eq logic t) ; literal (eq logic nil) (eq logic 'docno) ; 判定対象の docno (eq logic 'line) ; 判定対象の記事リストバッファ内での表示順位 (eq logic 'x) ; ユーザーが自由に利用できる一時変数 (eq logic 'y) (eq logic 'z))) logic) ;; 整数の場合はそのまま返す ((integerp logic) logic) ;; リストの場合は再帰的に解析 ((listp logic) (mapcar 'irex-auto-logic-generate logic)) ;; それ以外はエラー (t (error "解析できない要素があります : %s" (prin1-to-string logic))) ))