¿Qué es exactamente un lenguaje de programación? ¿Qué nos permite escribir en ese idioma?

26

Bien, soy nuevo en programación y admito que esta es una pregunta bastante abstracta.

El lenguaje natural que hablamos todos los días existe porque las personas pueden entenderse entre sí. ¿Cómo pueden las computadoras entender mi código escrito en cierto idioma?

Digamos que el Sr. A crea un nuevo lenguaje. ¿Cómo es eso aceptado por las máquinas? ¿Debe el creador comunicarse con la máquina utilizando lenguaje de máquina para crear un nuevo idioma? ¿Qué garantiza que podamos escribir en un idioma mientras la máquina nos entiende?

Erica Xu
fuente
1
¿Qué nos permite escribir en ese idioma? - "Cerebros: ¡el nuevo relleno de cabeza de maravilla!" - Spike Milligan.
Stephen C
66
Un poco amplio, pero una buena pregunta, no obstante. Demasiadas personas simplemente usan idiomas sin preguntarse cómo funcionan. Qué bueno que tengas curiosidad.
Riwalk
44
Esta es una pregunta de referencia general , fácil y trivialmente respondida por Wikipedia .
Aaronaught

Respuestas:

39

Puede resumir casi toda la respuesta a su conjunto de preguntas con la palabra "compilador" . Un compilador es un programa especial cuya función es tomar el código fuente como entrada, aplicar las reglas de idioma determinadas por el diseñador del lenguaje para descubrir qué significa el código y producir código con el mismo significado en otro idioma como salida. Generalmente es código de máquina o alguna forma de bytecode (el "código de máquina" para máquinas virtuales), aunque existen compiladores especializados que traducen código a otros lenguajes de alto nivel. Sin embargo, están más allá del alcance de esta pregunta.

No todos los idiomas tienen un compilador. Algunos de ellos tienen un intérprete , que hace las mismas cosas que hace un compilador, excepto que en lugar de producir código de máquina después de determinar lo que significa el programa, simplemente ejecuta el programa inmediatamente. Pero los principios básicos de analizar (leer) el código y determinar lo que significa son los mismos.

Responder más a fondo que esto entraría en la teoría del compilador, que es un tema muy amplio. Si está interesado en el tema, debe comenzar leyendo el artículo de Wikipedia para el "compilador" y verificando los enlaces, y si tiene preguntas específicas, no dude en preguntarlas aquí.

Mason Wheeler
fuente
11
+1 - También agregaría que cuando está escribiendo un nuevo idioma, tiene que escribir el compilador o el intérprete en otro idioma. Las versiones posteriores del compilador o intérprete pueden escribirse en versiones anteriores del lenguaje y compilarse con el compilador anterior. El primer ensamblador fue escrito en código máquina. La primera compilador C fue escrito en el montaje (lo más probable), etc.
de Scott Whitlock
1
Cambiaría la definición de compilador. No todos emiten código de máquina. Especialmente hoy en día con tantos compiladores que emiten "código intermedio", como MSIL. ¡Incluso hay compiladores que emiten JavaScript!
Neil N
3
Dudaría en afirmar que los compiladores producen código máquina por definición, incluso cuando se lo explican a un principiante. Es como decir que las funciones devuelven números reales, una simplificación excesiva sin sentido. Toda la construcción del compilador se cumple cuando se produce código que no es para una computadora realmente construida a partir de silicio, sino que solo se define de manera abstracta (ya sea una VM o un lenguaje de alto nivel; hay una razón por la cual se dice que el estándar C define una máquina abstracta , y hay es un compilador desde el LLVM IR de muy bajo nivel hasta el maldito JavaScript). Los principiantes necesitan obtener eso, cuanto antes mejor.
2
La simplificación que utilizan la mayoría de los libros de compilación es que un compilador aplica reglas de idioma para convertir de un idioma de origen a un idioma de destino como salida. (No es raro compilar en C, por ejemplo, especialmente para un curso introductorio).
JasonTrue
44
@delnan, aún más: cada idioma es un código de máquina , para su propia máquina abstracta. No importa qué tan alto sea el idioma.
SK-logic
11

Como señaló, los humanos se comunican entre sí a través de un lenguaje "natural" como el inglés, el francés, el alemán. Se llaman naturales porque los adquirimos naturalmente en lugar de inventarlos intencionalmente (el esperanto es una excepción).

Un lenguaje formal es uno inventado para un propósito u otro. Un lenguaje de programación como C, por ejemplo, es un lenguaje formal inventado con el propósito de programar computadoras.

Todos los idiomas se pueden describir usando una gramática. Noam Chomsky describió una jerarquía de gramáticas en 1956. Consta de los siguientes niveles:

Gramáticas tipo 0 (gramáticas sin restricciones). Son los más generales y equivalen a una máquina de Turing. Como tal, el problema de decidir si una cadena dada es parte de una gramática sin restricciones es indecidible.

Gramáticas tipo 1 (gramáticas sensibles al contexto). Casi todos los idiomas naturales como el inglés son sensibles al contexto. Un ejemplo de sensibilidad al contexto en inglés son las dos frases: "El tiempo vuela como una flecha". y "La fruta vuela como un plátano". En general, es difícil para las computadoras entender lenguajes sensibles al contexto.

Gramáticas tipo 2 (sin contexto). Los lenguajes sin contexto son la base teórica para la sintaxis de la mayoría de los lenguajes de programación.

Gramáticas tipo 3 (gramáticas regulares). La familia de idiomas regulares se puede obtener mediante expresiones regulares. Los lenguajes regulares se usan comúnmente para definir patrones de búsqueda y la estructura léxica de los lenguajes de programación.

Las gramáticas tipo 2 (sin contexto) y tipo 3 (regular) son más frecuentes en las computadoras porque los analizadores pueden implementarse de manera eficiente.

BNF (Backus Normal Form o Backus – Naur Form) es una técnica de notación para gramáticas libres de contexto, a menudo utilizada para describir la sintaxis de los lenguajes utilizados en informática.

Por ejemplo, un identificador podría describirse como:

<identifier> ::= <letter> { <letter> | <digit> }

lo que significa que debe comenzar con una letra y puede contener letras o dígitos adicionales.

Anteriormente, una letra se define como 'a' | 'b' | 'c', etc., y el dígito se define como '0' a '9' usando el mismo tipo de notación.

La declaración "for" de CA puede definirse como:

 <for_statement> ::=
    'for' '(' <expression> ';' <expression> ';' <expression> ')' <statement> 

Los analizadores y analizadores léxicos (las primeras etapas de un compilador o intérprete) se construyen para aceptar la gramática específica descrita por el BNF para un idioma en particular. Los analizadores léxicos se usan generalmente para separar los diversos tokens de un idioma (como una palabra clave, un identificador o un número), y el analizador se usa para descubrir cómo funcionan juntos los tokens, como cómo se construye una declaración "for" .

tcrosley
fuente
+1 gran redacción. Pero no me sorprende que esto no haya sido aceptado como respuesta. Esto es lo que pensé que OP estaba preguntando, pero según la respuesta que eligieron, parece que querían algo de un nivel mucho más alto.
Matthew Rodatus
5

Primero, definamos "lenguaje" en términos de lo que es. El lenguaje requiere primero un vocabulario (una lista de palabras que definen conceptos que son los objetos de comunicación), y luego una sintaxis (un "manual" o conjunto de reglas que definen la estructura de la comunicación).

En este nivel más básico, C # no es tan diferente del inglés. Lo que hace de C # un "lenguaje de programación" es su intención y, por lo tanto, su diseño; Está diseñado para ser digerido en comandos individuales de bajo nivel. Como tal, el vocabulario predefinido es limitado, la sintaxis se aplica de manera muy rígida y todo el lenguaje está diseñado para ser consumido de una manera predefinida muy conocida por su "audiencia" (la computadora; más exactamente el compilador, que asimilará el código fuente en un "lenguaje intermedio" de comandos simples que luego se pueden traducir al código de máquina por el "tiempo de ejecución"). No escribes prosa o poesía en C #; usted le dice a la computadora que haga un trabajo de la manera más inequívoca posible.

Para las computadoras, sí, se necesita una herramienta, generalmente llamada compilador, para tomar lo que escribes en el código y convertirlo a las instrucciones que la computadora puede usar. La informática, como la mayoría de la tecnología, es un proceso inherentemente iterativo, "en capas". Cuando se inventaron las computadoras, se programaron ingresando manualmente las instrucciones binarias. Esas instrucciones se estandarizaron para cada procesador en "códigos de máquina" hexadecimales; la diferencia está solo en cómo se agrupan los dígitos binarios para mostrarlos a los humanos. Luego, en el código ensamblador, la lista de comandos y algunos identificadores básicos como nombres de registro fueron sustituidos por sus códigos hexadecimales al escribir programas; ASM todavía se puede convertir 1: 1 en código de máquina nativo. El salto cuántico fue a la programación "imperativa" de tercera generación, que básicamente toma conceptos abstractos más comprensibles para los humanos, como variables y bucles lógicos, y los digiere en las instrucciones nativas, usando patrones basados ​​en palabras clave y sintaxis. Los primeros lenguajes como COBOL, FORTRAN, Pascal y C aún pueden ser "traducidos" por un humano a un lenguaje de máquina particular (generalmente 8086 ASM). Luego vino la revolución de la programación orientada a objetos, que son básicamente reglas de sintaxis adicionales que definen el código como encapsulado conceptualmente en "objetos" que tienen alguna combinación de estado y lógica. por un humano en un lenguaje de máquina particular (usualmente 8086 ASM). Luego vino la revolución de la programación orientada a objetos, que son básicamente reglas de sintaxis adicionales que definen el código como encapsulado conceptualmente en "objetos" que tienen alguna combinación de estado y lógica. por un humano en un lenguaje de máquina particular (usualmente 8086 ASM). Luego vino la revolución de la programación orientada a objetos, que son básicamente reglas de sintaxis adicionales que definen el código como encapsulado conceptualmente en "objetos" que tienen alguna combinación de estado y lógica.

Hoy en día, estamos bien en la "cuarta generación" de idiomas, que son idiomas escritos para definir la comunicación con otros programas en lugar de directamente a la máquina. Ampliamente definido, esto incluye lenguajes de "marcado" como XML / HTML, lenguajes de "scripting" como JavaScript y SQL, y la mayoría de los lenguajes de "sandbox" como Java y .NET Framework (que compila en un IL que luego es interpretado por un tiempo de ejecución que abstrae detalles específicos de la máquina y la plataforma). También se podría decir que abarca el ámbito de los lenguajes de programación funcionales, que HEAVILMENTE dependen de un tiempo de ejecución para proporcionar abstracción no solo de detalles específicos de la máquina, sino también de detalles específicos de la operación. Estos lenguajes de cuarta generación son más o menos inviables para que un humano los traduzca a instrucciones de máquinas nativas, y el punto es que no sería un esfuerzo que valga la pena; La fuerza de estos lenguajes es el proceso por capas en el que se utilizan para decirle a una computadora qué hacer en los niveles bajos.

KeithS
fuente
Gracias. Tengo un vistazo a la historia de la evolución del lenguaje de programación.
Erica Xu
2
@KeithS: es posible que desee volver a formatear el último párrafo para que sea un poco más legible.
Ivan Vučica
4

Es una buena pregunta. Una respuesta adecuada forma una buena mitad de lo que se llama "Ciencias de la Computación".

Para empezar, recomendaría hojear la semántica operacional y denotacional , y luego leer este libro . Le dará una comprensión más o menos sólida de lo que es el lenguaje de programación y cómo se puede definir formalmente.

Si lo anterior es demasiado académico, puede comenzar con Petzold, "Código" , y luego volver a la semántica.

SK-logic
fuente
1
¿Realmente esperas que un novato de 18 años lea alguna teoría pesada solo para responder esta pregunta?
Trabajo
2
@Job, según su pregunta anterior, está recibiendo dosis de Scheme (y, presumiblemente, SICP) en la universidad. Debería estar bien con un poco de semántica entonces. De todos modos, no hay una respuesta adecuada a esta pregunta sin una teoría sólida.
SK-logic
+1 por mencionar "Código". Ese libro debe ser leído para cada estudiante de CS de nivel de entrada.
Daniel Pryden
4

Si escribe un programa en un lenguaje de programación, un programa diferente convertirá los símbolos de su programa en símbolos que la computadora entienda. A veces esto lleva varios pasos. Por ejemplo en C:

  1. El usuario escribe el programa en lenguaje de alto nivel (C) que la CPU no comprende, pero el programador lo entiende directamente (¡esperamos!).

  2. El compilador convierte C en lenguaje Assmebly, que la CPU no entiende directamente pero que es fácil de convertir en algo más.

  3. Assempler convierte el ensamblaje en una secuencia de códigos binarios que la CPU entiende directamente. Algunos compiladores omiten el paso anterior (paso 2) y producen el binario compilado directamente desde el código fuente.

Para garantizar que la computadora comprenda su programa, el compilador o el intérprete le darán un error y generalmente se detendrán si encuentra algo que no es compilable, como un error de sintaxis. Si su programa no puede compilarse, nunca podrá llegar a la etapa en la que su programa intentará ejecutarlo y fallará porque no lo "entendió".

Para crear un nuevo idioma, primero debe diseñar su idioma de alto nivel y luego debe encontrar una manera de asignar los símbolos de su nuevo idioma a los comandos del lenguaje ensamblador que su CPU entiende.

FrustratedWithFormsDesigner
fuente
2
Realmente no; Los compiladores modernos no hacen el paso 2 y solo producen código binario directamente. Pero el ensamblaje y el código binario son casi equivalentes de todos modos; Puede desmontar (convertir el código binario de nuevo al ensamblaje) con muy alta fidelidad
MSalters