¿Hay algún compilador que intente reparar los errores de sintaxis por su cuenta? [cerrado]

15

Hace un tiempo escuché que solía haber un compilador que intentaba corregir los errores de sintaxis analizando el contexto e inferiendo lo que se pretendía.

¿Existe realmente ese compilador? Obviamente tiene poco valor práctico, pero sería muy interesante jugar y aprender de él.

Nathan Osman
fuente
3
¿IntelliSense cae en esta categoría? Muchos compiladores tienen errores similares a [punto y coma] esperados.
Robert Harvey
1
@Robert: No, pero ese es un buen punto.
Nathan Osman
1
Un amigo mío hackeó bastante el preprocesador C, por ejemplo, 'inlcude -> include', y trabajó en tratar de averiguar dónde deberían haberse cerrado los condicionales abiertos. Era su tesis de maestría, que rápidamente abandonó por algo más fácil. Aún así, una pregunta bastante interesante!
Tim Post
3
El compilador AC # falla con mensajes de error MUY útiles. Eso, combinado con una buena documentación disponible en línea para cada código de error, funciona bastante bien. Es una mala idea corregir automáticamente la sintaxis, aunque los intérpretes HTML (por ejemplo, los navegadores) a menudo lo hacen de todos modos.
Trabajo
1
El compilador al que te refieres era el PL / I original. Asumió que lo que sea que escribió el programador debe haber significado algo, e intentó adivinar qué podría ser. En mi experiencia, ¡adivinó muy mal!
david.pfx

Respuestas:

28

En cierto sentido, el acto de compilar es inferir lo que se supone que debe hacer cierta sintaxis y, por lo tanto, un error de sintaxis es cuando el compilador no puede resolverlo. Puede agregar más "adivinanzas" para que el compilador deduzca más cosas y sea más flexible con la sintaxis, pero debe inferir esto mediante un conjunto específico de reglas. Y esas reglas se convierten en parte del lenguaje y ya no son errores.

Entonces, no, no existen tales compiladores, realmente, porque la pregunta no tiene sentido. Adivinar qué errores de sintaxis deben hacer de acuerdo con un conjunto de reglas se convierte en parte de la sintaxis.

En ese sentido, hay un buen ejemplo de un compilador que hace esto: cualquier compilador de C. A menudo imprimen una advertencia de algo que no es como debería ser, y luego suponen que se refería a X, y continúan. De hecho, esto es "adivinar" un código poco claro (aunque en su mayoría no es sintaxis per se), algo que podría haber detenido la compilación con un error y, por lo tanto, calificarse como un error.

Lennart Regebro
fuente
44
Esta es la respuesta correcta. Una vez que un compilador puede recuperarse de un error, ya no es realmente un error. Perl es (¿in?) Famoso por este comportamiento de "Haz lo que quiero decir", eligiendo lo que el programador probablemente haya significado con una fuente ambigua.
Jon Purdy
Perl sacrifica la verbosidad por el tamaño del código fuente.
Nathan Osman
@George Edison: Eso es una tautología o una contradicción.
Jon Purdy
O una visión profunda. :)
Lennart Regebro
23

Suena muy peligroso Si un compilador intenta inferir su intención, lo infiere mal, corrige el código y luego no le dice (o le dice en alguna advertencia que usted, como todos, ignora), entonces está a punto de ejecutar un código que puede En serio hacer algo de daño.

Un compilador como este es probablemente algo que NO ha sido creado intencionalmente.

nganju
fuente
55
Yo sé eso. Tal compilador no tendría uso para la compilación, pero el concepto es bastante interesante y tiene potencial de aprendizaje.
Nathan Osman
2
casi todos los IDE más recientes ofrecen sugerencias de sintaxis y son realmente útiles. y para el resto de la parte de acuerdo con nganju
Jigar Joshi
No usaría tal compilador. Viene bajo el título de 'magia negra'.
Michael K
Hmmm, ¿dónde calificaría la inferencia de tipos de Scala en esta escala? Después de haberlo intentado, diría que es una contribución importante al código conciso. Por otro lado, ocasionalmente me ha disparado en el pie (por ejemplo, porque pensé que estaba lidiando con listas pero en realidad todavía estaba lidiando con conjuntos).
Timday
Tenemos cosas como autoscope en OMP, por lo que un poco es factible. Por supuesto, el código en el que trabajo se ha desactivado automáticamente porque no confiamos en él. Pude ver tener un compilador interactivo que pregunta "¿te refieres a XXX?". Eso es hasta donde estaría dispuesto a llegar. E incluso eso es probablemente demasiado peligroso.
Omega Centauri
12

El IDE para un lenguaje de programación generalmente en estos días tiene un compilador ejecutándose en segundo plano de alguna manera, para que pueda proporcionar servicios de análisis como coloración de sintaxis, IntelliSense, errores, etc. Obviamente, un compilador de este tipo debe poder dar sentido a un código profundamente roto; la mayoría de las veces al editar, el código no es correcto. Pero todavía tenemos que darle sentido.

Sin embargo, generalmente la función de recuperación de errores solo se usa durante la edición; no tiene mucho sentido permitir eso para la compilación real en escenarios de "línea principal".

Curiosamente, creamos esa característica en el compilador JScript.NET; básicamente es posible poner el compilador en un modo en el que permitimos que el compilador continúe incluso si se encuentra un error, si el IDE se hubiera recuperado de él. ¡Puede escribir código de Visual Basic , ejecutar el compilador JScript.NET en él y tener una posibilidad razonable de que un programa de trabajo salga por el otro extremo!

Esta es una demostración divertida, pero resulta que no es una característica muy buena para escenarios de "línea principal" por muchas razones. Una explicación completa sería bastante larga; La breve explicación es que crea programas que funcionan de manera impredecible y accidental , y dificulta la ejecución del mismo código a través de múltiples compiladores o múltiples versiones del mismo compilador. Los grandes gastos que agrega la función no se justifican por los pequeños beneficios.

Peter Torr, quien publicó la característica en el pasado, lo analiza brevemente en esta publicación de blog de 2003 .

Aunque exponemos esta característica a través de las API de hospedaje de scripts del motor JNET .NET, no conozco ningún cliente real que la haya usado alguna vez.

Eric Lippert
fuente
Desearía que mi empleador tuviera los recursos para experimentar así; ni siquiera ejecutamos pruebas unitarias por la noche porque hay muchas características que agregar y errores que corregir :(
Trabajo
1
Este es el tipo de respuesta que esperaba ... como mencioné antes, obviamente esta característica tiene poco uso práctico, pero proporcionaría una excelente manera de aprender algunas técnicas que podrían aplicarse a otras cosas. (Análisis de idiomas, etc.)
Nathan Osman
1
@ Job: La sabiduría general es que si no ejecutas regularmente las pruebas unitarias, tendrás muchos más errores que corregir .
Eric Lippert
Ya sé lo que tengo que hacer con mi trabajo en lugar de quejarme aquí. En algunas compañías de software, las personas de la cima no comprenden realmente la diferencia entre un prototipo y un producto terminado. Después de todo, en cuanto a píxeles, a menudo no hay mucha diferencia. Es imprudente no comenzar con un prototipo, para que no se pierda el tiempo. Pero la respuesta terrible "se ve bien, ¿cuántos días para pasar esto a producción?". Esas son las mismas personas que sospecharían si los ingenieros les dijeran que necesitan pasar tiempo en la infraestructura o la refactorización. Escuché que incluso a Spolsky no le gusta.
Trabajo
10

Lo primero que me viene a la mente es la inserción automática de punto y coma de Javascript . Una característica horrible, horrible que nunca debería haber llegado al lenguaje.

Eso no quiere decir que no podría haber hecho un mejor trabajo. Si miraba hacia adelante en la siguiente línea, entonces podría ser capaz de adivinar mejor la intención del programador, pero al final del día, si hay varias formas válidas de que la sintaxis podría haber desaparecido, entonces realmente no hay sustituto para que el programador sea explícito.

Dean Harding
fuente
1
Estoy totalmente de acuerdo con la función de inserción de punto y coma de JavaScript, completamente inútil.
Nathan Osman
7

Me parece que si un compilador puede corregir una sintaxis incorrecta, esa sintaxis debe documentarse en el idioma.

La razón de los errores de sintaxis es porque un analizador sintáctico no pudo crear el árbol de sintaxis abstracta fuera del programa. Esto sucede cuando una ficha está fuera de lugar. Para adivinar dónde debe estar ese token, si se debe eliminar o si se debe agregar algún otro token para corregir el error, necesitaría algún tipo de computadora que pueda adivinar la intención de un programador. ¿Cómo podría una máquina adivinar eso?

int x = 5 6;

Se suponía que era:

int x = 5 + 6;

Podría ser simplemente tan fácilmente cualquiera de los siguientes: 56, 5 - 6, 5 & 6. No hay forma de que un compilador lo sepa.

Esa tecnología aún no existe.

jjnguy
fuente
1
Tal tecnología no puede existir. La lectura de la mente no está permitida; todas las instrucciones deben proceder inequívocamente del código.
Trabajo
Es cierto, pero lo que realmente quise decir fue "¿Hay algún compilador que intente corregir la sintaxis no válida haciendo conjeturas basadas en el contexto". El hecho de que el compilador corrija la sintaxis no válida no hace que la sintaxis sea válida. Además, me doy cuenta de que tal herramienta sería inútil para el desarrollo de código.
Nathan Osman
6

Aunque no es exactamente lo mismo, esta es la razón por la cual HTML se convirtió en el desastre que es. Los navegadores toleraron un marcado incorrecto y lo siguiente que sabía es que el navegador A no podía funcionar de la misma manera que el navegador B (sí, hay otras razones, pero esta fue una de las pocas, especialmente hace unos 10 años antes de que algunas de las reglas de flexibilidad se convirtieran en convenciones )

Como infiere Eric Lippert, muchas de estas cosas son mejor manejadas por el IDE, no por el compilador. Eso te permite ver lo que los bits automáticos intentan arruinarte.

La estrategia que creo que predomina ahora es el continuo refinamiento del lenguaje en lugar de aflojar el compilador: si realmente es algo que el compilador puede descubrir automáticamente, entonces introduzca una construcción de lenguaje bien definida a su alrededor.

El ejemplo inmediato que viene a la mente son las propiedades automáticas en C # (no es el único lenguaje que tiene algo similar): dado que la mayoría de los captadores / establecedores en cualquier aplicación son solo envoltorios alrededor de un campo, solo permita que el desarrollador indique su intento y dejar que el compilador inyecte el resto.

Lo que me lleva a pensar: la mayoría de los lenguajes de estilo C ya lo hacen hasta cierto punto. Para las cosas que se pueden resolver automáticamente, simplemente refine la sintaxis:

 if (true == x)
 {
    dothis();
 }
 else
 {
    dothat();
 }

Se puede reducir a:

if (true == x)
    dothis();
else
    dothat();

Al final, creo que todo se reduce a esto: la tendencia es que no hagas que el compilador sea "más inteligente" o "más flexible". Es el lenguaje que se hace más inteligente o más flexible.

Además, demasiada "ayuda" puede ser peligrosa, como el clásico error "if":

if (true == x)
    if (true == y)
       dothis();
else
    dothat();
desaparecido en combate
fuente
Cabe señalar que XHTML proporcionó una solución para el desorden que crearon las pobres especificaciones de HTML.
Nathan Osman el
2
if (x && y) dothis(); else dothat();Se vería un poco mejor.
Trabajo
1
Un gato muere cada vez que alguien se compara con trueo false.
JensG
2

Cuando estaba codificando FORTRAN y PL / I a finales de los años 80 y principios de los 90 en sistemas de minicomputadora y mainframe de DEC e IBM, parece recordar que los compiladores desconectaban regularmente mensajes como "bla bla bla error; suponiendo que bla bla y continuando ... ". En aquel entonces, este era un legado de los días (incluso antes, antes de mi tiempo) de procesamiento por lotes y tarjetas perforadas, cuando probablemente hubo una enorme espera entre el envío de su código para ejecutar y obtener los resultados. Por lo tanto, tenía mucho sentido que los compiladores intentaran adivinar al programador y continuar en lugar de abortar el primer error encontrado. Eso sí, no recuerdo que las "correcciones" sean particularmente sofisticadas. Cuando finalmente me mudé a estaciones de trabajo interactivas de Unix (Sun, SGI, etc.),

Timday
fuente
2
Esos compiladores continuarían, pero continuarían SOLO con el propósito de tratar de encontrar más errores, por lo que podría (potencialmente) corregir varias cosas antes de volver a enviarlas. Las PC modernas son lo suficientemente rápidas como para que un compilador "interactivo" se detenga en el primer error de sintaxis y lo coloque en un editor. (Y, de hecho, el Turbo Pascal original, a principios de la década de 1980, funcionó exactamente de esa manera. Fue agradable.)
John R. Strohm
1
Sí, recuerdo que el compilador de optimización de IBM PL / I proporcionaría ocasionalmente sentencias BEGIN y END faltantes, ISTR también proporcionaría puntos y comas faltantes.
TMN
1

El objetivo de un compilador es producir ejecutables que se comporten como se desee. Si un programador escribe algo que no es válido, incluso si el compilador puede adivinar con un 90% de probabilidad lo que se pretendía, generalmente sería mejor requerir que el programador arregle el programa para aclarar la intención, que hacer que el compilador continúe y produzca un ejecutable lo que tendría una posibilidad significativa de ocultar un error.

Por supuesto, los lenguajes generalmente deben diseñarse de modo que el código que expresa claramente la intención sea legal, y el código que no expresa claramente la intención debería estar prohibido, pero eso no significa que lo sean. Considere el siguiente código [Java o C #]

const double oneTenth = 0.1;
const float  oneTenthF = 0.1f;
...
float f1 = oneTenth;
double d1 = oneTenthF;

f1Sería útil que un compilador agregue un tipo de letra implícito para la asignación , ya que solo hay una cosa lógica que el programador podría querer f1contener (el floatvalor más cercano a 1/10). Sin embargo, en lugar de alentar a los compiladores a aceptar programas inadecuados, sería mejor que la especificación permitiera conversiones implícitas de doble a flotante en algunos contextos. Por otro lado, la asignación de d1puede o no ser lo que el programador realmente pretendía, pero no hay una regla de lenguaje que lo prohíba.

Los peores tipos de reglas de lenguaje son aquellos en los que los compiladores harán inferencias en casos en los que algo no podría compilarse legítimamente de otra manera, pero donde un programa podría ser "accidentalmente" válido en un caso donde se pretendía hacer una inferencia. Muchas situaciones que involucran el final implícito de la declaración entran en esta categoría. Si un programador que tiene la intención de escribir dos declaraciones separadas omite un terminador de declaración, un compilador generalmente puede inferir el límite de la declaración, pero ocasionalmente puede considerar como una declaración algo que se suponía que debía procesarse como dos.

Super gato
fuente
0

Los errores de sintaxis son especialmente difíciles de corregir. Tomemos el caso de un derecho perdido ): sabemos que podemos reparar el código insertando uno, pero generalmente hay muchos lugares donde podríamos insertar uno y obtener un programa sintácticamente correcto.

Un punto mucho más fácil son los identificadores mal escritos (pero tenga en cuenta que esto no son errores de sintaxis). Se puede calcular la distancia de edición entre el identificador irresoluble y todos los identificadores en el alcance, y al reemplazar la palabra irresoluble por la que el usuario probablemente quiso decir, se obtendría un programa correcto en muchos casos. Sin embargo, resulta que todavía es mejor marcar el error y dejar que el IDE sugiera reemplazos válidos.

Ingo
fuente
-1

Tal compilador sería simplemente una implementación relajada y no estándar de cualquier idioma que esté compilando.

Rei Miyasaka
fuente
-2

Se ha probado varias veces, pero a menudo no logró el efecto deseado: piense en HAL 9000 o GlaDOS.

cbrandolino
fuente
-3

En C, no puede pasar matrices por valor, sin embargo, el compilador le permite escribir:

void foo(int array[10]);

que luego se reescribe en silencio como:

void foo(int* array);

¿Qué tan estúpido es eso? Preferiría un error difícil aquí en lugar de una reescritura silenciosa, porque esta regla especial ha llevado a muchos programadores a creer que las matrices y los punteros son básicamente lo mismo. Ellos no son.

flujo libre
fuente