Domanda

Sto cercando di costruire una grammatica Lisp. Facile, no? A quanto pare no.

presento questi ingressi e ricevo errori ...

( 1 1)
23 23 23 
ui ui

Questa è la grammatica ...

%%
sexpr: atom                 {printf("matched sexpr\n");}
    | list
    ;
list: '(' members ')'       {printf("matched list\n");}
    | '('')'                {printf("matched empty list\n");}
    ;
members: sexpr              {printf("members 1\n");}
    | sexpr members         {printf("members 2\n");}
    ;
atom: ID                    {printf("ID\n");}
    | NUM                   {printf("NUM\n");}
    | STR                   {printf("STR\n");}
    ;
%%

Da quanto posso dire, ho bisogno di un singolo non terminale definito come un programma, su cui l'intero albero sintattico può appendere. Ma ho provato e non è sembrato funzionare.

modifica - questo è stato il mio approccio "stazione a monte":

program: slist;

slist: slist sexpr | sexpr;

Ma permette problemi come:

( 1 1 

Edit2: il codice FLEX è ...

%{
    #include <stdio.h>
    #include "a.yacc.tab.h"
    int linenumber;
    extern int yylval;
%}
%%
\n                         { linenumber++; }
[0-9]+                     { yylval = atoi(yytext); return NUM; }
\"[^\"\n]*\"               { return STR; }
[a-zA-Z][a-zA-Z0-9]*       { return ID; }
.
%%

Un esempio della over-matching ...

(1 1 1)
NUM
matched sexpr
NUM
matched sexpr
NUM
matched sexpr
(1 1
NUM
matched sexpr
NUM
matched sexpr

Qual è l'errore qui?

modifica: L'errore è stato nel lexer

.
È stato utile?

Soluzione

L'errore è davvero nel lexer. I vostri parentesi finiscono come l'ultimo "" nel lexer, e non apparire come parentesi nel parser.

Aggiungi regole come

\)     { return RPAREN; }
\(     { return LPAREN; }

per il lexer e cambiare tutte le occorrenze di '(', ')' per LPAREN e RPAREN, rispettivamente, nel parser. (Anche, è necessario #define LPAREN e RPAREN dove si definisce la vostra lista di token)

Nota: Non sono sicuro sulla sintassi, potrebbero essere le barre inverse sono sbagliati

.

Altri suggerimenti

grammatica Lisp non può essere rappresentato come la grammatica context-free, e yacc non è in grado di analizzare tutto il codice Lisp. È a causa di caratteristiche lisp come lettura e valutazione lettore programmabile. Così, al fine solo per leggere un codice Lisp arbitrario, è necessario disporre di una completa esecuzione Lisp. Questo non è un oscuro, caratteristica non utilizzato, ma è effettivamente utilizzato. Per esempio, CL-INTERPOL, CL-SQL.

Se l'obiettivo è quello di analizzare un sottoinsieme di Lisp, quindi il testo del programma è una sequenza di sexprs.

Sei corretta in quanto è necessario definire un non-terminale. Questo sarebbe essere definito come un insieme di sEspr. Non sono sicuro della sintassi YACC per questo. Io ho un debole per ANTLR per i generatori di parser e la sintassi sarebbe:

program: sexpr*

Indicando 0 o più sEspr.

Aggiornamento con la sintassi YACC:

program :  /* empty */
        | program sexpr
        ;

Non in YACC, ma potrebbe essere utile in ogni caso, ecco una grammatica completa in ANTLR v3 che funziona per i casi descritti (esclude stringhe nel lexer perché non è importante per questo esempio, utilizza anche C # console di output perché è quello che ho testato con):

program: (sexpr)*;

sexpr: list
    |  atom            {Console.WriteLine("matched sexpr");}
    ;

list:     
   '('')'              {Console.WriteLine("matched empty list");}
   | '(' members ')'   {Console.WriteLine("matched list");}

    ;

members: (sexpr)+      {Console.WriteLine("members 1");};

atom: Id               {Console.WriteLine("ID");}
    | Num              {Console.WriteLine("NUM");}
    ;


Num: ( '0' .. '9')+;
Id: ('a' .. 'z' | 'A' .. 'Z')+;
Whitespace : ( ' ' | '\r' '\n' | '\n' | '\t' ) {Skip();};

Questo non funziona esattamente come è in YACC perché YACC genera e LALR parser ANTLR, mentre è una discesa ricorsiva modificato. C'è un C / C ++ di destinazione di output per ANTLR se si voleva andare in quel modo.

Avete bisogno di un neccesarily Yacc / parser bisonte? A "si legge un sottoinsieme della sintassi Lisp" lettore non è così difficile da implementare in C (iniziare con una funzione di read_sexpr, la spedizione verso un read_list quando si vede un '(', che a sua volta crea un elenco di sexprs contenuti fino a quando un ' )' è visto,. in caso contrario, chiamare un read_atom che raccoglie un atomo e la restituisce quando non è più in grado di leggere i caratteri atomo-componente)

Tuttavia, se si vuole essere in grado di leggere arbritary Common Lisp, è necessario (nel peggiore dei casi) implementare un Common Lisp, come CL può modificare run-time il lettore (e anche commutare tra diversi lettura-tavoli run-time sotto il controllo del programma;. molto utile quando hai intenzione di caricare il codice scritto in un'altra lingua o dialetto Lisp)

E 'passato molto tempo da quando ho lavorato con YACC, ma avete bisogno di un livello superiore non terminale. Potrebbe essere più preciso circa "provato" e "non mi sembrava al lavoro"? Oppure, se è per questo, ciò che gli errori sono?

Mi piacerebbe anche il sospetto che YACC potrebbe essere eccessivo per un linguaggio come la sintassi-luce. Qualcosa di più semplice (come discesa ricorsiva) potrebbe funzionare meglio.

Si potrebbe provare a questa grammatica qui .

Ho appena provato, il mio "yacc lisca grammatica" funziona bene:

%start exprs

exprs:
    | exprs expr
    /// if you prefer right recursion :
    /// | expr exprs
    ;

list:
    '(' exprs ')'
    ;

expr:
    atom
    | list
    ;

atom:
    IDENTIFIER
    | CONSTANT
    | NIL
    | '+'
    | '-'
    | '*'
    | '^'
    | '/'
    ;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top