首页 > 解决方案 > 如何摆脱词汇模式

问题描述

我一直在尝试使用模式来解析这样的消息:

-MSGTXT (DO NOT TOKENIZE (THERE CAN BE PARENS HERE) THIS PART)
-END END OF MESSAGE
-TEST 123

MSGTXT 的内容可以是任何字符,因此我将我的词法分析器语法设置如下:

lexer grammar ADEXPLexer;

// Fields
MSGTYP: 'MSGTYP';
ADEP: 'ADEP';
TITLE: 'TITLE';
FILTIM: 'FILTIM';
ORIGINDT: 'ORIGINDT';
IFPLID: 'IFPLID';
MSGTXT: 'MSGTXT' -> pushMode(MSG);
COMMENT: 'COMMENT';

// Message types.
ACK: 'ACK';
IFPL: 'IFPL';

// Lexical rules.
SEP: HYPHEN;
WS: [ \t\n\r] + -> skip;
KEYWORD: (ALPHA|DIGIT)+;

mode MSG;
  TEXT: CLOSE_MSG | (ALPHA|DIGIT|SPECIAL|WS|HYPHEN)+;
  CLOSE_MSG: ')' -> popMode;

fragment HYPHEN: '-';
fragment ALPHA: [A-Z];
fragment DIGIT: [0-9];
fragment SPECIAL
  : '('
    | '?'
    | ':'
    | '.'
    | ','
    | '\''
    | '='
    | '+'
    | '/'
    | ')'  
  ;

然而,现在的问题是,最后一个关闭的 ')' 永远不会用于重新进入默认模式,因此它会继续进入消息的其他部分。解析器规则本身如下所示:

msgtxt: SEP MSGTXT TEXT;

我正在寻找一种不涉及 TokenStreamRewriter 的方法来解决这个问题,因为 JavaScript 运行时中没有这样的东西。

任何帮助表示赞赏!

标签: antlr4

解决方案


不确定你到底需要什么,但如果你不需要检查内容是否TEXT是其中之一,请(ALPHA|DIGIT|SPECIAL|WS|HYPHEN)使用:

mode MSG;
  TEXT: ~[)]+;
  CLOSE_MSG: ')' -> popMode;

如果你这样做,只需')'排除fragment SPECIAL


推荐阅读