antlr 4 没有给出错误的正确行和位置
Antlr 4 does not give the correct line and position of the error
我在使用 Antlr 4 进行错误处理时遇到问题,当我在我的自定义侦听器中调用方法 notifyErrorListeners("msg")
时,Antlr 没有给我错误的确切行和位置。
这是我的 dsl 的一部分。
study( region = "region" , timestamp = 12:10 , processType = "processType")
...
我的问题是语法接受学习中变量的重复,例如。
study( region = "region" , region = "region" , timestamp = 12:10)
...
作为解决方案,我决定在我的自定义监听器中管理它。这是我的监听器
@Getter
public class StudyPatternListener extends StudyBaseListener {
private Map<String, Object> studyParams = new HashMap<>();
@Setter
private StudyParser parser;
@Override
public void enterStudyAssignProcessType(StudyAssignProcessTypeContext ctx) {
String processType = ctx.STRING().getText().replace("\"", "");
if (!this.studyParams.containsKey("processType")) {
this.studyParams.put("processType", processType);
} else {
// here Antlr doesn't give me the right line and the right position of the error.
parser.notifyErrorListeners("processType parameter is already assigned");
}
}
这是我的自定义错误侦听器。
public class StudyErrorListener extends BaseErrorListener {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine,
String msg, RecognitionException e) {
System.err.println("line = " + line + ", position = " + charPositionInLine + " , msg = " + msg);
}
}
这是我的语法。
grammar Study;
program: main EOF; // the program rule.
// LINE_COMMENT*
main: NEWLINE* study NEWLINE* ; // the main rule;
study : 'study' '(' studyParameters ')';
studyParameters: (| ( studyAssign (',' studyAssign)*) ); // assign in the study
studyAssign: 'timestamp' '=' TIMESTAMP # studyAssignTimestamp
| 'region' '=' STRING # studyAssignRegion
| 'processType' '=' STRING # studyAssignProcessType
| 'businessDate' '=' DATE # studyAssignBusinessDate
; // valid study parameters .
fragment LETTER : [A-Za-z];
fragment DIGIT : [0-9];
fragment TWODIGIT : DIGIT DIGIT;
TIMESTAMP: TWODIGIT ':' TWODIGIT;
DATE : TWODIGIT TWODIGIT ;
ID : LETTER+;
STRING : '"' ( ~ '"' )* '"' ;
NEWLINE:'\r'? '\n' ;
LINE_COMMENT: '#' ~[\r\n]* -> skip;
WS : [ \t]+ -> skip ;
在验证树遍历期间通过解析器错误侦听器返回报告将获取解析器的最后位置。不是你想要的(解析器将完成)。
需要从上下文节点中挖掘信息并转换为合理易懂的形式:
@Override
public void enterStudyAssignProcessType(StudyAssignProcessTypeContext ctx) {
...
// validate key/value pairs specified by an 'attribute' rule
for (AttributeContext attribute : ctx.attribute()) {
String id = attribute.id().getText();
Props props = AttrMap.get(id); // external map of allowed keys & values
if (props.name.equals(KeyAttr.INVALID)) { // whatever error check(s)
String cause = "Invalid name '" + id + "' at %s:%s[%s]";
reportProblem(IMarker.SEVERITY_ERROR, Kind.ATTRIBUTE, attribute.id().name, cause);
}
}
}
private void reportProblem(int severity, Kind kind, String cause, Token... tokens) {
Token beg = tokens[0];
Token end = tokens[tokens.length - 1];
errLine = beg.getLine();
errPos = beg.getCharPositionInLine();
errOffset = beg.getStartIndex();
errLen = end.getStopIndex() - errOffset + 1;
displayProblem(severity, kind, calcVisual(cause)); // your presentation
}
private String calcVisual(String cause) {
int beg = errOffset - errPos; // beg of line
if (beg > 0) {
String txt = Strings.EMPTY; // ""
Interval range = Interval.of(beg, errOffset);
try {
txt = record.cs.getText(range);
errVisPos = Strings.measureVisualWidth(txt, tabWidth); // adj for embedded tabs
} catch (Exception e) {
String name = ...; // source name
Log.error(this, "Bad visual position %s: %s (%s: %s)", e.getMessage(), name, range, txt);
}
txt = Strings.EMPTY;
range = Interval.of(beg, errOffset + errLen);
try {
txt = record.cs.getText(range);
errVisLen = Strings.measureVisualWidth(txt, tabWidth) - errVisPos;
} catch (Exception e) {
String name = ...;
Log.error(this, "Bad visual position %s: %s (%s: %s)", e.getMessage(), name, range, txt);
}
}
return String.format(cause, errLine, errVisPos, errVisLen);
}
我在使用 Antlr 4 进行错误处理时遇到问题,当我在我的自定义侦听器中调用方法 notifyErrorListeners("msg")
时,Antlr 没有给我错误的确切行和位置。
这是我的 dsl 的一部分。
study( region = "region" , timestamp = 12:10 , processType = "processType")
...
我的问题是语法接受学习中变量的重复,例如。
study( region = "region" , region = "region" , timestamp = 12:10)
...
作为解决方案,我决定在我的自定义监听器中管理它。这是我的监听器
@Getter
public class StudyPatternListener extends StudyBaseListener {
private Map<String, Object> studyParams = new HashMap<>();
@Setter
private StudyParser parser;
@Override
public void enterStudyAssignProcessType(StudyAssignProcessTypeContext ctx) {
String processType = ctx.STRING().getText().replace("\"", "");
if (!this.studyParams.containsKey("processType")) {
this.studyParams.put("processType", processType);
} else {
// here Antlr doesn't give me the right line and the right position of the error.
parser.notifyErrorListeners("processType parameter is already assigned");
}
}
这是我的自定义错误侦听器。
public class StudyErrorListener extends BaseErrorListener {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine,
String msg, RecognitionException e) {
System.err.println("line = " + line + ", position = " + charPositionInLine + " , msg = " + msg);
}
}
这是我的语法。
grammar Study;
program: main EOF; // the program rule.
// LINE_COMMENT*
main: NEWLINE* study NEWLINE* ; // the main rule;
study : 'study' '(' studyParameters ')';
studyParameters: (| ( studyAssign (',' studyAssign)*) ); // assign in the study
studyAssign: 'timestamp' '=' TIMESTAMP # studyAssignTimestamp
| 'region' '=' STRING # studyAssignRegion
| 'processType' '=' STRING # studyAssignProcessType
| 'businessDate' '=' DATE # studyAssignBusinessDate
; // valid study parameters .
fragment LETTER : [A-Za-z];
fragment DIGIT : [0-9];
fragment TWODIGIT : DIGIT DIGIT;
TIMESTAMP: TWODIGIT ':' TWODIGIT;
DATE : TWODIGIT TWODIGIT ;
ID : LETTER+;
STRING : '"' ( ~ '"' )* '"' ;
NEWLINE:'\r'? '\n' ;
LINE_COMMENT: '#' ~[\r\n]* -> skip;
WS : [ \t]+ -> skip ;
在验证树遍历期间通过解析器错误侦听器返回报告将获取解析器的最后位置。不是你想要的(解析器将完成)。
需要从上下文节点中挖掘信息并转换为合理易懂的形式:
@Override
public void enterStudyAssignProcessType(StudyAssignProcessTypeContext ctx) {
...
// validate key/value pairs specified by an 'attribute' rule
for (AttributeContext attribute : ctx.attribute()) {
String id = attribute.id().getText();
Props props = AttrMap.get(id); // external map of allowed keys & values
if (props.name.equals(KeyAttr.INVALID)) { // whatever error check(s)
String cause = "Invalid name '" + id + "' at %s:%s[%s]";
reportProblem(IMarker.SEVERITY_ERROR, Kind.ATTRIBUTE, attribute.id().name, cause);
}
}
}
private void reportProblem(int severity, Kind kind, String cause, Token... tokens) {
Token beg = tokens[0];
Token end = tokens[tokens.length - 1];
errLine = beg.getLine();
errPos = beg.getCharPositionInLine();
errOffset = beg.getStartIndex();
errLen = end.getStopIndex() - errOffset + 1;
displayProblem(severity, kind, calcVisual(cause)); // your presentation
}
private String calcVisual(String cause) {
int beg = errOffset - errPos; // beg of line
if (beg > 0) {
String txt = Strings.EMPTY; // ""
Interval range = Interval.of(beg, errOffset);
try {
txt = record.cs.getText(range);
errVisPos = Strings.measureVisualWidth(txt, tabWidth); // adj for embedded tabs
} catch (Exception e) {
String name = ...; // source name
Log.error(this, "Bad visual position %s: %s (%s: %s)", e.getMessage(), name, range, txt);
}
txt = Strings.EMPTY;
range = Interval.of(beg, errOffset + errLen);
try {
txt = record.cs.getText(range);
errVisLen = Strings.measureVisualWidth(txt, tabWidth) - errVisPos;
} catch (Exception e) {
String name = ...;
Log.error(this, "Bad visual position %s: %s (%s: %s)", e.getMessage(), name, range, txt);
}
}
return String.format(cause, errLine, errVisPos, errVisLen);
}