Как обнаружить новую линию в 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($2); $$ = $2; }
    ;

text
    : TEXT
        { $$ = $1; }
    ;

Вот как выглядит мой вклад в данный момент (я начал с самой базовой конструкции, которую планирую иметь, и я хотел бы построить ее оттуда):

[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

В будущем это будет немного сложнее, но моя первоначальная идея заключалась в том, чтобы разбить его на отдельные строки (во многих случаях новая строка будет служить разделителем). Я совершенно новичок в этом деле, поэтому у меня может быть совершенно неверное представление о том, как это решить. Итак, мой вопрос, как я могу обнаружить новую строку? Также, если есть лучший подход к тому, что я пытаюсь сделать, любой совет более чем приветствуется. Благодарю.

2 ответа

Решение

Оба эти правила будут соответствовать новой строке:

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

Так как первый - первый, он победит. (Flex даст вам предупреждение о том, что второе правило не используется, но я не верю, что jison проводит такой анализ.)

Изменение порядка правил, тем не менее, не поможет, поскольку первое правило будет соответствовать пробелу NL, тем самым проглатывая символ новой строки, если ему предшествует пробел. Вам нужно изменить правило пробела, чтобы оно совпадало только с пробелами, которые не являются символами новой строки.

Одна возможность будет:

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

Первый шаблон будет соответствовать новой строке, за которой следует любая последовательность пробелов, что означает, что он будет соответствовать нескольким символам новой строки. Это позволит избежать возврата более одного NL токен, когда на входе есть пустая строка; если пустые строки не являются значительными, это, вероятно, то, что вы хотите.

Второй шаблон избегает сопоставления с любой новой строкой, поэтому он не может конфликтовать с первым шаблоном.

Некоторые люди беспокоятся об использовании оконечных линий Windows (\r\n) но так как яваскрипт \s включает в себя \rЗдесь нет реальной проблемы. \r будет игнорироваться вторым правилом и \n признан первым. Вы можете изменить первое правило на \r?\n\s* для эффективности, если вы считаете, что это необходимо, но это может оказаться не так быстро.

Ответ @rici помог, и это поставило меня на правильный путь. Тем не мение, [ \t]+ не делал то, что мне было нужно. Вот две строки, которые я использовал в итоге:

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

Я нашел их здесь.

Изменить: обновленный ответ @rici яснее, чем этот ответ, и делает именно то, что мне нужно, поэтому я принимаю это.

Другие вопросы по тегам