9

// Utworzenie skanera odczytującego ze strumienia wejściowego przekazanego nam CSLexer lexer = nowy CSLexer (nowy ANTLRFileStream (f)); tokens.TokenSource = lexer;Budowanie własnego kompilatora C# za pomocą ANTLR: Compilation Unit

// 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; 

Co mogę zrobić z X, który jest typu compilation_unit_return, aby wydobyć swoje korzenie, swoje zajęcia, swoje metody etc? Czy muszę wyodrębnić jego adapter? Jak mogę to zrobić? Zauważ, że compilation_unit_return jest zdefiniowany jako taki w moim CSParser (który jest automatycznie generowany przez antlr):

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

Jednak drzewo Dostaję jest obiektem typu. Używam debuggera i wydawało mi się, że jest on typu BaseTree. Ale BaseTree to interfejs! Nie wiem, w jaki sposób odnosi się do BaseTree i nie wiem, jak wyodrębnić szczegóły z tego drzewa. Potrzebuję napisać odwiedzającego, który odwiedziłby jego klasę, metodę, zmienne ... Klasa ParserRuleReturn rozciąga się od RuleReturnScope i ma obiekt start i stop, którego nie wiem, co to jest ... Ponadto , istnieje klasa TreeVisitor dostarczona przez ANTLR, która wygląda na zagmatwaną. Wymaga to przekazania adaptera jako parametru do jego konstruktora (jeśli nie użyje domyślnego narzędzia CommonTreeAdaptor), to dlaczego zapytałem, w jaki sposób uzyskać adapter Earlera. I inne problemy też ... Dla API, możesz odnieść się do http://www.antlr.org/api/CSharp/annotated.html

Teraz jestem uderzony tutaj ... Jeśli wiesz cokolwiek, pls pomóc. Stukrotne dzięki.

Odpowiedz

3

Nie kiedykolwiek pracował z antlr z C#, ale po linku do API BaseTree jest wyraźnie nie interfejs - to class i ma właściwości publiczne: Type dostać rodzaj węzła, Text dostać (Zakładam) tekst źródłowy odpowiadający temu i Children, aby uzyskać węzły podrzędne. Czego jeszcze potrzebujesz?

+0

Jest to klasa abstrakcyjna ... publiczna klasa abstrakcyjna BaseTree: ITree – yeeen

+1

No tak, i dlaczego miałaby Cię powstrzymać? Masz węzeł główny drzewa, który wiesz, że jest typu, który ma wszystkie metody niezbędne do odzyskania jego potomków (i tym samym chodzenia drzewa do dowolnej głębokości). –

-2

Gdybym był zamiar zrobić C# kompilator dzisiaj, oto co bym zrobić spróbować jako pierwszą próbę:

  1. start z ANTLR C# 3 cel (oczywiście jestem stronniczy tutaj - poważnie możesz użyć celu CSharp2 lub CSharp3).
  2. Pobierz program Visual Studio 2010 z .NET Framework 4. Kluczem jest tutaj .NET 4 i jego nowe słodkie drzewa wyrażeń.
  3. Utwórz podstawowy parser złożony. Umieść jak najmniej logiki w analizatorze składni jako absolutnie możliwe. Powinien mieć kilka (jeśli w ogóle) działań, a wyjście powinno być nieskażoną AST, którą można chodzić z LL (1) walkerem.
  4. Zbuduj gramatykę drzewa, aby przejść drzewo i zidentyfikować wszystkie zadeklarowane typy. Powinien także zachować pod-drzewa member_declaration do późniejszego wykorzystania.
  5. Zbuduj drzewo walker, który idzie jeden member_declaration i dodaje członka do TypeBuilder. Śledzić ciała metod, ale jeszcze ich nie chodź głęboko.
  6. Zbuduj chodzik, który kroczy ciałem metody. Wygeneruj Expression<TDelegate> pasujące do metody i użyj własnego API (zobacz Pavel i moje komentarze), aby wygenerować kod IL.

Jeśli robić rzeczy, w tej kolejności, a następnie po pojawieniu się wreszcie parsowania wyrażeń (organy metoda, inicjalizatory pola), można użyć string Metody parametryzowane like this one w klasie Expression zapisać członkowie pracują rozwiązywania.

+0

Niestety, 'CompileToMethod' nie może być prawdziwie użyty w tym scenariuszu ze względu na jego ograniczenia - nie ma sposobu na kompilację kodu do innej metody, którą tworzysz obok, a cel' MethodBuilder' musi być dla metody statycznej tylko. Więcej informacji można znaleźć na stronie https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=473128. –

+0

Nice. No cóż, zacznę od zbudowania kompilatora 'Expression', który działa w tych przypadkach, a następnie użyj go. :) Zachowałbym kompilator 'Expression' jako niezależny moduł, więc można go używać z innymi projektami (i być może zrobię to dla zabawy). –

+0

Być może po prostu odejść nieco od mojego qn powyżej: I hv kod źródłowy dla antlr-3.1.3. N w folderze runtime znajdują się 2 foldery - CSharp n CSharp3. Od kiedy wspomniałeś o CSharp3, wiesz, dlaczego są 2 foldery? Jednak API udostępnione online wydawało się być tylko dla CSharp, a nie dla CSharp3, a także skompilowanej biblioteki dll. Jeśli ktoś chce używać CSharp3, musi sam skompilować kody? Wydaje mi się, że CSharp3 ma bardziej zaawansowane funkcje, ale w moim kontekście nie jest tak istotny. – yeeen

6

Można ustawić AST rodzaj drzewa w opcjach gramatycznych na początku pliku tak:

tree grammar CSharpTree; 
options { 
    ASTLabelType = CommonTree 
} 

Chciałbym zbudować 3rd gramatyki lub pracować go do istniejącej gramatyki parser, który zamienia drzewo w klasy, które tworzysz. Załóżmy na przykład, że masz regułę, która pasuje do operatora plus i ma 2 argumenty. Można zdefiniować reguły dopasowania to drzewo, które tworzy klasę które zostały napisane, nazwijmy to PlusExpression tak:

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

wyrażenie byłaby inna reguła w gramatykę dopasowywania wyrażeń. left i right są po prostu aliasami przypisanymi do wartości drzewiastych. Część pomiędzy {} jest prawie całkowicie zamieniona na kod C# dosłownie, z wyjątkiem zastąpienia odniesień zmiennych. Właściwość .value poza $ left i $ right pochodzi z powrotu określonego poza regułami, z których zostały utworzone.

Powiązane problemy