Как бы вы проанализировали стандартное утверждение if - else if - else? (с RPLY)

в обычном JavaScript в браузере:

var xhr = new XMLHttpRequest();

xhr.onreadystatechange = function() {
  if (xhr.readyState == XMLHttpRequest.DONE ) {
    if(xhr.status == 200){
      console.log(xhr.responseText);
    } else if(xhr.status == 400) {
      console.log('There was an error 400');
    } else {
      console.log('something else other than 200 was returned');
    }
  }
}

xhr.open("GET", "mock_data.json", true);

xhr.send();

Или если вы хотите использовать Browserify для объединения ваших модулей с помощью node.js , Вы можете использовать суперагент :

var request = require('superagent');
var url = '/mock_data.json';

 request
   .get(url)
   .end(function(err, res){
     if (res.ok) {
       console.log('yay got ' + JSON.stringify(res.body));
     } else {
       console.log('Oh no! error ' + res.text);
     }
 });

0
задан jonhue 15 January 2019 в 19:28
поделиться

1 ответ

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

Вот один пример:

else_if_clause_seq: else_if_clause .  [$end, NEWLINE, DEDENT]
                  | else_if_clause . NEWLINE else_if_clause_seq

Это взято из дампа конечного автомата Бизона для той же грамматики. Состояние синтаксического анализатора - это коллекция «элементов»; Каждый предмет - это производство с отмеченной позицией. (Метка - это . в двух продуктах.) Метка в основном показывает, как далеко продвинулся парсер, когда он достигает этого состояния; если . находится в конце производства (как в первой строке), то возможно действие сокращения, потому что синтаксический анализатор достиг конца производства. Если . имеет некоторый следующий символ, то парсер может сдвинуть следующий токен, если следующий токен может быть (или быть первым токеном в некотором расширении) следующим символом. В случае второй продукции, описанной выше, a NEWLINE можно было бы сдвинуть, если бы это был следующий токен.

Продукция в штате также аннотируется набором преднамеренного просмотра, хотя бизон показывает только набор предварительного просмотра для продукций, которые могут быть уменьшены. Аннотация [$end, NEWLINE, DEDENT] в конце первого производства - это перспективный набор этого производства. Другими словами, это набор возможных следующих токенов в контексте, в котором производство может быть сокращено.

Это состояние является конфликтом сдвига / уменьшения, потому что NEWLINE может либо вызвать уменьшение else_if_clause_seq: else_if_clause, либо его можно сдвинуть в предположении, что NEWLINE else_if_clause_seq будет проанализирован. Поскольку разрешением конфликта сдвига / уменьшения по умолчанию является предпочтение сдвига (в bison, ply, rply и большинстве других генераторов синтаксического анализатора LR), сокращение никогда не произойдет, что заставит синтаксический анализатор всегда выбирать попытки расширения else_if_clause_seq , Фактически это означает, что за else_if_clause, находящимся не в конце блока, всегда должен следовать другой else_if_clause, что делает невозможным анализ else_if true 1 else 1, в котором за else_if_clause следует предложение else. [тысяча сто пятьдесят-пять] 1156 У парсера, который мог бы смотреть вперед два токена, не было бы проблем с этой грамматикой. Второй следующий токен, следующий за NEWLINE, должен быть либо else, либо else_if; в первом случае требуется уменьшение, а во втором случае сдвиг является правильным действием. Фактически, NEWLINE действительно не имеет смысла, так как и else, и else_if всегда должны предшествовать токены NEWLINE. Кроме того, поскольку else_if_clause может заканчиваться только block, а block может заканчиваться только DEDENT, мы можем заключить, что NEWLINE должен предшествовать DEDENT.

Похоже, что вы решили отправить NEWLINE после DEDENT, поскольку ваша грамматика, кажется, указывает на то, что вы отправили NEWLINE до и INDENT. Это, вероятно, работает в теории, но это определенно приводит к конфликтам сдвига / уменьшения, которые вы испытываете.

Более распространенная реализация лексического сканирования с учетом пробелов использует алгоритм , описанный в руководстве по Python : токен NEWLINE генерируется при обнаружении новой строки, если только окружающие строки не присоединены явно или неявно. и затем принимается решение о выдаче либо одного INDENT, одного или нескольких DEDENT с, либо ничего. Тщательное изучение грамматики Python показывает, как это сочетается. Вот упрощенная выдержка в EBNF:

stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: expr_stmt …
compound_stmt: if_stmt …
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT

suite более или менее соответствует вашему block, но допускает использование однотипных операторов без отступов в одной строке, но обратите внимание, что оно начинается с NEWLINE. Простые (не составные) операторы заканчиваются на NEWLINE; составные операторы рассматриваются как самоограниченные.

Альтернативный подход состоит в том, чтобы выдавать токены NEWLINE только в случае, когда две последовательные строки имеют одинаковый отступ. Как отмечено выше, маркеры NEWLINE в строках с отступом или с отступом строго избыточны, так как их присутствие может быть выведено; их полное исключение уменьшает количество токенов, которые должны обрабатываться парсером. Но если вы сделаете это, вы больше не сможете использовать простой принцип, согласно которому простые операторы всегда заканчиваются символом NEWLINE, поскольку за последним простым оператором в block непосредственно следует DEDENT. Это делает необходимым использование несколько более сложного (и праворекурсивного) определения expression_seq:

block              : INDENT statement_sequence DEDENT
statement          : simple_statement | compound_statement
statement_sequence : statement
                   | simple_statement NEWLINE statement_sequence
                   | compound_statement statement_sequence
0
ответ дан rici 15 January 2019 в 19:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: