Está en la página 1de 31

UNIVERSIDAD NACIONAL “SANTIAGO

ANTÚNEZ DE MAYOLO”

FACULTA DE CIENCIAS

ESCUELA PROFESIONAL DE INGENIERÍA


DESISTEMAS E INFORMÁTICA

TEORIA DE LENGUAJES

“TIPOS DE TRADUCTORES”

DEPAZ OSCCO Brayan Alexis


JAIMES MOQUILLAZA Ricardo
PAMPA TARAZONA Daniel
RUPAY VILLALOBOS Álvaro
YAURI CALDUA Giuseppy
TIPOS DE TRADUCTORES
1. TRADUCTORES DE IDIOMAS
a. DEFINICION
Un traductor de idiomas es, en el ámbito de la informática, aquel sistema
que lee un texto escrito en cierto idioma y realiza un texto equivalente en
otro idioma.
Este usa una base de datos para poder realizar la traducción; y por causa de
esto, se generaron muchos problemas

b. INICIOS
Los primeros traductores de idiomas realizaban la traducción palabra por
palabra; haciendo que, entre los diferentes idiomas, no tenían sentido ni
coherencia.
Viendo esto; se tuvieron que realizar algunas modificaciones.
La principal fue la realización de inteligencias artificiales para poder dar el
sentido a las oraciones; que este también a su vez, conllevo a más
problemas

c. INTELIGENCIA ARTIFICIAL EN LA TRADUCCION


Las primeras inteligencias artificiales en la traducción tenían escasas
informaciones sobre la cultura lingüística de otros idiomas. Provocando que
las frases tuvieran un orden correcto, pero no sentido.

Otro problema era el egocentrismo del idioma anglosajón, por lo que se


deseaba, por ejemplo, la traducción del hindú al portugués; lo que realizaba
el sistema era traducir el hindú al inglés, y después el inglés al portugués,
provocando que se duplicara el problema original

En la actualidad, las inteligencias artificiales aún no están completas; ya que


cada idioma tiene culturas muy amplias sobre su idioma.
Sin embargo, se ha logrado un gran avance con la ayuda de técnicas
criptográficas, la aplicación del teorema de Shannon y la utilidad
estadística; ya que, estas inteligencias van adquiriendo nueva información
cada día con cada búsqueda; retroalimentándose y almacenando a sus
algoritmos las nuevas informaciones adquiridas de sus usuarios

d. AMBIGÜEDAD
Otro problema que sigue hasta la actualidad es la ambigüedad al momento
de traducir palabras que tienen doble sentido, o palabras que se puede
traducir de diferentes formas. Esto genero que al momento de traducir
textos de extrema importancia; parecían no tener ningún sentido después
de traducirlas
Cada vez la inteligencia artificial almacena los posibles conceptos de cada
palabra y logra encontrar esas palabras exactas para cada oración.

TRADUCCION LITERAL QUE NO TENDRIA EL MISMO


SENTIDO EN EL ESPAÑOL QUE EN EL INGLES

e. ACTUALIDAD
En la actualidad existen diferentes sistemas que necesitan un traductor de
idiomas, principalmente son los navegadores; que, según la documentación
de html, debe ser capaz de identificar la necesidad del cliente y poder
traducir paginas de otros idiomas para la facilitación del cliente.
Otros son los mismos sistemas de traducción de idiomas, como el traductor
de Google o Plugins de traducción, donde están más enfocados a una
mayor lingüística y poder ofrecer al cliente una mejor traducción
Sin embrago todos estos están incompletos; ya que existen mas de 7000
idiomas oficiales y no oficiales
2. COMPILADORES
a. DEFINICION

En informática, un compilador es un tipo de traductor que transforma


un programa entero de un lenguaje de programación a código máquina,
aunque también puede ser traducido a un código intermedio (bytecode) o
a texto.

b. CONSTRUCCION

La construcción de un compilador involucra la división del proceso en una


serie de fases que variará con su complejidad. Generalmente estas fases se
agrupan en dos tareas: .
 Análisis: se trata de la comprobación de la corrección del programa
fuente. Incluye las fases correspondientes al análisis léxico , análisis
sintáctico y análisis semántico.
 Síntesis: su objetivo es la generación de la salida expresada en el lenguaje
objeto y suele estar formado por una o varias combinaciones de fases de
generación de código y de optimización de código.
Alternativamente, las fases descritas para las tareas de análisis y síntesis se
pueden agrupar en:

 Analizador o front-end: es la parte que analiza el código fuente, comprueba


su validez, genera el árbol de derivación y rellena los valores de la tabla de
símbolos.
 Generador o back-end: es la parte que genera el código máquina,
específico de una plataforma, a partir de los resultados de la fase de
análisis, realizada por este generador.

c. INICIOS
Los primeros usuarios de los ordenadores descubrieron la ventaja de
escribir sus programas mediante claves más fáciles de recordar que esos
códigos; al final, todas esas claves juntas se traducían manualmente a
lenguaje máquina. Estas claves constituyen los llamados lenguajes
ensambladores.
Pese a todo, el lenguaje ensamblador seguía siendo el de una máquina,
pero más fácil de manejar. Los trabajos se orientaron hacia la creación de
un lenguaje que expresara las acciones a realizar de una manera lo más
sencilla posible para una persona.

El primer compilador fue escrito por Grace Hopper, en 1952 para el


lenguaje de programación A-0.
En 1954 se empezó a desarrollar un lenguaje que permitía escribir fórmulas
matemáticas de manera traducible por un ordenador; le llamaron
FORTRAN.
Surgió así por primera vez el concepto de un traductor como un programa
que traducía un lenguaje a otro lenguaje.
El primer compilador autocontenido fue el creado para Lisp en 1962. Desde
1970 se ha convertido en una práctica común escribir el compilador en el
mismo lenguaje que este compila, aunque PASCAL y C han sido alternativas
muy usadas.

d. TIPOS DE COMPILADORES

Se debe decir que puede haber compiladores que se adscriban a varias


categorías:
 Compiladores cruzados: generan código para un sistema distinto del que
están funcionando.
 Compiladores optimizadores: realizan cambios en el código para mejorar
su eficiencia, pero manteniendo la funcionalidad del programa original.
 Compiladores de una sola pasada: generan el código máquina a partir de
una única lectura del código fuente.
 Compiladores de varias pasadas: necesitan leer el código fuente varias
veces antes de poder producir el código máquina.
 Compiladores JIT (just in time): forman parte de un intérprete y compilan
partes del código según se necesitan.

e. PROCESOS DE COMPLIACION
Es el proceso por el cual se traducen las instrucciones escritas en un
determinado lenguaje de programación a lenguaje máquina. Un programa
fuente se puede dividir en módulos almacenados en archivos distintos.

Normalmente la creación de un programa ejecutable conlleva dos pasos. El


primer paso se llama compilación y traduce el código fuente escrito en
un lenguaje de programación almacenado en un archivo a código en bajo
nivel.

El segundo paso se llama enlazado en el cual se enlaza el código de bajo


nivel generado y se añade el código de las funciones que hay en las
bibliotecas del compilador para que el ejecutable pueda comunicarse
directamente con el sistema operativo, generando un módulo ejecutable.

f. ETAPAS DEL PROCESO

El proceso de traducción se compone internamente de varias etapas o


fases:
 Fase de análisis léxico

Aquí se lee el programa fuente de izquierda a derecha y se agrupa en


componentes léxicos.
Como la tarea que realiza el analizador léxico es un caso especial de
coincidencia de patrones, se necesitan los métodos de especificación y
reconocimiento de patrones, se usan principalmente los autómatas
finitos que acepten expresiones regulares. Sin embargo, un analizador
léxico también es la parte del traductor que maneja la entrada del
código fuente, y puesto que esta entrada a menudo involucra un
importante gasto de tiempo, el analizador léxico debe funcionar de
manera tan eficiente como sea posible.

 Fase de análisis sintáctico

En esta fase los caracteres o componentes léxicos se agrupan


jerárquicamente en frases gramaticales que el compilador utiliza para
sintetizar la salida.
La estructura jerárquica de un programa normalmente se expresa
utilizando reglas recursivas.

 Fase de análisis semántico


La fase de análisis semántico revisa el programa fuente para tratar de
encontrar errores semánticos y reúne la información sobre los tipos
para la fase posterior de generación de código.

 Fase de síntesis
Consiste en generar el código objeto equivalente al programa fuente.

 Generación de código intermedio


Después de los análisis sintáctico y semántico, algunos compiladores
generan una representación intermedia explícita del programa fuente.
La representación intermedia puede tener diversas formas.
 Optimización de código
La fase de optimización de código consiste en mejorar el código
intermedio, de modo que resulte un código máquina más rápido de
ejecutar.
3. INTERPRETES

a. DEFINICION

Un intérprete es aquel programa que analiza y ejecuta otro programa escrito en


algún lenguaje/código fuente.
Cualquier intérprete tiene 2 tipos de entradas: Un programa escrito en un lenguaje fuente
junto con los datos de entrada, consecuente a esto mediante un proceso de
interpretación va produciendo los resultados de dicho programa.

Ejemplo de un intérprete

Los intérpretes son diferentes a los compiladores, ya que estos últimos transforman el
programa a otro igual en un código objeto y en una segunda instancia generan los
resultados a partir de los datos que se usar de entrada.

Ejemplo de un compilador
b. ESTRUCTURA DE UN INTERPRETE

A la hora de construir un intérprete es conveniente utilizar una Representación


Interna (RI) del lenguaje fuente a analizar. De esta forma, la organización interna
de la mayoría de los intérpretes se descompone en los módulos:
Traductor a Representación Interna: Se toma como entrada el código del
programa ‘P’ en lenguaje fuente, lo analiza y después lo transforma a la
representación interna correspondiente a dicho programa ‘P’.

Representación Interna: La representación interna debe ser concisa respecto al


programa original. Los árboles sintácticos son los tipos de representación interna
más frecuentes y, si las características del lenguaje lo permiten, se puede utilizar
estructuras de pila para tener más eficiencia.

Tabla de Símbolos: Durante la traducción, es pertinente ir creando una tabla con


información relativa a los símbolos que aparecen. La información que se deberá
almacenar en la tabla de símbolos es dependiente a la complejidad del lenguaje
fuente. Se pueden almacenar etiquetas para instrucciones de salto, información
sobre identificadores (nombre, tipo, línea en la que aparecen, etc.) o cualquier
otro tipo de información que se necesite en la etapa de evaluación.

Evaluador de Representación Interna: A partir de la representación interna que se


realizó con anterioridad y de los datos que se usaron para la entrada se lleva a
cabo las acciones indicadas para obtener los resultados. Durante este proceso es
necesario observar la aparición de errores.

Tratamiento de Errores: Durante el proceso evaluador se podrían observar


diversos errores como desbordamiento de la pila, divisiones entre cero, entre
otros que el intérprete deberá contemplar.

Organización interna de un intérprete


Dependiendo de la complejidad del código a analizar, el intérprete puede contener
módulos similares a los de un compilador tradicional: Análisis léxico, sintáctico y
semántico. Durante la evaluación, el intérprete interactúa con los recursos del
sistema como la memoria, discos, etc. Muchos sistemas interpretados liberan al
programador del manejo explícito de memoria mediante técnicas de recolección
de basura. A la hora de evaluar la representación interna, existen dos métodos
fundamentales: la interpretación iterativa y la interpretación recursiva.

a) Interpretación Iterativa
Esta interpretación es ideal para lenguajes simples, donde se analiza y ejecuta
las expresiones directamente, entre ellos están los códigos de máquinas
abstractas o lenguajes de sentencias sencillas. La interpretación consiste en un
ciclo básico de búsqueda, análisis y ejecución de instrucciones.

b) Interpretación Recursiva
Comúnmente, el diseño de nuevos lenguajes de programación se realiza en dos
fases:
Una primera fase de especificación semántica mediante la construcción de un
intérprete prototipo que actúa como una especificación ejecutable y una
segunda fase de implementación del compilador de dicho lenguaje. Para la
construcción de prototipos suele utilizarse un modelo de interpretación
recursiva donde las sentencias pueden estar compuestas de otras sentencias y
la ejecución de una sentencia puede lanzar la ejecución de otras sentencias de
forma recursiva. Los intérpretes recursivos no son apropiados para aplicaciones
prácticas debido a su ineficiencia y se utilizan únicamente como prototipo
ejecutable del lenguaje. El problema de especificar un lenguaje mediante un
intérprete prototipo es decidir en qué lenguaje se implementa dicho
intérprete. Dicho lenguaje debe ser suficientemente expresivo y no ambigüo
para definir claramente cómo funcionan las diferentes construcciones. En
muchos casos se opta por utilizar lenguajes ya implementados pero que
carecen de una especificación semántica clara. La tendencia actual es
investigar técnicas de especificación semántica formal que permitan generar
automáticamente este tipo de intérpretes.
c. APLICACIONES DE LOS SISTEMAS BASADOS EN INTÉRPRETES

Los sistemas interpretados han tenido una gran importancia desde la aparición de
los primeros ordenadores. En la actualidad, la evolución del hardware abre nuevas
posibilidades a los sistemas interpretados. La preocupación ya no es tanto la
eficiencia como la capacidad de desarrollo rápido de nuevas aplicaciones. Las
principales aplicaciones podrían resumirse en:

- Intérpretes de Comandos: Los sistemas operativos cuentan con intérpretes de


comandos como el Korn-Shell, C-Shell, JCL, etc. Estos intérpretes toman un
lenguaje fuente que puede incluir sentencias de control (bucles, condiciones,
asignaciones, etc.) y ejecutan los diferentes comandos a medida que aparecen
en el lenguaje.
- Lenguajes basados en escritos: Diseñados como herramientas que sirvan de
enlace entre diferentes sistemas o aplicaciones. Suelen ser interpretados con el
fin de admitir una mayor flexibilidad a la hora de afrontar las peculiaridades de
cada sistema. Podrían destacarse Perl, Tcl/Tk, JavaScript, WordBasic.
- Entornos de Programación: Existen ciertos lenguajes que contienen
características que impiden su compilación o cuya compilación no es efectiva.
Estos lenguajes suelen disponer de un complejo entorno de desarrollo
interactivo con facilidades para la depuración de programas. Entre estos
sistemas pueden destacarse los entornos de desarrollo para Lisp, Visual Basic,
Smalltalk, etc.
- Lenguajes de Propósito Específico: Ciertos lenguajes incluyen sentencias que
realizan tareas complejas en contextos específicos. Existe una gran variedad de
aplicaciones en las que se utilizan este tipo de lenguajes como consultas de
Bases de Datos, simulación, descripción de hardware, robótica, CAD/CAM,
música, etc.
- Sistemas en Tiempo Real: Entornos que permiten modificar el código de una
aplicación en tiempo de ejecución de forma interactiva.
- Intérprete de código intermedio: Una tendencia tradicional en el diseño de
compiladores es la generación de un código intermedio para una máquina
abstracta, por ejemplo, el P-Code de Pascal o los bytecodes de Java. El
siguiente paso puede ser: generación del código objeto a partir del código
intermedio para una máquina concreta, finalizando el proceso de compilación
o interpretar dicho código intermedio en una máquina concreta. La tendencia
habitual es definir un lenguaje intermedio independiente de una máquina
concreta. Para ello, suele definirse una máquina virtual que contenga las
instrucciones definidas por el lenguaje intermedio, permitiendo una mayor
portabilidad. Un ejemplo sería la Máquina Virtual de Java, que es simulada en
la mayoría de los visualizadores Web.

d. TIPOS DE INTÉRPRETES

a) Intérpretes puros
Los intérpretes puros son los que analizan y ejecutan sentencia a sentencia
todo el programa fuente. Siguen el modelo de interpretación iterativa y, por
tanto, se utilizan principalmente para lenguajes sencillos. Los intérpretes puros
se han venido utilizando desde la primera generación de ordenadores al
permitir la ejecución de largos programas en ordenadores de memoria
reducida, ya que sólo debían contener en memoria el intérprete y la sentencia
a analizar y ejecutar en cada momento. El principal problema de este tipo de
intérpretes es que si a mitad del programa fuente se producen errores, se debe
de volver a comenzar el proceso.

Representación de un intérprete puro

b) Intérpretes avanzados
Los intérpretes avanzados o normales incorporan un paso previo de análisis de
todo el programa fuente. Generando posteriormente un lenguaje intermedio
que es ejecutado por ellos mismos. De esta forma en caso de errores
sintácticos no pasan de la fase de análisis. Se utilizan para lenguajes más
avanzados que los intérpretes puros, ya que permiten realizar un análisis más
detallado del programa fuente (comprobación de tipos, optimización de
instrucciones, etc.)
c) Intérpretes incrementales
Existen ciertos lenguajes que, por sus características, no se pueden compilar
directamente. La razón es que pueden manejar objetos o funciones que no son
conocidos en tiempo de compilación, ya que se crean dinámicamente en
tiempo en ejecución. Entre estos lenguajes, pueden considerarse Smalltalk,
Lisp o Prolog. Con el propósito de obtener una mayor eficiencia que en la
interpretación simple, se diseñan compiladores incrementales. La idea es
compilar aquellas partes estáticas del programa en lenguaje fuente, marcando
como dinámicas las que no puedan compilarse. Posteriormente, en tiempo de
ejecución, el sistema podrá compilar algunas partes dinámicas o recompilar
partes dinámicas que hayan sido modificadas. Estos sistemas no producen un
código objeto independiente, sino que acompañan el sistema que permite
compilar módulos en tiempo de ejecución (run time system) al código objeto
generado.
Normalmente, los compiladores incrementales se utilizan en sistemas
interactivos donde conviven módulos compilados con módulos modificables.

d) Evaluadores parciales
La utilización de evaluadores parciales o especializadores surge al considerar
que muchos programas contienen dos tipos de datos de entrada. Existen una
serie de datos de entrada que son diferentes en cada ejecución mientras que
otros datos no varían de una ejecución a otra. El primer conjunto, se conoce
como datos de entrada dinámicos (se denotará como Din), mientras que el
segundo conjunto, serían los datos de entrada estáticos (Est). Dado un
programa P, el proceso de evaluación parcial consiste en construir otro
programa especializado P_est para los datos estáticos de P. El programa P_est
suele estar escrito en el mismo lenguaje fuente que P y se debe garantizar que
cuando se le presenten los datos dinámicos produzca los mismos resultados
que si se hubiesen presentado todos los datos al programa P original.

e) Compiladores “Just-In-Time”
Con la aparición de Internet surge la necesidad de distribuir programas de una
forma independiente de la máquina permitiendo su ejecución en una amplia
variedad de plataformas. Los códigos de bytes de la máquina Virtual de Java
permiten la ejecución de programas distribuidos, ya que la mayoría de los
visualizadores tienen un mecanismo capaz de interpretarlos. La interpretación
de códigos de bytes supone una demora en los tiempos de ejecución. Para
evitar la interpretación, muchos sistemas transforman los códigos de bytes en
código nativo siguiendo el modelo “just in time”. En este modelo, una unidad
de compilación o clase se transmite en el formato de códigos de bytes, pero no
se realiza la interpretación. En lugar de ello, el código es compilado a código
nativo justo en el momento en que lo necesita el programa que se está
ejecutando.

Compilación de una clase Just In Time

f) Compilación continua
La compilación continua surge como un intento de mejorar la compilación “Just
in Time”. El sistema mezcla el proceso de compilación a código nativo con el
proceso de interpretación. Para conseguirlo, el sistema dispone de dos
módulos: un módulo de interpretación de los códigos de bytes y otro módulo
de compilación de códigos de bytes a código nativo. La idea consiste en que
ambos módulos actúen a la vez (lo ideal sería disponer de dos procesadores),
de forma que el sistema no se detenga a compilar un módulo, sino que vaya
interpretándolo hasta que el compilador haya generado el código nativo. La
principal ventaja de la compilación continua respecto a la compilación Just in
Time radica en no tener que esperar a compilar una unidad para comenzar su
ejecución.

Comparación de los otros compiladores con la compilación continua


4. Preprocesadores
Los preprocesadores son aquellos programas pertenecientes de un compilador que
preparan o modifica el código fuente antes de ser traducido a código binario Los cambios
los hace interpretando aquellas líneas del código que comienzan por el símbolo “#”. El uso
de estas directivas es tan común en los programas en C que parece que forman parte del
lenguaje, pero en realidad son parte de un lenguaje que sólo entiende el procesador. La
siguiente figura ilustra como se procesa un fichero de código fuente en realidad por el
compilador.

Como se puede comprobar, las dos líneas que comienzan por “#” han desaparecido, al
igual que los comentarios. Al traductor a código binario le llega fichero sin ninguna
directiva ni comentario. El preprocesador puede ser utilizado de forma independiente del
compilador mediante el comando cpp. Abre un terminal de comandos y consulta la página
de manual de este comando. Como puedes comprobar, es un programa que puede
procesar un amplio catálogo de directivas. De todas ellas, en este documento se describen
las más utilizadas.

a. La directiva #include

La directiva #include debe ir seguida del nombre de un fichero y su efecto es de


reemplazar esta línea en el código fuente por el contenido del fichero que se
especifica. La siguiente figura ilustra un ejemplo de esta directiva.
b. La directiva #define

Esta directiva posee dos versiones. La primera; si va seguida de una única cadena
de texto como:

el preprocesador simplemente anota internamente que este símbolo está


“definido”.
La segunda versión de esta directiva es cuando va seguida de dos cadenas de
texto. En este caso, a partir de ese punto, el preprocesador reemplaza toda
aparición de la primera cadena por la segunda. El siguiente ejemplo define el
símbolo CARGA_MAXIMA para que se reemplace por el valor 1500.

El efecto de esta directiva es idéntico al uso de la opción -D del compilador. En realidad,


cuando se invoca el compilador con la opción -Dnombre=valor, esta definición es
equivalente a que el procesador encontrase la línea #define nombre valor.

Con la directiva #define debes tener en cuenta lo siguiente:

 Esta directiva suele estar al comienzo de los ficheros de código, o si se necesitan en


varios ficheros, en un fichero de definiciones con extensión “.h” que se incluye en
otros ficheros.
 Para diferenciar en el código los símbolos normales de un programa de aquellos
que han sido definidos por la directiva #define y que van a ser reemplazados por sus
equivalentes por el preprocesador, estos últimos se suelen escribir siempre con
mayúsculas (esto es una convención, el preprocesador no realiza ningún tipo de
comprobación).
 El reemplazo del símbolo por su valor se realiza en todo el texto de un fichero. Esto
incluye también las propias directivas del preprocesador. En el siguiente ejemplo
el programa imprime el número uno. Es decir, la segunda directiva #define se procesa
como #define OTRO_UNO 1 al reemplazarse UNO por la definición de la línea anterior.

c. Las directivas #ifdef, #else y #endif

El preprocesador mantiene un conjunto símbolos definidos, y algunos de ellos


deben ser sustituidos por sus valores equivalentes. El preprocesador también
ofrece un mecanismo por el que una porción de código de un programa se puede
ocultar o considerar dependiendo del valor de alguno de los símbolos definidos
con la directiva #define. La estructura de esta construcción es la siguiente:

Cuando el preprocesador encuentra la primera directiva #ifdef SIMBOLO, si


SIMBOLO está definido, pasa el bloque de código 1 al compilador (hasta la
directiva #else) y elimina el bloque de código 2 (entre las directivas #else y #endif.
De forma análoga, si SIMBOLO no está definido, el bloque de código 1 se elimina y
el compilador sólo recibe el bloque de código 2. Esta construcción es similar al
if/then/else en C, pero la diferencia es que esta la interpreta el preprocesador
cuando se compila. La diferencia está en que si el bloque de código que se ignora
contiene un error de sintaxis, el compilador generará el programa igualmente,
pues no llega a procesar ese código.

Esta directiva se utiliza cuando se quiere mantener dos versiones de un programa


que se diferencian únicamente en un reducido número de líneas de código. Las dos
versiones pueden coexistir en el código fuente pero rodeadas de esta directiva. Al
compilar se utiliza entonces la opción -Dnombre=valor para seleccionar los bloques
de código pertinentes y generar el ejecutable.
El siguiente ejemplo muestra el uso de esta directiva para escribir dos versiones de
un mensaje de bienvenida a un sistema con dos posibles versiones. Si el símbolo
MAEMO está definido (por ejemplo al compilar gcc -DMAEMO ...) al ejecutar se
imprime un mensaje, y si no está definido este símbolo, se imprime un mensaje
alternativo.

d. Definición de ‘macros’ con la directiva #define

La directiva #define tiene una funcionalidad extra que puede utilizarse para definir
lo que se conoce como “macros”. El reemplazo que hace el preprocesador del
símbolo por su equivalente puede incluir parámetros. En el siguiente ejemplo se
define una macro para reemplazar el símbolo DEMASIADO_GRANDE(v) la
comparación de v dada con el valor 1000.

La macro DEMASIADO_GRANDE(v) se puede utilizar en el código con un nombre de


variable en lugar de v que será utilizado al reemplazarse el símbolo por su
equivalente tal y como se muestra en el siguiente ejemplo:
5. INTÉRPRETE DE LÍNEA DE COMANDOS

los usuarios ingresan comandos a través del teclado, luego el intérprete convierte los
comandos en funciones o llamadas al sistema.

Pensemos que es un traductor entre la maquina y nosotros en el que las instrucciones


pasan por este para que la maquina pueda comprender.

Como ventaja el uso de estás interfaces es que las instrucciones se ejecutan más rápido,
otra ventaja es que no todo el SO cuenta con botones para todas las acciones posibles por
el interprete es por esto que el interprete se convierte en la única solución en caso no
podamos mediante la SO.

Pueden estar en el kernel o como también en dispositivos externos este ultimo es más
conveniente por los cambios constantes que se dan en el Shell.

6. ENSAMBLADORES Y MACROENSAMBLADORES

Son los pioneros de los compiladores porque antes se escribían los códigos en lenguaje
maquina y era laborioso, constituyendo así el primer paso para los lenguajes de alto nivel,
los ensambladores.

El usuario escribe programas haciendo uso de las mnemotécnicas y el ensamblador se


encarga de convertirlo a código maquina puro.

El ensamblador permite la traducción de cada sentencia a una única instrucción de código


máquina.

Instrucción ensamblador: LD HL, #0100

Código máquina generada: 65h.00h.01h

Por otro lado, existen ensambladores avanzados que permiten ejecutar


macroinstrucciones maquina también llamados macroensambladores.
7. CONVERSORES FUENTE-FUENTE
Conversores fuente - fuente: Pasan un lenguaje de alto nivel a otro lenguaje de alto nivel,
para conseguir mayor portabilidad.

Por ejemplo, en un ordenador sólo hay un compilador de PASCAL, y queremos ejecutar un


programa escrito en COBOL; Un conversor COBOL –> PASCAL nos solucionaría el
problema.
* Los resultados pueden requerir retoques por dos motivos:

. Si el lenguaje destino no tiene las mismas características que el origen. Por ejemplo, un

conversor de JAVA a C, necesitaría retoques ya que C no tiene recolector de basura.

. Si la traducción no ha sido inteligente y el programa destino no es eficiente.

Una aplicación interesante de la traducción fuente-fuente es el desarrollo e


implementación de prototipos de nuevos lenguajes de programación.

Así, por ejemplo, si se desea definir un lenguaje especializado puede implementarse


rápidamente mediante su traducción a un lenguaje convencional de alto nivel.
8. COMPILADOR CRUZADO
Un compilador cruzado es un compilador capaz de crear código ejecutable para una
plataforma distinta a aquella en la que se ejecuta el compilador. Por ejemplo, un
compilador que se ejecuta en una PC con Windows 7 pero genera código que se ejecuta
en un teléfono inteligente Android es un compilador cruzado.

Es necesario un compilador cruzado para compilar código para múltiples plataformas


desde un host de desarrollo. La compilación directa en la plataforma de destino puede no
ser factible, por ejemplo, en un microcontrolador de un sistema integrado, porque esos
sistemas no contienen ningún sistema operativo. En la para-virtualización, una
computadora ejecuta múltiples sistemas operativos y un compilador cruzado podría
generar un ejecutable para cada uno de ellos desde una fuente principal.

Los compiladores cruzados son distintos de los compiladores de fuente a fuente. Un


compilador cruzado es para el desarrollo de software multiplataforma de código de
máquina, mientras que un compilador de fuente a fuente traduce de un lenguaje de
programación a otro en código de texto. Ambos son herramientas de programación.

Usos

El uso fundamental de un compilador cruzado es separar el entorno de compilación del


entorno de destino. Esto es útil en varias situaciones:

 Computadoras integradas donde un dispositivo tiene recursos extremadamente limitados.


Por ejemplo, un horno de microondas tendrá una computadora extremadamente pequeña
para leer su panel táctil y el sensor de la puerta, proporcionar salida a una pantalla digital
y un altavoz, y controlar la maquinaria para cocinar alimentos. Esta computadora no será
lo suficientemente poderosa para ejecutar un compilador, un sistema de archivos o un
entorno de desarrollo. Dado que la depuración y las pruebas también pueden requerir
más recursos de los que están disponibles en un sistema integrado, la compilación cruzada
puede ser menos complicada y menos propensa a errores que la compilación nativa.
 Compilación para varias máquinas. Por ejemplo, una empresa puede querer admitir varias
versiones diferentes de un sistema operativo o admitir varios sistemas operativos
diferentes. Mediante el uso de un compilador cruzado, se puede configurar un único
entorno de compilación para compilar cada uno de estos objetivos.
 Compilación en una granja de servidores. De manera similar a la compilación para varias
máquinas, una compilación complicada que implica muchas operaciones de compilación
se puede ejecutar en cualquier máquina que sea gratuita, independientemente de su
hardware subyacente o de la versión del sistema operativo que esté ejecutando.
 Bootstrapping a una nueva plataforma. Al desarrollar software para una nueva
plataforma, o el emulador de una plataforma futura, se usa un compilador cruzado para
compilar las herramientas necesarias, como el sistema operativo y un compilador nativo.
 Compilación de código nativo para emuladores para plataformas más antiguas ahora
obsoletas como Commodore 64 o Apple II por entusiastas que usan compiladores
cruzados que se ejecutan en una plataforma actual (como los compiladores cruzados MS-
DOS 6502 de Aztec C que se ejecutan en Windows XP).

El uso de máquinas virtuales (como la JVM de Java) resuelve algunas de las razones por las que
se desarrollaron compiladores cruzados. El paradigma de la máquina virtual permite que se
utilice la misma salida del compilador en varios sistemas de destino, aunque esto no siempre
es ideal porque las máquinas virtuales suelen ser más lentas y el programa compilado solo se
puede ejecutar en equipos con esa máquina virtual.

Normalmente, la arquitectura de hardware es diferente (por ejemplo, compilar un programa


destinado a la arquitectura MIPS en una computadora x86), pero la compilación cruzada
también es aplicable cuando solo difiere el entorno del sistema operativo, como cuando se
compila un programa FreeBSD en Linux, o incluso solo la biblioteca del sistema., como cuando
se compilan programas con uClibc en un host glibc.

Cruz canadiense

El Cross Canadian es una técnica para la construcción de compiladores cruzados para otras
máquinas. Dadas tres máquinas A, B y C, una usa la máquina A (por ejemplo, ejecutando
Windows XP en un procesador IA-32 ) para construir un compilador cruzado que se ejecuta en
la máquina B (por ejemplo, ejecutando Mac OS X en un procesador x86-64 ) para crear
ejecutables para la máquina C (por ejemplo, ejecutar Android en un procesador ARM ). Al usar
Canadian Cross con GCC, puede haber cuatro compiladores involucrados

 El compilador nativo propietario para la máquina A (1) (por ejemplo, el compilador de


Microsoft Visual Studio ) se utiliza para construir el compilador nativo gcc para la máquina
A (2) .
 El compilador nativo gcc para la máquina A (2) se usa para construir el compilador cruzado
gcc de la máquina A a la máquina B (3)
 El compilador cruzado gcc de la máquina A a la máquina B (3) se utiliza para construir el
compilador cruzado gcc de la máquina B a la máquina C (4)
El compilador cruzado de resultado final (4) no podrá ejecutarse en la máquina de compilación
A; en su lugar, se ejecutaría en la máquina B para compilar una aplicación en un código
ejecutable que luego se copiaría en la máquina C y se ejecutaría en la máquina C.

Por ejemplo, NetBSD proporciona un script de shell POSIX Unix llamado build.shque primero
construirá su propia cadena de herramientas con el compilador del host; esto, a su vez, se
usará para construir el compilador cruzado que se usará para construir todo el sistema.

El término Cruz Canadiense surgió porque en el momento en que se estaban debatiendo estos
temas, Canadá tenía tres partidos políticos nacionales.

Cronología de los primeros compiladores cruzados

1979 - ALGOL 68C generó ZCODE ; esto ayudó a portar el compilador y otras aplicaciones de
ALGOL 68 a plataformas alternativas. Para compilar el compilador ALGOL 68C se requieren
aproximadamente 120 KB de memoria. Con Z80, su memoria de 64 KB es demasiado pequeña
para compilar el compilador. Entonces, para el Z80, el compilador en sí tuvo que compilarse
de forma cruzada desde una computadora con capacidad CAP más grande o una
computadora central IBM System / 370 .

GCC y compilación cruzada

GCC , una colección de compiladores de software gratuito , se puede configurar para


compilación cruzada. Es compatible con muchas plataformas e idiomas.

GCC requiere que haya disponible una copia compilada de binutils para cada plataforma de
destino. Especialmente importante es el ensamblador GNU . Por lo tanto, binutils primero
debe compilarse correctamente con el conmutador --target=some-targetenviado al script de
configuración . GCC también debe configurarse con la misma --targetopción. Luego, GCC se
puede ejecutar normalmente siempre que las herramientas, que binutils crea, estén
disponibles en la ruta , lo que se puede hacer usando lo siguiente (en sistemas operativos tipo
UNIX con bash):

RUTA = / ruta / a / binutils / bin: $ {RUTA} make

Cross-compilar GCC requiere que una porción de la plataforma de destino' s biblioteca


estándar C estará disponible en la plataforma anfitrión . El programador puede optar por
compilar la biblioteca C completa, pero esta opción podría no ser confiable. La alternativa es
usar newlib , que es una pequeña biblioteca de C que contiene solo los componentes más
esenciales necesarios para compilar el código fuente de C.

Los paquetes de autotools de GNU (es decir , autoconf , automake y libtool ) utilizan la noción
de una plataforma de compilación , una plataforma de host y una plataforma de destino . La
plataforma de compilación es donde se compila realmente el compilador. En la mayoría de los
casos, la compilación debe dejarse sin definir (será el valor predeterminado del host). La
plataforma de host es siempre donde se ejecutarán los artefactos de salida del compilador, ya
sea que la salida sea de otro compilador o no. La plataforma de destino se utiliza cuando se
compilan compiladores cruzados, representa qué tipo de código de objeto producirá el
paquete; de lo contrario, la configuración de la plataforma de destino es irrelevante. [2] Por
ejemplo, considere la posibilidad de realizar una compilación cruzada de un videojuego que
se ejecutará en un Dreamcast . La máquina donde se compila el juego es la plataforma de
construcción, mientras que Dreamcast es la plataforma anfitriona . Los nombres de host y
target son relativos al compilador que se está utilizando y se han cambiado como hijo y nieto .

Otro método utilizado popularmente por los desarrolladores de Linux embebido implica la
combinación de compiladores GCC con entornos sandbox especializados como Scratchbox ,
scratchbox2 o PRoot . Estas herramientas crean una caja de arena " chrooted " donde el
programador puede crear las herramientas, libc y bibliotecas necesarias sin tener que
establecer rutas adicionales. También se proporcionan funciones para "engañar" al tiempo de
ejecución de modo que "crea" que realmente se está ejecutando en la CPU de destino
prevista (como una arquitectura ARM); esto permite que los scripts de configuración y
similares se ejecuten sin errores. Scratchbox se ejecuta más lentamente en comparación con
los métodos "no chrootados", y la mayoría de las herramientas que están en el host deben
moverse a Scratchbox para que funcionen.

Compiladores cruzados Manx Aztec C

Manx Software Systems , de Shrewsbury , Nueva Jersey , produjo compiladores de C a partir


de la década de 1980 dirigidos a desarrolladores profesionales para una variedad de
plataformas que incluyen PC y Mac .

El lenguaje de programación Aztec C de Manx estaba disponible para una variedad de


plataformas incluyendo MS-DOS , Apple II , DOS 3.3 y ProDOS , Commodore 64 , Macintosh
68XXX y Amiga .
Desde la década de 1980 y continuando a lo largo de la de 1990 hasta la desaparición de
Manx Software Systems, la versión MS-DOS de Aztec C se ofreció como compilador en modo
nativo o como compilador cruzado para otras plataformas con diferentes procesadores,
incluido el Commodore 64 y Apple II. Todavía existen distribuciones de Internet para Aztec C,
incluidos sus compiladores cruzados basados en MS-DOS. Todavía están en uso hoy.

Aztec C86 de Manx, su compilador de MS-DOS 8086 en modo nativo , también era un
compilador cruzado. Aunque no compiló código para un procesador diferente como sus
compiladores cruzados Aztec C65 6502 para Commodore 64 y Apple II, creó ejecutables
binarios para los sistemas operativos heredados de la familia de procesadores 8086 de 16
bits.

Cuando se introdujo por primera vez IBM PC, estaba disponible con una selección de sistemas
operativos, CP / M-86 y PC DOS eran dos de ellos. Aztec C86 se proporcionó con bibliotecas
de enlaces para generar código para ambos sistemas operativos IBM PC . A lo largo de la
década de 1980, las versiones posteriores de Aztec C86 (3.xx, 4.xx y 5.xx) agregaron soporte
para las versiones 1 y 2 "transitorias" de MS-DOS [8] y que eran menos robustas que las
versiones "de base" de MS-DOS. versión 3 y posterior que Aztec C86 apuntó hasta su
desaparición.

Por último, Aztec C86 proporcionó a los desarrolladores de lenguaje C la capacidad de


producir código "HEX" compatible con ROM que luego podría transferirse usando un
quemador de ROM directamente a un procesador basado en 8086. La paravirtualización
puede ser más común hoy en día, pero la práctica de crear código ROM de bajo nivel era más
común per cápita durante aquellos años en los que los programadores de aplicaciones solían
realizar el desarrollo de controladores de dispositivos para aplicaciones individuales, y los
nuevos dispositivos equivalían a una industria artesanal . No era raro que los programadores
de aplicaciones interactuaran directamente con el hardware sin el apoyo del fabricante. Esta
práctica era similar al desarrollo de sistemas integrados en la actualidad.

Thomas Fenwick y James Goodnow II fueron los dos principales desarrolladores de Aztec-C.
Fenwick más tarde se hizo conocido como el autor del kernel de Microsoft Windows CE o NK
("New Kernel") como se llamaba entonces.

Compiladores cruzados de Microsoft C

Historia temprana - década de 1980

Microsoft C (MSC) tiene una historia más corta que otros que se remontan a la década de
1980. Los primeros compiladores de Microsoft C fueron hechos por la misma compañía que
hizo Lattice C y Microsoft los renombró como propios, hasta que se lanzó MSC 4, que fue la
primera versión que Microsoft produjo.

En 1987, muchos desarrolladores comenzaron a cambiar a Microsoft C, y muchos más


seguirían durante el desarrollo de Microsoft Windows hasta su estado actual. Surgieron
productos como Clipper y más tarde Clarion que ofrecían un fácil desarrollo de aplicaciones
de bases de datos mediante el uso de técnicas de lenguaje cruzado, lo que permitió que parte
de sus programas se compilaran con Microsoft C.

Borland C (empresa de California) estuvo disponible para su compra años antes de que
Microsoft lanzara su primer producto C.

Mucho antes de Borland, BSD Unix (Universidad de Berkeley) había obtenido C de los autores
del lenguaje C: Kernighan y Ritche, quienes lo escribieron al unísono mientras trabajaban para
AT&T (laboratorios). Las necesidades originales de K&R no eran solo una elegante sintaxis
analizada de segundo nivel para reemplazar la sintaxis analizada de primer nivel de asm: se
diseñó para que se escribiera una cantidad mínima de asm para admitir cada plataforma (el
diseño original de C era la capacidad de compilar usando C con la código de soporte mínimo
por plataforma, que necesitaban). También ayer C directamente relacionado con el código
ASM donde no depende de la plataforma. El C de hoy (más bien c ++) ya no es compatible con
C y el código asm subyacente puede ser extremadamente diferente al escrito en una
plataforma determinada (en Linux: a veces reemplaza y desvía las llamadas a la biblioteca con
opciones de distribuidor). El C de hoy es un idioma de tercer o cuarto nivel que se usa a la
antigua como un idioma de segundo nivel.

1987

Los programas en C llevaban mucho tiempo vinculados con módulos escritos en lenguaje
ensamblador . La mayoría de los compiladores de C (incluso los compiladores actuales)
ofrecen un pase de lenguaje ensamblador (que puede modificarse para mayor eficiencia y
luego vincularse al resto del programa después del ensamblaje).

Los compiladores como Aztec-C convirtieron todo al lenguaje ensamblador como una pasada
distinta y luego ensamblaron el código en una pasada distinta, y se destacaron por su código
muy eficiente y pequeño, pero en 1987 el optimizador integrado en Microsoft C era muy
bueno, y solo Las partes "críticas para la misión" de un programa generalmente se
consideraban para reescribir. De hecho, la programación en lenguaje C se había convertido en
el lenguaje de "nivel más bajo", con la programación convirtiéndose en una industria de
crecimiento multidisciplinario y los proyectos cada vez más grandes, con programadores
escribiendo interfaces de usuario e interfaces de base de datos en lenguajes de nivel superior,
y había una necesidad surgió para el desarrollo de idiomas cruzados que continúa hasta el día
de hoy.

En 1987, con el lanzamiento de MSC 5.1, Microsoft ofrecía un entorno de desarrollo de


lenguajes cruzados para MS-DOS. El código de objeto binario de 16 bits escrito en lenguaje
ensamblador ( MASM ) y otros lenguajes de Microsoft, incluidos QuickBASIC , Pascal y
Fortran, podrían vincularse en un solo programa, en un proceso que llamaron "Programación
de lenguaje mixto" y ahora "Llamadas entre idiomas". Si se usó BASIC en esta mezcla, el
programa principal necesitaba estar en BASIC para soportar el sistema de ejecución interno
que compilaba el BASIC requerido para la recolección de basura y sus otras operaciones
administradas que simulaban un intérprete de BASIC como QBasic en MS-DOS.

La convención de llamada para el código C, en particular, era pasar parámetros en "orden


inverso" en la pila y devolver valores en la pila en lugar de en un registro de procesador .
Había otras reglas de programación para hacer que todos los lenguajes funcionaran juntos,
pero esta regla en particular persistió a través del desarrollo de lenguajes cruzados que
continuó en las versiones de Windows de 16 y 32 bits y en el desarrollo de programas para OS
/ 2 , y que persiste en este día. Se conoce como la convención de llamadas de Pascal .

Otro tipo de compilación cruzada para el que se utilizó Microsoft C durante este tiempo fue
en aplicaciones minoristas que requieren dispositivos de mano como el PDT3100 de Symbol
Technologies (utilizado para hacer inventario ), que proporciona una biblioteca de enlaces
dirigida a un lector de códigos de barras basado en 8088 . La aplicación se construyó en la
computadora host y luego se transfirió al dispositivo de mano (a través de un cable serial )
donde se ejecutó, similar a lo que se hace hoy para ese mismo mercado usando Windows
Mobile por compañías como Motorola , que compraron Symbol.

Principios de la década de 1990

A lo largo de la década de 1990 y comenzando con MSC 6 (su primer compilador compatible
con ANSI C ), Microsoft volvió a enfocar sus compiladores de C en el mercado emergente de
Windows, y también en OS / 2 y en el desarrollo de programas GUI . La compatibilidad de
idiomas mixtos se mantuvo a través de MSC 6 en el lado de MS-DOS, pero la API para
Microsoft Windows 3.0 y 3.1 se escribió en MSC 6. MSC 6 también se extendió para brindar
soporte para ensamblados de 32 bits y soporte para Windows for Workgroups emergente y
Windows NT que formaría la base de Windows XP . Se introdujo una práctica de
programación llamada procesador para permitir el paso entre programas de 16 y 32 bits que
aprovechaban el enlace en tiempo de ejecución (enlace dinámico ) en lugar del enlace
estático que se favorecía en las aplicaciones monolíticas de MS-DOS de 16 bits. Algunos
desarrolladores de código nativo todavía prefieren el enlace estático, pero generalmente no
proporciona el grado de reutilización de código requerido por las mejores prácticas más
recientes, como el modelo de madurez de capacidad (CMM).

El soporte de MS-DOS todavía se proporcionó con el lanzamiento del primer compilador de C


++ de Microsoft, MSC 7, que era compatible con versiones anteriores del lenguaje de
programación C y MS-DOS y admitía la generación de código de 16 y 32 bits.

MSC asumió el control donde lo dejó Aztec C86 . La cuota de mercado de los compiladores de
C se había convertido en compiladores cruzados que aprovechaban las últimas y mejores
características de Windows, ofrecían C y C ++ en un solo paquete y seguían admitiendo
sistemas MS-DOS que ya tenían una década, y las empresas más pequeñas que Los
compiladores producidos como Aztec C ya no podían competir y se dirigieron a nichos de
mercado como los sistemas integrados o desaparecieron.

El soporte de generación de código de 16 bits y MS-DOS continuó hasta MSC 8.00c, que se
incluía con Microsoft C ++ y Microsoft Application Studio 1.5, el precursor de Microsoft Visual
Studio, que es el entorno de desarrollo cruzado que Microsoft ofrece en la actualidad.

Finales de la década de 1990

MSC 12 se lanzó con Microsoft Visual Studio 6 y ya no proporcionó soporte para binarios de
16 bits de MS-DOS, sino que proporcionó soporte para aplicaciones de consola de 32 bits,
pero proporcionó soporte para la generación de código de Windows 95 y Windows 98 , así
como para Windows NT . Las bibliotecas de enlaces estaban disponibles para otros
procesadores que ejecutaban Microsoft Windows; una práctica que Microsoft continúa hasta
el día de hoy.

MSC 13 se lanzó con Visual Studio 2003 y MSC 14 se lanzó con Visual Studio 2005 , los cuales
todavía producen código para sistemas más antiguos como Windows 95, pero que producirán
código para varias plataformas de destino, incluido el mercado móvil y la arquitectura ARM .

.NET y más allá

En 2001, Microsoft desarrolló Common Language Runtime (CLR), que formó el núcleo de su
compilador .NET Framework en Visual Studio IDE. Esta capa del sistema operativo que se
encuentra en la API permite la combinación de lenguajes de desarrollo compilados en
plataformas que ejecutan el sistema operativo Windows.

El tiempo de ejecución de .NET Framework y CLR proporcionan una capa de mapeo a las
rutinas centrales para el procesador y los dispositivos en la computadora de destino. El
compilador C de la línea de comandos en Visual Studio compilará código nativo para una
variedad de procesadores y se puede usar para construir las rutinas centrales ellos mismos.

Las aplicaciones de Microsoft .NET para plataformas de destino como Windows Mobile en la
arquitectura ARM se compilan de forma cruzada en máquinas Windows con una variedad de
procesadores y Microsoft también ofrece emuladores y entornos de implementación remota
que requieren muy poca configuración, a diferencia de los compiladores cruzados de antaño
o en el futuro. otras plataformas.

Las bibliotecas en tiempo de ejecución, como Mono , proporcionan compatibilidad para


programas .NET compilados de forma cruzada con otros sistemas operativos, como Linux .

Bibliotecas como Qt y sus predecesores, incluido XVT, brindan capacidad de desarrollo


cruzado a nivel de código fuente con otras plataformas, al mismo tiempo que utilizan
Microsoft C para construir las versiones de Windows. Otros compiladores como MinGW
también se han vuelto populares en esta área, ya que son más directamente compatibles con
los Unix que comprenden el lado del desarrollo de software que no es de Windows, lo que
permite a esos desarrolladores apuntar a todas las plataformas utilizando un entorno de
compilación familiar.

Pascal libre

Free Pascal se desarrolló desde el principio como un compilador cruzado. El ejecutable del
compilador (ppcXXX donde XXX es una arquitectura de destino) es capaz de producir
ejecutables (o solo archivos de objeto si no existe un enlazador interno, o incluso solo
archivos de ensamblaje si no existe un ensamblador interno) para todos los sistemas
operativos de la misma arquitectura. Por ejemplo, ppc386 es capaz de producir ejecutables
para i386-linux, i386-win32, i386-go32v2 (DOS) y todos los demás sistemas operativos
(consulte [13] ). Sin embargo, para compilar en otra arquitectura, primero se debe construir
una versión de arquitectura cruzada del compilador. El ejecutable del compilador resultante
tendría 'ross' adicional antes de la arquitectura de destino en su nombre. es decir, si el
compilador está diseñado para apuntar a x64, entonces el ejecutable sería ppcrossx64.

Para compilar para un sistema operativo de arquitectura elegido, se puede utilizar el


modificador de compilador (para el controlador del compilador fpc) -P y -T. Esto también se
hace cuando se realiza una compilación cruzada del propio compilador, pero se establece
mediante la opción make CPU_TARGET y OS_TARGET. Se requiere el ensamblador y enlazador
GNU para la plataforma de destino si Free Pascal aún no tiene una versión interna de las
herramientas para la plataforma de destino.

Sonido metálico

Clang es de forma nativa un compilador cruzado, en el momento de la compilación puede


seleccionar las arquitecturas a las que desea que Clang pueda apuntar.

También podría gustarte