词汇和语法分析器软件
Lexical and syntax analyzer software
我正在设计一种基于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等)
你对要使用的工具/库有什么建议?
如果您希望不止一次这样做,请学习如何使用解析器生成器。从长远来看,这将为你省去很多痛苦。
从简单开始。这些工具会为你做很多事情,而且通常只需付出很少的努力。让他们这么做吧。在你尝试做复杂的事情之前,先把事情做好。
其余部分假设您将使用flex
和bison
(它们与lex
和yacc
类似);有很多选择。如果你决定尝试另一种选择,忽略这个答案的其余部分。
但flex
和bison
是坚固、维护良好、调试良好的软件包,包含大量文档,并且在很长一段时间内被广泛使用。请先阅读文档。
flex
将自动从标准输入或提供的文件描述符中读取。让它这么做吧flex
将为您跟踪行号。让它这么做吧bison
会自动为您生成代币编号。让它这么做吧-
CCD_ 10和CCD_。您不仅不需要提供令牌编号,甚至不需要提供代币名称。在您的flex文件中,只需将其放在末尾或末尾附近:
. { return yytext[0]; }
并且不用麻烦编写规则来处理单字符令牌。不要担心你会标记非法字符;
bison
将为您生成一条错误消息。 - 但是,不允许
flex
插入默认规则。(%option nodefault
足以抑制它。)
其他几个提示:
- 即使
yytext
是全球性的,也要假装它不是。您必须复制任何需要进一步处理的字符串。strdup
是你的朋友;使用它,而不是摆弄CCD_ 17和CCD_ 18。同时使用asprintf
;char* out; asprintf(&out, "%s%s%s", s1, s2, s3);
是连接三个字符串的最简单的方法。对于没有这些东西的平台,有一些不受限制的实现很容易获得,所以不要担心"但它们不是Posix/StandardC/yadda-yadda-yahda"的论点。甚至不要考虑固定长度的缓冲区。你不需要它们。诚实 - 另一方面,如果可以在扫描仪中处理令牌,请在那里进行处理。例如,数字;在扫描仪中执行一次
strtol
要容易得多,然后您甚至不需要考虑内存分配 - 当您不再需要
free()
字符串时,不要忘记使用它们,但如果您发现很难从泄漏内存开始,然后在解析器工作后修复问题。(我知道有些人会觉得这是一种亵渎,但只要你记得在生产前这样做,那没关系;一旦你有了基本的工作,你就会觉得更有动力。)
最后:
- 使用
bison
的合理最新版本。如果你发现自己有神秘的shift/reduce冲突,请使用glr
解析器:是的,它有点慢,但如果它能为你节省一些痛苦,那就值得了。你可以随时回去解决问题。(GLR语法分析器不会让你免于所有语法问题。你仍然需要确保你的语法不含糊。但它们会有所帮助。) - 我个人建议:使用
C
接口。用C++编译是可以的,你可以使用标准的C++容器和其他不错的功能;只是不要在语义值中使用它们,因为这与bison
的内部堆栈管理不兼容。(指向C++容器的指针也可以。)记住,flex
和bison
只是控制流;你的大部分程序将用C/C++编写,所以你不会使用编译器工具进入一个新的世界。您也没有获得免费通行证:在开始编写解析器之前,您需要知道如何使用C/C++
希望能有所帮助。祝你好运
我会使用一个带有递归下降解析器的自制扫描仪,因为这是一个非常简单的解析任务,使用解析器生成器将花费与自己编写解析器一样多或更多的时间。
您可能会看到Boost Spirit,它允许您轻松编写词法分析器(Boost.Lex)和语法分析器(Boot.Qi)。它有一种有趣的方法,包括直接在C++代码中定义语法/语法,而不是使用单独的语法文件。它便携、标准、独立且非常优雅。
如果您的语言要发展成更复杂的东西,您可以考虑Flex和Bison。他们使用与Lex&Yacc,它们是旧的Unix等价物。这些工具的优点是有大量的垃圾。不方便的是,它们通过将骨架代码与语法文件中提供的片段混合来生成代码。因此,掌握和维护更为复杂。
但在你的特殊情况下,你有一种非常简单的语言,只有几个标记,显然是一个简单的"LL(1)语法"。(例如,解析器需要提前读取单个令牌,以无歧义地确定要解析什么)。编写自己的代码很容易,甚至可以使用<regex>
来简化令牌扫描,并创建与您的语言结构相对应的对象。
- 用于在并发环境中访问 MMIO 的软件模式
- 有没有办法实现 fmu 导出到基于 c++ 的仿真软件以使用 fmi?
- 从C++调用 Python 并访问通过 Anaconda 安装的软件包
- 如何在程序执行时查看Valgrind Massif输出(或其他堆分析器)?
- 有关图像处理应用程序的硬件和软件安全性的建议
- 通过自制软件(macOS)安装的clang++:编译错误
- 如何在软件代码中使用ofstream创建文件
- 如何在Linux上正确发布C++软件(游戏)
- 为什么我的静态分析器找不到潜在的未初始化读取?
- #pragma(*诊断)当将Clang分析器与GCC编译器混合时
- 尝试使用 RTool 在 R4.0 上安装软件包时出现编译错误
- Clang 分析器潜在内存泄漏 - 误报
- Visual Studio Code输出被检测为恶意软件?
- 如何使用自制软件,cMake和cLion将库添加到C++项目中
- 我正在尝试编写将 ASCII 转换为十进制、添加并转换回 ASCII 的软件
- 在 C/C++ 中,是否可以通过使用指针更改"important"内存地址的值来创建简单的恶意软件?
- 使用策略模式设计软件时出现的问题
- 为什么 Avira 认为"CoCreateInstance()"是恶意软件?
- 在陈述"Implementation-defined"时,什么样的软件是"Implementation"的一部分?究竟什么是"Implementation"?
- 词汇和语法分析器软件