2010-08-19 16 views
15

Así que estoy leyendo esta entrevista con Walter brillante sobre la lengua D en modo bit (http://www.bitwisemag.com/copy/programming/d/interview/d_programming_language.html), y me encuentro con esta cita muy interesante sobre el lenguaje de análisis:Uso de Walter Bright de la palabra "redundancia" ... o "¿Qué diablos significa eso?"

Desde una perspectiva teórica, sin embargo, ser capaz de generar un buen diagnóstico requiere que haya redundancia en la sintaxis. La redundancia se usa para adivinar lo que se pretendía, y mientras más redundancia, más probable es que adivinar sea correcta. Es como el idioma inglés: si escribimos mal una palabra de vez en cuando, o si falta una palabra, la redundancia nos permite adivinar correctamente el significado. Si no hay redundancia en un idioma, cualquier secuencia aleatoria de caracteres es un programa válido.

Y ahora estoy tratando de averiguar qué diablos quiere decir cuando dice "redundancia".

Apenas puedo entender la última parte, donde menciona que es posible tener un lenguaje en el que "cualquier secuencia aleatoria de caracteres sea un programa válido". Me enseñaron que hay tres tipos de errores: sintáctico, de tiempo de ejecución y semántico. ¿Hay idiomas en los que los únicos errores posibles son semánticos? Es asamblea así? ¿Qué pasa con el código de máquina?

+1

Supongo que está hablando de sintaxis aquí. El código de máquina es probablemente muy cercano a lo que él está hablando. Cualquier cadena de operaciones de código de máquina válidas es una sintaxis válida. –

+0

Depende de qué conjunto de instrucciones. Algunos ciertamente tienen instrucciones ilegales, que a menudo causan una trampa. –

+0

Pero eso es como usar caracteres no válidos de un conjunto de caracteres en un script, no es realmente un problema de sintaxis. Si limita el conjunto de caracteres de entrada a operaciones de código de máquina válidas, puede colocarlos en cualquier orden y tiene un programa válido (en lo que respecta a la sintaxis del idioma). Entonces este lenguaje no tiene redundancia. –

Respuesta

9

lenguaje ensamblador (idiomas más de montaje, de todos modos) no es así en absoluto - que tienen una sintaxis muy rígida, y lo más aleatoria las cadenas serían diagnosticadas como errores.

El código de la máquina está mucho más cerca. Como no hay traducción del código de "fuente" a "objeto" involucrado, todos los errores son semánticos, no sintácticos. La mayoría de los procesadores tienen varias entradas que rechazarían (por ejemplo, ejecutar una interrupción/interrupción del "código de operación malo"). Podría argumentar que en algunos casos esto sería sintáctico (por ejemplo, un código de operación que no se reconoció en absoluto) mientras que otros son semánticos (por ejemplo, un conjunto de operandos que no se permitieron para esa instrucción).

Para aquellos que lo recuerdan, TECO era famoso (¿notorio?) Por asignar algún significado a casi cualquier entrada posible, así que era más o menos de la misma manera. Un reto interesante fue averiguar qué pasaría si escribía (por ejemplo) su nombre.

+2

Re. TECO: hay un desafío similar que implica predecir el efecto de mantener presionado Control o Meta y escribir su nombre en Emacs. –

+0

+1 por traerlo a la vieja escuela. Gracias, este fue el tipo de cosas que me preguntaba. – tel

+0

¿Tiene un enlace TECO? – BCS

3

Significa que la sintaxis contiene más información de la necesaria para codificar un programa en funcionamiento. Un ejemplo son los prototipos de funciones. Como K & R C nos muestra, son redundantes porque el compilador puede simplemente dejar que la persona que llama presione cualquier argumento que desee, luego deje que la función revele los argumentos correctos. Pero C++ y otros lenguajes los obligan, porque ayudan al compilador a verificar que está llamando a la función de la manera correcta.

Otro ejemplo es el requisito de declarar variables antes de usarlas. Algunos idiomas tienen esto, mientras que otros no. Es claramente redundante, pero a menudo ayuda a prevenir errores (por ejemplo, errores ortográficos, al usar una variable que se ha eliminado).

+0

Básicamente correcto, aunque el ejemplo no es el mejor: los encabezados solo "ayudan" al compilador, ya que hacen que los compiladores de un solo pase sean posibles (porque las referencias hacia adelante están prohibidas). – delnan

+0

@delnan, no sigo. En C, sin encabezados, el compilador no puede verificar su llamada de función en absoluto. En el mejor de los casos, obtendrá un error de enlazador. La información redundante en los encabezados permite al compilador proteger al programador de ciertos errores. –

+0

Declaraciones a futuro! = Encabezados. Las declaraciones directas hacen posibles los compiladores de un solo paso. Los encabezados hacen posible la compilación por separado cuando la información del tipo no forma parte del formato de archivo del objeto. – dan04

7

Bueno, para usar un ejemplo de C# (ya que no sé D). Si usted tiene una clase con un método abstracto, la clase en sí debe ser marcada abstracta:

public abstract class MyClass 
{ 
    public abstract MyFunc(); 
} 

Ahora, sería trivial para el compilador para marcar automáticamente MiClase tan abstracto (que es la forma en C++ lo maneja), pero en C#, debes hacerlo explícitamente, para que tus intenciones sean claras.

De manera similar con los métodos virtual. En C++, si se declara virtual en una clase base, un método es automáticamente virtual en todas las clases derivadas. En C#, el método debe sin embargo ser explícitamente marcado override, por lo que no hay confusión sobre lo que quería.

+0

Pero estos ejemplos no ayudan al analizador/analizador para dar más información, ¿verdad? Quiero decir que sabe exactamente lo mismo en ambos casos y que podría responder exactamente de la misma manera. –

+0

El compilador sabe qué * it * piensa que significa el código; no sabe qué * * piensas que significa el código. –

+0

Lo siento, lo que digo es esto: si implementa una subclase de MyClass y no implementa MyFunc, el compilador le puede decir en ambos casos exactamente lo que está mal: no implementó un método abstracto. Si intenta crear una instancia de MyClass, el compilador puede decirle exactamente lo que está mal: MyClass es abstracto (incluso puede decir "debido a que MyFunc es abstracto"). La redundancia aquí no tiene nada que ver con lo que Bright estaba hablando: análisis/compilación de pistas y comunicación de vuelta al usuario. Es solo redundancia para aquellos que miran el código que es diferente. –

8

nclds nglsh ll SRTS de ltrs XTR t mk que Esd T Leer

+0

Muy buen ejemplo :) –

+8

De hecho, es psíquico para aprender todo menos los fites y látigos de un wrod y raiten en lseat smoe snsee. Y dha rizn fonetisaizd ingglish haznt cot on iz dhat not missly mor difikalt tu rid widhaut dha vizhual kyuz uv dha kurent orthografi. –

23

Me centraré en por qué (creo) Walther Bright piensa que la redunidad es buena. Tomemos XML como ejemplo. Este fragmento:

<foo>...</foo> 

tiene redunancy, la etiqueta de cierre es redunant si usamos S-expresiones en su lugar:

(foo ...) 

Es más corto, y el programador no tiene que escribir foo más a menudo que lo necesite para darle sentido a ese fragmento. Menos redunancy. Pero tiene desventajas, como un ejemplo de http://www.prescod.net/xml/sexprs.html muestra:

(document author: "[email protected]" 
    (para "This is a paragraph " (footnote "(better than the one under there)" ".") 
    (para "Ha! I made you say \"underwear\".")) 


<document author="[email protected]"> 
<para>This is a paragraph <footnote>(just a little one).</para> 
<para>Ha! I made you say "underwear".</para> 
</document> 

En tanto, la etiqueta de final/a Paréntesis de cierre de la nota no se encuentra. La versión xml no es válida en cuanto el analizador ve </para>. El S-Expression uno solo es inválido al final del documento, y solo si no tiene una cuenta de cierre innecesaria en otro lugar. Entonces, la redunidad ayuda, en algunos casos, a entender lo que el escritor quiso decir (y señalar los errores en su forma de expresar eso).

+0

Gracias por la respuesta muy completa. ¿Sabes dónde podría comenzar a buscar una discusión más técnica/teórica sobre cómo los analizadores realmente implementan este tipo de cosas? Supongo que es bastante fácil descubrir cómo el analizador XML identificaría específicamente el error cuando vea cuando esperaba, pero, en general, ¿cómo buscan los analizadores la columna, la fila y el tipo de error? ¿Hay como una "Teoría general de manejo de errores para Dummies"? – tel

+0

Por lo que se sabe, no existe una "Teoría general del manejo de errores". Parece ser más un arte. – BCS

+0

Estoy de acuerdo con BCS, no creo que exista tal cosa. Pero supongo que (algunos de) los recursos de compilación habituales (la mayoría de los cuales se centran principalmente en la interfaz, es decir, el analizador) incluyen * una * forma de hacerlo. – delnan

2

Creo que un mejor ejemplo de redundancia es algo así como int a[10] =. En este punto, el compilador sabe qué debe venir a continuación, un inicializador de matriz int, y puede generar un mensaje de error apropiado si lo que sigue no es un inicializador de matriz int. Si la sintaxis del lenguaje decía que cualquier cosa podría seguir a int a[10], sería mucho más difícil para el compilador resolver los problemas con una.

4

Creo que hablaba de estructuras sintácticas en el lenguaje y de cómo se pueden interpretar. Como ejemplo, considere la humilde declaración "si", traducida en varios idiomas.

En bash (shell script), que se parece a esto:

if [ cond ]; then 
    stmts; 
elif [ other_cond ]; then 
    other_stmts; 
else 
    other_other_stmts; 
fi 

en C (w/statments individuales, no hay llaves):

if (cond) 
    stmt; 
else if (other_cond) 
    other_stmt; 
else 
    other_other_stmt; 

se puede ver que en bash, hay mucha más estructura sintáctica en la instrucción if que en C. De hecho, todas las estructuras de control en bash tienen sus propios delimitadores de cierre (por ejemplo, if/then/fi, for/do/done, case/in/esac, ...), mientras que en C la llave es usado en todas partes Estos delimitadores únicos eliminan la ambigüedad del significado del código y, por lo tanto, proporcionan un contexto desde el cual el intérprete/compilador puede diagnosticar las condiciones de error e informarlas al usuario.

Sin embargo, hay una compensación. Los programadores generalmente prefieren la sintaxis corta (a la C, Lisp, etc.) a la sintaxis detallada (a la Pascal, Ada, etc.). Sin embargo, también prefieren los mensajes de error descriptivos que contienen números de línea/columna y resoluciones sugeridas. Estos objetivos, por supuesto, están en desacuerdo entre ellos: no puede tener su pastel y comérselo también (al menos, manteniendo la implementación interna del compilador/intérprete simple).

+3

Es bastante bueno pensar en todos estos intercambios de diseño que subyacen al diseño y la sintaxis de todos estos idiomas. Realmente te hace darte cuenta de que para descartar aspectos de un lenguaje, como, por ejemplo, su elección de sintaxis, como arbitraria o simplemente una función de "estilo" es algo ingenuo. Todas estas elecciones se hicieron conscientemente y (supongo que al menos en el caso de los buenos lenguajes) de manera racional. Esta idea de que hay compensaciones entre todos estos objetivos conflictivos también ayuda a explicar por qué hay más de 1000 idiomas disponibles :) – tel

+1

También hay 'while; do; done'. No creo que sea realmente por diseño tampoco; solo un artefacto de sh tradicional. Y luego, por supuesto, está Java, con identificadores increíblemente detallados y un puñado de llaves. –

+0

@tc: De acuerdo - No quise dar a entender que se había hecho a propósito para introducir redundancia, solo que había tenido ese efecto. Sinceramente, me siento un poco culpable eligiendo sh/bash para la redundancia dada su concisión habitual (variables especiales de un personaje, etc.). Era solo un ejemplo obvio de una versión detallada de una construcción (if/else) que se puede expresar de manera más sucinta (menos redundante) en otro idioma. –

0

luego cualquier secuencia aleatoria de caracteres es un programa válido.

Aunque no todo "cualquier secuencia aleatoria es válida", considere Perl y expresiones regulares. Su sintaxis muy breve facilita que los caracteres no válidos pasen el análisis sintáctico y semántico.

Cuestiones relacionadas