2017-06-06 47 views
1

我是Rascal的新手,嘗試其轉換/術語重寫功能。使用RASCAL分割聲明和初始化

我想寫一個分裂的聲明類似的腳本:

INT X = 5;

進入聲明/初始化如:

int x; x = 5;

我該怎麼辦?假設我正在嘗試轉換的語言是Java。

感謝您的任何幫助。

回答

2

草圖的解決方案

好問題。有幾種方法可以做到這一點,我將展示最簡單的方法。請注意,您的示例不是最簡單的示例,因爲它需要從單個語句轉換爲語句列表(即,它不是類型保留)。

這裏沒有進一步的完整例子,下面的解釋如下。

module Decl 

import IO; 
import ParseTree; 

// Decl, a trivial language, to demo simple program trafo 

lexical Id = [a-z][a-z0-9]* !>> [a-z0-9] \ Reserved; 
lexical Natural = [0-9]+ ; 
lexical String = "\"" ![\"]* "\""; 

layout Layout = WhitespaceAndComment* !>> [\ \t\n]; 

lexical WhitespaceAndComment 
    = [\ \t\n\r] 
    ; 

keyword Reserved = "int" | "str" | "if" | "then" | "else" | "fi" | "while" | "do" | "od"; 

start syntax Program 
    = {Statement ";"}* body 
    ; 

syntax Type 
    = "int" 
    | "str" 
    ; 

syntax Statement 
    = Type tp Id var 
    | Type tp Id var ":=" Expression exp 
    | Id var ":=" Expression val                  
    | "if" Expression cond "then" {Statement ";"}* thenPart "else" {Statement ";"}* elsePart "fi" 
    | "while" Expression cond "do" {Statement ";"}* body "od"         
    ; 

syntax Expression 
    = Id name          
    | String string       
    | Natural natcon       
    | bracket "(" Expression e ")"     
    > left (Expression lhs "+" Expression rhs           
      | Expression lhs "-" Expression rhs 
     ) 
    ; 

str trafo1() { 
    p = parse(#start[Program], "int x := 1").top; 
    newBody = ""; 
    for(stat <- p.body){ 
     if((Statement) `<Type tp> <Id var> := <Expression exp>` := stat){ 
      newBody += "<tp> <var>; <var> := <exp>"; 
     } else { 
      newBody += "<stat>"; 
     } 
    } 
    return newBody; 
} 

主要部分是一個簡單語言的完整語法。實際轉換由trafo1完成:

  1. 解析示例。
  2. 介紹並初始化newBody(用於構建結果)。
  3. 迭代給定主體中的語句。
  4. 測試每個陳述是否是所需的形式。 如果爲true,則附加轉換後的語句。請注意,字符串模板在此處用於構建轉換後的語句。 如果爲false,請追加原始語句。
  5. 返回結果字符串。

討論

該解決方案的大號樣式取決於你的目標。這裏我們只是建立一個字符串。如果需要,您可以返回解析的字符串作爲結果。

替代方案:

  1. 轉化爲具體的解析樹(不那麼容易,因爲一些功能仍然缺乏,但我們的目標是使該轉換的首選解決方案)。
  2. 首先轉換爲抽象語法樹(AST)並在AST上執行轉換。

希望這可以幫助你開始。

+2

再次感謝,這正是我一直在尋找的。我想我需要更多的代表來表決,但這是值得的。第一個版本中有 –

1

我這裏有一些更多的代碼示例使用了具體語法匹配和替換,以你想要的東西到達:

module JavaMatch 

import lang::java::\syntax::Java15; 

// this just replaces exactly these specific kinds of declarations, as the only statement in a block: 
CompilationUnit splitInitializersSimple(CompilationUnit u) = visit(u) { 
    case (Block) `{ int i = 0; }` => (Block) `{int i; i = 0;}` 
}; 

// the next generalizes over any type, variable name or expression, but still one statement in a block: 
CompilationUnit splitInitializersSingle(CompilationUnit u) = visit(u) { 
    case (Block) `{ <Type t> <Id i> = <Expr e>; }` 
     => (Block) `{<Type t> <Id i>; <Id i> = <Expr e>;}` 
}; 

// Now we allow more statements around the declaration, and we simply leave them where they are 
CompilationUnit splitInitializersInContext(CompilationUnit u) = visit(u) { 
    case (Block) `{ <BlockStm* pre> 
       ' <Type t> <Id i> = <Expr e>; 
       ' <BlockStm* post> 
       '}` 
     => (Block) `{ <BlockStm* pre> 
       ' <Type t> <Id i>; 
       ' <Id i> = <Expr e>; 
       ' <BlockStm* post> 
       '}` 
}; 

// But there could be more initializers in the same decl as well, as in int i, j = 0, k; : 
CompilationUnit splitInitializersInContext2(CompilationUnit u) = visit(u) { 
case (Block) `{ <BlockStm* pre> 
      ' <Type t> <{VarDec ","}+ a>, <Id i>= <Expr e>, <{VarDec ","}+ b>; 
      ' <BlockStm* post> 
      '}` 
    => (Block) `{ <BlockStm* pre> 
      ' <Type t> <{VarDec ","}+ a>, <Id i>, <{VarDec ","}+ b>; 
      ' <Id i> = <Expr e>; 
      ' <BlockStm* post> 
      '}` 
}; 

// and now we add `innermost` such that not only the first but all occurrences are replaced: 
CompilationUnit splitInitializersInContext2(CompilationUnit u) = innermost visit(u) { 
case (Block) `{ <BlockStm* pre> 
      ' <Type t> <{VarDec ","}+ a>, <Id i>= <Expr e>, <{VarDec ","}+ b>; 
      ' <BlockStm* post> 
      '}` 
    => (Block) `{ <BlockStm* pre> 
      ' <Type t> <{VarDec ","}+ a>, <Id i>, <{VarDec ","}+ b>; 
      ' <Id i> = <Expr e>; 
      ' <BlockStm* post> 
      '}` 
}; 

void doIt(loc file) { 
    start[CompilationUnit] unit = parse(#start[CompilationUnit], file); 
    unit.top = splitInitializersInContext(unit.top); 
    writeFile(file, "<unit>"); 
} 

結束語,因爲這仍然不是完全通用:

  • 照顧修飾符和數組類型;這隻會增加更多的變數,以配合和執行,以右側
  • 的初始化現在將發生顛倒順序報表,並在它們之間的數據依賴關係的情況下,這將打破
  • 注意,規則的形狀很大程度上依賴於Java語法,因爲我們在這裏使用了具體的語法匹配。它有助於在創建此類代碼時瀏覽語法。
  • 此代碼在很多地方保留註釋,但並非全部,特別是在重寫的聲明和重寫的vardecs之間,使用此代碼將丟失註釋。
+0

有一些缺陷;現在測試並修復 – jurgenv

+0

,我同意Paul的具體語法功能沒有完全定案,所以這個答案在紙上看起來更好,然後輸入。我們仍在努力改進錯誤處理並完成一些必要的列表匹配和拼接功能。 – jurgenv

+0

這也是一個巨大的幫助。感謝您的替代解決方案。 –