1

我正在设计一种基于 CSS-ish(CSS+自定义扩展)的自定义语言,它基本上可以像这样工作:

[object.member.value = 5]{
object.member.anothervalue:8 
object.member.yetanothervalue:'hello'
object.member.yetyetanothervalue.anothervalue:blue
}

基本上,该语言允许检查某些条件(如果可以嵌套),然后将一些值应用于对象。没有循环。这将存储在纯文本文件中,并在启动时加载到应用程序 (C++) 中。

想法是将这个 CSS-ish 文件翻译成 C++ 树或类似的东西,可以在运行时进行评估

我正在考虑使用一些词法分析器和标记器(Yacc、Flex、Bison 等......)。

您对使用的工具/库有什么建议?

4

3 回答 3

1

You may have a look at Boost Spirit, which allows you to write easily lexical analysers (Boost.Lex), and parsers (Boost.Qi) . It has an interesting approach consisting of defining the syntax/grammar directly in the C++ code instead of using a separated grammar file. It's portable, standard, self-contained and very elegant.

You could consided Flex and Bison if your language is going to evolve into something more complex. They use the same kind of input files as Lex & Yacc, which are their older Unix equivalents. The advantage of these tools is that there is plenty of litterature. The inconvenient, is that they generate code by mixing their skeleton code with pieces that you give in the grammar files. Hence, it's more complex to master and maintain.

But in your special case, you have a very simple language with only a couple of tokens and apparently a simple "LL(1) grammar". (e.g. the parser needs to read a single token ahead to determine without ambiguity what it is going to parse). It would be easy to craft your own code, eventuell using <regex> to ease token scanning, and creating objects that correspond to your language structures.

于 2014-09-01T20:44:49.450 回答
1

如果您希望多次执行此类操作,请学习如何使用解析器生成器。从长远来看,它将为您节省很多痛苦。

从简单开始。这些工具将为您做很多事情,而且通常只需很少的努力。让他们这样做。在尝试做复杂的事情之前先让事情顺利进行。

其余部分假设您将使用flexand bison(它们是lexyacc相似的。)您不必这样做;有很多选择。如果您决定尝试其他选择之一,请忽略此答案的其余部分。

但是flex,并且bison是可靠、维护良好、调试良好的软件包,包含大量文档,并且它们已在很长一段时间内被广泛使用。首先阅读文档。

  • flex将自动从标准输入或提供的文件描述符中读取。让它这样做。
  • flex将为您跟踪行号。让它这样做。
  • bison将自动为您生成令牌编号。让它这样做。
  • bisonflex针对单字符标记进行了优化。您不仅不需要提供令牌编号,甚至不需要提供令牌名称。在您的 flex 文件中,只需将其放在末尾或附近:

    . { return yytext[0]; }
    

    并且不要费心编写规则来处理单字符标记。不用担心您会标记非法字符;bison将为您生成一条错误消息。

  • 但是,不允许flex插入默认规则。(%option nodefault足以压制它。)

其他几个提示:

  • 即使yytext是一个全球性的,假装它不是。您必须复制进一步处理所需的任何字符串。strdup是你的朋友; 使用它而不是乱用mallocand strcpy。也可以使用asprintfchar* out; asprintf(&out, "%s%s%s", s1, s2, s3);无疑是连接三个字符串的最简单方法。对于没有这些东西的平台,有很容易获得的不受限制的实现,所以不要担心“但它们不是 Posix/Standard C/yadda yadda yadda”参数。甚至不要考虑固定长度的缓冲区。你不需要它们。诚实的。
  • 另一方面,如果可以在扫描仪中处理令牌,请在此处进行。数字,例如;在扫描仪中执行一次要容易得多strtol,然后您甚至不需要考虑内存分配。
  • 当您不再需要它们时不要忘记free()字符串,但是如果您发现从泄漏内存开始困难,然后在您的解析器工作后修复问题。(我知道有些人会觉得这是亵渎神明,但只要你记得在制作前做这件事就可以了;一旦你掌握了基础知识,你会感到更有动力。)

最后:

  • 使用合理当前版本的bison. 如果您发现自己有神秘的移位/减少冲突,请使用glr解析器:是的,它有点慢,但如果它可以为您节省一些痛苦,那就值得了。您可以随时返回并稍后解决问题。(GLR 解析器不会让您摆脱所有语法问题。您仍然需要确保您的语法没有歧义。但它们可以提供帮助。)
  • 我个人的建议:使用C接口。可以使用 C++ 编译,并且可以使用标准 C++ 容器和其他不错的功能;只是不要在你的语义值中使用它们,因为这与bison's 的内部堆栈管理不能很好地配合。(不过,指向 C++ 容器的指针很好。)请记住,这flex只是bison控制流;您的大部分程序将用 C/C++ 编写,因此您不会通过使用编译器工具进入一个新世界。您也没有获得免费通行证:在开始编写解析器之前,您需要知道如何使用 C/C++。

希望有帮助。祝你好运。

于 2014-09-02T00:41:28.640 回答
1

我会使用带有递归下降解析器的自制扫描仪,因为这是一个非常简单的解析任务,并且使用解析器生成器将花费与自己编写解析器一样多或更多的时间。

于 2014-09-01T11:38:37.470 回答