Почему получается segmentation fault у программы на yacc?
Я пытаюсь запустить пример(4.3. Обрабатываем конфигурационный файл) из этого HOW-TO. Это код, который подан вход как язык L1:
zone "." {
type hint;
file "/etc/bind/db.root";
};
Это исходники, с которыми я работаю:
LEX-файл (example6.l)
%{
#include <stdio.h>
#include "y.tab.h"
%}
%%
zone return ZONETOK;
file return FILETOK;
[a-zA-Z][a-zA-Z0-9]* yylval=strdup(yytext); return WORD;
[a-zA-Z0-9\/.-]+ yylval=strdup(yytext); return FILENAME;
\" return QUOTE;
\{ return OBRACE;
\} return EBRACE;
; return SEMICOLON;
\n /* ignore EOL */;
[ \t]+ /* ignore whitespace */;
%%
Ниже - файл (example6.y) с грамматикой (yacc)
%{
#include <stdio.h>
#include <string.h>
#define YYSTYPE char *
int yydebug=0;//пока без дебага
void yyerror(const char *str)
{
fprintf(stderr,"error: %s\n",str);
}
int yywrap()
{
return 1;
}
main()
{
yyparse();
}
%}
%token WORD FILENAME QUOTE OBRACE EBRACE SEMICOLON ZONETOK FILETOK
%%
commands:
|
commands command SEMICOLON
;
command:
zone_set
;
zone_set:
ZONETOK quotedname zonecontent
{
printf("Complete zone for '%s' found\n",$2);
}
;
zonecontent:
OBRACE zonestatements EBRACE
quotedname:
QUOTE FILENAME QUOTE
{
$$=$2;
}
;
zonestatements:
|
zonestatements zonestatement SEMICOLON
;
zonestatement:
statements
|
FILETOK quotedname
{
printf("A zonefile name '%s' was encountered\n", $2);
}
;
block:
OBRACE zonestatements EBRACE SEMICOLON
;
statements:
| statements statement
;
statement: WORD | block | quotedname
Я компилирую вышеуказанные файлы:
yacc -d example6.y
lex (example6.l)
cc lex.yy.c y.tab.c -o example6
И ловлю Segmentation fault
elvin@ubuntu:~/Documents/myfirstlex/conf_file$ ./example6
zone "." {
type hint;
file "/etc/bind/db.root";
};Segmentation fault (core dumped)
elvin@ubuntu:~/Documents/myfirstlex/conf_file$
Пытаясь разобраться с ошибкой, я запускался в режиме отладки
elvin@ubuntu:~/Documents/myfirstlex/conf_file$ ./example6
Starting parse
Entering state 0
Reducing stack by rule 1 (line 30):
-> $$ = nterm commands ()
Stack now 0
Entering state 1
Reading a token: zone "." {
type hint;
file "/etc/bind/db.root";
type hint;
};Next token is token ZONETOK ()
Shifting token ZONETOK ()
.............................
Stack now 0 1 3 7 10 13 15
Entering state 18
Reducing stack by rule 10 (line 65):
$1 = token FILETOK ()
$2 = nterm quotedname ()
Segmentation fault (core dumped)
Можете объяснить, в чём может быть проблема? Если проблема с strdup, то как это можно избежать её использование?
Ответы (1 шт):
Нужно добавить #define YYSTYPE char * перед #include "y.tab.h" в LEX-файл.
Ошибка банальная и компилятор об этом должен был явно предупреждать:
example6.l: В функции «yylex»:
example6.l:12:7: предупреждение: assignment to «YYSTYPE» {aka «int»} from «char *» makes integer from pointer without a cast [-Wint-conversion]
12 | [a-zA-Z][a-zA-Z0-9]* yylval=strdup(yytext); return WORD;
| ^
example6.l:13:7: предупреждение: assignment to «YYSTYPE» {aka «int»} from «char *» makes integer from pointer without a cast [-Wint-conversion]
13 | [a-zA-Z0-9\/.-]+ yylval=strdup(yytext); return FILENAME;
HOWTO'шка писалась в те ламповые времена, когда указатели вмещались в int и поэтому на этом особо не заостряли внимания. Сегодня же попытка передать в 32-х битном int 64-х битный char *, само собой, заканчивается UB и крахом...