2012-04-23 3 views
0

Допустим, у меня есть часть моей .y грамматики, как это:Yacc (зубр) аст упрощение

stmt : expr { $$ = $1; } 
     | stmt expr { $$ = insert_stmt_list($1, $2); } 

, где я могу иметь утверждение, что дает выражение, или я могу иметь несколько выражений, которые приводят к список инструкций. О последнем я храню его через функцию insert_stmt ..., но сначала я отправляю его в верхнюю часть стека.

Вопрос: как я могу справиться с $$ = $ 1? Я имею в виду, что insert_stmt_list помещает все в структуру, и я знаю, что он есть, и я могу распечатать их значения и так далее, но где, черт возьми, идет $$ = S1? Как это прочитать? :-)

Спасибо!

ответ

1

Re: как его прочитать?

У вас есть левая рекурсивная грамматика, которая сначала должна распознать expr. Это уменьшено до stmt, а смысловое значение, вырабатываемое make_new_stmt_list, становится значением stmt1 с помощью $$ = $1;.

Это просто означает «принять семантическое значение первого символа с правой стороны (которое является единственным) и распространить его как семантическое значение левой стороны».

Тогда, если другой expr виден, синтаксический анализ продолжается с другой продукцией:

stmt : ... 
    | stmt expr { $$ = insert_stmt_list($1, $2); } 

Здесь $1 приходит из stmt с правой стороны, это семантическое значение, которое присваивается $$ в предшествующее восстановление, которое произвело stmt.

Вы разработали систему так, чтобы expr функционировал как stmt. Кроме того, expr создает значение, которое подходит как аргумент для insert_stmt_list: выражения представляют собой списки.

Итак:

  1. Если вход имеет только одно выражение E, то stmt, которая возникает только, что выражение.

  2. Если у вас есть два выражения E1 и E2, то stmt которого emeges является результатом:

    insert_stmt_list(E1, E2) 
    
  3. Если у вас есть три выражения, то общая stmt является результатом этих вызовов:

    insert_stmt_list(insert_stmt_list(E1, E2), E3) 
    

и так далее. Независимо от того, что имеет смысл, это зависит от семантики этой операции «вставки».

+0

Большой вопрос был на самом деле, если я ожидал заявления, как справиться с выражением? Я смог справиться с этим с помощью общей структуры, где у меня есть флаг {is_STATEMENT, is_EXPRESSION, ...} и указатель на соответствующую структуру. Все это, потому что C не позволяет узнать тип указателя. – Nitrate

+0

Вы можете посмотреть абстрактный синтаксис Lisp. Основной синтаксической единицей оценки является выражение. Если вы хотите, чтобы несколько выражений были оценены для их побочного эффекта, когда ожидалось одно выражение, у вас есть оператор для этого типа 'progn':' (progn expr1 expr2 ... exprn) '. Это не лишний узел. – Kaz

0

Это более идиоматическое, чтобы написать что-то вроде этого:

stmt : expr { $$ = make_new_stmt_list($1); } 
     | stmt expr { $$ = insert_stmt_list($1, $2); } 

Так или иначе, вам нужно обернуть структуру данных выражения в структуре данных списка операторов.

+1

Проблема с вашим решением заключается в том, что вы создаете список инструкций, когда для целей ast (абстрактное синтаксическое дерево) вы должны отбрасывать бессмысленные узлы. Вот почему я пришел к выводу, что перенос значения на вершину стека $$ = $ 1 был способом, но потом все размылось :-) – Nitrate

+0

Различие между списком выражений и одним выражением не является конечно, бессмысленно. Это то, что встречается в абстрактном синтаксисе. Путь * вы * на самом деле не можете абстрагироваться; ваш код буквально принимает грамматику. То есть 'stmt: expr' утверждает, что синтаксически оператор является выражением, и поэтому вы преобразовали его в' $$ = $ 1'. Более абстрактное представление состоит в том, что это леворекурсивное производство - это просто «джиг» для построения последовательности (в которой может быть только один элемент). – Kaz

Смежные вопросы