2010-04-08 8 views
5

ho qualche grammatica bisonti:In che modo Bison/YACC non riconosce un comando finché non analizza l'intera stringa?

input: /* empty */ 
     | input command 
; 

command: 
     builtin 
     | external 
; 

builtin: 
     CD { printf("Changing to home directory...\n"); } 
     | CD WORD { printf("Changing to directory %s\n", $2); } 
; 

Mi chiedo come ho Bison di non accettare (YYACCEPT?) Qualcosa come command fino a quando non legge tutti i ingresso. Quindi posso avere tutte queste regole sotto che usano la ricorsione o qualsiasi altra cosa per costruire le cose, il che risulta in un comando valido o qualcosa che non funzionerà.

Un semplice test che sto facendo con il codice sopra è solo inserendo "cd mydir mydir". Bison analizza CD e WORD e fa "hey! Questo è un comando, mettilo in cima!". Quindi il token successivo che trova è solo WORD, che non ha alcuna regola, quindi segnala un errore.

Desidero leggere l'intera riga e realizzare CD WORD WORD non è una regola, quindi segnalare un errore. Penso che mi manchi qualcosa di ovvio e apprezzerei molto ogni aiuto - grazie!

Inoltre - Ho provato con input command NEWLINE o qualcosa di simile, ma spinge ancora CD WORD verso l'alto come un comando e quindi analizza l'extra WORD separatamente.

+0

Sembra che il tuo 'incorporato 'debba essere terminato da una nuova riga (non da' input'). Come in 'CD WORD NEWLINE' – leeeroy

+0

Il' builtin' manca un '{', dovrebbe essere '| CD WORD {printf ("Modifica in directroy% s \ n", $ 2); } ' –

+0

Whoops sorry! Non era nel codice che sto usando per testare ... – chucknelson

risposta

2

A volte mi occupo di questi casi appiattendo le mie grammatiche.

Nel tuo caso, potrebbe avere senso aggiungere token al tuo lexer per i separatori di riga e comando (;) in modo che tu possa metterli esplicitamente nella tua grammatica Bison, così il parser si aspetterà una linea completa di input per un comando prima di accettare come comando.

sep: NEWLINE | SEMICOLON 
    ; 

command: CD sep 
    | CD WORD sep 
    ; 

Oppure, per un elenco arbitrario di argomenti come un vero e proprio guscio:

args: 
    /* empty */ 
    | args WORD 
    ; 

command: 
     CD args sep 
    ; 
+0

Questo sembra funzionare. È un fiasco, però, che devo menzionare specificamente l'espressione separatore per ogni comando. Potrei passare ad argomenti arbitrari ad un certo punto ... ma non ancora! Sono ancora curioso di sapere se ci sono altri modi per farlo ... – chucknelson

+0

Correzione: funziona con 2 parole (ciao ciao ciao), ma a quel punto spunta fuori i token. Quindi ricomincia per qualche motivo. Quindi "cd hello1 hello2 hello3" farà scoppiare cd, hello1 e hello2, ma poi proverà ad abbinare una regola separata per hello3. Sono così confuso ... – chucknelson

+0

Se si utilizza la regola "args" come nella seconda parte sopra, dovrebbe corrispondere a un numero arbitrario. – codenheim

0

Di solito, le cose non sono fatte nel modo in cui descrivete.

Con Bison/Yakk/Lex, in genere si progetta con cura la sintassi per fare esattamente ciò di cui hanno bisogno. Poiché Bison/Yakk/Lex sono naturalmente greedy con le loro espressioni regolari, questo dovrebbe aiutarti.

Quindi, che ne dici di questo.

Poiché si analizzano intere righe alla volta, penso che possiamo utilizzare questo fatto a nostro vantaggio e rivedere la sintassi.

input : /* empty */ 
     | line 


command-break : command-break semi-colon 
       | semi-colon 

line : commands new-line 

commands : commands command-break command 
     | commands command-break command command-break 
     | command 
     | command command-break 

... 

Dove new-line, 'virgola is defined in your lex source as something like \ n , \ t`. Questo dovrebbe darti la sintassi in stile UNIX per i comandi che stai cercando. Sono possibili tutti i tipi di cose, ed è un po 'gonfio consentendo più punti e virgola e non prende in considerazione lo spazio bianco, ma dovresti avere l'idea.

Lex e Yakk sono uno strumento potente, e li trovo molto divertenti - almeno, quando non si è in una scadenza.

0

Impossibile basta cambiare la regola partita azioni da aggiungere a un elenco di azioni che si desidera eseguire se il tutto funziona? Quindi, dopo che l'intero input è stato elaborato, decidi se vuoi fare ciò che era in quell'elenco di azioni in base a se hai visto errori di analisi.

1

Invece di chiamare direttamente le azioni, è sufficiente creare prima un albero astratto di sintassi. Quindi, a seconda del risultato e delle tue preferenze, esegui la parte di esso o nulla. Se c'è un errore di parsing durante la costruzione di alberi, potresti voler usare la direttiva% distructor per dire a bison come eseguire la pulizia.

Questo è effettivamente un modo corretto di farlo mentre si ottiene il pieno controllo dei contenuti e della logica e si lascia che il bisonte si occupi solo dell'analisi.

+0

Grazie per la risposta - in una classe corrente sono inserito stiamo facendo un progetto in cui analizziamo una lingua, costruiamo un codice AST e generiamo codice. Purtroppo non avevo questa esperienza nella classe in cui stavo usando Bison e YACC. Grazie ancora, probabilmente penserò al problema in modo diverso la prossima volta che devo fare qualcosa di simile. – chucknelson

Problemi correlati