Почему последнее правило соответствует моему файлу lex, когда у меня есть лучшие правила? - PullRequest
1 голос
/ 09 ноября 2019

У меня есть файл lex с моими правилами, такими как:

PROGRAM           return Parser::PROGRAM;
PROGRAM_END       return Parser::PROGRAM_END;
VARIABLES:        return Parser::VARIABLES;
INSTRUCTIONS:     return Parser::INSTRUCTIONS; 
SKIP              return Parser::SKIP;
.           {
                std::cerr << lineno() << ": ERROR." << std::endl;
                exit(1);
            }

, и когда я пытаюсь использовать полностью скомпилированную (с файлом yacc и т. Д.) Версию, то натестовый файл только этот, последнее правило используется, даже если тестовый файл правильный.

Например, это тестовый файл для этих правил:

PROGRAM fst
INSTRUCTIONS:
    SKIP
PROGRAM_END

Для этого файла я получил только: 1: ERROR.

Почему это так и как я могу решить эту проблему?

1 Ответ

1 голос
/ 09 ноября 2019

Как указано в комментариях, почти наверняка PROGRAM начинает распознаваться как токен и передается парсеру. Однако почти во всех случаях анализатор немедленно запросит другой токен, а следующий символ во входной последовательности - это пробел, которому соответствует последнее правило. Это правило печатает сообщение об ошибке и вызывает exit(), завершая работу приложения. (Как правило, это не очень хорошая идея, но я предполагаю, что это всего лишь тестовая программа.) Так что это все, что вы получите.

Если вы укажете аргумент командной строки -d при вызове (f) lex, тогда будет создан отладочный сканер, который сообщает о работе сканера, как он работает. Это очень простой способ увидеть, что происходит в вашем сканере. Bison также имеет режим отладки, как объяснено в руководстве по бизонам . Эти инструменты очень просты в использовании и рекомендуются к использованию.

Вот, например, быстрый тестовый стенд:

%{
#include <iostream>
#include <cstdlib>
class Parser {
  public:
    enum Token {
      PROGRAM = 257,
      PROGRAM_END, VARIABLES, INSTRUCTIONS, SKIP
    };
};
%}
%option batch noyywrap yylineno c++
%%
PROGRAM           return Parser::PROGRAM;
PROGRAM_END       return Parser::PROGRAM_END;
VARIABLES:        return Parser::VARIABLES;
INSTRUCTIONS:     return Parser::INSTRUCTIONS; 
SKIP              return Parser::SKIP;
.                 {
                    std::cerr << lineno() << ": ERROR." << std::endl;
                    exit(1);
                  }
%%
int main() {
  yyFlexLexer lexer{};
  lexer.set_debug(1);
  while(lexer.yylex() != 0) { }
  return 0;
}

и примерный прогон:

$ g++ lex.yy.cc && ./a.out<<<"PROGRAM fst"
--(end of buffer or a NUL)
--accepting rule at line 14("PROGRAM")
--accepting rule at line 19(" ")
1: ERROR.

, который дает понять, что сканер сначала выдал токен PROGRAM, прежде чем выйти из символа пробела.

...