parsing - ANTLR Lexer 匹配错误的规则
问题描述
我正在为一个旧的面向对象的聊天系统(MOO,以防任何读者熟悉它的语言)开发词法分析器和解析器。在该语言中,以下任何示例都是有效的浮点数:
2.3
3.
.2
3e+5
该语言还实现了一种索引语法,用于从字符串或列表中提取一个或多个字符(这是一组用大括号括起来的逗号分隔表达式)。问题出在语言支持索引括号内的范围运算符这一事实。例如:a = foo[1..3];
我知道 ANTLR 想首先匹配最长的匹配。不幸的是,这导致词法分析器将 '1..3' 视为两个浮点数(1. 和 .3),而不是它们之间带有范围运算符('..')的两个整数。有什么办法可以解决这个不使用词法分析器模式的问题吗?鉴于索引表达式中的值可以是任何有效的表达式,我将不得不复制很多令牌规则(基本上除了我理解的浮点数之外的所有)。现在,我是 ANTLR 的新手,所以我确定我遗漏了一些东西,非常感谢任何帮助。我将在下面提供我的词法分析器语法:
lexer grammar MooLexer;
channels { COMMENTS_CHANNEL }
SINGLE_LINE_COMMENT
: '//' INPUT_CHARACTER* -> channel(COMMENTS_CHANNEL);
DELIMITED_COMMENT
: '/*' .*? '*/' -> channel(COMMENTS_CHANNEL);
WS
: [ \t\r\n] -> channel(HIDDEN)
;
IF
: I F
;
ELSE
: E L S E
;
ELSEIF
: E L S E I F
;
ENDIF
: E N D I F
;
FOR
: F O R;
ENDFOR
: E N D F O R;
WHILE
: W H I L E
;
ENDWHILE
: E N D W H I L E
;
FORK
: F O R K
;
ENDFORK
: E N D F O R K
;
RETURN
: R E T U R N
;
BREAK
: B R E A K
;
CONTINUE
: C O N T I N U E
;
TRY
: T R Y
;
EXCEPT
: E X C E P T
;
ENDTRY
: E N D T R Y
;
IN
: I N
;
SPLICER
: '@';
UNDERSCORE
: '_';
DOLLAR
: '$';
SEMI
: ';';
COLON
: ':';
DOT
: '.';
COMMA
: ',';
BANG
: '!';
OPEN_QUOTE
: '`';
SINGLE_QUOTE
: '\'';
LEFT_BRACKET
: '[';
RIGHT_BRACKET
: ']';
LEFT_CURLY_BRACE
: '{';
RIGHT_CURLY_BRACE
: '}';
LEFT_PARENTHESIS
: '(';
RIGHT_PARENTHESIS
: ')';
PLUS
: '+';
MINUS
: '-';
STAR
: '*';
DIV
: '/';
PERCENT
: '%';
PIPE
: '|';
CARET
: '^';
ASSIGNMENT
: '=';
QMARK
: '?';
OP_AND
: '&&';
OP_OR
: '||';
OP_EQUALS
: '==';
OP_NOT_EQUAL
: '!=';
OP_LESS_THAN
: '<';
OP_GREATER_THAN
: '>';
OP_LESS_THAN_OR_EQUAL_TO
: '<=';
OP_GREATER_THAN_OR_EQUAL_TO
: '>=';
RANGE
: '..';
ERROR
: 'E_NONE'
| 'E_TYPE'
| 'E_DIV'
| 'E_PERM'
| 'E_PROPNF'
| 'E_VERBNF'
| 'E_VARNF'
| 'E_INVIND'
| 'E_RECMOVE'
| 'E_MAXREC'
| 'E_RANGE'
| 'E_ARGS'
| 'E_NACC'
| 'E_INVARG'
| 'E_QUOTA'
| 'E_FLOAT'
;
OBJECT
: '#' DIGIT+
| '#-' DIGIT+
;
STRING
: '"' ( ESC | [ !] | [#-[] | [\]-~] | [\t] )* '"';
INTEGER
: DIGIT+;
FLOAT
: DIGIT+ [.] (DIGIT*)? (EXPONENTNOTATION EXPONENTSIGN DIGIT+)?
| [.] DIGIT+ (EXPONENTNOTATION EXPONENTSIGN DIGIT+)?
| DIGIT+ EXPONENTNOTATION EXPONENTSIGN DIGIT+
;
IDENTIFIER
: (LETTER | DIGIT | UNDERSCORE)+
;
LETTER
: LOWERCASE
| UPPERCASE
;
/*
* fragments
*/
fragment LOWERCASE
: [a-z] ;
fragment UPPERCASE
: [A-Z] ;
fragment EXPONENTNOTATION
: ('E' | 'e');
fragment EXPONENTSIGN
: ('-' | '+');
fragment DIGIT
: [0-9] ;
fragment ESC
: '\\"' | '\\\\' ;
fragment INPUT_CHARACTER
: ~[\r\n\u0085\u2028\u2029];
fragment A : [aA];
fragment B : [bB];
fragment C : [cC];
fragment D : [dD];
fragment E : [eE];
fragment F : [fF];
fragment G : [gG];
fragment H : [hH];
fragment I : [iI];
fragment J : [jJ];
fragment K : [kK];
fragment L : [lL];
fragment M : [mM];
fragment N : [nN];
fragment O : [oO];
fragment P : [pP];
fragment Q : [qQ];
fragment R : [rR];
fragment S : [sS];
fragment T : [tT];
fragment U : [uU];
fragment V : [vV];
fragment W : [wW];
fragment X : [xX];
fragment Y : [yY];
fragment Z : [zZ];
解决方案
不,AFAIK,没有办法使用词法分析器模式解决这个问题。您需要一个带有一些目标特定代码的谓词。如果 Java 是您的目标,则可能如下所示:
lexer grammar RangeTestLexer;
FLOAT
: [0-9]+ '.' [0-9]+
| [0-9]+ '.' {_input.LA(1) != '.'}?
| '.' [0-9]+
;
INTEGER
: [0-9]+
;
RANGE
: '..'
;
SPACES
: [ \t\r\n] -> skip
;
如果您运行以下 Java 代码:
Lexer lexer = new RangeTestLexer(CharStreams.fromString("1 .2 3. 4.5 6..7 8 .. 9"));
CommonTokenStream tokens = new CommonTokenStream(lexer);
tokens.fill();
for (Token t : tokens.getTokens()) {
System.out.printf("%-20s `%s`\n", RangeTestLexer.VOCABULARY.getSymbolicName(t.getType()), t.getText());
}
你会得到以下输出:
INTEGER `1`
FLOAT `.2`
FLOAT `3.`
FLOAT `4.5`
INTEGER `6`
RANGE `..`
INTEGER `7`
INTEGER `8`
RANGE `..`
INTEGER `9`
EOF `<EOF>`
是{ ... }?
谓词,嵌入代码必须计算为布尔值。_input.LA(1) != '.'
在我的示例中,如果当前位置前 1 步的字符流不等于'.'
char ,则 Java 代码返回 true。
推荐阅读
- python - 在Regex Python中组合AND运算符和限制字符长度
- mysql - GCLOUD SQL 性能提升
- javascript - 有没有办法使用控制台自动触发 html 页面上的所有 onlick() 事件?
- visual-studio-code - 当我通过 Docker 运行我的 AWS 条带应用程序时,为什么没有检测到我的 PaymentMethod ID?
- authentication - 在 Open ID Connect 中配置静默认证
- android - 为什么我在 Google Play 商店中收到“此应用与您的所有设备的设备不兼容”
- javascript - JavaScript 日期格式
- c++ - 配对函数出错:没有运算符“>>”与这些操作数匹配
- javascript - JS 正则表达式查找替换 URL 的协议并从字符串到字符串结尾
- c++ - 如何在此 C++ lambda 表达式中获取局部变量?