Зубр: $$ и $ 1 указывают на одну и ту же ячейку памяти (объединение YYSTYPE двух типов указателей) - PullRequest
0 голосов
/ 08 ноября 2011

Я создавал парсер для очень простого парсера, когда внезапно начал получать SEGFAULT.Я сократил свой код до минимума, где он идет не так:

Это мой файл test.flex:

%{
#include "test.tab.h"
#include <iostream>
using namespace std;
%}
%option noyywrap
%%
model { yylval.a = new double(); return IDENTIFIER; }
.     { cerr << "Unrecognized token!" << endl; exit(1); }
%%

Это мой файл test.y:

%{
#include <iostream>
using namespace std;
int yylex();
int yyerror(const char *p) { cerr << "Error" << endl; }
%}

%union YYSTYPE {
  double* a;
  int* b;
};

%token <a> IDENTIFIER 
%type <b> expression

%%
expression : IDENTIFIER { cout << "got here! " << $1 << "|" << $$ << endl; };
%%

int main()
{
  yyparse();
  cout << "Success!" << endl;
  return 0;
}

Наш союз состоит из двух указателей, a и b.$ 1 и $$ имеют разные типы (a и b соответственно).

При вводе «model» вывод «получен здесь! 0x372a28 | 0x372a28» (и «Success!» Во второй строке),это означает, что $ 1 и $$ указывают на одно и то же место в памяти!Это, конечно, приводит к возникновению всевозможных плохих вещей.

Назначение yylval.a в лексере необходимо для проявления ошибки.

Я использую Bison 2.4.1 и Flex 2.5.4, оба для Windows (используя GnuWin32).Я делаю что-то неправильно?Это (известная) ошибка?

РЕДАКТИРОВАТЬ: Если я изменяю объединение на:

%union YYSTYPE {
  int a;
  int b;
};

и правило на

expression : IDENTIFIER { cout << "got here! " << &$1 << "|" << &$$ << endl; };

(и удаляем назначениев лексере) результирующие области памяти, описанные , различаются , что позволяет мне полагать, что области памяти самих переменных различны, если не используются указатели.Однако, если бы это было так, если я использую указатели, присваивание "yylval.a = new double ();"следует только изменить $ 1 и оставить $ $ нетронутым.

Ответы [ 2 ]

1 голос
/ 08 ноября 2011

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

Поскольку вы выполняете приведение типов здесь (?), я думаю, что вы должны иметь в действии что-то вроде

double *a = $1;
$$ = new int((int)(*a));
delete a;

Обратите внимание, что когда вы пишете в $$больше не могу читать $ 1, потому что вы взяли слот стека, где раньше был $ 1.

0 голосов
/ 08 ноября 2011

Выражение имеет только один компонент, поэтому его левая и правая части точно совпадают. Я не уверен, почему вы находите это удивительным.

Думаю, я знаю, где твое замешательство:

expression : IDENTIFIER

Это говорит о том, что одна действительная форма для expression - это IDENTIFIER. Таким образом, все, что является действительным IDENTIFIER, также является действительным expression.

...