2016-08-01 13 views
2

Ich habe an a text editor gearbeitet, das LPEG verwendet, um Unterstützung für Syntaxhervorhebung zu implementieren. Die Einrichtung war ziemlich einfach, aber ich habe nur das Minimum getan.Verwenden von Lpeg, um nur Wortgrenzen zu erfassen

Ich habe eine Reihe von Mustern wie folgt definiert:

-- Keywords 
local keyword = C(
    P"auto" + 
    P"break" + 
    P"case" + 
    P"char" + 
    P"int" 
    -- more .. 
)/function() add_syntax(RED, ...) 

Dieser Eingang richtig behandelt, aber leider zu viel übereinstimmt. Zum Beispiel int passt in der Mitte von printf, die erwartet wird, weil ich "P" für eine wörtliche Übereinstimmung verwende.

Offensichtlich „richtige“ ausführen muss ich passen auf Wortgrenzen markieren, so dass „int“ Spiele „int“, aber nicht „printf“, „vsprintf“ usw.

Ich habe versucht, zu verwenden, dies das Spiel nur auftritt, nachdem „<[{ \n“ zu begrenzen, aber dies nicht tun, was ich will:

-- space, newline, comma, brackets followed by the keyword 
    S(" \n(<{,")^1 * P"auto" + 

gibt es eine einfache, klar, Lösung, die ich hier bin fehlt nur Schlüsselwörter/Token übereinstimmen, die sind umgeben von Leerzeichen oder anderen Zeichen, die Sie in C-Code erwarten würden? Ich brauche das erbeutete Token, damit ich es hervorheben kann, aber ansonsten bin ich mit keinem bestimmten Ansatz verheiratet.

z.B. Diese sollten übereinstimmen:

int foo; 
void(int argc,std::list<int,int>) { .. }; 

aber dies sollte nicht:

fprintf(stderr, "blah. patterns are hard\n"); 

Antwort

3

Der LPeg Bau -pattern (oder genauer -idchar im folgende Beispiel) macht einen guten Job, dafür zu sorgen, dass das aktuelle Spiel wird nicht von pattern gefolgt (d idchar). Zum Glück funktioniert das auch für leere Strings am Ende der Eingabe, so dass wir dafür keine spezielle Behandlung benötigen. Um sicherzustellen, dass eine Übereinstimmung nicht durch ein Muster vorausgeht, bietet LPeg lpeg.B(pattern). Leider erfordert dies ein Muster, das einer Zeichenfolge mit fester Länge entspricht und daher am Anfang der Eingabe nicht funktioniert.Um dies zu beheben, dass der separat folgende Code versucht, ohne lpeg.B() am Anfang des Eingangs zu entsprechen, bevor zu einem Muster zurückzufallen, die Suffixe und Präfixe für den Rest des Strings überprüft:

local L = require("lpeg") 

local function decorate(word) 
    -- highlighting in UNIX terminals 
    return "\27[32;1m"..word.."\27[0m" 
end 

-- matches characters that may be part of an identifier 
local idchar = L.R("az", "AZ", "09") + L.P"_" 
-- list of keywords to be highlighted 
local keywords = L.C(L.P"in" + 
         L.P"for") 

local function highlight(s) 
    local p = L.P{ 
    (L.V"nosuffix" + "") * (L.V"exactmatch" + 1)^0, 
    nosuffix = (keywords/decorate) * -idchar, 
    exactmatch = L.B(1 - idchar) * L.V"nosuffix", 
    } 
    return L.match(L.Cs(p), s) 
end 

-- tests: 
print(highlight"") 
print(highlight"hello world") 
print(highlight"in 0in int for xfor for_ |for| in") 
+0

Ich war anspruchsvoll, wollte eine Antwort auf einem Teller, aber Sie haben meine Erwartungen definitiv übertroffen. Akzeptiert. Ich danke dir sehr. –

+0

Kopfgeld Magie angewendet. –

2

Ich denke, Sie sollten das passende Muster negieren ähnlich, wie es in dem Beispiel gemacht wird von der documentation:

Wenn wir wollen nur an Wortgrenzen nach einem Muster suchen, können wir den folgenden Transformator verwenden:

local t = lpeg.locale() 
function atwordboundary (p) 
    return lpeg.P{ 
    [1] = p + t.alpha^0 * (1 - t.alpha)^1 * lpeg.V(1) 
    } 
end 

Diese SO answer diskutiert auch etwas ähnliche Lösung, so kann von Interesse sein.

Es gibt auch another editor component, die LPeg für das Parsing mit dem Zweck der Syntaxhervorhebung verwendet, so dass Sie vielleicht sehen möchten, wie sie damit umgehen (oder ihre Lexer verwenden, wenn es für Ihr Design funktioniert).

+0

OK Blick auf diesem genauen Dieser Ansatz funktioniert zur Hervorhebung, behandelt jedoch nur Suffix-Matching. d. h. "endend" passt nicht zu "end", sondern "vend". –