如何在简单语法中使用 Space

How to use Space in a simple grammar

我是 antlr 和 ebnf 的初学者。

我在antlr4中表达了如下语法:

grammar RecordGrammar;

Record: 'record';
EndRecord: 'endrecord';

Track: 'track';
EndTrack: 'endtrack';

Length: 'length';

Name: [a-zA-Z]+;
Number: [0-9]+;
WS: [ \t\r\n]+;

records: (record)+ EOF;

record: Record WS Name WS
            tracks WS?
        EndRecord WS?;

tracks: track WS? (track WS)*;

track: Track WS
          length
       EndTrack WS?;

length: Length WS Number WS?;

当我在本文中使用上面的语法(使用 antlr)时:

record help
    track
     length 2
    endtrack
    track
       length 4
    endtrack
    track
       length 42
    endtrack
endrecord

...它工作得很好而且花花公子。

但我想扩展 EBNF 中的 'Name' 规则以也接受 Space。

所以我希望语法也接受这个文本文件:

record help me
    track
     length 2
    endtrack
    track
       length 4
    endtrack
    track
       length 42
    endtrack
endrecord

观察记录标签右侧的文字"help me"。

如何在语法中实现这一点?由于 Space 是一个自然的分隔符,我需要在我的规则中对此进行某种特殊处理。感谢我能得到的所有帮助...

您可以创建匹配多个 Name 标记的 name 解析器规则:

name : Name (WS+ Name)*;

但是因为你并没有真正对空格做任何事情,所以请注意在标记化过程中通过添加 -> skip 然后从你的解析器规则中删除所有 WS 来丢弃它们:

grammar RecordGrammar;

records     : record+ EOF;
record      : Record name tracks EndRecord;
tracks      : track+;
track       : Track length EndTrack;
length      : Length Number;
name        : Name+;

Record      : 'record';
EndRecord   : 'endrecord';
Track       : 'track';
EndTrack    : 'endtrack';
Length      : 'length';
Name        : [a-zA-Z]+;
Number      : [0-9]+;
WS          : [ \t\r\n]+ -> skip;

这将导致以下解析树:

您应该首先决定如何确定名称的实际结束位置。在最初的语法中,这很简单——它是一个单词,所以它以空白字符结尾。在 Bart 的回答中,它是单词 'record' 和 'track' * 之间的每个单词。但这是你的情况吗,或者这个名字实际上可以包含 'track' 这个词吗?

您可能还需要考虑以下选项:

  • 在行尾终止名称(在这种情况下,空格变得很重要,您需要在名称中允许该词,使其成为 非保留关键字 ).
  • 用引号 (") 或撇号 (') 括起一个多词名称 - 在这种情况下,空格并不重要,可以根据 Bart 的回答跳过。

*) 它比实际情况更复杂 - 但这是它如何查找记录名称末尾的基本概念。