使用RASCAL拆分声明和初始化

时间:2017-06-06 05:43:15

标签: transformation rascal

我是Rascal的新手并正在尝试其转换/术语重写能力。

我想编写一个分割声明的脚本,如:

int x = 5;

进入声明/初始化,如:

int x; x = 5;

我怎么能这样做?假设我正在尝试转换的语言是Java。

感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

解决方案草图

好问题。有几种方法可以做到这一点,我将展示最简单的方法。请注意,您的示例不是最简单的示例,因为它需要从单个语句转换为语句列表(即,它不是类型保留)。

以下是一个完整的例子,解释如下。

collectionData

主要部分是简单语言的完整语法。实际转换由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; } 完成,其中包括:

  1. 解析示例。
  2. 介绍并初始化trafo1(用于构建结果)。
  3. 迭代给定正文中的陈述。
  4. 测试每个语句是否为所需形式。 如果为true,则追加转换后的语句。请注意,此处使用字符串模板来构建转换后的语句。 如果为false,请附加原始声明。
  5. 返回结果字符串。
  6. 讨论

    解决方案风格很大取决于您的目标。这里我们只是构建一个字符串。如果需要,您可以返回解析后的字符串作为结果。

    备选方案:

    1. 转换为具体的解析树(不是那么容易,因为仍然缺少一些功能,但我们的目标是使其成为首选解决方案)。
    2. 首先转换为抽象语法树(AST)并对AST执行转换。
    3. 希望这有助于您开始使用。

答案 1 :(得分: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之间,使用此代码将丢失注释。