Parsing 如何在Jison中检测新线?

Parsing 如何在Jison中检测新线?,parsing,bison,jison,Parsing,Bison,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 ','; "-"

我有一段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($2); $$ = $2; }
    ;

text
    : TEXT
        { $$ = $1; }
    ;
[sectionA]
something1, something2, something3
something4, something5, something6

[sectionB]
something4, something5, something6

[sectionC]
something4, something5, something6
something4, something5, something6
something4, something5, something6
我遇到的问题是没有检测到新线。它总是进入
行内容
,而从不进入
行NL内容
。稍后,我将分析更像这样的内容:

%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($2); $$ = $2; }
    ;

text
    : TEXT
        { $$ = $1; }
    ;
[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会进行这种分析。)

但是,更改规则的顺序不会有帮助,因为第一条规则将匹配空格NL,因此如果换行符前面有空格,则会吞掉换行符。您需要更改空格规则,使其仅匹配不是换行符的空格

一种可能性是:

\n\s*     return 'NL';
[^\S\n]+  /* ignore whitespace other than newlines */
第一个模式将匹配一个换行符,后跟任何空格序列,这意味着它将匹配多个换行符。这将避免在输入中有空行时返回多个
NL
令牌;除非空行很重要,否则这可能就是你想要的

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


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

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

\s+                 /* skip whitespace */
\n+                 return 'NL';
既然第一个是第一个,它就会赢。(Flex会警告您第二条规则未被使用,但我不相信jison会进行这种分析。)

但是,更改规则的顺序不会有帮助,因为第一条规则将匹配空格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 */
我找到了


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

@rici的答案帮助了我,让我走上了正确的道路。但是,
[\t]+
没有完成我需要的任务。以下是我最后使用的两行代码:

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


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

这完全等同于将
\r
添加到空白字符列表中,除了一个重要的区别:您的原始答案为任意数量的换行返回一个换行符标记(实际上忽略空行)然而,这个答案中的一个会为每一个换行符发送一个换行符。再想一想,我建议您忽略空行的情况是
\n\s*
@rici-我不确定我是否理解您刚才写的内容。您的意思是如果我使用\n\s*而不是\n+,那会忽略多个连续的空行吗?Basicall我只是想知道什么时候出现了一个空行,这样我就可以用它作为一个分隔符,然后自己解析下一行。如果这有意义的话。如果你有一个比这个答案中的更好的解决方案,如果它符合我刚才描述的,我会很乐意接受它。总的来说,我觉得找不到关于这些规则的适当文档有点迷茫s每种语言在如何进行这种正则表达式模式匹配方面都有自己的怪癖,而且在Jison/Bison中似乎没有足够清晰的信息来说明如何进行这种匹配。我在回答中添加了我的建议。是的,正则表达式有些怪癖,但不同语言的概念是相同的;重要的是要清楚你想要什么确实如此。几乎每个解析器生成器中都会出现由多个令牌匹配的令牌问题,并且具有相同的分辨率。jison和flex在“空白字符”的拼写上有所不同,在jison和
[:space:]中,空白字符是
\s
在flex中。这既烦人又令人困惑,但至少有文档记录。这完全等同于将
\r
添加到空白字符列表中,除了一个重要的区别:原始代码为任意数量的换行返回一个换行标记(实际上忽略了空行)而这个答案中的那个会为每一条换行发送一个换行标记。再想想,我给cas推荐的是什么