我正在用Jflex和Bison做一个编译器。Jflex做词法分析。Bison进行解析。
词法分析(在.l文件中(是完美的。将输入标记化,并将输入传递到y.y文件,以便Bison进行解析。
我需要解析器为重新声明/未声明的变量打印一个错误。我的想法是,它需要某种内存来记住迄今为止初始化的所有变量,这样它就可以在看到未声明的变量被使用时,为传入的令牌生成错误。例如"池"测试"&"真"";,并且在新的行上;test2"&""假"";,解析器将需要某种内存来记住"测试";并且当它解析第二行时,它可以再次访问该存储器;test2";未声明,因此它将打印一个错误。
我感到困惑的是,我们如何在y.y文件中使用Java用bison制作这样的内存。对于C,你可以使用-d标志,它会生成两个具有枚举类型的文件和一个跟踪声明变量的头文件,但在Java中,我不太确定我是否能做到这一点,因为我不能以任何方式构建语法,以便它记住变量名。
我可以用Java代码制作一个符号表来检查重新声明的变量,但在y.y文件的main((中,我有
public static void main(String args[]) throws IOException {
EXAMPLELexer lexer = new EXAMPLLexer(System.in);
EXAMPLE parser = new EXAMPLE(lexer);
if(parser.parse()){
System.out.println("VALID FROM PARSER");
}
else{
System.out.println("ERROR FROM PARSER");
}
return;
}
没有办法单独获取令牌并将其传递到另一个java实例或其他任何实例中。%union{}不适用于Java,所以我不知道这怎么可能。我找不到任何一份文件来解释这一点,所以我很想得到一些答案!
实际上,将自己的数据添加到Bison生成的Java解析器比添加到C解析器(甚至C++解析器(要简单得多。
请注意,Bison的Java API没有联合,主要是因为Java没有联合。所有的语义值都是非基元类型,因此它们源自Object
。如果需要,可以将它们强制转换为更精确的类型,甚至是基元类型。
(可以选择为语义值类型定义更精确的基类,但Object
可能是一个很好的起点。(
%code { ... }
块只是被复制到解析器类中。因此,您可以添加自己的成员,以及操作它们的方法。如果您想要一个符号表,只需将其作为HashMap
添加到解析器类中,然后就可以在操作中向其添加任何您喜欢的内容。
由于所有解析器操作都在解析器类中,因此它们可以直接访问您添加到解析器中的任何成员和成员函数。除了手册中记录的成员函数外,Bison的所有内部成员和成员函数的名称都以yy
开头,因此您可以使用几乎任何想要的名称,而不用担心名称冲突。
您还可以使用%parse-param
向构造函数添加参数;每个参数对应一个类成员。但对于这个特殊的练习来说,这可能不是必要的。
当然,您必须弄清楚符号的合适值类型是什么;这完全取决于你想用符号做什么。如果你只想验证符号在使用时是否已定义,我想你可以使用HashSet
,但我相信最终你会想要存储一些更有用的信息。