Char * как YYSTYPE в flex / bison, возвращающий только первый символ в токене при использовании с strdup () в лексере - PullRequest
2 голосов
/ 03 декабря 2011

Я использую char* в качестве YYSTYPE в компиляторе, построенном с использованием flex и bison. Линия

#define YYSTYPE char*

вверху моего файла грамматики. Некоторым токенам в моем лексере нужно передать всю строку, соответствующую им, в мою грамматику, а другим просто нужно передать свой токен, так что это хорошо работает для меня. Я делаю такие вещи в моем лексере:

[(foo|bar)]    {yylval = *strdup(yytext); return FOOBAR;}

В своей грамматике я использую их с такими постановками:

fb:
    FOOBAR
    {
        sprintf($$, "%s", &$1);
    }
    ;

Устанавливает значение $$ для первого символа в оригинальном сопоставленном токене. Я (вероятно) понимаю, почему разыменованный char* является char, но шаги, которые я предпринял, чтобы исправить это, вызвали проблемы. Например, удаление & из строки sprintf() приводит к segfault. Удаление * из присваивания вызывает «делает целое число из указателя без приведения». Что я делаю? Я думаю, что проблема заключается в присвоении yylval.

Ответы [ 3 ]

4 голосов
/ 03 декабря 2011

Измените присвоение обратно на yylval = strdup(yytext), измените sprintf(...) на $$ = yylval.Убедитесь, что YYSTYPE определен в вашем файле синтаксического анализатора (.y), и что этот заголовок создан и импортирован в файл лексера (.l).


Я надеялся использоватьпросто YYSTYPE, но я не мог заставить это работать, поэтому используйте %union{}.
После экспериментов и немного вернувшись, я получил его для работы с этими изменениями:

В вашем parser.y:

%{
%}

%output "parser.c"
%defines "parser.h"

%union {
    char *str;
}

%type <str> fb
%start fb

%token FOOBAR

%%
fb: FOOBAR { $$ = yylval.str; }
%%

В вашем lexer.l:

%{
#include <string.h> 
#include "parser.h"
%}

%option outfile="lexer.c"
%option header-file="lexer.h"

%%
[(foo|bar)] { yylval.str = strdup(yytext); return FOOBAR; }
%%

Примечание:

  1. Вам нужно будет определить yyerror, yywrapи main где-то.
  2. В нынешнем виде это не free строка, вам нужно выяснить, где лучше всего это сделать.
4 голосов
/ 03 декабря 2011

Есть несколько проблем с тем, что вы делаете.Прежде всего, поскольку YYSTYPE является указателем на символ, на самом деле для строки не выделено места.Поэтому, когда вы делаете sprintf($$, "%s", &$1), вы пытаетесь напечатать строку в указатель, который не инициализирован ($$ является указателем, но ни на что не инициализирован, поэтому может указывать на любое место в памяти.)

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

Третья проблема - вы используете strdup в лексере, который выделяет память.Но вы никогда не освобождаете его где-то, что приводит к утечке памяти.

Четвертая и последняя проблема заключается в том, почему вы получаете только один символ, и вам действительно повезло, что вы это получили, и это потому, что пока strdup(yytext) возвращаетсякопия строки, звезда перед ней возвращает разыменованный указатель, который является символом.Таким образом, вы устанавливаете указатель на один символ.

Редактировать: Надеюсь, все это имеет смысл, уже поздно, и я мог бы выпить стакан вина или два ...

3 голосов
/ 10 мая 2013

Я решил это следующим образом (в .l и .y перед .tab.h #include):

#ifndef YYSTYPE
# define YYSTYPE char*
#endif
...