справка по выводу yacc - PullRequest
       16

справка по выводу yacc

0 голосов
/ 16 февраля 2011

если у меня есть этот грамматик, например

start : TKN id '{' '}' {cout<<$2<<endl;} ;

  • iostream включен, TKN объявлен как токен, тип id объявлен как char *

  • в качестве ввода я ввожу tkn aaa { }

не должен ли вывод быть aaa ??иногда он печатает } и 0, а иногда просто висит

Я хочу получить значение id, как правильно это сделать ??

lex.l

%{
  #include "yacc.hpp"
  #include <math.h>
  #include<iostream>
  #include<string>
  int rows = 1,tmp=0;
%}
Id          [a-zA-Z_][0-9a-zA-Z_]*
%x String ...
%option c++
%option noyywrap
%% 
{Id}        {strcpy(yylval.strVal,yytext);cout<<"lex= "<<yytext<<endl;return Id;}//output line 1
...

yacc.y

%output ="yacc.cpp"
%defines
%verbose
%token Id
%token NAMESPACE
%union{

int           iVal;
float         fVal;
char*         strVal;
class Symbol* symPtr;
class NS*     nsPtr;
};


%token <iVal> INT_VAL;
%token <fVal> F_VAL;
%token <strVal> STR_VAL INT FLOAT STRING Id ;
%type <nsPtr> namespacedecl  
%type <symPtr> ns_closer
%type <strVal> Q_ID

//-------------------------------------------
namespacedecl  : NAMESPACE Q_ID '{' '}'            {cout<<"ns= "<<$2<< endl ;} // output line 3
               | NAMESPACE Q_ID '{' typedecl_closer '}' ;

 Q_ID :          Q_ID '.' Id                       {cout<<$3<< endl ;$$ = $3;}
               | Id                                {$$ = $1;cout<<"qid="<<$$<<endl;} // output line 2

Конечно, файлы больше этого, но копируйте / вставляйте все, что приведет к потере ^^

, если есть способчтобы прикрепить файл, пожалуйста, скажите мне, потому что я все еще новичок здесь, и это было бы намного проще, чем копировать / вставить.

и вот что я получаю при запуске:

enter image description here

спасибо за ответ

Ответы [ 2 ]

1 голос
/ 17 февраля 2011

Зависит от того, что вернуло правило 'id'!

%%
start :             TKN id '{' '}' {cout<<$2<<endl;} ;

id :                ID             { return "XXXXX"; } // What is returned here
                                                       // Is what will be printed out by $2 

%%

Примечание:
Соглашение состоит в том, что терминальные токены являются заглавными (TKN). Пока нетерминальные токены являются строчными (id). В соответствии с этим соглашением, я ожидаю, что у id будет правило о том, как оно расширяется.

Я подозреваю, что вы делаете:

%%

id :                ID             { return yytext; }

%%

Указатель на буфер lex. Это энергозависимый буфер. Вы можете НЕ полагаться на то, что его содержимое остается неизменным (и при этом вы не можете полагать, что оно завершено '\ 0'). Вам нужно сделать копию токена в том месте, где вы его идентифицируете.

%%

id :                ID             { return strndup(yytext, yylen); }

%%

Редактировать на основе нового ввода:

В этих строках:

{Id}        {   strcpy(yylval.strVal,yytext);
                cout<<"lex= "<<yytext<<endl;
                return Id;
            }

strcpy (), вероятно, плохой.

  • Вы зарезервировали место для копии?
  • Вы не можете полагаться на прекращение действия yytext '\ 0'.

Cout опасен, так как вы не можете полагаться на завершение yytext '\ 0'.

Я бы сделал:

{ID}        {   cout << "lex=" << std::string(yytext,yytext+yylen); // use yylen
                return Id;
            }

Не связывайтесь со структурами yacc в lex. Он тесно связывает ваш файл lex с yacc (что не обязательно). Просто верните токен. Затем yacc может получить значение токена вручную.

Затем в файле YACC:

Q_ID :        Q_ID '.' ident        {$$ = $3; cout<<"Q.id="<<$$<<endl;}
           |  ident                 {$$ = $1; cout<<"ID  ="<<$$<<endl;}

ident :       Id                    {$$ = strndup(yytext, yylen);}

Для каждого терминала (Id), который имеет длинный токен, есть нетерминал для декодирования терминала и генерирования правильного значения в структуре объединения yacc. В этом случае у нас есть идентификатор, а не терминал. Он просто декодирует терминал Id и правильно устанавливает токен (этот Id не имеет типа в структуре объединения).

Также Примечание:

  • Традиционно для терминалов все заглавные буквы. Идентификатор не работает.
  • Традиционно для нетерминалов строчные буквы. Q_ID не работает.

Дополнительно:

Эта строка:

%token <strVal> STR_VAL INT FLOAT STRING Id ;

Выглядит неправильно, хотя трудно сказать, не зная, что такое INT, FLOAT и STRING. Я предполагаю, что это терминальные токены для ключевых слов int, float, string. В этом случае вам не нужно хранить актуальную строку токена. Достаточно того, что вы знаете, что это INT / FLOAT или STRING.

Это должно быть:

%token <strVal> STR_VAL;
%token <strVal> ident;
0 голосов
/ 17 февраля 2011

Это сильно зависит от того, что ваш лексер возвращает как yylval для токена id, так как это то, что копируется в стек анализатора при смещении токена, и, таким образом, к чему относится $2 при оценке правила. В предположении, у вас есть правило lex что-то вроде:

[a-zA-Z_][a-zA-Z_0-9]*      { yylval.str = yytext; return id; }

с

%token<str>    id

в вашем парсере. В этом случае вы сохраняете указатель во внутреннем буфере сканера flex, который в этот момент содержит «aaa», но будет перезаписан более поздним токеном, поэтому к моменту выполнения действия указатель в $ 2 указывает на что-то еще. Вам нужно скопировать строку куда-нибудь, где она не будет перезаписана, и установить yylval, чтобы указать на это. Вы можете использовать strdup (3), чтобы скопировать строку в некорректный буфер, что решит эту проблему, но может привести к утечкам памяти.

1012 * редактировать *

Что ж, с вашей дополнительной информацией, довольно удивительно, что ваша программа не падает - вы strcpy текст токена в yylval.strVal, но вы никогда не инициализируете yylval.Strval, чтобы указывать куда-либо, поэтому вы копируете его в какую-то случайную ячейку памяти. Вам нужно вставить что-то вроде yylval.strVal = malloc(strlen(yytext)+1); в действие lex.l, чтобы убедиться, что оно указывает на действительную память, или просто использовать более простой и эквивалентный вызов strdup, так как он объединяет malloc и strcpy:

[a-zA-Z_][a-zA-Z_0-9]*      { yylval.str = strdup(yytext); return id; }
...