0

我想为以下字符串创建一个使用 antlr 的解析器:

“1 AND (2 OR (3 AND 4)) AND 5” -> 所以我想要 AND 和 OR 操作,这应该会在解析成功后生成一棵树。这应该会产生以下树:

AND
   - 1
   - OR
       - 2
       - AND
           -3
           -4
   - 5

我还想避免像“1 AND 2 OR 3”这样的不清楚的输入,因为不清楚如何从中构造树。而且解析器似乎也“接受”了带有尾随歌声的输入,例如“1 AND 2asdf”。

到目前为止我所拥有的是(没有按预期工作):

    grammar code;

options {
  language=CSharp3;
  output=AST;
  ASTLabelType=CommonTree;
  //backtrack=true;
}

tokens {
  ROOT;
}


@rulecatch {
    catch {
        throw;
    }
}


@parser::namespace { Web.DealerNet.Areas.QueryBuilder.Parser }
@lexer::namespace { Web.DealerNet.Areas.QueryBuilder.Parser }

@lexer::members {
  public override void  ReportError(RecognitionException e) {
        throw e;
  }
}


public parse : exp EOF -> ^(ROOT exp);


exp
  : atom
    ( And^ atom (And! atom)*
    | Or^ atom (Or! atom)*
    )?
  ;

atom
  :  Number
  |  '(' exp ')' -> exp
  ;

Number
  :  ('0'..'9')+
  ;

And
  :  'AND' | 'and'
  ;

Or
  :  'OR' | 'or'
  ;

WS       :           (' '|'\t'|'\f'|'\n'|'\r')+{ Skip(); };

希望你们中的某个人可以帮助我走上正轨!

编辑:以及我如何归档“1 AND 2 AND 3”以产生

AND
    1
    2
    3

代替

AND
    AND
        1
        2
    3

编辑:

感谢伟大的解决方案,它就像一个魅力,除了一件事:当我在以下术语“1 AND(2 OR(1 AND 3) AND 4”(缺少右括号)上调用 parse() 方法时,解析器仍然接受输入为有效。

到目前为止,这是我的代码:语法代码;

options {
  language=CSharp3;
  output=AST;
  ASTLabelType=CommonTree;
}

tokens {
  ROOT;
}


@rulecatch {
    catch {
        throw;
    }
}


@lexer::members {
  public override void  ReportError(RecognitionException e) {
        throw e;
  }
}

public parse
  :  exp -> ^(ROOT exp)
  ;


exp
  : atom
    ( And^ atom (And! atom)*
    | Or^ atom (Or! atom)*
    )?
  ;

atom
  :  Number
  |  '(' exp ')' -> exp
  ;

Number
  :  ('0'..'9')+
  ;

And
  :  'AND' | 'and'
  ;

Or
  :  'OR' | 'or'
  ;

WS       :           (' '|'\t'|'\f'|'\n'|'\r')+{ Skip(); };

编辑2: 我刚刚发现我的语法有另一个问题:当我输入像“1 AND 2 OR 3”这样的输入时,语法被解析得很好,但它应该失败,因为“1 AND 2”需要在括号内或“ 2 或 3" 部分。我不明白为什么解析器会运行,因为我认为这个语法应该真正涵盖这种情况。是否有任何类型的在线测试环境来查找问题?(我试过antlrWorks,但那里给出的错误并没有把我带到任何地方......)

edit3: 更新了代码以表示建议的新语法。


我仍然有以下语法相同的问题:

public parse : exp EOF -> ^(ROOT exp);

没有解析到最后.. 生成的 c# 源似乎只是忽略了 EOF ......你能提供任何关于如何解决问题的进一步指导吗?

edit4 我仍然有以下语法相同的问题:

公共解析:exp EOF -> ^(ROOT exp);

没有解析到最后.. 生成的 c# 源似乎只是忽略了 EOF ......你能提供任何关于如何解决问题的进一步指导吗?

问题似乎出在这部分代码中:

EOF2=(IToken)Match(input,EOF,Follow._EOF_in_parse97);  
            stream_EOF.Add(EOF2);

当我添加以下代码(只是一个黑客)时,它可以工作......

        if (EOF2.Text == "<missing EOF>") {
            throw new Exception(EOF2.Text);
        }

我可以更改任何内容以便解析器从一开始就正确生成吗?

4

1 回答 1

1

此规则将禁止同时包含ANDOR不包含括号的表达式。它还将通过将第一个ANDorOR标记作为 AST 的根,然后将其余的ANDorOR标记隐藏在同一表达式中来构造您描述的解析树。

exp
  : atom
    ( 'AND'^ atom ('AND'! atom)*
    | 'OR'^ atom ('OR'! atom)*
    )?
  ;

编辑:第二个问题与此无关。如果您不通过EOF在您的解析器规则之一中包含显式符号来指示 ANTLR 使用所有输入,则允许它仅使用一部分输入以尝试成功匹配某事

原始parse规则说“将某些输入匹配为exp”。对规则的以下修改parse表示“将整个输入匹配为exp”。

public parse : exp EOF -> ^(ROOT exp);
于 2013-07-04T15:52:56.147 回答