0

我的 EBNF 和 Tatsu 实现中存在问题,为 Tatsu 提取语法 EBNF:

define  ='#define' constantename [constante] ;
constante = CONSTANTE ;  
CONSTANTE = ( Any | ``true`` ) ;
Any = /.*/ ;  
constantename = (/[A-Z0-9_()]*/) ;

当我测试时:

#define _TEST01_ "test01"
#define _TEST_
#define _TEST02_ "test02"

我得到:

[
    "#define",
    "_TEST01_",
    "\"test01\""
],
[
    "#define",
    "_TEST_",
    "#define _TEST02_ \"test02\""
]

但我想要这个:

[
    "#define",
    "_TEST01_",
    "\"test01\""
],
[
    "#define",
    "_TEST_",
    "true"
],
[
    "#define",
    "_TEST02_",
    "\"test02\""
]

我的错误在哪里?

非常感谢...

4

1 回答 1

2

问题是 Tatsu 默认跳过元素之间的空格,包括换行符。因此,当您将规则'#define' constantename [constante]应用于输入时:

#define _TEST_
#define _TEST02_ "test02"

它首先与 匹配#define'#define'然后跳过空格,然后与 匹配_TEST_constantename然后跳过换行符,然后#define _TEST02_ "test02"ANY(via constante) 匹配。

请注意,如果换行符不存在,这正是您想要的行为(我假设):

#define _TEST_ #define _TEST02_ "test02"

在这里你想要输出["#define", "_TEST_", "#define _TEST02_ \"test02\""],对吧?在这种情况下,至少 C 预处理器会以相同的方式处理它。

所以这告诉我们换行很重要。因此你不能忽视它。你可以告诉 Tatsu 只忽略制表符和空格(不是换行符),方法是whitespace = '\t '在创建解析器时作为选项传递,或者将此行添加到语法中:

@@whitespace :: /[\t ]+/

现在您需要在换行符应该去的任何地方明确提及换行符,因此您的规则变为:

define  ='#define' constantename [constante] '\n';

现在很清楚,如果存在常量,应该出现在换行符之前,所以对于 line #define _TEST_,它会意识到没有常量。

请注意,您还需要一个规则来匹配空行,因此空行不是语法错误。

于 2018-11-08T17:24:43.897 回答