2012-07-25 14 views
9

Tengo esencialmente la misma pregunta que PEG for Python style indentation, pero me gustaría obtener un poco más de dirección con respecto a this answer.nivel de sangría de Parse con PEG.js

La respuesta genera con éxito una matriz de cadenas que son cada línea de entrada con 'INDENT' y 'DEDENT' entre líneas. Parece que prácticamente ha usado PEG.js para tokenizar, pero no está teniendo lugar ningún análisis real.

Entonces, ¿cómo puedo extender su ejemplo para hacer un análisis real?

A modo de ejemplo, ¿cómo puedo cambiar esta gramática:

start = obj 
obj = id:id children:(indent obj* outdent)? 
     { 
      var o = {}; 
      o[id] = children[1]; 
      return (children[1] ? o : id); 
     } 
id = [a-z] 
indent = '{' 
outdent = '}' 

de usar la sangría en lugar de llaves para delimitar bloques, y aún así obtener el mismo resultado?

(Use http://pegjs.majda.cz/online para probar que la gramática con la siguiente entrada: a{bcd{zyx{}}})

Respuesta

18

Analizador:

// do not use result cache, nor line and column tracking 

{ var indentStack = [], indent = ""; } 

start 
    = INDENT? l:line 
    { return l; } 

line 
    = SAMEDENT line:(!EOL c:. { return c; })+ EOL? 
    children:(INDENT c:line* DEDENT { return c; })? 
    { var o = {}; o[line] = children; return children ? o : line.join(""); } 

EOL 
    = "\r\n"/"\n"/"\r" 

SAMEDENT 
    = i:[ \t]* &{ return i.join("") === indent; } 

INDENT 
    = &(i:[ \t]+ &{ return i.length > indent.length; } 
     { indentStack.push(indent); indent = i.join(""); pos = offset; }) 

DEDENT 
    = { indent = indentStack.pop(); } 

de entrada:

a 
    b 
    c 
    d 
    z 
    y 
    x 

de salida:

{ 
    "a": [ 
     "b", 
     "c", 
     { 
     "d": [ 
      "z", 
      "y", 
      "x" 
     ] 
     } 
    ] 
} 

No puede analizar un objeto vacío (último x), sin embargo, debería ser fácil de resolver. El truco aquí es la regla SAMEDENT, tiene éxito cuando el nivel de sangría no ha cambiado. INDENT y DEDENT cambiar el nivel de sangría actual sin cambiar la posición en el texto pos = offset.

+0

Realmente aprecio este awser. ¿Cómo se te ocurre este método, por favor? – jiyinyiyong

+0

Si copio/pego esto directamente en http://pegjs.majda.cz/online no compila. Y después de algunos ajustes, no está claro cómo "arreglarlo". – Clearly

+0

Acabo de probar esto, el fragmento compila y produce el resultado esperado muy bien. No estoy seguro de qué errores golpeó allí. – chakrit