【问题标题】:lexer that takes "not" but not "not like"接受“不”但不接受“不喜欢”的词法分析器
【发布时间】:2012-05-04 12:44:55
【问题描述】:

我需要一个小技巧来让我的解析器完全工作。 我使用 antlr 来解析布尔查询。

查询由元素组成,通过 ands、ors 和 nots 链接在一起。

所以我可以有类似的东西:

"(P or not Q or R) or (( not A  and B) or C)"

问题是,一个元素可以很长,一般是这样的:

a an_operator b

例如:

"New-York matches NY"

诡计,其中一个 an_operator 是“不像”

所以我想修改我的词法分析器,以便 not 检查它后面是否没有 like,以避免解析包含“not like”运算符的元素。

我现在的语法在这里:

// save it in a file called Logic.g
grammar Logic;

options {
  output=AST;
}

// parser/production rules start with a lower case letter
parse
  :  expression EOF!    // omit the EOF token
  ;

expression
  :  orexp
  ;

orexp
  :  andexp ('or'^ andexp)*    // make `or` the root
  ;

andexp
  :  notexp ('and'^ notexp)*      // make `and` the root
  ;

notexp
  :  'not'^ atom    // make `not` the root
  |  atom
  ;

atom
  :  ID
  |  '('! expression ')'!    // omit both `(` andexp `)`
  ;

// lexer/terminal rules start with an upper case letter
ID    : ('a'..'z' | 'A'..'Z')+;
Space : (' ' | '\t' | '\r' | '\n')+ {$channel=HIDDEN;};

任何帮助将不胜感激。 谢谢!

【问题讨论】:

  • 我说 lex 和 yacc,不是 Antlr。 lex 中的典型解决方案是显式识别关键字和运算符;解析器规范没有。在 Antlr 中,你能不能不写一个像“'not like'^ atom”这样的产生式?
  • @DavidGorsline,我不会让not likenot 这样的一元运算符。 not 通常否定布尔表达式,而 not like 比较 2 个值(表达式的左侧和右侧)。此外,创建与'not like' 匹配的标记会在中间有更多空格时导致问题,或者当词法分析器偶然发现'not likes''not lik' 之类的输入时(这将导致词法分析器跳闸,就像 gnu-lex会的,我相信,但我不会说那个太流利:))

标签: java parsing antlr grammar lexer


【解决方案1】:

这是一个可能的解决方案:

grammar Logic;

options {
  output=AST;
}

tokens {
  NOT_LIKE;
}

parse
  :  expression EOF!
  ;

expression
  :  orexp
  ;

orexp
  :  andexp (Or^ andexp)*
  ;

andexp
  :  fuzzyexp (And^ fuzzyexp)*
  ;

fuzzyexp
  :  (notexp -> notexp) ( Matches e=notexp  -> ^(Matches $fuzzyexp $e)
                        | Not Like e=notexp -> ^(NOT_LIKE $fuzzyexp $e)
                        | Like e=notexp     -> ^(Like $fuzzyexp $e)
                        )?
  ;

notexp
  :  Not^ atom
  |  atom
  ;

atom
  :  ID
  |  '('! expression ')'!
  ;

And     : 'and';
Or      : 'or';
Not     : 'not';
Like    : 'like';
Matches : 'matches';
ID      : ('a'..'z' | 'A'..'Z')+;
Space   : (' ' | '\t' | '\r' | '\n')+ {$channel=HIDDEN;};

这会将输入 "A not like B or C like D and (E or not F) and G matches H" 解析为以下 AST:

【讨论】:

  • 非常感谢,能多看到一些g代码就好了:)。我真的在寻找一种完全抛弃“不喜欢”的方法,因为我使用了另一种解析技术。我会搜索“A NOT LIKE B primary”和“C like D”。实际上只应处理 OR、NOT、AND 和括号
  • @jlengrand,我不确定您所说的“完全丢弃”是什么意思。你想跳过这些令牌吗?更多细节会有所帮助。请不要使用评论框进行解释:改为编辑您的原始问题。
  • 更新了我的答案。希望这会有所帮助
  • @jlengrand,不,我还不清楚。你说你'“不喜欢”不应该被处理',但这是什么意思呢?从流中跳过?标记为其他东西(然后呢?)?我发布了一个示例,说明从我的示例语法生成的解析器如何为输入 "A not like B or C like D and (E or not F) and G matches H" 构造一个 AST。现在,您能指出您要创建的 AST 是什么吗?不是文字,而是像我发布的真实图像(当然可以是 ASCII 图像)。
  • 嗨。抱歉耽搁了。我一直在重新考虑我的方法,我认为花一些时间真正学习 Antlr 的工作方式比仅仅为了快速修复而运行更有用。我将尝试只使用一个解析器而不是两个,所以你的答案非常适合这个问题。非常感谢
猜你喜欢
  • 2016-03-10
  • 2016-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-01
  • 2019-04-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多