В чем разница между абстрактным деревом синтаксиса и деревом синтаксиса бетона?

Я читал немного о том, как работают интерпретаторы/компиляторы, и одна область, где меня путают, - это разница между AST и CST. Я понимаю, что парсер делает КНТ, передает его семантическому анализатору, который превращает его в АСТ. Однако я понимаю, что семантический анализатор просто гарантирует соблюдение правил. Я действительно не понимаю, почему он действительно внесет какие-либо изменения, чтобы сделать его абстрактным, а не конкретным.

Есть ли что-то, что мне не хватает в семантическом анализаторе, или разница между AST и CST несколько искусственна?

Ответ 1

Конкретное дерево синтаксиса представляет исходный текст точно в анализируемой форме. В общем, он соответствует контекстно-свободной грамматике, определяющей исходный язык.

Тем не менее, в конкретной грамматике и дереве есть много вещей, которые необходимы, чтобы сделать исходный текст однозначно разборчивым, но не вносить вклад в реальный смысл. Например, чтобы реализовать приоритет оператора, ваш CFG обычно имеет несколько уровней компонентов выражения (термин, коэффициент и т.д.) С операторами, соединяющими их на разных уровнях (вы добавляете термины для получения выражений, термины состоят из факторов, и т.д.). Чтобы на самом деле интерпретировать или компилировать язык, вам это не нужно; вам просто нужны узлы Expression, у которых есть операторы и операнды. Абстрактное синтаксическое дерево является результатом упрощения конкретного дерева синтаксиса вплоть до того, что действительно необходимо для представления значения программы. Это дерево имеет гораздо более простое определение и, следовательно, легче обрабатывать на последующих этапах выполнения.

Обычно вам не нужно создавать конкретное дерево синтаксиса. Подпрограммы действий в вашей грамматике YACC (или Antlr, или Menhir или что-то еще...) могут непосредственно строить абстрактное синтаксическое дерево, поэтому конкретное дерево синтаксиса существует только как концептуальный объект, представляющий структуру синтаксиса исходного текста.

Ответ 2

Конкретное синтаксическое дерево соответствует тому, что говорят правила грамматики, - это синтаксис. Цель абстрактного синтаксического дерева - это "простое" представление того, что существенное в "дереве синтаксиса".

Реальная ценность в AST IMHO заключается в том, что она меньше, чем CST, и поэтому занимает меньше времени для обработки. (Можно сказать, кто заботится? Но я работаю с инструментом, где у нас есть десятки миллионов узлов, живущих сразу!).

Большинство генераторов парсеров, которые имеют любую поддержку для создания деревьев синтаксиса, настаивают на том, что вы лично указываете, как именно они создаются в предположении, что ваши узлы дерева будут "проще", чем CST (и в этом они, как правило, правы, поскольку программисты довольно ленивый). Возможно, это означает, что вам нужно закодировать меньше функций посетителя дерева, и это тоже важно, поскольку оно минимизирует инженерную энергию. Если у вас есть 3500 правил (например, для COBOL), это имеет значение. И это "более простое" приводит к хорошей собственности "малости".

Но наличие таких АСТ создает проблему, которой ее не было: она не соответствует грамматике, и теперь вы должны мысленно отслеживать их обоих. И когда есть 1500 узлов AST для 3500 грамматики правил, это очень важно. И если грамматика эволюционирует (они всегда делают!), Теперь у вас есть два гигантских набора вещей, чтобы синхронизировать их.

Другое решение - позволить парсеру просто создавать узлы CST для вас и просто использовать их. Это огромное преимущество при построении грамматик: нет необходимости изобретать 1500 специальных узлов АСТ для моделирования правил грамматики 3500. Подумайте о том, что дерево изоморфно грамматике. С точки зрения инженера-грамматики это совершенно безмозгло, что позволяет ему сосредоточиться на правильном использовании грамматики и взломать ее до глубины души. Возможно, вам нужно написать больше правил для посетителей узлов, но это можно управлять. Подробнее об этом позже.

Что мы делаем с DMS Software Reengineering Toolkit - это автоматическое построение CST на основе результатов анализа (GLR). Затем DMS автоматически создает "сжатый" CST по соображениям экономии пространства, исключая терминалы с нецензурной переносимостью (ключевые слова, пунктуацию), семантически бесполезные унаследованные производственные процессы и формируя списки для пар правил грамматики, которые перечислены следующим образом:

    L = e ;
    L = L e ;
    L2 = e2 ;
    L2 = L2  ','  e2 ;

и широкий спектр вариантов таких форм. Вы думаете с точки зрения правил грамматики и виртуального КНТ; инструмент работает с сжатым представлением. Легко на вашем мозгу, быстрее/меньше во время работы.

Примечательно, что сжатый CST, построенный таким образом, выглядит много AST, который вы, возможно, разработали вручную (см. Ссылку в конце на примеры). В частности, сжатый CST не несет никаких узлов, которые являются просто конкретным синтаксисом. Есть незначительные кусочки неловкости: например, в то время как конкретные узлы для '(' и ')', классически найденные в подграммах выражений, не находятся в дереве, в сжатом CST появляется "скобковый узел" и его нужно обрабатывать. Истинный АСТ не имел бы этого. Это похоже на довольно небольшую цену, чтобы заплатить за удобство, чтобы не указывать конструкцию AST. И документация для дерева всегда доступна и правильная: грамматика - это документация.

Как избежать "дополнительных посетителей"? Мы не полностью, но DMS предоставляет библиотеку AST, которая проходит AST и обрабатывает различия между CST и AST прозрачно. DMS также предлагает оценщик грамматики атрибутов (AGE), который является методом передачи значений, вычисляемых узлами вверх и вниз по дереву; AGE обрабатывает все проблемы с представлением дерева, и поэтому инженер-программист беспокоится о том, чтобы непосредственно писать вычисления непосредственно по самим правилам грамматики. Наконец, DMS также предоставляет шаблоны "поверхностный синтаксис", которые позволяют фрагментам кода из грамматики использоваться для поиска определенных типов поддеревьев, не зная большинства задействованных типов узлов.

Один из других ответов отмечает, что если вы хотите создать инструменты, которые могут восстановить источник, ваш АСТ должен соответствовать КНТ. Это не совсем так, но гораздо проще восстановить источник, если у вас есть узлы CST. DMS генерирует большую часть симпатичного принтера автоматически, поскольку он имеет доступ к обоим: -}

Итог: АСТ отлично подходят для небольших, как фискальных, так и концептуальных. Автоматизированная конструкция AST из CST обеспечивает и то и другое, и позволяет избежать проблемы отслеживания двух разных наборов.

EDIT March 2015: Ссылка на примеры CST против "AST", построенных таким образом

Ответ 3

Это сообщение в блоге может быть полезно.

Мне кажется, что AST "отбрасывает" много промежуточной грамматической/структурной информации, которая не будет способствовать семантике. Например, вам все равно, что 3 - это атом, а термин является фактором... Вам просто нужно, чтобы он 3, когда вы выполняете выражение экспоненции или что-то еще.

Ответ 4

Это основано на грамматике оценщика выражений Терренса Парра.

Грамматика для этого примера:

grammar Expr002;

options 
{
    output=AST;
    ASTLabelType=CommonTree; // type of $stat.tree ref etc...
}

prog    :   ( stat )+ ;

stat    :   expr NEWLINE        -> expr
        |   ID '=' expr NEWLINE -> ^('=' ID expr)
        |   NEWLINE             ->
        ;

expr    :   multExpr (( '+'^ | '-'^ ) multExpr)*
        ; 

multExpr
        :   atom ('*'^ atom)*
        ; 

atom    :   INT 
        |   ID
        |   '('! expr ')'!
        ;

ID      : ('a'..'z' | 'A'..'Z' )+ ;
INT     : '0'..'9'+ ;
NEWLINE : '\r'? '\n' ;
WS      : ( ' ' | '\t' )+ { skip(); } ;

вход

x=1
y=2
3*(x+y)

Дерево парсов

Дерево разбора представляет собой конкретное представление ввода. Дерево разбора сохраняет всю информацию ввода. Пустые поля представляют пробелы, т.е. Конец строки.

Parse Tree

АСТ

AST представляет собой абстрактное представление ввода. Обратите внимание, что в АСТ нет парен, потому что ассоциации выводятся из древовидной структуры.

AST

РЕДАКТИРОВАТЬ

Более подробное объяснение см. В разделе " Компиляторы и генераторы компиляторов" стр. 23

Ответ 5

Сильное синтаксическое дерево соответствует правилам грамматики языка. В грамматике "списки выражений" обычно определяются с помощью двух правил

  • expression_list может быть: выражение
  • expression_list может быть: expression, expression_list

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

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

Ответ 6

Конкретное дерево синтаксиса содержит всю информацию, такую ​​как лишние скобки и пробелы и комментарии, абстрактное синтаксическое дерево абстрагирует от этой информации.

 

NB: достаточно смешно, когда вы реализуете механизм рефакторинга, ваш АСТ снова будет содержать всю конкретную информацию, но вы будете ссылаться на нее как на АСТ, потому что это стало стандартным термином в поле (так можно было сказать он давно утратил свое первоначальное значение).

Ответ 7

Это разница, которая не имеет значения.

АСТ обычно объясняется как способ приближения семантики выражения языка программирования, отбрасывая лексический контент. Например, в свободной грамматике контекста вы можете написать следующее правило EBNF

term: atom (('*' | '/') term )*

тогда как в случае AST вы используете только mul_rule и div_rule, который выражает правильные арифметические операции.

Не могут ли эти правила быть введены в грамматике в первую очередь? Конечно. Вы можете переписать вышеприведенное компактное и абстрактное правило, разбив его на более конкретные правила, используемые для имитации упомянутых узлов AST:

term: mul_rule | div_rule
mul_rule: atom ('*' term)*
div_rule: atom ('/' term)*

Теперь, когда вы думаете с точки зрения синтаксического анализа сверху вниз, второй термин вводит конфликт FIRST/FIRST между mul_rule и div_rule то, с чем не может справиться парсер LL (1). Первая форма правила была левой факторизированной версией второй, которая эффективно устраняла структуру. Вы должны заплатить некоторый приз за использование LL (1) здесь.

Таким образом, АСТ являются специальным дополнением, используемым для устранения недостатков грамматик и парсеров. Трансформация CST → AST - это рефакторинг. Никто никогда не беспокоился, когда в дереве синтаксиса хранится дополнительная запятая или двоеточие. Напротив, некоторые авторы модифицируют их в АСТ, потому что они любят использовать АСТ для проведения рефакторинга вместо того, чтобы одновременно поддерживать различные деревья или писать дополнительный механизм вывода. Программисты ленивы по уважительным причинам. Фактически они сохраняют даже информацию о строках и столбцах, собранную лексическим анализом в AST для отчета об ошибках. Очень абстрактно.

Ответ 8

Просто, AST содержит только семантику кода, дерево синтаксиса /CST также содержит информацию о том, как именно был написан код.

Ответ 9

CST (Конкретное дерево синтаксиса) является древовидным представлением грамматики (правила написания программы). В зависимости от архитектуры компилятора он может использоваться Parser для производства AST.

AST (абстрактное дерево синтаксиса) является древовидным представлением Parsed source, созданным частью Parser компилятора. Он хранит информацию о токенах + грамматике.

В зависимости от архитектуры вашего компилятора, CST может использоваться для производства АСТ. Справедливости ради стоит сказать, что КНТ развивается в АСТ. Или, AST - более богатый CST.

Дополнительные пояснения можно найти по этой ссылке: http://eli.thegreenplace.net/2009/02/16/abstract-vs-concrete-syntax-trees#id6