Как придать значение индекса литералам в lex и yacc?


Скажем, у меня есть грамматика следующего вида:

dish: fruit type ';';
fruit: "apple" | "strawberry" | "pear";
type: "pie" | "cheesecake" | "flan";

...и у меня есть функция для хранения этих блюд:

bool storeDish(int fruit, int type);

Как мне эффективно сказать lex или yacc (я не знаю, какой именно), что я хочу, чтобы "яблоко" имело значение 0, "клубника" - значение 1, "груша" - значение 2, "пирог" - значение 0, "чизкейк" - значение 1 и "флан" - значение 2?

2 2

2 ответа:

Вы можете определить числовой тип в %union, определить ваши нетерминалы как этот числовой тип, сохранить значения для каждого фрукта и типа, а затем получить доступ к ним в вашем правиле блюда по индексу. Перечисление было бы предпочтительнее, но вот пример.

/* Define types, you will need to define one for each type of nonterminal */
%union
{
    int     numeric;
}

/* Specify the type of the nonterminal */
%type<numeric> fruit type

...

%%

...

/* Fruits value accessible by $1 and type by $2 */
dish
    : fruit type ';';
        { storeDish($1, $2); }
    ;

/* Assign each fruit and type a numeric value */
fruit
    : "apple" 
        { $$ = 0; }
    | "strawberry" 
        { $$ = 1; }
    | "pear"
        { $$ = 2; }
    ;
type
    : "pie" 
        { $$ = 0; }
    | "cheesecake"
        { $$ = 1; } 
    | "flan"
        { $$ = 2; }
    ; 

Http://dinosaur.compilertools.net/bison/bison_6.html#SEC53

@Joe, в качестве альтернативы вы можете заставить yylex распознавать слова, помещая значение перечисления фрукта, увиденного в yylval, и давая yacc маркер фрукта. Код C производства(ов) с использованием фруктов теперь может получить доступ к тому, какой тип фруктов был замечен в yylval:

fruits:
    fruits fruit
    | fruit  
    ;
fruit : FRUIT           {if ($1==1) printf("seen strawberry\n"); }

(Примечание: мой yacc ржавый; надеюсь, я не ошибся.)