【问题标题】:How will I parse a tag with space in its value using antlr?我将如何使用 antlr 解析带有空格的标签?
【发布时间】:2016-12-12 07:49:09
【问题描述】:

我有以下语法。

meta 
    : '<' NAME '>' TEXT '</' NAME '>'
    | '<' NAME S* attribute* '>';

dl : '<' NAME '><' TEXT '>' dt* '</' NAME '><' TEXT '>';

dt : '<' NAME '><' NAME S* attribute* S* '>' TEXT '</' NAME '>';

attribute : attributeName '=' attributeValue;

attributeName : NAME;

attributeValue : VAL;

NAME : [A-Z0-9_-]+;

VAL : '"'.*?'"';

TEXT : [A-Za-z0-9:\/\.@\-;\s*]+;

S : [ \t\r\n]+ -> skip;

字符串是

<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<TITLE>Abcd</TITLE>
<H1>Abcd</H1>
<DL><p>
    <DT><H3 ADD_DATE="1481473849" LAST_MODIFIED="1481473992" PERSONAL_XYZ_FOLDER="true">Foo bar</H3>
</DL><p>

我收到以下错误:

ParseError extraneous input 'bar' expecting '</'  clj-antlr.common/parse-error (common.clj:146)

问题是空格被跳过,所以当Foo bar 有空格时,它会给出错误。但是,如果我没有跳过空格,我会在 META 解析中遇到另一个错误。 (跳过空格时不需要S*)。

ParseError extraneous input ' ' expecting {'>', NAME}
mismatched input '>' expecting '><'
mismatched input '<' expecting {<EOF>, COMMENT, S}  clj-antlr.common/parse-error (common.clj:146)

这是我的 antlr 生成的令牌文件:

T__0=1
T__1=2
T__2=3
T__3=4
T__4=5
DTD=6
COMMENT=7
NAME=8
VAL=9
TEXT=10
S=11
'<'=1
'>'=2
'</'=3
'><'=4
'='=5

当我使用grun 运行时,我得到以下信息,但在报告的令牌中没有看到任何错误。它类似于我定义的语法。如何接受标签值中的空格?

$ grun MyGrammer r -tokens
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
[@0,0:0='<',<1>,1:0]
[@1,1:4='META',<8>,1:1]
[@2,5:5=' ',<11>,1:5]
[@3,6:15='HTTP-EQUIV',<8>,1:6]
[@4,16:16='=',<5>,1:16]
[@5,17:30='"Content-Type"',<9>,1:17]
[@6,31:31=' ',<11>,1:31]
[@7,32:38='CONTENT',<8>,1:32]
[@8,39:39='=',<5>,1:39]
[@9,40:65='"text/html; charset=UTF-8"',<9>,1:40]
[@10,66:66='>',<2>,1:66]
[@11,67:67='\n',<11>,1:67]
[@12,68:67='<EOF>',<-1>,2:0]
No method for rule r or it has arguments

谢谢。

【问题讨论】:

  • 如果你跳过了一个记号,比如 S,那么你就不能在规则中使用它,这个记号不会在记号流中的任何地方供解析器匹配。

标签: java clojure antlr antlr4 ebnf


【解决方案1】:

如果您在foobar 之间放置一个空格,词法分析器将其生成为两个标记(TEXT 类型),但语法规定只允许一个名称标记。要解决您的问题,您只需通过 plus-operator 允许在 seqnece 中包含一些 TEXT:

dt : '<' NAME '><' NAME S* attribute* S* '>' TEXT+ '</' NAME '>';

另外请注意,您可能会遇到问题,因为 Lexer 会在 NAME 而不是 TEXT 中转换相当多的输入,因为它们都可以匹配模式 [A-Z0-9]+

【讨论】:

  • 我给了TEXT+,但我收到一个错误:ParseError extraneous input ' ' expecting {'&lt;/', TEXT}
  • 就像你说的,当我将BOO 作为标签值时,它与NAME 匹配,所以我得到一个错误。我怎样才能避免这种情况?我不想用TEXT 替换NAME,以免它不匹配额外的字符。 antlr 可以吗?
  • 我修复了最后一部分,将content 作为值,content: NAME* | TEXT*;。但空间问题并没有解决。
  • 乌鸦:非常感谢!有效。我正在尝试没有S 中的skip 部分。
  • 不客气! :) 正如您已经(部分)发现,您在词法分析器中的问题可以通过将两个所需的标记与层中的相同标记匹配来解决,然后定义将来自词法分析器的各个标记组合成“新类型”的解析器规则"
猜你喜欢
  • 2012-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多