C# 我的ANTLR解析器(而不是lexer)如何触发一个词法“;包括「;(不是AST拼接)?
ANTLR网站描述了如何实施“包括”指令。第一种方法是识别lexer中的指令并以词汇形式包含文件(通过将CharStream推到堆栈上并用读取新文件的堆栈替换);第二种方法是识别解析器中的指令,启动子解析器来解析新文件,然后拼接子解析器生成的AST。这两个都不是我所需要的 在我正在分析的语言中,识别lexer中的指令是不切实际的,原因如下:C# 我的ANTLR解析器(而不是lexer)如何触发一个词法“;包括「;(不是AST拼接)?,c#,include,antlr,antlr3,C#,Include,Antlr,Antlr3,ANTLR网站描述了如何实施“包括”指令。第一种方法是识别lexer中的指令并以词汇形式包含文件(通过将CharStream推到堆栈上并用读取新文件的堆栈替换);第二种方法是识别解析器中的指令,启动子解析器来解析新文件,然后拼接子解析器生成的AST。这两个都不是我所需要的 在我正在分析的语言中,识别lexer中的指令是不切实际的,原因如下: 没有始终表示“这是一个include指令”的自包含字符模式。例如,包括“foo”是一个include指令,但在数组条-->include“foo”中或常量包
包括“foo”顶层的code>是一个include指令,但在数组条-->include“foo”中代码>或常量包括“foo”代码>单词包含
是一个标识符
{
开头,在包含的文件中以}
结尾是合法的。函数中包含的文件甚至可以关闭函数定义并启动新的函数定义
看起来我需要类似于第一种方法的东西,但是在令牌流而不是CharStreams级别。这是一个可行的方法吗?我需要在堆栈上保持多少状态,如何使解析器切换回原始令牌流,而不是在到达EOF时终止?还是有更好的方法来处理这个问题
==========
下面是该语言的一个示例,演示了在主文件中打开的块可以在包含的文件中关闭(反之亦然)。请注意,如果指令位于函数内部,但在函数外部是可选的,则需要在Include
之前添加#
main.inf:
[ Main;
print "This is Main!";
if (0) {
#include "other.h";
print "This is OtherFunction!";
];
[主要;
打印“这是主要的!”;
如果(0){
#包括“其他.h”;
打印“这是其他功能!”;
];
其他.h:
} ! end if
]; ! end Main
[ OtherFunction;
} ! 如果结束
]; ! 端干管
[其他职能;
每个
Include
语句都可以让解析器创建一个lexer的新实例,并在解析器当前所在的索引处插入lexer创建的这些新标记(请参阅解析器的@members
块中的insertTokens(…)
方法)
下面是一个快速演示:
Inform6.g
其他
主类
要运行演示,请在命令行上执行以下操作:
java -cp antlr-3.3.jar org.antlr.Tool Inform6.g
javac -cp antlr-3.3.jar *.java
java -cp .:antlr-3.3.jar Main
java-cp antlr-3.3.jar org.antlr.Tool Inform6.g
javac-cp antlr-3.3.jar*.java
java-cp.:antlr-3.3.jar Main
您将看到的输出对应于以下AST:
这是专为受虐狂设计的语言吗?嘿。这是Inform,一种用于编写文本冒险游戏的语言。英语像Inform 7()是当您的设计不受传统上下文无关解析工具约束时,您可以做的优雅而令人敬畏的事情的一个例子。不幸的是,我正在解析Inform 6,这是当您的设计不受传统上下文无关解析工具约束时,您可以做的难以形容的可怕事情的一个例子。@BartKiers幸运的是,不是:filename只能是一个带引号的字符串或一个在前面用
常量
定义的标识符。给定给常量
的定义必须是编译时常量,因此没有函数调用。该语言也没有文本运算符,因此没有连接,但它可以复制另一个常量:常量FOO“file.h”;Constant BAR FOO;Include BAR;
但是Constant
指令通常可以有任意复杂的表达式,因为它通常与数字一起使用:Constant FOO(BAR+5*BAZ);
等,因此在lexer中处理Constant
是不切实际的。
Constant IMPORT "other.h";
[ Main;
print "This is Main!";
if (0) {
Include IMPORT;
print "This is OtherFunction!";
];
} ! end if
]; ! end Main
[ OtherFunction;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main {
public static void main(String[] args) throws Exception {
// create lexer & parser
Inform6Lexer lexer = new Inform6Lexer(new ANTLRFileStream("main.inf"));
Inform6Parser parser = new Inform6Parser(new CommonTokenStream(lexer));
// print the AST
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT((CommonTree)parser.parse().getTree());
System.out.println(st);
}
}
java -cp antlr-3.3.jar org.antlr.Tool Inform6.g
javac -cp antlr-3.3.jar *.java
java -cp .:antlr-3.3.jar Main