用简单的逻辑字符串构造树的antlr语法

时间:2013-07-04 12:05:58

标签: c# parsing tree antlr

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

“1 AND(2 OR(3 AND 4))和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(); };

EDIT2: 我刚发现我的语法有另一个问题: 当我输入像“1 AND 2 OR 3”时,语法被解析得很好,但它应该失败,因为“1 AND 2”需要在括号内或“2 OR 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);
        }

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

1 个答案:

答案 0 :(得分:1)

此规则将禁止包含ANDOR且不带括号的表达式。它还将构造您描述的解析树,方法是将第一个ANDOR标记作为AST的根,然后隐藏ANDOR标记的其余部分来自同一个表达。

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

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

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

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