2016-05-31 8 views
1

У меня есть 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 

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

ответ

4

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

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

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

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

Одним из возможных вариантов было бы:

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

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

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

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

+0

Это сработало. Большое спасибо. Он делает именно то, что мне нужно, и ответ был в целом весьма информативным. – pootzko

0

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

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

Я нашел их here.

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

+0

Это было бы точно эквивалентно добавлению '\ r' в список символов пробела, за исключением одного важного отличия: ваш оригинал возвращает один токен NEWLINE для любого количества строк новой строки (фактически игнорируя пустые строки), тогда как тот, который указан в этом ответе отправляет токен NEWLINE для каждой новой строки. Еще раз подумав о том, что я рекомендую для случая, когда вы хотите игнорировать пустые строки, это '\ n \ s *'. – rici

+0

@rici - Я не уверен, что понял, что вы только что написали. Вы имели в виду, если я использовал \ n \ s * вместо \ n +, который игнорировал бы несколько последовательных пустых строк? В основном я просто хочу знать, когда была пустая строка, поэтому я мог бы использовать ее как разделитель, а затем самостоятельно анализировать следующую строку. Если это имеет смысл. Если у вас есть лучшее решение, чем в этом ответе, я с радостью приму его, если он сделает то, что я только что описал. – pootzko

+0

В целом я чувствую себя немного потерянным в поиске правильной документации по этим правилам, поскольку у каждого языка есть свои собственные причуды о том, как сделать такое соответствие шаблону регулярного выражения, и, похоже, нет достаточно ясной информации о том, как это сделать в Jison/Bison. – pootzko

Смежные вопросы