что означает $ 1 в yacc и как я могу получить его значение - PullRequest
0 голосов
/ 21 июня 2019

Я хочу завершить анализ объявления varlist, как varlist: id запятая varlist | id. В настоящее время мне нужно настроить список около var. Поэтому я пишу этот код:

varlist: id comma varlist{ createtnode($1.idcontext);}
        |id{createtnode($1.idcontext);};

Но я нахожу $1.idcontext - это не то, что idcontext Я хочу, который должен быть idcontext этого токена id.

Теперь, $1.idcontext это предложение 'varlist'. Без действия кода эта грамматика работает правильно.

typedef struct{
    int* TC;
    int* FC;
}boolcode;
typedef struct {
    char* idcontext;
    int constvalue;
    int chain;
    boolcode ftentry;
}includes;

/* Value type.  */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef struct{
    int classify;
    includes unique;
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif

VARList: IDENcode COMMA VARList{
    if(YYDEBUG) 
    {printf("6\n");
    printf("%s\n",$1.idcontext);
    }
    varlistnode* newvar=malloc(sizeof(varlistnode));
    newvar->varname=$1.idcontext;
    newvar->value=0;
    newvar->next=NULL;
    mynotes->next=newvar;
    mynotes=mynotes->next;
}|IDENcode{
    if(YYDEBUG) 
    {printf("7\n");printf("%s\n",$1.idcontext);}
    varlistnode* newvar=malloc(sizeof(varlistnode));
    newvar->varname=$1.idcontext;
    newvar->value=0;
    newvar->next=NULL;
    mynotes->next=newvar;
    mynotes=mynotes->next;
};

Слова ожидания распознают:

a,b,c,d

Результат printf() Функция:

7
d:
6
c,d:
6
b,c,d:
6
a,b,c,d:enter code here

1 Ответ

1 голос
/ 21 июня 2019

Настоящая проблема в этой программе не видна в этом вопросе, потому что ошибка в вашем лексическом сканере.

Вы не включили файл flex в вопрос, но разумно предположить, что он содержит что-то вроде этого:

[[:alpha:]_][[:alnum:]_]*  { yylval.unique.idcontext = yytext;  /* INCORRECT */
                             return IDENcode;
                           }

Следует читать

[[:alpha:]_][[:alnum:]_]*  { yylval.unique.idcontext = strdup(yytext);
                             return IDENcode;
                           }

yytext указывает на внутренний буфер сканера, содержимое которого изменяется при каждом вызове сканера. То, что вы видите, является мягкой версией этой проблемы, потому что ваш вклад очень короткий; если бы ввод был достаточно длинным, чтобы yylex требовалось заполнить буфер из входного файла, вы бы увидели полный мусор в ваших полях idcontext. Если вы хотите использовать строку позже, вам нужно сделать ее копию (и затем вам нужно будет помнить free() копию, когда она вам больше не нужна, что может быть сложной задачей).


Другая возможная проблема - и, честно говоря, я не знаю, считаете ли вы это проблемой или нет, потому что вы не указали, какой вывод вы ожидаете из своей трассировки отладки, - это ваше право -рекурсивное правило:

varlist: id comma varlist  { createtnode($1.idcontext); }
       | id                { createtnode($1.idcontext); }

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

Если вы хотите, чтобы действия выполнялись слева направо, вам нужно использовать левую рекурсию:

varlist: varlist comma id  { createtnode($3.idcontext); } /* See below */
       | id                { createtnode($1.idcontext); }

Левая рекурсия имеет и другие преимущества. Например, не требуется, чтобы все id s (и comma s) накапливались во внутреннем стеке синтаксического анализатора в ожидании окончательного действия сокращения.

Опять же, вы не показываете достаточно своего кода, чтобы увидеть, как вы используете результат этих действий. Мне кажется, что вы пытаетесь создать глобальный связанный список переменных, заголовок которого вы храните в глобальной переменной. (mynotes, очевидно, указывает на конец списка, поэтому его нельзя использовать для восстановления головы.) Если это так, то приведенные выше изменения должны работать нормально. Но было бы более нормально сделать семантическое значение varlist заголовком списка, избегая использования глобальных переменных. Это приведет к коду, который будет выглядеть примерно так:

varlist: id comma varlist  { $$ = append($1, createtnode($3.idcontext)); }
       | id                { $$ = append(newlist(), createtnode($1.idcontext); }
...