Как придать значение индекса литералам в 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 ответа:
Вы можете определить числовой тип в
%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; } ;
@Joe, в качестве альтернативы вы можете заставить yylex распознавать слова, помещая значение перечисления фрукта, увиденного в yylval, и давая yacc маркер фрукта. Код C производства(ов) с использованием фруктов теперь может получить доступ к тому, какой тип фруктов был замечен в yylval:
fruits: fruits fruit | fruit ; fruit : FRUIT {if ($1==1) printf("seen strawberry\n"); }
(Примечание: мой yacc ржавый; надеюсь, я не ошибся.)