ANTLR 访问者单元测试在一条规则上成功但在另一条规则上失败
ANTLR visitor unit test succeeds on one rule but fails on another
我正在尝试为我的 ANTLR 解析器定义单元测试。单元测试成功提取第一个expr的值,但是fails提取第一个idEscape的值。这表明我误解了解析器工作方式或访问者工作方式的核心内容。
我正在为 FileMaker Pro 中的计算编写解析器。在 FileMaker 中,标识符包含空格以及运算符和其他字符在技术上是有效的,否则这些字符将在计算引擎中具有功能性目的。在这些情况下,标识符通过用“${”和“}”包围来转义。虽然解析器成功地将 '${abcdef + 123}' 识别为有效表达式,
我仍然需要能够将 'abcdef + 123' 识别为有效标识符。当我在第二个单元测试中请求第一个 idEscape 的值时,我得到一个空字符串。
如果相关,我正在使用 ANTLR4.Runtime.Standard.
我做错了什么?任何帮助解决我的误解的帮助将不胜感激。谢谢。
语法
grammar FileMakerCalc;
// PARSER RULES
calculation : expr;
expr : idEscExpr;
idEscExpr : LEFTESCAPE idEscape RIGHTESCAPE;
idEscape : (WORD|WS|OPERATOR|INT|FLOAT)*?;
// LEXER RULES
fragment LOWERCASE : [a-z] ;
fragment UPPERCASE : [A-Z] ;
LEFTESCAPE : '${';
RIGHTESCAPE : '}';
OPERATOR : ('+'|'-'|'*'|'/'|'&'|'^'|'='|'≠'|'<>'|'>'|'<'|'≤'|'<='|'≥'|'>=' );
WORD : (LOWERCASE | UPPERCASE)+ ;
FLOAT : [0-9]+ '.' [0-9]+;
INT : [0-9]+ ;
NEWLINE : [\r\n]+ ;
WS : [ \t];
访客
public class FileMakerCalcVisitor : FileMakerCalcBaseVisitor<String>
{
public override string VisitExpr(FileMakerCalcParser.ExprContext context)
{
return context.GetText();
}
public override string VisitIdEscape(FileMakerCalcParser.IdEscapeContext context)
{
return context.GetText();
}
}
单元测试
namespace Antler_Tests
{
[TestFixture()]
public class ParserTest
{
private FileMakerCalcParser Setup(string text)
{
AntlrInputStream inputStream = new AntlrInputStream(text);
FileMakerCalcLexer lexer = new FileMakerCalcLexer(inputStream);
CommonTokenStream commonTokenStream = new CommonTokenStream(lexer);
FileMakerCalcParser parser = new FileMakerCalcParser(commonTokenStream);
return parser;
}
// This one successfully pulls '${abcdef + 123}' as the text of the first expr
[Test()]
public void EscapedID_CheckForExpr()
{
FileMakerCalcParser parser = Setup("${abcdef + 123}");
FileMakerCalcParser.ExprContext context = parser.expr();
FileMakerCalcVisitor visitor = new FileMakerCalcVisitor();
var testVal = visitor.VisitExpr(context);
Assert.AreEqual("${abcdef + 123}", testVal, testVal);
}
// This one does NOT successfully pull 'abcdef + 123' as the text of the first idEscape
[Test()]
public void EscapedID()
{
FileMakerCalcParser parser = Setup("${abcdef + 123}");
FileMakerCalcParser.IdEscapeContext context = parser.idEscape();
FileMakerCalcVisitor visitor = new FileMakerCalcVisitor();
var testVal = visitor.VisitIdEscape(context);
Assert.AreEqual("abcdef + 123", testVal);
}
}
}
${abcdef + 123}
不是有效的 idEscape
,因为它以 ${
开头并以 }
结尾,idEscape
规则均不接受。按照您定义它的方式,idEscape
仅匹配 ${}
和 idEscapeExpr
之间的内容。
所以你会希望你的测试调用 idEscapeExpr
规则而不是 idEscape
或者将你正在解析的字符串更改为 abcdef + 123
(或者对每个规则进行一个测试).
我正在尝试为我的 ANTLR 解析器定义单元测试。单元测试成功提取第一个expr的值,但是fails提取第一个idEscape的值。这表明我误解了解析器工作方式或访问者工作方式的核心内容。
我正在为 FileMaker Pro 中的计算编写解析器。在 FileMaker 中,标识符包含空格以及运算符和其他字符在技术上是有效的,否则这些字符将在计算引擎中具有功能性目的。在这些情况下,标识符通过用“${”和“}”包围来转义。虽然解析器成功地将 '${abcdef + 123}' 识别为有效表达式, 我仍然需要能够将 'abcdef + 123' 识别为有效标识符。当我在第二个单元测试中请求第一个 idEscape 的值时,我得到一个空字符串。 如果相关,我正在使用 ANTLR4.Runtime.Standard.
我做错了什么?任何帮助解决我的误解的帮助将不胜感激。谢谢。
语法
grammar FileMakerCalc;
// PARSER RULES
calculation : expr;
expr : idEscExpr;
idEscExpr : LEFTESCAPE idEscape RIGHTESCAPE;
idEscape : (WORD|WS|OPERATOR|INT|FLOAT)*?;
// LEXER RULES
fragment LOWERCASE : [a-z] ;
fragment UPPERCASE : [A-Z] ;
LEFTESCAPE : '${';
RIGHTESCAPE : '}';
OPERATOR : ('+'|'-'|'*'|'/'|'&'|'^'|'='|'≠'|'<>'|'>'|'<'|'≤'|'<='|'≥'|'>=' );
WORD : (LOWERCASE | UPPERCASE)+ ;
FLOAT : [0-9]+ '.' [0-9]+;
INT : [0-9]+ ;
NEWLINE : [\r\n]+ ;
WS : [ \t];
访客
public class FileMakerCalcVisitor : FileMakerCalcBaseVisitor<String>
{
public override string VisitExpr(FileMakerCalcParser.ExprContext context)
{
return context.GetText();
}
public override string VisitIdEscape(FileMakerCalcParser.IdEscapeContext context)
{
return context.GetText();
}
}
单元测试
namespace Antler_Tests
{
[TestFixture()]
public class ParserTest
{
private FileMakerCalcParser Setup(string text)
{
AntlrInputStream inputStream = new AntlrInputStream(text);
FileMakerCalcLexer lexer = new FileMakerCalcLexer(inputStream);
CommonTokenStream commonTokenStream = new CommonTokenStream(lexer);
FileMakerCalcParser parser = new FileMakerCalcParser(commonTokenStream);
return parser;
}
// This one successfully pulls '${abcdef + 123}' as the text of the first expr
[Test()]
public void EscapedID_CheckForExpr()
{
FileMakerCalcParser parser = Setup("${abcdef + 123}");
FileMakerCalcParser.ExprContext context = parser.expr();
FileMakerCalcVisitor visitor = new FileMakerCalcVisitor();
var testVal = visitor.VisitExpr(context);
Assert.AreEqual("${abcdef + 123}", testVal, testVal);
}
// This one does NOT successfully pull 'abcdef + 123' as the text of the first idEscape
[Test()]
public void EscapedID()
{
FileMakerCalcParser parser = Setup("${abcdef + 123}");
FileMakerCalcParser.IdEscapeContext context = parser.idEscape();
FileMakerCalcVisitor visitor = new FileMakerCalcVisitor();
var testVal = visitor.VisitIdEscape(context);
Assert.AreEqual("abcdef + 123", testVal);
}
}
}
${abcdef + 123}
不是有效的 idEscape
,因为它以 ${
开头并以 }
结尾,idEscape
规则均不接受。按照您定义它的方式,idEscape
仅匹配 ${}
和 idEscapeExpr
之间的内容。
所以你会希望你的测试调用 idEscapeExpr
规则而不是 idEscape
或者将你正在解析的字符串更改为 abcdef + 123
(或者对每个规则进行一个测试).