TwojePC.pl © 2001 - 2024
|
|
A R C H I W A L N A W I A D O M O Ś Ć |
|
|
|
[RegEx] - usuwanie komentarzy i literałów z kodu źródłowego - jak? , bwana 6/01/12 11:50 Co chcę uzyskać: mam kod źródłowy deklaracji pakietu PL/SQL (budową przypomina deklarację klasy). Chcę w sposób znormalizowany zebrać informacje o procedurach i funkcjach pakietu (w przypadku klasy byłyby to deklaracje metod) oraz o parametrach wywołania tych procedur i funkcji.
Występują dwa rodzaje komentarzy:
tekst kodu -- tekst komentarza
tekst kodu /* tekst
komentarza */ dalszy ciąg kodu
Mogą też w różnych miejscach występować literały tekstowe w pojedynczych albo w podwójnych cudzysłowach. Literał tekstowy może przełamywać linię tekstu bez dodatkowego znacznika.
No i teraz - chcę pozbyć się i komentarzy i literałów tekstowych. Ale nie bardzo już wiem, jak uwzględnić to, że w treści komentarza mogą wystąpić cudzysłowy i na odwrót - w literałach tekstowych mogą wystąpić znaki komentarzy '--' lub '/* */'.
przykładowo:
-----------------------------------------------------------------
package nazwa
/*
pakiet zawiera procedurę proc_a do której należy
podać parametr otoczony znakami apostrofu czyli '
*/
procedure proc_a(a varchar2 default 'ala ma
kota /*');
procedure proc_b(b varchar2 default 'ale
ma kota*/');
procedure proc_c(c varchar2 default 'ale ma -- problem');
end;
-----------------------------------------------------------------
jak widać, trudno jest określić sposób wyrzucania literałów i komentarzy z kodu. No ale przecież edytory tekstu radzą sobie z tym i może znacie jakieś spostrzeżenie, które naprowadzi mnie na rozwiązanie problemu.
Nie chodzi mi o gotowe narzędzie, tylko o algorytm, ponieważ całość chcę umieścić w pakiecie PL/SQL, który ma kod innych pakietów prezentować w znormalizowanej postaci (krótko mówiąc ma generować szablony wywołań dowolnie wskazanego API).
Rozwiązanie sprowadza się do określenia sposobu stwierdzenia, że "w tym miejscu w kodzie jest wnętrze komentarza" i "w tym miejscu w kodzie jest wnętrze literału tekstowego". Pomożecie?
Próbuję to rozwiązać używając wyrażeń regularnych i jestem daleki od implementowania automatu skończonego ze stosem, którym faktycznie coś takiego da się w miarę łatwo opanować - tylko że trzeba napisać sam automat:-D Tak więc - raczej sposobami "inżynierskimi" sypnijcie."you don't need your smile when I cut
your throat" - próbowałeś , Holyboy 6/01/12 12:19
wyszukać i zastąpić te znaki komentarzy znajdujące się wewnątrz stringów ?Strength is irrelevant.
Resistance is futile.
We wish to improve ourselves. - jasne:-D , bwana 6/01/12 12:58
tylko trzeba umieć rozpoznać, czy początek/koniec stringa jest w kodzie, czy w komentarzu. Podobnie na odwrót - trzeba rozpoznać, czy początek/koniec komentarza jest w literale tekstowym czy w kodzie.
Dlatego jednak robię to czytając kolejno po jednym znaku i podejmując decyzje i zapamiętując stany:
- czy to znak rozpoczynający/kończący komentarz
- czy to znak rozpoczynający/kończący literał tekstowy
czyli jednak zrobiłem coś w stylu DAS-a. No ale działa.
kod wygląda tak (o ile to kogoś interesuje, PL/SQL jako język programowania ogólnego zastosowania to jak za króla Ćwieczka):
PROCEDURE strip_comments(p_code IN out nocopy CLOB) AS
l_position NUMBER:=1;
in_dash_comment boolean:=FALSE;
in_mline_comment boolean:=FALSE;
in_s_literal boolean:=FALSE;
in_d_literal boolean:=FALSE;
l_result CLOB;
l_len NUMBER:=LENGTH(p_code);
FUNCTION in_comment RETURN boolean AS
BEGIN
return in_dash_comment or in_mline_comment;
END;
FUNCTION in_literal RETURN boolean AS
BEGIN
return in_s_literal or in_d_literal;
end;
BEGIN
loop
IF substr(p_code,l_position,2) = '--' and not in_mline_comment and not in_literal THEN
in_dash_comment:=TRUE;
l_position:=l_position+2;
ELSIF substr(p_code,l_position,2) = '/*' AND NOT in_dash_comment and not in_literal THEN
in_mline_comment:=TRUE;
l_position:=l_position+2;
elsif substr(p_code,l_position,1) = chr(10) AND in_dash_comment THEN
in_dash_comment:=FALSE;
l_result:=l_result||chr(10);
l_position:=l_position+1;
elsif substr(p_code,l_position,2) = '*/' AND in_mline_comment THEN
in_mline_comment:=FALSE;
l_position:=l_position+2;
elsif substr(p_code,l_position,1) = '''' AND NOT in_s_literal and not in_comment THEN
in_s_literal:=TRUE;
l_position:=l_position+1;
elsif substr(p_code,l_position,1) = '''' AND in_s_literal and not in_comment THEN
IF substr(p_code,l_position+1,1) = '''' THEN
l_position:=l_position+2;
ELSE
in_s_literal:=FALSE;
l_position:=l_position+1;
end if;
END IF;
IF NOT in_comment and not in_literal THEN
l_result:=l_result||substr(p_code,l_position, 1);
end if;
l_position:=l_position+1;
exit when l_position>=l_len;
END loop;
dbms_output.put_line(l_result);
p_code:=l_result;
end;"you don't need your smile when I cut
your throat"
- A może coś z tego: , Tig3r 6/01/12 19:42
http://www.perlmonks.org/...s%20from%20a%20file%3F - A dokładniej , Tig3r 6/01/12 19:53
/\*[^*]*\*+([^/*][^*]*\*+)*/|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|\n+|--[^\n]*|.[^/"--'\\]*)
Drobna zmiana żeby jeszcze złapać te komentarze w stylu --
To wyrażenie powinno podzielić tekst na kawałki. Sprawdzenie czym jest dany kawałek nie powinno być już problemem :D
BTW do testowania i pisania wyrażeń regularnych "na żywo" polecam RegEx Coach - świetny i darmowy.- na pierwszy rzut oka może być OK - o ile takie krzaczki na pierwszy rzut oka można ocenić , bwana 6/01/12 22:39
ale wydaje mi się, że to powinno być wyrażenie z modyfikatorem non-greedy.
Niestety, składnia PL/SQL jest nieco inna niż Perlowa (chyba najbardziej znana) i nad takim gotowcem i tak trzeba popracować."you don't need your smile when I cut
your throat"
|
|
|
|
|
All rights reserved ® Copyright and Design 2001-2024, TwojePC.PL |
|
|
|
|