Хорошо, я провожу несколько экспериментов с Lex / Bison (Yacc), и учитывая, что мои навыки C довольно ржавые (я когда-то создавал компиляторы и прочее со всеми этими инструментами, и теперь я потерялся в первых нескольких строках …: -S), мне нужна твоя помощь.
Вот как выглядит мой парсер:
%{
#include <stdio.h>
#include <string.h>
void yyerror(const char *str)
{
fprintf(stderr,"error: %s\n",str);
}
int yywrap()
{
return 1;
}
main()
{
yyparse();
}
%}
%union
{
char* str;
}
%token <str> WHAT IS FIND GET SHOW WITH POSS OF NUMBER WORD
%type <str> statement
%start statements
%%
statement
: GET { printf("get\n"); }
| SHOW { printf("%s\n",$1); }
| OF { printf("of\n"); }
;
statements
: statement
| statements statement
;
Проблема :
Таким образом, в основном, когда парсер встречает «get», он печатает «get». И так далее.
Тем не менее, при попытке напечатать «шоу» (используя $1
спецификатор) выдает segmentation fault
ошибка.
Что я делаю неправильно?
Лекс возвращает число, представляющее токен, вам нужно получить доступ к yytext, чтобы получить текст того, что анализируется.
что-то вроде
statement : GET { printf("get\n"); }
| SHOW { printf("%s\n",yytext); }
| OF { printf("of\n"); }
;
Чтобы распространить текст терминалов, я связываю нетерминал с терминалом, возвращаю символ * и начинаю, например, строить дерево разбора. Обратите внимание, что я пропустил тип decl и реализацию create_sww_ASTNode (char *, char *, char *); Однако важно то, что не все нетерминалы будут возвращать один и тот же тип, поскольку число — это целое число, слово return char * sww return astNode (или любая другая структура дерева абстрактного синтаксиса, которую вы придумали). Обычно за пределами терминалов, представляющих нетерминал, это все AST.
sww : show word word
{
$$ = create_sww_ASTNode($1,$2,$3);
}
;
word : WORD
{
$$ = malloc(strlen(yytext) + 1);
strcpy($$,yytext);
}
;
show : SHOW
{
$$ = malloc(strlen(yytext) + 1);
strcpy($$,yytext);
}
;
number : NUMBER
{
$$ = atoi(yytext);
}
;
Вы не показываете свой код лексера, но проблема, вероятно, в том, что вы никогда не устанавливали yylval
ни к чему, поэтому при доступе $1
в парсере он содержит мусор, и вы получаете сбой. Ваши действия лексера должны быть установлены yylval.str
к чему-то так будет действительно:
"show" { yylval.str = "SHOW"; return SHOW }
[a-z]+ { yylval.str = strdup(yytext); return WORD; }
Итак, вот ответ (Может кто-нибудь сказать мне, что я всегда придумываю решение, как только я уже опубликовал вопрос здесь в SO? LOL!)
Проблема была не с самим парсером, но на самом деле с лексером.
Дело в том, что когда вы говорите это { printf("%s\n",$1); }
на самом деле мы говорим, чтобы напечатать yylval
(который по умолчанию int
, а не строка).
Итак, хитрость заключается в том, чтобы преобразовать соответствующие токены в строки.
Вот мой (обновленный) файл Lexer:
%{
#include <stdio.h>
#include "parser.tab.h"
void toStr();
%}
DIGIT [0-9]
LETTER [a-zA-Z]
LETTER_OR_SPACE [a-zA-Z ]
%%
find { toStr(); return FIND; }
get { toStr(); return GET; }
show { toStr(); return SHOW; }
{DIGIT}+(\.{DIGIT}+)? { toStr(); return NUMBER; }
{LETTER}+ { toStr(); return WORD; }
\n /* ignore end of line */;
[ \t]+ /* ignore whitespace */;
%%
void toStr()
{
yylval.str=strdup(yytext);
}