Antlr4 用于简单命令处理器的Lexer和Parser规则

Antlr4 用于简单命令处理器的Lexer和Parser规则,antlr4,Antlr4,我正在尝试为遗留语言构建一个简单的命令处理器 我正在尝试使用C#使用antlr4版本“ANTLR”,“4.6.6”) 我无法在一种情况下取得进展,其中有几种情况 以下示例显示了命令PKS的各种示例调用 PKS 我无法解决的情况是PKS命令后跟文件名 Command: PKS (block (line (expr (command PKS)) (eol \r\n)) <EOF>) Command: PKS? (block (line (expr (command PKS) (quer

我正在尝试为遗留语言构建一个简单的命令处理器

我正在尝试使用C#使用antlr4版本“ANTLR”,“4.6.6”)

我无法在一种情况下取得进展,其中有几种情况

以下示例显示了命令PKS的各种示例调用

PKS
我无法解决的情况是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:
从lexer:

COMMAND     : PKS;
PKS         :'PKS' ;

QUERY       : '?'
            ;

fragment LETTER : [A-Z];
fragment DIGIT  : [0-9];
fragment UNDER  : [_];

TEXT        : (LETTER) (LETTER|DIGIT|UNDER)* ;

这里的主要问题是,您的
TEXT
规则也与
PKS
应该匹配的内容相匹配。由于
PKStext\u是一个文件名
可以完全与
TEXT
规则匹配,因此它比
PKS
规则更可取,即使它在语法中出现在第一位(如果两条规则匹配相同的输入,则第一条规则获胜)

要解决该问题,您有两个选项:

  • 在关键字(PKS)和表达式的其余部分之间需要空格
  • 更改
    TEXT
    规则以明确排除“PKS”作为有效输入
  • 选项2当然是可能的,但如果你有更多的关键字,就会变得非常混乱(因为它们都必须被排除在外)。在关键字和文本之间有一个空格,lexer会自动为您这样做

    让我给你一个解决此类问题的提示:总是检查lexer生成的令牌列表,看看它是否生成了你期望的令牌。我重新修改了您的语法,添加了缺少的标记,并通过我的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]
    
    
    以下是我使用的语法:

    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];
    
    
    以及生成的可视化解析树:

    COMMAND     : PKS;
    PKS         :'PKS' ;
    
    QUERY       : '?'
                ;
    
    fragment LETTER : [A-Z];
    fragment DIGIT  : [0-9];
    fragment UNDER  : [_];
    
    TEXT        : (LETTER) (LETTER|DIGIT|UNDER)* ;
    
    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];