[Part I. GIMP基礎功]

[Part II. 一種效果的誕生]
[Part III. Script-Fu的秘密]

21.8 Scheme 轉為 Python 的「轉碼程式」

總結:Script-fu 與 Python-fu 架構一樣,語法有很大的差別
  • Python-fu 有物件導向的呼叫方式語法。
    • 同樣功能的函式, Python-fu 有物件導向的呼叫方式。
    • pdb.gimp_image_new(width, height, RGB)相當於 gimp.Image(width, height, RGB)
  • 減號 - 要改成底線 _ ,gimp-image-new 要改成 pdb.gimp_image_new
  • Python 的敘述 statement 通常以行為單位,Scheme 則用括號()括住。
  • Python 的敘述 statement 可用分號 ; 來區隔,但「PEP 8 -- Style Guide for Python Code」 建議用換行來區隔不同的敘述。
  • Python 的註解是井號 # 開頭,Scheme 的註解是分號 ; 開頭。


「轉碼程式」的 Python 程式碼 scm_to_py_.py
  • 經過一番摸索,可以將「轉碼的流程」寫成 Python 程式。
  • 這個「轉碼程式」無法轉換加減乘除四則運算。
  • 這個「轉碼程式」無法完全正確轉換,最終還是需要一些手工的校正
  • 這個「轉碼程式」使用正規表示式,將 Scheme code 轉為 Python code
    • tmp.py 表示 Python code 的檔案
    • tmp.scm 表示 Scheme code 的檔案
    • 將所有的程式碼儲存在 scm_to_py_.py 的檔案內
    • 將 scm_to_py_.py 檔案權限設為可執行
    • 準備好 tmp.scm
    • 終端機下,鍵入 ./scm_to_py_.py
    • 執行後,就會得到 tmp.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re
f_py = open('./tmp.py', 'w')
f_scm = open('./tmp.scm', 'r')

# 請注意 Python 的縮排規則,否則可能會出錯
# 還要注意 Python 各種的逃脫字符(escape characters)
# 所有的「正規表示式」都包裹在這個 for 迴圈之內
for line in f_scm:
  # 取代註解符號
  line = re.sub('\;', '#', line)
  # 刪掉(define
  line = re.sub('\(define ', '', line)
  # 函數參數值的間隔符號,空白改為逗號
  p_with_pdb_if = re.compile('pdb')
  if p_with_pdb_if:
    line = re.sub(' ', ', ', line)

  # car 是取出函數的回傳值串列的"頭"(第一個元素)
  # 等號 = 表示參數值的指派,或接收函數的回傳值
  # 多數的函數回傳值只有一個元素(或一個物件)
  # 因此,這樣的修改是可行的
  line = re.sub('\, \(car\, \(', ' = ', line)
  line = re.sub('\-1', 'neg1', line)
  # Scheme 與 Python 函數命名規則略微不同
  # Scheme 函數名稱以減號 - 串接
  # 改為以底線 _ 串接
  line = re.sub('\-', '_', line)
  line = re.sub('gimp_', 'pdb.gimp_', line)
  line = re.sub('script_fu_', 'pdb.script_fu_', line)
  line = re.sub('plug_in_', 'pdb.plug_in_', line)
  line = re.sub('RUN_NONINTERACTIVE, ', '', line)
  # Python-Fu 預設就是 RUN_NONINTERACTIVE
  # 因此,刪掉 RUN_NONINTERACTIVE,
  # Scheme 與 Python 括號 () 的使用方式有很大的差異
  line = re.sub('\)', '', line)
  line = re.sub('\(', '', line)
  #
  p = re.compile('pdb.[a-z|_]*\, ')
  if re.search(p, line):
    m = re.search(p, line)
    find_p = m.group(0)
    new_p = re.sub(', ', '(', find_p)
    line = p.sub(new_p, line)

  # 過濾出 pdb.開頭 \n 結尾 的字串
  p = re.compile('pdb.[a-z|A-Z|0-9|\'|\"|\(||_|\s|\,|\.|+|-|\*|/]*\n')
  if re.search(p, line):
    m = re.search(p, line)
    find_p = m.group(0)
    new_p = re.sub('\n', ')\n', find_p)
    line = p.sub(new_p, line)

  # 直接用取代的方式,修正括號 () 的錯誤
  line = re.sub('gimp_context_push', 'gimp_context_push(', line)
  line = re.sub('gimp_displays_flush', 'gimp_displays_flush(', line)
  line = re.sub('gimp_context_pop', 'gimp_context_pop(', line)

  # 讓等號 = 出現在變數值指派的地方
  p_with_pdb_if = re.compile('pdb|if')
  p = re.compile('[0-9|TRUE|FALSE]\n')
  if not re.search(p_with_pdb_if, line):
    if re.search(p, line):
      m = re.search(p, line)
      find_p = m.group(0)
      line = re.sub('\, ', ' = ', line)

  p = re.compile('set\!\, [a-z|_]*\, ')
  if re.search(p, line):
    m = re.search(p, line)
    find_p = m.group(0)
    new_p = re.sub(', ', ' = ', find_p)
    line = p.sub(new_p, line)

  line = re.sub('set\!\, ', '', line)
  line = re.sub('set\! \= ', '', line)

  p = re.compile('^if')
  if re.search(p, line):
    m = re.search(p, line)
    find_p = m.group(0)
    line = re.sub('\, TRUE', ':', line)
    line = re.sub('\, =\, ', ' ', line)

  line = re.sub('neg1', '-1', line)
  #也可使用 print 直接將結果印在標準輸出
  #print line,
  f_py.write(line)
  #for 迴圈結束,重要的敘述,都在這個 for 迴圈之內

f_scm.close()
f_py.close()