Yylval и union

Какова цель объединения в файле yacc? Является ли это напрямую связано с yylval в файле flex? Если вы не используете yylval, вам не нужно использовать union?

Ответ 1

Цель union состоит в том, чтобы разрешить сохранение объектов разных типов в узлах, испускаемых flex.

Чтобы лучше объяснить, вы можете, например:

%union
{
    int intValue;
    float floatValue;
    char *stringValue;
}

в .y, если вы хотите предоставить базовую поддержку типов int, float и string. Что вы можете сделать с этим?

Две вещи:

Во-первых, вы можете автоматически устанавливать правильные значения при создании токенов. Подумайте о файле .l предыдущего примера, вы можете:

[a-zA-Z][a-zA-Z0-9]* {
 yylval.stringValue = strdup(yytext);
 return IDENTIFIER;
}

[0-9]+ { 
 yylval.intValue = atoi(yytext);
 return INTEGER;
}

[0-9]*\.[0-9]+"f"? {
    yylval.floatValue = new atof(yytext);
 return FLOAT;
}

Кроме того, вы можете использовать значение непосредственно в своей грамматике flex:

nexp: nexp '+' nexp { $<floatValue>$ = $<floatValue>1 + $<floatValue>3 }

Наконец, если вы планируете использовать дерево синтаксиса ООП, вы можете определить объединение как

%union
{
    class ASTNode *node;
}

в котором ASTNode является предковым классом любого вида синтаксиса node.

Ответ 2

Объявление %union изменяет тип yylval.

Руководство bison объясняет:

В обычном (нерентабельном) синтаксическом анализаторе семантическое значение токена должно храниться в глобальной переменной yylval. Когда вы используете только один тип данных для семантических значений, yylval имеет этот тип. Таким образом, если тип int (по умолчанию), вы можете записать это в yylex:

...
yylval = value;  /* Put value onto Bison stack. */
return INT;      /* Return the type of the token. */
...

Когда вы используете несколько типов данных, тип yylval - это объединение, сделанное из объявления %union (см. раздел "Коллекция типов значений" ). Поэтому, когда вы храните значение токена, вы должны использовать правильный член союза. Если объявление %union выглядит следующим образом:

%union {
  int intval;
  double val;
  symrec *tptr;
}

тогда код в yylex может выглядеть следующим образом:

...
yylval.intval = value; /* Put value onto Bison stack. */
return INT;          /* Return the type of the token. */
...