如何检测 Jison 中的新行?

How to detect new line in Jison?

我有一段 Jison 代码,如下所示:

%lex
%options flex

%{
if (!('regions' in yy)) {
    yy.regions = [];
}
%}

text                [a-zA-Z][a-zA-Z0-9]*

%%

\s+                 /* skip whitespace */
\n+                 return 'NL';
","                 return ',';
"-"                 return '-';
"["                 return '[';
"]"                 return ']';
{text}              return 'TEXT';
<<EOF>>             return 'EOF';

/lex

%start expressions

%%

expressions
    : content EOF
        {
            console.log(yy.regions);
            return yy.regions; 
        }
    | EOF
        {
            console.log("empty file");
            return yy.regions; 
        }
    ;

content
    : line NL content
        { console.log("NL"); }
    | line content
        { console.log("no NL"); }
    //| line NL
    //    { console.log("parsing line with NL"); }
    | line
        { console.log("parsing line"); }
    ;

line 
    : '[' text ']'
        { yy.regions.push(); $$ = ; }
    ;

text
    : TEXT
        { $$ = ; }
    ;

这是我目前输入的样子(我从我计划拥有的最基本的结构开始,我想从那里开始构建它):

[sectionA]
[sectionB]
[sectionC]

我遇到的问题是未检测到新行。它总是进入 line content 而从不进入 line NL content。稍后我想解析一些看起来更像这样的东西:

[sectionA]
something1, something2, something3
something4, something5, something6

[sectionB]
something4, something5, something6

[sectionC]
something4, something5, something6
something4, something5, something6
something4, something5, something6

将来这会变得更复杂一些,但我最初的想法是将其分解为每行(在许多情况下,新行将用作分隔符)。我对这些东西完全陌生,所以我可能对如何解决这个问题有一个完全错误的想法。所以我的问题是如何检测新行?此外,如果对我正在尝试做的事情有更好的方法,我们非常欢迎任何建议。谢谢。

这两个规则都将匹配换行符:

\s+                 /* skip whitespace */
\n+                 return 'NL';

既然先到先得,就赢了。 (Flex 会警告您未使用第二条规则,但我不相信 jison 会进行该分析。)

虽然改变规则的顺序没有帮助,因为第一条规则将匹配 SPACE NL ,从而吞下换行符(如果它前面有空格)。您需要更改空格规则以仅匹配不是换行符的空格。

一种可能性是:

\n\s*     return 'NL';
[^\S\n]+  /* ignore whitespace other than newlines */

第一个模式将匹配换行符后跟任何空格序列,这意味着它将匹配多个换行符。当输入中有一个空行时,这将避免返回多个 NL 标记;除非空白行很重要,否则这可能就是您想要的。

第二种模式避免匹配任何换行符,因此它不会与第一种模式冲突。

有些人担心 Windows 行尾 (\r\n) 的使用,但由于 Javascript 的 \s 包含 \r,所以有这里没有真正的问题。 \r 将被第二条规则忽略,而 \n 将被第一条规则识别。如果您认为有必要,可以将第一个规则更改为 \r?\n\s* 以提高效率,但结果可能不会更快。

@rici 的回答很有帮助,它让我走上了正确的轨道。然而,[ \t]+ 没有做我需要的。这些是我最终使用的两条线:

(\r?\n)+\s*         return 'NEWLINE';
[^\S\r\n]+          ; /* whitespace */

我找到了它们 here

编辑:@rici 更新后的答案比这个答案更清楚,并且完全符合我的需要,所以我接受了。