antlr4 - 用于简单命令处理器的 Lexer 和 Parser 规则
问题描述
我正在尝试为遗留语言构建一个简单的命令处理器。
我正在尝试使用具有 antlr4 版本“ANTLR”、“4.6.6”的 C#)
我无法在几种情况下取得进展。
以下示例显示命令 PKS 的各种示例调用。
PKS
PKS?
PKStext_that_is_a_filename
我无法解决的场景是 PKS 命令后跟文件名。
Command:
PKS
(block (line (expr (command PKS)) (eol \r\n)) <EOF>)
Command:
PKS?
(block (line (expr (command PKS) (query ?)) (eol \r\n)) <EOF>)
Command:
PKSFILENAME
line 1:0 mismatched input 'PKSFILENAME' expecting COMMAND
(block PKSFILENAME \r\n)
Command:
我认为是相关的语法片段:
block : line+ EOF;
line : (expr eol)+;
expr : command file
| command listOfDouble
| command query
| command
;
command : COMMAND
;
query : QUERY;
file : TEXT ;
eol : EOL;
listOfDouble: DOUBLE (COMMA DOUBLE)* ;
从词法分析器:
COMMAND : PKS;
PKS :'PKS' ;
QUERY : '?'
;
fragment LETTER : [A-Z];
fragment DIGIT : [0-9];
fragment UNDER : [_];
TEXT : (LETTER) (LETTER|DIGIT|UNDER)* ;
解决方案
这里的主要问题是您的TEXT
规则也匹配PKS
应该匹配的内容。并且由于PKStext_that_is_a_filename
可以完全与该TEXT
规则匹配,因此它优于PKS
规则,即使它首先出现在语法中(如果 2 个规则匹配相同的输入,则第一个获胜)。
为了解决该问题,您有 2 个选项:
- 在关键字 (PKS) 和表达式的其余部分之间需要空格。
- 更改
TEXT
规则以明确排除“PKS”作为有效输入。
选项 2 肯定是可能的,但是如果您有更多关键字(因为它们都必须被排除),它会变得非常混乱。在关键字和文本之间有一个空格,词法分析器会自动为您执行此操作。
让我给你一个提示来解决这类问题:总是检查词法分析器生成的标记列表,看看它是否生成了你期望的标记。我稍微修改了你的语法,添加了丢失的标记并通过我的 ANTLR4 调试器运行它,它给了我:
Parser error (5, 1): extraneous input 'PKStext_that_is_a_filename' expecting {<EOF>, COMMAND, EOL}
Tokens:
[@0,0:2='PKS',<1>,1:0]
[@1,3:3='\n',<8>,1:3]
[@2,4:4='\n',<8>,2:0]
[@3,5:7='PKS',<1>,3:0]
[@4,8:8='?',<3>,3:3]
[@5,9:9='\n',<8>,3:4]
[@6,10:10='\n',<8>,4:0]
[@7,11:36='PKStext_that_is_a_filename',<7>,5:0]
[@8,37:37='\n',<8>,5:26]
[@9,38:37='<EOF>',<-1>,6:0]
对于此输入:
PKS
PKS?
PKStext_that_is_a_filename
这是我使用的语法:
grammar Example;
start: block;
block: line+ EOF;
line: expr? eol;
expr: command (file | listOfDouble | query)?;
command: COMMAND;
query: QUERY;
file: TEXT;
eol: EOL;
listOfDouble: DOUBLE (COMMA DOUBLE)*;
COMMAND: PKS;
PKS: 'PKS';
QUERY: '?';
fragment LETTER: [a-zA-Z];
fragment DIGIT: [0-9];
fragment UNDER: [_];
COMMA: ',';
DOUBLE: DIGIT+ (DOT DIGIT*)?;
DOT: '.';
TEXT: LETTER (LETTER | DIGIT | UNDER)*;
EOL: [\n\r];
和生成的视觉解析树:
推荐阅读
- javascript - 让 Clock 组件真正可重用和封装?在反应 JS 中?
- angular - 如何路由 Angular 6 级联下拉列表?
- javascript - fetch() 中的 Async/Await 如何处理错误
- git - How is a local tracking branch created for a remote tracking branch?
- c++ - 如何将数据添加到指针数组?
- php - 读取位于 zip 存档中的 php 文件
- javascript - 为什么 jQuery each() 函数的行为就像是异步的?
- ios - 将数据从 Firestore 映射到 Swift 中的结构 - IOS
- go - 无需等待流缓冲区刷新即可将数据上传到表
- c++ - 有没有办法检查 QLabel pixmap 是否设置为特定的东西?