Domanda

Definizione di interpolazione di Wikipedia Sto solo imparando flex / bison e sto scrivendo la mia shell con esso. Sto cercando di capire un buon modo per eseguire l'interpolazione variabile. Il mio approccio iniziale a questo era di avere la scansione flessibile per qualcosa come ~ per la mia directory home, o $ myVar, e quindi impostare ciò che yyval.string su ciò che viene restituito usando una funzione di ricerca. Il mio problema è che questo non mi aiuta quando il testo appare un token:

kbsh:/home/kbrandt% echo ~
/home/kbrandt
kbsh:/home/kbrandt% echo ~/foo
/home/kbrandt /foo
kbsh:/home/kbrandt%

La definizione lex che ho per le variabili:

\$[a-zA-Z/0-9_]+    {
    yylval.string=return_value(&variables, (yytext + sizeof(char)));;
    return(WORD);
}

Quindi nella mia grammatica, ho cose come:

chdir_command:
    CD WORD { change_dir($2); }
    ;

Qualcuno sa di un buon modo di gestire questo genere di cose? Sto sbagliando tutto questo?

È stato utile?

Soluzione

Il modo in cui le shell 'tradizionali' gestiscono cose come la sostituzione variabile è difficile da gestire con lex / yacc. Quello che fanno è più simile all'espansione macro, dove DOPO l'espansione di una variabile, ricodificano quindi l'input, senza espandere ulteriori variabili. Ad esempio, un input come " xx $ {$ foo} " dove 'foo' è definito come 'bar' e 'bar' è definito come '$ y' si espanderà in 'xx $ y' che sarà trattato come una singola parola (e $ y NON sarà espanso).

PUOI affrontarlo in modo flessibile, ma hai bisogno di molto codice di supporto. È necessario utilizzare le cose yy_buffer_state di flex per reindirizzare a volte l'output in un buffer da cui eseguire nuovamente la scansione e utilizzare attentamente gli stati iniziali per controllare quando le variabili possono e non possono essere espanse.

Probabilmente è più facile usare un lexer molto semplice che restituisce token come ALPHA (uno o più caratteri alfabetici), NUMERIC (una o più cifre) o WHITESPACE (uno o più spazi o tab) e fare assemblare il parser appropriatamente, e finisci con regole come:

simple_command: wordlist NEWLINE ;

wordlist: word | wordlist WHITESPACE word ;

word: word_frag
    | word word_frag { $ = concat_string($1, $2); }
;

word_frag: single_quote_string
         | double_quote_string
         | variable
         | ALPHA
         | NUMERIC
        ...more options...
;

variable: '

come puoi vedere, questo diventa complesso abbastanza velocemente.

name { $ = lookup($2); } | '

come puoi vedere, questo diventa complesso abbastanza velocemente.

'{' word '}' { $ = lookup($3); } | '

come puoi vedere, questo diventa complesso abbastanza velocemente.

'{' word ':' ....

come puoi vedere, questo diventa complesso abbastanza velocemente.

Altri suggerimenti

Sembra generalmente OK


Non sono sicuro di cosa stia facendo return_value , spero che strdup (3) il nome della variabile, perché yytext è solo un buffer.

Se stai chiedendo informazioni sulla divisione del lavoro tra lex e parse, sono sicuro che è perfettamente ragionevole inserire l'elaborazione macro e la sostituzione dei parametri nello scanner e avere solo il tuo affare grammaticale con WORD s, liste, comandi, pipeline, reindirizzamenti, ecc. Dopotutto, sarebbe abbastanza ragionevole, anche se un po 'fuori moda e possibilmente sconfiggere il punto del tuo esercizio, fare tutto con il codice.

Penso che rendere cd o chdir un simbolo terminale e usarlo in una produzione grammaticale non sia ... la migliore decisione progettuale. Solo perché un comando è incorporato non significa che dovrebbe apparire come una regola. Vai avanti e analizza cd e chdir come qualsiasi altro comando. Controlla la semantica integrata come azione, non come produzione.

Dopo tutto, cosa succede se viene ridefinito come procedura di shell?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top