Função Buildargv com Ragel

Uso divertido do Ragel State Machine Compiler para criar uma função de análise de linha em int argc, char * argv [].


Tudo começou com o fato de que a função buildargv era necessária para analisar a cadeia de caracteres para transferência subsequente para


int main (int argc, char *argv[]) { body } 

Bem, pensei, não pode ser impossível emprestar para lugar algum, agora encontramos ... E não encontrei ...



Bem, não que eu não tivesse encontrado, por exemplo, https://github.com/gcc-mirror/gcc/blob/master/libiberty/argv.c (a GPLv2 é sempre boa), assumo imediatamente tais obrigações não estava pronto. Definitivamente, existe essa função no bash (a GPLv3 é ainda melhor). zsh? - vá encontrar (eu encontrei ... - eu não quero).


Em geral, não encontrei o que queria, mas não gostei do que encontrei. Bem, no final, tenho o direito a isso, mesmo assim, faço para mim uma sede de entretenimento no processo.


Eu não queria escrever esse caso de maneira convencional a partir da palavra, fiquei até chateado por esse motivo.


Em geral, encontramos o Ragel State Machine Compiler.


Toolkit


  • gcc;)
  • ragel
  • fazer
  • lcov
  • libcheck

O projeto pode ser encontrado aqui: JOYFUL CMDLINE PARSER ESCRITO EM RAGEL


Declaração do problema


Na entrada, temos uma string de qualquer tipo, a tarefa é obter da string uma matriz de argumentos separados por um espaço ou tabulação, com:


  • Qualquer caractere após o caractere de escape \ deve ser ignorado.
  • Qualquer caractere entre duas dobras ou deve
    ser considerado um elemento
  • No caso de ' ou ' não fechado, um erro será retornado

Em geral, não há muitas condições. E Ragel é bastante adequado para esta tarefa.


Implementação explicada


Vamos declarar uma máquina com o nome "buildargv" e pedir ao Ragel para colocar seus dados no início do arquivo (5.8.1 Write Data).


 %%{ machine buildargv; write data; }%% 

Em seguida, declaramos uma máquina lineElement , que por sua vez consiste em combinar (2.5.1 Union) duas máquinas: arg e whitespace .


 lineElement = arg >start_arg %end_arg | whitespace; main := blineElements**; 

Na entrada e na saída da máquina arg , as ações start_arg e end_arg respectivamente.


 action start_arg { argv_s = p; } action end_arg { nargv = (char**)realloc((*argv), (argc_ + 1)*sizeof(char*)); (*argv) = nargv; (*argv)[argc_] = strndup(argv_s, p - argv_s); argc_++; } 

Além disso, a tarefa start_arg para salvar a posição do caractere na entrada e a tarefa end_arg adicionam um novo elemento ao array argv , no caso de uma saída bem-sucedida da máquina arg .


Agora vamos dar uma olhada em arg .


 arg = '\''> { fcall squote; } | '"'>{ fcall dquote; } | ( '\\'>{fcall skip;} | ^[ \t"'\\] )+; 

Consiste em uma união de três máquinas ' , " e (\ | ^[ \t"'\]) , a última por sua vez é uma união de \ e ^[ \t"'\] respectivamente.


Quando encontramos o caractere ' chamamos squote ' , chamamos squote , ou se o caractere atual é \ chamamos skip , que ignora qualquer caractere que o segue e qualquer caractere não é 0x20 (espaço), 0x09 (tab), ' , " ou \ é considerado correto .


Resta considerar uma parte muito pequena:


 skip := any @{ fret; }; dquote := ( '\\'>{ fcall skip; } | ^[\\] )+ :> ["] @{ fret; } @err(dquote_err); squote := ( '\\'>{ fcall skip; } | ^[\\] )+ :> ['] @{ fret; } @err(squote_err); 

Com o skip já descobrimos o que ^['\\] também não deve causar perguntas. E aqui :> esta é Entry-Guarded Concatenation (4.2 operadores protegidos que encapsulam prioridades), seu significado é que a máquina ( '\\'>{ fcall skip; } | ^['\\] )+ completa a execução quando ["] retorna ao estado inicial.


E, finalmente, no caso de um erro de fim de linha com aspas em aberto, dquote_err e squote_err para indicar e definir o código de erro correspondente.


 action dquote_err { ret = -1; errsv = BUILDARGV_EDQUOTE; } action squote_err { ret = -1; errsv = BUILDARGV_ESQUOTE; } 

A geração de código é realizada pelo comando:


 ragel -e -L -F0 -o buildargv.c buildargv.rl 

Uma lista de linhas de teste pode ser encontrada em test_cmdline.c .


Conclusão


O problema está resolvido.


Foi mais rápido? Eu duvido. Mais claro? Se você é um especialista em Ragel.


Não finjo o absolutismo, serei grato por comentários construtivos sobre o código de Ragel.


Lista de materiais:


[^ 1]: Adrian Thurston. Ragel State Machine Compiler .

Source: https://habr.com/ru/post/pt477296/


All Articles