ANTLR4 忽略标记
ANTLR4 ignoring tokens
我正在为一种语言编写一个编译器,作为一个使用 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: [ \n\t] -> 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" +
"\t\tvarTest := 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 它显示这个:
line 1:0 mismatched input 'import' expecting {'(', INT, FLOAT, STRING, IDF}
我的语法哪里错了吗?如果不是,为什么要这样做?
这一行:
ParseTree tree = parser.expression();
告诉 parser
对象解析 expression
(即由您的语法定义的非终结符 expression
),因此当它看到标记 import
.
大概您的意图是解析一个 program
,在这种情况下您需要调用 program
成员函数:
ParseTree tree = parser.program();
您的 start
制作基本上毫无意义,因为它所做的只是遵从 program
。使用 start
规则开始语法很常见,因为其他一些解析器生成器具有 "start rule" 的概念,这意味着生成的解析器总是尝试解析相同的非终端。但是Antlr确实没有这个概念;您可以使用具有该名称的成员函数接受语法中任何非终结符的顶级匹配。
我正在为一种语言编写一个编译器,作为一个使用 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: [ \n\t] -> 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" +
"\t\tvarTest := 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 它显示这个:
line 1:0 mismatched input 'import' expecting {'(', INT, FLOAT, STRING, IDF}
我的语法哪里错了吗?如果不是,为什么要这样做?
这一行:
ParseTree tree = parser.expression();
告诉 parser
对象解析 expression
(即由您的语法定义的非终结符 expression
),因此当它看到标记 import
.
大概您的意图是解析一个 program
,在这种情况下您需要调用 program
成员函数:
ParseTree tree = parser.program();
您的 start
制作基本上毫无意义,因为它所做的只是遵从 program
。使用 start
规则开始语法很常见,因为其他一些解析器生成器具有 "start rule" 的概念,这意味着生成的解析器总是尝试解析相同的非终端。但是Antlr确实没有这个概念;您可以使用具有该名称的成员函数接受语法中任何非终结符的顶级匹配。