『漫游』酷论坛>『影音数码技术学习交流』>[分享] 将masktools 2使用 ..
[分享] 将masktools 2使用的逆波兰式转成S-表达式(emacs lisp)
linuxyouxia@2011-12-15 07:18
masktools 2用的逆波兰式不容易让人读懂,最近无聊折腾emacs,顺便用emacs lisp写了段代码将其转成S-表达式
使用效果:
http://img165.poco.cn/mypoco/myphoto/20111215/07/4476863220111215071552054.jpg
S-表达式
- (? (== 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下使用会遇到参数转义问题,就不发上来了)
- ((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))))))
代码:
- (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里面,方便粘贴
- (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也完全可以写一个转换用的宏
(闪
[ 此帖被linuxyouxia在2011-12-15 07:40重新编辑 ]
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脚本
- #!/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程序[ 此帖被linuxyouxia在2011-12-16 11:07重新编辑 ]
| TOP