【发布时间】:2012-08-19 17:14:20
【问题描述】:
ANTLR 网站描述了two approaches 以实现“包含”指令。第一种方法是识别词法分析器中的指令并在词法上包含文件(通过将 CharStream 推入堆栈并将其替换为读取新文件的堆栈);二是识别解析器中的指令,启动子解析器解析新文件,并拼接到子解析器生成的AST中。这些都不是我所需要的。
在我正在解析的语言中,由于以下几个原因,识别词法分析器中的指令是不切实际的:
- 没有始终表示“这是一个包含指令”的自包含字符模式。例如,顶层的
Include "foo";是一个包含指令,但在Array bar --> Include "foo";或Constant Include "foo";中,单词Include是一个标识符。 - 要包含的文件的名称可以作为字符串或常量标识符给出,并且可以使用任意复杂的表达式来定义此类常量。
所以我想从解析器触发包含。但是要执行包含,我不能启动子解析器并将 AST 拼接在一起;我必须拼接令牌。在主文件中以{ 开头并在包含文件中以} 终止的块是合法的。包含在函数中的文件甚至可以关闭函数定义并开始新的定义。
似乎我需要类似于第一种方法的方法,但在 TokenStreams 级别而不是 CharStreams 级别。这是一个可行的方法吗?我需要在堆栈上保留多少状态,以及如何使解析器切换回原始令牌流而不是在遇到 EOF 时终止?或者有没有更好的方法来处理这个问题?
===========
这是该语言的一个示例,演示了在主文件中打开的块可以在包含的文件中关闭(反之亦然)。请注意,当指令在函数内部时,# 在 Include 之前是必需的,但在外部是可选的。
main.inf:
[ 主要的; 打印“这是主要的!”; 如果(0){ #include "其他.h"; 打印“这是其他功能!”; ];其他.h:
} !万一 ]; !结束主要 [其他功能;【问题讨论】:
-
这是为受虐狂设计的语言吗?
-
嘿。这就是 Inform,一种用于编写文字冒险游戏的语言。类似英语的 Inform 7 (inform7.com) 是当您的设计不受传统上下文无关解析工具限制时可以做的优雅和令人敬畏的事情的一个例子。不幸的是,我正在解析 Inform 6,这是当您的设计不受传统上下文无关解析工具限制时您可以做的难以形容的可怕 事情的示例。
-
@BartKiers 幸运的是,不可以:文件名只能是带引号的字符串或之前使用
Constant定义的单个标识符。给Constant的定义必须是编译时常量,所以没有函数调用。该语言也没有文本运算符,因此没有连接,但它可以复制另一个常量:Constant FOO "file.h"; Constant BAR FOO; Include BAR; -
但是
Constant指令通常可以具有任意复杂的表达式,因为它通常与数字一起使用:Constant FOO (BAR + 5 * BAZ);等,因此在词法分析器中处理Constant是不切实际的。