当前位置: 首页 > 知识库问答 >
问题:

lexer和parser的ANTLR令牌识别错误

苏坚成
2023-03-14

我正在编写一个ANTLR Lexer和解析器语法,它将解析与Java类非常相似的文本。最终,它将解析如下所示的文本:

reference schema:"https://schema.org/";
reference dc:"https://www.dublincore.org/";

type dc:Author {
}

我正在慢慢地构建Lexer和Parser。我已经成功地解析了引用,但是在解析type时遇到了困难。

在添加对类型的支持之前,我能够在解析器中为空格、冒号和分号使用字符串文字,但在我遇到后无法为字符串文字错误创建隐式标记。我为这些字符中的每一个定义了一个词法分析器规则,并用该规则替换了所有出现的文字。但是,这破坏了引用s的解析。

我已经在下面列出了我的lexer和parser,它们成功地解析了引用(以及一个示例输入和解析的抽象语法树)和不起作用的改进版本。我没有收到任何编译错误,但有大量的令牌识别错误(下面包括屏幕截图)。

处理解析的正确方法是什么?

lexer grammar WorkingLexerGrammar;

WS: ('\t' | '\n' | '\r' )+ -> skip ;

fragment Colon : ':';
fragment SemiColon: ';';
fragment Underscores: '_'+ ;
fragment Digits: [0-9]+ ;
fragment LowercaseLetters: [a-z]+ ;
fragment UppercaseLetters: [A-Z]+ ;
fragment String: '"' .*? '"' ;
fragment Prefix: (Underscores | Digits | LowercaseLetters)+ ;

REFERENCE_KEYWORD: 'reference' ;
TYPE_KEYWORD: 'type' ;

PREFIXED_REFERENCE: ' ' -> pushMode(PrefixedReferenceMode) ;

mode PrefixedReferenceMode;
REFERENCE_PREFIX: Prefix;
REFERENCE_PREFIX_SEPARATOR: ':' -> pushMode(IriMode);
END_IRI: ';' -> popMode;

mode IriMode;
IRI: String  -> popMode;
parser grammar WorkingParserGrammar ;

options { tokenVocab=WorkingLexerGrammar; }

document: reference* EOF ;

prefixedReference: REFERENCE_PREFIX ':' IRI;
reference: REFERENCE_KEYWORD ' ' prefixedReference ';';
reference schema:"https://schema.org/";
reference dc:"https://www.dublincore.org/";

lexer grammar NotWorkingLexerGrammar;

WS: ('\t' | '\n' | '\r' )+ -> skip ;

fragment Colon : ':';
fragment SemiColon: ';';
fragment Underscores: '_'+ ;
fragment Digits: [0-9]+ ;
fragment LowercaseLetters: [a-z]+ ;
fragment UppercaseLetters: [A-Z]+ ;
fragment String: '"' .*? '"' ;
fragment Prefix: (Underscores | Digits | LowercaseLetters)+ ;

COLON: Colon;
SEMICOLON: SemiColon;
SPACE: ' ';

REFERENCE_KEYWORD: 'reference' ;
TYPE_KEYWORD: 'type' ;

PREFIXED_REFERENCE: SPACE -> pushMode(PrefixedReferenceMode) ;

mode PrefixedReferenceMode;
REFERENCE_PREFIX: Prefix;
REFERENCE_PREFIX_SEPARATOR: COLON -> pushMode(IriMode);
END_IRI: SEMICOLON -> popMode;

mode IriMode;
IRI: String  -> popMode;

PREFIXED_NAME: SPACE -> pushMode(PrefixedNameMode) ;

mode PrefixedNameMode;
NAME_PREFIX: Prefix;
NAME_PREFIX_SEPARATOR: COLON -> pushMode(LocalNameMode);
END_NAME: SEMICOLON -> popMode;

mode LocalNameMode;
LOCAL_NAME: (Underscores | Digits | LowercaseLetters | UppercaseLetters)+  -> popMode;
parser grammar NotWorkingParserGrammar ;

options { tokenVocab=NotWorkingLexerGrammar; }

document: reference* type* EOF ;

prefixedReference: REFERENCE_PREFIX COLON IRI;
reference: REFERENCE_KEYWORD SPACE prefixedReference SEMICOLON;

prefixedName: NAME_PREFIX SPACE LOCAL_NAME;
type: TYPE_KEYWORD SPACE prefixedName;

在巴特·基尔斯的帮助下,我对lexer和parser语法进行了两次更新,并取得了不同的成功。

此更改正确解析类型定义,但前提是我删除lexer规则以供参考。我认为原因是这两个规则是相同的(即PREFIXED_REFERENCE: SPACE-

lexer grammar NotWorkingLexerGrammar;

WS: ('\t' | '\n' | '\r' )+ -> skip ;

fragment Underscores: '_'+ ;
fragment Digits: [0-9]+ ;
fragment LowercaseLetters: [a-z]+ ;
fragment UppercaseLetters: [A-Z]+ ;
fragment String: '"' .*? '"' ;
fragment Prefix: (Underscores | Digits | LowercaseLetters)+ ;

fragment COLON: ':';
fragment SEMICOLON: ';';
fragment SPACE: ' ';

fragment REFERENCE_KEYWORD: 'reference' ;
fragment TYPE_KEYWORD: 'type' ;

PREFIXED_REFERENCE: SPACE -> pushMode(PrefixedReferenceMode) ;

mode PrefixedReferenceMode;
REFERENCE_PREFIX: Prefix;
REFERENCE_PREFIX_SEPARATOR: COLON -> pushMode(IriMode);
END_IRI: SEMICOLON -> popMode;

mode IriMode;
IRI: String  -> popMode;

PREFIXED_NAME: SPACE -> pushMode(PrefixedNameMode) ;

mode PrefixedNameMode;
NAME_PREFIX: Prefix;
NAME_PREFIX_SEPARATOR: COLON -> pushMode(LocalNameMode);
END_NAME: SEMICOLON -> popMode;

mode LocalNameMode;
LOCAL_NAME: (Underscores | Digits | LowercaseLetters | UppercaseLetters)+  -> popMode;
parser grammar NotWorkingParserGrammar ;

options { tokenVocab=NotWorkingLexerGrammar; }

document: reference* type* EOF ;

prefixedReference: REFERENCE_PREFIX REFERENCE_PREFIX_SEPARATOR IRI;
reference: REFERENCE_KEYWORD PREFIXED_REFERENCE prefixedReference END_IRI;

prefixedName: NAME_PREFIX NAME_PREFIX_SEPARATOR LOCAL_NAME;
type: TYPE_KEYWORD PREFIXED_NAME prefixedName END_NAME;

为了解决这个问题,我将引用和类型关键字移动到相应部分的Lexer规则中,但这仅在删除所有Lexer规则以供参考时才解析类型。但是,引用被正确解析。

lexer grammar NotWorkingLexerGrammar;

WS: ('\t' | '\n' | '\r' )+ -> skip ;

fragment Underscores: '_'+ ;
fragment Digits: [0-9]+ ;
fragment LowercaseLetters: [a-z]+ ;
fragment UppercaseLetters: [A-Z]+ ;
fragment String: '"' .*? '"' ;
fragment Prefix: (Underscores | Digits | LowercaseLetters)+ ;

fragment COLON: ':';
fragment SEMICOLON: ';';
fragment SPACE: ' ';

fragment REFERENCE_KEYWORD: 'reference' ;
fragment TYPE_KEYWORD: 'type' ;

PREFIXED_REFERENCE: REFERENCE_KEYWORD SPACE -> pushMode(PrefixedReferenceMode) ;

mode PrefixedReferenceMode;
REFERENCE_PREFIX: Prefix;
REFERENCE_PREFIX_SEPARATOR: COLON -> pushMode(IriMode);
END_IRI: SEMICOLON -> popMode;

mode IriMode;
IRI: String  -> popMode;

TYPE_DEFINITION: TYPE_KEYWORD SPACE -> pushMode(PrefixedNameMode) ;

mode PrefixedNameMode;
NAME_PREFIX: Prefix;
NAME_PREFIX_SEPARATOR: COLON -> pushMode(LocalNameMode);
END_NAME: SEMICOLON -> popMode;

mode LocalNameMode;
LOCAL_NAME: (Underscores | Digits | LowercaseLetters | UppercaseLetters)+  -> popMode;
parser grammar NotWorkingParserGrammar ;

options { tokenVocab=NotWorkingLexerGrammar; }

document: reference* type* EOF ;

prefixedReference: REFERENCE_PREFIX REFERENCE_PREFIX_SEPARATOR IRI;
reference: PREFIXED_REFERENCE prefixedReference END_IRI;

prefixedName: NAME_PREFIX NAME_PREFIX_SEPARATOR LOCAL_NAME;
type: TYPE_DEFINITION prefixedName END_NAME;

对于以下输入:

reference schema:"https://schema.org/";
reference dc:"https://www.dublincore.org/";

type dc:Author;

这是输出:

line 4:0 token recognition error at: 't'
line 4:1 token recognition error at: 'y'
line 4:2 token recognition error at: 'p'
line 4:3 token recognition error at: 'e'
line 4:4 token recognition error at: ' '
line 4:5 token recognition error at: 'd'
line 4:6 token recognition error at: 'c'
line 4:7 token recognition error at: ':'
line 4:8 token recognition error at: 'A'
line 4:9 token recognition error at: 'u'
line 4:10 token recognition error at: 't'
line 4:11 token recognition error at: 'h'
line 4:12 token recognition error at: 'o'
line 4:13 token recognition error at: 'r;'

我使用模式的理由是限制规则的范围。这是一种我可以控制的语言,但我不想对其进行太大的更改。这种语言比我在这里展示的要多得多,我们已经有了一种语法(目前是一种组合语法),但它非常脆弱。我试图做出改变,防止前缀中出现大写字符,但允许在本地名称中使用大写字符,但这种情况越来越严重,其他规则也开始适用。研究表明,模式是处理这种情况的一种方法,但我对ANTLR不是很熟悉,所以我可能误解了它。


共有1个答案

郎羽
2023-03-14

遇到以下错误/警告时:

line 4:0 token recognition error at: 't'
line 4:1 token recognition error at: 'y'
line 4:2 token recognition error at: 'p'
line 4:3 token recognition error at: 'e'
...

这意味着lexer无法为输入构造令牌(在这种情况下为type...)。在您的情况下,这意味着lexer无法从输入中创建令牌,因为它当时处于模式中。

我试图作出改变以防止大写字符在前缀但允许他们在本地名称但这滚雪球和其他规则开始适用

解决此类问题有两种选择:

  1. 只需像任何普通标识符一样解析前缀(大小写或小写),解析后,遍历生成的解析树并使用ANTLR访问者或侦听器验证前缀标识符确实是小写的(参见:https://github.com/antlr/antlr4/blob/master/doc/listeners.md)
  2. 在词法分析器中区分大小写标识符和大小写标识符,并在解析器规则中相应地使用它们,这样的东西可以工作:
document
 : reference* type* EOF
 ;

reference
 :  K_REFERENCE LOWER_ID COL STRING SCOL
 ;

type
 : K_TYPE LOWER_ID COL id OPAR CPAR
 ;

id
 : LOWER_ID
 | ID
 ;

K_REFERENCE : 'reference';
K_TYPE      : 'type';
LOWER_ID    : [a-z_] [a-z_0-9]*;
ID          : [a-zA-Z_] [a-zA-Z_0-9]*;
STRING      : '"' ~["]* '"';
SCOL        : ';';
COL         : ':';
OPAR        : '{';
CPAR        : '}';
SPACES      : [ \t\r\n] -> skip;

模式用于真正嵌入了两种(或更多)语言的输入。例如,解析HTML文件:有内容(文本)和带有属性的标记。依我看,你并不是在按本意使用它,依我看。

 类似资料:
  • 我有以下ANTLR 4的语法: 我试图解析以下字符串 代码解析出左侧的ab cd,在我的应用程序中,它将被视为文本字符串。然后,它将解析为一个字符集,在这种情况下,该字符集将转换为任何数字。我的语法对我来说很有用,但我不喜欢将语法作为语法分析器规则(CHAR | DASH),因为它只是被当作一个标记。我希望lexer创建一个字符串,并给我以下标记: 而不是这些 我看了其他的例子,但还没有弄明白。通

  • 现在我得到了:错误。 我知道我的输入被AND和TERM lexer规则匹配,但我希望能够指定TERM是除与AND规则匹配的内容之外的任何内容。

  • 本文向大家介绍ANTLR Lexer命令,包括了ANTLR Lexer命令的使用技巧和注意事项,需要的朋友参考一下 示例 词法分析器规则可以具有关联的命令: ->在规则末尾的a之后定义命令。 skip:跳过匹配的文本,不会发出令牌 channel(n):在其他频道上发出令牌 type(n):更改发出的令牌类型 mode(n),pushMode(n),popMode,more:控制词法分析器模式

  • 我需要antlr4来解析一些简单的HTML文件。我已经将语法分为解析器语法和lexer语法,这样我就可以对标记内部的东西( )使用孤岛语法,如“确定的ANTLR4引用”中所述。antlr4反复告诉我“令牌识别错误”。 解析器语法: 示例HTML文件: ANTLR4的输出:

  • 我使用ANTLR Version4创建编译器。第一阶段是Lexer部分。我创建了“compilerlexer.g4”文件,并在其中输入了lexer规则。 compilerlexer.g4: null 有几十个这样的警告和错误。病因是什么? 一般问题:使用组合语法和单独使用lexer和parser有什么不同?如何连接单独的语法和lexer文件?

  • 我试图使用ANTLR4创建一个简单的解析器,但我在识别lexer令牌方面遇到了问题。问题是,即使单词SAYS后面有一个“:”,解析器规则也不能识别它。而且对于提及,@Michael也没有被识别出来。 输入的文本是:john说:hello@Michael这将不起作用 //LEXER规则