лимон + re2c не получает правильное разрешение правила

Это моя грамматика парсера лимона

%nonassoc IMPLICATION.
%nonassoc PERIOD.
%nonassoc NEWLINE.
%nonassoc END.
%nonassoc STRING.

program ::= in END.
in ::= .
in ::= in rule NEWLINE.
in ::= in rule.
rule ::= STRING(A) IMPLICATION STRING(B) PERIOD. {cout<<A->token<<endl; cout<<B->token<<endl;}

Моя входная строка

p<-body1.
q<-body3.

Я ожидаю, что результат будет

p
body1
q
body3

но вместо этого я получаю вывод как

q
q
\n (Empty line here)
\n (Empty line here)

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

Вот код, который я использую для передачи токенов в парсер

do
{
token = lexer.scan(); // returns an int with the type of token
Token* t = new Token(lexer.getTokenValue().c_str());

lpmlnParse(pParser, token, t);
}while(token != PARSE_TOKEN_END);

Я в растерянности относительно того, что идет не так. Может кто-нибудь направить меня в правильном направлении.

0

Решение

Это все еще предположение, потому что нет никаких признаков того, как работает сканер, или каково значение lexer.getTokenValue() или как Token Конструктор использует свой аргумент.

Но давайте представим, что lexer объект включает в себя частный std::string элемент, который присваивается сопоставляемому тексту после сканирования каждого токена:

struct lexer {
// ...
int scan() {
int toke;
const char* start = current_;
/* re2c stuff */
tstring_.assign(start, current_ - start);
return toke;
}
const std::string& getTokenValue() const {
return tstring_;
}
std::string tstring_;
const char* current_;
};

И предположим, что Token включает в себя const char* член (вместо std::string):

struct Token {
explicit Token(const char* s) : str_(s) {}
const char* str_;
}

Это, по крайней мере, объясняет наблюдаемое поведение.

Каждый последующий призыв к lexer.scan() перезаписывает содержимое tstring_, (В общем случае std::string::assign может перераспределить внутренний массив символов, но поскольку современные библиотеки C ++ используют оптимизацию коротких строк, а все токены в примере кода являются короткими строками, здесь этого не произойдет.)

Так как ни std::string::c_str ни Token конструктор делает копию символов, конечным результатом является то, что вновь созданный Token имеет указатель на изменяемый внутренний буфер, который будет перезаписан (или, что еще хуже, удален) в процессе сканирования.

И, следовательно, строковое значение Token будет отличаться, когда это наблюдается в действии сокращения, что это было, когда Token был впервые создан.

Этого все еще недостаточно, чтобы объяснить, почему q печатается по правилу, которое предположительно уменьшено p->body1.,

В отличие от bison, lemon Парсер не пытается оптимизировать запросы. bisonСгенерированные синтаксические анализаторы будут выполнять сокращения до того, как будет запрашиваться токен предпросмотра, если маркер предпросмотра не требуется для принятия решения об уменьшении или сдвиге. По сравнению, lemon-произведенные парсеры уменьшаются только при наличии токена предпросмотра. В этом случае сокращение производства rule ::= STRING(A) IMPLICATION STRING(B) PERIOD. не зависит от токена, следующего за PERIOD, но парсер лимона все еще будет ждать следующего токена.

Из грамматики можно ожидать, что следующий токен был NEWLINE, но в этом случае выходные данные должны показывать два символа новой строки (или четыре пустых строки, так как семантическое действие также печатает новую строку). Поскольку это не так, мы можем предположить, что лексер пропускает символы новой строки, а не возвращает NEWLINE маркер. Если бы это было так, грамматика все равно будет работать, потому что NEWLINE токен не является обязательным (оба in rule а также in rule NEWLINE действительны с правой стороны). Тогда жетон предвкушения будет следующим STRING токен, который будет q, И жетон предвкушения после q->body3. будет END, а не NEWLINE, поэтому вполне вероятно, что соответствующая строка токена будет пустой, а не перевод строки.

Очевидно, что если все вышеприведенные предположения верны, решением будет сделать копию строки токена, например, заменить const char* str_; с std::string str_; в Token объект. И в этом случае было бы разумно заменить const char* конструктор с const std::string& конструктор, или даже простой std::string конструктор, что позволяет избежать необходимости использовать std::string::c_str(),

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]