2010-02-09 20 views
13

Estoy escribiendo un analizador en Emacs Lisp. Es un programa de análisis de archivos de texto con este aspecto:Análisis en Emacs Lisp

rule: 
    int: 1, 2, 3, ... 
    string: and, or, then, when 
    text: 
    ---------- 
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque 
    in tellus. In pharetra consequat augue. In congue. Curabitur 
    pellentesque iaculis eros. Proin magna odio, posuere sed, commodo nec, 
    varius nec, tortor. 
    ---------- 
    more: ... 

rule: 
    ... 

Realmente no me importa acerca de la clave (int, cadena, ...). Quiero el valor . Por lo tanto, para el archivo anterior int tiene el valor "1, 2, 3, ...", cadena "y, o, luego, cuando" y el texto "Lorem ..." (excluyendo los guiones).

Estoy pensando en dos soluciones diferentes, pero no sé cuál utilizar. Debería:

  1. crear un analizador simple que recorre todas las líneas y para cada línea de partidos con un poco de expresiones regulares y luego agrupar las partes que quiero?

  2. ¿hace un analizador más sofisticado con un lexer y un analizador?

En este momento los archivos son muy simples y supongo que no necesito hacer algo tan adelantado como la segunda opción. Pero estos archivos pueden obtener un un poco más complicado, por lo que quiero que sea fácil de ampliar.

¿Cómo solucionaría esto?

+0

Parece que estás reinventando YAML. – myfreeweb

+6

No estoy inventando nada. Son archivos de registro de estaciones de viento. Aunque se parecen un poco a YAML. – rejeep

Respuesta

5

para la materia analizador vistazo a la biblioteca semántica de CEDET proyecto

+0

Lo comprobé. Aunque parecía bastante exagerado. Supongo que aprender mucho es capaz de hacer algo útil con eso. – rejeep

+0

CEDET realmente es el camino a seguir si crees que va a ser complejo. CEDET se ha agregado al próximo GNU Emacs 23.2, por lo que es el camino sancionado oficialmente. Todo depende de cuán compleja sea la gramática y de cuánto espere que se expanda el formato.A menos que estés muy seguro de que la gramática no será mucho más complicada, probablemente optaría por la Semántica de CEDET. – haxney

5

Hay un programa de análisis relativamente simple que puede encontrar en el Wiki Emacs: ParserCompiler

The Parser Compiler for Emacs creates Recursive Descent parsers in pure elisp.

The goal of the project is to create a useful Parser Compiler that is both innovative and practically useful. This is an original work created by Mike Mattie - [email protected]

Parsers are compiled by a Macro that translates a parser definition DSL to pure elisp. The syntax supports the PEG grammar class currently.

+0

Entonces, si uso un Compilador de Parser, ¿tengo que incluir esa biblioteca con mi código? Me gustaría evitar las bibliotecas externas y escribir el analizador a mano. – rejeep

+0

@rejeep Sí, debería incluir la biblioteca. –

13

¿Está familiarizado con recursive descent parsers? Son relativamente fáciles de escribir a mano en su lenguaje de programación favorito, que incluiría Emacs Lisp. Para un análisis muy simple, a menudo se puede arreglar con looking-at y search-forward. Estos también formarán la base de cualquier rutina tokenizing que su analizador de bajadas recursivo llamará o cualquier otro estilo de analizador.

[11 Feb 2009] Agregué un ejemplo de analizador de descenso recursivo en emacs lisp a continuación. Analiza expresiones aritméticas simples que incluyen suma, resta, multiplicación, división, exponenciación y subexpresiones entre paréntesis. En este momento, asume que todos los tokens están en la variable global *tokens*, pero si modifica gettok y peektok según sea necesario, puede hacer que caminen a través de un búfer. Para usarlo como es, simplemente tratar el siguiente:

(setq *token* '(3^5^7 + 5 * 3 + 7/11)) 
(rdh/expr) 
=> (+ (+ (^ 3 (^ 5 7)) (* 5 3)) (/ 7 11)) 

El código de análisis sigue.

(defun gettok() 
    (and *token* (pop *token*))) 
(defun peektok() 
    (and *token* (car *token*))) 

(defun rdh/expr() 
    (rdh/expr-tail (rdh/factor))) 

(defun rdh/expr-tail (expr) 
    (let ((tok (peektok))) 
    (cond ((or (null tok) 
      (equal tok ")")) 
     expr) 
     ((member tok '(+ -)) 
     (gettok) 
     (let ((fac (rdh/factor))) 
     (rdh/expr-tail (list tok expr fac)))) 
     (t (error "bad expr"))))) 

(defun rdh/factor() 
    (rdh/factor-tail (rdh/term))) 

(defun rdh/factor-tail (fac) 
    (let ((tok (peektok))) 
    (cond ((or (null tok) 
      (member tok '(")" + -))) 
     fac) 
     ((member tok '(* /)) 
     (gettok) 
     (let ((term (rdh/term))) 
     (rdh/factor-tail (list tok fac term)))) 
     (t (error "bad factor"))))) 

(defun rdh/term() 
    (let* ((prim (rdh/prim)) 
     (tok (peektok))) 
    (cond ((or (null tok) 
       (member tok '(")" + -/*))) 
      prim) 
      ((equal tok '^) 
      (gettok) 
      (list tok prim (rdh/term))) 
      (t (error "bad term"))))) 

(defun rdh/prim() 
    (let ((tok (gettok))) 
    (cond ((numberp tok) tok) 
     ((equal tok "(") 
     (let* ((expr (rdh/expr)) 
      (tok (peektok))) 
     (if (not (equal tok ")")) 
     (error "bad parenthesized expr") 
      (gettok) 
      expr))) 
     (t (error "bad prim"))))) 
+0

Encontré la página de analizadores de descenso recursivo más temprano. Para mal, el c-example no estaba completo, así que pude probarlo. Pero supongo que esta es una buena manera de hacer el analizador en mi caso. ¿Conoces algún ejemplo de Lisp? – rejeep

+0

No conozco ningún ejemplo particular de ceceo, me temo, pero por lo que pude ver, todo lo que falta en el ejemplo son las rutinas de tokenización. –

+0

No conozco casi ninguna c, por lo que hubiera sido mucho mejor si el ejemplo funcionara desde cero. Pero buscaré otros ejemplos en Google. ¡Gracias! – rejeep