Pegjs: Agregar capacidad para rastrear la posición del nodo

Creado en 13 ago. 2011  ·  15Comentarios  ·  Fuente: pegjs/pegjs

Los analizadores generados por PEG.js actualmente no rastrean la posición (línea y columna). Me gustaría agregar esta característica ya que sería bastante útil.

Una forma es agregar las propiedades line y column a cada objeto devuelto como resultado de una coincidencia:

start = "a" b:"b" { return [b.line, b.column]; } // Returns [1, 2] on the input "ab".

Otra forma es simplemente hacer que las variables especiales line y column estén disponibles dentro de acciones/predicados, refiriéndose a la posición del comienzo de la regla actual:

start = "a" "b" { return [line, column]; } // Returns [1, 1] on the input "ab".

La primera forma es más flexible, pero es posible que esta flexibilidad no sea realmente necesaria. No estoy seguro de qué manera implementaré todavía.

Ambas formas dañarían el rendimiento. Para evitar esto en los casos en los que no se requiere el seguimiento de la posición, el seguimiento debe habilitarse solo si la opción trackPosition con un valor real se pasa a PEG.buildParser al generar el analizador.

feature

Comentario más útil

@tomitrescak esta característica aparentemente ha cambiado varias veces en el pasado. Eche un vistazo al registro de cambios para obtener más información. tl; dr es que necesitas usar la función location() en tu gramática

Todos 15 comentarios

Cualquiera de las opciones será genial. Para mis necesidades, simplemente línea, la columna estará bien.

También estoy buscando una solución para esto. Actualmente, he pirateado algo rápidamente basado en computeErrorPosition(), pero tiene varios problemas.

En la superficie, el primer enfoque parece más intuitivo que el segundo.

Me gusta más el primer enfoque, también.

Una posible eficiencia es hacer que nombre.posición sea una función, por lo que se puede calcular con pereza. Esto podría devolver una matriz de 2 elementos de línea y columna. Solo una idea para aquellos que no quieren calcular la posición de cada elemento.

En retrospectiva, parece mejor proporcionar las posiciones de los caracteres de inicio y final, y luego proporcionar una función de ayuda en la biblioteca que convierte la posición en línea/columna. Dado que, en el caso general, no necesita línea/columna a menos que haya un error, y una vez que haya llegado a un error, normalmente solo lo necesita una vez.

Actualmente estoy haciendo esto de una manera pirateada al abusar de las variables startPos0 y pos , lo que parece pirateado, pero funciona por ahora.

Hasta que haya una solución oficial, incluiré esta función (una copia aproximada de computeErrorPosition ) en la parte superior de mis gramáticas. Al menos me dará la posición _actual_ (aunque no la posición de los nodos individuales):

  function computeCurrentPos() {
    /*
     * The first idea was to use |String.split| to break the input up to the
     * error position along newlines and derive the line and column from
     * there. However IE's |split| implementation is so broken that it was
     * enough to prevent it.
     */

    var line = 1;
    var column = 1;
    var seenCR = false;

    for (var i = 0; i < pos; i++) {
      var ch = input.charAt(i);
      if (ch === '\n') {
        if (!seenCR) { line++; }
        column = 1;
        seenCR = false;
      } else if (ch === '\r' | ch === '\u2028' || ch === '\u2029') {
        line++;
        column = 1;
        seenCR = true;
      } else {
        column++;
        seenCR = false;
      }
    }

    return { line: line, column: column, pos: pos };
  }

Este problema se solucionó mediante una serie de confirmaciones .

Ahora puede pasar la opción trackLineAndColumn a la función PEG.buildParser :

var parser = PEG.buildParser(myGrammar, { trackLineAndColumn: true});

Establecer trackLineAndColumn en true hace que dos nuevas variables sean visibles en las acciones y predicados: line y column . Para las acciones, estas variables indican la posición inicial de la expresión de la acción, mientras que en los predicados indican la posición actual. El comportamiento ligeramente diferente está motivado por el uso esperado.

El seguimiento de líneas y columnas es opcional porque perjudica el rendimiento (hace que los analizadores sean entre 3 y 4 veces más lentos). Es posible que pueda optimizar esto un poco en el futuro (traté de hacerlo funcionar primero).

En la descripción del problema, mencioné un enfoque diferente para este problema: agregar propiedades line y column a cada resultado de coincidencia. Si bien esta solución era más limpia y preferida por los usuarios, me di cuenta de que no se pueden establecer propiedades en valores primitivos como cadenas, números o valores booleanos (que a menudo se devuelven como resultados de coincidencia). Devolver instancias de objetos envolventes (por ejemplo String , Number o Boolean ) sería una posible solución, pero probablemente conduciría a errores sutiles en los analizadores creados por los usuarios, porque estos envoltorios se comportan de forma ligeramente diferente a los primitivos. Por lo tanto, decidí implementar la propuesta alternativa.

¿Se actualizará la página de prueba en línea para admitir esta función?

@paulftw El editor en línea siempre usa la última versión estable de PEG.js (actualmente 0.6.2). Lo actualizaré una vez que publique PEG.js 0.7.0 (que incluirá esta función). A menos que surja algo inesperado, esto sucederá en la segunda quincena de abril.

Tenga en cuenta que el código fuente del sitio web está disponible en GitHub , por lo que si está impaciente, puede ejecutarlo y modificarlo usted mismo.

Me acabo de dar cuenta de que todas las filas y columnas están basadas en 1, mientras que las matrices JS, así como casi todos los lenguajes y bibliotecas modernos, usan indexación basada en 0.

¿Alguna posibilidad de revertir esa decisión de diseño?

@paulftw ¿Puede dar un ejemplo de un generador de analizador que informa líneas y columnas basadas en 0?

La idea detrás de mi decisión es que estos números probablemente se mostrarán a los usuarios (en mensajes de error, como posiciones de nodos, etc.), por lo que la indexación basada en 1 tiene más sentido que la basada en 0. Para el procesamiento de máquinas, la variable offset probablemente se usará con mayor frecuencia, y esa variable está basada en 0.

¿Alguna posibilidad de revertir esa decisión de diseño?

Sí, si me convenzo :-)

Uso peg.js para resaltar texto en el editor Ace. Naturalmente, los números de línea de Ace están basados ​​en 0.
Parece, sin embargo, que en Bison las ubicaciones están basadas en 1.
http://git.savannah.gnu.org/cgit/bison.git/tree/src/location.c#n73

Si este es realmente el caso, entonces debería dejar de discutir.

No estoy seguro de qué tipo de ejemplo quieres ver.
Ahora mismo uso el siguiente código para encontrar un nombre de símbolo:

apresador
= "" { devuelve nueva posición (línea - 1, columna - 1); }

símbolo
= inicio:captor nombre:IDENT final:captor S* { return nuevo Símbolo(nombre, nuevo Rango(inicio, fin)); }

@paulftw He dividido este problema en un problema separado . Esperaría a que los usuarios adopten 0.7.0 y veré cuál es el uso predominante para decidir.

Sé que esto está cerrado desde hace mucho tiempo, pero ¿cómo puedo hacer que esto funcione? Soy bastante novato en esto. Compilé mi gramática con el indicador "trackLineAndColumn': true", pero los nodos aún no contienen líneas ni columnas. ¿Qué más se necesita?

Usted menciona lo siguiente, simplemente no sé cómo usarlo, ¿está documentado en alguna parte, por favor?

Establecer trackLineAndColumn en true hace que dos nuevas variables sean visibles en las acciones y predicados: línea y columna. Para las acciones, estas variables indican la posición inicial de la expresión de la acción, mientras que en los predicados indican la posición actual. El comportamiento ligeramente diferente está motivado por el uso esperado.

@tomitrescak esta característica aparentemente ha cambiado varias veces en el pasado. Eche un vistazo al registro de cambios para obtener más información. tl; dr es que necesitas usar la función location() en tu gramática

¿Fue útil esta página
0 / 5 - 0 calificaciones