2012-07-19 8 views
7

Wdrażam tłumacza języka skryptów edytora tekstów o długim okresie przestarzałości i mam pewne problemy z prawidłowym działaniem lexera.Najbardziej efektywny sposób analizowania tego języka skryptowego

Oto przykład z problematycznej części języka:

T 
L /LOCATE ME/ 
C /LOCATE ME/CHANGED ME/ * * 
C ;CHANGED ME;CHANGED ME AGAIN; 1 * 

W / postacie wydają się cytować strun a także działać jako ogranicznik dla (CHANGE) polecenia w składni sed -Type C, chociaż pozwala dowolnemu znakowi jako ogranicznikowi.

Prawdopodobnie wdrożyłem około połowę najczęstszych poleceń, tylko do tej pory używałem parse_tokens(line.split()). To było szybkie i brudne, ale zadziałało zaskakująco dobrze.

Aby uniknąć pisania własnego lexera, spróbowałem shlex.

To działa całkiem dobrze, z wyjątkiem CHANGE przypadkach:

import shlex 

def shlex_test(cmd_str): 
    lex = shlex.shlex(cmd_str) 
    lex.quotes = '/' 
    return list(lex) 

print(shlex_test('L /spaced string/')) 
# OK! gives: ['L', '/spaced string/'] 

print(shlex_test('C /spaced string/another string/ * *')) 
# gives : ['C', '/spaced string/', 'another', 'string/', '*', '*'] 
# desired : any format that doesn't split on a space between /'s 

print(shlex_test('C ;a b;b a;')) 
# gives : ['C', ';', 'b', 'a', ';', 'a', 'b', ';'] 
# desired : same format as CHANGE command above 

Ktoś wie łatwy sposób do osiągnięcia tego celu (z shlex lub w inny sposób)?

EDIT:

Jeśli to pomoże, oto składnia polecenia CHANGE podany w pliku pomocy:

''' 
C [/stg1/stg2/ [n|n m]] 

    The CHANGE command replaces the m-th occurrence of "stg1" with "stg2" 
for the next n lines. The default value for m and n is 1.''' 

jednaki trudno tokenize X i Y polecenia:

''' 
X [/command/[command/[...]]n] 
Y [/command/[command/[...]]n] 

    The X and Y commands allow the execution of several commands contained 
in one command. To define an X or Y "command string", enter X (or Y) 
followed by a space, then individual commands, each separated by a 
delimiter (e.g. a period "."). An unlimited number of commands may be 
placed in the X or Y command string. Once the command string has been 
defined, entering X (or Y) followed optionally by a count n will execute 
the defined command string n times. If n is not specified, it will 
default to 1.''' 
+0

Czy masz dostęp do definicji języka? Jeśli tak, cytat z odpowiedniej części może być przydatny dla nas wszystkich. – Marcin

+1

@Marcin Dodałem pewne istotne informacje z pliku pomocy, to cała moja dokumentacja. –

+0

Nie wiem 'shlex' ale myślę, że' regex' [(re)] (http://docs.python.org/library/re.html) również może być użyteczne. – machaku

Odpowiedz

0

The Problem prawdopodobnie polega na tym, że / nie jest przeznaczony do cytowania, ale tylko do ograniczania. Zgaduję, że trzeci znak jest zawsze używany do definiowania ogranicznika. Co więcej, na wyjściu nie potrzebujesz / ani ;?

Właśnie odbywa się wyłącznie z następujących rozłamu w przypadku polecenia L i C:

>>> def parse(cmd): 
...  delim = cmd[2] 
...  return cmd.split(delim) 
... 
>>> c_cmd = "C /LOCATE ME/CHANGED ME/ * *" 
>>> parse(c_cmd) 
['C ', 'LOCATE ME', 'CHANGED ME', ' * *'] 

>>> c_cmd2 = "C ;a b;b a;" 
>>> parse(c_cmd2) 
['C ', 'a b', 'b a', ''] 

>>> l_cmd = "L /spaced string/" 
>>> parse(l_cmd) 
['L ', 'spaced string', ''] 

Dla opcjonalnego " * *" części można wykorzystać split(" ") na ostatniej liście elementu.

>>> parse(c_cmd)[-1].split(" ") 
['', '*', '*'] 
+0

Niestety to nie jest * zawsze * trzecia postać, ale spróbuję tego podejścia i oddzwonię, dzięki. –