2017-06-06 50 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

这也是一个巨大的帮助。感谢您的替代解决方案。 –