algoritmo per l'interprete di linguaggio shell per trovare se un char è tra virgolette

2

Supponiamo di avere una stringa s (un C char * ) che è un programma in una lingua L. Voglio analizzare L e sapere quanto segue da specification

The following characters must be quoted if they are to represent themselves:

| & ; < > ( ) $ ' \ " '

Quindi diciamo che analizzo e analizzo la stringa controllando char per char e costruendo dinamicamente una struttura in memoria per l'intero programma. Il programma può essere corto come echo foobar ma l'importante è analizzare i diversi significati di | in una stringa come echo foo|cat e echo 'foo|cat' dove il primo è una pipeline e il secondo sta stampando un valore letterale.

Ora ho un nuovo token char c che è il carattere corrente di s. Ora voglio avere una funzione boolean isBetweenQuotes(int position, string s) che restituisce true se il carattere alla posizione position è quotato nella stringa s - sei d'accordo che questo è un buon modo per risolvere il problema? Come dovrebbe essere la funzione isBetweenQuotes ? I valori di ritorno dovrebbero essere ad esempio

isBetweenQuotes(6, "echo foobar"); /* returns false */
isBetweenQuotes(6, "echo foobar|less"); /* returns false */
isBetweenQuotes(6, "echo 'foobar'|less"); /* returns true */
isBetweenQuotes(20, "echo "foo bar"|awk '{print $1}''"); /* returns true */

Mi è stato suggerito che si potesse usare una macchina a stati finiti e / o un albero di sintassi astratto e fare il codice con flex / bison o con uno scanner / tokenizzatore personalizzato. Attualmente posso eseguire pipeline banali e sto cercando di rendere il codice shell più leggibile rispetto alle altre shell attuali. Ho studiato il codice sorgente per le seguenti shell: ash, dash, sash, posh e shell personalizzate e il codice più leggibile è stato sash, mentre capisco che posh e dash sono più conformi a posix.

Il mio obiettivo è creare una shell in grado di eseguire pipeline infinite mediante ricorsione con fork e exec e risolvere alcuni problemi di gestione dei segnali che potrebbero avere altre shell se allocano memoria con malloc .

    
posta Niklas Rosencrantz 26.04.2016 - 08:43
fonte

2 risposte

1

In linea di principio, potresti utilizzare qualcosa come la tua funzione isBetweenQuotes , ma sei (probabilmente) meglio servito da un modo più strutturato di analizzare le pipeline degli argomenti.

Tuttavia, qualcosa come il seguente potrebbe funzionare:

int isBetweenQuotes(int pos, char *str) {
  return IBQplain(pos, str, 0);
}

int IBQplain(int pos, char *str, int offset) {      
  char ch;
  if (pos == offset)
    return 0;  /* Not within quotes */
  int escaped = 0;
  for (ch = str[offset]; ch; ch = str[++offset]) {
    if (!escaped) {
      switch (str[offset]) {
        '\'': return IBQsingle(pos, str, offset+1);
        '"':  return IBQdouble(pos, str, offset+1);
        '\': escaped = 1
      } else {
        escaped = 0;
      }
      if (pos == offset)
        return escaped;  /* Not within quotes, but may be single-escaped */
  }

}

int IBQsingle(int pos, char *str, int offset) {
  int escaped = 0;
  for (; str[offset]; ++offset) {
     if (!escaped) {
        switch (str[offset]) {
           case '\': escaped = 1;
           case '\'': return IBQplain(pos, str, offset+1);
         } 
      } else {
        escaped = 0;
      }
      if (pos == offset) {
        return 1;
      }
  }

E una funzione simile (sebbene cerchi " ) per IBQdouble . Si tratta essenzialmente di una semplice macchina di stato espressa come funzioni, con semplici stepper per evitare una ricorsione profonda per "auto-transizioni".

Detto questo, la soluzione migliore è probabilmente quella di avvicinarsi a questo costruendo una sequenza di strutture, imitando l'albero di analisi.

    
risposta data 26.04.2016 - 11:05
fonte
3

do you agree this is a good way of solving the problem?

No. Quando analizzi una riga di comando della shell, passi attraverso la stringa, e così in qualsiasi momento dovresti già sapere se sei all'interno delle virgolette. O perché la macchina dello stato di analisi si trova in uno stato "tra virgolette" o perché il parser della discesa ricorsiva si trova in una funzione "parse quoted string".

Rispondere alla domanda durante l'analisi significa in sostanza che è necessario ri-analizzare la stringa dall'inizio, il che non ha senso.

Se vuoi saperne di più sull'analisi, ti suggerisco di cercare un tutorial per compilatore / interprete. Una shell è solo un interprete per la sua lingua particolare, dopotutto.

    
risposta data 26.04.2016 - 12:06
fonte

Leggi altre domande sui tag