查看完整版本: [-- [分享] 将masktools 2使用的逆波兰式转成S-表达式(emacs lisp) --]

『漫游』酷论坛 -> 『影音数码技术学习交流』 -> [分享] 将masktools 2使用的逆波兰式转成S-表达式(emacs lisp) [打印本页] 登录 -> 注册 -> 回复主题 -> 发表主题

linuxyouxia 2011-12-15 07:18

[分享] 将masktools 2使用的逆波兰式转成S-表达式(emacs lisp)

masktools 2用的逆波兰式不容易让人读懂,最近无聊折腾emacs,顺便用emacs lisp写了段代码将其转成S-表达式

使用效果:
http://img165.poco.cn/mypoco/myphoto/20111215/07/4476863220111215071552054.jpg
S-表达式
  1. (? (== x y) x (+ x (* (* (* (* (^ (/ (abs (- x y)) 16) (/ 1 2)) 16) Str) (/ (^ (- x y) 2) (+ (^ (- x y) 2) (/ (* Str 100) 25)))) (/ (- x y) (abs (- x y))))))

对应的中缀表达式是(用一个Perl脚本转换,Windows Cmd下使用会遇到参数转义问题,就不发上来了)
  1. ((x == y) ? x : (x + ((((((abs((x - y)) / 16) ^ (1 / 2)) * 16) * Str) * (((x - y) ^ 2) / (((x - y) ^ 2) + ((Str * 100) / 25)))) * ((x - y) / abs((x - y))))))


代码:
  1. (require 'pp)
    ;;http://braeburn.aquamacs.org/code/master/lisp/emacs-lisp/pp.el

    (defun avs-masktool-postfix-format (expstr)
      (let ((initlist (delete "" (split-string expstr "\"")))
        (outlist nil))
        (defun expstrproc (procstr state)
          (defun append-outlist (separator-str)
        (setq outlist (append outlist (delete "" (split-string (car procstr) separator-str)))))
          (cond ((null procstr) outlist)
            ((= state 0)
            (append-outlist nil)
            (expstrproc (cdr procstr) 1))
            ((= state 1)    
            (append-outlist "+\\|\n\\|\s\\|\t\\|\r\\|\\\\")
            (expstrproc (cdr procstr) 0))
            (t nil)))
        (expstrproc initlist 0)))

    (defun avs-masktool-postfix-to-prefix-elisp (explist)
      (defun make-polish-symbol-table (list)
        (let ((p-symbol-table (make-hash-table :test 'equal)))
          (dolist (pair list)
        (puthash (car pair) (cadr pair) p-symbol-table))
          p-symbol-table))
      (let ((rpnstack nil)
        (polish-symbol-table (make-polish-symbol-table '(("+" 2) ("*" 2) ("/" 2) ("-" 2)
                                 ("^" 2) ("%" 2) ("?" 3) ("==" 2)
                                 ("=" 2) ("!=" 2) ("<=" 2) ("<" 2)
                                 (">=" 2) (">" 2) ("&" 2) ("|" 2)
                                 ("&!" 2) ("°" 2) ("@" 2) ("&u" 2)
                                 ("|u" 2) ("°u" 2) ("@u" 2) ("~u" 1)
                                 ("<<" 2) ("<<u" 2) (">>" 2) (">>u" 2)
                                 ("&s" 2) ("|s" 2) ("°s" 2) ("@s" 2)
                                 ("~s" 1) ("<<s" 2) (">>s" 2) ("cos" 1)
                                 ("sin" 1) ("tan" 1) ("log" 1) ("exp" 1)
                                 ("abs" 1) ("atan" 1) ("acos" 1) ("asin" 1)
                                 ("round" 1) ("clip" 3) ("min" 2) ("max" 2)
                                 ("ceil" 1) ("floor" 1) ("trunc" 1)))))
        (defun poprpn ()
          (let ((item (pop rpnstack)))
        (cond ((gethash item polish-symbol-table nil) (push item rpnstack) "*undef*")
              ((null item) "*undef*")
              (t item))))
        (defun funop (argc ele)
          (let ((item nil))
        (do ((i 1 (+ i 1)))
            ((> i argc) (push (concat "(" ele " " item ")") rpnstack))
          (setq item (concat (poprpn) (if item " " "") item)))))
        (let ((rpnelelist (delete "" explist)))
          (dolist (ele rpnelelist)
        (let ((eleargc (gethash ele polish-symbol-table nil)))
          (if eleargc
              (funop eleargc ele)
            (push ele rpnstack)))))
        (let ((res ""))
          (dolist (restele rpnstack)
        (setq res (concat res restele "\n")))
          res)))

    (defun avs-masktool-postfix-to-prefix (rstart rend)
      (interactive "r")
      (let ((data (buffer-substring-no-properties rstart rend))
        (info nil)
        (buf (get-buffer-create "*masktool helper*")))
        (set-buffer buf)
        (setq buffer-read-only nil)
        (erase-buffer)
        (setq info (avs-masktool-postfix-to-prefix-elisp (avs-masktool-postfix-format data)))
        (insert info)
        (pp-buffer)
        (clipboard-kill-ring-save (point-min) (point-max))
        (pop-to-buffer buf)
        (message info)))

    (provide 'avs-masktool-helper)


如果不想要格式化代码,可以把pp-buffer那行去掉

在emacs配置里,绑定下avs-masktool-postfix-to-prefix快捷键,选中逆波兰式字符串区域(包括引号),然后按快捷键或者M-x avs-masktool-postfix-to-prefix RET,输出格式化后的S-表达式,并添加到kill-ring里面,方便粘贴
  1. (add-to-list 'load-path "path2pp.el&avs-masktool-helper.el")
    (require 'pp)
    (require 'avs-masktool-helper)
    (global-set-key (kbd "C-C C-P") 'avs-masktool-postfix-to-prefix)


另1:masktools2提供了一个mt_polish函数用来将中缀表达式转成逆波兰式
另2:emacs曾有人写过一个视频编辑模式 GNEVE GNU Emacs Video Editing
另3:AvsPMod也完全可以写一个转换用的宏
(闪





06_taro 2011-12-16 08:02
masktools2内置mt_infix/mt_polish可以直接转换

linuxyouxia 2011-12-16 09:59
中缀表达式长了也容易看晕,继续看有缩进的S-表达式

mt_infix/mt_polish要通过avs调用,需要自己写个程序调用后直接返回字符串= =
(Windows下通过命令行把表达式当参数传过去需要转义;*nix下要调用Wine,麻烦)

转中缀表达式Perl脚本
  1. #!/usr/bin/env perl
    use strict;
    use warnings;

    my @rpnstack;

    my %opsymbol =
      (
       '+' => \&mathop, '*' => \&mathop, '/' => \&mathop, '-' => \&mathop,
       '^' => \&mathop, '%' => \&mathop, '?' => \&ifop, '==' => \&mathop,
       '=' => \&mathop, '!=' => \&mathop, '<=' => \&mathop, '<' => \&mathop,
       '>=' => \&mathop, '>' => \&mathop, '&' => \&mathop, '|' => \&mathop,
       '&!' => \&mathop, '°' => \&mathop, '@' => \&mathop, '&u' => \&mathop,
       '|u' => \&mathop, '°u' => \&mathop, '@u' => \&mathop, '~u' => &funop(1),
       '<<' => \&mathop, '<<u' => \&mathop, '>>' => \&mathop, '>>u' => \&mathop,
       '&s' => \&mathop, '|s' => \&mathop, '°s' => \&mathop, '@s' => \&mathop,
       '~s' => &funop(1), '<<s' => \&mathop, '>>s' => \&mathop, 'cos' => &funop(1),
       'sin' => &funop(1), 'tan' => &funop(1), 'log' => &funop(1), 'exp' => &funop(1),
       'abs' => &funop(1), 'atan' => &funop(1), 'acos' => &funop(1), 'asin' => &funop(1),
       'round' => &funop(1), 'clip' => &funop(3), 'min' => &funop(2), 'max' => &funop(2),
       'ceil' => &funop(1), 'floor' => &funop(1), 'trunc' => &funop(1)
      );

    sub poprpn {
      my $res = pop @rpnstack;
      if (!defined($res)) {
        print "$_: The user has not input sufficient values!\n";
        $res = '*undef*';
      } elsif (defined($opsymbol{$res})) {
        push(@rpnstack, $res);
        print "$_: The user has not input sufficient values!\n";
        $res = '*undef*';
      }
      return $res;
    }

    sub funop {
      my $argc = shift;
      return sub {
        my $opstr = shift;
        $_ = $opstr;
        my $res = &poprpn;
        for (my $i = 2; $i <= $argc; $i++) {
          my $element = &poprpn;
          $res = "$element ".$res;
        }
        return "$opstr($res)";
      }
    }

    sub mathop {
      my $opstr = shift;
      $_ = $opstr;
      my $item1 = &poprpn;
      my $item2 = &poprpn;
      return "($item2 $opstr $item1)";
    }

    sub ifop {
      $_ = '?';
      my $item1 = &poprpn;
      my $item2 = &poprpn;
      my $item3 = &poprpn;
      return "($item3 ? $item2 : $item1)";
    }
    my @instr = split /(?<=")|(?=")/, $ARGV[0];
    my $rpnexp = '';
    my $state = 1;
    foreach my $to (@instr) {
      if ($state == 0 ) {
        if ($to eq '"') {
          $state = 1;
          next;
        }
      } elsif ($state == 1) {
        if ($to eq '"') {
          $state = 0;
          next;
        }
        $to =~ s/\+|\\/ /g;
      }
      $rpnexp = $rpnexp."$to ";
    }
      
    my @rpnstr = split /\s+/, $rpnexp;

    foreach my $token (@rpnstr) {
      my $action = $opsymbol{$token};
      if (defined($action)) {
        my $res = &$action($token);
        push(@rpnstack, $res);
      } else {
        push(@rpnstack, $token);
      }
    }

    while (defined(my $exp = pop @rpnstack)) {
      print "$exp\n";
    }


顺便想到了,可以给avisynth写个REPL程序


查看完整版本: [-- [分享] 将masktools 2使用的逆波兰式转成S-表达式(emacs lisp) --] [-- top --]


Powered by phpwind v8.5 Code ©2003-2011 phpwind
Time 0.028959 second(s),query:3 Gzip disabled