如何在 xtext DSL 中嵌入C++代码

How to embed C++ code in a xtext DSL?

本文关键字:C++ 代码 DSL xtext      更新时间:2023-10-16

Xtext/ANTLR中处理C++代码块的正确方法是什么?

我们正在为DSL编写一个基于Xtext的eclipse插件,该插件支持在明确定义的范围(主要是serial { /* ... */ }块)中添加C++函数级代码,如下所示:

module m {
  chare c {
    entry void foo() {
      serial {
        // C++ code block
      }
    }
  }
}

有关更全面的示例,请参阅此处。然后将其移交给外部工具来处理进一步的编译/链接步骤,因此我们不会从 eclipse 生成任何代码。

这里的问题是如何处理这些C++代码块,特别是考虑到它们可能包含自己的大括号。这与如何在 Xtext DSL 中包含 Java 代码块非常相似?但就目前而言,我们满足于忽略该块(即没有内容辅助或语法突出显示并不理想,但可以接受。

在我们基于 bison/flex 的工具中,这是通过在解析器和词法分析器之间共享一个变量来完成的,该变量在某些语法规则中切换"C++解析模式",使词法分析器返回除相关分隔符(例如大括号)之外的所有内容的 CPROGRAM 标记。自然翻译似乎有一个自定义的ANTLR词法分析器,它使用语义谓词来达到相同的效果,例如

RULE_NON_BRACES: {in_braces}? ~('{' | '}')+;

作为第一个词法规则,但我找不到如何从 Xtext 语法中访问该全局变量,因为似乎没有像 bison 那样的"规则操作"概念。还有其他非"串行"语法上下文需要C++代码,因此解析器和词法分析器之间需要一些协调。

您的问题似乎更侧重于 DSL 词法分析器如何避免迷失在C++代码中。 基本答案是您需要匹配括号(例如,确保它们正确嵌套)。

我不知道你如何定义一个Xtext/ANTLR词汇规则来做到这一点;我认为有一种丑陋的方法可以下拉到过程代码中并开始逐个读取字符。 这可能会有一些并发症;您的参数匹配逻辑可能不得不担心C++代码中的各种类型的引用。 例如

        {   //   this } isn't a match

        {   char x[]="} this isnt a match { either" }

其他C++字符串引号可能会使这更加难以看到。 对于这样使用的C++宏,您将怎么做?

        {
        #define rcb }
            {   rcb
        }

您可能需要制定一些关于如何在嵌入式C++代码中处理 } 的特殊规则,并且您的逐字符扫描必须知道此规则。

与其

让事情变得复杂,我认为你应该做的是在C++中选择一个非常不可能的角色序列作为你的终止,例如,

    ][[

我相信除了字符串或评论之外,不能出现在C++中,或者

    }}}

并简单地使用它。 根本不需要匹配括号。 在几乎所有情况下,都不必触摸C++;在极少数情况下,当它恰好包含该序列时,只需进行简单的编辑(插入空格或换行符)即可修复它。 现在您的词法分析器规则很简单,可以使用标准词法分析器表示(我认为)。

如果你这样做,我建议你选择一个相应的开场序列来介绍C++代码,只是为了提醒读者需要一个有趣的序列,例如,

  serial {{{    <C++code>  }}}

  serial ]][   <C++code>   ][[

有了这个约定,即使是我丑陋的宏示例也很容易:

  serial {{{
      {
      #define rcb }
         {  rcb
      } 
  }}}

PS:这个有趣的记谱技巧被称为"域(记谱法)转义"。 这个问题发生在每个系统中(是的,在野外不是那么多,但我有一个:)这允许人们混合多个符号。 顺序因语言/系统而异,具体取决于口味。

如果你真的无法改变语法并且需要依赖匹配的大括号,那么你需要在Java中重新实现基于flex的解决方案(例如使用jflex)并使Xtext使用该词法分析器。我在这篇博文中简要介绍了这一点。它还包含一个指向示例代码的指针,其中我在 Xtext 中使用了基于 jflex 的词法分析器。