2013-02-04 13 views
1

我正在轉換一些舊的F77代碼,以便在gfortran下編譯。我有一堆以下列方式使用記錄:shell腳本預處理Fortran RECORDs到類型?

RecoRD /TEST/ this 
this.field = 1 
this.otherfield.sumthin = 2 
func = func(%val(ThIs.field,foo.bar,this.other.field)) 

我想這些都轉化爲類型,例如:

TYPE(TEST) this 
this%field = 1 
this%otherfield%sumthin = 2 
func = func(%val(ThIs%field,foo.bar,this%other%field)) 

我只是用SED確定,我可以處理文件用TYPE聲明替換RECORD聲明,但是有沒有辦法使用linux工具編寫預處理類型的腳本來將this.field表示法轉換爲此%字段表示法?我相信我會需要一些能夠識別已聲明的記錄名稱的東西,並專門針對它來避免在事故中使用其他變量。另外,任何想法如何處理包含文件?我覺得這樣會變得非常混亂,但如果有人做了類似的事情,那麼包含在解決方案中將會很好。

編輯: 我有python 2.4 avaialable給我。

+0

我認爲是安全的,你應該閱讀相關的STRUCTURE,並根據匹配變量和有效的字段名進行替換。我會使用比sed更高的語言,例如python。順便說一下,STRUCTURE/RECORD是一個擴展,不是標準的f77。 – agentp

回答

2

你可以使用Python。下面的腳本讀取從標準輸入文本,並將其輸出使用你要求更換到stdout:

import re 
import sys 

txt = sys.stdin.read() 
names = re.findall(r"RECORD /TEST/\s*\b(.+)\b", txt, re.MULTILINE) 
for name in list(set(names)): 
    txt = re.sub(r"\b%s\.(.*)\b"%name, r"%s%%\1"%name, txt, 
       re.MULTILINE) 
sys.stdout.write(txt) 

編輯:至於Python 2.4中:是的格式應符合%取代。至於具有子字段的結構,可以通過使用如下的sub()調用中的函數來輕鬆實現。我還添加情況下不敏感:

import re 
import sys 

def replace(match): 
    return match.group(0).replace(".", "%") 

txt = sys.stdin.read() 
names = re.findall(r"RECORD /TEST/\s*\b(.+)\b", txt, re.MULTILINE) 
for name in names: 
    txt = re.sub(r"\b%s(\.\w+)+\b" % name, replace, txt, 
       re.MULTILINE | re.IGNORECASE) 
sys.stdout.write(txt) 
+0

這看起來很有希望!我甚至沒有想過用python來做這件事。關於我的頭頂,我對這個問題作了一些澄清;記錄可以是多層次的,即this.obj.rec - > this%obj%rec;比賽必須不區分大小寫; RECORD語句也必須轉換爲TYPE語句;我正在使用Python 2.4,所以.format不可用。按照我的想法編輯你的答案。 – Ethereal

+0

我更新了我的帖子,應該爲任意數量的關卡工作。 –

1

隨着GNU AWK:

$ cat tst.awk 
/RECORD/ { $0 = gensub(/[^/]+[/]([^/]+)[/]/,"TYPE(\\1)",""); name=tolower($NF) } 
{ 
    while (match(tolower($0),"\\<" name "[.][[:alnum:]_.]+")) { 
     $0 = substr($0,1,RSTART-1) \ 
      gensub(/[.]/,"%","g",substr($0,RSTART,RLENGTH)) \ 
      substr($0,RSTART+RLENGTH) 
    } 
} 
{ print } 

$ cat file 
RECORD /TEST/ tHiS 
this.field = 1 
THIS.otherfield.sumthin = 2 
func = func(%val(ThIs.field,foo.bar,this.other.field)) 

$ awk -f tst.awk file 
TYPE(TEST) tHiS 
this%field = 1 
THIS%otherfield%sumthin = 2 
func = func(%val(ThIs%field,foo.bar,this%other%field)) 

請注意,我修改你的輸入顯示會隨着this.field多次出現發生在同一行什麼,並與其他」混合。 「參考文獻(foo.bar)。我還添加了一些「this」的混合情況,以說明這是如何工作的。

在回答以下關於如何處理包含文件的問題,這裏有一個方法:

這個腳本不僅將擴大所有說「包括子文件」的臺詞,但結果寫入tmp文件,重置ARGV [1](最高級輸入文件)並且不重置ARGV [2](tmp文件),然後讓awk對擴展結果進行任何正常記錄解析,因爲它現在存儲在tmp文件中。如果你不需要,只需執行「打印」標準輸出並刪除任何其他對tmp文件或ARGV [2]的引用。

awk 'function read(file) { 
     while ((getline < file) > 0) { 
      if ($1 == "include") { 
       read($2) 
      } else { 
       print > ARGV[2] 
      } 
     } 
     close(file) 
    } 
    BEGIN{ 
     read(ARGV[1]) 
     ARGV[1]="" 
     close(ARGV[2]) 
    }1' a.txt tmp 

跑步所給出這3個文件在當前目錄上面的結果:

a.txt    b.txt    c.txt 
    -----    -----    ----- 
    1     3     5 
    2     4     6 
    include b.txt  include c.txt 
    9     7 
    10    8 

將通過10打印數字1,並將其保存在一個名爲「TMP」的文件。

因此,對於這個應用程序,您可以用上面第一個腳本的內容替換上面腳本末尾的數字「1」,它會在tmp文件上工作,該文件現在包含擴展文件的內容。

+0

我在想,爲了隔離「這個」。它可能很簡單,只允許某些字符集在「this」之前,比如「(」,「\ n」,空白等等。我一直沒有找到一個「接受」的我還用更精確的約束更新了q – Ethereal

+0

我剛剛發佈了一個更新後的腳本,給出了你的新需求 –

+0

看起來很穩固需要我花一些時間來破譯你的腳本正在做什麼......我會在我的午餐休息時間回來!有沒有辦法用awk處理包含的文件,或者最好通過可能用來調用awk腳本的更高級別的腳本來解決? – Ethereal