Cuando alguien escribe un nuevo lenguaje de programación, ¿en qué lo escriben?

162

Por favor disculpe mi ignorancia. Estoy incursionando en PHP y mojándome los pies navegando SO, y me siento obligado a hacer una pregunta que me he estado preguntando durante años:

Cuando escribes un lenguaje de programación completamente nuevo, ¿en qué lo escribes ?

Esto probablemente les parezca realmente tonto a todos los programadores, por quienes tengo un gran respeto, pero para mí es algo desconcertante. ¿Qué haces? Dígase a sí mismo ¡ Hoy voy a inventar un nuevo idioma! y luego disparar ... ¿Bloc de notas? ¿Están todos los compiladores construidos en lenguajes previamente existentes, de tal manera que uno pudiera molestar a uno podría trazar todos los lenguajes de programación jamás ideados en un árbol de ramificación monstruoso que eventualmente se convirtió en ... No sé, algo viejo?

Con mi débil intelecto, esto me parece fascinante ... ¡Por favor, edúcame!

Dibujó
fuente

Respuestas:

193

No es una pregunta estúpida. Es una excelente pregunta.

Como ya se respondió, la respuesta corta es: "Otro idioma".

Bueno, eso lleva a algunas preguntas interesantes? ¿Qué pasa si es el primer idioma escrito para su pieza de hardware en particular? Un problema muy real para las personas que trabajan en dispositivos integrados. Como ya respondió "un idioma en otra computadora". De hecho, algunos dispositivos integrados nunca obtendrán un compilador, sus programas siempre se compilarán en una computadora diferente.

Pero puedes retrasarlo aún más. ¿Qué pasa con los primeros programas escritos?

Bueno, los primeros compiladores para "lenguajes de alto nivel" se habrían escrito en lo que se llama "lenguaje ensamblador". El lenguaje ensamblador es un lenguaje en el que cada instrucción en el idioma corresponde a una sola instrucción para la CPU. Su lenguaje de muy bajo nivel y extremadamente detallado y muy laborioso para escribir.

Pero incluso escribir lenguaje ensamblador requiere un programa llamado ensamblador para convertir el lenguaje ensamblador en "lenguaje máquina". Volvemos más lejos. Los primeros ensambladores se escribieron en "código de máquina". Un programa que consiste completamente en números binarios que son una correspondencia directa uno a uno con el lenguaje en bruto de la computadora misma.

Pero todavía no termina. Incluso un archivo con números apenas primas en que todavía necesita traducción. Aún necesita obtener esos números en bruto en un archivo en la computadora.

Bueno, lo creas o no, las primeras computadoras tenían una fila de interruptores en la parte delantera. Volteó los interruptores hasta que representaban un número binario, luego presionó otro interruptor y ese cargó ese número en la memoria de la computadora. Luego siguió moviendo el interruptor hasta que cargó un programa de computadora mínimo que podía leer programas de archivos de disco o tarjetas perforadas. Presionó otro interruptor e inició la ejecución del programa. Cuando fui a la universidad en los años 80, vi computadoras que tenían esa capacidad pero nunca se les dio la tarea de cargar un programa con los interruptores.

¡E incluso antes de eso, los programas de computadora tenían que estar conectados con tableros de enchufes !

Mateo
fuente
20
+1, creo que esta respuesta realmente encaja con el espíritu de la pregunta.
stderr
30
Una vez tomé una clase de Assembler II y el profesor me preguntó por qué elegimos la optativa. Fui por la divertida respuesta: "porque quería una A fácil". Pensé que tenía la mejor respuesta, pero teníamos una planta de Honeywell en la ciudad y el siguiente tipo dijo: "Escribo microcódigo todo el día y quería aprender un idioma de alto nivel".
T.Rob
3
Recomiendo encarecidamente el Código: El lenguaje oculto del hardware y software de la computadora . Esencialmente cubre el mismo material que esta respuesta, desde tubos de vacío hasta compiladores para lenguajes de alto nivel.
MatrixFrog
Las computadoras han evolucionado igual que los seres humanos, aunque en una cantidad de tiempo relativamente infinitesimal.
Gaurav Ojha
Ahora, este será un comentario no constructivo, pero tiene que ser escrito ... esta es una respuesta brillante brillante en todas las formas, formas e información :-)
Lukáš Řádek
23

La respuesta más común es C. La mayoría de los lenguajes se implementan en C o en un híbrido de C con devoluciones de llamada y un "lexer" como Flex y un generador de analizadores sintácticos como YACC . Estos son idiomas que se utilizan para un propósito: describir la sintaxis de otro idioma. A veces, cuando se trata de lenguajes compilados, primero se implementan en C. Luego, la primera versión del lenguaje se usa para crear una nueva versión, y así sucesivamente. (Como Haskell )

Prof. Falken
fuente
1
Algunos idiomas están escritos en ensamblador, como picolisp. ( blog.kowalczyk.info/article/picoLisp-Arc-before-Arc.html )
Prof. Falken el
1
¿Qué pasa con los programas lex / yacc (flex / bison)? ¿Se consideran estos suplementos para crear lenguajes en C?
Dave
1
¿Tienes algo para demostrar que la respuesta más común es C?
RichardOD
Empecé a revisar la lista aquí: google.com/Top/Computers/Programming/Languages/Open_Source. Luego, accidentalmente cerré la ventana de mi editor en el idioma 10 y perdí la motivación. De todos modos, aproximadamente la mitad hasta ahora se implementaron en C y el resto en su mayor parte se iniciaron para sí mismos.
Prof. Falken
3
Creo que tienes que mencionar Lex / Yacc (o alternativas). En general, uno no comienza a escribir un lenguaje en C, sino con un lexer y un analizador que luego son compatibles con el código C.
Steve Rowe
14

Muchos idiomas tienen bootstrap, eso está escrito en sí mismos . En cuanto a por qué querrías hacer esto, a menudo es una buena idea comer tu propia comida para perros .

El artículo de wikipedia al que me refiero discute el tema del huevo y la gallina . Creo que lo encontrarás bastante interesante.

RichardOD
fuente
55
Lo cual no es posible cuando recién estás comenzando.
Michael Borgwardt
1
Si obviamente. Pero muchos idiomas se escriben de esta manera una vez que es posible. Quería señalar esto como nadie más lo había hecho, y siento que es un punto importante.
RichardOD
+1 por usar el término bootstrap. Es interesante que tengas que compilar tu compilador dos veces. Obviamente, la primera vez es con el compilador básico que tiene y la segunda vez con el compilador que acaba de construir. Digamos que agregó optimización a su compilador. El compilador que construyó puede producir código con esas optimizaciones, pero no está ejecutando el código optimizado hasta que lo vuelva a compilar con el compilador de optimización.
Les
@ Les- Sí bootstrapping es un concepto interesante.
RichardOD
2
Comentario al azar aquí. La respuesta a la antigua pregunta sobre quién vino primero (pollo o huevo) es que el pollo vino primero. La razón es que para reproducir / replicar algo, primero debe tener el reproductor / replicador ya en su lugar para hacer la reproducción / replicación.
SpicyWeenie
10

Prácticamente cualquier lenguaje, aunque usar uno adecuado para trabajar con gráficos y otras estructuras de datos complejas facilitará muchas cosas. Los compiladores de producción a menudo se escriben en C o C ++ por razones de rendimiento, pero los lenguajes como OCaml, SML, Prolog y Lisp son posiblemente mejores para la creación de prototipos del lenguaje.

También hay varios "pequeños idiomas" utilizados en el diseño de idiomas. Lex y yacc se utilizan para especificar la sintaxis y las gramáticas, por ejemplo, y se compilan en C. (Hay puertos para otros idiomas, como ocamllex / ocamlyacc y muchas otras herramientas similares).

Como caso especial, los nuevos dialectos de Lisp a menudo se basan en implementaciones de Lisp existentes, ya que pueden aprovechar la mayor parte de la misma infraestructura. Escribir un intérprete de Scheme se puede hacer en Scheme en una página de código, momento en el cual se pueden agregar fácilmente nuevas funciones.

Básicamente, los compiladores son solo programas que leen algo y lo traducen a otra cosa: convertir la fuente LaTeX a DVI, convertir el código C a ensamblado y luego a lenguaje de máquina, convertir una especificación gramatical a código C para un analizador, etc. Su diseñador especifica la estructura del formato de origen (análisis), qué significan esas estructuras, cómo simplificar los datos (optimización) y el tipo de salida a generar. Los intérpretes leen la fuente y la ejecutan directamente. (Los intérpretes suelen ser más simples de escribir, pero mucho más lentos).

silentbicycle
fuente
4

En realidad, puedes escribir en casi cualquier idioma que desees. No hay nada que te impida escribir un compilador de C en Ruby. "Todo" que tiene que hacer es analizar el programa y emitir el código de máquina correspondiente. Si puede leer / escribir archivos, su lenguaje de programación probablemente será suficiente.

Si está comenzando desde cero en una nueva plataforma, puede hacer una compilación cruzada: escriba un compilador para su nueva plataforma, que se ejecute en Java o de forma nativa en x86. Desarrolle en su PC y luego transfiera el programa a su nueva plataforma de destino.

Los compiladores más básicos son probablemente Assembler y C.

ziggystar
fuente
Sin embargo, este "cualquier" lenguaje debería admitir llamadas recursivas. De lo contrario, implementar un analizador de sintaxis y un analizador será un verdadero desafío.
2
Si selecciona un idioma inadecuado para una tarea, es su culpa. Esto puede suceder para cualquier proyecto, no solo para compiladores / intérpretes.
ziggystar
4

"Escribir un nuevo lenguaje de programación" técnicamente no implica ningún código. Acaba de llegar a una especificación de cómo se ve su idioma y cómo funciona. Una vez que tenga una idea de cómo es su idioma, puede escribir traductores e intérpretes para que su idioma realmente "funcione".

Un traductor ingresa un programa en un idioma y emite un programa equivalente en otro idioma. Un intérprete ingresa un programa en algún idioma y lo ejecuta.

Por ejemplo, un compilador de C generalmente traduce el código fuente de C (el lenguaje de entrada) a un programa de lenguaje ensamblador (el lenguaje de salida). El ensamblador luego toma el programa de lenguaje ensamblador y produce lenguaje de máquina. Una vez que tenga su salida, no necesita los traductores para ejecutar su programa. Como ahora tiene un programa de lenguaje de máquina, la CPU actúa como intérprete.

Muchos idiomas se implementan de manera diferente. Por ejemplo, javaces un traductor que convierte el código fuente de Java a JVM bytecode. La JVM es un intérprete [1] que ejecuta el código de bytes de Java. Después de correr javacy obtener el código de bytes, ya no lo necesita javac. Sin embargo, cada vez que desee ejecutar su programa, necesitará la JVM.

El hecho de que no sea necesario tener en cuenta a los traductores para ejecutar un programa es lo que hace posible "arrancar" su idioma sin tener que terminar ejecutándose "encima de" capas y capas de otros idiomas.

[1] La mayoría de las JVM traducen detrás de escena, pero en realidad no son traductores, ya que la interfaz de la JVM no es "idioma de entrada -> idioma de salida".

Kannan Goundan
fuente
3

En general, puede usar casi cualquier idioma que desee. PHP fue escrito en C, por ejemplo. Si no tiene acceso a ningún compilador, tendrá que recurrir a escribir lenguaje ensamblador y compilarlo en código máquina a mano.

Kaivosukeltaja
fuente
2
No tiene que compilar el código de la máquina. Es el idioma nativo de la CPU por definición.
Stu Thompson
1
Cierto. Lo que quise decir fue "compilar a mano el código de máquina del lenguaje ensamblador o algo similar". Podría estar equivocado, pero supongo que pocas personas simplemente escriben el código como binario / hexadecimal de inmediato.
Kaivosukeltaja
2

Muchos idiomas se escribieron primero en otro idioma disponible y luego se volvieron a implementar en sí mismos y se reiniciaron de esa manera (o simplemente mantuvieron la implementación en el idioma extranjero, como PHP y perl), pero algunos idiomas, como el primer ensamblador, se compilaron manualmente en código de máquina como El primer compilador C fue compilado a mano para ensamblar.

He estado interesado en el bootstrapping desde que lo leí. Para obtener más información, intenté hacerlo yo mismo escribiendo mi propio superconjunto de BF, que llamé EBF , en sí mismo. la primera versión de EBF tenía 3 primitivas adicionales y compilé a mano el primer binario. Encontré un ritmo de dos pasos al hacerlo. Implementé una función en el idioma actual en una versión y tuve una versión dulce donde reescribí el código para utilizar la función implementada. El lenguaje era lo suficientemente expresivo como para ser utilizado para hacer un intérprete de LISP .

Tengo la versión compilada a mano junto con la fuente en la primera etiqueta de lanzamiento y el código es bastante pequeño. La última versión es 12 veces más grande en tamaño y el código y permite un código más compacto, por lo que sería difícil compilar la versión actual a mano.

Edmund Grimley Evans hizo algo similar con su lenguaje HEX

Una de las cosas interesantes de hacerlo usted mismo es que comprende por qué algunas cosas son como son. Mi código fue producto si pequeños ajustes incrementales y parece que ha evolucionado en lugar de haber sido diseñado desde cero. Lo tengo en cuenta al leer el código hoy, que creo que parece un poco extraño.

Sylwester
fuente
1

Por lo general, con un lenguaje de programación de propósito general adecuado para el desarrollo de sistemas, por ejemplo, C, Haskell, ML, Lisp, etc., pero la lista de opciones es larga. Además, generalmente con algunos lenguajes específicos de dominio para la implementación del lenguaje, es decir, generadores de analizadores léxicos y analizadores, lenguajes intermedios como LLVM , etc. Y probablemente algunos scripts de shell, marcos de prueba y un sistema de configuración de compilación, por ejemplo, autoconf.

James Woodyatt
fuente
1

La mayoría de los compiladores eran wriiten C o un programa similar a ac, si no c, entonces ensamblar lang es el camino a seguir. Sin embargo, al escribir un nuevo lang desde cero y no tiene una macro lib o código fuente de un lenguaje prototipo, debe definir sus propias funciones ¿Ahora en qué idioma? Simplemente puede escribir un Formulario "de código fuente llamado psedocode en la máquina, se ve como una gramática bnf de la especificación lang estructurada orientada a objetos, como el algoritmo básico Fortran. Entonces, la imagen que escribe un código cruzado similar a cualquiera de estas sintaxis de lenguaje es código psedo

Chris Anderson
fuente
1
No creo que se suponga que el código psedo sea legible por máquina
Richard Tingle
0

Incluso otras operaciones binarias o de ensamblaje deben traducirse en funciones, es decir, el trabajo de ensambladores / compiladores, luego en objetos, desde datos y funciones, si no tiene un archivo fuente para ver "cómo se debe representar la funcionalidad de estos objetos en su implementación del lenguaje, luego debe reconocer "ver" implementar, o definir sus propias funciones, procedimientos y estructuras de datos, lo que requiere mucho conocimiento, debe preguntarse qué es una función. Su mente se convierte en la simulación del lenguaje. Esto separa un programador maestro del resto.

usuario3093481
fuente
0

Yo también tuve esta pregunta hace unos meses. Y leí algunos artículos y vi algunos videos que me ayudaron a comenzar a escribir mi propio idioma llamado soft. Todavía no está completo, pero aprendí muchas cosas de este viaje.

Lo básico que debe saber es cómo funciona el compilador cuando tiene que ejecutar un fragmento de código. El compilador tiene muchas fases como análisis léxico, analizador semántico, AST (Árbol de sintaxis abstracta), etc.

Lo que hice en mi nuevo idioma se puede encontrar aquí: http://www.singhajit.com/writing-a-new-programming-language/

Si está escribiendo un idioma por primera vez, todo lo mejor y tiene un largo camino por recorrer.

Ajit Singh
fuente
0

¿Qué son los lenguajes de programación en general?

los lenguajes de programación son solo una forma de hablar con las computadoras. en términos generales al principio porque las computadoras solo podían entender ceros y unos (debido al hecho de que las computadoras están hechas de transistores como interruptores que solo podían tomar dos estados, llamamos a estos dos estados 0 y 1) y trabajar con 0,1 fue difícil para nosotros, como humanos, los informáticos decidieron hacer un mapeo uno a uno de cada instrucción en binario (0,1) a una forma más legible para los humanos, que llamaron lenguaje ensamblador.

por ejemplo si tuviéramos una instrucción como:

11001101

en asamblea se llamaría:

CARGA_A 15

lo que significa que cargue el contenido del registro a en la ubicación de memoria 15. como dije, era solo una convención como elegir 0 y 1 para dos estados de los transistores o cualquier otra cosa en la computadora. De esta manera, tener un programa con 50 instrucciones, recordar el lenguaje ensamblador sería más fácil. entonces el usuario escribiría el código de ensamblaje y algún programa (ensamblador en este caso) traduciría los códigos a instrucciones binarias o lenguaje de máquina como lo llaman.

pero luego, con las computadoras mejorando cada día, había espacio para programas más complicados con más instrucciones, digamos 10000.

en este caso, un mapeo uno a uno como el ensamblaje no funcionaría, por lo que se crearon otros lenguajes de programación de alto nivel. Dijeron, por ejemplo, que si una relación con dispositivos de E / S para imprimir algo en la pantalla creada por el usuario toma alrededor de 80 instrucciones, déjenos hacer algo aquí y podríamos empaquetar todo este código en una biblioteca y llamarlo, por ejemplo, printf y también cree otro programa que podría traducir este printf aquí al código de ensamblaje relacionado y desde allí el ensamblaje haría el resto. entonces lo llaman compilador.

así que ahora cada usuario que quiera imprimir algo en la pantalla no tendría que escribir todas las instrucciones en binario o ensamblado, simplemente escribe printf ("algo") y todos los programas como el compilador y el ensamblador harían el resto. ahora más tarde, otros códigos más largos se empaquetarían de la misma manera para facilitar el trabajo de otras personas, ya que puede simplificar una línea de código de miles en un código en Python y empaquetarla para el uso de otras personas.

así que digamos que ha empaquetado muchos códigos diferentes en python y ha creado un módulo (libray, paquete o cualquier cosa que quiera llamarlo) y llama a ese módulo mgh (solo mi nombre). ahora digamos que hemos creado este mgh de alguna manera que cualquiera que diga:

import mgh
mgh.connect(ip,port.data)...

podría conectarse fácilmente a un servidor remoto con la IP y el número de puerto especificado y enviar los datos después (o algo así). ahora la gente podría hacerlo todo con una sola línea, pero lo que sucede es que se están ejecutando muchos códigos que se han recuperado del archivo mgh. y empaquetar no ha sido para acelerar el proceso de ejecución sino más bien para facilitar el trabajo de otros programadores. así que aquí, si alguien quiere usar su código primero, debe importar el archivo y luego el intérprete de Python reconocerá todo el código y podrá interpretar el código.

ahora, si desea crear un lenguaje de programación y desea ejecutarlo, primero necesita una traducción, por ejemplo, supongamos que crea un programa que podría comprender la sintaxis y convertirla a c, en este caso después de que se haya traducido a c, el compilador de c se encargaría del resto, luego el ensamblador, el enlazador, .... aunque tendría que pagar el precio de ser más lento, ya que primero debe convertirse a c.

Ahora, otra cosa que podría hacer es crear un programa que pueda traducir todo el código al lenguaje ensamblador equivalente al igual que sucede con c, pero en este caso el programa podría hacerlo directamente y, a partir de ahí, el resto lo haría el enlazador. Sabemos que este programa se llama compilador.

así que de lo que estoy hablando es que, el único código que el sistema entiende es 0,1, por lo que de alguna manera deberías convertir tu sintaxis a eso, ahora en nuestros sistemas operativos muchos programas diferentes como ensamblador, enlazador y ... tienen creado para decirle que si pudiera convertir su código a ensamblado, ellos podrían encargarse del resto o, como dije, incluso podría usar otros compiladores de lenguajes de programación al convertir su código a ese idioma.

Mgh Gh
fuente