Codeparser: Bei mehreren Vorkommen in Zeile nur 1x zählen!

  • VB.NET

Es gibt 22 Antworten in diesem Thema. Der letzte Beitrag () ist von LucaWelker.

    Codeparser: Bei mehreren Vorkommen in Zeile nur 1x zählen!

    Hi Leute,

    ich bin gerade dabei, einen Codeparser zu programmieren. Dieser soll mir am Ende alle Funktionen, Klassen und Regionen einer C#-Klassendatei ausgeben, aber ich wollte ihn schon in VB programmieren.

    Nun stehe ich vor dem Problem, dass ich eine eigene Funktion implementiert habe, die mir die Vorkommen von Zeichenketten in einem String zurückgeben soll.

    VB.NET-Quellcode

    1. Function StringCountOccurrences(ByVal strText As String, ByVal strFind As String) As Long
    2. ' Counts occurrences of a particular character or characters
    3. Dim Occurrences As Integer
    4. Dim Start As Integer
    5. Dim Found As Integer
    6. Do
    7. Start = Found + 1
    8. Found = InStr(Start, strText, strFind)
    9. If Found = 0 Then Exit Do
    10. Occurrences += 1
    11. Loop
    12. StringCountOccurrences = Occurrences
    13. End Function
    14. Function SCO(ByVal strText As String, ByVal strFind As String) As Long
    15. SCO = StringCountOccurrences(strText, strFind)
    16. End Function



    Nun wollte ich die Funktionen in der Datei zählen. Funktionen in C# werden meines Wissens ja (ähnlich wie in Java) nur über einen Rückgabe-Datentyp, eventuell eine Reichweite (public, protected, private) und eine öffnende Klammer, der die Parameter folgen in einer Zeile definiert. Nun habe ich aber anscheinend das Problem (ich weiß nicht genau, ob es wirklich daran liegt), dass wenn ich mehrere Datentypen in der Zeile stehen habe, wegen den Parametern, der Funktionszähler um mehr als 1 hochgezählt wird:

    VB.NET-Quellcode

    1. ' loop through lines
    2. For Each line As String In lines
    3. If (SCO(line, "///") <> 1 And SCO(line, "//") <> 1) Then
    4. ' includes
    5. includes += CInt(SCO(line, "using"))
    6. ' classes
    7. classes += CInt(SCO(line, "class"))
    8. ' regions
    9. regions += CInt(SCO(line, "#region"))
    10. ' functions ' BIG PROBLEM ! ! !
    11. For Each keyword As String In func_keywords
    12. If (SCO(line, "(") = 1 And SCO(line, keyword) = 1) Then
    13. functions += 1 ' PROBLEM
    14. End If
    15. Next
    16. Else
    17. linecount = linecount - 1
    18. End If
    19. Next



    Habt ihr eine Idee, wie ich das einfacher lösen könnte? Vielen Dank schonmal!
    Du müsstest ' (In Vb) und glaube das ist // in Java natürlich beachten.

    Dazu könntest Du dir entweder ein Regex Pattern erstellen oder wenn du bei den normalen String Methoden bleiben willst dann mit

    VB.NET-Quellcode

    1. String.StartsWith
    auf / oder halt ' prüfen.
    Ähm, die Kommentare ausgeschlossen habe ich doch schon in Zeile 3 des 2. Codeblocks?

    VB.NET-Quellcode

    1. If (SCO(line, "///") <> 1 And SCO(line, "//") <> 1) Then


    Das schließt ja beide Kommentararten aus C# aus.

    Aber ja, das war ja gar nicht das eigentliche Thema. Es ging mir darum, eine eindeutige Zählfunktion zur Erkennung und Erfassung von Funktionen zu bekommen...
    Das mag sein, aber wenn ich Zeile für Zeile abarbeite (siehe oben), dann kann ich ja in der ersten Zeile nur z.B.

    public int ... ( int ...)

    denn die geschweifte Klammer könnte ja durchaus erst in der nächsten Zeile folgen. Darum war meine logische Schlussfolgerung, dass ich in einer Zeile nach "int" und "(" filtern muss. Aber 2x int bedeutet anscheinend 2x functions+1...
    Schreib doch mal ein paar Zeilen die funktionieren und ein paar Zeilen, die nicht funktionieren.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Habe den Code nur auf der Arbeit vorliegen, nicht privat. Aber um mich selbst von heut morgen zu zitieren:

    Wenn ich einzelne Schlüsselwörter (class, region, using) mit der Funktion

    VB.NET-Quellcode

    1. Function StringCountOccurrences(ByVal strText As String, ByVal strFind As String) As Long
    2. ' Counts occurrences of a particular character or characters
    3. Dim Occurrences As Integer
    4. Dim Start As Integer
    5. Dim Found As Integer
    6. Do
    7. Start = Found + 1
    8. Found = InStr(Start, strText, strFind)
    9. If Found = 0 Then Exit Do
    10. Occurrences += 1
    11. Loop
    12. StringCountOccurrences = Occurrences
    13. End Function
    14. Function SCO(ByVal strText As String, ByVal strFind As String) As Long
    15. SCO = StringCountOccurrences(strText, strFind)
    16. End Function



    zählen will, funktioniert es einwandfrei. Da von diesen Codewörtern (Kommentare ausgeschlossen) ja jeweils nur 1 in einer Zeile stehen darf. Aber sobald es dann daran geht, die Funktionen mit ihrer spezifischen Syntax (wie gesagt, ein Rückgabetyp und eine öffnende Klammer) zu prüfen, bekomme ich eben 2 Funktionen gezählt, wo nur eine ist, sobald zwei Datentypen gezählt werden, selbst bei nur einer Klammer.

    RodFromGermany schrieb:

    Schreib doch mal ein paar Zeilen die funktionieren und ein paar Zeilen, die nicht funktionieren.

    Ich meinte nicht den Quellcode Deines Programms, sondern die zu parsenden Texte.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ach so, ja also folgende Zeilen werden korrekt gezählt:

    VB.NET-Quellcode

    1. using TSystems.SharePoint.Common.Web;
    2. public partial class UserControlWrapper : LayoutsPageBase
    3. #region Variablen
    4. protected override void OnInit(EventArgs e)


    Und bei folgenden scheint der Fehler aufzutreten:

    VB.NET-Quellcode

    1. protected void Page_Load(object sender, EventArgs e)
    2. protected void Page_PreRender(object sender, EventArgs e)
    3. public bool IsInteger(string strvalue)


    wahrscheinlich einfach deshalb, weil 2 datentypen in einer Zeile stehen. Ich kriege mit obigem Code nämlich in summe 7 Funktionen gezählt.
    Ich würde jetzt wie folgt rangehen:
    protected void ==>
    public, private, internal // was da alles stehen kann
    // Trennzeichen: Leerzeichen
    void, int, long, bla, blabla // was da alles stehen kann, viel mehr als oben, implizite Annahme (keine Typprüfung)
    // Start von etwas
    (bla x1 // Start: Klammer auf, Typ, Variable
    , blabla x2 // Start: Komma, Typ, Variable
    , ... // Start: Komma, Typ, Variable, Typ, Variable, Typ, Variable, Typ, Variable, Typ, Variable, Typ, Variable, Typ, Variable, Typ, Variable
    ) // Ende: Klammer zu
    ------------------------
    Beachte aber auch, dass da mal
    int i /* = 0 */
    ref bla blabla
    out bbla bblabbla

    stehen kann.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Wie gesagt, ich würde hier zu ANTLR raten.
    Hier könntest du dir sogar die C# Parsergrammatik runterladen und müsstest in dieser nur noch an den gewünschten Stellen die C#-"Anweisungen" zum Zählen unterbringen und wärst fertig.
    Der Code wäre durch ANTLR auf jeden Fall richtig geparst und du könntest dir ne Menge Arbeit sparen.

    lg.
    lg.

    LucaWelker
    Wahrscheinlich ist @markuskoehler ein Sportler, der das selbst machen will. Finde ich gut, wenn es dem Lernen dient.
    Ist der Erfolg primär, würde ich auf @LucaWelker hören.
    Egal, meine Unterstützung ist Dir sicher. :thumbsup:
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Da gibt es eigentlich garnicht so viel zu lernen :) Außer man will das Zeugs selbst schreiben.
    Ansonsten gibt es irgendwo sicher die Parsergrammatik für C# und da muss man dann "nur noch" den VB.NET oder C# Code zum zählen einfügen.
    Ist meiner Meinung nach relativ leicht.

    lg.
    lg.

    LucaWelker
    Da habt ihr Recht, ich bin ein "sportler". Aber in dem fall wäre es ja ein mix aus beidem, sollte auch möglichst schnell möglichst zuverlässig funktionieren, da es eben für die firma ist, für die ich arbeite. bloß kam ja bis jetzt meiner auffassung nach noch kein beitrag, der wirklich in die do-it-yourself-richtung ging. ich hatte auf konstruktive vorschläge gehofft, wie ich meine zählfunktion effektiver hinkriege oder eine andere zählfunktion implementieren könnte. von einer vorgefertigten lösung ist mein kollege auch noch nicht so ganz überzeugt, müsste man sich vllt nochmal anschauen, den codeparser... aber lieber wär mir eig eine eigene lösung, da das progrämmchen noch um einiges komplexer wird, soll irgendwann bald mal funktionsnamen mit hierarchieebene, rückgabetyp, position im projekt und abhängigkeiten in eine mysql-tabelle schreiben...
    Ist C# nicht eine der Sprachen, wo man einfach mal alle Leerzeilen und sowas entfernen kann? Dafür hat das doch das Semikolon, oder? Dann müsstest du dich mit den verschiedenen Zeilen nicht rumschlagen

    Skybird schrieb:

    Das sind ja Ubisoftmethoden hier !

    Ähm - vergiss Eigenbau.
    Dassis sehr komplex, und wenn das produktiv genutzt werden soll, musses ja auch Bug-frei sein, d.h.: - so einige Prinzipien des Compilerbaus wirst du erlernen und berücksichtigen müssen, und Regex, Rekursion und Vererbung nurso aussm Ärmel schütteln - vlt. auch bischen Sprach-Theorie - Grammatiken verschiedener Ordnung und so Zeugs.

    Hier ein langweiliger Taschenrechner, und guck dir davon den Parse-Code an.
    Hat jmd geschrieben, ders studiert hat, und sich eingehend mitte Materie beschäftigt hat.