我正在使用ANTLR4为一种语言编写编译器作为大学项目。 我使用 Java 编写了这个编译器,并采用了访问者模式,当我进入测试阶段时,我注意到 ANTLR 忽略了我的部分代码并生成了不应该生成的错误。
语法:
grammar smallJava;
/*-----------------
Parser Rules
*/
start:program;
program
:imports* classcode EOF;
imports
:'import' imported ';';
imported
:classimported=('Small_Java.lang' | 'Small_Java.io');
classcode
:modifier? 'class_SJ' classname '{' declaration* 'main_SJ' '{' statement* '}' '}';
modifier
:'public'
|'protected';
classname
:IDF;
declaration
:type variables=vars ';';
type
:'int_SJ'
|'float_SJ'
|'string_SJ';
vars
:IDF ',' follow=vars #vars_follow
|IDF #vars_end
;
statement
:assign_statement
;
assign_statement
:idf=IDF ':=' right=expression ';';
expression: expressiona; // axiome of "expression"
//left recursion removed using : A -> A alpha / beta <=> A -> beta A' && A' -> alpha A' / epsilon
expressiona
:left=expressiona operator=('+'|'-') right=expressionb #expression_pm
|expressionb #expression_b
;
expressionb
:left=expressionb operator=('*'|'/') right=expressionc #expression_md
|expressionc #expression_c
;
expressionc
:'(' expressiona ')' #expression_parenthesis
|value #expression_value
;
value
:INT #integer
|STRING #string
|FLOAT #float
|IDF #idf
;
/*-----------------
Lexer Rules
*/
fragment DIGIT0: [0-9];
fragment DIGIT1: [1-9];
fragment LETTER: ('A'..'Z')|('a'..'z');
fragment CHAR: LETTER|DIGIT0;
INT: '0'|DIGIT1 DIGIT0*;
FLOAT
:'.' DIGIT0+
|INT '.' DIGIT0*;
STRING: '"' (CHAR|' '|'('|')'|'\"')*? '"'; //STRING: '"' ('\"'|.)*? '"';
IDF:LETTER (LETTER|DIGIT0)*;
WS: [ nt] -> skip;
这是我的主要内容:
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
public class Main {
public static void main(String[] args) {
String test =
"import Small_Java.lang;n" +
"public class_SJ Test{n" +
"tint_SJ varTest;n" +
"tmain_SJ{n" +
"ttvarTest := 1+1;n" +
"t}n" +
"}";
ANTLRInputStream input = new ANTLRInputStream(test);
smallJavaLexer lexer = new smallJavaLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
smallJavaParser parser = new smallJavaParser(tokens);
ParseTree tree = parser.expression();
myVisitor v = new myVisitor();
v.visit(tree);
}
}
当我运行 Main 时,它显示以下内容:
第 1:0 行不匹配的输入"导入"期望 {'(', INT, FLOAT, STRING, IDF}
我的语法某处错了吗?如果不是,为什么要这样做?
这一行:
ParseTree tree = parser.expression();
告诉parser
对象解析expression
(即语法定义的非终端expression
(,因此它在看到令牌import
时会正确抱怨。
大概你的目的是解析一个program
,在这种情况下,你需要调用program
成员函数:
ParseTree tree = parser.program();
您的start
生产基本上毫无意义,因为它所做的只是推迟program
。使用start
规则启动语法很常见,因为其他一些解析器生成器具有"启动规则"的概念,这意味着生成的解析器始终尝试解析相同的非终端。但安特尔真的没有这个概念;您可以使用具有该名称的成员函数接受语法中任何非终端的顶级匹配。