9

// Создайте сканер, который читает из переданного нам входного потока CSLexer lexer = новый CSLexer (новый ANTLRFileStream (f)); tokens.TokenSource = lexer;Создание собственного компилятора C# с использованием ANTLR: Компиляционный модуль

// Create a parser that reads from the scanner 
CSParser parser = new CSParser(tokens); 

// start parsing at the compilationUnit rule 
CSParser.compilation_unit_return x = parser.compilation_unit(); 
object ast = x.Tree; 

Что я могу сделать с х, имеет тип compilation_unit_return, чтобы извлечь его корень, его классы, его методы и т.д.? Должен ли я извлечь свой адаптер? Как мне это сделать? Обратите внимание, что compilation_unit_return определяется как таковой в моем CSParser (который автоматически генерируется ANTLR):

public class compilation_unit_return : ParserRuleReturnScope 
    { 
     private object tree; 
     override public object Tree 
     { 
      get { return tree; } 
      set { tree = (object) value; } 
     } 
    }; 

Однако дерево я получаю от типа объекта. Я запускаю использование отладчика и, похоже, вижу, что он имеет тип BaseTree. Но BaseTree - это интерфейс! Я не знаю, как это относится к BaseTree и не знает, как извлечь данные из этого дерева. Мне нужно написать посетителя, который посетил его класс, метод, переменные .... Класс ParserRuleReturn распространяется от RuleReturnScope и имеет объект начала и остановки, который я не знаю, что это такое ... Кроме того, , этот класс TreeVisitor предоставлен ANTLR, который выглядит запутанным. Для этого требуется переход Адаптера в качестве параметра к его конструктору (если он не будет использовать стандартный CommonTreeAdaptor), поэтому я спросил, как получить адаптер для подключения адаптера. И другие вопросы тоже ... Для API, можно обратиться к http://www.antlr.org/api/CSharp/annotated.html

Теперь я поражен здесь ... Если вы действительно ничего знаете, помогите нам помочь. Бесконечно благодарен.

ответ

3

Я никогда не работал с ANTLR из C#, но после вашей ссылки на API, BaseTree явно не интерфейс - это class, и имеет общие свойства: Type получить тип узла, Text получить (Я предполагаю) соответствующий ему исходный текст и Children для получения дочерних узлов. Что еще вам нужно, чтобы пройти?

+0

Это абстрактный класс ... Публичный абстрактный класс BaseTree: ITree – yeeen

+1

Ну да, и почему это остановит вас? У вас есть корневой узел дерева, который, как вы знаете, имеет тип, который имеет все методы, необходимые для извлечения своих детей (и, таким образом, перемещение дерева на любую глубину). –

-2

Если бы я собирался сделать # компилятор C сегодня, вот что я бы сделать попробовать в качестве первой попытки:

  1. Начнем с целевой ANTLR C# 3 (конечно, я предвзято здесь - вы можете использовать либо CSharp2, либо CSharp3).
  2. Получить Visual Studio 2010 с .NET Framework 4. Ключевым моментом здесь является .NET 4 и это сладкие новые деревья выражений.
  3. Создайте базовый комбинированный парсер. Положите так мало логики в парсере, насколько это абсолютно возможно. У него должно быть мало (если есть) действий, а выход должен быть неупорядоченным АСТ, с которым можно ходить с помощью LL (1).
  4. Создайте грамматику дерева, чтобы пройти дерево и определить все объявленные типы. Он также должен сохранить подэлементы member_declaration для последующего использования.
  5. Постройте пешеходный мост, который прогуливается по одному member_declaration и добавляет член к TypeBuilder. Следите за телами метода, но пока не углубляйте их.
  6. Постройте деревянный ходок, который ходит по телу метода. Создайте метод Expression<TDelegate>, соответствующий методу, и используйте метод CompileToMethod мой собственный API (см. Павел и мои комментарии) для генерации кода IL.

Если вы делаете вещи в таком порядке, а затем, когда вы, наконец, разбор выражений (метод тела, полевые инициализаторы), вы можете использовать string параметризованную Методе like this one в Expression классе, чтобы сохранить рабочие разрешения членов.

+0

К сожалению, 'CompileToMethod' не может быть действительно использован в этом сценарии из-за присущих ему ограничений - невозможно скомпилировать код в другом методе, который вы создаете рядом, а целевой метод MethodBuilder должен быть для статического метода только. Дополнительную информацию см. На странице https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=473128. –

+0

Nice. Ну, тогда я бы начал с создания компилятора 'Expression', который работает в этих случаях, а затем использовать его вместо этого. :) Я бы сохранил компилятор 'Expression' как независимый модуль, чтобы его можно было использовать с другими проектами (и, возможно, я все равно сделаю это для удовольствия). –

+0

Возможно, просто немного отклониться от моего qn выше: я hv исходный код для antlr-3.1.3. N в папке времени выполнения, есть 2 папки - CSharp n CSharp3. Так как вы упомянули abt CSharp3, вы знаете, почему есть 2 папки? Однако API, предоставляемый онлайн, как представляется, был для CSharp только не CSharp3, а также скомпилированной dll. Если кто-то хочет использовать CSharp3, он сам должен скомпилировать коды? Мне кажется, что CSharp3 имеет более сложные функции, но в моем контексте это не очень актуально. – yeeen

6

Вы можете установить AST типа дерева в параметрах грамматики в верхней части файла, например, так:

tree grammar CSharpTree; 
options { 
    ASTLabelType = CommonTree 
} 

я хотел бы построить 3-й грамматика или вставить его в существующей грамматику синтаксического анализа, который превращает дерево в классы, которые вы создаете. Например, предположим, что у вас есть правило, которое соответствует оператору плюс, и это два аргумента. Вы можете определить правило соответствия, что дерево, которое создает класс, который вы написали, давайте назовем это PlusExpression так:

plusExpr returns [PlusExpression value] 
    : ^(PLUS left=expr right=expr) { $value = new PlusExpression($left.value, $right.value); } 

выраж будет еще одно правило в ваших согласующих выражений грамматики. слева и справа - это просто псевдонимы, заданные значениям дерева. Часть между {} 's в значительной степени превращается в код C# дословно, за исключением замены ссылок на переменные. Свойство .value от $ left и $ right происходит от возврата, указанного в правилах, из которых они были созданы.