Моя простая грамматика ANTLR игнорирует некоторые неверные токены при разборе
Я задал вопрос пару недель назад о моей грамматике ANTLR ( моя простая грамматика ANTLR не работает должным образом). С тех пор как я задал этот вопрос, я стал больше копать и отлаживать и получил большую часть изломов. Я остался с одной проблемой, хотя.
Мой сгенерированный код синтаксического анализатора не собирает недопустимые токены в одной определенной части текста, который обрабатывается. Лексер правильно разбивает вещи на токены, но в некоторых случаях парсер не выбрасывает недействительные токены. В частности, когда недопустимый токен находится в конце фразы, такой как "A и B", анализатор игнорирует его - как будто токена даже нет.
Некоторые конкретные примеры:
- "А и Б" - совершенно верно
- "A@ and B" - синтаксический анализатор правильно подбирает неверный токен @
- "A and @B" - парсер правильно выбирает неверный токен @
- "A и B@" - вот загадка - лексер находит маркер @, а анализатор игнорирует его (!)
- "(A и B@) или C" - еще одна загадка - лексер находит маркер @, а синтаксический анализатор игнорирует его (!)
Вот моя грамматика:
grammar QvidianPlaybooks;
options{ language=CSharp3; output=AST; ASTLabelType = CommonTree; }
public parse
: expression
;
LPAREN : '(' ;
RPAREN : ')' ;
ANDOR : 'AND'|'and'|'OR'|'or';
NAME : ('A'..'Z');
WS : ' ' { $channel = Hidden; };
THEREST : .;
// ***************** parser rules:
expression : anexpression EOF!;
anexpression : atom (ANDOR^ atom)*;
atom : NAME | LPAREN! anexpression RPAREN!;
Код, который затем обрабатывает получающееся дерево, выглядит так:
... from the main program
QvidianPlaybooksLexer lexer = new QvidianPlaybooksLexer(new ANTLRStringStream(src));
QvidianPlaybooksParser parser = new QvidianPlaybooksParser(new CommonTokenStream(lexer));
parser.TreeAdaptor = new CommonTreeAdaptor();
CommonTree tree = (CommonTree)parser.parse().Tree;
ValidateTree(tree, 0, iValidIdentifierCount);
// recursive code that walks the tree
public static RuleLogicValidationResult ValidateTree(ITree Tree, int depth, int conditionCount)
{
RuleLogicValidationResult rlvr = null;
if (Tree != null)
{
CommonErrorNode commonErrorNode = Tree as CommonErrorNode;
if (null != commonErrorNode)
{
rlvr = new RuleLogicValidationResult();
rlvr.IsValid = false;
rlvr.ErrorType = LogicValidationErrorType.Other;
Console.WriteLine(rlvr.ToString());
}
else
{
string strTree = Tree.ToString();
strTree = strTree.Trim();
strTree = strTree.ToUpper();
if ((Tree.ChildCount != 0) && (Tree.ChildCount != 2))
{
rlvr = new RuleLogicValidationResult();
rlvr.IsValid = false;
rlvr.ErrorType = LogicValidationErrorType.Other;
rlvr.InvalidIdentifier = strTree;
rlvr.ErrorPosition = 0;
Console.WriteLine(String.Format("CHILD COUNT of {0} = {1}", strTree, tree.ChildCount));
}
// if the current node is valid, then validate the two child nodes
if (null == rlvr || rlvr.IsValid)
{
// output the tree node
for (int i = 0; i < depth; i++)
{
Console.Write(" ");
}
Console.WriteLine(Tree);
rlvr = ValidateTree(Tree.GetChild(0), depth + 1, conditionCount);
if (rlvr.IsValid)
{
rlvr = ValidateTree(Tree.GetChild(1), depth + 1, conditionCount);
}
}
else
{
Console.WriteLine(rlvr.ToString());
}
}
}
else
{
// this tree is null, return a "it's valid" result
rlvr = new RuleLogicValidationResult();
rlvr.ErrorType = LogicValidationErrorType.None;
rlvr.IsValid = true;
}
return rlvr;
}